improved os x crash reports, possible linux (and windows) broken

This commit is contained in:
John Preston 2016-01-31 14:32:29 +03:00
parent d28483fad4
commit 74248b0284
7 changed files with 224 additions and 31 deletions

View File

@ -546,6 +546,21 @@ void _moveOldDataFiles(const QString &wasDir) {
}
}
#if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#include <execinfo.h>
#include <signal.h>
#include <sys/syscall.h>
#ifdef Q_OS_MAC
#include <dlfcn.h>
#include <mach-o/dyld_images.h>
#include <mach-o/dyld.h>
#endif
#endif
namespace SignalHandlers {
QByteArray CrashDumpPath;
@ -629,7 +644,17 @@ namespace SignalHandlers {
bool LoggingCrashHeaderWritten = false;
QMutex LoggingCrashMutex;
// see https://github.com/benbjohnson/bandicoot
#if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
struct sigaction SIG_def[32];
void Handler(int signum, siginfo_t *info, void *ucontext) {
sigaction(signum, &SIG_def[signum], 0);
#else
void Handler(int signum) {
#endif
const char* name = 0;
switch (signum) {
case SIGABRT: name = "SIGABRT"; break;
@ -681,15 +706,69 @@ namespace SignalHandlers {
dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n";
}
#if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
ucontext_t *uc = (ucontext_t*)ucontext;
void *addresses[128] = { 0 };
void *caller = 0;
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
/* OSX < 10.6 */
#if defined(__x86_64__)
caller = (void*)uap->uc_mcontext->__ss.__rip;
#elif defined(__i386__)
caller = (void*)uap->uc_mcontext->__ss.__eip;
#else
caller = (void*)uap->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*)uap->uc_mcontext->__ss.__eip;
#endif
#elif defined(__linux__)
/* Linux */
#if defined(__i386__)
caller = (void*)uap->uc_mcontext.gregs[14]; /* Linux 32 */
#elif defined(__X86_64__) || defined(__x86_64__)
caller = (void*)uap->uc_mcontext.gregs[16]; /* Linux 64 */
#elif defined(__ia64__) /* Linux IA64 */
caller = (void*)uap->uc_mcontext.sc_ip;
#endif
#endif
size_t size = backtrace(addresses, 128);
/* overwrite sigaction with caller's address */
if (caller) addresses[1] = caller;
#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
dump() << "\nBacktrace:\n";
psWriteStackTrace(CrashDumpFileNo);
backtrace_symbols_fd(addresses, size, CrashDumpFileNo);
#else
psWriteStackTrace();
#endif
dump() << "\n";
LoggingCrashThreadId = 0;
#ifndef Q_OS_WIN
exit(1);
#endif
}
Status start() {
@ -729,13 +808,24 @@ namespace SignalHandlers {
t_assert(launchedBinaryName.size() < int(sizeof(LaunchedBinaryName)));
memcpy(LaunchedBinaryName, launchedBinaryName.constData(), launchedBinaryName.size());
#ifndef Q_OS_WIN
struct sigaction sigact;
sigact.sa_sigaction = SignalHandlers::Handler;
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]);
#else
signal(SIGABRT, SignalHandlers::Handler);
signal(SIGSEGV, SignalHandlers::Handler);
signal(SIGILL, SignalHandlers::Handler);
signal(SIGFPE, SignalHandlers::Handler);
#ifndef Q_OS_WIN
signal(SIGBUS, SignalHandlers::Handler);
signal(SIGSYS, SignalHandlers::Handler);
#endif
return Started;
}

View File

@ -976,14 +976,6 @@ QAbstractNativeEventFilter *psNativeEventFilter() {
void psWriteDump() {
}
void psWriteStackTrace(int file) {
void *addresses[1024] = { 0 };
size_t size = backtrace(addresses, 1024);
backtrace_symbols_fd(addresses, size, file);
}
QString demanglestr(const QString &mangled) {
QByteArray cmd = ("c++filt -n " + mangled).toUtf8();
FILE *f = popen(cmd.constData(), "r");

View File

@ -114,7 +114,6 @@ private:
};
void psWriteDump();
void psWriteStackTrace(int file);
int psShowCrash(const QString &crashdump);
void psDeleteDir(const QString &dir);

View File

@ -529,14 +529,6 @@ void psWriteDump() {
SignalHandlers::dump() << "OS-Version: " << v;
}
void psWriteStackTrace(int file) {
void *addresses[1024] = { 0 };
size_t size = backtrace(addresses, 1024);
backtrace_symbols_fd(addresses, size, file);
}
QString demanglestr(const QString &mangled) {
QByteArray cmd = ("c++filt -n " + mangled).toUtf8();
FILE *f = popen(cmd.constData(), "r");
@ -553,6 +545,69 @@ QString demanglestr(const QString &mangled) {
return result.trimmed();
}
QString escapeShell(const QString &str) {
QString result;
const QChar *b = str.constData(), *e = str.constEnd();
for (const QChar *ch = b; ch != e; ++ch) {
if (*ch == ' ' || *ch == '"' || *ch == '\'' || *ch == '\\') {
if (result.isEmpty()) {
result.reserve(str.size() * 2);
}
if (ch > b) {
result.append(b, ch - b);
}
result.append('\\');
b = ch;
}
}
if (result.isEmpty()) return str;
if (e > b) {
result.append(b, e - b);
}
return result;
}
QStringList atosstr(uint64 *addresses, int count, uint64 base) {
QStringList result;
if (!count) return result;
result.reserve(count);
QString cmdstr = "atos -o " + escapeShell(cExeDir() + cExeName()) + qsl("/Contents/MacOS/Telegram -l 0x%1").arg(base, 0, 16);
for (int i = 0; i < count; ++i) {
if (addresses[i]) {
cmdstr += qsl(" 0x%1").arg(addresses[i], 0, 16);
}
}
QByteArray cmd = cmdstr.toUtf8();
FILE *f = popen(cmd.constData(), "r");
QStringList atosResult;
if (f) {
char buffer[4096] = {0};
while (!feof(f)) {
if (fgets(buffer, 4096, f) != NULL) {
atosResult.push_back(QString::fromUtf8(buffer));
}
}
pclose(f);
}
for (int i = 0, j = 0; i < count; ++i) {
if (addresses[i]) {
if (j < atosResult.size() && !atosResult.at(j).isEmpty() && !atosResult.at(j).startsWith(qstr("0x"))) {
result.push_back(atosResult.at(j).trimmed());
} else {
result.push_back(QString());
}
++j;
} else {
result.push_back(QString());
}
}
return result;
}
QString _showCrashDump(const QByteArray &crashdump, QString dumpfile) {
QString initial = QString::fromUtf8(crashdump), result;
QStringList lines = initial.split('\n');
@ -560,6 +615,38 @@ QString _showCrashDump(const QByteArray &crashdump, QString dumpfile) {
int32 i = 0, l = lines.size();
while (i < l) {
uint64 addresses[1024] = { 0 };
for (; i < l; ++i) {
result.append(lines.at(i)).append('\n');
QString line = lines.at(i).trimmed();
if (line == qstr("Base image addresses:")) {
++i;
break;
}
}
uint64 base = 0;
for (int32 start = i; i < l; ++i) {
QString line = lines.at(i).trimmed();
if (line.isEmpty()) break;
if (!base) {
QRegularExpressionMatch m = QRegularExpression(qsl("^\\d+ (\\d+) \\((.+)\\)")).match(line);
if (m.hasMatch()) {
if (uint64 address = m.captured(1).toULongLong()) {
if (m.captured(2).endsWith(qstr("Contents/MacOS/Telegram"))) {
base = address;
}
}
}
}
}
if (base) {
result.append(qsl("(base address read: 0x%1)\n").arg(base, 0, 16));
} else {
result.append(qsl("ERROR: base address not read!\n"));
}
for (; i < l; ++i) {
result.append(lines.at(i)).append('\n');
QString line = lines.at(i).trimmed();
@ -569,7 +656,22 @@ QString _showCrashDump(const QByteArray &crashdump, QString dumpfile) {
}
}
for (int32 start = i; i < l; ++i) {
int32 start = i;
for (; i < l; ++i) {
QString line = lines.at(i).trimmed();
if (line.isEmpty()) break;
if (QRegularExpression(qsl("^\\d+")).match(line).hasMatch()) {
QStringList lst = line.split(' ', QString::SkipEmptyParts);
if (lst.size() > 2) {
uint64 addr = lst.at(2).startsWith(qstr("0x")) ? lst.at(2).mid(2).toULongLong(0, 16) : lst.at(2).toULongLong();
addresses[i - start] = addr;
}
}
}
QStringList atos = atosstr(addresses, i - start, base);
for (i = start; i < l; ++i) {
QString line = lines.at(i).trimmed();
if (line.isEmpty()) break;
@ -581,7 +683,18 @@ QString _showCrashDump(const QByteArray &crashdump, QString dumpfile) {
continue;
}
QStringList lst = line.split(' ', QString::SkipEmptyParts);
result.append(lst.at(0)).append(' ');
result.append('\n').append(lst.at(0)).append(qsl(". "));
if (lst.size() < 3) {
result.append(qstr("BAD LINE: ")).append(line).append('\n');
continue;
}
if (i - start < atos.size()) {
if (!atos.at(i - start).isEmpty()) {
result.append(atos.at(i - start)).append('\n');
continue;
}
}
for (int j = 1, s = lst.size();;) {
if (lst.at(j).startsWith('_')) {
result.append(demanglestr(lst.at(j)));
@ -606,7 +719,7 @@ QString _showCrashDump(const QByteArray &crashdump, QString dumpfile) {
break;
}
}
result.append('\n');
result.append(qsl(" [demangled]")).append('\n');
}
}
return result;

View File

@ -141,7 +141,6 @@ private:
};
void psWriteDump();
void psWriteStackTrace(int file);
int psShowCrash(const QString &crashdump);
void psDeleteDir(const QString &dir);

View File

@ -3008,7 +3008,7 @@ QString _showCrashDump(const QByteArray &crashdump, QString dumpfile) {
return result;
}
void psWriteStackTrace(int file) {
void psWriteStackTrace() {
if (!LoadDbgHelp()) {
SignalHandlers::dump() << "ERROR: Could not load dbghelp.dll!\n";
return;

View File

@ -118,7 +118,7 @@ LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers);
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
void psWriteDump();
void psWriteStackTrace(int file);
void psWriteStackTrace();
int psShowCrash(const QString &crashdump);
void psDeleteDir(const QString &dir);