mod dwarf;
mod expression;
mod units;
use crate::emit::{Emit, EmitContext};
use crate::{CustomSection, Module, RawCustomSection};
use gimli::*;
use self::dwarf::{AddressSearchPreference, ConvertContext, DEAD_CODE};
use self::expression::{CodeAddressConverter, CodeAddressGenerator};
use self::units::DebuggingInformationCursor;
#[derive(Debug, Default)]
pub struct ModuleDebugData {
pub dwarf: read::Dwarf<Vec<u8>>,
}
impl Module {
pub(crate) fn parse_debug_sections(
&mut self,
mut debug_sections: Vec<RawCustomSection>,
) -> Result<()> {
let load_section = |id: gimli::SectionId| -> Result<Vec<u8>> {
Ok(
match debug_sections
.iter_mut()
.find(|section| section.name() == id.name())
{
Some(section) => std::mem::take(&mut section.data),
None => Vec::new(),
},
)
};
self.debug.dwarf = read::Dwarf::load(load_section)?;
Ok(())
}
}
impl Emit for ModuleDebugData {
fn emit(&self, cx: &mut EmitContext) {
let address_generator = CodeAddressGenerator::new(&cx.module.funcs);
let address_converter = CodeAddressConverter::new(&cx.code_transform);
let convert_address = |address, search_preference| -> Option<write::Address> {
let address = address as usize;
let code = address_generator.find_address(address, search_preference);
let address = address_converter.find_address(code);
address
.map(|x| (x - cx.code_transform.code_section_start) as u64)
.map(write::Address::Constant)
};
#[allow(deprecated)]
let from_dwarf = cx
.module
.debug
.dwarf
.borrow(|sections| EndianSlice::new(sections.as_ref(), LittleEndian));
let mut dwarf = write::Dwarf::from(&from_dwarf, &|address| {
if address == 0 || address == DEAD_CODE {
Some(write::Address::Constant(address))
} else {
convert_address(address, AddressSearchPreference::InclusiveFunctionEnd)
.or(Some(write::Address::Constant(DEAD_CODE)))
}
})
.expect("cannot convert to writable dwarf");
let units = {
let mut from_unit_headers = from_dwarf.units();
let mut units = Vec::new();
while let Some(from_unit) = from_unit_headers.next().expect("") {
let index = units.len();
units.push((from_unit, dwarf.units.id(index)));
}
units
};
let mut convert_context = ConvertContext::new(
&from_dwarf.debug_str,
&from_dwarf.debug_line_str,
&mut dwarf.strings,
&mut dwarf.line_strings,
&convert_address,
);
for (from_id, id) in units {
let from_unit: Unit<EndianSlice<'_, LittleEndian>, usize> =
from_dwarf.unit(from_id).expect("readable unit");
let unit = dwarf.units.get_mut(id);
{
let mut from_entries = from_unit.entries();
let mut entries = DebuggingInformationCursor::new(unit);
convert_context.convert_high_pc(&mut from_entries, &mut entries);
}
if let Some(program) = convert_context.convert_unit_line_program(from_unit) {
unit.line_program = program;
}
}
let mut sections = write::Sections::new(write::EndianVec::new(gimli::LittleEndian));
dwarf.write(&mut sections).expect("write failed");
sections
.for_each(
|id: SectionId, data: &write::EndianVec<LittleEndian>| -> Result<()> {
if !data.slice().is_empty() {
cx.wasm_module.section(&wasm_encoder::CustomSection {
name: id.name().into(),
data: data.slice().into(),
});
}
Ok(())
},
)
.expect("never");
}
}