minidump_common/
format.rs

1//! Minidump structure definitions.
2//!
3//! Types defined here should match those defined in [Microsoft's headers][msdn]. Additionally
4//! some [Breakpad][breakpad] and [Crashpad][crashpad] extension types are defined here and should
5//! match the definitions from those projects.
6//!
7//! # Type Layouts
8//!
9//! This library isn't a "proper" minidump-sys library because it doesn't use repr attributes
10//! to force Rust to layout these structs identically to how they're laid out in memory.
11//!
12//! The reasons for this are 3-fold:
13//!
14//! 1. It isn't necessary because we specify how to serialize/deserialize things with `scroll`
15//!    via `derive(Pread, Pwrite)` which uses the declared field order and not the in-memory
16//!    layout, and assumes everything is packed anyway, which as a rule, minidump types are.
17//!    Specifically they're packed to align 4, but Microsoft is mercifully very attentive to
18//!    its type layouts so we're not aware of anywhere where packing to align 1 would change
19//!    offsets. Packing is mostly just there so 32-bit and 64-bit definitely agree on offsets.
20//!
21//! 2. We would have to mark several types as `repr(packed(4))`, making them dangerous to use
22//!    as several of the fields would become misaligned. This would create a bunch of
23//!    unnecessary and brittle `unsafe`.
24//!
25//! 3. It's not *actually* that useful to have structs with precise in-memory layouts since
26//!    a minidump parser needs to accept both little-endian and big-endian minidumps, and
27//!    is therefore swizzling the bytes of all the values anyway. Also it's dangerous to
28//!    reinterpret a pile of memory as arbitrary types without validation!
29//!
30//! [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/
31//! [breakpad]: https://chromium.googlesource.com/breakpad/breakpad/
32//! [crashpad]: https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md
33#![allow(non_camel_case_types)]
34#![allow(non_upper_case_globals)]
35
36use std::fmt;
37
38use bitflags::bitflags;
39use num_derive::FromPrimitive;
40use scroll::{Endian, Pread, Pwrite, SizeWith};
41use smart_default::SmartDefault;
42
43/// An offset from the start of the minidump file.
44pub type RVA = u32;
45pub type RVA64 = u64;
46
47/// The 4-byte magic number at the start of a minidump file.
48///
49/// In little endian this spells 'MDMP'.
50pub const MINIDUMP_SIGNATURE: u32 = 0x504d444d;
51
52/// The version of the minidump format.
53pub const MINIDUMP_VERSION: u32 = 42899;
54
55/// The header at the start of a minidump file.
56///
57/// This struct matches the [Microsoft struct][msdn] of the same name.
58///
59/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header
60#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
61pub struct MINIDUMP_HEADER {
62    /// This should be [`MINIDUMP_SIGNATURE`][signature].
63    ///
64    /// [signature]: constant.MINIDUMP_SIGNATURE.html
65    pub signature: u32,
66    /// This should be [`MINIDUMP_VERSION`][version].
67    ///
68    /// [version]: constant.MINIDUMP_VERSION.html
69    pub version: u32,
70    /// The number of streams contained in the stream directory.
71    pub stream_count: u32,
72    /// The offset to the stream directory within the minidump. This usually points
73    /// to immediately after the header. The stream directory is an array containing
74    /// `stream_count` [`MINIDUMP_DIRECTORY`][dir] entries.
75    ///
76    /// [dir]: struct.MINIDUMP_DIRECTORY.html
77    pub stream_directory_rva: RVA,
78    pub checksum: u32,
79    pub time_date_stamp: u32,
80    pub flags: u64,
81}
82
83/// A location within a minidump file comprised of an offset and a size.
84///
85/// This struct matches the [Microsoft struct][msdn] of the same name.
86///
87/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_location_descriptor
88#[derive(Debug, Copy, Default, Clone, Pread, Pwrite, SizeWith)]
89pub struct MINIDUMP_LOCATION_DESCRIPTOR {
90    /// The size of this data.
91    pub data_size: u32,
92    /// The offset to this data within the minidump file.
93    pub rva: RVA,
94}
95
96impl From<u8> for MINIDUMP_LOCATION_DESCRIPTOR {
97    fn from(_val: u8) -> Self {
98        Self::default()
99    }
100}
101
102/// A range of memory contained within a minidump consisting of a base address and a
103/// location descriptor.
104///
105/// This struct matches the [Microsoft struct][msdn] of the same name.
106///
107/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_descriptor
108#[derive(Debug, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
109pub struct MINIDUMP_MEMORY_DESCRIPTOR {
110    /// The base address of this memory range from the process.
111    pub start_of_memory_range: u64,
112    /// The offset and size of the actual bytes of memory contained in this dump.
113    pub memory: MINIDUMP_LOCATION_DESCRIPTOR,
114}
115
116/// A large range of memory contained within a minidump (usually a full dump)
117/// consisting of a base address and a size.
118///
119/// This struct matches the [Microsoft struct][msdn] of the same name.
120///
121/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_descriptor64
122#[derive(Debug, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
123pub struct MINIDUMP_MEMORY_DESCRIPTOR64 {
124    /// The base address of this memory range from the process.
125    pub start_of_memory_range: u64,
126    /// The size of this data.
127    pub data_size: u64,
128}
129
130/// Information about a data stream contained in a minidump file.
131///
132/// The minidump header contains a pointer to a list of these structs which allows locating
133/// specific streams in the dump.
134/// This struct matches the [Microsoft struct][msdn] of the same name.
135///
136/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_directory
137#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
138pub struct MINIDUMP_DIRECTORY {
139    /// This is usually one of the values in [`MINIDUMP_STREAM_TYPE`][ty] for known stream types,
140    /// but user streams can have arbitrary values.
141    ///
142    /// [ty]: enum.MINIDUMP_STREAM_TYPE.html
143    pub stream_type: u32,
144    /// The location of the stream contents within the dump.
145    pub location: MINIDUMP_LOCATION_DESCRIPTOR,
146}
147
148/// The types of known minidump data streams.
149///
150/// Most of these values are derived from the [Microsoft enum][msdn] of the same name, but
151/// the values after `LastReservedStream` are Breakpad and Crashpad extensions.
152///
153/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_stream_type
154#[repr(u32)]
155#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
156pub enum MINIDUMP_STREAM_TYPE {
157    /// An unused stream directory entry
158    UnusedStream = 0,
159    ReservedStream0 = 1,
160    ReservedStream1 = 2,
161    /// The list of threads from the process
162    ///
163    /// See [`MINIDUMP_THREAD`].
164    ///
165    /// Microsoft declares a [`MINIDUMP_THREAD_LIST`][list] struct which is the actual format
166    /// of this stream, but it is a variable-length struct so no matching definition is provided
167    /// in this crate.
168    ///
169    /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread_list
170    ThreadListStream = 3,
171    /// The list of executable modules from the process
172    ///
173    /// See [`MINIDUMP_MODULE`].
174    ///
175    /// Microsoft declares a [`MINIDUMP_MODULE_LIST`][list] struct which is the actual format
176    /// of this stream, but it is a variable-length struct so no matching definition is provided
177    /// in this crate.
178    ///
179    /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module_list
180    ModuleListStream = 4,
181    /// The list of memory regions from the process contained within this dump
182    ///
183    /// See [`MINIDUMP_MEMORY_DESCRIPTOR`].
184    ///
185    /// Microsoft declares a [`MINIDUMP_MEMORY_LIST`][list] struct which is the actual format
186    /// of this stream, but it is a variable-length struct so no matching definition is provided
187    /// in this crate.
188    ///
189    /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_list
190    MemoryListStream = 5,
191    /// Information about the exception that caused the process to exit
192    ///
193    /// See [`MINIDUMP_EXCEPTION_STREAM`].
194    ExceptionStream = 6,
195    /// System information
196    ///
197    /// See [`MINIDUMP_SYSTEM_INFO`].
198    SystemInfoStream = 7,
199    ThreadExListStream = 8,
200    /// The list of large memory regions from the process contained within this dump
201    ///
202    /// See [`MINIDUMP_MEMORY_DESCRIPTOR64`].
203    ///
204    /// Microsoft declares a [`MINIDUMP_MEMORY64_LIST`][list] struct which is the actual format
205    /// of this stream, but it is a variable-length struct so no matching definition is provided
206    /// in this crate.
207    ///
208    /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory64_list
209    Memory64ListStream = 9,
210    CommentStreamA = 10,
211    CommentStreamW = 11,
212    /// The list of handles used by the process
213    ///
214    /// See [`MINIDUMP_HANDLE_DATA_STREAM`]
215    HandleDataStream = 12,
216    FunctionTable = 13,
217    /// The list of executable modules from the process that were unloaded by the time of the crash
218    ///
219    /// See [`MINIDUMP_UNLOADED_MODULE`].
220    ///
221    /// Microsoft declares a [`MINIDUMP_UNLOADED_MODULE_LIST`][list] struct which is the actual
222    /// format of this stream, but it is a variable-length struct so no matching definition is
223    /// in this crate.
224    ///
225    /// Note that unlike other lists, this one has the newer "extended" header.
226    ///
227    /// [list]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_unloaded_module_list
228    UnloadedModuleListStream = 14,
229    /// Miscellaneous process and system information
230    ///
231    /// See ['MINIDUMP_MISC_INFO'].
232    MiscInfoStream = 15,
233    /// Information about memory regions from the process
234    ///
235    /// See ['MINIDUMP_MEMORY_INFO_LIST'].
236    MemoryInfoListStream = 16,
237    ThreadInfoListStream = 17,
238    HandleOperationListStream = 18,
239    TokenStream = 19,
240    JavaScriptDataStream = 20,
241    SystemMemoryInfoStream = 21,
242    ProcessVmCountersStream = 22,
243    IptTraceStream = 23,
244    /// Names of threads
245    ///
246    /// See ['MINIDUMP_THREAD_NAME'].
247    ThreadNamesStream = 24,
248    /* Windows CE types, the list  is available here https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms939649(v=msdn.10) */
249    /// Start of the Windows CE enumerated list, unused.
250    ceStreamNull = 0x00008000,
251    /// System-wide information about the device and operating system where the fault occurred. Windows CE-specific.
252    ceStreamSystemInfo = 0x00008001,
253    /// Exception record and context for the exception that caused the dump file creation. Windows CE-specific.
254    ceStreamException = 0x00008002,
255    /// Modules that were active on the device at the time the dump file was created. Windows CE-specific.
256    ceStreamModuleList = 0x00008003,
257    /// Processes that were active on the device at the time the dump file was created. Windows CE-specific.
258    ceStreamProcessList = 0x00008004,
259    /// Threads that were active on the device at the time the dump file was created. Windows CE-specific.
260    ceStreamThreadList = 0x00008005,
261    /// List of thread context records. Windows CE-specific.
262    ceStreamThreadContextList = 0x00008006,
263    /// List of thread callstack records. Windows CE-specific.
264    ceStreamThreadCallStackList = 0x00008007,
265    /// List of virtual memory dumps. Windows CE-specific.
266    ceStreamMemoryVirtualList = 0x00008008,
267    /// List of physical memory dumps. Windows CE-specific.
268    ceStreamMemoryPhysicalList = 0x00008009,
269    /// Bucketing parameters for Watson server. Windows CE-specific.
270    ceStreamBucketParameters = 0x0000800a,
271    /// Undocumented Windows CE-specific stream.
272    ceStreamProcessModuleMap = 0x0000800b,
273    /// Undocumented Windows CE-specific stream.
274    ceStreamDiagnosisList = 0x0000800c,
275    /// Last stream reserved for use by Windows Operating Systems.
276    LastReservedStream = 0x0000ffff,
277    /* Breakpad extension types.  0x4767 = "Gg" */
278    /// Additional process information (Breakpad extension)
279    ///
280    /// See ['MINIDUMP_BREAKPAD_INFO'].
281    BreakpadInfoStream = 0x47670001,
282    /// Assertion information (Breakpad extension)
283    ///
284    /// See ['MINIDUMP_ASSERTION_INFO'].
285    AssertionInfoStream = 0x47670002,
286    /* These are additional minidump stream values which are specific to
287     * the linux breakpad implementation. */
288    /// The contents of /proc/cpuinfo from a Linux system
289    LinuxCpuInfo = 0x47670003,
290    /// The contents of /proc/self/status from a Linux system
291    LinuxProcStatus = 0x47670004,
292    /// The contents of /etc/lsb-release from a Linux system
293    LinuxLsbRelease = 0x47670005,
294    /// The contents of /proc/self/cmdline from a Linux system
295    LinuxCmdLine = 0x47670006,
296    /// The contents of /proc/self/environ from a Linux system
297    LinuxEnviron = 0x47670007,
298    /// The contents of /proc/self/auxv from a Linux system
299    LinuxAuxv = 0x47670008,
300    /// The contents of /proc/self/maps from a Linux system
301    LinuxMaps = 0x47670009,
302    /// Information from the Linux dynamic linker useful for writing core dumps
303    ///
304    /// See ['DSO_DEBUG_64'] and ['DSO_DEBUG_32'].
305    LinuxDsoDebug = 0x4767000A,
306    // Crashpad extension types. 0x4350 = "CP"
307    /// Crashpad-specific information containing annotations.
308    ///
309    /// See [`MINIDUMP_CRASHPAD_INFO`].
310    CrashpadInfoStream = 0x43500001,
311
312    /// Chromium stability report stream
313    /// <https://source.chromium.org/chromium/chromium/src/+/main:components/stability_report/>
314    StabilityReportStream = 0x4b6b0002,
315
316    /// Data from the __DATA,__crash_info section of every module which contains
317    /// one that has useful data. Only available on macOS. 0x4D7A = "Mz".
318    ///
319    /// See ['MINIDUMP_MAC_CRASH_INFO'].
320    MozMacosCrashInfoStream = 0x4d7a0001,
321
322    /// The kernel boot args on the machine where the crashed process is
323    /// running. Only available on macOS. 0x4D7A = "Mz".
324    ///
325    /// See ['MINIDUMP_MAC_BOOTARGS']
326    MozMacosBootargsStream = 0x4d7a0002,
327
328    /// The contents of /proc/self/limits from a Linux system
329    MozLinuxLimits = 0x4d7a0003,
330
331    /// Soft errors reported during minidump generation
332    MozSoftErrors = 0x4d7a0004,
333}
334
335impl From<MINIDUMP_STREAM_TYPE> for u32 {
336    fn from(ty: MINIDUMP_STREAM_TYPE) -> Self {
337        ty as u32
338    }
339}
340
341/// The name of a thread, found in the ThreadNamesStream.
342#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
343pub struct MINIDUMP_THREAD_NAME {
344    /// The id of the thread.
345    pub thread_id: u32,
346    /// Where the name of the thread is stored (yes, the legendary RVA64 is real!!).
347    pub thread_name_rva: RVA64,
348}
349
350/// Information about a single module (executable or shared library) from a minidump
351///
352/// This struct matches the [Microsoft struct][msdn] of the same name.
353///
354/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module
355#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
356pub struct MINIDUMP_MODULE {
357    /// The base address of the executable image in memory.
358    pub base_of_image: u64,
359    /// The size of the executable image in memory, in bytes.
360    pub size_of_image: u32,
361    /// The checksum value from the PE headers.
362    pub checksum: u32,
363    /// The timestamp value from the PE headers in `time_t` format.
364    pub time_date_stamp: u32,
365    /// An offset to a length-prefixed UTF-16LE string containing the name of the module.
366    pub module_name_rva: RVA,
367    /// Version information for this module.
368    pub version_info: VS_FIXEDFILEINFO,
369    /// The location of a CodeView record describing debug information for this module.
370    ///
371    /// This should be one of [`CV_INFO_PDB70`][pdb70], [`CV_INFO_PDB20`][pdb20], or
372    /// [`CV_INFO_ELF`][elf]. `PDB70` is the most common in practice, describing a standalone PDB
373    /// file by way of GUID, age, and PDB filename, and `ELF` is a Breakpad extension for
374    /// describing ELF modules with Build IDs.
375    ///
376    /// See [Matching Debug Information][dbg] for more information.
377    ///
378    /// [dbg]: http://web.archive.org/web/20210227224734/https://www.debuginfo.com/articles/debuginfomatch.html
379    /// [pdb70]: struct.CV_INFO_PDB70.html
380    /// [pdb20]: struct.CV_INFO_PDB20.html
381    /// [elf]: struct.CV_INFO_ELF.html
382    pub cv_record: MINIDUMP_LOCATION_DESCRIPTOR,
383    /// The location of an `IMAGE_DEBUG_MISC` record describing debug information for this module.
384    pub misc_record: MINIDUMP_LOCATION_DESCRIPTOR,
385    pub reserved0: [u32; 2],
386    pub reserved1: [u32; 2],
387}
388
389/// Information about a single unloaded module (executable or shared library) from a minidump.
390///
391/// This struct matches the [Microsoft struct][msdn] of the same name.
392///
393/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_unloaded_module
394#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
395pub struct MINIDUMP_UNLOADED_MODULE {
396    /// The base address of the executable image in memory (when it was loaded).
397    pub base_of_image: u64,
398    /// The size of the executable image in memory, in bytes.
399    pub size_of_image: u32,
400    /// The checksum value from the PE headers.
401    pub checksum: u32,
402    /// The timestamp value from the PE headers in `time_t` format.
403    pub time_date_stamp: u32,
404    /// An offset to a length-prefixed UTF-16LE string containing the name of the module.
405    pub module_name_rva: RVA,
406}
407
408/// Version information for a file
409///
410/// This struct matches the [Microsoft struct][msdn] of the same name.
411///
412/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
413#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
414pub struct VS_FIXEDFILEINFO {
415    /// Contains the value of `VS_FFI_SIGNATURE`
416    pub signature: u32,
417    /// Should contain the value of `VS_FFI_STRUCVERSION`
418    pub struct_version: u32,
419    pub file_version_hi: u32,
420    pub file_version_lo: u32,
421    pub product_version_hi: u32,
422    pub product_version_lo: u32,
423    pub file_flags_mask: u32,
424    pub file_flags: u32,
425    pub file_os: u32,
426    pub file_type: u32,
427    pub file_subtype: u32,
428    pub file_date_hi: u32,
429    pub file_date_lo: u32,
430}
431
432/// The expected value of `VS_FIXEDFILEINFO.signature`
433pub const VS_FFI_SIGNATURE: u32 = 0xfeef04bd;
434
435/// The expected value of `VS_FIXEDFILEINFO.struct_version`
436pub const VS_FFI_STRUCVERSION: u32 = 0x00010000;
437
438/// Known values for the `signature` field of CodeView records
439///
440/// In addition to the two CodeView record formats used for linking
441/// to external pdb files it is possible for debugging data to be carried
442/// directly in the CodeView record itself.  These signature values will
443/// be found in the first 4 bytes of the CodeView record.  Additional values
444/// not commonly experienced in the wild are given by ["Microsoft Symbol and
445/// Type Information"][sym] section 7.2.  An in-depth description of the CodeView 4.1 format
446/// is given by ["Undocumented Windows 2000 Secrets"][win2k], Windows 2000 Debugging Support/
447/// Microsoft Symbol File Internals/CodeView Subsections.
448///
449/// [sym]: http://web.archive.org/web/20070915060650/http://www.x86.org/ftp/manuals/tools/sym.pdf
450/// [win2k]: https://dl.acm.org/citation.cfm?id=375734
451#[repr(u32)]
452#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
453pub enum CvSignature {
454    /// PDB 2.0 CodeView data: 'NB10': [`CV_INFO_PDB20`]
455    Pdb20 = 0x3031424e,
456    /// PDB 7.0 CodeView data: 'RSDS': [`CV_INFO_PDB70`]
457    Pdb70 = 0x53445352,
458    /// ELF Build ID, a Breakpad extension: 'BpEL': [`CV_INFO_ELF`]
459    Elf = 0x4270454c,
460    /// CodeView 4.10: 'NB09'
461    Cv41 = 0x3930424e,
462    /// CodeView 5.0: 'NB11'
463    Cv50 = 0x3131424e,
464}
465
466/// CodeView debug information in the older PDB 2.0 ("NB10") format.
467///
468/// This struct is defined as variable-length in C with a trailing PDB filename member.
469#[derive(Debug, Clone)]
470pub struct CV_INFO_PDB20 {
471    /// This field will always be [`CvSignature::Pdb20`].
472    pub cv_signature: u32,
473    pub cv_offset: u32,
474    pub signature: u32,
475    pub age: u32,
476    /// The PDB filename as a zero-terminated byte string
477    pub pdb_file_name: Vec<u8>,
478}
479
480impl scroll::ctx::TryFromCtx<'_, Endian> for CV_INFO_PDB20 {
481    type Error = scroll::Error;
482
483    fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
484        let offset = &mut 0;
485        Ok((
486            CV_INFO_PDB20 {
487                cv_signature: src.gread_with(offset, endian)?,
488                cv_offset: src.gread_with(offset, endian)?,
489                signature: src.gread_with(offset, endian)?,
490                age: src.gread_with(offset, endian)?,
491                pdb_file_name: {
492                    let size = src.len() - *offset;
493                    src.gread_with::<&[u8]>(offset, size)?.to_owned()
494                },
495            },
496            *offset,
497        ))
498    }
499}
500
501/// CodeView debug information in the current PDB 7.0 ("RSDS") format.
502///
503/// This struct is defined as variable-length in C with a trailing PDB filename member.
504#[derive(Debug, Clone)]
505pub struct CV_INFO_PDB70 {
506    /// This will always be [`CvSignature::Pdb70`]
507    pub cv_signature: u32,
508    /// A unique identifer for a module created on first build.
509    pub signature: GUID,
510    /// A counter, incremented for each rebuild that updates the PDB file.
511    pub age: u32,
512    /// The PDB filename as a zero-terminated byte string
513    pub pdb_file_name: Vec<u8>,
514}
515
516impl scroll::ctx::TryFromCtx<'_, Endian> for CV_INFO_PDB70 {
517    type Error = scroll::Error;
518
519    fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
520        let offset = &mut 0;
521        Ok((
522            CV_INFO_PDB70 {
523                cv_signature: src.gread_with(offset, endian)?,
524                signature: src.gread_with(offset, endian)?,
525                age: src.gread_with(offset, endian)?,
526                pdb_file_name: {
527                    let size = src.len() - *offset;
528                    src.gread_with::<&[u8]>(offset, size)?.to_owned()
529                },
530            },
531            *offset,
532        ))
533    }
534}
535
536/// A GUID as specified in Rpcdce.h
537///
538/// Matches the [Microsoft struct][msdn] of the same name.
539///
540/// # Display
541///
542/// There are two `Display` implementations for GUIDs. The regular formatting is lowercase with
543/// hyphens. The alternate formatting used with `#` is the symbol server format (uppercase without
544/// hyphens).
545///
546/// ```
547/// use minidump_common::format::GUID;
548///
549/// let guid = GUID { data1: 10, data2: 11, data3: 12, data4: [1,2,3,4,5,6,7,8] };
550///
551/// // default formatting
552/// assert_eq!("0000000a-000b-000c-0102-030405060708", guid.to_string());
553///
554/// // symbol server formatting
555/// assert_eq!("0000000A000B000C0102030405060708", format!("{:#}", guid));
556/// ```
557///
558/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
559#[derive(Clone, Copy, Debug, PartialEq, Eq, Pread, Pwrite, SizeWith)]
560pub struct GUID {
561    pub data1: u32,
562    pub data2: u16,
563    pub data3: u16,
564    pub data4: [u8; 8],
565}
566
567/// Creates a GUID from a raw byte array. It is assumed that the components in
568/// the array are in big-endian order.
569///
570/// ```
571/// use minidump_common::format::GUID;
572///
573/// let mut buf = [0u8; 16];
574/// buf[0..4].copy_from_slice(&0xdeadc0deu32.to_be_bytes());
575/// buf[4..6].copy_from_slice(&0xb105u16.to_be_bytes());
576/// buf[6..8].copy_from_slice(&0xc0deu16.to_be_bytes());
577/// buf[8..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]);
578///
579/// let guid: GUID = buf.into();
580///
581/// let expected = GUID { data1: 0xdeadc0de, data2: 0xb105, data3: 0xc0de, data4: [1, 2, 3, 4, 5, 6, 7, 8] };
582///
583/// assert_eq!(guid, expected);
584/// ```
585impl From<[u8; 16]> for GUID {
586    fn from(uuid: [u8; 16]) -> Self {
587        let data1 = ((uuid[0] as u32) << 24)
588            | ((uuid[1] as u32) << 16)
589            | ((uuid[2] as u32) << 8)
590            | uuid[3] as u32;
591        let data2 = ((uuid[4] as u16) << 8) | uuid[5] as u16;
592        let data3 = ((uuid[6] as u16) << 8) | uuid[7] as u16;
593        let mut data4 = [0u8; 8];
594        data4.copy_from_slice(&uuid[8..]);
595
596        Self {
597            data1,
598            data2,
599            data3,
600            data4,
601        }
602    }
603}
604
605impl fmt::Display for GUID {
606    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
607        // NB: This formatting is not endianness aware. GUIDs read from LE minidumps are printed
608        // with reversed fields.
609        if f.alternate() {
610            write!(
611                f,
612                "{:08X}{:04X}{:04X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
613                self.data1,
614                self.data2,
615                self.data3,
616                self.data4[0],
617                self.data4[1],
618                self.data4[2],
619                self.data4[3],
620                self.data4[4],
621                self.data4[5],
622                self.data4[6],
623                self.data4[7],
624            )
625        } else {
626            write!(
627                f,
628                "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
629                self.data1,
630                self.data2,
631                self.data3,
632                self.data4[0],
633                self.data4[1],
634                self.data4[2],
635                self.data4[3],
636                self.data4[4],
637                self.data4[5],
638                self.data4[6],
639                self.data4[7],
640            )
641        }
642    }
643}
644
645/// An ELF Build ID.
646///
647/// Modern ELF toolchains insert a "[build id][buildid]" into the ELF headers that typically
648/// contains a hash of some ELF headers and sections to uniquely identify a binary. The Build ID
649/// is allowed to be an arbitrary number of bytes however, and [GNU binutils allows creating
650/// ELF binaries with Build IDs of various formats][binutils].
651///
652/// [buildid]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/developer_guide/compiling-build-id
653/// [binutils]: https://sourceware.org/binutils/docs-2.26/ld/Options.html#index-g_t_002d_002dbuild_002did-292
654#[derive(Debug, Clone)]
655pub struct CV_INFO_ELF {
656    /// This will always be [`CvSignature::Elf`]
657    pub cv_signature: u32,
658    /// The build id, a variable number of bytes
659    pub build_id: Vec<u8>,
660}
661
662impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for CV_INFO_ELF {
663    type Error = scroll::Error;
664
665    fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
666        let offset = &mut 0;
667        Ok((
668            CV_INFO_ELF {
669                cv_signature: src.gread_with(offset, endian)?,
670                build_id: {
671                    let size = src.len() - *offset;
672                    src.gread_with::<&[u8]>(offset, size)?.to_owned()
673                },
674            },
675            *offset,
676        ))
677    }
678}
679
680/// Obsolete debug record type defined in WinNT.h.
681#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
682pub struct IMAGE_DEBUG_MISC {
683    pub data_type: u32,
684    pub length: u32,
685    pub unicode: u8,
686    pub reserved: [u8; 3],
687    pub data: [u8; 1],
688}
689
690/// Information about a single thread from a minidump
691///
692/// This struct matches the [Microsoft struct][msdn] of the same name.
693///
694/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread
695#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
696pub struct MINIDUMP_THREAD {
697    /// The identifier of this thread
698    pub thread_id: u32,
699    /// The suspend count for this thread
700    ///
701    /// If greater than zero, the thread is suspended.
702    pub suspend_count: u32,
703    /// The priority class of the thread
704    ///
705    /// See [Scheduling Priorities][msdn] on MSDN.
706    ///
707    /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/ProcThread/scheduling-priorities
708    pub priority_class: u32,
709    /// The priority level of the thread
710    pub priority: u32,
711    /// The thread environment block
712    pub teb: u64,
713    /// The location and base address of this thread's stack memory
714    pub stack: MINIDUMP_MEMORY_DESCRIPTOR,
715    /// The location of a CPU-specific `CONTEXT_` struct for this thread's CPU context
716    pub thread_context: MINIDUMP_LOCATION_DESCRIPTOR,
717}
718
719/// Information about the exception that caused the process to terminate.
720///
721/// This struct matches the [Microsoft struct][msdn] of the same name.
722///
723/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception_stream
724#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
725pub struct MINIDUMP_EXCEPTION_STREAM {
726    /// The identifier of the thread that encountered the exception.
727    pub thread_id: u32,
728    pub __align: u32,
729    /// Detailed information about the exception encountered.
730    pub exception_record: MINIDUMP_EXCEPTION,
731    /// The offset of a CPU context record from the time the thread encountered the exception.
732    ///
733    /// The actual data will be one of the `CONTEXT_*` structs defined here.
734    pub thread_context: MINIDUMP_LOCATION_DESCRIPTOR,
735}
736
737/// Detailed information about an exception.
738///
739/// This struct matches the [Microsoft struct][msdn] of the same name.
740///
741/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception
742#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
743pub struct MINIDUMP_EXCEPTION {
744    /// The reason the exception occurred.
745    ///
746    /// Possible values are in the following enums:
747    ///
748    /// * [`ExceptionCodeWindows`](crate::errors::ExceptionCodeWindows)
749    /// * [`WinErrorWindows`](crate::errors::WinErrorWindows)
750    /// * [`NtStatusWindows`](crate::errors::NtStatusWindows)
751    /// * [`ExceptionCodeLinux`](crate::errors::ExceptionCodeLinux)
752    /// * [`ExceptionCodeMac`](crate::errors::ExceptionCodeMac)
753    pub exception_code: u32,
754    /// Flags related to the exception.
755    ///
756    /// On Windows this is 1 for noncontinuable exceptions and 0 otherwise. For Breakpad-produced
757    /// minidumps on macOS this field is used to store additional exception information.
758    pub exception_flags: u32,
759    /// The address of an associated [`MINIDUMP_EXCEPTION`] for a nested exception.
760    ///
761    /// This address is in the minidump producing host's memory.
762    pub exception_record: u64,
763    /// The address where the exception occurred.
764    ///
765    /// For Breakpad-produced minidumps on macOS this is the exception subcode, which is
766    /// typically the address.
767    pub exception_address: u64,
768    /// The number of valid elements in [`MINIDUMP_EXCEPTION::exception_information`].
769    pub number_parameters: u32,
770    pub __align: u32,
771    /// An array of additional arguments that describe the exception.
772    ///
773    /// For most exception codes the array elements are undefined, but for access violations
774    /// the array will contain two elements: a read/write flag in the first element and
775    /// the virtual address whose access caused the exception in the second element.
776    pub exception_information: [u64; 15], // EXCEPTION_MAXIMUM_PARAMETERS
777}
778
779/// Valid bits in a `context_flags` for [`ContextFlagsCpu`]
780pub const CONTEXT_CPU_MASK: u32 = 0xffffff00;
781/// x86 and x64 contexts have this bit set in their `context_flags` when they have
782/// extra XSTATE beyond the traditional context definition.
783pub const CONTEXT_HAS_XSTATE: u32 = 0x00000040;
784
785bitflags! {
786    /// CPU type values in the `context_flags` member of `CONTEXT_` structs
787    ///
788    /// This applies to the [`CONTEXT_ARM`], [`CONTEXT_PPC`], [`CONTEXT_MIPS`],
789    /// [`CONTEXT_AMD64`], [`CONTEXT_ARM64`], [`CONTEXT_PPC64`], [`CONTEXT_SPARC`] and
790    /// [`CONTEXT_ARM64_OLD`] structs.
791    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
792    pub struct ContextFlagsCpu: u32 {
793        const CONTEXT_IA64 = 0x80000;
794        /// Super-H, includes SH3, from winnt.h in the Windows CE 5.0 SDK
795        const CONTEXT_SHX = 0xc0;
796        /// From winnt.h in the Windows CE 5.0 SDK, no longer used
797        ///
798        /// Originally used by Breakpad but changed after conflicts with other context
799        /// flag bits.
800        const CONTEXT_ARM_OLD = 0x40;
801        /// Alpha, from winnt.h in the Windows CE 5.0 SDK
802        const CONTEXT_ALPHA = 0x20000;
803        const CONTEXT_AMD64 = 0x100000;
804        const CONTEXT_ARM = 0x40000000;
805        const CONTEXT_ARM64 = 0x400000;
806        const CONTEXT_ARM64_OLD = 0x80000000;
807        const CONTEXT_MIPS = 0x40000;
808        const CONTEXT_MIPS64 = 0x80000;
809        const CONTEXT_PPC = 0x20000000;
810        const CONTEXT_PPC64 = 0x1000000;
811        const CONTEXT_SPARC = 0x10000000;
812        const CONTEXT_X86 = 0x10000;
813    }
814}
815
816impl ContextFlagsCpu {
817    /// Populate a [`ContextFlagsCpu`] with valid bits from `flags`
818    pub fn from_flags(flags: u32) -> ContextFlagsCpu {
819        ContextFlagsCpu::from_bits_truncate(flags & CONTEXT_CPU_MASK)
820    }
821}
822
823bitflags! {
824    /// Flags available for use in [`CONTEXT_AMD64.context_flags`]
825    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
826    pub struct ContextFlagsAmd64: u32 {
827        /// SegSs, Rsp, SegCs, Rip, and EFlags
828        const CONTEXT_AMD64_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_AMD64.bits();
829        /// Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, and R8-R15
830        const CONTEXT_AMD64_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_AMD64.bits();
831        /// SegDs, SegEs, SegFs, and SegGs
832        const CONTEXT_AMD64_SEGMENTS = 0x00000004 | ContextFlagsCpu::CONTEXT_AMD64.bits();
833        /// Xmm0-Xmm15
834        const CONTEXT_AMD64_FLOATING_POINT = 0x00000008 | ContextFlagsCpu::CONTEXT_AMD64.bits();
835        /// Dr0-Dr3 and Dr6-Dr7
836        const CONTEXT_AMD64_DEBUG_REGISTERS = 0x00000010 | ContextFlagsCpu::CONTEXT_AMD64.bits();
837        const CONTEXT_AMD64_XSTATE = 0x00000020 | ContextFlagsCpu::CONTEXT_AMD64.bits();
838        const CONTEXT_AMD64_FULL = Self::CONTEXT_AMD64_CONTROL.bits() | Self::CONTEXT_AMD64_INTEGER.bits() | Self::CONTEXT_AMD64_FLOATING_POINT.bits();
839        const CONTEXT_AMD64_ALL = Self::CONTEXT_AMD64_FULL.bits() | Self::CONTEXT_AMD64_SEGMENTS.bits() | Self::CONTEXT_AMD64_DEBUG_REGISTERS.bits();
840    }
841}
842
843bitflags! {
844    /// Flags available for use in [`CONTEXT_X86.context_flags`]
845    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
846    pub struct ContextFlagsX86: u32 {
847        /// Ebp, Eip, SegCs, EFlags, Esp, SegSs
848        const CONTEXT_X86_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_X86.bits();
849        /// Edi, Esi, Ebx, Edx, Ecx, Eax
850        const CONTEXT_X86_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_X86.bits();
851        /// SegDs, SegEs, SegFs, and SegGs
852        const CONTEXT_X86_SEGMENTS = 0x00000004 | ContextFlagsCpu::CONTEXT_X86.bits();
853        /// Fpcr, Fpsr, Fptag, Fpioff, Fpisel, Fpdoff, Fpdsel, Mxcsr, Mxcsr_mask, Xmm0-Xmm7
854        const CONTEXT_X86_FLOATING_POINT = 0x00000008 | ContextFlagsCpu::CONTEXT_X86.bits();
855        /// Dr0-Dr3 and Dr6-Dr7
856        const CONTEXT_X86_DEBUG_REGISTERS = 0x00000010 | ContextFlagsCpu::CONTEXT_X86.bits();
857        const CONTEXT_X86_EXTENDED_REGISTERS = 0x00000020 | ContextFlagsCpu::CONTEXT_X86.bits();
858        const CONTEXT_X86_XSTATE = 0x00000040 | ContextFlagsCpu::CONTEXT_X86.bits();
859        const CONTEXT_X86_FULL = Self::CONTEXT_X86_CONTROL.bits() | Self::CONTEXT_X86_INTEGER.bits() | Self::CONTEXT_X86_SEGMENTS.bits();
860        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();
861    }
862}
863
864bitflags! {
865    /// Flags available for use in [`CONTEXT_ARM64.context_flags`]
866    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
867    pub struct ContextFlagsArm64: u32 {
868        /// FP, LR, SP, PC, and CPSR
869        const CONTEXT_ARM64_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_ARM64.bits();
870        /// X0-X28 (but maybe not X18)
871        const CONTEXT_ARM64_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_ARM64.bits();
872        /// Fpcr, Fpsr, D0-D31 (AKA Q0-Q31, AKA S0-S31)
873        const CONTEXT_ARM64_FLOATING_POINT = 0x00000004 | ContextFlagsCpu::CONTEXT_ARM64.bits();
874        /// DBGBVR, DBGBCR, DBGWVR, DBGWCR
875        const CONTEXT_ARM64_DEBUG_REGISTERS = 0x0000008 | ContextFlagsCpu::CONTEXT_ARM64.bits();
876        /// Whether x18 has a valid value, because on Windows it contains the TEB.
877        ///
878        /// NOTE: at this precise moment breakpad doesn't define this, but Microsoft does!
879        const CONTEXT_ARM64_X18 = 0x0000010 | ContextFlagsCpu::CONTEXT_ARM64.bits();
880        const CONTEXT_ARM64_FULL = Self::CONTEXT_ARM64_CONTROL.bits() | Self::CONTEXT_ARM64_INTEGER.bits() | Self::CONTEXT_ARM64_FLOATING_POINT.bits();
881        const CONTEXT_ARM64_ALL = Self::CONTEXT_ARM64_FULL.bits() | Self::CONTEXT_ARM64_DEBUG_REGISTERS.bits() | Self::CONTEXT_ARM64_X18.bits();
882    }
883}
884
885bitflags! {
886    /// Flags available for use in [`CONTEXT_ARM64_OLD.context_flags`]
887    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
888    pub struct ContextFlagsArm64Old: u32 {
889        // Yes, breakpad never defined CONTROL for this context
890
891        /// FP, LR, SP, PC, CPSR, and X0-X28
892        const CONTEXT_ARM64_OLD_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_ARM64_OLD.bits();
893        /// Fpcr, Fpsr, D0-D31 (AKA Q0-Q31, AKA S0-S31)
894        const CONTEXT_ARM64_OLD_FLOATING_POINT = 0x00000004 | ContextFlagsCpu::CONTEXT_ARM64_OLD.bits();
895        const CONTEXT_ARM64_OLD_FULL = Self::CONTEXT_ARM64_OLD_INTEGER.bits() | Self::CONTEXT_ARM64_OLD_FLOATING_POINT.bits();
896        const CONTEXT_ARM64_OLD_ALL = Self::CONTEXT_ARM64_OLD_FULL.bits();
897    }
898}
899
900bitflags! {
901    /// Flags available for use in [`CONTEXT_ARM.context_flags`]
902    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
903    pub struct ContextFlagsArm: u32 {
904        // Yes, breakpad never defined CONTROL for this context
905
906        /// SP, LR, PC, and CPSR
907        const CONTEXT_ARM_CONTROL = 0x00000001 | ContextFlagsCpu::CONTEXT_ARM.bits();
908        /// R0-R12
909        const CONTEXT_ARM_INTEGER = 0x00000002 | ContextFlagsCpu::CONTEXT_ARM.bits();
910        /// Q0-Q15 / D0-D31 / S0-S31
911        const CONTEXT_ARM_FLOATING_POINT = 0x00000004 | ContextFlagsCpu::CONTEXT_ARM.bits();
912        /// DBGBVR, DBGBCR, DBGWVR, DBGWCR
913        const CONTEXT_ARM_DEBUG_REGISTERS = 0x00000008 | ContextFlagsCpu::CONTEXT_ARM.bits();
914        const CONTEXT_ARM_FULL = Self::CONTEXT_ARM_CONTROL.bits() | Self::CONTEXT_ARM_INTEGER.bits() | Self::CONTEXT_ARM_FLOATING_POINT.bits();
915        const CONTEXT_ARM_ALL = Self::CONTEXT_ARM_FULL.bits() | Self::CONTEXT_ARM_DEBUG_REGISTERS.bits();
916    }
917}
918
919/// Possible contents of [`CONTEXT_AMD64::float_save`].
920///
921/// This struct matches the definition of the struct with the same name from WinNT.h.
922#[derive(Debug, SmartDefault, Clone, Pread, Pwrite, SizeWith)]
923pub struct XMM_SAVE_AREA32 {
924    pub control_word: u16,
925    pub status_word: u16,
926    pub tag_word: u8,
927    pub reserved1: u8,
928    pub error_opcode: u16,
929    pub error_offset: u32,
930    pub error_selector: u16,
931    pub reserved2: u16,
932    pub data_offset: u32,
933    pub data_selector: u16,
934    pub reserved3: u16,
935    pub mx_csr: u32,
936    pub mx_csr_mask: u32,
937    #[default([0; 8])]
938    pub float_registers: [u128; 8],
939    #[default([0; 16])]
940    pub xmm_registers: [u128; 16],
941    #[default([0; 96])]
942    pub reserved4: [u8; 96],
943}
944
945/// Possible contents of [`CONTEXT_AMD64::float_save`].
946///
947/// This is defined as an anonymous struct inside an anonymous union in
948/// the x86-64 CONTEXT struct in WinNT.h.
949#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
950pub struct SSE_REGISTERS {
951    pub header: [u128; 2],
952    pub legacy: [u128; 8],
953    pub xmm0: u128,
954    pub xmm1: u128,
955    pub xmm2: u128,
956    pub xmm3: u128,
957    pub xmm4: u128,
958    pub xmm5: u128,
959    pub xmm6: u128,
960    pub xmm7: u128,
961    pub xmm8: u128,
962    pub xmm9: u128,
963    pub xmm10: u128,
964    pub xmm11: u128,
965    pub xmm12: u128,
966    pub xmm13: u128,
967    pub xmm14: u128,
968    pub xmm15: u128,
969}
970
971/// An x86-64 (amd64) CPU context
972///
973/// This struct matches the definition of `CONTEXT` in WinNT.h for x86-64.
974#[derive(Debug, SmartDefault, Clone, Pread, Pwrite, SizeWith)]
975#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
976pub struct CONTEXT_AMD64 {
977    pub p1_home: u64,
978    pub p2_home: u64,
979    pub p3_home: u64,
980    pub p4_home: u64,
981    pub p5_home: u64,
982    pub p6_home: u64,
983    pub context_flags: u32,
984    pub mx_csr: u32,
985    pub cs: u16,
986    pub ds: u16,
987    pub es: u16,
988    pub fs: u16,
989    pub gs: u16,
990    pub ss: u16,
991    pub eflags: u32,
992    pub dr0: u64,
993    pub dr1: u64,
994    pub dr2: u64,
995    pub dr3: u64,
996    pub dr6: u64,
997    pub dr7: u64,
998    pub rax: u64,
999    pub rcx: u64,
1000    pub rdx: u64,
1001    pub rbx: u64,
1002    pub rsp: u64,
1003    pub rbp: u64,
1004    pub rsi: u64,
1005    pub rdi: u64,
1006    pub r8: u64,
1007    pub r9: u64,
1008    pub r10: u64,
1009    pub r11: u64,
1010    pub r12: u64,
1011    pub r13: u64,
1012    pub r14: u64,
1013    pub r15: u64,
1014    pub rip: u64,
1015    /// Floating point state
1016    ///
1017    /// This is defined as a union in the C headers, but also
1018    /// ` MAXIMUM_SUPPORTED_EXTENSION` is defined as 512 bytes.
1019    ///
1020    /// Callers that want to access the underlying data can use [`Pread`] to read either
1021    /// an [`XMM_SAVE_AREA32`] or [`SSE_REGISTERS`] struct from this raw data as appropriate.
1022    #[default([0; 512])]
1023    pub float_save: [u8; 512],
1024    #[default([0; 26])]
1025    pub vector_register: [u128; 26],
1026    pub vector_control: u64,
1027    pub debug_control: u64,
1028    pub last_branch_to_rip: u64,
1029    pub last_branch_from_rip: u64,
1030    pub last_exception_to_rip: u64,
1031    pub last_exception_from_rip: u64,
1032}
1033
1034/// ARM floating point state
1035#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
1036#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1037pub struct FLOATING_SAVE_AREA_ARM {
1038    pub fpscr: u64,
1039    pub regs: [u64; 32],
1040    pub extra: [u32; 8],
1041}
1042
1043/// An ARM CPU context
1044///
1045/// This is a Breakpad extension, and does not match the definition of `CONTEXT` for ARM
1046/// in WinNT.h.
1047#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
1048#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1049pub struct CONTEXT_ARM {
1050    pub context_flags: u32,
1051    // [r0, r1, ..., r15]
1052    pub iregs: [u32; 16],
1053    pub cpsr: u32,
1054    pub float_save: FLOATING_SAVE_AREA_ARM,
1055}
1056
1057/// Offsets into [`CONTEXT_ARM::iregs`] for registers with a dedicated or conventional purpose
1058#[repr(usize)]
1059#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1060pub enum ArmRegisterNumbers {
1061    IosFramePointer = 7,
1062    FramePointer = 11,
1063    StackPointer = 13,
1064    LinkRegister = 14,
1065    ProgramCounter = 15,
1066}
1067
1068impl ArmRegisterNumbers {
1069    pub const fn name(self) -> &'static str {
1070        match self {
1071            Self::IosFramePointer => "r7",
1072            Self::FramePointer => "r11",
1073            Self::StackPointer => "r13",
1074            Self::LinkRegister => "r14",
1075            Self::ProgramCounter => "r15",
1076        }
1077    }
1078}
1079
1080/// An old (breakpad-style) aarch64 (arm64) CPU context.
1081///
1082/// This is a breakpad extension, but contrary to what the name might suggest,
1083/// it isn't completely out of service. I believe all non-windows platforms
1084/// still prefer emitting this format to avoid needless churn.
1085///
1086/// Semantically this type agrees with the "new" [CONTEXT_ARM64][] and can
1087/// generally be handled with all the same logic. i.e. the general purpose
1088/// `iregs` are the same. It's just that the other fields are shuffled around.
1089///
1090/// As I understand it, this is basically an artifact of breakpad getting to
1091/// arm64 "first" (Android would be first in line for it!) and picking a
1092/// definition they thought was reasonable. Thankfully they picked an
1093/// "out of the way" context id so that when Microsoft came along and picked
1094/// their own definition, there wouldn't be a conflict.
1095///
1096/// Note that we have inlined the fields of the "float save" struct from
1097/// breakpad's definition to be more uniform with [CONTEXT_ARM64][].
1098///
1099/// NOTE: if you ever decide to try to make this repr(C) and get really clever,
1100/// this type is actually non-trivially repr(packed(4)) in the headers!
1101#[derive(Debug, Clone, Copy, Default, Pread, Pwrite, SizeWith)]
1102#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1103pub struct CONTEXT_ARM64_OLD {
1104    pub context_flags: u64,
1105    /// `[x0, x1, ..., x28, fp, lr]`. See [Arm64RegisterNumbers][].
1106    pub iregs: [u64; 31],
1107    pub sp: u64,
1108    pub pc: u64,
1109    pub cpsr: u32,
1110    /// FPU status register.
1111    pub fpsr: u32,
1112    /// FPU control register.
1113    pub fpcr: u32,
1114    /// float/NEON registers `[d0, d1, ..., d31]`
1115    pub float_regs: [u128; 32usize],
1116}
1117
1118/// A (microsoft-style) aarch64 (arm64) CPU context
1119///
1120/// This matches the layout of how Windows defines this type. Breakpad defines
1121/// it in an equivalent but more-quirky way that relies more on packing.
1122///
1123/// For general purpose registers:
1124///
1125/// * microsoft: make iregs have 31 values and have sp and pc as explicit fields.
1126/// * breakpad make iregs have 33 values, no explicit fields.
1127///
1128/// For float registers:
1129///
1130/// * microsoft: inline the fields for float_regs, fpcr, fpsr.
1131/// * breakpad: wrap them in a struct.
1132///
1133/// -----------------
1134///
1135/// Why *we* went with these definitions:
1136///
1137/// * ARM64 actually defines x0..x30 register names, but sp and pc aren't
1138///   "x31" and "x32". Breakpad is effectively punning them as such, and
1139///   that's kinda weird?
1140///
1141/// * Microsft's inlining of the float registers eliminates any need for
1142///   padding on all platforms (note how there's always an even number of
1143///   u32's before a u64, and an even number of u64's before a u128!)
1144///
1145/// NOTE: if you ever decide to try to make this repr(C) and get really clever,
1146/// note that microsoft aligns this to 16 (and as of this writing, rust does
1147/// not consistently aling u128 as such).
1148#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
1149#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1150pub struct CONTEXT_ARM64 {
1151    pub context_flags: u32,
1152    pub cpsr: u32,
1153    /// `[x0, x1, ..., x28, fp, lr]`. See [Arm64RegisterNumbers][].
1154    pub iregs: [u64; 31],
1155    pub sp: u64,
1156    pub pc: u64,
1157    /// float/NEON registers `[d0, d1, ..., d31]`
1158    pub float_regs: [u128; 32usize],
1159    /// FPU control register.
1160    pub fpcr: u32,
1161    /// FPU status register.
1162    pub fpsr: u32,
1163    pub bcr: [u32; 8],
1164    pub bvr: [u64; 8],
1165    pub wcr: [u32; 2],
1166    pub wvr: [u64; 2],
1167}
1168
1169/// Offsets into [`CONTEXT_ARM64::iregs`] for registers with a dedicated or conventional purpose
1170#[repr(usize)]
1171#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1172pub enum Arm64RegisterNumbers {
1173    FramePointer = 29,
1174    LinkRegister = 30,
1175}
1176
1177impl Arm64RegisterNumbers {
1178    pub const fn name(self) -> &'static str {
1179        match self {
1180            Self::FramePointer => "x29",
1181            Self::LinkRegister => "x30",
1182        }
1183    }
1184}
1185
1186/// MIPS floating point state
1187#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
1188#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1189pub struct FLOATING_SAVE_AREA_MIPS {
1190    pub regs: [u64; 32],
1191    pub fpcsr: u32,
1192    pub fir: u32,
1193}
1194
1195/// A MIPS CPU context
1196///
1197/// This is a Breakpad extension, as there is no definition of `CONTEXT` for MIPS in WinNT.h.
1198#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
1199#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1200pub struct CONTEXT_MIPS {
1201    pub context_flags: u32,
1202    pub _pad0: u32,
1203    pub iregs: [u64; 32],
1204    pub mdhi: u64,
1205    pub mdlo: u64,
1206    pub hi: [u32; 3],
1207    pub lo: [u32; 3],
1208    pub dsp_control: u32,
1209    pub _pad1: u32,
1210    pub epc: u64,
1211    pub badvaddr: u64,
1212    pub status: u32,
1213    pub cause: u32,
1214    pub float_save: FLOATING_SAVE_AREA_MIPS,
1215}
1216
1217/// Offsets into [`CONTEXT_MIPS::iregs`] for registers with a dedicated or conventional purpose
1218#[repr(usize)]
1219#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1220pub enum MipsRegisterNumbers {
1221    S0 = 16,
1222    S1 = 17,
1223    S2 = 18,
1224    S3 = 19,
1225    S4 = 20,
1226    S5 = 21,
1227    S6 = 22,
1228    S7 = 23,
1229    GlobalPointer = 28,
1230    StackPointer = 29,
1231    FramePointer = 30,
1232    ReturnAddress = 31,
1233}
1234
1235impl MipsRegisterNumbers {
1236    pub const fn name(self) -> &'static str {
1237        match self {
1238            MipsRegisterNumbers::S0 => "s0",
1239            MipsRegisterNumbers::S1 => "s1",
1240            MipsRegisterNumbers::S2 => "s2",
1241            MipsRegisterNumbers::S3 => "s3",
1242            MipsRegisterNumbers::S4 => "s4",
1243            MipsRegisterNumbers::S5 => "s5",
1244            MipsRegisterNumbers::S6 => "s6",
1245            MipsRegisterNumbers::S7 => "s7",
1246            MipsRegisterNumbers::GlobalPointer => "gp",
1247            MipsRegisterNumbers::StackPointer => "sp",
1248            MipsRegisterNumbers::FramePointer => "fp",
1249            MipsRegisterNumbers::ReturnAddress => "ra",
1250        }
1251    }
1252}
1253
1254/// PPC floating point state
1255#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1256#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1257pub struct FLOATING_SAVE_AREA_PPC {
1258    pub fpregs: [u64; 32],
1259    pub fpscr_pad: u32,
1260    pub fpscr: u32,
1261}
1262
1263/// PPC vector state
1264#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1265#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1266pub struct VECTOR_SAVE_AREA_PPC {
1267    pub save_vr: [u128; 32],
1268    pub save_vscr: u128,
1269    pub save_pad5: [u32; 4],
1270    pub save_vrvalid: u32,
1271    pub save_pad6: [u32; 7],
1272}
1273
1274/// A PPC CPU context
1275///
1276/// This is a Breakpad extension, as there is no definition of `CONTEXT` for PPC in WinNT.h.
1277#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1278#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1279pub struct CONTEXT_PPC {
1280    pub context_flags: u32,
1281    pub srr0: u32,
1282    pub srr1: u32,
1283    pub gpr: [u32; 32],
1284    pub cr: u32,
1285    pub xer: u32,
1286    pub lr: u32,
1287    pub ctr: u32,
1288    pub mq: u32,
1289    pub vrsave: u32,
1290    pub float_save: FLOATING_SAVE_AREA_PPC,
1291    pub vector_save: VECTOR_SAVE_AREA_PPC,
1292}
1293
1294/// Offsets into [`CONTEXT_PPC::gpr`] for registers with a dedicated or conventional purpose
1295#[repr(usize)]
1296#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1297pub enum PpcRegisterNumbers {
1298    StackPointer = 1,
1299}
1300
1301/// A PPC64 CPU context
1302///
1303/// This is a Breakpad extension, as there is no definition of `CONTEXT` for PPC64 in WinNT.h.
1304#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1305#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1306pub struct CONTEXT_PPC64 {
1307    pub context_flags: u64,
1308    pub srr0: u64,
1309    pub srr1: u64,
1310    pub gpr: [u64; 32],
1311    pub cr: u64,
1312    pub xer: u64,
1313    pub lr: u64,
1314    pub ctr: u64,
1315    pub vrsave: u64,
1316    pub float_save: FLOATING_SAVE_AREA_PPC,
1317    pub vector_save: VECTOR_SAVE_AREA_PPC,
1318}
1319
1320/// Offsets into [`CONTEXT_PPC64::gpr`] for registers with a dedicated or conventional purpose
1321#[repr(usize)]
1322#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1323pub enum Ppc64RegisterNumbers {
1324    StackPointer = 1,
1325}
1326
1327/// SPARC floating point state
1328#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1329#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1330pub struct FLOATING_SAVE_AREA_SPARC {
1331    pub regs: [u64; 32],
1332    pub filler: u64,
1333    pub fsr: u64,
1334}
1335
1336/// A SPARC CPU context
1337///
1338/// This is a Breakpad extension, as there is no definition of `CONTEXT` for SPARC in WinNT.h.
1339#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1340#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1341pub struct CONTEXT_SPARC {
1342    pub context_flags: u32,
1343    pub flag_pad: u32,
1344    pub g_r: [u64; 32],
1345    pub ccr: u64,
1346    pub pc: u64,
1347    pub npc: u64,
1348    pub y: u64,
1349    pub asi: u64,
1350    pub fprs: u64,
1351    pub float_save: FLOATING_SAVE_AREA_SPARC,
1352}
1353
1354/// Offsets into [`CONTEXT_SPARC::g_r`] for registers with a dedicated or conventional purpose
1355#[repr(usize)]
1356#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1357pub enum SparcRegisterNumbers {
1358    StackPointer = 14,
1359}
1360
1361/// x86 floating point state
1362///
1363/// This struct matches the definition of the `FLOATING_SAVE_AREA` struct from WinNT.h.
1364#[derive(Debug, Clone, SmartDefault, Pread, Pwrite, SizeWith)]
1365#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1366pub struct FLOATING_SAVE_AREA_X86 {
1367    pub control_word: u32,
1368    pub status_word: u32,
1369    pub tag_word: u32,
1370    pub error_offset: u32,
1371    pub error_selector: u32,
1372    pub data_offset: u32,
1373    pub data_selector: u32,
1374    #[default([0; 80])]
1375    pub register_area: [u8; 80], // SIZE_OF_80387_REGISTERS
1376    pub cr0_npx_state: u32,
1377}
1378
1379/// An x86 CPU context
1380///
1381/// This struct matches the definition of `CONTEXT` in WinNT.h for x86.
1382#[derive(Debug, Clone, SmartDefault, Pread, Pwrite, SizeWith)]
1383#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1384pub struct CONTEXT_X86 {
1385    pub context_flags: u32,
1386    pub dr0: u32,
1387    pub dr1: u32,
1388    pub dr2: u32,
1389    pub dr3: u32,
1390    pub dr6: u32,
1391    pub dr7: u32,
1392    pub float_save: FLOATING_SAVE_AREA_X86,
1393    pub gs: u32,
1394    pub fs: u32,
1395    pub es: u32,
1396    pub ds: u32,
1397    pub edi: u32,
1398    pub esi: u32,
1399    pub ebx: u32,
1400    pub edx: u32,
1401    pub ecx: u32,
1402    pub eax: u32,
1403    pub ebp: u32,
1404    pub eip: u32,
1405    pub cs: u32,
1406    pub eflags: u32,
1407    pub esp: u32,
1408    pub ss: u32,
1409    #[default([0; 512])]
1410    pub extended_registers: [u8; 512], // MAXIMUM_SUPPORTED_EXTENSION
1411}
1412
1413/// CPU information contained within the [`MINIDUMP_SYSTEM_INFO`] struct
1414///
1415/// This struct matches the definition of the `CPU_INFORMATION` union from minidumpapiset.h.
1416#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1417pub struct CPU_INFORMATION {
1418    /// `data` is defined as a union in the Microsoft headers
1419    ///
1420    /// It is the union of [`X86CpuInfo`], [`ARMCpuInfo`] (Breakpad-specific), and
1421    /// [`OtherCpuInfo`] defined below. It does not seem possible to safely derive [`Pread`]
1422    /// on an actual union, so we provide the raw data here and expect callers to use
1423    /// [`Pread`] to derive the specific union representation desired.
1424    pub data: [u8; 24],
1425}
1426
1427/// x86-specific CPU information derived from the `cpuid` instruction
1428///
1429/// This struct matches the definition of the struct of the same name from minidumpapiset.h,
1430/// which is contained within the [`CPU_INFORMATION`] union.
1431#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1432pub struct X86CpuInfo {
1433    pub vendor_id: [u32; 3],
1434    pub version_information: u32,
1435    pub feature_information: u32,
1436    pub amd_extended_cpu_features: u32,
1437}
1438
1439/// Arm-specific CPU information (Breakpad extension)
1440#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1441pub struct ARMCpuInfo {
1442    pub cpuid: u32,
1443    /// Hardware capabilities
1444    ///
1445    /// See [`ArmElfHwCaps`] for possible values.
1446    pub elf_hwcaps: u32,
1447}
1448
1449/// CPU information for non-x86 CPUs
1450///
1451/// This struct matches the definition of the struct of the same name from minidumpapiset.h,
1452/// which is contained within the [`CPU_INFORMATION`] union.
1453#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1454pub struct OtherCpuInfo {
1455    pub processor_features: [u64; 2],
1456}
1457
1458/// Processor and operating system information
1459///
1460/// This struct matches the [Microsoft struct][msdn] of the same name.
1461///
1462/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_system_info
1463#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1464pub struct MINIDUMP_SYSTEM_INFO {
1465    /// The system's processor architecture
1466    ///
1467    /// Known values are defined in [`ProcessorArchitecture`].
1468    pub processor_architecture: u16,
1469    /// x86 (5 = 586, 6 = 686 ...) or ARM (6 = ARMv6, 7 = ARMv7 ...) CPU level
1470    pub processor_level: u16,
1471    /// For x86, 0xMMSS where MM=model, SS=stepping
1472    pub processor_revision: u16,
1473    pub number_of_processors: u8,
1474    pub product_type: u8,
1475    pub major_version: u32,
1476    pub minor_version: u32,
1477    pub build_number: u32,
1478    /// The operating system platform
1479    ///
1480    /// Known values are defined in [`PlatformId`].
1481    pub platform_id: u32,
1482    pub csd_version_rva: RVA,
1483    pub suite_mask: u16,
1484    pub reserved2: u16,
1485    pub cpu: CPU_INFORMATION,
1486}
1487
1488/// Known values of [`MINIDUMP_SYSTEM_INFO::processor_architecture`]
1489///
1490/// Many of these are taken from definitions in WinNT.h, but several of them are
1491/// Breakpad extensions.
1492#[repr(u16)]
1493#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
1494pub enum ProcessorArchitecture {
1495    PROCESSOR_ARCHITECTURE_INTEL = 0,
1496    PROCESSOR_ARCHITECTURE_MIPS = 1,
1497    PROCESSOR_ARCHITECTURE_ALPHA = 2,
1498    PROCESSOR_ARCHITECTURE_PPC = 3,
1499    PROCESSOR_ARCHITECTURE_SHX = 4,
1500    PROCESSOR_ARCHITECTURE_ARM = 5,
1501    PROCESSOR_ARCHITECTURE_IA64 = 6,
1502    PROCESSOR_ARCHITECTURE_ALPHA64 = 7,
1503    /// Microsoft Intermediate Language
1504    PROCESSOR_ARCHITECTURE_MSIL = 8,
1505    PROCESSOR_ARCHITECTURE_AMD64 = 9,
1506    /// WoW64
1507    PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10,
1508    PROCESSOR_ARCHITECTURE_ARM64 = 12,
1509    /// Breakpad-defined value for SPARC
1510    PROCESSOR_ARCHITECTURE_SPARC = 0x8001,
1511    /// Breakpad-defined value for PPC64
1512    PROCESSOR_ARCHITECTURE_PPC64 = 0x8002,
1513    /// Breakpad-defined value for ARM64
1514    PROCESSOR_ARCHITECTURE_ARM64_OLD = 0x8003,
1515    /// Breakpad-defined value for MIPS64
1516    PROCESSOR_ARCHITECTURE_MIPS64 = 0x8004,
1517    PROCESSOR_ARCHITECTURE_UNKNOWN = 0xffff,
1518}
1519
1520/// Known values of [`MINIDUMP_SYSTEM_INFO::platform_id`]
1521///
1522/// The Windows values here are taken from defines in WinNT.h, but the rest are Breakpad
1523/// extensions.
1524#[repr(u32)]
1525#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
1526pub enum PlatformId {
1527    /// Windows 3.1
1528    VER_PLATFORM_WIN32s = 1,
1529    /// Windows 95-98-Me
1530    VER_PLATFORM_WIN32_WINDOWS = 2,
1531    /// Windows NT, 2000+
1532    VER_PLATFORM_WIN32_NT = 3,
1533    /// Windows CE, Windows Mobile
1534    VER_PLATFORM_WIN32_CE = 4,
1535    /// Generic Unix-ish (Breakpad extension)
1536    Unix = 0x8000,
1537    /// macOS/Darwin (Breakpad extension)
1538    MacOs = 0x8101,
1539    /// iOS (Breakpad extension)
1540    Ios = 0x8102,
1541    /// Linux (Breakpad extension)
1542    Linux = 0x8201,
1543    /// Solaris (Breakpad extension)
1544    Solaris = 0x8202,
1545    /// Android (Breakpad extension)
1546    Android = 0x8203,
1547    /// PlayStation 3 (Breakpad extension)
1548    Ps3 = 0x8204,
1549    /// Native Client (Breakpad extension)
1550    NaCl = 0x8205,
1551}
1552
1553/// A date and time
1554///
1555/// This struct matches the [Microsoft struct][msdn] of the same name.
1556///
1557/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
1558#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith, PartialEq, Eq)]
1559pub struct SYSTEMTIME {
1560    pub year: u16,
1561    pub month: u16,
1562    pub day_of_week: u16,
1563    pub day: u16,
1564    pub hour: u16,
1565    pub minute: u16,
1566    pub second: u16,
1567    pub milliseconds: u16,
1568}
1569
1570/// Settings for a time zone
1571///
1572/// This struct matches the [Microsoft struct][msdn] of the same name.
1573///
1574/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information
1575#[derive(Debug, Clone, Default, Pread, Pwrite, SizeWith)]
1576pub struct TIME_ZONE_INFORMATION {
1577    pub bias: i32,
1578    pub standard_name: [u16; 32],
1579    pub standard_date: SYSTEMTIME,
1580    pub standard_bias: i32,
1581    pub daylight_name: [u16; 32],
1582    pub daylight_date: SYSTEMTIME,
1583    pub daylight_bias: i32,
1584}
1585
1586/*
1587 * There are multiple versions of the misc info struct, and each new version includes all
1588 * fields from the previous versions. We declare them with a macro to avoid repeating
1589 * the fields excessively.
1590 */
1591macro_rules! multi_structs {
1592    // With no trailing struct left, terminate.
1593    (@next { $($prev:tt)* }) => {};
1594    // Declare the next struct, including fields from previous structs.
1595    (@next { $($prev:tt)* } $(#[$attr:meta])* pub struct $name:ident { $($cur:tt)* } $($tail:tt)* ) => {
1596        // Prepend fields from previous structs to this struct.
1597        multi_structs!($(#[$attr])* pub struct $name { $($prev)* $($cur)* } $($tail)*);
1598    };
1599    // Declare a single struct.
1600    ($(#[$attr:meta])* pub struct $name:ident { $( pub $field:ident: $t:tt, )* } $($tail:tt)* ) => {
1601        $(#[$attr])*
1602        #[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1603        pub struct $name {
1604            $( pub $field: $t, )*
1605        }
1606        // Persist its fields down to the following structs.
1607        multi_structs!(@next { $( pub $field: $t, )* } $($tail)*);
1608    };
1609}
1610
1611multi_structs! {
1612    /// Miscellaneous process information
1613    ///
1614    /// This struct matches the [Microsoft struct][msdn] of the same name.
1615    ///
1616    /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_misc_info
1617    pub struct MINIDUMP_MISC_INFO {
1618        pub size_of_info: u32,
1619        pub flags1: u32,
1620        pub process_id: u32,
1621        pub process_create_time: u32,
1622        pub process_user_time: u32,
1623        pub process_kernel_time: u32,
1624    }
1625    // Includes fields from MINIDUMP_MISC_INFO
1626    /// Miscellaneous process and system information
1627    ///
1628    /// This struct matches the [Microsoft struct][msdn] of the same name.
1629    ///
1630    /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_misc_info_2
1631    pub struct MINIDUMP_MISC_INFO_2 {
1632        pub processor_max_mhz: u32,
1633        pub processor_current_mhz: u32,
1634        pub processor_mhz_limit: u32,
1635        pub processor_max_idle_state: u32,
1636        pub processor_current_idle_state: u32,
1637    }
1638    // Includes fields from MINIDUMP_MISC_INFO and MINIDUMP_MISC_INFO_2
1639    /// Miscellaneous process and system information
1640    ///
1641    /// This struct matches the struct of the same name from minidumpapiset.h.
1642    pub struct MINIDUMP_MISC_INFO_3 {
1643        pub process_integrity_level: u32,
1644        pub process_execute_flags: u32,
1645        pub protected_process: u32,
1646        pub time_zone_id: u32,
1647        pub time_zone: TIME_ZONE_INFORMATION,
1648    }
1649    // Includes fields from MINIDUMP_MISC_INFO..3
1650    /// Miscellaneous process and system information
1651    ///
1652    /// This struct matches the struct of the same name from minidumpapiset.h.
1653    pub struct MINIDUMP_MISC_INFO_4 {
1654        pub build_string: [u16; 260], // MAX_PATH
1655        pub dbg_bld_str: [u16; 40],
1656    }
1657
1658    // Includes fields from MINIDUMP_MISC_INFO..4
1659    /// Miscellaneous process and system information
1660    ///
1661    /// This struct matches the struct of the same name from minidumpapiset.h.
1662    pub struct MINIDUMP_MISC_INFO_5 {
1663        pub xstate_data: XSTATE_CONFIG_FEATURE_MSC_INFO,
1664        pub process_cookie: u32,
1665    }
1666}
1667
1668/// A descriptor of the XSAVE context, which extends a normal x86/x64 context.
1669///
1670/// The sections of this context are dumps of some of the CPUs registers
1671/// (e.g. one section might contain the contents of the SSE registers).
1672///
1673/// Intel documents its XSAVE entries in Volume 1, Chapter 13 of the
1674/// "Intel 64 and IA-32 Architectures Software Developer’s Manual".
1675///
1676///
1677/// # The XSTATE Format in Minidumps
1678///
1679/// This format is slightly messed up in the context of minidumps because it's
1680/// grafted onto Microsoft's own formats. Here's what's important to know:
1681///
1682/// * The "Cpu Context" and the "XSAVE context" are in fact the same regions
1683///   of memory.
1684///
1685/// * Whether XSTATE is present or not, the classic layouts of CONTEXT_X86
1686///   and [`CONTEXT_AMD64`] both apply -- xstate will only add stuff after *or*
1687///   refine your understanding of memory in the existing layout. So you can
1688///   safely ignore the existence of XSTATE, but you might be missing new info.
1689///
1690/// * AMD64 doesn't have a standard way to save general purpose registers,
1691///   so the first 256 bytes of [`CONTEXT_AMD64`] are just however microsoft
1692///   decided to save the registers, and will not be referred to by the XSTATE.
1693///
1694/// **!!! THIS PART IS IMPORTANT !!!**
1695///
1696/// * As a consequence, all [`XSTATE_FEATURE::offset`] values must have 256
1697///   added to them to get the correct offset for that feature! For example, the
1698///   LEGACY_FLOATING_POINT feature should always have an offset of 0, but it
1699///   is actually at offset 256 in [`CONTEXT_AMD64`] (it corresponds to
1700///   [`CONTEXT_AMD64::float_save`]).
1701///
1702/// * The following features are already contained inside of [`CONTEXT_AMD64`]:
1703///    * LEGACY_FLOATING_POINT
1704///    * LEGACY_SSE
1705///    * GSSE_AND_AVX
1706///
1707/// * If there are XSTATE entries that *actually* map outside of the context's
1708///   normal memory range, then the context's [`context_flags`](`CONTEXT_AMD64::context_flags`)
1709///   will have bit 0x40 set ([`CONTEXT_HAS_XSTATE`]).
1710///
1711/// * [`ContextFlagsCpu::from_flags`] will mask out the [`CONTEXT_HAS_XSTATE`] bit.
1712///   If you want to check for that bit, check the raw value of
1713///   [`context_flags`](`CONTEXT_AMD64::context_flags`).
1714
1715#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1716pub struct XSTATE_CONFIG_FEATURE_MSC_INFO {
1717    /// The size of this struct.
1718    pub size_of_info: u32,
1719    /// The size of the XSAVE context.
1720    pub context_size: u32,
1721    /// The bit `enabled_features[i]` indicates that `features[i]` contains valid data.
1722    pub enabled_features: u64,
1723    /// The offset and size of each XSAVE entry inside the XSAVE context.
1724    pub features: [XSTATE_FEATURE; 64],
1725}
1726
1727impl Default for XSTATE_CONFIG_FEATURE_MSC_INFO {
1728    fn default() -> Self {
1729        Self {
1730            size_of_info: std::mem::size_of::<XSTATE_CONFIG_FEATURE_MSC_INFO>() as u32,
1731            context_size: 0,
1732            enabled_features: 0,
1733            features: [XSTATE_FEATURE::default(); 64],
1734        }
1735    }
1736}
1737
1738impl XSTATE_CONFIG_FEATURE_MSC_INFO {
1739    /// Gets an iterator of all the enabled features.
1740    pub fn iter(&self) -> XstateFeatureIter<'_> {
1741        XstateFeatureIter { info: self, idx: 0 }
1742    }
1743}
1744
1745/// An iterator of all the enabled features in an XSTATE_CONFIG_FEATURE_MSC_INFO.
1746#[derive(Debug)]
1747pub struct XstateFeatureIter<'a> {
1748    info: &'a XSTATE_CONFIG_FEATURE_MSC_INFO,
1749    idx: usize,
1750}
1751
1752impl Iterator for XstateFeatureIter<'_> {
1753    type Item = (usize, XSTATE_FEATURE);
1754    fn next(&mut self) -> Option<Self::Item> {
1755        while self.idx < self.info.features.len() {
1756            let cur_idx = self.idx;
1757            self.idx += 1;
1758            if (self.info.enabled_features & (1 << cur_idx)) != 0 {
1759                return Some((cur_idx, self.info.features[cur_idx]));
1760            }
1761        }
1762        None
1763    }
1764}
1765
1766/// Several known entries in `XSTATE_CONFIG_FEATURE_MSC_INFO.features`.
1767#[repr(usize)]
1768#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1769pub enum XstateFeatureIndex {
1770    LEGACY_FLOATING_POINT = 0,
1771    LEGACY_SSE = 1,
1772    GSSE_AND_AVX = 2,
1773    MPX_BNDREGS = 3,
1774    MPX_BNDCSR = 4,
1775    AVX512_KMASK = 5,
1776    AVX512_ZMM_H = 6,
1777    ACK512_ZMM = 7,
1778    XSTATE_IPT = 8,
1779    XSTATE_LWP = 62,
1780}
1781
1782impl XstateFeatureIndex {
1783    pub fn from_index(idx: usize) -> Option<Self> {
1784        use XstateFeatureIndex::*;
1785        match idx {
1786            0 => Some(LEGACY_FLOATING_POINT),
1787            1 => Some(LEGACY_SSE),
1788            2 => Some(GSSE_AND_AVX),
1789            3 => Some(MPX_BNDREGS),
1790            4 => Some(MPX_BNDCSR),
1791            5 => Some(AVX512_KMASK),
1792            6 => Some(AVX512_ZMM_H),
1793            7 => Some(ACK512_ZMM),
1794            8 => Some(XSTATE_IPT),
1795            62 => Some(XSTATE_LWP),
1796            _ => None,
1797        }
1798    }
1799}
1800
1801/// The offset and size of each XSAVE entry inside the XSAVE context.
1802#[derive(Clone, Copy, Debug, Default, Pread, Pwrite, SizeWith, PartialEq, Eq)]
1803pub struct XSTATE_FEATURE {
1804    /// This entry's offset from the start of the context (in bytes).
1805    ///
1806    /// NOTE: THIS VALUE IS A LIE. At least on AMD64 you need to add 256
1807    /// to this! See the docs of [`XSTATE_CONFIG_FEATURE_MSC_INFO`].
1808    pub offset: u32,
1809    /// This entry's size (in bytes).
1810    pub size: u32,
1811}
1812
1813// For whatever reason Pread array derives use 0u8.into() instead of Default to
1814// create an initial array to write into. Weird.
1815impl From<u8> for XSTATE_FEATURE {
1816    fn from(_input: u8) -> Self {
1817        XSTATE_FEATURE { offset: 0, size: 0 }
1818    }
1819}
1820
1821bitflags! {
1822    /// Known flags for `MINIDUMP_MISC_INFO*.flags1`
1823    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1824    pub struct MiscInfoFlags: u32 {
1825        const MINIDUMP_MISC1_PROCESS_ID            = 0x00000001;
1826        const MINIDUMP_MISC1_PROCESS_TIMES         = 0x00000002;
1827        const MINIDUMP_MISC1_PROCESSOR_POWER_INFO  = 0x00000004;
1828        const MINIDUMP_MISC3_PROCESS_INTEGRITY     = 0x00000010;
1829        const MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS = 0x00000020;
1830        const MINIDUMP_MISC3_TIMEZONE              = 0x00000040;
1831        const MINIDUMP_MISC3_PROTECTED_PROCESS     = 0x00000080;
1832        const MINIDUMP_MISC4_BUILDSTRING           = 0x00000100;
1833        const MINIDUMP_MISC5_PROCESS_COOKIE        = 0x00000200;
1834    }
1835}
1836
1837/// A list of memory regions in a minidump
1838///
1839/// This is the format of the [`MINIDUMP_STREAM_TYPE::MemoryInfoListStream`]. The individual
1840/// [`MINIDUMP_MEMORY_INFO`] entries follow this header in the stream.
1841///
1842/// This struct matches the [Microsoft struct][msdn] of the same name.
1843///
1844/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info_list
1845#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1846pub struct MINIDUMP_MEMORY_INFO_LIST {
1847    /// The size of this header
1848    pub size_of_header: u32,
1849    /// The size of each entry in the list
1850    pub size_of_entry: u32,
1851    /// The number of entries in the list
1852    pub number_of_entries: u64,
1853}
1854
1855/// Information about a memory region in a minidump
1856///
1857/// This struct matches the [Microsoft struct][msdn] of the same name.
1858///
1859/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info
1860#[derive(Debug, Clone, PartialEq, Eq, Pread, Pwrite, SizeWith)]
1861pub struct MINIDUMP_MEMORY_INFO {
1862    /// The base address of the region of pages
1863    pub base_address: u64,
1864    /// The base address of a range of pages in this region
1865    pub allocation_base: u64,
1866    /// The memory protection when the region was initially allocated
1867    ///
1868    /// See [`MemoryProtection`] for valid values.
1869    pub allocation_protection: u32,
1870    pub __alignment1: u32,
1871    /// The size of the region in which all pages have identical attributes, in bytes
1872    pub region_size: u64,
1873    /// The state of the pages in the region
1874    ///
1875    /// See [`MemoryState`] for valid values.
1876    pub state: u32,
1877    /// The access protection of the pages in the region
1878    ///
1879    /// See [`MemoryProtection`] for valid values.
1880    pub protection: u32,
1881    /// The type of pages in the region
1882    ///
1883    /// See [`MemoryType`] for valid values.
1884    pub _type: u32,
1885    pub __alignment2: u32,
1886}
1887
1888bitflags! {
1889    /// Potential values for [`MINIDUMP_MEMORY_INFO::state`]
1890    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1891    pub struct MemoryState: u32 {
1892        const MEM_COMMIT  = 0x01000;
1893        const MEM_FREE    = 0x10000;
1894        const MEM_RESERVE = 0x02000;
1895    }
1896}
1897
1898bitflags! {
1899    /// Potential values for [`MINIDUMP_MEMORY_INFO::protection`] and `allocation_protection`
1900    ///
1901    /// See [Microsoft's documentation][msdn] for details.
1902    ///
1903    /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants
1904    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1905    pub struct MemoryProtection: u32 {
1906        const PAGE_NOACCESS           = 0x01;
1907        const PAGE_READONLY           = 0x02;
1908        const PAGE_READWRITE          = 0x04;
1909        const PAGE_WRITECOPY          = 0x08;
1910        const PAGE_EXECUTE            = 0x10;
1911        const PAGE_EXECUTE_READ       = 0x20;
1912        const PAGE_EXECUTE_READWRITE  = 0x40;
1913        const PAGE_EXECUTE_WRITECOPY  = 0x80;
1914        const ACCESS_MASK             = 0xff;
1915        const PAGE_GUARD              = 0x100;
1916        const PAGE_NOCACHE            = 0x200;
1917        const PAGE_WRITECOMBINE       = 0x400;
1918    }
1919}
1920
1921bitflags! {
1922    /// Potential values for [`MINIDUMP_MEMORY_INFO::_type`]
1923    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1924    pub struct MemoryType: u32 {
1925        const MEM_PRIVATE = 0x00020000;
1926        const MEM_MAPPED  = 0x00040000;
1927        const MEM_IMAGE   = 0x01000000;
1928    }
1929}
1930
1931/// A Breakpad extension containing some additional process information
1932///
1933/// Taken from the definition in Breakpad's [minidump_format.h][fmt].
1934///
1935/// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#962
1936#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1937pub struct MINIDUMP_BREAKPAD_INFO {
1938    pub validity: u32,
1939    /// The Thread ID of the handler thread
1940    pub dump_thread_id: u32,
1941    /// The Thread ID of the thread that requested the dump
1942    pub requesting_thread_id: u32,
1943}
1944
1945bitflags! {
1946    /// Potential values for [`MINIDUMP_BREAKPAD_INFO::validity`]
1947    ///
1948    /// Taken from definitions in Breakpad's [minidump_format.h][fmt].
1949    ///
1950    /// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#989
1951    pub struct BreakpadInfoValid: u32 {
1952        const DumpThreadId       = 1 << 0;
1953        const RequestingThreadId = 1 << 1;
1954    }
1955}
1956
1957/// A Breakpad extension containing information about an assertion that terminated the process
1958///
1959/// Taken from the definition in Breakpad's [minidump_format.h][fmt].
1960///
1961/// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#998
1962#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1963pub struct MINIDUMP_ASSERTION_INFO {
1964    /// The assertion that failed, as a 0-terminated UTF16-LE string
1965    pub expression: [u16; 128],
1966    /// The function containing the assertion, as a 0-terminated UTF16-LE string
1967    pub function: [u16; 128],
1968    /// The source file containing the assertion, as a 0-terminated UTF16-LE string
1969    pub file: [u16; 128],
1970    /// The line number in [`file`] containing the assertion
1971    pub line: u32,
1972    /// The assertion type
1973    pub _type: u32,
1974}
1975
1976/// Known values of [`MINIDUMP_ASSERTION_INFO::_type`]
1977/// Taken from the definition in Breakpad's [minidump_format.h][fmt].
1978///
1979/// [fmt]: https://chromium.googlesource.com/breakpad/breakpad/+/88d8114fda3e4a7292654bd6ac0c34d6c88a8121/src/google_breakpad/common/minidump_format.h#1011
1980#[repr(u32)]
1981#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
1982pub enum AssertionType {
1983    Unknown = 0,
1984    InvalidParameter = 1,
1985    PureVirtualCall = 2,
1986}
1987
1988/// Dynamic linker information for a shared library on 32-bit Linux
1989///
1990/// This is functionally equivalent to the data in `struct link_map` defined in <link.h>.
1991#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
1992pub struct LINK_MAP_32 {
1993    pub addr: u32,
1994    /// The offset of a string containing the filename of this shared library
1995    pub name: RVA,
1996    pub ld: u32,
1997}
1998
1999/// DSO debug data for 32-bit Linux minidumps
2000///
2001/// Used when converting minidumps to coredumps. This is functionally equivalent to the data
2002/// in `struct r_debug` defined in <link.h>.
2003#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2004pub struct DSO_DEBUG_32 {
2005    /// The version number of this protocol, from `r_debug.r_version`
2006    pub version: u32,
2007    /// The offset of an array of [`LINK_MAP_32`] structs
2008    pub map: RVA,
2009    /// The number of [`LINK_MAP_32`] entries pointed to by `map`
2010    pub dso_count: u32,
2011    /// The address of a function internal to the run-time linker used by debuggers to
2012    /// set a breakpoint.
2013    pub brk: u32,
2014    /// Base address the linker is loaded at
2015    pub ldbase: u32,
2016    /// The address of the "dynamic structure"
2017    pub dynamic: u32,
2018}
2019
2020/// Dynamic linker information for a shared library on 64-bit Linux
2021///
2022/// This is functionally equivalent to the data in `struct link_map` defined in <link.h>.
2023#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2024pub struct LINK_MAP_64 {
2025    pub addr: u64,
2026    /// The offset of a string containing the filename of this shared library
2027    pub name: RVA,
2028    pub ld: u64,
2029}
2030
2031/// DSO debug data for 64-bit Linux minidumps
2032///
2033/// Used when converting minidumps to coredumps. This is functionally equivalent to the data
2034/// in `struct r_debug` defined in <link.h>.
2035#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2036pub struct DSO_DEBUG_64 {
2037    /// The version number of this protocol, from `r_debug.r_version`
2038    pub version: u32,
2039    /// The offset of an array of [`LINK_MAP_64`] structs
2040    pub map: RVA,
2041    /// The number of [`LINK_MAP_64`] entries pointed to by `map`
2042    pub dso_count: u32,
2043    /// The address of a function internal to the run-time linker used by debuggers to
2044    /// set a breakpoint.
2045    pub brk: u64,
2046    /// Base address the linker is loaded at
2047    pub ldbase: u64,
2048    /// The address of the "dynamic structure"
2049    pub dynamic: u64,
2050}
2051
2052/// A variable-length UTF-8-encoded string carried within a minidump file.
2053///
2054/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpUTF8String.html>
2055#[derive(Debug, Clone)]
2056pub struct MINIDUMP_UTF8_STRING {
2057    /// The length of the #Buffer field in bytes, not including the `NUL` terminator.
2058    ///
2059    /// This field is interpreted as a byte count, not a count of Unicode code points.
2060    pub length: u32,
2061    /// The string, encoded in UTF-8, and terminated with a `NUL` byte.
2062    pub buffer: Vec<u8>,
2063}
2064
2065impl scroll::ctx::TryFromCtx<'_, Endian> for MINIDUMP_UTF8_STRING {
2066    type Error = scroll::Error;
2067
2068    fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> {
2069        let offset = &mut 0;
2070        let length: u32 = src.gread_with(offset, endian)?;
2071        let data: &[u8] = src.gread_with(offset, length as usize + 1)?; // +1 for NUL
2072
2073        if !data.ends_with(&[0]) {
2074            return Err(scroll::Error::Custom(
2075                "Minidump String does not end with NUL byte".to_owned(),
2076            ));
2077        }
2078
2079        let buffer = data.to_vec();
2080        Ok((Self { length, buffer }, *offset))
2081    }
2082}
2083
2084/// A key-value pair.
2085///
2086/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpSimpleStringDictionaryEntry.html>
2087#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2088pub struct MINIDUMP_SIMPLE_STRING_DICTIONARY_ENTRY {
2089    /// RVA of a MinidumpUTF8String containing the key of a key-value pair.
2090    pub key: RVA,
2091    /// RVA of a MinidumpUTF8String containing the value of a key-value pair.
2092    pub value: RVA,
2093}
2094
2095/// A list of key-value pairs.
2096///
2097/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpSimpleStringDictionary.html>
2098#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2099pub struct MINIDUMP_SIMPLE_STRING_DICTIONARY {
2100    /// The number of key-value pairs present.
2101    pub count: u32,
2102}
2103
2104/// A list of RVA pointers.
2105///
2106/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpRVAList.html>
2107#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2108pub struct MINIDUMP_RVA_LIST {
2109    /// The number of pointers present.
2110    pub count: u32,
2111}
2112
2113/// A typed annotation object.
2114///
2115/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpAnnotation.html>
2116#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2117pub struct MINIDUMP_ANNOTATION {
2118    /// RVA of a MinidumpUTF8String containing the name of the annotation.
2119    pub name: RVA,
2120    /// The type of data stored in the `value` of the annotation. This may correspond to an \a
2121    /// `MINIDUMP_ANNOTATION_TYPE` or it may be user-defined.
2122    pub ty: u16,
2123    /// This field is always `0`.
2124    pub _reserved: u16,
2125    /// RVA of a `MinidumpByteArray` to the data for the annotation.
2126    pub value: RVA,
2127}
2128
2129impl MINIDUMP_ANNOTATION {
2130    /// An invalid annotation. Reserved for internal use.
2131    ///
2132    /// See <https://crashpad.chromium.org/doxygen/classcrashpad_1_1Annotation.html#a734ee64cd20afdb78acb8656ed867d34>
2133    pub const TYPE_INVALID: u16 = 0;
2134    /// A `NUL`-terminated C-string.
2135    ///
2136    /// See <https://crashpad.chromium.org/doxygen/classcrashpad_1_1Annotation.html#a734ee64cd20afdb78acb8656ed867d34>
2137    pub const TYPE_STRING: u16 = 1;
2138    /// Clients may declare their own custom types by using values greater than this.
2139    ///
2140    /// See <https://crashpad.chromium.org/doxygen/classcrashpad_1_1Annotation.html#a734ee64cd20afdb78acb8656ed867d34>
2141    pub const TYPE_USER_DEFINED: u16 = 0x8000;
2142}
2143
2144/// Additional Crashpad-specific information about a module carried within a minidump file.
2145///
2146/// This structure augments the information provided by MINIDUMP_MODULE. The minidump file must
2147/// contain a module list stream (::kMinidumpStreamTypeModuleList) in order for this structure to
2148/// appear.
2149///
2150/// This structure is versioned. When changing this structure, leave the existing structure intact
2151/// so that earlier parsers will be able to understand the fields they are aware of, and make
2152/// additions at the end of the structure. Revise #kVersion and document each field’s validity based
2153/// on #version, so that newer parsers will be able to determine whether the added fields are valid
2154/// or not.
2155///
2156/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpModuleCrashpadInfo.html>
2157#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2158pub struct MINIDUMP_MODULE_CRASHPAD_INFO {
2159    /// The structure’s version number.
2160    ///
2161    /// Readers can use this field to determine which other fields in the structure are valid. Upon
2162    /// encountering a value greater than `VERSION`, a reader should assume that the structure’s
2163    /// layout is compatible with the structure defined as having value #kVersion.
2164    ///
2165    /// Writers may produce values less than `VERSION` in this field if there is no need for any
2166    /// fields present in later versions.
2167    pub version: u32,
2168    /// A `MinidumpRVAList` pointing to MinidumpUTF8String objects. The module controls the data
2169    /// that appears here.
2170    ///
2171    /// These strings correspond to `ModuleSnapshot::AnnotationsVector()` and do not duplicate
2172    /// anything in `simple_annotations` or `annotation_objects`.
2173    pub list_annotations: MINIDUMP_LOCATION_DESCRIPTOR,
2174    /// A `MinidumpSimpleStringDictionary` pointing to strings interpreted as key-value pairs. The
2175    /// module controls the data that appears here.
2176    ///
2177    /// These key-value pairs correspond to `ModuleSnapshot::AnnotationsSimpleMap()` and do not
2178    /// duplicate anything in `list_annotations` or `annotation_objects`.
2179    pub simple_annotations: MINIDUMP_LOCATION_DESCRIPTOR,
2180    /// A `MinidumpAnnotationList` object containing the annotation objects stored within the
2181    /// module. The module controls the data that appears here.
2182    ///
2183    /// These key-value pairs correspond to `ModuleSnapshot::AnnotationObjects()` and do not
2184    /// duplicate anything in `list_annotations` or `simple_annotations`.
2185    pub annotation_objects: MINIDUMP_LOCATION_DESCRIPTOR,
2186}
2187
2188impl MINIDUMP_MODULE_CRASHPAD_INFO {
2189    /// The structure’s version number.
2190    ///
2191    /// Readers can use this field to determine which other fields in the structure are valid. Upon
2192    /// encountering a value greater than `VERSION`, a reader should assume that the structure’s
2193    /// layout is compatible with the structure defined as having value #kVersion.
2194    ///
2195    /// Writers may produce values less than `VERSION` in this field if there is no need for any
2196    /// fields present in later versions.
2197    pub const VERSION: u32 = 1;
2198}
2199
2200/// A link between a `MINIDUMP_MODULE` structure and additional Crashpad-specific information about a
2201/// module carried within a minidump file.
2202///
2203/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpModuleCrashpadInfoLink.html>
2204#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2205pub struct MINIDUMP_MODULE_CRASHPAD_INFO_LINK {
2206    /// A link to a MINIDUMP_MODULE structure in the module list stream.
2207    ///
2208    /// This field is an index into `MINIDUMP_MODULE_LIST::Modules`. This field’s value must be in
2209    /// the range of `MINIDUMP_MODULE_LIST::NumberOfEntries`.
2210    pub minidump_module_list_index: u32,
2211
2212    /// A link to a MinidumpModuleCrashpadInfo structure.
2213    ///
2214    /// MinidumpModuleCrashpadInfo structures are accessed indirectly through
2215    /// `MINIDUMP_LOCATION_DESCRIPTOR` pointers to allow for future growth of the
2216    /// `MinidumpModuleCrashpadInfo` structure.
2217    pub location: MINIDUMP_LOCATION_DESCRIPTOR,
2218}
2219
2220/// Additional Crashpad-specific information about modules carried within a minidump file.
2221///
2222/// This structure augments the information provided by `MINIDUMP_MODULE_LIST`. The minidump file
2223/// must contain a module list stream (::kMinidumpStreamTypeModuleList) in order for this structure
2224/// to appear.
2225///
2226/// `MinidumpModuleCrashpadInfoList::count` may be less than the value of
2227/// `MINIDUMP_MODULE_LIST::NumberOfModules` because not every `MINIDUMP_MODULE` structure carried
2228/// within the minidump file will necessarily have Crashpad-specific information provided by a
2229/// `MinidumpModuleCrashpadInfo` structure.
2230///
2231/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpModuleCrashpadInfoList.html>
2232#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2233pub struct MINIDUMP_MODULE_CRASHPAD_INFO_LIST {
2234    /// The number of key-value pairs present.
2235    pub count: u32,
2236}
2237
2238/// Additional Crashpad-specific information carried within a minidump file.
2239///
2240/// This structure is versioned. When changing this structure, leave the existing structure intact
2241/// so that earlier parsers will be able to understand the fields they are aware of, and make
2242/// additions at the end of the structure. Revise #kVersion and document each field’s validity based
2243/// on `version`, so that newer parsers will be able to determine whether the added fields are valid
2244/// or not.
2245///
2246/// See <https://crashpad.chromium.org/doxygen/structcrashpad_1_1MinidumpCrashpadInfo.html>
2247#[derive(Clone, Debug, Pread, Pwrite, SizeWith)]
2248pub struct MINIDUMP_CRASHPAD_INFO {
2249    /// The structure’s version number.
2250    ///
2251    /// Readers can use this field to determine which other fields in the structure are valid. Upon
2252    /// encountering a value greater than `VERSION`, a reader should assume that the structure’s
2253    /// layout is compatible with the structure defined as having value #kVersion.
2254    ///
2255    /// Writers may produce values less than `VERSION` in this field if there is no need for any
2256    /// fields present in later versions.
2257    pub version: u32,
2258    /// A `Uuid` identifying an individual crash report.
2259    ///
2260    /// This provides a stable identifier for a crash even as the report is converted to different
2261    /// formats, provided that all formats support storing a crash report ID.
2262    ///
2263    /// If no identifier is available, this field will contain zeroes.
2264    pub report_id: GUID,
2265    /// A `Uuid` identifying the client that crashed.
2266    ///
2267    /// Client identification is within the scope of the application, but it is expected that the
2268    /// identifier will be unique for an instance of Crashpad monitoring an application or set of
2269    /// applications for a user. The identifier shall remain stable over time.
2270    ///
2271    /// If no identifier is available, this field will contain zeroes.
2272    pub client_id: GUID,
2273    /// A MinidumpSimpleStringDictionary pointing to strings interpreted as key-value pairs.
2274    ///
2275    /// These key-value pairs correspond to Crashpad's `ProcessSnapshot::AnnotationsSimpleMap()`.
2276    pub simple_annotations: MINIDUMP_LOCATION_DESCRIPTOR,
2277    /// A pointer to a MinidumpModuleCrashpadInfoList structure.
2278    pub module_list: MINIDUMP_LOCATION_DESCRIPTOR,
2279}
2280
2281impl MINIDUMP_CRASHPAD_INFO {
2282    /// The structure’s currently-defined version number.
2283    pub const VERSION: u32 = 1;
2284}
2285
2286/// MacOS __DATA,__crash_info data.
2287///
2288/// This is the format of the [`MINIDUMP_STREAM_TYPE::MozMacosCrashInfoStream`]. The individual
2289/// [`MINIDUMP_MAC_CRASH_INFO_RECORD`] entries follow this header in the stream.
2290#[derive(Debug, Pread, Pwrite, SizeWith)]
2291pub struct MINIDUMP_MAC_CRASH_INFO {
2292    pub stream_type: u32,
2293    /// The number of [`MINIDUMP_MAC_CRASH_INFO_RECORD`]s.
2294    pub record_count: u32,
2295    /// The size of the "fixed-size" part of MINIDUMP_MAC_CRASH_INFO_RECORD.
2296    /// Used to offset to the variable-length portion of the struct, where
2297    /// C-strings are stored. This allows us to access all the fields we know
2298    /// about, even when newer versions of this format introduce new ones.
2299    pub record_start_size: u32,
2300    pub records: [MINIDUMP_LOCATION_DESCRIPTOR; 20],
2301}
2302
2303// MozMacosCrashInfoStream is a versioned format where new fields are added to
2304// the end of the struct, but there are also variable-length c-string fields
2305// that follow the "fixed-size" fields. As such, the versioned strings are separated
2306// out into their own separate struct with the same version. So e.g.
2307//
2308// MINIDUMP_MAC_CRASH_INFO_RECORD_4 should be paired with MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4
2309
2310multi_structs! {
2311    /// Contents of MacOS's `<CrashReporterClient.h>`'s `crashreporter_annotations_t`,
2312    /// but with the by-reference C-strings hoisted out to the end of the struct
2313    /// and inlined (so this is a variable-length struct).
2314    ///
2315    /// The variable-length strings are listed in [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS`].
2316    /// Use [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] to access them.
2317    pub struct MINIDUMP_MAC_CRASH_INFO_RECORD {
2318      pub stream_type: u64,
2319      // Version of this format, currently at 5.
2320      //
2321      // Although theoretically this field being here means we can support multiple
2322      // versions of this struct in one [`MINIDUMP_MAC_CRASH_INFO`] stream, our reliance on
2323      // [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] means we can't actually handle
2324      // such a heterogeneous situation. So all records should have the same version value.
2325      pub version: u64,
2326    }
2327    // Includes fields from MINIDUMP_MAC_CRASH_INFO_RECORD
2328    /// Contents of MacOS's `<CrashReporterClient.h>`'s `crashreporter_annotations_t`,
2329    /// but with the by-reference C-strings hoisted out to the end of the struct
2330    /// and inlined (so this is a variable-length struct).
2331    ///
2332    /// The variable-length strings are listed in [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4`].
2333    /// Use [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] to access them.
2334    pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_4 {
2335        pub thread: u64,
2336        pub dialog_mode: u64,
2337    }
2338    // Includes fields from MINIDUMP_MAC_CRASH_INFO_RECORD and MINIDUMP_MAC_CRASH_INFO_RECORD_4
2339    /// Contents of MacOS's `<CrashReporterClient.h>`'s `crashreporter_annotations_t`,
2340    /// but with the by-reference C-strings hoisted out to the end of the struct
2341    /// and inlined (so this is a variable-length struct).
2342    ///
2343    /// The variable-length strings are listed in [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_5`].
2344    /// Use [`MINIDUMP_MAC_CRASH_INFO::record_start_size`] to access them.
2345    pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_5 {
2346        pub abort_cause: u64,
2347    }
2348}
2349
2350macro_rules! replace_expr {
2351    ($_t:tt $sub:expr) => {
2352        $sub
2353    };
2354}
2355
2356macro_rules! count_tts {
2357    ($($tts:tt)*) => {0usize $(+ replace_expr!($tts 1usize))*};
2358}
2359
2360// Like multi_structs but specialized for a struct of strings that can be set by index.
2361macro_rules! multi_strings {
2362    // With no trailing struct left, terminate.
2363    (@next { $($prev:tt)* }) => {};
2364    // Declare the next struct, including fields from previous structs.
2365    (@next { $($prev:tt)* } $(#[$attr:meta])* pub struct $name:ident { $($cur:tt)* } $($tail:tt)* ) => {
2366        // Prepend fields from previous structs to this struct.
2367        multi_strings!($(#[$attr])* pub struct $name { $($prev)* $($cur)* } $($tail)*);
2368    };
2369    // Declare a single struct.
2370    ($(#[$attr:meta])* pub struct $name:ident { $( pub $field:ident: $t:tt, )* } $($tail:tt)* ) => {
2371        $(#[$attr])*
2372        #[derive(Default, Debug, Clone)]
2373        pub struct $name {
2374            $( pub $field: $t, )*
2375        }
2376
2377        impl $name {
2378            pub fn num_strings() -> usize {
2379                count_tts!($($t)*)
2380            }
2381
2382            #[allow(unused_variables, unused_mut)]
2383            pub fn set_string(&mut self, idx: usize, string: String) {
2384                let mut cur_idx = 0;
2385                $(if cur_idx == idx {
2386                    self.$field = string;
2387                    return;
2388                }
2389                cur_idx += 1;
2390                )*
2391                panic!("string index out of bounds {} >= {}", idx, cur_idx);
2392            }
2393        }
2394
2395        // Persist its fields down to the following structs.
2396        multi_strings!(@next { $( pub $field: $t, )* } $($tail)*);
2397    };
2398}
2399
2400multi_strings! {
2401    /// Variable-length data for [`MINIDUMP_MAC_CRASH_INFO_RECORD`].
2402    pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS {
2403        // No strings in the base version
2404    }
2405
2406    // Includes fields from [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS`]
2407    /// Variable-length data for [`MINIDUMP_MAC_CRASH_INFO_RECORD_4`].
2408    pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4 {
2409        pub module_path: String,
2410        pub message: String,
2411        pub signature_string: String,
2412        pub backtrace: String,
2413        pub message2: String,
2414    }
2415
2416    // Includes fields from [`MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_4`]
2417    /// Variable-length data for [`MINIDUMP_MAC_CRASH_INFO_RECORD_5`].
2418    pub struct MINIDUMP_MAC_CRASH_INFO_RECORD_STRINGS_5 {
2419        // No new strings
2420    }
2421}
2422
2423/// The maximum supported size of a C-string in [`MINIDUMP_MAC_CRASH_INFO_RECORD`].
2424///
2425/// Assume the stream is corrupted if a string is longer than this.
2426pub const MAC_CRASH_INFO_STRING_MAX_SIZE: usize = 8192;
2427
2428/// The maximum supported count of [`MINIDUMP_MAC_CRASH_INFO_RECORD`]s.
2429///
2430/// In principle there should only be one or two non-empty __DATA,__crash_info
2431/// sections per process. But the __crash_info section is almost entirely
2432/// undocumented, so just in case we set a large maximum.
2433pub const MAC_CRASH_INFOS_MAX: usize = 20;
2434
2435/// MacOS kernel boot args
2436#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2437pub struct MINIDUMP_MAC_BOOTARGS {
2438    pub stream_type: u32,
2439    pub bootargs: RVA64,
2440}
2441
2442bitflags! {
2443    /// Possible values of [`ARMCpuInfo::elf_hwcaps`]
2444    ///
2445    /// This matches the Linux kernel definitions from [<asm/hwcaps.h>][hwcap].
2446    ///
2447    /// [hwcap]: https://elixir.bootlin.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
2448    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2449    pub struct ArmElfHwCaps: u32 {
2450        const HWCAP_SWP       = (1 << 0);
2451        const HWCAP_HALF      = (1 << 1);
2452        const HWCAP_THUMB     = (1 << 2);
2453        const HWCAP_26BIT     = (1 << 3);
2454        const HWCAP_FAST_MULT = (1 << 4);
2455        const HWCAP_FPA       = (1 << 5);
2456        const HWCAP_VFP       = (1 << 6);
2457        const HWCAP_EDSP      = (1 << 7);
2458        const HWCAP_JAVA      = (1 << 8);
2459        const HWCAP_IWMMXT    = (1 << 9);
2460        const HWCAP_CRUNCH    = (1 << 10);
2461        const HWCAP_THUMBEE   = (1 << 11);
2462        const HWCAP_NEON      = (1 << 12);
2463        const HWCAP_VFPv3     = (1 << 13);
2464        const HWCAP_VFPv3D16  = (1 << 14);
2465        const HWCAP_TLS       = (1 << 15);
2466        const HWCAP_VFPv4     = (1 << 16);
2467        const HWCAP_IDIVA     = (1 << 17);
2468        const HWCAP_IDIVT     = (1 << 18);
2469        const HWCAP_VFPD32    = (1 << 19);
2470        const HWCAP_IDIV      = ArmElfHwCaps::HWCAP_IDIVA.bits() | Self::HWCAP_IDIVT.bits();
2471        const HWCAP_LPAE      = (1 << 20);
2472        const HWCAP_EVTSTRM   = (1 << 21);
2473    }
2474}
2475
2476#[repr(u32)]
2477#[derive(Copy, Clone, PartialEq, Eq, Debug, FromPrimitive)]
2478pub enum MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE {
2479    MiniHandleObjectInformationNone,
2480    MiniThreadInformation1,
2481    MiniMutantInformation1,
2482    MiniMutantInformation2,
2483    MiniProcessInformation1,
2484    MiniProcessInformation2,
2485    MiniEventInformation1,
2486    MiniSectionInformation1,
2487    MiniSemaphoreInformation1,
2488    MiniHandleObjectInformationTypeMax,
2489}
2490
2491/// OS-specific handle object information. Microsoft headers state that it can
2492/// change based on the target platform. The object is larger than this structure
2493/// (as specified by `size_of_info`) and the remaining data is stored after the
2494/// `size_of_info` field. The format of this information is not specified.
2495#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2496pub struct MINIDUMP_HANDLE_OBJECT_INFORMATION {
2497    /// RVA pointing to the next handle object information. Elements of this type
2498    /// are chained and the last one has this field set to 0.
2499    pub next_info_rva: RVA,
2500    /// Type of this handle object information element, see [`MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE`]
2501    pub info_type: u32,
2502    /// Size of this element, this must be larger than `size_of::<MINIDUMP_HANDLE_OBJECT_INFORMATION>()`
2503    pub size_of_info: u32,
2504}
2505
2506#[derive(Debug, Default, Clone, Pread, Pwrite, SizeWith)]
2507pub struct MINIDUMP_HANDLE_DESCRIPTOR {
2508    /// The operating system handle value. A HANDLE on Windows and file descriptor number on Linux.
2509    pub handle: u64,
2510    /// An RVA to a `MINIDUMP_STRING` structure that specifies the object type of the handle.
2511    /// This member can be zero.
2512    pub type_name_rva: RVA,
2513    /// An RVA to a `MINIDUMP_STRING` structure that specifies the object name of the handle.
2514    /// This member can be zero.
2515    pub object_name_rva: RVA,
2516    /// The meaning of this member depends on the handle type and the operating system.
2517    pub attributes: u32,
2518    /// The meaning of this member depends on the handle type and the operating system.
2519    pub granted_access: u32,
2520    /// The meaning of this member depends on the handle type and the operating system.
2521    pub handle_count: u32,
2522    /// The meaning of this member depends on the handle type and the operating system.
2523    pub pointer_count: u32,
2524}
2525
2526#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2527pub struct MINIDUMP_HANDLE_DESCRIPTOR_2 {
2528    /// The operating system handle value. A HANDLE on Windows and file descriptor number on Linux.
2529    pub handle: u64,
2530    /// An RVA to a `MINIDUMP_STRING` structure that specifies the object type of the handle.
2531    /// This member can be zero.
2532    pub type_name_rva: RVA,
2533    /// An RVA to a `MINIDUMP_STRING` structure that specifies the object name of the handle.
2534    /// This member can be zero.
2535    pub object_name_rva: RVA,
2536    /// The meaning of this member depends on the handle type and the operating system.
2537    pub attributes: u32,
2538    /// The meaning of this member depends on the handle type and the operating system.
2539    pub granted_access: u32,
2540    /// The meaning of this member depends on the handle type and the operating system.
2541    pub handle_count: u32,
2542    /// The meaning of this member depends on the handle type and the operating system.
2543    pub pointer_count: u32,
2544    /// An RVA to a [`MINIDUMP_HANDLE_OBJECT_INFORMATION`] structure that specifies object-specific information.
2545    /// This member can be 0 if there is no extra information.
2546    pub object_info_rva: RVA,
2547    /// Reserved for future use; must be zero.
2548    reserved0: u32,
2549}
2550
2551#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2552pub struct MINIDUMP_HANDLE_DATA_STREAM {
2553    /// The size of this header, in bytes.
2554    pub size_of_header: u32,
2555    /// The size of each descriptor in the stream, in bytes.
2556    pub size_of_descriptor: u32,
2557    /// The number of descriptors in the stream.
2558    pub number_of_descriptors: u32,
2559    /// Reserved for future use; must be zero.
2560    pub reserved: u32,
2561}
2562
2563#[derive(Debug, Clone, Pread, Pwrite, SizeWith)]
2564pub struct MINIDUMP_THREAD_INFO {
2565    /// Thread identifier
2566    pub thread_id: u32,
2567    /// Thread state flags
2568    pub dump_flags: u32,
2569    /// HRESULT value of dump status
2570    pub dump_error: u32,
2571    /// The thread's exit code
2572    pub exit_status: u32,
2573    /// UTC time the thread was created
2574    pub create_time: u64,
2575    /// UTC time the thread exited
2576    pub exit_time: u64,
2577    /// Time executed in kernel mode
2578    pub kernel_time: u64,
2579    /// Time executed in user mode
2580    pub user_time: u64,
2581    /// Start address of the thread
2582    pub start_address: u64,
2583    /// Processor affinity mask
2584    pub affinity: u64,
2585}