[MIPS]: Use mcontext_t structure for MIPS

This change removes user_regs_struct and
user_fpregs_struct structures for mips
and uses mcontext_t instead.

R=fdegans@chromium.org, mark@chromium.org, rmcilroy@chromium.org

Review URL: https://breakpad.appspot.com/3744002

Patch from Gordana Cmiljanovic <Gordana.Cmiljanovic@imgtec.com>.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1452 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
rmcilroy@chromium.org 2015-04-21 21:34:14 +00:00
parent 9c6af3e29c
commit 0f27af628f
9 changed files with 134 additions and 160 deletions

View File

@ -30,6 +30,7 @@
#include "client/linux/dump_writer_common/thread_info.h" #include "client/linux/dump_writer_common/thread_info.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include "common/linux/linux_libc_support.h" #include "common/linux/linux_libc_support.h"
#include "google_breakpad/common/minidump_format.h" #include "google_breakpad/common/minidump_format.h"
@ -230,37 +231,69 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
#elif defined(__mips__) #elif defined(__mips__)
uintptr_t ThreadInfo::GetInstructionPointer() const { uintptr_t ThreadInfo::GetInstructionPointer() const {
return regs.epc; return mcontext.pc;
} }
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
out->context_flags = MD_CONTEXT_MIPS_FULL; out->context_flags = MD_CONTEXT_MIPS_FULL;
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
out->iregs[i] = regs.regs[i]; out->iregs[i] = mcontext.gregs[i];
out->mdhi = regs.hi; out->mdhi = mcontext.mdhi;
out->mdlo = regs.lo; out->mdlo = mcontext.mdlo;
out->dsp_control = mcontext.dsp;
for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) { out->hi[0] = mcontext.hi1;
out->hi[i] = hi[i]; out->lo[0] = mcontext.lo1;
out->lo[i] = lo[i]; out->hi[1] = mcontext.hi2;
} out->lo[1] = mcontext.lo2;
out->dsp_control = dsp_control; out->hi[2] = mcontext.hi3;
out->lo[2] = mcontext.lo3;
out->epc = regs.epc; out->epc = mcontext.pc;
out->badvaddr = regs.badvaddr; out->badvaddr = 0; // Not stored in mcontext
out->status = regs.status; out->status = 0; // Not stored in mcontext
out->cause = regs.cause; out->cause = 0; // Not stored in mcontext
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
out->float_save.regs[i] = fpregs.regs[i]; out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs;
out->float_save.fpcsr = fpregs.fpcsr; out->float_save.fpcsr = mcontext.fpc_csr;
#if _MIPS_SIM == _ABIO32 #if _MIPS_SIM == _ABIO32
out->float_save.fir = fpregs.fir; out->float_save.fir = mcontext.fpc_eir;
#endif #endif
} }
#endif // __mips__
void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
assert(gp_regs || size);
#if defined(__mips__)
if (gp_regs)
*gp_regs = mcontext.gregs;
if (size)
*size = sizeof(mcontext.gregs);
#else
if (gp_regs)
*gp_regs = &regs;
if (size)
*size = sizeof(regs);
#endif #endif
}
void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
assert(fp_regs || size);
#if defined(__mips__)
if (fp_regs)
*fp_regs = &mcontext.fpregs;
if (size)
*size = sizeof(mcontext.fpregs);
#else
if (fp_regs)
*fp_regs = &fpregs;
if (size)
*size = sizeof(fpregs);
#endif
}
} // namespace google_breakpad } // namespace google_breakpad

View File

@ -69,11 +69,8 @@ struct ThreadInfo {
struct user_pt_regs regs; struct user_pt_regs regs;
struct user_fpsimd_state fpregs; struct user_fpsimd_state fpregs;
#elif defined(__mips__) #elif defined(__mips__)
user_regs_struct regs; // Use the structure defined in <sys/ucontext.h>.
user_fpregs_struct fpregs; mcontext_t mcontext;
uint32_t hi[3];
uint32_t lo[3];
uint32_t dsp_control;
#endif #endif
// Returns the instruction pointer (platform-dependent impl.). // Returns the instruction pointer (platform-dependent impl.).
@ -81,6 +78,12 @@ struct ThreadInfo {
// Fills a RawContextCPU using the context in the ThreadInfo object. // Fills a RawContextCPU using the context in the ThreadInfo object.
void FillCPUContext(RawContextCPU* out) const; void FillCPUContext(RawContextCPU* out) const;
// Returns the pointer and size of general purpose register area.
void GetGeneralPurposeRegisters(void** gp_regs, size_t* size);
// Returns the pointer and size of float point register area.
void GetFloatingPointRegisters(void** fp_regs, size_t* size);
}; };
} // namespace google_breakpad } // namespace google_breakpad

View File

@ -38,6 +38,10 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/procfs.h> #include <sys/procfs.h>
#if defined(__mips__) && defined(__ANDROID__)
// To get register definitions.
#include <asm/reg.h>
#endif
#include "common/linux/linux_libc_support.h" #include "common/linux/linux_libc_support.h"
@ -105,7 +109,7 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
#elif defined(__mips__) #elif defined(__mips__)
stack_pointer = stack_pointer =
reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]); reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
#else #else
#error "This code hasn't been ported to your platform yet." #error "This code hasn't been ported to your platform yet."
#endif #endif
@ -191,18 +195,19 @@ bool LinuxCoreDumper::EnumerateThreads() {
info.tgid = status->pr_pgrp; info.tgid = status->pr_pgrp;
info.ppid = status->pr_ppid; info.ppid = status->pr_ppid;
#if defined(__mips__) #if defined(__mips__)
#if defined(__ANDROID__)
for (int i = EF_R0; i <= EF_R31; i++)
info.mcontext.gregs[i - EF_R0] = status->pr_reg[i];
#else // __ANDROID__
for (int i = EF_REG0; i <= EF_REG31; i++) for (int i = EF_REG0; i <= EF_REG31; i++)
info.regs.regs[i - EF_REG0] = status->pr_reg[i]; info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i];
#endif // __ANDROID__
info.regs.lo = status->pr_reg[EF_LO]; info.mcontext.mdlo = status->pr_reg[EF_LO];
info.regs.hi = status->pr_reg[EF_HI]; info.mcontext.mdhi = status->pr_reg[EF_HI];
info.regs.epc = status->pr_reg[EF_CP0_EPC]; info.mcontext.pc = status->pr_reg[EF_CP0_EPC];
info.regs.badvaddr = status->pr_reg[EF_CP0_BADVADDR]; #else // __mips__
info.regs.status = status->pr_reg[EF_CP0_STATUS];
info.regs.cause = status->pr_reg[EF_CP0_CAUSE];
#else
memcpy(&info.regs, status->pr_reg, sizeof(info.regs)); memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
#endif #endif // __mips__
if (first_thread) { if (first_thread) {
crash_thread_ = pid; crash_thread_ = pid;
crash_signal_ = status->pr_info.si_signo; crash_signal_ = status->pr_info.si_signo;

View File

@ -190,23 +190,25 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#ifdef PTRACE_GETREGSET #ifdef PTRACE_GETREGSET
struct iovec io; struct iovec io;
io.iov_base = &info->regs; info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len);
io.iov_len = sizeof(info->regs);
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
return false; return false;
} }
io.iov_base = &info->fpregs; info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len);
io.iov_len = sizeof(info->fpregs);
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
return false; return false;
} }
#else #else // PTRACE_GETREGSET
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) { void* gp_addr;
info->GetGeneralPurposeRegisters(&gp_addr, NULL);
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) {
return false; return false;
} }
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { void* fp_addr;
info->GetFloatingPointRegisters(&fp_addr, NULL);
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) {
return false; return false;
} }
#endif #endif
@ -241,14 +243,20 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#endif #endif
#if defined(__mips__) #if defined(__mips__)
for (int i = 0; i < 3; ++i) {
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + (i * 2)), &info->hi[i]);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + (i * 2) + 1), &info->lo[i]);
}
sys_ptrace(PTRACE_PEEKUSER, tid, sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_CONTROL), &info->dsp_control); reinterpret_cast<void*>(DSP_BASE), &info->mcontext.hi1);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 1), &info->mcontext.lo1);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 2), &info->mcontext.hi2);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 3), &info->mcontext.lo2);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 4), &info->mcontext.hi3);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 5), &info->mcontext.lo3);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_CONTROL), &info->mcontext.dsp);
#endif #endif
const uint8_t* stack_pointer; const uint8_t* stack_pointer;
@ -262,7 +270,7 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
#elif defined(__mips__) #elif defined(__mips__)
stack_pointer = stack_pointer =
reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]); reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
#else #else
#error "This code hasn't been ported to your platform yet." #error "This code hasn't been ported to your platform yet."
#endif #endif

View File

@ -441,7 +441,7 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx); pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx);
#elif defined(__mips__) #elif defined(__mips__)
pid_t* process_tid_location = pid_t* process_tid_location =
reinterpret_cast<pid_t*>(one_thread.regs.regs[1]); reinterpret_cast<pid_t*>(one_thread.mcontext.gregs[1]);
#else #else
#error This test has not been ported to this platform. #error This test has not been ported to this platform.
#endif #endif

View File

@ -38,6 +38,9 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if defined (__mips__)
#include <sys/types.h>
#endif
#include <sys/user.h> #include <sys/user.h>
#include <unistd.h> #include <unistd.h>

View File

@ -33,88 +33,12 @@
// The purpose of this file is to glue the mismatching headers (Android NDK vs // The purpose of this file is to glue the mismatching headers (Android NDK vs
// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code. // glibc) and therefore avoid doing otherwise awkward #ifdefs in the code.
// The following quirks are currently handled by this file: // The following quirks are currently handled by this file:
// - MIPS: Keep using forked definitions of user.h structs. The definition in
// the NDK is completely different. Internal bug b/18097715
// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct. // - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct.
// - x86_64: Override a typo in user_fpregs_struct (mxcsr_mask -> mxcr_mask). // - x86_64: Override a typo in user_fpregs_struct (mxcsr_mask -> mxcr_mask).
// The typo has been fixed in NDK r10d, but a preprocessor workaround is // The typo has been fixed in NDK r10d, but a preprocessor workaround is
// required to make breakpad build with r10c and lower (more details below). // required to make breakpad build with r10c and lower (more details below).
// - Other platforms: Just use the Android NDK unchanged. // - Other platforms: Just use the Android NDK unchanged.
#ifdef __mips__
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#define EF_REG0 6
#define EF_REG1 7
#define EF_REG2 8
#define EF_REG3 9
#define EF_REG4 10
#define EF_REG5 11
#define EF_REG6 12
#define EF_REG7 13
#define EF_REG8 14
#define EF_REG9 15
#define EF_REG10 16
#define EF_REG11 17
#define EF_REG12 18
#define EF_REG13 19
#define EF_REG14 20
#define EF_REG15 21
#define EF_REG16 22
#define EF_REG17 23
#define EF_REG18 24
#define EF_REG19 25
#define EF_REG20 26
#define EF_REG21 27
#define EF_REG22 28
#define EF_REG23 29
#define EF_REG24 30
#define EF_REG25 31
/*
* k0/k1 unsaved
*/
#define EF_REG26 32
#define EF_REG27 33
#define EF_REG28 34
#define EF_REG29 35
#define EF_REG30 36
#define EF_REG31 37
/*
* Saved special registers
*/
#define EF_LO 38
#define EF_HI 39
#define EF_CP0_EPC 40
#define EF_CP0_BADVADDR 41
#define EF_CP0_STATUS 42
#define EF_CP0_CAUSE 43
struct user_regs_struct {
unsigned long long regs[32];
unsigned long long lo;
unsigned long long hi;
unsigned long long epc;
unsigned long long badvaddr;
unsigned long long status;
unsigned long long cause;
};
struct user_fpregs_struct {
unsigned long long regs[32];
unsigned int fpcsr;
unsigned int fir;
};
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#else // __mips__
// TODO(primiano): remove this after Chromium has stably rolled to NDK r10d. // TODO(primiano): remove this after Chromium has stably rolled to NDK r10d.
// Historical context: NDK releases < r10d had a typo in sys/user.h (mxcsr_mask // Historical context: NDK releases < r10d had a typo in sys/user.h (mxcsr_mask
// instead of mxcr_mask), which is fixed in r10d. However, just switching to use // instead of mxcr_mask), which is fixed in r10d. However, just switching to use
@ -143,6 +67,4 @@ typedef struct user_fxsr_struct user_fpxregs_struct;
#endif // __cplusplus #endif // __cplusplus
#endif // __i386__ #endif // __i386__
#endif // __mips__
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H #endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H

View File

@ -66,24 +66,6 @@
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ #ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ #define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
#if defined(__mips__) && !defined(__ANDROID__)
typedef struct {
uint64_t regs[32];
uint64_t lo;
uint64_t hi;
uint64_t epc;
uint64_t badvaddr;
uint64_t status;
uint64_t cause;
} user_regs_struct;
typedef struct {
uint64_t regs[32];
uint32_t fpcsr;
uint32_t fir;
} user_fpregs_struct;
#endif
#define MD_CONTEXT_MIPS_GPR_COUNT 32 #define MD_CONTEXT_MIPS_GPR_COUNT 32
#define MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT 32 #define MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT 32
#define MD_CONTEXT_MIPS_DSP_COUNT 3 #define MD_CONTEXT_MIPS_DSP_COUNT 3
@ -112,8 +94,8 @@ typedef struct {
/* 32 64-bit integer registers, r0..r31. /* 32 64-bit integer registers, r0..r31.
* Note the following fixed uses: * Note the following fixed uses:
* r30 is the stack pointer. * r29 is the stack pointer.
* r31 is the return address (link register). * r31 is the return address.
*/ */
uint64_t iregs[MD_CONTEXT_MIPS_GPR_COUNT]; uint64_t iregs[MD_CONTEXT_MIPS_GPR_COUNT];

View File

@ -81,6 +81,9 @@
// containing core registers, while they use 'user_regs_struct' on other // containing core registers, while they use 'user_regs_struct' on other
// architectures. This file-local typedef simplifies the source code. // architectures. This file-local typedef simplifies the source code.
typedef user_regs user_regs_struct; typedef user_regs user_regs_struct;
#elif defined (__mips__)
// This file-local typedef simplifies the source code.
typedef gregset_t user_regs_struct;
#endif #endif
using google_breakpad::MDTypeHelper; using google_breakpad::MDTypeHelper;
@ -208,13 +211,17 @@ struct CrashedProcess {
struct Thread { struct Thread {
pid_t tid; pid_t tid;
#if defined(__mips__)
mcontext_t mcontext;
#else // __mips__
user_regs_struct regs; user_regs_struct regs;
#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) #if defined(__i386__) || defined(__x86_64__)
user_fpregs_struct fpregs; user_fpregs_struct fpregs;
#endif #endif // __i386__ || __x86_64__
#if defined(__i386__) #if defined(__i386__)
user_fpxregs_struct fpxregs; user_fpxregs_struct fpxregs;
#endif #endif // __i386__
#endif // __mips__
uintptr_t stack_addr; uintptr_t stack_addr;
const uint8_t* stack; const uint8_t* stack;
size_t stack_length; size_t stack_length;
@ -371,21 +378,28 @@ ParseThreadRegisters(CrashedProcess::Thread* thread,
const MDRawContextMIPS* rawregs = range.GetData<MDRawContextMIPS>(0); const MDRawContextMIPS* rawregs = range.GetData<MDRawContextMIPS>(0);
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
thread->regs.regs[i] = rawregs->iregs[i]; thread->mcontext.gregs[i] = rawregs->iregs[i];
thread->regs.lo = rawregs->mdlo; thread->mcontext.pc = rawregs->epc;
thread->regs.hi = rawregs->mdhi;
thread->regs.epc = rawregs->epc;
thread->regs.badvaddr = rawregs->badvaddr;
thread->regs.status = rawregs->status;
thread->regs.cause = rawregs->cause;
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) thread->mcontext.mdlo = rawregs->mdlo;
thread->fpregs.regs[i] = rawregs->float_save.regs[i]; thread->mcontext.mdhi = rawregs->mdhi;
thread->fpregs.fpcsr = rawregs->float_save.fpcsr; thread->mcontext.hi1 = rawregs->hi[0];
thread->mcontext.lo1 = rawregs->lo[0];
thread->mcontext.hi2 = rawregs->hi[1];
thread->mcontext.lo2 = rawregs->lo[1];
thread->mcontext.hi3 = rawregs->hi[2];
thread->mcontext.lo3 = rawregs->lo[2];
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) {
thread->mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs =
rawregs->float_save.regs[i];
}
thread->mcontext.fpc_csr = rawregs->float_save.fpcsr;
#if _MIPS_SIM == _ABIO32 #if _MIPS_SIM == _ABIO32
thread->fpregs.fir = rawregs->float_save.fir; thread->mcontext.fpc_eir = rawregs->float_save.fir;
#endif #endif
} }
#else #else
@ -751,7 +765,11 @@ WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
pr.pr_info.si_signo = fatal_signal; pr.pr_info.si_signo = fatal_signal;
pr.pr_cursig = fatal_signal; pr.pr_cursig = fatal_signal;
pr.pr_pid = thread.tid; pr.pr_pid = thread.tid;
#if defined(__mips__)
memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct));
#else
memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct)); memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct));
#endif
Nhdr nhdr; Nhdr nhdr;
memset(&nhdr, 0, sizeof(nhdr)); memset(&nhdr, 0, sizeof(nhdr));