Commit 75e5fea6 authored by Per Lindgren's avatar Per Lindgren

cargo-klee

parent 222e0169
/target
target
**/*.rs.bk
[[package]]
name = "cargo-klee"
version = "0.1.0"
dependencies = [
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2"
[package]
authors = ["Jorge Aparicio <jorge@japaric.io>"]
name = "cargo-klee"
version = "0.1.0"
[dependencies]
libc = "0.2.33"
extern crate libc;
use std::io::{self, Read, Write};
use std::process::{Command, Stdio};
use std::{env, str};
fn main() {
// first argument is the path to this binary; the second argument is always "klee" -- both can
// be ignored
let args = env::args().skip(2).collect::<Vec<_>>();
// turn `cargo klee --example foo` into `xargo rustc --example foo -- (..)`
let mut c = Command::new("xargo");
c.arg("rustc")
.args(&args)
// verbose output for debugging purposes
.arg("-v")
.arg("--color=always")
.arg("--")
// ignore linking
.args(&["-C", "linker=true"])
// force LTO
.args(&["-C", "lto"])
// also output the LLVM-IR (.ll file) for debugging purposes
.arg("--emit=llvm-bc,llvm-ir")
// force panic=abort in all crates
.env("RUSTFLAGS", "-C panic=abort")
// collect stderr
.stderr(Stdio::piped());
// print full command for debugging purposes
eprintln!("{:?}", c);
// spawn process and drive it completion while replicating its stderr in ours
let mut p = c.spawn().unwrap();
let mut pstderr = p.stderr.take().unwrap();
let mut buf = [0; 1024];
let mut output = vec![];
let stderr = io::stderr();
let mut stderr = stderr.lock();
loop {
if let Ok(n) = pstderr.read(&mut buf) {
stderr.write(&buf[..n]).unwrap();
output.extend_from_slice(&buf[..n]);
}
if let Some(status) = p.try_wait().unwrap() {
assert!(status.success());
break;
}
}
// next we are going to try to run the .bc file using klee inside a docker container
// FIXME the way we find out which .bc file we have to use is pretty hacky; using Cargo as a
// library would be cleaner, I suppose
// find out the argument passed to `--example`, if used at all
let mut example = None;
let mut iargs = args.iter();
while let Some(arg) = iargs.next() {
if arg == "--example" {
example = iargs.next();
break;
}
}
// get the suffix of the example
let (example, suffix) = if let Some(example) = example {
let mut suffix = None;
let output = str::from_utf8(&output).unwrap();
for line in output.lines() {
if line.contains(&format!("examples/{}.rs", example)) {
for part in line.split(' ') {
if part.starts_with("extra-filename=") {
suffix = part.split('=').nth(1);
}
}
}
}
(example, suffix.unwrap())
} else {
// nothing to do if the user didn't use `--example`
return;
};
let profile = if args.iter().any(|a| a == "--release") {
"release"
} else {
"debug"
};
let mut docker = Command::new("docker");
docker
.arg("run")
.arg("--rm")
.args(&["--user", &format!("{}:{}", uid(), gid())])
.args(&[
"-v",
&format!("{}:/mnt", env::current_dir().unwrap().display()),
])
.args(&["-w", "/mnt"])
.arg("-it")
.arg("afoht/llvm-klee-4")
.args(&[
"/usr/bin/klee",
&format!("target/{}/examples/{}{}.bc", profile, example, suffix),
]);
// print full command for debugging purposes
eprintln!("{:?}", docker);
assert!(docker.status().unwrap().success());
}
// NOTE from cross
fn gid() -> u32 {
unsafe { libc::getgid() }
}
// NOTE from cross
fn uid() -> u32 {
unsafe { libc::getuid() }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment