Initial reorg.

This is largely the same as #305, but updated for the current tree.
This commit is contained in:
Dan Gohman
2019-11-07 17:11:06 -08:00
parent 2c69546a24
commit 22641de629
351 changed files with 52 additions and 52 deletions

192
crates/debug/src/lib.rs Normal file
View File

@@ -0,0 +1,192 @@
//! Debug utils for WebAssembly using Cranelift.
#![allow(clippy::cast_ptr_alignment)]
use alloc::string::String;
use alloc::vec::Vec;
use cranelift_codegen::isa::TargetFrontendConfig;
use faerie::{Artifact, Decl};
use failure::Error;
use target_lexicon::{BinaryFormat, Triple};
use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};
#[cfg(not(feature = "std"))]
use hashbrown::{hash_map, HashMap, HashSet};
#[cfg(feature = "std")]
use std::collections::{hash_map, HashMap, HashSet};
pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData, WasmFileInfo};
pub use crate::transform::transform_dwarf;
pub use crate::write_debuginfo::{emit_dwarf, ResolvedSymbol, SymbolResolver};
mod gc;
mod read_debuginfo;
mod transform;
mod write_debuginfo;
extern crate alloc;
struct FunctionRelocResolver {}
impl SymbolResolver for FunctionRelocResolver {
fn resolve_symbol(&self, symbol: usize, addend: i64) -> ResolvedSymbol {
let name = format!("_wasm_function_{}", symbol);
ResolvedSymbol::Reloc { name, addend }
}
}
pub fn emit_debugsections(
obj: &mut Artifact,
vmctx_info: &ModuleVmctxInfo,
target_config: &TargetFrontendConfig,
debuginfo_data: &DebugInfoData,
at: &ModuleAddressMap,
ranges: &ValueLabelsRanges,
) -> Result<(), Error> {
let resolver = FunctionRelocResolver {};
let dwarf = transform_dwarf(target_config, debuginfo_data, at, vmctx_info, ranges)?;
emit_dwarf(obj, dwarf, &resolver)?;
Ok(())
}
struct ImageRelocResolver<'a> {
func_offsets: &'a Vec<u64>,
}
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)
}
}
pub fn emit_debugsections_image(
triple: Triple,
target_config: &TargetFrontendConfig,
debuginfo_data: &DebugInfoData,
vmctx_info: &ModuleVmctxInfo,
at: &ModuleAddressMap,
ranges: &ValueLabelsRanges,
funcs: &[(*const u8, usize)],
) -> Result<Vec<u8>, Error> {
let func_offsets = &funcs
.iter()
.map(|(ptr, _)| *ptr as u64)
.collect::<Vec<u64>>();
let mut obj = Artifact::new(triple, String::from("module"));
let resolver = ImageRelocResolver { func_offsets };
let dwarf = transform_dwarf(target_config, debuginfo_data, at, vmctx_info, ranges)?;
// Assuming all functions in the same code block, looking min/max of its range.
assert!(funcs.len() > 0);
let mut segment_body: (usize, usize) = (!0, 0);
for (body_ptr, body_len) in funcs {
segment_body.0 = ::core::cmp::min(segment_body.0, *body_ptr as usize);
segment_body.1 = ::core::cmp::max(segment_body.1, *body_ptr as usize + body_len);
}
let segment_body = (segment_body.0 as *const u8, segment_body.1 - segment_body.0);
let body = unsafe { ::core::slice::from_raw_parts(segment_body.0, segment_body.1) };
obj.declare_with("all", Decl::function(), body.to_vec())?;
emit_dwarf(&mut obj, dwarf, &resolver)?;
// LLDB is too "magical" about mach-o, generating elf
let mut bytes = obj.emit_as(BinaryFormat::Elf)?;
// elf is still missing details...
convert_faerie_elf_to_loadable_file(&mut bytes, segment_body.0);
// let mut file = ::std::fs::File::create(::std::path::Path::new("test.o")).expect("file");
// ::std::io::Write::write(&mut file, &bytes).expect("write");
Ok(bytes)
}
fn convert_faerie_elf_to_loadable_file(bytes: &mut Vec<u8>, code_ptr: *const u8) {
use std::ffi::CStr;
use std::os::raw::c_char;
assert!(
bytes[0x4] == 2 && bytes[0x5] == 1,
"bits and endianess in .ELF"
);
let e_phoff = unsafe { *(bytes.as_ptr().offset(0x20) as *const u64) };
let e_phnum = unsafe { *(bytes.as_ptr().offset(0x38) as *const u16) };
assert!(
e_phoff == 0 && e_phnum == 0,
"program header table is empty"
);
let e_phentsize = unsafe { *(bytes.as_ptr().offset(0x36) as *const u16) };
assert!(e_phentsize == 0x38, "size of ph");
let e_shentsize = unsafe { *(bytes.as_ptr().offset(0x3A) as *const u16) };
assert!(e_shentsize == 0x40, "size of sh");
let e_shoff = unsafe { *(bytes.as_ptr().offset(0x28) as *const u64) };
let e_shnum = unsafe { *(bytes.as_ptr().offset(0x3C) as *const u16) };
let mut shstrtab_off = 0;
let mut segment = None;
for i in 0..e_shnum {
let off = e_shoff as isize + i as isize * e_shentsize as isize;
let sh_type = unsafe { *(bytes.as_ptr().offset(off + 0x4) as *const u32) };
if sh_type == /* SHT_SYMTAB */ 3 {
shstrtab_off = unsafe { *(bytes.as_ptr().offset(off + 0x18) as *const u64) };
}
if sh_type != /* SHT_PROGBITS */ 1 {
continue;
}
// It is a SHT_PROGBITS, but we need to check sh_name to ensure it is our function
let sh_name = unsafe {
let sh_name_off = *(bytes.as_ptr().offset(off) as *const u32);
CStr::from_ptr(
bytes
.as_ptr()
.offset((shstrtab_off + sh_name_off as u64) as isize)
as *const c_char,
)
.to_str()
.expect("name")
};
if sh_name != ".text.all" {
continue;
}
assert!(segment.is_none());
// Functions was added at emit_debugsections_image as .text.all.
// Patch vaddr, and save file location and its size.
unsafe {
*(bytes.as_ptr().offset(off + 0x10) as *mut u64) = code_ptr as u64;
};
let sh_offset = unsafe { *(bytes.as_ptr().offset(off + 0x18) as *const u64) };
let sh_size = unsafe { *(bytes.as_ptr().offset(off + 0x20) as *const u64) };
segment = Some((sh_offset, code_ptr, sh_size));
// Fix name too: cut it to just ".text"
unsafe {
let sh_name_off = *(bytes.as_ptr().offset(off) as *const u32);
bytes[(shstrtab_off + sh_name_off as u64) as usize + ".text".len()] = 0;
}
}
// LLDB wants segment with virtual address set, placing them at the end of ELF.
let ph_off = bytes.len();
if let Some((sh_offset, v_offset, sh_size)) = segment {
let segment = vec![0; 0x38];
unsafe {
*(segment.as_ptr() as *mut u32) = /* PT_LOAD */ 0x1;
*(segment.as_ptr().offset(0x8) as *mut u64) = sh_offset;
*(segment.as_ptr().offset(0x10) as *mut u64) = v_offset as u64;
*(segment.as_ptr().offset(0x18) as *mut u64) = v_offset as u64;
*(segment.as_ptr().offset(0x20) as *mut u64) = sh_size;
*(segment.as_ptr().offset(0x28) as *mut u64) = sh_size;
}
bytes.extend_from_slice(&segment);
} else {
unreachable!();
}
// It is somewhat loadable ELF file at this moment.
// Update e_flags, e_phoff and e_phnum.
unsafe {
*(bytes.as_ptr().offset(0x10) as *mut u16) = /* ET_DYN */ 3;
*(bytes.as_ptr().offset(0x20) as *mut u64) = ph_off as u64;
*(bytes.as_ptr().offset(0x38) as *mut u16) = 1 as u16;
}
}