1 use anyhow::{Result, bail, format_err}; 2 use filecheck::{CheckerBuilder, NO_VARIABLES}; 3 use std::env; 4 use std::io::Write; 5 use std::process::Command; 6 use tempfile::NamedTempFile; 7 8 fn gdb_with_script(args: &[&str], script: &str) -> Result<String> { 9 let lldb_path = env::var("GDB").unwrap_or("gdb".to_string()); 10 let mut cmd = Command::new(&lldb_path); 11 12 cmd.arg("--batch"); 13 let mut script_file = NamedTempFile::new()?; 14 script_file.write(script.as_bytes())?; 15 let script_path = script_file.path().to_str().unwrap(); 16 cmd.args(&["-x", &script_path]); 17 18 cmd.arg("--args"); 19 20 let mut me = std::env::current_exe().expect("current_exe specified"); 21 me.pop(); // chop off the file name 22 me.pop(); // chop off `deps` 23 me.push("wasmtime"); 24 cmd.arg(me); 25 26 cmd.args(args); 27 28 let output = cmd.output().expect("success"); 29 if !output.status.success() { 30 bail!( 31 "failed to execute {:?}: {}", 32 cmd, 33 String::from_utf8_lossy(&output.stderr), 34 ); 35 } 36 Ok(String::from_utf8(output.stdout)?) 37 } 38 39 fn check_gdb_output(output: &str, directives: &str) -> Result<()> { 40 let mut builder = CheckerBuilder::new(); 41 builder 42 .text(directives) 43 .map_err(|e| format_err!("unable to build checker: {e:?}"))?; 44 let checker = builder.finish(); 45 let check = checker 46 .explain(output, NO_VARIABLES) 47 .map_err(|e| format_err!("{e:?}"))?; 48 assert!(check.0, "didn't pass check {}", check.1); 49 Ok(()) 50 } 51 52 #[test] 53 #[ignore] 54 fn test_debug_dwarf_gdb() -> Result<()> { 55 let output = gdb_with_script( 56 &[ 57 "-Ccache=n", 58 "-Ddebug-info", 59 "-Oopt-level=0", 60 "--invoke", 61 "fib", 62 test_programs_artifacts::DWARF_FIB_WASM, 63 "3", 64 ], 65 r#"set breakpoint pending on 66 b fib 67 r 68 info locals 69 c"#, 70 )?; 71 72 check_gdb_output( 73 &output, 74 r#" 75 check: Breakpoint 1 (fib) pending 76 check: hit Breakpoint 1 77 sameln: fib (n=3) 78 check: a = 0 79 check: b = 0 80 check: exited normally 81 "#, 82 )?; 83 Ok(()) 84 } 85