Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL context.rs   Sprache: unbekannt

 
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! CPU contexts.

use num_traits::FromPrimitive;
use scroll::Pread;
use std::collections::HashSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::mem;
use tracing::warn;

use crate::iostuff::*;
use crate::{MinidumpMiscInfo, MinidumpSystemInfo};
use minidump_common::format as md;
use minidump_common::format::ContextFlagsCpu;

/// The CPU-specific context structure.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "arbitrary_impls", derive(arbitrary::Arbitrary))]
pub enum MinidumpRawContext {
    X86(md::CONTEXT_X86),
    Ppc(md::CONTEXT_PPC),
    Ppc64(md::CONTEXT_PPC64),
    Amd64(md::CONTEXT_AMD64),
    Sparc(md::CONTEXT_SPARC),
    Arm(md::CONTEXT_ARM),
    Arm64(md::CONTEXT_ARM64),
    OldArm64(md::CONTEXT_ARM64_OLD),
    Mips(md::CONTEXT_MIPS),
}

/// Generic over the specifics of a CPU context.
pub trait CpuContext {
    /// The word size of general-purpose registers in the context.
    type Register: fmt::LowerHex;

    /// General purpose registers in this context type.
    const REGISTERS: &'static [&'static str];

    /// Gets whether the given register is valid
    ///
    /// This is exposed so that the context can map aliases. For instance
    /// "lr" and "x30" are aliases in ARM64.
    fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
        if let MinidumpContextValidity::Some(ref which) = *valid {
            which.contains(reg)
        } else {
            self.memoize_register(reg).is_some()
        }
    }

    /// Get a register value if it is valid.
    ///
    /// Get the value of the register named `reg` from this CPU context
    /// if `valid` indicates that it has a valid value, otherwise return
    /// `None`.
    fn get_register(&self, reg: &str, valid: &MinidumpContextValidity) -> Option<Self::Register> {
        if self.register_is_valid(reg, valid) {
            Some(self.get_register_always(reg))
        } else {
            None
        }
    }

    /// Get a register value regardless of whether it is valid.
    fn get_register_always(&self, reg: &str) -> Self::Register;

    /// Set a register value, if that register name it exists.
    ///
    /// Returns None if the register name isn't supported.
    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()>;

    /// Gets a static version of the given register name, if possible.
    ///
    /// Returns the default name of the register for register name aliases.
    fn memoize_register(&self, reg: &str) -> Option<&'static str> {
        default_memoize_register(Self::REGISTERS, reg)
    }

    /// Return a String containing the value of `reg` formatted to its natural width.
    fn format_register(&self, reg: &str) -> String {
        format!(
            "0x{:01$x}",
            self.get_register_always(reg),
            mem::size_of::<Self::Register>() * 2
        )
    }

    /// An iterator over all registers in this context.
    ///
    /// This iterator yields registers and values regardless of whether the register is valid. To
    /// get valid values, use [`valid_registers`](Self::valid_registers), instead.
    fn registers(&self) -> CpuRegisters<'_, Self> {
        self.valid_registers(&MinidumpContextValidity::All)
    }

    /// An iterator over valid registers in this context.
    ///
    /// This iterator yields valid registers and their values.
    fn valid_registers<'a>(&'a self, valid: &'a MinidumpContextValidity) -> CpuRegisters<'a, Self> {
        let regs = match valid {
            MinidumpContextValidity::All => CpuRegistersInner::Slice(Self::REGISTERS.iter()),
            MinidumpContextValidity::Some(valid) => CpuRegistersInner::Set(valid.iter()),
        };

        CpuRegisters {
            regs,
            context: self,
        }
    }

    /// Gets the name of the stack pointer register (for use with get_register/set_register).
    fn stack_pointer_register_name(&self) -> &'static str;

    /// Gets the name of the instruction pointer register (for use with get_register/set_register).
    fn instruction_pointer_register_name(&self) -> &'static str;
}

/// Default implementation for `CpuContext::memoize_register`.
fn default_memoize_register(registers: &[&'static str], reg: &str) -> Option<&'static str> {
    let idx = registers.iter().position(|val| *val == reg)?;
    Some(registers[idx])
}

#[derive(Debug, Clone)]
enum CpuRegistersInner<'a> {
    Slice(std::slice::Iter<'a, &'static str>),
    Set(std::collections::hash_set::Iter<'a, &'static str>),
}

/// An iterator over registers and values in a [`CpuContext`].
///
/// Returned by [`CpuContext::registers`] and [`CpuContext::valid_registers`].
#[derive(Clone, Debug)]
pub struct CpuRegisters<'a, T: ?Sized> {
    regs: CpuRegistersInner<'a>,
    context: &'a T,
}

impl<'a, T> Iterator for CpuRegisters<'a, T>
where
    T: CpuContext,
{
    type Item = (&'static str, T::Register);

    fn next(&mut self) -> Option<Self::Item> {
        let reg = match &mut self.regs {
            CpuRegistersInner::Slice(iter) => iter.next(),
            CpuRegistersInner::Set(iter) => iter.next(),
        }?;

        Some((reg, self.context.get_register_always(reg)))
    }
}

impl CpuContext for md::CONTEXT_X86 {
    type Register = u32;

    const REGISTERS: &'static [&'static str] = &[
        "eip", "esp", "ebp", "ebx", "esi", "edi", "eax", "ecx", "edx", "eflags",
    ];

    fn get_register_always(&self, reg: &str) -> u32 {
        match reg {
            "eip" => self.eip,
            "esp" => self.esp,
            "ebp" => self.ebp,
            "ebx" => self.ebx,
            "esi" => self.esi,
            "edi" => self.edi,
            "eax" => self.eax,
            "ecx" => self.ecx,
            "edx" => self.edx,
            "eflags" => self.eflags,
            _ => unreachable!("Invalid x86 register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "eip" => self.eip = val,
            "esp" => self.esp = val,
            "ebp" => self.ebp = val,
            "ebx" => self.ebx = val,
            "esi" => self.esi = val,
            "edi" => self.edi = val,
            "eax" => self.eax = val,
            "ecx" => self.ecx = val,
            "edx" => self.edx = val,
            "eflags" => self.eflags = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "esp"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "eip"
    }
}

impl CpuContext for md::CONTEXT_AMD64 {
    type Register = u64;

    const REGISTERS: &'static [&'static str] = &[
        "rax", "rdx", "rcx", "rbx", "rsi", "rdi", "rbp", "rsp", "r8", "r9", "r10", "r11", "r12",
        "r13", "r14", "r15", "rip",
    ];

    fn get_register_always(&self, reg: &str) -> u64 {
        match reg {
            "rax" => self.rax,
            "rdx" => self.rdx,
            "rcx" => self.rcx,
            "rbx" => self.rbx,
            "rsi" => self.rsi,
            "rdi" => self.rdi,
            "rbp" => self.rbp,
            "rsp" => self.rsp,
            "r8" => self.r8,
            "r9" => self.r9,
            "r10" => self.r10,
            "r11" => self.r11,
            "r12" => self.r12,
            "r13" => self.r13,
            "r14" => self.r14,
            "r15" => self.r15,
            "rip" => self.rip,
            _ => unreachable!("Invalid x86-64 register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "rax" => self.rax = val,
            "rdx" => self.rdx = val,
            "rcx" => self.rcx = val,
            "rbx" => self.rbx = val,
            "rsi" => self.rsi = val,
            "rdi" => self.rdi = val,
            "rbp" => self.rbp = val,
            "rsp" => self.rsp = val,
            "r8" => self.r8 = val,
            "r9" => self.r9 = val,
            "r10" => self.r10 = val,
            "r11" => self.r11 = val,
            "r12" => self.r12 = val,
            "r13" => self.r13 = val,
            "r14" => self.r14 = val,
            "r15" => self.r15 = val,
            "rip" => self.rip = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "rsp"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "rip"
    }
}

impl CpuContext for md::CONTEXT_ARM {
    type Register = u32;

    const REGISTERS: &'static [&'static str] = &[
        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r12", "fp", "sp", "lr",
        "pc",
    ];

    fn memoize_register(&self, reg: &str) -> Option<&'static str> {
        match reg {
            "r11" => Some("fp"),
            "r13" => Some("sp"),
            "r14" => Some("lr"),
            "r15" => Some("pc"),
            _ => default_memoize_register(Self::REGISTERS, reg),
        }
    }

    fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
        if let MinidumpContextValidity::Some(ref which) = valid {
            match reg {
                "r11" | "fp" => which.contains("r11") || which.contains("fp"),
                "r13" | "sp" => which.contains("r13") || which.contains("sp"),
                "r14" | "lr" => which.contains("r14") || which.contains("lr"),
                "r15" | "pc" => which.contains("r15") || which.contains("pc"),
                _ => which.contains(reg),
            }
        } else {
            self.memoize_register(reg).is_some()
        }
    }

    fn get_register_always(&self, reg: &str) -> u32 {
        match reg {
            "r0" => self.iregs[0],
            "r1" => self.iregs[1],
            "r2" => self.iregs[2],
            "r3" => self.iregs[3],
            "r4" => self.iregs[4],
            "r5" => self.iregs[5],
            "r6" => self.iregs[6],
            "r7" => self.iregs[7],
            "r8" => self.iregs[8],
            "r9" => self.iregs[9],
            "r10" => self.iregs[10],
            "r11" => self.iregs[11],
            "r12" => self.iregs[12],
            "r13" => self.iregs[13],
            "r14" => self.iregs[14],
            "r15" => self.iregs[15],
            "pc" => self.iregs[md::ArmRegisterNumbers::ProgramCounter as usize],
            "lr" => self.iregs[md::ArmRegisterNumbers::LinkRegister as usize],
            "fp" => self.iregs[md::ArmRegisterNumbers::FramePointer as usize],
            "sp" => self.iregs[md::ArmRegisterNumbers::StackPointer as usize],
            _ => unreachable!("Invalid arm register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "r0" => self.iregs[0] = val,
            "r1" => self.iregs[1] = val,
            "r2" => self.iregs[2] = val,
            "r3" => self.iregs[3] = val,
            "r4" => self.iregs[4] = val,
            "r5" => self.iregs[5] = val,
            "r6" => self.iregs[6] = val,
            "r7" => self.iregs[7] = val,
            "r8" => self.iregs[8] = val,
            "r9" => self.iregs[9] = val,
            "r10" => self.iregs[10] = val,
            "r11" => self.iregs[11] = val,
            "r12" => self.iregs[12] = val,
            "r13" => self.iregs[13] = val,
            "r14" => self.iregs[14] = val,
            "r15" => self.iregs[15] = val,
            "pc" => self.iregs[md::ArmRegisterNumbers::ProgramCounter as usize] = val,
            "lr" => self.iregs[md::ArmRegisterNumbers::LinkRegister as usize] = val,
            "fp" => self.iregs[md::ArmRegisterNumbers::FramePointer as usize] = val,
            "sp" => self.iregs[md::ArmRegisterNumbers::StackPointer as usize] = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "sp"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "pc"
    }
}

impl CpuContext for md::CONTEXT_ARM64_OLD {
    type Register = u64;

    const REGISTERS: &'static [&'static str] = &[
        "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13",
        "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26",
        "x27", "x28", "fp", "lr", "sp", "pc",
    ];

    fn memoize_register(&self, reg: &str) -> Option<&'static str> {
        match reg {
            "x29" => Some("fp"),
            "x30" => Some("lr"),
            _ => default_memoize_register(Self::REGISTERS, reg),
        }
    }

    fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
        if let MinidumpContextValidity::Some(ref which) = valid {
            match reg {
                "x29" | "fp" => which.contains("x29") || which.contains("fp"),
                "x30" | "lr" => which.contains("x30") || which.contains("lr"),
                _ => which.contains(reg),
            }
        } else {
            self.memoize_register(reg).is_some()
        }
    }

    fn get_register_always(&self, reg: &str) -> u64 {
        match reg {
            "x0" => self.iregs[0],
            "x1" => self.iregs[1],
            "x2" => self.iregs[2],
            "x3" => self.iregs[3],
            "x4" => self.iregs[4],
            "x5" => self.iregs[5],
            "x6" => self.iregs[6],
            "x7" => self.iregs[7],
            "x8" => self.iregs[8],
            "x9" => self.iregs[9],
            "x10" => self.iregs[10],
            "x11" => self.iregs[11],
            "x12" => self.iregs[12],
            "x13" => self.iregs[13],
            "x14" => self.iregs[14],
            "x15" => self.iregs[15],
            "x16" => self.iregs[16],
            "x17" => self.iregs[17],
            "x18" => self.iregs[18],
            "x19" => self.iregs[19],
            "x20" => self.iregs[20],
            "x21" => self.iregs[21],
            "x22" => self.iregs[22],
            "x23" => self.iregs[23],
            "x24" => self.iregs[24],
            "x25" => self.iregs[25],
            "x26" => self.iregs[26],
            "x27" => self.iregs[27],
            "x28" => self.iregs[28],
            "x29" => self.iregs[29],
            "x30" => self.iregs[30],
            "pc" => self.pc,
            "sp" => self.sp,
            "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize],
            "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize],
            _ => unreachable!("Invalid aarch64 register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "x0" => self.iregs[0] = val,
            "x1" => self.iregs[1] = val,
            "x2" => self.iregs[2] = val,
            "x3" => self.iregs[3] = val,
            "x4" => self.iregs[4] = val,
            "x5" => self.iregs[5] = val,
            "x6" => self.iregs[6] = val,
            "x7" => self.iregs[7] = val,
            "x8" => self.iregs[8] = val,
            "x9" => self.iregs[9] = val,
            "x10" => self.iregs[10] = val,
            "x11" => self.iregs[11] = val,
            "x12" => self.iregs[12] = val,
            "x13" => self.iregs[13] = val,
            "x14" => self.iregs[14] = val,
            "x15" => self.iregs[15] = val,
            "x16" => self.iregs[16] = val,
            "x17" => self.iregs[17] = val,
            "x18" => self.iregs[18] = val,
            "x19" => self.iregs[19] = val,
            "x20" => self.iregs[20] = val,
            "x21" => self.iregs[21] = val,
            "x22" => self.iregs[22] = val,
            "x23" => self.iregs[23] = val,
            "x24" => self.iregs[24] = val,
            "x25" => self.iregs[25] = val,
            "x26" => self.iregs[26] = val,
            "x27" => self.iregs[27] = val,
            "x28" => self.iregs[28] = val,
            "x29" => self.iregs[29] = val,
            "x30" => self.iregs[30] = val,
            "pc" => self.pc = val,
            "sp" => self.sp = val,
            "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize] = val,
            "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize] = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "sp"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "pc"
    }
}

impl CpuContext for md::CONTEXT_ARM64 {
    type Register = u64;

    const REGISTERS: &'static [&'static str] = &[
        "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13",
        "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26",
        "x27", "x28", "fp", "lr", "sp", "pc",
    ];

    fn memoize_register(&self, reg: &str) -> Option<&'static str> {
        match reg {
            "x29" => Some("fp"),
            "x30" => Some("lr"),
            _ => default_memoize_register(Self::REGISTERS, reg),
        }
    }

    fn register_is_valid(&self, reg: &str, valid: &MinidumpContextValidity) -> bool {
        if let MinidumpContextValidity::Some(ref which) = valid {
            match reg {
                "x29" | "fp" => which.contains("x29") || which.contains("fp"),
                "x30" | "lr" => which.contains("x30") || which.contains("lr"),
                _ => which.contains(reg),
            }
        } else {
            self.memoize_register(reg).is_some()
        }
    }

    fn get_register_always(&self, reg: &str) -> u64 {
        match reg {
            "x0" => self.iregs[0],
            "x1" => self.iregs[1],
            "x2" => self.iregs[2],
            "x3" => self.iregs[3],
            "x4" => self.iregs[4],
            "x5" => self.iregs[5],
            "x6" => self.iregs[6],
            "x7" => self.iregs[7],
            "x8" => self.iregs[8],
            "x9" => self.iregs[9],
            "x10" => self.iregs[10],
            "x11" => self.iregs[11],
            "x12" => self.iregs[12],
            "x13" => self.iregs[13],
            "x14" => self.iregs[14],
            "x15" => self.iregs[15],
            "x16" => self.iregs[16],
            "x17" => self.iregs[17],
            "x18" => self.iregs[18],
            "x19" => self.iregs[19],
            "x20" => self.iregs[20],
            "x21" => self.iregs[21],
            "x22" => self.iregs[22],
            "x23" => self.iregs[23],
            "x24" => self.iregs[24],
            "x25" => self.iregs[25],
            "x26" => self.iregs[26],
            "x27" => self.iregs[27],
            "x28" => self.iregs[28],
            "x29" => self.iregs[29],
            "x30" => self.iregs[30],
            "pc" => self.pc,
            "sp" => self.sp,
            "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize],
            "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize],
            _ => unreachable!("Invalid aarch64 register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "x0" => self.iregs[0] = val,
            "x1" => self.iregs[1] = val,
            "x2" => self.iregs[2] = val,
            "x3" => self.iregs[3] = val,
            "x4" => self.iregs[4] = val,
            "x5" => self.iregs[5] = val,
            "x6" => self.iregs[6] = val,
            "x7" => self.iregs[7] = val,
            "x8" => self.iregs[8] = val,
            "x9" => self.iregs[9] = val,
            "x10" => self.iregs[10] = val,
            "x11" => self.iregs[11] = val,
            "x12" => self.iregs[12] = val,
            "x13" => self.iregs[13] = val,
            "x14" => self.iregs[14] = val,
            "x15" => self.iregs[15] = val,
            "x16" => self.iregs[16] = val,
            "x17" => self.iregs[17] = val,
            "x18" => self.iregs[18] = val,
            "x19" => self.iregs[19] = val,
            "x20" => self.iregs[20] = val,
            "x21" => self.iregs[21] = val,
            "x22" => self.iregs[22] = val,
            "x23" => self.iregs[23] = val,
            "x24" => self.iregs[24] = val,
            "x25" => self.iregs[25] = val,
            "x26" => self.iregs[26] = val,
            "x27" => self.iregs[27] = val,
            "x28" => self.iregs[28] = val,
            "x29" => self.iregs[29] = val,
            "x30" => self.iregs[30] = val,
            "pc" => self.pc = val,
            "sp" => self.sp = val,
            "lr" => self.iregs[md::Arm64RegisterNumbers::LinkRegister as usize] = val,
            "fp" => self.iregs[md::Arm64RegisterNumbers::FramePointer as usize] = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "sp"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "pc"
    }
}

impl CpuContext for md::CONTEXT_PPC {
    type Register = u32;

    const REGISTERS: &'static [&'static str] = &[
        "srr0", "srr1", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
        "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24",
        "r25", "r26", "r27", "r28", "r29", "r30", "r31", "cr", "xer", "lr", "ctr", "mq", "vrsave",
    ];

    fn get_register_always(&self, reg: &str) -> Self::Register {
        match reg {
            "srr0" => self.srr0,
            "srr1" => self.srr1,
            "r0" => self.gpr[0],
            "r1" => self.gpr[1],
            "r2" => self.gpr[2],
            "r3" => self.gpr[3],
            "r4" => self.gpr[4],
            "r5" => self.gpr[5],
            "r6" => self.gpr[6],
            "r7" => self.gpr[7],
            "r8" => self.gpr[8],
            "r9" => self.gpr[9],
            "r10" => self.gpr[10],
            "r11" => self.gpr[11],
            "r12" => self.gpr[12],
            "r13" => self.gpr[13],
            "r14" => self.gpr[14],
            "r15" => self.gpr[15],
            "r16" => self.gpr[16],
            "r17" => self.gpr[17],
            "r18" => self.gpr[18],
            "r19" => self.gpr[19],
            "r20" => self.gpr[20],
            "r21" => self.gpr[21],
            "r22" => self.gpr[22],
            "r23" => self.gpr[23],
            "r24" => self.gpr[24],
            "r25" => self.gpr[25],
            "r26" => self.gpr[26],
            "r27" => self.gpr[27],
            "r28" => self.gpr[28],
            "r29" => self.gpr[29],
            "r30" => self.gpr[30],
            "r31" => self.gpr[31],
            "cr" => self.cr,
            "xer" => self.xer,
            "lr" => self.lr,
            "ctr" => self.ctr,
            "mq" => self.mq,
            "vrsave" => self.vrsave,
            _ => unreachable!("Invalid ppc register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "srr0" => self.srr0 = val,
            "srr1" => self.srr1 = val,
            "r0" => self.gpr[0] = val,
            "r1" => self.gpr[1] = val,
            "r2" => self.gpr[2] = val,
            "r3" => self.gpr[3] = val,
            "r4" => self.gpr[4] = val,
            "r5" => self.gpr[5] = val,
            "r6" => self.gpr[6] = val,
            "r7" => self.gpr[7] = val,
            "r8" => self.gpr[8] = val,
            "r9" => self.gpr[9] = val,
            "r10" => self.gpr[10] = val,
            "r11" => self.gpr[11] = val,
            "r12" => self.gpr[12] = val,
            "r13" => self.gpr[13] = val,
            "r14" => self.gpr[14] = val,
            "r15" => self.gpr[15] = val,
            "r16" => self.gpr[16] = val,
            "r17" => self.gpr[17] = val,
            "r18" => self.gpr[18] = val,
            "r19" => self.gpr[19] = val,
            "r20" => self.gpr[20] = val,
            "r21" => self.gpr[21] = val,
            "r22" => self.gpr[22] = val,
            "r23" => self.gpr[23] = val,
            "r24" => self.gpr[24] = val,
            "r25" => self.gpr[25] = val,
            "r26" => self.gpr[26] = val,
            "r27" => self.gpr[27] = val,
            "r28" => self.gpr[28] = val,
            "r29" => self.gpr[29] = val,
            "r30" => self.gpr[30] = val,
            "r31" => self.gpr[31] = val,
            "cr" => self.cr = val,
            "xer" => self.xer = val,
            "lr" => self.lr = val,
            "ctr" => self.ctr = val,
            "mq" => self.mq = val,
            "vrsave" => self.vrsave = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "r1"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "srr0"
    }
}

impl CpuContext for md::CONTEXT_PPC64 {
    type Register = u64;

    const REGISTERS: &'static [&'static str] = &[
        "srr0", "srr1", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
        "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24",
        "r25", "r26", "r27", "r28", "r29", "r30", "r31", "cr", "xer", "lr", "ctr", "vrsave",
    ];

    fn get_register_always(&self, reg: &str) -> Self::Register {
        match reg {
            "srr0" => self.srr0,
            "srr1" => self.srr1,
            "r0" => self.gpr[0],
            "r1" => self.gpr[1],
            "r2" => self.gpr[2],
            "r3" => self.gpr[3],
            "r4" => self.gpr[4],
            "r5" => self.gpr[5],
            "r6" => self.gpr[6],
            "r7" => self.gpr[7],
            "r8" => self.gpr[8],
            "r9" => self.gpr[9],
            "r10" => self.gpr[10],
            "r11" => self.gpr[11],
            "r12" => self.gpr[12],
            "r13" => self.gpr[13],
            "r14" => self.gpr[14],
            "r15" => self.gpr[15],
            "r16" => self.gpr[16],
            "r17" => self.gpr[17],
            "r18" => self.gpr[18],
            "r19" => self.gpr[19],
            "r20" => self.gpr[20],
            "r21" => self.gpr[21],
            "r22" => self.gpr[22],
            "r23" => self.gpr[23],
            "r24" => self.gpr[24],
            "r25" => self.gpr[25],
            "r26" => self.gpr[26],
            "r27" => self.gpr[27],
            "r28" => self.gpr[28],
            "r29" => self.gpr[29],
            "r30" => self.gpr[30],
            "r31" => self.gpr[31],
            "cr" => self.cr,
            "xer" => self.xer,
            "lr" => self.lr,
            "ctr" => self.ctr,
            "vrsave" => self.vrsave,
            _ => unreachable!("Invalid ppc64 register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "srr0" => self.srr0 = val,
            "srr1" => self.srr1 = val,
            "r0" => self.gpr[0] = val,
            "r1" => self.gpr[1] = val,
            "r2" => self.gpr[2] = val,
            "r3" => self.gpr[3] = val,
            "r4" => self.gpr[4] = val,
            "r5" => self.gpr[5] = val,
            "r6" => self.gpr[6] = val,
            "r7" => self.gpr[7] = val,
            "r8" => self.gpr[8] = val,
            "r9" => self.gpr[9] = val,
            "r10" => self.gpr[10] = val,
            "r11" => self.gpr[11] = val,
            "r12" => self.gpr[12] = val,
            "r13" => self.gpr[13] = val,
            "r14" => self.gpr[14] = val,
            "r15" => self.gpr[15] = val,
            "r16" => self.gpr[16] = val,
            "r17" => self.gpr[17] = val,
            "r18" => self.gpr[18] = val,
            "r19" => self.gpr[19] = val,
            "r20" => self.gpr[20] = val,
            "r21" => self.gpr[21] = val,
            "r22" => self.gpr[22] = val,
            "r23" => self.gpr[23] = val,
            "r24" => self.gpr[24] = val,
            "r25" => self.gpr[25] = val,
            "r26" => self.gpr[26] = val,
            "r27" => self.gpr[27] = val,
            "r28" => self.gpr[28] = val,
            "r29" => self.gpr[29] = val,
            "r30" => self.gpr[30] = val,
            "r31" => self.gpr[31] = val,
            "cr" => self.cr = val,
            "xer" => self.xer = val,
            "lr" => self.lr = val,
            "ctr" => self.ctr = val,
            "vrsave" => self.vrsave = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "r1"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "srr0"
    }
}

impl CpuContext for md::CONTEXT_MIPS {
    type Register = u64;

    const REGISTERS: &'static [&'static str] = &[
        "gp", "sp", "fp", "ra", "pc", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
    ];

    fn get_register_always(&self, reg: &str) -> Self::Register {
        match reg {
            "gp" => self.iregs[md::MipsRegisterNumbers::GlobalPointer as usize],
            "sp" => self.iregs[md::MipsRegisterNumbers::StackPointer as usize],
            "fp" => self.iregs[md::MipsRegisterNumbers::FramePointer as usize],
            "ra" => self.iregs[md::MipsRegisterNumbers::ReturnAddress as usize],
            "pc" => self.epc,
            "s0" => self.iregs[md::MipsRegisterNumbers::S0 as usize],
            "s1" => self.iregs[md::MipsRegisterNumbers::S1 as usize],
            "s2" => self.iregs[md::MipsRegisterNumbers::S2 as usize],
            "s3" => self.iregs[md::MipsRegisterNumbers::S3 as usize],
            "s4" => self.iregs[md::MipsRegisterNumbers::S4 as usize],
            "s5" => self.iregs[md::MipsRegisterNumbers::S5 as usize],
            "s6" => self.iregs[md::MipsRegisterNumbers::S6 as usize],
            "s7" => self.iregs[md::MipsRegisterNumbers::S7 as usize],
            _ => unreachable!("Invalid mips register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "gp" => self.iregs[md::MipsRegisterNumbers::GlobalPointer as usize] = val,
            "sp" => self.iregs[md::MipsRegisterNumbers::StackPointer as usize] = val,
            "fp" => self.iregs[md::MipsRegisterNumbers::FramePointer as usize] = val,
            "ra" => self.iregs[md::MipsRegisterNumbers::ReturnAddress as usize] = val,
            "pc" => self.epc = val,
            "s0" => self.iregs[md::MipsRegisterNumbers::S0 as usize] = val,
            "s1" => self.iregs[md::MipsRegisterNumbers::S1 as usize] = val,
            "s2" => self.iregs[md::MipsRegisterNumbers::S2 as usize] = val,
            "s3" => self.iregs[md::MipsRegisterNumbers::S3 as usize] = val,
            "s4" => self.iregs[md::MipsRegisterNumbers::S4 as usize] = val,
            "s5" => self.iregs[md::MipsRegisterNumbers::S5 as usize] = val,
            "s6" => self.iregs[md::MipsRegisterNumbers::S6 as usize] = val,
            "s7" => self.iregs[md::MipsRegisterNumbers::S7 as usize] = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "sp"
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "pc"
    }
}

impl CpuContext for md::CONTEXT_SPARC {
    type Register = u64;

    const REGISTERS: &'static [&'static str] = &[
        "g_r0", "g_r1", "g_r2", "g_r3", "g_r4", "g_r5", "g_r6", "g_r7", "g_r8", "g_r9", "g_r10",
        "g_r11", "g_r12", "g_r13", "g_r14", "g_r15", "g_r16", "g_r17", "g_r18", "g_r19", "g_r20",
        "g_r21", "g_r22", "g_r23", "g_r24", "g_r25", "g_r26", "g_r27", "g_r28", "g_r29", "g_r30",
        "g_r31", "ccr", "pc", "npc", "y", "asi", "fprs",
    ];

    fn get_register_always(&self, reg: &str) -> Self::Register {
        match reg {
            "g_r0" | "g0" => self.g_r[0],
            "g_r1" | "g1" => self.g_r[1],
            "g_r2" | "g2" => self.g_r[2],
            "g_r3" | "g3" => self.g_r[3],
            "g_r4" | "g4" => self.g_r[4],
            "g_r5" | "g5" => self.g_r[5],
            "g_r6" | "g6" => self.g_r[6],
            "g_r7" | "g7" => self.g_r[7],
            "g_r8" | "o0" => self.g_r[8],
            "g_r9" | "o1" => self.g_r[9],
            "g_r10" | "o2" => self.g_r[10],
            "g_r11" | "o3" => self.g_r[11],
            "g_r12" | "o4" => self.g_r[12],
            "g_r13" | "o5" => self.g_r[13],
            "g_r14" | "o6" => self.g_r[14],
            "g_r15" | "o7" => self.g_r[15],
            "g_r16" | "l0" => self.g_r[16],
            "g_r17" | "l1" => self.g_r[17],
            "g_r18" | "l2" => self.g_r[18],
            "g_r19" | "l3" => self.g_r[19],
            "g_r20" | "l4" => self.g_r[20],
            "g_r21" | "l5" => self.g_r[21],
            "g_r22" | "l6" => self.g_r[22],
            "g_r23" | "l7" => self.g_r[23],
            "g_r24" | "i0" => self.g_r[24],
            "g_r25" | "i1" => self.g_r[25],
            "g_r26" | "i2" => self.g_r[26],
            "g_r27" | "i3" => self.g_r[27],
            "g_r28" | "i4" => self.g_r[28],
            "g_r29" | "i5" => self.g_r[29],
            "g_r30" | "i6" => self.g_r[30],
            "g_r31" | "i7" => self.g_r[31],
            "ccr" => self.ccr,
            "pc" => self.pc,
            "npc" => self.npc,
            "y" => self.y,
            "asi" => self.asi,
            "fprs" => self.fprs,
            _ => unreachable!("Invalid sparc register! {}", reg),
        }
    }

    fn set_register(&mut self, reg: &str, val: Self::Register) -> Option<()> {
        match reg {
            "g_r0" | "g0" => self.g_r[0] = val,
            "g_r1" | "g1" => self.g_r[1] = val,
            "g_r2" | "g2" => self.g_r[2] = val,
            "g_r3" | "g3" => self.g_r[3] = val,
            "g_r4" | "g4" => self.g_r[4] = val,
            "g_r5" | "g5" => self.g_r[5] = val,
            "g_r6" | "g6" => self.g_r[6] = val,
            "g_r7" | "g7" => self.g_r[7] = val,
            "g_r8" | "o0" => self.g_r[8] = val,
            "g_r9" | "o1" => self.g_r[9] = val,
            "g_r10" | "o2" => self.g_r[10] = val,
            "g_r11" | "o3" => self.g_r[11] = val,
            "g_r12" | "o4" => self.g_r[12] = val,
            "g_r13" | "o5" => self.g_r[13] = val,
            "g_r14" | "o6" => self.g_r[14] = val,
            "g_r15" | "o7" => self.g_r[15] = val,
            "g_r16" | "l0" => self.g_r[16] = val,
            "g_r17" | "l1" => self.g_r[17] = val,
            "g_r18" | "l2" => self.g_r[18] = val,
            "g_r19" | "l3" => self.g_r[19] = val,
            "g_r20" | "l4" => self.g_r[20] = val,
            "g_r21" | "l5" => self.g_r[21] = val,
            "g_r22" | "l6" => self.g_r[22] = val,
            "g_r23" | "l7" => self.g_r[23] = val,
            "g_r24" | "i0" => self.g_r[24] = val,
            "g_r25" | "i1" => self.g_r[25] = val,
            "g_r26" | "i2" => self.g_r[26] = val,
            "g_r27" | "i3" => self.g_r[27] = val,
            "g_r28" | "i4" => self.g_r[28] = val,
            "g_r29" | "i5" => self.g_r[29] = val,
            "g_r30" | "i6" => self.g_r[30] = val,
            "g_r31" | "i7" => self.g_r[31] = val,
            "ccr" => self.ccr = val,
            "pc" => self.pc = val,
            "npc" => self.npc = val,
            "y" => self.y = val,
            "asi" => self.asi = val,
            "fprs" => self.fprs = val,
            _ => return None,
        }
        Some(())
    }

    fn stack_pointer_register_name(&self) -> &'static str {
        "g_r14" // alias out register o6
    }

    fn instruction_pointer_register_name(&self) -> &'static str {
        "pc"
    }
}

/// Information about which registers are valid in a `MinidumpContext`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MinidumpContextValidity {
    // All registers are valid.
    All,
    // The registers in this set are valid.
    Some(HashSet<&'static str>),
}

/// CPU context such as register states.
///
/// MinidumpContext carries a CPU-specific MDRawContext structure, which
/// contains CPU context such as register states.  Each thread has its
/// own context, and the exception record, if present, also has its own
/// context.  Note that if the exception record is present, the context it
/// refers to is probably what the user wants to use for the exception
/// thread, instead of that thread's own context.  The exception thread's
/// context (as opposed to the exception record's context) will contain
/// context for the exception handler (which performs minidump generation),
/// and not the context that caused the exception (which is probably what the
/// user wants).
#[derive(Debug, Clone)]
pub struct MinidumpContext {
    /// The raw CPU register state.
    pub raw: MinidumpRawContext,
    /// Which registers are valid in `raw`.
    pub valid: MinidumpContextValidity,
}

/// Errors encountered while reading a `MinidumpContext`.
#[derive(Debug)]
pub enum ContextError {
    /// Failed to read data.
    ReadFailure,
    /// Encountered an unknown CPU context.
    UnknownCpuContext,
}

//======================================================
// Implementations

impl MinidumpContext {
    /// Return a MinidumpContext given a `MinidumpRawContext`.
    pub fn from_raw(raw: MinidumpRawContext) -> MinidumpContext {
        MinidumpContext {
            raw,
            valid: MinidumpContextValidity::All,
        }
    }

    /// Read a `MinidumpContext` from `bytes`.
    pub fn read(
        bytes: &[u8],
        endian: scroll::Endian,
        system_info: &MinidumpSystemInfo,
        _misc: Option<&MinidumpMiscInfo>,
    ) -> Result<MinidumpContext, ContextError> {
        use md::ProcessorArchitecture::*;

        let mut offset = 0;

        // Although every context contains `context_flags` which tell us what kind
        // ok context we're handling, they aren't all in the same location, so we
        // need to use SystemInfo to choose what kind of context to parse this as.
        // We can then use the `context_flags` to validate our parse.
        // We need to use the raw processor_architecture because system_info.cpu
        // flattens away some key distinctions for this code.
        match md::ProcessorArchitecture::from_u16(system_info.raw.processor_architecture) {
            Some(PROCESSOR_ARCHITECTURE_INTEL) | Some(PROCESSOR_ARCHITECTURE_IA32_ON_WIN64) => {
                // Not 100% sure IA32_ON_WIN64 is this format, but let's assume so?
                let ctx: md::CONTEXT_X86 = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_X86 {
                    if ctx.context_flags & md::CONTEXT_HAS_XSTATE != 0 {
                        // FIXME: uses MISC_INFO_5 to parse out extra sections here
                        warn!("Cpu context has extra XSTATE that is being ignored");
                    }
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::X86(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_AMD64) => {
                let ctx: md::CONTEXT_AMD64 = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_AMD64 {
                    if ctx.context_flags & md::CONTEXT_HAS_XSTATE != 0 {
                        // FIXME: uses MISC_INFO_5 to parse out extra sections here
                        warn!("Cpu context has extra XSTATE that is being ignored");
                    }
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Amd64(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_PPC) => {
                let ctx: md::CONTEXT_PPC = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_PPC {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Ppc(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_PPC64) => {
                let ctx: md::CONTEXT_PPC64 = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags as u32);
                if flags == ContextFlagsCpu::CONTEXT_PPC64 {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Ppc64(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_SPARC) => {
                let ctx: md::CONTEXT_SPARC = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_SPARC {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Sparc(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_ARM) => {
                let ctx: md::CONTEXT_ARM = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_ARM {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Arm(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_ARM64) => {
                let ctx: md::CONTEXT_ARM64 = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_ARM64 {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Arm64(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_ARM64_OLD) => {
                let ctx: md::CONTEXT_ARM64_OLD = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags as u32);
                if flags == ContextFlagsCpu::CONTEXT_ARM64_OLD {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::OldArm64(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            Some(PROCESSOR_ARCHITECTURE_MIPS) => {
                let ctx: md::CONTEXT_MIPS = bytes
                    .gread_with(&mut offset, endian)
                    .or(Err(ContextError::ReadFailure))?;

                let flags = ContextFlagsCpu::from_flags(ctx.context_flags);
                if flags == ContextFlagsCpu::CONTEXT_MIPS {
                    Ok(MinidumpContext::from_raw(MinidumpRawContext::Mips(ctx)))
                } else {
                    Err(ContextError::ReadFailure)
                }
            }
            _ => Err(ContextError::UnknownCpuContext),
        }
    }

    pub fn get_instruction_pointer(&self) -> u64 {
        match self.raw {
            MinidumpRawContext::Amd64(ref ctx) => ctx.rip,
            MinidumpRawContext::Arm(ref ctx) => {
                ctx.iregs[md::ArmRegisterNumbers::ProgramCounter as usize] as u64
            }
            MinidumpRawContext::Arm64(ref ctx) => ctx.pc,
            MinidumpRawContext::OldArm64(ref ctx) => ctx.pc,
            MinidumpRawContext::Ppc(ref ctx) => ctx.srr0 as u64,
            MinidumpRawContext::Ppc64(ref ctx) => ctx.srr0,
            MinidumpRawContext::Sparc(ref ctx) => ctx.pc,
            MinidumpRawContext::X86(ref ctx) => ctx.eip as u64,
            MinidumpRawContext::Mips(ref ctx) => ctx.epc,
        }
    }

    pub fn get_stack_pointer(&self) -> u64 {
        match self.raw {
            MinidumpRawContext::Amd64(ref ctx) => ctx.rsp,
            MinidumpRawContext::Arm(ref ctx) => {
                ctx.iregs[md::ArmRegisterNumbers::StackPointer as usize] as u64
            }
            MinidumpRawContext::Arm64(ref ctx) => ctx.sp,
            MinidumpRawContext::OldArm64(ref ctx) => ctx.sp,
            MinidumpRawContext::Ppc(ref ctx) => {
                ctx.gpr[md::PpcRegisterNumbers::StackPointer as usize] as u64
            }
            MinidumpRawContext::Ppc64(ref ctx) => {
                ctx.gpr[md::Ppc64RegisterNumbers::StackPointer as usize]
            }
            MinidumpRawContext::Sparc(ref ctx) => {
                ctx.g_r[md::SparcRegisterNumbers::StackPointer as usize]
            }
            MinidumpRawContext::X86(ref ctx) => ctx.esp as u64,
            MinidumpRawContext::Mips(ref ctx) => {
                ctx.iregs[md::MipsRegisterNumbers::StackPointer as usize]
            }
        }
    }

    pub fn get_register_always(&self, reg: &str) -> u64 {
        match self.raw {
            MinidumpRawContext::Amd64(ref ctx) => ctx.get_register_always(reg),
            MinidumpRawContext::Arm(ref ctx) => ctx.get_register_always(reg).into(),
            MinidumpRawContext::Arm64(ref ctx) => ctx.get_register_always(reg),
            MinidumpRawContext::OldArm64(ref ctx) => ctx.get_register_always(reg),
            MinidumpRawContext::Ppc(ref ctx) => ctx.get_register_always(reg).into(),
            MinidumpRawContext::Ppc64(ref ctx) => ctx.get_register_always(reg),
            MinidumpRawContext::Sparc(ref ctx) => ctx.get_register_always(reg),
            MinidumpRawContext::X86(ref ctx) => ctx.get_register_always(reg).into(),
            MinidumpRawContext::Mips(ref ctx) => ctx.get_register_always(reg),
        }
    }

    pub fn get_register(&self, reg: &str) -> Option<u64> {
        let valid = match &self.raw {
            MinidumpRawContext::X86(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Ppc(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Ppc64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Amd64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Sparc(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Arm(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Arm64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::OldArm64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Mips(ctx) => ctx.register_is_valid(reg, &self.valid),
        };

        if valid {
            Some(self.get_register_always(reg))
        } else {
            None
        }
    }

    pub fn format_register(&self, reg: &str) -> String {
        match self.raw {
            MinidumpRawContext::Amd64(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::Arm(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::Arm64(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::OldArm64(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::Ppc(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::Ppc64(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::Sparc(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::X86(ref ctx) => ctx.format_register(reg),
            MinidumpRawContext::Mips(ref ctx) => ctx.format_register(reg),
        }
    }

    pub fn general_purpose_registers(&self) -> &'static [&'static str] {
        match self.raw {
            MinidumpRawContext::Amd64(_) => md::CONTEXT_AMD64::REGISTERS,
            MinidumpRawContext::Arm(_) => md::CONTEXT_ARM::REGISTERS,
            MinidumpRawContext::Arm64(_) => md::CONTEXT_ARM64::REGISTERS,
            MinidumpRawContext::OldArm64(_) => md::CONTEXT_ARM64::REGISTERS,
            MinidumpRawContext::Ppc(_) => md::CONTEXT_PPC::REGISTERS,
            MinidumpRawContext::Ppc64(_) => md::CONTEXT_PPC64::REGISTERS,
            MinidumpRawContext::Sparc(_) => md::CONTEXT_SPARC::REGISTERS,
            MinidumpRawContext::X86(_) => md::CONTEXT_X86::REGISTERS,
            MinidumpRawContext::Mips(_) => md::CONTEXT_MIPS::REGISTERS,
        }
    }

    pub fn registers(&self) -> impl Iterator<Item = (&'static str, u64)> + '_ {
        self.general_purpose_registers()
            .iter()
            .map(move |®| (reg, self.get_register_always(reg)))
    }

    pub fn valid_registers(&self) -> impl Iterator<Item = (&'static str, u64)> + '_ {
        // This is suboptimal in theory, as we could iterate over self.valid just like the original
        // and faster `CpuRegisters` iterator does. However, this complicates code here, and the
        // minimal gain in performance hasn't been worth the added complexity.
        self.registers().filter(move |(reg, _)| match &self.raw {
            MinidumpRawContext::X86(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Ppc(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Ppc64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Amd64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Sparc(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Arm(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Arm64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::OldArm64(ctx) => ctx.register_is_valid(reg, &self.valid),
            MinidumpRawContext::Mips(ctx) => ctx.register_is_valid(reg, &self.valid),
        })
    }

    /// Get the size (in bytes) of general-purpose registers.
    pub fn register_size(&self) -> usize {
        fn get<T: CpuContext>(_: &T) -> usize {
            std::mem::size_of::<T::Register>()
        }

        match &self.raw {
            MinidumpRawContext::X86(ctx) => get(ctx),
            MinidumpRawContext::Ppc(ctx) => get(ctx),
            MinidumpRawContext::Ppc64(ctx) => get(ctx),
            MinidumpRawContext::Amd64(ctx) => get(ctx),
            MinidumpRawContext::Sparc(ctx) => get(ctx),
            MinidumpRawContext::Arm(ctx) => get(ctx),
            MinidumpRawContext::Arm64(ctx) => get(ctx),
            MinidumpRawContext::OldArm64(ctx) => get(ctx),
            MinidumpRawContext::Mips(ctx) => get(ctx),
        }
    }

    /// Write a human-readable description of this `MinidumpContext` to `f`.
    ///
    /// This is very verbose, it is the format used by `minidump_dump`.
    pub fn print<T: Write>(&self, f: &mut T) -> io::Result<()> {
        match self.raw {
            MinidumpRawContext::X86(ref raw) => {
                write!(
                    f,
                    r#"CONTEXT_X86
  context_flags                = {:#x}
  dr0                          = {:#x}
  dr1                          = {:#x}
  dr2                          = {:#x}
  dr3                          = {:#x}
  dr6                          = {:#x}
  dr7                          = {:#x}
  float_save.control_word      = {:#x}
  float_save.status_word       = {:#x}
  float_save.tag_word          = {:#x}
  float_save.error_offset      = {:#x}
  float_save.error_selector    = {:#x}
  float_save.data_offset       = {:#x}
  float_save.data_selector     = {:#x}
  float_save.register_area[{:2}] = 0x"#,
                    raw.context_flags,
                    raw.dr0,
                    raw.dr1,
                    raw.dr2,
                    raw.dr3,
                    raw.dr6,
                    raw.dr7,
                    raw.float_save.control_word,
                    raw.float_save.status_word,
                    raw.float_save.tag_word,
                    raw.float_save.error_offset,
                    raw.float_save.error_selector,
                    raw.float_save.data_offset,
                    raw.float_save.data_selector,
                    raw.float_save.register_area.len(),
                )?;
                write_bytes(f, &raw.float_save.register_area)?;
                writeln!(f)?;
                write!(
                    f,
                    r#"  float_save.cr0_npx_state     = {:#x}
  gs                           = {:#x}
  fs                           = {:#x}
  es                           = {:#x}
  ds                           = {:#x}
  edi                          = {:#x}
  esi                          = {:#x}
  ebx                          = {:#x}
  edx                          = {:#x}
  ecx                          = {:#x}
  eax                          = {:#x}
  ebp                          = {:#x}
  eip                          = {:#x}
  cs                           = {:#x}
  eflags                       = {:#x}
  esp                          = {:#x}
  ss                           = {:#x}
  extended_registers[{:3}]      = 0x"#,
                    raw.float_save.cr0_npx_state,
                    raw.gs,
                    raw.fs,
                    raw.es,
                    raw.ds,
                    raw.edi,
                    raw.esi,
                    raw.ebx,
                    raw.edx,
                    raw.ecx,
                    raw.eax,
                    raw.ebp,
                    raw.eip,
                    raw.cs,
                    raw.eflags,
                    raw.esp,
                    raw.ss,
                    raw.extended_registers.len(),
                )?;
                write_bytes(f, &raw.extended_registers)?;
                write!(f, "\n\n")?;
            }
            MinidumpRawContext::Ppc(_) => {
                unimplemented!();
            }
            MinidumpRawContext::Ppc64(_) => {
                unimplemented!();
            }
            MinidumpRawContext::Amd64(ref raw) => {
                write!(
                    f,
                    r#"CONTEXT_AMD64
  p1_home       = {:#x}
  p2_home       = {:#x}
  p3_home       = {:#x}
  p4_home       = {:#x}
  p5_home       = {:#x}
  p6_home       = {:#x}
  context_flags = {:#x}
  mx_csr        = {:#x}
  cs            = {:#x}
  ds            = {:#x}
  es            = {:#x}
  fs            = {:#x}
  gs            = {:#x}
  ss            = {:#x}
  eflags        = {:#x}
  dr0           = {:#x}
  dr1           = {:#x}
  dr2           = {:#x}
  dr3           = {:#x}
  dr6           = {:#x}
  dr7           = {:#x}
  rax           = {:#x}
  rcx           = {:#x}
  rdx           = {:#x}
  rbx           = {:#x}
  rsp           = {:#x}
  rbp           = {:#x}
  rsi           = {:#x}
  rdi           = {:#x}
  r8            = {:#x}
  r9            = {:#x}
  r10           = {:#x}
  r11           = {:#x}
  r12           = {:#x}
  r13           = {:#x}
  r14           = {:#x}
  r15           = {:#x}
  rip           = {:#x}

"#,
                    raw.p1_home,
                    raw.p2_home,
                    raw.p3_home,
                    raw.p4_home,
                    raw.p5_home,
                    raw.p6_home,
                    raw.context_flags,
                    raw.mx_csr,
                    raw.cs,
                    raw.ds,
                    raw.es,
                    raw.fs,
                    raw.gs,
                    raw.ss,
                    raw.eflags,
                    raw.dr0,
                    raw.dr1,
                    raw.dr2,
                    raw.dr3,
                    raw.dr6,
                    raw.dr7,
                    raw.rax,
                    raw.rcx,
                    raw.rdx,
                    raw.rbx,
                    raw.rsp,
                    raw.rbp,
                    raw.rsi,
                    raw.rdi,
                    raw.r8,
                    raw.r9,
                    raw.r10,
                    raw.r11,
                    raw.r12,
                    raw.r13,
                    raw.r14,
                    raw.r15,
                    raw.rip,
                )?;
            }
            MinidumpRawContext::Sparc(_) => {
                unimplemented!();
            }
            MinidumpRawContext::Arm(ref raw) => {
                write!(
                    f,
                    r#"CONTEXT_ARM
  context_flags       = {:#x}
"#,
                    raw.context_flags
                )?;
                for (i, reg) in raw.iregs.iter().enumerate() {
                    writeln!(f, "  iregs[{i:2}]            = {reg:#x}")?;
                }
                write!(
                    f,
                    r#"  cpsr                = {:#x}
  float_save.fpscr     = {:#x}
"#,
                    raw.cpsr, raw.float_save.fpscr
                )?;
                for (i, reg) in raw.float_save.regs.iter().enumerate() {
                    writeln!(f, "  float_save.regs[{i:2}] = {reg:#x}")?;
                }
                for (i, reg) in raw.float_save.extra.iter().enumerate() {
                    writeln!(f, "  float_save.extra[{i:2}] = {reg:#x}")?;
                }
            }
            MinidumpRawContext::Arm64(ref raw) => {
                write!(
                    f,
                    r#"CONTEXT_ARM64
  context_flags        = {:#x}
"#,
                    raw.context_flags
                )?;
                for (i, reg) in raw.iregs[..29].iter().enumerate() {
                    writeln!(f, "  x{i:<2}                  = {reg:#x}")?;
                }
                writeln!(f, "  x29 (fp)             = {:#x}", raw.iregs[29])?;
                writeln!(f, "  x30 (lr)             = {:#x}", raw.iregs[30])?;
                writeln!(f, "  sp                   = {:#x}", raw.sp)?;
                writeln!(f, "  pc                   = {:#x}", raw.pc)?;
                writeln!(f, "  cpsr                 = {:#x}", raw.cpsr)?;
                writeln!(f, "  fpsr                 = {:#x}", raw.fpsr)?;
                writeln!(f, "  fpcr                 = {:#x}", raw.fpcr)?;
                for (i, reg) in raw.float_regs.iter().enumerate() {
                    writeln!(f, "  d{i:<2} = {reg:#x}")?;
                }
                for (i, reg) in raw.bcr.iter().enumerate() {
                    writeln!(f, "  bcr[{i:2}] = {reg:#x}")?;
                }
                for (i, reg) in raw.bvr.iter().enumerate() {
                    writeln!(f, "  bvr[{i:2}] = {reg:#x}")?;
                }
                for (i, reg) in raw.wcr.iter().enumerate() {
                    writeln!(f, "  wcr[{i:2}] = {reg:#x}")?;
                }
                for (i, reg) in raw.wvr.iter().enumerate() {
                    writeln!(f, "  wvr[{i:2}] = {reg:#x}")?;
                }
            }
            MinidumpRawContext::OldArm64(ref raw) => {
                write!(
                    f,
                    r#"CONTEXT_ARM64_OLD
  context_flags        = {:#x}
"#,
                    raw.context_flags
                )?;
                for (i, reg) in raw.iregs[..29].iter().enumerate() {
                    writeln!(f, "  x{i:<2}                  = {reg:#x}")?;
                }
                writeln!(f, "  x29 (fp)             = {:#x}", raw.iregs[29])?;
                writeln!(f, "  x30 (lr)             = {:#x}", raw.iregs[30])?;
                writeln!(f, "  sp                   = {:#x}", raw.sp)?;
                writeln!(f, "  pc                   = {:#x}", raw.pc)?;
                writeln!(f, "  cpsr                 = {:#x}", raw.cpsr)?;
                writeln!(f, "  fpsr                 = {:#x}", raw.fpsr)?;
                writeln!(f, "  fpcr                 = {:#x}", raw.fpcr)?;
                for (i, reg) in raw.float_regs.iter().enumerate() {
                    writeln!(f, "  d{i:<2} = {reg:#x}")?;
                }
            }
            MinidumpRawContext::Mips(ref raw) => {
                write!(
                    f,
                    r#"CONTEXT_MIPS
  context_flags       = {:#x}
"#,
                    raw.context_flags
                )?;

                use md::MipsRegisterNumbers;
                const MIPS_REGS: &[MipsRegisterNumbers] = &[
                    MipsRegisterNumbers::S0,
                    MipsRegisterNumbers::S1,
                    MipsRegisterNumbers::S2,
                    MipsRegisterNumbers::S3,
                    MipsRegisterNumbers::S4,
                    MipsRegisterNumbers::S5,
                    MipsRegisterNumbers::S6,
                    MipsRegisterNumbers::S7,
                    MipsRegisterNumbers::GlobalPointer,
                    MipsRegisterNumbers::StackPointer,
                    MipsRegisterNumbers::FramePointer,
                    MipsRegisterNumbers::ReturnAddress,
                ];
                for reg in MIPS_REGS {
                    writeln!(
                        f,
                        r#"  {}                = {:#x}"#,
                        reg.name(),
                        raw.iregs[*reg as usize]
                    )?;
                }
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    /// Smoke test for the default implementation of `memoize_register`.
    fn test_memoize_amd64() {
        let context = md::CONTEXT_AMD64::default();
        assert_eq!(context.memoize_register("rip"), Some("rip"));
        assert_eq!(context.memoize_register("foo"), None);
    }

    #[test]
    /// Test ARM register aliases by example of `fp`.
    fn test_memoize_arm_alias() {
        let context = md::CONTEXT_ARM::default();
        assert_eq!(context.memoize_register("r11"), Some("fp"));
        assert_eq!(context.memoize_register("fp"), Some("fp"));
        assert_eq!(context.memoize_register("foo"), None);
    }

    #[test]
    /// Test ARM register aliases by example of `fp`.
    fn test_memoize_arm64_alias() {
        let context = md::CONTEXT_ARM64::default();
        assert_eq!(context.memoize_register("x29"), Some("fp"));
        assert_eq!(context.memoize_register("fp"), Some("fp"));
        assert_eq!(context.memoize_register("foo"), None);
    }
}

[ Verzeichnis aufwärts0.78unsichere Verbindung  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge