@@ -114,26 +114,60 @@ extern "C" fn error_cb(_data: *mut c_void, _msg: *const c_char, _errnum: c_int)
114
114
// do nothing for now
115
115
}
116
116
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
+
117
123
extern "C" fn syminfo_cb (
118
124
data : * mut c_void ,
119
125
pc : uintptr_t ,
120
126
symname : * const c_char ,
121
127
_symval : uintptr_t ,
122
128
_symsize : uintptr_t ,
123
129
) {
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`.
124
137
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 {
128
154
inner : Symbol :: Syminfo {
129
155
pc : pc,
130
156
symname : symname,
131
157
} ,
132
- } ,
133
- ) ;
158
+ } ) ;
159
+ bomb. enabled = false ;
160
+ }
134
161
}
135
162
}
136
163
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
+
137
171
extern "C" fn pcinfo_cb (
138
172
data : * mut c_void ,
139
173
pc : uintptr_t ,
@@ -145,28 +179,33 @@ extern "C" fn pcinfo_cb(
145
179
if filename. is_null ( ) || function. is_null ( ) {
146
180
return -1 ;
147
181
}
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
156
200
} ,
157
201
} ,
158
- ) ;
202
+ } ) ;
203
+ bomb. enabled = false ;
204
+
159
205
return 0 ;
160
206
}
161
207
}
162
208
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
-
170
209
// The libbacktrace API supports creating a state, but it does not
171
210
// support destroying a state. I personally take this to mean that a
172
211
// state is meant to be created and then live forever.
@@ -334,7 +373,7 @@ unsafe fn init_state() -> *mut bt::backtrace_state {
334
373
}
335
374
}
336
375
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 ) ) {
338
377
let symaddr = what. address_or_ip ( ) ;
339
378
340
379
// backtrace errors are currently swept under the rug
@@ -343,20 +382,21 @@ pub unsafe fn resolve(what: ResolveWhat, mut cb: &mut FnMut(&super::Symbol)) {
343
382
return ;
344
383
}
345
384
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 (
347
396
state,
348
397
symaddr as uintptr_t ,
349
- pcinfo_cb ,
398
+ syminfo_cb ,
350
399
error_cb,
351
- & mut cb as * mut _ as * mut _ ,
400
+ & mut syminfo_state as * mut _ as * mut _ ,
352
401
) ;
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
- }
362
402
}
0 commit comments