15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Doug Kwan 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is inspired by Craig Silverstein's PowerPC stacktrace code. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_STACKTRACE_ARM_INL_H_ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_STACKTRACE_ARM_INL_H_ 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: this file is included into stacktrace.cc more than once. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Anything that should only be defined once should be here: 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h> // for uintptr_t 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" // for NULL 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/stacktrace.h> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WARNING: 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This only works if all your code is in either ARM or THUMB mode. With 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// interworking, the frame pointer of the caller can either be in r11 (ARM 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mode) or r7 (THUMB mode). A callee only saves the frame pointer of its 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mode in a fixed location on its stack frame. If the caller is a different 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mode, there is no easy way to find the frame pointer. It can either be 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// still in the designated register or saved on stack along with other callee 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// saved registers. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Given a pointer to a stack frame, locate and return the calling 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stackframe, or return NULL if no stackframe can be found. Perform sanity 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// checks (the strictness of which is controlled by the boolean parameter 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<bool STRICT_UNWINDING> 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void **NextStackFrame(void **old_sp) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void **new_sp = (void**) old_sp[-1]; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check that the transition from frame pointer old_sp to frame 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pointer new_sp isn't clearly bogus 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (STRICT_UNWINDING) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // With the stack growing downwards, older stack frame must be 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // at a greater address that the current one. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_sp <= old_sp) return NULL; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assume stack frames larger than 100,000 bytes are bogus. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In the non-strict mode, allow discontiguous stack frames. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (alternate-signal-stacks for example). 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_sp == old_sp) return NULL; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // And allow frames upto about 1MB. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((new_sp > old_sp) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new_sp; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This ensures that GetStackTrace stes up the Link Register properly. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __GNUC__ 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StacktraceArmDummyFunction() __attribute__((noinline)); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StacktraceArmDummyFunction() { __asm__ volatile(""); } 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# error StacktraceArmDummyFunction() needs to be ported to this platform. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // BASE_STACKTRACE_ARM_INL_H_ 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: this part of the file is included several times. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Do not put globals below. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following 4 functions are generated from the code below: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetStack{Trace,Frames}() 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetStack{Trace,Frames}WithContext() 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These functions take the following args: 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// void** result: the stack-trace, as an array 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// int* sizes: the size of each stack frame, as an array 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (GetStackFrames* only) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// int max_depth: the size of the result (and sizes) array(s) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// int skip_count: how many stack pointers to skip before storing in result 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GET_STACK_TRACE_OR_FRAMES { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __GNUC__ 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void **sp = reinterpret_cast<void**>(__builtin_frame_address(0)); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# error reading stack point not yet supported on this platform. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On ARM, the return address is stored in the link register (r14). 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is not saved on the stack frame of a leaf function. To 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // simplify code that reads return addresses, we call a dummy 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function so that the return address of this function is also 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stored in the stack frame. This works at least for gcc. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StacktraceArmDummyFunction(); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n = 0; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (sp && n < max_depth) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The GetStackFrames routine is called when we are in some 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // informational context (the failure signal handler for example). 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use the non-strict unwinding rules to produce a stack trace 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that is as complete as possible (even if it contains a few bogus 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entries in some rare cases). 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void **next_sp = NextStackFrame<IS_STACK_FRAMES == 0>(sp); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (skip_count > 0) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skip_count--; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result[n] = *sp; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if IS_STACK_FRAMES 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_sp > sp) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A frame-size of 0 is used to indicate unknown frame size. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizes[n] = 0; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n++; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sp = next_sp; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return n; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 146