1// Copyright (c) 2011, Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30// --- 31// Author: Doug Kwan 32// This is inspired by Craig Silverstein's PowerPC stacktrace code. 33// 34 35#ifndef BASE_STACKTRACE_ARM_INL_H_ 36#define BASE_STACKTRACE_ARM_INL_H_ 37// Note: this file is included into stacktrace.cc more than once. 38// Anything that should only be defined once should be here: 39 40#include <stdint.h> // for uintptr_t 41#include "base/basictypes.h" // for NULL 42#include <gperftools/stacktrace.h> 43 44// WARNING: 45// This only works if all your code is in either ARM or THUMB mode. With 46// interworking, the frame pointer of the caller can either be in r11 (ARM 47// mode) or r7 (THUMB mode). A callee only saves the frame pointer of its 48// mode in a fixed location on its stack frame. If the caller is a different 49// mode, there is no easy way to find the frame pointer. It can either be 50// still in the designated register or saved on stack along with other callee 51// saved registers. 52 53// Given a pointer to a stack frame, locate and return the calling 54// stackframe, or return NULL if no stackframe can be found. Perform sanity 55// checks (the strictness of which is controlled by the boolean parameter 56// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. 57template<bool STRICT_UNWINDING> 58static void **NextStackFrame(void **old_sp) { 59 void **new_sp = (void**) old_sp[-1]; 60 61 // Check that the transition from frame pointer old_sp to frame 62 // pointer new_sp isn't clearly bogus 63 if (STRICT_UNWINDING) { 64 // With the stack growing downwards, older stack frame must be 65 // at a greater address that the current one. 66 if (new_sp <= old_sp) return NULL; 67 // Assume stack frames larger than 100,000 bytes are bogus. 68 if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL; 69 } else { 70 // In the non-strict mode, allow discontiguous stack frames. 71 // (alternate-signal-stacks for example). 72 if (new_sp == old_sp) return NULL; 73 // And allow frames upto about 1MB. 74 if ((new_sp > old_sp) 75 && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL; 76 } 77 if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL; 78 return new_sp; 79} 80 81// This ensures that GetStackTrace stes up the Link Register properly. 82#ifdef __GNUC__ 83void StacktraceArmDummyFunction() __attribute__((noinline)); 84void StacktraceArmDummyFunction() { __asm__ volatile(""); } 85#else 86# error StacktraceArmDummyFunction() needs to be ported to this platform. 87#endif 88#endif // BASE_STACKTRACE_ARM_INL_H_ 89 90// Note: this part of the file is included several times. 91// Do not put globals below. 92 93// The following 4 functions are generated from the code below: 94// GetStack{Trace,Frames}() 95// GetStack{Trace,Frames}WithContext() 96// 97// These functions take the following args: 98// void** result: the stack-trace, as an array 99// int* sizes: the size of each stack frame, as an array 100// (GetStackFrames* only) 101// int max_depth: the size of the result (and sizes) array(s) 102// int skip_count: how many stack pointers to skip before storing in result 103// void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) 104int GET_STACK_TRACE_OR_FRAMES { 105#ifdef __GNUC__ 106 void **sp = reinterpret_cast<void**>(__builtin_frame_address(0)); 107#else 108# error reading stack point not yet supported on this platform. 109#endif 110 111 // On ARM, the return address is stored in the link register (r14). 112 // This is not saved on the stack frame of a leaf function. To 113 // simplify code that reads return addresses, we call a dummy 114 // function so that the return address of this function is also 115 // stored in the stack frame. This works at least for gcc. 116 StacktraceArmDummyFunction(); 117 118 int n = 0; 119 while (sp && n < max_depth) { 120 // The GetStackFrames routine is called when we are in some 121 // informational context (the failure signal handler for example). 122 // Use the non-strict unwinding rules to produce a stack trace 123 // that is as complete as possible (even if it contains a few bogus 124 // entries in some rare cases). 125 void **next_sp = NextStackFrame<IS_STACK_FRAMES == 0>(sp); 126 127 if (skip_count > 0) { 128 skip_count--; 129 } else { 130 result[n] = *sp; 131 132#if IS_STACK_FRAMES 133 if (next_sp > sp) { 134 sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; 135 } else { 136 // A frame-size of 0 is used to indicate unknown frame size. 137 sizes[n] = 0; 138 } 139#endif 140 n++; 141 } 142 sp = next_sp; 143 } 144 return n; 145} 146