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. 57 template<bool STRICT_UNWINDING> 58 static 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__ 83 void StacktraceArmDummyFunction() __attribute__((noinline)); 84 void 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) 104 int 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