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 }
59}
60
61/// A jump buffer.
62///
63/// This is essentially the register state of a point in execution at the time
64/// of a [`sigsetjmp`] call that can be returned to by passing this buffer to
65/// [`siglongjmp`].
66#[repr(C)]
67pub struct JmpBuf {
68 /// CPU context
69 __jmp_buf: __jmp_buf,
70 /// Whether the signal mask was saved
71 __fl: u32,
72 /// Saved signal mask
73 __ss: [u32; 32],
74}
75
76unsafe extern "C" {
77 /// Set jump point for a non-local goto.
78 ///
79 /// The return value will be 0 if this is a direct invocation (ie the "first
80 /// time" `sigsetjmp` is executed), and will be the value passed to `siglongjmp`
81 /// otherwise.
82 ///
83 /// See [sigsetjmp](https://man7.org/linux/man-pages/man3/sigsetjmp.3p.html)
84 /// for more information.
85 #[cfg_attr(target_env = "gnu", link_name = "__sigsetjmp")]
86 pub fn sigsetjmp(jb: *mut JmpBuf, save_mask: i32) -> i32;
87 /// Non-local goto with signal handling
88 ///
89 /// The value passed here will be returned by `sigsetjmp` when returning
90 /// to that callsite. Note that passing a value of 0 here will be changed
91 /// to a 1.
92 ///
93 /// See [siglongjmp](https://man7.org/linux/man-pages/man3/siglongjmp.3p.html)
94 /// for more information.
95 pub fn siglongjmp(jb: *mut JmpBuf, val: i32) -> !;
96}