From 33cc4959dca16ded32cf2d1f546ccbfd37991c8c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 10 Jun 2024 17:07:39 -0500 Subject: [PATCH] Fix meaning of generated `.debug_loc` sections (#8753) This commit is a fix to Wasmtime's DWARF processing transform to correct the meaning of the `.debug_loc` section. This section's addresses are relative to the `DW_AT_low_pc` entry located in the `DW_TAG_compile_unit` container, but Wasmtime's construction of this section didn't take this into account. Instead all addresses in `.debug_loc` are relative to the start of the compiled object, not to the start of the compile unit itself. This commit fixes this by unconditionally describing `DW_TAG_compile_unit` locations with `DW_AT_ranges` instead of `DW_AT_low_pc`. This ends up fixing debug information for debug information using `.debug_loc` with multiple codegen units. Closes #8752 --- .../src/debug/transform/range_info_builder.rs | 15 ++++++- .../src/bin/dwarf_multiple_codegen_units.rs | 14 +++++++ tests/all/debug/lldb.rs | 42 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 crates/test-programs/src/bin/dwarf_multiple_codegen_units.rs diff --git a/crates/cranelift/src/debug/transform/range_info_builder.rs b/crates/cranelift/src/debug/transform/range_info_builder.rs index 568eeac940..980a495018 100644 --- a/crates/cranelift/src/debug/transform/range_info_builder.rs +++ b/crates/cranelift/src/debug/transform/range_info_builder.rs @@ -145,7 +145,20 @@ impl RangeInfoBuilder { for (begin, end) in ranges { result.extend(addr_tr.translate_ranges(*begin, *end)); } - if result.len() != 1 { + + // If we're seeing the ranges for a `DW_TAG_compile_unit` DIE + // then don't use `DW_AT_low_pc` and `DW_AT_high_pc`. These + // attributes, if set, will configure the base address of all + // location lists that this unit refers to. Currently this + // debug transform does not take this base address into account + // when generate the `.debug_loc` section. Consequently when a + // compile unit is configured here the `DW_AT_ranges` attribute + // is unconditionally used instead of + // `DW_AT_low_pc`/`DW_AT_high_pc`. + let is_attr_for_compile_unit = + out_unit.get(current_scope_id).tag() == gimli::DW_TAG_compile_unit; + + if result.len() != 1 || is_attr_for_compile_unit { let range_list = result .iter() .map(|tr| write::Range::StartLength { diff --git a/crates/test-programs/src/bin/dwarf_multiple_codegen_units.rs b/crates/test-programs/src/bin/dwarf_multiple_codegen_units.rs new file mode 100644 index 0000000000..afbfa94ffc --- /dev/null +++ b/crates/test-programs/src/bin/dwarf_multiple_codegen_units.rs @@ -0,0 +1,14 @@ +fn main() { + let a = 3; + foo::bar(a); +} + +mod foo { + pub fn bar(x: u32) -> u32 { + let mut sum = 0; + for i in 0..x { + sum += i; + } + sum + } +} diff --git a/tests/all/debug/lldb.rs b/tests/all/debug/lldb.rs index ee347a162c..232ab540f7 100644 --- a/tests/all/debug/lldb.rs +++ b/tests/all/debug/lldb.rs @@ -376,4 +376,46 @@ check: exited with status = 0 fn dwarf_shared_memory() -> Result<()> { test_dwarf_simple(DWARF_SHARED_MEMORY, &[]) } + + #[test] + #[ignore] + fn dwarf_multiple_codegen_units() -> Result<()> { + for wasm in [ + DWARF_MULTIPLE_CODEGEN_UNITS, + DWARF_MULTIPLE_CODEGEN_UNITS_COMPONENT, + ] { + println!("testing {wasm:?}"); + let output = lldb_with_script( + &["-Ccache=n", "-Oopt-level=0", "-Ddebug-info", wasm], + r#" +breakpoint set --file dwarf_multiple_codegen_units.rs --line 3 +breakpoint set --file dwarf_multiple_codegen_units.rs --line 10 +r +fr v +c +fr v +breakpoint delete 2 +finish +c"#, + )?; + + check_lldb_output( + &output, + r#" +check: Breakpoint 1: no locations (pending) +check: Breakpoint 2: no locations (pending) +check: stop reason = breakpoint 1.1 +check: foo::bar(a) +check: a = 3 +check: sum += i +check: x = 3 +check: sum = 0 +check: 1 breakpoints deleted +check: Return value: $(=.*) 3 +check: exited with status = 0 +"#, + )?; + } + Ok(()) + } }