summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minidump-writer/src/windows/ffi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/minidump-writer/src/windows/ffi.rs')
-rw-r--r--third_party/rust/minidump-writer/src/windows/ffi.rs449
1 files changed, 449 insertions, 0 deletions
diff --git a/third_party/rust/minidump-writer/src/windows/ffi.rs b/third_party/rust/minidump-writer/src/windows/ffi.rs
new file mode 100644
index 0000000000..933228f8e6
--- /dev/null
+++ b/third_party/rust/minidump-writer/src/windows/ffi.rs
@@ -0,0 +1,449 @@
+//! Contains bindings for [`MiniDumpWriteDump`](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump)
+//! and related structures, as they are not present in `winapi` and we don't want
+//! to depend on `windows-sys` due to version churn.
+//!
+//! Also has a binding for [`GetThreadContext`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext)
+//! as the `CONTEXT` structures in `winapi` are not correctly aligned which can
+//! 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,
+ clippy::upper_case_acronyms
+)]
+
+pub use crash_context::{capture_context, CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD};
+
+pub type HANDLE = isize;
+pub type BOOL = i32;
+pub const FALSE: BOOL = 0;
+
+pub type Hresult = i32;
+pub const STATUS_NONCONTINUABLE_EXCEPTION: i32 = -1073741787;
+
+pub type PROCESS_ACCESS_RIGHTS = u32;
+pub const PROCESS_ALL_ACCESS: PROCESS_ACCESS_RIGHTS = 2097151;
+
+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! {
+ /// <https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_type>
+ #[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;
+ }
+}
+
+pub type VS_FIXEDFILEINFO_FILE_FLAGS = u32;
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_USER_STREAM {
+ pub Type: u32,
+ pub BufferSize: u32,
+ pub Buffer: *mut std::ffi::c_void,
+}
+#[repr(C, packed(4))]
+pub struct MINIDUMP_USER_STREAM_INFORMATION {
+ pub UserStreamCount: u32,
+ pub UserStreamArray: *mut MINIDUMP_USER_STREAM,
+}
+
+#[repr(C, packed(4))]
+pub struct MINIDUMP_EXCEPTION_INFORMATION {
+ pub ThreadId: u32,
+ pub ExceptionPointers: *mut EXCEPTION_POINTERS,
+ pub ClientPointers: BOOL,
+}
+
+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_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,
+}
+
+/// 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::<CONTEXT>()]);
+
+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<MINIDUMP_THREAD_CALLBACK>,
+ pub ThreadEx: std::mem::ManuallyDrop<MINIDUMP_THREAD_EX_CALLBACK>,
+ pub Module: std::mem::ManuallyDrop<MINIDUMP_MODULE_CALLBACK>,
+ pub IncludeThread: std::mem::ManuallyDrop<MINIDUMP_INCLUDE_THREAD_CALLBACK>,
+ pub IncludeModule: std::mem::ManuallyDrop<MINIDUMP_INCLUDE_MODULE_CALLBACK>,
+ pub Io: std::mem::ManuallyDrop<MINIDUMP_IO_CALLBACK>,
+ pub ReadMemoryFailure: std::mem::ManuallyDrop<MINIDUMP_READ_MEMORY_FAILURE_CALLBACK>,
+ pub SecondaryFlags: u32,
+ pub VmQuery: std::mem::ManuallyDrop<MINIDUMP_VM_QUERY_CALLBACK>,
+ pub VmPreRead: std::mem::ManuallyDrop<MINIDUMP_VM_PRE_READ_CALLBACK>,
+ pub VmPostRead: std::mem::ManuallyDrop<MINIDUMP_VM_POST_READ_CALLBACK>,
+}
+
+#[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,
+ __alignment2: u32,
+}
+
+#[repr(C, packed(4))]
+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<MINIDUMP_CALLBACK_OUTPUT_0_0>,
+ pub Anonymous2: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_1>,
+ pub Handle: HANDLE,
+ pub Anonymous3: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_2>,
+ pub Anonymous4: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_3>,
+ pub Anonymous5: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_4>,
+ 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 MiniDumpWriteDump(
+ 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;
+}