Select Git revision
call_err2.rs
main.rs 7.79 KiB
extern crate libc;
use std::io::{self, Read, Write};
use std::process::{Command, Stdio};
use std::{env, str};
#[derive(Debug)]
struct Out {
hash: Option<String>,
crate_name: Option<String>,
out_dir: Option<String>,
}
// Parse the output from rustc
// we skip the last line (Finished ...)
// and look for `--crate-name x`, `extra-filename=y` and `--out dir z`
//
// Notice, the parsing is a bit of a hack, implemnting look-ahead using flags.
fn parse_out(out_str: &str) -> Out {
let mut out = Out {
hash: None,
crate_name: None,
out_dir: None,
};
let output = out_str;
let mut i = output.lines().into_iter();
i.next_back(); // skip last line (Finished)
if let Some(line) = i.next_back() {
let mut crate_name = false;
let mut out_dir = false;
for part in line.split(' ') {
if crate_name {
out.crate_name = Some(part.to_string());
crate_name = false;
} else if out_dir {
out.out_dir = Some(part.to_string());
out_dir = false;
} else if part.starts_with("--crate-name") {
crate_name = true;
} else if part.starts_with("--out-dir") {
out_dir = true;
} else if part.starts_with("extra-filename=") {
out.hash = Some(part.split('=').nth(1).unwrap().to_string());
}
}
}
out
}
fn main() {
println!("start sub command");
// first argument is the path to this binary; the second argument is always "call-stack" -- both can
// be ignored
let args = env::args().skip(2).collect::<Vec<_>>();
// turn `cargo klee --example foo` into `cargo rustc --example foo -- (..)`
let mut c = Command::new("cargo");
c.arg("rustc")
.args(&args)
// verbose output for debugging purposes
.arg("-v")
.arg("--color=always")
.arg("--")
// ignore linking
//.args(&["-C", "linker=true"])
// link for embedded with retained stack section
// .args(&["-C", "link-arg=-Tlink.x"])
// .arg("codegen-units = 1") // for now assume that this is already in the user crate
// force LTO
.args(&["-C", "lto"])
// also output the LLVM-IR (.ll file) for debugging purposes
.arg("--emit=llvm-bc,llvm-ir")
// emit stack sizes for the top level (not dependencies)
.args(&["-Z", "emit-stack-sizes"])
// 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 until 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;
}
}
let out = parse_out(str::from_utf8(&output).unwrap());
println!("{:?}", out);
use std::fmt::Write;
let mut s = String::new();
write!(
&mut s,
"{}/{}{}.ll",
out.out_dir.expect("--out-dir missing"),
out.crate_name.expect("--crate-name missing"),
out.hash.expect("extra-filename missing")
)
.expect("internal error");
println!("s: {}", s);
let mut c = Command::new("opt");
c.arg("-analyze").arg("-print-callgraph").arg(s);
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;
}
}
// -analyze -print-callgraph /home/pln/rust/stack-test/target/thumbv7m-none-eabi/release/deps/stack_test-87f399c0e9e1fb93.ll
// } else {
// panic!("could not determine hash, please recompile in `--release` mode");
// }
// 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;
// }
// }
// let output = str::from_utf8(&output).unwrap();
// if let (Some(hash), Some(crate_name), example) = parse_output(&output) {
// println!("{:?}, {:?}, {:?}", example, hash, crate_name);
// } else {
// panic!("could not determine hash, please recompile in `--release` mode");
// }
// // 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();
// println!("here ...");
// 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);
// }
// }
// }
// }
// match suffix {
// None => panic!(format!(
// "Cannot determine hash, please run `touch example/{}.rs` to force recompiltaion.",
// example
// )),
// Some(s) => (example, s),
// }
// } else {
// // nothing to do if the user didn't use `--example`
// println!("try to determinte hash");
// let output = str::from_utf8(&output).unwrap();
// println!("here ...");
// let mut suffix = None;
// for line in output.lines() {
// for part in line.split(' ') {
// if part.starts_with("extra-filename=") {
// suffix = part.split('=').nth(1);
// }
// }
// }
// match suffix {
// None => panic!(format!(
// "Cannot determine hash, please force recompiltaion."
// )),
// Some(s) => panic!("main hash {}", s),
// }
// // return;
// };
// println!("{:?}", (example, suffix));
/*
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() }
*/
}
// blx511
// ARN
// LINDGREN
// PER
// 03021968 Piteå
// Swedish
// pass#
// Aquamarine
// Tourist