1cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// Copyright (c) 2013 Google Inc. 2cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// All rights reserved. 3cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// 4cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// Redistribution and use in source and binary forms, with or without 5cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// modification, are permitted provided that the following conditions are 6cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// met: 7cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// 8cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// * Redistributions of source code must retain the above copyright 9cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// notice, this list of conditions and the following disclaimer. 10cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// * Redistributions in binary form must reproduce the above 11cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// copyright notice, this list of conditions and the following disclaimer 12cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// in the documentation and/or other materials provided with the 13cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// distribution. 14cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// * Neither the name of Google Inc. nor the names of its 15cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// contributors may be used to endorse or promote products derived from 16cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// this software without specific prior written permission. 17cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// 18cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 30cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// stackwalker_ppc64.cc: ppc64-specific stackwalker. 31cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// 32cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org// See stackwalker_ppc64.h for documentation. 33cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 34cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 35cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org#include "processor/stackwalker_ppc64.h" 36cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org#include "google_breakpad/processor/call_stack.h" 37cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org#include "google_breakpad/processor/memory_region.h" 38cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org#include "google_breakpad/processor/stack_frame_cpu.h" 39cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org#include "processor/logging.h" 40cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 41cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org#include <stdio.h> 42cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 43cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.orgnamespace google_breakpad { 44cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 45cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 46cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.orgStackwalkerPPC64::StackwalkerPPC64(const SystemInfo* system_info, 47cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org const MDRawContextPPC64* context, 48cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org MemoryRegion* memory, 49cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org const CodeModules* modules, 50cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org StackFrameSymbolizer* resolver_helper) 51cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org : Stackwalker(system_info, memory, modules, resolver_helper), 52cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org context_(context) { 53cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org} 54cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 55cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 56cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.orgStackFrame* StackwalkerPPC64::GetContextFrame() { 57cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org if (!context_) { 58cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org BPLOG(ERROR) << "Can't get context frame without context"; 59cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org return NULL; 60cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org } 61cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 62cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org StackFramePPC64* frame = new StackFramePPC64(); 63cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 64cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // The instruction pointer is stored directly in a register, so pull it 65cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // straight out of the CPU context structure. 66cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->context = *context_; 67cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->context_validity = StackFramePPC64::CONTEXT_VALID_ALL; 68cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->trust = StackFrame::FRAME_TRUST_CONTEXT; 69cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->instruction = frame->context.srr0; 70cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 71cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org return frame; 72cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org} 73cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 74cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 7542b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.comStackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack, 7642b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.com bool stack_scan_allowed) { 77cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org if (!memory_ || !stack) { 78cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org BPLOG(ERROR) << "Can't get caller frame without memory or stack"; 79cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org return NULL; 80cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org } 81cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 82cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // The instruction pointers for previous frames are saved on the stack. 83cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // The typical ppc64 calling convention is for the called procedure to store 84cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // its return address in the calling procedure's stack frame at 8(%r1), 85cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // and to allocate its own stack frame by decrementing %r1 (the stack 86cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // pointer) and saving the old value of %r1 at 0(%r1). Because the ppc64 has 87cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // no hardware stack, there is no distinction between the stack pointer and 88cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // frame pointer, and what is typically thought of as the frame pointer on 89cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // an x86 is usually referred to as the stack pointer on a ppc64. 90cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 91cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org StackFramePPC64* last_frame = static_cast<StackFramePPC64*>( 92cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org stack->frames()->back()); 93cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 94cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // A caller frame must reside higher in memory than its callee frames. 95cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // Anything else is an error, or an indication that we've reached the 96cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // end of the stack. 97cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org uint64_t stack_pointer; 98cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1], 99cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org &stack_pointer) || 100cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org stack_pointer <= last_frame->context.gpr[1]) { 101cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org return NULL; 102cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org } 103cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 104cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // Mac OS X/Darwin gives 1 as the return address from the bottom-most 105cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // frame in a stack (a thread's entry point). I haven't found any 106cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // documentation on this, but 0 or 1 would be bogus return addresses, 107cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // so check for them here and return false (end of stack) when they're 108cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // hit to avoid having a phantom frame. 109cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org uint64_t instruction; 110cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org if (!memory_->GetMemoryAtAddress(stack_pointer + 16, &instruction) || 111cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org instruction <= 1) { 112cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org return NULL; 113cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org } 114cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 115cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org StackFramePPC64* frame = new StackFramePPC64(); 116cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 117cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->context = last_frame->context; 118cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->context.srr0 = instruction; 119cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->context.gpr[1] = stack_pointer; 120cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->context_validity = StackFramePPC64::CONTEXT_VALID_SRR0 | 121cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org StackFramePPC64::CONTEXT_VALID_GPR1; 122cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->trust = StackFrame::FRAME_TRUST_FP; 123cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 124cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // frame->context.srr0 is the return address, which is one instruction 125cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // past the branch that caused us to arrive at the callee. Set 126cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // frame_ppc64->instruction to eight less than that. Since all ppc64 127cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // instructions are 8 bytes wide, this is the address of the branch 128cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // instruction. This allows source line information to match up with the 129cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // line that contains a function call. Callers that require the exact 130cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org // return address value may access the context.srr0 field of StackFramePPC64. 131cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org frame->instruction = frame->context.srr0 - 8; 132cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 133cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org return frame; 134cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org} 135cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 136cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org 137cd1f1a6399d5a73ac2bdf5671f8322ba013e8e21thestig@chromium.org} // namespace google_breakpad 138