blob: 1f697ca57b5e85b5ff6994a5997a4191d1e20ee7 [file] [log] [blame]
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements backtrace for posix.
*/
#include "openthread-posix-config.h"
#include "platform-posix.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common/code_utils.hpp"
#include "common/logging.hpp"
#if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE
#if OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE || defined(__GLIBC__)
#if OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE
#include <log/log.h>
#include <utils/CallStack.h>
#include <utils/Printer.h>
class LogPrinter : public android::Printer
{
public:
virtual void printLine(const char *string) { otLogCritPlat("%s", string); }
};
static void dumpStack(void)
{
LogPrinter printer;
android::CallStack callstack;
callstack.update();
callstack.print(printer);
}
#else // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE
#include <cxxabi.h>
#include <execinfo.h>
static void demangleSymbol(int aIndex, const char *aSymbol)
{
constexpr uint16_t kMaxNameSize = 256;
int status;
char program[kMaxNameSize + 1];
char mangledName[kMaxNameSize + 1];
char *demangledName = nullptr;
char *functionName = nullptr;
unsigned int offset = 0;
unsigned int address = 0;
// Try to demangle a C++ name
if (sscanf(aSymbol, "%256[^(]%*[^_]%256[^)+]%*[^0x]%x%*[^0x]%x", program, mangledName, &offset, &address) == 4)
{
demangledName = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status);
functionName = demangledName;
}
VerifyOrExit(demangledName == nullptr);
// If failed to demangle a C++ name, try to get a regular C symbol
if (sscanf(aSymbol, "%256[^(](%256[^)+]%*[^0x]%x%*[^0x]%x", program, mangledName, &offset, &address) == 4)
{
functionName = mangledName;
}
exit:
if (functionName != nullptr)
{
otLogCritPlat("#%2d: %s %s+0x%x [0x%x]\n", aIndex, program, functionName, offset, address);
}
else
{
otLogCritPlat("#%2d: %s\n", aIndex, aSymbol);
}
if (demangledName != nullptr)
{
free(demangledName);
}
}
static void dumpStack(void)
{
constexpr uint8_t kMaxDepth = 50;
void *stack[kMaxDepth];
char **symbols;
int depth;
depth = backtrace(stack, kMaxDepth);
symbols = backtrace_symbols(stack, depth);
VerifyOrExit(symbols != nullptr);
for (int i = 0; i < depth; i++)
{
demangleSymbol(i, symbols[i]);
}
free(symbols);
exit:
return;
}
#endif // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE
static constexpr uint8_t kNumSignals = 6;
static constexpr int kSignals[kNumSignals] = {SIGABRT, SIGILL, SIGSEGV, SIGBUS, SIGTRAP, SIGFPE};
static struct sigaction sSigActions[kNumSignals];
static void resetSignalActions(void)
{
for (uint8_t i = 0; i < kNumSignals; i++)
{
sigaction(kSignals[i], &sSigActions[i], (struct sigaction *)nullptr);
}
}
static void signalCritical(int sig, siginfo_t *info, void *ucontext)
{
OT_UNUSED_VARIABLE(ucontext);
OT_UNUSED_VARIABLE(info);
otLogCritPlat("------------------ BEGINNING OF CRASH -------------");
otLogCritPlat("*** FATAL ERROR: Caught signal: %d (%s)", sig, strsignal(sig));
dumpStack();
otLogCritPlat("------------------ END OF CRASH ------------------");
resetSignalActions();
raise(sig);
}
void platformBacktraceInit(void)
{
struct sigaction sigact;
sigact.sa_sigaction = &signalCritical;
sigact.sa_flags = SA_RESTART | SA_SIGINFO | SA_NOCLDWAIT;
for (uint8_t i = 0; i < kNumSignals; i++)
{
sigaction(kSignals[i], &sigact, &sSigActions[i]);
}
}
#else // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE || defined(__GLIBC__)
void platformBacktraceInit(void) {}
#endif // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE || defined(__GLIBC__)
#endif // OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE