diff --git a/cargo-klee/src/cli.rs b/cargo-klee/src/cli.rs index e461c6c3068d8b89084c7bc56ef22b1424da8ade..b69ecede359a2940d1b7a381e0ddacfdb814d137 100644 --- a/cargo-klee/src/cli.rs +++ b/cargo-klee/src/cli.rs @@ -45,7 +45,7 @@ pub struct Cli { /// GDB Replay #[arg(long, short)] - pub replay: bool, + pub gdb: bool, // #[command(subcommand)] // binary: Option<Commands>, } diff --git a/cargo-klee/src/main.rs b/cargo-klee/src/main.rs index db6535fc8fac0bec4d02d2286581ad389c1767f3..8964e552e3dbf62ee338d91232d7e5c4c4d705f8 100644 --- a/cargo-klee/src/main.rs +++ b/cargo-klee/src/main.rs @@ -156,7 +156,7 @@ fn main() -> Result<(), Error> { // enable coloring of output .arg("--color") // ll file to analyse - .arg(ll); + .arg(ll.clone()); println!("klee {:?}", klee); @@ -174,11 +174,78 @@ fn main() -> Result<(), Error> { if !output.success() { return Err(anyhow!("`klee` failed, exiting `cargo-klee`")); } + } - let output = klee.stdout(Stdio::piped()).output()?; - let stderr = String::from_utf8(output.stderr)?; + // replay execution in `gdb` + if args.gdb { + // compile to object code for replay using `llc` + let mut llc = Command::new("llc"); + llc.arg("-filetype=obj") + .arg("-relocation-model=pic") + .arg(ll.clone()); - eprintln!("{}", stderr); + if args.verbose { + eprintln!("\n{:?}\n", llc); + } + + let output = llc + .stdout(Stdio::piped()) + .status() + .expect("failed to invoke `llc`, exiting `cargo-klee`"); + + if !output.success() { + return Err(anyhow!("`llc` failed, exiting `cargo-klee`")); + } + + // compile to executable for replay using `clang` + let mut clang = Command::new("clang"); + + let obj_name = format!("{}.o", ll); + let replay_name = format!("{}.replay", ll); + + clang + .arg(obj_name) + .arg("--rtlib=compiler-rt") + .arg("-lkleeRuntest") + .args(&["-o", &replay_name]); + + if args.verbose { + eprintln!("\n{:?}\n", clang); + } + + let output = llc + .stdout(Stdio::piped()) + .status() + .expect("failed to invoke `clang`, exiting `cargo-klee`"); + + if !output.success() { + return Err(anyhow!("`clang` failed, exiting `cargo-klee`")); + } + + let mut gdb = Command::new("gdb"); + if let Ok(cwd) = env::var("GDB_CWD") { + // set gdb current dir to `GDB_CWD` + gdb.current_dir(cwd); + } else { + // set gdb current dir to the target directory + gdb.current_dir(out_dir); + }; + + // set replay name to be loaded by gdb + gdb.arg(replay_name); + + if args.verbose { + eprintln!("\n{:?}\n", gdb); + } + + let output = gdb + .stdout(Stdio::piped()) + .status() + .expect("failed to invoke `gdb`, exiting `cargo-klee`"); + + if !output.success() { + return Err(anyhow!("`gdb` failed, exiting `cargo-klee`")); + } } println!("--- done ---");