Skip to content

Commit a9cef25

Browse files
committed
fix(walltime): extract unwind data for binaries without eh_frame_hdr
unwind_data_from_elf bailed when .eh_frame_hdr was absent, leaving modules like Valgrind's statically-linked tools without any unwind data. Samples passing through their code could not be unwound, producing broken stacks in the flamegraph. Only require .eh_frame and emit the hdr fields as None when the section is missing.
1 parent 8299295 commit a9cef25

8 files changed

Lines changed: 47 additions & 29 deletions

src/executor/wall_time/profiler/perf/jit_dump.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ impl JitDump {
8282
let unwind_data = UnwindData {
8383
path,
8484
base_svma: 0,
85-
eh_frame_hdr,
86-
eh_frame_hdr_svma: 0..0,
85+
eh_frame_hdr: Some(eh_frame_hdr),
86+
eh_frame_hdr_svma: Some(0..0),
8787
eh_frame,
8888
eh_frame_svma: 0..0,
8989
};

src/executor/wall_time/profiler/perf/snapshots/codspeed_runner__executor__wall_time__profiler__perf__unwind_data__tests__cpp_unwind_data.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
2-
source: src/executor/wall_time/perf/unwind_data.rs
3-
expression: "unwind_data_from_elf(MODULE_PATH.as_bytes(), start_addr, end_addr, None,\nload_bias,)"
2+
source: src/executor/wall_time/profiler/perf/unwind_data.rs
3+
expression: "unwind_data_from_elf(module_path.as_bytes(), start_addr, end_addr, None,\nexpected_load_bias,)"
44
---
55
Ok(
66
(
77
UnwindData {
88
path: "testdata/perf_map/cpp_my_benchmark.bin",
99
base_svma: 400000,
10-
eh_frame_hdr_svma: 4577bc..458b30,
11-
eh_frame_hdr_hash: 4b4eac90f7f5e60d,
10+
eh_frame_hdr_svma: Some(4577bc..458b30),
11+
eh_frame_hdr_hash: Some(4b4eac90f7f5e60d),
1212
eh_frame_hash: 233bdd4ae9fe4ba4,
1313
eh_frame_svma: 451098..4577bc,
1414
},

src/executor/wall_time/profiler/perf/snapshots/codspeed_runner__executor__wall_time__profiler__perf__unwind_data__tests__golang_unwind_data.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
2-
source: src/executor/wall_time/perf/unwind_data.rs
3-
expression: "unwind_data_from_elf(MODULE_PATH.as_bytes(), start_addr, end_addr, None,\nload_bias,)"
2+
source: src/executor/wall_time/profiler/perf/unwind_data.rs
3+
expression: "unwind_data_from_elf(module_path.as_bytes(), start_addr, end_addr, None,\nexpected_load_bias,)"
44
---
55
Ok(
66
(
77
UnwindData {
88
path: "testdata/perf_map/go_fib.bin",
99
base_svma: 400000,
10-
eh_frame_hdr_svma: 6498b0..649b94,
11-
eh_frame_hdr_hash: f1f69beb959a08d7,
10+
eh_frame_hdr_svma: Some(6498b0..649b94),
11+
eh_frame_hdr_hash: Some(f1f69beb959a08d7),
1212
eh_frame_hash: a8727039dd21b51c,
1313
eh_frame_svma: 649b98..64aa70,
1414
},

src/executor/wall_time/profiler/perf/snapshots/codspeed_runner__executor__wall_time__profiler__perf__unwind_data__tests__ruff_unwind_data.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
2-
source: src/executor/wall_time/perf/unwind_data.rs
3-
expression: "unwind_data_from_elf(MODULE_PATH.as_bytes(), start_addr, end_addr, None,\nload_bias,)"
2+
source: src/executor/wall_time/profiler/perf/unwind_data.rs
3+
expression: "unwind_data_from_elf(module_path.as_bytes(), start_addr, end_addr, None,\nexpected_load_bias,)"
44
---
55
Ok(
66
(
77
UnwindData {
88
path: "testdata/perf_map/ty_walltime",
99
base_svma: 0,
10-
eh_frame_hdr_svma: 7ec298..80f67c,
11-
eh_frame_hdr_hash: 6d6dd1e2c782318a,
10+
eh_frame_hdr_svma: Some(7ec298..80f67c),
11+
eh_frame_hdr_hash: Some(6d6dd1e2c782318a),
1212
eh_frame_hash: ee27244db791265a,
1313
eh_frame_svma: 80f680..918a9c,
1414
},

src/executor/wall_time/profiler/perf/snapshots/codspeed_runner__executor__wall_time__profiler__perf__unwind_data__tests__rust_divan_unwind_data.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
2-
source: src/executor/wall_time/perf/unwind_data.rs
3-
expression: "unwind_data_from_elf(MODULE_PATH.as_bytes(), start_addr, end_addr, None,\nload_bias,)"
2+
source: src/executor/wall_time/profiler/perf/unwind_data.rs
3+
expression: "unwind_data_from_elf(module_path.as_bytes(), start_addr, end_addr, None,\nexpected_load_bias,)"
44
---
55
Ok(
66
(
77
UnwindData {
88
path: "testdata/perf_map/divan_sleep_benches.bin",
99
base_svma: 0,
10-
eh_frame_hdr_svma: 2ac74..2ea60,
11-
eh_frame_hdr_hash: f579da4368e627c1,
10+
eh_frame_hdr_svma: Some(2ac74..2ea60),
11+
eh_frame_hdr_hash: Some(f579da4368e627c1),
1212
eh_frame_hash: 791501d5a9c438d,
1313
eh_frame_svma: 11540..2ac74,
1414
},

src/executor/wall_time/profiler/perf/snapshots/codspeed_runner__executor__wall_time__profiler__perf__unwind_data__tests__the_algorithms_unwind_data.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
2-
source: src/executor/wall_time/perf/unwind_data.rs
3-
expression: "unwind_data_from_elf(MODULE_PATH.as_bytes(), start_addr, end_addr, None,\nload_bias,)"
2+
source: src/executor/wall_time/profiler/perf/unwind_data.rs
3+
expression: "unwind_data_from_elf(module_path.as_bytes(), start_addr, end_addr, None,\nexpected_load_bias,)"
44
---
55
Ok(
66
(
77
UnwindData {
88
path: "testdata/perf_map/the_algorithms.bin",
99
base_svma: 0,
10-
eh_frame_hdr_svma: 2f0ec..33590,
11-
eh_frame_hdr_hash: 277fbdb59e6decaa,
10+
eh_frame_hdr_svma: Some(2f0ec..33590),
11+
eh_frame_hdr_hash: Some(277fbdb59e6decaa),
1212
eh_frame_hash: 21d8b0c8da0d1029,
1313
eh_frame_svma: 128a8..2f0ec,
1414
},

src/executor/wall_time/profiler/perf/unwind_data.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@ pub fn unwind_data_from_elf(
6262
section.address()..section.address() + section.size()
6363
}
6464

65-
let v3 = UnwindData {
65+
// `.eh_frame_hdr` is only an optional lookup index into `.eh_frame` — some
66+
// binaries (e.g. Valgrind's statically-linked tools) are linked without
67+
// `ld --eh-frame-hdr` and don't carry it. The parser rebuilds the index
68+
// from `.eh_frame` in that case.
69+
let unwind_data = UnwindData {
6670
path: path.clone(),
6771
base_svma,
68-
eh_frame_hdr: eh_frame_hdr_data.context("Failed to find eh_frame hdr data")?,
69-
eh_frame_hdr_svma: eh_frame_hdr
70-
.as_ref()
71-
.map(svma_range)
72-
.context("Failed to find eh_frame hdr section")?,
72+
eh_frame_hdr: eh_frame_hdr_data,
73+
eh_frame_hdr_svma: eh_frame_hdr.as_ref().map(svma_range),
7374
eh_frame: eh_frame_data.context("Failed to find eh_frame data")?,
7475
eh_frame_svma: eh_frame
7576
.as_ref()
@@ -84,7 +85,7 @@ pub fn unwind_data_from_elf(
8485
base_avma,
8586
};
8687

87-
Ok((v3, mapping))
88+
Ok((unwind_data, mapping))
8889
}
8990

9091
#[cfg(all(test, target_os = "linux"))]
@@ -230,6 +231,20 @@ mod tests {
230231
));
231232
}
232233

234+
#[test]
235+
fn test_valgrind_unwind_data_without_eh_frame_hdr() {
236+
// Valgrind's statically-linked tools (here: callgrind-amd64-linux) are
237+
// linked with a custom linker script without `ld --eh-frame-hdr`, so
238+
// they carry `.eh_frame` but no `.eh_frame_hdr`. Unwind data extraction
239+
// must still succeed since the hdr is only an optional lookup index.
240+
let module_path = "testdata/perf_map/valgrind";
241+
let (unwind_data, _) =
242+
unwind_data_from_elf(module_path.as_bytes(), 0x58000000, 0x58292000, None, 0)
243+
.expect("unwind data extraction should succeed without .eh_frame_hdr");
244+
assert!(unwind_data.eh_frame_hdr.is_none());
245+
assert!(!unwind_data.eh_frame.is_empty());
246+
}
247+
233248
#[test]
234249
fn test_ruff_unwind_data() {
235250
// gdb testdata/perf_map/ty_walltime -ex "break main" -ex "run" -ex "info proc mappings" -ex "continue" -ex "quit" -batch

testdata/perf_map/valgrind

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:5461304de8a1b9242ba3b0b912c50e21d9b28b5423754de13e20cb7c7ff6df05
3+
size 13298232

0 commit comments

Comments
 (0)