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