Next Generation WASM Microkernel Operating System
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use core::ffi::c_void;
9use core::{fmt, str};
10use fallible_iterator::FallibleIterator;
11use gimli::{EndianSlice, NativeEndian};
12use rustc_demangle::{Demangle, try_demangle};
13use xmas_elf::sections::SectionData;
14use xmas_elf::symbol_table::Entry;
15
16pub enum Symbol<'a> {
17 /// We were able to locate frame information for this symbol, and
18 /// `addr2line`'s frame internally has all the nitty gritty details.
19 Frame {
20 addr: *mut c_void,
21 location: Option<kaddr2line::Location<'a>>,
22 name: Option<&'a str>,
23 },
24 /// Couldn't find debug information, but we found it in the symbol table of
25 /// the elf executable.
26 Symtab { name: &'a str },
27}
28
29impl Symbol<'_> {
30 pub fn name(&self) -> Option<SymbolName<'_>> {
31 match self {
32 Symbol::Frame { name, .. } => {
33 let name = name.as_ref()?;
34 Some(SymbolName::new(name))
35 }
36 Symbol::Symtab { name, .. } => Some(SymbolName::new(name)),
37 }
38 }
39
40 pub fn addr(&self) -> Option<*mut c_void> {
41 match self {
42 Symbol::Frame { addr, .. } => Some(*addr),
43 Symbol::Symtab { .. } => None,
44 }
45 }
46
47 pub fn filename(&self) -> Option<&str> {
48 match self {
49 Symbol::Frame { location, .. } => {
50 let file = location.as_ref()?.file?;
51 Some(file)
52 }
53 Symbol::Symtab { .. } => None,
54 }
55 }
56
57 pub fn lineno(&self) -> Option<u32> {
58 match self {
59 Symbol::Frame { location, .. } => location.as_ref()?.line,
60 Symbol::Symtab { .. } => None,
61 }
62 }
63
64 pub fn colno(&self) -> Option<u32> {
65 match self {
66 Symbol::Frame { location, .. } => location.as_ref()?.column,
67 Symbol::Symtab { .. } => None,
68 }
69 }
70}
71
72impl fmt::Debug for Symbol<'_> {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 let mut d = f.debug_struct("Symbol");
75 d.field("name", &self.name());
76 d.field("addr", &self.addr());
77 d.field("filename", &self.filename());
78 d.field("lineno", &self.lineno());
79 d.field("colno", &self.colno());
80 d.finish()
81 }
82}
83
84pub struct SymbolName<'a> {
85 raw: &'a str,
86 demangled: Option<Demangle<'a>>,
87}
88
89impl<'a> SymbolName<'a> {
90 pub fn new(raw: &'a str) -> SymbolName<'a> {
91 let demangled = try_demangle(raw).ok();
92
93 Self { raw, demangled }
94 }
95
96 pub fn as_raw_str(&self) -> &'a str {
97 self.demangled
98 .as_ref()
99 .map(|s| s.as_str())
100 .unwrap_or(self.raw)
101 }
102}
103
104impl fmt::Display for SymbolName<'_> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 if let Some(ref s) = self.demangled {
107 return s.fmt(f);
108 }
109
110 f.write_str(self.raw)
111 }
112}
113
114impl fmt::Debug for SymbolName<'_> {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 if let Some(ref s) = self.demangled {
117 return s.fmt(f);
118 }
119
120 f.write_str(self.raw)
121 }
122}
123
124pub struct SymbolsIter<'a, 'ctx> {
125 addr: u64,
126 elf: &'ctx xmas_elf::ElfFile<'a>,
127 symtab: &'ctx [xmas_elf::symbol_table::Entry64],
128 iter: kaddr2line::FrameIter<'ctx, EndianSlice<'a, NativeEndian>>,
129 anything: bool,
130}
131
132impl<'ctx> SymbolsIter<'_, 'ctx> {
133 fn search_symtab(&self) -> Option<&'ctx str> {
134 self.symtab
135 .iter()
136 .find(|sym| sym.value() == self.addr)
137 .map(|sym| sym.get_name(self.elf).unwrap())
138 }
139}
140
141impl<'ctx> FallibleIterator for SymbolsIter<'_, 'ctx> {
142 type Item = Symbol<'ctx>;
143 type Error = gimli::Error;
144
145 fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
146 if let Some(frame) = self.iter.next()? {
147 self.anything = true;
148
149 let name = if let Some(func) = frame.function {
150 str::from_utf8(func.name.slice()).ok()
151 } else {
152 self.search_symtab()
153 };
154
155 Ok(Some(Symbol::Frame {
156 addr: self.addr as *mut c_void,
157 location: frame.location,
158 name,
159 }))
160 } else if !self.anything {
161 self.anything = true;
162 // the iterator didn't produce any frames, so let's try the symbol table
163 if let Some(name) = self.search_symtab() {
164 Ok(Some(Symbol::Symtab { name }))
165 } else {
166 Ok(None)
167 }
168 } else {
169 Ok(None)
170 }
171 }
172}
173
174/// Context necessary to resolve an address to its symbol name and source location.
175pub struct SymbolizeContext<'a> {
176 addr2line: kaddr2line::Context<EndianSlice<'a, NativeEndian>>,
177 elf: xmas_elf::ElfFile<'a>,
178 adjust_vma: u64,
179}
180
181impl<'a> SymbolizeContext<'a> {
182 /// # Errors
183 ///
184 /// Returns an error when parsing the DWARF fails.
185 pub fn new(elf: xmas_elf::ElfFile<'a>, adjust_vma: u64) -> gimli::Result<Self> {
186 let dwarf = gimli::Dwarf::load(|section_id| -> gimli::Result<_> {
187 let data = match elf.find_section_by_name(section_id.name()) {
188 Some(section) => section.raw_data(&elf),
189 None => &[],
190 };
191 Ok(EndianSlice::new(data, NativeEndian))
192 })?;
193 let addr2line = kaddr2line::Context::from_dwarf(dwarf)?;
194
195 Ok(Self {
196 addr2line,
197 elf,
198 adjust_vma,
199 })
200 }
201
202 /// # Errors
203 ///
204 /// Returns an error if the given address doesn't correspond to a symbol or parsing the DWARF info
205 /// fails.
206 ///
207 /// # Panics
208 ///
209 /// Panics if the ELF file doesn't contain a symbol table.
210 pub fn resolve_unsynchronized(&self, probe: u64) -> gimli::Result<SymbolsIter<'a, '_>> {
211 let probe = probe - self.adjust_vma;
212 let iter = self.addr2line.find_frames(probe).skip_all_loads()?;
213
214 let symtab = self
215 .elf
216 .section_iter()
217 .find_map(|section| {
218 section
219 .get_data(&self.elf)
220 .ok()
221 .and_then(|data| match data {
222 SectionData::SymbolTable64(symtab) => Some(symtab),
223 _ => None,
224 })
225 })
226 .unwrap();
227
228 Ok(SymbolsIter {
229 addr: probe,
230 elf: &self.elf,
231 symtab,
232 iter,
233 anything: false,
234 })
235 }
236}