Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 149 additions & 22 deletions wasmtime-debug/src/read_debuginfo.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;
use wasmparser::{ModuleReader, SectionCode};
use std::path::PathBuf;
use wasmparser::{self, ModuleReader, SectionCode};

use gimli;

Expand All @@ -13,48 +14,77 @@ trait Reader: gimli::Reader<Offset = usize, Endian = LittleEndian> {}

impl<'input> Reader for gimli::EndianSlice<'input, LittleEndian> {}

pub use wasmparser::Type as WasmType;

pub type Dwarf<'input> = gimli::Dwarf<gimli::EndianSlice<'input, LittleEndian>>;

#[derive(Debug)]
pub struct FunctionMetadata {
pub params: Box<[WasmType]>,
pub locals: Box<[(u32, WasmType)]>,
}

#[derive(Debug)]
pub struct WasmFileInfo {
pub path: Option<PathBuf>,
pub code_section_offset: u64,
pub funcs: Box<[FunctionMetadata]>,
}

#[derive(Debug)]
pub struct NameSection {
pub module_name: Option<String>,
pub func_names: HashMap<u32, String>,
pub locals_names: HashMap<u32, HashMap<u32, String>>,
}

#[derive(Debug)]
pub struct DebugInfoData<'a> {
pub dwarf: Dwarf<'a>,
pub name_section: Option<NameSection>,
pub wasm_file: WasmFileInfo,
}

fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {
const EMPTY_SECTION: &[u8] = &[];

let endian = LittleEndian;
let debug_str = DebugStr::new(sections[".debug_str"], endian);
let debug_abbrev = DebugAbbrev::new(sections[".debug_abbrev"], endian);
let debug_info = DebugInfo::new(sections[".debug_info"], endian);
let debug_line = DebugLine::new(sections[".debug_line"], endian);
let debug_str = DebugStr::new(sections.get(".debug_str").unwrap_or(&EMPTY_SECTION), endian);
let debug_abbrev = DebugAbbrev::new(
sections.get(".debug_abbrev").unwrap_or(&EMPTY_SECTION),
endian,
);
let debug_info = DebugInfo::new(
sections.get(".debug_info").unwrap_or(&EMPTY_SECTION),
endian,
);
let debug_line = DebugLine::new(
sections.get(".debug_line").unwrap_or(&EMPTY_SECTION),
endian,
);

if sections.contains_key(".debug_addr") {
panic!("Unexpected .debug_addr");
}

let debug_addr = DebugAddr::from(EndianSlice::new(&[], endian));
let debug_addr = DebugAddr::from(EndianSlice::new(EMPTY_SECTION, endian));

if sections.contains_key(".debug_line_str") {
panic!("Unexpected .debug_line_str");
}

let debug_line_str = DebugLineStr::from(EndianSlice::new(&[], endian));
let debug_str_sup = DebugStr::from(EndianSlice::new(&[], endian));
let debug_line_str = DebugLineStr::from(EndianSlice::new(EMPTY_SECTION, endian));
let debug_str_sup = DebugStr::from(EndianSlice::new(EMPTY_SECTION, endian));

if sections.contains_key(".debug_rnglists") {
panic!("Unexpected .debug_rnglists");
}

let debug_ranges = match sections.get(".debug_ranges") {
Some(section) => DebugRanges::new(section, endian),
None => DebugRanges::new(&[], endian),
None => DebugRanges::new(EMPTY_SECTION, endian),
};
let debug_rnglists = DebugRngLists::new(&[], endian);
let debug_rnglists = DebugRngLists::new(EMPTY_SECTION, endian);
let ranges = RangeLists::new(debug_ranges, debug_rnglists);

if sections.contains_key(".debug_loclists") {
Expand All @@ -63,22 +93,22 @@ fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {

let debug_loc = match sections.get(".debug_loc") {
Some(section) => DebugLoc::new(section, endian),
None => DebugLoc::new(&[], endian),
None => DebugLoc::new(EMPTY_SECTION, endian),
};
let debug_loclists = DebugLocLists::new(&[], endian);
let debug_loclists = DebugLocLists::new(EMPTY_SECTION, endian);
let locations = LocationLists::new(debug_loc, debug_loclists);

if sections.contains_key(".debug_str_offsets") {
panic!("Unexpected .debug_str_offsets");
}

let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(&[], endian));
let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(EMPTY_SECTION, endian));

if sections.contains_key(".debug_types") {
panic!("Unexpected .debug_types");
}

let debug_types = DebugTypes::from(EndianSlice::new(&[], endian));
let debug_types = DebugTypes::from(EndianSlice::new(EMPTY_SECTION, endian));

Dwarf {
debug_abbrev,
Expand All @@ -95,27 +125,124 @@ fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {
}
}

fn read_name_section(reader: wasmparser::NameSectionReader) -> wasmparser::Result<NameSection> {
let mut module_name = None;
let mut func_names = HashMap::new();
let mut locals_names = HashMap::new();
for i in reader.into_iter() {
match i? {
wasmparser::Name::Module(m) => {
module_name = Some(String::from(m.get_name()?));
}
wasmparser::Name::Function(f) => {
let mut reader = f.get_map()?;
while let Ok(naming) = reader.read() {
func_names.insert(naming.index, String::from(naming.name));
}
}
wasmparser::Name::Local(l) => {
let mut reader = l.get_function_local_reader()?;
while let Ok(f) = reader.read() {
let mut names = HashMap::new();
let mut reader = f.get_map()?;
while let Ok(naming) = reader.read() {
names.insert(naming.index, String::from(naming.name));
}
locals_names.insert(f.func_index, names);
}
}
}
}
let result = NameSection {
module_name,
func_names,
locals_names,
};
Ok(result)
}

pub fn read_debuginfo(data: &[u8]) -> DebugInfoData {
let mut reader = ModuleReader::new(data).expect("reader");
let mut sections = HashMap::new();
let mut name_section = None;
let mut code_section_offset = 0;

let mut signatures_params: Vec<Box<[WasmType]>> = Vec::new();
let mut func_params_refs: Vec<usize> = Vec::new();
let mut func_locals: Vec<Box<[(u32, WasmType)]>> = Vec::new();

while !reader.eof() {
let section = reader.read().expect("section");
if let SectionCode::Custom { name, .. } = section.code {
if name.starts_with(".debug_") {
let mut reader = section.get_binary_reader();
let len = reader.bytes_remaining();
sections.insert(name, reader.read_bytes(len).expect("bytes"));
match section.code {
SectionCode::Custom { name, .. } => {
if name.starts_with(".debug_") {
let mut reader = section.get_binary_reader();
let len = reader.bytes_remaining();
sections.insert(name, reader.read_bytes(len).expect("bytes"));
}
if name == "name" {
if let Ok(reader) = section.get_name_section_reader() {
if let Ok(section) = read_name_section(reader) {
name_section = Some(section);
}
}
}
}
}
if let SectionCode::Code = section.code {
code_section_offset = section.range().start as u64;
SectionCode::Type => {
signatures_params = section
.get_type_section_reader()
.expect("type section")
.into_iter()
.map(|ft| ft.expect("type").params)
.collect::<Vec<_>>();
}
SectionCode::Function => {
func_params_refs = section
.get_function_section_reader()
.expect("function section")
.into_iter()
.map(|index| index.expect("func index") as usize)
.collect::<Vec<_>>();
}
SectionCode::Code => {
code_section_offset = section.range().start as u64;
func_locals = section
.get_code_section_reader()
.expect("code section")
.into_iter()
.map(|body| {
let locals = body
.expect("body")
.get_locals_reader()
.expect("locals reader");
locals
.into_iter()
.collect::<Result<Vec<_>, _>>()
.expect("locals data")
.into_boxed_slice()
})
.collect::<Vec<_>>();
}
_ => (),
}
}

let func_meta = func_params_refs
.into_iter()
.zip(func_locals.into_iter())
.map(|(params_index, locals)| FunctionMetadata {
params: signatures_params[params_index].clone(),
locals,
})
.collect::<Vec<_>>();

DebugInfoData {
dwarf: convert_sections(sections),
name_section,
wasm_file: WasmFileInfo {
path: None,
code_section_offset,
funcs: func_meta.into_boxed_slice(),
},
}
}
2 changes: 2 additions & 0 deletions wasmtime-debug/src/transform/address_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,9 @@ mod tests {
let at = AddressTransform::new(
&input,
&WasmFileInfo {
path: None,
code_section_offset: 1,
funcs: Box::new([]),
},
);

Expand Down
6 changes: 5 additions & 1 deletion wasmtime-debug/src/transform/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ impl Clone for CompiledExpressionPart {

impl CompiledExpression {
pub fn vmctx() -> CompiledExpression {
CompiledExpression::from_label(get_vmctx_value_label())
}

pub fn from_label(label: ValueLabel) -> CompiledExpression {
CompiledExpression {
parts: vec![
CompiledExpressionPart::Local(get_vmctx_value_label()),
CompiledExpressionPart::Local(label),
CompiledExpressionPart::Code(vec![gimli::constants::DW_OP_stack_value.0 as u8]),
],
need_deref: false,
Expand Down
16 changes: 16 additions & 0 deletions wasmtime-debug/src/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::gc::build_dependencies;
use crate::DebugInfoData;
use cranelift_codegen::isa::TargetFrontendConfig;
use failure::Error;
use simulate::generate_simulated_dwarf;
use std::collections::HashSet;
use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};

Expand All @@ -22,7 +23,9 @@ mod attr;
mod expression;
mod line_program;
mod range_info_builder;
mod simulate;
mod unit;
mod utils;

pub(crate) trait Reader: gimli::Reader<Offset = usize> {}

Expand Down Expand Up @@ -78,6 +81,7 @@ pub fn transform_dwarf(

let out_line_strings = write::LineStringTable::default();

let mut translated = HashSet::new();
let mut iter = di.dwarf.debug_info.units();
while let Some(unit) = iter.next().unwrap_or(None) {
let unit = di.dwarf.unit(unit)?;
Expand All @@ -90,9 +94,21 @@ pub fn transform_dwarf(
&vmctx_info,
&mut out_units,
&mut out_strings,
&mut translated,
)?;
}

generate_simulated_dwarf(
&addr_tr,
di,
&vmctx_info,
&ranges,
&translated,
&out_encoding,
&mut out_units,
&mut out_strings,
)?;

Ok(write::Dwarf {
units: out_units,
line_programs: vec![],
Expand Down
Loading