Skip to content
This repository was archived by the owner on Jan 30, 2024. It is now read-only.

Commit 4865413

Browse files
committedSep 16, 2020
start using DWARF info in the unwinder
this is works towards #17 for now it extends the backtrace with inlined functions (which were not shown before) it doesn't add line info just yet though there is some, no super-precise line info available
1 parent 7e26e33 commit 4865413

File tree

4 files changed

+397
-57
lines changed

4 files changed

+397
-57
lines changed
 

‎Cargo.lock

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ probe-rs-rtt = "0.3.0"
2424
rustc-demangle = "0.1.16"
2525
structopt = "0.3.15"
2626
object = "0.21.1"
27+
intervaltree = "0.2.6"
2728

2829
[features]
2930
defmt = ["defmt-elf2table", "defmt-decoder"]

‎src/main.rs

+57-57
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
mod logger;
2+
mod pc2frames;
23

34
use core::{
45
cmp,
56
convert::TryInto,
67
mem,
7-
ops::Range,
88
sync::atomic::{AtomicBool, Ordering},
99
};
1010
use std::{
11-
collections::{btree_map, BTreeMap},
11+
collections::{btree_map, BTreeMap, HashSet},
1212
fs,
1313
io::{self, Write as _},
1414
path::PathBuf,
@@ -26,7 +26,7 @@ use gimli::{
2626
};
2727
use object::{
2828
read::{File as ElfFile, Object as _, ObjectSection as _},
29-
SectionIndex,
29+
SymbolSection,
3030
};
3131
use probe_rs::config::{registry, MemoryRegion, RamRegion};
3232
use probe_rs::{
@@ -123,13 +123,6 @@ fn notmain() -> Result<i32, anyhow::Error> {
123123
);
124124
}
125125

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-
133126
#[cfg(feature = "defmt")]
134127
let (table, locs) = {
135128
let table = defmt_elf2table::parse(&bytes)?;
@@ -228,7 +221,31 @@ fn notmain() -> Result<i32, anyhow::Error> {
228221
}
229222
}
230223

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)?;
232249

233250
let vector_table = vector_table.ok_or_else(|| anyhow!("`.vector_table` section is missing"))?;
234251
log::debug!("vector table: {:x?}", vector_table);
@@ -454,7 +471,8 @@ fn notmain() -> Result<i32, anyhow::Error> {
454471
&mut core,
455472
pc,
456473
debug_frame,
457-
&range_names,
474+
&elf,
475+
&pc2frames,
458476
&vector_table,
459477
&sp_ram_region,
460478
)?;
@@ -598,7 +616,8 @@ fn backtrace(
598616
core: &mut Core<'_>,
599617
mut pc: u32,
600618
debug_frame: &[u8],
601-
range_names: &RangeNames,
619+
elf: &ElfFile,
620+
pc2frames: &pc2frames::Map,
602621
vector_table: &VectorTable,
603622
sp_ram_region: &Option<RamRegion>,
604623
) -> Result<Option<TopException>, anyhow::Error> {
@@ -614,23 +633,31 @@ fn backtrace(
614633
let ctx = &mut UninitializedUnwindContext::new();
615634

616635
let mut top_exception = None;
617-
let mut frame = 0;
636+
let mut frame_index = 0;
618637
let mut registers = Registers::new(lr, sp, core);
619638
println!("stack backtrace:");
620639
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+
}
634661

635662
// on hard fault exception entry we hit the breakpoint before the subroutine prelude (`push
636663
// lr`) is executed so special handling is required
@@ -708,8 +735,6 @@ fn backtrace(
708735
}
709736
pc = lr & !THUMB_BIT;
710737
}
711-
712-
frame += 1;
713738
}
714739

715740
Ok(top_exception)
@@ -853,15 +878,10 @@ impl Stacked {
853878
num_words as u32 * 4
854879
}
855880
}
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)>;
859881

860-
fn range_names_from(
882+
fn rtt_and_heap_info_from(
861883
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> {
865885
let mut rtt = None;
866886
let mut uses_heap = false;
867887

@@ -879,29 +899,9 @@ fn range_names_from(
879899
}
880900
_ => {}
881901
}
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-
}
900902
}
901903

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))
905905
}
906906

907907
const LR: CoreRegisterAddress = CoreRegisterAddress(14);

0 commit comments

Comments
 (0)