minidump/
context.rs

1// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3
4//! CPU contexts.
5
6use 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/// The CPU-specific context structure.
21#[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
35/// Generic over the specifics of a CPU context.
36pub trait CpuContext {
37    /// The word size of general-purpose registers in the context.
38    type Register: fmt::LowerHex;
39
40    /// General purpose registers in this context type.
41    const REGISTERS: &'static [&'static str];
42
43    /// Gets whether the given register is valid
44    ///
45    /// This is exposed so that the context can map aliases. For instance
46    /// "lr" and "x30" are aliases in ARM64.
47    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    /// Get a register value if it is valid.
56    ///
57    /// Get the value of the register named `reg` from this CPU context
58    /// if `valid` indicates that it has a valid value, otherwise return
59    /// `None`.
60    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    /// Get a register value regardless of whether it is valid.
69    fn get_register_always(&self, reg: &str) -> Self::Register;
70
71    /// Set a register value, if that register name it exists.
72    ///
73    /// Returns None if the register name isn't supported.
74    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()>;
75
76    /// Gets a static version of the given register name, if possible.
77    ///
78    /// Returns the default name of the register for register name aliases.
79    fn memoize_register(&self, reg: &str) -> Option<&'static str> {
80        default_memoize_register(Self::REGISTERS, reg)
81    }
82
83    /// Return a String containing the value of `reg` formatted to its natural width.
84    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    /// An iterator over all registers in this context.
93    ///
94    /// This iterator yields registers and values regardless of whether the register is valid. To
95    /// get valid values, use [`valid_registers`](Self::valid_registers), instead.
96    fn registers(&self) -> CpuRegisters<'_, Self> {
97        self.valid_registers(&MinidumpContextValidity::All)
98    }
99
100    /// An iterator over valid registers in this context.
101    ///
102    /// This iterator yields valid registers and their values.
103    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    /// Gets the name of the stack pointer register (for use with get_register/set_register).
116    fn stack_pointer_register_name(&self) -> &'static str;
117
118    /// Gets the name of the instruction pointer register (for use with get_register/set_register).
119    fn instruction_pointer_register_name(&self) -> &'static str;
120}
121
122/// Default implementation for `CpuContext::memoize_register`.
123fn 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/// An iterator over registers and values in a [`CpuContext`].
135///
136/// Returned by [`CpuContext::registers`] and [`CpuContext::valid_registers`].
137#[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" // alias out register o6
984    }
985
986    fn instruction_pointer_register_name(&self) -> &'static str {
987        "pc"
988    }
989}
990
991/// Information about which registers are valid in a `MinidumpContext`.
992#[derive(Clone, Debug, PartialEq, Eq)]
993pub enum MinidumpContextValidity {
994    // All registers are valid.
995    All,
996    // The registers in this set are valid.
997    Some(HashSet<&'static str>),
998}
999
1000/// CPU context such as register states.
1001///
1002/// MinidumpContext carries a CPU-specific MDRawContext structure, which
1003/// contains CPU context such as register states.  Each thread has its
1004/// own context, and the exception record, if present, also has its own
1005/// context.  Note that if the exception record is present, the context it
1006/// refers to is probably what the user wants to use for the exception
1007/// thread, instead of that thread's own context.  The exception thread's
1008/// context (as opposed to the exception record's context) will contain
1009/// context for the exception handler (which performs minidump generation),
1010/// and not the context that caused the exception (which is probably what the
1011/// user wants).
1012#[derive(Debug, Clone)]
1013pub struct MinidumpContext {
1014    /// The raw CPU register state.
1015    pub raw: MinidumpRawContext,
1016    /// Which registers are valid in `raw`.
1017    pub valid: MinidumpContextValidity,
1018}
1019
1020/// Errors encountered while reading a `MinidumpContext`.
1021#[derive(Debug)]
1022pub enum ContextError {
1023    /// Failed to read data.
1024    ReadFailure,
1025    /// Encountered an unknown CPU context.
1026    UnknownCpuContext,
1027}
1028
1029//======================================================
1030// Implementations
1031
1032impl MinidumpContext {
1033    /// Return a MinidumpContext given a `MinidumpRawContext`.
1034    pub fn from_raw(raw: MinidumpRawContext) -> MinidumpContext {
1035        MinidumpContext {
1036            raw,
1037            valid: MinidumpContextValidity::All,
1038        }
1039    }
1040
1041    /// Read a `MinidumpContext` from `bytes`.
1042    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        // Although every context contains `context_flags` which tell us what kind
1053        // ok context we're handling, they aren't all in the same location, so we
1054        // need to use SystemInfo to choose what kind of context to parse this as.
1055        // We can then use the `context_flags` to validate our parse.
1056        // We need to use the raw processor_architecture because system_info.cpu
1057        // flattens away some key distinctions for this code.
1058        match md::ProcessorArchitecture::from_u16(system_info.raw.processor_architecture) {
1059            Some(PROCESSOR_ARCHITECTURE_INTEL) | Some(PROCESSOR_ARCHITECTURE_IA32_ON_WIN64) => {
1060                // Not 100% sure IA32_ON_WIN64 is this format, but let's assume so?
1061                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                        // FIXME: uses MISC_INFO_5 to parse out extra sections here
1069                        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                        // FIXME: uses MISC_INFO_5 to parse out extra sections here
1085                        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| (reg, self.get_register_always(reg)))
1286    }
1287
1288    pub fn valid_registers(&self) -> impl Iterator<Item = (&'static str, u64)> + '_ {
1289        // This is suboptimal in theory, as we could iterate over self.valid just like the original
1290        // and faster `CpuRegisters` iterator does. However, this complicates code here, and the
1291        // minimal gain in performance hasn't been worth the added complexity.
1292        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    /// Get the size (in bytes) of general-purpose registers.
1306    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    /// Write a human-readable description of this `MinidumpContext` to `f`.
1325    ///
1326    /// This is very verbose, it is the format used by `minidump_dump`.
1327    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    /// Smoke test for the default implementation of `memoize_register`.
1626    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    /// Test ARM register aliases by example of `fp`.
1634    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    /// Test ARM register aliases by example of `fp`.
1643    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}