Skip to content

Commit 686cc7b

Browse files
committed
Unify IP adjustments across platforms
Looks like we're just doing this everywhere, so have everyone do it the same way during symbolication.
1 parent 25b5423 commit 686cc7b

File tree

6 files changed

+38
-39
lines changed

6 files changed

+38
-39
lines changed

src/backtrace/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use core::fmt;
21
use core::ffi::c_void;
2+
use core::fmt;
33

44
/// Inspects the current call-stack, passing all active frames into the closure
55
/// provided to calculate a stack trace.

src/dbghelp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@
2323
2424
#![allow(non_snake_case)]
2525

26+
use crate::windows::*;
2627
use core::mem;
2728
use core::ptr;
28-
use crate::windows::*;
2929

3030
// Work around `SymGetOptions` and `SymSetOptions` not being present in winapi
3131
// itself. Otherwise this is only used when we're double-checking types against
3232
// winapi.
3333
#[cfg(feature = "verify-winapi")]
3434
mod dbghelp {
35+
use crate::windows::*;
3536
pub use winapi::um::dbghelp::{
3637
StackWalk64, SymCleanup, SymFromAddrW, SymFunctionTableAccess64, SymGetLineFromAddrW64,
3738
SymGetModuleBase64, SymInitializeW,
3839
};
39-
use crate::windows::*;
4040

4141
extern "system" {
4242
// Not defined in winapi yet

src/symbolize/coresymbolication.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,6 @@ unsafe fn try_resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) -> bool
218218
CSRelease: lib.CSRelease(),
219219
};
220220

221-
// Typically `addr` is the *next* instruction during a backtrace so we're
222-
// careful to subtract one here to get the filename/line information for the
223-
// previous instruction which is the one we're interested in.
224-
let addr = (addr as usize - 1) as *mut c_void;
225221
let info = lib.CSSymbolicatorGetSourceInfoWithAddressAtTime()(cs, addr, CS_NOW);
226222
let sym = if info == CSREF_NULL {
227223
lib.CSSymbolicatorGetSymbolWithAddressAtTime()(cs, addr, CS_NOW)

src/symbolize/dbghelp.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
8787
};
8888

8989
match what {
90-
ResolveWhat::Address(addr) => resolve_without_inline(&dbghelp, addr, cb),
90+
ResolveWhat::Address(_) => resolve_without_inline(&dbghelp, what.address_or_ip(), cb),
9191
ResolveWhat::Frame(frame) => match &frame.inner {
9292
Frame::New(frame) => resolve_with_inline(&dbghelp, frame, cb),
9393
Frame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb),
@@ -104,11 +104,7 @@ unsafe fn resolve_with_inline(
104104
|info| {
105105
dbghelp.SymFromInlineContextW()(
106106
GetCurrentProcess(),
107-
// FIXME: why is `-1` used here and below? It seems to produce
108-
// more accurate backtraces on Windows (aka passes tests in
109-
// rust-lang/rust), but it's unclear why it's required in the
110-
// first place.
111-
frame.AddrPC.Offset - 1,
107+
super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64,
112108
frame.InlineFrameContext,
113109
&mut 0,
114110
info,
@@ -117,7 +113,7 @@ unsafe fn resolve_with_inline(
117113
|line| {
118114
dbghelp.SymGetLineFromInlineContextW()(
119115
GetCurrentProcess(),
120-
frame.AddrPC.Offset - 1,
116+
super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64,
121117
frame.InlineFrameContext,
122118
0,
123119
&mut 0,
@@ -133,8 +129,6 @@ unsafe fn resolve_without_inline(
133129
addr: *mut c_void,
134130
cb: &mut FnMut(&super::Symbol),
135131
) {
136-
// See above for why there's a `-1` here
137-
let addr = (addr as usize - 1) as *mut c_void;
138132
do_resolve(
139133
|info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr as DWORD64, &mut 0, info),
140134
|line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr as DWORD64, &mut 0, line),

src/symbolize/libbacktrace.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -411,24 +411,7 @@ unsafe fn init_state() -> *mut bt::backtrace_state {
411411
}
412412

413413
pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
414-
let mut symaddr = what.address_or_ip() as usize;
415-
416-
// IP values from stack frames are typically (always?) the instruction
417-
// *after* the call that's the actual stack trace. Symbolizing this on
418-
// causes the filename/line number to be one ahead and perhaps into
419-
// the void if it's near the end of the function.
420-
//
421-
// On Windows it's pretty sure that it's always the case that the IP is one
422-
// ahead (except for the final frame but oh well) and for Unix it appears
423-
// that we used to use `_Unwind_GetIPInfo` which tells us if the instruction
424-
// is the next or not, but it seems that on all platforms it's always the
425-
// next instruction so far so let's just always assume that.
426-
//
427-
// In any case we'll probably have to tweak this over time, but for now this
428-
// gives the most accurate backtraces.
429-
if symaddr > 0 {
430-
symaddr -= 1;
431-
}
414+
let symaddr = what.address_or_ip() as usize;
432415

433416
// backtrace errors are currently swept under the rug
434417
let state = init_state();

src/symbolize/mod.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ cfg_if::cfg_if! {
77
}
88
}
99

10-
use core::ffi::c_void;
1110
use crate::backtrace::Frame;
12-
use crate::types::{BytesOrWideString};
11+
use crate::types::BytesOrWideString;
12+
use core::ffi::c_void;
1313
use rustc_demangle::{try_demangle, Demangle};
1414

1515
/// Resolve an address to a symbol, passing the symbol to the specified
@@ -113,13 +113,39 @@ pub enum ResolveWhat<'a> {
113113
impl<'a> ResolveWhat<'a> {
114114
#[allow(dead_code)]
115115
fn address_or_ip(&self) -> *mut c_void {
116-
match *self {
117-
ResolveWhat::Address(a) => a,
118-
ResolveWhat::Frame(ref f) => f.ip(),
116+
match self {
117+
ResolveWhat::Address(a) => adjust_ip(*a),
118+
ResolveWhat::Frame(f) => adjust_ip(f.ip()),
119119
}
120120
}
121121
}
122122

123+
// IP values from stack frames are typically (always?) the instruction
124+
// *after* the call that's the actual stack trace. Symbolizing this on
125+
// causes the filename/line number to be one ahead and perhaps into
126+
// the void if it's near the end of the function.
127+
//
128+
// This appears to basically always be the case on all platforms, so we always
129+
// subtract one from a resolved ip to resolve it to the previous call
130+
// instruction instead of the instruction being returned to.
131+
//
132+
// Ideally we would not do this. Ideally we would require callers of the
133+
// `resolve` APIs here to manually do the -1 and account that they want location
134+
// information for the *previous* instruction, not the current. Ideally we'd
135+
// also expose on `Frame` if we are indeed the address of the next instruction
136+
// or the current.
137+
//
138+
// For now though this is a pretty niche concern so we just internally always
139+
// subtract one. Consumers should keep working and getting pretty good results,
140+
// so we should be good enough.
141+
fn adjust_ip(a: *mut c_void) -> *mut c_void {
142+
if a.is_null() {
143+
a
144+
} else {
145+
(a as usize - 1) as *mut c_void
146+
}
147+
}
148+
123149
/// Same as `resolve`, only unsafe as it's unsynchronized.
124150
///
125151
/// This function does not have synchronization guarentees but is available when

0 commit comments

Comments
 (0)