Generate simulated DWARF for rest of the functions
This commit is contained in:
committed by
Dan Gohman
parent
4937dd0632
commit
b4a505d5d3
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use wasmparser::{ModuleReader, SectionCode};
|
use std::path::PathBuf;
|
||||||
|
use wasmparser::{self, ModuleReader, SectionCode};
|
||||||
|
|
||||||
use gimli;
|
use gimli;
|
||||||
|
|
||||||
@@ -13,38 +14,67 @@ trait Reader: gimli::Reader<Offset = usize, Endian = LittleEndian> {}
|
|||||||
|
|
||||||
impl<'input> Reader for gimli::EndianSlice<'input, 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>>;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct WasmFileInfo {
|
pub struct WasmFileInfo {
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
pub code_section_offset: u64,
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct DebugInfoData<'a> {
|
pub struct DebugInfoData<'a> {
|
||||||
pub dwarf: Dwarf<'a>,
|
pub dwarf: Dwarf<'a>,
|
||||||
|
pub name_section: Option<NameSection>,
|
||||||
pub wasm_file: WasmFileInfo,
|
pub wasm_file: WasmFileInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {
|
fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {
|
||||||
|
const EMPTY_SECTION: &[u8] = &[];
|
||||||
|
|
||||||
let endian = LittleEndian;
|
let endian = LittleEndian;
|
||||||
let debug_str = DebugStr::new(sections[".debug_str"], endian);
|
let debug_str = DebugStr::new(sections.get(".debug_str").unwrap_or(&EMPTY_SECTION), endian);
|
||||||
let debug_abbrev = DebugAbbrev::new(sections[".debug_abbrev"], endian);
|
let debug_abbrev = DebugAbbrev::new(
|
||||||
let debug_info = DebugInfo::new(sections[".debug_info"], endian);
|
sections.get(".debug_abbrev").unwrap_or(&EMPTY_SECTION),
|
||||||
let debug_line = DebugLine::new(sections[".debug_line"], endian);
|
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") {
|
if sections.contains_key(".debug_addr") {
|
||||||
panic!("Unexpected .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") {
|
if sections.contains_key(".debug_line_str") {
|
||||||
panic!("Unexpected .debug_line_str");
|
panic!("Unexpected .debug_line_str");
|
||||||
}
|
}
|
||||||
|
|
||||||
let debug_line_str = DebugLineStr::from(EndianSlice::new(&[], endian));
|
let debug_line_str = DebugLineStr::from(EndianSlice::new(EMPTY_SECTION, endian));
|
||||||
let debug_str_sup = DebugStr::from(EndianSlice::new(&[], endian));
|
let debug_str_sup = DebugStr::from(EndianSlice::new(EMPTY_SECTION, endian));
|
||||||
|
|
||||||
if sections.contains_key(".debug_rnglists") {
|
if sections.contains_key(".debug_rnglists") {
|
||||||
panic!("Unexpected .debug_rnglists");
|
panic!("Unexpected .debug_rnglists");
|
||||||
@@ -52,9 +82,9 @@ fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {
|
|||||||
|
|
||||||
let debug_ranges = match sections.get(".debug_ranges") {
|
let debug_ranges = match sections.get(".debug_ranges") {
|
||||||
Some(section) => DebugRanges::new(section, endian),
|
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);
|
let ranges = RangeLists::new(debug_ranges, debug_rnglists);
|
||||||
|
|
||||||
if sections.contains_key(".debug_loclists") {
|
if sections.contains_key(".debug_loclists") {
|
||||||
@@ -63,22 +93,22 @@ fn convert_sections<'a>(sections: HashMap<&str, &'a [u8]>) -> Dwarf<'a> {
|
|||||||
|
|
||||||
let debug_loc = match sections.get(".debug_loc") {
|
let debug_loc = match sections.get(".debug_loc") {
|
||||||
Some(section) => DebugLoc::new(section, endian),
|
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);
|
let locations = LocationLists::new(debug_loc, debug_loclists);
|
||||||
|
|
||||||
if sections.contains_key(".debug_str_offsets") {
|
if sections.contains_key(".debug_str_offsets") {
|
||||||
panic!("Unexpected .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") {
|
if sections.contains_key(".debug_types") {
|
||||||
panic!("Unexpected .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 {
|
Dwarf {
|
||||||
debug_abbrev,
|
debug_abbrev,
|
||||||
@@ -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 {
|
pub fn read_debuginfo(data: &[u8]) -> DebugInfoData {
|
||||||
let mut reader = ModuleReader::new(data).expect("reader");
|
let mut reader = ModuleReader::new(data).expect("reader");
|
||||||
let mut sections = HashMap::new();
|
let mut sections = HashMap::new();
|
||||||
|
let mut name_section = None;
|
||||||
let mut code_section_offset = 0;
|
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() {
|
while !reader.eof() {
|
||||||
let section = reader.read().expect("section");
|
let section = reader.read().expect("section");
|
||||||
if let SectionCode::Custom { name, .. } = section.code {
|
match section.code {
|
||||||
if name.starts_with(".debug_") {
|
SectionCode::Custom { name, .. } => {
|
||||||
let mut reader = section.get_binary_reader();
|
if name.starts_with(".debug_") {
|
||||||
let len = reader.bytes_remaining();
|
let mut reader = section.get_binary_reader();
|
||||||
sections.insert(name, reader.read_bytes(len).expect("bytes"));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
SectionCode::Type => {
|
||||||
if let SectionCode::Code = section.code {
|
signatures_params = section
|
||||||
code_section_offset = section.range().start as u64;
|
.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 {
|
DebugInfoData {
|
||||||
dwarf: convert_sections(sections),
|
dwarf: convert_sections(sections),
|
||||||
|
name_section,
|
||||||
wasm_file: WasmFileInfo {
|
wasm_file: WasmFileInfo {
|
||||||
|
path: None,
|
||||||
code_section_offset,
|
code_section_offset,
|
||||||
|
funcs: func_meta.into_boxed_slice(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -609,7 +609,9 @@ mod tests {
|
|||||||
let at = AddressTransform::new(
|
let at = AddressTransform::new(
|
||||||
&input,
|
&input,
|
||||||
&WasmFileInfo {
|
&WasmFileInfo {
|
||||||
|
path: None,
|
||||||
code_section_offset: 1,
|
code_section_offset: 1,
|
||||||
|
funcs: Box::new([]),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,13 @@ impl Clone for CompiledExpressionPart {
|
|||||||
|
|
||||||
impl CompiledExpression {
|
impl CompiledExpression {
|
||||||
pub fn vmctx() -> CompiledExpression {
|
pub fn vmctx() -> CompiledExpression {
|
||||||
|
CompiledExpression::from_label(get_vmctx_value_label())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_label(label: ValueLabel) -> CompiledExpression {
|
||||||
CompiledExpression {
|
CompiledExpression {
|
||||||
parts: vec![
|
parts: vec![
|
||||||
CompiledExpressionPart::Local(get_vmctx_value_label()),
|
CompiledExpressionPart::Local(label),
|
||||||
CompiledExpressionPart::Code(vec![gimli::constants::DW_OP_stack_value.0 as u8]),
|
CompiledExpressionPart::Code(vec![gimli::constants::DW_OP_stack_value.0 as u8]),
|
||||||
],
|
],
|
||||||
need_deref: false,
|
need_deref: false,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::gc::build_dependencies;
|
|||||||
use crate::DebugInfoData;
|
use crate::DebugInfoData;
|
||||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
use simulate::generate_simulated_dwarf;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};
|
use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};
|
||||||
|
|
||||||
@@ -22,7 +23,9 @@ mod attr;
|
|||||||
mod expression;
|
mod expression;
|
||||||
mod line_program;
|
mod line_program;
|
||||||
mod range_info_builder;
|
mod range_info_builder;
|
||||||
|
mod simulate;
|
||||||
mod unit;
|
mod unit;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
pub(crate) trait Reader: gimli::Reader<Offset = usize> {}
|
pub(crate) trait Reader: gimli::Reader<Offset = usize> {}
|
||||||
|
|
||||||
@@ -78,6 +81,7 @@ pub fn transform_dwarf(
|
|||||||
|
|
||||||
let out_line_strings = write::LineStringTable::default();
|
let out_line_strings = write::LineStringTable::default();
|
||||||
|
|
||||||
|
let mut translated = HashSet::new();
|
||||||
let mut iter = di.dwarf.debug_info.units();
|
let mut iter = di.dwarf.debug_info.units();
|
||||||
while let Some(unit) = iter.next().unwrap_or(None) {
|
while let Some(unit) = iter.next().unwrap_or(None) {
|
||||||
let unit = di.dwarf.unit(unit)?;
|
let unit = di.dwarf.unit(unit)?;
|
||||||
@@ -90,9 +94,21 @@ pub fn transform_dwarf(
|
|||||||
&vmctx_info,
|
&vmctx_info,
|
||||||
&mut out_units,
|
&mut out_units,
|
||||||
&mut out_strings,
|
&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 {
|
Ok(write::Dwarf {
|
||||||
units: out_units,
|
units: out_units,
|
||||||
line_programs: vec![],
|
line_programs: vec![],
|
||||||
|
|||||||
370
wasmtime-debug/src/transform/simulate.rs
Normal file
370
wasmtime-debug/src/transform/simulate.rs
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
use crate::read_debuginfo::WasmFileInfo;
|
||||||
|
pub use crate::read_debuginfo::{DebugInfoData, FunctionMetadata, WasmType};
|
||||||
|
use cranelift_entity::EntityRef;
|
||||||
|
use cranelift_wasm::get_vmctx_value_label;
|
||||||
|
use failure::Error;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges};
|
||||||
|
|
||||||
|
use gimli::write;
|
||||||
|
use gimli::{self, LineEncoding};
|
||||||
|
|
||||||
|
use super::expression::{CompiledExpression, FunctionFrameInfo};
|
||||||
|
use super::utils::{add_internal_types, append_vmctx_info, get_function_frame_info};
|
||||||
|
use super::AddressTransform;
|
||||||
|
|
||||||
|
const PRODUCER_NAME: &str = "wasmtime";
|
||||||
|
|
||||||
|
fn generate_line_info(
|
||||||
|
addr_tr: &AddressTransform,
|
||||||
|
translated: &HashSet<u32>,
|
||||||
|
out_encoding: &gimli::Encoding,
|
||||||
|
w: &WasmFileInfo,
|
||||||
|
comp_dir_id: write::StringId,
|
||||||
|
name_id: write::StringId,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<write::LineProgram, Error> {
|
||||||
|
let out_comp_dir = write::LineString::StringRef(comp_dir_id);
|
||||||
|
let out_comp_name = write::LineString::StringRef(name_id);
|
||||||
|
|
||||||
|
let line_encoding = LineEncoding::default();
|
||||||
|
|
||||||
|
let mut out_program = write::LineProgram::new(
|
||||||
|
*out_encoding,
|
||||||
|
line_encoding,
|
||||||
|
out_comp_dir,
|
||||||
|
out_comp_name,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let file_index = out_program.add_file(
|
||||||
|
write::LineString::String(name.as_bytes().to_vec()),
|
||||||
|
out_program.default_directory(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (i, map) in addr_tr.map() {
|
||||||
|
let symbol = i.index();
|
||||||
|
if translated.contains(&(symbol as u32)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let base_addr = map.offset;
|
||||||
|
out_program.begin_sequence(Some(write::Address::Symbol { symbol, addend: 0 }));
|
||||||
|
for addr_map in map.addresses.iter() {
|
||||||
|
let address_offset = (addr_map.generated - base_addr) as u64;
|
||||||
|
out_program.row().address_offset = address_offset;
|
||||||
|
out_program.row().op_index = 0;
|
||||||
|
out_program.row().file = file_index;
|
||||||
|
let wasm_offset = w.code_section_offset + addr_map.wasm as u64;
|
||||||
|
out_program.row().line = wasm_offset;
|
||||||
|
out_program.row().column = 0;
|
||||||
|
out_program.row().discriminator = 1;
|
||||||
|
out_program.row().is_statement = true;
|
||||||
|
out_program.row().basic_block = false;
|
||||||
|
out_program.row().prologue_end = false;
|
||||||
|
out_program.row().epilogue_begin = false;
|
||||||
|
out_program.row().isa = 0;
|
||||||
|
out_program.generate_row();
|
||||||
|
}
|
||||||
|
let end_addr = (map.offset + map.len - 1) as u64;
|
||||||
|
out_program.end_sequence(end_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out_program)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn autogenerate_dwarf_wasm_path(di: &DebugInfoData) -> PathBuf {
|
||||||
|
let module_name = di
|
||||||
|
.name_section
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|ns| ns.module_name.to_owned())
|
||||||
|
.unwrap_or_else(|| unsafe {
|
||||||
|
static mut GEN_ID: u32 = 0;
|
||||||
|
GEN_ID += 1;
|
||||||
|
format!("<gen-{}>", GEN_ID)
|
||||||
|
});
|
||||||
|
let path = format!("/<wasm-module>/{}.wasm", module_name);
|
||||||
|
PathBuf::from(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WasmTypesDieRefs {
|
||||||
|
vmctx: write::UnitEntryId,
|
||||||
|
i32: write::UnitEntryId,
|
||||||
|
i64: write::UnitEntryId,
|
||||||
|
f32: write::UnitEntryId,
|
||||||
|
f64: write::UnitEntryId,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_wasm_types(
|
||||||
|
unit: &mut write::Unit,
|
||||||
|
root_id: write::UnitEntryId,
|
||||||
|
out_strings: &mut write::StringTable,
|
||||||
|
vmctx_info: &ModuleVmctxInfo,
|
||||||
|
) -> WasmTypesDieRefs {
|
||||||
|
let (_wp_die_id, vmctx_die_id) = add_internal_types(unit, root_id, out_strings, vmctx_info);
|
||||||
|
|
||||||
|
macro_rules! def_type {
|
||||||
|
($id:literal, $size:literal, $enc:path) => {{
|
||||||
|
let die_id = unit.add(root_id, gimli::DW_TAG_base_type);
|
||||||
|
let die = unit.get_mut(die_id);
|
||||||
|
die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add($id)),
|
||||||
|
);
|
||||||
|
die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1($size));
|
||||||
|
die.set(gimli::DW_AT_encoding, write::AttributeValue::Encoding($enc));
|
||||||
|
die_id
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
let i32_die_id = def_type!("i32", 4, gimli::DW_ATE_signed);
|
||||||
|
let i64_die_id = def_type!("i64", 8, gimli::DW_ATE_signed);
|
||||||
|
let f32_die_id = def_type!("f32", 4, gimli::DW_ATE_float);
|
||||||
|
let f64_die_id = def_type!("f64", 8, gimli::DW_ATE_float);
|
||||||
|
|
||||||
|
WasmTypesDieRefs {
|
||||||
|
vmctx: vmctx_die_id,
|
||||||
|
i32: i32_die_id,
|
||||||
|
i64: i64_die_id,
|
||||||
|
f32: f32_die_id,
|
||||||
|
f64: f64_die_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_var_type(
|
||||||
|
index: usize,
|
||||||
|
wasm_types: &WasmTypesDieRefs,
|
||||||
|
func_meta: &FunctionMetadata,
|
||||||
|
) -> Option<(write::UnitEntryId, bool)> {
|
||||||
|
let (ty, is_param) = if index < func_meta.params.len() {
|
||||||
|
(func_meta.params[index], true)
|
||||||
|
} else {
|
||||||
|
let mut i = (index - func_meta.params.len()) as u32;
|
||||||
|
let mut j = 0;
|
||||||
|
while j < func_meta.locals.len() && i >= func_meta.locals[j].0 {
|
||||||
|
i -= func_meta.locals[j].0;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
if j >= func_meta.locals.len() {
|
||||||
|
// Ignore the var index out of bound.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
(func_meta.locals[j].1, false)
|
||||||
|
};
|
||||||
|
let type_die_id = match ty {
|
||||||
|
WasmType::I32 => wasm_types.i32,
|
||||||
|
WasmType::I64 => wasm_types.i64,
|
||||||
|
WasmType::F32 => wasm_types.f32,
|
||||||
|
WasmType::F64 => wasm_types.f64,
|
||||||
|
_ => {
|
||||||
|
// Ignore unsupported types.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some((type_die_id, is_param))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_vars(
|
||||||
|
unit: &mut write::Unit,
|
||||||
|
die_id: write::UnitEntryId,
|
||||||
|
addr_tr: &AddressTransform,
|
||||||
|
frame_info: &FunctionFrameInfo,
|
||||||
|
scope_ranges: &[(u64, u64)],
|
||||||
|
wasm_types: &WasmTypesDieRefs,
|
||||||
|
func_meta: &FunctionMetadata,
|
||||||
|
locals_names: Option<&HashMap<u32, String>>,
|
||||||
|
out_strings: &mut write::StringTable,
|
||||||
|
) {
|
||||||
|
let vmctx_label = get_vmctx_value_label();
|
||||||
|
|
||||||
|
for (label, _range) in frame_info.value_ranges {
|
||||||
|
if label.index() == vmctx_label.index() {
|
||||||
|
append_vmctx_info(
|
||||||
|
unit,
|
||||||
|
die_id,
|
||||||
|
wasm_types.vmctx,
|
||||||
|
addr_tr,
|
||||||
|
Some(frame_info),
|
||||||
|
scope_ranges,
|
||||||
|
out_strings,
|
||||||
|
)
|
||||||
|
.expect("append_vmctx_info success");
|
||||||
|
} else {
|
||||||
|
let var_index = label.index();
|
||||||
|
let (type_die_id, is_param) =
|
||||||
|
if let Some(result) = resolve_var_type(var_index, wasm_types, func_meta) {
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
// Skipping if type of local cannot be detected.
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let loc_list_id = {
|
||||||
|
let endian = gimli::RunTimeEndian::Little;
|
||||||
|
|
||||||
|
let expr = CompiledExpression::from_label(label.clone());
|
||||||
|
let mut locs = Vec::new();
|
||||||
|
for (begin, length, data) in
|
||||||
|
expr.build_with_locals(scope_ranges, addr_tr, Some(frame_info), endian)
|
||||||
|
{
|
||||||
|
locs.push(write::Location::StartLength {
|
||||||
|
begin,
|
||||||
|
length,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
unit.locations.add(write::LocationList(locs))
|
||||||
|
};
|
||||||
|
|
||||||
|
let var_id = unit.add(
|
||||||
|
die_id,
|
||||||
|
if is_param {
|
||||||
|
gimli::DW_TAG_formal_parameter
|
||||||
|
} else {
|
||||||
|
gimli::DW_TAG_variable
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let var = unit.get_mut(var_id);
|
||||||
|
|
||||||
|
let name_id = match locals_names.and_then(|m| m.get(&(var_index as u32))) {
|
||||||
|
Some(n) => out_strings.add(n.to_owned()),
|
||||||
|
None => out_strings.add(format!("var{}", var_index)),
|
||||||
|
};
|
||||||
|
|
||||||
|
var.set(gimli::DW_AT_name, write::AttributeValue::StringRef(name_id));
|
||||||
|
var.set(
|
||||||
|
gimli::DW_AT_type,
|
||||||
|
write::AttributeValue::ThisUnitEntryRef(type_die_id),
|
||||||
|
);
|
||||||
|
var.set(
|
||||||
|
gimli::DW_AT_location,
|
||||||
|
write::AttributeValue::LocationListRef(loc_list_id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_simulated_dwarf(
|
||||||
|
addr_tr: &AddressTransform,
|
||||||
|
di: &DebugInfoData,
|
||||||
|
vmctx_info: &ModuleVmctxInfo,
|
||||||
|
ranges: &ValueLabelsRanges,
|
||||||
|
translated: &HashSet<u32>,
|
||||||
|
out_encoding: &gimli::Encoding,
|
||||||
|
out_units: &mut write::UnitTable,
|
||||||
|
out_strings: &mut write::StringTable,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let path = di
|
||||||
|
.wasm_file
|
||||||
|
.path
|
||||||
|
.to_owned()
|
||||||
|
.unwrap_or_else(|| autogenerate_dwarf_wasm_path(di));
|
||||||
|
|
||||||
|
let (func_names, locals_names) = if let Some(ref name_section) = di.name_section {
|
||||||
|
(
|
||||||
|
Some(&name_section.func_names),
|
||||||
|
Some(&name_section.locals_names),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (unit, root_id, name_id) = {
|
||||||
|
let comp_dir_id = out_strings.add(path.parent().expect("path dir").to_str().unwrap());
|
||||||
|
let name = path.file_name().expect("path name").to_str().unwrap();
|
||||||
|
let name_id = out_strings.add(name);
|
||||||
|
|
||||||
|
let out_program = generate_line_info(
|
||||||
|
addr_tr,
|
||||||
|
translated,
|
||||||
|
out_encoding,
|
||||||
|
&di.wasm_file,
|
||||||
|
comp_dir_id,
|
||||||
|
name_id,
|
||||||
|
name,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let unit_id = out_units.add(write::Unit::new(*out_encoding, out_program));
|
||||||
|
let unit = out_units.get_mut(unit_id);
|
||||||
|
|
||||||
|
let root_id = unit.root();
|
||||||
|
let root = unit.get_mut(root_id);
|
||||||
|
|
||||||
|
let id = out_strings.add(PRODUCER_NAME);
|
||||||
|
root.set(gimli::DW_AT_producer, write::AttributeValue::StringRef(id));
|
||||||
|
root.set(gimli::DW_AT_name, write::AttributeValue::StringRef(name_id));
|
||||||
|
root.set(
|
||||||
|
gimli::DW_AT_stmt_list,
|
||||||
|
write::AttributeValue::LineProgramRef,
|
||||||
|
);
|
||||||
|
root.set(
|
||||||
|
gimli::DW_AT_comp_dir,
|
||||||
|
write::AttributeValue::StringRef(comp_dir_id),
|
||||||
|
);
|
||||||
|
(unit, root_id, name_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
let wasm_types = add_wasm_types(unit, root_id, out_strings, vmctx_info);
|
||||||
|
|
||||||
|
for (i, map) in addr_tr.map().iter() {
|
||||||
|
let index = i.index();
|
||||||
|
if translated.contains(&(index as u32)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = map.offset as u64;
|
||||||
|
let end = start + map.len as u64;
|
||||||
|
let die_id = unit.add(root_id, gimli::DW_TAG_subprogram);
|
||||||
|
let die = unit.get_mut(die_id);
|
||||||
|
die.set(
|
||||||
|
gimli::DW_AT_low_pc,
|
||||||
|
write::AttributeValue::Address(write::Address::Symbol {
|
||||||
|
symbol: index,
|
||||||
|
addend: start as i64,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
die.set(
|
||||||
|
gimli::DW_AT_high_pc,
|
||||||
|
write::AttributeValue::Udata((end - start) as u64),
|
||||||
|
);
|
||||||
|
|
||||||
|
let id = match func_names.and_then(|m| m.get(&(index as u32))) {
|
||||||
|
Some(n) => out_strings.add(n.to_owned()),
|
||||||
|
None => out_strings.add(format!("wasm-function[{}]", index)),
|
||||||
|
};
|
||||||
|
|
||||||
|
die.set(gimli::DW_AT_name, write::AttributeValue::StringRef(id));
|
||||||
|
|
||||||
|
die.set(
|
||||||
|
gimli::DW_AT_decl_file,
|
||||||
|
write::AttributeValue::StringRef(name_id),
|
||||||
|
);
|
||||||
|
|
||||||
|
let f = addr_tr.map().get(i).unwrap();
|
||||||
|
let f_start = f.addresses[0].wasm;
|
||||||
|
let wasm_offset = di.wasm_file.code_section_offset + f_start as u64;
|
||||||
|
die.set(
|
||||||
|
gimli::DW_AT_decl_file,
|
||||||
|
write::AttributeValue::Udata(wasm_offset),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(frame_info) = get_function_frame_info(vmctx_info, i, ranges) {
|
||||||
|
let source_range = addr_tr.func_source_range(i);
|
||||||
|
generate_vars(
|
||||||
|
unit,
|
||||||
|
die_id,
|
||||||
|
addr_tr,
|
||||||
|
&frame_info,
|
||||||
|
&[(source_range.0, source_range.1)],
|
||||||
|
&wasm_types,
|
||||||
|
&di.wasm_file.funcs[index],
|
||||||
|
locals_names.and_then(|m| m.get(&(index as u32))),
|
||||||
|
out_strings,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use cranelift_wasm::DefinedFuncIndex;
|
use cranelift_entity::EntityRef;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges};
|
use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges};
|
||||||
|
|
||||||
use gimli;
|
use gimli;
|
||||||
@@ -11,9 +11,10 @@ use gimli::write;
|
|||||||
|
|
||||||
use super::address_transform::AddressTransform;
|
use super::address_transform::AddressTransform;
|
||||||
use super::attr::{clone_die_attributes, FileAttributeContext};
|
use super::attr::{clone_die_attributes, FileAttributeContext};
|
||||||
use super::expression::{compile_expression, CompiledExpression, FunctionFrameInfo};
|
use super::expression::compile_expression;
|
||||||
use super::line_program::clone_line_program;
|
use super::line_program::clone_line_program;
|
||||||
use super::range_info_builder::RangeInfoBuilder;
|
use super::range_info_builder::RangeInfoBuilder;
|
||||||
|
use super::utils::{add_internal_types, append_vmctx_info, get_function_frame_info};
|
||||||
use super::{DebugInputContext, Reader, TransformError};
|
use super::{DebugInputContext, Reader, TransformError};
|
||||||
|
|
||||||
pub(crate) type PendingDieRef = (write::UnitEntryId, gimli::DwAt, UnitOffset);
|
pub(crate) type PendingDieRef = (write::UnitEntryId, gimli::DwAt, UnitOffset);
|
||||||
@@ -46,109 +47,6 @@ impl<T> InheritedAttr<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_function_frame_info<'a, 'b, 'c>(
|
|
||||||
module_info: &'b ModuleVmctxInfo,
|
|
||||||
func_index: DefinedFuncIndex,
|
|
||||||
value_ranges: &'c ValueLabelsRanges,
|
|
||||||
) -> Option<FunctionFrameInfo<'a>>
|
|
||||||
where
|
|
||||||
'b: 'a,
|
|
||||||
'c: 'a,
|
|
||||||
{
|
|
||||||
if let Some(value_ranges) = value_ranges.get(func_index) {
|
|
||||||
let frame_info = FunctionFrameInfo {
|
|
||||||
value_ranges,
|
|
||||||
memory_offset: module_info.memory_offset,
|
|
||||||
stack_slots: &module_info.stack_slots[func_index],
|
|
||||||
};
|
|
||||||
Some(frame_info)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_internal_types(
|
|
||||||
comp_unit: &mut write::Unit,
|
|
||||||
root_id: write::UnitEntryId,
|
|
||||||
out_strings: &mut write::StringTable,
|
|
||||||
module_info: &ModuleVmctxInfo,
|
|
||||||
) -> (write::UnitEntryId, write::UnitEntryId) {
|
|
||||||
let wp_die_id = comp_unit.add(root_id, gimli::DW_TAG_base_type);
|
|
||||||
let wp_die = comp_unit.get_mut(wp_die_id);
|
|
||||||
wp_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("WebAssemblyPtr")),
|
|
||||||
);
|
|
||||||
wp_die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1(4));
|
|
||||||
wp_die.set(
|
|
||||||
gimli::DW_AT_encoding,
|
|
||||||
write::AttributeValue::Encoding(gimli::DW_ATE_unsigned),
|
|
||||||
);
|
|
||||||
|
|
||||||
let memory_byte_die_id = comp_unit.add(root_id, gimli::DW_TAG_base_type);
|
|
||||||
let memory_byte_die = comp_unit.get_mut(memory_byte_die_id);
|
|
||||||
memory_byte_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("u8")),
|
|
||||||
);
|
|
||||||
memory_byte_die.set(
|
|
||||||
gimli::DW_AT_encoding,
|
|
||||||
write::AttributeValue::Encoding(gimli::DW_ATE_unsigned),
|
|
||||||
);
|
|
||||||
memory_byte_die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1(1));
|
|
||||||
|
|
||||||
let memory_bytes_die_id = comp_unit.add(root_id, gimli::DW_TAG_pointer_type);
|
|
||||||
let memory_bytes_die = comp_unit.get_mut(memory_bytes_die_id);
|
|
||||||
memory_bytes_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("u8*")),
|
|
||||||
);
|
|
||||||
memory_bytes_die.set(
|
|
||||||
gimli::DW_AT_type,
|
|
||||||
write::AttributeValue::ThisUnitEntryRef(memory_byte_die_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
let memory_offset = module_info.memory_offset;
|
|
||||||
let vmctx_die_id = comp_unit.add(root_id, gimli::DW_TAG_structure_type);
|
|
||||||
let vmctx_die = comp_unit.get_mut(vmctx_die_id);
|
|
||||||
vmctx_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("WasmtimeVMContext")),
|
|
||||||
);
|
|
||||||
vmctx_die.set(
|
|
||||||
gimli::DW_AT_byte_size,
|
|
||||||
write::AttributeValue::Data4(memory_offset as u32 + 8),
|
|
||||||
);
|
|
||||||
|
|
||||||
let m_die_id = comp_unit.add(vmctx_die_id, gimli::DW_TAG_member);
|
|
||||||
let m_die = comp_unit.get_mut(m_die_id);
|
|
||||||
m_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("memory")),
|
|
||||||
);
|
|
||||||
m_die.set(
|
|
||||||
gimli::DW_AT_type,
|
|
||||||
write::AttributeValue::ThisUnitEntryRef(memory_bytes_die_id),
|
|
||||||
);
|
|
||||||
m_die.set(
|
|
||||||
gimli::DW_AT_data_member_location,
|
|
||||||
write::AttributeValue::Udata(memory_offset as u64),
|
|
||||||
);
|
|
||||||
|
|
||||||
let vmctx_ptr_die_id = comp_unit.add(root_id, gimli::DW_TAG_pointer_type);
|
|
||||||
let vmctx_ptr_die = comp_unit.get_mut(vmctx_ptr_die_id);
|
|
||||||
vmctx_ptr_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("WasmtimeVMContext*")),
|
|
||||||
);
|
|
||||||
vmctx_ptr_die.set(
|
|
||||||
gimli::DW_AT_type,
|
|
||||||
write::AttributeValue::ThisUnitEntryRef(vmctx_die_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
(wp_die_id, vmctx_ptr_die_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_base_type_name<R>(
|
fn get_base_type_name<R>(
|
||||||
type_entry: &DebuggingInformationEntry<R>,
|
type_entry: &DebuggingInformationEntry<R>,
|
||||||
unit: &Unit<R, R::Offset>,
|
unit: &Unit<R, R::Offset>,
|
||||||
@@ -252,48 +150,6 @@ where
|
|||||||
Ok(die_id)
|
Ok(die_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_vmctx_info(
|
|
||||||
comp_unit: &mut write::Unit,
|
|
||||||
parent_id: write::UnitEntryId,
|
|
||||||
vmctx_die_id: write::UnitEntryId,
|
|
||||||
addr_tr: &AddressTransform,
|
|
||||||
frame_info: Option<&FunctionFrameInfo>,
|
|
||||||
scope_ranges: &[(u64, u64)],
|
|
||||||
out_strings: &mut write::StringTable,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let loc = {
|
|
||||||
let endian = gimli::RunTimeEndian::Little;
|
|
||||||
|
|
||||||
let expr = CompiledExpression::vmctx();
|
|
||||||
let mut locs = Vec::new();
|
|
||||||
for (begin, length, data) in
|
|
||||||
expr.build_with_locals(scope_ranges, addr_tr, frame_info, endian)
|
|
||||||
{
|
|
||||||
locs.push(write::Location::StartLength {
|
|
||||||
begin,
|
|
||||||
length,
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let list_id = comp_unit.locations.add(write::LocationList(locs));
|
|
||||||
write::AttributeValue::LocationListRef(list_id)
|
|
||||||
};
|
|
||||||
|
|
||||||
let var_die_id = comp_unit.add(parent_id, gimli::DW_TAG_variable);
|
|
||||||
let var_die = comp_unit.get_mut(var_die_id);
|
|
||||||
var_die.set(
|
|
||||||
gimli::DW_AT_name,
|
|
||||||
write::AttributeValue::StringRef(out_strings.add("__vmctx")),
|
|
||||||
);
|
|
||||||
var_die.set(
|
|
||||||
gimli::DW_AT_type,
|
|
||||||
write::AttributeValue::ThisUnitEntryRef(vmctx_die_id),
|
|
||||||
);
|
|
||||||
var_die.set(gimli::DW_AT_location, loc);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clone_unit<'a, R>(
|
pub(crate) fn clone_unit<'a, R>(
|
||||||
unit: Unit<R, R::Offset>,
|
unit: Unit<R, R::Offset>,
|
||||||
context: &DebugInputContext<R>,
|
context: &DebugInputContext<R>,
|
||||||
@@ -303,6 +159,7 @@ pub(crate) fn clone_unit<'a, R>(
|
|||||||
module_info: &ModuleVmctxInfo,
|
module_info: &ModuleVmctxInfo,
|
||||||
out_units: &mut write::UnitTable,
|
out_units: &mut write::UnitTable,
|
||||||
out_strings: &mut write::StringTable,
|
out_strings: &mut write::StringTable,
|
||||||
|
translated: &mut HashSet<u32>,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
R: Reader,
|
R: Reader,
|
||||||
@@ -414,6 +271,7 @@ where
|
|||||||
{
|
{
|
||||||
current_value_range.push(new_stack_len, frame_info);
|
current_value_range.push(new_stack_len, frame_info);
|
||||||
}
|
}
|
||||||
|
translated.insert(func_index.index() as u32);
|
||||||
current_scope_ranges.push(new_stack_len, range_builder.get_ranges(addr_tr));
|
current_scope_ranges.push(new_stack_len, range_builder.get_ranges(addr_tr));
|
||||||
Some(range_builder)
|
Some(range_builder)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
154
wasmtime-debug/src/transform/utils.rs
Normal file
154
wasmtime-debug/src/transform/utils.rs
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
use cranelift_wasm::DefinedFuncIndex;
|
||||||
|
use failure::Error;
|
||||||
|
use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges};
|
||||||
|
|
||||||
|
use gimli;
|
||||||
|
use gimli::write;
|
||||||
|
|
||||||
|
use super::address_transform::AddressTransform;
|
||||||
|
use super::expression::{CompiledExpression, FunctionFrameInfo};
|
||||||
|
|
||||||
|
pub(crate) fn add_internal_types(
|
||||||
|
comp_unit: &mut write::Unit,
|
||||||
|
root_id: write::UnitEntryId,
|
||||||
|
out_strings: &mut write::StringTable,
|
||||||
|
module_info: &ModuleVmctxInfo,
|
||||||
|
) -> (write::UnitEntryId, write::UnitEntryId) {
|
||||||
|
let wp_die_id = comp_unit.add(root_id, gimli::DW_TAG_base_type);
|
||||||
|
let wp_die = comp_unit.get_mut(wp_die_id);
|
||||||
|
wp_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("WebAssemblyPtr")),
|
||||||
|
);
|
||||||
|
wp_die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1(4));
|
||||||
|
wp_die.set(
|
||||||
|
gimli::DW_AT_encoding,
|
||||||
|
write::AttributeValue::Encoding(gimli::DW_ATE_unsigned),
|
||||||
|
);
|
||||||
|
|
||||||
|
let memory_byte_die_id = comp_unit.add(root_id, gimli::DW_TAG_base_type);
|
||||||
|
let memory_byte_die = comp_unit.get_mut(memory_byte_die_id);
|
||||||
|
memory_byte_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("u8")),
|
||||||
|
);
|
||||||
|
memory_byte_die.set(
|
||||||
|
gimli::DW_AT_encoding,
|
||||||
|
write::AttributeValue::Encoding(gimli::DW_ATE_unsigned),
|
||||||
|
);
|
||||||
|
memory_byte_die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1(1));
|
||||||
|
|
||||||
|
let memory_bytes_die_id = comp_unit.add(root_id, gimli::DW_TAG_pointer_type);
|
||||||
|
let memory_bytes_die = comp_unit.get_mut(memory_bytes_die_id);
|
||||||
|
memory_bytes_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("u8*")),
|
||||||
|
);
|
||||||
|
memory_bytes_die.set(
|
||||||
|
gimli::DW_AT_type,
|
||||||
|
write::AttributeValue::ThisUnitEntryRef(memory_byte_die_id),
|
||||||
|
);
|
||||||
|
|
||||||
|
let memory_offset = module_info.memory_offset;
|
||||||
|
let vmctx_die_id = comp_unit.add(root_id, gimli::DW_TAG_structure_type);
|
||||||
|
let vmctx_die = comp_unit.get_mut(vmctx_die_id);
|
||||||
|
vmctx_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("WasmtimeVMContext")),
|
||||||
|
);
|
||||||
|
vmctx_die.set(
|
||||||
|
gimli::DW_AT_byte_size,
|
||||||
|
write::AttributeValue::Data4(memory_offset as u32 + 8),
|
||||||
|
);
|
||||||
|
|
||||||
|
let m_die_id = comp_unit.add(vmctx_die_id, gimli::DW_TAG_member);
|
||||||
|
let m_die = comp_unit.get_mut(m_die_id);
|
||||||
|
m_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("memory")),
|
||||||
|
);
|
||||||
|
m_die.set(
|
||||||
|
gimli::DW_AT_type,
|
||||||
|
write::AttributeValue::ThisUnitEntryRef(memory_bytes_die_id),
|
||||||
|
);
|
||||||
|
m_die.set(
|
||||||
|
gimli::DW_AT_data_member_location,
|
||||||
|
write::AttributeValue::Udata(memory_offset as u64),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vmctx_ptr_die_id = comp_unit.add(root_id, gimli::DW_TAG_pointer_type);
|
||||||
|
let vmctx_ptr_die = comp_unit.get_mut(vmctx_ptr_die_id);
|
||||||
|
vmctx_ptr_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("WasmtimeVMContext*")),
|
||||||
|
);
|
||||||
|
vmctx_ptr_die.set(
|
||||||
|
gimli::DW_AT_type,
|
||||||
|
write::AttributeValue::ThisUnitEntryRef(vmctx_die_id),
|
||||||
|
);
|
||||||
|
|
||||||
|
(wp_die_id, vmctx_ptr_die_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn append_vmctx_info(
|
||||||
|
comp_unit: &mut write::Unit,
|
||||||
|
parent_id: write::UnitEntryId,
|
||||||
|
vmctx_die_id: write::UnitEntryId,
|
||||||
|
addr_tr: &AddressTransform,
|
||||||
|
frame_info: Option<&FunctionFrameInfo>,
|
||||||
|
scope_ranges: &[(u64, u64)],
|
||||||
|
out_strings: &mut write::StringTable,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let loc = {
|
||||||
|
let endian = gimli::RunTimeEndian::Little;
|
||||||
|
|
||||||
|
let expr = CompiledExpression::vmctx();
|
||||||
|
let mut locs = Vec::new();
|
||||||
|
for (begin, length, data) in
|
||||||
|
expr.build_with_locals(scope_ranges, addr_tr, frame_info, endian)
|
||||||
|
{
|
||||||
|
locs.push(write::Location::StartLength {
|
||||||
|
begin,
|
||||||
|
length,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let list_id = comp_unit.locations.add(write::LocationList(locs));
|
||||||
|
write::AttributeValue::LocationListRef(list_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
let var_die_id = comp_unit.add(parent_id, gimli::DW_TAG_variable);
|
||||||
|
let var_die = comp_unit.get_mut(var_die_id);
|
||||||
|
var_die.set(
|
||||||
|
gimli::DW_AT_name,
|
||||||
|
write::AttributeValue::StringRef(out_strings.add("__vmctx")),
|
||||||
|
);
|
||||||
|
var_die.set(
|
||||||
|
gimli::DW_AT_type,
|
||||||
|
write::AttributeValue::ThisUnitEntryRef(vmctx_die_id),
|
||||||
|
);
|
||||||
|
var_die.set(gimli::DW_AT_location, loc);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_function_frame_info<'a, 'b, 'c>(
|
||||||
|
module_info: &'b ModuleVmctxInfo,
|
||||||
|
func_index: DefinedFuncIndex,
|
||||||
|
value_ranges: &'c ValueLabelsRanges,
|
||||||
|
) -> Option<FunctionFrameInfo<'a>>
|
||||||
|
where
|
||||||
|
'b: 'a,
|
||||||
|
'c: 'a,
|
||||||
|
{
|
||||||
|
if let Some(value_ranges) = value_ranges.get(func_index) {
|
||||||
|
let frame_info = FunctionFrameInfo {
|
||||||
|
value_ranges,
|
||||||
|
memory_offset: module_info.memory_offset,
|
||||||
|
stack_slots: &module_info.stack_slots[func_index],
|
||||||
|
};
|
||||||
|
Some(frame_info)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user