From d7eee80109f63c2b9ca8057b7461d8753827f010 Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Thu, 30 Mar 2023 09:05:49 +0200
Subject: [PATCH 1/6] Nuke winapi
---
Cargo.toml | 12 +-
src/bin/test.rs | 19 +-
src/windows.rs | 4 +-
src/windows/ffi.rs | 474 +++++++++++++++++++++++++++++----
src/windows/minidump_writer.rs | 29 +-
5 files changed, 457 insertions(+), 81 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index ee85b34f..d34bdd1e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,16 +31,13 @@ nix = { version = "0.26", default-features = false, features = [
"user",
] }
+[target.'cfg(target_os = "windows")'.dependencies]
+bitflags = "2.0"
+
[target.'cfg(target_os = "macos")'.dependencies]
# Binds some additional mac specifics not in libc
mach2 = "0.4"
-# Additional bindings to Windows specific APIs. Note we don't use windows-sys
-# due to massive version churn
-[target.'cfg(target_os = "windows")'.dependencies.winapi]
-version = "0.3"
-features = ["handleapi", "minwindef", "processthreadsapi", "winnt"]
-
[dev-dependencies]
# Minidump-processor is async so we need an executor
futures = { version = "0.3", features = ["executor"] }
@@ -54,3 +51,6 @@ dump_syms = { version = "2.0.0", default-features = false }
minidump-processor = { version = "0.15", default-features = false }
similar-asserts = "1.2"
uuid = "1.0"
+
+[patch.crates-io]
+crash-context = { path = "../crash-handling/crash-context" }
diff --git a/src/bin/test.rs b/src/bin/test.rs
index accbc998..21555fdb 100644
--- a/src/bin/test.rs
+++ b/src/bin/test.rs
@@ -295,14 +295,17 @@ mod linux {
#[cfg(target_os = "windows")]
mod windows {
- use minidump_writer::ffi::{
- GetCurrentProcessId, GetCurrentThread, GetCurrentThreadId, GetThreadContext,
- EXCEPTION_POINTERS, EXCEPTION_RECORD,
- };
-
use super::*;
use std::mem;
+ #[link(name = "kernel32")]
+ extern "system" {
+ pub fn GetCurrentProcessId() -> u32;
+ pub fn GetCurrentThreadId() -> u32;
+ pub fn GetCurrentThread() -> isize;
+ pub fn GetThreadContext(thread: isize, context: *mut crash_context::CONTEXT) -> i32;
+ }
+
#[inline(never)]
pub(super) fn real_main(args: Vec) -> Result<()> {
let exception_code = u32::from_str_radix(&args[0], 16).unwrap();
@@ -310,7 +313,7 @@ mod windows {
// Generate the exception and communicate back where the exception pointers
// are
unsafe {
- let mut exception_record: EXCEPTION_RECORD = mem::zeroed();
+ let mut exception_record: crash_context::EXCEPTION_RECORD = mem::zeroed();
let mut exception_context = std::mem::MaybeUninit::uninit();
let pid = GetCurrentProcessId();
@@ -320,12 +323,12 @@ mod windows {
let mut exception_context = exception_context.assume_init();
- let exception_ptrs = EXCEPTION_POINTERS {
+ let exception_ptrs = crash_context::EXCEPTION_POINTERS {
ExceptionRecord: &mut exception_record,
ContextRecord: &mut exception_context,
};
- exception_record.ExceptionCode = exception_code;
+ exception_record.ExceptionCode = exception_code as _;
let exc_ptr_addr = &exception_ptrs as *const _ as usize;
diff --git a/src/windows.rs b/src/windows.rs
index 1717ad03..34b72444 100644
--- a/src/windows.rs
+++ b/src/windows.rs
@@ -1,3 +1,5 @@
pub mod errors;
-pub mod ffi;
+mod ffi;
pub mod minidump_writer;
+
+pub use ffi::MinidumpType;
diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs
index 9841075c..cc919f57 100644
--- a/src/windows/ffi.rs
+++ b/src/windows/ffi.rs
@@ -7,51 +7,151 @@
//! cause crashes or bad data, so the [`crash_context::ffi::CONTEXT`] is used
//! instead. See [#63](https://github.com/rust-minidump/minidump-writer/issues/63)
-#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
+#![allow(
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals,
+ clippy::upper_case_acronyms
+)]
-pub use crash_context::ffi::{capture_context, CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD};
-pub use winapi::{
- shared::minwindef::BOOL,
- um::{
- processthreadsapi::{
- GetCurrentProcess, GetCurrentProcessId, GetCurrentThread, GetCurrentThreadId,
- OpenProcess, OpenThread, ResumeThread, SuspendThread,
- },
- winnt::HANDLE,
- },
-};
+pub use crash_context::{capture_context, CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD};
-pub type MINIDUMP_TYPE = u32;
+pub type HANDLE = isize;
+pub type BOOL = i32;
+pub const FALSE: BOOL = 0;
-pub const MiniDumpNormal: MINIDUMP_TYPE = 0u32;
+pub type Hresult = i32;
+pub const STATUS_NONCONTINUABLE_EXCEPTION: i32 = -1073741787;
-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,
->;
+pub type PROCESS_ACCESS_RIGHTS = u32;
+pub const PROCESS_ALL_ACCESS: PROCESS_ACCESS_RIGHTS = 2097151;
-#[derive(Copy, Clone)]
-#[repr(C, packed(4))]
-pub struct MINIDUMP_CALLBACK_INPUT {
- dummy: u32,
+pub type THREAD_ACCESS_RIGHTS = u32;
+pub const THREAD_SUSPEND_RESUME: THREAD_ACCESS_RIGHTS = 2;
+pub const THREAD_GET_CONTEXT: THREAD_ACCESS_RIGHTS = 8;
+pub const THREAD_QUERY_INFORMATION: THREAD_ACCESS_RIGHTS = 64;
+
+bitflags::bitflags! {
+ ///
+ #[derive(Copy, Clone, Debug)]
+ #[repr(transparent)]
+ pub struct MinidumpType: u32 {
+ /// Include just the information necessary to capture stack traces for all
+ /// existing threads in a process.
+ const Normal = 0;
+ /// Include the data sections from all loaded modules.
+ ///
+ /// This results in the inclusion of global variables, which can make
+ /// the minidump file significantly larger.
+ const WithDataSegs = 1 << 0;
+ /// Include all accessible memory in the process.
+ ///
+ /// The raw memory data is included at the end, so that the initial
+ /// structures can be mapped directly without the raw memory information.
+ /// This option can result in a very large file.
+ const WithFullMemory = 1 << 1;
+ /// Include high-level information about the operating system handles that
+ /// are active when the minidump is made.
+ const WithHandleData = 1 << 2;
+ /// Stack and backing store memory written to the minidump file should be
+ /// filtered to remove all but the pointer values necessary to reconstruct a
+ /// stack trace.
+ const FilterMemory = 1 << 3;
+ /// Stack and backing store memory should be scanned for pointer references
+ /// to modules in the module list.
+ ///
+ /// If a module is referenced by stack or backing store memory, the
+ /// [`MINIDUMP_CALLBACK_OUTPUT_0::ModuleWriteFlags`] field is set to
+ /// [`ModuleWriteFlags::ModuleReferencedByMemory`].
+ const ScanMemory = 1 << 4;
+ /// Include information from the list of modules that were recently
+ /// unloaded, if this information is maintained by the operating system.
+ const WithUnloadedModules = 1 << 5;
+ /// Include pages with data referenced by locals or other stack memory.
+ /// This option can increase the size of the minidump file significantly.
+ const WithIndirectlyReferencedMemory = 1 << 6;
+ /// Filter module paths for information such as user names or important
+ /// directories.
+ ///
+ /// This option may prevent the system from locating the image file and
+ /// should be used only in special situations.
+ const FilterModulePaths = 1 << 7;
+ /// Include complete per-process and per-thread information from the
+ /// operating system.
+ const WithProcessThreadData = 1 << 8;
+ /// Scan the virtual address space for [`PAGE_READWRITE`](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants)
+ /// memory to be included.
+ const WithPrivateReadWriteMemory = 1 << 9;
+ /// Reduce the data that is dumped by eliminating memory regions that
+ /// are not essential to meet criteria specified for the dump.
+ ///
+ /// This can avoid dumping memory that may contain data that is private
+ /// to the user. However, it is not a guarantee that no private information
+ /// will be present.
+ const WithoutOptionalData = 1 << 10;
+ /// Include memory region information.
+ ///
+ /// See [MINIDUMP_MEMORY_INFO_LIST](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info_list)
+ const WithFullMemoryInfo = 1 << 11;
+ /// Include thread state information.
+ ///
+ /// See [MINIDUMP_THREAD_INFO_LIST](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread_info_list)
+ const WithThreadInfo = 1 << 12;
+ /// Include all code and code-related sections from loaded modules to
+ /// capture executable content.
+ ///
+ /// For per-module control, use the [`ModuleWriteFlags::ModuleWriteCodeSegs`]
+ const WithCodeSegs = 1 << 13;
+ /// Turns off secondary auxiliary-supported memory gathering.
+ const WithoutAuxiliaryState = 1 << 14;
+ /// Requests that auxiliary data providers include their state in the
+ /// dump image; the state data that is included is provider dependent.
+ ///
+ /// This option can result in a large dump image.
+ const WithFullAuxiliaryState = 1 << 15;
+ /// Scans the virtual address space for [`PAGE_WRITECOPY`](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants) memory to be included.
+ const WithPrivateWriteCopyMemory = 1 << 16;
+ /// If you specify [`MinidumpType::MiniDumpWithFullMemory`], the
+ /// `MiniDumpWriteDump` function will fail if the function cannot read
+ /// the memory regions; however, if you include
+ /// [`IgnoreInaccessibleMemory`], the `MiniDumpWriteDump` function will
+ /// ignore the memory read failures and continue to generate the dump.
+ ///
+ /// Note that the inaccessible memory regions are not included in the dump.
+ const IgnoreInaccessibleMemory = 1 << 17;
+ /// Adds security token related data.
+ ///
+ /// This will make the "!token" extension work when processing a user-mode dump.
+ const WithTokenInformation = 1 << 18;
+ /// Adds module header related data.
+ const WithModuleHeaders = 1 << 19;
+ /// Adds filter triage related data.
+ const FilterTriage = 1 << 20;
+ /// Adds AVX crash state context registers.
+ const WithAvxXStateContext = 1 << 21;
+ /// Adds Intel Processor Trace related data.
+ const WithIptTrace = 1 << 22;
+ /// Scans inaccessible partial memory pages.
+ const ScanInaccessiblePartialPages = 1 << 23;
+ /// Exclude all memory with the virtual protection attribute of [`PAGE_WRITECOMBINE`](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants).
+ const FilterWriteCombinedMemory = 1 << 24;
+ }
}
-#[derive(Copy, Clone)]
+pub type VS_FIXEDFILEINFO_FILE_FLAGS = u32;
+
#[repr(C, packed(4))]
-pub struct MINIDUMP_CALLBACK_OUTPUT {
- dummy: u32,
+pub struct MINIDUMP_USER_STREAM {
+ pub Type: u32,
+ pub BufferSize: u32,
+ pub Buffer: *mut std::ffi::c_void,
}
-#[derive(Copy, Clone)]
#[repr(C, packed(4))]
-pub struct MINIDUMP_CALLBACK_INFORMATION {
- pub CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE,
- pub CallbackParam: *mut ::core::ffi::c_void,
+pub struct MINIDUMP_USER_STREAM_INFORMATION {
+ pub UserStreamCount: u32,
+ pub UserStreamArray: *mut MINIDUMP_USER_STREAM,
}
-#[derive(Copy, Clone)]
#[repr(C, packed(4))]
pub struct MINIDUMP_EXCEPTION_INFORMATION {
pub ThreadId: u32,
@@ -59,30 +159,306 @@ pub struct MINIDUMP_EXCEPTION_INFORMATION {
pub ClientPointers: BOOL,
}
-#[derive(Copy, Clone)]
+pub type VS_FIXEDFILEINFO_FILE_OS = i32;
+pub type VS_FIXEDFILEINFO_FILE_TYPE = i32;
+pub type VS_FIXEDFILEINFO_FILE_SUBTYPE = i32;
+
+#[repr(C)]
+pub struct VS_FIXEDFILEINFO {
+ pub dwSignature: u32,
+ pub dwStrucVersion: u32,
+ pub dwFileVersionMS: u32,
+ pub dwFileVersionLS: u32,
+ pub dwProductVersionMS: u32,
+ pub dwProductVersionLS: u32,
+ pub dwFileFlagsMask: u32,
+ pub dwFileFlags: VS_FIXEDFILEINFO_FILE_FLAGS,
+ pub dwFileOS: VS_FIXEDFILEINFO_FILE_OS,
+ pub dwFileType: VS_FIXEDFILEINFO_FILE_TYPE,
+ pub dwFileSubtype: VS_FIXEDFILEINFO_FILE_SUBTYPE,
+ pub dwFileDateMS: u32,
+ pub dwFileDateLS: u32,
+}
+#[repr(C, packed(4))]
+pub struct MINIDUMP_MODULE_CALLBACK {
+ pub FullPath: *mut u16,
+ pub BaseOfImage: u64,
+ pub SizeOfImage: u32,
+ pub CheckSum: u32,
+ pub TimeDateStamp: u32,
+ pub VersionInfo: VS_FIXEDFILEINFO,
+ pub CvRecord: *mut std::ffi::c_void,
+ pub SizeOfCvRecord: u32,
+ pub MiscRecord: *mut std::ffi::c_void,
+ pub SizeOfMiscRecord: u32,
+}
+
#[repr(C, packed(4))]
-pub struct MINIDUMP_USER_STREAM {
+pub struct MINIDUMP_INCLUDE_THREAD_CALLBACK {
+ pub ThreadId: u32,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_INCLUDE_MODULE_CALLBACK {
+ pub BaseOfImage: u64,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_IO_CALLBACK {
+ pub Handle: HANDLE,
+ pub Offset: u64,
+ pub Buffer: *mut std::ffi::c_void,
+ pub BufferBytes: u32,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_READ_MEMORY_FAILURE_CALLBACK {
+ pub Offset: u64,
+ pub Bytes: u32,
+ pub FailureStatus: Hresult,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_VM_QUERY_CALLBACK {
+ pub Offset: u64,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_VM_PRE_READ_CALLBACK {
+ pub Offset: u64,
+ pub Buffer: *mut std::ffi::c_void,
+ pub Size: u32,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_VM_POST_READ_CALLBACK {
+ pub Offset: u64,
+ pub Buffer: *mut std::ffi::c_void,
+ pub Size: u32,
+ pub Completed: u32,
+ pub Status: Hresult,
+}
+
+cfg_if::cfg_if! {
+ if #[cfg(target_arch = "x86")] {
+ #[repr(C)]
+ struct CALLBACK_CONTEXT([u8; 716]);
+ } else if #[cfg(target_arch = "x86_64")] {
+
+ } else if #[cfg(target_arch = "aarch64")] {
+ #[repr(C)]
+ struct CALLBACK_CONTEXT([u8; 912]);
+ }
+}
+
+/// Oof, so we have a problem with these structs, they are all packed(4), but
+/// `CONTEXT` is aligned by either 4 (x86) or 16 (x86_64/aarch64)...which Rust
+/// doesn't currently allow https://github.com/rust-lang/rust/issues/59154, so
+/// we need to basically cheat with a big byte array until that issue is fixed (possibly never)
+#[repr(C)]
+pub struct CALLBACK_CONTEXT([u8; std::mem::size_of::()]);
+
+cfg_if::cfg_if! {
+ if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+ #[repr(C, packed(4))]
+ pub struct MINIDUMP_THREAD_CALLBACK {
+ pub ThreadId: u32,
+ pub ThreadHandle: HANDLE,
+ pub Context: CALLBACK_CONTEXT,
+ pub SizeOfContext: u32,
+ pub StackBase: u64,
+ pub StackEnd: u64,
+ }
+
+ #[repr(C, packed(4))]
+ pub struct MINIDUMP_THREAD_EX_CALLBACK {
+ pub ThreadId: u32,
+ pub ThreadHandle: HANDLE,
+ pub Context: CALLBACK_CONTEXT,
+ pub SizeOfContext: u32,
+ pub StackBase: u64,
+ pub StackEnd: u64,
+ pub BackingStoreBase: u64,
+ pub BackingStoreEnd: u64,
+ }
+ } else if #[cfg(target_arch = "aarch64")] {
+ #[repr(C, packed(4))]
+ pub struct MINIDUMP_THREAD_CALLBACK {
+ pub ThreadId: u32,
+ pub ThreadHandle: HANDLE,
+ pub Pad: u32,
+ pub Context: CALLBACK_CONTEXT,
+ pub SizeOfContext: u32,
+ pub StackBase: u64,
+ pub StackEnd: u64,
+ }
+
+ #[repr(C, packed(4))]
+ pub struct MINIDUMP_THREAD_EX_CALLBACK {
+ pub ThreadId: u32,
+ pub ThreadHandle: HANDLE,
+ pub Pad: u32,
+ pub Context: CALLBACK_CONTEXT,
+ pub SizeOfContext: u32,
+ pub StackBase: u64,
+ pub StackEnd: u64,
+ pub BackingStoreBase: u64,
+ pub BackingStoreEnd: u64,
+ }
+ }
+}
+
+#[repr(C)]
+pub union MINIDUMP_CALLBACK_INPUT_0 {
+ pub Status: Hresult,
+ pub Thread: std::mem::ManuallyDrop,
+ pub ThreadEx: std::mem::ManuallyDrop,
+ pub Module: std::mem::ManuallyDrop,
+ pub IncludeThread: std::mem::ManuallyDrop,
+ pub IncludeModule: std::mem::ManuallyDrop,
+ pub Io: std::mem::ManuallyDrop,
+ pub ReadMemoryFailure: std::mem::ManuallyDrop,
+ pub SecondaryFlags: u32,
+ pub VmQuery: std::mem::ManuallyDrop,
+ pub VmPreRead: std::mem::ManuallyDrop,
+ pub VmPostRead: std::mem::ManuallyDrop,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_CALLBACK_INPUT {
+ pub ProcessId: u32,
+ pub ProcessHandle: HANDLE,
+ pub CallbackType: u32,
+ pub Anonymous: MINIDUMP_CALLBACK_INPUT_0,
+}
+
+pub type VIRTUAL_ALLOCATION_TYPE = u32;
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_MEMORY_INFO {
+ pub BaseAddress: u64,
+ pub AllocationBase: u64,
+ pub AllocationProtect: u32,
+ __alignment1: u32,
+ pub RegionSize: u64,
+ pub State: VIRTUAL_ALLOCATION_TYPE,
+ pub Protect: u32,
pub Type: u32,
- pub BufferSize: u32,
- pub Buffer: *mut ::core::ffi::c_void,
+ __alignment2: u32,
}
-#[derive(Copy, Clone)]
#[repr(C, packed(4))]
-pub struct MINIDUMP_USER_STREAM_INFORMATION {
- pub UserStreamCount: u32,
- pub UserStreamArray: *mut MINIDUMP_USER_STREAM,
+pub struct MINIDUMP_CALLBACK_OUTPUT_0_0 {
+ pub MemoryBase: u64,
+ pub MemorySize: u32,
+}
+
+#[repr(C)]
+pub struct MINIDUMP_CALLBACK_OUTPUT_0_1 {
+ pub CheckCancel: BOOL,
+ pub Cancel: BOOL,
+}
+
+#[repr(C)]
+pub struct MINIDUMP_CALLBACK_OUTPUT_0_2 {
+ pub VmRegion: MINIDUMP_MEMORY_INFO,
+ pub Continue: BOOL,
}
+#[repr(C)]
+pub struct MINIDUMP_CALLBACK_OUTPUT_0_3 {
+ pub VmQueryStatus: Hresult,
+ pub VmQueryResult: MINIDUMP_MEMORY_INFO,
+}
+
+#[repr(C)]
+pub struct MINIDUMP_CALLBACK_OUTPUT_0_4 {
+ pub VmReadStatus: Hresult,
+ pub VmReadBytesCompleted: u32,
+}
+
+bitflags::bitflags! {
+ /// Identifies the type of module information that will be written to the
+ /// minidump file by the MiniDumpWriteDump function.
+ #[derive(Copy, Clone)]
+ #[repr(transparent)]
+ pub struct ModuleWriteFlags: u32 {
+ /// Only module information will be written to the minidump file.
+ const ModuleWriteModule = 0x0001;
+ const ModuleWriteDataSeg = 0x0002;
+ const ModuleWriteMiscRecord = 0x0004;
+ const ModuleWriteCvRecord = 0x0008;
+ const ModuleReferencedByMemory = 0x0010;
+ const ModuleWriteTlsData = 0x0020;
+ const ModuleWriteCodeSegs = 0x0040;
+ }
+}
+
+#[repr(C)]
+pub union MINIDUMP_CALLBACK_OUTPUT_0 {
+ pub ModuleWriteFlags: ModuleWriteFlags,
+ pub ThreadWriteFlags: u32,
+ pub SecondaryFlags: u32,
+ pub Anonymous1: std::mem::ManuallyDrop,
+ pub Anonymous2: std::mem::ManuallyDrop,
+ pub Handle: HANDLE,
+ pub Anonymous3: std::mem::ManuallyDrop,
+ pub Anonymous4: std::mem::ManuallyDrop,
+ pub Anonymous5: std::mem::ManuallyDrop,
+ pub Status: Hresult,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_CALLBACK_OUTPUT {
+ pub Anonymous: MINIDUMP_CALLBACK_OUTPUT_0,
+}
+
+pub type MINIDUMP_CALLBACK_ROUTINE = Option<
+ unsafe extern "system" fn(
+ CallbackParam: *mut std::ffi::c_void,
+ CallbackInput: *const MINIDUMP_CALLBACK_INPUT,
+ CallbackOutput: *mut MINIDUMP_CALLBACK_OUTPUT,
+ ) -> BOOL,
+>;
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_CALLBACK_INFORMATION {
+ pub CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE,
+ pub CallbackParam: *mut std::ffi::c_void,
+}
+
+#[link(name = "kernel32")]
+extern "system" {
+ pub fn CloseHandle(handle: HANDLE) -> BOOL;
+ pub fn GetCurrentProcess() -> HANDLE;
+ pub fn GetCurrentThreadId() -> u32;
+ pub fn OpenProcess(
+ desired_access: PROCESS_ACCESS_RIGHTS,
+ inherit_handle: BOOL,
+ process_id: u32,
+ ) -> HANDLE;
+ pub fn OpenThread(
+ desired_access: THREAD_ACCESS_RIGHTS,
+ inherit_handle: BOOL,
+ thread_id: u32,
+ ) -> HANDLE;
+ pub fn ResumeThread(thread: HANDLE) -> u32;
+ pub fn SuspendThread(thread: HANDLE) -> u32;
+ pub fn GetThreadContext(thread: HANDLE, context: *mut CONTEXT) -> BOOL;
+}
+
+#[link(name = "dbghelp")]
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,
+ process: HANDLE,
+ process_id: u32,
+ file: HANDLE,
+ dump_type: MinidumpType,
+ exception_param: *const MINIDUMP_EXCEPTION_INFORMATION,
+ user_stream_param: *const MINIDUMP_USER_STREAM_INFORMATION,
+ callback_param: *const MINIDUMP_CALLBACK_INFORMATION,
) -> BOOL;
}
+
+// #[minwin]
+// mod blah {}
diff --git a/src/windows/minidump_writer.rs b/src/windows/minidump_writer.rs
index e538907b..eeb8dd00 100644
--- a/src/windows/minidump_writer.rs
+++ b/src/windows/minidump_writer.rs
@@ -1,22 +1,17 @@
+#![allow(unsafe_code)]
+
use crate::windows::errors::Error;
use crate::windows::ffi::{
- capture_context, GetCurrentProcess, GetCurrentThreadId, GetThreadContext, MiniDumpNormal,
- MiniDumpWriteDump, OpenProcess, OpenThread, ResumeThread, SuspendThread, EXCEPTION_POINTERS,
- HANDLE, MINIDUMP_EXCEPTION_INFORMATION, MINIDUMP_USER_STREAM, MINIDUMP_USER_STREAM_INFORMATION,
+ capture_context, CloseHandle, GetCurrentProcess, GetCurrentThreadId, GetThreadContext,
+ MiniDumpWriteDump, MinidumpType, OpenProcess, OpenThread, ResumeThread, 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;
-use winapi::{
- shared::minwindef::FALSE,
- um::{
- handleapi::CloseHandle,
- winnt::{
- EXCEPTION_RECORD, PROCESS_ALL_ACCESS, STATUS_NONCONTINUABLE_EXCEPTION,
- THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,
- },
- },
-};
pub struct MinidumpWriter {
/// Optional exception information
@@ -29,7 +24,7 @@ pub struct MinidumpWriter {
tid: u32,
/// The exception code for the dump
#[allow(dead_code)]
- exception_code: u32,
+ exception_code: i32,
/// Whether we are dumping the current process or not
is_external_process: bool,
}
@@ -49,7 +44,7 @@ impl MinidumpWriter {
/// function can also fail if `thread_id` is specified and we are unable to
/// acquire the thread's context
pub fn dump_local_context(
- exception_code: Option,
+ exception_code: Option,
thread_id: Option,
destination: &mut std::fs::File,
) -> Result<(), Error> {
@@ -76,7 +71,7 @@ impl MinidumpWriter {
tid, // thread id
);
- if thread_handle.is_null() {
+ if thread_handle == 0 {
return Err(Error::ThreadOpen(std::io::Error::last_os_error()));
}
@@ -276,7 +271,7 @@ impl MinidumpWriter {
validity: BreakpadInfoValid::DumpThreadId.bits()
| BreakpadInfoValid::RequestingThreadId.bits(),
dump_thread_id: self.tid,
- // Safety: syscall
+ // SAFETY: syscall
requesting_thread_id: unsafe { GetCurrentThreadId() },
};
From b1bdeafd7b6f58786c5873e557d791873899cd15 Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Thu, 30 Mar 2023 09:07:47 +0200
Subject: [PATCH 2/6] Add ability to specify MinidumpType
---
src/windows/minidump_writer.rs | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/windows/minidump_writer.rs b/src/windows/minidump_writer.rs
index eeb8dd00..70cc420e 100644
--- a/src/windows/minidump_writer.rs
+++ b/src/windows/minidump_writer.rs
@@ -46,6 +46,7 @@ impl MinidumpWriter {
pub fn dump_local_context(
exception_code: Option,
thread_id: Option,
+ minidump_type: Option,
destination: &mut std::fs::File,
) -> Result<(), Error> {
let exception_code = exception_code.unwrap_or(STATUS_NONCONTINUABLE_EXCEPTION);
@@ -129,7 +130,7 @@ impl MinidumpWriter {
exception_code,
};
- Self::dump_crash_context(cc, destination)
+ Self::dump_crash_context(cc, minidump_type, destination)
}
}
@@ -149,6 +150,7 @@ impl MinidumpWriter {
/// for the duration of this function call.
pub fn dump_crash_context(
crash_context: crash_context::CrashContext,
+ minidump_type: Option,
destination: &mut std::fs::File,
) -> Result<(), Error> {
let pid = crash_context.process_id;
@@ -162,7 +164,7 @@ impl MinidumpWriter {
pid, // pid
);
- if proc.is_null() {
+ if proc == 0 {
return Err(std::io::Error::last_os_error().into());
}
@@ -203,11 +205,15 @@ impl MinidumpWriter {
is_external_process,
};
- mdw.dump(destination)
+ mdw.dump(minidump_type, destination)
}
/// Writes a minidump to the specified file
- fn dump(mut self, destination: &mut std::fs::File) -> Result<(), Error> {
+ fn dump(
+ mut self,
+ minidump_type: Option,
+ destination: &mut std::fs::File,
+ ) -> Result<(), Error> {
let exc_info = self.exc_info.take();
let mut user_streams = Vec::with_capacity(1);
@@ -236,7 +242,7 @@ impl MinidumpWriter {
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
- MiniDumpNormal, // MINIDUMP_TYPE - we _might_ want to make this configurable
+ minidump_type.unwrap_or(MinidumpType::Normal),
exc_info
.as_ref()
.map_or(std::ptr::null(), |ei| ei as *const _), // exceptionparam - the actual exception information
From 79a8c921c5d3f6c7e5ef0340c01e8738dec917c3 Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Mon, 3 Apr 2023 12:46:31 +0200
Subject: [PATCH 3/6] Update crash-context
---
Cargo.toml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index d34bdd1e..8729cc53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,7 @@ license = "MIT"
[dependencies]
byteorder = "1.3.2"
cfg-if = "1.0"
-crash-context = "0.5"
+crash-context = "0.6"
memoffset = "0.8"
minidump-common = "0.15"
scroll = "0.11"
@@ -51,6 +51,3 @@ dump_syms = { version = "2.0.0", default-features = false }
minidump-processor = { version = "0.15", default-features = false }
similar-asserts = "1.2"
uuid = "1.0"
-
-[patch.crates-io]
-crash-context = { path = "../crash-handling/crash-context" }
From 330cabf8e44b6da9f883663c00c91d5b769b68ae Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Mon, 3 Apr 2023 12:50:10 +0200
Subject: [PATCH 4/6] Oops
---
src/windows/ffi.rs | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs
index cc919f57..9c1a1984 100644
--- a/src/windows/ffi.rs
+++ b/src/windows/ffi.rs
@@ -239,18 +239,6 @@ pub struct MINIDUMP_VM_POST_READ_CALLBACK {
pub Status: Hresult,
}
-cfg_if::cfg_if! {
- if #[cfg(target_arch = "x86")] {
- #[repr(C)]
- struct CALLBACK_CONTEXT([u8; 716]);
- } else if #[cfg(target_arch = "x86_64")] {
-
- } else if #[cfg(target_arch = "aarch64")] {
- #[repr(C)]
- struct CALLBACK_CONTEXT([u8; 912]);
- }
-}
-
/// Oof, so we have a problem with these structs, they are all packed(4), but
/// `CONTEXT` is aligned by either 4 (x86) or 16 (x86_64/aarch64)...which Rust
/// doesn't currently allow https://github.com/rust-lang/rust/issues/59154, so
From 3cc83df6dab24dc59e1a44a730a371566689da1e Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Mon, 3 Apr 2023 12:56:06 +0200
Subject: [PATCH 5/6] Fix windows test
---
src/windows/ffi.rs | 3 ---
tests/windows_minidump_writer.rs | 7 ++++---
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/windows/ffi.rs b/src/windows/ffi.rs
index 9c1a1984..933228f8 100644
--- a/src/windows/ffi.rs
+++ b/src/windows/ffi.rs
@@ -447,6 +447,3 @@ extern "system" {
callback_param: *const MINIDUMP_CALLBACK_INFORMATION,
) -> BOOL;
}
-
-// #[minwin]
-// mod blah {}
diff --git a/tests/windows_minidump_writer.rs b/tests/windows_minidump_writer.rs
index 9a6efa65..aeccb942 100644
--- a/tests/windows_minidump_writer.rs
+++ b/tests/windows_minidump_writer.rs
@@ -8,10 +8,11 @@ use minidump_writer::minidump_writer::MinidumpWriter;
mod common;
use common::start_child_and_return;
-use winapi::um::{minwinbase::EXCEPTION_ILLEGAL_INSTRUCTION, winnt::STATUS_INVALID_PARAMETER};
-
+const EXCEPTION_ILLEGAL_INSTRUCTION: i32 = -1073741795;
+const STATUS_INVALID_PARAMETER: i32 = -1073741811;
+#[link(name = "kernel32")]
extern "system" {
- pub(crate) fn GetCurrentThreadId() -> u32;
+ fn GetCurrentThreadId() -> u32;
}
fn get_crash_reason<'a, T: std::ops::Deref + 'a>(
From e974ba96194ef4f59b7fa6a68b849c806750e764 Mon Sep 17 00:00:00 2001
From: Jake Shadle
Date: Mon, 3 Apr 2023 13:05:28 +0200
Subject: [PATCH 6/6] More fixup
---
tests/windows_minidump_writer.rs | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/tests/windows_minidump_writer.rs b/tests/windows_minidump_writer.rs
index aeccb942..1b2c1d4b 100644
--- a/tests/windows_minidump_writer.rs
+++ b/tests/windows_minidump_writer.rs
@@ -36,8 +36,13 @@ fn dump_current_process() {
.tempfile()
.unwrap();
- MinidumpWriter::dump_local_context(Some(STATUS_INVALID_PARAMETER), None, tmpfile.as_file_mut())
- .expect("failed to write minidump");
+ MinidumpWriter::dump_local_context(
+ Some(STATUS_INVALID_PARAMETER),
+ None,
+ None,
+ tmpfile.as_file_mut(),
+ )
+ .expect("failed to write minidump");
let md = Minidump::read_path(tmpfile.path()).expect("failed to read minidump");
@@ -84,6 +89,7 @@ fn dump_specific_thread() {
MinidumpWriter::dump_local_context(
Some(STATUS_INVALID_PARAMETER),
Some(crashing_thread_id),
+ None,
tmpfile.as_file_mut(),
)
.expect("failed to write minidump");
@@ -141,6 +147,7 @@ fn dump_external_process() {
(process_id, exception_pointers, thread_id, exception_code)
};
+ let exception_code = exception_code as i32;
assert_eq!(exception_code, EXCEPTION_ILLEGAL_INSTRUCTION);
let crash_context = crash_context::CrashContext {
@@ -157,7 +164,7 @@ fn dump_external_process() {
// SAFETY: We keep the process we are dumping alive until the minidump is written
// and the test process keep the pointers it sent us alive until it is killed
- MinidumpWriter::dump_crash_context(crash_context, tmpfile.as_file_mut())
+ MinidumpWriter::dump_crash_context(crash_context, None, tmpfile.as_file_mut())
.expect("failed to write minidump");
child.kill().expect("failed to kill child");