4
4
//! all platforms, but it's hoped to be developed over time! Long-term this is
5
5
//! intended to wholesale replace the `libbacktrace.rs` implementation.
6
6
7
+ use crate :: symbolize:: dladdr;
7
8
use crate :: symbolize:: ResolveWhat ;
8
9
use crate :: types:: BytesOrWideString ;
9
10
use crate :: SymbolName ;
@@ -49,7 +50,6 @@ fn mmap(path: &Path) -> Option<Mmap> {
49
50
let file = File :: open ( path) . ok ( ) ?;
50
51
// TODO: not completely safe, see https://github.com/danburkert/memmap-rs/issues/25
51
52
unsafe { Mmap :: map ( & file) . ok ( ) }
52
-
53
53
}
54
54
55
55
impl Mapping {
@@ -189,8 +189,13 @@ where
189
189
} ) ;
190
190
}
191
191
192
- pub fn resolve ( what : ResolveWhat , cb : & mut FnMut ( & super :: Symbol ) ) {
192
+ pub unsafe fn resolve ( what : ResolveWhat , cb : & mut FnMut ( & super :: Symbol ) ) {
193
193
let addr = what. address_or_ip ( ) ;
194
+ let mut cb = DladdrFallback {
195
+ cb,
196
+ addr,
197
+ called : false ,
198
+ } ;
194
199
195
200
// First, find the file containing the segment that the given AVMA (after
196
201
// relocation) address falls within. Use the containing segment to compute
@@ -248,7 +253,7 @@ pub fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
248
253
let sym = super :: Symbol {
249
254
inner : Symbol :: new ( addr. 0 as usize , file, line, name) ,
250
255
} ;
251
- cb ( & sym) ;
256
+ cb. call ( & sym) ;
252
257
found_sym = true ;
253
258
}
254
259
}
@@ -259,22 +264,55 @@ pub fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
259
264
let sym = super :: Symbol {
260
265
inner : Symbol :: new ( addr. 0 as usize , None , None , Some ( name. to_string ( ) ) ) ,
261
266
} ;
262
- cb ( & sym) ;
267
+ cb. call ( & sym) ;
263
268
}
264
269
}
265
270
} ) ;
271
+
272
+ drop ( cb) ;
273
+ }
274
+
275
+ struct DladdrFallback < ' a , ' b > {
276
+ addr : * mut c_void ,
277
+ called : bool ,
278
+ cb : & ' a mut ( FnMut ( & super :: Symbol ) + ' b ) ,
279
+ }
280
+
281
+ impl DladdrFallback < ' _ , ' _ > {
282
+ fn call ( & mut self , sym : & super :: Symbol ) {
283
+ self . called = true ;
284
+ ( self . cb ) ( sym) ;
285
+ }
266
286
}
267
287
268
- pub struct Symbol {
269
- addr : usize ,
270
- file : Option < String > ,
271
- line : Option < u64 > ,
272
- name : Option < String > ,
288
+ impl Drop for DladdrFallback < ' _ , ' _ > {
289
+ fn drop ( & mut self ) {
290
+ if self . called {
291
+ return ;
292
+ }
293
+ unsafe {
294
+ dladdr:: resolve ( self . addr , & mut |sym| {
295
+ ( self . cb ) ( & super :: Symbol {
296
+ inner : Symbol :: Dladdr ( sym) ,
297
+ } )
298
+ } ) ;
299
+ }
300
+ }
301
+ }
302
+
303
+ pub enum Symbol {
304
+ Dladdr ( dladdr:: Symbol ) ,
305
+ Gimli {
306
+ addr : usize ,
307
+ file : Option < String > ,
308
+ line : Option < u64 > ,
309
+ name : Option < String > ,
310
+ } ,
273
311
}
274
312
275
313
impl Symbol {
276
314
fn new ( addr : usize , file : Option < String > , line : Option < u64 > , name : Option < String > ) -> Symbol {
277
- Symbol {
315
+ Symbol :: Gimli {
278
316
addr,
279
317
file,
280
318
line,
@@ -283,25 +321,42 @@ impl Symbol {
283
321
}
284
322
285
323
pub fn name ( & self ) -> Option < SymbolName > {
286
- self . name . as_ref ( ) . map ( |s| SymbolName :: new ( s. as_bytes ( ) ) )
324
+ match self {
325
+ Symbol :: Dladdr ( s) => s. name ( ) ,
326
+ Symbol :: Gimli { name, .. } => name. as_ref ( ) . map ( |s| SymbolName :: new ( s. as_bytes ( ) ) ) ,
327
+ }
287
328
}
288
329
289
330
pub fn addr ( & self ) -> Option < * mut c_void > {
290
- Some ( self . addr as * mut c_void )
331
+ match self {
332
+ Symbol :: Dladdr ( s) => s. addr ( ) ,
333
+ Symbol :: Gimli { addr, .. } => Some ( * addr as * mut c_void ) ,
334
+ }
291
335
}
292
336
293
337
pub fn filename_raw ( & self ) -> Option < BytesOrWideString > {
294
- self . file
295
- . as_ref ( )
338
+ let file = match self {
339
+ Symbol :: Dladdr ( s) => return s. filename_raw ( ) ,
340
+ Symbol :: Gimli { file, .. } => file,
341
+ } ;
342
+ file. as_ref ( )
296
343
. map ( |f| BytesOrWideString :: Bytes ( f. as_bytes ( ) ) )
297
344
}
298
345
299
346
pub fn filename ( & self ) -> Option < & Path > {
300
- self . file . as_ref ( ) . map ( Path :: new)
347
+ let file = match self {
348
+ Symbol :: Dladdr ( s) => return s. filename ( ) ,
349
+ Symbol :: Gimli { file, .. } => file,
350
+ } ;
351
+ file. as_ref ( ) . map ( Path :: new)
301
352
}
302
353
303
354
pub fn lineno ( & self ) -> Option < u32 > {
304
- self . line . and_then ( |l| {
355
+ let line = match self {
356
+ Symbol :: Dladdr ( s) => return s. lineno ( ) ,
357
+ Symbol :: Gimli { line, .. } => line,
358
+ } ;
359
+ line. and_then ( |l| {
305
360
if l > ( u32:: MAX as u64 ) {
306
361
None
307
362
} else {
0 commit comments