Skip to content

Commit 70ad093

Browse files
Feature: module base address added to the Frame (#368)
* Module base address added to the Frame * Test added for module base address of the Frame * Process handle cached
1 parent 4b8f2be commit 70ad093

File tree

7 files changed

+106
-26
lines changed

7 files changed

+106
-26
lines changed

crates/without_debuginfo/tests/smoke.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,18 @@ fn all_frames_have_symbols() {
2727
assert_eq!(missing_symbols, 0);
2828
}
2929
}
30+
31+
#[test]
32+
fn all_frames_have_module_base_address() {
33+
let mut missing_base_addresses = 0;
34+
backtrace::trace(|frame| {
35+
if frame.module_base_address().is_none() {
36+
missing_base_addresses += 1;
37+
}
38+
true
39+
});
40+
41+
if cfg!(windows) {
42+
assert_eq!(missing_base_addresses, 0);
43+
}
44+
}

src/backtrace/dbghelp.rs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ use core::ffi::c_void;
2626
use core::mem;
2727

2828
#[derive(Clone, Copy)]
29-
pub enum Frame {
29+
pub enum StackFrame {
3030
New(STACKFRAME_EX),
3131
Old(STACKFRAME64),
3232
}
3333

34+
#[derive(Clone, Copy)]
35+
pub struct Frame {
36+
pub(crate) stack_frame: StackFrame,
37+
base_address: *mut c_void,
38+
}
39+
3440
// we're just sending around raw pointers and reading them, never interpreting
3541
// them so this should be safe to both send and share across threads.
3642
unsafe impl Send for Frame {}
@@ -49,38 +55,42 @@ impl Frame {
4955
self.ip()
5056
}
5157

58+
pub fn module_base_address(&self) -> Option<*mut c_void> {
59+
Some(self.base_address)
60+
}
61+
5262
fn addr_pc(&self) -> &ADDRESS64 {
53-
match self {
54-
Frame::New(new) => &new.AddrPC,
55-
Frame::Old(old) => &old.AddrPC,
63+
match self.stack_frame {
64+
StackFrame::New(ref new) => &new.AddrPC,
65+
StackFrame::Old(ref old) => &old.AddrPC,
5666
}
5767
}
5868

5969
fn addr_pc_mut(&mut self) -> &mut ADDRESS64 {
60-
match self {
61-
Frame::New(new) => &mut new.AddrPC,
62-
Frame::Old(old) => &mut old.AddrPC,
70+
match self.stack_frame {
71+
StackFrame::New(ref mut new) => &mut new.AddrPC,
72+
StackFrame::Old(ref mut old) => &mut old.AddrPC,
6373
}
6474
}
6575

6676
fn addr_frame_mut(&mut self) -> &mut ADDRESS64 {
67-
match self {
68-
Frame::New(new) => &mut new.AddrFrame,
69-
Frame::Old(old) => &mut old.AddrFrame,
77+
match self.stack_frame {
78+
StackFrame::New(ref mut new) => &mut new.AddrFrame,
79+
StackFrame::Old(ref mut old) => &mut old.AddrFrame,
7080
}
7181
}
7282

7383
fn addr_stack(&self) -> &ADDRESS64 {
74-
match self {
75-
Frame::New(new) => &new.AddrStack,
76-
Frame::Old(old) => &old.AddrStack,
84+
match self.stack_frame {
85+
StackFrame::New(ref new) => &new.AddrStack,
86+
StackFrame::Old(ref old) => &old.AddrStack,
7787
}
7888
}
7989

8090
fn addr_stack_mut(&mut self) -> &mut ADDRESS64 {
81-
match self {
82-
Frame::New(new) => &mut new.AddrStack,
83-
Frame::Old(old) => &mut old.AddrStack,
91+
match self.stack_frame {
92+
StackFrame::New(ref mut new) => &mut new.AddrStack,
93+
StackFrame::Old(ref mut old) => &mut old.AddrStack,
8494
}
8595
}
8696
}
@@ -131,16 +141,21 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
131141
}
132142
}
133143

144+
let process_handle = GetCurrentProcess();
145+
134146
// Attempt to use `StackWalkEx` if we can, but fall back to `StackWalk64`
135147
// since it's in theory supported on more systems.
136148
match (*dbghelp.dbghelp()).StackWalkEx() {
137149
Some(StackWalkEx) => {
138150
let mut frame = super::Frame {
139-
inner: Frame::New(mem::zeroed()),
151+
inner: Frame {
152+
stack_frame: StackFrame::New(mem::zeroed()),
153+
base_address: 0 as _,
154+
},
140155
};
141156
let image = init_frame(&mut frame.inner, &context.0);
142-
let frame_ptr = match &mut frame.inner {
143-
Frame::New(ptr) => ptr as *mut STACKFRAME_EX,
157+
let frame_ptr = match &mut frame.inner.stack_frame {
158+
StackFrame::New(ptr) => ptr as *mut STACKFRAME_EX,
144159
_ => unreachable!(),
145160
};
146161

@@ -157,18 +172,23 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
157172
0,
158173
) == TRUE
159174
{
175+
frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _;
176+
160177
if !cb(&frame) {
161178
break;
162179
}
163180
}
164181
}
165182
None => {
166183
let mut frame = super::Frame {
167-
inner: Frame::Old(mem::zeroed()),
184+
inner: Frame {
185+
stack_frame: StackFrame::Old(mem::zeroed()),
186+
base_address: 0 as _,
187+
},
168188
};
169189
let image = init_frame(&mut frame.inner, &context.0);
170-
let frame_ptr = match &mut frame.inner {
171-
Frame::Old(ptr) => ptr as *mut STACKFRAME64,
190+
let frame_ptr = match &mut frame.inner.stack_frame {
191+
StackFrame::Old(ptr) => ptr as *mut STACKFRAME64,
172192
_ => unreachable!(),
173193
};
174194

@@ -184,6 +204,8 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
184204
None,
185205
) == TRUE
186206
{
207+
frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _;
208+
187209
if !cb(&frame) {
188210
break;
189211
}

src/backtrace/libunwind.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ impl Frame {
7979
unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) }
8080
}
8181
}
82+
83+
pub fn module_base_address(&self) -> Option<*mut c_void> {
84+
None
85+
}
8286
}
8387

8488
impl Clone for Frame {

src/backtrace/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ impl Frame {
109109
pub fn symbol_address(&self) -> *mut c_void {
110110
self.inner.symbol_address()
111111
}
112+
113+
/// Returns the base address of the module to which the frame belongs.
114+
pub fn module_base_address(&self) -> Option<*mut c_void> {
115+
self.inner.module_base_address()
116+
}
112117
}
113118

114119
impl fmt::Debug for Frame {
@@ -145,6 +150,7 @@ cfg_if::cfg_if! {
145150
mod dbghelp;
146151
use self::dbghelp::trace as trace_imp;
147152
pub(crate) use self::dbghelp::Frame as FrameImp;
153+
pub(crate) use self::dbghelp::StackFrame;
148154
} else {
149155
mod noop;
150156
use self::noop::trace as trace_imp;

src/backtrace/noop.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ impl Frame {
2121
pub fn symbol_address(&self) -> *mut c_void {
2222
0 as *mut _
2323
}
24+
25+
pub fn module_base_address(&self) -> Option<*mut c_void> {
26+
None
27+
}
2428
}

src/capture.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ enum Frame {
5858
Deserialized {
5959
ip: usize,
6060
symbol_address: usize,
61+
module_base_address: Option<usize>,
6162
},
6263
}
6364

@@ -75,6 +76,16 @@ impl Frame {
7576
Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void,
7677
}
7778
}
79+
80+
fn module_base_address(&self) -> Option<*mut c_void> {
81+
match *self {
82+
Frame::Raw(ref f) => f.module_base_address(),
83+
Frame::Deserialized {
84+
module_base_address,
85+
..
86+
} => module_base_address.map(|addr| addr as *mut c_void),
87+
}
88+
}
7889
}
7990

8091
/// Captured version of a symbol in a backtrace.
@@ -265,6 +276,18 @@ impl BacktraceFrame {
265276
self.frame.symbol_address() as *mut c_void
266277
}
267278

279+
/// Same as `Frame::module_base_address`
280+
///
281+
/// # Required features
282+
///
283+
/// This function requires the `std` feature of the `backtrace` crate to be
284+
/// enabled, and the `std` feature is enabled by default.
285+
pub fn module_base_address(&self) -> Option<*mut c_void> {
286+
self.frame
287+
.module_base_address()
288+
.map(|addr| addr as *mut c_void)
289+
}
290+
268291
/// Returns the list of symbols that this frame corresponds to.
269292
///
270293
/// Normally there is only one symbol per frame, but sometimes if a number
@@ -409,6 +432,7 @@ mod rustc_serialize_impls {
409432
struct SerializedFrame {
410433
ip: usize,
411434
symbol_address: usize,
435+
module_base_address: Option<usize>,
412436
symbols: Option<Vec<BacktraceSymbol>>,
413437
}
414438

@@ -422,6 +446,7 @@ mod rustc_serialize_impls {
422446
frame: Frame::Deserialized {
423447
ip: frame.ip,
424448
symbol_address: frame.symbol_address,
449+
module_base_address: frame.module_base_address,
425450
},
426451
symbols: frame.symbols,
427452
})
@@ -437,6 +462,7 @@ mod rustc_serialize_impls {
437462
SerializedFrame {
438463
ip: frame.ip() as usize,
439464
symbol_address: frame.symbol_address() as usize,
465+
module_base_address: frame.module_base_address().map(|addr| addr as usize),
440466
symbols: symbols.clone(),
441467
}
442468
.encode(e)
@@ -457,6 +483,7 @@ mod serde_impls {
457483
struct SerializedFrame {
458484
ip: usize,
459485
symbol_address: usize,
486+
module_base_address: Option<usize>,
460487
symbols: Option<Vec<BacktraceSymbol>>,
461488
}
462489

@@ -469,6 +496,7 @@ mod serde_impls {
469496
SerializedFrame {
470497
ip: frame.ip() as usize,
471498
symbol_address: frame.symbol_address() as usize,
499+
module_base_address: frame.module_base_address().map(|addr| addr as usize),
472500
symbols: symbols.clone(),
473501
}
474502
.serialize(s)
@@ -485,6 +513,7 @@ mod serde_impls {
485513
frame: Frame::Deserialized {
486514
ip: frame.ip,
487515
symbol_address: frame.symbol_address,
516+
module_base_address: frame.module_base_address,
488517
},
489518
symbols: frame.symbols,
490519
})

src/symbolize/dbghelp.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
2828
#![allow(bad_style)]
2929

30-
use super::super::{backtrace::FrameImp as Frame, dbghelp, windows::*};
30+
use super::super::{backtrace::StackFrame, dbghelp, windows::*};
3131
use super::{BytesOrWideString, ResolveWhat, SymbolName};
3232
use core::char;
3333
use core::ffi::c_void;
@@ -90,9 +90,9 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
9090

9191
match what {
9292
ResolveWhat::Address(_) => resolve_without_inline(&dbghelp, what.address_or_ip(), cb),
93-
ResolveWhat::Frame(frame) => match &frame.inner {
94-
Frame::New(frame) => resolve_with_inline(&dbghelp, frame, cb),
95-
Frame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb),
93+
ResolveWhat::Frame(frame) => match &frame.inner.stack_frame {
94+
StackFrame::New(frame) => resolve_with_inline(&dbghelp, frame, cb),
95+
StackFrame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb),
9696
},
9797
}
9898
}

0 commit comments

Comments
 (0)