Skip to content
Snippets Groups Projects
Select Git revision
  • b47e562abaa2d0e055d47d4c7162d9cbf5af8d43
  • master default protected
2 results

call_err2.rs

Blame
  • 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