1 /*
2 * Copyright (c) 2022, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements backtrace for posix.
32 */
33
34 #include "openthread-posix-config.h"
35 #include "platform-posix.h"
36
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "common/code_utils.hpp"
44 #include "common/logging.hpp"
45
46 #if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE
47 #if OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE || defined(__GLIBC__)
48 #if OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE
49 #include <log/log.h>
50 #include <utils/CallStack.h>
51 #include <utils/Printer.h>
52
53 class LogPrinter : public android::Printer
54 {
55 public:
printLine(const char * string)56 virtual void printLine(const char *string) { otLogCritPlat("%s", string); }
57 };
58
dumpStack(void)59 static void dumpStack(void)
60 {
61 LogPrinter printer;
62 android::CallStack callstack;
63
64 callstack.update();
65 callstack.print(printer);
66 }
67 #else // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE
68 #include <cxxabi.h>
69 #include <execinfo.h>
70
demangleSymbol(int aIndex,const char * aSymbol)71 static void demangleSymbol(int aIndex, const char *aSymbol)
72 {
73 constexpr uint16_t kMaxNameSize = 256;
74 int status;
75 char program[kMaxNameSize + 1];
76 char mangledName[kMaxNameSize + 1];
77 char *demangledName = nullptr;
78 char *functionName = nullptr;
79 unsigned int offset = 0;
80 unsigned int address = 0;
81
82 // Try to demangle a C++ name
83 if (sscanf(aSymbol, "%256[^(]%*[^_]%256[^)+]%*[^0x]%x%*[^0x]%x", program, mangledName, &offset, &address) == 4)
84 {
85 demangledName = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status);
86 functionName = demangledName;
87 }
88
89 VerifyOrExit(demangledName == nullptr);
90
91 // If failed to demangle a C++ name, try to get a regular C symbol
92 if (sscanf(aSymbol, "%256[^(](%256[^)+]%*[^0x]%x%*[^0x]%x", program, mangledName, &offset, &address) == 4)
93 {
94 functionName = mangledName;
95 }
96
97 exit:
98 if (functionName != nullptr)
99 {
100 otLogCritPlat("#%2d: %s %s+0x%x [0x%x]\n", aIndex, program, functionName, offset, address);
101 }
102 else
103 {
104 otLogCritPlat("#%2d: %s\n", aIndex, aSymbol);
105 }
106
107 if (demangledName != nullptr)
108 {
109 free(demangledName);
110 }
111 }
112
dumpStack(void)113 static void dumpStack(void)
114 {
115 constexpr uint8_t kMaxDepth = 50;
116 void *stack[kMaxDepth];
117 char **symbols;
118 int depth;
119
120 depth = backtrace(stack, kMaxDepth);
121 symbols = backtrace_symbols(stack, depth);
122 VerifyOrExit(symbols != nullptr);
123
124 for (int i = 0; i < depth; i++)
125 {
126 demangleSymbol(i, symbols[i]);
127 }
128
129 free(symbols);
130
131 exit:
132 return;
133 }
134 #endif // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE
135 static constexpr uint8_t kNumSignals = 6;
136 static constexpr int kSignals[kNumSignals] = {SIGABRT, SIGILL, SIGSEGV, SIGBUS, SIGTRAP, SIGFPE};
137 static struct sigaction sSigActions[kNumSignals];
138
resetSignalActions(void)139 static void resetSignalActions(void)
140 {
141 for (uint8_t i = 0; i < kNumSignals; i++)
142 {
143 sigaction(kSignals[i], &sSigActions[i], (struct sigaction *)nullptr);
144 }
145 }
146
signalCritical(int sig,siginfo_t * info,void * ucontext)147 static void signalCritical(int sig, siginfo_t *info, void *ucontext)
148 {
149 OT_UNUSED_VARIABLE(ucontext);
150 OT_UNUSED_VARIABLE(info);
151
152 otLogCritPlat("------------------ BEGINNING OF CRASH -------------");
153 otLogCritPlat("*** FATAL ERROR: Caught signal: %d (%s)", sig, strsignal(sig));
154
155 dumpStack();
156
157 otLogCritPlat("------------------ END OF CRASH ------------------");
158
159 resetSignalActions();
160 raise(sig);
161 }
162
platformBacktraceInit(void)163 void platformBacktraceInit(void)
164 {
165 struct sigaction sigact;
166
167 sigact.sa_sigaction = &signalCritical;
168 sigact.sa_flags = SA_RESTART | SA_SIGINFO | SA_NOCLDWAIT;
169
170 for (uint8_t i = 0; i < kNumSignals; i++)
171 {
172 sigaction(kSignals[i], &sigact, &sSigActions[i]);
173 }
174 }
175 #else // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE || defined(__GLIBC__)
platformBacktraceInit(void)176 void platformBacktraceInit(void) {}
177 #endif // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE || defined(__GLIBC__)
178 #endif // OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE
179