From 0c759c6f62c9eff18087b04b1de3285978858629 Mon Sep 17 00:00:00 2001 From: "thestig@chromium.org" Date: Fri, 12 Apr 2013 23:24:02 +0000 Subject: Add PPC64 support to breakpad processor. A=Jia Ji Original review: https://breakpad.appspot.com/557002/ Review URL: https://breakpad.appspot.com/558002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1147 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/google_breakpad/common/minidump_cpu_ppc64.h | 16 +-- src/google_breakpad/common/minidump_format.h | 1 + src/google_breakpad/processor/minidump.h | 2 + src/google_breakpad/processor/stack_frame_cpu.h | 26 +++++ src/processor/minidump.cc | 138 ++++++++++++++++++++++++ src/processor/minidump_processor.cc | 5 + src/processor/stackwalker.cc | 7 ++ src/processor/stackwalker_ppc64.cc | 136 +++++++++++++++++++++++ src/processor/stackwalker_ppc64.h | 76 +++++++++++++ 9 files changed, 399 insertions(+), 8 deletions(-) create mode 100644 src/processor/stackwalker_ppc64.cc create mode 100644 src/processor/stackwalker_ppc64.h (limited to 'src') diff --git a/src/google_breakpad/common/minidump_cpu_ppc64.h b/src/google_breakpad/common/minidump_cpu_ppc64.h index da4f8723..3a883230 100644 --- a/src/google_breakpad/common/minidump_cpu_ppc64.h +++ b/src/google_breakpad/common/minidump_cpu_ppc64.h @@ -116,14 +116,14 @@ typedef struct { * context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other * CPUs. */ -#define MD_CONTEXT_PPC 0x20000000 -#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001) -#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008) -#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020) +#define MD_CONTEXT_PPC64 0x01000000 +#define MD_CONTEXT_PPC64_BASE (MD_CONTEXT_PPC64 | 0x00000001) +#define MD_CONTEXT_PPC64_FLOATING_POINT (MD_CONTEXT_PPC64 | 0x00000008) +#define MD_CONTEXT_PPC64_VECTOR (MD_CONTEXT_PPC64 | 0x00000020) -#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE -#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \ - MD_CONTEXT_PPC_FLOATING_POINT | \ - MD_CONTEXT_PPC_VECTOR) +#define MD_CONTEXT_PPC64_FULL MD_CONTEXT_PPC64_BASE +#define MD_CONTEXT_PPC64_ALL (MD_CONTEXT_PPC64_FULL | \ + MD_CONTEXT_PPC64_FLOATING_POINT | \ + MD_CONTEXT_PPC64_VECTOR) #endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */ diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h index af8cab0a..6406e4a9 100644 --- a/src/google_breakpad/common/minidump_format.h +++ b/src/google_breakpad/common/minidump_format.h @@ -604,6 +604,7 @@ typedef enum { MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ MD_CPU_ARCHITECTURE_X86_WIN64 = 10, /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ + MD_CPU_ARCHITECTURE_PPC64 = 0x8000, /* Breakpad-defined value for PPC64 */ MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */ MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ } MDCPUArchitecture; diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h index 18097714..87c00276 100644 --- a/src/google_breakpad/processor/minidump.h +++ b/src/google_breakpad/processor/minidump.h @@ -188,6 +188,7 @@ class MinidumpContext : public MinidumpStream { const MDRawContextAMD64* GetContextAMD64() const; const MDRawContextARM* GetContextARM() const; const MDRawContextPPC* GetContextPPC() const; + const MDRawContextPPC64* GetContextPPC64() const; const MDRawContextSPARC* GetContextSPARC() const; const MDRawContextX86* GetContextX86() const; @@ -202,6 +203,7 @@ class MinidumpContext : public MinidumpStream { MDRawContextBase* base; MDRawContextX86* x86; MDRawContextPPC* ppc; + MDRawContextPPC64* ppc64; MDRawContextAMD64* amd64; // on Solaris SPARC, sparc is defined as a numeric constant, // so variables can NOT be named as sparc diff --git a/src/google_breakpad/processor/stack_frame_cpu.h b/src/google_breakpad/processor/stack_frame_cpu.h index a9cf99b7..cda3a8de 100644 --- a/src/google_breakpad/processor/stack_frame_cpu.h +++ b/src/google_breakpad/processor/stack_frame_cpu.h @@ -123,6 +123,32 @@ struct StackFramePPC : public StackFrame { int context_validity; }; +struct StackFramePPC64 : public StackFrame { + // ContextValidity should eventually contain entries for the validity of + // other nonvolatile (callee-save) registers as in + // StackFrameX86::ContextValidity, but the ppc stackwalker doesn't currently + // locate registers other than the ones listed here. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_SRR0 = 1 << 0, + CONTEXT_VALID_GPR1 = 1 << 1, + CONTEXT_VALID_ALL = -1 + }; + + StackFramePPC64() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextPPC64 context; + + // context_validity is actually ContextValidity, but int is used because + // the OR operator doesn't work well with enumerated types. This indicates + // which fields in context are valid. + int context_validity; +}; + struct StackFrameAMD64 : public StackFrame { // ContextValidity has one entry for each register that we might be able // to recover. diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 43d22e61..17232b8d 100755 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -409,6 +409,78 @@ bool MinidumpContext::Read(uint32_t expected_size) { context_.amd64 = context_amd64.release(); } + // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext + // in the else case have 32 bits |context_flags|, so special case it here. + else if (expected_size == sizeof(MDRawContextPPC64)) { + uint64_t context_flags; + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { + BPLOG(ERROR) << "MinidumpContext could not read context flags"; + return false; + } + if (minidump_->swap()) + Swap(&context_flags); + + uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; + + scoped_ptr context_ppc64(new MDRawContextPPC64()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_ppc64->context_flags = context_flags; + + size_t flags_size = sizeof(context_ppc64->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_ppc64.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextPPC64) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read ppc64 context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext ppc64 does not match system info"; + return false; + } + if (minidump_->swap()) { + // context_ppc64->context_flags was already swapped. + Swap(&context_ppc64->srr0); + Swap(&context_ppc64->srr1); + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_PPC64_GPR_COUNT; + ++gpr_index) { + Swap(&context_ppc64->gpr[gpr_index]); + } + Swap(&context_ppc64->cr); + Swap(&context_ppc64->xer); + Swap(&context_ppc64->lr); + Swap(&context_ppc64->ctr); + Swap(&context_ppc64->vrsave); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; + ++fpr_index) { + Swap(&context_ppc64->float_save.fpregs[fpr_index]); + } + // Don't swap context_ppc64->float_save.fpscr_pad because it is only + // used for padding. + Swap(&context_ppc64->float_save.fpscr); + for (unsigned int vr_index = 0; + vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT; + ++vr_index) { + Normalize128(&context_ppc64->vector_save.save_vr[vr_index], true); + Swap(&context_ppc64->vector_save.save_vr[vr_index]); + } + Swap(&context_ppc64->vector_save.save_vscr); + // Don't swap the padding fields in vector_save. + Swap(&context_ppc64->vector_save.save_vrvalid); + } + + context_flags_ = context_ppc64->context_flags; + context_.ppc64 = context_ppc64.release(); + } + else { uint32_t context_flags; if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { @@ -753,6 +825,9 @@ bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const { 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; @@ -787,6 +862,15 @@ const MDRawContextPPC* MinidumpContext::GetContextPPC() const { 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"; @@ -824,6 +908,10 @@ void MinidumpContext::FreeContext() { delete context_.ppc; break; + case MD_CONTEXT_PPC64: + delete context_.ppc64; + break; + case MD_CONTEXT_AMD64: delete context_.amd64; break; @@ -886,6 +974,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) { return_value = true; break; + case MD_CONTEXT_PPC64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC64) + return_value = true; + break; + case MD_CONTEXT_AMD64: if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) return_value = true; @@ -1020,6 +1113,44 @@ void MinidumpContext::Print() { break; } + case MD_CONTEXT_PPC64: { + const MDRawContextPPC64* context_ppc64 = GetContextPPC64(); + printf("MDRawContextPPC64\n"); + printf(" context_flags = 0x%lx\n", + context_ppc64->context_flags); + printf(" srr0 = 0x%lx\n", context_ppc64->srr0); + printf(" srr1 = 0x%lx\n", context_ppc64->srr1); + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_PPC64_GPR_COUNT; + ++gpr_index) { + printf(" gpr[%2d] = 0x%lx\n", + gpr_index, context_ppc64->gpr[gpr_index]); + } + printf(" cr = 0x%lx\n", context_ppc64->cr); + printf(" xer = 0x%lx\n", context_ppc64->xer); + printf(" lr = 0x%lx\n", context_ppc64->lr); + printf(" ctr = 0x%lx\n", context_ppc64->ctr); + printf(" vrsave = 0x%lx\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"); @@ -3198,6 +3329,10 @@ string MinidumpSystemInfo::GetCPU() { cpu = "ppc"; break; + case MD_CPU_ARCHITECTURE_PPC64: + cpu = "ppc64"; + break; + case MD_CPU_ARCHITECTURE_SPARC: cpu = "sparc"; break; @@ -3863,6 +3998,9 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) { case MD_CPU_ARCHITECTURE_PPC: *context_cpu_flags = MD_CONTEXT_PPC; break; + case MD_CPU_ARCHITECTURE_PPC64: + *context_cpu_flags = MD_CONTEXT_PPC64; + break; case MD_CPU_ARCHITECTURE_SHX: *context_cpu_flags = MD_CONTEXT_SHX; break; diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index 08682780..afe15ca6 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -347,6 +347,11 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { break; } + case MD_CPU_ARCHITECTURE_PPC64: { + info->cpu = "ppc64"; + break; + } + case MD_CPU_ARCHITECTURE_SPARC: { info->cpu = "sparc"; break; diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index a92d71b8..076f2e5f 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -48,6 +48,7 @@ #include "processor/linked_ptr.h" #include "processor/logging.h" #include "processor/stackwalker_ppc.h" +#include "processor/stackwalker_ppc64.h" #include "processor/stackwalker_sparc.h" #include "processor/stackwalker_x86.h" #include "processor/stackwalker_amd64.h" @@ -165,6 +166,12 @@ Stackwalker* Stackwalker::StackwalkerForCPU( memory, modules, frame_symbolizer); break; + case MD_CONTEXT_PPC64: + cpu_stackwalker = new StackwalkerPPC64(system_info, + context->GetContextPPC64(), + memory, modules, frame_symbolizer); + break; + case MD_CONTEXT_AMD64: cpu_stackwalker = new StackwalkerAMD64(system_info, context->GetContextAMD64(), diff --git a/src/processor/stackwalker_ppc64.cc b/src/processor/stackwalker_ppc64.cc new file mode 100644 index 00000000..fa49ce39 --- /dev/null +++ b/src/processor/stackwalker_ppc64.cc @@ -0,0 +1,136 @@ +// Copyright (c) 2013 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. + +// stackwalker_ppc64.cc: ppc64-specific stackwalker. +// +// See stackwalker_ppc64.h for documentation. + + +#include "processor/stackwalker_ppc64.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/logging.h" + +#include + +namespace google_breakpad { + + +StackwalkerPPC64::StackwalkerPPC64(const SystemInfo* system_info, + const MDRawContextPPC64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context) { +} + + +StackFrame* StackwalkerPPC64::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFramePPC64* frame = new StackFramePPC64(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFramePPC64::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.srr0; + + return frame; +} + + +StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + // The instruction pointers for previous frames are saved on the stack. + // The typical ppc64 calling convention is for the called procedure to store + // its return address in the calling procedure's stack frame at 8(%r1), + // and to allocate its own stack frame by decrementing %r1 (the stack + // pointer) and saving the old value of %r1 at 0(%r1). Because the ppc64 has + // no hardware stack, there is no distinction between the stack pointer and + // frame pointer, and what is typically thought of as the frame pointer on + // an x86 is usually referred to as the stack pointer on a ppc64. + + StackFramePPC64* last_frame = static_cast( + stack->frames()->back()); + + // A caller frame must reside higher in memory than its callee frames. + // Anything else is an error, or an indication that we've reached the + // end of the stack. + uint64_t stack_pointer; + if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1], + &stack_pointer) || + stack_pointer <= last_frame->context.gpr[1]) { + return NULL; + } + + // Mac OS X/Darwin gives 1 as the return address from the bottom-most + // frame in a stack (a thread's entry point). I haven't found any + // documentation on this, but 0 or 1 would be bogus return addresses, + // so check for them here and return false (end of stack) when they're + // hit to avoid having a phantom frame. + uint64_t instruction; + if (!memory_->GetMemoryAtAddress(stack_pointer + 16, &instruction) || + instruction <= 1) { + return NULL; + } + + StackFramePPC64* frame = new StackFramePPC64(); + + frame->context = last_frame->context; + frame->context.srr0 = instruction; + frame->context.gpr[1] = stack_pointer; + frame->context_validity = StackFramePPC64::CONTEXT_VALID_SRR0 | + StackFramePPC64::CONTEXT_VALID_GPR1; + frame->trust = StackFrame::FRAME_TRUST_FP; + + // frame->context.srr0 is the return address, which is one instruction + // past the branch that caused us to arrive at the callee. Set + // frame_ppc64->instruction to eight less than that. Since all ppc64 + // instructions are 8 bytes wide, this is the address of the branch + // instruction. This allows source line information to match up with the + // line that contains a function call. Callers that require the exact + // return address value may access the context.srr0 field of StackFramePPC64. + frame->instruction = frame->context.srr0 - 8; + + return frame; +} + + +} // namespace google_breakpad diff --git a/src/processor/stackwalker_ppc64.h b/src/processor/stackwalker_ppc64.h new file mode 100644 index 00000000..6579db70 --- /dev/null +++ b/src/processor/stackwalker_ppc64.h @@ -0,0 +1,76 @@ +// Copyright (c) 2013 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. + +// stackwalker_ppc64.h: ppc-specific stackwalker. +// +// Provides stack frames given ppc64 register context and a memory region +// corresponding to a ppc64 stack. + + +#ifndef PROCESSOR_STACKWALKER_PPC64_H__ +#define PROCESSOR_STACKWALKER_PPC64_H__ + + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stackwalker.h" + +namespace google_breakpad { + +class CodeModules; + +class StackwalkerPPC64 : public Stackwalker { + public: + // context is a ppc64 context object that gives access to ppc64-specific + // register state corresponding to the innermost called frame to be + // included in the stack. The other arguments are passed directly through + // to the base Stackwalker constructor. + StackwalkerPPC64(const SystemInfo* system_info, + const MDRawContextPPC64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + private: + // Implementation of Stackwalker, using ppc64 context (stack pointer in %r1, + // saved program counter in %srr0) and stack conventions (saved stack + // pointer at 0(%r1), return address at 8(0(%r1)). + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextPPC64* context_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_PPC64_H__ -- cgit v1.2.1