1 use std::{ops::Deref, path::PathBuf}; 2 3 use goblin::elf::Sym; 4 use log::info; 5 6 use crate::app::AppResult; 7 8 use super::error::{BackendError, BackendErrorKind}; 9 10 #[derive(Debug)] 11 pub struct KernelLoader; 12 13 impl KernelLoader { 14 pub fn load(kernel: &PathBuf) -> AppResult<KernelMetadata> { 15 info!("Loading kernel: {:?}", kernel); 16 let kernel_bytes = std::fs::read(kernel)?; 17 let elf = goblin::elf::Elf::parse(&kernel_bytes).map_err(|e| { 18 BackendError::new( 19 BackendErrorKind::KernelLoadError, 20 Some(format!("Failed to load kernel: {:?}", e)), 21 ) 22 })?; 23 let mut result = KernelMetadata::new(kernel.clone()); 24 25 info!("Parsing symbols..."); 26 for sym in elf.syms.iter() { 27 let name = elf.strtab.get_at(sym.st_name).unwrap_or(""); 28 result.add_symbol(sym.clone(), name.to_string()); 29 } 30 info!("Parsed {} symbols", result.symbols().len()); 31 info!("Loaded kernel: {:?}", kernel); 32 return Ok(result); 33 } 34 } 35 36 #[derive(Debug)] 37 pub struct KernelMetadata { 38 pub kernel: PathBuf, 39 sym_collection: SymbolCollection, 40 } 41 42 impl KernelMetadata { 43 pub fn new(kernel: PathBuf) -> Self { 44 Self { 45 kernel, 46 sym_collection: SymbolCollection::new(), 47 } 48 } 49 50 pub fn symbols(&self) -> &[Symbol] { 51 &self.sym_collection.symbols 52 } 53 54 pub fn sym_collection(&self) -> &SymbolCollection { 55 &self.sym_collection 56 } 57 58 pub fn add_symbol(&mut self, sym: Sym, name: String) { 59 self.sym_collection.add_symbol(sym, name); 60 } 61 } 62 63 #[derive(Debug)] 64 pub struct SymbolCollection { 65 symbols: Vec<Symbol>, 66 } 67 68 impl SymbolCollection { 69 pub fn new() -> Self { 70 Self { 71 symbols: Vec::new(), 72 } 73 } 74 75 pub fn add_symbol(&mut self, sym: Sym, name: String) { 76 self.symbols.push(Symbol::new(sym, name)); 77 } 78 79 #[allow(dead_code)] 80 pub fn len(&self) -> usize { 81 self.symbols.len() 82 } 83 84 pub fn find_by_name(&self, name: &str) -> Option<&Symbol> { 85 self.symbols.iter().find(|sym| sym.name() == name) 86 } 87 } 88 89 #[derive(Debug, Clone)] 90 pub struct Symbol { 91 sym: Sym, 92 name: String, 93 } 94 95 impl Symbol { 96 pub fn new(sym: Sym, name: String) -> Self { 97 Self { sym, name } 98 } 99 100 pub fn name(&self) -> &str { 101 &self.name 102 } 103 104 /// Returns the virtual address of the symbol. 105 #[allow(dead_code)] 106 pub fn vaddr(&self) -> usize { 107 self.sym.st_value as usize 108 } 109 110 /// Returns the offset of the symbol in the kernel memory. 111 pub fn memory_offset(&self) -> u64 { 112 self.sym.st_value & (!0xffff_8000_0000_0000) 113 } 114 } 115 116 impl Deref for Symbol { 117 type Target = Sym; 118 119 fn deref(&self) -> &Self::Target { 120 &self.sym 121 } 122 } 123