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