183e085b7a331c96237cf8e814f97b3ef4c36a70fjimblandy// Copyright (c) 2010 Google Inc.
2960e5277ee489960c40c50c6222606200419302ammentovai// All rights reserved.
3960e5277ee489960c40c50c6222606200419302ammentovai//
4960e5277ee489960c40c50c6222606200419302ammentovai// Redistribution and use in source and binary forms, with or without
5960e5277ee489960c40c50c6222606200419302ammentovai// modification, are permitted provided that the following conditions are
6960e5277ee489960c40c50c6222606200419302ammentovai// met:
7960e5277ee489960c40c50c6222606200419302ammentovai//
8960e5277ee489960c40c50c6222606200419302ammentovai//     * Redistributions of source code must retain the above copyright
9960e5277ee489960c40c50c6222606200419302ammentovai// notice, this list of conditions and the following disclaimer.
10960e5277ee489960c40c50c6222606200419302ammentovai//     * Redistributions in binary form must reproduce the above
11960e5277ee489960c40c50c6222606200419302ammentovai// copyright notice, this list of conditions and the following disclaimer
12960e5277ee489960c40c50c6222606200419302ammentovai// in the documentation and/or other materials provided with the
13960e5277ee489960c40c50c6222606200419302ammentovai// distribution.
14960e5277ee489960c40c50c6222606200419302ammentovai//     * Neither the name of Google Inc. nor the names of its
15960e5277ee489960c40c50c6222606200419302ammentovai// contributors may be used to endorse or promote products derived from
16960e5277ee489960c40c50c6222606200419302ammentovai// this software without specific prior written permission.
17960e5277ee489960c40c50c6222606200419302ammentovai//
18960e5277ee489960c40c50c6222606200419302ammentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19960e5277ee489960c40c50c6222606200419302ammentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20960e5277ee489960c40c50c6222606200419302ammentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21960e5277ee489960c40c50c6222606200419302ammentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22960e5277ee489960c40c50c6222606200419302ammentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23960e5277ee489960c40c50c6222606200419302ammentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24960e5277ee489960c40c50c6222606200419302ammentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25960e5277ee489960c40c50c6222606200419302ammentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26960e5277ee489960c40c50c6222606200419302ammentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27960e5277ee489960c40c50c6222606200419302ammentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28960e5277ee489960c40c50c6222606200419302ammentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29960e5277ee489960c40c50c6222606200419302ammentovai
30960e5277ee489960c40c50c6222606200419302ammentovai// stackwalker_ppc.cc: ppc-specific stackwalker.
31960e5277ee489960c40c50c6222606200419302ammentovai//
32960e5277ee489960c40c50c6222606200419302ammentovai// See stackwalker_ppc.h for documentation.
33960e5277ee489960c40c50c6222606200419302ammentovai//
34960e5277ee489960c40c50c6222606200419302ammentovai// Author: Mark Mentovai
35960e5277ee489960c40c50c6222606200419302ammentovai
36960e5277ee489960c40c50c6222606200419302ammentovai
37960e5277ee489960c40c50c6222606200419302ammentovai#include "processor/stackwalker_ppc.h"
38e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/call_stack.h"
39e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/memory_region.h"
40e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/stack_frame_cpu.h"
4165571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai#include "processor/logging.h"
42960e5277ee489960c40c50c6222606200419302ammentovai
43e5dc60822e5938fea2ae892ccddb906641ba174emmentovainamespace google_breakpad {
44960e5277ee489960c40c50c6222606200419302ammentovai
45960e5277ee489960c40c50c6222606200419302ammentovai
469753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.comStackwalkerPPC::StackwalkerPPC(const SystemInfo* system_info,
479753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                               const MDRawContextPPC* context,
489753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                               MemoryRegion* memory,
499753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                               const CodeModules* modules,
509753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                               StackFrameSymbolizer* resolver_helper)
519753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com    : Stackwalker(system_info, memory, modules, resolver_helper),
52960e5277ee489960c40c50c6222606200419302ammentovai      context_(context) {
53e721e628ec10381c96e38cfc82c1816983097165ted.mielczarek@gmail.com  if (memory_ && memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) {
54960e5277ee489960c40c50c6222606200419302ammentovai    // This implementation only covers 32-bit ppc CPUs.  The limits of the
55960e5277ee489960c40c50c6222606200419302ammentovai    // supplied stack are invalid.  Mark memory_ = NULL, which will cause
56960e5277ee489960c40c50c6222606200419302ammentovai    // stackwalking to fail.
5765571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai    BPLOG(ERROR) << "Memory out of range for stackwalking: " <<
5865571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai                    HexString(memory_->GetBase()) << "+" <<
5965571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai                    HexString(memory_->GetSize());
60960e5277ee489960c40c50c6222606200419302ammentovai    memory_ = NULL;
61960e5277ee489960c40c50c6222606200419302ammentovai  }
62960e5277ee489960c40c50c6222606200419302ammentovai}
63960e5277ee489960c40c50c6222606200419302ammentovai
64960e5277ee489960c40c50c6222606200419302ammentovai
65246f4068280b5b191303ff13671e43a0522987demmentovaiStackFrame* StackwalkerPPC::GetContextFrame() {
66e721e628ec10381c96e38cfc82c1816983097165ted.mielczarek@gmail.com  if (!context_) {
67e721e628ec10381c96e38cfc82c1816983097165ted.mielczarek@gmail.com    BPLOG(ERROR) << "Can't get context frame without context";
68246f4068280b5b191303ff13671e43a0522987demmentovai    return NULL;
6965571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai  }
70960e5277ee489960c40c50c6222606200419302ammentovai
719753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFramePPC* frame = new StackFramePPC();
72960e5277ee489960c40c50c6222606200419302ammentovai
73246f4068280b5b191303ff13671e43a0522987demmentovai  // The instruction pointer is stored directly in a register, so pull it
74246f4068280b5b191303ff13671e43a0522987demmentovai  // straight out of the CPU context structure.
75246f4068280b5b191303ff13671e43a0522987demmentovai  frame->context = *context_;
76246f4068280b5b191303ff13671e43a0522987demmentovai  frame->context_validity = StackFramePPC::CONTEXT_VALID_ALL;
778c33b3e9c95a67a9bb06c033d5d4c28d9a55168bted.mielczarek  frame->trust = StackFrame::FRAME_TRUST_CONTEXT;
78246f4068280b5b191303ff13671e43a0522987demmentovai  frame->instruction = frame->context.srr0;
79960e5277ee489960c40c50c6222606200419302ammentovai
80246f4068280b5b191303ff13671e43a0522987demmentovai  return frame;
81246f4068280b5b191303ff13671e43a0522987demmentovai}
82960e5277ee489960c40c50c6222606200419302ammentovai
83960e5277ee489960c40c50c6222606200419302ammentovai
8442b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.comStackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack,
8542b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.com                                           bool stack_scan_allowed) {
8665571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai  if (!memory_ || !stack) {
8765571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai    BPLOG(ERROR) << "Can't get caller frame without memory or stack";
88246f4068280b5b191303ff13671e43a0522987demmentovai    return NULL;
8965571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai  }
90960e5277ee489960c40c50c6222606200419302ammentovai
91246f4068280b5b191303ff13671e43a0522987demmentovai  // The instruction pointers for previous frames are saved on the stack.
92246f4068280b5b191303ff13671e43a0522987demmentovai  // The typical ppc calling convention is for the called procedure to store
93246f4068280b5b191303ff13671e43a0522987demmentovai  // its return address in the calling procedure's stack frame at 8(%r1),
94246f4068280b5b191303ff13671e43a0522987demmentovai  // and to allocate its own stack frame by decrementing %r1 (the stack
95246f4068280b5b191303ff13671e43a0522987demmentovai  // pointer) and saving the old value of %r1 at 0(%r1).  Because the ppc has
96246f4068280b5b191303ff13671e43a0522987demmentovai  // no hardware stack, there is no distinction between the stack pointer and
97246f4068280b5b191303ff13671e43a0522987demmentovai  // frame pointer, and what is typically thought of as the frame pointer on
98246f4068280b5b191303ff13671e43a0522987demmentovai  // an x86 is usually referred to as the stack pointer on a ppc.
99960e5277ee489960c40c50c6222606200419302ammentovai
1009753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFramePPC* last_frame = static_cast<StackFramePPC*>(
101246f4068280b5b191303ff13671e43a0522987demmentovai      stack->frames()->back());
102960e5277ee489960c40c50c6222606200419302ammentovai
103960e5277ee489960c40c50c6222606200419302ammentovai  // A caller frame must reside higher in memory than its callee frames.
104960e5277ee489960c40c50c6222606200419302ammentovai  // Anything else is an error, or an indication that we've reached the
105960e5277ee489960c40c50c6222606200419302ammentovai  // end of the stack.
1066162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t stack_pointer;
107246f4068280b5b191303ff13671e43a0522987demmentovai  if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1],
108246f4068280b5b191303ff13671e43a0522987demmentovai                                   &stack_pointer) ||
109246f4068280b5b191303ff13671e43a0522987demmentovai      stack_pointer <= last_frame->context.gpr[1]) {
110246f4068280b5b191303ff13671e43a0522987demmentovai    return NULL;
111246f4068280b5b191303ff13671e43a0522987demmentovai  }
112960e5277ee489960c40c50c6222606200419302ammentovai
113960e5277ee489960c40c50c6222606200419302ammentovai  // Mac OS X/Darwin gives 1 as the return address from the bottom-most
114960e5277ee489960c40c50c6222606200419302ammentovai  // frame in a stack (a thread's entry point).  I haven't found any
115960e5277ee489960c40c50c6222606200419302ammentovai  // documentation on this, but 0 or 1 would be bogus return addresses,
116960e5277ee489960c40c50c6222606200419302ammentovai  // so check for them here and return false (end of stack) when they're
117960e5277ee489960c40c50c6222606200419302ammentovai  // hit to avoid having a phantom frame.
1186162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint32_t instruction;
119246f4068280b5b191303ff13671e43a0522987demmentovai  if (!memory_->GetMemoryAtAddress(stack_pointer + 8, &instruction) ||
120246f4068280b5b191303ff13671e43a0522987demmentovai      instruction <= 1) {
121246f4068280b5b191303ff13671e43a0522987demmentovai    return NULL;
122246f4068280b5b191303ff13671e43a0522987demmentovai  }
123246f4068280b5b191303ff13671e43a0522987demmentovai
1249753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFramePPC* frame = new StackFramePPC();
125246f4068280b5b191303ff13671e43a0522987demmentovai
126246f4068280b5b191303ff13671e43a0522987demmentovai  frame->context = last_frame->context;
127246f4068280b5b191303ff13671e43a0522987demmentovai  frame->context.srr0 = instruction;
128246f4068280b5b191303ff13671e43a0522987demmentovai  frame->context.gpr[1] = stack_pointer;
129246f4068280b5b191303ff13671e43a0522987demmentovai  frame->context_validity = StackFramePPC::CONTEXT_VALID_SRR0 |
130246f4068280b5b191303ff13671e43a0522987demmentovai                            StackFramePPC::CONTEXT_VALID_GPR1;
1318c33b3e9c95a67a9bb06c033d5d4c28d9a55168bted.mielczarek  frame->trust = StackFrame::FRAME_TRUST_FP;
132960e5277ee489960c40c50c6222606200419302ammentovai
133246f4068280b5b191303ff13671e43a0522987demmentovai  // frame->context.srr0 is the return address, which is one instruction
134246f4068280b5b191303ff13671e43a0522987demmentovai  // past the branch that caused us to arrive at the callee.  Set
135246f4068280b5b191303ff13671e43a0522987demmentovai  // frame_ppc->instruction to four less than that.  Since all ppc
136246f4068280b5b191303ff13671e43a0522987demmentovai  // instructions are 4 bytes wide, this is the address of the branch
137246f4068280b5b191303ff13671e43a0522987demmentovai  // instruction.  This allows source line information to match up with the
138246f4068280b5b191303ff13671e43a0522987demmentovai  // line that contains a function call.  Callers that require the exact
139246f4068280b5b191303ff13671e43a0522987demmentovai  // return address value may access the context.srr0 field of StackFramePPC.
140246f4068280b5b191303ff13671e43a0522987demmentovai  frame->instruction = frame->context.srr0 - 4;
141960e5277ee489960c40c50c6222606200419302ammentovai
142246f4068280b5b191303ff13671e43a0522987demmentovai  return frame;
143960e5277ee489960c40c50c6222606200419302ammentovai}
144960e5277ee489960c40c50c6222606200419302ammentovai
145960e5277ee489960c40c50c6222606200419302ammentovai
146e5dc60822e5938fea2ae892ccddb906641ba174emmentovai}  // namespace google_breakpad
147