1 use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t}; 2 use anyhow::{anyhow, Error}; 3 use std::cell::OnceCell; 4 use wasmtime::{Trap, WasmBacktrace}; 5 6 #[repr(C)] 7 pub struct wasm_trap_t { 8 pub(crate) error: Error, 9 } 10 11 // This is currently only needed for the `wasm_trap_copy` API in the C API. 12 // 13 // For now the impl here is "fake it til you make it" since this is losing 14 // context by only cloning the error string. 15 impl Clone for wasm_trap_t { 16 fn clone(&self) -> wasm_trap_t { 17 wasm_trap_t { 18 error: anyhow!("{:?}", self.error), 19 } 20 } 21 } 22 23 wasmtime_c_api_macros::declare_ref!(wasm_trap_t); 24 25 impl wasm_trap_t { 26 pub(crate) fn new(error: Error) -> wasm_trap_t { 27 wasm_trap_t { error } 28 } 29 } 30 31 #[repr(C)] 32 #[derive(Clone)] 33 pub struct wasm_frame_t<'a> { 34 trace: &'a WasmBacktrace, 35 idx: usize, 36 func_name: OnceCell<Option<wasm_name_t>>, 37 module_name: OnceCell<Option<wasm_name_t>>, 38 } 39 40 wasmtime_c_api_macros::declare_own!(wasm_frame_t); 41 42 pub type wasm_message_t = wasm_name_t; 43 44 #[unsafe(no_mangle)] 45 pub extern "C" fn wasm_trap_new( 46 _store: &wasm_store_t, 47 message: &wasm_message_t, 48 ) -> Box<wasm_trap_t> { 49 let message = message.as_slice(); 50 if message[message.len() - 1] != 0 { 51 panic!("wasm_trap_new message stringz expected"); 52 } 53 let message = String::from_utf8_lossy(&message[..message.len() - 1]); 54 Box::new(wasm_trap_t { 55 error: Error::msg(message.into_owned()), 56 }) 57 } 58 59 #[unsafe(no_mangle)] 60 pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Box<wasm_trap_t> { 61 let bytes = crate::slice_from_raw_parts(message, len); 62 let message = String::from_utf8_lossy(&bytes); 63 Box::new(wasm_trap_t { 64 error: Error::msg(message.into_owned()), 65 }) 66 } 67 68 #[unsafe(no_mangle)] 69 pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) { 70 let mut buffer = Vec::new(); 71 buffer.extend_from_slice(format!("{:?}", trap.error).as_bytes()); 72 buffer.reserve_exact(1); 73 buffer.push(0); 74 out.set_buffer(buffer); 75 } 76 77 #[unsafe(no_mangle)] 78 pub extern "C" fn wasm_trap_origin(raw: &wasm_trap_t) -> Option<Box<wasm_frame_t<'_>>> { 79 let trace = match raw.error.downcast_ref::<WasmBacktrace>() { 80 Some(trap) => trap, 81 None => return None, 82 }; 83 if trace.frames().len() > 0 { 84 Some(Box::new(wasm_frame_t { 85 trace, 86 idx: 0, 87 func_name: OnceCell::new(), 88 module_name: OnceCell::new(), 89 })) 90 } else { 91 None 92 } 93 } 94 95 #[unsafe(no_mangle)] 96 pub extern "C" fn wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>) { 97 error_trace(&raw.error, out) 98 } 99 100 pub(crate) fn error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>) { 101 let trace = match error.downcast_ref::<WasmBacktrace>() { 102 Some(trap) => trap, 103 None => return out.set_buffer(Vec::new()), 104 }; 105 let vec = (0..trace.frames().len()) 106 .map(|idx| { 107 Some(Box::new(wasm_frame_t { 108 trace, 109 idx, 110 func_name: OnceCell::new(), 111 module_name: OnceCell::new(), 112 })) 113 }) 114 .collect(); 115 out.set_buffer(vec); 116 } 117 118 #[unsafe(no_mangle)] 119 pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool { 120 let trap = match raw.error.downcast_ref::<Trap>() { 121 Some(trap) => trap, 122 None => return false, 123 }; 124 *code = match trap { 125 Trap::StackOverflow => 0, 126 Trap::MemoryOutOfBounds => 1, 127 Trap::HeapMisaligned => 2, 128 Trap::TableOutOfBounds => 3, 129 Trap::IndirectCallToNull => 4, 130 Trap::BadSignature => 5, 131 Trap::IntegerOverflow => 6, 132 Trap::IntegerDivisionByZero => 7, 133 Trap::BadConversionToInteger => 8, 134 Trap::UnreachableCodeReached => 9, 135 Trap::Interrupt => 10, 136 Trap::OutOfFuel => 11, 137 Trap::AlwaysTrapAdapter => unreachable!("component model not supported"), 138 _ => unreachable!(), 139 }; 140 true 141 } 142 143 #[unsafe(no_mangle)] 144 pub extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32 { 145 frame.trace.frames()[frame.idx].func_index() 146 } 147 148 #[unsafe(no_mangle)] 149 pub extern "C" fn wasmtime_frame_func_name<'a>( 150 frame: &'a wasm_frame_t<'_>, 151 ) -> Option<&'a wasm_name_t> { 152 frame 153 .func_name 154 .get_or_init(|| { 155 frame.trace.frames()[frame.idx] 156 .func_name() 157 .map(|s| wasm_name_t::from(s.to_string().into_bytes())) 158 }) 159 .as_ref() 160 } 161 162 #[unsafe(no_mangle)] 163 pub extern "C" fn wasmtime_frame_module_name<'a>( 164 frame: &'a wasm_frame_t<'_>, 165 ) -> Option<&'a wasm_name_t> { 166 frame 167 .module_name 168 .get_or_init(|| { 169 frame.trace.frames()[frame.idx] 170 .module() 171 .name() 172 .map(|s| wasm_name_t::from(s.to_string().into_bytes())) 173 }) 174 .as_ref() 175 } 176 177 #[unsafe(no_mangle)] 178 pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize { 179 frame.trace.frames()[frame.idx] 180 .func_offset() 181 .unwrap_or(usize::MAX) 182 } 183 184 #[unsafe(no_mangle)] 185 pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t { 186 unimplemented!("wasm_frame_instance") 187 } 188 189 #[unsafe(no_mangle)] 190 pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize { 191 frame.trace.frames()[frame.idx] 192 .module_offset() 193 .unwrap_or(usize::MAX) 194 } 195 196 #[unsafe(no_mangle)] 197 pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> { 198 Box::new(frame.clone()) 199 } 200