diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 686db06b7b..d8137a1136 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -231,6 +231,8 @@ void Application::socketReading() { } void Application::socketError(QLocalSocket::LocalSocketError e) { + if (App::quiting()) return; + if (_secondInstance) { LOG(("Could not write show command, error %1, quiting..").arg(e)); return App::quit(); @@ -265,18 +267,33 @@ void Application::singleInstanceChecked() { if (cManyInstance()) { Logs::multipleInstances(); } - if ((!cManyInstance() && !Logs::instanceChecked()) || !Logs::started()) { - MessageBox(0, (QString::fromStdWString(L"Could not initialize logs!\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR); - // show error window - App::quit(); - return; - } Global::start(); - // if crashed, show window and try to autoupdate - - new AppClass(); + if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) { + // show error window + MessageBox(0, (QString::fromStdWString(L"Could not start Telegram Dekstop! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR); + App::quit(); + } else { + SignalHandlers::Status status = SignalHandlers::start(); + if (status == SignalHandlers::CantOpen) { + // show error window + MessageBox(0, (QString::fromStdWString(L"Could not start Telegram Dekstop! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR); + App::quit(); + } else { + if (status == SignalHandlers::LastCrashed) { + // show error window + MessageBox(0, (QString::fromStdWString(L"Last time Telegram Dekstop crashed! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR); + if (SignalHandlers::restart() == SignalHandlers::CantOpen) { + // show error window + MessageBox(0, (QString::fromStdWString(L"Could not start Telegram Dekstop! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR); + App::quit(); + return; + } + } + new AppClass(); + } + } } void Application::socketDisconnected() { @@ -638,8 +655,6 @@ AppClass::AppClass() : QObject() , _uploader(0) { AppObject = this; - installSignalHandlers(); - ThirdParty::start(); Sandbox::start(); Local::start(); @@ -1035,6 +1050,8 @@ void AppClass::execExternal(const QString &cmd) { } AppClass::~AppClass() { + abort(); + _window.setParent(0); anim::stopManager(); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 1be6560e19..2c3fd675fb 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -179,6 +179,8 @@ namespace Notify { struct GlobalDataStruct { QString LangSystemISO; int32 LangSystem = languageDefault; + + QByteArray LastCrashDump; }; GlobalDataStruct *GlobalData = 0; @@ -278,6 +280,7 @@ Type &Ref##Name() { \ DefineGlobalReadOnly(QString, LangSystemISO); DefineGlobalReadOnly(int32, LangSystem); + DefineGlobal(QByteArray, LastCrashDump); } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 70749a67f2..e86c125d92 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -111,6 +111,7 @@ namespace Global { DeclareGlobalReadOnly(QString, LangSystemISO); DeclareGlobalReadOnly(int32, LangSystem); + DeclareGlobal(QByteArray, LastCrashDump); } diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index d957bdd131..4869f079db 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -267,13 +267,11 @@ namespace Logs { } bool workingDirChosen = cBetaVersion(); - QString moveOldDataFrom; + QString initialWorkingDir = QDir(cWorkingDir()).absolutePath() + '/', moveOldDataFrom; if (cBetaVersion()) { cSetDebug(true); #if (defined Q_OS_MAC || defined Q_OS_LINUX) } else { - QString wasDir = QDir(cWorkingDir()).absolutePath() + '/'; - #ifdef _DEBUG cForceWorkingDir(cExeDir()); #else @@ -284,7 +282,7 @@ namespace Logs { workingDirChosen = true; #if (defined Q_OS_LINUX && !defined _DEBUG) // fix first version - moveOldDataFrom = wasDir; + moveOldDataFrom = initialWorkingDir; #endif #endif @@ -303,17 +301,22 @@ namespace Logs { cForceWorkingDir(QDir(cWorkingDir()).absolutePath() + '/'); QDir().setCurrent(cWorkingDir()); + QDir().mkpath(cWorkingDir() + qstr("tdata")); Global::WorkingDirReady(); - LOG(("Launched version: %1, dev: %2, beta: %3, debug mode: %4, test dc: %5").arg(AppVersion).arg(Logs::b(cDevVersion())).arg(cBetaVersion()).arg(Logs::b(cDebug())).arg(Logs::b(cTestMode()))); - LOG(("Executable dir: %1, name: %2").arg(cExeDir()).arg(cExeName())); - LOG(("Working dir: %1").arg(cWorkingDir())); - LOG(("Arguments: %1").arg(cArguments())); - if (!LogsData->openMain()) { delete LogsData; LogsData = 0; + } + + LOG(("Launched version: %1, dev: %2, beta: %3, debug mode: %4, test dc: %5").arg(AppVersion).arg(Logs::b(cDevVersion())).arg(cBetaVersion()).arg(Logs::b(cDebug())).arg(Logs::b(cTestMode()))); + LOG(("Executable dir: %1, name: %2").arg(cExeDir()).arg(cExeName())); + LOG(("Initial working dir: %1").arg(initialWorkingDir)); + LOG(("Working dir: %1").arg(cWorkingDir())); + LOG(("Arguments: %1").arg(cArguments())); + + if (!LogsData) { LOG(("Could not open '%1' for writing log!").arg(_logsFilePath(LogDataMain, qsl("_startXX")))); return; } @@ -333,11 +336,12 @@ namespace Logs { for (LogsInMemoryList::const_iterator i = list.cbegin(), e = list.cend(); i != e; ++i) { if (i->first == LogDataMain) { _logsWrite(i->first, i->second); + LOG(("First: %1, %2").arg(i->first).arg(i->second)); } } } - LOG(("Logs started.")); + LOG(("Logs started")); } Initializer::~Initializer() { @@ -368,6 +372,8 @@ namespace Logs { return false; } + + if (LogsInMemory) { t_assert(LogsInMemory != DeletedLogsInMemory); LogsInMemoryList list = *LogsInMemory; @@ -539,3 +545,126 @@ void _moveOldDataFiles(const QString &wasDir) { } } } + +namespace SignalHandlers { + + QByteArray CrashDumpPath; + FILE *CrashDumpFile = 0; + int CrashDumpFileNo = 0; + + void _writeChar(char ch) { + fwrite(&ch, 1, 1, CrashDumpFile); + } + + dump::~dump() { + if (CrashDumpFile) { + fflush(CrashDumpFile); + } + } + + const dump &operator<<(const dump &stream, const char *str) { + if (!CrashDumpFile) return stream; + + fwrite(str, 1, strlen(str), CrashDumpFile); + return stream; + } + + const dump &operator<<(const dump &stream, int num) { + if (!CrashDumpFile) return stream; + + if (num < 0) { + _writeChar('-'); + num = -num; + } + int upper = 1, prev = num / 10; + while (prev >= upper) { + upper *= 10; + } + while (upper > 0) { + int digit = (num / upper); + _writeChar('0' + digit); + num -= digit * upper; + upper /= 10; + } + return stream; + } + + void Handler(int signum) { + const char* name = 0; + switch (signum) { + case SIGABRT: name = "SIGABRT"; break; + case SIGSEGV: name = "SIGSEGV"; break; + case SIGILL: name = "SIGILL"; break; + case SIGFPE: name = "SIGFPE"; break; +#ifndef Q_OS_WIN + case SIGBUS: name = "SIGBUS"; break; + case SIGSYS: name = "SIGSYS"; break; +#endif + } + + if (name) { + dump() << "Caught signal " << signum << " (" << name << ")\n"; + } else { + dump() << "Caught signal " << signum << "\n"; + } + dump() << "Platform: "; + switch (cPlatform()) { + case dbipWindows: dump() << "win"; break; + case dbipMac: dump() << "mac"; break; + case dbipMacOld: dump() << "macold"; break; + case dbipLinux64: dump() << "linux64"; break; + case dbipLinux32: dump() << "linux32"; break; + } + dump() << "\n\nBacktrace:\n"; + psWriteStackTrace(CrashDumpFileNo); + } + + Status start() { + CrashDumpPath = (cWorkingDir() + qsl("tdata/working")).toUtf8(); + if (FILE *f = fopen(CrashDumpPath.constData(), "rb")) { + QByteArray lastdump; + char buffer[64 * 1024] = { 0 }; + int32 read = 0; + while ((read = fread(buffer, 1, 64 * 1024, f)) > 0) { + lastdump.append(buffer, read); + } + fclose(f); + + Global::SetLastCrashDump(lastdump); + + LOG(("Opened '%1' for reading, the previous Telegram Desktop launch was not finished properly :( Crash log size: %2").arg(QString::fromUtf8(CrashDumpPath)).arg(lastdump.size())); + + return LastCrashed; + } + return restart(); + } + + Status restart() { + CrashDumpFile = fopen(CrashDumpPath.constData(), "wb"); + if (CrashDumpFile) { + CrashDumpFileNo = fileno(CrashDumpFile); + + 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; + } + + LOG(("Could not open '%1' for writing!").arg(QString::fromUtf8(CrashDumpPath))); + + return CantOpen; + } + + void finish() { + if (CrashDumpFile) { + fclose(CrashDumpFile); + unlink(CrashDumpPath.constData()); + } + } + +} diff --git a/Telegram/SourceFiles/logs.h b/Telegram/SourceFiles/logs.h index bbfbc46abb..d706ba289c 100644 --- a/Telegram/SourceFiles/logs.h +++ b/Telegram/SourceFiles/logs.h @@ -85,3 +85,22 @@ namespace Logs { #define MTP_LOG(dc, msg) { if (cDebug() || !Logs::started()) Logs::writeMtp(dc, QString msg); } //usage MTP_LOG(dc, ("log: %1 %2").arg(1).arg(2)) + +namespace SignalHandlers { + + struct dump { + ~dump(); + }; + const dump &operator<<(const dump &stream, const char *str); + const dump &operator<<(const dump &stream, int num); + + enum Status { + CantOpen, + LastCrashed, + Started + }; + Status start(); + Status restart(); // can be only CantOpen or Started + void finish(); + +} diff --git a/Telegram/SourceFiles/main.cpp b/Telegram/SourceFiles/main.cpp index dde5bfaa69..e98700fdac 100644 --- a/Telegram/SourceFiles/main.cpp +++ b/Telegram/SourceFiles/main.cpp @@ -67,5 +67,6 @@ int main(int argc, char *argv[]) { psExecTelegram(); } + SignalHandlers::finish(); return result; } diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index 847cb761f5..3aa0aaef02 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -2368,6 +2368,88 @@ typedef BOOL (FAR STDAPICALLTYPE *t_miniDumpWriteDump)( ); t_miniDumpWriteDump miniDumpWriteDump = 0; +//// SymCleanup() +//typedef BOOL(__stdcall *tSC)(IN HANDLE hProcess); +//tSC pSC; +// +// SymFunctionTableAccess64() +typedef PVOID (FAR STDAPICALLTYPE *t_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); +t_SymFunctionTableAccess64 symFunctionTableAccess64 = 0; + +//// SymGetLineFromAddr64() +//typedef BOOL(__stdcall *tSGLFA)(IN HANDLE hProcess, IN DWORD64 dwAddr, +// OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line); +//tSGLFA pSGLFA; +// +// SymGetModuleBase64() +typedef DWORD64 (FAR STDAPICALLTYPE *t_SymGetModuleBase64)(IN HANDLE hProcess, IN DWORD64 dwAddr); +t_SymGetModuleBase64 symGetModuleBase64 = 0; + +//// SymGetModuleInfo64() +//typedef BOOL(__stdcall *tSGMI)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo); +//tSGMI pSGMI; + +// // SymGetModuleInfo64() +// typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo ); +// tSGMI_V3 pSGMI_V3; + +//// SymGetOptions() +//typedef DWORD(__stdcall *tSGO)(VOID); +//tSGO pSGO; +// +//// SymGetSymFromAddr64() +//typedef BOOL(__stdcall *tSGSFA)(IN HANDLE hProcess, IN DWORD64 dwAddr, +// OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol); +//tSGSFA pSGSFA; +// +//// SymInitialize() +//typedef BOOL(__stdcall *tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess); +//tSI pSI; +// +//// SymLoadModule64() +//typedef DWORD64(__stdcall *tSLM)(IN HANDLE hProcess, IN HANDLE hFile, +// IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll); +//tSLM pSLM; +// +//// SymSetOptions() +//typedef DWORD(__stdcall *tSSO)(IN DWORD SymOptions); +//tSSO pSSO; + +typedef BOOL (FAR STDAPICALLTYPE *t_StackWalk64)( + _In_ DWORD MachineType, + _In_ HANDLE hProcess, + _In_ HANDLE hThread, + _Inout_ LPSTACKFRAME64 StackFrame, + _Inout_ PVOID ContextRecord, + _In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + _In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + _In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + _In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress +); +t_StackWalk64 stackWalk64 = 0; + +//// UnDecorateSymbolName() +//typedef DWORD(__stdcall WINAPI *tUDSN)(PCSTR DecoratedName, PSTR UnDecoratedName, +// DWORD UndecoratedLength, DWORD Flags); +//tUDSN pUDSN; +// +//typedef BOOL(__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); +//tSGSP pSGSP; + +BOOL __stdcall ReadProcessMemoryRoutine64( + _In_ HANDLE hProcess, + _In_ DWORD64 qwBaseAddress, + _Out_writes_bytes_(nSize) PVOID lpBuffer, + _In_ DWORD nSize, + _Out_ LPDWORD lpNumberOfBytesRead + ) { + SIZE_T st; + BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st); + *lpNumberOfBytesRead = (DWORD)st; + //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); + return bRet; +} + HANDLE _generateDumpFileAtPath(const WCHAR *path) { static const int maxFileLen = MAX_PATH * 10; @@ -2381,7 +2463,7 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) { } } - WCHAR szFileName[maxFileLen]; + WCHAR szFileName[maxFileLen]; WCHAR szExeName[maxFileLen]; wcscpy_s(szExeName, _exeName); @@ -2410,14 +2492,94 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) { return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); } +bool LoadDbgHelp() { + if (miniDumpWriteDump) return true; + + HMODULE hDll = 0; + + WCHAR szTemp[4096]; + if (GetModuleFileName(NULL, szTemp, 4096) > 0) { + wcscat(szTemp, L".local"); + if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) { + // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" + if (GetEnvironmentVariable(L"ProgramFiles", szTemp, 4096) > 0) { + wcscat(szTemp, L"\\Debugging Tools for Windows\\dbghelp.dll"); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { + hDll = LoadLibrary(szTemp); + } + } + // Still not found? Then try to load the 64-Bit version: + if (!hDll && (GetEnvironmentVariable(L"ProgramFiles", szTemp, 4096) > 0)) { + wcscat(szTemp, L"\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"); + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) { + hDll = LoadLibrary(szTemp); + } + } + } + } + if (!hDll) { + hDll = LoadLibrary(L"DBGHELP.DLL"); + } + + if (!hDll) return false; + + miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump"); + + //pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize"); + //pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup"); + + stackWalk64 = (t_StackWalk64)GetProcAddress(hDll, "StackWalk64"); + //pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions"); + //pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions"); + + symFunctionTableAccess64 = (t_SymFunctionTableAccess64)GetProcAddress(hDll, "SymFunctionTableAccess64"); + //pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64"); + symGetModuleBase64 = (t_SymGetModuleBase64)GetProcAddress(hDll, "SymGetModuleBase64"); + //pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64"); + ////pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); + //pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64"); + //pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName"); + //pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64"); + //pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath"); + + if (!miniDumpWriteDump || + !stackWalk64) { + miniDumpWriteDump = 0; + return false; + } + + //// SymInitialize + //if (szSymPath != NULL) + // m_szSymPath = _strdup(szSymPath); + //if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) + // this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); + + //DWORD symOptions = this->pSGO(); // SymGetOptions + //symOptions |= SYMOPT_LOAD_LINES; + //symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; + ////symOptions |= SYMOPT_NO_PROMPTS; + //// SymSetOptions + //symOptions = this->pSSO(symOptions); + + //char buf[StackWalker::STACKWALK_MAX_NAMELEN] = { 0 }; + //if (this->pSGSP != NULL) + //{ + // if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) + // this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); + //} + //char szUserName[1024] = { 0 }; + //DWORD dwSize = 1024; + //GetUserNameA(szUserName, &dwSize); + //this->m_parent->OnSymInit(buf, symOptions, szUserName); + + return true; +} + void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) { static const int maxFileLen = MAX_PATH * 10; - HMODULE hDll = LoadLibrary(L"DBGHELP.DLL"); - if (!hDll) return; - - miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump"); - if (!miniDumpWriteDump) return; + if (!LoadDbgHelp()) return; HANDLE hDumpFile = 0; @@ -2465,6 +2627,150 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_op return 0; } +// stack walking code taken from StackWalker +static const int StackEntryMaxNameLength = 1024; +struct StackEntry { + DWORD64 offset; // if 0, we have no valid entry + CHAR name[StackEntryMaxNameLength]; + CHAR undName[StackEntryMaxNameLength]; + CHAR undFullName[StackEntryMaxNameLength]; + DWORD64 offsetFromSmybol; + DWORD offsetFromLine; + DWORD lineNumber; + CHAR lineFileName[StackEntryMaxNameLength]; + DWORD symType; + LPCSTR symTypeString; + CHAR moduleName[StackEntryMaxNameLength]; + DWORD64 baseOfImage; + CHAR loadedImageName[StackEntryMaxNameLength]; +}; + +enum StackEntryType { + StackEntryFirst, + StackEntryNext, + StackEntryLast, +}; + +struct IMAGEHLP_MODULE64_V2 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +}; + +char ImageHlpSymbol64[sizeof(IMAGEHLP_SYMBOL64) + StackEntryMaxNameLength]; + +void psWriteStackTrace(int n) { + if (!LoadDbgHelp()) return; + + HANDLE hThread = GetCurrentThread(), hProcess = GetCurrentProcess(); + const CONTEXT *context = NULL; + LPVOID pUserData = NULL; + + CONTEXT c; + StackEntry csEntry; + IMAGEHLP_SYMBOL64 *pSym = NULL; + IMAGEHLP_MODULE64_V2 Module; + IMAGEHLP_LINE64 Line; + int frameNum; + + if (!LoadDbgHelp()) { + SignalHandlers::dump() << "ERROR: Could not load dbghelp.dll!\n"; + return; + } + + memset(&c, 0, sizeof(CONTEXT)); + c.ContextFlags = CONTEXT_FULL; + RtlCaptureContext(&c); + + // init STACKFRAME for first call + STACKFRAME64 s; // in/out stackframe + memset(&s, 0, sizeof(s)); + DWORD imageType; +#ifdef _M_IX86 + // normally, call ImageNtHeader() and use machine info from PE header + imageType = IMAGE_FILE_MACHINE_I386; + s.AddrPC.Offset = c.Eip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Ebp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Esp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_X64 + imageType = IMAGE_FILE_MACHINE_AMD64; + s.AddrPC.Offset = c.Rip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Rsp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Rsp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_IA64 + imageType = IMAGE_FILE_MACHINE_IA64; + s.AddrPC.Offset = c.StIIP; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.IntSp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrBStore.Offset = c.RsBSP; + s.AddrBStore.Mode = AddrModeFlat; + s.AddrStack.Offset = c.IntSp; + s.AddrStack.Mode = AddrModeFlat; +#else +#error "Platform not supported!" +#endif + + pSym = (IMAGEHLP_SYMBOL64 *)ImageHlpSymbol64; + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + StackEntryMaxNameLength); + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSym->MaxNameLength = StackEntryMaxNameLength; + + memset(&Line, 0, sizeof(Line)); + Line.SizeOfStruct = sizeof(Line); + + memset(&Module, 0, sizeof(Module)); + Module.SizeOfStruct = sizeof(Module); + + for (frameNum = 0; ; ++frameNum) { + // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) + // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can + // assume that either you are done, or that the stack is so hosed that the next + // deeper frame could not be found. + // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386! + if (!stackWalk64(imageType, hProcess, hThread, &s, &c, ReadProcessMemoryRoutine64, symFunctionTableAccess64, symGetModuleBase64, NULL)) { + SignalHandlers::dump() << "ERROR: Call to StackWalk64() failed!\n"; + return; + } + + csEntry.offset = s.AddrPC.Offset; + csEntry.name[0] = 0; + csEntry.undName[0] = 0; + csEntry.undFullName[0] = 0; + csEntry.offsetFromSmybol = 0; + csEntry.offsetFromLine = 0; + csEntry.lineFileName[0] = 0; + csEntry.lineNumber = 0; + csEntry.loadedImageName[0] = 0; + csEntry.moduleName[0] = 0; + if (s.AddrPC.Offset == s.AddrReturn.Offset) { + SignalHandlers::dump() << s.AddrPC.Offset << "\n"; + SignalHandlers::dump() << "ERROR: StackWalk64() endless callstack!"; + return; + } + if (s.AddrPC.Offset != 0) { // we seem to have a valid PC + SignalHandlers::dump() << s.AddrPC.Offset << "\n"; + } + + if (s.AddrReturn.Offset == 0) { + break; + } + } +} + class StringReferenceWrapper { public: diff --git a/Telegram/SourceFiles/pspecific_wnd.h b/Telegram/SourceFiles/pspecific_wnd.h index b5f09d427d..cbda8dc02d 100644 --- a/Telegram/SourceFiles/pspecific_wnd.h +++ b/Telegram/SourceFiles/pspecific_wnd.h @@ -117,6 +117,8 @@ extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter; LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); +void psWriteStackTrace(int n); + void psDeleteDir(const QString &dir); void psUserActionDone(); diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 44098d9e14..8f285ba201 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -22,6 +22,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #define PSAPI_VERSION 1 // fix WinXP //#define Q_NO_TEMPLATE_FRIENDS // fix some compiler difference issues +#include + #include #include #include diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp index 6835e4956f..7a1bdd1701 100644 --- a/Telegram/SourceFiles/types.cpp +++ b/Telegram/SourceFiles/types.cpp @@ -22,8 +22,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "application.h" -#include - uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 }; #ifdef Q_OS_WIN @@ -309,47 +307,6 @@ namespace ThirdParty { } -namespace { - FILE *_crashDump = 0; - int _crashDumpNo = 0; -} - -void _signalHandler(int signum) { - const char* name = 0; - switch (signum) { - case SIGABRT: name = "SIGABRT"; break; - case SIGSEGV: name = "SIGSEGV"; break; - case SIGILL: name = "SIGILL"; break; - case SIGFPE: name = "SIGFPE"; break; -#ifndef Q_OS_WIN - case SIGBUS: name = "SIGBUS"; break; - case SIGSYS: name = "SIGSYS"; break; -#endif - } - LOG(("Caught signal %1").arg(name)); - if (name) - fprintf(stdout, "Caught signal %d (%s)\n", signum, name); - else - fprintf(stdout, "Caught signal %d\n", signum); - - - //printStackTrace(); -} - -void installSignalHandlers() { - _crashDump = fopen((cWorkingDir() + qsl("tdata/working")).toUtf8().constData(), "wb"); - if (_crashDump) _crashDumpNo = fileno(_crashDump); - - signal(SIGABRT, _signalHandler); - signal(SIGSEGV, _signalHandler); - signal(SIGILL, _signalHandler); - signal(SIGFPE, _signalHandler); -#ifndef Q_OS_WIN - signal(SIGBUS, _signalHandler); - signal(SIGSYS, _signalHandler); -#endif -} - bool checkms() { int64 unixms = (myunixtime() - _timeStart) * 1000LL + _msAddToUnixtime; int64 ms = int64(getms(true)); diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index 50ddd51e99..d7043d70bb 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -143,8 +143,6 @@ inline void mylocaltime(struct tm * _Tm, const time_t * _Time) { #endif } -void installSignalHandlers(); - namespace ThirdParty { void start();