xref: /wasmtime-44.0.1/crates/c-api/src/trap.rs (revision fee9be21)
1 use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
2 use anyhow::{Error, anyhow};
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 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)]
77 pub 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)]
86 pub 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)]
104 pub 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 
108 pub(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)]
127 pub 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)]
137 pub 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)]
142 pub 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)]
156 pub 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)]
171 pub 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)]
178 pub 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)]
183 pub 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)]
190 pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> {
191     Box::new(frame.clone())
192 }
193