445 lines
12 KiB
Rust
445 lines
12 KiB
Rust
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(std::ptr::read_unaligned(bytes.as_ptr().cast::<Self>())) }
|
|
}
|
|
}
|
|
|
|
#[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],
|
|
/// Shadow stack
|
|
__ssp: [u64; 4],
|
|
}
|
|
|
|
#[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,
|
|
}
|
|
} else if #[cfg(target_arch = "riscv64")] {
|
|
#[repr(C)]
|
|
#[derive(Clone)]
|
|
#[doc(hidden)]
|
|
pub struct ucontext_t {
|
|
pub __uc_flags: u64,
|
|
pub uc_link: *mut ucontext_t,
|
|
pub uc_stack: stack_t,
|
|
pub uc_sigmask: sigset_t,
|
|
pub uc_mcontext: mcontext_t,
|
|
}
|
|
|
|
#[repr(C, align(16))]
|
|
#[derive(Clone)]
|
|
#[doc(hidden)]
|
|
pub struct mcontext_t {
|
|
pub __gregs: [u64; 32],
|
|
pub __fpregs: __riscv_mc_fp_state,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy)]
|
|
#[doc(hidden)]
|
|
pub union __riscv_mc_fp_state {
|
|
pub __f: __riscv_mc_f_ext_state,
|
|
pub __d: __riscv_mc_d_ext_state,
|
|
pub __q: __riscv_mc_q_ext_state,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy)]
|
|
#[doc(hidden)]
|
|
pub struct __riscv_mc_f_ext_state {
|
|
pub __f: [u32; 32],
|
|
pub __fcsr: u32,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy)]
|
|
#[doc(hidden)]
|
|
pub struct __riscv_mc_d_ext_state {
|
|
pub __f: [u64; 32],
|
|
pub __fcsr: u32,
|
|
}
|
|
|
|
#[repr(C, align(16))]
|
|
#[derive(Clone, Copy)]
|
|
#[doc(hidden)]
|
|
pub struct __riscv_mc_q_ext_state {
|
|
pub __f: [u64; 64],
|
|
pub __fcsr: u32,
|
|
pub __reserved: [u32; 3],
|
|
}
|
|
|
|
pub type fpregset_t = __riscv_mc_fp_state;
|
|
} else if #[cfg(target_arch = "s390x")] {
|
|
#[repr(C)]
|
|
#[derive(Clone)]
|
|
#[doc(hidden)]
|
|
pub struct ucontext_t {
|
|
pub uc_flags: u64,
|
|
pub uc_link: *mut ucontext_t,
|
|
pub uc_stack: stack_t,
|
|
pub uc_mcontext: mcontext_t,
|
|
pub uc_sigmask: sigset_t,
|
|
}
|
|
|
|
#[repr(C, align(8))]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct mcontext_t {
|
|
pub psw: psw_t,
|
|
pub gregs: [u64; 16],
|
|
pub aregs: [u32; 16],
|
|
pub __fpregs: fpregset_t,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct fpregset_t {
|
|
pub fpc: u32,
|
|
__pad: u32,
|
|
pub fprs: [fpreg_t; 16],
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct fpreg_t {
|
|
pub d: f64,
|
|
// pub f: f32,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct psw_t {
|
|
pub mask: u64,
|
|
pub addr: u64,
|
|
}
|
|
} else if #[cfg(target_arch = "loongarch64")] {
|
|
pub const SC_USED_FP: u32 = 1;
|
|
pub const FPU_CTX_MAGIC: u32 = 0x46505501;
|
|
pub const FPU_CTX_ALIGN: usize = 8;
|
|
pub const LSX_CTX_MAGIC: u32 = 0x53580001;
|
|
pub const LSX_CTX_ALIGN: usize = 16;
|
|
pub const LASX_CTX_MAGIC: u32 = 0x41535801;
|
|
pub const LASX_CTX_ALIGN: usize = 32;
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone)]
|
|
#[doc(hidden)]
|
|
pub struct ucontext_t {
|
|
pub uc_flags: u64,
|
|
pub uc_link: *mut ucontext_t,
|
|
pub uc_stack: stack_t,
|
|
pub uc_sigmask: sigset_t,
|
|
pub uc_mcontext: mcontext_t,
|
|
}
|
|
|
|
#[repr(C, align(16))]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct mcontext_t {
|
|
pub __pc: u64,
|
|
pub __gregs: [u64; 32],
|
|
pub __flags: u32,
|
|
pub __extcontext: [u64; 0],
|
|
}
|
|
|
|
#[repr(C, align(16))]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct sctx_info {
|
|
pub magic: u32,
|
|
pub size: u32,
|
|
padding: u64,
|
|
}
|
|
|
|
#[repr(C, align(8))]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct fpu_context {
|
|
pub regs: [u64; 32],
|
|
pub fcc: u64,
|
|
pub fcsr: u32,
|
|
}
|
|
|
|
#[repr(C, align(16))]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct lsx_context {
|
|
pub regs: [u64; 2*32],
|
|
pub fcc: u64,
|
|
pub fcsr: u32,
|
|
}
|
|
|
|
#[repr(C, align(32))]
|
|
#[derive(Clone,Copy)]
|
|
#[doc(hidden)]
|
|
pub struct lasx_context {
|
|
pub regs: [u64; 4*32],
|
|
pub fcc: u64,
|
|
pub fcsr: u32,
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub type fpregset_t = fpu_context;
|
|
}
|
|
}
|
|
|
|
#[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>()
|
|
);
|
|
}
|
|
}
|