1use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
2use anyhow::{Error, anyhow};
3use std::cell::OnceCell;
4use wasmtime::{Trap, WasmBacktrace};
5
6#[repr(C)]
7pub struct wasm_trap_t {
8 pub(crate) error: Error,
9}
10
11impl 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
23wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
24
25impl 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)]
33pub 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
40wasmtime_c_api_macros::declare_own!(wasm_frame_t);
41
42pub type wasm_message_t = wasm_name_t;
43
44#[unsafe(no_mangle)]
45pub 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)]
60pub 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)]
69pub unsafe extern "C" fn wasmtime_trap_new_code(code: u8) -> Box<wasm_trap_t> {
70 let trap = Trap::from_u8(code).unwrap();
71 Box::new(wasm_trap_t {
72 error: Error::new(trap),
73 })
74}
75
76#[unsafe(no_mangle)]
77pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) {
78 let mut buffer = Vec::new();
79 buffer.extend_from_slice(format!("{:?}", trap.error).as_bytes());
80 buffer.reserve_exact(1);
81 buffer.push(0);
82 out.set_buffer(buffer);
83}
84
85#[unsafe(no_mangle)]
86pub extern "C" fn wasm_trap_origin(raw: &wasm_trap_t) -> Option<Box<wasm_frame_t<'_>>> {
87 let trace = match raw.error.downcast_ref::<WasmBacktrace>() {
88 Some(trap) => trap,
89 None => return None,
90 };
91 if trace.frames().len() > 0 {
92 Some(Box::new(wasm_frame_t {
93 trace,
94 idx: 0,
95 func_name: OnceCell::new(),
96 module_name: OnceCell::new(),
97 }))
98 } else {
99 None
100 }
101}
102
103#[unsafe(no_mangle)]
104pub extern "C" fn wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>) {
105 error_trace(&raw.error, out)
106}
107
108pub(crate) fn error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>) {
109 let trace = match error.downcast_ref::<WasmBacktrace>() {
110 Some(trap) => trap,
111 None => return out.set_buffer(Vec::new()),
112 };
113 let vec = (0..trace.frames().len())
114 .map(|idx| {
115 Some(Box::new(wasm_frame_t {
116 trace,
117 idx,
118 func_name: OnceCell::new(),
119 module_name: OnceCell::new(),
120 }))
121 })
122 .collect();
123 out.set_buffer(vec);
124}
125
126#[unsafe(no_mangle)]
127pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool {
128 let trap = match raw.error.downcast_ref::<Trap>() {
129 Some(trap) => trap,
130 None => return false,
131 };
132 *code = *trap as u8;
133 true
134}
135
136#[unsafe(no_mangle)]
137pub extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32 {
138 frame.trace.frames()[frame.idx].func_index()
139}
140
141#[unsafe(no_mangle)]
142pub extern "C" fn wasmtime_frame_func_name<'a>(
143 frame: &'a wasm_frame_t<'_>,
144) -> Option<&'a wasm_name_t> {
145 frame
146 .func_name
147 .get_or_init(|| {
148 frame.trace.frames()[frame.idx]
149 .func_name()
150 .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
151 })
152 .as_ref()
153}
154
155#[unsafe(no_mangle)]
156pub extern "C" fn wasmtime_frame_module_name<'a>(
157 frame: &'a wasm_frame_t<'_>,
158) -> Option<&'a wasm_name_t> {
159 frame
160 .module_name
161 .get_or_init(|| {
162 frame.trace.frames()[frame.idx]
163 .module()
164 .name()
165 .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
166 })
167 .as_ref()
168}
169
170#[unsafe(no_mangle)]
171pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize {
172 frame.trace.frames()[frame.idx]
173 .func_offset()
174 .unwrap_or(usize::MAX)
175}
176
177#[unsafe(no_mangle)]
178pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t {
179 unimplemented!("wasm_frame_instance")
180}
181
182#[unsafe(no_mangle)]
183pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize {
184 frame.trace.frames()[frame.idx]
185 .module_offset()
186 .unwrap_or(usize::MAX)
187}
188
189#[unsafe(no_mangle)]
190pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> {
191 Box::new(frame.clone())
192}