diff --git a/Telegram/SourceFiles/core/crash_reports.cpp b/Telegram/SourceFiles/core/crash_reports.cpp index 46992e718..ecad96753 100644 --- a/Telegram/SourceFiles/core/crash_reports.cpp +++ b/Telegram/SourceFiles/core/crash_reports.cpp @@ -174,8 +174,7 @@ void SignalHandler(int signum) { ProcessAnnotations[i.first] = wrapped; } - const Annotations c_ProcessAnnotations(ProcessAnnotations); - for (const auto &i : c_ProcessAnnotations) { + for (const auto &i : ProcessAnnotations) { dump() << i.first.c_str() << ": " << i.second.c_str() << "\n"; } psWriteDump(); @@ -260,9 +259,7 @@ void SignalHandler(int signum) { backtrace_symbols_fd(addresses, size, ReportFileNo); #else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64 - dump() << "\nBacktrace:\n"; - - psWriteStackTrace(); + dump() << "\nBacktrace omitted.\n"; #endif // else for Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64 dump() << "\n"; diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index 0e89ede48..2e8b933cc 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -746,442 +746,28 @@ void psUpdateOverlayed(TWidget *widget) { if (!wv) widget->setAttribute(Qt::WA_WState_Visible, false); } -// Stack walk code is inspired by http://www.codeproject.com/Articles/11132/Walking-the-callstack - -static const int StackEntryMaxNameLength = MAX_SYM_NAME + 1; - -typedef BOOL(FAR STDAPICALLTYPE *t_SymCleanup)( - _In_ HANDLE hProcess -); -t_SymCleanup symCleanup = 0; - -typedef PVOID (FAR STDAPICALLTYPE *t_SymFunctionTableAccess64)( - _In_ HANDLE hProcess, - _In_ DWORD64 AddrBase -); -t_SymFunctionTableAccess64 symFunctionTableAccess64 = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_SymGetLineFromAddr64)( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr, - _Out_ PDWORD pdwDisplacement, - _Out_ PIMAGEHLP_LINEW64 Line -); -t_SymGetLineFromAddr64 symGetLineFromAddr64 = 0; - -typedef DWORD64 (FAR STDAPICALLTYPE *t_SymGetModuleBase64)( - _In_ HANDLE hProcess, - _In_ DWORD64 qwAddr -); -t_SymGetModuleBase64 symGetModuleBase64 = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_SymGetModuleInfo64)( - _In_ HANDLE hProcess, - _In_ DWORD64 qwAddr, - _Out_ PIMAGEHLP_MODULEW64 ModuleInfo -); -t_SymGetModuleInfo64 symGetModuleInfo64 = 0; - -typedef DWORD (FAR STDAPICALLTYPE *t_SymGetOptions)( - VOID -); -t_SymGetOptions symGetOptions = 0; - -typedef DWORD (FAR STDAPICALLTYPE *t_SymSetOptions)( - _In_ DWORD SymOptions -); -t_SymSetOptions symSetOptions = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_SymGetSymFromAddr64)( - IN HANDLE hProcess, - IN DWORD64 dwAddr, - OUT PDWORD64 pdwDisplacement, - OUT PIMAGEHLP_SYMBOL64 Symbol -); -t_SymGetSymFromAddr64 symGetSymFromAddr64 = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_SymInitialize)( - _In_ HANDLE hProcess, - _In_opt_ PCWSTR UserSearchPath, - _In_ BOOL fInvadeProcess -); -t_SymInitialize symInitialize = 0; - -typedef DWORD64 (FAR STDAPICALLTYPE *t_SymLoadModule64)( - _In_ HANDLE hProcess, - _In_opt_ HANDLE hFile, - _In_opt_ PCSTR ImageName, - _In_opt_ PCSTR ModuleName, - _In_ DWORD64 BaseOfDll, - _In_ DWORD SizeOfDll -); -t_SymLoadModule64 symLoadModule64; - -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; - -typedef DWORD (FAR STDAPICALLTYPE *t_UnDecorateSymbolName)( - PCSTR DecoratedName, - PSTR UnDecoratedName, - DWORD UndecoratedLength, - DWORD Flags -); -t_UnDecorateSymbolName unDecorateSymbolName = 0; - -typedef BOOL(FAR STDAPICALLTYPE *t_SymGetSearchPath)( - _In_ HANDLE hProcess, - _Out_writes_(SearchPathLength) PWSTR SearchPath, - _In_ DWORD SearchPathLength -); -t_SymGetSearchPath symGetSearchPath = 0; - -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; - - return bRet; -} - -// **************************************** ToolHelp32 ************************ -#define MAX_MODULE_NAME32 255 -#define TH32CS_SNAPMODULE 0x00000008 -#pragma pack( push, 8 ) -typedef struct tagMODULEENTRY32 -{ - DWORD dwSize; - DWORD th32ModuleID; // This module - DWORD th32ProcessID; // owning process - DWORD GlblcntUsage; // Global usage count on the module - DWORD ProccntUsage; // Module usage count in th32ProcessID's context - BYTE * modBaseAddr; // Base address of module in th32ProcessID's context - DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr - HMODULE hModule; // The hModule of this module in th32ProcessID's context - char szModule[MAX_MODULE_NAME32 + 1]; - char szExePath[MAX_PATH]; -} MODULEENTRY32; -typedef MODULEENTRY32 *PMODULEENTRY32; -typedef MODULEENTRY32 *LPMODULEENTRY32; -#pragma pack( pop ) - -typedef HANDLE (FAR STDAPICALLTYPE *t_CreateToolhelp32Snapshot)(DWORD dwFlags, DWORD th32ProcessID); -t_CreateToolhelp32Snapshot createToolhelp32Snapshot = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_Module32First)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); -t_Module32First module32First = 0; - -typedef BOOL (FAR STDAPICALLTYPE *t_Module32Next)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); -t_Module32Next module32Next = 0; - -bool LoadDbgHelp(bool extended = false) { - if (stackWalk64 && (!extended || symInitialize)) return true; - - HMODULE hDll = 0; - - WCHAR szTemp[4096]; - if (GetModuleFileName(NULL, szTemp, 4096) > 0) { - wcscat_s(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_s(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_s(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; - - stackWalk64 = (t_StackWalk64)GetProcAddress(hDll, "StackWalk64"); - symFunctionTableAccess64 = (t_SymFunctionTableAccess64)GetProcAddress(hDll, "SymFunctionTableAccess64"); - symGetModuleBase64 = (t_SymGetModuleBase64)GetProcAddress(hDll, "SymGetModuleBase64"); - - if (!stackWalk64 || - !symFunctionTableAccess64 || - !symGetModuleBase64) { - stackWalk64 = 0; - return false; - } - - if (extended) { - HANDLE hProcess = GetCurrentProcess(); - DWORD dwProcessId = GetCurrentProcessId(); - - symGetLineFromAddr64 = (t_SymGetLineFromAddr64)GetProcAddress(hDll, "SymGetLineFromAddrW64"); - symGetModuleInfo64 = (t_SymGetModuleInfo64)GetProcAddress(hDll, "SymGetModuleInfoW64"); - symGetSymFromAddr64 = (t_SymGetSymFromAddr64)GetProcAddress(hDll, "SymGetSymFromAddr64"); - unDecorateSymbolName = (t_UnDecorateSymbolName)GetProcAddress(hDll, "UnDecorateSymbolName"); - symInitialize = (t_SymInitialize)GetProcAddress(hDll, "SymInitializeW"); - symCleanup = (t_SymCleanup)GetProcAddress(hDll, "SymCleanup"); - symGetSearchPath = (t_SymGetSearchPath)GetProcAddress(hDll, "SymGetSearchPathW"); - symGetOptions = (t_SymGetOptions)GetProcAddress(hDll, "SymGetOptions"); - symSetOptions = (t_SymSetOptions)GetProcAddress(hDll, "SymSetOptions"); - symLoadModule64 = (t_SymLoadModule64)GetProcAddress(hDll, "SymLoadModule64"); - if (!symGetModuleInfo64 || - !symGetLineFromAddr64 || - !symGetSymFromAddr64 || - !unDecorateSymbolName || - !symInitialize || - !symCleanup || - !symGetOptions || - !symSetOptions || - !symLoadModule64) { - symInitialize = 0; - return false; - } - - const size_t nSymPathLen = 10 * MAX_PATH; - WCHAR szSymPath[nSymPathLen] = { 0 }; - - wcscat_s(szSymPath, nSymPathLen, L".;..;"); - - WCHAR szTemp[MAX_PATH + 1] = { 0 }; - if (GetCurrentDirectory(MAX_PATH, szTemp) > 0) { - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L";"); - } - - if (GetModuleFileName(NULL, szTemp, MAX_PATH) > 0) { - for (WCHAR *p = (szTemp + wcslen(szTemp) - 1); p >= szTemp; --p) { - if ((*p == '\\') || (*p == '/') || (*p == ':')) { - *p = 0; - break; - } - } - if (wcslen(szTemp) > 0) { - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L";"); - } - } - if (GetEnvironmentVariable(L"_NT_SYMBOL_PATH", szTemp, MAX_PATH) > 0) { - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L";"); - } - if (GetEnvironmentVariable(L"_NT_ALTERNATE_SYMBOL_PATH", szTemp, MAX_PATH) > 0) { - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L";"); - } - if (GetEnvironmentVariable(L"SYSTEMROOT", szTemp, MAX_PATH) > 0) { - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L";"); - - // also add the "system32"-directory: - wcscat_s(szTemp, MAX_PATH, L"\\system32"); - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L";"); - } - - if (GetEnvironmentVariable(L"SYSTEMDRIVE", szTemp, MAX_PATH) > 0) { - wcscat_s(szSymPath, nSymPathLen, L"SRV*"); - wcscat_s(szSymPath, nSymPathLen, szTemp); - wcscat_s(szSymPath, nSymPathLen, L"\\websymbols*http://msdl.microsoft.com/download/symbols;"); - } else { - wcscat_s(szSymPath, nSymPathLen, L"SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); - } - - if (symInitialize(hProcess, szSymPath, FALSE) == FALSE) { - symInitialize = 0; - return false; - } - - DWORD symOptions = symGetOptions(); - symOptions |= SYMOPT_LOAD_LINES; - symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; - symOptions = symSetOptions(symOptions); - - const WCHAR *dllname[] = { L"kernel32.dll", L"tlhelp32.dll" }; - HINSTANCE hToolhelp = NULL; - - HANDLE hSnap; - MODULEENTRY32 me; - me.dwSize = sizeof(me); - BOOL keepGoing; - size_t i; - - for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++) { - hToolhelp = LoadLibrary(dllname[i]); - if (!hToolhelp) continue; - - createToolhelp32Snapshot = (t_CreateToolhelp32Snapshot)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); - module32First = (t_Module32First)GetProcAddress(hToolhelp, "Module32First"); - module32Next = (t_Module32Next)GetProcAddress(hToolhelp, "Module32Next"); - if (createToolhelp32Snapshot && module32First && module32Next) { - break; // found the functions! - } - FreeLibrary(hToolhelp); - hToolhelp = NULL; - } - - if (hToolhelp == NULL) { - return false; - } - - hSnap = createToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); - if (hSnap == (HANDLE)-1) - return FALSE; - - keepGoing = !!module32First(hSnap, &me); - int cnt = 0; - while (keepGoing) { - symLoadModule64(hProcess, 0, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr, me.modBaseSize); - ++cnt; - keepGoing = !!module32Next(hSnap, &me); - } - CloseHandle(hSnap); - FreeLibrary(hToolhelp); - - return (cnt > 0); - } - - return true; -} - -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; - WCHAR lineFileName[StackEntryMaxNameLength]; - DWORD symType; - LPCSTR symTypeString; - WCHAR moduleName[StackEntryMaxNameLength]; - DWORD64 baseOfImage; - WCHAR loadedImageName[StackEntryMaxNameLength]; -}; - -enum StackEntryType { - StackEntryFirst, - StackEntryNext, - StackEntryLast, -}; - -char GetModuleInfoData[2 * sizeof(IMAGEHLP_MODULEW64)]; -BOOL _getModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULEW64 *pModuleInfo) { - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); - - memcpy(GetModuleInfoData, pModuleInfo, sizeof(IMAGEHLP_MODULEW64)); - if (symGetModuleInfo64(hProcess, baseAddr, (IMAGEHLP_MODULEW64*)GetModuleInfoData) != FALSE) { - // only copy as much memory as is reserved... - memcpy(pModuleInfo, GetModuleInfoData, sizeof(IMAGEHLP_MODULEW64)); - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); - return TRUE; - } - return FALSE; -} - void psWriteDump() { -} - -void psWriteStackTrace() { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS - if (!LoadDbgHelp()) { - CrashReports::dump() << "ERROR: Could not load dbghelp.dll!\n"; - return; + PROCESS_MEMORY_COUNTERS data = { 0 }; + if (Dlls::GetProcessMemoryInfo + && Dlls::GetProcessMemoryInfo( + GetCurrentProcess(), + &data, + sizeof(data))) { + CrashReports::dump() + << "Memory-usage: " + << data.PeakWorkingSetSize + << " (peak), " + << data.WorkingSetSize + << " (current)\n"; + CrashReports::dump() + << "Pagefile-usage: " + << data.PeakPagefileUsage + << " (peak), " + << data.PagefileUsage + << " (current)\n"; } - - HANDLE hThread = GetCurrentThread(), hProcess = GetCurrentProcess(); - const CONTEXT *context = NULL; - LPVOID pUserData = NULL; - - CONTEXT c; - int frameNum; - - 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 - - for (frameNum = 0; frameNum < 1024; ++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)) { - CrashReports::dump() << "ERROR: Call to StackWalk64() failed!\n"; - return; - } - - if (s.AddrPC.Offset == s.AddrReturn.Offset) { - CrashReports::dump() << s.AddrPC.Offset << "\n"; - CrashReports::dump() << "ERROR: StackWalk64() endless callstack!"; - return; - } - if (s.AddrPC.Offset != 0) { // we seem to have a valid PC - CrashReports::dump() << s.AddrPC.Offset << "\n"; - } - - if (s.AddrReturn.Offset == 0) { - break; - } - } -#endif // !TDESKTOP_DISABLE_CRASH_REPORTS +#endif // TDESKTOP_DISABLE_CRASH_REPORTS } bool psLaunchMaps(const LocationCoords &coords) { diff --git a/Telegram/SourceFiles/platform/win/specific_win.h b/Telegram/SourceFiles/platform/win/specific_win.h index 5483e178b..3c4657cd6 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.h +++ b/Telegram/SourceFiles/platform/win/specific_win.h @@ -54,7 +54,6 @@ inline void psCheckLocalSocket(const QString &) { } void psWriteDump(); -void psWriteStackTrace(); void psDeleteDir(const QString &dir); diff --git a/Telegram/SourceFiles/platform/win/windows_dlls.cpp b/Telegram/SourceFiles/platform/win/windows_dlls.cpp index e8f776b75..bb3d66c9d 100644 --- a/Telegram/SourceFiles/platform/win/windows_dlls.cpp +++ b/Telegram/SourceFiles/platform/win/windows_dlls.cpp @@ -50,6 +50,7 @@ f_RmRegisterResources RmRegisterResources; f_RmGetList RmGetList; f_RmShutdown RmShutdown; f_RmEndSession RmEndSession; +f_GetProcessMemoryInfo GetProcessMemoryInfo; HINSTANCE LibUxTheme; HINSTANCE LibShell32; @@ -58,6 +59,7 @@ HINSTANCE LibPropSys; HINSTANCE LibComBase; HINSTANCE LibDwmApi; HINSTANCE LibRstrtMgr; +HINSTANCE LibPsApi; void start() { init(); @@ -101,6 +103,9 @@ void start() { load(LibRstrtMgr, "RmShutdown", RmShutdown); load(LibRstrtMgr, "RmEndSession", RmEndSession); } + + LibPsApi = LoadLibrary(L"PSAPI.DLL"); + load(LibPsApi, "GetProcessMemoryInfo", GetProcessMemoryInfo); } } // namespace Dlls diff --git a/Telegram/SourceFiles/platform/win/windows_dlls.h b/Telegram/SourceFiles/platform/win/windows_dlls.h index 8ac439d33..bd4d48230 100644 --- a/Telegram/SourceFiles/platform/win/windows_dlls.h +++ b/Telegram/SourceFiles/platform/win/windows_dlls.h @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include +#include namespace Platform { namespace Dlls { @@ -166,5 +167,13 @@ using f_RmEndSession = DWORD(FAR STDAPICALLTYPE*)( _In_ DWORD dwSessionHandle); extern f_RmEndSession RmEndSession; +// PSAPI.DLL + +using f_GetProcessMemoryInfo = BOOL(FAR STDAPICALLTYPE*)( + HANDLE Process, + PPROCESS_MEMORY_COUNTERS ppsmemCounters, + DWORD cb); +extern f_GetProcessMemoryInfo GetProcessMemoryInfo; + } // namespace Dlls } // namespace Platform