mod func;
mod line;
#[cfg(test)]
#[path = "tests.rs"]
mod tests;
use std::collections::HashMap;
use std::sync::{Arc, OnceLock};
use wasmparser::{BinaryReader, Name, NameSectionReader};
use self::func::FuncTable;
use self::line::LineTable;
#[derive(Debug, Clone)]
pub(crate) struct SourceLoc {
pub file: Arc<str>,
pub line: u32,
pub column: u32,
}
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
pub(crate) struct DebugSections {
dwarf: HashMap<String, Box<[u8]>>,
func_names: HashMap<u32, Box<str>>,
module_name: Option<Box<str>>,
code_base: u32,
#[serde(skip)]
index: OnceLock<Option<LineTable>>,
#[serde(skip)]
funcs: OnceLock<Option<FuncTable>>,
}
impl DebugSections {
pub(crate) fn set_code_base(&mut self, base: u32) {
self.code_base = base;
}
pub(crate) fn add_dwarf_section(&mut self, name: &str, data: &[u8]) {
self.dwarf
.insert(name.to_string(), data.to_vec().into_boxed_slice());
}
pub(crate) fn add_name_section(&mut self, data: &[u8], offset: usize, keep_func_names: bool) {
let reader = NameSectionReader::new(BinaryReader::new(data, offset));
for sub in reader {
match sub {
Ok(Name::Module { name, .. }) => self.module_name = Some(name.into()),
Ok(Name::Function(map)) if keep_func_names => {
for naming in map {
let Ok(naming) = naming else { break };
self.func_names.insert(naming.index, naming.name.into());
}
}
_ => {}
}
}
}
pub(crate) fn func_name(&self, func_index: u32) -> Option<&str> {
self.func_names.get(&func_index).map(|s| &**s)
}
pub(crate) fn module_name(&self) -> Option<&str> {
self.module_name.as_deref()
}
pub(crate) fn dwarf_func_name(&self, code_offset: u32) -> Option<Arc<str>> {
let table = self.funcs.get_or_init(|| func::build(&self.dwarf));
let addr = code_offset.checked_sub(self.code_base)?;
table.as_ref()?.lookup(addr)
}
pub(crate) fn lookup(&self, code_offset: u32) -> Option<SourceLoc> {
let table = self.index.get_or_init(|| line::build(&self.dwarf));
let addr = code_offset.checked_sub(self.code_base)?;
table.as_ref()?.lookup(addr)
}
#[cfg(test)]
pub(crate) fn index_built(&self) -> bool {
self.index.get().is_some()
}
}