|
|
@ -50,6 +50,7 @@
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif /* __GLIBC__ */
|
|
|
|
#endif /* __GLIBC__ */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
#include <vector>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(__EMSCRIPTEN__)
|
|
|
|
#if defined(__EMSCRIPTEN__)
|
|
|
@ -65,6 +66,9 @@
|
|
|
|
/** The signals we want our crash handler to handle. */
|
|
|
|
/** The signals we want our crash handler to handle. */
|
|
|
|
static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL, SIGQUIT };
|
|
|
|
static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL, SIGQUIT };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::atomic<pid_t> _crash_tid;
|
|
|
|
|
|
|
|
std::atomic<uint32_t> _crash_other_threads;
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(__GLIBC__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
|
|
|
#if defined(__GLIBC__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
|
|
|
#pragma GCC diagnostic ignored "-Wclobbered"
|
|
|
|
#pragma GCC diagnostic ignored "-Wclobbered"
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
@ -73,6 +77,7 @@ static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGI
|
|
|
|
static char *internal_fault_saved_buffer;
|
|
|
|
static char *internal_fault_saved_buffer;
|
|
|
|
static jmp_buf internal_fault_jmp_buf;
|
|
|
|
static jmp_buf internal_fault_jmp_buf;
|
|
|
|
sigset_t internal_fault_old_sig_proc_mask;
|
|
|
|
sigset_t internal_fault_old_sig_proc_mask;
|
|
|
|
|
|
|
|
std::atomic<bool> internal_fault_use_signal_handler;
|
|
|
|
|
|
|
|
|
|
|
|
static void InternalFaultSigHandler(int sig)
|
|
|
|
static void InternalFaultSigHandler(int sig)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -372,6 +377,18 @@ class CrashLogUnix : public CrashLog {
|
|
|
|
return this->LogGdbInfo(buffer, last);
|
|
|
|
return this->LogGdbInfo(buffer, last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Log crash trailer
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *LogCrashTrailer(char *buffer, const char *last) const override
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
uint32_t other_crashed_threads = _crash_other_threads.load();
|
|
|
|
|
|
|
|
if (other_crashed_threads > 0) {
|
|
|
|
|
|
|
|
buffer += seprintf(buffer, last, "\n*** %u other threads have also crashed ***\n\n", other_crashed_threads);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Show registers if possible
|
|
|
|
* Show registers if possible
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -651,15 +668,7 @@ class CrashLogUnix : public CrashLog {
|
|
|
|
sigaddset(&sigs, signum);
|
|
|
|
sigaddset(&sigs, signum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct sigaction sa;
|
|
|
|
internal_fault_use_signal_handler.store(true);
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
|
|
|
|
|
|
sa.sa_flags = SA_RESTART;
|
|
|
|
|
|
|
|
sa.sa_handler = InternalFaultSigHandler;
|
|
|
|
|
|
|
|
sa.sa_mask = sigs;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
|
|
|
|
sigaction(signum, &sa, nullptr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sigprocmask(SIG_UNBLOCK, &sigs, &internal_fault_old_sig_proc_mask);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &sigs, &internal_fault_old_sig_proc_mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -667,9 +676,7 @@ class CrashLogUnix : public CrashLog {
|
|
|
|
{
|
|
|
|
{
|
|
|
|
internal_fault_saved_buffer = nullptr;
|
|
|
|
internal_fault_saved_buffer = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
internal_fault_use_signal_handler.store(false);
|
|
|
|
signal(signum, SIG_DFL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sigprocmask(SIG_SETMASK, &internal_fault_old_sig_proc_mask, nullptr);
|
|
|
|
sigprocmask(SIG_SETMASK, &internal_fault_old_sig_proc_mask, nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -779,10 +786,44 @@ static void CDECL HandleCrash(int signum, siginfo_t *si, void *context)
|
|
|
|
static void CDECL HandleCrash(int signum)
|
|
|
|
static void CDECL HandleCrash(int signum)
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
pid_t tid = 1;
|
|
|
|
|
|
|
|
#if defined(WITH_DBG_GDB)
|
|
|
|
|
|
|
|
tid = syscall(SYS_gettid);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pid_t already_crashed = _crash_tid.load();
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
/* Is this a recursive call from the crash thread */
|
|
|
|
|
|
|
|
if (already_crashed == tid) {
|
|
|
|
|
|
|
|
#if defined(__GLIBC__) && defined(WITH_SIGACTION)
|
|
|
|
|
|
|
|
if (internal_fault_use_signal_handler.load()) {
|
|
|
|
|
|
|
|
InternalFaultSigHandler(signum);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This should never be reached, just give up at this point */
|
|
|
|
|
|
|
|
_exit(43);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Is a different thread in the crash logger already? */
|
|
|
|
|
|
|
|
if (already_crashed != 0) {
|
|
|
|
|
|
|
|
/* Just sleep forever while the other thread is busy logging the crash */
|
|
|
|
|
|
|
|
_crash_other_threads++;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
|
|
pause();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Atomically mark this thread as the crashing thread */
|
|
|
|
|
|
|
|
} while (!_crash_tid.compare_exchange_weak(already_crashed, tid));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef WITH_SIGACTION
|
|
|
|
/* Disable all handling of signals by us, so we don't go into infinite loops. */
|
|
|
|
/* Disable all handling of signals by us, so we don't go into infinite loops. */
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
signal(signum, SIG_DFL);
|
|
|
|
signal(signum, SIG_DFL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
const char *abort_reason = CrashLog::GetAbortCrashlogReason();
|
|
|
|
const char *abort_reason = CrashLog::GetAbortCrashlogReason();
|
|
|
|
if (abort_reason != nullptr) {
|
|
|
|
if (abort_reason != nullptr) {
|
|
|
@ -817,21 +858,29 @@ static void CDECL HandleCrash(int signum)
|
|
|
|
ss.ss_flags = 0;
|
|
|
|
ss.ss_flags = 0;
|
|
|
|
sigaltstack(&ss, nullptr);
|
|
|
|
sigaltstack(&ss, nullptr);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
|
|
|
|
#ifdef WITH_SIGACTION
|
|
|
|
#ifdef WITH_SIGACTION
|
|
|
|
|
|
|
|
sigset_t sigs;
|
|
|
|
|
|
|
|
sigemptyset(&sigs);
|
|
|
|
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
|
|
|
|
sigaddset(&sigs, signum);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
struct sigaction sa;
|
|
|
|
struct sigaction sa;
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
|
|
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
|
|
|
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
|
|
|
#ifdef WITH_SIGALTSTACK
|
|
|
|
#ifdef WITH_SIGALTSTACK
|
|
|
|
sa.sa_flags |= SA_ONSTACK;
|
|
|
|
sa.sa_flags |= SA_ONSTACK;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sa.sa_mask = sigs;
|
|
|
|
sa.sa_sigaction = HandleCrash;
|
|
|
|
sa.sa_sigaction = HandleCrash;
|
|
|
|
sigaction(signum, &sa, nullptr);
|
|
|
|
sigaction(signum, &sa, nullptr);
|
|
|
|
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
|
|
|
|
for (int signum : _signals_to_handle) {
|
|
|
|
signal(signum, HandleCrash);
|
|
|
|
signal(signum, HandleCrash);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* static */ void CrashLog::InitThread()
|
|
|
|
/* static */ void CrashLog::InitThread()
|
|
|
|