Skip to main content

crash_handler/linux/
jmp.rs

1//! FFI bindings for non-local goto
2//!
3//! ```
4//! use crash_handler::jmp;
5//!
6//! unsafe {
7//!     let mut jmp_buf = std::mem::MaybeUninit::uninit();
8//!
9//!     let val = jmp::sigsetjmp(jmp_buf.as_mut_ptr(), 1);
10//!
11//!     if val == 0 {
12//!         jmp::siglongjmp(jmp_buf.as_mut_ptr(), 22);
13//!     } else {
14//!         assert_eq!(val, 22);
15//!     }
16//! }
17//! ```
18
19cfg_if::cfg_if! {
20    if #[cfg(target_arch = "x86_64")] {
21        #[repr(C)]
22        #[doc(hidden)]
23        #[allow(non_camel_case_types)]
24        pub struct __jmp_buf([u64; 8]);
25    } else if #[cfg(target_arch = "x86")] {
26        #[repr(C)]
27        #[doc(hidden)]
28        #[allow(non_camel_case_types)]
29        pub struct __jmp_buf([u32; 6]);
30    } else if #[cfg(target_arch = "arm")] {
31        #[repr(C)]
32        #[doc(hidden)]
33        #[allow(non_camel_case_types)]
34        pub struct __jmp_buf([u64; 32]);
35    } else if #[cfg(target_arch = "aarch64")] {
36        #[repr(C)]
37        #[doc(hidden)]
38        #[allow(non_camel_case_types)]
39        pub struct __jmp_buf([u64; 22]);
40    } else if #[cfg(target_arch = "riscv64")] {
41        #[repr(C)]
42        #[doc(hidden)]
43        #[allow(non_camel_case_types)]
44        pub struct __jmp_buf {
45            __pc: u64,
46            __regs: [u64; 12],
47            __sp: u64,
48            __fpregs: [f64; 12],
49        }
50    } else if #[cfg(target_arch = "s390x" )] {
51        #[repr(C)]
52        #[doc(hidden)]
53        #[allow(non_camel_case_types)]
54        pub struct __jmp_buf{
55            __gregs: [u64; 10],
56            __fpregs: [f64; 8],
57        }
58    } else if #[cfg(target_arch = "loongarch64")] {
59        #[repr(C)]
60        #[doc(hidden)]
61        #[allow(non_camel_case_types)]
62        pub struct __jmp_buf {
63            __pc: u64,
64            __sp: u64,
65            __x: u64,
66            __fp: u64,
67            __regs: [u64; 9],
68            __fpregs: [f64; 8],
69        }
70    }
71}
72
73/// A jump buffer.
74///
75/// This is essentially the register state of a point in execution at the time
76/// of a [`sigsetjmp`] call that can be returned to by passing this buffer to
77/// [`siglongjmp`].
78#[repr(C)]
79pub struct JmpBuf {
80    /// CPU context
81    __jmp_buf: __jmp_buf,
82    /// Whether the signal mask was saved
83    __fl: u32,
84    /// Saved signal mask
85    __ss: [u32; 32],
86}
87
88unsafe extern "C" {
89    /// Set jump point for a non-local goto.
90    ///
91    /// The return value will be 0 if this is a direct invocation (ie the "first
92    /// time" `sigsetjmp` is executed), and will be the value passed to `siglongjmp`
93    /// otherwise.
94    ///
95    /// See [sigsetjmp](https://man7.org/linux/man-pages/man3/sigsetjmp.3p.html)
96    /// for more information.
97    #[cfg_attr(target_env = "gnu", link_name = "__sigsetjmp")]
98    pub fn sigsetjmp(jb: *mut JmpBuf, save_mask: i32) -> i32;
99    /// Non-local goto with signal handling
100    ///
101    /// The value passed here will be returned by `sigsetjmp` when returning
102    /// to that callsite. Note that passing a value of 0 here will be changed
103    /// to a 1.
104    ///
105    /// See [siglongjmp](https://man7.org/linux/man-pages/man3/siglongjmp.3p.html)
106    /// for more information.
107    pub fn siglongjmp(jb: *mut JmpBuf, val: i32) -> !;
108}