Files
2026-08-24 10:03:24 +08:00

224 lines
6.5 KiB
C++

/*
* Copyright (c) 2020 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*/
#define LOG_TAG "AmlMpSignalHandler"
#include "AmlMpSignalHandler.h"
#include "AmlMpLog.h"
#include <string.h>
#include <unistd.h>
#include <execinfo.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <cxxabi.h>
static const char* mName = LOG_TAG;
namespace aml_mp {
int AmlMpSignalHandler::installSignalHandlers()
{
int ret = 0;
struct sigaction act, old;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_flags |= SA_SIGINFO | SA_ONSTACK;
act.sa_sigaction = unexpectedSignalHandler;
ret = sigaction(SIGABRT, &act, &old);
if (ret == 0) instance().mOldSignalHandlers[SIGABRT] = old.sa_handler;
ret += sigaction(SIGBUS, &act, &old);
if (ret == 0) instance().mOldSignalHandlers[SIGBUS] = old.sa_handler;
ret += sigaction(SIGFPE, &act, &old);
if (ret == 0) instance().mOldSignalHandlers[SIGFPE] = old.sa_handler;
ret += sigaction(SIGILL, &act, &old);
if (ret == 0) instance().mOldSignalHandlers[SIGILL] = old.sa_handler;
ret += sigaction(SIGSEGV, &act, &old);
if (ret == 0) instance().mOldSignalHandlers[SIGSEGV] = old.sa_handler;
ret += sigaction(SIGTRAP, &act, &old);
if (ret == 0) instance().mOldSignalHandlers[SIGTRAP] = old.sa_handler;
return 0;
}
void AmlMpSignalHandler::unexpectedSignalHandler(int signal_number, siginfo_t *info, void* )
{
static bool handlingUnexpectedSignal = false;
if (handlingUnexpectedSignal) {
MLOGE("HandleUnexpectedSignal reentered\n");
_exit(1);
}
handlingUnexpectedSignal = true;
bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
signal_number == SIGFPE || signal_number == SIGSEGV);
std::stringstream ss;
ss << "\n *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
<< " Fatal signal " << signal_number << " (" << getSignalName(signal_number) << "), code "
<< info->si_code << " (" << getSignalCodeName(signal_number, info->si_code) << ")";
if (has_address) {
ss << ", fault addr " << std::hex << info->si_addr << "\n";
}
instance().dumpstack(ss);
MLOGE("%s", ss.str().c_str());
fprintf(stderr, "%s\n", ss.str().c_str());
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = instance().mOldSignalHandlers[signal_number];
sigaction(signal_number, &action, NULL);
// ...and re-raise so we die with the appropriate status.
kill(getpid(), signal_number);
}
const char* AmlMpSignalHandler::getSignalName(int signal_number)
{
switch (signal_number) {
case SIGABRT: return "SIGABRT";
case SIGBUS: return "SIGBUS";
case SIGFPE: return "SIGFPE";
case SIGILL: return "SIGILL";
case SIGPIPE: return "SIGPIPE";
case SIGSEGV: return "SIGSEGV";
#if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT";
#endif
case SIGTRAP: return "SIGTRAP";
}
return "??";
}
const char* AmlMpSignalHandler::getSignalCodeName(int signal_number, int signal_code)
{
// Try the signal-specific codes...
switch (signal_number) {
case SIGILL:
switch (signal_code) {
case ILL_ILLOPC: return "ILL_ILLOPC";
case ILL_ILLOPN: return "ILL_ILLOPN";
case ILL_ILLADR: return "ILL_ILLADR";
case ILL_ILLTRP: return "ILL_ILLTRP";
case ILL_PRVOPC: return "ILL_PRVOPC";
case ILL_PRVREG: return "ILL_PRVREG";
case ILL_COPROC: return "ILL_COPROC";
case ILL_BADSTK: return "ILL_BADSTK";
}
break;
case SIGBUS:
switch (signal_code) {
case BUS_ADRALN: return "BUS_ADRALN";
case BUS_ADRERR: return "BUS_ADRERR";
case BUS_OBJERR: return "BUS_OBJERR";
}
break;
case SIGFPE:
switch (signal_code) {
case FPE_INTDIV: return "FPE_INTDIV";
case FPE_INTOVF: return "FPE_INTOVF";
case FPE_FLTDIV: return "FPE_FLTDIV";
case FPE_FLTOVF: return "FPE_FLTOVF";
case FPE_FLTUND: return "FPE_FLTUND";
case FPE_FLTRES: return "FPE_FLTRES";
case FPE_FLTINV: return "FPE_FLTINV";
case FPE_FLTSUB: return "FPE_FLTSUB";
}
break;
case SIGSEGV:
switch (signal_code) {
case SEGV_MAPERR: return "SEGV_MAPERR";
case SEGV_ACCERR: return "SEGV_ACCERR";
}
break;
case SIGTRAP:
switch (signal_code) {
case TRAP_BRKPT: return "TRAP_BRKPT";
case TRAP_TRACE: return "TRAP_TRACE";
}
break;
}
// Then the other codes...
switch (signal_code) {
case SI_USER: return "SI_USER";
#if defined(SI_KERNEL)
case SI_KERNEL: return "SI_KERNEL";
#endif
case SI_QUEUE: return "SI_QUEUE";
case SI_TIMER: return "SI_TIMER";
case SI_MESGQ: return "SI_MESGQ";
case SI_ASYNCIO: return "SI_ASYNCIO";
#if defined(SI_SIGIO)
case SI_SIGIO: return "SI_SIGIO";
#endif
#if defined(SI_TKILL)
case SI_TKILL: return "SI_TKILL";
#endif
}
// Then give up...
return "?";
}
void AmlMpSignalHandler::dumpstack(std::ostream& os)
{
char* stack[20] = {0};
int depth = backtrace(reinterpret_cast<void**>(stack), sizeof(stack)/sizeof(stack[0]));
if (depth) {
char** symbols = backtrace_symbols(reinterpret_cast<void**>(stack), depth);
if (symbols) {
os << std::dec;
for (int i = 0; i < depth; i++) {
os << "#" << std::setw(2) << std::left << i + 1 << " " << demangleSymbol(symbols[i]) << "\n";
}
}
free(symbols);
}
}
std::string AmlMpSignalHandler::demangleSymbol(const char* symbol)
{
std::string result;
const char* p = strchr(symbol, '(');
if (p == nullptr) {
return symbol;
}
std::string libraryName(symbol, p - symbol);
result.append(libraryName);
const char* pSymbolName = p +1;
p = strchr(pSymbolName, '+');
if (p == nullptr) {
return symbol;
}
std::string symbolName(pSymbolName, p - pSymbolName);
int status;
char* demangleResult = abi::__cxa_demangle(symbolName.c_str(), nullptr, nullptr, &status);
if (status == 0) {
result.append("(");
result.append(demangleResult);
result.append(p);
}
free(demangleResult);
return result;
}
}