Add wip debugging code

This commit is contained in:
Mark McCaskey
2020-02-11 09:52:21 -08:00
parent 42132c42b6
commit 0564000da3
16 changed files with 402 additions and 199 deletions

View File

@ -112,9 +112,12 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, 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<RwLock<ModuleInfo>>) -> Result<&mut FCG, E>;
fn next_function(&mut self, module_info: Arc<RwLock<ModuleInfo>>, loc: (u32, u32)) -> Result<&mut FCG, E>;
/// Finalizes this module.
fn finalize(self, module_info: &ModuleInfo) -> Result<((RM, Option<DebugMetadata>), Box<dyn CacheGen>), E>;
fn finalize(
self,
module_info: &ModuleInfo,
) -> Result<((RM, Option<DebugMetadata>), Box<dyn CacheGen>), E>;
/// Creates a module from cache.
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
@ -127,6 +130,10 @@ pub struct DebugMetadata {
pub func_info: PrimaryMap<FuncIndex, wasm_debug::types::CompiledFunctionData>,
/// inst_info
pub inst_info: PrimaryMap<FuncIndex, wasm_debug::types::ValueLabelsRangesInner>,
/// stack slot offsets!
pub stack_slot_offsets: PrimaryMap<FuncIndex, Vec<Option<i32>>>,
/// function pointers and their lengths
pub pointers: Vec<(*const u8, usize)>,
}
/// A streaming compiler which is designed to generated code for a module based on a stream
@ -241,7 +248,6 @@ impl<
validate_with_features(wasm, &compiler_config.features)?;
}
let mut mcg = match MCG::backend_id() {
"llvm" => MCG::new_with_target(
compiler_config.triple.clone(),
@ -252,13 +258,15 @@ impl<
};
let mut chain = (self.middleware_chain_generator)();
let info = crate::parse::read_module(wasm, &mut mcg, &mut chain, &compiler_config)?;
let ((exec_context, debug_metadata), cache_gen) =
mcg.finalize(&info.read().unwrap())
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
let ((exec_context, debug_metadata), cache_gen) = mcg
.finalize(&info.read().unwrap())
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
use target_lexicon::{Triple, Architecture, Vendor, OperatingSystem, Environment, BinaryFormat};
use target_lexicon::{
Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor,
};
const X86_64_OSX: Triple = Triple {
architecture: Architecture::X86_64,
vendor: Vendor::Apple,
@ -266,34 +274,37 @@ impl<
environment: Environment::Unknown,
binary_format: BinaryFormat::Macho,
};
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 {
memory_offset: 0,
stack_slot_offsets: cranelift_entity::PrimaryMap::new(),
};
let extra_info = wasm_debug::types::ModuleVmctxInfo::new(14 * 8, debug_metadata.stack_slot_offsets.values());
// lazy type hack (TODO:)
let compiled_fn_map = unsafe { std::mem::transmute(debug_metadata.func_info) };
let range_map = unsafe { std::mem::transmute(debug_metadata.inst_info) };
let raw_func_slice = vec![];//exec_context.get_local_function_pointers_and_lengths().expect("raw func slice");
dbg!("DEBUG INFO GENERATED");
let debug_image = wasm_debug::emit_debugsections_image(X86_64_OSX,
std::mem::size_of::<usize>() as u8,
&debug_info,
&extra_info,
&compiled_fn_map,
&range_map,
&raw_func_slice).expect("make debug image");
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;
crate::jit_debug::register_new_jit_code_entry(&debug_image, crate::jit_debug::JITAction::JIT_REGISTER_FN);
}
dbg!("DEBUG INFO GENERATED");
let debug_image = wasm_debug::emit_debugsections_image(
X86_64_OSX,
std::mem::size_of::<usize>() as u8,
&debug_info,
&extra_info,
&compiled_fn_map,
&range_map,
&raw_func_slice,
)
.expect("make debug image");
crate::jit_debug::register_new_jit_code_entry(
&debug_image,
crate::jit_debug::JITAction::JIT_REGISTER_FN,
);
}
Ok(ModuleInner {
cache_gen,
runnable_module: Arc::new(Box::new(exec_context)),
info: Arc::try_unwrap(info).unwrap().into_inner().unwrap(),
debug_info: None,
})
}
@ -340,6 +351,7 @@ impl MiddlewareChain {
fcg: Option<&mut FCG>,
ev: Event,
module_info: &ModuleInfo,
loc: u32,
) -> Result<(), String> {
let mut sink = EventSink {
buffer: SmallVec::new(),
@ -348,12 +360,12 @@ impl MiddlewareChain {
for m in &mut self.chain {
let prev: SmallVec<[Event; 2]> = sink.buffer.drain().collect();
for ev in prev {
m.feed_event(ev, module_info, &mut sink)?;
m.feed_event(ev, module_info, &mut sink, loc)?;
}
}
if let Some(fcg) = fcg {
for ev in sink.buffer {
fcg.feed_event(ev, module_info)
fcg.feed_event(ev, module_info, loc)
.map_err(|x| format!("{:?}", x))?;
}
}
@ -372,6 +384,7 @@ pub trait FunctionMiddleware {
op: Event<'a, 'b>,
module_info: &ModuleInfo,
sink: &mut EventSink<'a, 'b>,
loc: u32,
) -> Result<(), Self::Error>;
}
@ -381,6 +394,7 @@ pub(crate) trait GenericFunctionMiddleware {
op: Event<'a, 'b>,
module_info: &ModuleInfo,
sink: &mut EventSink<'a, 'b>,
loc: u32,
) -> Result<(), String>;
}
@ -390,8 +404,9 @@ impl<E: Debug, T: FunctionMiddleware<Error = E>> GenericFunctionMiddleware for T
op: Event<'a, 'b>,
module_info: &ModuleInfo,
sink: &mut EventSink<'a, 'b>,
loc: u32,
) -> Result<(), String> {
<Self as FunctionMiddleware>::feed_event(self, op, module_info, sink)
<Self as FunctionMiddleware>::feed_event(self, op, module_info, sink, loc)
.map_err(|x| format!("{:?}", x))
}
}
@ -405,13 +420,13 @@ pub trait FunctionCodeGenerator<E: Debug> {
fn feed_param(&mut self, ty: WpType) -> Result<(), E>;
/// Adds `n` locals to the function.
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), E>;
fn feed_local(&mut self, ty: WpType, n: usize, loc: u32) -> Result<(), E>;
/// Called before the first call to `feed_opcode`.
fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
/// Called for each operator.
fn feed_event(&mut self, op: Event, module_info: &ModuleInfo) -> Result<(), E>;
fn feed_event(&mut self, op: Event, module_info: &ModuleInfo, loc: u32) -> Result<(), E>;
/// Finalizes the function.
fn finalize(&mut self) -> Result<(), E>;

View File

@ -86,9 +86,14 @@ impl Instance {
None => vm::Ctx::new(backing, import_backing, &module),
};
vmctx.as_mut_ptr().write(real_ctx);
for (_, memory) in backing.vm_memories.iter_mut() {
let mem: &mut vm::LocalMemory = &mut **memory;
mem.vmctx = dbg!(vmctx.as_mut_ptr());
}
};
Box::leak(vmctx);
let instance = Instance {
module,
inner,

View File

@ -8,15 +8,25 @@ use std::ptr;
//
// see also https://sourceware.org/gdb/current/onlinedocs/gdb.html#JIT-Interface
#[no_mangle]
#[inline(never)]
pub extern "C" fn __jit_debug_register_code() {
extern "C" fn __jit_debug_register_code() {
// implementation of this function copied from wasmtime (TODO: link and attribution)
// prevent optimization of this function
let x = 3;
unsafe {
std::ptr::read_volatile(&x);
}
}
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(u32)]
pub enum JITAction { JIT_NOACTION = 0, JIT_REGISTER_FN = 1, JIT_UNREGISTER_FN = 2 }
pub enum JITAction {
JIT_NOACTION = 0,
JIT_REGISTER_FN = 1,
JIT_UNREGISTER_FN = 2,
}
#[no_mangle]
#[repr(C)]
@ -76,9 +86,15 @@ unsafe fn push_front(jce: *mut JITCodeEntry) {
// deleted static (added and deleted by Mark): TODO:
pub fn register_new_jit_code_entry(bytes: &[u8], action: JITAction) -> *mut JITCodeEntry {
let owned_bytes = bytes.iter().cloned().collect::<Vec<u8>>();
let ptr = owned_bytes.as_ptr();
let len = owned_bytes.len();
std::mem::forget(bytes);
let entry: *mut JITCodeEntry = Box::into_raw(Box::new(JITCodeEntry {
symfile_addr: bytes.as_ptr(),
symfile_size: bytes.len() as _,
symfile_addr: ptr,
symfile_size: len as _,
..JITCodeEntry::default()
}));
@ -86,6 +102,9 @@ pub fn register_new_jit_code_entry(bytes: &[u8], action: JITAction) -> *mut JITC
push_front(entry);
__jit_debug_descriptor.relevant_entry = entry;
__jit_debug_descriptor.action_flag = action as u32;
__jit_debug_register_code();
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
__jit_debug_descriptor.action_flag = JITAction::JIT_NOACTION as _;
}
entry

View File

@ -66,10 +66,10 @@ pub mod vmcalls;
pub use trampoline_x64 as trampoline;
#[cfg(unix)]
pub mod fault;
pub mod jit_debug;
pub mod state;
#[cfg(feature = "managed")]
pub mod tiering;
pub mod jit_debug;
use self::error::CompileResult;
#[doc(inline)]

View File

@ -227,6 +227,7 @@ impl UnsharedMemory {
base: std::ptr::null_mut(),
bound: 0,
memory: std::ptr::null_mut(),
vmctx: std::ptr::null_mut(),
};
let storage = match desc.memory_type() {
@ -314,6 +315,7 @@ impl SharedMemory {
base: std::ptr::null_mut(),
bound: 0,
memory: std::ptr::null_mut(),
vmctx: std::ptr::null_mut(),
};
let memory = StaticMemory::new(desc, &mut local)?;

View File

@ -20,18 +20,12 @@ use indexmap::IndexMap;
use std::collections::HashMap;
use std::sync::Arc;
#[doc(hidden)]
pub struct DebugInfo {
}
/// This is used to instantiate a new WebAssembly module.
#[doc(hidden)]
pub struct ModuleInner {
pub runnable_module: Arc<Box<dyn RunnableModule>>,
pub cache_gen: Box<dyn CacheGen>,
pub info: ModuleInfo,
pub debug_info: Option<DebugInfo>,
}
/// Container for module data including memories, globals, tables, imports, and exports.
@ -83,6 +77,18 @@ pub struct ModuleInfo {
/// Custom sections.
pub custom_sections: HashMap<String, Vec<u8>>,
/// Debug info for funcs
pub func_debug_info: Map<FuncIndex, FuncDebugInfo>,
}
#[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,
}
impl ModuleInfo {

View File

@ -6,8 +6,8 @@ use crate::{
backend::{CompilerConfig, RunnableModule},
error::CompileError,
module::{
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
TableInitializer,
DataInitializer, ExportIndex, FuncDebugInfo, ImportName, ModuleInfo, StringTable,
StringTableBuilder, TableInitializer,
},
structures::{Map, TypedIndex},
types::{
@ -90,6 +90,8 @@ pub fn read_module<
em_symbol_map: compiler_config.symbol_map.clone(),
custom_sections: HashMap::new(),
func_debug_info: Map::new(),
}));
let mut parser = wasmparser::ValidatingParser::new(
@ -206,91 +208,113 @@ pub fn read_module<
ParserState::StartSectionEntry(start_index) => {
info.write().unwrap().start_func = Some(FuncIndex::new(start_index as usize));
}
ParserState::BeginFunctionBody { .. } => {
ParserState::BeginFunctionBody { range } => {
let id = func_count;
if !mcg_info_fed {
mcg_info_fed = true;
info.write().unwrap().namespace_table =
namespace_builder.take().unwrap().finish();
info.write().unwrap().name_table = name_builder.take().unwrap().finish();
mcg.feed_signatures(info.read().unwrap().signatures.clone())
{
let mut info_write = info.write().unwrap();
info_write.namespace_table = namespace_builder.take().unwrap().finish();
info_write.name_table = name_builder.take().unwrap().finish();
}
let info_read = info.read().unwrap();
mcg.feed_signatures(info_read.signatures.clone())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
mcg.feed_function_signatures(info.read().unwrap().func_assoc.clone())
mcg.feed_function_signatures(info_read.func_assoc.clone())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
mcg.check_precondition(&info.read().unwrap())
mcg.check_precondition(&info_read)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
let fcg = mcg
.next_function(Arc::clone(&info))
.next_function(Arc::clone(&info), (range.start as u32, range.end as u32))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
let info_read = info.read().unwrap();
let sig = info_read
.signatures
.get(
*info
.read()
.unwrap()
.func_assoc
.get(FuncIndex::new(
id as usize + info.read().unwrap().imported_functions.len(),
))
.unwrap(),
)
.unwrap();
for ret in sig.returns() {
fcg.feed_return(type_to_wp_type(*ret))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
for param in sig.params() {
fcg.feed_param(type_to_wp_type(*param))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
let mut body_begun = false;
loop {
let state = parser.read();
match state {
ParserState::Error(err) => return Err(LoadError::Parse(*err)),
ParserState::FunctionBodyLocals { ref locals } => {
for &(count, ty) in locals.iter() {
fcg.feed_local(ty, count as usize)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
}
ParserState::CodeOperator(op) => {
if !body_begun {
body_begun = true;
fcg.begin_body(&info.read().unwrap())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
middlewares
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
&info.read().unwrap(),
)
.map_err(LoadError::Codegen)?;
}
middlewares
.run(Some(fcg), Event::Wasm(op), &info.read().unwrap())
.map_err(LoadError::Codegen)?;
}
ParserState::EndFunctionBody => break,
_ => unreachable!(),
{
let info_read = info.read().unwrap();
let sig = info_read
.signatures
.get(
*info
.read()
.unwrap()
.func_assoc
.get(FuncIndex::new(
id as usize + info_read.imported_functions.len(),
))
.unwrap(),
)
.unwrap();
for ret in sig.returns() {
fcg.feed_return(type_to_wp_type(*ret))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
for param in sig.params() {
fcg.feed_param(type_to_wp_type(*param))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
}
middlewares
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionEnd),
&info.read().unwrap(),
)
.map_err(LoadError::Codegen)?;
let mut operator_parser = parser.create_binary_reader();
// read locals in function body
{
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 (count, ty) = operator_parser
.read_local_decl(&mut total)
.expect("Expected local");
fcg.feed_local(ty, count as usize, cur_pos)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
}
// 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;
fcg.begin_body(&info_read)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
middlewares
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
&info_read,
cur_pos,
)
.map_err(LoadError::Codegen)?;
while let Ok(op) = operator_parser.read_operator() {
middlewares
.run(Some(fcg), Event::WasmOwned(op), &info_read, cur_pos)
.map_err(LoadError::Codegen)?;
cur_pos = range.start as u32 + operator_parser.current_position() as u32;
}
cur_pos = range.start as u32 + operator_parser.current_position() as u32;
middlewares
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionEnd),
&info_read,
cur_pos,
)
.map_err(LoadError::Codegen)?;
}
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);

View File

@ -8,7 +8,7 @@ use crate::{
module::{ModuleInfo, ModuleInner},
sig_registry::SigRegistry,
structures::TypedIndex,
types::{LocalOrImport, MemoryIndex, TableIndex, Value},
types::{LocalOrImport, MemoryIndex, TableIndex, Value, LocalMemoryIndex},
vmcalls,
};
use std::{
@ -134,6 +134,9 @@ pub struct InternalCtx {
/// Interrupt signal mem.
pub interrupt_signal_mem: *mut u8,
/// hmm
pub first_mem: *mut LocalMemory,
}
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
@ -283,6 +286,7 @@ impl Ctx {
};
((*mem).base, (*mem).bound)
};
dbg!(mem_bound);
Self {
internal: InternalCtx {
memories: local_backing.vm_memories.as_mut_ptr(),
@ -306,6 +310,7 @@ impl Ctx {
internals: &mut local_backing.internals.0,
interrupt_signal_mem: get_interrupt_signal_mem(),
first_mem: local_backing.vm_memories[LocalMemoryIndex::new(0)],
},
local_functions: local_backing.local_functions.as_ptr(),
@ -336,6 +341,8 @@ impl Ctx {
};
((*mem).base, (*mem).bound)
};
dbg!(mem_bound);
Self {
internal: InternalCtx {
memories: local_backing.vm_memories.as_mut_ptr(),
@ -359,6 +366,8 @@ impl Ctx {
internals: &mut local_backing.internals.0,
interrupt_signal_mem: get_interrupt_signal_mem(),
first_mem: local_backing.vm_memories[LocalMemoryIndex::new(0)],
},
local_functions: local_backing.local_functions.as_ptr(),
@ -537,7 +546,7 @@ impl Ctx {
}
pub const fn offset_local_functions() -> u8 {
14 * (mem::size_of::<usize>() as u8)
15 * (mem::size_of::<usize>() as u8)
}
}
@ -666,6 +675,9 @@ pub struct LocalMemory {
/// This is either `*mut DynamicMemory`, `*mut StaticMemory`,
/// or `*mut SharedStaticMemory`.
pub memory: *mut (),
/// wat
pub vmctx: *mut Ctx,
}
// manually implemented because LocalMemory contains raw pointers