1
1
mod logger;
2
+ mod pc2frames;
2
3
3
4
use core:: {
4
5
cmp,
5
6
convert:: TryInto ,
6
7
mem,
7
- ops:: Range ,
8
8
sync:: atomic:: { AtomicBool , Ordering } ,
9
9
} ;
10
10
use std:: {
11
- collections:: { btree_map, BTreeMap } ,
11
+ collections:: { btree_map, BTreeMap , HashSet } ,
12
12
fs,
13
13
io:: { self , Write as _} ,
14
14
path:: PathBuf ,
@@ -26,7 +26,7 @@ use gimli::{
26
26
} ;
27
27
use object:: {
28
28
read:: { File as ElfFile , Object as _, ObjectSection as _} ,
29
- SectionIndex ,
29
+ SymbolSection ,
30
30
} ;
31
31
use probe_rs:: config:: { registry, MemoryRegion , RamRegion } ;
32
32
use probe_rs:: {
@@ -123,13 +123,6 @@ fn notmain() -> Result<i32, anyhow::Error> {
123
123
) ;
124
124
}
125
125
126
- let text = elf. section_by_name ( ".text" ) . ok_or_else ( || {
127
- anyhow ! (
128
- "`.text` section is missing, please make sure that the linker script was passed to the \
129
- linker (check `.cargo/config.toml` and the `RUSTFLAGS` variable)"
130
- )
131
- } ) ?;
132
-
133
126
#[ cfg( feature = "defmt" ) ]
134
127
let ( table, locs) = {
135
128
let table = defmt_elf2table:: parse ( & bytes) ?;
@@ -228,7 +221,31 @@ fn notmain() -> Result<i32, anyhow::Error> {
228
221
}
229
222
}
230
223
231
- let ( range_names, rtt_addr, uses_heap) = range_names_from ( & elf, text. index ( ) ) ?;
224
+ let text = elf
225
+ . section_by_name ( ".text" )
226
+ . map ( |section| section. index ( ) )
227
+ . ok_or_else ( || {
228
+ anyhow ! (
229
+ "`.text` section is missing, please make sure that the linker script was passed to the \
230
+ linker (check `.cargo/config.toml` and the `RUSTFLAGS` variable)"
231
+ )
232
+ } ) ?;
233
+
234
+ let live_functions = elf
235
+ . symbol_map ( )
236
+ . symbols ( )
237
+ . iter ( )
238
+ . filter_map ( |sym| {
239
+ if sym. section ( ) == SymbolSection :: Section ( text) {
240
+ sym. name ( )
241
+ } else {
242
+ None
243
+ }
244
+ } )
245
+ . collect :: < HashSet < _ > > ( ) ;
246
+
247
+ let pc2frames = pc2frames:: from ( & elf, & live_functions) ?;
248
+ let ( rtt_addr, uses_heap) = rtt_and_heap_info_from ( & elf) ?;
232
249
233
250
let vector_table = vector_table. ok_or_else ( || anyhow ! ( "`.vector_table` section is missing" ) ) ?;
234
251
log:: debug!( "vector table: {:x?}" , vector_table) ;
@@ -454,7 +471,8 @@ fn notmain() -> Result<i32, anyhow::Error> {
454
471
& mut core,
455
472
pc,
456
473
debug_frame,
457
- & range_names,
474
+ & elf,
475
+ & pc2frames,
458
476
& vector_table,
459
477
& sp_ram_region,
460
478
) ?;
@@ -598,7 +616,8 @@ fn backtrace(
598
616
core : & mut Core < ' _ > ,
599
617
mut pc : u32 ,
600
618
debug_frame : & [ u8 ] ,
601
- range_names : & RangeNames ,
619
+ elf : & ElfFile ,
620
+ pc2frames : & pc2frames:: Map ,
602
621
vector_table : & VectorTable ,
603
622
sp_ram_region : & Option < RamRegion > ,
604
623
) -> Result < Option < TopException > , anyhow:: Error > {
@@ -614,23 +633,31 @@ fn backtrace(
614
633
let ctx = & mut UninitializedUnwindContext :: new ( ) ;
615
634
616
635
let mut top_exception = None ;
617
- let mut frame = 0 ;
636
+ let mut frame_index = 0 ;
618
637
let mut registers = Registers :: new ( lr, sp, core) ;
619
638
println ! ( "stack backtrace:" ) ;
620
639
loop {
621
- let name = range_names
622
- . binary_search_by ( |rn| {
623
- if rn. 0 . contains ( & pc) {
624
- cmp:: Ordering :: Equal
625
- } else if pc < rn. 0 . start {
626
- cmp:: Ordering :: Greater
627
- } else {
628
- cmp:: Ordering :: Less
629
- }
630
- } )
631
- . map ( |idx| & * range_names[ idx] . 1 )
632
- . unwrap_or ( "<unknown>" ) ;
633
- println ! ( "{:>4}: {:#010x} - {}" , frame, pc, name) ;
640
+ let mut frames = pc2frames. query_point ( pc as u64 ) . collect :: < Vec < _ > > ( ) ;
641
+ // `IntervalTree` docs don't specify the order of the elements returned by `query_point` so
642
+ // we sort them by depth before printing
643
+ frames. sort_by_key ( |frame| -frame. value . depth ) ;
644
+
645
+ if frames. is_empty ( ) {
646
+ // this means there was no DWARF info associated to this PC; the PC could point into
647
+ // external assembly or external C code. Fall back to a symtab lookup
648
+ let map = elf. symbol_map ( ) ;
649
+ if let Some ( name) = map. get ( pc as u64 ) . and_then ( |symbol| symbol. name ( ) ) {
650
+ println ! ( "{:>4}: {}" , frame_index, name) ;
651
+ } else {
652
+ println ! ( "{:>4}: <unknown> @ {:#012x}" , frame_index, pc) ;
653
+ }
654
+ frame_index += 1 ;
655
+ } else {
656
+ for frame in frames {
657
+ println ! ( "{:>4}: {}" , frame_index, frame. value. name) ;
658
+ frame_index += 1 ;
659
+ }
660
+ }
634
661
635
662
// on hard fault exception entry we hit the breakpoint before the subroutine prelude (`push
636
663
// lr`) is executed so special handling is required
@@ -708,8 +735,6 @@ fn backtrace(
708
735
}
709
736
pc = lr & !THUMB_BIT ;
710
737
}
711
-
712
- frame += 1 ;
713
738
}
714
739
715
740
Ok ( top_exception)
@@ -853,15 +878,10 @@ impl Stacked {
853
878
num_words as u32 * 4
854
879
}
855
880
}
856
- // FIXME this might already exist in the DWARF data; we should just use that
857
- /// Map from PC ranges to demangled Rust names
858
- type RangeNames = Vec < ( Range < u32 > , String ) > ;
859
881
860
- fn range_names_from (
882
+ fn rtt_and_heap_info_from (
861
883
elf : & ElfFile ,
862
- text : SectionIndex ,
863
- ) -> Result < ( RangeNames , Option < u32 > , bool /* uses heap */ ) , anyhow:: Error > {
864
- let mut range_names = vec ! [ ] ;
884
+ ) -> Result < ( Option < u32 > , bool /* uses heap */ ) , anyhow:: Error > {
865
885
let mut rtt = None ;
866
886
let mut uses_heap = false ;
867
887
@@ -879,29 +899,9 @@ fn range_names_from(
879
899
}
880
900
_ => { }
881
901
}
882
-
883
- if symbol. section_index ( ) == Some ( text) && symbol. size ( ) > 0 {
884
- let mut name = rustc_demangle:: demangle ( name) . to_string ( ) ;
885
- // clear the thumb bit
886
- let start = symbol. address ( ) as u32 & !1 ;
887
-
888
- // strip the hash (e.g. `::hd881d91ced85c2b0`)
889
- let hash_len = "::hd881d91ced85c2b0" . len ( ) ;
890
- if let Some ( pos) = name. len ( ) . checked_sub ( hash_len) {
891
- let maybe_hash = & name[ pos..] ;
892
- if maybe_hash. starts_with ( "::h" ) {
893
- // FIXME avoid this allocation
894
- name = name[ ..pos] . to_string ( ) ;
895
- }
896
- }
897
-
898
- range_names. push ( ( start..start + symbol. size ( ) as u32 , name) ) ;
899
- }
900
902
}
901
903
902
- range_names. sort_unstable_by ( |a, b| a. 0 . start . cmp ( & b. 0 . start ) ) ;
903
-
904
- Ok ( ( range_names, rtt, uses_heap) )
904
+ Ok ( ( rtt, uses_heap) )
905
905
}
906
906
907
907
const LR : CoreRegisterAddress = CoreRegisterAddress ( 14 ) ;
0 commit comments