use super::dump::{DwarfDumpSection, get_dwarfdump}; use super::obj::compile_cranelift; use anyhow::{Result, format_err}; use filecheck::{CheckerBuilder, NO_VARIABLES}; use std::fs::read; use tempfile::NamedTempFile; use test_programs_artifacts::*; fn check_wasm(wasm_path: &str, directives: &str) -> Result<()> { println!("check {wasm_path}"); let wasm = read(wasm_path)?; let obj_file = NamedTempFile::new()?; let obj_path = obj_file.path().to_str().unwrap(); compile_cranelift(&wasm, Some(wasm_path.as_ref()), None, obj_path)?; let dump = get_dwarfdump(obj_path, DwarfDumpSection::DebugInfo)?; let mut builder = CheckerBuilder::new(); builder .text(directives) .map_err(|e| format_err!("unable to build checker: {e:?}"))?; let checker = builder.finish(); let check = checker .explain(&dump, NO_VARIABLES) .map_err(|e| format_err!("{e:?}"))?; assert!(check.0, "didn't pass check {}", check.1); Ok(()) } #[test] #[ignore] fn test_debug_dwarf_translate_dead_code() -> Result<()> { check_wasm( DWARF_DEAD_CODE, r##" check: DW_TAG_compile_unit # We don't have "bar" function because it is dead code not: DW_AT_name ("bar") # We have "foo" function check: DW_TAG_subprogram check: DW_AT_name ("foo") # We have "baz" function # it was marked `noinline` so isn't dead code check: DW_TAG_subprogram check: DW_AT_name ("baz") "##, ) } #[test] #[ignore] fn test_debug_dwarf_translate() -> Result<()> { check_wasm( DWARF_FIB_WASM, r##" check: DW_TAG_compile_unit # We have "fib" function check: DW_TAG_subprogram check: DW_AT_name ("fib") # Accepts one parameter check: DW_TAG_formal_parameter check: DW_AT_name ("n") check: DW_AT_decl_line (3) # Has four locals: t, a, b, i check: DW_TAG_variable check: DW_AT_name ("t") check: DW_AT_decl_line (4) check: DW_TAG_variable check: DW_AT_name ("a") check: DW_TAG_variable check: DW_AT_name ("b") check: DW_TAG_variable check: DW_AT_name ("i") check: DW_AT_decl_line (5) "##, ) } #[test] #[ignore] fn test_debug_dwarf5_translate() -> Result<()> { check_wasm( DWARF_FIB_WASM_DWARF5, r##" check: DW_TAG_compile_unit # We have "fib" function check: DW_TAG_subprogram check: DW_AT_name ("fib") # Accepts one parameter check: DW_TAG_formal_parameter check: DW_AT_name ("n") check: DW_AT_decl_line (3) # Has four locals: t, a, b, i check: DW_TAG_variable check: DW_AT_name ("t") check: DW_AT_decl_line (4) check: DW_TAG_variable check: DW_AT_name ("a") check: DW_TAG_variable check: DW_AT_name ("b") check: DW_TAG_variable check: DW_AT_name ("i") check: DW_AT_decl_line (5) "##, ) } #[test] #[ignore] fn test_debug_split_dwarf4_translate() -> Result<()> { check_wasm( DWARF_FIB_WASM_SPLIT4, r##" check: DW_TAG_compile_unit # We have "fib" function check: DW_TAG_subprogram check: DW_AT_name ("fib") # Accepts one parameter check: DW_TAG_formal_parameter check: DW_AT_name ("n") check: DW_AT_decl_line (4) # Has four locals: t, a, b, i check: DW_TAG_variable check: DW_AT_name ("t") check: DW_AT_decl_line (5) check: DW_TAG_variable check: DW_AT_name ("a") check: DW_TAG_variable check: DW_AT_name ("b") check: DW_TAG_variable check: DW_AT_name ("i") check: DW_AT_decl_line (6) "##, ) } #[test] #[ignore] fn test_debug_dwarf_translate_generated() -> Result<()> { check_wasm( DWARF_FRACTION_NORM, r##" check: DW_TAG_compile_unit check: DW_TAG_compile_unit check: DW_AT_producer ("wasmtime") check: DW_AT_name ("dwarf_fraction_norm.wasm") check: DW_AT_comp_dir ("/") check: DW_TAG_subprogram check: DW_AT_name ("__wasm_call_ctors") check: DW_AT_decl_file ("//dwarf_fraction_norm.wasm") check: DW_AT_decl_line ($(=\d+)) "##, ) } #[test] #[ignore] fn test_debug_dwarf_translate_fission() -> Result<()> { check_wasm( DWARF_FISSION, r##" check: DW_TAG_compile_unit check: DW_AT_producer ("clang $(=.*)") check: DW_AT_language (DW_LANG_C11) check: DW_AT_name ("$(=.*)dwarf_fission.c") check: DW_AT_ranges (0x$(=.+) check: DW_AT_stmt_list (0x$(=.+)) check: DW_AT_comp_dir ("$(=.*)artifacts") "##, ) }