Files
wasmtime/wasmtime-debug/src/address_transform.rs
2019-07-16 17:15:02 -07:00

140 lines
4.4 KiB
Rust

use crate::read_debuginfo::WasmFileInfo;
use crate::transform::ModuleAddressMap;
use cranelift_entity::{EntityRef, PrimaryMap};
use cranelift_wasm::DefinedFuncIndex;
use gimli::write;
use std::collections::BTreeMap;
use std::ops::Bound::{Included, Unbounded};
use std::vec::Vec;
pub type GeneratedAddress = usize;
pub type WasmAddress = u64;
pub type SymbolIndex = usize;
#[derive(Debug)]
pub struct AddressMap {
pub generated: GeneratedAddress,
pub wasm: WasmAddress,
}
#[derive(Debug)]
pub struct FunctionMap {
pub offset: GeneratedAddress,
pub len: GeneratedAddress,
pub addresses: Box<[AddressMap]>,
}
#[derive(Debug)]
pub struct AddressTransform {
lookup: BTreeMap<WasmAddress, (SymbolIndex, GeneratedAddress, GeneratedAddress)>,
map: PrimaryMap<DefinedFuncIndex, FunctionMap>,
func_ranges: Vec<(usize, usize)>,
}
impl AddressTransform {
pub fn new(at: &ModuleAddressMap, wasm_file: &WasmFileInfo) -> Self {
let code_section_offset = wasm_file.code_section_offset;
let function_offsets = &wasm_file.function_offsets_and_sizes;
let mut lookup = BTreeMap::new();
let mut map = PrimaryMap::new();
let mut func_ranges = Vec::new();
for (i, ft) in at {
let index = i.index();
let (fn_offset, fn_size) = function_offsets[index];
assert!(code_section_offset <= fn_offset);
let fn_offset: WasmAddress = fn_offset - code_section_offset;
let fn_size = fn_size as WasmAddress;
func_ranges.push((ft.body_offset, ft.body_offset + ft.body_len));
lookup.insert(
fn_offset as WasmAddress,
(index, ft.body_offset, ft.body_offset),
);
let mut fn_map = Vec::new();
for t in &ft.instructions {
if t.srcloc.is_default() {
// TODO extend some range if possible
continue;
}
// src_offset is a wasm bytecode offset in the code section
let src_offset = t.srcloc.bits() as WasmAddress - code_section_offset;
assert!(fn_offset <= src_offset && src_offset <= fn_offset + fn_size);
lookup.insert(
src_offset,
(index, t.code_offset, t.code_offset + t.code_len),
);
fn_map.push(AddressMap {
generated: t.code_offset,
wasm: src_offset,
});
}
let last_addr = ft.body_offset + ft.body_len;
lookup.insert(fn_offset + fn_size, (index, last_addr, last_addr));
fn_map.sort_by(|a, b| a.generated.cmp(&b.generated));
map.push(FunctionMap {
offset: ft.body_offset,
len: ft.body_len,
addresses: fn_map.into_boxed_slice(),
});
}
AddressTransform {
lookup,
map,
func_ranges,
}
}
pub fn translate(&self, addr: u64) -> Option<write::Address> {
if addr == 0 {
// It's normally 0 for debug info without the linked code.
return None;
}
let search = self.lookup.range((Unbounded, Included(addr)));
if let Some((_, value)) = search.last() {
return Some(write::Address::Symbol {
symbol: value.0,
addend: value.1 as i64,
});
}
// Address was not found: function was not compiled?
None
}
pub fn diff(&self, addr1: u64, addr2: u64) -> Option<u64> {
let t1 = self.translate(addr1);
let t2 = self.translate(addr2);
if t1.is_none() || t2.is_none() {
return None;
}
if let (
Some(write::Address::Symbol {
symbol: s1,
addend: a,
}),
Some(write::Address::Symbol {
symbol: s2,
addend: b,
}),
) = (t1, t2)
{
if s1 != s2 {
panic!("different symbol");
}
Some((b - a) as u64)
} else {
unreachable!();
}
}
pub fn delta(&self, addr1: u64, u: u64) -> Option<u64> {
self.diff(addr1, addr1 + u)
}
pub fn map(&self) -> &PrimaryMap<DefinedFuncIndex, FunctionMap> {
&self.map
}
pub fn func_range(&self, index: usize) -> (usize, usize) {
self.func_ranges[index]
}
}