xref: /aosp_15_r20/external/angle/src/common/backtrace_utils_android.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // backtrace_utils_android.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //   Implements the functions related to the backtrace info class for Android platforms.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "backtrace_utils.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include <dlfcn.h>
13*8975f5c5SAndroid Build Coastguard Worker #include <unwind.h>
14*8975f5c5SAndroid Build Coastguard Worker 
15*8975f5c5SAndroid Build Coastguard Worker namespace
16*8975f5c5SAndroid Build Coastguard Worker {
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker // Size limit for the backtrace obtained from the device.
19*8975f5c5SAndroid Build Coastguard Worker constexpr uint32_t kMaxBacktraceSize = 16;
20*8975f5c5SAndroid Build Coastguard Worker 
21*8975f5c5SAndroid Build Coastguard Worker struct UnwindCallbackFnState
22*8975f5c5SAndroid Build Coastguard Worker {
UnwindCallbackFnState__anon12e382ed0111::UnwindCallbackFnState23*8975f5c5SAndroid Build Coastguard Worker     UnwindCallbackFnState() : current(nullptr), end(nullptr) {}
UnwindCallbackFnState__anon12e382ed0111::UnwindCallbackFnState24*8975f5c5SAndroid Build Coastguard Worker     UnwindCallbackFnState(void **current, void **end) : current(current), end(end) {}
25*8975f5c5SAndroid Build Coastguard Worker     void **current;
26*8975f5c5SAndroid Build Coastguard Worker     void **end;
27*8975f5c5SAndroid Build Coastguard Worker };
28*8975f5c5SAndroid Build Coastguard Worker 
29*8975f5c5SAndroid Build Coastguard Worker // Unwind callback function, which is called until the end of stack is reached.
unwindCallbackFn(struct _Unwind_Context * context,void * args)30*8975f5c5SAndroid Build Coastguard Worker _Unwind_Reason_Code unwindCallbackFn(struct _Unwind_Context *context, void *args)
31*8975f5c5SAndroid Build Coastguard Worker {
32*8975f5c5SAndroid Build Coastguard Worker     auto *state = reinterpret_cast<UnwindCallbackFnState *>(args);
33*8975f5c5SAndroid Build Coastguard Worker 
34*8975f5c5SAndroid Build Coastguard Worker     // Get the instruction pointer.
35*8975f5c5SAndroid Build Coastguard Worker     uintptr_t ip = _Unwind_GetIP(context);
36*8975f5c5SAndroid Build Coastguard Worker     if (ip == 0)
37*8975f5c5SAndroid Build Coastguard Worker     {
38*8975f5c5SAndroid Build Coastguard Worker         return _URC_NO_REASON;
39*8975f5c5SAndroid Build Coastguard Worker     }
40*8975f5c5SAndroid Build Coastguard Worker 
41*8975f5c5SAndroid Build Coastguard Worker     // The buffer is populated at the current location with the instruction pointer address. The
42*8975f5c5SAndroid Build Coastguard Worker     // current value is incremented to prepare for the next entry in the stack trace. Once "current"
43*8975f5c5SAndroid Build Coastguard Worker     // gets to "end", the callback should stop.
44*8975f5c5SAndroid Build Coastguard Worker     if (state->current == state->end)
45*8975f5c5SAndroid Build Coastguard Worker     {
46*8975f5c5SAndroid Build Coastguard Worker         return _URC_END_OF_STACK;
47*8975f5c5SAndroid Build Coastguard Worker     }
48*8975f5c5SAndroid Build Coastguard Worker 
49*8975f5c5SAndroid Build Coastguard Worker     *state->current++ = reinterpret_cast<void *>(ip);
50*8975f5c5SAndroid Build Coastguard Worker     return _URC_NO_REASON;
51*8975f5c5SAndroid Build Coastguard Worker }
52*8975f5c5SAndroid Build Coastguard Worker }  // namespace
53*8975f5c5SAndroid Build Coastguard Worker 
54*8975f5c5SAndroid Build Coastguard Worker namespace angle
55*8975f5c5SAndroid Build Coastguard Worker {
56*8975f5c5SAndroid Build Coastguard Worker 
populateBacktraceInfo(void ** stackAddressBuffer,size_t stackAddressCount)57*8975f5c5SAndroid Build Coastguard Worker void BacktraceInfo::populateBacktraceInfo(void **stackAddressBuffer, size_t stackAddressCount)
58*8975f5c5SAndroid Build Coastguard Worker {
59*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mStackAddresses.empty() && mStackSymbols.empty());
60*8975f5c5SAndroid Build Coastguard Worker 
61*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < stackAddressCount; i++)
62*8975f5c5SAndroid Build Coastguard Worker     {
63*8975f5c5SAndroid Build Coastguard Worker         void *stackAddr = stackAddressBuffer[i];
64*8975f5c5SAndroid Build Coastguard Worker         mStackAddresses.push_back(stackAddr);
65*8975f5c5SAndroid Build Coastguard Worker 
66*8975f5c5SAndroid Build Coastguard Worker         // Get the symbol if possible. dladdr() returns 0 on failure.
67*8975f5c5SAndroid Build Coastguard Worker         Dl_info dlInfo;
68*8975f5c5SAndroid Build Coastguard Worker         if (dladdr(stackAddr, &dlInfo) != 0 && dlInfo.dli_sname)
69*8975f5c5SAndroid Build Coastguard Worker         {
70*8975f5c5SAndroid Build Coastguard Worker             mStackSymbols.emplace_back(dlInfo.dli_sname);
71*8975f5c5SAndroid Build Coastguard Worker         }
72*8975f5c5SAndroid Build Coastguard Worker         else
73*8975f5c5SAndroid Build Coastguard Worker         {
74*8975f5c5SAndroid Build Coastguard Worker             mStackSymbols.emplace_back("unknown_symbol");
75*8975f5c5SAndroid Build Coastguard Worker         }
76*8975f5c5SAndroid Build Coastguard Worker     }
77*8975f5c5SAndroid Build Coastguard Worker 
78*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mStackAddresses.size() == mStackSymbols.size());
79*8975f5c5SAndroid Build Coastguard Worker }
80*8975f5c5SAndroid Build Coastguard Worker 
getBacktraceInfo()81*8975f5c5SAndroid Build Coastguard Worker BacktraceInfo getBacktraceInfo()
82*8975f5c5SAndroid Build Coastguard Worker {
83*8975f5c5SAndroid Build Coastguard Worker     void *stackAddrBuffer[kMaxBacktraceSize];
84*8975f5c5SAndroid Build Coastguard Worker 
85*8975f5c5SAndroid Build Coastguard Worker     UnwindCallbackFnState unwindFnState(stackAddrBuffer, stackAddrBuffer + kMaxBacktraceSize);
86*8975f5c5SAndroid Build Coastguard Worker     _Unwind_Backtrace(unwindCallbackFn, &unwindFnState);
87*8975f5c5SAndroid Build Coastguard Worker 
88*8975f5c5SAndroid Build Coastguard Worker     // The number of the collected IPs is shown by how far "current" has moved.
89*8975f5c5SAndroid Build Coastguard Worker     auto stackAddressCount = static_cast<size_t>(unwindFnState.current - stackAddrBuffer);
90*8975f5c5SAndroid Build Coastguard Worker 
91*8975f5c5SAndroid Build Coastguard Worker     BacktraceInfo backtraceInfo;
92*8975f5c5SAndroid Build Coastguard Worker     backtraceInfo.populateBacktraceInfo(stackAddrBuffer, stackAddressCount);
93*8975f5c5SAndroid Build Coastguard Worker     return backtraceInfo;
94*8975f5c5SAndroid Build Coastguard Worker }
95*8975f5c5SAndroid Build Coastguard Worker 
96*8975f5c5SAndroid Build Coastguard Worker // The following function has been defined in each platform separately.
97*8975f5c5SAndroid Build Coastguard Worker // - void printBacktraceInfo(BacktraceInfo backtraceInfo);
98*8975f5c5SAndroid Build Coastguard Worker 
99*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
100