|
|
|
|
@ -169,7 +169,7 @@ void CrashHandler::WriteDumpForCaller()
|
|
|
|
|
WriteMinidumpAndCallstack(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#elif defined(ENABLE_LIBBACKTRACE)
|
|
|
|
|
#elif !defined(__APPLE__)
|
|
|
|
|
|
|
|
|
|
#include <backtrace.h>
|
|
|
|
|
#include <cstdarg>
|
|
|
|
|
@ -194,15 +194,12 @@ static void AllocateBuffer(BacktraceBuffer* buf);
|
|
|
|
|
static void FreeBuffer(BacktraceBuffer* buf);
|
|
|
|
|
static void AppendToBuffer(BacktraceBuffer* buf, const char* format, ...);
|
|
|
|
|
static int BacktraceFullCallback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function);
|
|
|
|
|
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx);
|
|
|
|
|
static void CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx);
|
|
|
|
|
static void LogCallstack(int signal, const void* exception_pc);
|
|
|
|
|
|
|
|
|
|
static std::recursive_mutex s_crash_mutex;
|
|
|
|
|
static bool s_in_signal_handler = false;
|
|
|
|
|
|
|
|
|
|
static backtrace_state* s_backtrace_state = nullptr;
|
|
|
|
|
static struct sigaction s_old_sigbus_action;
|
|
|
|
|
static struct sigaction s_old_sigsegv_action;
|
|
|
|
|
} // namespace CrashHandler
|
|
|
|
|
|
|
|
|
|
const char* CrashHandler::GetSignalName(int signal_no)
|
|
|
|
|
@ -268,23 +265,25 @@ int CrashHandler::BacktraceFullCallback(void* data, uintptr_t pc, const char* fi
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CrashHandler::CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
|
|
|
|
void CrashHandler::LogCallstack(int signal, const void* exception_pc)
|
|
|
|
|
{
|
|
|
|
|
const struct sigaction& sa = (signal == SIGBUS) ? s_old_sigbus_action : s_old_sigsegv_action;
|
|
|
|
|
if (sa.sa_flags & SA_SIGINFO)
|
|
|
|
|
{
|
|
|
|
|
sa.sa_sigaction(signal, siginfo, ctx);
|
|
|
|
|
}
|
|
|
|
|
else if (sa.sa_handler == SIG_DFL)
|
|
|
|
|
{
|
|
|
|
|
// Re-raising the signal would just queue it, and since we'd restore the handler back to us,
|
|
|
|
|
// we'd end up right back here again. So just abort, because that's probably what it'd do anyway.
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
else if (sa.sa_handler != SIG_IGN)
|
|
|
|
|
{
|
|
|
|
|
sa.sa_handler(signal);
|
|
|
|
|
}
|
|
|
|
|
BacktraceBuffer buf;
|
|
|
|
|
AllocateBuffer(&buf);
|
|
|
|
|
if (signal != 0 || exception_pc)
|
|
|
|
|
AppendToBuffer(&buf, "*************** Unhandled %s at %p ***************\n", GetSignalName(signal), exception_pc);
|
|
|
|
|
else
|
|
|
|
|
AppendToBuffer(&buf, "*******************************************************************\n");
|
|
|
|
|
|
|
|
|
|
const int rc = backtrace_full(s_backtrace_state, 0, BacktraceFullCallback, nullptr, &buf);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
AppendToBuffer(&buf, " backtrace_full() failed: %d\n");
|
|
|
|
|
|
|
|
|
|
AppendToBuffer(&buf, "*******************************************************************\n");
|
|
|
|
|
|
|
|
|
|
if (buf.used > 0)
|
|
|
|
|
write(STDERR_FILENO, buf.buffer, buf.used);
|
|
|
|
|
|
|
|
|
|
FreeBuffer(&buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
|
|
|
|
@ -306,27 +305,17 @@ void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
|
|
|
|
void* const exception_pc = nullptr;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
BacktraceBuffer buf;
|
|
|
|
|
AllocateBuffer(&buf);
|
|
|
|
|
AppendToBuffer(&buf, "*************** Unhandled %s at %p ***************\n", GetSignalName(signal), exception_pc);
|
|
|
|
|
|
|
|
|
|
const int rc = backtrace_full(s_backtrace_state, 0, BacktraceFullCallback, nullptr, &buf);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
AppendToBuffer(&buf, " backtrace_full() failed: %d\n");
|
|
|
|
|
|
|
|
|
|
AppendToBuffer(&buf, "*******************************************************************\n");
|
|
|
|
|
|
|
|
|
|
if (buf.used > 0)
|
|
|
|
|
write(STDERR_FILENO, buf.buffer, buf.used);
|
|
|
|
|
|
|
|
|
|
FreeBuffer(&buf);
|
|
|
|
|
LogCallstack(signal, exception_pc);
|
|
|
|
|
|
|
|
|
|
s_in_signal_handler = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Chances are we're not going to have anything else to call, but just in case.
|
|
|
|
|
lock.unlock();
|
|
|
|
|
CallExistingSignalHandler(signal, siginfo, ctx);
|
|
|
|
|
|
|
|
|
|
// We can't continue from here. Just bail out and dump core.
|
|
|
|
|
std::fputs("Aborting application.\n", stderr);
|
|
|
|
|
std::fflush(stderr);
|
|
|
|
|
std::abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CrashHandler::Install()
|
|
|
|
|
@ -341,9 +330,9 @@ bool CrashHandler::Install()
|
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
|
sa.sa_flags = SA_SIGINFO | SA_NODEFER;
|
|
|
|
|
sa.sa_sigaction = CrashSignalHandler;
|
|
|
|
|
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
|
|
|
|
|
if (sigaction(SIGBUS, &sa, nullptr) != 0)
|
|
|
|
|
return false;
|
|
|
|
|
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
|
|
|
|
|
if (sigaction(SIGSEGV, &sa, nullptr) != 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
@ -355,6 +344,7 @@ void CrashHandler::SetWriteDirectory(std::string_view dump_directory)
|
|
|
|
|
|
|
|
|
|
void CrashHandler::WriteDumpForCaller()
|
|
|
|
|
{
|
|
|
|
|
LogCallstack(0, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
@ -372,4 +362,12 @@ void CrashHandler::WriteDumpForCaller()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
|
|
|
|
{
|
|
|
|
|
// We can't continue from here. Just bail out and dump core.
|
|
|
|
|
std::fputs("Aborting application.\n", stderr);
|
|
|
|
|
std::fflush(stderr);
|
|
|
|
|
std::abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|