Next Generation WASM Microkernel Operating System
at trap_handler 236 lines 6.9 kB view raw
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}