From 18d57a82fcc7d47c740aae6e0f4e10bf057ed193 Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Wed, 26 Oct 2022 13:19:20 +0200 Subject: [PATCH] Remove the windows-sys dependency (#60) * Remove the windows-sys dependency * Fix build.rs Co-authored-by: Jake Shadle --- Cargo.toml | 13 - build.rs | 5 + src/bin/test.rs | 9 +- src/windows.rs | 1 + src/windows/ffi.rs | 570 +++++++++++++++++++++++++++++++ src/windows/minidump_writer.rs | 69 ++-- tests/windows_minidump_writer.rs | 17 +- 7 files changed, 628 insertions(+), 56 deletions(-) create mode 100644 build.rs create mode 100644 src/windows/ffi.rs diff --git a/Cargo.toml b/Cargo.toml index 5bf9a60f..ad102d6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,19 +31,6 @@ nix = { version = "0.25", default-features = false, features = [ "user", ] } -[target.'cfg(target_os = "windows")'.dependencies.windows-sys] -version = "0.42" -features = [ - # MiniDumpWriteDump requires...a lot of features - "Win32_Foundation", - "Win32_Storage_FileSystem", - "Win32_System_Diagnostics_Debug", - "Win32_System_Kernel", - "Win32_System_Memory", - # GetCurrentThreadId & OpenProcess - "Win32_System_Threading", -] - [target.'cfg(target_os = "macos")'.dependencies] # Binds some additional mac specifics not in libc mach2 = "0.4" diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..23efce46 --- /dev/null +++ b/build.rs @@ -0,0 +1,5 @@ +fn main() { + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") { + println!("cargo:rustc-link-lib=dylib=dbghelp"); + } +} diff --git a/src/bin/test.rs b/src/bin/test.rs index c5ad8e0c..239e97ee 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -295,12 +295,13 @@ mod linux { #[cfg(target_os = "windows")] mod windows { + use minidump_writer::ffi::{ + GetCurrentProcessId, GetCurrentThread, GetCurrentThreadId, GetThreadContext, CONTEXT, + EXCEPTION_POINTERS, EXCEPTION_RECORD, + }; + use super::*; use std::mem; - use windows_sys::Win32::System::{ - Diagnostics::Debug::{GetThreadContext, CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD}, - Threading::{GetCurrentProcessId, GetCurrentThread, GetCurrentThreadId}, - }; #[inline(never)] pub(super) fn real_main(args: Vec) -> Result<()> { diff --git a/src/windows.rs b/src/windows.rs index 1ae7a276..1717ad03 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,2 +1,3 @@ pub mod errors; +pub mod ffi; pub mod minidump_writer; diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs new file mode 100644 index 00000000..8a9dcca7 --- /dev/null +++ b/src/windows/ffi.rs @@ -0,0 +1,570 @@ +pub type BOOL = i32; +pub const FALSE: BOOL = 0; + +pub type HANDLE = isize; +pub type NTSTATUS = i32; + +pub const STATUS_NONCONTINUABLE_EXCEPTION: NTSTATUS = -1073741787i32; + +extern "system" { + pub fn CloseHandle(hobject: HANDLE) -> BOOL; +} + +// threading + +#[allow(non_camel_case_types)] +pub type PROCESS_ACCESS_RIGHTS = u32; + +pub const PROCESS_ALL_ACCESS: PROCESS_ACCESS_RIGHTS = 2097151u32; + +#[allow(non_camel_case_types)] +pub type THREAD_ACCESS_RIGHTS = u32; + +pub const THREAD_SUSPEND_RESUME: THREAD_ACCESS_RIGHTS = 2u32; +pub const THREAD_GET_CONTEXT: THREAD_ACCESS_RIGHTS = 8u32; +pub const THREAD_QUERY_INFORMATION: THREAD_ACCESS_RIGHTS = 64u32; + +extern "system" { + pub fn GetCurrentProcess() -> HANDLE; + pub fn GetCurrentProcessId() -> u32; + pub fn GetCurrentThread() -> HANDLE; + pub fn GetCurrentThreadId() -> u32; + pub fn OpenProcess( + dwdesiredaccess: PROCESS_ACCESS_RIGHTS, + binherithandle: BOOL, + dwprocessid: u32, + ) -> HANDLE; + pub fn OpenThread( + dwdesiredaccess: THREAD_ACCESS_RIGHTS, + binherithandle: BOOL, + dwthreadid: u32, + ) -> HANDLE; + pub fn ResumeThread(hthread: HANDLE) -> u32; + pub fn SuspendThread(hthread: HANDLE) -> u32; +} + +// context + +#[allow(non_snake_case)] +#[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], +} + +impl ::core::marker::Copy for ARM64_NT_NEON128 {} +impl ::core::clone::Clone for ARM64_NT_NEON128 { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +pub struct ARM64_NT_NEON128_0 { + pub Low: u64, + pub High: i64, +} + +impl ::core::marker::Copy for ARM64_NT_NEON128_0 {} +impl ::core::clone::Clone for ARM64_NT_NEON128_0 { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "aarch64")] +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], +} + +#[cfg(target_arch = "aarch64")] +impl ::core::marker::Copy for CONTEXT {} +#[cfg(target_arch = "aarch64")] +impl ::core::clone::Clone for CONTEXT { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "aarch64")] +pub union CONTEXT_0 { + pub Anonymous: CONTEXT_0_0, + pub X: [u64; 31], +} + +#[cfg(target_arch = "aarch64")] +impl ::core::marker::Copy for CONTEXT_0 {} +#[cfg(target_arch = "aarch64")] +impl ::core::clone::Clone for CONTEXT_0 { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "aarch64")] +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, +} + +#[cfg(target_arch = "aarch64")] +impl ::core::marker::Copy for CONTEXT_0_0 {} +#[cfg(target_arch = "aarch64")] +impl ::core::clone::Clone for CONTEXT_0_0 { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "x86_64")] +pub struct CONTEXT { + pub P1Home: u64, + pub P2Home: u64, + pub P3Home: u64, + pub P4Home: u64, + pub P5Home: u64, + pub P6Home: u64, + pub ContextFlags: u32, + pub MxCsr: u32, + pub SegCs: u16, + pub SegDs: u16, + pub SegEs: u16, + pub SegFs: u16, + pub SegGs: u16, + pub SegSs: u16, + pub EFlags: u32, + pub Dr0: u64, + pub Dr1: u64, + pub Dr2: u64, + pub Dr3: u64, + pub Dr6: u64, + pub Dr7: u64, + pub Rax: u64, + pub Rcx: u64, + pub Rdx: u64, + pub Rbx: u64, + pub Rsp: u64, + pub Rbp: u64, + pub Rsi: u64, + pub Rdi: u64, + pub R8: u64, + pub R9: u64, + pub R10: u64, + pub R11: u64, + pub R12: u64, + pub R13: u64, + pub R14: u64, + pub R15: u64, + pub Rip: u64, + pub Anonymous: CONTEXT_0, + pub VectorRegister: [M128A; 26], + pub VectorControl: u64, + pub DebugControl: u64, + pub LastBranchToRip: u64, + pub LastBranchFromRip: u64, + pub LastExceptionToRip: u64, + pub LastExceptionFromRip: u64, +} + +#[cfg(target_arch = "x86_64")] +impl ::core::marker::Copy for CONTEXT {} +#[cfg(target_arch = "x86_64")] +impl ::core::clone::Clone for CONTEXT { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "x86_64")] +pub union CONTEXT_0 { + pub FltSave: XSAVE_FORMAT, + pub Anonymous: CONTEXT_0_0, +} + +#[cfg(target_arch = "x86_64")] +impl ::core::marker::Copy for CONTEXT_0 {} +#[cfg(target_arch = "x86_64")] +impl ::core::clone::Clone for CONTEXT_0 { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "x86_64")] +pub struct CONTEXT_0_0 { + pub Header: [M128A; 2], + pub Legacy: [M128A; 8], + pub Xmm0: M128A, + pub Xmm1: M128A, + pub Xmm2: M128A, + pub Xmm3: M128A, + pub Xmm4: M128A, + pub Xmm5: M128A, + pub Xmm6: M128A, + pub Xmm7: M128A, + pub Xmm8: M128A, + pub Xmm9: M128A, + pub Xmm10: M128A, + pub Xmm11: M128A, + pub Xmm12: M128A, + pub Xmm13: M128A, + pub Xmm14: M128A, + pub Xmm15: M128A, +} +#[cfg(target_arch = "x86_64")] +impl ::core::marker::Copy for CONTEXT_0_0 {} +#[cfg(target_arch = "x86_64")] +impl ::core::clone::Clone for CONTEXT_0_0 { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "x86")] +pub struct CONTEXT { + pub ContextFlags: u32, + pub Dr0: u32, + pub Dr1: u32, + pub Dr2: u32, + pub Dr3: u32, + pub Dr6: u32, + pub Dr7: u32, + pub FloatSave: FLOATING_SAVE_AREA, + pub SegGs: u32, + pub SegFs: u32, + pub SegEs: u32, + pub SegDs: u32, + pub Edi: u32, + pub Esi: u32, + pub Ebx: u32, + pub Edx: u32, + pub Ecx: u32, + pub Eax: u32, + pub Ebp: u32, + pub Eip: u32, + pub SegCs: u32, + pub EFlags: u32, + pub Esp: u32, + pub SegSs: u32, + pub ExtendedRegisters: [u8; 512], +} + +#[cfg(target_arch = "x86")] +impl ::core::marker::Copy for CONTEXT {} +#[cfg(target_arch = "x86")] +impl ::core::clone::Clone for CONTEXT { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] +pub struct FLOATING_SAVE_AREA { + pub ControlWord: u32, + pub StatusWord: u32, + pub TagWord: u32, + pub ErrorOffset: u32, + pub ErrorSelector: u32, + pub DataOffset: u32, + pub DataSelector: u32, + pub RegisterArea: [u8; 80], + pub Cr0NpxState: u32, +} + +#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] +impl ::core::marker::Copy for FLOATING_SAVE_AREA {} +#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] +impl ::core::clone::Clone for FLOATING_SAVE_AREA { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "x86")] +pub struct FLOATING_SAVE_AREA { + pub ControlWord: u32, + pub StatusWord: u32, + pub TagWord: u32, + pub ErrorOffset: u32, + pub ErrorSelector: u32, + pub DataOffset: u32, + pub DataSelector: u32, + pub RegisterArea: [u8; 80], + pub Spare0: u32, +} + +#[cfg(target_arch = "x86")] +impl ::core::marker::Copy for FLOATING_SAVE_AREA {} +#[cfg(target_arch = "x86")] +impl ::core::clone::Clone for FLOATING_SAVE_AREA { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] +pub struct XSAVE_FORMAT { + pub ControlWord: u16, + pub StatusWord: u16, + pub TagWord: u8, + pub Reserved1: u8, + pub ErrorOpcode: u16, + pub ErrorOffset: u32, + pub ErrorSelector: u16, + pub Reserved2: u16, + pub DataOffset: u32, + pub DataSelector: u16, + pub Reserved3: u16, + pub MxCsr: u32, + pub MxCsr_Mask: u32, + pub FloatRegisters: [M128A; 8], + pub XmmRegisters: [M128A; 16], + pub Reserved4: [u8; 96], +} + +#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] +impl ::core::marker::Copy for XSAVE_FORMAT {} +#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] +impl ::core::clone::Clone for XSAVE_FORMAT { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +#[cfg(target_arch = "x86")] +pub struct XSAVE_FORMAT { + pub ControlWord: u16, + pub StatusWord: u16, + pub TagWord: u8, + pub Reserved1: u8, + pub ErrorOpcode: u16, + pub ErrorOffset: u32, + pub ErrorSelector: u16, + pub Reserved2: u16, + pub DataOffset: u32, + pub DataSelector: u16, + pub Reserved3: u16, + pub MxCsr: u32, + pub MxCsr_Mask: u32, + pub FloatRegisters: [M128A; 8], + pub XmmRegisters: [M128A; 8], + pub Reserved4: [u8; 224], +} + +#[cfg(target_arch = "x86")] +impl ::core::marker::Copy for XSAVE_FORMAT {} +#[cfg(target_arch = "x86")] +impl ::core::clone::Clone for XSAVE_FORMAT { + fn clone(&self) -> Self { + *self + } +} + +// minidump + +#[allow(non_camel_case_types)] +pub type MINIDUMP_TYPE = u32; + +#[allow(non_upper_case_globals)] +pub const MiniDumpNormal: MINIDUMP_TYPE = 0u32; + +#[allow(non_camel_case_types)] +pub type MINIDUMP_CALLBACK_ROUTINE = Option< + unsafe extern "system" fn( + callbackparam: *mut ::core::ffi::c_void, + callbackinput: *const MINIDUMP_CALLBACK_INPUT, + callbackoutput: *mut MINIDUMP_CALLBACK_OUTPUT, + ) -> BOOL, +>; + +#[repr(C, packed(4))] +pub struct MINIDUMP_CALLBACK_INPUT { + dummy: u32, +} + +impl ::core::marker::Copy for MINIDUMP_CALLBACK_INPUT {} +impl ::core::clone::Clone for MINIDUMP_CALLBACK_INPUT { + fn clone(&self) -> Self { + *self + } +} + +#[repr(C, packed(4))] +pub struct MINIDUMP_CALLBACK_OUTPUT { + dummy: u32, +} + +impl ::core::marker::Copy for MINIDUMP_CALLBACK_OUTPUT {} +impl ::core::clone::Clone for MINIDUMP_CALLBACK_OUTPUT { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C)] +pub struct M128A { + pub Low: u64, + pub High: i64, +} + +impl ::core::marker::Copy for M128A {} +impl ::core::clone::Clone for M128A { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C, packed(4))] +pub struct MINIDUMP_CALLBACK_INFORMATION { + pub CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE, + pub CallbackParam: *mut ::core::ffi::c_void, +} + +impl ::core::marker::Copy for MINIDUMP_CALLBACK_INFORMATION {} +impl ::core::clone::Clone for MINIDUMP_CALLBACK_INFORMATION { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C, packed(4))] +pub struct MINIDUMP_EXCEPTION_INFORMATION { + pub ThreadId: u32, + pub ExceptionPointers: *mut EXCEPTION_POINTERS, + pub ClientPointers: BOOL, +} + +#[allow(non_snake_case)] +#[repr(C)] +pub struct EXCEPTION_POINTERS { + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ContextRecord: *mut CONTEXT, +} + +#[allow(non_snake_case)] +#[repr(C)] +pub struct EXCEPTION_RECORD { + pub ExceptionCode: NTSTATUS, + pub ExceptionFlags: u32, + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ExceptionAddress: *mut ::core::ffi::c_void, + pub NumberParameters: u32, + pub ExceptionInformation: [usize; 15], +} + +impl ::core::marker::Copy for EXCEPTION_RECORD {} +impl ::core::clone::Clone for EXCEPTION_RECORD { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C, packed(4))] +pub struct MINIDUMP_USER_STREAM { + pub Type: u32, + pub BufferSize: u32, + pub Buffer: *mut ::core::ffi::c_void, +} +impl ::core::marker::Copy for MINIDUMP_USER_STREAM {} +impl ::core::clone::Clone for MINIDUMP_USER_STREAM { + fn clone(&self) -> Self { + *self + } +} + +#[allow(non_snake_case)] +#[repr(C, packed(4))] +pub struct MINIDUMP_USER_STREAM_INFORMATION { + pub UserStreamCount: u32, + pub UserStreamArray: *mut MINIDUMP_USER_STREAM, +} +impl ::core::marker::Copy for MINIDUMP_USER_STREAM_INFORMATION {} +impl ::core::clone::Clone for MINIDUMP_USER_STREAM_INFORMATION { + fn clone(&self) -> Self { + *self + } +} + +extern "system" { + pub fn GetThreadContext(hthread: HANDLE, lpcontext: *mut CONTEXT) -> BOOL; + pub fn MiniDumpWriteDump( + hprocess: HANDLE, + processid: u32, + hfile: HANDLE, + dumptype: MINIDUMP_TYPE, + exceptionparam: *const MINIDUMP_EXCEPTION_INFORMATION, + userstreamparam: *const MINIDUMP_USER_STREAM_INFORMATION, + callbackparam: *const MINIDUMP_CALLBACK_INFORMATION, + ) -> BOOL; + pub fn RtlCaptureContext(contextrecord: *mut CONTEXT); +} diff --git a/src/windows/minidump_writer.rs b/src/windows/minidump_writer.rs index 68938f2e..8218beb5 100644 --- a/src/windows/minidump_writer.rs +++ b/src/windows/minidump_writer.rs @@ -1,16 +1,19 @@ use crate::windows::errors::Error; +use crate::windows::ffi::{ + CloseHandle, GetCurrentProcess, GetCurrentThreadId, GetThreadContext, MiniDumpNormal, + MiniDumpWriteDump, OpenProcess, OpenThread, ResumeThread, RtlCaptureContext, SuspendThread, + EXCEPTION_POINTERS, EXCEPTION_RECORD, FALSE, HANDLE, MINIDUMP_EXCEPTION_INFORMATION, + MINIDUMP_USER_STREAM, MINIDUMP_USER_STREAM_INFORMATION, PROCESS_ALL_ACCESS, + STATUS_NONCONTINUABLE_EXCEPTION, THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, + THREAD_SUSPEND_RESUME, +}; use minidump_common::format::{BreakpadInfoValid, MINIDUMP_BREAKPAD_INFO, MINIDUMP_STREAM_TYPE}; use scroll::Pwrite; use std::os::windows::io::AsRawHandle; -pub use windows_sys::Win32::Foundation::HANDLE; -use windows_sys::Win32::{ - Foundation::{CloseHandle, STATUS_NONCONTINUABLE_EXCEPTION}, - System::{Diagnostics::Debug as md, Threading as threading}, -}; pub struct MinidumpWriter { /// Optional exception information - exc_info: Option, + exc_info: Option, /// Handle to the crashing process, which could be ourselves crashing_process: HANDLE, /// The id of the process we are dumping @@ -53,19 +56,17 @@ impl MinidumpWriter { // We need to suspend the thread to get its context, which would be bad // if it's the current thread, so we check it early before regrets happen - if tid == threading::GetCurrentThreadId() { - md::RtlCaptureContext(ec.as_mut_ptr()); + if tid == GetCurrentThreadId() { + RtlCaptureContext(ec.as_mut_ptr()); } else { // We _could_ just fallback to the current thread if we can't get the // thread handle, but probably better for this to fail with a specific // error so that the caller can do that themselves if they want to // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread - let thread_handle = threading::OpenThread( - threading::THREAD_GET_CONTEXT - | threading::THREAD_QUERY_INFORMATION - | threading::THREAD_SUSPEND_RESUME, // desired access rights, we only need to get the context, which also requires suspension - 0, // inherit handles - tid, // thread id + let thread_handle = OpenThread( + THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME, // desired access rights, we only need to get the context, which also requires suspension + FALSE, // inherit handles + tid, // thread id ); if thread_handle == 0 { @@ -85,14 +86,14 @@ impl MinidumpWriter { // As noted in the GetThreadContext docs, we have to suspend the thread before we can get its context // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread - if threading::SuspendThread(thread_handle.0) == u32::MAX { + if SuspendThread(thread_handle.0) == u32::MAX { return Err(Error::ThreadSuspend(std::io::Error::last_os_error())); } // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext - if md::GetThreadContext(thread_handle.0, ec.as_mut_ptr()) == 0 { + if GetThreadContext(thread_handle.0, ec.as_mut_ptr()) == 0 { // Try to be a good citizen and resume the thread - threading::ResumeThread(thread_handle.0); + ResumeThread(thread_handle.0); return Err(Error::ThreadContext(std::io::Error::last_os_error())); } @@ -100,19 +101,19 @@ impl MinidumpWriter { // _presumably_ this will not fail if SuspendThread succeeded, but if it does // there's really not much we can do about it, thus we don't bother checking the // return value - threading::ResumeThread(thread_handle.0); + ResumeThread(thread_handle.0); } ec.assume_init() } else { let mut ec = std::mem::MaybeUninit::uninit(); - md::RtlCaptureContext(ec.as_mut_ptr()); + RtlCaptureContext(ec.as_mut_ptr()); ec.assume_init() }; - let mut exception_record: md::EXCEPTION_RECORD = std::mem::zeroed(); + let mut exception_record: EXCEPTION_RECORD = std::mem::zeroed(); - let exception_ptrs = md::EXCEPTION_POINTERS { + let exception_ptrs = EXCEPTION_POINTERS { ExceptionRecord: &mut exception_record, ContextRecord: &mut exception_context, }; @@ -120,9 +121,9 @@ impl MinidumpWriter { exception_record.ExceptionCode = exception_code; let cc = crash_context::CrashContext { - exception_pointers: (&exception_ptrs as *const md::EXCEPTION_POINTERS).cast(), + exception_pointers: (&exception_ptrs as *const EXCEPTION_POINTERS).cast(), process_id: std::process::id(), - thread_id: thread_id.unwrap_or_else(|| threading::GetCurrentThreadId()), + thread_id: thread_id.unwrap_or_else(|| GetCurrentThreadId()), exception_code, }; @@ -153,10 +154,10 @@ impl MinidumpWriter { // SAFETY: syscalls let (crashing_process, is_external_process) = unsafe { if pid != std::process::id() { - let proc = threading::OpenProcess( - threading::PROCESS_ALL_ACCESS, // desired access - 0, // inherit handles - pid, // pid + let proc = OpenProcess( + PROCESS_ALL_ACCESS, // desired access + FALSE, // inherit handles + pid, // pid ); if proc == 0 { @@ -165,7 +166,7 @@ impl MinidumpWriter { (proc, true) } else { - (threading::GetCurrentProcess(), false) + (GetCurrentProcess(), false) } }; @@ -175,7 +176,7 @@ impl MinidumpWriter { let exc_info = (!crash_context.exception_pointers.is_null()).then_some( // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception_information - md::MINIDUMP_EXCEPTION_INFORMATION { + MINIDUMP_EXCEPTION_INFORMATION { ThreadId: crash_context.thread_id, // This is a mut pointer for some reason...I don't _think_ it is // actually mut in practice...? @@ -212,7 +213,7 @@ impl MinidumpWriter { let mut breakpad_info = self.fill_breakpad_stream(); if let Some(bp_info) = &mut breakpad_info { - user_streams.push(md::MINIDUMP_USER_STREAM { + user_streams.push(MINIDUMP_USER_STREAM { Type: MINIDUMP_STREAM_TYPE::BreakpadInfoStream as u32, BufferSize: bp_info.len() as u32, // Again with the mut pointer @@ -220,7 +221,7 @@ impl MinidumpWriter { }); } - let user_stream_infos = md::MINIDUMP_USER_STREAM_INFORMATION { + let user_stream_infos = MINIDUMP_USER_STREAM_INFORMATION { UserStreamCount: user_streams.len() as u32, UserStreamArray: user_streams.as_mut_ptr(), }; @@ -229,11 +230,11 @@ impl MinidumpWriter { // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump // SAFETY: syscall let ret = unsafe { - md::MiniDumpWriteDump( + MiniDumpWriteDump( self.crashing_process, // HANDLE to the process with the crash we want to capture self.pid, // process id destination.as_raw_handle() as HANDLE, // file to write the minidump to - md::MiniDumpNormal, // MINIDUMP_TYPE - we _might_ want to make this configurable + MiniDumpNormal, // MINIDUMP_TYPE - we _might_ want to make this configurable exc_info .as_ref() .map_or(std::ptr::null(), |ei| ei as *const _), // exceptionparam - the actual exception information @@ -269,7 +270,7 @@ impl MinidumpWriter { | BreakpadInfoValid::RequestingThreadId.bits(), dump_thread_id: self.tid, // Safety: syscall - requesting_thread_id: unsafe { threading::GetCurrentThreadId() }, + requesting_thread_id: unsafe { GetCurrentThreadId() }, }; // TODO: derive Pwrite for MINIDUMP_BREAKPAD_INFO diff --git a/tests/windows_minidump_writer.rs b/tests/windows_minidump_writer.rs index c0b32168..1ea04710 100644 --- a/tests/windows_minidump_writer.rs +++ b/tests/windows_minidump_writer.rs @@ -5,10 +5,18 @@ use minidump::{ MinidumpThreadList, }; use minidump_writer::minidump_writer::MinidumpWriter; -use windows_sys::Win32::Foundation::{EXCEPTION_ILLEGAL_INSTRUCTION, STATUS_INVALID_PARAMETER}; mod common; use common::start_child_and_return; +type NTSTATUS = i32; + +const EXCEPTION_ILLEGAL_INSTRUCTION: NTSTATUS = -1073741795i32; +const STATUS_INVALID_PARAMETER: NTSTATUS = -1073741811i32; + +extern "system" { + pub(crate) fn GetCurrentThreadId() -> u32; +} + fn get_crash_reason<'a, T: std::ops::Deref + 'a>( md: &Minidump<'a, T>, ) -> CrashReason { @@ -47,7 +55,7 @@ fn dump_current_process() { ); // SAFETY: syscall - let thread_id = unsafe { windows_sys::Win32::System::Threading::GetCurrentThreadId() }; + let thread_id = unsafe { GetCurrentThreadId() }; let bp_info: MinidumpBreakpadInfo = md.get_stream().expect("Couldn't find MinidumpBreakpadInfo"); @@ -67,7 +75,7 @@ fn dump_specific_thread() { let jh = std::thread::spawn(move || { // SAFETY: syscall - let thread_id = unsafe { windows_sys::Win32::System::Threading::GetCurrentThreadId() }; + let thread_id = unsafe { GetCurrentThreadId() }; while tx.send(thread_id).is_ok() { std::thread::sleep(std::time::Duration::from_millis(10)); } @@ -99,8 +107,7 @@ fn dump_specific_thread() { ); // SAFETY: syscall - let requesting_thread_id = - unsafe { windows_sys::Win32::System::Threading::GetCurrentThreadId() }; + let requesting_thread_id = unsafe { GetCurrentThreadId() }; let bp_info: MinidumpBreakpadInfo = md.get_stream().expect("Couldn't find MinidumpBreakpadInfo");