Skip to content

Commit

Permalink
Generate simulated DWARF for rest of the functions
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed Aug 9, 2019
1 parent 6def6de commit 8532385
Show file tree
Hide file tree
Showing 7 changed files with 702 additions and 171 deletions.
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

0 comments on commit 8532385

Please sign in to comment.