@@ -9,7 +9,9 @@ use self::stash::Stash;
9
9
use super :: BytesOrWideString ;
10
10
use super :: ResolveWhat ;
11
11
use super :: SymbolName ;
12
+ use super :: ShortBacktrace ;
12
13
use addr2line:: gimli;
14
+ use addr2line:: { LookupResult , LookupContinuation } ;
13
15
use core:: convert:: TryInto ;
14
16
use core:: mem;
15
17
use core:: u32;
@@ -170,9 +172,24 @@ impl<'data> Context<'data> {
170
172
stash : & ' data Stash ,
171
173
probe : u64 ,
172
174
) -> gimli:: Result < addr2line:: FrameIter < ' _ , EndianSlice < ' data , Endian > > > {
173
- use addr2line:: { LookupContinuation , LookupResult } ;
175
+ let continuation = self . dwarf . find_frames ( probe) ;
176
+ self . continuation_helper ( stash, continuation)
177
+ }
178
+
179
+ fn find_dwarf_and_unit (
180
+ & ' _ self ,
181
+ stash : & ' data Stash ,
182
+ probe : u64 ,
183
+ ) -> Option < gimli:: UnitRef < ' _ , EndianSlice < ' data , Endian > > > {
184
+ let continuation = self . dwarf . find_dwarf_and_unit ( probe) ;
185
+ self . continuation_helper ( stash, continuation)
186
+ }
174
187
175
- let mut l = self . dwarf . find_frames ( probe) ;
188
+ fn continuation_helper < O > (
189
+ & ' _ self ,
190
+ stash : & ' data Stash ,
191
+ mut l : LookupResult < impl LookupContinuation < Output = O , Buf = EndianSlice < ' data , Endian > > > ,
192
+ ) -> O {
176
193
loop {
177
194
let ( load, continuation) = match l {
178
195
LookupResult :: Output ( output) => break output,
@@ -409,6 +426,43 @@ impl Cache {
409
426
}
410
427
}
411
428
429
+ impl ShortBacktrace {
430
+ fn from_raw ( raw : u8 ) -> Option < Self > {
431
+ let this = match raw {
432
+ 0 => ShortBacktrace :: ThisFrameOnly ,
433
+ 1 => ShortBacktrace :: Start ,
434
+ 2 => ShortBacktrace :: End ,
435
+ _ => return None ,
436
+ } ;
437
+ Some ( this)
438
+ }
439
+ }
440
+
441
+ const DW_AT_short_backtrace : gimli:: DwAt = gimli:: DwAt ( 0x3c00 ) ;
442
+
443
+ fn parse_short_backtrace < ' data , R : gimli:: Reader < Offset = usize > > (
444
+ unit_ref : gimli:: UnitRef < ' _ , R > ,
445
+ stash : & ' data Stash ,
446
+ addr : u64 ,
447
+ frame : & addr2line:: Frame < ' _ , R > ,
448
+ ) -> Option < ShortBacktrace > {
449
+ use core:: ops:: ControlFlow ;
450
+
451
+ let mut short_backtrace = None ;
452
+ unit_ref. shared_attrs ( frame. dw_die_offset ?, 16 , |attr, _| {
453
+ if attr. name ( ) == DW_AT_short_backtrace {
454
+ let parsed = ShortBacktrace :: from_raw (
455
+ attr. u8_value ( ) . ok_or ( gimli:: Error :: UnsupportedAttributeForm ) ?,
456
+ ) ;
457
+ short_backtrace = Some ( parsed. expect ( "rustc generated invalid debuginfo?" ) ) ;
458
+ return Ok ( ControlFlow :: Break ( ( ) ) ) ;
459
+ }
460
+ Ok ( ControlFlow :: Continue ( ( ) ) )
461
+ } ) ;
462
+
463
+ short_backtrace
464
+ }
465
+
412
466
pub unsafe fn resolve ( what : ResolveWhat < ' _ > , cb : & mut dyn FnMut ( & super :: Symbol ) ) {
413
467
let addr = what. address_or_ip ( ) ;
414
468
let mut call = |sym : Symbol < ' _ > | {
@@ -435,24 +489,32 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
435
489
if let Ok ( mut frames) = cx. find_frames ( stash, addr as u64 ) {
436
490
while let Ok ( Some ( frame) ) = frames. next ( ) {
437
491
any_frames = true ;
438
- let name = match frame. function {
492
+ let name = match & frame. function {
439
493
Some ( f) => Some ( f. name . slice ( ) ) ,
440
494
None => cx. object . search_symtab ( addr as u64 ) ,
441
495
} ;
496
+ let unit_ref = cx. find_dwarf_and_unit ( stash, addr as u64 ) ;
497
+ let short_backtrace = unit_ref
498
+ . and_then ( |unit| parse_short_backtrace ( unit, stash, addr as u64 , & frame) ) ;
442
499
call ( Symbol :: Frame {
443
500
addr : addr as * mut c_void ,
444
501
location : frame. location ,
445
502
name,
503
+ short_backtrace,
446
504
} ) ;
447
505
}
448
506
}
449
507
if !any_frames {
450
508
if let Some ( ( object_cx, object_addr) ) = cx. object . search_object_map ( addr as u64 ) {
509
+ let unit_ref = None ;
451
510
if let Ok ( mut frames) = object_cx. find_frames ( stash, object_addr) {
452
511
while let Ok ( Some ( frame) ) = frames. next ( ) {
453
512
any_frames = true ;
454
513
call ( Symbol :: Frame {
455
514
addr : addr as * mut c_void ,
515
+ short_backtrace : unit_ref. and_then ( |unit| {
516
+ parse_short_backtrace ( unit, stash, object_addr, & frame)
517
+ } ) ,
456
518
location : frame. location ,
457
519
name : frame. function . map ( |f| f. name . slice ( ) ) ,
458
520
} ) ;
@@ -475,6 +537,7 @@ pub enum Symbol<'a> {
475
537
addr : * mut c_void ,
476
538
location : Option < addr2line:: Location < ' a > > ,
477
539
name : Option < & ' a [ u8 ] > ,
540
+ short_backtrace : Option < ShortBacktrace > ,
478
541
} ,
479
542
/// Couldn't find debug information, but we found it in the symbol table of
480
543
/// the elf executable.
@@ -532,4 +595,11 @@ impl Symbol<'_> {
532
595
Symbol :: Symtab { .. } => None ,
533
596
}
534
597
}
598
+
599
+ pub fn short_backtrace ( & self ) -> Option < ShortBacktrace > {
600
+ match self {
601
+ Symbol :: Frame { short_backtrace, .. } => * short_backtrace,
602
+ Symbol :: Symtab { .. } => None ,
603
+ }
604
+ }
535
605
}
0 commit comments