1#![allow(non_camel_case_types)]
2
3pub use self::lucet_result::*;
4pub use self::lucet_val::*;
5
6use crate::alloc::Limits;
7use crate::error::Error;
8use crate::instance::signals::SignalBehavior;
9use libc::{c_int, c_void};
10use num_derive::FromPrimitive;
11
12#[macro_export]
13macro_rules! assert_nonnull {
14 ( $name:ident ) => {
15 if $name.is_null() {
16 return lucet_error::InvalidArgument;
17 }
18 };
19}
20
21#[macro_export]
25macro_rules! with_ffi_arcs {
26 ( [ $name:ident : dyn $ty:ident ], $body:block ) => {{
27 assert_nonnull!($name);
28 let $name = Arc::from_raw($name as *const Arc<dyn $ty>);
29 let res = $body;
30 Arc::into_raw($name);
31 res
32 }};
33 ( [ $name:ident : $ty:ty ], $body:block ) => {{
34 assert_nonnull!($name);
35 let $name = Arc::from_raw($name as *const $ty);
36 let res = $body;
37 Arc::into_raw($name);
38 res
39 }};
40 ( [ $name:ident : dyn $ty:ident, $($tail:tt)* ], $body:block ) => {{
41 assert_nonnull!($name);
42 let $name = Arc::from_raw($name as *const Arc<dyn $ty>);
43 let rec = with_ffi_arcs!([$($tail)*], $body);
44 Arc::into_raw($name);
45 rec
46 }};
47 ( [ $name:ident : $ty:ty, $($tail:tt)* ], $body:block ) => {{
48 assert_nonnull!($name);
49 let $name = Arc::from_raw($name as *const $ty);
50 let rec = with_ffi_arcs!([$($tail)*], $body);
51 Arc::into_raw($name);
52 rec
53 }};
54}
55
56#[repr(C)]
61pub struct lucet_vmctx {
62 _unused: [u8; 0],
63}
64
65#[repr(C)]
66#[derive(Clone, Copy, Debug, FromPrimitive)]
67pub enum lucet_error {
68 Ok,
69 InvalidArgument,
70 RegionFull,
71 Module,
72 LimitsExceeded,
73 NoLinearMemory,
74 SymbolNotFound,
75 FuncNotFound,
76 RuntimeFault,
77 RuntimeTerminated,
78 Dl,
79 InstanceNotReturned,
80 InstanceNotYielded,
81 StartYielded,
82 Internal,
83 Unsupported,
84}
85
86impl From<Error> for lucet_error {
87 fn from(e: Error) -> lucet_error {
88 lucet_error::from(&e)
89 }
90}
91
92impl From<&Error> for lucet_error {
93 fn from(e: &Error) -> lucet_error {
94 match e {
95 Error::InvalidArgument(_) => lucet_error::InvalidArgument,
96 Error::RegionFull(_) => lucet_error::RegionFull,
97 Error::ModuleError(_) => lucet_error::Module,
98 Error::LimitsExceeded(_) => lucet_error::LimitsExceeded,
99 Error::NoLinearMemory(_) => lucet_error::NoLinearMemory,
100 Error::SymbolNotFound(_) => lucet_error::SymbolNotFound,
101 Error::FuncNotFound(_, _) => lucet_error::FuncNotFound,
102 Error::RuntimeFault(_) => lucet_error::RuntimeFault,
103 Error::RuntimeTerminated(_) => lucet_error::RuntimeTerminated,
104 Error::DlError(_) => lucet_error::Dl,
105 Error::InstanceNotReturned => lucet_error::InstanceNotReturned,
106 Error::InstanceNotYielded => lucet_error::InstanceNotYielded,
107 Error::StartYielded => lucet_error::StartYielded,
108 Error::InternalError(_) => lucet_error::Internal,
109 Error::Unsupported(_) => lucet_error::Unsupported,
110 }
111 }
112}
113
114#[repr(C)]
115pub struct lucet_instance {
116 _unused: [u8; 0],
117}
118
119#[repr(C)]
120pub struct lucet_region {
121 _unused: [u8; 0],
122}
123
124#[repr(C)]
125pub struct lucet_dl_module {
126 _unused: [u8; 0],
127}
128
129#[derive(Clone, Debug)]
133#[repr(C)]
134pub struct lucet_alloc_limits {
135 pub heap_memory_size: u64,
137 pub heap_address_space_size: u64,
139 pub stack_size: u64,
141 pub globals_size: u64,
143 pub signal_stack_size: u64,
153}
154
155impl From<Limits> for lucet_alloc_limits {
156 fn from(limits: Limits) -> lucet_alloc_limits {
157 (&limits).into()
158 }
159}
160
161impl From<&Limits> for lucet_alloc_limits {
162 fn from(limits: &Limits) -> lucet_alloc_limits {
163 lucet_alloc_limits {
164 heap_memory_size: limits.heap_memory_size as u64,
165 heap_address_space_size: limits.heap_address_space_size as u64,
166 stack_size: limits.stack_size as u64,
167 globals_size: limits.globals_size as u64,
168 signal_stack_size: limits.signal_stack_size as u64,
169 }
170 }
171}
172
173impl From<lucet_alloc_limits> for Limits {
174 fn from(limits: lucet_alloc_limits) -> Limits {
175 (&limits).into()
176 }
177}
178
179impl From<&lucet_alloc_limits> for Limits {
180 fn from(limits: &lucet_alloc_limits) -> Limits {
181 Limits {
182 heap_memory_size: limits.heap_memory_size as usize,
183 heap_address_space_size: limits.heap_address_space_size as usize,
184 stack_size: limits.stack_size as usize,
185 globals_size: limits.globals_size as usize,
186 signal_stack_size: limits.signal_stack_size as usize,
187 }
188 }
189}
190
191#[repr(C)]
192#[derive(Clone, Copy, Debug)]
193pub enum lucet_signal_behavior {
194 Default,
195 Continue,
196 Terminate,
197}
198
199impl From<lucet_signal_behavior> for SignalBehavior {
200 fn from(sb: lucet_signal_behavior) -> SignalBehavior {
201 sb.into()
202 }
203}
204
205impl From<&lucet_signal_behavior> for SignalBehavior {
206 fn from(sb: &lucet_signal_behavior) -> SignalBehavior {
207 match sb {
208 lucet_signal_behavior::Default => SignalBehavior::Default,
209 lucet_signal_behavior::Continue => SignalBehavior::Continue,
210 lucet_signal_behavior::Terminate => SignalBehavior::Terminate,
211 }
212 }
213}
214
215pub type lucet_signal_handler = unsafe extern "C" fn(
216 inst: *mut lucet_instance,
217 trap: lucet_result::lucet_trapcode,
218 signum: c_int,
219 siginfo: *const libc::siginfo_t,
220 context: *const c_void,
221) -> lucet_signal_behavior;
222
223pub type lucet_fatal_handler = unsafe extern "C" fn(inst: *mut lucet_instance);
224
225pub struct CTerminationDetails {
226 pub details: *mut c_void,
227}
228
229unsafe impl Send for CTerminationDetails {}
230unsafe impl Sync for CTerminationDetails {}
231
232pub struct CYieldedVal {
233 pub val: *mut c_void,
234}
235
236unsafe impl Send for CYieldedVal {}
237unsafe impl Sync for CYieldedVal {}
238
239pub mod lucet_result {
240 use super::lucet_error;
241 use crate::c_api::{lucet_val, CTerminationDetails, CYieldedVal};
242 use crate::error::Error;
243 use crate::instance::{RunResult, TerminationDetails};
244 use crate::module::{AddrDetails, TrapCode};
245 use libc::{c_uchar, c_void};
246 use num_derive::FromPrimitive;
247 use std::ffi::CString;
248 use std::ptr;
249
250 impl From<Result<RunResult, Error>> for lucet_result {
251 fn from(res: Result<RunResult, Error>) -> lucet_result {
252 match res {
253 Ok(RunResult::Returned(retval)) => lucet_result {
254 tag: lucet_result_tag::Returned,
255 val: lucet_result_val {
256 returned: retval.into(),
257 },
258 },
259 Ok(RunResult::Yielded(val)) => lucet_result {
260 tag: lucet_result_tag::Yielded,
261 val: lucet_result_val {
262 yielded: lucet_yielded {
263 val: val
264 .downcast_ref()
265 .map(|CYieldedVal { val }| *val)
266 .unwrap_or(ptr::null_mut()),
267 },
268 },
269 },
270 Err(Error::RuntimeFault(details)) => lucet_result {
272 tag: lucet_result_tag::Faulted,
273 val: lucet_result_val {
274 fault: lucet_runtime_faulted {
275 fatal: details.fatal,
276 trapcode: details.trapcode.into(),
277 rip_addr: details.rip_addr,
278 rip_addr_details: details.rip_addr_details.into(),
279 },
280 },
281 },
282 Err(Error::RuntimeTerminated(details)) => lucet_result {
284 tag: lucet_result_tag::Terminated,
285 val: lucet_result_val {
286 terminated: match details {
287 TerminationDetails::Signal => lucet_terminated {
288 reason: lucet_terminated_reason::Signal,
289 provided: ptr::null_mut(),
290 },
291 TerminationDetails::CtxNotFound => lucet_terminated {
292 reason: lucet_terminated_reason::CtxNotFound,
293 provided: ptr::null_mut(),
294 },
295 TerminationDetails::YieldTypeMismatch => lucet_terminated {
296 reason: lucet_terminated_reason::YieldTypeMismatch,
297 provided: ptr::null_mut(),
298 },
299 TerminationDetails::BorrowError(_) => lucet_terminated {
300 reason: lucet_terminated_reason::BorrowError,
301 provided: ptr::null_mut(),
302 },
303 TerminationDetails::Provided(p) => lucet_terminated {
304 reason: lucet_terminated_reason::Provided,
305 provided: p
306 .downcast_ref()
307 .map(|CTerminationDetails { details }| *details)
308 .unwrap_or(ptr::null_mut()),
309 },
310 TerminationDetails::Remote => lucet_terminated {
311 reason: lucet_terminated_reason::Remote,
312 provided: std::ptr::null_mut(),
313 },
314 },
315 },
316 },
317 Err(e) => lucet_result {
318 tag: lucet_result_tag::Errored,
319 val: lucet_result_val { errored: e.into() },
320 },
321 }
322 }
323 }
324
325 #[repr(C)]
326 #[derive(Clone, Copy)]
327 pub struct lucet_result {
328 pub tag: lucet_result_tag,
329 pub val: lucet_result_val,
330 }
331
332 #[repr(C)]
333 #[derive(Clone, Copy, Debug, FromPrimitive)]
334 pub enum lucet_result_tag {
335 Returned,
336 Yielded,
337 Faulted,
338 Terminated,
339 Errored,
340 }
341
342 #[repr(C)]
343 #[derive(Clone, Copy)]
344 pub union lucet_result_val {
345 pub returned: lucet_val::lucet_untyped_retval,
346 pub yielded: lucet_yielded,
347 pub fault: lucet_runtime_faulted,
348 pub terminated: lucet_terminated,
349 pub errored: lucet_error,
350 }
351
352 #[repr(C)]
353 #[derive(Clone, Copy)]
354 pub struct lucet_terminated {
355 pub reason: lucet_terminated_reason,
356 pub provided: *mut c_void,
357 }
358
359 #[repr(C)]
360 #[derive(Clone, Copy)]
361 pub enum lucet_terminated_reason {
362 Signal,
363 CtxNotFound,
364 YieldTypeMismatch,
365 BorrowError,
366 Provided,
367 Remote,
368 }
369
370 #[repr(C)]
371 #[derive(Clone, Copy)]
372 pub struct lucet_yielded {
373 pub val: *mut c_void,
374 }
375
376 #[repr(C)]
377 #[derive(Clone, Copy)]
378 pub struct lucet_runtime_faulted {
379 pub fatal: bool,
380 pub trapcode: lucet_trapcode,
381 pub rip_addr: libc::uintptr_t,
382 pub rip_addr_details: lucet_module_addr_details,
383 }
384
385 #[repr(C)]
386 #[derive(Clone, Copy, Debug)]
387 pub enum lucet_trapcode {
388 StackOverflow,
389 HeapOutOfBounds,
390 OutOfBounds,
391 IndirectCallToNull,
392 BadSignature,
393 IntegerOverflow,
394 IntegerDivByZero,
395 BadConversionToInteger,
396 Interrupt,
397 TableOutOfBounds,
398 Unreachable,
399 Unknown,
400 }
401
402 impl From<Option<TrapCode>> for lucet_trapcode {
403 fn from(ty: Option<TrapCode>) -> lucet_trapcode {
404 (&ty).into()
405 }
406 }
407
408 impl From<&Option<TrapCode>> for lucet_trapcode {
409 fn from(ty: &Option<TrapCode>) -> lucet_trapcode {
410 if let Some(ty) = ty {
411 match ty {
412 TrapCode::StackOverflow => lucet_trapcode::StackOverflow,
413 TrapCode::HeapOutOfBounds => lucet_trapcode::HeapOutOfBounds,
414 TrapCode::OutOfBounds => lucet_trapcode::OutOfBounds,
415 TrapCode::IndirectCallToNull => lucet_trapcode::IndirectCallToNull,
416 TrapCode::BadSignature => lucet_trapcode::BadSignature,
417 TrapCode::IntegerOverflow => lucet_trapcode::IntegerOverflow,
418 TrapCode::IntegerDivByZero => lucet_trapcode::IntegerDivByZero,
419 TrapCode::BadConversionToInteger => lucet_trapcode::BadConversionToInteger,
420 TrapCode::Interrupt => lucet_trapcode::Interrupt,
421 TrapCode::TableOutOfBounds => lucet_trapcode::TableOutOfBounds,
422 TrapCode::Unreachable => lucet_trapcode::Unreachable,
423 }
424 } else {
425 lucet_trapcode::Unknown
426 }
427 }
428 }
429
430 const ADDR_DETAILS_NAME_LEN: usize = 256;
431
432 #[repr(C)]
435 #[derive(Clone, Copy)]
436 pub struct lucet_module_addr_details {
437 pub module_code_resolvable: bool,
438 pub in_module_code: bool,
439 pub file_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
440 pub sym_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
441 }
442
443 impl Default for lucet_module_addr_details {
444 fn default() -> Self {
445 lucet_module_addr_details {
446 module_code_resolvable: false,
447 in_module_code: false,
448 file_name: [0; ADDR_DETAILS_NAME_LEN],
449 sym_name: [0; ADDR_DETAILS_NAME_LEN],
450 }
451 }
452 }
453
454 impl From<Option<AddrDetails>> for lucet_module_addr_details {
455 fn from(details: Option<AddrDetails>) -> Self {
456 fn trunc_c_str_bytes(s: &str) -> Vec<u8> {
459 let s = CString::new(s);
460 let mut bytes = s.ok().map(|s| s.into_bytes_with_nul()).unwrap_or(vec![0]);
461 bytes.truncate(ADDR_DETAILS_NAME_LEN);
462 *bytes.last_mut().unwrap() = 0;
464 bytes
465 }
466
467 let mut ret = details
468 .as_ref()
469 .map(|details| lucet_module_addr_details {
470 module_code_resolvable: true,
471 in_module_code: details.in_module_code,
472 file_name: [0; ADDR_DETAILS_NAME_LEN],
473 sym_name: [0; ADDR_DETAILS_NAME_LEN],
474 })
475 .unwrap_or_default();
476
477 let file_name_bytes = details
479 .as_ref()
480 .and_then(|details| details.file_name.as_ref().map(|s| trunc_c_str_bytes(s)))
481 .unwrap_or_else(|| vec![0]);
482 let sym_name_bytes = details
483 .and_then(|details| details.sym_name.as_ref().map(|s| trunc_c_str_bytes(s)))
484 .unwrap_or_else(|| vec![0]);
485
486 ret.file_name[0..file_name_bytes.len()].copy_from_slice(file_name_bytes.as_slice());
488 ret.sym_name[0..sym_name_bytes.len()].copy_from_slice(sym_name_bytes.as_slice());
489
490 ret
491 }
492 }
493}
494
495pub mod lucet_val {
496 use crate::val::{UntypedRetVal, UntypedRetValInternal, Val};
497 use libc::{c_char, c_void};
498
499 #[repr(C)]
504 #[derive(Clone, Copy, Debug)]
505 pub enum lucet_val_type {
506 C_Ptr, GuestPtr, U8, U16, U32, U64, I8, I16, I32, I64, USize, ISize, Bool, F32, F64, }
522
523 #[repr(C)]
524 #[derive(Clone, Copy)]
525 pub union lucet_val_inner_val {
526 as_c_ptr: *mut c_void, as_u64: u64, as_i64: i64, as_f32: f32, as_f64: f64, }
532
533 #[repr(C)]
534 #[derive(Clone, Copy)]
535 pub struct lucet_val {
536 ty: lucet_val_type,
537 inner_val: lucet_val_inner_val,
538 }
539
540 impl From<lucet_val> for Val {
541 fn from(val: lucet_val) -> Val {
542 (&val).into()
543 }
544 }
545
546 impl From<&lucet_val> for Val {
547 fn from(val: &lucet_val) -> Val {
548 match val.ty {
549 lucet_val_type::C_Ptr => Val::CPtr(unsafe { val.inner_val.as_u64 } as _),
550 lucet_val_type::GuestPtr => Val::GuestPtr(unsafe { val.inner_val.as_u64 } as _),
551 lucet_val_type::U8 => Val::U8(unsafe { val.inner_val.as_u64 } as _),
552 lucet_val_type::U16 => Val::U16(unsafe { val.inner_val.as_u64 } as _),
553 lucet_val_type::U32 => Val::U32(unsafe { val.inner_val.as_u64 } as _),
554 lucet_val_type::U64 => Val::U64(unsafe { val.inner_val.as_u64 } as _),
555 lucet_val_type::I8 => Val::I16(unsafe { val.inner_val.as_i64 } as _),
556 lucet_val_type::I16 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
557 lucet_val_type::I32 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
558 lucet_val_type::I64 => Val::I64(unsafe { val.inner_val.as_i64 } as _),
559 lucet_val_type::USize => Val::USize(unsafe { val.inner_val.as_u64 } as _),
560 lucet_val_type::ISize => Val::ISize(unsafe { val.inner_val.as_i64 } as _),
561 lucet_val_type::Bool => Val::Bool(unsafe { val.inner_val.as_u64 } != 0),
562 lucet_val_type::F32 => Val::F32(unsafe { val.inner_val.as_f32 } as _),
563 lucet_val_type::F64 => Val::F64(unsafe { val.inner_val.as_f64 } as _),
564 }
565 }
566 }
567
568 impl From<Val> for lucet_val {
569 fn from(val: Val) -> Self {
570 (&val).into()
571 }
572 }
573
574 impl From<&Val> for lucet_val {
575 fn from(val: &Val) -> Self {
576 match val {
577 Val::CPtr(a) => lucet_val {
578 ty: lucet_val_type::C_Ptr,
579 inner_val: lucet_val_inner_val { as_u64: *a as _ },
580 },
581 Val::GuestPtr(a) => lucet_val {
582 ty: lucet_val_type::GuestPtr,
583 inner_val: lucet_val_inner_val { as_u64: *a as _ },
584 },
585 Val::U8(a) => lucet_val {
586 ty: lucet_val_type::U8,
587 inner_val: lucet_val_inner_val { as_u64: *a as _ },
588 },
589 Val::U16(a) => lucet_val {
590 ty: lucet_val_type::U16,
591 inner_val: lucet_val_inner_val { as_u64: *a as _ },
592 },
593 Val::U32(a) => lucet_val {
594 ty: lucet_val_type::U32,
595 inner_val: lucet_val_inner_val { as_u64: *a as _ },
596 },
597 Val::U64(a) => lucet_val {
598 ty: lucet_val_type::U64,
599 inner_val: lucet_val_inner_val { as_u64: *a as _ },
600 },
601 Val::I8(a) => lucet_val {
602 ty: lucet_val_type::I8,
603 inner_val: lucet_val_inner_val { as_i64: *a as _ },
604 },
605 Val::I16(a) => lucet_val {
606 ty: lucet_val_type::I16,
607 inner_val: lucet_val_inner_val { as_i64: *a as _ },
608 },
609 Val::I32(a) => lucet_val {
610 ty: lucet_val_type::I32,
611 inner_val: lucet_val_inner_val { as_i64: *a as _ },
612 },
613 Val::I64(a) => lucet_val {
614 ty: lucet_val_type::I64,
615 inner_val: lucet_val_inner_val { as_i64: *a as _ },
616 },
617 Val::USize(a) => lucet_val {
618 ty: lucet_val_type::USize,
619 inner_val: lucet_val_inner_val { as_u64: *a as _ },
620 },
621 Val::ISize(a) => lucet_val {
622 ty: lucet_val_type::ISize,
623 inner_val: lucet_val_inner_val { as_i64: *a as _ },
624 },
625 Val::Bool(a) => lucet_val {
626 ty: lucet_val_type::Bool,
627 inner_val: lucet_val_inner_val { as_u64: *a as _ },
628 },
629 Val::F32(a) => lucet_val {
630 ty: lucet_val_type::F32,
631 inner_val: lucet_val_inner_val { as_f32: *a as _ },
632 },
633 Val::F64(a) => lucet_val {
634 ty: lucet_val_type::F64,
635 inner_val: lucet_val_inner_val { as_f64: *a as _ },
636 },
637 }
638 }
639 }
640
641 #[repr(C)]
642 #[derive(Clone, Copy, Debug)]
643 pub struct lucet_untyped_retval {
644 pub fp: [c_char; 16],
645 pub gp: [c_char; 8],
646 }
647
648 #[repr(C)]
649 #[derive(Clone, Copy)]
650 pub union lucet_retval_gp {
651 pub as_untyped: [c_char; 8],
652 pub as_c_ptr: *mut c_void,
653 pub as_u64: u64,
654 pub as_i64: i64,
655 }
656
657 impl From<UntypedRetVal> for lucet_untyped_retval {
658 fn from(retval: UntypedRetVal) -> lucet_untyped_retval {
659 let mut v = lucet_untyped_retval {
660 fp: [0; 16],
661 gp: [0; 8],
662 };
663 unsafe {
664 core::arch::x86_64::_mm_storeu_ps(
665 v.fp.as_mut().as_mut_ptr() as *mut f32,
666 retval.fp(),
667 );
668 *(v.gp.as_mut().as_mut_ptr() as *mut u64) = retval.gp();
669 }
670 v
671 }
672 }
673}