diff --git a/Cargo.lock b/Cargo.lock index e484a5eed..514b12118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,7 +235,7 @@ dependencies = [ "cranelift-entity", "log", "smallvec 1.1.0", - "target-lexicon 0.9.0", + "target-lexicon", "thiserror", ] @@ -269,7 +269,7 @@ checksum = "21398a0bc6ba389ea86964ac4a495426dd61080f2ddd306184777a8560fe9976" dependencies = [ "cranelift-codegen", "raw-cpuid", - "target-lexicon 0.9.0", + "target-lexicon", ] [[package]] @@ -468,23 +468,7 @@ dependencies = [ "log", "scroll 0.10.1", "string-interner", - "target-lexicon 0.9.0", - "thiserror", -] - -[[package]] -name = "faerie" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b9ed6159e4a6212c61d9c6a86bee01876b192a64accecf58d5b5ae3b667b52" -dependencies = [ - "anyhow", - "goblin 0.1.3", - "indexmap", - "log", - "scroll 0.10.1", - "string-interner", - "target-lexicon 0.10.0", + "target-lexicon", "thiserror", ] @@ -1552,12 +1536,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4" -[[package]] -name = "target-lexicon" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" - [[package]] name = "tempfile" version = "3.1.0" @@ -1752,10 +1730,10 @@ version = "0.1.0" dependencies = [ "anyhow", "cranelift-entity", - "faerie 0.13.0", + "faerie", "gimli", "more-asserts", - "target-lexicon 0.9.0", + "target-lexicon", "thiserror", "wasmparser 0.39.3", ] @@ -1776,7 +1754,6 @@ dependencies = [ "typetag", "wabt", "wasmer-clif-backend", - "wasmer-debug-writer", "wasmer-dev-utils", "wasmer-emscripten", "wasmer-emscripten-tests", @@ -1807,7 +1784,7 @@ dependencies = [ "serde-bench", "serde_bytes", "serde_derive", - "target-lexicon 0.9.0", + "target-lexicon", "wasm-debug", "wasmer-clif-fork-frontend", "wasmer-clif-fork-wasm", @@ -1826,7 +1803,7 @@ dependencies = [ "cranelift-codegen", "log", "smallvec 1.1.0", - "target-lexicon 0.9.0", + "target-lexicon", ] [[package]] @@ -1843,18 +1820,6 @@ dependencies = [ "wasmparser 0.45.0", ] -[[package]] -name = "wasmer-debug-writer" -version = "0.13.1" -dependencies = [ - "faerie 0.14.0", - "gimli", - "target-lexicon 0.9.0", - "wasm-debug", - "wasmer-runtime-core", - "wasmparser 0.45.0", -] - [[package]] name = "wasmer-dev-utils" version = "0.13.1" @@ -2000,7 +1965,7 @@ dependencies = [ "serde_bytes", "serde_derive", "smallvec 0.6.13", - "target-lexicon 0.9.0", + "target-lexicon", "wasm-debug", "wasmparser 0.45.0", "winapi", diff --git a/Cargo.toml b/Cargo.toml index 652606384..8b74cd54c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,6 @@ wasmer-wasi-tests = { path = "lib/wasi-tests", optional = true } wasmer-middleware-common-tests = { path = "lib/middleware-common-tests", optional = true } wasmer-emscripten-tests = { path = "lib/emscripten-tests", optional = true } wasmer-wasi-experimental-io-devices = { path = "lib/wasi-experimental-io-devices", optional = true } -wasmer-debug-writer = { path = "lib/debug-writer", optional = true } [workspace] members = [ @@ -65,7 +64,6 @@ members = [ "lib/wasi-tests", "lib/emscripten-tests", "lib/middleware-common-tests", - "lib/debug-writer", "examples/parallel", "examples/plugin-for-example", "examples/parallel-guest", @@ -81,7 +79,7 @@ serde = { version = "1", features = ["derive"] } # used by the plugin example typetag = "0.1" # used by the plugin example [features] -default = ["fast-tests", "wasi", "backend-cranelift", "wabt", "wasmer-debug-writer"] +default = ["fast-tests", "wasi", "backend-cranelift", "wabt"] "loader-kernel" = ["wasmer-kernel-loader"] debug = ["fern", "log/max_level_debug", "log/release_max_level_debug"] trace = ["fern", "log/max_level_trace", "log/release_max_level_trace"] diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 4705b07a6..e78333f66 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -7,7 +7,7 @@ use crate::{ }; use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder, ValueLabel}; +use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder}; use cranelift_codegen::isa::CallConv; use cranelift_codegen::{cursor::FuncCursor, isa}; use cranelift_frontend::{FunctionBuilder, Position, Variable}; @@ -106,7 +106,10 @@ impl ModuleCodeGenerator end: loc.1, }; - func_env.func.collect_debug_info(); + let generate_debug_info = module_info.read().unwrap().generate_debug_info; + if generate_debug_info { + func_env.func.collect_debug_info(); + } debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty"); debug_assert_eq!(func_env.func.dfg.num_insts(), 0, "Function must be empty"); @@ -1107,7 +1110,12 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { Ok(()) } - fn feed_event(&mut self, event: Event, _module_info: &ModuleInfo, loc: u32) -> Result<(), CodegenError> { + fn feed_event( + &mut self, + event: Event, + _module_info: &ModuleInfo, + loc: u32, + ) -> Result<(), CodegenError> { let op = match event { Event::Wasm(x) => x, Event::WasmOwned(ref x) => x, @@ -1159,7 +1167,7 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { // // If the exit block is unreachable, it may not have the correct arguments, so we would // generate a return instruction that doesn't match the signature. - if state.reachable { + if state.reachable() { debug_assert!(builder.is_pristine()); if !builder.is_unreachable() { match return_mode { @@ -1247,11 +1255,11 @@ fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> u // This is a normal WebAssembly signature parameter, so create a local for it. let local = Variable::new(next_local); builder.declare_var(local, param_type.value_type); - let value_label = ValueLabel::from_u32(next_local as u32); + //let value_label = ValueLabel::from_u32(next_local as u32); next_local += 1; let param_value = builder.ebb_params(entry_block)[i]; - builder.set_val_label(param_value, value_label); + //builder.set_val_label(param_value, value_label); builder.def_var(local, param_value); } if param_type.purpose == ir::ArgumentPurpose::VMContext { diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index e039af433..a608ad504 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -10,10 +10,9 @@ use crate::{ }; use byteorder::{ByteOrder, LittleEndian}; use cranelift_codegen::{ - ValueLabelsRanges, binemit::{Stackmap, StackmapSink}, entity::PrimaryMap, - ir, isa, Context, + ir, isa, Context, ValueLabelsRanges, }; use rayon::prelude::*; use std::{ @@ -111,22 +110,21 @@ impl FuncResolverBuilder { let mut trap_sink = TrapSink::new(); - let fb = function_bodies.iter().collect::>(); - rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap(); + let generate_debug_info = info.generate_debug_info; + let fb = function_bodies.iter().collect::>(); let compiled_functions: Result< - Vec<(Vec, + Vec<( + Vec, ( LocalFuncIndex, - CompiledFunctionData, - ValueLabelsRanges, - Vec>, + Option<(CompiledFunctionData, ValueLabelsRanges, Vec>)>, RelocSink, LocalTrapSink, ), )>, CompileError, - > = fb + > = fb .par_iter() .map_init( || Context::new(), @@ -137,15 +135,6 @@ impl FuncResolverBuilder { let mut local_trap_sink = LocalTrapSink::new(); let mut stackmap_sink = NoopStackmapSink {}; - //ctx.eliminate_unreachable_code(isa).unwrap(); - /*ctx.dce(isa).unwrap(); - ctx.shrink_instructions(isa).unwrap(); - ctx.redundant_reload_remover(isa).unwrap(); - ctx.preopt(isa).unwrap(); - ctx.legalize(isa).unwrap(); - ctx.postopt(isa).unwrap();*/ - ctx.verify(isa).unwrap(); - ctx.compile_and_emit( isa, &mut code_buf, @@ -155,66 +144,68 @@ impl FuncResolverBuilder { ) .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; - // begin debug stuff - let func = &ctx.func; - let encinfo = isa.encoding_info(); - let mut ebbs = func.layout.ebbs().collect::>(); - ebbs.sort_by_key(|ebb| func.offsets[*ebb]); - let instructions = /*func - .layout - .ebbs()*/ - ebbs.into_iter() - .flat_map(|ebb| { - func.inst_offsets(ebb, &encinfo) - .map(|(offset, inst, length)| { - let srcloc = func.srclocs[inst]; - let val = srcloc.bits(); - wasm_debug::types::CompiledInstructionData { - // we write this data later - loc: wasm_debug::types::SourceLoc::new(val),//srcloc.bits()), - offset: offset as usize, - length: length as usize, - } - }) - }) - .collect::>(); + let debug_entry = if generate_debug_info { + let func = &ctx.func; + let encinfo = isa.encoding_info(); + let mut ebbs = func.layout.ebbs().collect::>(); + ebbs.sort_by_key(|ebb| func.offsets[*ebb]); + let instructions = ebbs + .into_iter() + .flat_map(|ebb| { + func.inst_offsets(ebb, &encinfo) + .map(|(offset, inst, length)| { + let srcloc = func.srclocs[inst]; + let val = srcloc.bits(); + wasm_debug::types::CompiledInstructionData { + loc: wasm_debug::types::SourceLoc::new(val), + offset: offset as usize, + length: length as usize, + } + }) + }) + .collect::>(); - /*let mut unwind = vec![]; - ctx.emit_unwind_info(isa, &mut unwind); - dbg!(unwind.len());*/ + /*let mut unwind = vec![]; + ctx.emit_unwind_info(isa, &mut unwind); + dbg!(unwind.len());*/ - let stack_slots = ctx.func.stack_slots.iter().map(|(_, ssd)| ssd.offset).collect::>>(); - let labels_ranges = ctx.build_value_labels_ranges(isa).unwrap_or_default(); - if labels_ranges.len() == 24 || labels_ranges.len() == 25 { - let mut vec = labels_ranges.iter().map(|(a,b)| (*a, b.clone())).collect::>(); - vec.sort_by(|a, b| a.0.as_u32().cmp(&b.0.as_u32())); - dbg!(labels_ranges.len(), &vec); - } + let stack_slots = ctx + .func + .stack_slots + .iter() + .map(|(_, ssd)| ssd.offset) + .collect::>>(); + let labels_ranges = ctx.build_value_labels_ranges(isa).unwrap_or_default(); - let entry = CompiledFunctionData { - instructions, - start: wasm_debug::types::SourceLoc::new(*start), - end: wasm_debug::types::SourceLoc::new(*end), - // this not being 0 breaks inst-level debugging - compiled_offset: 0, - compiled_size: code_buf.len(), + let entry = CompiledFunctionData { + instructions, + start: wasm_debug::types::SourceLoc::new(*start), + end: wasm_debug::types::SourceLoc::new(*end), + // this not being 0 breaks inst-level debugging + compiled_offset: 0, + compiled_size: code_buf.len(), + }; + Some((entry, labels_ranges, stack_slots)) + } else { + None }; - // end debug stuff - ctx.clear(); - Ok((code_buf, (*lfi, entry, labels_ranges, stack_slots, reloc_sink, local_trap_sink))) + Ok((code_buf, (*lfi, debug_entry, reloc_sink, local_trap_sink))) }, ) .collect(); - use wasm_debug::types::CompiledFunctionData; - let mut debug_metadata = wasmer_runtime_core::codegen::DebugMetadata { - func_info: PrimaryMap::new(), - inst_info: PrimaryMap::new(), - pointers: vec![], - stack_slot_offsets: PrimaryMap::new(), + let mut debug_metadata = if generate_debug_info { + Some(wasmer_runtime_core::codegen::DebugMetadata { + func_info: PrimaryMap::new(), + inst_info: PrimaryMap::new(), + pointers: vec![], + stack_slot_offsets: PrimaryMap::new(), + }) + } else { + None }; let mut compiled_functions = compiled_functions?; @@ -226,24 +217,23 @@ impl FuncResolverBuilder { Vec>, Vec<( LocalFuncIndex, - CompiledFunctionData, - ValueLabelsRanges, - Vec>, + Option<(CompiledFunctionData, ValueLabelsRanges, Vec>)>, RelocSink, LocalTrapSink, )>, ) = compiled_functions.into_iter().unzip(); - for ( - code_buf, - (_, entry, vlr, stackslots, reloc_sink, mut local_trap_sink), - ) in code_bufs - .iter() - .zip(sinks.into_iter()) + for (code_buf, (_, debug_info, reloc_sink, mut local_trap_sink)) in + code_bufs.iter().zip(sinks.into_iter()) { let rounded_size = round_up(code_buf.len(), mem::size_of::()); - debug_metadata.func_info.push(entry); - debug_metadata.inst_info.push(unsafe {std::mem::transmute(vlr)}); - debug_metadata.stack_slot_offsets.push(stackslots); + if let Some(ref mut dbg_metadata) = debug_metadata { + let (entry, vlr, stackslots) = debug_info.unwrap(); + dbg_metadata.func_info.push(entry); + dbg_metadata + .inst_info + .push(unsafe { std::mem::transmute(vlr) }); + dbg_metadata.stack_slot_offsets.push(stackslots); + } // Clear the local trap sink and consolidate all trap info // into a single location. @@ -283,10 +273,12 @@ impl FuncResolverBuilder { let mut previous_end = 0; for compiled in code_bufs.iter() { let length = round_up(compiled.len(), mem::size_of::()); - debug_metadata.pointers.push(( - (memory.as_ptr() as usize + previous_end) as *const u8, - length, - )); + if let Some(ref mut dbg_metadata) = debug_metadata { + dbg_metadata.pointers.push(( + (memory.as_ptr() as usize + previous_end) as *const u8, + length, + )); + } let new_end = previous_end + length; unsafe { memory.as_slice_mut()[previous_end..previous_end + compiled.len()] @@ -309,7 +301,7 @@ impl FuncResolverBuilder { func_resolver_builder.relocate_locals(); - Ok((func_resolver_builder, Some(debug_metadata), handler_data)) + Ok((func_resolver_builder, debug_metadata, handler_data)) } fn relocate_locals(&mut self) { diff --git a/lib/debug-writer/Cargo.toml b/lib/debug-writer/Cargo.toml deleted file mode 100644 index e3f6dba4c..000000000 --- a/lib/debug-writer/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "wasmer-debug-writer" -version = "0.13.1" -authors = ["The Wasmer Engineering Team "] -edition = "2018" -repository = "https://github.com/wasmerio/wasmer" -publish = false -description = "Library for writing debug information from Wasm" -license = "MIT" - -[dependencies] -faerie = "0.14" -gimli = "0.20" -target-lexicon = "0.9" -wasm-debug = { version = "0.1.0", path = "../../../Dev/wasm-debug" } -wasmer-runtime-core = { path = "../runtime-core", version = "0.13.1" } -wasmparser = "0.45" diff --git a/lib/debug-writer/README.md b/lib/debug-writer/README.md deleted file mode 100644 index e55264abb..000000000 --- a/lib/debug-writer/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Wasmer debug info writer - -This crate deals with passing DWARF debug information along from -compiled Wasm modules to the machine code that we generate. - -This crate is effectively a derivative work of WasmTime's -[`wasmtime-debug`](https://github.com/bytecodealliance/wasmtime/tree/master/crates/debug) -crate. After beginning work on a clean reimplementation we realized -that the WasmTime implementation is high quality and it didn't make -sense for us to duplicate their hard work. - -Additionally by keeping the code structure of `wasmer-debug-writer` -similar to `wasmtime-debug`, we hope to upstream bug fixes and -improvements to `wasmtime-debug`. - -Copied files include the copyright notice as well, but as a catch all, -this crate is a derivative work of WasmTime's `wasmtime-debug` - -``` -Copyright 2020 WasmTime Project Developers - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` - -The latest revision at the time of cloning is `3992b8669f9b9e185abe81e9998ce2ff4d40ff68`. - -Changes to this crate are copyright of Wasmer inc. unless otherwise indicated -and are licensed under the Wasmer project's license: - -``` -MIT License - -Copyright (c) 2020 Wasmer, Inc. and its affiliates. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -``` diff --git a/lib/debug-writer/src/gc.rs b/lib/debug-writer/src/gc.rs deleted file mode 100644 index 7d20c9f8f..000000000 --- a/lib/debug-writer/src/gc.rs +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `39e57e3e9ac9c15bef45eb77a2544a7c0b76501a`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use crate::transform::AddressTransform; -use gimli::constants; -use gimli::read; -use gimli::{Reader, UnitSectionOffset}; -use std::collections::{HashMap, HashSet}; - -#[derive(Debug)] -pub struct Dependencies { - edges: HashMap>, - roots: HashSet, -} - -impl Dependencies { - fn new() -> Dependencies { - Dependencies { - edges: HashMap::new(), - roots: HashSet::new(), - } - } - - fn add_edge(&mut self, a: UnitSectionOffset, b: UnitSectionOffset) { - use std::collections::hash_map::Entry; - match self.edges.entry(a) { - Entry::Occupied(mut o) => { - o.get_mut().insert(b); - } - Entry::Vacant(v) => { - let mut set = HashSet::new(); - set.insert(b); - v.insert(set); - } - } - } - - fn add_root(&mut self, root: UnitSectionOffset) { - self.roots.insert(root); - } - - pub fn get_reachable(&self) -> HashSet { - let mut reachable = self.roots.clone(); - let mut queue = Vec::new(); - for i in self.roots.iter() { - if let Some(deps) = self.edges.get(i) { - for j in deps { - if reachable.contains(j) { - continue; - } - reachable.insert(*j); - queue.push(*j); - } - } - } - while let Some(i) = queue.pop() { - if let Some(deps) = self.edges.get(&i) { - for j in deps { - if reachable.contains(j) { - continue; - } - reachable.insert(*j); - queue.push(*j); - } - } - } - reachable - } -} - -pub fn build_dependencies>( - dwarf: &read::Dwarf, - at: &AddressTransform, -) -> read::Result { - let mut deps = Dependencies::new(); - let mut units = dwarf.units(); - while let Some(unit) = units.next()? { - build_unit_dependencies(unit, dwarf, at, &mut deps)?; - } - Ok(deps) -} - -fn build_unit_dependencies>( - header: read::CompilationUnitHeader, - dwarf: &read::Dwarf, - at: &AddressTransform, - deps: &mut Dependencies, -) -> read::Result<()> { - let unit = dwarf.unit(header)?; - let mut tree = unit.entries_tree(None)?; - let root = tree.root()?; - build_die_dependencies(root, dwarf, &unit, at, deps)?; - Ok(()) -} - -fn has_die_back_edge>(die: &read::DebuggingInformationEntry) -> bool { - match die.tag() { - constants::DW_TAG_variable - | constants::DW_TAG_constant - | constants::DW_TAG_inlined_subroutine - | constants::DW_TAG_lexical_block - | constants::DW_TAG_label - | constants::DW_TAG_with_stmt - | constants::DW_TAG_try_block - | constants::DW_TAG_catch_block - | constants::DW_TAG_template_type_parameter - | constants::DW_TAG_member - | constants::DW_TAG_formal_parameter => true, - _ => false, - } -} - -fn has_valid_code_range>( - die: &read::DebuggingInformationEntry, - dwarf: &read::Dwarf, - unit: &read::Unit, - at: &AddressTransform, -) -> read::Result { - match die.tag() { - constants::DW_TAG_subprogram => { - if let Some(ranges_attr) = die.attr_value(constants::DW_AT_ranges)? { - let offset = match ranges_attr { - read::AttributeValue::RangeListsRef(val) => val, - read::AttributeValue::DebugRngListsIndex(index) => { - dwarf.ranges_offset(unit, index)? - } - _ => return Ok(false), - }; - let mut has_valid_base = if let Some(read::AttributeValue::Addr(low_pc)) = - die.attr_value(constants::DW_AT_low_pc)? - { - Some(at.can_translate_address(low_pc)) - } else { - None - }; - let mut it = dwarf.ranges.raw_ranges(offset, unit.encoding())?; - while let Some(range) = it.next()? { - // If at least one of the range addresses can be converted, - // declaring code range as valid. - match range { - read::RawRngListEntry::AddressOrOffsetPair { .. } - if has_valid_base.is_some() => - { - if has_valid_base.unwrap() { - return Ok(true); - } - } - read::RawRngListEntry::StartEnd { begin, .. } - | read::RawRngListEntry::StartLength { begin, .. } - | read::RawRngListEntry::AddressOrOffsetPair { begin, .. } => { - if at.can_translate_address(begin) { - return Ok(true); - } - } - read::RawRngListEntry::StartxEndx { begin, .. } - | read::RawRngListEntry::StartxLength { begin, .. } => { - let addr = dwarf.address(unit, begin)?; - if at.can_translate_address(addr) { - return Ok(true); - } - } - read::RawRngListEntry::BaseAddress { addr } => { - has_valid_base = Some(at.can_translate_address(addr)); - } - read::RawRngListEntry::BaseAddressx { addr } => { - let addr = dwarf.address(unit, addr)?; - has_valid_base = Some(at.can_translate_address(addr)); - } - read::RawRngListEntry::OffsetPair { .. } => (), - } - } - return Ok(false); - } else if let Some(low_pc) = die.attr_value(constants::DW_AT_low_pc)? { - if let read::AttributeValue::Addr(a) = low_pc { - return Ok(at.can_translate_address(a)); - } - } - } - _ => (), - } - Ok(false) -} - -fn build_die_dependencies>( - die: read::EntriesTreeNode, - dwarf: &read::Dwarf, - unit: &read::Unit, - at: &AddressTransform, - deps: &mut Dependencies, -) -> read::Result<()> { - let entry = die.entry(); - let offset = entry.offset().to_unit_section_offset(unit); - let mut attrs = entry.attrs(); - while let Some(attr) = attrs.next()? { - build_attr_dependencies(&attr, offset, dwarf, unit, at, deps)?; - } - - let mut children = die.children(); - while let Some(child) = children.next()? { - let child_entry = child.entry(); - let child_offset = child_entry.offset().to_unit_section_offset(unit); - deps.add_edge(child_offset, offset); - if has_die_back_edge(child_entry) { - deps.add_edge(offset, child_offset); - } - if has_valid_code_range(child_entry, dwarf, unit, at)? { - deps.add_root(child_offset); - } - build_die_dependencies(child, dwarf, unit, at, deps)?; - } - Ok(()) -} - -fn build_attr_dependencies>( - attr: &read::Attribute, - offset: UnitSectionOffset, - _dwarf: &read::Dwarf, - unit: &read::Unit, - _at: &AddressTransform, - deps: &mut Dependencies, -) -> read::Result<()> { - match attr.value() { - read::AttributeValue::UnitRef(val) => { - let ref_offset = val.to_unit_section_offset(unit); - deps.add_edge(offset, ref_offset); - } - read::AttributeValue::DebugInfoRef(val) => { - let ref_offset = UnitSectionOffset::DebugInfoOffset(val); - deps.add_edge(offset, ref_offset); - } - _ => (), - } - Ok(()) -} diff --git a/lib/debug-writer/src/lib.rs b/lib/debug-writer/src/lib.rs deleted file mode 100644 index 655a5a6dc..000000000 --- a/lib/debug-writer/src/lib.rs +++ /dev/null @@ -1,177 +0,0 @@ -// TODO: add attribution to LLVM for data definitions and WasmTime for code structure -use std::ffi::c_void; -use std::ptr; -use std::str::FromStr; - -pub use wasm_debug::{emit_dwarf, ResolvedSymbol, SymbolResolver}; -pub use wasm_debug::{read_debuginfo, DebugInfoData, WasmFileInfo}; - -use gimli::write::{ - self, Address, AttributeValue, DwarfUnit, EndianVec, Range, RangeList, Sections, -}; -use target_lexicon::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; - -use wasmer_runtime_core::{module::ModuleInfo, state::CodeVersion}; - -/// Triple of x86_64 GNU/Linux -const X86_64_GNU_LINUX: Triple = Triple { - architecture: Architecture::X86_64, - vendor: Vendor::Unknown, - operating_system: OperatingSystem::Linux, - environment: Environment::Gnu, - binary_format: BinaryFormat::Elf, -}; - -/// Triple of x86_64 OSX -const X86_64_OSX: Triple = Triple { - architecture: Architecture::X86_64, - vendor: Vendor::Apple, - operating_system: OperatingSystem::Darwin, - environment: Environment::Unknown, - binary_format: BinaryFormat::Macho, -}; - -/// Triple of x86_64 Windows -const X86_64_WINDOWS: Triple = Triple { - architecture: Architecture::X86_64, - vendor: Vendor::Pc, - operating_system: OperatingSystem::Windows, - environment: Environment::Msvc, - binary_format: BinaryFormat::Coff, -}; - -// this code also from WasmTime -// TODO: attribute -struct ImageRelocResolver<'a> { - func_offsets: &'a Vec, -} - -// this code also from WasmTime -// TODO: attribute -impl<'a> SymbolResolver for ImageRelocResolver<'a> { - fn resolve_symbol(&self, symbol: usize, addend: i64) -> ResolvedSymbol { - let func_start = self.func_offsets[symbol]; - ResolvedSymbol::PhysicalAddress(func_start + addend as u64) - } -} - -/* -// the structure of this function and some of its details come from WasmTime -// TODO: attribute -pub fn generate_dwarf(module_info: &ModuleInfo, debug_info_data: &DebugInfoData, code_version: &CodeVersion, platform: Triple) -> Result, String> { - let func_offsets = unimplemented!(); - let resolver = ImageRelocResolver { func_offsets }; - // copied from https://docs.rs/gimli/0.20.0/gimli/write/index.html ; TODO: review these values - let processed_dwarf = reprocess_dwarf(module_info, debug_info_data, code_version, platform).ok_or_else(|| "Failed to reprocess Wasm's dwarf".to_string())?; - let encoding = gimli::Encoding { - format: gimli::Format::Dwarf32, - version: 3, - address_size: 8, - }; - let mut dwarf = DwarfUnit::new(encoding); - // TODO: figure out what range is (from example) - let range_list = RangeList(vec![Range::StartLength { - begin: Address::Constant(0x100), - length: 42, - }]); - let range_list_id = dwarf.unit.ranges.add(range_list); - let root = dwarf.unit.root(); - dwarf.unit.get_mut(root).set( - gimli::DW_AT_ranges, - AttributeValue::RangeListRef(range_list_id), - ); - let mut string_table = write::StringTable::default(); - let mut line_string_table = write::LineStringTable::default(); - - let mut obj = faerie::Artifact::new(platform, String::from("module")); - - let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); - // Finally, write the DWARF data to the sections. - dwarf.write(&mut sections).map_err(|e| e.to_string())?; - emit_dwarf(&mut obj, dwarf, &resolver); - sections.for_each(|id, data| { - // Here you can add the data to the output object file. - Ok(()) - }); - - obj.emit_as(BinaryFormat::Elf).expect("TODO"); - // We want to populate DwarfUnit::line_str_table with WAT probably - // and set up the string table with things like function signatures in WAT, function names, etc - - // NOTES from DWARF spec: - // http://dwarfstd.org/doc/DWARF5.pdf - // - `DIE`s form the core of dwarf and live in .debug_info - // - the tags can get fairly specific, it looks like we'll just need a mapping - // from object code to a bunch of tags and ranges? created with the Wasm - // data for extra info about types, etc. - // - debug info can live in a separate object file (that's what we'll do here) - // - attribute types are unique per DIE (lots of info here (like is tail call, - // return addr, etc.) - // - DW_AT_language: WebAssembly :bonjour: - // - `DW_AT_linkage_name` function namespaces? (later described as the raw, mangled name) - // `DW_AT_name` function name? - // - `DW_AT_location` where in the code it is - // - `DW_AT_main_subprogram` where to start from - // - `DW_AT_producer`: wasmer - // - `DW_AT_recursive` -- is this mandatory? what is it used for? TODO: find out - // - `DW_AT_signature` -- can we use wasm type signature info here? TODO: - // - `DIE`s form a graph/tree though a tree-like graph when it is a graph, docs say - // this is how structs and relationship of code blocks is represented. - // - when serialized the tree is in post-fix order (probably not important for our - // purposes but mildly interesting) - // - we'll need pointer sizer and platform information - // - dwarf executes a typed stack-machine to compute the locations of things - // - lots of neat info about the dwarf stack machine skipping for now because I - // think gimli exposes a higher-level interface (if not, I'll add notes here - // or further down about it) - // - can use dwarf expressions/dynamically computing things to handle things like - // a tiering JIT? - // - location lists are needed for things that aren't lexically scoped, otherwise - // single location descriptions (dwarf expressions) are sufficient - // - I wonder what this means in the context of spilling registers... do we have - // to create dwarf expressions that can handle that? - // - `DW_AT_artificial` is used to tag `DIE` that didn't come directly from the code - // - `DW_AT_declaration` for function/etc declarations at the top of the wasm module, - // see section 2.13.2 for how to connect the definiton and the declaration - // - `DW_AT_decl_line`, `DW_AT_decl_column` refer to the exact location in the source - // file, so presumably we include the entire source file in one of the sections? - // or perhaps that's purely for human consumption. - // - `DW_AT_ranges` is for non-contiguous ranges of address and, - // `DW_AT_low_pc` and `DW_AT_high_pc` are good for continuous - // `DW_AT_low_pc` alone can work for a single address, but we can probably not - // worry about that for now. These attribtues associate machine code with the DIE - // - - - match platform { - X86_64_GNU_LINUX => unimplemented!("in progress"), - X86_64_OSX => unimplemented!("in progress"), - X86_64_WINDOWS => unimplemented!("in progress"), - _ => return Err(format!("Debug output for the platform {} is not yet supported", platform)), - } - Ok(vec![]) -} -*/ - -// converts existing dwarf into a usable form with metadata from the JIT -fn reprocess_dwarf( - module_info: &ModuleInfo, - debug_info_data: &DebugInfoData, - code_version: &CodeVersion, - platform: Triple, -) -> Option { - None -} - -// black box, needs some kind of input, some kind of processing -// and returns a bunch of bytes we can give to GDB -// -// where is this documented? -// we need to pass in target triple, isa config, memories/pointers to memories, ranges of where things are, -// and info like function names -pub fn generate_debug_sections_image(bytes: &[u8]) -> Option> { - let debug_info = read_debuginfo(bytes); - dbg!(debug_info); - - //emit_debugsections_image(X86_64_OSX, 8, debug_info, ) - None -} diff --git a/lib/debug-writer/src/read_debug_info.rs b/lib/debug-writer/src/read_debug_info.rs deleted file mode 100644 index 595a3430d..000000000 --- a/lib/debug-writer/src/read_debug_info.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. It reads DWARF info from a Wasm module. -// It was copied at revision `39e57e3e9ac9c15bef45eb77a2544a7c0b76501a`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. - -use gimli::{ - DebugAbbrev, DebugAddr, DebugInfo, DebugLine, DebugLineStr, DebugLoc, DebugLocLists, - DebugRanges, DebugRngLists, DebugStr, DebugStrOffsets, DebugTypes, EndianSlice, LittleEndian, - LocationLists, RangeLists, -}; -use std::collections::HashMap; -use std::path::PathBuf; -use wasmparser::{self, ModuleReader, SectionCode}; - -trait Reader: gimli::Reader {} - -impl<'input> Reader for gimli::EndianSlice<'input, LittleEndian> {} - -pub use wasmparser::Type as WasmType; - -pub type Dwarf<'input> = gimli::Dwarf>; - -#[derive(Debug)] -pub struct FunctionMetadata { - pub params: Box<[WasmType]>, - pub locals: Box<[(u32, WasmType)]>, -} - -#[derive(Debug)] -pub struct WasmFileInfo { - pub path: Option, - pub code_section_offset: u64, - pub funcs: Box<[FunctionMetadata]>, -} - -#[derive(Debug)] -pub struct NameSection { - pub module_name: Option, - pub func_names: HashMap, - pub locals_names: HashMap>, -} - -#[derive(Debug)] -pub struct DebugInfoData<'a> { - pub dwarf: Dwarf<'a>, - pub name_section: Option, - 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.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(EMPTY_SECTION, endian)); - - if sections.contains_key(".debug_line_str") { - panic!("Unexpected .debug_line_str"); - } - - 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(EMPTY_SECTION, endian), - }; - let debug_rnglists = DebugRngLists::new(EMPTY_SECTION, endian); - let ranges = RangeLists::new(debug_ranges, debug_rnglists); - - if sections.contains_key(".debug_loclists") { - panic!("Unexpected .debug_loclists"); - } - - let debug_loc = match sections.get(".debug_loc") { - Some(section) => DebugLoc::new(section, endian), - None => DebugLoc::new(EMPTY_SECTION, 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(EMPTY_SECTION, endian)); - - if sections.contains_key(".debug_types") { - panic!("Unexpected .debug_types"); - } - - let debug_types = DebugTypes::from(EndianSlice::new(EMPTY_SECTION, endian)); - - Dwarf { - debug_abbrev, - debug_addr, - debug_info, - debug_line, - debug_line_str, - debug_str, - debug_str_offsets, - debug_str_sup, - debug_types, - locations, - ranges, - } -} - -fn read_name_section(reader: wasmparser::NameSectionReader) -> wasmparser::Result { - 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_debug_info(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> = Vec::new(); - let mut func_params_refs: Vec = Vec::new(); - let mut func_locals: Vec> = Vec::new(); - - while !reader.eof() { - let section = reader.read().expect("section"); - 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); - } - } - } - } - SectionCode::Type => { - signatures_params = section - .get_type_section_reader() - .expect("type section") - .into_iter() - .map(|ft| ft.expect("type").params) - .collect::>(); - } - SectionCode::Function => { - func_params_refs = section - .get_function_section_reader() - .expect("function section") - .into_iter() - .map(|index| index.expect("func index") as usize) - .collect::>(); - } - 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::, _>>() - .expect("locals data") - .into_boxed_slice() - }) - .collect::>(); - } - _ => (), - } - } - - 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::>(); - - DebugInfoData { - dwarf: convert_sections(sections), - name_section, - wasm_file: WasmFileInfo { - path: None, - code_section_offset, - funcs: func_meta.into_boxed_slice(), - }, - } -} diff --git a/lib/debug-writer/src/transform/address_transform.rs b/lib/debug-writer/src/transform/address_transform.rs deleted file mode 100644 index 876e2a6c7..000000000 --- a/lib/debug-writer/src/transform/address_transform.rs +++ /dev/null @@ -1,676 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `907e7aac01af333a0af310ce0472abbc8a9adb6c`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use crate::WasmFileInfo; -use cranelift_codegen::ir::SourceLoc; -use cranelift_entity::{EntityRef, PrimaryMap}; -use gimli::write; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::iter::FromIterator; -use wasmer_runtime_core::types::FuncIndex; -use wasmtime_environ::{FunctionAddressMap, ModuleAddressMap}; - -pub type GeneratedAddress = usize; -pub type WasmAddress = u64; - -/// Contains mapping of the generated address to its original -/// source location. -#[derive(Debug)] -pub struct AddressMap { - pub generated: GeneratedAddress, - pub wasm: WasmAddress, -} - -/// Information about generated function code: its body start, -/// length, and instructions addresses. -#[derive(Debug)] -pub struct FunctionMap { - pub offset: GeneratedAddress, - pub len: GeneratedAddress, - pub wasm_start: WasmAddress, - pub wasm_end: WasmAddress, - pub addresses: Box<[AddressMap]>, -} - -/// Mapping of the source location to its generated code range. -#[derive(Debug)] -struct Position { - wasm_pos: WasmAddress, - gen_start: GeneratedAddress, - gen_end: GeneratedAddress, -} - -/// Mapping of continuous range of source location to its generated -/// code. The positions are always in accending order for search. -#[derive(Debug)] -struct Range { - wasm_start: WasmAddress, - wasm_end: WasmAddress, - gen_start: GeneratedAddress, - gen_end: GeneratedAddress, - positions: Box<[Position]>, -} - -/// Helper function address lookup data. Contains ranges start positions -/// index and ranges data. The multiple ranges can include the same -/// original source position. The index (B-Tree) uses range start -/// position as a key. -#[derive(Debug)] -struct FuncLookup { - index: Vec<(WasmAddress, Box<[usize]>)>, - ranges: Box<[Range]>, -} - -/// Mapping of original functions to generated code locations/ranges. -#[derive(Debug)] -struct FuncTransform { - start: WasmAddress, - end: WasmAddress, - index: FuncIndex, - lookup: FuncLookup, -} - -/// Module functions mapping to generated code. -#[derive(Debug)] -pub struct AddressTransform { - map: PrimaryMap, - func: Vec<(WasmAddress, FuncTransform)>, -} - -/// Returns a wasm bytecode offset in the code section from SourceLoc. -pub fn get_wasm_code_offset(loc: SourceLoc, code_section_offset: u64) -> WasmAddress { - // Code section size <= 4GB, allow wrapped SourceLoc to recover the overflow. - loc.bits().wrapping_sub(code_section_offset as u32) as WasmAddress -} - -fn build_function_lookup( - ft: &FunctionAddressMap, - code_section_offset: u64, -) -> (WasmAddress, WasmAddress, FuncLookup) { - assert!(code_section_offset <= ft.start_srcloc.bits() as u64); - let fn_start = get_wasm_code_offset(ft.start_srcloc, code_section_offset); - let fn_end = get_wasm_code_offset(ft.end_srcloc, code_section_offset); - assert!(fn_start <= fn_end); - - // Build ranges of continuous source locations. The new ranges starts when - // non-descending order is interrupted. Assuming the same origin location can - // be present in multiple ranges. - let mut range_wasm_start = fn_start; - let mut range_gen_start = ft.body_offset; - let mut last_wasm_pos = range_wasm_start; - let mut ranges = Vec::new(); - let mut ranges_index = BTreeMap::new(); - let mut current_range = Vec::new(); - for t in &ft.instructions { - if t.srcloc.is_default() { - continue; - } - - let offset = get_wasm_code_offset(t.srcloc, code_section_offset); - assert!(fn_start <= offset); - assert!(offset <= fn_end); - - let inst_gen_start = t.code_offset; - let inst_gen_end = t.code_offset + t.code_len; - - if last_wasm_pos > offset { - // Start new range. - ranges_index.insert(range_wasm_start, ranges.len()); - ranges.push(Range { - wasm_start: range_wasm_start, - wasm_end: last_wasm_pos, - gen_start: range_gen_start, - gen_end: inst_gen_start, - positions: current_range.into_boxed_slice(), - }); - range_wasm_start = offset; - range_gen_start = inst_gen_start; - current_range = Vec::new(); - } - // Continue existing range: add new wasm->generated code position. - current_range.push(Position { - wasm_pos: offset, - gen_start: inst_gen_start, - gen_end: inst_gen_end, - }); - last_wasm_pos = offset; - } - let last_gen_addr = ft.body_offset + ft.body_len; - ranges_index.insert(range_wasm_start, ranges.len()); - ranges.push(Range { - wasm_start: range_wasm_start, - wasm_end: fn_end, - gen_start: range_gen_start, - gen_end: last_gen_addr, - positions: current_range.into_boxed_slice(), - }); - - // Making ranges lookup faster by building index: B-tree with every range - // start position that maps into list of active ranges at this position. - let ranges = ranges.into_boxed_slice(); - let mut active_ranges = Vec::new(); - let mut index = BTreeMap::new(); - let mut last_wasm_pos = None; - for (wasm_start, range_index) in ranges_index { - if Some(wasm_start) == last_wasm_pos { - active_ranges.push(range_index); - continue; - } - if last_wasm_pos.is_some() { - index.insert( - last_wasm_pos.unwrap(), - active_ranges.clone().into_boxed_slice(), - ); - } - active_ranges.retain(|r| ranges[*r].wasm_end.cmp(&wasm_start) != std::cmp::Ordering::Less); - active_ranges.push(range_index); - last_wasm_pos = Some(wasm_start); - } - index.insert(last_wasm_pos.unwrap(), active_ranges.into_boxed_slice()); - let index = Vec::from_iter(index.into_iter()); - (fn_start, fn_end, FuncLookup { index, ranges }) -} - -fn build_function_addr_map( - at: &ModuleAddressMap, - code_section_offset: u64, -) -> PrimaryMap { - let mut map = PrimaryMap::new(); - for (_, ft) in at { - let mut fn_map = Vec::new(); - for t in &ft.instructions { - if t.srcloc.is_default() { - continue; - } - let offset = get_wasm_code_offset(t.srcloc, code_section_offset); - fn_map.push(AddressMap { - generated: t.code_offset, - wasm: offset, - }); - } - - if cfg!(debug) { - // fn_map is sorted by the generated field -- see FunctionAddressMap::instructions. - for i in 1..fn_map.len() { - assert!(fn_map[i - 1].generated <= fn_map[i].generated); - } - } - - map.push(FunctionMap { - offset: ft.body_offset, - len: ft.body_len, - wasm_start: get_wasm_code_offset(ft.start_srcloc, code_section_offset), - wasm_end: get_wasm_code_offset(ft.end_srcloc, code_section_offset), - addresses: fn_map.into_boxed_slice(), - }); - } - map -} - -struct TransformRangeIter<'a> { - addr: u64, - indicies: &'a [usize], - ranges: &'a [Range], -} - -impl<'a> TransformRangeIter<'a> { - fn new(func: &'a FuncTransform, addr: u64) -> Self { - let found = match func - .lookup - .index - .binary_search_by(|entry| entry.0.cmp(&addr)) - { - Ok(i) => Some(&func.lookup.index[i].1), - Err(i) => { - if i > 0 { - Some(&func.lookup.index[i - 1].1) - } else { - None - } - } - }; - if let Some(range_indices) = found { - TransformRangeIter { - addr, - indicies: range_indices, - ranges: &func.lookup.ranges, - } - } else { - unreachable!(); - } - } -} -impl<'a> Iterator for TransformRangeIter<'a> { - type Item = (usize, usize); - fn next(&mut self) -> Option { - if let Some((first, tail)) = self.indicies.split_first() { - let range_index = *first; - let range = &self.ranges[range_index]; - self.indicies = tail; - let address = match range - .positions - .binary_search_by(|a| a.wasm_pos.cmp(&self.addr)) - { - Ok(i) => range.positions[i].gen_start, - Err(i) => { - if i == 0 { - range.gen_start - } else { - range.positions[i - 1].gen_end - } - } - }; - Some((address, range_index)) - } else { - None - } - } -} - -struct TransformRangeEndIter<'a> { - addr: u64, - indicies: &'a [usize], - ranges: &'a [Range], -} - -impl<'a> TransformRangeEndIter<'a> { - fn new(func: &'a FuncTransform, addr: u64) -> Self { - let found = match func - .lookup - .index - .binary_search_by(|entry| entry.0.cmp(&addr)) - { - Ok(i) => Some(&func.lookup.index[i].1), - Err(i) => { - if i > 0 { - Some(&func.lookup.index[i - 1].1) - } else { - None - } - } - }; - if let Some(range_indices) = found { - TransformRangeEndIter { - addr, - indicies: range_indices, - ranges: &func.lookup.ranges, - } - } else { - unreachable!(); - } - } -} - -impl<'a> Iterator for TransformRangeEndIter<'a> { - type Item = (usize, usize); - fn next(&mut self) -> Option { - while let Some((first, tail)) = self.indicies.split_first() { - let range_index = *first; - let range = &self.ranges[range_index]; - if range.wasm_start >= self.addr { - continue; - } - self.indicies = tail; - let address = match range - .positions - .binary_search_by(|a| a.wasm_pos.cmp(&self.addr)) - { - Ok(i) => range.positions[i].gen_end, - Err(i) => { - if i == range.positions.len() { - range.gen_end - } else { - range.positions[i].gen_start - } - } - }; - return Some((address, range_index)); - } - None - } -} - -impl AddressTransform { - pub fn new(at: &ModuleAddressMap, wasm_file: &WasmFileInfo) -> Self { - let code_section_offset = wasm_file.code_section_offset; - - let mut func = BTreeMap::new(); - for (i, ft) in at { - let (fn_start, fn_end, lookup) = build_function_lookup(ft, code_section_offset); - - func.insert( - fn_start, - FuncTransform { - start: fn_start, - end: fn_end, - index: i, - lookup, - }, - ); - } - - let map = build_function_addr_map(at, code_section_offset); - let func = Vec::from_iter(func.into_iter()); - AddressTransform { map, func } - } - - fn find_func(&self, addr: u64) -> Option<&FuncTransform> { - // TODO check if we need to include end address - let func = match self.func.binary_search_by(|entry| entry.0.cmp(&addr)) { - Ok(i) => &self.func[i].1, - Err(i) => { - if i > 0 { - &self.func[i - 1].1 - } else { - return None; - } - } - }; - if addr >= func.start { - return Some(func); - } - None - } - - pub fn find_func_index(&self, addr: u64) -> Option { - self.find_func(addr).map(|f| f.index) - } - - pub fn translate_raw(&self, addr: u64) -> Option<(FuncIndex, GeneratedAddress)> { - if addr == 0 { - // It's normally 0 for debug info without the linked code. - return None; - } - if let Some(func) = self.find_func(addr) { - if addr == func.end { - // Clamp last address to the end to extend translation to the end - // of the function. - let map = &self.map[func.index]; - return Some((func.index, map.len)); - } - let first_result = TransformRangeIter::new(func, addr).next(); - first_result.map(|(address, _)| (func.index, address)) - } else { - // Address was not found: function was not compiled? - None - } - } - - pub fn can_translate_address(&self, addr: u64) -> bool { - self.translate(addr).is_some() - } - - pub fn translate(&self, addr: u64) -> Option { - self.translate_raw(addr) - .map(|(func_index, address)| write::Address::Symbol { - symbol: func_index.index(), - addend: address as i64, - }) - } - - pub fn translate_ranges_raw( - &self, - start: u64, - end: u64, - ) -> Option<(FuncIndex, Vec<(GeneratedAddress, GeneratedAddress)>)> { - if start == 0 { - // It's normally 0 for debug info without the linked code. - return None; - } - if let Some(func) = self.find_func(start) { - let mut starts: HashMap = - HashMap::from_iter(TransformRangeIter::new(func, start).map(|(a, r)| (r, a))); - let mut result = Vec::new(); - TransformRangeEndIter::new(func, end).for_each(|(a, r)| { - let range_start = if let Some(range_start) = starts.get(&r) { - let range_start = *range_start; - starts.remove(&r); - range_start - } else { - let range = &func.lookup.ranges[r]; - range.gen_start - }; - result.push((range_start, a)); - }); - for (r, range_start) in starts { - let range = &func.lookup.ranges[r]; - result.push((range_start, range.gen_end)); - } - return Some((func.index, result)); - } - // Address was not found: function was not compiled? - None - } - - pub fn translate_ranges(&self, start: u64, end: u64) -> Vec<(write::Address, u64)> { - self.translate_ranges_raw(start, end) - .map_or(vec![], |(func_index, ranges)| { - ranges - .iter() - .map(|(start, end)| { - ( - write::Address::Symbol { - symbol: func_index.index(), - addend: *start as i64, - }, - (*end - *start) as u64, - ) - }) - .collect::>() - }) - } - - pub fn map(&self) -> &PrimaryMap { - &self.map - } - - pub fn func_range(&self, index: FuncIndex) -> (GeneratedAddress, GeneratedAddress) { - let map = &self.map[index]; - (map.offset, map.offset + map.len) - } - - pub fn func_source_range(&self, index: FuncIndex) -> (WasmAddress, WasmAddress) { - let map = &self.map[index]; - (map.wasm_start, map.wasm_end) - } - - pub fn convert_to_code_range( - &self, - addr: write::Address, - len: u64, - ) -> (GeneratedAddress, GeneratedAddress) { - let start = if let write::Address::Symbol { addend, .. } = addr { - // TODO subtract self.map[symbol].offset ? - addend as GeneratedAddress - } else { - unreachable!(); - }; - (start, start + len as GeneratedAddress) - } -} - -#[cfg(test)] -mod tests { - use super::{build_function_lookup, get_wasm_code_offset, AddressTransform}; - use crate::read_debug_info::WasmFileInfo; - use cranelift_codegen::ir::SourceLoc; - use cranelift_entity::PrimaryMap; - use gimli::write::Address; - use std::iter::FromIterator; - use wasmtime_environ::{FunctionAddressMap, InstructionAddressMap, ModuleAddressMap}; - - #[test] - fn test_get_wasm_code_offset() { - let offset = get_wasm_code_offset(SourceLoc::new(3), 1); - assert_eq!(2, offset); - let offset = get_wasm_code_offset(SourceLoc::new(16), 0xF000_0000); - assert_eq!(0x1000_0010, offset); - let offset = get_wasm_code_offset(SourceLoc::new(1), 0x20_8000_0000); - assert_eq!(0x8000_0001, offset); - } - - fn create_simple_func(wasm_offset: u32) -> FunctionAddressMap { - FunctionAddressMap { - instructions: vec![ - InstructionAddressMap { - srcloc: SourceLoc::new(wasm_offset + 2), - code_offset: 5, - code_len: 3, - }, - InstructionAddressMap { - srcloc: SourceLoc::new(wasm_offset + 7), - code_offset: 15, - code_len: 8, - }, - ], - start_srcloc: SourceLoc::new(wasm_offset), - end_srcloc: SourceLoc::new(wasm_offset + 10), - body_offset: 0, - body_len: 30, - } - } - - fn create_simple_module(func: FunctionAddressMap) -> ModuleAddressMap { - PrimaryMap::from_iter(vec![func]) - } - - #[test] - fn test_build_function_lookup_simple() { - let input = create_simple_func(11); - let (start, end, lookup) = build_function_lookup(&input, 1); - assert_eq!(10, start); - assert_eq!(20, end); - - assert_eq!(1, lookup.index.len()); - let index_entry = lookup.index.into_iter().next().unwrap(); - assert_eq!((10u64, vec![0].into_boxed_slice()), index_entry); - assert_eq!(1, lookup.ranges.len()); - let range = &lookup.ranges[0]; - assert_eq!(10, range.wasm_start); - assert_eq!(20, range.wasm_end); - assert_eq!(0, range.gen_start); - assert_eq!(30, range.gen_end); - let positions = &range.positions; - assert_eq!(2, positions.len()); - assert_eq!(12, positions[0].wasm_pos); - assert_eq!(5, positions[0].gen_start); - assert_eq!(8, positions[0].gen_end); - assert_eq!(17, positions[1].wasm_pos); - assert_eq!(15, positions[1].gen_start); - assert_eq!(23, positions[1].gen_end); - } - - #[test] - fn test_build_function_lookup_two_ranges() { - let mut input = create_simple_func(11); - // append instruction with same srcloc as input.instructions[0] - input.instructions.push(InstructionAddressMap { - srcloc: SourceLoc::new(11 + 2), - code_offset: 23, - code_len: 3, - }); - let (start, end, lookup) = build_function_lookup(&input, 1); - assert_eq!(10, start); - assert_eq!(20, end); - - assert_eq!(2, lookup.index.len()); - let index_entries = Vec::from_iter(lookup.index.into_iter()); - assert_eq!((10u64, vec![0].into_boxed_slice()), index_entries[0]); - assert_eq!((12u64, vec![0, 1].into_boxed_slice()), index_entries[1]); - assert_eq!(2, lookup.ranges.len()); - - let range = &lookup.ranges[0]; - assert_eq!(10, range.wasm_start); - assert_eq!(17, range.wasm_end); - assert_eq!(0, range.gen_start); - assert_eq!(23, range.gen_end); - let positions = &range.positions; - assert_eq!(2, positions.len()); - assert_eq!(12, positions[0].wasm_pos); - assert_eq!(5, positions[0].gen_start); - assert_eq!(8, positions[0].gen_end); - assert_eq!(17, positions[1].wasm_pos); - assert_eq!(15, positions[1].gen_start); - assert_eq!(23, positions[1].gen_end); - - let range = &lookup.ranges[1]; - assert_eq!(12, range.wasm_start); - assert_eq!(20, range.wasm_end); - assert_eq!(23, range.gen_start); - assert_eq!(30, range.gen_end); - let positions = &range.positions; - assert_eq!(1, positions.len()); - assert_eq!(12, positions[0].wasm_pos); - assert_eq!(23, positions[0].gen_start); - assert_eq!(26, positions[0].gen_end); - } - - #[test] - fn test_addr_translate() { - let input = create_simple_module(create_simple_func(11)); - let at = AddressTransform::new( - &input, - &WasmFileInfo { - path: None, - code_section_offset: 1, - funcs: Box::new([]), - }, - ); - - let addr = at.translate(10); - assert_eq!( - Some(Address::Symbol { - symbol: 0, - addend: 0, - }), - addr - ); - - let addr = at.translate(20); - assert_eq!( - Some(Address::Symbol { - symbol: 0, - addend: 30, - }), - addr - ); - - let addr = at.translate(0); - assert_eq!(None, addr); - - let addr = at.translate(12); - assert_eq!( - Some(Address::Symbol { - symbol: 0, - addend: 5, - }), - addr - ); - - let addr = at.translate(18); - assert_eq!( - Some(Address::Symbol { - symbol: 0, - addend: 23, - }), - addr - ); - } -} diff --git a/lib/debug-writer/src/transform/attr.rs b/lib/debug-writer/src/transform/attr.rs deleted file mode 100644 index bd15586e9..000000000 --- a/lib/debug-writer/src/transform/attr.rs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `907e7aac01af333a0af310ce0472abbc8a9adb6c`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::address_transform::AddressTransform; -use super::expression::{compile_expression, CompiledExpression, FunctionFrameInfo}; -use super::range_info_builder::RangeInfoBuilder; -use super::unit::PendingDieRef; -use super::{DebugInputContext, Reader, TransformError}; -use anyhow::Error; -use gimli::{ - write, AttributeValue, DebugLineOffset, DebugStr, DebuggingInformationEntry, UnitOffset, -}; -use std::collections::HashMap; - -pub(crate) enum FileAttributeContext<'a> { - Root(Option), - Children(&'a Vec, Option<&'a CompiledExpression>), -} - -fn is_exprloc_to_loclist_allowed(attr_name: gimli::constants::DwAt) -> bool { - match attr_name { - gimli::DW_AT_location - | gimli::DW_AT_string_length - | gimli::DW_AT_return_addr - | gimli::DW_AT_data_member_location - | gimli::DW_AT_frame_base - | gimli::DW_AT_segment - | gimli::DW_AT_static_link - | gimli::DW_AT_use_location - | gimli::DW_AT_vtable_elem_location => true, - _ => false, - } -} - -pub(crate) fn clone_die_attributes<'a, R>( - entry: &DebuggingInformationEntry, - context: &DebugInputContext, - addr_tr: &'a AddressTransform, - frame_info: Option<&FunctionFrameInfo>, - unit_encoding: gimli::Encoding, - out_unit: &mut write::Unit, - current_scope_id: write::UnitEntryId, - subprogram_range_builder: Option, - scope_ranges: Option<&Vec<(u64, u64)>>, - cu_low_pc: u64, - out_strings: &mut write::StringTable, - die_ref_map: &HashMap, - pending_die_refs: &mut Vec, - file_context: FileAttributeContext<'a>, -) -> Result<(), Error> -where - R: Reader, -{ - let _tag = &entry.tag(); - let endian = gimli::RunTimeEndian::Little; - - let range_info = if let Some(subprogram_range_builder) = subprogram_range_builder { - subprogram_range_builder - } else if entry.tag() == gimli::DW_TAG_compile_unit { - // FIXME currently address_transform operate on a single func range, - // once it is fixed we can properly set DW_AT_ranges attribute. - // Using for now DW_AT_low_pc = 0. - RangeInfoBuilder::Position(0) - } else { - RangeInfoBuilder::from(entry, context, unit_encoding, cu_low_pc)? - }; - range_info.build(addr_tr, out_unit, current_scope_id); - - let mut attrs = entry.attrs(); - while let Some(attr) = attrs.next()? { - let attr_value = match attr.value() { - AttributeValue::Addr(_) if attr.name() == gimli::DW_AT_low_pc => { - continue; - } - AttributeValue::Udata(_) if attr.name() == gimli::DW_AT_high_pc => { - continue; - } - AttributeValue::RangeListsRef(_) if attr.name() == gimli::DW_AT_ranges => { - continue; - } - AttributeValue::Exprloc(_) if attr.name() == gimli::DW_AT_frame_base => { - continue; - } - - AttributeValue::Addr(u) => { - let addr = addr_tr.translate(u).unwrap_or(write::Address::Constant(0)); - write::AttributeValue::Address(addr) - } - AttributeValue::Udata(u) => write::AttributeValue::Udata(u), - AttributeValue::Data1(d) => write::AttributeValue::Data1(d), - AttributeValue::Data2(d) => write::AttributeValue::Data2(d), - AttributeValue::Data4(d) => write::AttributeValue::Data4(d), - AttributeValue::Sdata(d) => write::AttributeValue::Sdata(d), - AttributeValue::Flag(f) => write::AttributeValue::Flag(f), - AttributeValue::DebugLineRef(line_program_offset) => { - if let FileAttributeContext::Root(o) = file_context { - if o != Some(line_program_offset) { - return Err(TransformError("invalid debug_line offset").into()); - } - write::AttributeValue::LineProgramRef - } else { - return Err(TransformError("unexpected debug_line index attribute").into()); - } - } - AttributeValue::FileIndex(i) => { - if let FileAttributeContext::Children(file_map, _) = file_context { - write::AttributeValue::FileIndex(Some(file_map[(i - 1) as usize])) - } else { - return Err(TransformError("unexpected file index attribute").into()); - } - } - AttributeValue::DebugStrRef(str_offset) => { - let s = context.debug_str.get_str(str_offset)?.to_slice()?.to_vec(); - write::AttributeValue::StringRef(out_strings.add(s)) - } - AttributeValue::RangeListsRef(r) => { - let range_info = - RangeInfoBuilder::from_ranges_ref(r, context, unit_encoding, cu_low_pc)?; - let range_list_id = range_info.build_ranges(addr_tr, &mut out_unit.ranges); - write::AttributeValue::RangeListRef(range_list_id) - } - AttributeValue::LocationListsRef(r) => { - let low_pc = 0; - let mut locs = context.loclists.locations( - r, - unit_encoding, - low_pc, - &context.debug_addr, - context.debug_addr_base, - )?; - let frame_base = if let FileAttributeContext::Children(_, frame_base) = file_context - { - frame_base - } else { - None - }; - let mut result = None; - while let Some(loc) = locs.next()? { - if let Some(expr) = compile_expression(&loc.data, unit_encoding, frame_base)? { - if result.is_none() { - result = Some(Vec::new()); - } - for (start, len, expr) in expr.build_with_locals( - &[(loc.range.begin, loc.range.end)], - addr_tr, - frame_info, - endian, - ) { - if len == 0 { - // Ignore empty range - continue; - } - result.as_mut().unwrap().push(write::Location::StartLength { - begin: start, - length: len, - data: expr, - }); - } - } else { - // FIXME _expr contains invalid expression - continue; // ignore entry - } - } - if result.is_none() { - continue; // no valid locations - } - let list_id = out_unit.locations.add(write::LocationList(result.unwrap())); - write::AttributeValue::LocationListRef(list_id) - } - AttributeValue::Exprloc(ref expr) => { - let frame_base = if let FileAttributeContext::Children(_, frame_base) = file_context - { - frame_base - } else { - None - }; - if let Some(expr) = compile_expression(expr, unit_encoding, frame_base)? { - if expr.is_simple() { - if let Some(expr) = expr.build() { - write::AttributeValue::Exprloc(expr) - } else { - continue; - } - } else { - // Conversion to loclist is required. - if let Some(scope_ranges) = scope_ranges { - let exprs = - expr.build_with_locals(scope_ranges, addr_tr, frame_info, endian); - if exprs.is_empty() { - continue; - } - let found_single_expr = { - // Micro-optimization all expressions alike, use one exprloc. - let mut found_expr: Option = None; - for (_, _, expr) in &exprs { - if let Some(ref prev_expr) = found_expr { - if expr.0.eq(&prev_expr.0) { - continue; // the same expression - } - found_expr = None; - break; - } - found_expr = Some(expr.clone()) - } - found_expr - }; - if found_single_expr.is_some() { - write::AttributeValue::Exprloc(found_single_expr.unwrap()) - } else if is_exprloc_to_loclist_allowed(attr.name()) { - // Converting exprloc to loclist. - let mut locs = Vec::new(); - for (begin, length, data) in exprs { - if length == 0 { - // Ignore empty range - continue; - } - locs.push(write::Location::StartLength { - begin, - length, - data, - }); - } - let list_id = out_unit.locations.add(write::LocationList(locs)); - write::AttributeValue::LocationListRef(list_id) - } else { - continue; - } - } else { - continue; - } - } - } else { - // FIXME _expr contains invalid expression - continue; // ignore attribute - } - } - AttributeValue::Encoding(e) => write::AttributeValue::Encoding(e), - AttributeValue::DecimalSign(e) => write::AttributeValue::DecimalSign(e), - AttributeValue::Endianity(e) => write::AttributeValue::Endianity(e), - AttributeValue::Accessibility(e) => write::AttributeValue::Accessibility(e), - AttributeValue::Visibility(e) => write::AttributeValue::Visibility(e), - AttributeValue::Virtuality(e) => write::AttributeValue::Virtuality(e), - AttributeValue::Language(e) => write::AttributeValue::Language(e), - AttributeValue::AddressClass(e) => write::AttributeValue::AddressClass(e), - AttributeValue::IdentifierCase(e) => write::AttributeValue::IdentifierCase(e), - AttributeValue::CallingConvention(e) => write::AttributeValue::CallingConvention(e), - AttributeValue::Inline(e) => write::AttributeValue::Inline(e), - AttributeValue::Ordering(e) => write::AttributeValue::Ordering(e), - AttributeValue::UnitRef(ref offset) => { - if let Some(unit_id) = die_ref_map.get(offset) { - write::AttributeValue::ThisUnitEntryRef(*unit_id) - } else { - pending_die_refs.push((current_scope_id, attr.name(), *offset)); - continue; - } - } - // AttributeValue::DebugInfoRef(_) => { - // continue; - // } - _ => panic!(), //write::AttributeValue::StringRef(out_strings.add("_")), - }; - let current_scope = out_unit.get_mut(current_scope_id); - current_scope.set(attr.name(), attr_value); - } - Ok(()) -} - -pub(crate) fn clone_attr_string( - attr_value: &AttributeValue, - form: gimli::DwForm, - debug_str: &DebugStr, - out_strings: &mut write::StringTable, -) -> Result -where - R: Reader, -{ - let content = match attr_value { - AttributeValue::DebugStrRef(str_offset) => { - debug_str.get_str(*str_offset)?.to_slice()?.to_vec() - } - AttributeValue::String(b) => b.to_slice()?.to_vec(), - _ => panic!("Unexpected attribute value"), - }; - Ok(match form { - gimli::DW_FORM_strp => { - let id = out_strings.add(content); - write::LineString::StringRef(id) - } - gimli::DW_FORM_string => write::LineString::String(content), - _ => panic!("DW_FORM_line_strp or other not supported"), - }) -} diff --git a/lib/debug-writer/src/transform/expression.rs b/lib/debug-writer/src/transform/expression.rs deleted file mode 100644 index 390f5cba2..000000000 --- a/lib/debug-writer/src/transform/expression.rs +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright 2029 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `3992b8669f9b9e185abe81e9998ce2ff4d40ff68`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::address_transform::AddressTransform; -use anyhow::Error; -use cranelift_codegen::ir::{StackSlots, ValueLabel, ValueLoc}; -use cranelift_codegen::isa::RegUnit; -use cranelift_codegen::ValueLabelsRanges; -use cranelift_entity::EntityRef; -use cranelift_wasm::{get_vmctx_value_label, DefinedFuncIndex}; -use gimli::{self, write, Expression, Operation, Reader, ReaderOffset, Register, X86_64}; -use std::collections::{HashMap, HashSet}; - -#[derive(Debug)] -pub struct FunctionFrameInfo<'a> { - pub value_ranges: &'a ValueLabelsRanges, - pub memory_offset: i64, - pub stack_slots: &'a StackSlots, -} - -#[derive(Debug)] -enum CompiledExpressionPart { - Code(Vec), - Local(ValueLabel), - Deref, -} - -#[derive(Debug)] -pub struct CompiledExpression { - parts: Vec, - need_deref: bool, -} - -impl Clone for CompiledExpressionPart { - fn clone(&self) -> Self { - match self { - CompiledExpressionPart::Code(c) => CompiledExpressionPart::Code(c.clone()), - CompiledExpressionPart::Local(i) => CompiledExpressionPart::Local(*i), - CompiledExpressionPart::Deref => CompiledExpressionPart::Deref, - } - } -} - -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(label), - CompiledExpressionPart::Code(vec![gimli::constants::DW_OP_stack_value.0 as u8]), - ], - need_deref: false, - } - } -} - -fn map_reg(reg: RegUnit) -> Register { - static mut REG_X86_MAP: Option> = None; - // FIXME lazy initialization? - unsafe { - if REG_X86_MAP.is_none() { - REG_X86_MAP = Some(HashMap::new()); - } - if let Some(val) = REG_X86_MAP.as_mut().unwrap().get(®) { - return *val; - } - let result = match reg { - 0 => X86_64::RAX, - 1 => X86_64::RCX, - 2 => X86_64::RDX, - 3 => X86_64::RBX, - 4 => X86_64::RSP, - 5 => X86_64::RBP, - 6 => X86_64::RSI, - 7 => X86_64::RDI, - 8 => X86_64::R8, - 9 => X86_64::R9, - 10 => X86_64::R10, - 11 => X86_64::R11, - 12 => X86_64::R12, - 13 => X86_64::R13, - 14 => X86_64::R14, - 15 => X86_64::R15, - 16 => X86_64::XMM0, - 17 => X86_64::XMM1, - 18 => X86_64::XMM2, - 19 => X86_64::XMM3, - 20 => X86_64::XMM4, - 21 => X86_64::XMM5, - 22 => X86_64::XMM6, - 23 => X86_64::XMM7, - 24 => X86_64::XMM8, - 25 => X86_64::XMM9, - 26 => X86_64::XMM10, - 27 => X86_64::XMM11, - 28 => X86_64::XMM12, - 29 => X86_64::XMM13, - 30 => X86_64::XMM14, - 31 => X86_64::XMM15, - _ => panic!("unknown x86_64 register {}", reg), - }; - REG_X86_MAP.as_mut().unwrap().insert(reg, result); - result - } -} - -fn translate_loc(loc: ValueLoc, frame_info: Option<&FunctionFrameInfo>) -> Option> { - match loc { - ValueLoc::Reg(reg) => { - let machine_reg = map_reg(reg).0 as u8; - assert!(machine_reg < 32); // FIXME - Some(vec![gimli::constants::DW_OP_reg0.0 + machine_reg]) - } - ValueLoc::Stack(ss) => { - if let Some(frame_info) = frame_info { - if let Some(ss_offset) = frame_info.stack_slots[ss].offset { - use gimli::write::Writer; - let endian = gimli::RunTimeEndian::Little; - let mut writer = write::EndianVec::new(endian); - writer - .write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8) - .expect("bp wr"); - writer.write_sleb128(ss_offset as i64 + 16).expect("ss wr"); - writer - .write_u8(gimli::constants::DW_OP_deref.0 as u8) - .expect("bp wr"); - let buf = writer.into_vec(); - return Some(buf); - } - } - None - } - _ => None, - } -} - -fn append_memory_deref( - buf: &mut Vec, - frame_info: &FunctionFrameInfo, - vmctx_loc: ValueLoc, - endian: gimli::RunTimeEndian, -) -> write::Result { - use gimli::write::Writer; - let mut writer = write::EndianVec::new(endian); - match vmctx_loc { - ValueLoc::Reg(vmctx_reg) => { - let reg = map_reg(vmctx_reg); - writer.write_u8(gimli::constants::DW_OP_breg0.0 + reg.0 as u8)?; - writer.write_sleb128(frame_info.memory_offset)?; - } - ValueLoc::Stack(ss) => { - if let Some(ss_offset) = frame_info.stack_slots[ss].offset { - writer.write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)?; - writer.write_sleb128(ss_offset as i64 + 16)?; - writer.write_u8(gimli::constants::DW_OP_deref.0 as u8)?; - - writer.write_u8(gimli::constants::DW_OP_consts.0 as u8)?; - writer.write_sleb128(frame_info.memory_offset)?; - writer.write_u8(gimli::constants::DW_OP_plus.0 as u8)?; - } else { - return Ok(false); - } - } - _ => { - return Ok(false); - } - } - writer.write_u8(gimli::constants::DW_OP_deref.0 as u8)?; - writer.write_u8(gimli::constants::DW_OP_swap.0 as u8)?; - writer.write_u8(gimli::constants::DW_OP_stack_value.0 as u8)?; - writer.write_u8(gimli::constants::DW_OP_constu.0 as u8)?; - writer.write_uleb128(0xffff_ffff)?; - writer.write_u8(gimli::constants::DW_OP_and.0 as u8)?; - writer.write_u8(gimli::constants::DW_OP_plus.0 as u8)?; - buf.extend_from_slice(writer.slice()); - Ok(true) -} - -impl CompiledExpression { - pub fn is_simple(&self) -> bool { - if let [CompiledExpressionPart::Code(_)] = self.parts.as_slice() { - true - } else { - self.parts.is_empty() - } - } - - pub fn build(&self) -> Option { - if let [CompiledExpressionPart::Code(code)] = self.parts.as_slice() { - return Some(write::Expression(code.to_vec())); - } - // locals found, not supported - None - } - - pub fn build_with_locals( - &self, - scope: &[(u64, u64)], // wasm ranges - addr_tr: &AddressTransform, - frame_info: Option<&FunctionFrameInfo>, - endian: gimli::RunTimeEndian, - ) -> Vec<(write::Address, u64, write::Expression)> { - if scope.is_empty() { - return vec![]; - } - - if let [CompiledExpressionPart::Code(code)] = self.parts.as_slice() { - let mut result_scope = Vec::new(); - for s in scope { - for (addr, len) in addr_tr.translate_ranges(s.0, s.1) { - result_scope.push((addr, len, write::Expression(code.to_vec()))); - } - } - return result_scope; - } - - let vmctx_label = get_vmctx_value_label(); - - // Some locals are present, preparing and divided ranges based on the scope - // and frame_info data. - let mut ranges_builder = ValueLabelRangesBuilder::new(scope, addr_tr, frame_info); - for p in &self.parts { - match p { - CompiledExpressionPart::Code(_) => (), - CompiledExpressionPart::Local(label) => ranges_builder.process_label(*label), - CompiledExpressionPart::Deref => ranges_builder.process_label(vmctx_label), - } - } - if self.need_deref { - ranges_builder.process_label(vmctx_label); - } - ranges_builder.remove_incomplete_ranges(); - let ranges = ranges_builder.ranges; - - let mut result = Vec::new(); - 'range: for CachedValueLabelRange { - func_index, - start, - end, - label_location, - } in ranges - { - // build expression - let mut code_buf = Vec::new(); - for part in &self.parts { - match part { - CompiledExpressionPart::Code(c) => code_buf.extend_from_slice(c.as_slice()), - CompiledExpressionPart::Local(label) => { - let loc = *label_location.get(&label).expect("loc"); - if let Some(expr) = translate_loc(loc, frame_info) { - code_buf.extend_from_slice(&expr) - } else { - continue 'range; - } - } - CompiledExpressionPart::Deref => { - if let (Some(vmctx_loc), Some(frame_info)) = - (label_location.get(&vmctx_label), frame_info) - { - if !append_memory_deref(&mut code_buf, frame_info, *vmctx_loc, endian) - .expect("append_memory_deref") - { - continue 'range; - } - } else { - continue 'range; - }; - } - } - } - if self.need_deref { - if let (Some(vmctx_loc), Some(frame_info)) = - (label_location.get(&vmctx_label), frame_info) - { - if !append_memory_deref(&mut code_buf, frame_info, *vmctx_loc, endian) - .expect("append_memory_deref") - { - continue 'range; - } - } else { - continue 'range; - }; - } - result.push(( - write::Address::Symbol { - symbol: func_index.index(), - addend: start as i64, - }, - (end - start) as u64, - write::Expression(code_buf), - )); - } - - result - } -} - -pub fn compile_expression( - expr: &Expression, - encoding: gimli::Encoding, - frame_base: Option<&CompiledExpression>, -) -> Result, Error> -where - R: Reader, -{ - let mut parts = Vec::new(); - let mut need_deref = false; - if let Some(frame_base) = frame_base { - parts.extend_from_slice(&frame_base.parts); - need_deref = frame_base.need_deref; - } - let base_len = parts.len(); - let mut pc = expr.0.clone(); - let mut code_chunk = Vec::new(); - let buf = expr.0.to_slice()?; - while !pc.is_empty() { - let next = buf[pc.offset_from(&expr.0).into_u64() as usize]; - need_deref = true; - if next == 0xED { - // WebAssembly DWARF extension - pc.read_u8()?; - let ty = pc.read_uleb128()?; - assert_eq!(ty, 0); - let index = pc.read_sleb128()?; - pc.read_u8()?; // consume 159 - if code_chunk.len() > 0 { - parts.push(CompiledExpressionPart::Code(code_chunk)); - code_chunk = Vec::new(); - } - let label = ValueLabel::from_u32(index as u32); - parts.push(CompiledExpressionPart::Local(label)); - } else { - let pos = pc.offset_from(&expr.0).into_u64() as usize; - let op = Operation::parse(&mut pc, &expr.0, encoding)?; - match op { - Operation::Literal { .. } | Operation::PlusConstant { .. } => (), - Operation::StackValue => { - need_deref = false; - } - Operation::Deref { .. } => { - if code_chunk.len() > 0 { - parts.push(CompiledExpressionPart::Code(code_chunk)); - code_chunk = Vec::new(); - } - parts.push(CompiledExpressionPart::Deref); - } - _ => { - return Ok(None); - } - } - let chunk = &buf[pos..pc.offset_from(&expr.0).into_u64() as usize]; - code_chunk.extend_from_slice(chunk); - } - } - - if code_chunk.len() > 0 { - parts.push(CompiledExpressionPart::Code(code_chunk)); - } - - if base_len > 0 && base_len + 1 < parts.len() { - // see if we can glue two code chunks - if let [CompiledExpressionPart::Code(cc1), CompiledExpressionPart::Code(cc2)] = - &parts[base_len..base_len + 1] - { - let mut combined = cc1.clone(); - combined.extend_from_slice(cc2); - parts[base_len] = CompiledExpressionPart::Code(combined); - parts.remove(base_len + 1); - } - } - - Ok(Some(CompiledExpression { parts, need_deref })) -} - -#[derive(Debug, Clone)] -struct CachedValueLabelRange { - func_index: DefinedFuncIndex, - start: usize, - end: usize, - label_location: HashMap, -} - -struct ValueLabelRangesBuilder<'a, 'b> { - ranges: Vec, - addr_tr: &'a AddressTransform, - frame_info: Option<&'a FunctionFrameInfo<'b>>, - processed_labels: HashSet, -} - -impl<'a, 'b> ValueLabelRangesBuilder<'a, 'b> { - fn new( - scope: &[(u64, u64)], // wasm ranges - addr_tr: &'a AddressTransform, - frame_info: Option<&'a FunctionFrameInfo<'b>>, - ) -> Self { - let mut ranges = Vec::new(); - for s in scope { - if let Some((func_index, tr)) = addr_tr.translate_ranges_raw(s.0, s.1) { - for (start, end) in tr { - ranges.push(CachedValueLabelRange { - func_index, - start, - end, - label_location: HashMap::new(), - }) - } - } - } - ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start)); - ValueLabelRangesBuilder { - ranges, - addr_tr, - frame_info, - processed_labels: HashSet::new(), - } - } - - fn process_label(&mut self, label: ValueLabel) { - if self.processed_labels.contains(&label) { - return; - } - self.processed_labels.insert(label); - - let value_ranges = if let Some(frame_info) = self.frame_info { - &frame_info.value_ranges - } else { - return; - }; - - let ranges = &mut self.ranges; - if let Some(local_ranges) = value_ranges.get(&label) { - for local_range in local_ranges { - let wasm_start = local_range.start; - let wasm_end = local_range.end; - let loc = local_range.loc; - // Find all native ranges for the value label ranges. - for (addr, len) in self - .addr_tr - .translate_ranges(wasm_start as u64, wasm_end as u64) - { - let (range_start, range_end) = self.addr_tr.convert_to_code_range(addr, len); - if range_start == range_end { - continue; - } - assert!(range_start < range_end); - // Find acceptable scope of ranges to intersect with. - let i = match ranges.binary_search_by(|s| s.start.cmp(&range_start)) { - Ok(i) => i, - Err(i) => { - if i > 0 && range_start < ranges[i - 1].end { - i - 1 - } else { - i - } - } - }; - let j = match ranges.binary_search_by(|s| s.start.cmp(&range_end)) { - Ok(i) | Err(i) => i, - }; - // Starting for the end, intersect (range_start..range_end) with - // self.ranges array. - for i in (i..j).rev() { - if range_end <= ranges[i].start || ranges[i].end <= range_start { - continue; - } - if range_end < ranges[i].end { - // Cutting some of the range from the end. - let mut tail = ranges[i].clone(); - ranges[i].end = range_end; - tail.start = range_end; - ranges.insert(i + 1, tail); - } - assert!(ranges[i].end <= range_end); - if range_start <= ranges[i].start { - ranges[i].label_location.insert(label, loc); - continue; - } - // Cutting some of the range from the start. - let mut tail = ranges[i].clone(); - ranges[i].end = range_start; - tail.start = range_start; - tail.label_location.insert(label, loc); - ranges.insert(i + 1, tail); - } - } - } - } - } - - fn remove_incomplete_ranges(&mut self) { - // Ranges with not-enough labels are discarded. - let processed_labels_len = self.processed_labels.len(); - self.ranges - .retain(|r| r.label_location.len() == processed_labels_len); - } -} diff --git a/lib/debug-writer/src/transform/line_program.rs b/lib/debug-writer/src/transform/line_program.rs deleted file mode 100644 index f584630a0..000000000 --- a/lib/debug-writer/src/transform/line_program.rs +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `cc6e8e1af25e5f9b64e183970d50f62c8338f259`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::address_transform::AddressTransform; -use super::attr::clone_attr_string; -use super::{Reader, TransformError}; -use anyhow::Error; -use cranelift_entity::EntityRef; -use gimli::{ - write, DebugLine, DebugLineOffset, DebugStr, DebuggingInformationEntry, LineEncoding, Unit, -}; -use std::collections::BTreeMap; -use std::iter::FromIterator; - -#[derive(Debug)] -enum SavedLineProgramRow { - Normal { - address: u64, - op_index: u64, - file_index: u64, - line: u64, - column: u64, - discriminator: u64, - is_stmt: bool, - basic_block: bool, - prologue_end: bool, - epilogue_begin: bool, - isa: u64, - }, - EndOfSequence(u64), -} - -#[derive(Debug, Eq, PartialEq)] -enum ReadLineProgramState { - SequenceEnded, - ReadSequence, - IgnoreSequence, -} - -pub(crate) fn clone_line_program( - unit: &Unit, - root: &DebuggingInformationEntry, - addr_tr: &AddressTransform, - out_encoding: gimli::Encoding, - debug_str: &DebugStr, - debug_line: &DebugLine, - out_strings: &mut write::StringTable, -) -> Result<(write::LineProgram, DebugLineOffset, Vec), Error> -where - R: Reader, -{ - let offset = match root.attr_value(gimli::DW_AT_stmt_list)? { - Some(gimli::AttributeValue::DebugLineRef(offset)) => offset, - _ => { - return Err(TransformError("Debug line offset is not found").into()); - } - }; - let comp_dir = root.attr_value(gimli::DW_AT_comp_dir)?; - let comp_name = root.attr_value(gimli::DW_AT_name)?; - let out_comp_dir = clone_attr_string( - comp_dir.as_ref().expect("comp_dir"), - gimli::DW_FORM_strp, - debug_str, - out_strings, - )?; - let out_comp_name = clone_attr_string( - comp_name.as_ref().expect("comp_name"), - gimli::DW_FORM_strp, - debug_str, - out_strings, - )?; - - let program = debug_line.program( - offset, - unit.header.address_size(), - comp_dir.and_then(|val| val.string_value(&debug_str)), - comp_name.and_then(|val| val.string_value(&debug_str)), - ); - if let Ok(program) = program { - let header = program.header(); - assert!(header.version() <= 4, "not supported 5"); - let line_encoding = LineEncoding { - minimum_instruction_length: header.minimum_instruction_length(), - maximum_operations_per_instruction: header.maximum_operations_per_instruction(), - default_is_stmt: header.default_is_stmt(), - line_base: header.line_base(), - line_range: header.line_range(), - }; - let mut out_program = write::LineProgram::new( - out_encoding, - line_encoding, - out_comp_dir, - out_comp_name, - None, - ); - let mut dirs = Vec::new(); - dirs.push(out_program.default_directory()); - for dir_attr in header.include_directories() { - let dir_id = out_program.add_directory(clone_attr_string( - dir_attr, - gimli::DW_FORM_string, - debug_str, - out_strings, - )?); - dirs.push(dir_id); - } - let mut files = Vec::new(); - for file_entry in header.file_names() { - let dir_id = dirs[file_entry.directory_index() as usize]; - let file_id = out_program.add_file( - clone_attr_string( - &file_entry.path_name(), - gimli::DW_FORM_string, - debug_str, - out_strings, - )?, - dir_id, - None, - ); - files.push(file_id); - } - - let mut rows = program.rows(); - let mut saved_rows = BTreeMap::new(); - let mut state = ReadLineProgramState::SequenceEnded; - while let Some((_header, row)) = rows.next_row()? { - if state == ReadLineProgramState::IgnoreSequence { - if row.end_sequence() { - state = ReadLineProgramState::SequenceEnded; - } - continue; - } - let saved_row = if row.end_sequence() { - state = ReadLineProgramState::SequenceEnded; - SavedLineProgramRow::EndOfSequence(row.address()) - } else { - if state == ReadLineProgramState::SequenceEnded { - // Discard sequences for non-existent code. - if row.address() == 0 { - state = ReadLineProgramState::IgnoreSequence; - continue; - } - state = ReadLineProgramState::ReadSequence; - } - SavedLineProgramRow::Normal { - address: row.address(), - op_index: row.op_index(), - file_index: row.file_index(), - line: row.line().unwrap_or(0), - column: match row.column() { - gimli::ColumnType::LeftEdge => 0, - gimli::ColumnType::Column(val) => val, - }, - discriminator: row.discriminator(), - is_stmt: row.is_stmt(), - basic_block: row.basic_block(), - prologue_end: row.prologue_end(), - epilogue_begin: row.epilogue_begin(), - isa: row.isa(), - } - }; - saved_rows.insert(row.address(), saved_row); - } - - let saved_rows = Vec::from_iter(saved_rows.into_iter()); - for (i, map) in addr_tr.map() { - if map.len == 0 { - continue; // no code generated - } - let symbol = i.index(); - let base_addr = map.offset; - 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() { - let saved_row = match saved_rows.binary_search_by_key(&addr_map.wasm, |i| i.0) { - Ok(i) => Some(&saved_rows[i].1), - Err(i) => { - if i > 0 { - Some(&saved_rows[i - 1].1) - } else { - None - } - } - }; - if let Some(SavedLineProgramRow::Normal { - address, - op_index, - file_index, - line, - column, - discriminator, - is_stmt, - basic_block, - prologue_end, - epilogue_begin, - isa, - }) = saved_row - { - // Ignore duplicates - if Some(*address) != last_address { - let address_offset = if last_address.is_none() { - // Extend first entry to the function declaration - // TODO use the function declaration line instead - 0 - } else { - (addr_map.generated - base_addr) as u64 - }; - out_program.row().address_offset = address_offset; - out_program.row().op_index = *op_index; - out_program.row().file = files[(file_index - 1) as usize]; - out_program.row().line = *line; - out_program.row().column = *column; - out_program.row().discriminator = *discriminator; - out_program.row().is_statement = *is_stmt; - out_program.row().basic_block = *basic_block; - out_program.row().prologue_end = *prologue_end; - out_program.row().epilogue_begin = *epilogue_begin; - out_program.row().isa = *isa; - out_program.generate_row(); - last_address = Some(*address); - } - } - } - let end_addr = (map.offset + map.len - 1) as u64; - out_program.end_sequence(end_addr); - } - Ok((out_program, offset, files)) - } else { - Err(TransformError("Valid line program not found").into()) - } -} diff --git a/lib/debug-writer/src/transform/mod.rs b/lib/debug-writer/src/transform/mod.rs deleted file mode 100644 index 9b79765c2..000000000 --- a/lib/debug-writer/src/transform/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `907e7aac01af333a0af310ce0472abbc8a9adb6c`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use crate::gc::build_dependencies; -use crate::DebugInfoData; -use anyhow::Error; -use cranelift_codegen::isa::TargetFrontendConfig; -use gimli::{ - write, DebugAddr, DebugAddrBase, DebugLine, DebugStr, LocationLists, RangeLists, - UnitSectionOffset, -}; -use simulate::generate_simulated_dwarf; -use std::collections::HashSet; -use thiserror::Error; -use unit::clone_unit; -use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; - -pub use address_transform::AddressTransform; - -mod address_transform; -mod attr; -mod expression; -mod line_program; -mod range_info_builder; -mod simulate; -mod unit; -mod utils; - -pub(crate) trait Reader: gimli::Reader {} - -impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where Endian: gimli::Endianity {} - -#[derive(Error, Debug)] -#[error("Debug info transform error: {0}")] -pub struct TransformError(&'static str); - -pub(crate) struct DebugInputContext<'a, R> -where - R: Reader, -{ - debug_str: &'a DebugStr, - debug_line: &'a DebugLine, - debug_addr: &'a DebugAddr, - debug_addr_base: DebugAddrBase, - rnglists: &'a RangeLists, - loclists: &'a LocationLists, - reachable: &'a HashSet, -} - -pub fn transform_dwarf( - target_config: &TargetFrontendConfig, - di: &DebugInfoData, - at: &ModuleAddressMap, - vmctx_info: &ModuleVmctxInfo, - ranges: &ValueLabelsRanges, -) -> Result { - let addr_tr = AddressTransform::new(at, &di.wasm_file); - let reachable = build_dependencies(&di.dwarf, &addr_tr)?.get_reachable(); - - let context = DebugInputContext { - debug_str: &di.dwarf.debug_str, - debug_line: &di.dwarf.debug_line, - debug_addr: &di.dwarf.debug_addr, - debug_addr_base: DebugAddrBase(0), - rnglists: &di.dwarf.ranges, - loclists: &di.dwarf.locations, - reachable: &reachable, - }; - - let out_encoding = gimli::Encoding { - format: gimli::Format::Dwarf32, - // TODO: this should be configurable - // macOS doesn't seem to support DWARF > 3 - version: 3, - address_size: target_config.pointer_bytes(), - }; - - let mut out_strings = write::StringTable::default(); - let mut out_units = write::UnitTable::default(); - - 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)?; - clone_unit( - unit, - &context, - &addr_tr, - &ranges, - out_encoding, - &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![], - line_strings: out_line_strings, - strings: out_strings, - }) -} diff --git a/lib/debug-writer/src/transform/range_info_builder.rs b/lib/debug-writer/src/transform/range_info_builder.rs deleted file mode 100644 index 881dcca1e..000000000 --- a/lib/debug-writer/src/transform/range_info_builder.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `907e7aac01af333a0af310ce0472abbc8a9adb6c`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::address_transform::AddressTransform; -use super::{DebugInputContext, Reader}; -use anyhow::Error; -use cranelift_entity::EntityRef; -use wasmer_runtime_core::types::FuncIndex -use gimli::{write, AttributeValue, DebuggingInformationEntry, RangeListsOffset}; - -pub(crate) enum RangeInfoBuilder { - Undefined, - Position(u64), - Ranges(Vec<(u64, u64)>), - Function(FuncIndex), -} - -impl RangeInfoBuilder { - pub(crate) fn from( - entry: &DebuggingInformationEntry, - context: &DebugInputContext, - unit_encoding: gimli::Encoding, - cu_low_pc: u64, - ) -> Result - where - R: Reader, - { - if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges)? { - return RangeInfoBuilder::from_ranges_ref(r, context, unit_encoding, cu_low_pc); - }; - - let low_pc = - if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? { - addr - } else { - return Ok(RangeInfoBuilder::Undefined); - }; - - Ok( - if let Some(AttributeValue::Udata(u)) = entry.attr_value(gimli::DW_AT_high_pc)? { - RangeInfoBuilder::Ranges(vec![(low_pc, low_pc + u)]) - } else { - RangeInfoBuilder::Position(low_pc) - }, - ) - } - - pub(crate) fn from_ranges_ref( - ranges: RangeListsOffset, - context: &DebugInputContext, - unit_encoding: gimli::Encoding, - cu_low_pc: u64, - ) -> Result - where - R: Reader, - { - let mut ranges = context.rnglists.ranges( - ranges, - unit_encoding, - cu_low_pc, - &context.debug_addr, - context.debug_addr_base, - )?; - let mut result = Vec::new(); - while let Some(range) = ranges.next()? { - if range.begin >= range.end { - // ignore empty ranges - } - result.push((range.begin, range.end)); - } - - Ok(if result.len() > 0 { - RangeInfoBuilder::Ranges(result) - } else { - RangeInfoBuilder::Undefined - }) - } - - pub(crate) fn from_subprogram_die( - entry: &DebuggingInformationEntry, - context: &DebugInputContext, - unit_encoding: gimli::Encoding, - addr_tr: &AddressTransform, - cu_low_pc: u64, - ) -> Result - where - R: Reader, - { - let addr = - if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? { - addr - } else if let Some(AttributeValue::RangeListsRef(r)) = - entry.attr_value(gimli::DW_AT_ranges)? - { - let mut ranges = context.rnglists.ranges( - r, - unit_encoding, - cu_low_pc, - &context.debug_addr, - context.debug_addr_base, - )?; - if let Some(range) = ranges.next()? { - range.begin - } else { - return Ok(RangeInfoBuilder::Undefined); - } - } else { - return Ok(RangeInfoBuilder::Undefined); - }; - - let index = addr_tr.find_func_index(addr); - if index.is_none() { - return Ok(RangeInfoBuilder::Undefined); - } - Ok(RangeInfoBuilder::Function(index.unwrap())) - } - - pub(crate) fn build( - &self, - addr_tr: &AddressTransform, - out_unit: &mut write::Unit, - current_scope_id: write::UnitEntryId, - ) { - match self { - RangeInfoBuilder::Undefined => (), - RangeInfoBuilder::Position(pc) => { - let addr = addr_tr - .translate(*pc) - .unwrap_or(write::Address::Constant(0)); - let current_scope = out_unit.get_mut(current_scope_id); - current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr)); - } - RangeInfoBuilder::Ranges(ranges) => { - let mut result = Vec::new(); - for (begin, end) in ranges { - for tr in addr_tr.translate_ranges(*begin, *end) { - if tr.1 == 0 { - // Ignore empty range - continue; - } - result.push(tr); - } - } - if result.len() != 1 { - let range_list = result - .iter() - .map(|tr| write::Range::StartLength { - begin: tr.0, - length: tr.1, - }) - .collect::>(); - let range_list_id = out_unit.ranges.add(write::RangeList(range_list)); - let current_scope = out_unit.get_mut(current_scope_id); - current_scope.set( - gimli::DW_AT_ranges, - write::AttributeValue::RangeListRef(range_list_id), - ); - } else { - let current_scope = out_unit.get_mut(current_scope_id); - current_scope.set( - gimli::DW_AT_low_pc, - write::AttributeValue::Address(result[0].0), - ); - current_scope.set( - gimli::DW_AT_high_pc, - write::AttributeValue::Udata(result[0].1), - ); - } - } - RangeInfoBuilder::Function(index) => { - let range = addr_tr.func_range(*index); - let symbol = index.index(); - let addr = write::Address::Symbol { - symbol, - addend: range.0 as i64, - }; - let len = (range.1 - range.0) as u64; - let current_scope = out_unit.get_mut(current_scope_id); - current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr)); - current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len)); - } - } - } - - pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> { - match self { - RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![], - RangeInfoBuilder::Ranges(ranges) => ranges.clone(), - RangeInfoBuilder::Function(index) => { - let range = addr_tr.func_source_range(*index); - vec![(range.0, range.1)] - } - } - } - - pub(crate) fn build_ranges( - &self, - addr_tr: &AddressTransform, - out_range_lists: &mut write::RangeListTable, - ) -> write::RangeListId { - if let RangeInfoBuilder::Ranges(ranges) = self { - let mut range_list = Vec::new(); - for (begin, end) in ranges { - assert!(begin < end); - for tr in addr_tr.translate_ranges(*begin, *end) { - if tr.1 == 0 { - // Ignore empty range - continue; - } - range_list.push(write::Range::StartLength { - begin: tr.0, - length: tr.1, - }); - } - } - out_range_lists.add(write::RangeList(range_list)) - } else { - unreachable!(); - } - } -} diff --git a/lib/debug-writer/src/transform/simulate.rs b/lib/debug-writer/src/transform/simulate.rs deleted file mode 100644 index 244878c73..000000000 --- a/lib/debug-writer/src/transform/simulate.rs +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `cc6e8e1af25e5f9b64e183970d50f62c8338f259`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::expression::{CompiledExpression, FunctionFrameInfo}; -use super::utils::{add_internal_types, append_vmctx_info, get_function_frame_info}; -use super::AddressTransform; -use crate::read_debug_info::WasmFileInfo; -use anyhow::Error; -use cranelift_entity::EntityRef; -use cranelift_wasm::get_vmctx_value_label; -use gimli::write; -use gimli::{self, LineEncoding}; -use std::collections::{HashMap, HashSet}; -use std::path::PathBuf; -// TODO: ValueLabelsRanges -use wasmer_runtime_core::{module::ModuleInfo, state::CodeVersion}; - -pub use crate::read_debug_info::{DebugInfoData, FunctionMetadata, WasmType}; - -const PRODUCER_NAME: &str = "wasmtime"; - -fn generate_line_info( - addr_tr: &AddressTransform, - translated: &HashSet, - out_encoding: gimli::Encoding, - w: &WasmFileInfo, - comp_dir_id: write::StringId, - name_id: write::StringId, - name: &str, -) -> Result { - 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_ID) - }); - let path = format!("//{}.wasm", module_name); - PathBuf::from(path) -} - -struct WasmTypesDieRefs { - vmctx: write::UnitEntryId, - i32: write::UnitEntryId, - i64: write::UnitEntryId, - i128: 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: &ModuleInfo, -) -> 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 i128_die_id = def_type!("i128", 16, 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, - i128: i128_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>, - out_strings: &mut write::StringTable, -) { - let vmctx_label = get_vmctx_value_label(); - - for label in frame_info.value_ranges.keys() { - 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); - 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, - 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(()) -} diff --git a/lib/debug-writer/src/transform/unit.rs b/lib/debug-writer/src/transform/unit.rs deleted file mode 100644 index 042095072..000000000 --- a/lib/debug-writer/src/transform/unit.rs +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `907e7aac01af333a0af310ce0472abbc8a9adb6c`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::address_transform::AddressTransform; -use super::attr::{clone_die_attributes, FileAttributeContext}; -use super::expression::compile_expression; -use super::line_program::clone_line_program; -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 anyhow::Error; -use cranelift_entity::EntityRef; -use gimli::write; -use gimli::{AttributeValue, DebuggingInformationEntry, Unit, UnitOffset}; -use std::collections::{HashMap, HashSet}; -use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges}; - -pub(crate) type PendingDieRef = (write::UnitEntryId, gimli::DwAt, UnitOffset); - -struct InheritedAttr { - stack: Vec<(usize, T)>, -} - -impl InheritedAttr { - fn new() -> Self { - InheritedAttr { stack: Vec::new() } - } - - fn update(&mut self, depth: usize) { - while !self.stack.is_empty() && self.stack.last().unwrap().0 >= depth { - self.stack.pop(); - } - } - - fn push(&mut self, depth: usize, value: T) { - self.stack.push((depth, value)); - } - - fn top(&self) -> Option<&T> { - self.stack.last().map(|entry| &entry.1) - } - - fn is_empty(&self) -> bool { - self.stack.is_empty() - } -} - -fn get_base_type_name( - type_entry: &DebuggingInformationEntry, - unit: &Unit, - context: &DebugInputContext, -) -> Result -where - R: Reader, -{ - // FIXME remove recursion. - match type_entry.attr_value(gimli::DW_AT_type)? { - Some(AttributeValue::UnitRef(ref offset)) => { - let mut entries = unit.entries_at_offset(*offset)?; - entries.next_entry()?; - if let Some(die) = entries.current() { - if let Some(AttributeValue::DebugStrRef(str_offset)) = - die.attr_value(gimli::DW_AT_name)? - { - return Ok(String::from( - context.debug_str.get_str(str_offset)?.to_string()?, - )); - } - match die.tag() { - gimli::DW_TAG_const_type => { - return Ok(format!("const {}", get_base_type_name(die, unit, context)?)); - } - gimli::DW_TAG_pointer_type => { - return Ok(format!("{}*", get_base_type_name(die, unit, context)?)); - } - gimli::DW_TAG_reference_type => { - return Ok(format!("{}&", get_base_type_name(die, unit, context)?)); - } - gimli::DW_TAG_array_type => { - return Ok(format!("{}[]", get_base_type_name(die, unit, context)?)); - } - _ => (), - } - } - } - _ => (), - }; - Ok(String::from("??")) -} - -fn replace_pointer_type( - parent_id: write::UnitEntryId, - comp_unit: &mut write::Unit, - wp_die_id: write::UnitEntryId, - entry: &DebuggingInformationEntry, - unit: &Unit, - context: &DebugInputContext, - out_strings: &mut write::StringTable, - pending_die_refs: &mut Vec<(write::UnitEntryId, gimli::DwAt, UnitOffset)>, -) -> Result -where - R: Reader, -{ - let die_id = comp_unit.add(parent_id, gimli::DW_TAG_structure_type); - let die = comp_unit.get_mut(die_id); - - let name = format!( - "WebAssemblyPtrWrapper<{}>", - get_base_type_name(entry, unit, context)? - ); - die.set( - gimli::DW_AT_name, - write::AttributeValue::StringRef(out_strings.add(name.as_str())), - ); - die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1(4)); - - let p_die_id = comp_unit.add(die_id, gimli::DW_TAG_template_type_parameter); - let p_die = comp_unit.get_mut(p_die_id); - p_die.set( - gimli::DW_AT_name, - write::AttributeValue::StringRef(out_strings.add("T")), - ); - p_die.set( - gimli::DW_AT_type, - write::AttributeValue::ThisUnitEntryRef(wp_die_id), - ); - match entry.attr_value(gimli::DW_AT_type)? { - Some(AttributeValue::UnitRef(ref offset)) => { - pending_die_refs.push((p_die_id, gimli::DW_AT_type, *offset)) - } - _ => (), - } - - let m_die_id = comp_unit.add(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("__ptr")), - ); - m_die.set( - gimli::DW_AT_type, - write::AttributeValue::ThisUnitEntryRef(wp_die_id), - ); - m_die.set( - gimli::DW_AT_data_member_location, - write::AttributeValue::Data1(0), - ); - Ok(die_id) -} - -pub(crate) fn clone_unit<'a, R>( - unit: Unit, - context: &DebugInputContext, - addr_tr: &'a AddressTransform, - value_ranges: &'a ValueLabelsRanges, - out_encoding: gimli::Encoding, - module_info: &ModuleVmctxInfo, - out_units: &mut write::UnitTable, - out_strings: &mut write::StringTable, - translated: &mut HashSet, -) -> Result<(), Error> -where - R: Reader, -{ - let mut die_ref_map = HashMap::new(); - let mut pending_die_refs = Vec::new(); - let mut stack = Vec::new(); - - // Iterate over all of this compilation unit's entries. - let mut entries = unit.entries(); - let (mut comp_unit, file_map, cu_low_pc, wp_die_id, vmctx_die_id) = - if let Some((depth_delta, entry)) = entries.next_dfs()? { - assert_eq!(depth_delta, 0); - let (out_line_program, debug_line_offset, file_map) = clone_line_program( - &unit, - entry, - addr_tr, - out_encoding, - context.debug_str, - context.debug_line, - out_strings, - )?; - - if entry.tag() == gimli::DW_TAG_compile_unit { - let unit_id = out_units.add(write::Unit::new(out_encoding, out_line_program)); - let comp_unit = out_units.get_mut(unit_id); - - let root_id = comp_unit.root(); - die_ref_map.insert(entry.offset(), root_id); - - let cu_low_pc = if let Some(AttributeValue::Addr(addr)) = - entry.attr_value(gimli::DW_AT_low_pc)? - { - addr - } else { - // FIXME? return Err(TransformError("No low_pc for unit header").into()); - 0 - }; - - clone_die_attributes( - entry, - context, - addr_tr, - None, - unit.encoding(), - comp_unit, - root_id, - None, - None, - cu_low_pc, - out_strings, - &die_ref_map, - &mut pending_die_refs, - FileAttributeContext::Root(Some(debug_line_offset)), - )?; - - let (wp_die_id, vmctx_die_id) = - add_internal_types(comp_unit, root_id, out_strings, module_info); - - stack.push(root_id); - (comp_unit, file_map, cu_low_pc, wp_die_id, vmctx_die_id) - } else { - return Err(TransformError("Unexpected unit header").into()); - } - } else { - return Ok(()); // empty - }; - let mut skip_at_depth = None; - let mut current_frame_base = InheritedAttr::new(); - let mut current_value_range = InheritedAttr::new(); - let mut current_scope_ranges = InheritedAttr::new(); - while let Some((depth_delta, entry)) = entries.next_dfs()? { - let depth_delta = if let Some((depth, cached)) = skip_at_depth { - let new_depth = depth + depth_delta; - if new_depth > 0 { - skip_at_depth = Some((new_depth, cached)); - continue; - } - skip_at_depth = None; - new_depth + cached - } else { - depth_delta - }; - - if !context - .reachable - .contains(&entry.offset().to_unit_section_offset(&unit)) - { - // entry is not reachable: discarding all its info. - skip_at_depth = Some((0, depth_delta)); - continue; - } - - let new_stack_len = stack.len().wrapping_add(depth_delta as usize); - current_frame_base.update(new_stack_len); - current_scope_ranges.update(new_stack_len); - current_value_range.update(new_stack_len); - let range_builder = if entry.tag() == gimli::DW_TAG_subprogram { - let range_builder = RangeInfoBuilder::from_subprogram_die( - entry, - context, - unit.encoding(), - addr_tr, - cu_low_pc, - )?; - if let RangeInfoBuilder::Function(func_index) = range_builder { - if let Some(frame_info) = - get_function_frame_info(module_info, func_index, value_ranges) - { - 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)); - Some(range_builder) - } else { - // FIXME current_scope_ranges.push() - None - } - } else { - let high_pc = entry.attr_value(gimli::DW_AT_high_pc)?; - let ranges = entry.attr_value(gimli::DW_AT_ranges)?; - if high_pc.is_some() || ranges.is_some() { - let range_builder = - RangeInfoBuilder::from(entry, context, unit.encoding(), cu_low_pc)?; - current_scope_ranges.push(new_stack_len, range_builder.get_ranges(addr_tr)); - Some(range_builder) - } else { - None - } - }; - - if depth_delta <= 0 { - for _ in depth_delta..1 { - stack.pop(); - } - } else { - assert_eq!(depth_delta, 1); - } - - if let Some(AttributeValue::Exprloc(expr)) = entry.attr_value(gimli::DW_AT_frame_base)? { - if let Some(expr) = compile_expression(&expr, unit.encoding(), None)? { - current_frame_base.push(new_stack_len, expr); - } - } - - let parent = stack.last().unwrap(); - - if entry.tag() == gimli::DW_TAG_pointer_type { - // Wrap pointer types. - // TODO reference types? - let die_id = replace_pointer_type( - *parent, - comp_unit, - wp_die_id, - entry, - &unit, - context, - out_strings, - &mut pending_die_refs, - )?; - stack.push(die_id); - assert_eq!(stack.len(), new_stack_len); - die_ref_map.insert(entry.offset(), die_id); - continue; - } - - let die_id = comp_unit.add(*parent, entry.tag()); - - stack.push(die_id); - assert_eq!(stack.len(), new_stack_len); - die_ref_map.insert(entry.offset(), die_id); - - clone_die_attributes( - entry, - context, - addr_tr, - current_value_range.top(), - unit.encoding(), - &mut comp_unit, - die_id, - range_builder, - current_scope_ranges.top(), - cu_low_pc, - out_strings, - &die_ref_map, - &mut pending_die_refs, - FileAttributeContext::Children(&file_map, current_frame_base.top()), - )?; - - if entry.tag() == gimli::DW_TAG_subprogram && !current_scope_ranges.is_empty() { - append_vmctx_info( - comp_unit, - die_id, - vmctx_die_id, - addr_tr, - current_value_range.top(), - current_scope_ranges.top().expect("range"), - out_strings, - )?; - } - } - for (die_id, attr_name, offset) in pending_die_refs { - let die = comp_unit.get_mut(die_id); - if let Some(unit_id) = die_ref_map.get(&offset) { - die.set(attr_name, write::AttributeValue::ThisUnitEntryRef(*unit_id)); - } else { - // TODO check why loosing DIEs - } - } - Ok(()) -} diff --git a/lib/debug-writer/src/transform/utils.rs b/lib/debug-writer/src/transform/utils.rs deleted file mode 100644 index 207ec6540..000000000 --- a/lib/debug-writer/src/transform/utils.rs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. -// It was copied at revision `cc6e8e1af25e5f9b64e183970d50f62c8338f259`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. -use super::address_transform::AddressTransform; -use super::expression::{CompiledExpression, FunctionFrameInfo}; -use anyhow::Error; -// TODO: review -use wasmer_runtime_core::types::FuncIndex; -use gimli::write; -use wasmer_runtime_core::{module::ModuleInfo, state::CodeVersion}; -// TODO: ValueLabelsRanges - -pub(crate) fn add_internal_types( - comp_unit: &mut write::Unit, - root_id: write::UnitEntryId, - out_strings: &mut write::StringTable, - module_info: &ModuleInfo, -) -> (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 = unimplemented!("TODO"); - 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("WasmerVMContext")), - ); - 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("WasmerVMContext*")), - ); - 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 ModuleInfo, - func_index: FuncIndex, - value_ranges: &'c ValueLabelsRanges, -) -> Option> -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 - } -} diff --git a/lib/debug-writer/src/write_debug_info.rs b/lib/debug-writer/src/write_debug_info.rs deleted file mode 100644 index 365643733..000000000 --- a/lib/debug-writer/src/write_debug_info.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2019 WasmTime Project Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file is from the WasmTime project. It reads DWARF info from a Wasm module. -// It was copied at revision `ea73d4fa91399349fd8d42e833363a0b1cad9f1c`. -// -// Changes to this file are copyright of Wasmer inc. unless otherwise indicated -// and are licensed under the Wasmer project's license. - -use faerie::artifact::{Decl, SectionKind}; -use faerie::*; -use gimli::write::{Address, Dwarf, EndianVec, Result, Sections, Writer}; -use gimli::{RunTimeEndian, SectionId}; - -#[derive(Clone)] -struct DebugReloc { - offset: u32, - size: u8, - name: String, - addend: i64, -} - -pub enum ResolvedSymbol { - PhysicalAddress(u64), - Reloc { name: String, addend: i64 }, -} - -pub trait SymbolResolver { - fn resolve_symbol(&self, symbol: usize, addend: i64) -> ResolvedSymbol; -} - -pub fn emit_dwarf( - artifact: &mut Artifact, - mut dwarf: Dwarf, - symbol_resolver: &dyn SymbolResolver, -) -> anyhow::Result<()> { - let endian = RunTimeEndian::Little; - - let mut sections = Sections::new(WriterRelocate::new(endian, symbol_resolver)); - dwarf.write(&mut sections)?; - sections.for_each_mut(|id, s| -> anyhow::Result<()> { - artifact.declare_with( - id.name(), - Decl::section(SectionKind::Debug), - s.writer.take(), - ) - })?; - sections.for_each_mut(|id, s| -> anyhow::Result<()> { - 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(()) -} - -#[derive(Clone)] -pub struct WriterRelocate<'a> { - relocs: Vec, - writer: EndianVec, - symbol_resolver: &'a dyn SymbolResolver, -} - -impl<'a> WriterRelocate<'a> { - pub fn new(endian: RunTimeEndian, symbol_resolver: &'a dyn SymbolResolver) -> Self { - WriterRelocate { - relocs: Vec::new(), - writer: EndianVec::new(endian), - symbol_resolver, - } - } -} - -impl<'a> Writer for WriterRelocate<'a> { - type Endian = RunTimeEndian; - - fn endian(&self) -> Self::Endian { - self.writer.endian() - } - - fn len(&self) -> usize { - self.writer.len() - } - - fn write(&mut self, bytes: &[u8]) -> Result<()> { - self.writer.write(bytes) - } - - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { - self.writer.write_at(offset, bytes) - } - - fn write_address(&mut self, address: Address, size: u8) -> Result<()> { - match address { - 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_udata(addr, size), - ResolvedSymbol::Reloc { name, addend } => { - let offset = self.len() as u64; - self.relocs.push(DebugReloc { - offset: offset as u32, - size, - name, - addend, - }); - self.write_udata(addend as u64, size) - } - } - } - } - } - - fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> { - let offset = self.len() as u32; - let name = section.name().to_string(); - self.relocs.push(DebugReloc { - offset, - size, - name, - addend: val as i64, - }); - self.write_udata(val as u64, size) - } - - fn write_offset_at( - &mut self, - offset: usize, - val: usize, - section: SectionId, - size: u8, - ) -> Result<()> { - let name = section.name().to_string(); - self.relocs.push(DebugReloc { - offset: offset as u32, - size, - name, - addend: val as i64, - }); - self.write_udata_at(offset, val as u64, size) - } -} diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index a892349bb..b3c207521 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1000,7 +1000,7 @@ impl<'ctx> FunctionCodeGenerator for LLVMFunctionCodeGenerator<'ct Ok(()) } - fn feed_local(&mut self, ty: WpType, count: usize) -> Result<(), CodegenError> { + fn feed_local(&mut self, ty: WpType, count: usize, _loc: u32) -> Result<(), CodegenError> { let param_len = self.num_params; let wasmer_ty = wp_type_to_type(ty)?; @@ -1101,7 +1101,12 @@ impl<'ctx> FunctionCodeGenerator for LLVMFunctionCodeGenerator<'ct Ok(()) } - fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { + fn feed_event( + &mut self, + event: Event, + module_info: &ModuleInfo, + _loc: u32, + ) -> Result<(), CodegenError> { let mut state = &mut self.state; let builder = self.builder.as_ref().unwrap(); let context = self.context.as_ref().unwrap(); @@ -8734,6 +8739,7 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod fn next_function( &mut self, _module_info: Arc>, + _loc: (u32, u32), ) -> Result<&mut LLVMFunctionCodeGenerator<'ctx>, CodegenError> { // Creates a new function and returns the function-scope code generator for it. let (context, builder, intrinsics) = match self.functions.last_mut() { @@ -8839,7 +8845,16 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod fn finalize( mut self, module_info: &ModuleInfo, - ) -> Result<(LLVMBackend, Box), CodegenError> { + ) -> Result< + ( + ( + LLVMBackend, + Option, + ), + Box, + ), + CodegenError, + > { let (context, builder, intrinsics) = match self.functions.last_mut() { Some(x) => ( x.context.take().unwrap(), @@ -8927,7 +8942,7 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod &self.target_machine, &mut self.llvm_callbacks, ); - Ok((backend, Box::new(cache_gen))) + Ok(((backend, None), Box::new(cache_gen))) } fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> { diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 835bc4501..79fa8c21b 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -112,7 +112,11 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, /// Checks the precondition for a module. fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>; /// Creates a new function and returns the function-scope code generator for it. - fn next_function(&mut self, module_info: Arc>, loc: (u32, u32)) -> Result<&mut FCG, E>; + fn next_function( + &mut self, + module_info: Arc>, + loc: (u32, u32), + ) -> Result<&mut FCG, E>; /// Finalizes this module. fn finalize( self, @@ -278,13 +282,17 @@ impl< if compiler_config.generate_debug_info { let debug_metadata = debug_metadata.expect("debug metadata"); let debug_info = wasm_debug::read_debuginfo(wasm); - let extra_info = wasm_debug::types::ModuleVmctxInfo::new(14 * 8, debug_metadata.stack_slot_offsets.values()); + let extra_info = wasm_debug::types::ModuleVmctxInfo::new( + 14 * 8, + debug_metadata.stack_slot_offsets.values(), + ); // lazy type hack (TODO:) - let compiled_fn_map = wasm_debug::types::create_module_address_map(debug_metadata.func_info.values()); - let range_map = wasm_debug::types::build_values_ranges(debug_metadata.inst_info.values()); + let compiled_fn_map = + wasm_debug::types::create_module_address_map(debug_metadata.func_info.values()); + let range_map = + wasm_debug::types::build_values_ranges(debug_metadata.inst_info.values()); let raw_func_slice = debug_metadata.pointers; - dbg!("DEBUG INFO GENERATED"); let debug_image = wasm_debug::emit_debugsections_image( X86_64_OSX, std::mem::size_of::() as u8, diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index bb8f29ad0..d6eb65934 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -88,12 +88,12 @@ impl Instance { vmctx.as_mut_ptr().write(real_ctx); for (_, memory) in backing.vm_memories.iter_mut() { let mem: &mut vm::LocalMemory = &mut **memory; + // remaining left to do: mem.vmctx = dbg!(vmctx.as_mut_ptr()); } }; Box::leak(vmctx); - let instance = Instance { module, inner, diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 4b04a6d6b..166151536 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -78,17 +78,9 @@ pub struct ModuleInfo { /// Custom sections. pub custom_sections: HashMap>, - /// Debug info for funcs - pub func_debug_info: Map, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -/// info about functions for debugging -pub struct FuncDebugInfo { - /// byte offset from start of code section where the function starts at - pub start: u32, - /// byte offset from start of code section where the function starts at - pub end: u32, + /// Flag controlling whether or not debug information for use in a debugger + /// will be generated + pub generate_debug_info: bool, } impl ModuleInfo { diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index b6a7ff6d5..205db736d 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -6,8 +6,8 @@ use crate::{ backend::{CompilerConfig, RunnableModule}, error::CompileError, module::{ - DataInitializer, ExportIndex, FuncDebugInfo, ImportName, ModuleInfo, StringTable, - StringTableBuilder, TableInitializer, + DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder, + TableInitializer, }, structures::{Map, TypedIndex}, types::{ @@ -91,7 +91,7 @@ pub fn read_module< custom_sections: HashMap::new(), - func_debug_info: Map::new(), + generate_debug_info: compiler_config.generate_debug_info, })); let mut parser = wasmparser::ValidatingParser::new( @@ -226,7 +226,6 @@ pub fn read_module< .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } - let fcg = mcg .next_function(Arc::clone(&info), (range.start as u32, range.end as u32)) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; @@ -263,7 +262,8 @@ pub fn read_module< let local_count = operator_parser.read_local_count().unwrap(); let mut total = 0; for _ in 0..local_count { - let cur_pos = range.start as u32 + operator_parser.current_position() as u32; + let cur_pos = + range.start as u32 + operator_parser.current_position() as u32; let (count, ty) = operator_parser .read_local_decl(&mut total) .expect("Expected local"); @@ -275,7 +275,8 @@ pub fn read_module< // read instruction locations into vector for debug purposes { let info_read = info.read().unwrap(); - let mut cur_pos = range.start as u32 + operator_parser.current_position() as u32; + let mut cur_pos = + range.start as u32 + operator_parser.current_position() as u32; fcg.begin_body(&info_read) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; middlewares @@ -308,13 +309,6 @@ pub fn read_module< fcg.finalize() .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; func_count = func_count.wrapping_add(1); - - // debug info - let debug_entry = FuncDebugInfo { - start: range.start as u32, - end: range.end as u32, - }; - info.write().unwrap().func_debug_info.push(debug_entry); } ParserState::BeginActiveElementSectionEntry(table_index) => { let table_index = TableIndex::new(table_index as usize); diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index ceb7e3114..a566e7a88 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -8,7 +8,7 @@ use crate::{ module::{ModuleInfo, ModuleInner}, sig_registry::SigRegistry, structures::TypedIndex, - types::{LocalOrImport, MemoryIndex, TableIndex, Value, LocalMemoryIndex}, + types::{LocalMemoryIndex, LocalOrImport, MemoryIndex, TableIndex, Value}, vmcalls, }; use std::{ @@ -286,7 +286,6 @@ impl Ctx { }; ((*mem).base, (*mem).bound) }; - dbg!(mem_bound); Self { internal: InternalCtx { memories: local_backing.vm_memories.as_mut_ptr(), diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index b58b84ced..3fc299522 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -678,6 +678,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, _module_info: Arc>, + _loc: (u32, u32), ) -> Result<&mut X64FunctionCode, CodegenError> { let (mut assembler, mut function_labels, breakpoints, exception_table) = match self.functions.last_mut() { @@ -736,7 +737,16 @@ impl ModuleCodeGenerator fn finalize( mut self, _: &ModuleInfo, - ) -> Result<(X64ExecutionContext, Box), CodegenError> { + ) -> Result< + ( + ( + X64ExecutionContext, + Option, + ), + Box, + ), + CodegenError, + > { let (assembler, function_labels, breakpoints, exception_table) = match self.functions.last_mut() { Some(x) => ( @@ -829,16 +839,19 @@ impl ModuleCodeGenerator }; Ok(( - X64ExecutionContext { - code: output, - signatures: self.signatures.as_ref().unwrap().clone(), - breakpoints: breakpoints, - func_import_count: self.func_import_count, - function_pointers: out_labels, - function_offsets: out_offsets, - msm: msm, - exception_table, - }, + ( + X64ExecutionContext { + code: output, + signatures: self.signatures.as_ref().unwrap().clone(), + breakpoints: breakpoints, + func_import_count: self.func_import_count, + function_pointers: out_labels, + function_offsets: out_offsets, + msm: msm, + exception_table, + }, + None, + ), Box::new(cache), )) } @@ -2405,7 +2418,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Ok(()) } - fn feed_local(&mut self, _ty: WpType, n: usize) -> Result<(), CodegenError> { + fn feed_local(&mut self, _ty: WpType, n: usize, _loc: u32) -> Result<(), CodegenError> { self.num_locals += n; Ok(()) } @@ -2515,7 +2528,12 @@ impl FunctionCodeGenerator for X64FunctionCode { Ok(()) } - fn feed_event(&mut self, ev: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { + fn feed_event( + &mut self, + ev: Event, + module_info: &ModuleInfo, + _loc: u32, + ) -> Result<(), CodegenError> { let a = self.assembler.as_mut().unwrap(); match ev { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 761daec25..a46541166 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -258,6 +258,10 @@ struct Run { #[structopt(long = "debug", short = "d")] debug: bool, + /// Generate debug information for use in a debugger + #[structopt(long = "generate-debug-info", short = "g")] + generate_debug_info: bool, + /// Application arguments #[structopt(name = "--", multiple = true)] args: Vec, @@ -719,7 +723,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { track_state, features: options.features.into_backend_features(), backend_specific_config, - generate_debug_info: true, + generate_debug_info: options.generate_debug_info, ..Default::default() }, &*compiler,