1use num_traits::FromPrimitive;
7use scroll::Pread;
8use std::collections::HashSet;
9use std::fmt;
10use std::io;
11use std::io::prelude::*;
12use std::mem;
13use tracing::warn;
14
15use crate::iostuff::*;
16use crate::{MinidumpMiscInfo, MinidumpSystemInfo};
17use minidump_common::format as md;
18use minidump_common::format::ContextFlagsCpu;
19
20#[derive(Debug, Clone)]
22#[cfg_attr(feature = "arbitrary_impls", derive(arbitrary::Arbitrary))]
23pub enum MinidumpRawContext {
24 X86(md::CONTEXT_X86),
25 Ppc(md::CONTEXT_PPC),
26 Ppc64(md::CONTEXT_PPC64),
27 Amd64(md::CONTEXT_AMD64),
28 Sparc(md::CONTEXT_SPARC),
29 Arm(md::CONTEXT_ARM),
30 Arm64(md::CONTEXT_ARM64),
31 OldArm64(md::CONTEXT_ARM64_OLD),
32 Mips(md::CONTEXT_MIPS),
33}
34
35pub trait CpuContext {
37 type Register: fmt::LowerHex;
39
40 const REGISTERS: &'static [&'static str];
42
43 fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
48 if let MinidumpContextValidity::Some(ref which) = *valid {
49 which.contains(reg)
50 } else {
51 self.memoize_register(reg).is_some()
52 }
53 }
54
55 fn get_register(&self, reg: &str, valid: &MinidumpContextValidity) -> Option<Self::Register> {
61 if self.register_is_valid(reg, valid) {
62 Some(self.get_register_always(reg))
63 } else {
64 None
65 }
66 }
67
68 fn get_register_always(&self, reg: &str) -> Self::Register;
70
71 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()>;
75
76 fn memoize_register(&self, reg: &str) -> Option<&'static str> {
80 default_memoize_register(Self::REGISTERS, reg)
81 }
82
83 fn format_register(&self, reg: &str) -> String {
85 format!(
86 "0x{:01$x}",
87 self.get_register_always(reg),
88 mem::size_of::<Self::Register>() * 2
89 )
90 }
91
92 fn registers(&self) -> CpuRegisters<'_, Self> {
97 self.valid_registers(&MinidumpContextValidity::All)
98 }
99
100 fn valid_registers<'a>(&'a self, valid: &'a MinidumpContextValidity) -> CpuRegisters<'a, Self> {
104 let regs = match valid {
105 MinidumpContextValidity::All => CpuRegistersInner::Slice(Self::REGISTERS.iter()),
106 MinidumpContextValidity::Some(valid) => CpuRegistersInner::Set(valid.iter()),
107 };
108
109 CpuRegisters {
110 regs,
111 context: self,
112 }
113 }
114
115 fn stack_pointer_register_name(&self) -> &'static str;
117
118 fn instruction_pointer_register_name(&self) -> &'static str;
120}
121
122fn default_memoize_register(registers: &[&'static str], reg: &str) -> Option<&'static str> {
124 let idx = registers.iter().position(|val| *val == reg)?;
125 Some(registers[idx])
126}
127
128#[derive(Debug, Clone)]
129enum CpuRegistersInner<'a> {
130 Slice(std::slice::Iter<'a, &'static str>),
131 Set(std::collections::hash_set::Iter<'a, &'static str>),
132}
133
134#[derive(Clone, Debug)]
138pub struct CpuRegisters<'a, T: ?Sized> {
139 regs: CpuRegistersInner<'a>,
140 context: &'a T,
141}
142
143impl<T> Iterator for CpuRegisters<'_, T>
144where
145 T: CpuContext,
146{
147 type Item = (&'static str, T::Register);
148
149 fn next(&mut self) -> Option<Self::Item> {
150 let reg = match &mut self.regs {
151 CpuRegistersInner::Slice(iter) => iter.next(),
152 CpuRegistersInner::Set(iter) => iter.next(),
153 }?;
154
155 Some((reg, self.context.get_register_always(reg)))
156 }
157}
158
159impl CpuContext for md::CONTEXT_X86 {
160 type Register = u32;
161
162 const REGISTERS: &'static [&'static str] = &[
163 "eip", "esp", "ebp", "ebx", "esi", "edi", "eax", "ecx", "edx", "eflags",
164 ];
165
166 fn get_register_always(&self, reg: &str) -> u32 {
167 match reg {
168 "eip" => self.eip,
169 "esp" => self.esp,
170 "ebp" => self.ebp,
171 "ebx" => self.ebx,
172 "esi" => self.esi,
173 "edi" => self.edi,
174 "eax" => self.eax,
175 "ecx" => self.ecx,
176 "edx" => self.edx,
177 "eflags" => self.eflags,
178 _ => unreachable!("Invalid x86 register! {}", reg),
179 }
180 }
181
182 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
183 match reg {
184 "eip" => self.eip = val,
185 "esp" => self.esp = val,
186 "ebp" => self.ebp = val,
187 "ebx" => self.ebx = val,
188 "esi" => self.esi = val,
189 "edi" => self.edi = val,
190 "eax" => self.eax = val,
191 "ecx" => self.ecx = val,
192 "edx" => self.edx = val,
193 "eflags" => self.eflags = val,
194 _ => return None,
195 }
196 Some(())
197 }
198
199 fn stack_pointer_register_name(&self) -> &'static str {
200 "esp"
201 }
202
203 fn instruction_pointer_register_name(&self) -> &'static str {
204 "eip"
205 }
206}
207
208impl CpuContext for md::CONTEXT_AMD64 {
209 type Register = u64;
210
211 const REGISTERS: &'static [&'static str] = &[
212 "rax", "rdx", "rcx", "rbx", "rsi", "rdi", "rbp", "rsp", "r8", "r9", "r10", "r11", "r12",
213 "r13", "r14", "r15", "rip",
214 ];
215
216 fn get_register_always(&self, reg: &str) -> u64 {
217 match reg {
218 "rax" => self.rax,
219 "rdx" => self.rdx,
220 "rcx" => self.rcx,
221 "rbx" => self.rbx,
222 "rsi" => self.rsi,
223 "rdi" => self.rdi,
224 "rbp" => self.rbp,
225 "rsp" => self.rsp,
226 "r8" => self.r8,
227 "r9" => self.r9,
228 "r10" => self.r10,
229 "r11" => self.r11,
230 "r12" => self.r12,
231 "r13" => self.r13,
232 "r14" => self.r14,
233 "r15" => self.r15,
234 "rip" => self.rip,
235 _ => unreachable!("Invalid x86-64 register! {}", reg),
236 }
237 }
238
239 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
240 match reg {
241 "rax" => self.rax = val,
242 "rdx" => self.rdx = val,
243 "rcx" => self.rcx = val,
244 "rbx" => self.rbx = val,
245 "rsi" => self.rsi = val,
246 "rdi" => self.rdi = val,
247 "rbp" => self.rbp = val,
248 "rsp" => self.rsp = val,
249 "r8" => self.r8 = val,
250 "r9" => self.r9 = val,
251 "r10" => self.r10 = val,
252 "r11" => self.r11 = val,
253 "r12" => self.r12 = val,
254 "r13" => self.r13 = val,
255 "r14" => self.r14 = val,
256 "r15" => self.r15 = val,
257 "rip" => self.rip = val,
258 _ => return None,
259 }
260 Some(())
261 }
262
263 fn stack_pointer_register_name(&self) -> &'static str {
264 "rsp"
265 }
266
267 fn instruction_pointer_register_name(&self) -> &'static str {
268 "rip"
269 }
270}
271
272impl CpuContext for md::CONTEXT_ARM {
273 type Register = u32;
274
275 const REGISTERS: &'static [&'static str] = &[
276 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r12", "fp", "sp", "lr",
277 "pc",
278 ];
279
280 fn memoize_register(&self, reg: &str) -> Option<&'static str> {
281 match reg {
282 "r11" => Some("fp"),
283 "r13" => Some("sp"),
284 "r14" => Some("lr"),
285 "r15" => Some("pc"),
286 _ => default_memoize_register(Self::REGISTERS, reg),
287 }
288 }
289
290 fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
291 if let MinidumpContextValidity::Some(ref which) = valid {
292 match reg {
293 "r11" | "fp" => which.contains("r11") || which.contains("fp"),
294 "r13" | "sp" => which.contains("r13") || which.contains("sp"),
295 "r14" | "lr" => which.contains("r14") || which.contains("lr"),
296 "r15" | "pc" => which.contains("r15") || which.contains("pc"),
297 _ => which.contains(reg),
298 }
299 } else {
300 self.memoize_register(reg).is_some()
301 }
302 }
303
304 fn get_register_always(&self, reg: &str) -> u32 {
305 match reg {
306 "r0" => self.iregs[0],
307 "r1" => self.iregs[1],
308 "r2" => self.iregs[2],
309 "r3" => self.iregs[3],
310 "r4" => self.iregs[4],
311 "r5" => self.iregs[5],
312 "r6" => self.iregs[6],
313 "r7" => self.iregs[7],
314 "r8" => self.iregs[8],
315 "r9" => self.iregs[9],
316 "r10" => self.iregs[10],
317 "r11" => self.iregs[11],
318 "r12" => self.iregs[12],
319 "r13" => self.iregs[13],
320 "r14" => self.iregs[14],
321 "r15" => self.iregs[15],
322 "pc" => self.iregs[md::ArmRegisterNumbers::ProgramCounter as usize],
323 "lr" => self.iregs[md::ArmRegisterNumbers::LinkRegister as usize],
324 "fp" => self.iregs[md::ArmRegisterNumbers::FramePointer as usize],
325 "sp" => self.iregs[md::ArmRegisterNumbers::StackPointer as usize],
326 _ => unreachable!("Invalid arm register! {}", reg),
327 }
328 }
329
330 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
331 match reg {
332 "r0" => self.iregs[0] = val,
333 "r1" => self.iregs[1] = val,
334 "r2" => self.iregs[2] = val,
335 "r3" => self.iregs[3] = val,
336 "r4" => self.iregs[4] = val,
337 "r5" => self.iregs[5] = val,
338 "r6" => self.iregs[6] = val,
339 "r7" => self.iregs[7] = val,
340 "r8" => self.iregs[8] = val,
341 "r9" => self.iregs[9] = val,
342 "r10" => self.iregs[10] = val,
343 "r11" => self.iregs[11] = val,
344 "r12" => self.iregs[12] = val,
345 "r13" => self.iregs[13] = val,
346 "r14" => self.iregs[14] = val,
347 "r15" => self.iregs[15] = val,
348 "pc" => self.iregs[md::ArmRegisterNumbers::ProgramCounter as usize] = val,
349 "lr" => self.iregs[md::ArmRegisterNumbers::LinkRegister as usize] = val,
350 "fp" => self.iregs[md::ArmRegisterNumbers::FramePointer as usize] = val,
351 "sp" => self.iregs[md::ArmRegisterNumbers::StackPointer as usize] = val,
352 _ => return None,
353 }
354 Some(())
355 }
356
357 fn stack_pointer_register_name(&self) -> &'static str {
358 "sp"
359 }
360
361 fn instruction_pointer_register_name(&self) -> &'static str {
362 "pc"
363 }
364}
365
366impl CpuContext for md::CONTEXT_ARM64_OLD {
367 type Register = u64;
368
369 const REGISTERS: &'static [&'static str] = &[
370 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13",
371 "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26",
372 "x27", "x28", "fp", "lr", "sp", "pc",
373 ];
374
375 fn memoize_register(&self, reg: &str) -> Option<&'static str> {
376 match reg {
377 "x29" => Some("fp"),
378 "x30" => Some("lr"),
379 _ => default_memoize_register(Self::REGISTERS, reg),
380 }
381 }
382
383 fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
384 if let MinidumpContextValidity::Some(ref which) = valid {
385 match reg {
386 "x29" | "fp" => which.contains("x29") || which.contains("fp"),
387 "x30" | "lr" => which.contains("x30") || which.contains("lr"),
388 _ => which.contains(reg),
389 }
390 } else {
391 self.memoize_register(reg).is_some()
392 }
393 }
394
395 fn get_register_always(&self, reg: &str) -> u64 {
396 match reg {
397 "x0" => self.iregs[0],
398 "x1" => self.iregs[1],
399 "x2" => self.iregs[2],
400 "x3" => self.iregs[3],
401 "x4" => self.iregs[4],
402 "x5" => self.iregs[5],
403 "x6" => self.iregs[6],
404 "x7" => self.iregs[7],
405 "x8" => self.iregs[8],
406 "x9" => self.iregs[9],
407 "x10" => self.iregs[10],
408 "x11" => self.iregs[11],
409 "x12" => self.iregs[12],
410 "x13" => self.iregs[13],
411 "x14" => self.iregs[14],
412 "x15" => self.iregs[15],
413 "x16" => self.iregs[16],
414 "x17" => self.iregs[17],
415 "x18" => self.iregs[18],
416 "x19" => self.iregs[19],
417 "x20" => self.iregs[20],
418 "x21" => self.iregs[21],
419 "x22" => self.iregs[22],
420 "x23" => self.iregs[23],
421 "x24" => self.iregs[24],
422 "x25" => self.iregs[25],
423 "x26" => self.iregs[26],
424 "x27" => self.iregs[27],
425 "x28" => self.iregs[28],
426 "x29" => self.iregs[29],
427 "x30" => self.iregs[30],
428 "pc" => self.pc,
429 "sp" => self.sp,
430 "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize],
431 "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize],
432 _ => unreachable!("Invalid aarch64 register! {}", reg),
433 }
434 }
435
436 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
437 match reg {
438 "x0" => self.iregs[0] = val,
439 "x1" => self.iregs[1] = val,
440 "x2" => self.iregs[2] = val,
441 "x3" => self.iregs[3] = val,
442 "x4" => self.iregs[4] = val,
443 "x5" => self.iregs[5] = val,
444 "x6" => self.iregs[6] = val,
445 "x7" => self.iregs[7] = val,
446 "x8" => self.iregs[8] = val,
447 "x9" => self.iregs[9] = val,
448 "x10" => self.iregs[10] = val,
449 "x11" => self.iregs[11] = val,
450 "x12" => self.iregs[12] = val,
451 "x13" => self.iregs[13] = val,
452 "x14" => self.iregs[14] = val,
453 "x15" => self.iregs[15] = val,
454 "x16" => self.iregs[16] = val,
455 "x17" => self.iregs[17] = val,
456 "x18" => self.iregs[18] = val,
457 "x19" => self.iregs[19] = val,
458 "x20" => self.iregs[20] = val,
459 "x21" => self.iregs[21] = val,
460 "x22" => self.iregs[22] = val,
461 "x23" => self.iregs[23] = val,
462 "x24" => self.iregs[24] = val,
463 "x25" => self.iregs[25] = val,
464 "x26" => self.iregs[26] = val,
465 "x27" => self.iregs[27] = val,
466 "x28" => self.iregs[28] = val,
467 "x29" => self.iregs[29] = val,
468 "x30" => self.iregs[30] = val,
469 "pc" => self.pc = val,
470 "sp" => self.sp = val,
471 "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize] = val,
472 "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize] = val,
473 _ => return None,
474 }
475 Some(())
476 }
477
478 fn stack_pointer_register_name(&self) -> &'static str {
479 "sp"
480 }
481
482 fn instruction_pointer_register_name(&self) -> &'static str {
483 "pc"
484 }
485}
486
487impl CpuContext for md::CONTEXT_ARM64 {
488 type Register = u64;
489
490 const REGISTERS: &'static [&'static str] = &[
491 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13",
492 "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26",
493 "x27", "x28", "fp", "lr", "sp", "pc",
494 ];
495
496 fn memoize_register(&self, reg: &str) -> Option<&'static str> {
497 match reg {
498 "x29" => Some("fp"),
499 "x30" => Some("lr"),
500 _ => default_memoize_register(Self::REGISTERS, reg),
501 }
502 }
503
504 fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
505 if let MinidumpContextValidity::Some(ref which) = valid {
506 match reg {
507 "x29" | "fp" => which.contains("x29") || which.contains("fp"),
508 "x30" | "lr" => which.contains("x30") || which.contains("lr"),
509 _ => which.contains(reg),
510 }
511 } else {
512 self.memoize_register(reg).is_some()
513 }
514 }
515
516 fn get_register_always(&self, reg: &str) -> u64 {
517 match reg {
518 "x0" => self.iregs[0],
519 "x1" => self.iregs[1],
520 "x2" => self.iregs[2],
521 "x3" => self.iregs[3],
522 "x4" => self.iregs[4],
523 "x5" => self.iregs[5],
524 "x6" => self.iregs[6],
525 "x7" => self.iregs[7],
526 "x8" => self.iregs[8],
527 "x9" => self.iregs[9],
528 "x10" => self.iregs[10],
529 "x11" => self.iregs[11],
530 "x12" => self.iregs[12],
531 "x13" => self.iregs[13],
532 "x14" => self.iregs[14],
533 "x15" => self.iregs[15],
534 "x16" => self.iregs[16],
535 "x17" => self.iregs[17],
536 "x18" => self.iregs[18],
537 "x19" => self.iregs[19],
538 "x20" => self.iregs[20],
539 "x21" => self.iregs[21],
540 "x22" => self.iregs[22],
541 "x23" => self.iregs[23],
542 "x24" => self.iregs[24],
543 "x25" => self.iregs[25],
544 "x26" => self.iregs[26],
545 "x27" => self.iregs[27],
546 "x28" => self.iregs[28],
547 "x29" => self.iregs[29],
548 "x30" => self.iregs[30],
549 "pc" => self.pc,
550 "sp" => self.sp,
551 "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize],
552 "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize],
553 _ => unreachable!("Invalid aarch64 register! {}", reg),
554 }
555 }
556
557 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
558 match reg {
559 "x0" => self.iregs[0] = val,
560 "x1" => self.iregs[1] = val,
561 "x2" => self.iregs[2] = val,
562 "x3" => self.iregs[3] = val,
563 "x4" => self.iregs[4] = val,
564 "x5" => self.iregs[5] = val,
565 "x6" => self.iregs[6] = val,
566 "x7" => self.iregs[7] = val,
567 "x8" => self.iregs[8] = val,
568 "x9" => self.iregs[9] = val,
569 "x10" => self.iregs[10] = val,
570 "x11" => self.iregs[11] = val,
571 "x12" => self.iregs[12] = val,
572 "x13" => self.iregs[13] = val,
573 "x14" => self.iregs[14] = val,
574 "x15" => self.iregs[15] = val,
575 "x16" => self.iregs[16] = val,
576 "x17" => self.iregs[17] = val,
577 "x18" => self.iregs[18] = val,
578 "x19" => self.iregs[19] = val,
579 "x20" => self.iregs[20] = val,
580 "x21" => self.iregs[21] = val,
581 "x22" => self.iregs[22] = val,
582 "x23" => self.iregs[23] = val,
583 "x24" => self.iregs[24] = val,
584 "x25" => self.iregs[25] = val,
585 "x26" => self.iregs[26] = val,
586 "x27" => self.iregs[27] = val,
587 "x28" => self.iregs[28] = val,
588 "x29" => self.iregs[29] = val,
589 "x30" => self.iregs[30] = val,
590 "pc" => self.pc = val,
591 "sp" => self.sp = val,
592 "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize] = val,
593 "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize] = val,
594 _ => return None,
595 }
596 Some(())
597 }
598
599 fn stack_pointer_register_name(&self) -> &'static str {
600 "sp"
601 }
602
603 fn instruction_pointer_register_name(&self) -> &'static str {
604 "pc"
605 }
606}
607
608impl CpuContext for md::CONTEXT_PPC {
609 type Register = u32;
610
611 const REGISTERS: &'static [&'static str] = &[
612 "srr0", "srr1", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
613 "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24",
614 "r25", "r26", "r27", "r28", "r29", "r30", "r31", "cr", "xer", "lr", "ctr", "mq", "vrsave",
615 ];
616
617 fn get_register_always(&self, reg: &str) -> Self::Register {
618 match reg {
619 "srr0" => self.srr0,
620 "srr1" => self.srr1,
621 "r0" => self.gpr[0],
622 "r1" => self.gpr[1],
623 "r2" => self.gpr[2],
624 "r3" => self.gpr[3],
625 "r4" => self.gpr[4],
626 "r5" => self.gpr[5],
627 "r6" => self.gpr[6],
628 "r7" => self.gpr[7],
629 "r8" => self.gpr[8],
630 "r9" => self.gpr[9],
631 "r10" => self.gpr[10],
632 "r11" => self.gpr[11],
633 "r12" => self.gpr[12],
634 "r13" => self.gpr[13],
635 "r14" => self.gpr[14],
636 "r15" => self.gpr[15],
637 "r16" => self.gpr[16],
638 "r17" => self.gpr[17],
639 "r18" => self.gpr[18],
640 "r19" => self.gpr[19],
641 "r20" => self.gpr[20],
642 "r21" => self.gpr[21],
643 "r22" => self.gpr[22],
644 "r23" => self.gpr[23],
645 "r24" => self.gpr[24],
646 "r25" => self.gpr[25],
647 "r26" => self.gpr[26],
648 "r27" => self.gpr[27],
649 "r28" => self.gpr[28],
650 "r29" => self.gpr[29],
651 "r30" => self.gpr[30],
652 "r31" => self.gpr[31],
653 "cr" => self.cr,
654 "xer" => self.xer,
655 "lr" => self.lr,
656 "ctr" => self.ctr,
657 "mq" => self.mq,
658 "vrsave" => self.vrsave,
659 _ => unreachable!("Invalid ppc register! {}", reg),
660 }
661 }
662
663 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
664 match reg {
665 "srr0" => self.srr0 = val,
666 "srr1" => self.srr1 = val,
667 "r0" => self.gpr[0] = val,
668 "r1" => self.gpr[1] = val,
669 "r2" => self.gpr[2] = val,
670 "r3" => self.gpr[3] = val,
671 "r4" => self.gpr[4] = val,
672 "r5" => self.gpr[5] = val,
673 "r6" => self.gpr[6] = val,
674 "r7" => self.gpr[7] = val,
675 "r8" => self.gpr[8] = val,
676 "r9" => self.gpr[9] = val,
677 "r10" => self.gpr[10] = val,
678 "r11" => self.gpr[11] = val,
679 "r12" => self.gpr[12] = val,
680 "r13" => self.gpr[13] = val,
681 "r14" => self.gpr[14] = val,
682 "r15" => self.gpr[15] = val,
683 "r16" => self.gpr[16] = val,
684 "r17" => self.gpr[17] = val,
685 "r18" => self.gpr[18] = val,
686 "r19" => self.gpr[19] = val,
687 "r20" => self.gpr[20] = val,
688 "r21" => self.gpr[21] = val,
689 "r22" => self.gpr[22] = val,
690 "r23" => self.gpr[23] = val,
691 "r24" => self.gpr[24] = val,
692 "r25" => self.gpr[25] = val,
693 "r26" => self.gpr[26] = val,
694 "r27" => self.gpr[27] = val,
695 "r28" => self.gpr[28] = val,
696 "r29" => self.gpr[29] = val,
697 "r30" => self.gpr[30] = val,
698 "r31" => self.gpr[31] = val,
699 "cr" => self.cr = val,
700 "xer" => self.xer = val,
701 "lr" => self.lr = val,
702 "ctr" => self.ctr = val,
703 "mq" => self.mq = val,
704 "vrsave" => self.vrsave = val,
705 _ => return None,
706 }
707 Some(())
708 }
709
710 fn stack_pointer_register_name(&self) -> &'static str {
711 "r1"
712 }
713
714 fn instruction_pointer_register_name(&self) -> &'static str {
715 "srr0"
716 }
717}
718
719impl CpuContext for md::CONTEXT_PPC64 {
720 type Register = u64;
721
722 const REGISTERS: &'static [&'static str] = &[
723 "srr0", "srr1", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
724 "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24",
725 "r25", "r26", "r27", "r28", "r29", "r30", "r31", "cr", "xer", "lr", "ctr", "vrsave",
726 ];
727
728 fn get_register_always(&self, reg: &str) -> Self::Register {
729 match reg {
730 "srr0" => self.srr0,
731 "srr1" => self.srr1,
732 "r0" => self.gpr[0],
733 "r1" => self.gpr[1],
734 "r2" => self.gpr[2],
735 "r3" => self.gpr[3],
736 "r4" => self.gpr[4],
737 "r5" => self.gpr[5],
738 "r6" => self.gpr[6],
739 "r7" => self.gpr[7],
740 "r8" => self.gpr[8],
741 "r9" => self.gpr[9],
742 "r10" => self.gpr[10],
743 "r11" => self.gpr[11],
744 "r12" => self.gpr[12],
745 "r13" => self.gpr[13],
746 "r14" => self.gpr[14],
747 "r15" => self.gpr[15],
748 "r16" => self.gpr[16],
749 "r17" => self.gpr[17],
750 "r18" => self.gpr[18],
751 "r19" => self.gpr[19],
752 "r20" => self.gpr[20],
753 "r21" => self.gpr[21],
754 "r22" => self.gpr[22],
755 "r23" => self.gpr[23],
756 "r24" => self.gpr[24],
757 "r25" => self.gpr[25],
758 "r26" => self.gpr[26],
759 "r27" => self.gpr[27],
760 "r28" => self.gpr[28],
761 "r29" => self.gpr[29],
762 "r30" => self.gpr[30],
763 "r31" => self.gpr[31],
764 "cr" => self.cr,
765 "xer" => self.xer,
766 "lr" => self.lr,
767 "ctr" => self.ctr,
768 "vrsave" => self.vrsave,
769 _ => unreachable!("Invalid ppc64 register! {}", reg),
770 }
771 }
772
773 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
774 match reg {
775 "srr0" => self.srr0 = val,
776 "srr1" => self.srr1 = val,
777 "r0" => self.gpr[0] = val,
778 "r1" => self.gpr[1] = val,
779 "r2" => self.gpr[2] = val,
780 "r3" => self.gpr[3] = val,
781 "r4" => self.gpr[4] = val,
782 "r5" => self.gpr[5] = val,
783 "r6" => self.gpr[6] = val,
784 "r7" => self.gpr[7] = val,
785 "r8" => self.gpr[8] = val,
786 "r9" => self.gpr[9] = val,
787 "r10" => self.gpr[10] = val,
788 "r11" => self.gpr[11] = val,
789 "r12" => self.gpr[12] = val,
790 "r13" => self.gpr[13] = val,
791 "r14" => self.gpr[14] = val,
792 "r15" => self.gpr[15] = val,
793 "r16" => self.gpr[16] = val,
794 "r17" => self.gpr[17] = val,
795 "r18" => self.gpr[18] = val,
796 "r19" => self.gpr[19] = val,
797 "r20" => self.gpr[20] = val,
798 "r21" => self.gpr[21] = val,
799 "r22" => self.gpr[22] = val,
800 "r23" => self.gpr[23] = val,
801 "r24" => self.gpr[24] = val,
802 "r25" => self.gpr[25] = val,
803 "r26" => self.gpr[26] = val,
804 "r27" => self.gpr[27] = val,
805 "r28" => self.gpr[28] = val,
806 "r29" => self.gpr[29] = val,
807 "r30" => self.gpr[30] = val,
808 "r31" => self.gpr[31] = val,
809 "cr" => self.cr = val,
810 "xer" => self.xer = val,
811 "lr" => self.lr = val,
812 "ctr" => self.ctr = val,
813 "vrsave" => self.vrsave = val,
814 _ => return None,
815 }
816 Some(())
817 }
818
819 fn stack_pointer_register_name(&self) -> &'static str {
820 "r1"
821 }
822
823 fn instruction_pointer_register_name(&self) -> &'static str {
824 "srr0"
825 }
826}
827
828impl CpuContext for md::CONTEXT_MIPS {
829 type Register = u64;
830
831 const REGISTERS: &'static [&'static str] = &[
832 "gp", "sp", "fp", "ra", "pc", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
833 ];
834
835 fn get_register_always(&self, reg: &str) -> Self::Register {
836 match reg {
837 "gp" => self.iregs[md::MipsRegisterNumbers::GlobalPointer as usize],
838 "sp" => self.iregs[md::MipsRegisterNumbers::StackPointer as usize],
839 "fp" => self.iregs[md::MipsRegisterNumbers::FramePointer as usize],
840 "ra" => self.iregs[md::MipsRegisterNumbers::ReturnAddress as usize],
841 "pc" => self.epc,
842 "s0" => self.iregs[md::MipsRegisterNumbers::S0 as usize],
843 "s1" => self.iregs[md::MipsRegisterNumbers::S1 as usize],
844 "s2" => self.iregs[md::MipsRegisterNumbers::S2 as usize],
845 "s3" => self.iregs[md::MipsRegisterNumbers::S3 as usize],
846 "s4" => self.iregs[md::MipsRegisterNumbers::S4 as usize],
847 "s5" => self.iregs[md::MipsRegisterNumbers::S5 as usize],
848 "s6" => self.iregs[md::MipsRegisterNumbers::S6 as usize],
849 "s7" => self.iregs[md::MipsRegisterNumbers::S7 as usize],
850 _ => unreachable!("Invalid mips register! {}", reg),
851 }
852 }
853
854 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
855 match reg {
856 "gp" => self.iregs[md::MipsRegisterNumbers::GlobalPointer as usize] = val,
857 "sp" => self.iregs[md::MipsRegisterNumbers::StackPointer as usize] = val,
858 "fp" => self.iregs[md::MipsRegisterNumbers::FramePointer as usize] = val,
859 "ra" => self.iregs[md::MipsRegisterNumbers::ReturnAddress as usize] = val,
860 "pc" => self.epc = val,
861 "s0" => self.iregs[md::MipsRegisterNumbers::S0 as usize] = val,
862 "s1" => self.iregs[md::MipsRegisterNumbers::S1 as usize] = val,
863 "s2" => self.iregs[md::MipsRegisterNumbers::S2 as usize] = val,
864 "s3" => self.iregs[md::MipsRegisterNumbers::S3 as usize] = val,
865 "s4" => self.iregs[md::MipsRegisterNumbers::S4 as usize] = val,
866 "s5" => self.iregs[md::MipsRegisterNumbers::S5 as usize] = val,
867 "s6" => self.iregs[md::MipsRegisterNumbers::S6 as usize] = val,
868 "s7" => self.iregs[md::MipsRegisterNumbers::S7 as usize] = val,
869 _ => return None,
870 }
871 Some(())
872 }
873
874 fn stack_pointer_register_name(&self) -> &'static str {
875 "sp"
876 }
877
878 fn instruction_pointer_register_name(&self) -> &'static str {
879 "pc"
880 }
881}
882
883impl CpuContext for md::CONTEXT_SPARC {
884 type Register = u64;
885
886 const REGISTERS: &'static [&'static str] = &[
887 "g_r0", "g_r1", "g_r2", "g_r3", "g_r4", "g_r5", "g_r6", "g_r7", "g_r8", "g_r9", "g_r10",
888 "g_r11", "g_r12", "g_r13", "g_r14", "g_r15", "g_r16", "g_r17", "g_r18", "g_r19", "g_r20",
889 "g_r21", "g_r22", "g_r23", "g_r24", "g_r25", "g_r26", "g_r27", "g_r28", "g_r29", "g_r30",
890 "g_r31", "ccr", "pc", "npc", "y", "asi", "fprs",
891 ];
892
893 fn get_register_always(&self, reg: &str) -> Self::Register {
894 match reg {
895 "g_r0" | "g0" => self.g_r[0],
896 "g_r1" | "g1" => self.g_r[1],
897 "g_r2" | "g2" => self.g_r[2],
898 "g_r3" | "g3" => self.g_r[3],
899 "g_r4" | "g4" => self.g_r[4],
900 "g_r5" | "g5" => self.g_r[5],
901 "g_r6" | "g6" => self.g_r[6],
902 "g_r7" | "g7" => self.g_r[7],
903 "g_r8" | "o0" => self.g_r[8],
904 "g_r9" | "o1" => self.g_r[9],
905 "g_r10" | "o2" => self.g_r[10],
906 "g_r11" | "o3" => self.g_r[11],
907 "g_r12" | "o4" => self.g_r[12],
908 "g_r13" | "o5" => self.g_r[13],
909 "g_r14" | "o6" => self.g_r[14],
910 "g_r15" | "o7" => self.g_r[15],
911 "g_r16" | "l0" => self.g_r[16],
912 "g_r17" | "l1" => self.g_r[17],
913 "g_r18" | "l2" => self.g_r[18],
914 "g_r19" | "l3" => self.g_r[19],
915 "g_r20" | "l4" => self.g_r[20],
916 "g_r21" | "l5" => self.g_r[21],
917 "g_r22" | "l6" => self.g_r[22],
918 "g_r23" | "l7" => self.g_r[23],
919 "g_r24" | "i0" => self.g_r[24],
920 "g_r25" | "i1" => self.g_r[25],
921 "g_r26" | "i2" => self.g_r[26],
922 "g_r27" | "i3" => self.g_r[27],
923 "g_r28" | "i4" => self.g_r[28],
924 "g_r29" | "i5" => self.g_r[29],
925 "g_r30" | "i6" => self.g_r[30],
926 "g_r31" | "i7" => self.g_r[31],
927 "ccr" => self.ccr,
928 "pc" => self.pc,
929 "npc" => self.npc,
930 "y" => self.y,
931 "asi" => self.asi,
932 "fprs" => self.fprs,
933 _ => unreachable!("Invalid sparc register! {}", reg),
934 }
935 }
936
937 fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
938 match reg {
939 "g_r0" | "g0" => self.g_r[0] = val,
940 "g_r1" | "g1" => self.g_r[1] = val,
941 "g_r2" | "g2" => self.g_r[2] = val,
942 "g_r3" | "g3" => self.g_r[3] = val,
943 "g_r4" | "g4" => self.g_r[4] = val,
944 "g_r5" | "g5" => self.g_r[5] = val,
945 "g_r6" | "g6" => self.g_r[6] = val,
946 "g_r7" | "g7" => self.g_r[7] = val,
947 "g_r8" | "o0" => self.g_r[8] = val,
948 "g_r9" | "o1" => self.g_r[9] = val,
949 "g_r10" | "o2" => self.g_r[10] = val,
950 "g_r11" | "o3" => self.g_r[11] = val,
951 "g_r12" | "o4" => self.g_r[12] = val,
952 "g_r13" | "o5" => self.g_r[13] = val,
953 "g_r14" | "o6" => self.g_r[14] = val,
954 "g_r15" | "o7" => self.g_r[15] = val,
955 "g_r16" | "l0" => self.g_r[16] = val,
956 "g_r17" | "l1" => self.g_r[17] = val,
957 "g_r18" | "l2" => self.g_r[18] = val,
958 "g_r19" | "l3" => self.g_r[19] = val,
959 "g_r20" | "l4" => self.g_r[20] = val,
960 "g_r21" | "l5" => self.g_r[21] = val,
961 "g_r22" | "l6" => self.g_r[22] = val,
962 "g_r23" | "l7" => self.g_r[23] = val,
963 "g_r24" | "i0" => self.g_r[24] = val,
964 "g_r25" | "i1" => self.g_r[25] = val,
965 "g_r26" | "i2" => self.g_r[26] = val,
966 "g_r27" | "i3" => self.g_r[27] = val,
967 "g_r28" | "i4" => self.g_r[28] = val,
968 "g_r29" | "i5" => self.g_r[29] = val,
969 "g_r30" | "i6" => self.g_r[30] = val,
970 "g_r31" | "i7" => self.g_r[31] = val,
971 "ccr" => self.ccr = val,
972 "pc" => self.pc = val,
973 "npc" => self.npc = val,
974 "y" => self.y = val,
975 "asi" => self.asi = val,
976 "fprs" => self.fprs = val,
977 _ => return None,
978 }
979 Some(())
980 }
981
982 fn stack_pointer_register_name(&self) -> &'static str {
983 "g_r14" }
985
986 fn instruction_pointer_register_name(&self) -> &'static str {
987 "pc"
988 }
989}
990
991#[derive(Clone, Debug, PartialEq, Eq)]
993pub enum MinidumpContextValidity {
994 All,
996 Some(HashSet<&'static str>),
998}
999
1000#[derive(Debug, Clone)]
1013pub struct MinidumpContext {
1014 pub raw: MinidumpRawContext,
1016 pub valid: MinidumpContextValidity,
1018}
1019
1020#[derive(Debug)]
1022pub enum ContextError {
1023 ReadFailure,
1025 UnknownCpuContext,
1027}
1028
1029impl MinidumpContext {
1033 pub fn from_raw(raw: MinidumpRawContext) -> MinidumpContext {
1035 MinidumpContext {
1036 raw,
1037 valid: MinidumpContextValidity::All,
1038 }
1039 }
1040
1041 pub fn read(
1043 bytes: &[u8],
1044 endian: scroll::Endian,
1045 system_info: &MinidumpSystemInfo,
1046 _misc: Option<&MinidumpMiscInfo>,
1047 ) -> Result<MinidumpContext, ContextError> {
1048 use md::ProcessorArchitecture::*;
1049
1050 let mut offset = 0;
1051
1052 match md::ProcessorArchitecture::from_u16(system_info.raw.processor_architecture) {
1059 Some(PROCESSOR_ARCHITECTURE_INTEL) | Some(PROCESSOR_ARCHITECTURE_IA32_ON_WIN64) => {
1060 let ctx: md::CONTEXT_X86 = bytes
1062 .gread_with(&mut offset, endian)
1063 .or(Err(ContextError::ReadFailure))?;
1064
1065 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1066 if flags == ContextFlagsCpu::CONTEXT_X86 {
1067 if ctx.context_flags & md::CONTEXT_HAS_XSTATE != 0 {
1068 warn!("Cpu context has extra XSTATE that is being ignored");
1070 }
1071 Ok(MinidumpContext::from_raw(MinidumpRawContext::X86(ctx)))
1072 } else {
1073 Err(ContextError::ReadFailure)
1074 }
1075 }
1076 Some(PROCESSOR_ARCHITECTURE_AMD64) => {
1077 let ctx: md::CONTEXT_AMD64 = bytes
1078 .gread_with(&mut offset, endian)
1079 .or(Err(ContextError::ReadFailure))?;
1080
1081 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1082 if flags == ContextFlagsCpu::CONTEXT_AMD64 {
1083 if ctx.context_flags & md::CONTEXT_HAS_XSTATE != 0 {
1084 warn!("Cpu context has extra XSTATE that is being ignored");
1086 }
1087 Ok(MinidumpContext::from_raw(MinidumpRawContext::Amd64(ctx)))
1088 } else {
1089 Err(ContextError::ReadFailure)
1090 }
1091 }
1092 Some(PROCESSOR_ARCHITECTURE_PPC) => {
1093 let ctx: md::CONTEXT_PPC = bytes
1094 .gread_with(&mut offset, endian)
1095 .or(Err(ContextError::ReadFailure))?;
1096
1097 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1098 if flags == ContextFlagsCpu::CONTEXT_PPC {
1099 Ok(MinidumpContext::from_raw(MinidumpRawContext::Ppc(ctx)))
1100 } else {
1101 Err(ContextError::ReadFailure)
1102 }
1103 }
1104 Some(PROCESSOR_ARCHITECTURE_PPC64) => {
1105 let ctx: md::CONTEXT_PPC64 = bytes
1106 .gread_with(&mut offset, endian)
1107 .or(Err(ContextError::ReadFailure))?;
1108
1109 let flags = ContextFlagsCpu::from_flags(ctx.context_flags as u32);
1110 if flags == ContextFlagsCpu::CONTEXT_PPC64 {
1111 Ok(MinidumpContext::from_raw(MinidumpRawContext::Ppc64(ctx)))
1112 } else {
1113 Err(ContextError::ReadFailure)
1114 }
1115 }
1116 Some(PROCESSOR_ARCHITECTURE_SPARC) => {
1117 let ctx: md::CONTEXT_SPARC = bytes
1118 .gread_with(&mut offset, endian)
1119 .or(Err(ContextError::ReadFailure))?;
1120
1121 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1122 if flags == ContextFlagsCpu::CONTEXT_SPARC {
1123 Ok(MinidumpContext::from_raw(MinidumpRawContext::Sparc(ctx)))
1124 } else {
1125 Err(ContextError::ReadFailure)
1126 }
1127 }
1128 Some(PROCESSOR_ARCHITECTURE_ARM) => {
1129 let ctx: md::CONTEXT_ARM = bytes
1130 .gread_with(&mut offset, endian)
1131 .or(Err(ContextError::ReadFailure))?;
1132
1133 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1134 if flags == ContextFlagsCpu::CONTEXT_ARM {
1135 Ok(MinidumpContext::from_raw(MinidumpRawContext::Arm(ctx)))
1136 } else {
1137 Err(ContextError::ReadFailure)
1138 }
1139 }
1140 Some(PROCESSOR_ARCHITECTURE_ARM64) => {
1141 let ctx: md::CONTEXT_ARM64 = bytes
1142 .gread_with(&mut offset, endian)
1143 .or(Err(ContextError::ReadFailure))?;
1144
1145 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1146 if flags == ContextFlagsCpu::CONTEXT_ARM64 {
1147 Ok(MinidumpContext::from_raw(MinidumpRawContext::Arm64(ctx)))
1148 } else {
1149 Err(ContextError::ReadFailure)
1150 }
1151 }
1152 Some(PROCESSOR_ARCHITECTURE_ARM64_OLD) => {
1153 let ctx: md::CONTEXT_ARM64_OLD = bytes
1154 .gread_with(&mut offset, endian)
1155 .or(Err(ContextError::ReadFailure))?;
1156
1157 let flags = ContextFlagsCpu::from_flags(ctx.context_flags as u32);
1158 if flags == ContextFlagsCpu::CONTEXT_ARM64_OLD {
1159 Ok(MinidumpContext::from_raw(MinidumpRawContext::OldArm64(ctx)))
1160 } else {
1161 Err(ContextError::ReadFailure)
1162 }
1163 }
1164 Some(PROCESSOR_ARCHITECTURE_MIPS) => {
1165 let ctx: md::CONTEXT_MIPS = bytes
1166 .gread_with(&mut offset, endian)
1167 .or(Err(ContextError::ReadFailure))?;
1168
1169 let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
1170 if flags == ContextFlagsCpu::CONTEXT_MIPS {
1171 Ok(MinidumpContext::from_raw(MinidumpRawContext::Mips(ctx)))
1172 } else {
1173 Err(ContextError::ReadFailure)
1174 }
1175 }
1176 _ => Err(ContextError::UnknownCpuContext),
1177 }
1178 }
1179
1180 pub fn get_instruction_pointer(&self) -> u64 {
1181 match self.raw {
1182 MinidumpRawContext::Amd64(ref ctx) => ctx.rip,
1183 MinidumpRawContext::Arm(ref ctx) => {
1184 ctx.iregs[md::ArmRegisterNumbers::ProgramCounter as usize] as u64
1185 }
1186 MinidumpRawContext::Arm64(ref ctx) => ctx.pc,
1187 MinidumpRawContext::OldArm64(ref ctx) => ctx.pc,
1188 MinidumpRawContext::Ppc(ref ctx) => ctx.srr0 as u64,
1189 MinidumpRawContext::Ppc64(ref ctx) => ctx.srr0,
1190 MinidumpRawContext::Sparc(ref ctx) => ctx.pc,
1191 MinidumpRawContext::X86(ref ctx) => ctx.eip as u64,
1192 MinidumpRawContext::Mips(ref ctx) => ctx.epc,
1193 }
1194 }
1195
1196 pub fn get_stack_pointer(&self) -> u64 {
1197 match self.raw {
1198 MinidumpRawContext::Amd64(ref ctx) => ctx.rsp,
1199 MinidumpRawContext::Arm(ref ctx) => {
1200 ctx.iregs[md::ArmRegisterNumbers::StackPointer as usize] as u64
1201 }
1202 MinidumpRawContext::Arm64(ref ctx) => ctx.sp,
1203 MinidumpRawContext::OldArm64(ref ctx) => ctx.sp,
1204 MinidumpRawContext::Ppc(ref ctx) => {
1205 ctx.gpr[md::PpcRegisterNumbers::StackPointer as usize] as u64
1206 }
1207 MinidumpRawContext::Ppc64(ref ctx) => {
1208 ctx.gpr[md::Ppc64RegisterNumbers::StackPointer as usize]
1209 }
1210 MinidumpRawContext::Sparc(ref ctx) => {
1211 ctx.g_r[md::SparcRegisterNumbers::StackPointer as usize]
1212 }
1213 MinidumpRawContext::X86(ref ctx) => ctx.esp as u64,
1214 MinidumpRawContext::Mips(ref ctx) => {
1215 ctx.iregs[md::MipsRegisterNumbers::StackPointer as usize]
1216 }
1217 }
1218 }
1219
1220 pub fn get_register_always(&self, reg: &str) -> u64 {
1221 match self.raw {
1222 MinidumpRawContext::Amd64(ref ctx) => ctx.get_register_always(reg),
1223 MinidumpRawContext::Arm(ref ctx) => ctx.get_register_always(reg).into(),
1224 MinidumpRawContext::Arm64(ref ctx) => ctx.get_register_always(reg),
1225 MinidumpRawContext::OldArm64(ref ctx) => ctx.get_register_always(reg),
1226 MinidumpRawContext::Ppc(ref ctx) => ctx.get_register_always(reg).into(),
1227 MinidumpRawContext::Ppc64(ref ctx) => ctx.get_register_always(reg),
1228 MinidumpRawContext::Sparc(ref ctx) => ctx.get_register_always(reg),
1229 MinidumpRawContext::X86(ref ctx) => ctx.get_register_always(reg).into(),
1230 MinidumpRawContext::Mips(ref ctx) => ctx.get_register_always(reg),
1231 }
1232 }
1233
1234 pub fn get_register(&self, reg: &str) -> Option<u64> {
1235 let valid = match &self.raw {
1236 MinidumpRawContext::X86(ctx) => ctx.register_is_valid(reg, &self.valid),
1237 MinidumpRawContext::Ppc(ctx) => ctx.register_is_valid(reg, &self.valid),
1238 MinidumpRawContext::Ppc64(ctx) => ctx.register_is_valid(reg, &self.valid),
1239 MinidumpRawContext::Amd64(ctx) => ctx.register_is_valid(reg, &self.valid),
1240 MinidumpRawContext::Sparc(ctx) => ctx.register_is_valid(reg, &self.valid),
1241 MinidumpRawContext::Arm(ctx) => ctx.register_is_valid(reg, &self.valid),
1242 MinidumpRawContext::Arm64(ctx) => ctx.register_is_valid(reg, &self.valid),
1243 MinidumpRawContext::OldArm64(ctx) => ctx.register_is_valid(reg, &self.valid),
1244 MinidumpRawContext::Mips(ctx) => ctx.register_is_valid(reg, &self.valid),
1245 };
1246
1247 if valid {
1248 Some(self.get_register_always(reg))
1249 } else {
1250 None
1251 }
1252 }
1253
1254 pub fn format_register(&self, reg: &str) -> String {
1255 match self.raw {
1256 MinidumpRawContext::Amd64(ref ctx) => ctx.format_register(reg),
1257 MinidumpRawContext::Arm(ref ctx) => ctx.format_register(reg),
1258 MinidumpRawContext::Arm64(ref ctx) => ctx.format_register(reg),
1259 MinidumpRawContext::OldArm64(ref ctx) => ctx.format_register(reg),
1260 MinidumpRawContext::Ppc(ref ctx) => ctx.format_register(reg),
1261 MinidumpRawContext::Ppc64(ref ctx) => ctx.format_register(reg),
1262 MinidumpRawContext::Sparc(ref ctx) => ctx.format_register(reg),
1263 MinidumpRawContext::X86(ref ctx) => ctx.format_register(reg),
1264 MinidumpRawContext::Mips(ref ctx) => ctx.format_register(reg),
1265 }
1266 }
1267
1268 pub fn general_purpose_registers(&self) -> &'static [&'static str] {
1269 match self.raw {
1270 MinidumpRawContext::Amd64(_) => md::CONTEXT_AMD64::REGISTERS,
1271 MinidumpRawContext::Arm(_) => md::CONTEXT_ARM::REGISTERS,
1272 MinidumpRawContext::Arm64(_) => md::CONTEXT_ARM64::REGISTERS,
1273 MinidumpRawContext::OldArm64(_) => md::CONTEXT_ARM64::REGISTERS,
1274 MinidumpRawContext::Ppc(_) => md::CONTEXT_PPC::REGISTERS,
1275 MinidumpRawContext::Ppc64(_) => md::CONTEXT_PPC64::REGISTERS,
1276 MinidumpRawContext::Sparc(_) => md::CONTEXT_SPARC::REGISTERS,
1277 MinidumpRawContext::X86(_) => md::CONTEXT_X86::REGISTERS,
1278 MinidumpRawContext::Mips(_) => md::CONTEXT_MIPS::REGISTERS,
1279 }
1280 }
1281
1282 pub fn registers(&self) -> impl Iterator<Item = (&'static str, u64)> + '_ {
1283 self.general_purpose_registers()
1284 .iter()
1285 .map(move |®| (reg, self.get_register_always(reg)))
1286 }
1287
1288 pub fn valid_registers(&self) -> impl Iterator<Item = (&'static str, u64)> + '_ {
1289 self.registers().filter(move |(reg, _)| match &self.raw {
1293 MinidumpRawContext::X86(ctx) => ctx.register_is_valid(reg, &self.valid),
1294 MinidumpRawContext::Ppc(ctx) => ctx.register_is_valid(reg, &self.valid),
1295 MinidumpRawContext::Ppc64(ctx) => ctx.register_is_valid(reg, &self.valid),
1296 MinidumpRawContext::Amd64(ctx) => ctx.register_is_valid(reg, &self.valid),
1297 MinidumpRawContext::Sparc(ctx) => ctx.register_is_valid(reg, &self.valid),
1298 MinidumpRawContext::Arm(ctx) => ctx.register_is_valid(reg, &self.valid),
1299 MinidumpRawContext::Arm64(ctx) => ctx.register_is_valid(reg, &self.valid),
1300 MinidumpRawContext::OldArm64(ctx) => ctx.register_is_valid(reg, &self.valid),
1301 MinidumpRawContext::Mips(ctx) => ctx.register_is_valid(reg, &self.valid),
1302 })
1303 }
1304
1305 pub fn register_size(&self) -> usize {
1307 fn get<T: CpuContext>(_: &T) -> usize {
1308 std::mem::size_of::<T::Register>()
1309 }
1310
1311 match &self.raw {
1312 MinidumpRawContext::X86(ctx) => get(ctx),
1313 MinidumpRawContext::Ppc(ctx) => get(ctx),
1314 MinidumpRawContext::Ppc64(ctx) => get(ctx),
1315 MinidumpRawContext::Amd64(ctx) => get(ctx),
1316 MinidumpRawContext::Sparc(ctx) => get(ctx),
1317 MinidumpRawContext::Arm(ctx) => get(ctx),
1318 MinidumpRawContext::Arm64(ctx) => get(ctx),
1319 MinidumpRawContext::OldArm64(ctx) => get(ctx),
1320 MinidumpRawContext::Mips(ctx) => get(ctx),
1321 }
1322 }
1323
1324 pub fn print<T: Write>(&self, f: &mut T) -> io::Result<()> {
1328 match self.raw {
1329 MinidumpRawContext::X86(ref raw) => {
1330 write!(
1331 f,
1332 r#"CONTEXT_X86
1333 context_flags = {:#x}
1334 dr0 = {:#x}
1335 dr1 = {:#x}
1336 dr2 = {:#x}
1337 dr3 = {:#x}
1338 dr6 = {:#x}
1339 dr7 = {:#x}
1340 float_save.control_word = {:#x}
1341 float_save.status_word = {:#x}
1342 float_save.tag_word = {:#x}
1343 float_save.error_offset = {:#x}
1344 float_save.error_selector = {:#x}
1345 float_save.data_offset = {:#x}
1346 float_save.data_selector = {:#x}
1347 float_save.register_area[{:2}] = 0x"#,
1348 raw.context_flags,
1349 raw.dr0,
1350 raw.dr1,
1351 raw.dr2,
1352 raw.dr3,
1353 raw.dr6,
1354 raw.dr7,
1355 raw.float_save.control_word,
1356 raw.float_save.status_word,
1357 raw.float_save.tag_word,
1358 raw.float_save.error_offset,
1359 raw.float_save.error_selector,
1360 raw.float_save.data_offset,
1361 raw.float_save.data_selector,
1362 raw.float_save.register_area.len(),
1363 )?;
1364 write_bytes(f, &raw.float_save.register_area)?;
1365 writeln!(f)?;
1366 write!(
1367 f,
1368 r#" float_save.cr0_npx_state = {:#x}
1369 gs = {:#x}
1370 fs = {:#x}
1371 es = {:#x}
1372 ds = {:#x}
1373 edi = {:#x}
1374 esi = {:#x}
1375 ebx = {:#x}
1376 edx = {:#x}
1377 ecx = {:#x}
1378 eax = {:#x}
1379 ebp = {:#x}
1380 eip = {:#x}
1381 cs = {:#x}
1382 eflags = {:#x}
1383 esp = {:#x}
1384 ss = {:#x}
1385 extended_registers[{:3}] = 0x"#,
1386 raw.float_save.cr0_npx_state,
1387 raw.gs,
1388 raw.fs,
1389 raw.es,
1390 raw.ds,
1391 raw.edi,
1392 raw.esi,
1393 raw.ebx,
1394 raw.edx,
1395 raw.ecx,
1396 raw.eax,
1397 raw.ebp,
1398 raw.eip,
1399 raw.cs,
1400 raw.eflags,
1401 raw.esp,
1402 raw.ss,
1403 raw.extended_registers.len(),
1404 )?;
1405 write_bytes(f, &raw.extended_registers)?;
1406 write!(f, "\n\n")?;
1407 }
1408 MinidumpRawContext::Ppc(_) => {
1409 unimplemented!();
1410 }
1411 MinidumpRawContext::Ppc64(_) => {
1412 unimplemented!();
1413 }
1414 MinidumpRawContext::Amd64(ref raw) => {
1415 write!(
1416 f,
1417 r#"CONTEXT_AMD64
1418 p1_home = {:#x}
1419 p2_home = {:#x}
1420 p3_home = {:#x}
1421 p4_home = {:#x}
1422 p5_home = {:#x}
1423 p6_home = {:#x}
1424 context_flags = {:#x}
1425 mx_csr = {:#x}
1426 cs = {:#x}
1427 ds = {:#x}
1428 es = {:#x}
1429 fs = {:#x}
1430 gs = {:#x}
1431 ss = {:#x}
1432 eflags = {:#x}
1433 dr0 = {:#x}
1434 dr1 = {:#x}
1435 dr2 = {:#x}
1436 dr3 = {:#x}
1437 dr6 = {:#x}
1438 dr7 = {:#x}
1439 rax = {:#x}
1440 rcx = {:#x}
1441 rdx = {:#x}
1442 rbx = {:#x}
1443 rsp = {:#x}
1444 rbp = {:#x}
1445 rsi = {:#x}
1446 rdi = {:#x}
1447 r8 = {:#x}
1448 r9 = {:#x}
1449 r10 = {:#x}
1450 r11 = {:#x}
1451 r12 = {:#x}
1452 r13 = {:#x}
1453 r14 = {:#x}
1454 r15 = {:#x}
1455 rip = {:#x}
1456
1457"#,
1458 raw.p1_home,
1459 raw.p2_home,
1460 raw.p3_home,
1461 raw.p4_home,
1462 raw.p5_home,
1463 raw.p6_home,
1464 raw.context_flags,
1465 raw.mx_csr,
1466 raw.cs,
1467 raw.ds,
1468 raw.es,
1469 raw.fs,
1470 raw.gs,
1471 raw.ss,
1472 raw.eflags,
1473 raw.dr0,
1474 raw.dr1,
1475 raw.dr2,
1476 raw.dr3,
1477 raw.dr6,
1478 raw.dr7,
1479 raw.rax,
1480 raw.rcx,
1481 raw.rdx,
1482 raw.rbx,
1483 raw.rsp,
1484 raw.rbp,
1485 raw.rsi,
1486 raw.rdi,
1487 raw.r8,
1488 raw.r9,
1489 raw.r10,
1490 raw.r11,
1491 raw.r12,
1492 raw.r13,
1493 raw.r14,
1494 raw.r15,
1495 raw.rip,
1496 )?;
1497 }
1498 MinidumpRawContext::Sparc(_) => {
1499 unimplemented!();
1500 }
1501 MinidumpRawContext::Arm(ref raw) => {
1502 write!(
1503 f,
1504 r#"CONTEXT_ARM
1505 context_flags = {:#x}
1506"#,
1507 raw.context_flags
1508 )?;
1509 for (i, reg) in raw.iregs.iter().enumerate() {
1510 writeln!(f, " iregs[{i:2}] = {reg:#x}")?;
1511 }
1512 write!(
1513 f,
1514 r#" cpsr = {:#x}
1515 float_save.fpscr = {:#x}
1516"#,
1517 raw.cpsr, raw.float_save.fpscr
1518 )?;
1519 for (i, reg) in raw.float_save.regs.iter().enumerate() {
1520 writeln!(f, " float_save.regs[{i:2}] = {reg:#x}")?;
1521 }
1522 for (i, reg) in raw.float_save.extra.iter().enumerate() {
1523 writeln!(f, " float_save.extra[{i:2}] = {reg:#x}")?;
1524 }
1525 }
1526 MinidumpRawContext::Arm64(ref raw) => {
1527 write!(
1528 f,
1529 r#"CONTEXT_ARM64
1530 context_flags = {:#x}
1531"#,
1532 raw.context_flags
1533 )?;
1534 for (i, reg) in raw.iregs[..29].iter().enumerate() {
1535 writeln!(f, " x{i:<2} = {reg:#x}")?;
1536 }
1537 writeln!(f, " x29 (fp) = {:#x}", raw.iregs[29])?;
1538 writeln!(f, " x30 (lr) = {:#x}", raw.iregs[30])?;
1539 writeln!(f, " sp = {:#x}", raw.sp)?;
1540 writeln!(f, " pc = {:#x}", raw.pc)?;
1541 writeln!(f, " cpsr = {:#x}", raw.cpsr)?;
1542 writeln!(f, " fpsr = {:#x}", raw.fpsr)?;
1543 writeln!(f, " fpcr = {:#x}", raw.fpcr)?;
1544 for (i, reg) in raw.float_regs.iter().enumerate() {
1545 writeln!(f, " d{i:<2} = {reg:#x}")?;
1546 }
1547 for (i, reg) in raw.bcr.iter().enumerate() {
1548 writeln!(f, " bcr[{i:2}] = {reg:#x}")?;
1549 }
1550 for (i, reg) in raw.bvr.iter().enumerate() {
1551 writeln!(f, " bvr[{i:2}] = {reg:#x}")?;
1552 }
1553 for (i, reg) in raw.wcr.iter().enumerate() {
1554 writeln!(f, " wcr[{i:2}] = {reg:#x}")?;
1555 }
1556 for (i, reg) in raw.wvr.iter().enumerate() {
1557 writeln!(f, " wvr[{i:2}] = {reg:#x}")?;
1558 }
1559 }
1560 MinidumpRawContext::OldArm64(ref raw) => {
1561 write!(
1562 f,
1563 r#"CONTEXT_ARM64_OLD
1564 context_flags = {:#x}
1565"#,
1566 raw.context_flags
1567 )?;
1568 for (i, reg) in raw.iregs[..29].iter().enumerate() {
1569 writeln!(f, " x{i:<2} = {reg:#x}")?;
1570 }
1571 writeln!(f, " x29 (fp) = {:#x}", raw.iregs[29])?;
1572 writeln!(f, " x30 (lr) = {:#x}", raw.iregs[30])?;
1573 writeln!(f, " sp = {:#x}", raw.sp)?;
1574 writeln!(f, " pc = {:#x}", raw.pc)?;
1575 writeln!(f, " cpsr = {:#x}", raw.cpsr)?;
1576 writeln!(f, " fpsr = {:#x}", raw.fpsr)?;
1577 writeln!(f, " fpcr = {:#x}", raw.fpcr)?;
1578 for (i, reg) in raw.float_regs.iter().enumerate() {
1579 writeln!(f, " d{i:<2} = {reg:#x}")?;
1580 }
1581 }
1582 MinidumpRawContext::Mips(ref raw) => {
1583 write!(
1584 f,
1585 r#"CONTEXT_MIPS
1586 context_flags = {:#x}
1587"#,
1588 raw.context_flags
1589 )?;
1590
1591 use md::MipsRegisterNumbers;
1592 const MIPS_REGS: &[MipsRegisterNumbers] = &[
1593 MipsRegisterNumbers::S0,
1594 MipsRegisterNumbers::S1,
1595 MipsRegisterNumbers::S2,
1596 MipsRegisterNumbers::S3,
1597 MipsRegisterNumbers::S4,
1598 MipsRegisterNumbers::S5,
1599 MipsRegisterNumbers::S6,
1600 MipsRegisterNumbers::S7,
1601 MipsRegisterNumbers::GlobalPointer,
1602 MipsRegisterNumbers::StackPointer,
1603 MipsRegisterNumbers::FramePointer,
1604 MipsRegisterNumbers::ReturnAddress,
1605 ];
1606 for reg in MIPS_REGS {
1607 writeln!(
1608 f,
1609 r#" {} = {:#x}"#,
1610 reg.name(),
1611 raw.iregs[*reg as usize]
1612 )?;
1613 }
1614 }
1615 }
1616 Ok(())
1617 }
1618}
1619
1620#[cfg(test)]
1621mod tests {
1622 use super::*;
1623
1624 #[test]
1625 fn test_memoize_amd64() {
1627 let context = md::CONTEXT_AMD64::default();
1628 assert_eq!(context.memoize_register("rip"), Some("rip"));
1629 assert_eq!(context.memoize_register("foo"), None);
1630 }
1631
1632 #[test]
1633 fn test_memoize_arm_alias() {
1635 let context = md::CONTEXT_ARM::default();
1636 assert_eq!(context.memoize_register("r11"), Some("fp"));
1637 assert_eq!(context.memoize_register("fp"), Some("fp"));
1638 assert_eq!(context.memoize_register("foo"), None);
1639 }
1640
1641 #[test]
1642 fn test_memoize_arm64_alias() {
1644 let context = md::CONTEXT_ARM64::default();
1645 assert_eq!(context.memoize_register("x29"), Some("fp"));
1646 assert_eq!(context.memoize_register("fp"), Some("fp"));
1647 assert_eq!(context.memoize_register("foo"), None);
1648 }
1649}