From 6f94ecd9ff8760f08fdcc4b88b18da049d278fdb Mon Sep 17 00:00:00 2001
From: Gabriele Svelto
Date: Wed, 26 Oct 2022 10:07:19 +0200
Subject: [PATCH 1/2] Remove the windows-sys dependency
---
Cargo.toml | 13 -
build.rs | 4 +
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, 627 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..72e79d7f
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,4 @@
+fn main() {
+ #![cfg(all(target_os = "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");
From ccffad6c5e51ad6e682b60bbd9098d3fbcfd2a26 Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Wed, 26 Oct 2022 13:09:57 +0200
Subject: [PATCH 2/2] Fix build.rs
---
build.rs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/build.rs b/build.rs
index 72e79d7f..23efce46 100644
--- a/build.rs
+++ b/build.rs
@@ -1,4 +1,5 @@
fn main() {
- #![cfg(all(target_os = "windows"))]
- println!("cargo:rustc-link-lib=dylib=dbghelp");
+ if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") {
+ println!("cargo:rustc-link-lib=dylib=dbghelp");
+ }
}