summaryrefslogtreecommitdiffstats
path: root/third_party/rust/crash-context/src/linux.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/crash-context/src/linux.rs')
-rw-r--r--third_party/rust/crash-context/src/linux.rs273
1 files changed, 273 insertions, 0 deletions
diff --git a/third_party/rust/crash-context/src/linux.rs b/third_party/rust/crash-context/src/linux.rs
new file mode 100644
index 0000000000..f9952c12d9
--- /dev/null
+++ b/third_party/rust/crash-context/src/linux.rs
@@ -0,0 +1,273 @@
+mod getcontext;
+
+pub use getcontext::crash_context_getcontext;
+
+/// The full context for a Linux/Android crash
+#[repr(C)]
+#[derive(Clone)]
+pub struct CrashContext {
+ /// Crashing thread context.
+ ///
+ /// Note that we use [`crate::ucontext_t`] instead of [`libc::ucontext_t`]
+ /// as libc's differs between glibc and musl <https://github.com/rust-lang/libc/pull/1646>
+ /// even though the ucontext_t received from a signal will be the same
+ /// regardless of the libc implementation used as it is only arch specific
+ /// and not libc specific
+ ///
+ /// Note that we hide `ucontext_t::uc_link` as it is a pointer and thus can't
+ /// be accessed in a process other than the one the `CrashContext` was created
+ /// in. This is a just a self-reference so is not useful in practice.
+ ///
+ /// Note that the same applies to [`mcontext_t::fpregs`], but since that points
+ /// to floating point registers and _is_ interesting to read in another process,
+ /// those registers available as [`Self::float_state`], except on the `arm`
+ /// architecture since they aren't part of `mcontext_t` at all.
+ pub context: ucontext_t,
+ /// State of floating point registers.
+ ///
+ /// This isn't part of the user ABI for Linux arm
+ #[cfg(not(target_arch = "arm"))]
+ pub float_state: fpregset_t,
+ /// The signal info for the crash
+ pub siginfo: libc::signalfd_siginfo,
+ /// The id of the crashing process
+ pub pid: libc::pid_t,
+ /// The id of the crashing thread
+ pub tid: libc::pid_t,
+}
+
+unsafe impl Send for CrashContext {}
+
+impl CrashContext {
+ pub fn as_bytes(&self) -> &[u8] {
+ unsafe {
+ let size = std::mem::size_of_val(self);
+ let ptr = (self as *const Self).cast();
+ std::slice::from_raw_parts(ptr, size)
+ }
+ }
+
+ pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
+ if bytes.len() != std::mem::size_of::<Self>() {
+ return None;
+ }
+
+ unsafe { Some((*bytes.as_ptr().cast::<Self>()).clone()) }
+ }
+}
+
+#[repr(C)]
+#[derive(Clone)]
+#[doc(hidden)]
+pub struct sigset_t {
+ #[cfg(target_pointer_width = "32")]
+ __val: [u32; 32],
+ #[cfg(target_pointer_width = "64")]
+ __val: [u64; 16],
+}
+
+#[repr(C)]
+#[derive(Clone)]
+#[doc(hidden)]
+pub struct stack_t {
+ pub ss_sp: *mut std::ffi::c_void,
+ pub ss_flags: i32,
+ pub ss_size: usize,
+}
+
+cfg_if::cfg_if! {
+ if #[cfg(target_arch = "x86_64")] {
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct ucontext_t {
+ pub uc_flags: u64,
+ uc_link: *mut ucontext_t,
+ pub uc_stack: stack_t,
+ pub uc_mcontext: mcontext_t,
+ pub uc_sigmask: sigset_t,
+ __private: [u8; 512],
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct mcontext_t {
+ pub gregs: [i64; 23],
+ pub fpregs: *mut fpregset_t,
+ __reserved: [u64; 8],
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct fpregset_t {
+ pub cwd: u16,
+ pub swd: u16,
+ pub ftw: u16,
+ pub fop: u16,
+ pub rip: u64,
+ pub rdp: u64,
+ pub mxcsr: u32,
+ pub mxcr_mask: u32,
+ pub st_space: [u32; 32],
+ pub xmm_space: [u32; 64],
+ __padding: [u64; 12],
+ }
+ } else if #[cfg(target_arch = "x86")] {
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct ucontext_t {
+ pub uc_flags: u32,
+ uc_link: *mut ucontext_t,
+ pub uc_stack: stack_t,
+ pub uc_mcontext: mcontext_t,
+ pub uc_sigmask: sigset_t,
+ pub __fpregs_mem: [u32; 28],
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct mcontext_t {
+ pub gregs: [i32; 23],
+ pub fpregs: *mut fpregset_t,
+ pub oldmask: u32,
+ pub cr2: u32,
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct fpreg_t {
+ pub significand: [u16; 4],
+ pub exponent: u16,
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct fpregset_t {
+ pub cw: u32,
+ pub sw: u32,
+ pub tag: u32,
+ pub ipoff: u32,
+ pub cssel: u32,
+ pub dataoff: u32,
+ pub datasel: u32,
+ pub _st: [fpreg_t; 8],
+ pub status: u32,
+ }
+ } else if #[cfg(target_arch = "aarch64")] {
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct ucontext_t {
+ pub uc_flags: u64,
+ uc_link: *mut ucontext_t,
+ pub uc_stack: stack_t,
+ pub uc_sigmask: sigset_t,
+ pub uc_mcontext: mcontext_t,
+ }
+
+ // Note you might see this defined in C with `unsigned long` or
+ // `unsigned long long` and think, WTF, those aren't the same! Except
+ // `long` means either 32-bit _or_ 64-bit depending on the data model,
+ // and the default data model for C/C++ is LP64 which means long is
+ // 64-bit. I had forgotten what a trash type long was.
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct mcontext_t {
+ // Note in the kernel this is just part of regs which is length 32
+ pub fault_address: u64,
+ pub regs: [u64; 31],
+ pub sp: u64,
+ pub pc: u64,
+ pub pstate: u64,
+ // Note that u128 is ABI safe on aarch64, this is actually a
+ // `long double` in C which Rust doesn't have native support
+ pub __reserved: [u128; 256],
+ }
+
+ /// Magic value written by the kernel and our custom getcontext
+ #[doc(hidden)]
+ pub const FPSIMD_MAGIC: u32 = 0x46508001;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct _aarch64_ctx {
+ pub magic: u32,
+ pub size: u32,
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct fpsimd_context {
+ pub head: _aarch64_ctx,
+ pub fpsr: u32,
+ pub fpcr: u32,
+ pub vregs: [u128; 32],
+ }
+
+ #[doc(hidden)]
+ pub type fpregset_t = fpsimd_context;
+ } else if #[cfg(target_arch = "arm")] {
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct ucontext_t {
+ pub uc_flags: u32,
+ uc_link: *mut ucontext_t,
+ pub uc_stack: stack_t,
+ // Note that the mcontext_t and sigset_t are swapped compared to
+ // all of the other arches currently supported :p
+ pub uc_mcontext: mcontext_t,
+ pub uc_sigmask: sigset_t,
+ pub uc_regspace: [u64; 64],
+ }
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[doc(hidden)]
+ pub struct mcontext_t {
+ pub trap_no: u32,
+ pub error_code: u32,
+ pub oldmask: u32,
+ pub arm_r0: u32,
+ pub arm_r1: u32,
+ pub arm_r2: u32,
+ pub arm_r3: u32,
+ pub arm_r4: u32,
+ pub arm_r5: u32,
+ pub arm_r6: u32,
+ pub arm_r7: u32,
+ pub arm_r8: u32,
+ pub arm_r9: u32,
+ pub arm_r10: u32,
+ pub arm_fp: u32,
+ pub arm_ip: u32,
+ pub arm_sp: u32,
+ pub arm_lr: u32,
+ pub arm_pc: u32,
+ pub arm_cpsr: u32,
+ pub fault_address: u32,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ // Musl doesn't contain fpregs in libc because reasons https://github.com/rust-lang/libc/pull/1646
+ #[cfg(not(target_env = "musl"))]
+ #[test]
+ fn matches_libc() {
+ assert_eq!(
+ std::mem::size_of::<libc::ucontext_t>(),
+ std::mem::size_of::<super::ucontext_t>()
+ );
+ }
+}