aboutsummaryrefslogtreecommitdiff
path: root/src/processor/stackwalker_ppc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/processor/stackwalker_ppc.cc')
-rw-r--r--src/processor/stackwalker_ppc.cc94
1 files changed, 54 insertions, 40 deletions
diff --git a/src/processor/stackwalker_ppc.cc b/src/processor/stackwalker_ppc.cc
index 668f59c2..2980c51a 100644
--- a/src/processor/stackwalker_ppc.cc
+++ b/src/processor/stackwalker_ppc.cc
@@ -35,6 +35,8 @@
#include "processor/stackwalker_ppc.h"
+#include "google/call_stack.h"
+#include "google/stack_frame_cpu.h"
#include "processor/minidump.h"
namespace google_airbag {
@@ -55,65 +57,77 @@ StackwalkerPPC::StackwalkerPPC(const MDRawContextPPC *context,
}
-bool StackwalkerPPC::GetContextFrame(StackFrame *frame) {
- if (!context_ || !memory_ || !frame)
- return false;
+StackFrame* StackwalkerPPC::GetContextFrame() {
+ if (!context_ || !memory_)
+ return NULL;
- // The stack frame and instruction pointers are stored directly in
- // registers, so pull them straight out of the CPU context structure.
- frame->frame_pointer = context_->gpr[1];
- frame->instruction = context_->srr0;
+ StackFramePPC *frame = new StackFramePPC();
- return true;
-}
+ // 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 = StackFramePPC::CONTEXT_VALID_ALL;
+ frame->instruction = frame->context.srr0;
+ return frame;
+}
-bool StackwalkerPPC::GetCallerFrame(StackFrame *frame,
- const StackFrames *walked_frames) {
- if (!memory_ || !frame || !walked_frames)
- return false;
- // The stack frame and instruction pointers for previous frames are saved
- // on the stack. The typical ppc 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 ppc 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 ppc.
+StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack *stack) {
+ if (!memory_ || !stack)
+ return NULL;
- u_int32_t last_stack_pointer = walked_frames->back().frame_pointer;
+ // The instruction pointers for previous frames are saved on the stack.
+ // The typical ppc 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 ppc 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 ppc.
- // Don't pass frame.frame_pointer or frame.instruction directly
- // ReadMemory, because their types are too wide (64-bit), and we
- // specifically want to read 32-bit quantities for both.
- u_int32_t stack_pointer;
- if (!memory_->GetMemoryAtAddress(last_stack_pointer, &stack_pointer))
- return false;
+ StackFramePPC *last_frame = static_cast<StackFramePPC*>(
+ 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.
- if (stack_pointer <= last_stack_pointer)
- return false;
-
- u_int32_t instruction;
- if (!memory_->GetMemoryAtAddress(stack_pointer + 8, &instruction))
- return false;
+ u_int32_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.
- if (instruction <= 1)
- return false;
+ u_int32_t instruction;
+ if (!memory_->GetMemoryAtAddress(stack_pointer + 8, &instruction) ||
+ instruction <= 1) {
+ return NULL;
+ }
+
+ StackFramePPC *frame = new StackFramePPC();
+
+ frame->context = last_frame->context;
+ frame->context.srr0 = instruction;
+ frame->context.gpr[1] = stack_pointer;
+ frame->context_validity = StackFramePPC::CONTEXT_VALID_SRR0 |
+ StackFramePPC::CONTEXT_VALID_GPR1;
- frame->frame_pointer = stack_pointer;
- frame->instruction = instruction;
+ // frame->context.srr0 is the return address, which is one instruction
+ // past the branch that caused us to arrive at the callee. Set
+ // frame_ppc->instruction to four less than that. Since all ppc
+ // instructions are 4 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 StackFramePPC.
+ frame->instruction = frame->context.srr0 - 4;
- return true;
+ return frame;
}