Skip to content

Commit 0fdcf49

Browse files
authored
Merge pull request #185 from alexcrichton/always-syminfo
Always call backtrace_syminfo with libbacktrace
2 parents 9ed25b5 + f6c2e00 commit 0fdcf49

File tree

1 file changed

+74
-34
lines changed

1 file changed

+74
-34
lines changed

src/symbolize/libbacktrace.rs

+74-34
Original file line numberDiff line numberDiff line change
@@ -114,26 +114,60 @@ extern "C" fn error_cb(_data: *mut c_void, _msg: *const c_char, _errnum: c_int)
114114
// do nothing for now
115115
}
116116

117+
/// Type of the `data` pointer passed into `syminfo_cb`
118+
struct SyminfoState<'a> {
119+
cb: &'a mut (FnMut(&super::Symbol) + 'a),
120+
pc: usize,
121+
}
122+
117123
extern "C" fn syminfo_cb(
118124
data: *mut c_void,
119125
pc: uintptr_t,
120126
symname: *const c_char,
121127
_symval: uintptr_t,
122128
_symsize: uintptr_t,
123129
) {
130+
// Once this callback is invoked from `backtrace_syminfo` when we start
131+
// resolving we go further to call `backtrace_pcinfo`. The
132+
// `backtrace_pcinfo` function will consult debug information and attemp tto
133+
// do things like recover file/line information as well as inlined frames.
134+
// Note though that `backtrace_pcinfo` can fail or not do much if there's
135+
// not debug info, so if that happens we're sure to call the callback with
136+
// at least one symbol from the `syminfo_cb`.
124137
unsafe {
125-
call(
126-
data,
127-
&super::Symbol {
138+
let syminfo_state = &mut *(data as *mut SyminfoState);
139+
let mut pcinfo_state = PcinfoState {
140+
symname,
141+
called: false,
142+
cb: syminfo_state.cb,
143+
};
144+
bt::backtrace_pcinfo(
145+
init_state(),
146+
syminfo_state.pc as uintptr_t,
147+
pcinfo_cb,
148+
error_cb,
149+
&mut pcinfo_state as *mut _ as *mut _,
150+
);
151+
if !pcinfo_state.called {
152+
let mut bomb = ::Bomb { enabled: true };
153+
(pcinfo_state.cb)(&super::Symbol {
128154
inner: Symbol::Syminfo {
129155
pc: pc,
130156
symname: symname,
131157
},
132-
},
133-
);
158+
});
159+
bomb.enabled = false;
160+
}
134161
}
135162
}
136163

164+
/// Type of the `data` pointer passed into `pcinfo_cb`
165+
struct PcinfoState<'a> {
166+
cb: &'a mut (FnMut(&super::Symbol) + 'a),
167+
symname: *const c_char,
168+
called: bool,
169+
}
170+
137171
extern "C" fn pcinfo_cb(
138172
data: *mut c_void,
139173
pc: uintptr_t,
@@ -145,28 +179,33 @@ extern "C" fn pcinfo_cb(
145179
if filename.is_null() || function.is_null() {
146180
return -1;
147181
}
148-
call(
149-
data,
150-
&super::Symbol {
151-
inner: Symbol::Pcinfo {
152-
pc: pc,
153-
filename: filename,
154-
lineno: lineno,
155-
function: function,
182+
let state = &mut *(data as *mut PcinfoState);
183+
let mut bomb = ::Bomb { enabled: true };
184+
state.called = true;
185+
(state.cb)(&super::Symbol {
186+
inner: Symbol::Pcinfo {
187+
pc: pc,
188+
filename: filename,
189+
lineno: lineno,
190+
191+
// Favor the function name going into the `syminfo_cb`. That's
192+
// typically from the symbol table and is the full symbol name
193+
// whereas the `function` above is coming from debuginfo which
194+
// isn't always as descriptive when considering the whole
195+
// program.
196+
function: if !state.symname.is_null() {
197+
state.symname
198+
} else {
199+
function
156200
},
157201
},
158-
);
202+
});
203+
bomb.enabled = false;
204+
159205
return 0;
160206
}
161207
}
162208

163-
unsafe fn call(data: *mut c_void, sym: &super::Symbol) {
164-
let cb = data as *mut &mut FnMut(&super::Symbol);
165-
let mut bomb = ::Bomb { enabled: true };
166-
(*cb)(sym);
167-
bomb.enabled = false;
168-
}
169-
170209
// The libbacktrace API supports creating a state, but it does not
171210
// support destroying a state. I personally take this to mean that a
172211
// state is meant to be created and then live forever.
@@ -334,7 +373,7 @@ unsafe fn init_state() -> *mut bt::backtrace_state {
334373
}
335374
}
336375

337-
pub unsafe fn resolve(what: ResolveWhat, mut cb: &mut FnMut(&super::Symbol)) {
376+
pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
338377
let symaddr = what.address_or_ip();
339378

340379
// backtrace errors are currently swept under the rug
@@ -343,20 +382,21 @@ pub unsafe fn resolve(what: ResolveWhat, mut cb: &mut FnMut(&super::Symbol)) {
343382
return;
344383
}
345384

346-
let ret = bt::backtrace_pcinfo(
385+
// Call the `backtrace_syminfo` API first. This is (from reading the code)
386+
// guaranteed to call `syminfo_cb` exactly once (or fail with an error
387+
// presumably). We then handle more within the `syminfo_cb`.
388+
//
389+
// Note that we do this since `syminfo` will consult the symbol table,
390+
// finding symbol names even if there's no debug information in the binary.
391+
let mut syminfo_state = SyminfoState {
392+
pc: symaddr as usize,
393+
cb: cb,
394+
};
395+
bt::backtrace_syminfo(
347396
state,
348397
symaddr as uintptr_t,
349-
pcinfo_cb,
398+
syminfo_cb,
350399
error_cb,
351-
&mut cb as *mut _ as *mut _,
400+
&mut syminfo_state as *mut _ as *mut _,
352401
);
353-
if ret != 0 {
354-
bt::backtrace_syminfo(
355-
state,
356-
symaddr as uintptr_t,
357-
syminfo_cb,
358-
error_cb,
359-
&mut cb as *mut _ as *mut _,
360-
);
361-
}
362402
}

0 commit comments

Comments
 (0)