use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t}; use anyhow::{anyhow, Error}; use once_cell::unsync::OnceCell; use wasmtime::{Trap, WasmBacktrace}; #[repr(C)] pub struct wasm_trap_t { pub(crate) error: Error, } // This is currently only needed for the `wasm_trap_copy` API in the C API. // // For now the impl here is "fake it til you make it" since this is losing // context by only cloning the error string. impl Clone for wasm_trap_t { fn clone(&self) -> wasm_trap_t { wasm_trap_t { error: anyhow!("{:?}", self.error), } } } wasmtime_c_api_macros::declare_ref!(wasm_trap_t); impl wasm_trap_t { pub(crate) fn new(error: Error) -> wasm_trap_t { wasm_trap_t { error } } } #[repr(C)] #[derive(Clone)] pub struct wasm_frame_t<'a> { trace: &'a WasmBacktrace, idx: usize, func_name: OnceCell>, module_name: OnceCell>, } wasmtime_c_api_macros::declare_own!(wasm_frame_t); pub type wasm_message_t = wasm_name_t; #[no_mangle] pub extern "C" fn wasm_trap_new( _store: &wasm_store_t, message: &wasm_message_t, ) -> Box { let message = message.as_slice(); if message[message.len() - 1] != 0 { panic!("wasm_trap_new message stringz expected"); } let message = String::from_utf8_lossy(&message[..message.len() - 1]); Box::new(wasm_trap_t { error: Error::msg(message.into_owned()), }) } #[no_mangle] pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Box { let bytes = crate::slice_from_raw_parts(message, len); let message = String::from_utf8_lossy(&bytes); Box::new(wasm_trap_t { error: Error::msg(message.into_owned()), }) } #[no_mangle] pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) { let mut buffer = Vec::new(); buffer.extend_from_slice(format!("{:?}", trap.error).as_bytes()); buffer.reserve_exact(1); buffer.push(0); out.set_buffer(buffer); } #[no_mangle] pub extern "C" fn wasm_trap_origin(raw: &wasm_trap_t) -> Option>> { let trace = match raw.error.downcast_ref::() { Some(trap) => trap, None => return None, }; if trace.frames().len() > 0 { Some(Box::new(wasm_frame_t { trace, idx: 0, func_name: OnceCell::new(), module_name: OnceCell::new(), })) } else { None } } #[no_mangle] pub extern "C" fn wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>) { error_trace(&raw.error, out) } pub(crate) fn error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>) { let trace = match error.downcast_ref::() { Some(trap) => trap, None => return out.set_buffer(Vec::new()), }; let vec = (0..trace.frames().len()) .map(|idx| { Some(Box::new(wasm_frame_t { trace, idx, func_name: OnceCell::new(), module_name: OnceCell::new(), })) }) .collect(); out.set_buffer(vec); } #[no_mangle] pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool { let trap = match raw.error.downcast_ref::() { Some(trap) => trap, None => return false, }; *code = match trap { Trap::StackOverflow => 0, Trap::MemoryOutOfBounds => 1, Trap::HeapMisaligned => 2, Trap::TableOutOfBounds => 3, Trap::IndirectCallToNull => 4, Trap::BadSignature => 5, Trap::IntegerOverflow => 6, Trap::IntegerDivisionByZero => 7, Trap::BadConversionToInteger => 8, Trap::UnreachableCodeReached => 9, Trap::Interrupt => 10, Trap::OutOfFuel => 11, Trap::AlwaysTrapAdapter => unreachable!("component model not supported"), _ => unreachable!(), }; true } #[no_mangle] pub extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32 { frame.trace.frames()[frame.idx].func_index() } #[no_mangle] pub extern "C" fn wasmtime_frame_func_name<'a>( frame: &'a wasm_frame_t<'_>, ) -> Option<&'a wasm_name_t> { frame .func_name .get_or_init(|| { frame.trace.frames()[frame.idx] .func_name() .map(|s| wasm_name_t::from(s.to_string().into_bytes())) }) .as_ref() } #[no_mangle] pub extern "C" fn wasmtime_frame_module_name<'a>( frame: &'a wasm_frame_t<'_>, ) -> Option<&'a wasm_name_t> { frame .module_name .get_or_init(|| { frame.trace.frames()[frame.idx] .module_name() .map(|s| wasm_name_t::from(s.to_string().into_bytes())) }) .as_ref() } #[no_mangle] pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize { frame.trace.frames()[frame.idx] .func_offset() .unwrap_or(usize::MAX) } #[no_mangle] pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t { unimplemented!("wasm_frame_instance") } #[no_mangle] pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize { frame.trace.frames()[frame.idx] .module_offset() .unwrap_or(usize::MAX) } #[no_mangle] pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box> { Box::new(frame.clone()) }