183e085b7a331c96237cf8e814f97b3ef4c36a70fjimblandy// Copyright (c) 2010 Google Inc. 29276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// All rights reserved. 39276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// 49276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// Redistribution and use in source and binary forms, with or without 59276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// modification, are permitted provided that the following conditions are 69276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// met: 79276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// 89276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// * Redistributions of source code must retain the above copyright 99276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// notice, this list of conditions and the following disclaimer. 109276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// * Redistributions in binary form must reproduce the above 119276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// copyright notice, this list of conditions and the following disclaimer 129276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// in the documentation and/or other materials provided with the 139276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// distribution. 149276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// * Neither the name of Google Inc. nor the names of its 159276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// contributors may be used to endorse or promote products derived from 169276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// this software without specific prior written permission. 179276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// 189276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 199276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 209276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 219276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 229276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 239276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 249276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 259276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 269276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 279276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 289276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 299276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 309276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// stackwalker_arm.cc: arm-specific stackwalker. 319276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// 329276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// See stackwalker_arm.h for documentation. 339276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek// 34c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy// Author: Mark Mentovai, Ted Mielczarek, Jim Blandy 359276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 369753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com#include <vector> 379753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com 382cc15ba4327831f917ff55b87e6d5fc3c7750085ted.mielczarek@gmail.com#include "common/scoped_ptr.h" 399276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek#include "google_breakpad/processor/call_stack.h" 409276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek#include "google_breakpad/processor/memory_region.h" 41c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy#include "google_breakpad/processor/source_line_resolver_interface.h" 429276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek#include "google_breakpad/processor/stack_frame_cpu.h" 43c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy#include "processor/cfi_frame_info.h" 449276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek#include "processor/logging.h" 45c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy#include "processor/stackwalker_arm.h" 469276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 479276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczareknamespace google_breakpad { 489276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 499276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 509753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.comStackwalkerARM::StackwalkerARM(const SystemInfo* system_info, 519753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com const MDRawContextARM* context, 520fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org int fp_register, 539753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com MemoryRegion* memory, 549753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com const CodeModules* modules, 559753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameSymbolizer* resolver_helper) 569753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com : Stackwalker(system_info, memory, modules, resolver_helper), 570fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org context_(context), fp_register_(fp_register), 58c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy context_frame_validity_(StackFrameARM::CONTEXT_VALID_ALL) { } 599276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 609276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 619276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarekStackFrame* StackwalkerARM::GetContextFrame() { 62e721e628ec10381c96e38cfc82c1816983097165ted.mielczarek@gmail.com if (!context_) { 63e721e628ec10381c96e38cfc82c1816983097165ted.mielczarek@gmail.com BPLOG(ERROR) << "Can't get context frame without context"; 649276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek return NULL; 659276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek } 669276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 679753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* frame = new StackFrameARM(); 689276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 699276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek // The instruction pointer is stored directly in a register (r15), so pull it 709276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek // straight out of the CPU context structure. 719276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek frame->context = *context_; 72c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context_validity = context_frame_validity_; 738c33b3e9c95a67a9bb06c033d5d4c28d9a55168bted.mielczarek frame->trust = StackFrame::FRAME_TRUST_CONTEXT; 740fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC]; 759276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 769276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek return frame; 779276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek} 789276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 799753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.comStackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( 809753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com const vector<StackFrame*> &frames, 819753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com CFIFrameInfo* cfi_frame_info) { 829753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 83c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 849753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com static const char* register_names[] = { 85c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 86c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", 87c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 88c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy "fps", "cpsr", 89c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy NULL 90c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy }; 91c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 92c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // Populate a dictionary with the valid register values in last_frame. 936162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; 94c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy for (int i = 0; register_names[i]; i++) 95c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) 96c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy callee_registers[register_names[i]] = last_frame->context.iregs[i]; 97c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 98c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // Use the STACK CFI data to recover the caller's register values. 996162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; 100c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, 101c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy &caller_registers)) 102c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy return NULL; 103c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 104c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // Construct a new stack frame given the values the CFI recovered. 105c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy scoped_ptr<StackFrameARM> frame(new StackFrameARM()); 106c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy for (int i = 0; register_names[i]; i++) { 1076162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 108c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy caller_registers.find(register_names[i]); 109c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (entry != caller_registers.end()) { 110c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // We recovered the value of this register; fill the context with the 111c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // value from caller_registers. 112c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context_validity |= StackFrameARM::RegisterValidFlag(i); 113c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context.iregs[i] = entry->second; 114c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } else if (4 <= i && i <= 11 && (last_frame->context_validity & 115c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy StackFrameARM::RegisterValidFlag(i))) { 116c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // If the STACK CFI data doesn't mention some callee-saves register, and 117c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // it is valid in the callee, assume the callee has not yet changed it. 118c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // Registers r4 through r11 are callee-saves, according to the Procedure 119c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // Call Standard for the ARM Architecture, which the Linux ABI follows. 120c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context_validity |= StackFrameARM::RegisterValidFlag(i); 121c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context.iregs[i] = last_frame->context.iregs[i]; 122c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } 123c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } 124c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // If the CFI doesn't recover the PC explicitly, then use .ra. 1259753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { 1266162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 127c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy caller_registers.find(".ra"); 128c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (entry != caller_registers.end()) { 1290fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org if (fp_register_ == -1) { 1300fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; 1310fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; 1320fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org } else { 1330fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org // The CFI updated the link register and not the program counter. 1340fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org // Handle getting the program counter from the link register. 1350fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; 1360fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; 1370fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; 1380fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = 1390fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; 1400fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org } 141c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } 142c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } 143c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // If the CFI doesn't recover the SP explicitly, then use .cfa. 1449753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { 1456162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 146c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy caller_registers.find(".cfa"); 147c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (entry != caller_registers.end()) { 148c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; 149c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; 150c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } 151c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy } 152c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 153c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // If we didn't recover the PC and the SP, then the frame isn't very useful. 154c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy static const int essentials = (StackFrameARM::CONTEXT_VALID_SP 155c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy | StackFrameARM::CONTEXT_VALID_PC); 156c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if ((frame->context_validity & essentials) != essentials) 157c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy return NULL; 158c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 159c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame->trust = StackFrame::FRAME_TRUST_CFI; 160c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek return frame.release(); 161c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek} 162c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 1639753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.comStackFrameARM* StackwalkerARM::GetCallerByStackScan( 1649753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com const vector<StackFrame*> &frames) { 1659753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 1666162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; 1676162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com uint32_t caller_sp, caller_pc; 1680fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 169bc9a28655784a66e8772cdc5b428ef5bb6286d8cted.mielczarek@gmail.com if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, 1707a58af62ecb1e3d76ea0c0d0ad6198e378b4e3f4ivan.penkov@gmail.com frames.size() == 1 /* is_context_frame */)) { 171c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // No plausible return address was found. 172c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek return NULL; 173c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek } 174c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 175c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // ScanForReturnAddress found a reasonable return address. Advance 176c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // %sp to the location above the one where the return address was 177c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // found. 178c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek caller_sp += 4; 179c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 180c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // Create a new stack frame (ownership will be transferred to the caller) 181c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // and fill it in. 1829753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* frame = new StackFrameARM(); 183c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 184c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame->trust = StackFrame::FRAME_TRUST_SCAN; 185c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame->context = last_frame->context; 186c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = caller_pc; 187c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; 188c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | 189c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek StackFrameARM::CONTEXT_VALID_SP; 190c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 191c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek return frame; 192c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek} 193c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 1949753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.comStackFrameARM* StackwalkerARM::GetCallerByFramePointer( 1959753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com const vector<StackFrame*> &frames) { 1969753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 1970fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 1980fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org if (!(last_frame->context_validity & 1990fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org StackFrameARM::RegisterValidFlag(fp_register_))) { 2000fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org return NULL; 2010fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org } 2020fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2036162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com uint32_t last_fp = last_frame->context.iregs[fp_register_]; 2040fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2056162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com uint32_t caller_fp = 0; 2060fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { 2070fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" 2080fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org << std::hex << last_fp; 2090fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org return NULL; 2100fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org } 2110fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2126162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com uint32_t caller_lr = 0; 2130fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_lr)) { 2140fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 4: 0x" 2150fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org << std::hex << (last_fp + 4); 2160fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org return NULL; 2170fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org } 2180fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2196162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com uint32_t caller_sp = last_fp ? last_fp + 8 : 2200fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; 2210fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2220fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org // Create a new stack frame (ownership will be transferred to the caller) 2230fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org // and fill it in. 2249753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* frame = new StackFrameARM(); 2250fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2260fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->trust = StackFrame::FRAME_TRUST_FP; 2270fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context = last_frame->context; 2280fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[fp_register_] = caller_fp; 2290fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; 2300fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = 2310fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; 2320fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = caller_lr; 2330fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | 2340fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org StackFrameARM::CONTEXT_VALID_LR | 2350fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org StackFrameARM::RegisterValidFlag(fp_register_) | 2360fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org StackFrameARM::CONTEXT_VALID_SP; 2370fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org return frame; 2380fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org} 2390fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 24042b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.comStackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, 24142b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.com bool stack_scan_allowed) { 242c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek if (!memory_ || !stack) { 243c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek BPLOG(ERROR) << "Can't get caller frame without memory or stack"; 244c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek return NULL; 245c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek } 246c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 2479753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com const vector<StackFrame*> &frames = *stack->frames(); 2489753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); 249c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek scoped_ptr<StackFrameARM> frame; 250c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 251c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // See if there is DWARF call frame information covering this address. 252281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek scoped_ptr<CFIFrameInfo> cfi_frame_info( 2539753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com frame_symbolizer_->FindCFIFrameInfo(last_frame)); 254c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek if (cfi_frame_info.get()) 255c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); 256c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 257c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // If CFI failed, or there wasn't CFI available, fall back 2580fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org // to frame pointer, if this is configured. 2590fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org if (fp_register_ >= 0 && !frame.get()) 2600fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame.reset(GetCallerByFramePointer(frames)); 2610fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org 2620fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org // If everuthing failed, fall back to stack scanning. 26342b91fbbf30f8a6d900d1fb97e96394dbb363890ted.mielczarek@gmail.com if (stack_scan_allowed && !frame.get()) 264c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek frame.reset(GetCallerByStackScan(frames)); 265c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 266c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek // If nothing worked, tell the caller. 267c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek if (!frame.get()) 268c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek return NULL; 269c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 270c653618a9175d3252cc6d1aa8c3393f9558646e8ted.mielczarek 271c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // An instruction address of zero marks the end of the stack. 272c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (frame->context.iregs[MD_CONTEXT_ARM_REG_PC] == 0) 273c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy return NULL; 274c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 275c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // If the new stack pointer is at a lower address than the old, then 276c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // that's clearly incorrect. Treat this as end-of-stack to enforce 277c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // progress and avoid infinite loops. 278c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy if (frame->context.iregs[MD_CONTEXT_ARM_REG_SP] 279c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy < last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]) 280c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy return NULL; 281c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 282c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // The new frame's context's PC is the return address, which is one 283c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // instruction past the instruction that caused us to arrive at the 284c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // callee. Set new_frame->instruction to one less than the PC. This won't 285c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // reference the beginning of the call instruction, but it's at least 286c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // within it, which is sufficient to get the source line information to 287c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // match up with the line that contains the function call. Callers that 288c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // require the exact return address value may access 289c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy // frame->context.iregs[MD_CONTEXT_ARM_REG_PC]. 2900fd250335b66b12609aaf1b749384b711ecddaa9qsr@chromium.org frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC] - 2; 291c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy 292c609f474a955e1f617802ff1185efaa5ef9659f9jimblandy return frame.release(); 2939276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek} 2949276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 2959276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek 2969276b0d3017ad5ca93c8b593cacf317e1eaa114eted.mielczarek} // namespace google_breakpad 297