Skip to content

Commit 6410d30

Browse files
committed
feat: add unwind data v2 format
1 parent f0ff2ff commit 6410d30

5 files changed

Lines changed: 137 additions & 58 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/runner-shared/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ edition = "2024"
77
anyhow = "1.0.100"
88
serde = { version = "1.0.225", features = ["derive"] }
99
serde_json = "1.0.145"
10+
bincode = "1.3.3"
11+
log = "0.4.28"

crates/runner-shared/src/unwind_data.rs

Lines changed: 124 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,153 @@ use core::{
55
use serde::{Deserialize, Serialize};
66
use std::{hash::DefaultHasher, ops::Range};
77

8-
/// Unwind data for a single module.
8+
/// A versioned enum for `UnwindData` to allow for future extensions while maintaining backward compatibility.
99
#[derive(Serialize, Deserialize)]
10-
pub struct UnwindData {
11-
pub path: String,
10+
pub enum UnwindData {
11+
V1(UnwindDataV1),
12+
V2(UnwindDataV2),
13+
}
1214

13-
pub avma_range: Range<u64>,
14-
pub base_avma: u64,
15-
pub eh_frame_hdr: Vec<u8>,
16-
pub eh_frame_hdr_svma: Range<u64>,
15+
impl UnwindData {
16+
pub fn path(&self) -> &str {
17+
match self {
18+
UnwindData::V1(data) => &data.path,
19+
UnwindData::V2(data) => &data.path,
20+
}
21+
}
1722

18-
pub eh_frame: Vec<u8>,
19-
pub eh_frame_svma: Range<u64>,
23+
pub fn avma_range(&self) -> &Range<u64> {
24+
match self {
25+
UnwindData::V1(data) => &data.avma_range,
26+
UnwindData::V2(data) => &data.avma_range,
27+
}
28+
}
2029

21-
#[serde(default)]
22-
pub base_svma: u64,
30+
pub fn base_avma(&self) -> u64 {
31+
match self {
32+
UnwindData::V1(data) => data.base_avma,
33+
UnwindData::V2(data) => data.base_avma,
34+
}
35+
}
36+
37+
pub fn base_svma(&self) -> u64 {
38+
match self {
39+
UnwindData::V1(_) => 0,
40+
UnwindData::V2(data) => data.base_svma,
41+
}
42+
}
43+
44+
pub fn eh_frame_hdr(&self) -> &Vec<u8> {
45+
match self {
46+
UnwindData::V1(data) => &data.eh_frame_hdr,
47+
UnwindData::V2(data) => &data.eh_frame_hdr,
48+
}
49+
}
50+
51+
pub fn eh_frame_hdr_svma(&self) -> &Range<u64> {
52+
match self {
53+
UnwindData::V1(data) => &data.eh_frame_hdr_svma,
54+
UnwindData::V2(data) => &data.eh_frame_hdr_svma,
55+
}
56+
}
57+
58+
pub fn eh_frame(&self) -> &Vec<u8> {
59+
match self {
60+
UnwindData::V1(data) => &data.eh_frame,
61+
UnwindData::V2(data) => &data.eh_frame,
62+
}
63+
}
64+
65+
pub fn eh_frame_svma(&self) -> &Range<u64> {
66+
match self {
67+
UnwindData::V1(data) => &data.eh_frame_svma,
68+
UnwindData::V2(data) => &data.eh_frame_svma,
69+
}
70+
}
71+
72+
pub fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: i32) -> anyhow::Result<()> {
73+
let unwind_data_path = folder.as_ref().join(format!(
74+
"{}_{:x}_{:x}.unwind2",
75+
pid,
76+
self.avma_range().start,
77+
self.avma_range().end
78+
));
79+
self.to_file(unwind_data_path)?;
80+
81+
Ok(())
82+
}
83+
84+
pub fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()> {
85+
if let Ok(true) = std::fs::exists(path.as_ref()) {
86+
log::warn!(
87+
"{} already exists, file will be truncated",
88+
path.as_ref().display()
89+
);
90+
log::warn!("{} {:x?}", self.path(), self.avma_range());
91+
}
92+
93+
let mut writer = std::fs::File::create(path.as_ref())?;
94+
bincode::serialize_into(&mut writer, self)?;
95+
Ok(())
96+
}
2397
}
2498

2599
impl Debug for UnwindData {
26100
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27101
let eh_frame_hdr_hash = {
28102
let mut hasher = DefaultHasher::new();
29-
self.eh_frame_hdr.hash(&mut hasher);
103+
self.eh_frame_hdr().hash(&mut hasher);
30104
hasher.finish()
31105
};
32106
let eh_frame_hash = {
33107
let mut hasher = DefaultHasher::new();
34-
self.eh_frame.hash(&mut hasher);
108+
self.eh_frame().hash(&mut hasher);
35109
hasher.finish()
36110
};
37111

38112
f.debug_struct("UnwindData")
39-
.field("path", &self.path)
40-
.field("avma_range", &format_args!("{:x?}", self.avma_range))
41-
.field("base_avma", &format_args!("{:x}", self.base_avma))
42-
.field("base_svma", &format_args!("{:x}", self.base_svma))
113+
.field("path", &self.path())
114+
.field("avma_range", &format_args!("{:x?}", self.avma_range()))
115+
.field("base_avma", &format_args!("{:x}", self.base_avma()))
116+
.field("base_svma", &format_args!("{:x}", self.base_svma()))
43117
.field(
44118
"eh_frame_hdr_svma",
45-
&format_args!("{:x?}", self.eh_frame_hdr_svma),
119+
&format_args!("{:x?}", self.eh_frame_hdr_svma()),
46120
)
47121
.field("eh_frame_hdr_hash", &format_args!("{eh_frame_hdr_hash:x}"))
48122
.field("eh_frame_hash", &format_args!("{eh_frame_hash:x}"))
49-
.field("eh_frame_svma", &format_args!("{:x?}", self.eh_frame_svma))
123+
.field(
124+
"eh_frame_svma",
125+
&format_args!("{:x?}", self.eh_frame_svma()),
126+
)
50127
.finish()
51128
}
52129
}
130+
131+
#[derive(Serialize, Deserialize)]
132+
pub struct UnwindDataV1 {
133+
pub path: String,
134+
135+
pub avma_range: Range<u64>,
136+
pub base_avma: u64,
137+
pub eh_frame_hdr: Vec<u8>,
138+
pub eh_frame_hdr_svma: Range<u64>,
139+
140+
pub eh_frame: Vec<u8>,
141+
pub eh_frame_svma: Range<u64>,
142+
}
143+
144+
#[derive(Serialize, Deserialize, Clone)]
145+
pub struct UnwindDataV2 {
146+
pub path: String,
147+
148+
pub avma_range: Range<u64>,
149+
pub base_avma: u64,
150+
pub base_svma: u64,
151+
152+
pub eh_frame_hdr: Vec<u8>,
153+
pub eh_frame_hdr_svma: Range<u64>,
154+
155+
pub eh_frame: Vec<u8>,
156+
pub eh_frame_svma: Range<u64>,
157+
}

src/run/runner/wall_time/perf/jit_dump.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use crate::{
22
prelude::*,
3-
run::runner::wall_time::perf::{
4-
perf_map::{ModuleSymbols, Symbol},
5-
unwind_data::UnwindDataExt,
6-
},
3+
run::runner::wall_time::perf::perf_map::{ModuleSymbols, Symbol},
74
};
85
use linux_perf_data::jitdump::{JitDumpReader, JitDumpRecord};
9-
use runner_shared::unwind_data::UnwindData;
6+
use runner_shared::unwind_data::{UnwindData, UnwindDataV2};
107
use std::{
118
collections::HashSet,
129
path::{Path, PathBuf},
@@ -75,7 +72,7 @@ impl JitDump {
7572
continue;
7673
};
7774

78-
jit_unwind_data.push(UnwindData {
75+
jit_unwind_data.push(UnwindData::V2(UnwindDataV2 {
7976
path: format!("jit_{name}"),
8077
avma_range: avma_start..avma_end,
8178
base_avma: 0,
@@ -84,7 +81,7 @@ impl JitDump {
8481
eh_frame,
8582
eh_frame_svma: 0..0,
8683
base_svma: 0,
87-
});
84+
}));
8885
}
8986
JitDumpRecord::CodeUnwindingInfo(record) => {
9087
// Store unwind info for the next code loads

src/run/runner/wall_time/perf/unwind_data.rs

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
use crate::run::runner::wall_time::perf::elf_helper;
44
use anyhow::{Context, bail};
55
use debugid::CodeId;
6-
use libc::pid_t;
76
use object::Object;
87
use object::ObjectSection;
98
use runner_shared::unwind_data::UnwindData;
9+
use runner_shared::unwind_data::UnwindDataV2;
1010
use std::ops::Range;
1111

1212
pub trait UnwindDataExt {
@@ -19,9 +19,6 @@ pub trait UnwindDataExt {
1919
) -> anyhow::Result<Self>
2020
where
2121
Self: Sized;
22-
23-
fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: pid_t) -> anyhow::Result<()>;
24-
fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()>;
2522
}
2623

2724
impl UnwindDataExt for UnwindData {
@@ -83,7 +80,7 @@ impl UnwindDataExt for UnwindData {
8380
section.address()..section.address() + section.size()
8481
}
8582

86-
Ok(Self {
83+
Ok(UnwindData::V2(UnwindDataV2 {
8784
path,
8885
avma_range,
8986
base_avma,
@@ -98,31 +95,7 @@ impl UnwindDataExt for UnwindData {
9895
.as_ref()
9996
.map(svma_range)
10097
.context("Failed to find eh_frame section")?,
101-
})
102-
}
103-
104-
fn save_to<P: AsRef<std::path::Path>>(&self, folder: P, pid: pid_t) -> anyhow::Result<()> {
105-
let unwind_data_path = folder.as_ref().join(format!(
106-
"{}_{:x}_{:x}.unwind",
107-
pid, self.avma_range.start, self.avma_range.end
108-
));
109-
self.to_file(unwind_data_path)?;
110-
111-
Ok(())
112-
}
113-
114-
fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> anyhow::Result<()> {
115-
if let Ok(true) = std::fs::exists(path.as_ref()) {
116-
log::warn!(
117-
"{} already exists, file will be truncated",
118-
path.as_ref().display()
119-
);
120-
log::warn!("{} {:x?}", self.path, self.avma_range);
121-
}
122-
123-
let mut writer = std::fs::File::create(path.as_ref())?;
124-
bincode::serialize_into(&mut writer, self)?;
125-
Ok(())
98+
}))
12699
}
127100
}
128101

0 commit comments

Comments
 (0)