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