1*9356374aSAndroid Build Coastguard Worker// Copyright 2017 The Abseil Authors. 2*9356374aSAndroid Build Coastguard Worker// 3*9356374aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*9356374aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*9356374aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*9356374aSAndroid Build Coastguard Worker// 7*9356374aSAndroid Build Coastguard Worker// https://www.apache.org/licenses/LICENSE-2.0 8*9356374aSAndroid Build Coastguard Worker// 9*9356374aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*9356374aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*9356374aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9356374aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*9356374aSAndroid Build Coastguard Worker// limitations under the License. 14*9356374aSAndroid Build Coastguard Worker// 15*9356374aSAndroid Build Coastguard Worker// This is inspired by Craig Silverstein's PowerPC stacktrace code. 16*9356374aSAndroid Build Coastguard Worker 17*9356374aSAndroid Build Coastguard Worker#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ 18*9356374aSAndroid Build Coastguard Worker#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ 19*9356374aSAndroid Build Coastguard Worker 20*9356374aSAndroid Build Coastguard Worker#include <cstdint> 21*9356374aSAndroid Build Coastguard Worker 22*9356374aSAndroid Build Coastguard Worker#include "absl/debugging/stacktrace.h" 23*9356374aSAndroid Build Coastguard Worker 24*9356374aSAndroid Build Coastguard Worker// WARNING: 25*9356374aSAndroid Build Coastguard Worker// This only works if all your code is in either ARM or THUMB mode. With 26*9356374aSAndroid Build Coastguard Worker// interworking, the frame pointer of the caller can either be in r11 (ARM 27*9356374aSAndroid Build Coastguard Worker// mode) or r7 (THUMB mode). A callee only saves the frame pointer of its 28*9356374aSAndroid Build Coastguard Worker// mode in a fixed location on its stack frame. If the caller is a different 29*9356374aSAndroid Build Coastguard Worker// mode, there is no easy way to find the frame pointer. It can either be 30*9356374aSAndroid Build Coastguard Worker// still in the designated register or saved on stack along with other callee 31*9356374aSAndroid Build Coastguard Worker// saved registers. 32*9356374aSAndroid Build Coastguard Worker 33*9356374aSAndroid Build Coastguard Worker// Given a pointer to a stack frame, locate and return the calling 34*9356374aSAndroid Build Coastguard Worker// stackframe, or return nullptr if no stackframe can be found. Perform sanity 35*9356374aSAndroid Build Coastguard Worker// checks (the strictness of which is controlled by the boolean parameter 36*9356374aSAndroid Build Coastguard Worker// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. 37*9356374aSAndroid Build Coastguard Workertemplate<bool STRICT_UNWINDING> 38*9356374aSAndroid Build Coastguard Workerstatic void **NextStackFrame(void **old_sp) { 39*9356374aSAndroid Build Coastguard Worker void **new_sp = (void**) old_sp[-1]; 40*9356374aSAndroid Build Coastguard Worker 41*9356374aSAndroid Build Coastguard Worker // Check that the transition from frame pointer old_sp to frame 42*9356374aSAndroid Build Coastguard Worker // pointer new_sp isn't clearly bogus 43*9356374aSAndroid Build Coastguard Worker if (STRICT_UNWINDING) { 44*9356374aSAndroid Build Coastguard Worker // With the stack growing downwards, older stack frame must be 45*9356374aSAndroid Build Coastguard Worker // at a greater address that the current one. 46*9356374aSAndroid Build Coastguard Worker if (new_sp <= old_sp) return nullptr; 47*9356374aSAndroid Build Coastguard Worker // Assume stack frames larger than 100,000 bytes are bogus. 48*9356374aSAndroid Build Coastguard Worker if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr; 49*9356374aSAndroid Build Coastguard Worker } else { 50*9356374aSAndroid Build Coastguard Worker // In the non-strict mode, allow discontiguous stack frames. 51*9356374aSAndroid Build Coastguard Worker // (alternate-signal-stacks for example). 52*9356374aSAndroid Build Coastguard Worker if (new_sp == old_sp) return nullptr; 53*9356374aSAndroid Build Coastguard Worker // And allow frames upto about 1MB. 54*9356374aSAndroid Build Coastguard Worker if ((new_sp > old_sp) 55*9356374aSAndroid Build Coastguard Worker && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr; 56*9356374aSAndroid Build Coastguard Worker } 57*9356374aSAndroid Build Coastguard Worker if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr; 58*9356374aSAndroid Build Coastguard Worker return new_sp; 59*9356374aSAndroid Build Coastguard Worker} 60*9356374aSAndroid Build Coastguard Worker 61*9356374aSAndroid Build Coastguard Worker// This ensures that absl::GetStackTrace sets up the Link Register properly. 62*9356374aSAndroid Build Coastguard Worker#ifdef __GNUC__ 63*9356374aSAndroid Build Coastguard Workervoid StacktraceArmDummyFunction() __attribute__((noinline)); 64*9356374aSAndroid Build Coastguard Workervoid StacktraceArmDummyFunction() { __asm__ volatile(""); } 65*9356374aSAndroid Build Coastguard Worker#else 66*9356374aSAndroid Build Coastguard Worker# error StacktraceArmDummyFunction() needs to be ported to this platform. 67*9356374aSAndroid Build Coastguard Worker#endif 68*9356374aSAndroid Build Coastguard Worker 69*9356374aSAndroid Build Coastguard Workertemplate <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> 70*9356374aSAndroid Build Coastguard Workerstatic int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, 71*9356374aSAndroid Build Coastguard Worker const void * /* ucp */, int *min_dropped_frames) { 72*9356374aSAndroid Build Coastguard Worker#ifdef __GNUC__ 73*9356374aSAndroid Build Coastguard Worker void **sp = reinterpret_cast<void**>(__builtin_frame_address(0)); 74*9356374aSAndroid Build Coastguard Worker#else 75*9356374aSAndroid Build Coastguard Worker# error reading stack point not yet supported on this platform. 76*9356374aSAndroid Build Coastguard Worker#endif 77*9356374aSAndroid Build Coastguard Worker 78*9356374aSAndroid Build Coastguard Worker // On ARM, the return address is stored in the link register (r14). 79*9356374aSAndroid Build Coastguard Worker // This is not saved on the stack frame of a leaf function. To 80*9356374aSAndroid Build Coastguard Worker // simplify code that reads return addresses, we call a dummy 81*9356374aSAndroid Build Coastguard Worker // function so that the return address of this function is also 82*9356374aSAndroid Build Coastguard Worker // stored in the stack frame. This works at least for gcc. 83*9356374aSAndroid Build Coastguard Worker StacktraceArmDummyFunction(); 84*9356374aSAndroid Build Coastguard Worker 85*9356374aSAndroid Build Coastguard Worker int n = 0; 86*9356374aSAndroid Build Coastguard Worker while (sp && n < max_depth) { 87*9356374aSAndroid Build Coastguard Worker // The absl::GetStackFrames routine is called when we are in some 88*9356374aSAndroid Build Coastguard Worker // informational context (the failure signal handler for example). 89*9356374aSAndroid Build Coastguard Worker // Use the non-strict unwinding rules to produce a stack trace 90*9356374aSAndroid Build Coastguard Worker // that is as complete as possible (even if it contains a few bogus 91*9356374aSAndroid Build Coastguard Worker // entries in some rare cases). 92*9356374aSAndroid Build Coastguard Worker void **next_sp = NextStackFrame<!IS_STACK_FRAMES>(sp); 93*9356374aSAndroid Build Coastguard Worker 94*9356374aSAndroid Build Coastguard Worker if (skip_count > 0) { 95*9356374aSAndroid Build Coastguard Worker skip_count--; 96*9356374aSAndroid Build Coastguard Worker } else { 97*9356374aSAndroid Build Coastguard Worker result[n] = *sp; 98*9356374aSAndroid Build Coastguard Worker 99*9356374aSAndroid Build Coastguard Worker if (IS_STACK_FRAMES) { 100*9356374aSAndroid Build Coastguard Worker if (next_sp > sp) { 101*9356374aSAndroid Build Coastguard Worker sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; 102*9356374aSAndroid Build Coastguard Worker } else { 103*9356374aSAndroid Build Coastguard Worker // A frame-size of 0 is used to indicate unknown frame size. 104*9356374aSAndroid Build Coastguard Worker sizes[n] = 0; 105*9356374aSAndroid Build Coastguard Worker } 106*9356374aSAndroid Build Coastguard Worker } 107*9356374aSAndroid Build Coastguard Worker n++; 108*9356374aSAndroid Build Coastguard Worker } 109*9356374aSAndroid Build Coastguard Worker sp = next_sp; 110*9356374aSAndroid Build Coastguard Worker } 111*9356374aSAndroid Build Coastguard Worker if (min_dropped_frames != nullptr) { 112*9356374aSAndroid Build Coastguard Worker // Implementation detail: we clamp the max of frames we are willing to 113*9356374aSAndroid Build Coastguard Worker // count, so as not to spend too much time in the loop below. 114*9356374aSAndroid Build Coastguard Worker const int kMaxUnwind = 200; 115*9356374aSAndroid Build Coastguard Worker int num_dropped_frames = 0; 116*9356374aSAndroid Build Coastguard Worker for (int j = 0; sp != nullptr && j < kMaxUnwind; j++) { 117*9356374aSAndroid Build Coastguard Worker if (skip_count > 0) { 118*9356374aSAndroid Build Coastguard Worker skip_count--; 119*9356374aSAndroid Build Coastguard Worker } else { 120*9356374aSAndroid Build Coastguard Worker num_dropped_frames++; 121*9356374aSAndroid Build Coastguard Worker } 122*9356374aSAndroid Build Coastguard Worker sp = NextStackFrame<!IS_STACK_FRAMES>(sp); 123*9356374aSAndroid Build Coastguard Worker } 124*9356374aSAndroid Build Coastguard Worker *min_dropped_frames = num_dropped_frames; 125*9356374aSAndroid Build Coastguard Worker } 126*9356374aSAndroid Build Coastguard Worker return n; 127*9356374aSAndroid Build Coastguard Worker} 128*9356374aSAndroid Build Coastguard Worker 129*9356374aSAndroid Build Coastguard Workernamespace absl { 130*9356374aSAndroid Build Coastguard WorkerABSL_NAMESPACE_BEGIN 131*9356374aSAndroid Build Coastguard Workernamespace debugging_internal { 132*9356374aSAndroid Build Coastguard Workerbool StackTraceWorksForTest() { 133*9356374aSAndroid Build Coastguard Worker return false; 134*9356374aSAndroid Build Coastguard Worker} 135*9356374aSAndroid Build Coastguard Worker} // namespace debugging_internal 136*9356374aSAndroid Build Coastguard WorkerABSL_NAMESPACE_END 137*9356374aSAndroid Build Coastguard Worker} // namespace absl 138*9356374aSAndroid Build Coastguard Worker 139*9356374aSAndroid Build Coastguard Worker#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ 140