Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(common): Add MIPS and MIPS64 architectures #141

Merged
merged 1 commit into from
May 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions common/src/heuristics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Heuristics for correcting instruction pointers based on the CPU architecture.

use crate::types::Arch;
use crate::types::{Arch, CpuFamily};

const SIGILL: u32 = 4;
const SIGBUS: u32 = 10;
Expand Down Expand Up @@ -54,7 +54,16 @@ impl InstructionInfo {
/// the preceding instruction will be returned. For this reason, the return
/// value of this function should be considered an upper bound.
pub fn previous_address(&self) -> u64 {
self.aligned_address() - self.arch.instruction_alignment().unwrap_or(1)
let instruction_size = self.arch.instruction_alignment().unwrap_or(1);

// In MIPS, the return address apparently often points two instructions after the the
// previous program counter. On other architectures, just subtract one instruction.
let pc_offset = match self.arch.cpu_family() {
CpuFamily::Mips32 | CpuFamily::Mips64 => 2 * instruction_size,
_ => instruction_size,
};

self.aligned_address() - pc_offset
}

/// Returns whether the application attempted to jump to an invalid,
Expand Down
34 changes: 31 additions & 3 deletions common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ static ARM64: &[&'static str] = &[
"v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
];

/// Names for MIPS CPU registers by register number.
static MIPS: &[&'static str] = &[
"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$t0", "$t1", "$t2", "$t3", "$t4",
"$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9",
"$k0", "$k1", "$gp", "$sp", "$fp", "$ra", "$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4",
"$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16",
"$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28",
"$f29", "$f30", "$f31", "$fcsr", "$fir",
];

/// Represents a family of CPUs.
///
/// This is strongly connected to the [`Arch`] type, but reduces the selection to a range of
Expand All @@ -71,6 +81,10 @@ pub enum CpuFamily {
Ppc32 = 5,
/// 64-bit big-endian PowerPC.
Ppc64 = 6,
/// 32-bit MIPS.
Mips32 = 7,
/// 64-bit MIPS.
Mips64 = 8,
}

impl Default for CpuFamily {
Expand Down Expand Up @@ -112,6 +126,8 @@ pub enum Arch {
Arm64Unknown = 499,
Ppc = 501,
Ppc64 = 601,
Mips = 701,
Mips64 = 801,
}

impl Arch {
Expand Down Expand Up @@ -141,6 +157,8 @@ impl Arch {
499 => Arch::Arm64Unknown,
17 | 501 => Arch::Ppc,
18 | 601 => Arch::Ppc64,
701 => Arch::Mips,
801 => Arch::Mips64,
_ => Arch::Unknown,
}
}
Expand All @@ -165,6 +183,8 @@ impl Arch {
| Arch::ArmUnknown => CpuFamily::Arm32,
Arch::Ppc => CpuFamily::Ppc32,
Arch::Ppc64 => CpuFamily::Ppc64,
Arch::Mips => CpuFamily::Mips32,
Arch::Mips64 => CpuFamily::Mips64,
}
}

Expand Down Expand Up @@ -194,15 +214,17 @@ impl Arch {
Arch::ArmUnknown => "arm_unknown",
Arch::Ppc => "ppc",
Arch::Ppc64 => "ppc64",
Arch::Mips => "mips",
Arch::Mips64 => "mips64",
}
}

/// Returns the native pointer size.
pub fn pointer_size(self) -> Option<usize> {
match self.cpu_family() {
CpuFamily::Unknown => None,
CpuFamily::Amd64 | CpuFamily::Arm64 | CpuFamily::Ppc64 => Some(8),
CpuFamily::Intel32 | CpuFamily::Arm32 | CpuFamily::Ppc32 => Some(4),
CpuFamily::Amd64 | CpuFamily::Arm64 | CpuFamily::Ppc64 | CpuFamily::Mips64 => Some(8),
CpuFamily::Intel32 | CpuFamily::Arm32 | CpuFamily::Ppc32 | CpuFamily::Mips32 => Some(4),
}
}

Expand All @@ -211,7 +233,7 @@ impl Arch {
match self.cpu_family() {
CpuFamily::Arm32 => Some(2),
CpuFamily::Arm64 => Some(4),
CpuFamily::Ppc32 => Some(4),
CpuFamily::Ppc32 | CpuFamily::Mips32 | CpuFamily::Mips64 => Some(4),
CpuFamily::Ppc64 => Some(8),
CpuFamily::Intel32 | CpuFamily::Amd64 => None,
CpuFamily::Unknown => None,
Expand All @@ -220,11 +242,14 @@ impl Arch {

/// The name of the IP register if known.
pub fn ip_register_name(self) -> Option<&'static str> {
// NOTE: These values do not correspond to the register names defined in this file, but to
// the names exposed by breakpad. This mapping is implemented in `data_structures.cpp`.
match self.cpu_family() {
CpuFamily::Intel32 => Some("eip"),
CpuFamily::Amd64 => Some("rip"),
CpuFamily::Arm32 | CpuFamily::Arm64 => Some("pc"),
CpuFamily::Ppc32 | CpuFamily::Ppc64 => Some("srr0"),
CpuFamily::Mips32 | CpuFamily::Mips64 => Some("pc"),
CpuFamily::Unknown => None,
}
}
Expand All @@ -250,6 +275,7 @@ impl Arch {
CpuFamily::Amd64 => X86_64.get(index),
CpuFamily::Arm64 => ARM64.get(index),
CpuFamily::Arm32 => ARM.get(index),
CpuFamily::Mips32 | CpuFamily::Mips64 => MIPS.get(index),
_ => None,
};

Expand Down Expand Up @@ -299,6 +325,8 @@ impl str::FromStr for Arch {
"arm_unknown" => Arch::ArmUnknown,
"ppc" => Arch::Ppc,
"ppc64" => Arch::Ppc64,
"mips" => Arch::Mips,
"mips64" => Arch::Mips64,
_ => return Err(UnknownArchError),
})
}
Expand Down
21 changes: 21 additions & 0 deletions debuginfo/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ const PAGE_SIZE: usize = 4096;
const SHN_UNDEF: usize = elf::section_header::SHN_UNDEF as usize;
const SHF_COMPRESSED: u64 = elf::section_header::SHF_COMPRESSED as u64;

/// This file follows the first MIPS 32 bit ABI
#[allow(unused)]
const EF_MIPS_ABI_O32: u32 = 0x0000_1000;
/// O32 ABI extended for 64-bit architecture.
const EF_MIPS_ABI_O64: u32 = 0x0000_2000;
/// EABI in 32 bit mode.
#[allow(unused)]
const EF_MIPS_ABI_EABI32: u32 = 0x0000_3000;
/// EABI in 64 bit mode.
const EF_MIPS_ABI_EABI64: u32 = 0x0000_4000;

/// Any flag value that might indicate 64-bit MIPS.
const MIPS_64_FLAGS: u32 = EF_MIPS_ABI_O64 | EF_MIPS_ABI_EABI64;

/// An error when dealing with [`ElfObject`](struct.ElfObject.html).
#[derive(Debug, Fail)]
pub enum ElfError {
Expand Down Expand Up @@ -113,6 +127,13 @@ impl<'d> ElfObject<'d> {
goblin::elf::header::EM_ARM => Arch::Arm,
goblin::elf::header::EM_PPC => Arch::Ppc,
goblin::elf::header::EM_PPC64 => Arch::Ppc64,
goblin::elf::header::EM_MIPS | goblin::elf::header::EM_MIPS_RS3_LE => {
if self.elf.header.e_flags & MIPS_64_FLAGS != 0 {
Arch::Mips64
} else {
Arch::Mips
}
}
_ => Arch::Unknown,
}
}
Expand Down
64 changes: 64 additions & 0 deletions minidump/cpp/data_structures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ using google_breakpad::StackFrame;
using google_breakpad::StackFrameAMD64;
using google_breakpad::StackFrameARM;
using google_breakpad::StackFrameARM64;
using google_breakpad::StackFrameMIPS;
using google_breakpad::StackFramePPC;
using google_breakpad::StackFramePPC64;
using google_breakpad::StackFrameX86;
Expand Down Expand Up @@ -481,6 +482,69 @@ regval_t *stack_frame_registers(const stack_frame_t *frame,
break;
}

case 7: // Mips
case 8: { // Mips64
const StackFrameMIPS *frame_mips =
reinterpret_cast<const StackFrameMIPS *>(frame);

uint8_t reg_size = (family == 7) ? 4 : 8;

if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP)
registers.push_back(
{"gp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP)
registers.push_back(
{"sp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP)
registers.push_back(
{"fp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA)
registers.push_back(
{"ra", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC)
registers.push_back({"pc", frame_mips->context.epc, reg_size});

// Save registers s0-s7
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0)
registers.push_back(
{"s0", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1)
registers.push_back(
{"s1", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2)
registers.push_back(
{"s2", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3)
registers.push_back(
{"s3", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4)
registers.push_back(
{"s4", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5)
registers.push_back(
{"s5", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6)
registers.push_back(
{"s6", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6],
reg_size});
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7)
registers.push_back(
{"s7", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7],
reg_size});

break;
}

case 0: // Unknown
default:
break; // leave registers empty
Expand Down