1use std::collections::BTreeMap;
4use std::fmt::Debug;
5
6use crate::error::{Error, Result};
7use crate::gxa::Gpa;
8
9pub unsafe trait Pod {}
26
27unsafe impl Pod for u64 {}
28unsafe impl Pod for u32 {}
29unsafe impl Pod for u16 {}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum PageKind {
34 Normal,
36 Large,
38 Huge,
40}
41
42impl PageKind {
43 #[must_use]
45 pub fn size(&self) -> u64 {
46 match self {
47 Self::Normal => 4 * 1_024,
48 Self::Large => 2 * 1_024 * 1_024,
49 Self::Huge => 1_024 * 1_024 * 1_024,
50 }
51 }
52
53 #[must_use]
55 pub fn page_offset(&self, addr: u64) -> u64 {
56 let mask = self.size() - 1;
57
58 addr & mask
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq)]
64#[repr(u32)]
65pub enum DumpType {
66 Full = 0x1,
68 Bmp = 0x5,
69 LiveKernelMemory = 0x6,
73 KernelMemory = 0x8,
75 KernelAndUserMemory = 0x9,
77 CompleteMemory = 0xa,
79}
80
81pub type PhysmemMap = BTreeMap<Gpa, u64>;
83
84impl TryFrom<u32> for DumpType {
85 type Error = Error;
86
87 fn try_from(value: u32) -> Result<Self> {
88 match value {
89 x if x == DumpType::Full as u32 => Ok(DumpType::Full),
90 x if x == DumpType::Bmp as u32 => Ok(DumpType::Bmp),
91 x if x == DumpType::KernelMemory as u32 => Ok(DumpType::KernelMemory),
92 x if x == DumpType::KernelAndUserMemory as u32 => Ok(DumpType::KernelAndUserMemory),
93 x if x == DumpType::CompleteMemory as u32 => Ok(DumpType::CompleteMemory),
94 x if x == DumpType::LiveKernelMemory as u32 => Ok(DumpType::LiveKernelMemory),
95 _ => Err(Error::UnknownDumpType(value)),
96 }
97 }
98}
99
100#[repr(C)]
101#[derive(Debug, Default)]
102pub struct ExceptionRecord64 {
103 pub exception_code: u32,
104 pub exception_flags: u32,
105 pub exception_record: u64,
106 pub exception_address: u64,
107 pub number_parameters: u32,
108 unused_alignment1: u32,
109 pub exception_information: [u64; 15],
110}
111
112pub const DUMP_HEADER64_EXPECTED_SIGNATURE: u32 = 0x45_47_41_50; pub const DUMP_HEADER64_EXPECTED_VALID_DUMP: u32 = 0x34_36_55_44; #[repr(C)]
119pub struct Header64 {
120 pub signature: u32,
121 pub valid_dump: u32,
122 pub major_version: u32,
123 pub minor_version: u32,
124 pub directory_table_base: u64,
125 pub pfn_database: u64,
126 pub ps_loaded_module_list: u64,
127 pub ps_active_process_head: u64,
128 pub machine_image_type: u32,
129 pub number_processors: u32,
130 pub bug_check_code: u32,
131 padding1: u32,
132 pub bug_check_code_parameters: [u64; 4],
133 pub version_user: [u8; 32],
134 pub kd_debugger_data_block: u64,
135 pub physical_memory_block_buffer: [u8; 700],
136 padding2: u32,
137 pub context_record_buffer: [u8; 3_000],
138 pub exception: ExceptionRecord64,
139 pub dump_type: u32,
140 padding3: u32,
141 pub required_dump_space: i64,
142 pub system_time: i64,
143 pub comment: [u8; 128],
144 pub system_up_time: i64,
145 pub minidump_fields: u32,
146 pub secondary_data_state: u32,
147 pub product_type: u32,
148 pub suite_mask: u32,
149 pub writer_status: u32,
150 unused1: u8,
151 pub kd_secondary_version: u8,
152 unused2: [u8; 2],
153 pub attributes: u32,
154 pub boot_id: u32,
155 reserved1: [u8; 4008],
156}
157
158unsafe impl Pod for Header64 {}
159
160impl Debug for Header64 {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 f.debug_struct("Header64")
163 .field("signature", &self.signature)
164 .field("valid_dump", &self.valid_dump)
165 .field("major_version", &self.major_version)
166 .field("minor_version", &self.minor_version)
167 .field("directory_table_base", &self.directory_table_base)
168 .field("pfn_database", &self.pfn_database)
169 .field("ps_loaded_module_list", &self.ps_loaded_module_list)
170 .field("ps_active_process_head", &self.ps_active_process_head)
171 .field("machine_image_type", &self.machine_image_type)
172 .field("number_processors", &self.number_processors)
173 .field("bug_check_code", &self.bug_check_code)
174 .field("bug_check_code_parameters", &self.bug_check_code_parameters)
175 .field("version_user", &self.version_user)
176 .field("kd_debugger_data_block", &self.kd_debugger_data_block)
177 .field("exception", &self.exception)
178 .field("dump_type", &self.dump_type)
179 .field("required_dump_space", &self.required_dump_space)
180 .field("system_time", &self.system_time)
181 .field("comment", &self.comment)
182 .field("system_up_time", &self.system_up_time)
183 .field("minidump_fields", &self.minidump_fields)
184 .field("secondary_data_state", &self.secondary_data_state)
185 .field("product_type", &self.product_type)
186 .field("suite_mask", &self.suite_mask)
187 .field("writer_status", &self.writer_status)
188 .field("kd_secondary_version", &self.kd_secondary_version)
189 .field("attributes", &self.attributes)
190 .field("boot_id", &self.boot_id)
191 .finish_non_exhaustive()
192 }
193}
194
195const BMPHEADER64_EXPECTED_SIGNATURE: u32 = 0x50_4D_44_53; const BMPHEADER64_EXPECTED_SIGNATURE2: u32 = 0x50_4D_44_46; const BMPHEADER64_EXPECTED_VALID_DUMP: u32 = 0x50_4D_55_44; #[derive(Debug, Default)]
200#[repr(C)]
201pub struct BmpHeader64 {
202 pub signature: u32,
203 pub valid_dump: u32,
204 padding1: [u8; 0x20 - (0x4 + size_of::<u32>())],
212 pub first_page: u64,
214 pub total_present_pages: u64,
216 pub pages: u64,
220 }
222
223unsafe impl Pod for BmpHeader64 {}
224
225impl BmpHeader64 {
226 #[must_use]
227 pub fn looks_good(&self) -> bool {
228 (self.signature == BMPHEADER64_EXPECTED_SIGNATURE
229 || self.signature == BMPHEADER64_EXPECTED_SIGNATURE2)
230 && self.valid_dump == BMPHEADER64_EXPECTED_VALID_DUMP
231 }
232}
233
234#[derive(Debug, Default)]
235#[repr(C)]
236pub struct PhysmemRun {
237 pub base_page: u64,
238 pub page_count: u64,
239}
240
241unsafe impl Pod for PhysmemRun {}
242
243impl PhysmemRun {
244 pub fn phys_addr(&self, page_idx: u64) -> Option<Gpa> {
248 debug_assert!(page_idx < self.page_count);
249
250 self.base_page
251 .checked_add(page_idx)?
252 .checked_mul(PageKind::Normal.size())
253 .map(Gpa::new)
254 }
255}
256
257#[derive(Debug, Default)]
258#[repr(C)]
259pub struct PhysmemDesc {
260 pub number_of_runs: u32,
261 padding1: u32,
262 pub number_of_pages: u64,
263 }
265
266unsafe impl Pod for PhysmemDesc {}
267
268impl TryFrom<&[u8]> for PhysmemDesc {
269 type Error = Error;
270
271 fn try_from(slice: &[u8]) -> Result<Self> {
272 let expected_len = size_of::<Self>();
273 if slice.len() < expected_len {
274 return Err(Error::InvalidData("physmem desc is too small"));
275 }
276
277 let number_of_runs = u32::from_le_bytes((&slice[0..4]).try_into().unwrap());
278 let number_of_pages = u64::from_le_bytes((&slice[4..12]).try_into().unwrap());
279
280 Ok(Self {
281 number_of_runs,
282 number_of_pages,
283 ..Default::default()
284 })
285 }
286}
287
288#[derive(PartialEq)]
289#[repr(C)]
290pub struct Context {
291 pub p1_home: u64,
292 pub p2_home: u64,
293 pub p3_home: u64,
294 pub p4_home: u64,
295 pub p5_home: u64,
296 pub p6_home: u64,
297 pub context_flags: u32,
298 pub mxcsr: u32,
299 pub seg_cs: u16,
300 pub seg_ds: u16,
301 pub seg_es: u16,
302 pub seg_fs: u16,
303 pub seg_gs: u16,
304 pub seg_ss: u16,
305 pub eflags: u32,
306 pub dr0: u64,
307 pub dr1: u64,
308 pub dr2: u64,
309 pub dr3: u64,
310 pub dr6: u64,
311 pub dr7: u64,
312 pub rax: u64,
313 pub rcx: u64,
314 pub rdx: u64,
315 pub rbx: u64,
316 pub rsp: u64,
317 pub rbp: u64,
318 pub rsi: u64,
319 pub rdi: u64,
320 pub r8: u64,
321 pub r9: u64,
322 pub r10: u64,
323 pub r11: u64,
324 pub r12: u64,
325 pub r13: u64,
326 pub r14: u64,
327 pub r15: u64,
328 pub rip: u64,
329 pub control_word: u16,
330 pub status_word: u16,
331 pub tag_word: u8,
332 reserved1: u8,
333 pub error_opcode: u16,
334 pub error_offset: u32,
335 pub error_selector: u16,
336 reserved2: u16,
337 pub data_offset: u32,
338 pub data_selector: u16,
339 reserved3: u16,
340 pub mxcsr2: u32,
341 pub mxcsr_mask: u32,
342 pub float_registers: [u128; 8],
343 pub xmm_registers: [u128; 16],
344 reserved4: [u8; 96],
345 pub vector_register: [u128; 26],
346 pub vector_control: u64,
347 pub debug_control: u64,
348 pub last_branch_to_rip: u64,
349 pub last_branch_from_rip: u64,
350 pub last_exception_to_rip: u64,
351 pub last_exception_from_rip: u64,
352}
353
354unsafe impl Pod for Context {}
355
356impl Debug for Context {
357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358 f.debug_struct("Context")
359 .field("p1_home", &self.p1_home)
360 .field("p2_home", &self.p2_home)
361 .field("p3_home", &self.p3_home)
362 .field("p4_home", &self.p4_home)
363 .field("p5_home", &self.p5_home)
364 .field("p6_home", &self.p6_home)
365 .field("context_flags", &self.context_flags)
366 .field("mxcsr", &self.mxcsr)
367 .field("seg_cs", &self.seg_cs)
368 .field("seg_ds", &self.seg_ds)
369 .field("seg_es", &self.seg_es)
370 .field("seg_fs", &self.seg_fs)
371 .field("seg_gs", &self.seg_gs)
372 .field("seg_ss", &self.seg_ss)
373 .field("eflags", &self.eflags)
374 .field("dr0", &self.dr0)
375 .field("dr1", &self.dr1)
376 .field("dr2", &self.dr2)
377 .field("dr3", &self.dr3)
378 .field("dr6", &self.dr6)
379 .field("dr7", &self.dr7)
380 .field("rax", &self.rax)
381 .field("rcx", &self.rcx)
382 .field("rdx", &self.rdx)
383 .field("rbx", &self.rbx)
384 .field("rsp", &self.rsp)
385 .field("rbp", &self.rbp)
386 .field("rsi", &self.rsi)
387 .field("rdi", &self.rdi)
388 .field("r8", &self.r8)
389 .field("r9", &self.r9)
390 .field("r10", &self.r10)
391 .field("r11", &self.r11)
392 .field("r12", &self.r12)
393 .field("r13", &self.r13)
394 .field("r14", &self.r14)
395 .field("r15", &self.r15)
396 .field("rip", &self.rip)
397 .field("control_word", &self.control_word)
398 .field("status_word", &self.status_word)
399 .field("tag_word", &self.tag_word)
400 .field("error_opcode", &self.error_opcode)
401 .field("error_offset", &self.error_offset)
402 .field("error_selector", &self.error_selector)
403 .field("data_offset", &self.data_offset)
404 .field("data_selector", &self.data_selector)
405 .field("mxcsr2", &self.mxcsr2)
406 .field("mxcsr_mask", &self.mxcsr_mask)
407 .field("float_registers", &self.float_registers)
408 .field("xmm_registers", &self.xmm_registers)
409 .field("vector_register", &self.vector_register)
410 .field("vector_control", &self.vector_control)
411 .field("debug_control", &self.debug_control)
412 .field("last_branch_to_rip", &self.last_branch_to_rip)
413 .field("last_branch_from_rip", &self.last_branch_from_rip)
414 .field("last_exception_to_rip", &self.last_exception_to_rip)
415 .field("last_exception_from_rip", &self.last_exception_from_rip)
416 .finish_non_exhaustive()
417 }
418}
419
420const RDMP_HEADER64_EXPECTED_MARKER: u32 = 0x40;
421const RDMP_HEADER64_EXPECTED_SIGNATURE: u32 = 0x50_4D_44_52; const RDMP_HEADER64_EXPECTED_VALID_DUMP: u32 = 0x50_4D_55_44; #[repr(C)]
425#[derive(Debug, Default)]
426pub struct RdmpHeader64 {
427 pub marker: u32,
428 pub signature: u32,
429 pub valid_dump: u32,
430 reserved1: u32,
431 pub metadata_size: u64,
432 pub first_page_offset: u64,
433 }
435
436impl RdmpHeader64 {
437 #[must_use]
438 pub fn looks_good(&self) -> bool {
439 if self.marker != RDMP_HEADER64_EXPECTED_MARKER {
440 return false;
441 }
442
443 if self.signature != RDMP_HEADER64_EXPECTED_SIGNATURE {
444 return false;
445 }
446
447 if self.valid_dump != RDMP_HEADER64_EXPECTED_VALID_DUMP {
448 return false;
449 }
450
451 if self.metadata_size - 0x20 != self.first_page_offset - 0x20_40 {
452 return false;
453 }
454
455 true
456 }
457}
458
459#[repr(C)]
460#[derive(Debug, Default)]
461pub struct KernelRdmpHeader64 {
462 pub hdr: RdmpHeader64,
463 unknown1: u64,
464 unknown2: u64,
465 }
467
468unsafe impl Pod for KernelRdmpHeader64 {}
469
470#[repr(C)]
471#[derive(Debug, Default)]
472pub struct FullRdmpHeader64 {
473 pub hdr: RdmpHeader64,
474 pub number_of_ranges: u32,
475 reserved1: u16,
476 reserved2: u16,
477 pub total_number_of_pages: u64,
478 }
480
481unsafe impl Pod for FullRdmpHeader64 {}
482
483#[repr(C)]
484#[derive(Debug, Default)]
485pub struct PfnRange {
486 pub page_file_number: u64,
487 pub number_of_pages: u64,
488}
489
490unsafe impl Pod for PfnRange {}
491
492#[repr(C)]
493#[derive(Debug, Default)]
494pub struct ListEntry<P: Pod> {
495 pub flink: P,
496 pub blink: P,
497}
498
499unsafe impl<P: Pod> Pod for ListEntry<P> {}
500
501#[repr(C)]
502#[derive(Debug, Default)]
503pub struct UnicodeString<P: Pod> {
504 pub length: u16,
505 pub maximum_length: u16,
506 pub buffer: P,
507}
508
509unsafe impl<P: Pod> Pod for UnicodeString<P> {}
510
511#[derive(Debug, Default)]
512#[repr(C)]
513pub struct LdrDataTableEntry<P: Pod> {
514 pub in_load_order_links: ListEntry<P>,
515 pub in_memory_order_links: ListEntry<P>,
516 pub in_initialization_order_links: ListEntry<P>,
517 pub dll_base: P,
518 pub entry_point: P,
519 pub size_of_image: u32,
520 pub full_dll_name: UnicodeString<P>,
521 pub base_dll_name: UnicodeString<P>,
522}
523
524unsafe impl<P: Pod> Pod for LdrDataTableEntry<P> {}
525
526#[repr(C)]
528#[derive(Debug, Default)]
529pub struct DbgKdDebugDataHeader64 {
530 pub list: ListEntry<u64>,
532 pub owner_tag: u32,
535 pub size: u32,
538}
539
540unsafe impl Pod for DbgKdDebugDataHeader64 {}
541
542#[repr(C)]
544#[derive(Debug, Default)]
545pub struct KdDebuggerData64 {
546 pub header: DbgKdDebugDataHeader64,
547 pub kern_base: u64,
549 pub breakpoint_with_status: u64,
555 pub saved_context: u64,
559 pub th_callback_stack: u16,
564 pub next_callback: u16,
566 pub frame_pointer: u16,
568 pub pae_enabled: u16,
570 pub ki_call_user_mode: u64,
572 pub ke_user_callback_dispatcher: u64,
574 pub ps_loaded_module_list: u64,
575 pub ps_active_process_head: u64,
576 pub psp_cid_table: u64,
577 pub exp_system_resources_list: u64,
578 pub exp_paged_pool_descriptor: u64,
579 pub exp_number_of_paged_pools: u64,
580 pub ke_time_increment: u64,
581 pub ke_bug_check_callback_list_head: u64,
582 pub ki_bugcheck_data: u64,
583 pub iop_error_log_list_head: u64,
584 pub obp_root_directory_object: u64,
585 pub obp_type_object_type: u64,
586 pub mm_system_cache_start: u64,
587 pub mm_system_cache_end: u64,
588 pub mm_system_cache_ws: u64,
589 pub mm_pfn_database: u64,
590 pub mm_system_ptes_start: u64,
591 pub mm_system_ptes_end: u64,
592 pub mm_subsection_base: u64,
593 pub mm_number_of_paging_files: u64,
594 pub mm_lowest_physical_page: u64,
595 pub mm_highest_physical_page: u64,
596 pub mm_number_of_physical_pages: u64,
597 pub mm_maximum_non_paged_pool_in_bytes: u64,
598 pub mm_non_paged_system_start: u64,
599 pub mm_non_paged_pool_start: u64,
600 pub mm_non_paged_pool_end: u64,
601 pub mm_paged_pool_start: u64,
602 pub mm_paged_pool_end: u64,
603 pub mm_paged_pool_information: u64,
604 pub mm_page_size: u64,
605 pub mm_size_of_paged_pool_in_bytes: u64,
606 pub mm_total_commit_limit: u64,
607 pub mm_total_committed_pages: u64,
608 pub mm_shared_commit: u64,
609 pub mm_driver_commit: u64,
610 pub mm_process_commit: u64,
611 pub mm_paged_pool_commit: u64,
612 pub mm_extended_commit: u64,
613 pub mm_zeroed_page_list_head: u64,
614 pub mm_free_page_list_head: u64,
615 pub mm_standby_page_list_head: u64,
616 pub mm_modified_page_list_head: u64,
617 pub mm_modified_no_write_page_list_head: u64,
618 pub mm_available_pages: u64,
619 pub mm_resident_available_pages: u64,
620 pub pool_track_table: u64,
621 pub non_paged_pool_descriptor: u64,
622 pub mm_highest_user_address: u64,
623 pub mm_system_range_start: u64,
624 pub mm_user_probe_address: u64,
625 pub kd_print_circular_buffer: u64,
626 pub kd_print_circular_buffer_end: u64,
627 pub kd_print_write_pointer: u64,
628 pub kd_print_rollover_count: u64,
629 pub mm_loaded_user_image_list: u64,
630 pub nt_build_lab: u64,
632 pub ki_normal_system_call: u64,
633 pub ki_processor_block: u64,
635 pub mm_unloaded_drivers: u64,
636 pub mm_last_unloaded_driver: u64,
637 pub mm_triage_action_taken: u64,
638 pub mm_special_pool_tag: u64,
639 pub kernel_verifier: u64,
640 pub mm_verifier_data: u64,
641 pub mm_allocated_non_paged_pool: u64,
642 pub mm_peak_commitment: u64,
643 pub mm_total_commit_limit_maximum: u64,
644 pub cm_nt_csd_version: u64,
645 pub mm_physical_memory_block: u64,
647 pub mm_session_base: u64,
648 pub mm_session_size: u64,
649 pub mm_system_parent_table_page: u64,
650 pub mm_virtual_translation_base: u64,
652 pub offset_kthread_next_processor: u16,
653 pub offset_kthread_teb: u16,
654 pub offset_kthread_kernel_stack: u16,
655 pub offset_kthread_initial_stack: u16,
656 pub offset_kthread_apc_process: u16,
657 pub offset_kthread_state: u16,
658 pub offset_kthread_b_store: u16,
659 pub offset_kthread_b_store_limit: u16,
660 pub size_eprocess: u16,
661 pub offset_eprocess_peb: u16,
662 pub offset_eprocess_parent_cid: u16,
663 pub offset_eprocess_directory_table_base: u16,
664 pub size_prcb: u16,
665 pub offset_prcb_dpc_routine: u16,
666 pub offset_prcb_current_thread: u16,
667 pub offset_prcb_mhz: u16,
668 pub offset_prcb_cpu_type: u16,
669 pub offset_prcb_vendor_string: u16,
670 pub offset_prcb_proc_state_context: u16,
671 pub offset_prcb_number: u16,
672 pub size_ethread: u16,
673 pub kd_print_circular_buffer_ptr: u64,
674 pub kd_print_buffer_size: u64,
675 pub ke_loader_block: u64,
676 pub size_pcr: u16,
677 pub offset_pcr_self_pcr: u16,
678 pub offset_pcr_current_prcb: u16,
679 pub offset_pcr_contained_prcb: u16,
680 pub offset_pcr_initial_b_store: u16,
681 pub offset_pcr_b_store_limit: u16,
682 pub offset_pcr_initial_stack: u16,
683 pub offset_pcr_stack_limit: u16,
684 pub offset_prcb_pcr_page: u16,
685 pub offset_prcb_proc_state_special_reg: u16,
686 pub gdt_r0_code: u16,
687 pub gdt_r0_data: u16,
688 pub gdt_r0_pcr: u16,
689 pub gdt_r3_code: u16,
690 pub gdt_r3_data: u16,
691 pub gdt_r3_teb: u16,
692 pub gdt_ldt: u16,
693 pub gdt_tss: u16,
694 pub gdt64_r3_cm_code: u16,
695 pub gdt64_r3_cm_teb: u16,
696 pub iop_num_triage_dump_data_blocks: u64,
697 pub iop_triage_dump_data_blocks: u64,
698 pub vf_crash_data_block: u64,
700 pub mm_bad_pages_detected: u64,
701 pub mm_zeroed_page_single_bit_errors_detected: u64,
702 pub etwp_debugger_data: u64,
704 pub offset_prcb_context: u16,
705 }
707
708unsafe impl Pod for KdDebuggerData64 {}
709
710const _: () = assert!(size_of::<PhysmemDesc>() == 0x10);
711const _: () = assert!(size_of::<PhysmemRun>() == 0x10);
712const _: () = assert!(size_of::<Header64>() == 0x2_000);
713const _: () = assert!(size_of::<Context>() == 0x4d0);