summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minidump-common/src/format.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/minidump-common/src/format.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/minidump-common/src/format.rs')
-rw-r--r--third_party/rust/minidump-common/src/format.rs2554
1 files changed, 2554 insertions, 0 deletions
diff --git a/third_party/rust/minidump-common/src/format.rs b/third_party/rust/minidump-common/src/format.rs
new file mode 100644
index 0000000000..2b610ef559
--- /dev/null
+++ b/third_party/rust/minidump-common/src/format.rs
@@ -0,0 +1,2554 @@
+//! Minidump structure definitions.
+//!
+//! Types defined here should match those defined in [Microsoft's headers][msdn]. Additionally
+//! some [Breakpad][breakpad] and [Crashpad][crashpad] extension types are defined here and should
+//! match the definitions from those projects.
+//!
+//! # Type Layouts
+//!
+//! This library isn't a "proper" minidump-sys library because it doesn't use repr attributes
+//! to force Rust to layout these structs identically to how they're laid out in memory.
+//!
+//! The reasons for this are 3-fold:
+//!
+//! 1. It isn't necessary because we specify how to serialize/deserialize things with `scroll`
+//! via `derive(Pread, Pwrite)` which uses the declared field order and not the in-memory
+//! layout, and assumes everything is packed anyway, which as a rule, minidump types are.
+//! Specifically they're packed to align 4, but Microsoft is mercifully very attentive to
+//! its type layouts so we're not aware of anywhere where packing to align 1 would change
+//! offsets. Packing is mostly just there so 32-bit and 64-bit definitely agree on offsets.
+//!
+//! 2. We would have to mark several types as `repr(packed(4))`, making them dangerous to use
+//! as several of the fields would become misaligned. This would create a bunch of
+//! unnecessary and brittle `unsafe`.
+//!
+//! 3. It's not *actually* that useful to have structs with precise in-memory layouts since
+//! a minidump parser needs to accept both little-endian and big-endian minidumps, and
+//! is therefore swizzling the bytes of all the values anyway. Also it's dangerous to
+//! reinterpret a pile of memory as arbitrary types without validation!
+//!
+//! [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/
+//! [breakpad]: https://chromium.googlesource.com/breakpad/breakpad/
+//! [crashpad]: https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
+use std::fmt;
+
+use bitflags::bitflags;
+use num_derive::FromPrimitive;
+use scroll::{Endian, Pread, Pwrite, SizeWith};
+use smart_default::SmartDefault;
+
+/// An offset from the start of the minidump file.
+pub type RVA = u32;
+pub type RVA64 = u64;
+
+/// The 4-byte magic number at the start of a minidump file.
+///
+/// In little endian this spells 'MDMP'.
+pub const MINIDUMP_SIGNATURE: u32 = 0x504d444d;
+
+/// The version of the minidump format.
+pub const MINIDUMP_VERSION: u32 = 42899;
+
+/// The header at the start of a minidump file.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_HEADER {
+ /// This should be [`MINIDUMP_SIGNATURE`][signature].
+ ///
+ /// [signature]: constant.MINIDUMP_SIGNATURE.html
+ pub signature: u32,
+ /// This should be [`MINIDUMP_VERSION`][version].
+ ///
+ /// [version]: constant.MINIDUMP_VERSION.html
+ pub version: u32,
+ /// The number of streams contained in the stream directory.
+ pub stream_count: u32,
+ /// The offset to the stream directory within the minidump. This usually points
+ /// to immediately after the header. The stream directory is an array containing
+ /// `stream_count` [`MINIDUMP_DIRECTORY`][dir] entries.
+ ///
+ /// [dir]: struct.MINIDUMP_DIRECTORY.html
+ pub stream_directory_rva: RVA,
+ pub checksum: u32,
+ pub time_date_stamp: u32,
+ pub flags: u64,
+}
+
+/// A location within a minidump file comprised of an offset and a size.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_location_descriptor
+#[derive(Debug, Copy, Default, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_LOCATION_DESCRIPTOR {
+ /// The size of this data.
+ pub data_size: u32,
+ /// The offset to this data within the minidump file.
+ pub rva: RVA,
+}
+
+impl From<u8> for MINIDUMP_LOCATION_DESCRIPTOR {
+ fn from(_val: u8) -> Self {
+ Self::default()
+ }
+}
+
+/// A range of memory contained within a minidump consisting of a base address and a
+/// location descriptor.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_descriptor
+#[derive(Debug, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MEMORY_DESCRIPTOR {
+ /// The base address of this memory range from the process.
+ pub start_of_memory_range: u64,
+ /// The offset and size of the actual bytes of memory contained in this dump.
+ pub memory: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+/// A large range of memory contained within a minidump (usually a full dump)
+/// consisting of a base address and a size.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_descriptor64
+#[derive(Debug, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MEMORY_DESCRIPTOR64 {
+ /// The base address of this memory range from the process.
+ pub start_of_memory_range: u64,
+ /// The size of this data.
+ pub data_size: u64,
+}
+
+/// Information about a data stream contained in a minidump file.
+///
+/// The minidump header contains a pointer to a list of these structs which allows locating
+/// specific streams in the dump.
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_directory
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_DIRECTORY {
+ /// This is usually one of the values in [`MINIDUMP_STREAM_TYPE`][ty] for known stream types,
+ /// but user streams can have arbitrary values.
+ ///
+ /// [ty]: enum.MINIDUMP_STREAM_TYPE.html
+ pub stream_type: u32,
+ /// The location of the stream contents within the dump.
+ pub location: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+/// The types of known minidump data streams.
+///
+/// Most of these values are derived from the [Microsoft enum][msdn] of the same name, but
+/// the values after `LastReservedStream` are Breakpad and Crashpad extensions.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_stream_type
+#[repr(u32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
+pub enum MINIDUMP_STREAM_TYPE {
+ /// An unused stream directory entry
+ UnusedStream = 0,
+ ReservedStream0 = 1,
+ ReservedStream1 = 2,
+ /// The list of threads from the process
+ ///
+ /// See [`MINIDUMP_THREAD`].
+ ///
+ /// Microsoft declares a [`MINIDUMP_THREAD_LIST`][list] struct which is the actual format
+ /// of this stream, but it is a variable-length struct so no matching definition is provided
+ /// in this crate.
+ ///
+ /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread_list
+ ThreadListStream = 3,
+ /// The list of executable modules from the process
+ ///
+ /// See [`MINIDUMP_MODULE`].
+ ///
+ /// Microsoft declares a [`MINIDUMP_MODULE_LIST`][list] struct which is the actual format
+ /// of this stream, but it is a variable-length struct so no matching definition is provided
+ /// in this crate.
+ ///
+ /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module_list
+ ModuleListStream = 4,
+ /// The list of memory regions from the process contained within this dump
+ ///
+ /// See [`MINIDUMP_MEMORY_DESCRIPTOR`].
+ ///
+ /// Microsoft declares a [`MINIDUMP_MEMORY_LIST`][list] struct which is the actual format
+ /// of this stream, but it is a variable-length struct so no matching definition is provided
+ /// in this crate.
+ ///
+ /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_list
+ MemoryListStream = 5,
+ /// Information about the exception that caused the process to exit
+ ///
+ /// See [`MINIDUMP_EXCEPTION_STREAM`].
+ ExceptionStream = 6,
+ /// System information
+ ///
+ /// See [`MINIDUMP_SYSTEM_INFO`].
+ SystemInfoStream = 7,
+ ThreadExListStream = 8,
+ /// The list of large memory regions from the process contained within this dump
+ ///
+ /// See [`MINIDUMP_MEMORY_DESCRIPTOR64`].
+ ///
+ /// Microsoft declares a [`MINIDUMP_MEMORY64_LIST`][list] struct which is the actual format
+ /// of this stream, but it is a variable-length struct so no matching definition is provided
+ /// in this crate.
+ ///
+ /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory64_list
+ Memory64ListStream = 9,
+ CommentStreamA = 10,
+ CommentStreamW = 11,
+ /// The list of handles used by the process
+ ///
+ /// See [`MINIDUMP_HANDLE_DATA_STREAM`]
+ HandleDataStream = 12,
+ FunctionTable = 13,
+ /// The list of executable modules from the process that were unloaded by the time of the crash
+ ///
+ /// See [`MINIDUMP_UNLOADED_MODULE`].
+ ///
+ /// Microsoft declares a [`MINIDUMP_UNLOADED_MODULE_LIST`][list] struct which is the actual
+ /// format of this stream, but it is a variable-length struct so no matching definition is
+ /// in this crate.
+ ///
+ /// Note that unlike other lists, this one has the newer "extended" header.
+ ///
+ /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_unloaded_module_list
+ UnloadedModuleListStream = 14,
+ /// Miscellaneous process and system information
+ ///
+ /// See ['MINIDUMP_MISC_INFO'].
+ MiscInfoStream = 15,
+ /// Information about memory regions from the process
+ ///
+ /// See ['MINIDUMP_MEMORY_INFO_LIST'].
+ MemoryInfoListStream = 16,
+ ThreadInfoListStream = 17,
+ HandleOperationListStream = 18,
+ TokenStream = 19,
+ JavaScriptDataStream = 20,
+ SystemMemoryInfoStream = 21,
+ ProcessVmCountersStream = 22,
+ IptTraceStream = 23,
+ /// Names of threads
+ ///
+ /// See ['MINIDUMP_THREAD_NAME'].
+ ThreadNamesStream = 24,
+ /* Windows CE types, the list is available here https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms939649(v=msdn.10) */
+ /// Start of the Windows CE enumerated list, unused.
+ ceStreamNull = 0x00008000,
+ /// System-wide information about the device and operating system where the fault occurred. Windows CE-specific.
+ ceStreamSystemInfo = 0x00008001,
+ /// Exception record and context for the exception that caused the dump file creation. Windows CE-specific.
+ ceStreamException = 0x00008002,
+ /// Modules that were active on the device at the time the dump file was created. Windows CE-specific.
+ ceStreamModuleList = 0x00008003,
+ /// Processes that were active on the device at the time the dump file was created. Windows CE-specific.
+ ceStreamProcessList = 0x00008004,
+ /// Threads that were active on the device at the time the dump file was created. Windows CE-specific.
+ ceStreamThreadList = 0x00008005,
+ /// List of thread context records. Windows CE-specific.
+ ceStreamThreadContextList = 0x00008006,
+ /// List of thread callstack records. Windows CE-specific.
+ ceStreamThreadCallStackList = 0x00008007,
+ /// List of virtual memory dumps. Windows CE-specific.
+ ceStreamMemoryVirtualList = 0x00008008,
+ /// List of physical memory dumps. Windows CE-specific.
+ ceStreamMemoryPhysicalList = 0x00008009,
+ /// Bucketing parameters for Watson server. Windows CE-specific.
+ ceStreamBucketParameters = 0x0000800a,
+ /// Undocumented Windows CE-specific stream.
+ ceStreamProcessModuleMap = 0x0000800b,
+ /// Undocumented Windows CE-specific stream.
+ ceStreamDiagnosisList = 0x0000800c,
+ /// Last stream reserved for use by Windows Operating Systems.
+ LastReservedStream = 0x0000ffff,
+ /* Breakpad extension types. 0x4767 = "Gg" */
+ /// Additional process information (Breakpad extension)
+ ///
+ /// See ['MINIDUMP_BREAKPAD_INFO'].
+ BreakpadInfoStream = 0x47670001,
+ /// Assertion information (Breakpad extension)
+ ///
+ /// See ['MINIDUMP_ASSERTION_INFO'].
+ AssertionInfoStream = 0x47670002,
+ /* These are additional minidump stream values which are specific to
+ * the linux breakpad implementation. */
+ /// The contents of /proc/cpuinfo from a Linux system
+ LinuxCpuInfo = 0x47670003,
+ /// The contents of /proc/self/status from a Linux system
+ LinuxProcStatus = 0x47670004,
+ /// The contents of /etc/lsb-release from a Linux system
+ LinuxLsbRelease = 0x47670005,
+ /// The contents of /proc/self/cmdline from a Linux system
+ LinuxCmdLine = 0x47670006,
+ /// The contents of /proc/self/environ from a Linux system
+ LinuxEnviron = 0x47670007,
+ /// The contents of /proc/self/auxv from a Linux system
+ LinuxAuxv = 0x47670008,
+ /// The contents of /proc/self/maps from a Linux system
+ LinuxMaps = 0x47670009,
+ /// Information from the Linux dynamic linker useful for writing core dumps
+ ///
+ /// See ['DSO_DEBUG_64'] and ['DSO_DEBUG_32'].
+ LinuxDsoDebug = 0x4767000A,
+ // Crashpad extension types. 0x4350 = "CP"
+ /// Crashpad-specific information containing annotations.
+ ///
+ /// See [`MINIDUMP_CRASHPAD_INFO`].
+ CrashpadInfoStream = 0x43500001,
+
+ /// Data from the __DATA,__crash_info section of every module which contains
+ /// one that has useful data. Only available on macOS. 0x4D7A = "Mz".
+ ///
+ /// See ['MINIDUMP_MAC_CRASH_INFO'].
+ MozMacosCrashInfoStream = 0x4d7a0001,
+
+ /// The kernel boot args on the machine where the crashed process is
+ /// running. Only available on macOS. 0x4D7A = "Mz".
+ ///
+ /// See ['MINIDUMP_MAC_BOOTARGS']
+ MozMacosBootargsStream = 0x4d7a0002,
+
+ /// The contents of /proc/self/limits from a Linux system
+ MozLinuxLimits = 0x4d7a0003,
+}
+
+impl From<MINIDUMP_STREAM_TYPE> for u32 {
+ fn from(ty: MINIDUMP_STREAM_TYPE) -> Self {
+ ty as u32
+ }
+}
+
+/// The name of a thread, found in the ThreadNamesStream.
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_THREAD_NAME {
+ /// The id of the thread.
+ pub thread_id: u32,
+ /// Where the name of the thread is stored (yes, the legendary RVA64 is real!!).
+ pub thread_name_rva: RVA64,
+}
+
+/// Information about a single module (executable or shared library) from a minidump
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MODULE {
+ /// The base address of the executable image in memory.
+ pub base_of_image: u64,
+ /// The size of the executable image in memory, in bytes.
+ pub size_of_image: u32,
+ /// The checksum value from the PE headers.
+ pub checksum: u32,
+ /// The timestamp value from the PE headers in `time_t` format.
+ pub time_date_stamp: u32,
+ /// An offset to a length-prefixed UTF-16LE string containing the name of the module.
+ pub module_name_rva: RVA,
+ /// Version information for this module.
+ pub version_info: VS_FIXEDFILEINFO,
+ /// The location of a CodeView record describing debug information for this module.
+ ///
+ /// This should be one of [`CV_INFO_PDB70`][pdb70], [`CV_INFO_PDB20`][pdb20], or
+ /// [`CV_INFO_ELF`][elf]. `PDB70` is the most common in practice, describing a standalone PDB
+ /// file by way of GUID, age, and PDB filename, and `ELF` is a Breakpad extension for
+ /// describing ELF modules with Build IDs.
+ ///
+ /// See [Matching Debug Information][dbg] for more information.
+ ///
+ /// [dbg]: http://web.archive.org/web/20210227224734/https://www.debuginfo.com/articles/debuginfomatch.html
+ /// [pdb70]: struct.CV_INFO_PDB70.html
+ /// [pdb20]: struct.CV_INFO_PDB20.html
+ /// [elf]: struct.CV_INFO_ELF.html
+ pub cv_record: MINIDUMP_LOCATION_DESCRIPTOR,
+ /// The location of an `IMAGE_DEBUG_MISC` record describing debug information for this module.
+ pub misc_record: MINIDUMP_LOCATION_DESCRIPTOR,
+ pub reserved0: [u32; 2],
+ pub reserved1: [u32; 2],
+}
+
+/// Information about a single unloaded module (executable or shared library) from a minidump.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_unloaded_module
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_UNLOADED_MODULE {
+ /// The base address of the executable image in memory (when it was loaded).
+ pub base_of_image: u64,
+ /// The size of the executable image in memory, in bytes.
+ pub size_of_image: u32,
+ /// The checksum value from the PE headers.
+ pub checksum: u32,
+ /// The timestamp value from the PE headers in `time_t` format.
+ pub time_date_stamp: u32,
+ /// An offset to a length-prefixed UTF-16LE string containing the name of the module.
+ pub module_name_rva: RVA,
+}
+
+/// Version information for a file
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct VS_FIXEDFILEINFO {
+ /// Contains the value of `VS_FFI_SIGNATURE`
+ pub signature: u32,
+ /// Should contain the value of `VS_FFI_STRUCVERSION`
+ pub struct_version: u32,
+ pub file_version_hi: u32,
+ pub file_version_lo: u32,
+ pub product_version_hi: u32,
+ pub product_version_lo: u32,
+ pub file_flags_mask: u32,
+ pub file_flags: u32,
+ pub file_os: u32,
+ pub file_type: u32,
+ pub file_subtype: u32,
+ pub file_date_hi: u32,
+ pub file_date_lo: u32,
+}
+
+/// The expected value of `VS_FIXEDFILEINFO.signature`
+pub const VS_FFI_SIGNATURE: u32 = 0xfeef04bd;
+
+/// The expected value of `VS_FIXEDFILEINFO.struct_version`
+pub const VS_FFI_STRUCVERSION: u32 = 0x00010000;
+
+/// Known values for the `signature` field of CodeView records
+///
+/// In addition to the two CodeView record formats used for linking
+/// to external pdb files it is possible for debugging data to be carried
+/// directly in the CodeView record itself. These signature values will
+/// be found in the first 4 bytes of the CodeView record. Additional values
+/// not commonly experienced in the wild are given by ["Microsoft Symbol and
+/// Type Information"][sym] section 7.2. An in-depth description of the CodeView 4.1 format
+/// is given by ["Undocumented Windows 2000 Secrets"][win2k], Windows 2000 Debugging Support/
+/// Microsoft Symbol File Internals/CodeView Subsections.
+///
+/// [sym]: http://web.archive.org/web/20070915060650/http://www.x86.org/ftp/manuals/tools/sym.pdf
+/// [win2k]: https://dl.acm.org/citation.cfm?id=375734
+#[repr(u32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
+pub enum CvSignature {
+ /// PDB 2.0 CodeView data: 'NB10': [`CV_INFO_PDB20`]
+ Pdb20 = 0x3031424e,
+ /// PDB 7.0 CodeView data: 'RSDS': [`CV_INFO_PDB70`]
+ Pdb70 = 0x53445352,
+ /// ELF Build ID, a Breakpad extension: 'BpEL': [`CV_INFO_ELF`]
+ Elf = 0x4270454c,
+ /// CodeView 4.10: 'NB09'
+ Cv41 = 0x3930424e,
+ /// CodeView 5.0: 'NB11'
+ Cv50 = 0x3131424e,
+}
+
+/// CodeView debug information in the older PDB 2.0 ("NB10") format.
+///
+/// This struct is defined as variable-length in C with a trailing PDB filename member.
+#[derive(Debug, Clone)]
+pub struct CV_INFO_PDB20 {
+ /// This field will always be [`CvSignature::Pdb20`].
+ pub cv_signature: u32,
+ pub cv_offset: u32,
+ pub signature: u32,
+ pub age: u32,
+ /// The PDB filename as a zero-terminated byte string
+ pub pdb_file_name: Vec<u8>,
+}
+
+impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for CV_INFO_PDB20 {
+ type Error = scroll::Error;
+
+ fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
+ let offset = &mut 0;
+ Ok((
+ CV_INFO_PDB20 {
+ cv_signature: src.gread_with(offset, endian)?,
+ cv_offset: src.gread_with(offset, endian)?,
+ signature: src.gread_with(offset, endian)?,
+ age: src.gread_with(offset, endian)?,
+ pdb_file_name: {
+ let size = src.len() - *offset;
+ src.gread_with::<&[u8]>(offset, size)?.to_owned()
+ },
+ },
+ *offset,
+ ))
+ }
+}
+
+/// CodeView debug information in the current PDB 7.0 ("RSDS") format.
+///
+/// This struct is defined as variable-length in C with a trailing PDB filename member.
+#[derive(Debug, Clone)]
+pub struct CV_INFO_PDB70 {
+ /// This will always be [`CvSignature::Pdb70`]
+ pub cv_signature: u32,
+ /// A unique identifer for a module created on first build.
+ pub signature: GUID,
+ /// A counter, incremented for each rebuild that updates the PDB file.
+ pub age: u32,
+ /// The PDB filename as a zero-terminated byte string
+ pub pdb_file_name: Vec<u8>,
+}
+
+impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for CV_INFO_PDB70 {
+ type Error = scroll::Error;
+
+ fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
+ let offset = &mut 0;
+ Ok((
+ CV_INFO_PDB70 {
+ cv_signature: src.gread_with(offset, endian)?,
+ signature: src.gread_with(offset, endian)?,
+ age: src.gread_with(offset, endian)?,
+ pdb_file_name: {
+ let size = src.len() - *offset;
+ src.gread_with::<&[u8]>(offset, size)?.to_owned()
+ },
+ },
+ *offset,
+ ))
+ }
+}
+
+/// A GUID as specified in Rpcdce.h
+///
+/// Matches the [Microsoft struct][msdn] of the same name.
+///
+/// # Display
+///
+/// There are two `Display` implementations for GUIDs. The regular formatting is lowercase with
+/// hyphens. The alternate formatting used with `#` is the symbol server format (uppercase without
+/// hyphens).
+///
+/// ```
+/// use minidump_common::format::GUID;
+///
+/// let guid = GUID { data1: 10, data2: 11, data3: 12, data4: [1,2,3,4,5,6,7,8] };
+///
+/// // default formatting
+/// assert_eq!("0000000a-000b-000c-0102-030405060708", guid.to_string());
+///
+/// // symbol server formatting
+/// assert_eq!("0000000A000B000C0102030405060708", format!("{:#}", guid));
+/// ```
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Pread, Pwrite, SizeWith)]
+pub struct GUID {
+ pub data1: u32,
+ pub data2: u16,
+ pub data3: u16,
+ pub data4: [u8; 8],
+}
+
+/// Creates a GUID from a raw byte array. It is assumed that the components in
+/// the array are in big-endian order.
+///
+/// ```
+/// use minidump_common::format::GUID;
+///
+/// let mut buf = [0u8; 16];
+/// buf[0..4].copy_from_slice(&0xdeadc0deu32.to_be_bytes());
+/// buf[4..6].copy_from_slice(&0xb105u16.to_be_bytes());
+/// buf[6..8].copy_from_slice(&0xc0deu16.to_be_bytes());
+/// buf[8..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]);
+///
+/// let guid: GUID = buf.into();
+///
+/// let expected = GUID { data1: 0xdeadc0de, data2: 0xb105, data3: 0xc0de, data4: [1, 2, 3, 4, 5, 6, 7, 8] };
+///
+/// assert_eq!(guid, expected);
+/// ```
+impl From<[u8; 16]> for GUID {
+ fn from(uuid: [u8; 16]) -> Self {
+ let data1 = (uuid[0] as u32) << 24
+ | (uuid[1] as u32) << 16
+ | (uuid[2] as u32) << 8
+ | uuid[3] as u32;
+ let data2 = (uuid[4] as u16) << 8 | uuid[5] as u16;
+ let data3 = (uuid[6] as u16) << 8 | uuid[7] as u16;
+ let mut data4 = [0u8; 8];
+ data4.copy_from_slice(&uuid[8..]);
+
+ Self {
+ data1,
+ data2,
+ data3,
+ data4,
+ }
+ }
+}
+
+impl fmt::Display for GUID {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // NB: This formatting is not endianness aware. GUIDs read from LE minidumps are printed
+ // with reversed fields.
+ if f.alternate() {
+ write!(
+ f,
+ "{:08X}{:04X}{:04X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
+ self.data1,
+ self.data2,
+ self.data3,
+ self.data4[0],
+ self.data4[1],
+ self.data4[2],
+ self.data4[3],
+ self.data4[4],
+ self.data4[5],
+ self.data4[6],
+ self.data4[7],
+ )
+ } else {
+ write!(
+ f,
+ "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
+ self.data1,
+ self.data2,
+ self.data3,
+ self.data4[0],
+ self.data4[1],
+ self.data4[2],
+ self.data4[3],
+ self.data4[4],
+ self.data4[5],
+ self.data4[6],
+ self.data4[7],
+ )
+ }
+ }
+}
+
+/// An ELF Build ID.
+///
+/// Modern ELF toolchains insert a "[build id][buildid]" into the ELF headers that typically
+/// contains a hash of some ELF headers and sections to uniquely identify a binary. The Build ID
+/// is allowed to be an arbitrary number of bytes however, and [GNU binutils allows creating
+/// ELF binaries with Build IDs of various formats][binutils].
+///
+/// [buildid]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/developer_guide/compiling-build-id
+/// [binutils]: https://sourceware.org/binutils/docs-2.26/ld/Options.html#index-g_t_002d_002dbuild_002did-292
+#[derive(Debug, Clone)]
+pub struct CV_INFO_ELF {
+ /// This will always be [`CvSignature::Elf`]
+ pub cv_signature: u32,
+ /// The build id, a variable number of bytes
+ pub build_id: Vec<u8>,
+}
+
+impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for CV_INFO_ELF {
+ type Error = scroll::Error;
+
+ fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
+ let offset = &mut 0;
+ Ok((
+ CV_INFO_ELF {
+ cv_signature: src.gread_with(offset, endian)?,
+ build_id: {
+ let size = src.len() - *offset;
+ src.gread_with::<&[u8]>(offset, size)?.to_owned()
+ },
+ },
+ *offset,
+ ))
+ }
+}
+
+/// Obsolete debug record type defined in WinNT.h.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct IMAGE_DEBUG_MISC {
+ pub data_type: u32,
+ pub length: u32,
+ pub unicode: u8,
+ pub reserved: [u8; 3],
+ pub data: [u8; 1],
+}
+
+/// Information about a single thread from a minidump
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_THREAD {
+ /// The identifier of this thread
+ pub thread_id: u32,
+ /// The suspend count for this thread
+ ///
+ /// If greater than zero, the thread is suspended.
+ pub suspend_count: u32,
+ /// The priority class of the thread
+ ///
+ /// See [Scheduling Priorities][msdn] on MSDN.
+ ///
+ /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/ProcThread/scheduling-priorities
+ pub priority_class: u32,
+ /// The priority level of the thread
+ pub priority: u32,
+ /// The thread environment block
+ pub teb: u64,
+ /// The location and base address of this thread's stack memory
+ pub stack: MINIDUMP_MEMORY_DESCRIPTOR,
+ /// The location of a CPU-specific `CONTEXT_` struct for this thread's CPU context
+ pub thread_context: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+/// Information about the exception that caused the process to terminate.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception_stream
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_EXCEPTION_STREAM {
+ /// The identifier of the thread that encountered the exception.
+ pub thread_id: u32,
+ pub __align: u32,
+ /// Detailed information about the exception encountered.
+ pub exception_record: MINIDUMP_EXCEPTION,
+ /// The offset of a CPU context record from the time the thread encountered the exception.
+ ///
+ /// The actual data will be one of the `CONTEXT_*` structs defined here.
+ pub thread_context: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+/// Detailed information about an exception.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_EXCEPTION {
+ /// The reason the exception occurred.
+ ///
+ /// Possible values are in the following enums:
+ ///
+ /// * [`ExceptionCodeWindows`](crate::errors::ExceptionCodeWindows)
+ /// * [`WinErrorWindows`](crate::errors::WinErrorWindows)
+ /// * [`NtStatusWindows`](crate::errors::NtStatusWindows)
+ /// * [`ExceptionCodeLinux`](crate::errors::ExceptionCodeLinux)
+ /// * [`ExceptionCodeMac`](crate::errors::ExceptionCodeMac)
+ pub exception_code: u32,
+ /// Flags related to the exception.
+ ///
+ /// On Windows this is 1 for noncontinuable exceptions and 0 otherwise. For Breakpad-produced
+ /// minidumps on macOS this field is used to store additional exception information.
+ pub exception_flags: u32,
+ /// The address of an associated [`MINIDUMP_EXCEPTION`] for a nested exception.
+ ///
+ /// This address is in the minidump producing host's memory.
+ pub exception_record: u64,
+ /// The address where the exception occurred.
+ ///
+ /// For Breakpad-produced minidumps on macOS this is the exception subcode, which is
+ /// typically the address.
+ pub exception_address: u64,
+ /// The number of valid elements in [`MINIDUMP_EXCEPTION::exception_information`].
+ pub number_parameters: u32,
+ pub __align: u32,
+ /// An array of additional arguments that describe the exception.
+ ///
+ /// For most exception codes the array elements are undefined, but for access violations
+ /// the array will contain two elements: a read/write flag in the first element and
+ /// the virtual address whose access caused the exception in the second element.
+ pub exception_information: [u64; 15], // EXCEPTION_MAXIMUM_PARAMETERS
+}
+
+/// Valid bits in a `context_flags` for [`ContextFlagsCpu`]
+pub const CONTEXT_CPU_MASK: u32 = 0xffffff00;
+/// x86 and x64 contexts have this bit set in their `context_flags` when they have
+/// extra XSTATE beyond the traditional context definition.
+pub const CONTEXT_HAS_XSTATE: u32 = 0x00000040;
+
+bitflags! {
+ /// CPU type values in the `context_flags` member of `CONTEXT_` structs
+ ///
+ /// This applies to the [`CONTEXT_ARM`], [`CONTEXT_PPC`], [`CONTEXT_MIPS`],
+ /// [`CONTEXT_AMD64`], [`CONTEXT_ARM64`], [`CONTEXT_PPC64`], [`CONTEXT_SPARC`] and
+ /// [`CONTEXT_ARM64_OLD`] structs.
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ContextFlagsCpu: u32 {
+ const CONTEXT_IA64 = 0x80000;
+ /// Super-H, includes SH3, from winnt.h in the Windows CE 5.0 SDK
+ const CONTEXT_SHX = 0xc0;
+ /// From winnt.h in the Windows CE 5.0 SDK, no longer used
+ ///
+ /// Originally used by Breakpad but changed after conflicts with other context
+ /// flag bits.
+ const CONTEXT_ARM_OLD = 0x40;
+ /// Alpha, from winnt.h in the Windows CE 5.0 SDK
+ const CONTEXT_ALPHA = 0x20000;
+ const CONTEXT_AMD64 = 0x100000;
+ const CONTEXT_ARM = 0x40000000;
+ const CONTEXT_ARM64 = 0x400000;
+ const CONTEXT_ARM64_OLD = 0x80000000;
+ const CONTEXT_MIPS = 0x40000;
+ const CONTEXT_MIPS64 = 0x80000;
+ const CONTEXT_PPC = 0x20000000;
+ const CONTEXT_PPC64 = 0x1000000;
+ const CONTEXT_SPARC = 0x10000000;
+ const CONTEXT_X86 = 0x10000;
+ }
+}
+
+impl ContextFlagsCpu {
+ /// Populate a [`ContextFlagsCpu`] with valid bits from `flags`
+ pub fn from_flags(flags: u32) -> ContextFlagsCpu {
+ ContextFlagsCpu::from_bits_truncate(flags & CONTEXT_CPU_MASK)
+ }
+}
+
+bitflags! {
+ /// Flags available for use in [`CONTEXT_AMD64.context_flags`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ContextFlagsAmd64: u32 {
+ /// SegSs, Rsp, SegCs, Rip, and EFlags
+ const CONTEXT_AMD64_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_AMD64.bits();
+ /// Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, and R8-R15
+ const CONTEXT_AMD64_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_AMD64.bits();
+ /// SegDs, SegEs, SegFs, and SegGs
+ const CONTEXT_AMD64_SEGMENTS = 0x00000004 | ContextFlagsCpu::CONTEXT_AMD64.bits();
+ /// Xmm0-Xmm15
+ const CONTEXT_AMD64_FLOATING_POINT = 0x00000008 | ContextFlagsCpu::CONTEXT_AMD64.bits();
+ /// Dr0-Dr3 and Dr6-Dr7
+ const CONTEXT_AMD64_DEBUG_REGISTERS = 0x00000010 | ContextFlagsCpu::CONTEXT_AMD64.bits();
+ const CONTEXT_AMD64_XSTATE = 0x00000020 | ContextFlagsCpu::CONTEXT_AMD64.bits();
+ const CONTEXT_AMD64_FULL = Self::CONTEXT_AMD64_CONTROL.bits() | Self::CONTEXT_AMD64_INTEGER.bits() | Self::CONTEXT_AMD64_FLOATING_POINT.bits();
+ const CONTEXT_AMD64_ALL = Self::CONTEXT_AMD64_FULL.bits() | Self::CONTEXT_AMD64_SEGMENTS.bits() | Self::CONTEXT_AMD64_DEBUG_REGISTERS.bits();
+ }
+}
+
+bitflags! {
+ /// Flags available for use in [`CONTEXT_X86.context_flags`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ContextFlagsX86: u32 {
+ /// Ebp, Eip, SegCs, EFlags, Esp, SegSs
+ const CONTEXT_X86_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_X86.bits();
+ /// Edi, Esi, Ebx, Edx, Ecx, Eax
+ const CONTEXT_X86_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_X86.bits();
+ /// SegDs, SegEs, SegFs, and SegGs
+ const CONTEXT_X86_SEGMENTS = 0x00000004 | ContextFlagsCpu::CONTEXT_X86.bits();
+ /// Fpcr, Fpsr, Fptag, Fpioff, Fpisel, Fpdoff, Fpdsel, Mxcsr, Mxcsr_mask, Xmm0-Xmm7
+ const CONTEXT_X86_FLOATING_POINT = 0x00000008 | ContextFlagsCpu::CONTEXT_X86.bits();
+ /// Dr0-Dr3 and Dr6-Dr7
+ const CONTEXT_X86_DEBUG_REGISTERS = 0x00000010 | ContextFlagsCpu::CONTEXT_X86.bits();
+ const CONTEXT_X86_EXTENDED_REGISTERS = 0x00000020 | ContextFlagsCpu::CONTEXT_X86.bits();
+ const CONTEXT_X86_XSTATE = 0x00000040 | ContextFlagsCpu::CONTEXT_X86.bits();
+ const CONTEXT_X86_FULL = Self::CONTEXT_X86_CONTROL.bits() | Self::CONTEXT_X86_INTEGER.bits() | Self::CONTEXT_X86_SEGMENTS.bits();
+ const CONTEXT_X86_ALL = Self::CONTEXT_X86_FULL.bits() | Self::CONTEXT_X86_FLOATING_POINT.bits() | Self::CONTEXT_X86_DEBUG_REGISTERS.bits() | Self::CONTEXT_X86_EXTENDED_REGISTERS.bits();
+ }
+}
+
+bitflags! {
+ /// Flags available for use in [`CONTEXT_ARM64.context_flags`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ContextFlagsArm64: u32 {
+ /// FP, LR, SP, PC, and CPSR
+ const CONTEXT_ARM64_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_ARM64.bits();
+ /// X0-X28 (but maybe not X18)
+ const CONTEXT_ARM64_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_ARM64.bits();
+ /// Fpcr, Fpsr, D0-D31 (AKA Q0-Q31, AKA S0-S31)
+ const CONTEXT_ARM64_FLOATING_POINT = 0x00000004 | ContextFlagsCpu::CONTEXT_ARM64.bits();
+ /// DBGBVR, DBGBCR, DBGWVR, DBGWCR
+ const CONTEXT_ARM64_DEBUG_REGISTERS = 0x0000008 | ContextFlagsCpu::CONTEXT_ARM64.bits();
+ /// Whether x18 has a valid value, because on Windows it contains the TEB.
+ ///
+ /// NOTE: at this precise moment breakpad doesn't define this, but Microsoft does!
+ const CONTEXT_ARM64_X18 = 0x0000010 | ContextFlagsCpu::CONTEXT_ARM64.bits();
+ const CONTEXT_ARM64_FULL = Self::CONTEXT_ARM64_CONTROL.bits() | Self::CONTEXT_ARM64_INTEGER.bits() | Self::CONTEXT_ARM64_FLOATING_POINT.bits();
+ const CONTEXT_ARM64_ALL = Self::CONTEXT_ARM64_FULL.bits() | Self::CONTEXT_ARM64_DEBUG_REGISTERS.bits() | Self::CONTEXT_ARM64_X18.bits();
+ }
+}
+
+bitflags! {
+ /// Flags available for use in [`CONTEXT_ARM64_OLD.context_flags`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ContextFlagsArm64Old: u32 {
+ // Yes, breakpad never defined CONTROL for this context
+
+ /// FP, LR, SP, PC, CPSR, and X0-X28
+ const CONTEXT_ARM64_OLD_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_ARM64_OLD.bits();
+ /// Fpcr, Fpsr, D0-D31 (AKA Q0-Q31, AKA S0-S31)
+ const CONTEXT_ARM64_OLD_FLOATING_POINT = 0x00000004 | ContextFlagsCpu::CONTEXT_ARM64_OLD.bits();
+ const CONTEXT_ARM64_OLD_FULL = Self::CONTEXT_ARM64_OLD_INTEGER.bits() | Self::CONTEXT_ARM64_OLD_FLOATING_POINT.bits();
+ const CONTEXT_ARM64_OLD_ALL = Self::CONTEXT_ARM64_OLD_FULL.bits();
+ }
+}
+
+bitflags! {
+ /// Flags available for use in [`CONTEXT_ARM.context_flags`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ContextFlagsArm: u32 {
+ // Yes, breakpad never defined CONTROL for this context
+
+ /// SP, LR, PC, and CPSR
+ const CONTEXT_ARM_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_ARM.bits();
+ /// R0-R12
+ const CONTEXT_ARM_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_ARM.bits();
+ /// Q0-Q15 / D0-D31 / S0-S31
+ const CONTEXT_ARM_FLOATING_POINT = 0x00000004 | ContextFlagsCpu::CONTEXT_ARM.bits();
+ /// DBGBVR, DBGBCR, DBGWVR, DBGWCR
+ const CONTEXT_ARM_DEBUG_REGISTERS = 0x00000008 | ContextFlagsCpu::CONTEXT_ARM.bits();
+ const CONTEXT_ARM_FULL = Self::CONTEXT_ARM_CONTROL.bits() | Self::CONTEXT_ARM_INTEGER.bits() | Self::CONTEXT_ARM_FLOATING_POINT.bits();
+ const CONTEXT_ARM_ALL = Self::CONTEXT_ARM_FULL.bits() | Self::CONTEXT_ARM_DEBUG_REGISTERS.bits();
+ }
+}
+
+/// Possible contents of [`CONTEXT_AMD64::float_save`].
+///
+/// This struct matches the definition of the struct with the same name from WinNT.h.
+#[derive(Debug, SmartDefault, Clone, Pread, Pwrite, SizeWith)]
+pub struct XMM_SAVE_AREA32 {
+ pub control_word: u16,
+ pub status_word: u16,
+ pub tag_word: u8,
+ pub reserved1: u8,
+ pub error_opcode: u16,
+ pub error_offset: u32,
+ pub error_selector: u16,
+ pub reserved2: u16,
+ pub data_offset: u32,
+ pub data_selector: u16,
+ pub reserved3: u16,
+ pub mx_csr: u32,
+ pub mx_csr_mask: u32,
+ #[default([0; 8])]
+ pub float_registers: [u128; 8],
+ #[default([0; 16])]
+ pub xmm_registers: [u128; 16],
+ #[default([0; 96])]
+ pub reserved4: [u8; 96],
+}
+
+/// Possible contents of [`CONTEXT_AMD64::float_save`].
+///
+/// This is defined as an anonymous struct inside an anonymous union in
+/// the x86-64 CONTEXT struct in WinNT.h.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct SSE_REGISTERS {
+ pub header: [u128; 2],
+ pub legacy: [u128; 8],
+ pub xmm0: u128,
+ pub xmm1: u128,
+ pub xmm2: u128,
+ pub xmm3: u128,
+ pub xmm4: u128,
+ pub xmm5: u128,
+ pub xmm6: u128,
+ pub xmm7: u128,
+ pub xmm8: u128,
+ pub xmm9: u128,
+ pub xmm10: u128,
+ pub xmm11: u128,
+ pub xmm12: u128,
+ pub xmm13: u128,
+ pub xmm14: u128,
+ pub xmm15: u128,
+}
+
+/// An x86-64 (amd64) CPU context
+///
+/// This struct matches the definition of `CONTEXT` in WinNT.h for x86-64.
+#[derive(Debug, SmartDefault, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_AMD64 {
+ pub p1_home: u64,
+ pub p2_home: u64,
+ pub p3_home: u64,
+ pub p4_home: u64,
+ pub p5_home: u64,
+ pub p6_home: u64,
+ pub context_flags: u32,
+ pub mx_csr: u32,
+ pub cs: u16,
+ pub ds: u16,
+ pub es: u16,
+ pub fs: u16,
+ pub gs: u16,
+ pub ss: 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,
+ /// Floating point state
+ ///
+ /// This is defined as a union in the C headers, but also
+ /// ` MAXIMUM_SUPPORTED_EXTENSION` is defined as 512 bytes.
+ ///
+ /// Callers that want to access the underlying data can use [`Pread`] to read either
+ /// an [`XMM_SAVE_AREA32`] or [`SSE_REGISTERS`] struct from this raw data as appropriate.
+ #[default([0; 512])]
+ pub float_save: [u8; 512],
+ #[default([0; 26])]
+ pub vector_register: [u128; 26],
+ pub vector_control: u64,
+ pub debug_control: u64,
+ pub last_branch_to_rip: u64,
+ pub last_branch_from_rip: u64,
+ pub last_exception_to_rip: u64,
+ pub last_exception_from_rip: u64,
+}
+
+/// ARM floating point state
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct FLOATING_SAVE_AREA_ARM {
+ pub fpscr: u64,
+ pub regs: [u64; 32],
+ pub extra: [u32; 8],
+}
+
+/// An ARM CPU context
+///
+/// This is a Breakpad extension, and does not match the definition of `CONTEXT` for ARM
+/// in WinNT.h.
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_ARM {
+ pub context_flags: u32,
+ // [r0, r1, ..., r15]
+ pub iregs: [u32; 16],
+ pub cpsr: u32,
+ pub float_save: FLOATING_SAVE_AREA_ARM,
+}
+
+/// Offsets into [`CONTEXT_ARM::iregs`] for registers with a dedicated or conventional purpose
+#[repr(usize)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum ArmRegisterNumbers {
+ IosFramePointer = 7,
+ FramePointer = 11,
+ StackPointer = 13,
+ LinkRegister = 14,
+ ProgramCounter = 15,
+}
+
+impl ArmRegisterNumbers {
+ pub const fn name(self) -> &'static str {
+ match self {
+ Self::IosFramePointer => "r7",
+ Self::FramePointer => "r11",
+ Self::StackPointer => "r13",
+ Self::LinkRegister => "r14",
+ Self::ProgramCounter => "r15",
+ }
+ }
+}
+
+/// An old (breakpad-style) aarch64 (arm64) CPU context.
+///
+/// This is a breakpad extension, but contrary to what the name might suggest,
+/// it isn't completely out of service. I believe all non-windows platforms
+/// still prefer emitting this format to avoid needless churn.
+///
+/// Semantically this type agrees with the "new" [CONTEXT_ARM64][] and can
+/// generally be handled with all the same logic. i.e. the general purpose
+/// `iregs` are the same. It's just that the other fields are shuffled around.
+///
+/// As I understand it, this is basically an artifact of breakpad getting to
+/// arm64 "first" (Android would be first in line for it!) and picking a
+/// definition they thought was reasonable. Thankfully they picked an
+/// "out of the way" context id so that when Microsoft came along and picked
+/// their own definition, there wouldn't be a conflict.
+///
+/// Note that we have inlined the fields of the "float save" struct from
+/// breakpad's definition to be more uniform with [CONTEXT_ARM64][].
+///
+/// NOTE: if you ever decide to try to make this repr(C) and get really clever,
+/// this type is actually non-trivially repr(packed(4)) in the headers!
+#[derive(Debug, Clone, Copy, Default, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_ARM64_OLD {
+ pub context_flags: u64,
+ /// `[x0, x1, ..., x28, fp, lr]`. See [Arm64RegisterNumbers][].
+ pub iregs: [u64; 31],
+ pub sp: u64,
+ pub pc: u64,
+ pub cpsr: u32,
+ /// FPU status register.
+ pub fpsr: u32,
+ /// FPU control register.
+ pub fpcr: u32,
+ /// float/NEON registers `[d0, d1, ..., d31]`
+ pub float_regs: [u128; 32usize],
+}
+
+/// A (microsoft-style) aarch64 (arm64) CPU context
+///
+/// This matches the layout of how Windows defines this type. Breakpad defines
+/// it in an equivalent but more-quirky way that relies more on packing.
+///
+/// For general purpose registers:
+///
+/// * microsoft: make iregs have 31 values and have sp and pc as explicit fields.
+/// * breakpad make iregs have 33 values, no explicit fields.
+///
+/// For float registers:
+///
+/// * microsoft: inline the fields for float_regs, fpcr, fpsr.
+/// * breakpad: wrap them in a struct.
+///
+/// -----------------
+///
+/// Why *we* went with these definitions:
+///
+/// * ARM64 actually defines x0..x30 register names, but sp and pc aren't
+/// "x31" and "x32". Breakpad is effectively punning them as such, and
+/// that's kinda weird?
+///
+/// * Microsft's inlining of the float registers eliminates any need for
+/// padding on all platforms (note how there's always an even number of
+/// u32's before a u64, and an even number of u64's before a u128!)
+///
+/// NOTE: if you ever decide to try to make this repr(C) and get really clever,
+/// note that microsoft aligns this to 16 (and as of this writing, rust does
+/// not consistently aling u128 as such).
+#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_ARM64 {
+ pub context_flags: u32,
+ pub cpsr: u32,
+ /// `[x0, x1, ..., x28, fp, lr]`. See [Arm64RegisterNumbers][].
+ pub iregs: [u64; 31],
+ pub sp: u64,
+ pub pc: u64,
+ /// float/NEON registers `[d0, d1, ..., d31]`
+ pub float_regs: [u128; 32usize],
+ /// FPU control register.
+ pub fpcr: u32,
+ /// FPU status register.
+ pub fpsr: u32,
+ pub bcr: [u32; 8],
+ pub bvr: [u64; 8],
+ pub wcr: [u32; 2],
+ pub wvr: [u64; 2],
+}
+
+/// Offsets into [`CONTEXT_ARM64::iregs`] for registers with a dedicated or conventional purpose
+#[repr(usize)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Arm64RegisterNumbers {
+ FramePointer = 29,
+ LinkRegister = 30,
+}
+
+impl Arm64RegisterNumbers {
+ pub const fn name(self) -> &'static str {
+ match self {
+ Self::FramePointer => "x29",
+ Self::LinkRegister => "x30",
+ }
+ }
+}
+
+/// MIPS floating point state
+#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct FLOATING_SAVE_AREA_MIPS {
+ pub regs: [u64; 32],
+ pub fpcsr: u32,
+ pub fir: u32,
+}
+
+/// A MIPS CPU context
+///
+/// This is a Breakpad extension, as there is no definition of `CONTEXT` for MIPS in WinNT.h.
+#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_MIPS {
+ pub context_flags: u32,
+ pub _pad0: u32,
+ pub iregs: [u64; 32],
+ pub mdhi: u64,
+ pub mdlo: u64,
+ pub hi: [u32; 3],
+ pub lo: [u32; 3],
+ pub dsp_control: u32,
+ pub _pad1: u32,
+ pub epc: u64,
+ pub badvaddr: u64,
+ pub status: u32,
+ pub cause: u32,
+ pub float_save: FLOATING_SAVE_AREA_MIPS,
+}
+
+/// Offsets into [`CONTEXT_MIPS::iregs`] for registers with a dedicated or conventional purpose
+#[repr(usize)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum MipsRegisterNumbers {
+ S0 = 16,
+ S1 = 17,
+ S2 = 18,
+ S3 = 19,
+ S4 = 20,
+ S5 = 21,
+ S6 = 22,
+ S7 = 23,
+ GlobalPointer = 28,
+ StackPointer = 29,
+ FramePointer = 30,
+ ReturnAddress = 31,
+}
+
+impl MipsRegisterNumbers {
+ pub const fn name(self) -> &'static str {
+ match self {
+ MipsRegisterNumbers::S0 => "s0",
+ MipsRegisterNumbers::S1 => "s1",
+ MipsRegisterNumbers::S2 => "s2",
+ MipsRegisterNumbers::S3 => "s3",
+ MipsRegisterNumbers::S4 => "s4",
+ MipsRegisterNumbers::S5 => "s5",
+ MipsRegisterNumbers::S6 => "s6",
+ MipsRegisterNumbers::S7 => "s7",
+ MipsRegisterNumbers::GlobalPointer => "gp",
+ MipsRegisterNumbers::StackPointer => "sp",
+ MipsRegisterNumbers::FramePointer => "fp",
+ MipsRegisterNumbers::ReturnAddress => "ra",
+ }
+ }
+}
+
+/// PPC floating point state
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct FLOATING_SAVE_AREA_PPC {
+ pub fpregs: [u64; 32],
+ pub fpscr_pad: u32,
+ pub fpscr: u32,
+}
+
+/// PPC vector state
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct VECTOR_SAVE_AREA_PPC {
+ pub save_vr: [u128; 32],
+ pub save_vscr: u128,
+ pub save_pad5: [u32; 4],
+ pub save_vrvalid: u32,
+ pub save_pad6: [u32; 7],
+}
+
+/// A PPC CPU context
+///
+/// This is a Breakpad extension, as there is no definition of `CONTEXT` for PPC in WinNT.h.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_PPC {
+ pub context_flags: u32,
+ pub srr0: u32,
+ pub srr1: u32,
+ pub gpr: [u32; 32],
+ pub cr: u32,
+ pub xer: u32,
+ pub lr: u32,
+ pub ctr: u32,
+ pub mq: u32,
+ pub vrsave: u32,
+ pub float_save: FLOATING_SAVE_AREA_PPC,
+ pub vector_save: VECTOR_SAVE_AREA_PPC,
+}
+
+/// Offsets into [`CONTEXT_PPC::gpr`] for registers with a dedicated or conventional purpose
+#[repr(usize)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum PpcRegisterNumbers {
+ StackPointer = 1,
+}
+
+/// A PPC64 CPU context
+///
+/// This is a Breakpad extension, as there is no definition of `CONTEXT` for PPC64 in WinNT.h.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_PPC64 {
+ pub context_flags: u64,
+ pub srr0: u64,
+ pub srr1: u64,
+ pub gpr: [u64; 32],
+ pub cr: u64,
+ pub xer: u64,
+ pub lr: u64,
+ pub ctr: u64,
+ pub vrsave: u64,
+ pub float_save: FLOATING_SAVE_AREA_PPC,
+ pub vector_save: VECTOR_SAVE_AREA_PPC,
+}
+
+/// Offsets into [`CONTEXT_PPC64::gpr`] for registers with a dedicated or conventional purpose
+#[repr(usize)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Ppc64RegisterNumbers {
+ StackPointer = 1,
+}
+
+/// SPARC floating point state
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct FLOATING_SAVE_AREA_SPARC {
+ pub regs: [u64; 32],
+ pub filler: u64,
+ pub fsr: u64,
+}
+
+/// A SPARC CPU context
+///
+/// This is a Breakpad extension, as there is no definition of `CONTEXT` for SPARC in WinNT.h.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_SPARC {
+ pub context_flags: u32,
+ pub flag_pad: u32,
+ pub g_r: [u64; 32],
+ pub ccr: u64,
+ pub pc: u64,
+ pub npc: u64,
+ pub y: u64,
+ pub asi: u64,
+ pub fprs: u64,
+ pub float_save: FLOATING_SAVE_AREA_SPARC,
+}
+
+/// Offsets into [`CONTEXT_SPARC::g_r`] for registers with a dedicated or conventional purpose
+#[repr(usize)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum SparcRegisterNumbers {
+ StackPointer = 14,
+}
+
+/// x86 floating point state
+///
+/// This struct matches the definition of the `FLOATING_SAVE_AREA` struct from WinNT.h.
+#[derive(Debug, Clone, SmartDefault, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct FLOATING_SAVE_AREA_X86 {
+ pub control_word: u32,
+ pub status_word: u32,
+ pub tag_word: u32,
+ pub error_offset: u32,
+ pub error_selector: u32,
+ pub data_offset: u32,
+ pub data_selector: u32,
+ #[default([0; 80])]
+ pub register_area: [u8; 80], // SIZE_OF_80387_REGISTERS
+ pub cr0_npx_state: u32,
+}
+
+/// An x86 CPU context
+///
+/// This struct matches the definition of `CONTEXT` in WinNT.h for x86.
+#[derive(Debug, Clone, SmartDefault, Pread, Pwrite, SizeWith)]
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+pub struct CONTEXT_X86 {
+ pub context_flags: u32,
+ pub dr0: u32,
+ pub dr1: u32,
+ pub dr2: u32,
+ pub dr3: u32,
+ pub dr6: u32,
+ pub dr7: u32,
+ pub float_save: FLOATING_SAVE_AREA_X86,
+ pub gs: u32,
+ pub fs: u32,
+ pub es: u32,
+ pub ds: 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 cs: u32,
+ pub eflags: u32,
+ pub esp: u32,
+ pub ss: u32,
+ #[default([0; 512])]
+ pub extended_registers: [u8; 512], // MAXIMUM_SUPPORTED_EXTENSION
+}
+
+/// CPU information contained within the [`MINIDUMP_SYSTEM_INFO`] struct
+///
+/// This struct matches the definition of the `CPU_INFORMATION` union from minidumpapiset.h.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct CPU_INFORMATION {
+ /// `data` is defined as a union in the Microsoft headers
+ ///
+ /// It is the union of [`X86CpuInfo`], [`ARMCpuInfo`] (Breakpad-specific), and
+ /// [`OtherCpuInfo`] defined below. It does not seem possible to safely derive [`Pread`]
+ /// on an actual union, so we provide the raw data here and expect callers to use
+ /// [`Pread`] to derive the specific union representation desired.
+ pub data: [u8; 24],
+}
+
+/// x86-specific CPU information derived from the `cpuid` instruction
+///
+/// This struct matches the definition of the struct of the same name from minidumpapiset.h,
+/// which is contained within the [`CPU_INFORMATION`] union.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct X86CpuInfo {
+ pub vendor_id: [u32; 3],
+ pub version_information: u32,
+ pub feature_information: u32,
+ pub amd_extended_cpu_features: u32,
+}
+
+/// Arm-specific CPU information (Breakpad extension)
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct ARMCpuInfo {
+ pub cpuid: u32,
+ /// Hardware capabilities
+ ///
+ /// See [`ArmElfHwCaps`] for possible values.
+ pub elf_hwcaps: u32,
+}
+
+/// CPU information for non-x86 CPUs
+///
+/// This struct matches the definition of the struct of the same name from minidumpapiset.h,
+/// which is contained within the [`CPU_INFORMATION`] union.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct OtherCpuInfo {
+ pub processor_features: [u64; 2],
+}
+
+/// Processor and operating system information
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_system_info
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_SYSTEM_INFO {
+ /// The system's processor architecture
+ ///
+ /// Known values are defined in [`ProcessorArchitecture`].
+ pub processor_architecture: u16,
+ /// x86 (5 = 586, 6 = 686 ...) or ARM (6 = ARMv6, 7 = ARMv7 ...) CPU level
+ pub processor_level: u16,
+ /// For x86, 0xMMSS where MM=model, SS=stepping
+ pub processor_revision: u16,
+ pub number_of_processors: u8,
+ pub product_type: u8,
+ pub major_version: u32,
+ pub minor_version: u32,
+ pub build_number: u32,
+ /// The operating system platform
+ ///
+ /// Known values are defined in [`PlatformId`].
+ pub platform_id: u32,
+ pub csd_version_rva: RVA,
+ pub suite_mask: u16,
+ pub reserved2: u16,
+ pub cpu: CPU_INFORMATION,
+}
+
+/// Known values of [`MINIDUMP_SYSTEM_INFO::processor_architecture`]
+///
+/// Many of these are taken from definitions in WinNT.h, but several of them are
+/// Breakpad extensions.
+#[repr(u16)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
+pub enum ProcessorArchitecture {
+ PROCESSOR_ARCHITECTURE_INTEL = 0,
+ PROCESSOR_ARCHITECTURE_MIPS = 1,
+ PROCESSOR_ARCHITECTURE_ALPHA = 2,
+ PROCESSOR_ARCHITECTURE_PPC = 3,
+ PROCESSOR_ARCHITECTURE_SHX = 4,
+ PROCESSOR_ARCHITECTURE_ARM = 5,
+ PROCESSOR_ARCHITECTURE_IA64 = 6,
+ PROCESSOR_ARCHITECTURE_ALPHA64 = 7,
+ /// Microsoft Intermediate Language
+ PROCESSOR_ARCHITECTURE_MSIL = 8,
+ PROCESSOR_ARCHITECTURE_AMD64 = 9,
+ /// WoW64
+ PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10,
+ PROCESSOR_ARCHITECTURE_ARM64 = 12,
+ /// Breakpad-defined value for SPARC
+ PROCESSOR_ARCHITECTURE_SPARC = 0x8001,
+ /// Breakpad-defined value for PPC64
+ PROCESSOR_ARCHITECTURE_PPC64 = 0x8002,
+ /// Breakpad-defined value for ARM64
+ PROCESSOR_ARCHITECTURE_ARM64_OLD = 0x8003,
+ /// Breakpad-defined value for MIPS64
+ PROCESSOR_ARCHITECTURE_MIPS64 = 0x8004,
+ PROCESSOR_ARCHITECTURE_UNKNOWN = 0xffff,
+}
+
+/// Known values of [`MINIDUMP_SYSTEM_INFO::platform_id`]
+///
+/// The Windows values here are taken from defines in WinNT.h, but the rest are Breakpad
+/// extensions.
+#[repr(u32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
+pub enum PlatformId {
+ /// Windows 3.1
+ VER_PLATFORM_WIN32s = 1,
+ /// Windows 95-98-Me
+ VER_PLATFORM_WIN32_WINDOWS = 2,
+ /// Windows NT, 2000+
+ VER_PLATFORM_WIN32_NT = 3,
+ /// Windows CE, Windows Mobile
+ VER_PLATFORM_WIN32_CE = 4,
+ /// Generic Unix-ish (Breakpad extension)
+ Unix = 0x8000,
+ /// macOS/Darwin (Breakpad extension)
+ MacOs = 0x8101,
+ /// iOS (Breakpad extension)
+ Ios = 0x8102,
+ /// Linux (Breakpad extension)
+ Linux = 0x8201,
+ /// Solaris (Breakpad extension)
+ Solaris = 0x8202,
+ /// Android (Breakpad extension)
+ Android = 0x8203,
+ /// PlayStation 3 (Breakpad extension)
+ Ps3 = 0x8204,
+ /// Native Client (Breakpad extension)
+ NaCl = 0x8205,
+}
+
+/// A date and time
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith, PartialEq, Eq)]
+pub struct SYSTEMTIME {
+ pub year: u16,
+ pub month: u16,
+ pub day_of_week: u16,
+ pub day: u16,
+ pub hour: u16,
+ pub minute: u16,
+ pub second: u16,
+ pub milliseconds: u16,
+}
+
+/// Settings for a time zone
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information
+#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct TIME_ZONE_INFORMATION {
+ pub bias: i32,
+ pub standard_name: [u16; 32],
+ pub standard_date: SYSTEMTIME,
+ pub standard_bias: i32,
+ pub daylight_name: [u16; 32],
+ pub daylight_date: SYSTEMTIME,
+ pub daylight_bias: i32,
+}
+
+/*
+ * There are multiple versions of the misc info struct, and each new version includes all
+ * fields from the previous versions. We declare them with a macro to avoid repeating
+ * the fields excessively.
+ */
+macro_rules! multi_structs {
+ // With no trailing struct left, terminate.
+ (@next { $($prev:tt)* }) => {};
+ // Declare the next struct, including fields from previous structs.
+ (@next { $($prev:tt)* } $(#[$attr:meta])* pub struct $name:ident { $($cur:tt)* } $($tail:tt)* ) => {
+ // Prepend fields from previous structs to this struct.
+ multi_structs!($(#[$attr])* pub struct $name { $($prev)* $($cur)* } $($tail)*);
+ };
+ // Declare a single struct.
+ ($(#[$attr:meta])* pub struct $name:ident { $( pub $field:ident: $t:tt, )* } $($tail:tt)* ) => {
+ $(#[$attr])*
+ #[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+ pub struct $name {
+ $( pub $field: $t, )*
+ }
+ // Persist its fields down to the following structs.
+ multi_structs!(@next { $( pub $field: $t, )* } $($tail)*);
+ };
+}
+
+multi_structs! {
+ /// Miscellaneous process information
+ ///
+ /// This struct matches the [Microsoft struct][msdn] of the same name.
+ ///
+ /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_misc_info
+ pub struct MINIDUMP_MISC_INFO {
+ pub size_of_info: u32,
+ pub flags1: u32,
+ pub process_id: u32,
+ pub process_create_time: u32,
+ pub process_user_time: u32,
+ pub process_kernel_time: u32,
+ }
+ // Includes fields from MINIDUMP_MISC_INFO
+ /// Miscellaneous process and system information
+ ///
+ /// This struct matches the [Microsoft struct][msdn] of the same name.
+ ///
+ /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_misc_info_2
+ pub struct MINIDUMP_MISC_INFO_2 {
+ pub processor_max_mhz: u32,
+ pub processor_current_mhz: u32,
+ pub processor_mhz_limit: u32,
+ pub processor_max_idle_state: u32,
+ pub processor_current_idle_state: u32,
+ }
+ // Includes fields from MINIDUMP_MISC_INFO and MINIDUMP_MISC_INFO_2
+ /// Miscellaneous process and system information
+ ///
+ /// This struct matches the struct of the same name from minidumpapiset.h.
+ pub struct MINIDUMP_MISC_INFO_3 {
+ pub process_integrity_level: u32,
+ pub process_execute_flags: u32,
+ pub protected_process: u32,
+ pub time_zone_id: u32,
+ pub time_zone: TIME_ZONE_INFORMATION,
+ }
+ // Includes fields from MINIDUMP_MISC_INFO..3
+ /// Miscellaneous process and system information
+ ///
+ /// This struct matches the struct of the same name from minidumpapiset.h.
+ pub struct MINIDUMP_MISC_INFO_4 {
+ pub build_string: [u16; 260], // MAX_PATH
+ pub dbg_bld_str: [u16; 40],
+ }
+
+ // Includes fields from MINIDUMP_MISC_INFO..4
+ /// Miscellaneous process and system information
+ ///
+ /// This struct matches the struct of the same name from minidumpapiset.h.
+ pub struct MINIDUMP_MISC_INFO_5 {
+ pub xstate_data: XSTATE_CONFIG_FEATURE_MSC_INFO,
+ pub process_cookie: u32,
+ }
+}
+
+/// A descriptor of the XSAVE context, which extends a normal x86/x64 context.
+///
+/// The sections of this context are dumps of some of the CPUs registers
+/// (e.g. one section might contain the contents of the SSE registers).
+///
+/// Intel documents its XSAVE entries in Volume 1, Chapter 13 of the
+/// "Intel 64 and IA-32 Architectures Software Developer’s Manual".
+///
+///
+/// # The XSTATE Format in Minidumps
+///
+/// This format is slightly messed up in the context of minidumps because it's
+/// grafted onto Microsoft's own formats. Here's what's important to know:
+///
+/// * The "Cpu Context" and the "XSAVE context" are in fact the same regions
+/// of memory.
+///
+/// * Whether XSTATE is present or not, the classic layouts of CONTEXT_X86
+/// and [`CONTEXT_AMD64`] both apply -- xstate will only add stuff after *or*
+/// refine your understanding of memory in the existing layout. So you can
+/// safely ignore the existence of XSTATE, but you might be missing new info.
+///
+/// * AMD64 doesn't have a standard way to save general purpose registers,
+/// so the first 256 bytes of [`CONTEXT_AMD64`] are just however microsoft
+/// decided to save the registers, and will not be referred to by the XSTATE.
+///
+/// **!!! THIS PART IS IMPORTANT !!!**
+///
+/// * As a consequence, all [`XSTATE_FEATURE::offset`] values must have 256
+/// added to them to get the correct offset for that feature! For example, the
+/// LEGACY_FLOATING_POINT feature should always have an offset of 0, but it
+/// is actually at offset 256 in [`CONTEXT_AMD64`] (it corresponds to
+/// [`CONTEXT_AMD64::float_save`]).
+///
+/// * The following features are already contained inside of [`CONTEXT_AMD64`]:
+/// * LEGACY_FLOATING_POINT
+/// * LEGACY_SSE
+/// * GSSE_AND_AVX
+///
+/// * If there are XSTATE entries that *actually* map outside of the context's
+/// normal memory range, then the context's [`context_flags`](`CONTEXT_AMD64::context_flags`)
+/// will have bit 0x40 set ([`CONTEXT_HAS_XSTATE`]).
+///
+/// * [`ContextFlagsCpu::from_flags`] will mask out the [`CONTEXT_HAS_XSTATE`] bit.
+/// If you want to check for that bit, check the raw value of
+/// [`context_flags`](`CONTEXT_AMD64::context_flags`).
+
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct XSTATE_CONFIG_FEATURE_MSC_INFO {
+ /// The size of this struct.
+ pub size_of_info: u32,
+ /// The size of the XSAVE context.
+ pub context_size: u32,
+ /// The bit `enabled_features[i]` indicates that `features[i]` contains valid data.
+ pub enabled_features: u64,
+ /// The offset and size of each XSAVE entry inside the XSAVE context.
+ pub features: [XSTATE_FEATURE; 64],
+}
+
+impl Default for XSTATE_CONFIG_FEATURE_MSC_INFO {
+ fn default() -> Self {
+ Self {
+ size_of_info: std::mem::size_of::<XSTATE_CONFIG_FEATURE_MSC_INFO>() as u32,
+ context_size: 0,
+ enabled_features: 0,
+ features: [XSTATE_FEATURE::default(); 64],
+ }
+ }
+}
+
+impl XSTATE_CONFIG_FEATURE_MSC_INFO {
+ /// Gets an iterator of all the enabled features.
+ pub fn iter(&self) -> XstateFeatureIter {
+ XstateFeatureIter { info: self, idx: 0 }
+ }
+}
+
+/// An iterator of all the enabled features in an XSTATE_CONFIG_FEATURE_MSC_INFO.
+#[derive(Debug)]
+pub struct XstateFeatureIter<'a> {
+ info: &'a XSTATE_CONFIG_FEATURE_MSC_INFO,
+ idx: usize,
+}
+
+impl<'a> Iterator for XstateFeatureIter<'a> {
+ type Item = (usize, XSTATE_FEATURE);
+ fn next(&mut self) -> Option<Self::Item> {
+ while self.idx < self.info.features.len() {
+ let cur_idx = self.idx;
+ self.idx += 1;
+ if (self.info.enabled_features & (1 << cur_idx)) != 0 {
+ return Some((cur_idx, self.info.features[cur_idx]));
+ }
+ }
+ None
+ }
+}
+
+/// Several known entries in `XSTATE_CONFIG_FEATURE_MSC_INFO.features`.
+#[repr(usize)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum XstateFeatureIndex {
+ LEGACY_FLOATING_POINT = 0,
+ LEGACY_SSE = 1,
+ GSSE_AND_AVX = 2,
+ MPX_BNDREGS = 3,
+ MPX_BNDCSR = 4,
+ AVX512_KMASK = 5,
+ AVX512_ZMM_H = 6,
+ ACK512_ZMM = 7,
+ XSTATE_IPT = 8,
+ XSTATE_LWP = 62,
+}
+
+impl XstateFeatureIndex {
+ pub fn from_index(idx: usize) -> Option<Self> {
+ use XstateFeatureIndex::*;
+ match idx {
+ 0 => Some(LEGACY_FLOATING_POINT),
+ 1 => Some(LEGACY_SSE),
+ 2 => Some(GSSE_AND_AVX),
+ 3 => Some(MPX_BNDREGS),
+ 4 => Some(MPX_BNDCSR),
+ 5 => Some(AVX512_KMASK),
+ 6 => Some(AVX512_ZMM_H),
+ 7 => Some(ACK512_ZMM),
+ 8 => Some(XSTATE_IPT),
+ 62 => Some(XSTATE_LWP),
+ _ => None,
+ }
+ }
+}
+
+/// The offset and size of each XSAVE entry inside the XSAVE context.
+#[derive(Clone, Copy, Debug, Default, Pread, Pwrite, SizeWith, PartialEq, Eq)]
+pub struct XSTATE_FEATURE {
+ /// This entry's offset from the start of the context (in bytes).
+ ///
+ /// NOTE: THIS VALUE IS A LIE. At least on AMD64 you need to add 256
+ /// to this! See the docs of [`XSTATE_CONFIG_FEATURE_MSC_INFO`].
+ pub offset: u32,
+ /// This entry's size (in bytes).
+ pub size: u32,
+}
+
+// For whatever reason Pread array derives use 0u8.into() instead of Default to
+// create an initial array to write into. Weird.
+impl From<u8> for XSTATE_FEATURE {
+ fn from(_input: u8) -> Self {
+ XSTATE_FEATURE { offset: 0, size: 0 }
+ }
+}
+
+bitflags! {
+ /// Known flags for `MINIDUMP_MISC_INFO*.flags1`
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct MiscInfoFlags: u32 {
+ const MINIDUMP_MISC1_PROCESS_ID = 0x00000001;
+ const MINIDUMP_MISC1_PROCESS_TIMES = 0x00000002;
+ const MINIDUMP_MISC1_PROCESSOR_POWER_INFO = 0x00000004;
+ const MINIDUMP_MISC3_PROCESS_INTEGRITY = 0x00000010;
+ const MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS = 0x00000020;
+ const MINIDUMP_MISC3_TIMEZONE = 0x00000040;
+ const MINIDUMP_MISC3_PROTECTED_PROCESS = 0x00000080;
+ const MINIDUMP_MISC4_BUILDSTRING = 0x00000100;
+ const MINIDUMP_MISC5_PROCESS_COOKIE = 0x00000200;
+ }
+}
+
+/// A list of memory regions in a minidump
+///
+/// This is the format of the [`MINIDUMP_STREAM_TYPE::MemoryInfoListStream`]. The individual
+/// [`MINIDUMP_MEMORY_INFO`] entries follow this header in the stream.
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info_list
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MEMORY_INFO_LIST {
+ /// The size of this header
+ pub size_of_header: u32,
+ /// The size of each entry in the list
+ pub size_of_entry: u32,
+ /// The number of entries in the list
+ pub number_of_entries: u64,
+}
+
+/// Information about a memory region in a minidump
+///
+/// This struct matches the [Microsoft struct][msdn] of the same name.
+///
+/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info
+#[derive(Debug, Clone, PartialEq, Eq, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MEMORY_INFO {
+ /// The base address of the region of pages
+ pub base_address: u64,
+ /// The base address of a range of pages in this region
+ pub allocation_base: u64,
+ /// The memory protection when the region was initially allocated
+ ///
+ /// See [`MemoryProtection`] for valid values.
+ pub allocation_protection: u32,
+ pub __alignment1: u32,
+ /// The size of the region in which all pages have identical attributes, in bytes
+ pub region_size: u64,
+ /// The state of the pages in the region
+ ///
+ /// See [`MemoryState`] for valid values.
+ pub state: u32,
+ /// The access protection of the pages in the region
+ ///
+ /// See [`MemoryProtection`] for valid values.
+ pub protection: u32,
+ /// The type of pages in the region
+ ///
+ /// See [`MemoryType`] for valid values.
+ pub _type: u32,
+ pub __alignment2: u32,
+}
+
+bitflags! {
+ /// Potential values for [`MINIDUMP_MEMORY_INFO::state`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct MemoryState: u32 {
+ const MEM_COMMIT = 0x01000;
+ const MEM_FREE = 0x10000;
+ const MEM_RESERVE = 0x02000;
+ }
+}
+
+bitflags! {
+ /// Potential values for [`MINIDUMP_MEMORY_INFO::protection`] and `allocation_protection`
+ ///
+ /// See [Microsoft's documentation][msdn] for details.
+ ///
+ /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct MemoryProtection: u32 {
+ const PAGE_NOACCESS = 0x01;
+ const PAGE_READONLY = 0x02;
+ const PAGE_READWRITE = 0x04;
+ const PAGE_WRITECOPY = 0x08;
+ const PAGE_EXECUTE = 0x10;
+ const PAGE_EXECUTE_READ = 0x20;
+ const PAGE_EXECUTE_READWRITE = 0x40;
+ const PAGE_EXECUTE_WRITECOPY = 0x80;
+ const ACCESS_MASK = 0xff;
+ const PAGE_GUARD = 0x100;
+ const PAGE_NOCACHE = 0x200;
+ const PAGE_WRITECOMBINE = 0x400;
+ }
+}
+
+bitflags! {
+ /// Potential values for [`MINIDUMP_MEMORY_INFO::_type`]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct MemoryType: u32 {
+ const MEM_PRIVATE = 0x00020000;
+ const MEM_MAPPED = 0x00040000;
+ const MEM_IMAGE = 0x01000000;
+ }
+}
+
+/// A Breakpad extension containing some additional process information
+///
+/// Taken from the definition in Breakpad's [minidump_format.h][fmt].
+///
+/// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#962
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_BREAKPAD_INFO {
+ pub validity: u32,
+ /// The Thread ID of the handler thread
+ pub dump_thread_id: u32,
+ /// The Thread ID of the thread that requested the dump
+ pub requesting_thread_id: u32,
+}
+
+bitflags! {
+ /// Potential values for [`MINIDUMP_BREAKPAD_INFO::validity`]
+ ///
+ /// Taken from definitions in Breakpad's [minidump_format.h][fmt].
+ ///
+ /// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#989
+ pub struct BreakpadInfoValid: u32 {
+ const DumpThreadId = 1 << 0;
+ const RequestingThreadId = 1 << 1;
+ }
+}
+
+/// A Breakpad extension containing information about an assertion that terminated the process
+///
+/// Taken from the definition in Breakpad's [minidump_format.h][fmt].
+///
+/// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#998
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_ASSERTION_INFO {
+ /// The assertion that failed, as a 0-terminated UTF16-LE string
+ pub expression: [u16; 128],
+ /// The function containing the assertion, as a 0-terminated UTF16-LE string
+ pub function: [u16; 128],
+ /// The source file containing the assertion, as a 0-terminated UTF16-LE string
+ pub file: [u16; 128],
+ /// The line number in [`file`] containing the assertion
+ pub line: u32,
+ /// The assertion type
+ pub _type: u32,
+}
+
+/// Known values of [`MINIDUMP_ASSERTION_INFO::_type`]
+/// Taken from the definition in Breakpad's [minidump_format.h][fmt].
+///
+/// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#1011
+#[repr(u32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
+pub enum AssertionType {
+ Unknown = 0,
+ InvalidParameter = 1,
+ PureVirtualCall = 2,
+}
+
+/// Dynamic linker information for a shared library on 32-bit Linux
+///
+/// This is functionally equivalent to the data in `struct link_map` defined in <link.h>.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct LINK_MAP_32 {
+ pub addr: u32,
+ /// The offset of a string containing the filename of this shared library
+ pub name: RVA,
+ pub ld: u32,
+}
+
+/// DSO debug data for 32-bit Linux minidumps
+///
+/// Used when converting minidumps to coredumps. This is functionally equivalent to the data
+/// in `struct r_debug` defined in <link.h>.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct DSO_DEBUG_32 {
+ /// The version number of this protocol, from `r_debug.r_version`
+ pub version: u32,
+ /// The offset of an array of [`LINK_MAP_32`] structs
+ pub map: RVA,
+ /// The number of [`LINK_MAP_32`] entries pointed to by `map`
+ pub dso_count: u32,
+ /// The address of a function internal to the run-time linker used by debuggers to
+ /// set a breakpoint.
+ pub brk: u32,
+ /// Base address the linker is loaded at
+ pub ldbase: u32,
+ /// The address of the "dynamic structure"
+ pub dynamic: u32,
+}
+
+/// Dynamic linker information for a shared library on 64-bit Linux
+///
+/// This is functionally equivalent to the data in `struct link_map` defined in <link.h>.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct LINK_MAP_64 {
+ pub addr: u64,
+ /// The offset of a string containing the filename of this shared library
+ pub name: RVA,
+ pub ld: u64,
+}
+
+/// DSO debug data for 64-bit Linux minidumps
+///
+/// Used when converting minidumps to coredumps. This is functionally equivalent to the data
+/// in `struct r_debug` defined in <link.h>.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct DSO_DEBUG_64 {
+ /// The version number of this protocol, from `r_debug.r_version`
+ pub version: u32,
+ /// The offset of an array of [`LINK_MAP_64`] structs
+ pub map: RVA,
+ /// The number of [`LINK_MAP_64`] entries pointed to by `map`
+ pub dso_count: u32,
+ /// The address of a function internal to the run-time linker used by debuggers to
+ /// set a breakpoint.
+ pub brk: u64,
+ /// Base address the linker is loaded at
+ pub ldbase: u64,
+ /// The address of the "dynamic structure"
+ pub dynamic: u64,
+}
+
+/// A variable-length UTF-8-encoded string carried within a minidump file.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpUTF8String.html>
+#[derive(Debug, Clone)]
+pub struct MINIDUMP_UTF8_STRING {
+ /// The length of the #Buffer field in bytes, not including the `NUL` terminator.
+ ///
+ /// This field is interpreted as a byte count, not a count of Unicode code points.
+ pub length: u32,
+ /// The string, encoded in UTF-8, and terminated with a `NUL` byte.
+ pub buffer: Vec<u8>,
+}
+
+impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for MINIDUMP_UTF8_STRING {
+ type Error = scroll::Error;
+
+ fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
+ let offset = &mut 0;
+ let length: u32 = src.gread_with(offset, endian)?;
+ let data: &[u8] = src.gread_with(offset, length as usize + 1)?; // +1 for NUL
+
+ if !data.ends_with(&[0]) {
+ return Err(scroll::Error::Custom(
+ "Minidump String does not end with NUL byte".to_owned(),
+ ));
+ }
+
+ let buffer = data.to_vec();
+ Ok((Self { length, buffer }, *offset))
+ }
+}
+
+/// A key-value pair.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpSimpleStringDictionaryEntry.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_SIMPLE_STRING_DICTIONARY_ENTRY {
+ /// RVA of a MinidumpUTF8String containing the key of a key-value pair.
+ pub key: RVA,
+ /// RVA of a MinidumpUTF8String containing the value of a key-value pair.
+ pub value: RVA,
+}
+
+/// A list of key-value pairs.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpSimpleStringDictionary.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_SIMPLE_STRING_DICTIONARY {
+ /// The number of key-value pairs present.
+ pub count: u32,
+}
+
+/// A list of RVA pointers.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpRVAList.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_RVA_LIST {
+ /// The number of pointers present.
+ pub count: u32,
+}
+
+/// A typed annotation object.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpAnnotation.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_ANNOTATION {
+ /// RVA of a MinidumpUTF8String containing the name of the annotation.
+ pub name: RVA,
+ /// The type of data stored in the `value` of the annotation. This may correspond to an \a
+ /// `MINIDUMP_ANNOTATION_TYPE` or it may be user-defined.
+ pub ty: u16,
+ /// This field is always `0`.
+ pub _reserved: u16,
+ /// RVA of a `MinidumpByteArray` to the data for the annotation.
+ pub value: RVA,
+}
+
+impl MINIDUMP_ANNOTATION {
+ /// An invalid annotation. Reserved for internal use.
+ ///
+ /// See <https://crashpad.chromium.org/doxygen/classcrashpad_1_1Annotation.html#a734ee64cd20afdb78acb8656ed867d34>
+ pub const TYPE_INVALID: u16 = 0;
+ /// A `NUL`-terminated C-string.
+ ///
+ /// See <https://crashpad.chromium.org/doxygen/classcrashpad_1_1Annotation.html#a734ee64cd20afdb78acb8656ed867d34>
+ pub const TYPE_STRING: u16 = 1;
+ /// Clients may declare their own custom types by using values greater than this.
+ ///
+ /// See <https://crashpad.chromium.org/doxygen/classcrashpad_1_1Annotation.html#a734ee64cd20afdb78acb8656ed867d34>
+ pub const TYPE_USER_DEFINED: u16 = 0x8000;
+}
+
+/// Additional Crashpad-specific information about a module carried within a minidump file.
+///
+/// This structure augments the information provided by MINIDUMP_MODULE. The minidump file must
+/// contain a module list stream (::kMinidumpStreamTypeModuleList) in order for this structure to
+/// appear.
+///
+/// This structure is versioned. When changing this structure, leave the existing structure intact
+/// so that earlier parsers will be able to understand the fields they are aware of, and make
+/// additions at the end of the structure. Revise #kVersion and document each field’s validity based
+/// on #version, so that newer parsers will be able to determine whether the added fields are valid
+/// or not.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpModuleCrashpadInfo.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MODULE_CRASHPAD_INFO {
+ /// The structure’s version number.
+ ///
+ /// Readers can use this field to determine which other fields in the structure are valid. Upon
+ /// encountering a value greater than `VERSION`, a reader should assume that the structure’s
+ /// layout is compatible with the structure defined as having value #kVersion.
+ ///
+ /// Writers may produce values less than `VERSION` in this field if there is no need for any
+ /// fields present in later versions.
+ pub version: u32,
+ /// A `MinidumpRVAList` pointing to MinidumpUTF8String objects. The module controls the data
+ /// that appears here.
+ ///
+ /// These strings correspond to `ModuleSnapshot::AnnotationsVector()` and do not duplicate
+ /// anything in `simple_annotations` or `annotation_objects`.
+ pub list_annotations: MINIDUMP_LOCATION_DESCRIPTOR,
+ /// A `MinidumpSimpleStringDictionary` pointing to strings interpreted as key-value pairs. The
+ /// module controls the data that appears here.
+ ///
+ /// These key-value pairs correspond to `ModuleSnapshot::AnnotationsSimpleMap()` and do not
+ /// duplicate anything in `list_annotations` or `annotation_objects`.
+ pub simple_annotations: MINIDUMP_LOCATION_DESCRIPTOR,
+ /// A `MinidumpAnnotationList` object containing the annotation objects stored within the
+ /// module. The module controls the data that appears here.
+ ///
+ /// These key-value pairs correspond to `ModuleSnapshot::AnnotationObjects()` and do not
+ /// duplicate anything in `list_annotations` or `simple_annotations`.
+ pub annotation_objects: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+impl MINIDUMP_MODULE_CRASHPAD_INFO {
+ /// The structure’s version number.
+ ///
+ /// Readers can use this field to determine which other fields in the structure are valid. Upon
+ /// encountering a value greater than `VERSION`, a reader should assume that the structure’s
+ /// layout is compatible with the structure defined as having value #kVersion.
+ ///
+ /// Writers may produce values less than `VERSION` in this field if there is no need for any
+ /// fields present in later versions.
+ pub const VERSION: u32 = 1;
+}
+
+/// A link between a `MINIDUMP_MODULE` structure and additional Crashpad-specific information about a
+/// module carried within a minidump file.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpModuleCrashpadInfoLink.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MODULE_CRASHPAD_INFO_LINK {
+ /// A link to a MINIDUMP_MODULE structure in the module list stream.
+ ///
+ /// This field is an index into `MINIDUMP_MODULE_LIST::Modules`. This field’s value must be in
+ /// the range of `MINIDUMP_MODULE_LIST::NumberOfEntries`.
+ pub minidump_module_list_index: u32,
+
+ /// A link to a MinidumpModuleCrashpadInfo structure.
+ ///
+ /// MinidumpModuleCrashpadInfo structures are accessed indirectly through
+ /// `MINIDUMP_LOCATION_DESCRIPTOR` pointers to allow for future growth of the
+ /// `MinidumpModuleCrashpadInfo` structure.
+ pub location: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+/// Additional Crashpad-specific information about modules carried within a minidump file.
+///
+/// This structure augments the information provided by `MINIDUMP_MODULE_LIST`. The minidump file
+/// must contain a module list stream (::kMinidumpStreamTypeModuleList) in order for this structure
+/// to appear.
+///
+/// `MinidumpModuleCrashpadInfoList::count` may be less than the value of
+/// `MINIDUMP_MODULE_LIST::NumberOfModules` because not every `MINIDUMP_MODULE` structure carried
+/// within the minidump file will necessarily have Crashpad-specific information provided by a
+/// `MinidumpModuleCrashpadInfo` structure.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpModuleCrashpadInfoList.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MODULE_CRASHPAD_INFO_LIST {
+ /// The number of key-value pairs present.
+ pub count: u32,
+}
+
+/// Additional Crashpad-specific information carried within a minidump file.
+///
+/// This structure is versioned. When changing this structure, leave the existing structure intact
+/// so that earlier parsers will be able to understand the fields they are aware of, and make
+/// additions at the end of the structure. Revise #kVersion and document each field’s validity based
+/// on `version`, so that newer parsers will be able to determine whether the added fields are valid
+/// or not.
+///
+/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpCrashpadInfo.html>
+#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_CRASHPAD_INFO {
+ /// The structure’s version number.
+ ///
+ /// Readers can use this field to determine which other fields in the structure are valid. Upon
+ /// encountering a value greater than `VERSION`, a reader should assume that the structure’s
+ /// layout is compatible with the structure defined as having value #kVersion.
+ ///
+ /// Writers may produce values less than `VERSION` in this field if there is no need for any
+ /// fields present in later versions.
+ pub version: u32,
+ /// A `Uuid` identifying an individual crash report.
+ ///
+ /// This provides a stable identifier for a crash even as the report is converted to different
+ /// formats, provided that all formats support storing a crash report ID.
+ ///
+ /// If no identifier is available, this field will contain zeroes.
+ pub report_id: GUID,
+ /// A `Uuid` identifying the client that crashed.
+ ///
+ /// Client identification is within the scope of the application, but it is expected that the
+ /// identifier will be unique for an instance of Crashpad monitoring an application or set of
+ /// applications for a user. The identifier shall remain stable over time.
+ ///
+ /// If no identifier is available, this field will contain zeroes.
+ pub client_id: GUID,
+ /// A MinidumpSimpleStringDictionary pointing to strings interpreted as key-value pairs.
+ ///
+ /// These key-value pairs correspond to Crashpad's `ProcessSnapshot::AnnotationsSimpleMap()`.
+ pub simple_annotations: MINIDUMP_LOCATION_DESCRIPTOR,
+ /// A pointer to a MinidumpModuleCrashpadInfoList structure.
+ pub module_list: MINIDUMP_LOCATION_DESCRIPTOR,
+}
+
+impl MINIDUMP_CRASHPAD_INFO {
+ /// The structure’s currently-defined version number.
+ pub const VERSION: u32 = 1;
+}
+
+/// MacOS __DATA,__crash_info data.
+///
+/// This is the format of the [`MINIDUMP_STREAM_TYPE::MozMacosCrashInfoStream`]. The individual
+/// [`MINIDUMP_MAC_CRASH_INFO_RECORD`] entries follow this header in the stream.
+#[derive(Debug, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MAC_CRASH_INFO {
+ pub stream_type: u32,
+ /// The number of [`MINIDUMP_MAC_CRASH_INFO_RECORD`]s.
+ pub record_count: u32,
+ /// The size of the "fixed-size" part of MINIDUMP_MAC_CRASH_INFO_RECORD.
+ /// Used to offset to the variable-length portion of the struct, where
+ /// C-strings are stored. This allows us to access all the fields we know
+ /// about, even when newer versions of this format introduce new ones.
+ pub record_start_size: u32,
+ pub records: [MINIDUMP_LOCATION_DESCRIPTOR; 20],
+}
+
+// MozMacosCrashInfoStream is a versioned format where new fields are added to
+// the end of the struct, but there are also variable-length c-string fields
+// that follow the "fixed-size" fields. As such, the versioned strings are separated
+// out into their own separate struct with the same version. So e.g.
+//
+// MINIDUMP_MAC_CRASH_INFO_RECORD_4 should be paired with MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4
+
+multi_structs! {
+ /// Contents of MacOS's `<CrashReporterClient.h>`'s `crashreporter_annotations_t`,
+ /// but with the by-reference C-strings hoisted out to the end of the struct
+ /// and inlined (so this is a variable-length struct).
+ ///
+ /// The variable-length strings are listed in [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS`].
+ /// Use [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] to access them.
+ pub struct MINIDUMP_MAC_CRASH_INFO_RECORD {
+ pub stream_type: u64,
+ // Version of this format, currently at 5.
+ //
+ // Although theoretically this field being here means we can support multiple
+ // versions of this struct in one [`MINIDUMP_MAC_CRASH_INFO`] stream, our reliance on
+ // [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] means we can't actually handle
+ // such a heterogeneous situation. So all records should have the same version value.
+ pub version: u64,
+ }
+ // Includes fields from MINIDUMP_MAC_CRASH_INFO_RECORD
+ /// Contents of MacOS's `<CrashReporterClient.h>`'s `crashreporter_annotations_t`,
+ /// but with the by-reference C-strings hoisted out to the end of the struct
+ /// and inlined (so this is a variable-length struct).
+ ///
+ /// The variable-length strings are listed in [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4`].
+ /// Use [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] to access them.
+ pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_4 {
+ pub thread: u64,
+ pub dialog_mode: u64,
+ }
+ // Includes fields from MINIDUMP_MAC_CRASH_INFO_RECORD and MINIDUMP_MAC_CRASH_INFO_RECORD_4
+ /// Contents of MacOS's `<CrashReporterClient.h>`'s `crashreporter_annotations_t`,
+ /// but with the by-reference C-strings hoisted out to the end of the struct
+ /// and inlined (so this is a variable-length struct).
+ ///
+ /// The variable-length strings are listed in [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_5`].
+ /// Use [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] to access them.
+ pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_5 {
+ pub abort_cause: u64,
+ }
+}
+
+macro_rules! replace_expr {
+ ($_t:tt $sub:expr) => {
+ $sub
+ };
+}
+
+macro_rules! count_tts {
+ ($($tts:tt)*) => {0usize $(+ replace_expr!($tts 1usize))*};
+}
+
+// Like multi_structs but specialized for a struct of strings that can be set by index.
+macro_rules! multi_strings {
+ // With no trailing struct left, terminate.
+ (@next { $($prev:tt)* }) => {};
+ // Declare the next struct, including fields from previous structs.
+ (@next { $($prev:tt)* } $(#[$attr:meta])* pub struct $name:ident { $($cur:tt)* } $($tail:tt)* ) => {
+ // Prepend fields from previous structs to this struct.
+ multi_strings!($(#[$attr])* pub struct $name { $($prev)* $($cur)* } $($tail)*);
+ };
+ // Declare a single struct.
+ ($(#[$attr:meta])* pub struct $name:ident { $( pub $field:ident: $t:tt, )* } $($tail:tt)* ) => {
+ $(#[$attr])*
+ #[derive(Default, Debug, Clone)]
+ pub struct $name {
+ $( pub $field: $t, )*
+ }
+
+ impl $name {
+ pub fn num_strings() -> usize {
+ count_tts!($($t)*)
+ }
+
+ #[allow(unused_variables, unused_mut)]
+ pub fn set_string(&mut self, idx: usize, string: String) {
+ let mut cur_idx = 0;
+ $(if cur_idx == idx {
+ self.$field = string;
+ return;
+ }
+ cur_idx += 1;
+ )*
+ panic!("string index out of bounds {} >= {}", idx, cur_idx);
+ }
+ }
+
+ // Persist its fields down to the following structs.
+ multi_strings!(@next { $( pub $field: $t, )* } $($tail)*);
+ };
+}
+
+multi_strings! {
+ /// Variable-length data for [`MINIDUMP_MAC_CRASH_INFO_RECORD`].
+ pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS {
+ // No strings in the base version
+ }
+
+ // Includes fields from [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS`]
+ /// Variable-length data for [`MINIDUMP_MAC_CRASH_INFO_RECORD_4`].
+ pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4 {
+ pub module_path: String,
+ pub message: String,
+ pub signature_string: String,
+ pub backtrace: String,
+ pub message2: String,
+ }
+
+ // Includes fields from [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4`]
+ /// Variable-length data for [`MINIDUMP_MAC_CRASH_INFO_RECORD_5`].
+ pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_5 {
+ // No new strings
+ }
+}
+
+/// The maximum supported size of a C-string in [`MINIDUMP_MAC_CRASH_INFO_RECORD`].
+///
+/// Assume the stream is corrupted if a string is longer than this.
+pub const MAC_CRASH_INFO_STRING_MAX_SIZE: usize = 8192;
+
+/// The maximum supported count of [`MINIDUMP_MAC_CRASH_INFO_RECORD`]s.
+///
+/// In principle there should only be one or two non-empty __DATA,__crash_info
+/// sections per process. But the __crash_info section is almost entirely
+/// undocumented, so just in case we set a large maximum.
+pub const MAC_CRASH_INFOS_MAX: usize = 20;
+
+/// MacOS kernel boot args
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_MAC_BOOTARGS {
+ pub stream_type: u32,
+ pub bootargs: RVA64,
+}
+
+bitflags! {
+ /// Possible values of [`ARMCpuInfo::elf_hwcaps`]
+ ///
+ /// This matches the Linux kernel definitions from [<asm/hwcaps.h>][hwcap].
+ ///
+ /// [hwcap]: https://elixir.bootlin.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct ArmElfHwCaps: u32 {
+ const HWCAP_SWP = (1 << 0);
+ const HWCAP_HALF = (1 << 1);
+ const HWCAP_THUMB = (1 << 2);
+ const HWCAP_26BIT = (1 << 3);
+ const HWCAP_FAST_MULT = (1 << 4);
+ const HWCAP_FPA = (1 << 5);
+ const HWCAP_VFP = (1 << 6);
+ const HWCAP_EDSP = (1 << 7);
+ const HWCAP_JAVA = (1 << 8);
+ const HWCAP_IWMMXT = (1 << 9);
+ const HWCAP_CRUNCH = (1 << 10);
+ const HWCAP_THUMBEE = (1 << 11);
+ const HWCAP_NEON = (1 << 12);
+ const HWCAP_VFPv3 = (1 << 13);
+ const HWCAP_VFPv3D16 = (1 << 14);
+ const HWCAP_TLS = (1 << 15);
+ const HWCAP_VFPv4 = (1 << 16);
+ const HWCAP_IDIVA = (1 << 17);
+ const HWCAP_IDIVT = (1 << 18);
+ const HWCAP_VFPD32 = (1 << 19);
+ const HWCAP_IDIV = ArmElfHwCaps::HWCAP_IDIVA.bits() | Self::HWCAP_IDIVT.bits();
+ const HWCAP_LPAE = (1 << 20);
+ const HWCAP_EVTSTRM = (1 << 21);
+ }
+}
+
+#[repr(u32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
+pub enum MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE {
+ MiniHandleObjectInformationNone,
+ MiniThreadInformation1,
+ MiniMutantInformation1,
+ MiniMutantInformation2,
+ MiniProcessInformation1,
+ MiniProcessInformation2,
+ MiniEventInformation1,
+ MiniSectionInformation1,
+ MiniSemaphoreInformation1,
+ MiniHandleObjectInformationTypeMax,
+}
+
+/// OS-specific handle object information. Microsoft headers state that it can
+/// change based on the target platform. The object is larger than this structure
+/// (as specified by `size_of_info`) and the remaining data is stored after the
+/// `size_of_info` field. The format of this information is not specified.
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_HANDLE_OBJECT_INFORMATION {
+ /// RVA pointing to the next handle object information. Elements of this type
+ /// are chained and the last one has this field set to 0.
+ pub next_info_rva: RVA,
+ /// Type of this handle object information element, see [`MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE`]
+ pub info_type: u32,
+ /// Size of this element, this must be larger than `size_of::<MINIDUMP_HANDLE_OBJECT_INFORMATION>()`
+ pub size_of_info: u32,
+}
+
+#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_HANDLE_DESCRIPTOR {
+ /// The operating system handle value. A HANDLE on Windows and file descriptor number on Linux.
+ pub handle: u64,
+ /// An RVA to a `MINIDUMP_STRING` structure that specifies the object type of the handle.
+ /// This member can be zero.
+ pub type_name_rva: RVA,
+ /// An RVA to a `MINIDUMP_STRING` structure that specifies the object name of the handle.
+ /// This member can be zero.
+ pub object_name_rva: RVA,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub attributes: u32,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub granted_access: u32,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub handle_count: u32,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub pointer_count: u32,
+}
+
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_HANDLE_DESCRIPTOR_2 {
+ /// The operating system handle value. A HANDLE on Windows and file descriptor number on Linux.
+ pub handle: u64,
+ /// An RVA to a `MINIDUMP_STRING` structure that specifies the object type of the handle.
+ /// This member can be zero.
+ pub type_name_rva: RVA,
+ /// An RVA to a `MINIDUMP_STRING` structure that specifies the object name of the handle.
+ /// This member can be zero.
+ pub object_name_rva: RVA,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub attributes: u32,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub granted_access: u32,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub handle_count: u32,
+ /// The meaning of this member depends on the handle type and the operating system.
+ pub pointer_count: u32,
+ /// An RVA to a [`MINIDUMP_HANDLE_OBJECT_INFORMATION`] structure that specifies object-specific information.
+ /// This member can be 0 if there is no extra information.
+ pub object_info_rva: RVA,
+ /// Reserved for future use; must be zero.
+ reserved0: u32,
+}
+
+#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
+pub struct MINIDUMP_HANDLE_DATA_STREAM {
+ /// The size of this header, in bytes.
+ pub size_of_header: u32,
+ /// The size of each descriptor in the stream, in bytes.
+ pub size_of_descriptor: u32,
+ /// The number of descriptors in the stream.
+ pub number_of_descriptors: u32,
+ /// Reserved for future use; must be zero.
+ pub reserved: u32,
+}