xref: /wasmtime-44.0.1/crates/c-api/src/trap.rs (revision dcdbed12)
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