From efe9dd7b86026c63ca1fda601f1e8c068d214731 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 3 Jul 2019 16:58:35 -0500 Subject: [PATCH] Update gimli version; refactor debug data structures --- wasmtime-debug/Cargo.toml | 3 +- wasmtime-debug/src/address_transform.rs | 12 +- wasmtime-debug/src/lib.rs | 21 ++-- wasmtime-debug/src/transform.rs | 78 ++++++++----- wasmtime-debug/src/write_debuginfo.rs | 144 +++++++----------------- wasmtime-environ/Cargo.toml | 1 + wasmtime-environ/src/compilation.rs | 32 +----- wasmtime-environ/src/cranelift.rs | 18 ++- wasmtime-environ/src/lib.rs | 3 +- 9 files changed, 120 insertions(+), 192 deletions(-) diff --git a/wasmtime-debug/Cargo.toml b/wasmtime-debug/Cargo.toml index 6593347469..0b4cc292d0 100644 --- a/wasmtime-debug/Cargo.toml +++ b/wasmtime-debug/Cargo.toml @@ -12,13 +12,12 @@ readme = "README.md" edition = "2018" [dependencies] -gimli = "0.17.0" +gimli = "0.19.0" wasmparser = { version = "0.32.1" } cranelift-codegen = "0.33.0" cranelift-entity = "0.33.0" cranelift-wasm = "0.33.0" faerie = "0.10.1" -wasmtime-environ = { path = "../wasmtime-environ", default-features = false } target-lexicon = { version = "0.4.0", default-features = false } failure = { version = "0.1.3", default-features = false } failure_derive = { version = "0.1.3", default-features = false } diff --git a/wasmtime-debug/src/address_transform.rs b/wasmtime-debug/src/address_transform.rs index 595e76f5df..427b1f6825 100644 --- a/wasmtime-debug/src/address_transform.rs +++ b/wasmtime-debug/src/address_transform.rs @@ -1,11 +1,11 @@ use crate::read_debuginfo::WasmFileInfo; +use crate::transform::ModuleAddressMap; use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_wasm::DefinedFuncIndex; use gimli::write; use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; use std::vec::Vec; -use wasmtime_environ::AddressTransforms; pub type GeneratedAddress = usize; pub type WasmAddress = u64; @@ -32,7 +32,7 @@ pub struct AddressTransform { } impl AddressTransform { - pub fn new(at: &AddressTransforms, wasm_file: &WasmFileInfo) -> Self { + pub fn new(at: &ModuleAddressMap, wasm_file: &WasmFileInfo) -> Self { let code_section_offset = wasm_file.code_section_offset; let function_offsets = &wasm_file.function_offsets_and_sizes; let mut lookup = BTreeMap::new(); @@ -50,7 +50,7 @@ impl AddressTransform { (index, ft.body_offset, ft.body_offset), ); let mut fn_map = Vec::new(); - for t in &ft.locations { + for t in &ft.instructions { if t.srcloc.is_default() { // TODO extend some range if possible continue; @@ -90,7 +90,7 @@ impl AddressTransform { } let search = self.lookup.range((Unbounded, Included(addr))); if let Some((_, value)) = search.last() { - return Some(write::Address::Relative { + return Some(write::Address::Symbol { symbol: value.0, addend: value.1 as i64, }); @@ -106,11 +106,11 @@ impl AddressTransform { return None; } if let ( - Some(write::Address::Relative { + Some(write::Address::Symbol { symbol: s1, addend: a, }), - Some(write::Address::Relative { + Some(write::Address::Symbol { symbol: s2, addend: b, }), diff --git a/wasmtime-debug/src/lib.rs b/wasmtime-debug/src/lib.rs index 0b2ee5fa44..49ff0c2840 100644 --- a/wasmtime-debug/src/lib.rs +++ b/wasmtime-debug/src/lib.rs @@ -4,12 +4,13 @@ use faerie::{Artifact, Decl}; use failure::Error; use target_lexicon::{BinaryFormat, Triple}; -pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData}; -pub use crate::transform::transform_dwarf; +pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData, WasmFileInfo}; +pub use crate::transform::{ + transform_dwarf, FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleVmctxInfo, + ValueLabelsRanges, +}; pub use crate::write_debuginfo::{emit_dwarf, ResolvedSymbol, SymbolResolver}; -use wasmtime_environ::AddressTransforms; - mod address_transform; mod read_debuginfo; mod transform; @@ -30,11 +31,11 @@ pub fn emit_debugsections( obj: &mut Artifact, target_config: &TargetFrontendConfig, debuginfo_data: &DebugInfoData, - at: &AddressTransforms, + at: &ModuleAddressMap, ) -> Result<(), Error> { - let dwarf = transform_dwarf(target_config, debuginfo_data, at)?; let resolver = FunctionRelocResolver {}; - emit_dwarf(obj, dwarf, &resolver); + let dwarf = transform_dwarf(target_config, debuginfo_data, at)?; + emit_dwarf(obj, dwarf, &resolver)?; Ok(()) } @@ -53,7 +54,7 @@ pub fn emit_debugsections_image( triple: Triple, target_config: &TargetFrontendConfig, debuginfo_data: &DebugInfoData, - at: &AddressTransforms, + at: &ModuleAddressMap, funcs: &Vec<(*const u8, usize)>, ) -> Result, Error> { let ref func_offsets = funcs @@ -61,8 +62,8 @@ pub fn emit_debugsections_image( .map(|(ptr, _)| *ptr as u64) .collect::>(); let mut obj = Artifact::new(triple, String::from("module")); - let dwarf = transform_dwarf(target_config, debuginfo_data, at)?; let resolver = ImageRelocResolver { func_offsets }; + let dwarf = transform_dwarf(target_config, debuginfo_data, at)?; // Assuming all functions in the same code block, looking min/max of its range. assert!(funcs.len() > 0); @@ -76,7 +77,7 @@ pub fn emit_debugsections_image( let body = unsafe { ::std::slice::from_raw_parts(segment_body.0, segment_body.1) }; obj.declare_with("all", Decl::function(), body.to_vec())?; - emit_dwarf(&mut obj, dwarf, &resolver); + emit_dwarf(&mut obj, dwarf, &resolver)?; // LLDB is too "magical" about mach-o, generating elf let mut bytes = obj.emit_as(BinaryFormat::Elf)?; diff --git a/wasmtime-debug/src/transform.rs b/wasmtime-debug/src/transform.rs index 038be623b5..bb04b89323 100644 --- a/wasmtime-debug/src/transform.rs +++ b/wasmtime-debug/src/transform.rs @@ -1,7 +1,9 @@ use crate::address_transform::AddressTransform; pub use crate::read_debuginfo::DebugInfoData; +use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; -use cranelift_entity::EntityRef; +use cranelift_entity::{EntityRef, PrimaryMap}; +use cranelift_wasm::DefinedFuncIndex; use failure::Error; use std::collections::{BTreeMap, HashMap}; use std::ops::Bound::{Included, Unbounded}; @@ -24,14 +26,45 @@ impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where Endian: #[fail(display = "Debug info transform error: {}", _0)] pub struct TransformError(&'static str); -pub struct TransformedDwarf { - pub encoding: gimli::Encoding, - pub strings: write::StringTable, - pub units: write::UnitTable, - pub line_strings: write::LineStringTable, - pub range_lists: write::RangeListTable, +/// Single wasm source location to generated address mapping. +#[derive(Debug, Clone)] +pub struct InstructionAddressMap { + /// Original source location. + pub srcloc: ir::SourceLoc, + + /// Generated instructions offset. + pub code_offset: usize, + + /// Generated instructions length. + pub code_len: usize, } +/// Function and its instructions addresses mappings. +#[derive(Debug, Clone)] +pub struct FunctionAddressMap { + /// Instructions maps. + /// The array is sorted by the InstructionAddressMap::code_offset field. + pub instructions: Vec, + + /// Generated function body offset if applicable, otherwise 0. + pub body_offset: usize, + + /// Generated function body length. + pub body_len: usize, +} + +/// Module functions addresses mappings. +pub type ModuleAddressMap = PrimaryMap; + +/// Module `vmctx` related info. +pub struct ModuleVmctxInfo { + pub memory_offset: i64, + pub stack_slots: PrimaryMap, +} + +/// Value ranges for functions. +pub type ValueLabelsRanges = PrimaryMap; + struct DebugInputContext<'a, R> where R: Reader, @@ -84,7 +117,7 @@ where write::AttributeValue::Udata(subprogram_range.unwrap().1) } AttributeValue::Addr(u) => { - let addr = addr_tr.translate(u).unwrap_or(write::Address::Absolute(0)); + let addr = addr_tr.translate(u).unwrap_or(write::Address::Constant(0)); if attr.name() == gimli::DW_AT_low_pc { low_pc = Some((u, addr)); } @@ -370,7 +403,7 @@ where for (i, map) in addr_tr.map() { let symbol = i.index(); let base_addr = map.offset; - out_program.begin_sequence(Some(write::Address::Relative { symbol, addend: 0 })); + out_program.begin_sequence(Some(write::Address::Symbol { symbol, addend: 0 })); // TODO track and place function declaration line here let mut last_address = None; for addr_map in map.addresses.iter() { @@ -440,9 +473,9 @@ where let low_pc = entry.attr_value(gimli::DW_AT_low_pc)?; if let Some(AttributeValue::Addr(addr)) = low_pc { let transformed = addr_tr.translate(addr); - if let Some(write::Address::Relative { symbol, .. }) = transformed { + if let Some(write::Address::Symbol { symbol, .. }) = transformed { let range = addr_tr.func_range(symbol); - let addr = write::Address::Relative { + let addr = write::Address::Symbol { symbol, addend: range.0 as i64, }; @@ -580,8 +613,8 @@ where pub fn transform_dwarf( target_config: &TargetFrontendConfig, di: &DebugInfoData, - at: &wasmtime_environ::AddressTransforms, -) -> Result { + at: &ModuleAddressMap, +) -> Result { let context = DebugInputContext { debug_abbrev: &di.dwarf.debug_abbrev, debug_str: &di.dwarf.debug_str, @@ -605,7 +638,6 @@ pub fn transform_dwarf( let mut out_strings = write::StringTable::default(); let mut out_units = write::UnitTable::default(); - let out_range_lists = write::RangeListTable::default(); let out_line_strings = write::LineStringTable::default(); let mut iter = di.dwarf.debug_info.units(); @@ -620,22 +652,10 @@ pub fn transform_dwarf( )?; } - // let unit_range_list = write::RangeList(Vec::new()); - // let unit_range_list_id = out_range_lists.add(unit_range_list.clone()); - // let unit = dwarf.units.get_mut(self.unit_id); - // let root = unit.root(); - // let root = unit.get_mut(root); - // root.set( - // gimli::DW_AT_ranges, - // AttributeValue::RangeListRef(unit_range_list_id), - // ); - - //println!("{:?} \n====\n {:?}", di, at); - Ok(TransformedDwarf { - encoding: out_encoding, - strings: out_strings, + Ok(write::Dwarf { units: out_units, + line_programs: vec![], line_strings: out_line_strings, - range_lists: out_range_lists, + strings: out_strings, }) } diff --git a/wasmtime-debug/src/write_debuginfo.rs b/wasmtime-debug/src/write_debuginfo.rs index b4d7878995..6920472c3b 100644 --- a/wasmtime-debug/src/write_debuginfo.rs +++ b/wasmtime-debug/src/write_debuginfo.rs @@ -1,14 +1,11 @@ -use crate::transform::TransformedDwarf; - -use gimli::write::{ - Address, DebugAbbrev, DebugInfo, DebugLine, DebugLineStr, DebugRanges, DebugRngLists, DebugStr, - EndianVec, Result, SectionId, Sections, Writer, -}; -use gimli::RunTimeEndian; +use gimli::write::{Address, Dwarf, EndianVec, Result, Sections, Writer}; +use gimli::{RunTimeEndian, SectionId}; use faerie::artifact::{Decl, SectionKind}; use faerie::*; +use std::result; +#[derive(Clone)] struct DebugReloc { offset: u32, size: u8, @@ -16,38 +13,6 @@ struct DebugReloc { addend: i64, } -macro_rules! decl_section { - ($artifact:ident . $section:ident = $name:expr) => { - $artifact - .declare_with( - SectionId::$section.name(), - Decl::section(SectionKind::Debug), - $name.0.writer.into_vec(), - ) - .unwrap(); - }; -} - -macro_rules! sect_relocs { - ($artifact:ident . $section:ident = $name:expr) => { - for reloc in $name.0.relocs { - $artifact - .link_with( - faerie::Link { - from: SectionId::$section.name(), - to: &reloc.name, - at: u64::from(reloc.offset), - }, - faerie::Reloc::Debug { - size: reloc.size, - addend: reloc.addend as i32, - }, - ) - .expect("faerie relocation error"); - } - }; -} - pub enum ResolvedSymbol { PhysicalAddress(u64), Reloc { name: String, addend: i64 }, @@ -59,75 +24,48 @@ pub trait SymbolResolver { pub fn emit_dwarf( artifact: &mut Artifact, - mut dwarf: TransformedDwarf, + mut dwarf: Dwarf, symbol_resolver: &SymbolResolver, -) { +) -> result::Result<(), failure::Error> { let endian = RunTimeEndian::Little; - let debug_abbrev = DebugAbbrev::from(WriterRelocate::new(endian, symbol_resolver)); - let debug_info = DebugInfo::from(WriterRelocate::new(endian, symbol_resolver)); - let debug_str = DebugStr::from(WriterRelocate::new(endian, symbol_resolver)); - let debug_line = DebugLine::from(WriterRelocate::new(endian, symbol_resolver)); - let debug_ranges = DebugRanges::from(WriterRelocate::new(endian, symbol_resolver)); - let debug_rnglists = DebugRngLists::from(WriterRelocate::new(endian, symbol_resolver)); - let debug_line_str = DebugLineStr::from(WriterRelocate::new(endian, symbol_resolver)); - let mut sections = Sections { - debug_abbrev, - debug_info, - debug_line, - debug_line_str, - debug_ranges, - debug_rnglists, - debug_str, - }; - - let debug_str_offsets = dwarf.strings.write(&mut sections.debug_str).unwrap(); - let debug_line_str_offsets = dwarf - .line_strings - .write(&mut sections.debug_line_str) - .unwrap(); - dwarf - .units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - decl_section!(artifact.DebugAbbrev = sections.debug_abbrev); - decl_section!(artifact.DebugInfo = sections.debug_info); - decl_section!(artifact.DebugStr = sections.debug_str); - decl_section!(artifact.DebugLine = sections.debug_line); - - let debug_ranges_not_empty = !sections.debug_ranges.0.writer.slice().is_empty(); - if debug_ranges_not_empty { - decl_section!(artifact.DebugRanges = sections.debug_ranges); - } - - let debug_rnglists_not_empty = !sections.debug_rnglists.0.writer.slice().is_empty(); - if debug_rnglists_not_empty { - decl_section!(artifact.DebugRngLists = sections.debug_rnglists); - } - - sect_relocs!(artifact.DebugAbbrev = sections.debug_abbrev); - sect_relocs!(artifact.DebugInfo = sections.debug_info); - sect_relocs!(artifact.DebugStr = sections.debug_str); - sect_relocs!(artifact.DebugLine = sections.debug_line); - - if debug_ranges_not_empty { - sect_relocs!(artifact.DebugRanges = sections.debug_ranges); - } - - if debug_rnglists_not_empty { - sect_relocs!(artifact.DebugRngLists = sections.debug_rnglists); - } + let mut sections = Sections::new(WriterRelocate::new(endian, symbol_resolver)); + dwarf.write(&mut sections)?; + sections.for_each_mut(|id, s| -> result::Result<(), failure::Error> { + artifact.declare_with( + id.name(), + Decl::section(SectionKind::Debug), + s.writer.take(), + ) + })?; + sections.for_each_mut(|id, s| -> result::Result<(), failure::Error> { + for reloc in &s.relocs { + artifact.link_with( + faerie::Link { + from: id.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + )?; + } + Ok(()) + })?; + Ok(()) } -struct WriterRelocate<'a> { +#[derive(Clone)] +pub struct WriterRelocate<'a> { relocs: Vec, writer: EndianVec, symbol_resolver: &'a SymbolResolver, } impl<'a> WriterRelocate<'a> { - fn new(endian: RunTimeEndian, symbol_resolver: &'a SymbolResolver) -> Self { + pub fn new(endian: RunTimeEndian, symbol_resolver: &'a SymbolResolver) -> Self { WriterRelocate { relocs: Vec::new(), writer: EndianVec::new(endian), @@ -157,10 +95,10 @@ impl<'a> Writer for WriterRelocate<'a> { fn write_address(&mut self, address: Address, size: u8) -> Result<()> { match address { - Address::Absolute(val) => self.write_word(val, size), - Address::Relative { symbol, addend } => { + Address::Constant(val) => self.write_udata(val, size), + Address::Symbol { symbol, addend } => { match self.symbol_resolver.resolve_symbol(symbol, addend as i64) { - ResolvedSymbol::PhysicalAddress(addr) => self.write_word(addr, size), + ResolvedSymbol::PhysicalAddress(addr) => self.write_udata(addr, size), ResolvedSymbol::Reloc { name, addend } => { let offset = self.len() as u64; self.relocs.push(DebugReloc { @@ -169,7 +107,7 @@ impl<'a> Writer for WriterRelocate<'a> { name, addend, }); - self.write_word(addend as u64, size) + self.write_udata(addend as u64, size) } } } @@ -185,7 +123,7 @@ impl<'a> Writer for WriterRelocate<'a> { name, addend: val as i64, }); - self.write_word(val as u64, size) + self.write_udata(val as u64, size) } fn write_offset_at( @@ -202,6 +140,6 @@ impl<'a> Writer for WriterRelocate<'a> { name, addend: val as i64, }); - self.write_word_at(offset, val as u64, size) + self.write_udata_at(offset, val as u64, size) } } diff --git a/wasmtime-environ/Cargo.toml b/wasmtime-environ/Cargo.toml index ba7347aaaf..7e444e2637 100644 --- a/wasmtime-environ/Cargo.toml +++ b/wasmtime-environ/Cargo.toml @@ -20,6 +20,7 @@ failure = { version = "0.1.3", default-features = false } failure_derive = { version = "0.1.3", default-features = false } indexmap = "1.0.2" rayon = "1.0" +wasmtime-debug = { path = "../wasmtime-debug", default-features = false } [features] default = ["std"] diff --git a/wasmtime-environ/src/compilation.rs b/wasmtime-environ/src/compilation.rs index 1a130a5180..2bd7fc7d97 100644 --- a/wasmtime-environ/src/compilation.rs +++ b/wasmtime-environ/src/compilation.rs @@ -8,6 +8,7 @@ use cranelift_entity::PrimaryMap; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError}; use std::ops::Range; use std::vec::Vec; +use wasmtime_debug::ModuleAddressMap; /// Compiled machine code: body and jump table offsets. #[derive(Debug, Clone)] @@ -139,35 +140,6 @@ pub enum CompileError { Codegen(CodegenError), } -/// Single address point transform. -#[derive(Debug)] -pub struct InstructionAddressTransform { - /// Original source location. - pub srcloc: ir::SourceLoc, - - /// Generated instructions offset. - pub code_offset: usize, - - /// Generated instructions length. - pub code_len: usize, -} - -/// Function and its instructions transforms. -#[derive(Debug)] -pub struct FunctionAddressTransform { - /// Instructions transforms - pub locations: Vec, - - /// Generated function body offset if applicable, otherwise 0. - pub body_offset: usize, - - /// Generated function body length. - pub body_len: usize, -} - -/// Function AddressTransforms collection. -pub type AddressTransforms = PrimaryMap; - /// An implementation of a compiler from parsed WebAssembly module to native code. pub trait Compiler { /// Compile a parsed module with the given `TargetIsa`. @@ -176,5 +148,5 @@ pub trait Compiler { function_body_inputs: PrimaryMap>, isa: &dyn isa::TargetIsa, generate_debug_info: bool, - ) -> Result<(Compilation, Relocations, AddressTransforms), CompileError>; + ) -> Result<(Compilation, Relocations, ModuleAddressMap), CompileError>; } diff --git a/wasmtime-environ/src/cranelift.rs b/wasmtime-environ/src/cranelift.rs index 7c5e8e6190..9bf9686584 100644 --- a/wasmtime-environ/src/cranelift.rs +++ b/wasmtime-environ/src/cranelift.rs @@ -1,8 +1,7 @@ //! Support for compiling with Cranelift. use crate::compilation::{ - AddressTransforms, CodeAndJTOffsets, Compilation, CompileError, FunctionAddressTransform, - InstructionAddressTransform, Relocation, RelocationTarget, Relocations, + CodeAndJTOffsets, Compilation, CompileError, Relocation, RelocationTarget, Relocations, }; use crate::func_environ::{ get_func_name, get_imported_memory32_grow_name, get_imported_memory32_size_name, @@ -19,6 +18,7 @@ use cranelift_entity::PrimaryMap; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::vec::Vec; +use wasmtime_debug::{FunctionAddressMap, InstructionAddressMap, ModuleAddressMap}; /// Implementation of a relocation sink that just saves all the information for later pub struct RelocSink { @@ -89,10 +89,7 @@ impl RelocSink { } } -fn get_address_transform( - context: &Context, - isa: &isa::TargetIsa, -) -> Vec { +fn get_address_transform(context: &Context, isa: &isa::TargetIsa) -> Vec { let mut result = Vec::new(); let func = &context.func; @@ -103,7 +100,7 @@ fn get_address_transform( for ebb in ebbs { for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) { let srcloc = func.srclocs[inst]; - result.push(InstructionAddressTransform { + result.push(InstructionAddressMap { srcloc, code_offset: offset as usize, code_len: size as usize, @@ -125,7 +122,7 @@ impl crate::compilation::Compiler for Cranelift { function_body_inputs: PrimaryMap>, isa: &dyn isa::TargetIsa, generate_debug_info: bool, - ) -> Result<(Compilation, Relocations, AddressTransforms), CompileError> { + ) -> Result<(Compilation, Relocations, ModuleAddressMap), CompileError> { let mut functions = PrimaryMap::with_capacity(function_body_inputs.len()); let mut relocations = PrimaryMap::with_capacity(function_body_inputs.len()); let mut address_transforms = PrimaryMap::with_capacity(function_body_inputs.len()); @@ -162,8 +159,9 @@ impl crate::compilation::Compiler for Cranelift { let address_transform = if generate_debug_info { let body_len = code_buf.len(); let at = get_address_transform(&context, isa); - Some(FunctionAddressTransform { - locations: at, + + Some(FunctionAddressMap { + instructions: at, body_offset: 0, body_len, }) diff --git a/wasmtime-environ/src/lib.rs b/wasmtime-environ/src/lib.rs index 4c0d214fbf..7f35a9ba7b 100644 --- a/wasmtime-environ/src/lib.rs +++ b/wasmtime-environ/src/lib.rs @@ -49,8 +49,7 @@ pub mod cranelift; pub mod lightbeam; pub use crate::compilation::{ - AddressTransforms, Compilation, CompileError, Compiler, InstructionAddressTransform, - Relocation, RelocationTarget, Relocations, + Compilation, CompileError, Compiler, Relocation, RelocationTarget, Relocations, }; pub use crate::cranelift::Cranelift; #[cfg(feature = "lightbeam")]