1use crate::error::Result;
2use object::{Object, ObjectSection, ObjectSymbol, SymbolKind};
3use serde::Serialize;
4use std::collections::BTreeMap;
5use std::ops::Range;
6
7#[derive(Debug, Clone, Serialize)]
8pub struct ResolvedSymbol {
9 pub name: String,
10 pub address: u64,
11 pub size: u64,
12 pub section: Option<String>,
13}
14
15pub struct SymbolTable {
16 by_address: BTreeMap<u64, ResolvedSymbol>,
17}
18
19impl SymbolTable {
20 pub fn build(file: &object::File<'_>) -> Result<Self> {
21 let mut by_address = BTreeMap::new();
22 for sym in file.symbols() {
23 if matches!(sym.kind(), SymbolKind::Unknown | SymbolKind::Label) {
24 continue;
25 }
26 let address = sym.address();
27 if address == 0 {
28 continue;
29 }
30 let name = sym.name().unwrap_or("<unknown>").to_owned();
31 let size = sym.size();
32 let section = sym
33 .section_index()
34 .and_then(|idx| file.section_by_index(idx).ok())
35 .and_then(|s| s.name().ok().map(|n: &str| n.to_owned()));
36 by_address.insert(address, ResolvedSymbol { name, address, size, section });
37 }
38 Ok(Self { by_address })
39 }
40
41 pub fn symbol_at(&self, address: u64) -> Option<&ResolvedSymbol> {
43 self.by_address
44 .range(..=address)
45 .next_back()
46 .map(|(_, sym)| sym)
47 .filter(|sym| sym.size == 0 || address < sym.address + sym.size)
48 }
49
50 pub fn symbols_in(&self, range: Range<u64>) -> impl Iterator<Item = &ResolvedSymbol> {
51 self.by_address
52 .range(range.clone())
53 .map(|(_, sym)| sym)
54 .filter(move |sym| sym.address < range.end)
55 }
56
57 pub fn iter(&self) -> impl Iterator<Item = &ResolvedSymbol> {
58 self.by_address.values()
59 }
60}