2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-09-02 07:25:46 +00:00

Fix crash dump generation on Linux.

This commit is contained in:
John Preston
2021-05-03 17:34:33 +04:00
parent 9a857659ce
commit b1c4524612
9 changed files with 145 additions and 177 deletions

View File

@@ -131,20 +131,98 @@ void InstallQtMessageHandler() {
});
}
Qt::HANDLE ReportingThreadId = nullptr;
bool ReportingHeaderWritten = false;
QMutex ReportingMutex;
std::atomic<Qt::HANDLE> ReportingThreadId/* = nullptr*/;
bool ReportingHeaderWritten/* = false*/;
const char *BreakpadDumpPath/* = nullptr*/;
const wchar_t *BreakpadDumpPathW/* = nullptr*/;
const char *BreakpadDumpPath = nullptr;
const wchar_t *BreakpadDumpPathW = nullptr;
const int HandledSignals[] = {
SIGSEGV,
SIGABRT,
SIGFPE,
SIGILL,
#ifdef Q_OS_UNIX
SIGBUS,
SIGTRAP,
#endif // Q_OS_UNIX
};
#ifdef Q_OS_UNIX
struct sigaction SIG_def[32];
struct sigaction OldSigActions[32]/* = { 0 }*/;
void RestoreSignalHandlers() {
for (const auto signal : HandledSignals) {
sigaction(signal, &OldSigActions[signal], nullptr);
}
}
void InvokeOldSignalHandler(int signum, siginfo_t *info, void *ucontext) {
if (signum < 0 || signum > 31) {
return;
} else if (OldSigActions[signum].sa_flags & SA_SIGINFO) {
if (OldSigActions[signum].sa_sigaction) {
OldSigActions[signum].sa_sigaction(signum, info, ucontext);
}
} else {
if (OldSigActions[signum].sa_handler) {
OldSigActions[signum].sa_handler(signum);
}
}
}
void WriteReportHeader() {
if (ReportingHeaderWritten) {
return;
}
ReportingHeaderWritten = true;
const auto dec2hex = [](int value) -> char {
if (value >= 0 && value < 10) {
return '0' + value;
} else if (value >= 10 && value < 16) {
return 'a' + (value - 10);
}
return '#';
};
for (const auto &i : ProcessAnnotationRefs) {
QByteArray utf8 = i.second->toUtf8();
std::string wrapped;
wrapped.reserve(4 * utf8.size());
for (auto ch : utf8) {
auto uch = static_cast<uchar>(ch);
wrapped.append("\\x", 2).append(1, dec2hex(uch >> 4)).append(1, dec2hex(uch & 0x0F));
}
ProcessAnnotations[i.first] = wrapped;
}
for (const auto &i : ProcessAnnotations) {
dump() << i.first.c_str() << ": " << i.second.c_str() << "\n";
}
Platform::WriteCrashDumpDetails();
dump() << "\n";
}
void WriteReportInfo(int signum, const char *name) {
WriteReportHeader();
const auto thread = ReportingThreadId.load();
if (name) {
dump() << "Caught signal " << signum << " (" << name << ") in thread " << uint64(thread) << "\n";
} else if (signum == -1) {
dump() << "Google Breakpad caught a crash, minidump written in thread " << uint64(thread) << "\n";
if (BreakpadDumpPath) {
dump() << "Minidump: " << BreakpadDumpPath << "\n";
} else if (BreakpadDumpPathW) {
dump() << "Minidump: " << BreakpadDumpPathW << "\n";
}
} else {
dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n";
}
dump() << "\nBacktrace omitted.\n";
dump() << "\n";
}
void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
if (signum > 0) {
sigaction(signum, &SIG_def[signum], 0);
}
RestoreSignalHandlers();
#else // Q_OS_UNIX
void SignalHandler(int signum) {
@@ -162,125 +240,17 @@ void SignalHandler(int signum) {
#endif // !Q_OS_WIN
}
Qt::HANDLE thread = QThread::currentThreadId();
if (thread == ReportingThreadId) return;
auto expected = Qt::HANDLE(nullptr);
const auto thread = QThread::currentThreadId();
QMutexLocker lock(&ReportingMutex);
ReportingThreadId = thread;
if (!ReportingHeaderWritten) {
ReportingHeaderWritten = true;
auto dec2hex = [](int value) -> char {
if (value >= 0 && value < 10) {
return '0' + value;
} else if (value >= 10 && value < 16) {
return 'a' + (value - 10);
}
return '#';
};
for (const auto &i : ProcessAnnotationRefs) {
QByteArray utf8 = i.second->toUtf8();
std::string wrapped;
wrapped.reserve(4 * utf8.size());
for (auto ch : utf8) {
auto uch = static_cast<uchar>(ch);
wrapped.append("\\x", 2).append(1, dec2hex(uch >> 4)).append(1, dec2hex(uch & 0x0F));
}
ProcessAnnotations[i.first] = wrapped;
}
for (const auto &i : ProcessAnnotations) {
dump() << i.first.c_str() << ": " << i.second.c_str() << "\n";
}
psWriteDump();
dump() << "\n";
}
if (name) {
dump() << "Caught signal " << signum << " (" << name << ") in thread " << uint64(thread) << "\n";
} else if (signum == -1) {
dump() << "Google Breakpad caught a crash, minidump written in thread " << uint64(thread) << "\n";
if (BreakpadDumpPath) {
dump() << "Minidump: " << BreakpadDumpPath << "\n";
} else if (BreakpadDumpPathW) {
dump() << "Minidump: " << BreakpadDumpPathW << "\n";
}
} else {
dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n";
if (ReportingThreadId.compare_exchange_strong(expected, thread)) {
WriteReportInfo(signum, name);
ReportingThreadId = nullptr;
}
// see https://github.com/benbjohnson/bandicoot
#ifdef Q_OS_UNIX
ucontext_t *uc = (ucontext_t*)ucontext;
void *caller = 0;
if (uc) {
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
/* OSX < 10.6 */
#if defined(__x86_64__)
caller = (void*)uc->uc_mcontext->__ss.__rip;
#elif defined(__i386__)
caller = (void*)uc->uc_mcontext->__ss.__eip;
#else
caller = (void*)uc->uc_mcontext->__ss.__srr0;
#endif
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
/* OSX >= 10.6 */
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
caller = (void*)uc->uc_mcontext->__ss.__rip;
#else
caller = (void*)uc->uc_mcontext->__ss.__eip;
#endif
#elif defined(__linux__)
/* Linux */
#if defined(__i386__)
caller = (void*)uc->uc_mcontext.gregs[14]; /* Linux 32 */
#elif defined(__X86_64__) || defined(__x86_64__)
caller = (void*)uc->uc_mcontext.gregs[16]; /* Linux 64 */
#elif defined(__ia64__) /* Linux IA64 */
caller = (void*)uc->uc_mcontext.sc_ip;
#endif
#endif
}
void *addresses[132] = { 0 };
size_t size = backtrace(addresses, 128);
/* overwrite sigaction with caller's address */
if (caller) {
for (int i = size; i > 1; --i) {
addresses[i + 3] = addresses[i];
}
addresses[2] = (void*)0x1;
addresses[3] = caller;
addresses[4] = (void*)0x1;
}
#ifdef Q_OS_MAC
dump() << "\nBase image addresses:\n";
for (size_t i = 0; i < size; ++i) {
Dl_info info;
dump() << i << " ";
if (dladdr(addresses[i], &info)) {
dump() << uint64(info.dli_fbase) << " (" << info.dli_fname << ")\n";
} else {
dump() << "_unknown_module_\n";
}
}
#endif // Q_OS_MAC
dump() << "\nBacktrace:\n";
backtrace_symbols_fd(addresses, size, ReportFileNo);
#else // Q_OS_UNIX
dump() << "\nBacktrace omitted.\n";
#endif // else for Q_OS_UNIX
dump() << "\n";
ReportingThreadId = nullptr;
InvokeOldSignalHandler(signum, info, ucontext);
#endif // Q_OS_UNIX
}
bool SetSignalHandlers = true;
@@ -475,17 +445,13 @@ Status Restart() {
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
sigaction(SIGABRT, &sigact, &SIG_def[SIGABRT]);
sigaction(SIGSEGV, &sigact, &SIG_def[SIGSEGV]);
sigaction(SIGILL, &sigact, &SIG_def[SIGILL]);
sigaction(SIGFPE, &sigact, &SIG_def[SIGFPE]);
sigaction(SIGBUS, &sigact, &SIG_def[SIGBUS]);
sigaction(SIGSYS, &sigact, &SIG_def[SIGSYS]);
for (const auto signal : HandledSignals) {
sigaction(signal, &sigact, &OldSigActions[signal]);
}
#else // !Q_OS_WIN
signal(SIGABRT, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGFPE, SignalHandler);
for (const auto signal : HandledSignals) {
signal(signal, SignalHandler);
}
#endif // else for !Q_OS_WIN
}