mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-28 11:30:54 +00:00
Fix crash dump generation on Linux.
This commit is contained in:
parent
9a857659ce
commit
b1c4524612
@ -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
|
||||
}
|
||||
|
||||
|
@ -1559,20 +1559,27 @@ bool checkReadyUpdate() {
|
||||
#elif defined Q_OS_UNIX // Q_OS_MAC
|
||||
// if the files in the directory are owned by user, while the directory is not,
|
||||
// update will still fail since it's not possible to remove files
|
||||
if (unlink(QFile::encodeName(curUpdater).constData())) {
|
||||
if (QFile::exists(curUpdater)
|
||||
&& unlink(QFile::encodeName(curUpdater).constData())) {
|
||||
if (errno == EACCES) {
|
||||
DEBUG_LOG(("Update Info: "
|
||||
"could not unlink current Updater, access denied."));
|
||||
cSetWriteProtected(true);
|
||||
return true;
|
||||
} else {
|
||||
DEBUG_LOG(("Update Error: could not unlink current Updater."));
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
|
||||
if (errno == EACCES) {
|
||||
DEBUG_LOG(("Update Info: "
|
||||
"could not copy new Updater, access denied."));
|
||||
cSetWriteProtected(true);
|
||||
return true;
|
||||
} else {
|
||||
DEBUG_LOG(("Update Error: could not copy new Updater."));
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
|
@ -650,9 +650,6 @@ bool SkipTaskbarSupported() {
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
void psWriteDump() {
|
||||
}
|
||||
|
||||
void psActivateProcess(uint64 pid) {
|
||||
// objc_activateProgram();
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ void InstallLauncher(bool force = false);
|
||||
inline void IgnoreApplicationActivationRightNow() {
|
||||
}
|
||||
|
||||
inline void WriteCrashDumpDetails() {
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
inline void psCheckLocalSocket(const QString &serverName) {
|
||||
@ -35,8 +38,6 @@ inline void psCheckLocalSocket(const QString &serverName) {
|
||||
}
|
||||
}
|
||||
|
||||
void psWriteDump();
|
||||
|
||||
void psActivateProcess(uint64 pid = 0);
|
||||
QString psAppDataPath();
|
||||
void psAutoStart(bool start, bool silent = false);
|
||||
|
@ -52,8 +52,6 @@ inline void psCheckLocalSocket(const QString &serverName) {
|
||||
}
|
||||
}
|
||||
|
||||
void psWriteDump();
|
||||
|
||||
void psActivateProcess(uint64 pid = 0);
|
||||
QString psAppDataPath();
|
||||
void psAutoStart(bool start, bool silent = false);
|
||||
|
@ -37,13 +37,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <mach-o/dyld.h>
|
||||
#include <AVFoundation/AVFoundation.h>
|
||||
|
||||
void psWriteDump() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
double v = objc_appkitVersion();
|
||||
CrashReports::dump() << "OS-Version: " << v;
|
||||
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void psActivateProcess(uint64 pid) {
|
||||
if (!pid) {
|
||||
const auto window = Core::App().activeWindow();
|
||||
@ -113,6 +106,13 @@ std::optional<bool> IsDarkMode() {
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
void WriteCrashDumpDetails() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
double v = objc_appkitVersion();
|
||||
CrashReports::dump() << "OS-Version: " << v;
|
||||
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void RegisterCustomScheme(bool force) {
|
||||
OSStatus result = LSSetDefaultHandlerForURLScheme(CFSTR("tg"), (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]);
|
||||
DEBUG_LOG(("App Info: set default handler for 'tg' scheme result: %1").arg(result));
|
||||
|
@ -39,7 +39,8 @@ void IgnoreApplicationActivationRightNow();
|
||||
bool AutostartSupported();
|
||||
bool TrayIconSupported();
|
||||
bool SkipTaskbarSupported();
|
||||
QImage GetImageFromClipboard();
|
||||
[[nodiscard]] QImage GetImageFromClipboard();
|
||||
void WriteCrashDumpDetails();
|
||||
|
||||
[[nodiscard]] std::optional<bool> IsDarkMode();
|
||||
[[nodiscard]] inline bool IsDarkModeSupported() {
|
||||
|
@ -293,6 +293,31 @@ bool AutostartSupported() {
|
||||
return !IsWindowsStoreBuild();
|
||||
}
|
||||
|
||||
void WriteCrashDumpDetails() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
PROCESS_MEMORY_COUNTERS data = { 0 };
|
||||
if (Dlls::GetProcessMemoryInfo
|
||||
&& Dlls::GetProcessMemoryInfo(
|
||||
GetCurrentProcess(),
|
||||
&data,
|
||||
sizeof(data))) {
|
||||
const auto mb = 1024 * 1024;
|
||||
CrashReports::dump()
|
||||
<< "Memory-usage: "
|
||||
<< (data.PeakWorkingSetSize / mb)
|
||||
<< " MB (peak), "
|
||||
<< (data.WorkingSetSize / mb)
|
||||
<< " MB (current)\n";
|
||||
CrashReports::dump()
|
||||
<< "Pagefile-usage: "
|
||||
<< (data.PeakPagefileUsage / mb)
|
||||
<< " MB (peak), "
|
||||
<< (data.PagefileUsage / mb)
|
||||
<< " MB (current)\n";
|
||||
}
|
||||
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
namespace {
|
||||
@ -522,31 +547,6 @@ void psSendToMenu(bool send, bool silent) {
|
||||
_manageAppLnk(send, silent, CSIDL_SENDTO, L"-sendpath", L"Telegram send to link.\nYou can disable send to menu item in Telegram settings.");
|
||||
}
|
||||
|
||||
void psWriteDump() {
|
||||
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
PROCESS_MEMORY_COUNTERS data = { 0 };
|
||||
if (Dlls::GetProcessMemoryInfo
|
||||
&& Dlls::GetProcessMemoryInfo(
|
||||
GetCurrentProcess(),
|
||||
&data,
|
||||
sizeof(data))) {
|
||||
const auto mb = 1024 * 1024;
|
||||
CrashReports::dump()
|
||||
<< "Memory-usage: "
|
||||
<< (data.PeakWorkingSetSize / mb)
|
||||
<< " MB (peak), "
|
||||
<< (data.WorkingSetSize / mb)
|
||||
<< " MB (current)\n";
|
||||
CrashReports::dump()
|
||||
<< "Pagefile-usage: "
|
||||
<< (data.PeakPagefileUsage / mb)
|
||||
<< " MB (peak), "
|
||||
<< (data.PagefileUsage / mb)
|
||||
<< " MB (current)\n";
|
||||
}
|
||||
#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
bool psLaunchMaps(const Data::LocationPoint &point) {
|
||||
return QDesktopServices::openUrl(qsl("bingmaps:?lvl=16&collection=point.%1_%2_Point").arg(point.latAsString()).arg(point.lonAsString()));
|
||||
}
|
||||
|
@ -47,8 +47,6 @@ inline void finish() {
|
||||
inline void psCheckLocalSocket(const QString &) {
|
||||
}
|
||||
|
||||
void psWriteDump();
|
||||
|
||||
void psActivateProcess(uint64 pid = 0);
|
||||
QString psAppDataPath();
|
||||
QString psAppDataPathOld();
|
||||
|
Loading…
Reference in New Issue
Block a user