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