Refactoring in preparation for microdump processing
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1370 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
@@ -102,6 +103,9 @@ class MockMemoryRegion: public MemoryRegion {
|
||||
*value = address;
|
||||
return true;
|
||||
}
|
||||
void Print() const {
|
||||
assert(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Verify that, for every association in ACTUAL, EXPECTED has the same
|
||||
|
||||
@@ -60,6 +60,7 @@ class MockMemoryRegion: public MemoryRegion {
|
||||
MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t *));
|
||||
MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t *));
|
||||
MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t *));
|
||||
MOCK_CONST_METHOD0(Print, void());
|
||||
};
|
||||
|
||||
// Handy definitions for all tests.
|
||||
|
||||
605
src/processor/dump_context.cc
Normal file
605
src/processor/dump_context.cc
Normal file
@@ -0,0 +1,605 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dump_context.cc: A (mini/micro)dump context.
|
||||
//
|
||||
// See dump_context.h for documentation.
|
||||
|
||||
#include "google_breakpad/processor/dump_context.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "processor/logging.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
DumpContext::DumpContext() : context_(),
|
||||
context_flags_(0) { }
|
||||
|
||||
DumpContext::~DumpContext() {
|
||||
FreeContext();
|
||||
}
|
||||
|
||||
uint32_t DumpContext::GetContextCPU() const {
|
||||
if (!valid_) {
|
||||
// Don't log a message, GetContextCPU can be legitimately called with
|
||||
// valid_ false by FreeContext, which is called by Read.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return context_flags_ & MD_CONTEXT_CPU_MASK;
|
||||
}
|
||||
|
||||
uint32_t DumpContext::GetContextFlags() const {
|
||||
return context_flags_;
|
||||
}
|
||||
|
||||
const MDRawContextX86* DumpContext::GetContextX86() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_X86) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get x86 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.x86;
|
||||
}
|
||||
|
||||
const MDRawContextPPC* DumpContext::GetContextPPC() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_PPC) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get ppc context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ppc;
|
||||
}
|
||||
|
||||
const MDRawContextPPC64* DumpContext::GetContextPPC64() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_PPC64) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get ppc64 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ppc64;
|
||||
}
|
||||
|
||||
const MDRawContextAMD64* DumpContext::GetContextAMD64() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_AMD64) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get amd64 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.amd64;
|
||||
}
|
||||
|
||||
const MDRawContextSPARC* DumpContext::GetContextSPARC() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_SPARC) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get sparc context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ctx_sparc;
|
||||
}
|
||||
|
||||
const MDRawContextARM* DumpContext::GetContextARM() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_ARM) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get arm context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.arm;
|
||||
}
|
||||
|
||||
const MDRawContextARM64* DumpContext::GetContextARM64() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_ARM64) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get arm64 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.arm64;
|
||||
}
|
||||
|
||||
const MDRawContextMIPS* DumpContext::GetContextMIPS() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_MIPS) {
|
||||
BPLOG(ERROR) << "DumpContext cannot get MIPS context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ctx_mips;
|
||||
}
|
||||
|
||||
bool DumpContext::GetInstructionPointer(uint64_t* ip) const {
|
||||
BPLOG_IF(ERROR, !ip) << "DumpContext::GetInstructionPointer requires |ip|";
|
||||
assert(ip);
|
||||
*ip = 0;
|
||||
|
||||
if (!valid_) {
|
||||
BPLOG(ERROR) << "Invalid DumpContext for GetInstructionPointer";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (GetContextCPU()) {
|
||||
case MD_CONTEXT_AMD64:
|
||||
*ip = GetContextAMD64()->rip;
|
||||
break;
|
||||
case MD_CONTEXT_ARM:
|
||||
*ip = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_PC];
|
||||
break;
|
||||
case MD_CONTEXT_ARM64:
|
||||
*ip = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_PC];
|
||||
break;
|
||||
case MD_CONTEXT_PPC:
|
||||
*ip = GetContextPPC()->srr0;
|
||||
break;
|
||||
case MD_CONTEXT_PPC64:
|
||||
*ip = GetContextPPC64()->srr0;
|
||||
break;
|
||||
case MD_CONTEXT_SPARC:
|
||||
*ip = GetContextSPARC()->pc;
|
||||
break;
|
||||
case MD_CONTEXT_X86:
|
||||
*ip = GetContextX86()->eip;
|
||||
break;
|
||||
case MD_CONTEXT_MIPS:
|
||||
*ip = GetContextMIPS()->epc;
|
||||
break;
|
||||
default:
|
||||
// This should never happen.
|
||||
BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextFlags(uint32_t context_flags) {
|
||||
context_flags_ = context_flags;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextX86(MDRawContextX86* x86) {
|
||||
context_.x86 = x86;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextPPC(MDRawContextPPC* ppc) {
|
||||
context_.ppc = ppc;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextPPC64(MDRawContextPPC64* ppc64) {
|
||||
context_.ppc64 = ppc64;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextAMD64(MDRawContextAMD64* amd64) {
|
||||
context_.amd64 = amd64;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextSPARC(MDRawContextSPARC* ctx_sparc) {
|
||||
context_.ctx_sparc = ctx_sparc;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextARM(MDRawContextARM* arm) {
|
||||
context_.arm = arm;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextARM64(MDRawContextARM64* arm64) {
|
||||
context_.arm64 = arm64;
|
||||
}
|
||||
|
||||
void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) {
|
||||
context_.ctx_mips = ctx_mips;
|
||||
}
|
||||
|
||||
void DumpContext::FreeContext() {
|
||||
switch (GetContextCPU()) {
|
||||
case MD_CONTEXT_X86:
|
||||
delete context_.x86;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_PPC:
|
||||
delete context_.ppc;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_PPC64:
|
||||
delete context_.ppc64;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_AMD64:
|
||||
delete context_.amd64;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_SPARC:
|
||||
delete context_.ctx_sparc;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_ARM:
|
||||
delete context_.arm;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_ARM64:
|
||||
delete context_.arm64;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_MIPS:
|
||||
delete context_.ctx_mips;
|
||||
break;
|
||||
|
||||
default:
|
||||
// There is no context record (valid_ is false) or there's a
|
||||
// context record for an unknown CPU (shouldn't happen, only known
|
||||
// records are stored by Read).
|
||||
break;
|
||||
}
|
||||
|
||||
context_flags_ = 0;
|
||||
context_.base = NULL;
|
||||
}
|
||||
|
||||
void DumpContext::Print() {
|
||||
if (!valid_) {
|
||||
BPLOG(ERROR) << "DumpContext cannot print invalid data";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (GetContextCPU()) {
|
||||
case MD_CONTEXT_X86: {
|
||||
const MDRawContextX86* context_x86 = GetContextX86();
|
||||
printf("MDRawContextX86\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_x86->context_flags);
|
||||
printf(" dr0 = 0x%x\n", context_x86->dr0);
|
||||
printf(" dr1 = 0x%x\n", context_x86->dr1);
|
||||
printf(" dr2 = 0x%x\n", context_x86->dr2);
|
||||
printf(" dr3 = 0x%x\n", context_x86->dr3);
|
||||
printf(" dr6 = 0x%x\n", context_x86->dr6);
|
||||
printf(" dr7 = 0x%x\n", context_x86->dr7);
|
||||
printf(" float_save.control_word = 0x%x\n",
|
||||
context_x86->float_save.control_word);
|
||||
printf(" float_save.status_word = 0x%x\n",
|
||||
context_x86->float_save.status_word);
|
||||
printf(" float_save.tag_word = 0x%x\n",
|
||||
context_x86->float_save.tag_word);
|
||||
printf(" float_save.error_offset = 0x%x\n",
|
||||
context_x86->float_save.error_offset);
|
||||
printf(" float_save.error_selector = 0x%x\n",
|
||||
context_x86->float_save.error_selector);
|
||||
printf(" float_save.data_offset = 0x%x\n",
|
||||
context_x86->float_save.data_offset);
|
||||
printf(" float_save.data_selector = 0x%x\n",
|
||||
context_x86->float_save.data_selector);
|
||||
printf(" float_save.register_area[%2d] = 0x",
|
||||
MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
|
||||
for (unsigned int register_index = 0;
|
||||
register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
|
||||
++register_index) {
|
||||
printf("%02x", context_x86->float_save.register_area[register_index]);
|
||||
}
|
||||
printf("\n");
|
||||
printf(" float_save.cr0_npx_state = 0x%x\n",
|
||||
context_x86->float_save.cr0_npx_state);
|
||||
printf(" gs = 0x%x\n", context_x86->gs);
|
||||
printf(" fs = 0x%x\n", context_x86->fs);
|
||||
printf(" es = 0x%x\n", context_x86->es);
|
||||
printf(" ds = 0x%x\n", context_x86->ds);
|
||||
printf(" edi = 0x%x\n", context_x86->edi);
|
||||
printf(" esi = 0x%x\n", context_x86->esi);
|
||||
printf(" ebx = 0x%x\n", context_x86->ebx);
|
||||
printf(" edx = 0x%x\n", context_x86->edx);
|
||||
printf(" ecx = 0x%x\n", context_x86->ecx);
|
||||
printf(" eax = 0x%x\n", context_x86->eax);
|
||||
printf(" ebp = 0x%x\n", context_x86->ebp);
|
||||
printf(" eip = 0x%x\n", context_x86->eip);
|
||||
printf(" cs = 0x%x\n", context_x86->cs);
|
||||
printf(" eflags = 0x%x\n", context_x86->eflags);
|
||||
printf(" esp = 0x%x\n", context_x86->esp);
|
||||
printf(" ss = 0x%x\n", context_x86->ss);
|
||||
printf(" extended_registers[%3d] = 0x",
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
|
||||
for (unsigned int register_index = 0;
|
||||
register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
|
||||
++register_index) {
|
||||
printf("%02x", context_x86->extended_registers[register_index]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_PPC: {
|
||||
const MDRawContextPPC* context_ppc = GetContextPPC();
|
||||
printf("MDRawContextPPC\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_ppc->context_flags);
|
||||
printf(" srr0 = 0x%x\n", context_ppc->srr0);
|
||||
printf(" srr1 = 0x%x\n", context_ppc->srr1);
|
||||
for (unsigned int gpr_index = 0;
|
||||
gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
|
||||
++gpr_index) {
|
||||
printf(" gpr[%2d] = 0x%x\n",
|
||||
gpr_index, context_ppc->gpr[gpr_index]);
|
||||
}
|
||||
printf(" cr = 0x%x\n", context_ppc->cr);
|
||||
printf(" xer = 0x%x\n", context_ppc->xer);
|
||||
printf(" lr = 0x%x\n", context_ppc->lr);
|
||||
printf(" ctr = 0x%x\n", context_ppc->ctr);
|
||||
printf(" mq = 0x%x\n", context_ppc->mq);
|
||||
printf(" vrsave = 0x%x\n", context_ppc->vrsave);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_ppc->float_save.fpregs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpscr = 0x%x\n",
|
||||
context_ppc->float_save.fpscr);
|
||||
// TODO(mmentovai): print the 128-bit quantities in
|
||||
// context_ppc->vector_save. This isn't done yet because printf
|
||||
// doesn't support 128-bit quantities, and printing them using
|
||||
// PRIx64 as two 64-bit quantities requires knowledge of the CPU's
|
||||
// byte ordering.
|
||||
printf(" vector_save.save_vrvalid = 0x%x\n",
|
||||
context_ppc->vector_save.save_vrvalid);
|
||||
printf("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_PPC64: {
|
||||
const MDRawContextPPC64* context_ppc64 = GetContextPPC64();
|
||||
printf("MDRawContextPPC64\n");
|
||||
printf(" context_flags = 0x%" PRIx64 "\n",
|
||||
context_ppc64->context_flags);
|
||||
printf(" srr0 = 0x%" PRIx64 "\n",
|
||||
context_ppc64->srr0);
|
||||
printf(" srr1 = 0x%" PRIx64 "\n",
|
||||
context_ppc64->srr1);
|
||||
for (unsigned int gpr_index = 0;
|
||||
gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
|
||||
++gpr_index) {
|
||||
printf(" gpr[%2d] = 0x%" PRIx64 "\n",
|
||||
gpr_index, context_ppc64->gpr[gpr_index]);
|
||||
}
|
||||
printf(" cr = 0x%" PRIx64 "\n", context_ppc64->cr);
|
||||
printf(" xer = 0x%" PRIx64 "\n",
|
||||
context_ppc64->xer);
|
||||
printf(" lr = 0x%" PRIx64 "\n", context_ppc64->lr);
|
||||
printf(" ctr = 0x%" PRIx64 "\n",
|
||||
context_ppc64->ctr);
|
||||
printf(" vrsave = 0x%" PRIx64 "\n",
|
||||
context_ppc64->vrsave);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_ppc64->float_save.fpregs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpscr = 0x%x\n",
|
||||
context_ppc64->float_save.fpscr);
|
||||
// TODO(mmentovai): print the 128-bit quantities in
|
||||
// context_ppc64->vector_save. This isn't done yet because printf
|
||||
// doesn't support 128-bit quantities, and printing them using
|
||||
// PRIx64 as two 64-bit quantities requires knowledge of the CPU's
|
||||
// byte ordering.
|
||||
printf(" vector_save.save_vrvalid = 0x%x\n",
|
||||
context_ppc64->vector_save.save_vrvalid);
|
||||
printf("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_AMD64: {
|
||||
const MDRawContextAMD64* context_amd64 = GetContextAMD64();
|
||||
printf("MDRawContextAMD64\n");
|
||||
printf(" p1_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p1_home);
|
||||
printf(" p2_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p2_home);
|
||||
printf(" p3_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p3_home);
|
||||
printf(" p4_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p4_home);
|
||||
printf(" p5_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p5_home);
|
||||
printf(" p6_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p6_home);
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_amd64->context_flags);
|
||||
printf(" mx_csr = 0x%x\n",
|
||||
context_amd64->mx_csr);
|
||||
printf(" cs = 0x%x\n", context_amd64->cs);
|
||||
printf(" ds = 0x%x\n", context_amd64->ds);
|
||||
printf(" es = 0x%x\n", context_amd64->es);
|
||||
printf(" fs = 0x%x\n", context_amd64->fs);
|
||||
printf(" gs = 0x%x\n", context_amd64->gs);
|
||||
printf(" ss = 0x%x\n", context_amd64->ss);
|
||||
printf(" eflags = 0x%x\n", context_amd64->eflags);
|
||||
printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0);
|
||||
printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1);
|
||||
printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2);
|
||||
printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3);
|
||||
printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6);
|
||||
printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7);
|
||||
printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax);
|
||||
printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx);
|
||||
printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx);
|
||||
printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx);
|
||||
printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp);
|
||||
printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp);
|
||||
printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi);
|
||||
printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi);
|
||||
printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8);
|
||||
printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9);
|
||||
printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10);
|
||||
printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11);
|
||||
printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12);
|
||||
printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13);
|
||||
printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14);
|
||||
printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15);
|
||||
printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip);
|
||||
// TODO: print xmm, vector, debug registers
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_SPARC: {
|
||||
const MDRawContextSPARC* context_sparc = GetContextSPARC();
|
||||
printf("MDRawContextSPARC\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_sparc->context_flags);
|
||||
for (unsigned int g_r_index = 0;
|
||||
g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
|
||||
++g_r_index) {
|
||||
printf(" g_r[%2d] = 0x%" PRIx64 "\n",
|
||||
g_r_index, context_sparc->g_r[g_r_index]);
|
||||
}
|
||||
printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr);
|
||||
printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc);
|
||||
printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc);
|
||||
printf(" y = 0x%" PRIx64 "\n", context_sparc->y);
|
||||
printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi);
|
||||
printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs);
|
||||
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_sparc->float_save.regs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.filler = 0x%" PRIx64 "\n",
|
||||
context_sparc->float_save.filler);
|
||||
printf(" float_save.fsr = 0x%" PRIx64 "\n",
|
||||
context_sparc->float_save.fsr);
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_ARM: {
|
||||
const MDRawContextARM* context_arm = GetContextARM();
|
||||
printf("MDRawContextARM\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_arm->context_flags);
|
||||
for (unsigned int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
printf(" iregs[%2d] = 0x%x\n",
|
||||
ireg_index, context_arm->iregs[ireg_index]);
|
||||
}
|
||||
printf(" cpsr = 0x%x\n", context_arm->cpsr);
|
||||
printf(" float_save.fpscr = 0x%" PRIx64 "\n",
|
||||
context_arm->float_save.fpscr);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_arm->float_save.regs[fpr_index]);
|
||||
}
|
||||
for (unsigned int fpe_index = 0;
|
||||
fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
|
||||
++fpe_index) {
|
||||
printf(" float_save.extra[%2d] = 0x%" PRIx32 "\n",
|
||||
fpe_index, context_arm->float_save.extra[fpe_index]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_ARM64: {
|
||||
const MDRawContextARM64* context_arm64 = GetContextARM64();
|
||||
printf("MDRawContextARM64\n");
|
||||
printf(" context_flags = 0x%" PRIx64 "\n",
|
||||
context_arm64->context_flags);
|
||||
for (unsigned int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
printf(" iregs[%2d] = 0x%" PRIx64 "\n",
|
||||
ireg_index, context_arm64->iregs[ireg_index]);
|
||||
}
|
||||
printf(" cpsr = 0x%x\n", context_arm64->cpsr);
|
||||
printf(" float_save.fpsr = 0x%x\n", context_arm64->float_save.fpsr);
|
||||
printf(" float_save.fpcr = 0x%x\n", context_arm64->float_save.fpcr);
|
||||
|
||||
for (unsigned int freg_index = 0;
|
||||
freg_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
|
||||
++freg_index) {
|
||||
uint128_struct fp_value = context_arm64->float_save.regs[freg_index];
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n",
|
||||
freg_index, fp_value.high, fp_value.low);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_MIPS: {
|
||||
const MDRawContextMIPS* context_mips = GetContextMIPS();
|
||||
printf("MDRawContextMIPS\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_mips->context_flags);
|
||||
for (int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_MIPS_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
printf(" iregs[%2d] = 0x%" PRIx64 "\n",
|
||||
ireg_index, context_mips->iregs[ireg_index]);
|
||||
}
|
||||
printf(" mdhi = 0x%" PRIx64 "\n",
|
||||
context_mips->mdhi);
|
||||
printf(" mdlo = 0x%" PRIx64 "\n",
|
||||
context_mips->mdhi);
|
||||
for (int dsp_index = 0;
|
||||
dsp_index < MD_CONTEXT_MIPS_DSP_COUNT;
|
||||
++dsp_index) {
|
||||
printf(" hi[%1d] = 0x%" PRIx32 "\n",
|
||||
dsp_index, context_mips->hi[dsp_index]);
|
||||
printf(" lo[%1d] = 0x%" PRIx32 "\n",
|
||||
dsp_index, context_mips->lo[dsp_index]);
|
||||
}
|
||||
printf(" dsp_control = 0x%" PRIx32 "\n",
|
||||
context_mips->dsp_control);
|
||||
printf(" epc = 0x%" PRIx64 "\n",
|
||||
context_mips->epc);
|
||||
printf(" badvaddr = 0x%" PRIx64 "\n",
|
||||
context_mips->badvaddr);
|
||||
printf(" status = 0x%" PRIx32 "\n",
|
||||
context_mips->status);
|
||||
printf(" cause = 0x%" PRIx32 "\n",
|
||||
context_mips->cause);
|
||||
|
||||
for (int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_mips->float_save.regs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpcsr = 0x%" PRIx32 "\n",
|
||||
context_mips->float_save.fpcsr);
|
||||
printf(" float_save.fir = 0x%" PRIx32 "\n",
|
||||
context_mips->float_save.fir);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
39
src/processor/dump_object.cc
Normal file
39
src/processor/dump_object.cc
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dump_object.cc: A base class for all mini/micro dump object.
|
||||
|
||||
#include "google_breakpad/processor/dump_object.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
DumpObject::DumpObject() : valid_(false) {
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
@@ -37,6 +37,7 @@
|
||||
//
|
||||
// Author: Siyang Xie (lambxsy@google.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sstream>
|
||||
@@ -113,6 +114,9 @@ class MockMemoryRegion: public MemoryRegion {
|
||||
*value = address;
|
||||
return true;
|
||||
}
|
||||
void Print() const {
|
||||
assert(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Verify that, for every association in ACTUAL, EXPECTED has the same
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include "processor/range_map-inl.h"
|
||||
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "google_breakpad/processor/dump_context.h"
|
||||
#include "processor/basic_code_module.h"
|
||||
#include "processor/basic_code_modules.h"
|
||||
#include "processor/logging.h"
|
||||
@@ -391,8 +392,8 @@ string TimeTToUTCString(time_t tt) {
|
||||
|
||||
|
||||
MinidumpObject::MinidumpObject(Minidump* minidump)
|
||||
: minidump_(minidump),
|
||||
valid_(false) {
|
||||
: DumpObject(),
|
||||
minidump_(minidump) {
|
||||
}
|
||||
|
||||
|
||||
@@ -412,17 +413,13 @@ MinidumpStream::MinidumpStream(Minidump* minidump)
|
||||
|
||||
|
||||
MinidumpContext::MinidumpContext(Minidump* minidump)
|
||||
: MinidumpStream(minidump),
|
||||
context_(),
|
||||
context_flags_(0) {
|
||||
: DumpContext(),
|
||||
minidump_(minidump) {
|
||||
}
|
||||
|
||||
|
||||
MinidumpContext::~MinidumpContext() {
|
||||
FreeContext();
|
||||
}
|
||||
|
||||
|
||||
bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
valid_ = false;
|
||||
|
||||
@@ -547,9 +544,9 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_amd64->last_exception_from_rip);
|
||||
}
|
||||
|
||||
context_flags_ = context_amd64->context_flags;
|
||||
SetContextFlags(context_amd64->context_flags);
|
||||
|
||||
context_.amd64 = context_amd64.release();
|
||||
SetContextAMD64(context_amd64.release());
|
||||
} else if (expected_size == sizeof(MDRawContextPPC64)) {
|
||||
// |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext
|
||||
// in the else case have 32 bits |context_flags|, so special case it here.
|
||||
@@ -633,17 +630,17 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_ppc64->vector_save.save_vrvalid);
|
||||
}
|
||||
|
||||
context_flags_ = static_cast<uint32_t>(context_ppc64->context_flags);
|
||||
SetContextFlags(static_cast<uint32_t>(context_ppc64->context_flags));
|
||||
|
||||
// Check for data loss when converting context flags from uint64_t into
|
||||
// uint32_t
|
||||
if (static_cast<uint64_t>(context_flags_) !=
|
||||
if (static_cast<uint64_t>(GetContextFlags()) !=
|
||||
context_ppc64->context_flags) {
|
||||
BPLOG(ERROR) << "Data loss detected when converting PPC64 context_flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
context_.ppc64 = context_ppc64.release();
|
||||
SetContextPPC64(context_ppc64.release());
|
||||
} else if (expected_size == sizeof(MDRawContextARM64)) {
|
||||
// |context_flags| of MDRawContextARM64 is 64 bits, but other MDRawContext
|
||||
// in the else case have 32 bits |context_flags|, so special case it here.
|
||||
@@ -718,17 +715,17 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_arm64->float_save.regs[fpr_index]);
|
||||
}
|
||||
}
|
||||
context_flags_ = static_cast<uint32_t>(context_arm64->context_flags);
|
||||
SetContextFlags(static_cast<uint32_t>(context_arm64->context_flags));
|
||||
|
||||
// Check for data loss when converting context flags from uint64_t into
|
||||
// uint32_t
|
||||
if (static_cast<uint64_t>(context_flags_) !=
|
||||
if (static_cast<uint64_t>(GetContextFlags()) !=
|
||||
context_arm64->context_flags) {
|
||||
BPLOG(ERROR) << "Data loss detected when converting ARM64 context_flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
context_.arm64 = context_arm64.release();
|
||||
SetContextARM64(context_arm64.release());
|
||||
} else {
|
||||
uint32_t context_flags;
|
||||
if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
|
||||
@@ -833,7 +830,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
// does not need to be swapped.
|
||||
}
|
||||
|
||||
context_.x86 = context_x86.release();
|
||||
SetContextX86(context_x86.release());
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -909,7 +906,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_ppc->vector_save.save_vrvalid);
|
||||
}
|
||||
|
||||
context_.ppc = context_ppc.release();
|
||||
SetContextPPC(context_ppc.release());
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -965,7 +962,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_sparc->float_save.filler);
|
||||
Swap(&context_sparc->float_save.fsr);
|
||||
}
|
||||
context_.ctx_sparc = context_sparc.release();
|
||||
SetContextSPARC(context_sparc.release());
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1020,16 +1017,16 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_arm->float_save.extra[fpe_index]);
|
||||
}
|
||||
}
|
||||
context_.arm = context_arm.release();
|
||||
SetContextARM(context_arm.release());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_MIPS: {
|
||||
if (expected_size != sizeof(MDRawContextMIPS)) {
|
||||
BPLOG(ERROR) << "MinidumpContext MIPS size mismatch, "
|
||||
<< expected_size
|
||||
<< " != "
|
||||
BPLOG(ERROR) << "MinidumpContext MIPS size mismatch, "
|
||||
<< expected_size
|
||||
<< " != "
|
||||
<< sizeof(MDRawContextMIPS);
|
||||
return false;
|
||||
}
|
||||
@@ -1085,7 +1082,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
Swap(&context_mips->float_save.fpcsr);
|
||||
Swap(&context_mips->float_save.fir);
|
||||
}
|
||||
context_.ctx_mips = context_mips.release();
|
||||
SetContextMIPS(context_mips.release());
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1099,188 +1096,13 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
context_flags_ = context_flags;
|
||||
SetContextFlags(context_flags);
|
||||
}
|
||||
|
||||
valid_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t MinidumpContext::GetContextCPU() const {
|
||||
if (!valid_) {
|
||||
// Don't log a message, GetContextCPU can be legitimately called with
|
||||
// valid_ false by FreeContext, which is called by Read.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return context_flags_ & MD_CONTEXT_CPU_MASK;
|
||||
}
|
||||
|
||||
bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const {
|
||||
BPLOG_IF(ERROR, !ip) << "MinidumpContext::GetInstructionPointer "
|
||||
"requires |ip|";
|
||||
assert(ip);
|
||||
*ip = 0;
|
||||
|
||||
if (!valid_) {
|
||||
BPLOG(ERROR) << "Invalid MinidumpContext for GetInstructionPointer";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (context_flags_ & MD_CONTEXT_CPU_MASK) {
|
||||
case MD_CONTEXT_AMD64:
|
||||
*ip = context_.amd64->rip;
|
||||
break;
|
||||
case MD_CONTEXT_ARM:
|
||||
*ip = context_.arm->iregs[MD_CONTEXT_ARM_REG_PC];
|
||||
break;
|
||||
case MD_CONTEXT_ARM64:
|
||||
*ip = context_.arm64->iregs[MD_CONTEXT_ARM64_REG_PC];
|
||||
break;
|
||||
case MD_CONTEXT_PPC:
|
||||
*ip = context_.ppc->srr0;
|
||||
break;
|
||||
case MD_CONTEXT_PPC64:
|
||||
*ip = context_.ppc64->srr0;
|
||||
break;
|
||||
case MD_CONTEXT_SPARC:
|
||||
*ip = context_.ctx_sparc->pc;
|
||||
break;
|
||||
case MD_CONTEXT_X86:
|
||||
*ip = context_.x86->eip;
|
||||
break;
|
||||
case MD_CONTEXT_MIPS:
|
||||
*ip = context_.ctx_mips->epc;
|
||||
break;
|
||||
default:
|
||||
// This should never happen.
|
||||
BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const MDRawContextX86* MinidumpContext::GetContextX86() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_X86) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get x86 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.x86;
|
||||
}
|
||||
|
||||
|
||||
const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_PPC) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get ppc context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ppc;
|
||||
}
|
||||
|
||||
const MDRawContextPPC64* MinidumpContext::GetContextPPC64() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_PPC64) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get ppc64 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ppc64;
|
||||
}
|
||||
|
||||
const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_AMD64) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.amd64;
|
||||
}
|
||||
|
||||
const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_SPARC) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ctx_sparc;
|
||||
}
|
||||
|
||||
const MDRawContextARM* MinidumpContext::GetContextARM() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_ARM) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get arm context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.arm;
|
||||
}
|
||||
|
||||
const MDRawContextARM64* MinidumpContext::GetContextARM64() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_ARM64) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get arm64 context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.arm64;
|
||||
}
|
||||
|
||||
const MDRawContextMIPS* MinidumpContext::GetContextMIPS() const {
|
||||
if (GetContextCPU() != MD_CONTEXT_MIPS) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot get MIPS context";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context_.ctx_mips;
|
||||
}
|
||||
|
||||
void MinidumpContext::FreeContext() {
|
||||
switch (GetContextCPU()) {
|
||||
case MD_CONTEXT_X86:
|
||||
delete context_.x86;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_PPC:
|
||||
delete context_.ppc;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_PPC64:
|
||||
delete context_.ppc64;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_AMD64:
|
||||
delete context_.amd64;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_SPARC:
|
||||
delete context_.ctx_sparc;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_ARM:
|
||||
delete context_.arm;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_ARM64:
|
||||
delete context_.arm64;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_MIPS:
|
||||
delete context_.ctx_mips;
|
||||
break;
|
||||
|
||||
default:
|
||||
// There is no context record (valid_ is false) or there's a
|
||||
// context record for an unknown CPU (shouldn't happen, only known
|
||||
// records are stored by Read).
|
||||
break;
|
||||
}
|
||||
|
||||
context_flags_ = 0;
|
||||
context_.base = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
|
||||
// It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
|
||||
// as this function just implements a sanity check.
|
||||
@@ -1359,352 +1181,6 @@ bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
|
||||
}
|
||||
|
||||
|
||||
void MinidumpContext::Print() {
|
||||
if (!valid_) {
|
||||
BPLOG(ERROR) << "MinidumpContext cannot print invalid data";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (GetContextCPU()) {
|
||||
case MD_CONTEXT_X86: {
|
||||
const MDRawContextX86* context_x86 = GetContextX86();
|
||||
printf("MDRawContextX86\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_x86->context_flags);
|
||||
printf(" dr0 = 0x%x\n", context_x86->dr0);
|
||||
printf(" dr1 = 0x%x\n", context_x86->dr1);
|
||||
printf(" dr2 = 0x%x\n", context_x86->dr2);
|
||||
printf(" dr3 = 0x%x\n", context_x86->dr3);
|
||||
printf(" dr6 = 0x%x\n", context_x86->dr6);
|
||||
printf(" dr7 = 0x%x\n", context_x86->dr7);
|
||||
printf(" float_save.control_word = 0x%x\n",
|
||||
context_x86->float_save.control_word);
|
||||
printf(" float_save.status_word = 0x%x\n",
|
||||
context_x86->float_save.status_word);
|
||||
printf(" float_save.tag_word = 0x%x\n",
|
||||
context_x86->float_save.tag_word);
|
||||
printf(" float_save.error_offset = 0x%x\n",
|
||||
context_x86->float_save.error_offset);
|
||||
printf(" float_save.error_selector = 0x%x\n",
|
||||
context_x86->float_save.error_selector);
|
||||
printf(" float_save.data_offset = 0x%x\n",
|
||||
context_x86->float_save.data_offset);
|
||||
printf(" float_save.data_selector = 0x%x\n",
|
||||
context_x86->float_save.data_selector);
|
||||
printf(" float_save.register_area[%2d] = 0x",
|
||||
MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
|
||||
for (unsigned int register_index = 0;
|
||||
register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
|
||||
++register_index) {
|
||||
printf("%02x", context_x86->float_save.register_area[register_index]);
|
||||
}
|
||||
printf("\n");
|
||||
printf(" float_save.cr0_npx_state = 0x%x\n",
|
||||
context_x86->float_save.cr0_npx_state);
|
||||
printf(" gs = 0x%x\n", context_x86->gs);
|
||||
printf(" fs = 0x%x\n", context_x86->fs);
|
||||
printf(" es = 0x%x\n", context_x86->es);
|
||||
printf(" ds = 0x%x\n", context_x86->ds);
|
||||
printf(" edi = 0x%x\n", context_x86->edi);
|
||||
printf(" esi = 0x%x\n", context_x86->esi);
|
||||
printf(" ebx = 0x%x\n", context_x86->ebx);
|
||||
printf(" edx = 0x%x\n", context_x86->edx);
|
||||
printf(" ecx = 0x%x\n", context_x86->ecx);
|
||||
printf(" eax = 0x%x\n", context_x86->eax);
|
||||
printf(" ebp = 0x%x\n", context_x86->ebp);
|
||||
printf(" eip = 0x%x\n", context_x86->eip);
|
||||
printf(" cs = 0x%x\n", context_x86->cs);
|
||||
printf(" eflags = 0x%x\n", context_x86->eflags);
|
||||
printf(" esp = 0x%x\n", context_x86->esp);
|
||||
printf(" ss = 0x%x\n", context_x86->ss);
|
||||
printf(" extended_registers[%3d] = 0x",
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
|
||||
for (unsigned int register_index = 0;
|
||||
register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
|
||||
++register_index) {
|
||||
printf("%02x", context_x86->extended_registers[register_index]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_PPC: {
|
||||
const MDRawContextPPC* context_ppc = GetContextPPC();
|
||||
printf("MDRawContextPPC\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_ppc->context_flags);
|
||||
printf(" srr0 = 0x%x\n", context_ppc->srr0);
|
||||
printf(" srr1 = 0x%x\n", context_ppc->srr1);
|
||||
for (unsigned int gpr_index = 0;
|
||||
gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
|
||||
++gpr_index) {
|
||||
printf(" gpr[%2d] = 0x%x\n",
|
||||
gpr_index, context_ppc->gpr[gpr_index]);
|
||||
}
|
||||
printf(" cr = 0x%x\n", context_ppc->cr);
|
||||
printf(" xer = 0x%x\n", context_ppc->xer);
|
||||
printf(" lr = 0x%x\n", context_ppc->lr);
|
||||
printf(" ctr = 0x%x\n", context_ppc->ctr);
|
||||
printf(" mq = 0x%x\n", context_ppc->mq);
|
||||
printf(" vrsave = 0x%x\n", context_ppc->vrsave);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_ppc->float_save.fpregs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpscr = 0x%x\n",
|
||||
context_ppc->float_save.fpscr);
|
||||
// TODO(mmentovai): print the 128-bit quantities in
|
||||
// context_ppc->vector_save. This isn't done yet because printf
|
||||
// doesn't support 128-bit quantities, and printing them using
|
||||
// PRIx64 as two 64-bit quantities requires knowledge of the CPU's
|
||||
// byte ordering.
|
||||
printf(" vector_save.save_vrvalid = 0x%x\n",
|
||||
context_ppc->vector_save.save_vrvalid);
|
||||
printf("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_PPC64: {
|
||||
const MDRawContextPPC64* context_ppc64 = GetContextPPC64();
|
||||
printf("MDRawContextPPC64\n");
|
||||
printf(" context_flags = 0x%" PRIx64 "\n",
|
||||
context_ppc64->context_flags);
|
||||
printf(" srr0 = 0x%" PRIx64 "\n",
|
||||
context_ppc64->srr0);
|
||||
printf(" srr1 = 0x%" PRIx64 "\n",
|
||||
context_ppc64->srr1);
|
||||
for (unsigned int gpr_index = 0;
|
||||
gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
|
||||
++gpr_index) {
|
||||
printf(" gpr[%2d] = 0x%" PRIx64 "\n",
|
||||
gpr_index, context_ppc64->gpr[gpr_index]);
|
||||
}
|
||||
printf(" cr = 0x%" PRIx64 "\n", context_ppc64->cr);
|
||||
printf(" xer = 0x%" PRIx64 "\n",
|
||||
context_ppc64->xer);
|
||||
printf(" lr = 0x%" PRIx64 "\n", context_ppc64->lr);
|
||||
printf(" ctr = 0x%" PRIx64 "\n",
|
||||
context_ppc64->ctr);
|
||||
printf(" vrsave = 0x%" PRIx64 "\n",
|
||||
context_ppc64->vrsave);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_ppc64->float_save.fpregs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpscr = 0x%x\n",
|
||||
context_ppc64->float_save.fpscr);
|
||||
// TODO(mmentovai): print the 128-bit quantities in
|
||||
// context_ppc64->vector_save. This isn't done yet because printf
|
||||
// doesn't support 128-bit quantities, and printing them using
|
||||
// PRIx64 as two 64-bit quantities requires knowledge of the CPU's
|
||||
// byte ordering.
|
||||
printf(" vector_save.save_vrvalid = 0x%x\n",
|
||||
context_ppc64->vector_save.save_vrvalid);
|
||||
printf("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_AMD64: {
|
||||
const MDRawContextAMD64* context_amd64 = GetContextAMD64();
|
||||
printf("MDRawContextAMD64\n");
|
||||
printf(" p1_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p1_home);
|
||||
printf(" p2_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p2_home);
|
||||
printf(" p3_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p3_home);
|
||||
printf(" p4_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p4_home);
|
||||
printf(" p5_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p5_home);
|
||||
printf(" p6_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p6_home);
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_amd64->context_flags);
|
||||
printf(" mx_csr = 0x%x\n",
|
||||
context_amd64->mx_csr);
|
||||
printf(" cs = 0x%x\n", context_amd64->cs);
|
||||
printf(" ds = 0x%x\n", context_amd64->ds);
|
||||
printf(" es = 0x%x\n", context_amd64->es);
|
||||
printf(" fs = 0x%x\n", context_amd64->fs);
|
||||
printf(" gs = 0x%x\n", context_amd64->gs);
|
||||
printf(" ss = 0x%x\n", context_amd64->ss);
|
||||
printf(" eflags = 0x%x\n", context_amd64->eflags);
|
||||
printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0);
|
||||
printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1);
|
||||
printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2);
|
||||
printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3);
|
||||
printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6);
|
||||
printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7);
|
||||
printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax);
|
||||
printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx);
|
||||
printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx);
|
||||
printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx);
|
||||
printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp);
|
||||
printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp);
|
||||
printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi);
|
||||
printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi);
|
||||
printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8);
|
||||
printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9);
|
||||
printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10);
|
||||
printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11);
|
||||
printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12);
|
||||
printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13);
|
||||
printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14);
|
||||
printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15);
|
||||
printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip);
|
||||
// TODO: print xmm, vector, debug registers
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_SPARC: {
|
||||
const MDRawContextSPARC* context_sparc = GetContextSPARC();
|
||||
printf("MDRawContextSPARC\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_sparc->context_flags);
|
||||
for (unsigned int g_r_index = 0;
|
||||
g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
|
||||
++g_r_index) {
|
||||
printf(" g_r[%2d] = 0x%" PRIx64 "\n",
|
||||
g_r_index, context_sparc->g_r[g_r_index]);
|
||||
}
|
||||
printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr);
|
||||
printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc);
|
||||
printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc);
|
||||
printf(" y = 0x%" PRIx64 "\n", context_sparc->y);
|
||||
printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi);
|
||||
printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs);
|
||||
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_sparc->float_save.regs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.filler = 0x%" PRIx64 "\n",
|
||||
context_sparc->float_save.filler);
|
||||
printf(" float_save.fsr = 0x%" PRIx64 "\n",
|
||||
context_sparc->float_save.fsr);
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_ARM: {
|
||||
const MDRawContextARM* context_arm = GetContextARM();
|
||||
printf("MDRawContextARM\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_arm->context_flags);
|
||||
for (unsigned int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
printf(" iregs[%2d] = 0x%x\n",
|
||||
ireg_index, context_arm->iregs[ireg_index]);
|
||||
}
|
||||
printf(" cpsr = 0x%x\n", context_arm->cpsr);
|
||||
printf(" float_save.fpscr = 0x%" PRIx64 "\n",
|
||||
context_arm->float_save.fpscr);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_arm->float_save.regs[fpr_index]);
|
||||
}
|
||||
for (unsigned int fpe_index = 0;
|
||||
fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
|
||||
++fpe_index) {
|
||||
printf(" float_save.extra[%2d] = 0x%" PRIx32 "\n",
|
||||
fpe_index, context_arm->float_save.extra[fpe_index]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_ARM64: {
|
||||
const MDRawContextARM64* context_arm64 = GetContextARM64();
|
||||
printf("MDRawContextARM64\n");
|
||||
printf(" context_flags = 0x%" PRIx64 "\n",
|
||||
context_arm64->context_flags);
|
||||
for (unsigned int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
printf(" iregs[%2d] = 0x%" PRIx64 "\n",
|
||||
ireg_index, context_arm64->iregs[ireg_index]);
|
||||
}
|
||||
printf(" cpsr = 0x%x\n", context_arm64->cpsr);
|
||||
printf(" float_save.fpsr = 0x%x\n", context_arm64->float_save.fpsr);
|
||||
printf(" float_save.fpcr = 0x%x\n", context_arm64->float_save.fpcr);
|
||||
|
||||
for (unsigned int freg_index = 0;
|
||||
freg_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
|
||||
++freg_index) {
|
||||
uint128_struct fp_value = context_arm64->float_save.regs[freg_index];
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n",
|
||||
freg_index, fp_value.high, fp_value.low);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_MIPS: {
|
||||
const MDRawContextMIPS* context_mips = GetContextMIPS();
|
||||
printf("MDRawContextMIPS\n");
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_mips->context_flags);
|
||||
for (int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_MIPS_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
printf(" iregs[%2d] = 0x%" PRIx64 "\n",
|
||||
ireg_index, context_mips->iregs[ireg_index]);
|
||||
}
|
||||
printf(" mdhi = 0x%" PRIx64 "\n",
|
||||
context_mips->mdhi);
|
||||
printf(" mdlo = 0x%" PRIx64 "\n",
|
||||
context_mips->mdhi);
|
||||
for (int dsp_index = 0;
|
||||
dsp_index < MD_CONTEXT_MIPS_DSP_COUNT;
|
||||
++dsp_index) {
|
||||
printf(" hi[%1d] = 0x%" PRIx32 "\n",
|
||||
dsp_index, context_mips->hi[dsp_index]);
|
||||
printf(" lo[%1d] = 0x%" PRIx32 "\n",
|
||||
dsp_index, context_mips->lo[dsp_index]);
|
||||
}
|
||||
printf(" dsp_control = 0x%" PRIx32 "\n",
|
||||
context_mips->dsp_control);
|
||||
printf(" epc = 0x%" PRIx64 "\n",
|
||||
context_mips->epc);
|
||||
printf(" badvaddr = 0x%" PRIx64 "\n",
|
||||
context_mips->badvaddr);
|
||||
printf(" status = 0x%" PRIx32 "\n",
|
||||
context_mips->status);
|
||||
printf(" cause = 0x%" PRIx32 "\n",
|
||||
context_mips->cause);
|
||||
|
||||
for (int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_mips->float_save.regs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpcsr = 0x%" PRIx32 "\n",
|
||||
context_mips->float_save.fpcsr);
|
||||
printf(" float_save.fir = 0x%" PRIx32 "\n",
|
||||
context_mips->float_save.fir);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MinidumpMemoryRegion
|
||||
//
|
||||
@@ -1867,7 +1343,7 @@ bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
}
|
||||
|
||||
|
||||
void MinidumpMemoryRegion::Print() {
|
||||
void MinidumpMemoryRegion::Print() const {
|
||||
if (!valid_) {
|
||||
BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
|
||||
return;
|
||||
|
||||
@@ -299,8 +299,8 @@ class TestMinidumpContext : public MinidumpContext {
|
||||
explicit TestMinidumpContext(const MDRawContextX86& context) :
|
||||
MinidumpContext(NULL) {
|
||||
valid_ = true;
|
||||
context_.x86 = new MDRawContextX86(context);
|
||||
context_flags_ = MD_CONTEXT_X86;
|
||||
SetContextX86(new MDRawContextX86(context));
|
||||
SetContextFlags(MD_CONTEXT_X86);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
@@ -75,6 +76,9 @@ class FakeMemoryRegion : public MemoryRegion {
|
||||
*value = address + 1;
|
||||
return true;
|
||||
}
|
||||
virtual void Print() const {
|
||||
assert(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/code_modules.h"
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
#include "google_breakpad/processor/dump_context.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "google_breakpad/processor/stack_frame_symbolizer.h"
|
||||
#include "google_breakpad/processor/system_info.h"
|
||||
@@ -190,7 +190,7 @@ bool Stackwalker::Walk(
|
||||
// static
|
||||
Stackwalker* Stackwalker::StackwalkerForCPU(
|
||||
const SystemInfo* system_info,
|
||||
MinidumpContext* context,
|
||||
DumpContext* context,
|
||||
MemoryRegion* memory,
|
||||
const CodeModules* modules,
|
||||
StackFrameSymbolizer* frame_symbolizer) {
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "processor/logging.h"
|
||||
|
||||
#if defined(__i386) && !defined(__i386__)
|
||||
@@ -102,17 +104,20 @@ using google_breakpad::StackwalkerSPARC;
|
||||
// process' memory space by pointer.
|
||||
class SelfMemoryRegion : public MemoryRegion {
|
||||
public:
|
||||
virtual uint64_t GetBase() { return 0; }
|
||||
virtual uint32_t GetSize() { return 0xffffffff; }
|
||||
virtual uint64_t GetBase() const { return 0; }
|
||||
virtual uint32_t GetSize() const { return 0xffffffff; }
|
||||
|
||||
bool GetMemoryAtAddress(uint64_t address, uint8_t* value) {
|
||||
bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
|
||||
return GetMemoryAtAddressInternal(address, value); }
|
||||
bool GetMemoryAtAddress(uint64_t address, uint16_t* value) {
|
||||
bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
|
||||
return GetMemoryAtAddressInternal(address, value); }
|
||||
bool GetMemoryAtAddress(uint64_t address, uint32_t* value) {
|
||||
bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
|
||||
return GetMemoryAtAddressInternal(address, value); }
|
||||
bool GetMemoryAtAddress(uint64_t address, uint64_t* value) {
|
||||
bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
|
||||
return GetMemoryAtAddressInternal(address, value); }
|
||||
void Print() const {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T> bool GetMemoryAtAddressInternal(uint64_t address,
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#ifndef PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
|
||||
#define PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -75,6 +76,9 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion {
|
||||
bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
void Print() const {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
private:
|
||||
// Fetch a little-endian value from ADDRESS in contents_ whose size
|
||||
|
||||
Reference in New Issue
Block a user