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