emu/src/symbol_table.rs

128 lines
3.6 KiB
Rust
Raw Normal View History

2022-10-23 17:18:32 -05:00
use crate::symbol::Symbol;
use anyhow::anyhow;
2022-11-16 10:40:26 -06:00
use elf::abi::{STT_FILE, STT_SECTION};
use elf::endian::AnyEndian;
use elf::ElfStream;
2022-10-20 11:29:06 -05:00
use indexmap::IndexSet;
use itertools::Itertools;
2022-10-20 11:29:06 -05:00
use std::collections::HashMap;
use std::fmt::Display;
2022-10-20 14:42:08 -05:00
use std::fs::File;
use thiserror::Error;
pub struct SymbolDisplayer<'a>(&'a SymbolTable);
impl Display for SymbolDisplayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"{}",
self.0
.symbols
.iter()
.format_with("\n", |(name, symbol), g| {
g(&format_args!("{name}: {symbol}"))
})
))
}
}
#[derive(Debug, Copy, Clone, Error)]
#[error("Invalid symbol table")]
struct InvalidSymbolTable;
pub struct BreakpointDisplayer<'a>(&'a SymbolTable);
impl Display for BreakpointDisplayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.0.breakpoints.iter().format("\n")))
}
}
2022-10-20 11:29:06 -05:00
#[derive(Debug)]
pub struct SymbolTable {
symbols: HashMap<String, Symbol>,
breakpoints: IndexSet<String>,
2022-10-20 11:29:06 -05:00
pub active: bool,
}
#[derive(Debug, Copy, Clone, Error)]
#[error("Invalid symbol name")]
pub struct InvalidSymbolName;
2022-10-20 11:29:06 -05:00
impl SymbolTable {
pub fn new(symbols: HashMap<String, Symbol>) -> Self {
Self {
symbols,
breakpoints: IndexSet::new(),
active: true,
}
}
2022-10-23 17:18:32 -05:00
pub fn read_from_file(path: &str) -> anyhow::Result<Self> {
2022-11-16 10:40:26 -06:00
let mut file = ElfStream::<AnyEndian, _>::open_stream(File::open(path)?)?;
2022-10-20 14:42:08 -05:00
let (symtab, symstrtab) = file
2022-10-22 18:54:47 -05:00
.symbol_table()?
.ok_or_else(|| anyhow!("No symbol table in {}", path))?;
2022-10-20 14:42:08 -05:00
let symbols = symtab
.iter()
.skip(1)
2022-11-12 09:09:17 -06:00
.filter(|sym| sym.st_symtype() != STT_FILE && sym.st_symtype() != STT_SECTION)
2022-10-20 14:42:08 -05:00
.map(|sym| {
(
symstrtab.get(sym.st_name as usize).unwrap().to_string(),
Symbol::from(sym),
)
})
.collect::<HashMap<_, _>>();
Ok(Self::new(symbols))
}
pub fn update_symbols_from(&mut self, table: Self) {
2022-10-20 11:29:06 -05:00
self.breakpoints = self
.breakpoints
.iter()
.cloned()
.filter(|sym| table.symbols.contains_key(sym))
2022-10-20 11:29:06 -05:00
.collect::<IndexSet<_>>();
self.symbols = table.symbols;
2022-10-20 11:29:06 -05:00
}
2022-10-20 14:42:08 -05:00
pub fn breakpoint_set_at(&self, addr: u32) -> bool {
self.breakpoints
.iter()
.any(|sym| self.symbols[sym].value() == addr)
}
pub fn set_breakpoint(&mut self, symbol: String) {
self.breakpoints.insert(symbol);
}
pub fn delete_breakpoint(&mut self, symbol: &str) -> bool {
self.breakpoints.shift_remove(symbol)
}
2022-10-20 14:42:08 -05:00
pub fn address_to_symbol(&self, addr: u32) -> Option<(&String, u32)> {
self.symbols
.iter()
.filter(|(_, sym)| sym.value() <= addr)
.map(|(sym_name, sym)| (sym_name, addr - sym.value()))
.min_by_key(|(_, offset)| *offset)
}
pub fn get_symbol(&self, symbol: &str) -> anyhow::Result<&Symbol> {
Ok(self.symbols.get(symbol).ok_or(InvalidSymbolName)?)
}
pub fn contains_symbol(&self, symbol: &str) -> bool {
self.symbols.contains_key(symbol)
}
pub fn symbol_displayer(&self) -> SymbolDisplayer<'_> {
SymbolDisplayer(self)
}
pub fn breakpoint_displayer(&self) -> BreakpointDisplayer {
BreakpointDisplayer(self)
}
2022-10-20 11:29:06 -05:00
}