Skip to content

Commit

Permalink
Add RtlCaptureContext replacement (#62)
Browse files Browse the repository at this point in the history
* Cleanup implementation, add aarch64

* Fix clippy lints

* Expose ffi module

* Cache deny step

* Fixup crash-handler with crash-context

* Update crash-handler with crash-context changes

* Pointless
  • Loading branch information
Jake-Shadle authored Nov 17, 2022
1 parent 7cba205 commit 11fc5c9
Show file tree
Hide file tree
Showing 14 changed files with 630 additions and 99 deletions.
5 changes: 5 additions & 0 deletions crash-context/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ libc = "0.2"
[target.'cfg(target_os = "macos")'.dependencies]
# provides bindings to mach specifics
mach2 = "0.4"

# Provides bindings to Win32
[target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3"
features = ["winnt"]
11 changes: 5 additions & 6 deletions crash-context/src/windows.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
pub mod ffi;

/// Full Windows crash context
pub struct CrashContext {
/// The information on the exception.
///
/// Note that this is a pointer into the actual memory of the crashed process,
/// and is a pointer to an [EXCEPTION_POINTERS](https://docs.rs/windows-sys/0.35.0/windows_sys/Win32/System/Diagnostics/Debug/struct.EXCEPTION_POINTERS.html)
///
/// We intentionally don't use `windows-sys` here as the type information is
/// completely lost when crossing process boundaries anyways
pub exception_pointers: *const std::ffi::c_void,
/// and is a pointer to an [EXCEPTION_POINTERS](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_pointers)
pub exception_pointers: *const ffi::EXCEPTION_POINTERS,
/// The top level exception code from the exception_pointers. This is provided
/// so that external processes don't need to use `ReadProcessMemory` to inspect
/// the exception code
pub exception_code: i32,
pub exception_code: u32,
/// The pid of the process that crashed
pub process_id: u32,
/// The thread id on which the exception occurred
Expand Down
49 changes: 49 additions & 0 deletions crash-context/src/windows/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Custom bindings to `CONTEXT` and some structures that relate to it, to both
//! deal with bugs in bindings, as well as not be dependent particularly on
//! `windows-sys` due the massive amount of version churn that crate introduces.
//!
//! Both [`winapi`](https://docs.rs/winapi/latest/winapi/) and
//! [`windows-sys`](https://docs.rs/windows-sys/latest/windows_sys/) have
//! incorrect bindings with regards to `CONTEXT` and its related structures.
//! These structures **must** be aligned to 16 bytes, but [are not](https://github.com/microsoft/win32metadata/issues/1044).

#![allow(non_snake_case)]

extern "C" {
/// Reimplementation of [`RtlCaptureContext`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlcapturecontext)
///
/// As noted above, the structures from `winapi` and `windows-sys` have
/// incorrect alignment.
///
/// In addition, `RtlCaptureContext` only captures the state of the integer
/// registers, while this implementation additionally captures floating point
/// and vector state.
///
/// The implementation is ported from Crashpad.
///
/// - [x86](https://github.com/chromium/crashpad/blob/f742c1aa4aff1834dc55e97895f8cdfdfc945a21/util/misc/capture_context_win.asm)
/// - [aarch64](https://github.com/chromium/crashpad/blob/f742c1aa4aff1834dc55e97895f8cdfdfc945a21/util/misc/capture_context_win_arm64.asm)
pub fn capture_context(ctx: *mut CONTEXT);
}

pub use winapi::um::winnt::EXCEPTION_RECORD;

cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
mod x86_64;
pub use x86_64::*;
} else if #[cfg(target_arch = "x86")] {
compile_error!("Please file an issue if you care about this target");
//mod x86;
} else if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use aarch64::*;
}
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct EXCEPTION_POINTERS {
pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ContextRecord: *mut CONTEXT,
}
143 changes: 143 additions & 0 deletions crash-context/src/windows/ffi/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2019 The Crashpad Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[derive(Copy, Clone)]
// Note this is intentionally using natural alignment
#[repr(C)]
pub union ARM64_NT_NEON128 {
pub Anonymous: ARM64_NT_NEON128_0,
pub D: [f64; 2],
pub S: [f32; 4],
pub H: [u16; 8],
pub B: [u8; 16],
}

#[derive(Copy, Clone)]
// Note this is intentionally using natural alignment
#[repr(C)]
pub struct ARM64_NT_NEON128_0 {
pub Low: u64,
pub High: i64,
}

#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct CONTEXT {
pub ContextFlags: u32,
pub Cpsr: u32,
pub Anonymous: CONTEXT_0,
pub Sp: u64,
pub Pc: u64,
pub V: [ARM64_NT_NEON128; 32],
pub Fpcr: u32,
pub Fpsr: u32,
pub Bcr: [u32; 8],
pub Bvr: [u64; 8],
pub Wcr: [u32; 2],
pub Wvr: [u64; 2],
}

#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub union CONTEXT_0 {
pub Anonymous: CONTEXT_0_0,
pub X: [u64; 31],
}

#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct CONTEXT_0_0 {
pub X0: u64,
pub X1: u64,
pub X2: u64,
pub X3: u64,
pub X4: u64,
pub X5: u64,
pub X6: u64,
pub X7: u64,
pub X8: u64,
pub X9: u64,
pub X10: u64,
pub X11: u64,
pub X12: u64,
pub X13: u64,
pub X14: u64,
pub X15: u64,
pub X16: u64,
pub X17: u64,
pub X18: u64,
pub X19: u64,
pub X20: u64,
pub X21: u64,
pub X22: u64,
pub X23: u64,
pub X24: u64,
pub X25: u64,
pub X26: u64,
pub X27: u64,
pub X28: u64,
pub Fp: u64,
pub Lr: u64,
}

std::arch::global_asm! {
".text",
".global capture_context",
"capture_context:",
// Save general purpose registers in context.regs[i].
// The original x0 can't be recovered.
"stp x0, x1, [x0, #0x008]",
"stp x2, x3, [x0, #0x018]",
"stp x4, x5, [x0, #0x028]",
"stp x6, x7, [x0, #0x038]",
"stp x8, x9, [x0, #0x048]",
"stp x10, x11, [x0, #0x058]",
"stp x12, x13, [x0, #0x068]",
"stp x14, x15, [x0, #0x078]",
"stp x16, x17, [x0, #0x088]",
"stp x18, x19, [x0, #0x098]",
"stp x20, x21, [x0, #0x0a8]",
"stp x22, x23, [x0, #0x0b8]",
"stp x24, x25, [x0, #0x0c8]",
"stp x26, x27, [x0, #0x0d8]",
"stp x28, x29, [x0, #0x0e8]",

// The original LR can't be recovered.
"str LR, [x0, #0x0f8]",

// Use x1 as a scratch register.
"mov x1, SP",
// context.sp
"str x1, [x0, #0x100]",

// The link register holds the return address for this function.
// context.pc
"str LR, [x0, #0x108]",

// pstate should hold SPSR but NZCV are the only bits we know about.
"mrs x1, NZCV",

// Enable Control flags, such as CONTEXT_ARM64, CONTEXT_CONTROL,
// CONTEXT_INTEGER
"ldr w1, =0x00400003",

// Set ControlFlags /0x000/ and pstate /0x004/ at the same time.
"str x1, [x0, #0x000]",

// Restore x1 from the saved context.
"ldr x1, [x0, #0x010]",

// TODO(https://crashpad.chromium.org/bug/300): save floating-point registers
"ret",
}
Loading

0 comments on commit 11fc5c9

Please sign in to comment.