139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// Copyright (c) 2013 Google Inc. 239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// All rights reserved. 339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// 439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// Redistribution and use in source and binary forms, with or without 539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// modification, are permitted provided that the following conditions are 639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// met: 739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// 839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// * Redistributions of source code must retain the above copyright 939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// notice, this list of conditions and the following disclaimer. 1039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// * Redistributions in binary form must reproduce the above 1139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// copyright notice, this list of conditions and the following disclaimer 1239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// in the documentation and/or other materials provided with the 1339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// distribution. 1439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// * Neither the name of Google Inc. nor the names of its 1539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// contributors may be used to endorse or promote products derived from 1639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// this software without specific prior written permission. 1739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// 1839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 3039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// stackwalker_arm64.cc: arm64-specific stackwalker. 3139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// 3239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// See stackwalker_arm64.h for documentation. 3339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// 3439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org// Author: Mark Mentovai, Ted Mielczarek, Jim Blandy, Colin Blundell 3539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 3639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include <vector> 3739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 3839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "common/scoped_ptr.h" 3939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "google_breakpad/processor/call_stack.h" 4039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "google_breakpad/processor/memory_region.h" 4139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "google_breakpad/processor/source_line_resolver_interface.h" 4239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "google_breakpad/processor/stack_frame_cpu.h" 4339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "processor/cfi_frame_info.h" 4439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "processor/logging.h" 4539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org#include "processor/stackwalker_arm64.h" 4639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 4739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgnamespace google_breakpad { 4839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 4939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 5039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgStackwalkerARM64::StackwalkerARM64(const SystemInfo* system_info, 5139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org const MDRawContextARM64* context, 5239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org MemoryRegion* memory, 5339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org const CodeModules* modules, 5439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameSymbolizer* resolver_helper) 5539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org : Stackwalker(system_info, memory, modules, resolver_helper), 5639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org context_(context), 5739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org context_frame_validity_(StackFrameARM64::CONTEXT_VALID_ALL) { } 5839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 5939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 6039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgStackFrame* StackwalkerARM64::GetContextFrame() { 6139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (!context_) { 6239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org BPLOG(ERROR) << "Can't get context frame without context"; 6339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 6439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org } 6539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 6639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64* frame = new StackFrameARM64(); 6739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 6839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // The instruction pointer is stored directly in a register (x32), so pull it 6939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // straight out of the CPU context structure. 7039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context = *context_; 7139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context_validity = context_frame_validity_; 7239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->trust = StackFrame::FRAME_TRUST_CONTEXT; 7339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC]; 7439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 7539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return frame; 7639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org} 7739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 7839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgStackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( 7939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org const vector<StackFrame*> &frames, 8039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org CFIFrameInfo* cfi_frame_info) { 81dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); 82dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org 83dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org static const char* register_names[] = { 84dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 85dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 86dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 87dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", 88dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org "pc", NULL 89dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org }; 90dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org 91dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // Populate a dictionary with the valid register values in last_frame. 92dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org CFIFrameInfo::RegisterValueMap<uint64_t> callee_registers; 93dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org for (int i = 0; register_names[i]; i++) { 94dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (last_frame->context_validity & StackFrameARM64::RegisterValidFlag(i)) 95dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org callee_registers[register_names[i]] = last_frame->context.iregs[i]; 96dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 97dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org 98dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // Use the STACK CFI data to recover the caller's register values. 99dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org CFIFrameInfo::RegisterValueMap<uint64_t> caller_registers; 100dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, 101dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org &caller_registers)) { 102dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org return NULL; 103dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 104dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // Construct a new stack frame given the values the CFI recovered. 105dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org scoped_ptr<StackFrameARM64> frame(new StackFrameARM64()); 106dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org for (int i = 0; register_names[i]; i++) { 107dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry = 108dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org caller_registers.find(register_names[i]); 109dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (entry != caller_registers.end()) { 110dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // We recovered the value of this register; fill the context with the 111dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // value from caller_registers. 112dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context_validity |= StackFrameARM64::RegisterValidFlag(i); 113dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context.iregs[i] = entry->second; 114dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } else if (19 <= i && i <= 29 && (last_frame->context_validity & 115dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org StackFrameARM64::RegisterValidFlag(i))) { 116dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // If the STACK CFI data doesn't mention some callee-saves register, and 117dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // it is valid in the callee, assume the callee has not yet changed it. 118dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // Registers r19 through r29 are callee-saves, according to the Procedure 119dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // Call Standard for the ARM AARCH64 Architecture, which the Linux ABI 120dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // follows. 121dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context_validity |= StackFrameARM64::RegisterValidFlag(i); 122dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context.iregs[i] = last_frame->context.iregs[i]; 123dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 124dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 125dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // If the CFI doesn't recover the PC explicitly, then use .ra. 126dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (!(frame->context_validity & StackFrameARM64::CONTEXT_VALID_PC)) { 127dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry = 128dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org caller_registers.find(".ra"); 129dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (entry != caller_registers.end()) { 130dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context_validity |= StackFrameARM64::CONTEXT_VALID_PC; 131dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = entry->second; 132dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 133dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 134dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // If the CFI doesn't recover the SP explicitly, then use .cfa. 135dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (!(frame->context_validity & StackFrameARM64::CONTEXT_VALID_SP)) { 136dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry = 137dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org caller_registers.find(".cfa"); 138dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if (entry != caller_registers.end()) { 139dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context_validity |= StackFrameARM64::CONTEXT_VALID_SP; 140dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = entry->second; 141dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 142dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org } 143dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org 144dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org // If we didn't recover the PC and the SP, then the frame isn't very useful. 145dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org static const uint64_t essentials = (StackFrameARM64::CONTEXT_VALID_SP 146dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org | StackFrameARM64::CONTEXT_VALID_PC); 147dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org if ((frame->context_validity & essentials) != essentials) 148dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org return NULL; 149dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org 150dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org frame->trust = StackFrame::FRAME_TRUST_CFI; 151dc48ba29af49e4c5c1a38f43d2ed052c96de33bbrmcilroy@chromium.org return frame.release(); 15239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org} 15339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 15439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgStackFrameARM64* StackwalkerARM64::GetCallerByStackScan( 15539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org const vector<StackFrame*> &frames) { 15639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); 15739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]; 15839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org uint64_t caller_sp, caller_pc; 15939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 16039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, 16139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frames.size() == 1 /* is_context_frame */)) { 16239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // No plausible return address was found. 16339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 16439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org } 16539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 16639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // ScanForReturnAddress found a reasonable return address. Advance 16739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // %sp to the location above the one where the return address was 16839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // found. 16939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org caller_sp += 8; 17039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 17139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // Create a new stack frame (ownership will be transferred to the caller) 17239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // and fill it in. 17339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64* frame = new StackFrameARM64(); 17439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 17539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->trust = StackFrame::FRAME_TRUST_SCAN; 17639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context = last_frame->context; 17739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = caller_pc; 17839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = caller_sp; 17939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context_validity = StackFrameARM64::CONTEXT_VALID_PC | 18039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64::CONTEXT_VALID_SP; 18139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 18239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return frame; 18339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org} 18439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 18539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgStackFrameARM64* StackwalkerARM64::GetCallerByFramePointer( 18639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org const vector<StackFrame*> &frames) { 18739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); 18839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 18939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org uint64_t last_fp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP]; 19039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 19139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org uint64_t caller_fp = 0; 19239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { 19339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" 19439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org << std::hex << last_fp; 19539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 19639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org } 19739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 19839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org uint64_t caller_lr = 0; 19939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 8, &caller_lr)) { 20039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 8: 0x" 20139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org << std::hex << (last_fp + 8); 20239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 20339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org } 20439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 20539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org uint64_t caller_sp = last_fp ? last_fp + 16 : 20639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]; 20739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 20839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // Create a new stack frame (ownership will be transferred to the caller) 20939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // and fill it in. 21039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64* frame = new StackFrameARM64(); 21139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 21239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->trust = StackFrame::FRAME_TRUST_FP; 21339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context = last_frame->context; 21439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] = caller_fp; 21539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = caller_sp; 21639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = 21739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR]; 21839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = caller_lr; 21939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->context_validity = StackFrameARM64::CONTEXT_VALID_PC | 22039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64::CONTEXT_VALID_LR | 22139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64::CONTEXT_VALID_FP | 22239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64::CONTEXT_VALID_SP; 22339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return frame; 22439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org} 22539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 22639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.orgStackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, 22739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org bool stack_scan_allowed) { 22839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (!memory_ || !stack) { 22939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org BPLOG(ERROR) << "Can't get caller frame without memory or stack"; 23039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 23139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org } 23239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 23339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org const vector<StackFrame*> &frames = *stack->frames(); 23439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); 23539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org scoped_ptr<StackFrameARM64> frame; 23639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 23739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // See if there is DWARF call frame information covering this address. 23839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org scoped_ptr<CFIFrameInfo> cfi_frame_info( 23939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame_symbolizer_->FindCFIFrameInfo(last_frame)); 24039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (cfi_frame_info.get()) 24139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); 24239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 24339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // If CFI failed, or there wasn't CFI available, fall back to frame pointer. 24439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (!frame.get()) 24539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame.reset(GetCallerByFramePointer(frames)); 24639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 24739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // If everything failed, fall back to stack scanning. 24839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (stack_scan_allowed && !frame.get()) 24939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame.reset(GetCallerByStackScan(frames)); 25039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 25139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // If nothing worked, tell the caller. 25239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (!frame.get()) 25339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 25439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 25539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // An instruction address of zero marks the end of the stack. 25639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] == 0) 25739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 25839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 25939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // If the new stack pointer is at a lower address than the old, then 26039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // that's clearly incorrect. Treat this as end-of-stack to enforce 26139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // progress and avoid infinite loops. 26239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org if (frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] 26339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org < last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]) 26439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return NULL; 26539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 26639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // The new frame's context's PC is the return address, which is one 26739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // instruction past the instruction that caused us to arrive at the callee. 26839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // ARM64 instructions have a uniform 4-byte encoding, so subtracting 4 off 26939d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // the return address gets back to the beginning of the call instruction. 27039d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // Callers that require the exact return address value may access 27139d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org // frame->context.iregs[MD_CONTEXT_ARM64_REG_PC]. 27239d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] - 4; 27339d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 27439d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org return frame.release(); 27539d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org} 27639d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 27739d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org 27839d7964df5d3ba7c3889bf19004f6e18eee5cfc6mark@chromium.org} // namespace google_breakpad 279