1use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
2use std::cell::OnceCell;
3use wasmtime::{Error, Trap, WasmBacktrace, format_err};
4
5const _: () = {
9 assert!(Trap::StackOverflow as u8 == 0);
10 assert!(Trap::MemoryOutOfBounds as u8 == 1);
11 assert!(Trap::HeapMisaligned as u8 == 2);
12 assert!(Trap::TableOutOfBounds as u8 == 3);
13 assert!(Trap::IndirectCallToNull as u8 == 4);
14 assert!(Trap::BadSignature as u8 == 5);
15 assert!(Trap::IntegerOverflow as u8 == 6);
16 assert!(Trap::IntegerDivisionByZero as u8 == 7);
17 assert!(Trap::BadConversionToInteger as u8 == 8);
18 assert!(Trap::UnreachableCodeReached as u8 == 9);
19 assert!(Trap::Interrupt as u8 == 10);
20 assert!(Trap::OutOfFuel as u8 == 11);
21 assert!(Trap::AtomicWaitNonSharedMemory as u8 == 12);
22 assert!(Trap::NullReference as u8 == 13);
23 assert!(Trap::ArrayOutOfBounds as u8 == 14);
24 assert!(Trap::AllocationTooLarge as u8 == 15);
25 assert!(Trap::CastFailure as u8 == 16);
26 assert!(Trap::CannotEnterComponent as u8 == 17);
27 assert!(Trap::NoAsyncResult as u8 == 18);
28 assert!(Trap::UnhandledTag as u8 == 19);
29 assert!(Trap::ContinuationAlreadyConsumed as u8 == 20);
30 assert!(Trap::DisabledOpcode as u8 == 21);
31 assert!(Trap::AsyncDeadlock as u8 == 22);
32 assert!(Trap::CannotLeaveComponent as u8 == 23);
33 assert!(Trap::CannotBlockSyncTask as u8 == 24);
34 assert!(Trap::InvalidChar as u8 == 25);
35 assert!(Trap::DebugAssertStringEncodingFinished as u8 == 26);
36 assert!(Trap::DebugAssertEqualCodeUnits as u8 == 27);
37 assert!(Trap::DebugAssertPointerAligned as u8 == 28);
38 assert!(Trap::DebugAssertUpperBitsUnset as u8 == 29);
39 assert!(Trap::StringOutOfBounds as u8 == 30);
40 assert!(Trap::ListOutOfBounds as u8 == 31);
41 assert!(Trap::InvalidDiscriminant as u8 == 32);
42 assert!(Trap::UnalignedPointer as u8 == 33);
43 assert!(Trap::TaskCancelNotCancelled as u8 == 34);
44 assert!(Trap::TaskCancelOrReturnTwice as u8 == 35);
45 assert!(Trap::SubtaskCancelAfterTerminal as u8 == 36);
46 assert!(Trap::TaskReturnInvalid as u8 == 37);
47 assert!(Trap::WaitableSetDropHasWaiters as u8 == 38);
48 assert!(Trap::SubtaskDropNotResolved as u8 == 39);
49 assert!(Trap::ThreadNewIndirectInvalidType as u8 == 40);
50 assert!(Trap::ThreadNewIndirectUninitialized as u8 == 41);
51 assert!(Trap::BackpressureOverflow as u8 == 42);
52 assert!(Trap::UnsupportedCallbackCode as u8 == 43);
53 assert!(Trap::CannotResumeThread as u8 == 44);
54 assert!(Trap::ConcurrentFutureStreamOp as u8 == 45);
55 assert!(Trap::ReferenceCountOverflow as u8 == 46);
56 assert!(Trap::StreamOpTooBig as u8 == 47);
57 assert!(Trap::WaitableSyncAndAsync as u8 == 48);
58 assert!(Trap::UncaughtException as u8 == 49);
59};
60
61#[repr(C)]
62pub struct wasm_trap_t {
63 pub(crate) error: Error,
64}
65
66impl Clone for wasm_trap_t {
71 fn clone(&self) -> wasm_trap_t {
72 wasm_trap_t {
73 error: format_err!("{:?}", self.error),
74 }
75 }
76}
77
78wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
79
80impl wasm_trap_t {
81 pub(crate) fn new(error: Error) -> wasm_trap_t {
82 wasm_trap_t { error }
83 }
84}
85
86#[repr(C)]
87#[derive(Clone)]
88pub struct wasm_frame_t<'a> {
89 trace: &'a WasmBacktrace,
90 idx: usize,
91 func_name: OnceCell<Option<wasm_name_t>>,
92 module_name: OnceCell<Option<wasm_name_t>>,
93}
94
95wasmtime_c_api_macros::declare_own!(wasm_frame_t);
96
97pub type wasm_message_t = wasm_name_t;
98
99#[unsafe(no_mangle)]
100pub extern "C" fn wasm_trap_new(
101 _store: &wasm_store_t,
102 message: &wasm_message_t,
103) -> Box<wasm_trap_t> {
104 let message = message.as_slice();
105 if message[message.len() - 1] != 0 {
106 panic!("wasm_trap_new message stringz expected");
107 }
108 let message = String::from_utf8_lossy(&message[..message.len() - 1]);
109 Box::new(wasm_trap_t {
110 error: Error::msg(message.into_owned()),
111 })
112}
113
114#[unsafe(no_mangle)]
115pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Box<wasm_trap_t> {
116 let bytes = crate::slice_from_raw_parts(message, len);
117 let message = String::from_utf8_lossy(&bytes);
118 Box::new(wasm_trap_t {
119 error: Error::msg(message.into_owned()),
120 })
121}
122
123#[unsafe(no_mangle)]
124pub unsafe extern "C" fn wasmtime_trap_new_code(code: u8) -> Box<wasm_trap_t> {
125 let trap = Trap::from_u8(code).unwrap();
126 Box::new(wasm_trap_t {
127 error: Error::new(trap),
128 })
129}
130
131#[unsafe(no_mangle)]
132pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) {
133 let mut buffer = Vec::new();
134 buffer.extend_from_slice(format!("{:?}", trap.error).as_bytes());
135 buffer.reserve_exact(1);
136 buffer.push(0);
137 out.set_buffer(buffer);
138}
139
140#[unsafe(no_mangle)]
141pub extern "C" fn wasm_trap_origin(raw: &wasm_trap_t) -> Option<Box<wasm_frame_t<'_>>> {
142 let trace = match raw.error.downcast_ref::<WasmBacktrace>() {
143 Some(trap) => trap,
144 None => return None,
145 };
146 if trace.frames().len() > 0 {
147 Some(Box::new(wasm_frame_t {
148 trace,
149 idx: 0,
150 func_name: OnceCell::new(),
151 module_name: OnceCell::new(),
152 }))
153 } else {
154 None
155 }
156}
157
158#[unsafe(no_mangle)]
159pub extern "C" fn wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>) {
160 error_trace(&raw.error, out)
161}
162
163pub(crate) fn error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>) {
164 let trace = match error.downcast_ref::<WasmBacktrace>() {
165 Some(trap) => trap,
166 None => return out.set_buffer(Vec::new()),
167 };
168 let vec = (0..trace.frames().len())
169 .map(|idx| {
170 Some(Box::new(wasm_frame_t {
171 trace,
172 idx,
173 func_name: OnceCell::new(),
174 module_name: OnceCell::new(),
175 }))
176 })
177 .collect();
178 out.set_buffer(vec);
179}
180
181#[unsafe(no_mangle)]
182pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool {
183 let trap = match raw.error.downcast_ref::<Trap>() {
184 Some(trap) => trap,
185 None => return false,
186 };
187 *code = *trap as u8;
188 true
189}
190
191#[unsafe(no_mangle)]
192pub extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32 {
193 frame.trace.frames()[frame.idx].func_index()
194}
195
196#[unsafe(no_mangle)]
197pub extern "C" fn wasmtime_frame_func_name<'a>(
198 frame: &'a wasm_frame_t<'_>,
199) -> Option<&'a wasm_name_t> {
200 frame
201 .func_name
202 .get_or_init(|| {
203 frame.trace.frames()[frame.idx]
204 .func_name()
205 .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
206 })
207 .as_ref()
208}
209
210#[unsafe(no_mangle)]
211pub extern "C" fn wasmtime_frame_module_name<'a>(
212 frame: &'a wasm_frame_t<'_>,
213) -> Option<&'a wasm_name_t> {
214 frame
215 .module_name
216 .get_or_init(|| {
217 frame.trace.frames()[frame.idx]
218 .module()
219 .name()
220 .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
221 })
222 .as_ref()
223}
224
225#[unsafe(no_mangle)]
226pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize {
227 frame.trace.frames()[frame.idx]
228 .func_offset()
229 .unwrap_or(usize::MAX)
230}
231
232#[unsafe(no_mangle)]
233pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t {
234 unimplemented!("wasm_frame_instance")
235}
236
237#[unsafe(no_mangle)]
238pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize {
239 frame.trace.frames()[frame.idx]
240 .module_offset()
241 .unwrap_or(usize::MAX)
242}
243
244#[unsafe(no_mangle)]
245pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> {
246 Box::new(frame.clone())
247}