From 8d547d06448e8e50b2d818c2185bbc525f388593 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 6 Jun 2024 17:32:48 -0700 Subject: [PATCH] Fix meaning of generated `.debug_loc` sections 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 568eeac94086..980a4950186a 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 000000000000..afbfa94ffc1e --- /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 ee347a162c09..232ab540f78c 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(()) + } }