xref: /aosp_15_r20/external/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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