Skip to main content

thruput_native_exec/
host_fn_error.rs

1use std::panic::panic_any;
2use thruput_trace::ffi_enums::HostFnErrorCode;
3use thruput_xdr::syserr::SysErr;
4
5/// Perform one guest syscall against the mocked FFI handler, returning its
6/// result code. Host-side terminations unwind with the matching
7/// [`crate::invoke_error`] payload instead of returning.
8#[allow(clippy::too_many_arguments)]
9pub fn perform_mocked_syscall(
10    syscall: i32,
11    arg1: u64,
12    arg2: u64,
13    arg3: u64,
14    arg4: u64,
15    arg5: u64,
16    arg6: u64,
17    arg7: u64,
18) -> i32 {
19    let result: thruput_sys::ForeignHostFnResult = unsafe {
20        thruput_sys::mock_syscall_entrypoint(
21            syscall, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
22        )
23    };
24
25    match result.panic {
26        x if x == HostFnErrorCode::NoneOrRecoverable.0 => result.result_code,
27        x if x == HostFnErrorCode::OutOfGas.0 => {
28            panic_any(crate::invoke_error::out_of_gas_error());
29        }
30        x if x == HostFnErrorCode::Unrecoverable.0 => {
31            panic_any(crate::invoke_error::unrecoverable_error());
32        }
33        x if x == HostFnErrorCode::Return.0 => {
34            panic_any(crate::invoke_error::control_flow_unwind());
35        }
36        // Exit is a deterministic frame revert on every runtime (rv32,
37        // native precompiles): the `Exit` syscall and every host-side
38        // rejection of `Return` (over-limit buffer, bad returned auth
39        // tokens) raise it. Unwinding it as a completed frame would report
40        // the caller an `Ok(Return)` with an empty buffer instead.
41        x if x == HostFnErrorCode::Exit.0 => {
42            panic_any(crate::invoke_error::deterministic_error());
43        }
44        x if x == HostFnErrorCode::ValidationFailure.0 => {
45            panic_any(crate::invoke_error::validation_error());
46        }
47        x if x == HostFnErrorCode::Abandon.0 => {
48            panic_any(crate::invoke_error::abort_transaction_error());
49        }
50        _ => {
51            panic_any(crate::invoke_error::unrecoverable_error());
52        }
53    }
54}
55
56/// The symbol thruput-xdr's `syscalls_mock` extern declaration links
57/// against; forwards to [`perform_mocked_syscall`].
58#[unsafe(no_mangle)]
59pub extern "C-unwind" fn syscall_wrapper_impl(
60    // Matches thruput-xdr's `syscalls_mock` extern declaration, which passes
61    // `SyscallNo` widened to a native `SyscallWord` (u64). `SyscallNo` itself is
62    // now `repr(transparent)` over a `u32`, so taking it directly here would be
63    // an ABI mismatch.
64    syscall_no: u64,
65    arg1: u64,
66    arg2: u64,
67    arg3: u64,
68    arg4: u64,
69    arg5: u64,
70    arg6: u64,
71    arg7: u64,
72) -> SysErr {
73    SysErr(perform_mocked_syscall(
74        syscall_no as i32,
75        arg1,
76        arg2,
77        arg3,
78        arg4,
79        arg5,
80        arg6,
81        arg7,
82    ))
83}