void GetProgramInfo(str::Str<char>& s) { s.AppendFmt("Ver: %s", CURR_VERSION_STRA); #ifdef SVN_PRE_RELEASE_VER s.AppendFmt(" pre-release"); #endif #ifdef DEBUG if (!str::EndsWith(s.Get(), " (dbg)")) s.Append(" (dbg)"); #endif s.Append("\r\n"); }
static void DumpSymbol(IDiaSymbol *symbol) { DWORD section, offset, rva; DWORD dwTag; enum SymTagEnum tag; ULONGLONG length = 0; const char * typeName = NULL; char * dataTypeName = NULL; const char * thunkTypeName = NULL; symbol->get_symTag(&dwTag); tag = (enum SymTagEnum)dwTag; typeName = GetSymTypeName(tag); symbol->get_relativeVirtualAddress(&rva); symbol->get_addressSection(§ion); symbol->get_addressOffset(&offset); // for data, get length from type if (SymTagData == tag) { IDiaSymbol *type = NULL; if (symbol->get_type(&type) == S_OK) // no SUCCEEDED test as may return S_FALSE! { type->get_length(&length); const char *s = GetUndecoratedSymbolName(type, ""); if (s && *s) dataTypeName = str::Dup(s); type->Release(); } } if (SymTagThunk == tag) { DWORD dwThunkKind; if (S_OK == symbol->get_thunkOrdinal(&dwThunkKind)) thunkTypeName = GetThunkTypeName(dwThunkKind); } else { symbol->get_length(&length); } const char *nameStr = GetUndecoratedSymbolName(symbol); if (SymTagData == tag) { // type | section | length | offset | rva | name | dataTypeName char *tmp = dataTypeName ? dataTypeName : ""; g_report.AppendFmt("%s|%d|%d|%d|%d|%s|%s\n", typeName, (int)section, (int)length, (int)offset, (int)rva, nameStr, tmp); free(dataTypeName); } else if (SymTagThunk == tag) { const char *tmp = thunkTypeName ? thunkTypeName : ""; // type | section | length | offset | rva | name | thunkTypeName g_report.AppendFmt("%s|%d|%d|%d|%d|%s|%s\n", typeName, (int)section, (int)length, (int)offset, (int)rva, nameStr, tmp); } else { // type | section | length | offset | rva | name g_report.AppendFmt("%s|%d|%d|%d|%d|%s\n", typeName, (int)section, (int)length, (int)offset, (int)rva, nameStr); } }
static void GetLanguage(str::Str<char>& s) { char country[32] = { 0 }, lang[32] = { 0 }; GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, dimof(country) - 1); GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, dimof(lang) - 1); s.AppendFmt("Lang: %s %s\r\n", lang, country); }
void GetThreadCallstack(str::Str<char>& s, DWORD threadId) { if (threadId == GetCurrentThreadId()) return; s.AppendFmt("\r\nThread: %x\r\n", threadId); DWORD access = THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME; HANDLE hThread = OpenThread(access, false, threadId); if (!hThread) { s.Append("Failed to OpenThread()\r\n"); return; } DWORD res = SuspendThread(hThread); if (-1 == res) { s.Append("Failed to SuspendThread()\r\n"); } else { CONTEXT ctx = { 0 }; ctx.ContextFlags = CONTEXT_FULL; BOOL ok = GetThreadContext(hThread, &ctx); if (ok) GetCallstack(s, ctx, hThread); else s.Append("Failed to GetThreadContext()\r\n"); ResumeThread(hThread); } CloseHandle(hThread); }
void GetProgramInfo(str::Str<char>& s) { s.AppendFmt("Ver: %s", CURR_VERSION_STRA); #ifdef SVN_PRE_RELEASE_VER s.AppendFmt(" pre-release"); #endif if (IsProcess64()) { s.Append(" 64-bit"); } #ifdef DEBUG if (!str::Find(s.Get(), " (dbg)")) s.Append(" (dbg)"); #endif s.Append("\r\n"); #if defined(GIT_COMMIT_ID) const char* gitSha1 = QM(GIT_COMMIT_ID); s.AppendFmt("Git: %s (https://github.com/sumatrapdfreader/sumatrapdf/tree/%s)\r\n", gitSha1, gitSha1); #endif }
static void GetInternedStringsReport(str::Str<char>& resOut) { resOut.Append("Strings:\n"); int n = g_strInterner.StringsCount(); for (int i = 0; i < n; i++) { resOut.AppendFmt("%d|%s\n", i, g_strInterner.GetByIndex(i)); } resOut.Append("\n"); }
static void GetAddressInfo(str::Str<char>& s, DWORD64 addr) { static const int MAX_SYM_LEN = 512; char buf[sizeof(SYMBOL_INFO) + MAX_SYM_LEN * sizeof(char)]; SYMBOL_INFO *symInfo = (SYMBOL_INFO*)buf; memset(buf, 0, sizeof(buf)); symInfo->SizeOfStruct = sizeof(SYMBOL_INFO); symInfo->MaxNameLen = MAX_SYM_LEN; DWORD64 symDisp = 0; char *symName = nullptr; BOOL ok = _SymFromAddr(GetCurrentProcess(), addr, &symDisp, symInfo); if (ok) symName = &(symInfo->Name[0]); char module[MAX_PATH] = { 0 }; DWORD section; DWORD_PTR offset; if (GetAddrInfo((void*)addr, module, sizeof(module), section, offset)) { str::ToLower(module); const char *moduleShort = path::GetBaseName(module); AppendAddress(s, addr); s.AppendFmt(" %02X:", section); AppendAddress(s, offset); s.AppendFmt(" %s", moduleShort); if (symName) { s.AppendFmt("!%s+0x%x", symName, (int)symDisp); } else if (symDisp != 0) { s.AppendFmt("+0x%x", (int)symDisp); } IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD disp; if (_SymGetLineFromAddr64(GetCurrentProcess(), addr, &disp, &line)) { s.AppendFmt(" %s+%d", line.FileName, line.LineNumber); } } else { AppendAddress(s, addr); } s.Append("\r\n"); }
static void GetMachineName(str::Str<char>& s) { WCHAR *s1 = ReadRegStr(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", L"SystemFamily"); WCHAR *s2 = ReadRegStr(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", L"SystemVersion"); ScopedMem<char> s1u(s1 ? str::conv::ToUtf8(s1) : NULL); ScopedMem<char> s2u(s2 ? str::conv::ToUtf8(s2) : NULL); if (!s1u && !s2u) ; // pass else if (!s1u) s.AppendFmt("Machine: %s\r\n", s2u.Get()); else if (!s2u || str::EqI(s1u, s2u)) s.AppendFmt("Machine: %s\r\n", s1u.Get()); else s.AppendFmt("Machine: %s %s\r\n", s1u.Get(), s2u.Get()); free(s1); free(s2); }
static void GetProcessorName(str::Str<char>& s) { WCHAR *name = ReadRegStr(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", L"ProcessorNameString"); if (!name) // if more than one processor name = ReadRegStr(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", L"ProcessorNameString"); if (!name) return; ScopedMem<char> tmp(str::conv::ToUtf8(name)); s.AppendFmt("Processor: %s\r\n", tmp); free(name); }
static void GetSystemInfo(str::Str<char>& s) { SYSTEM_INFO si; GetSystemInfo(&si); s.AppendFmt("Number Of Processors: %d\r\n", si.dwNumberOfProcessors); GetProcessorName(s); MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); GlobalMemoryStatusEx(&ms); float physMemGB = (float)ms.ullTotalPhys / (float)(1024 * 1024 * 1024); float totalPageGB = (float)ms.ullTotalPageFile / (float)(1024 * 1024 * 1024); DWORD usedPerc = ms.dwMemoryLoad; s.AppendFmt("Physical Memory: %.2f GB\r\nCommit Charge Limit: %.2f GB\r\nMemory Used: %d%%\r\n", physMemGB, totalPageGB, usedPerc); GetMachineName(s); GetLanguage(s); GetGraphicsDriverInfo(s); // Note: maybe more information, like: // * processor capabilities (mmx, sse, sse2 etc.) }
static void GetOsVersion(str::Str<char>& s) { OSVERSIONINFOEX ver; ZeroMemory(&ver, sizeof(ver)); ver.dwOSVersionInfoSize = sizeof(ver); BOOL ok = GetVersionEx((OSVERSIONINFO*)&ver); if (!ok) return; char *os = OsNameFromVer(ver); int servicePackMajor = ver.wServicePackMajor; int servicePackMinor = ver.wServicePackMinor; int buildNumber = ver.dwBuildNumber & 0xFFFF; #ifdef _WIN64 char *arch = "64-bit"; #else char *arch = IsRunningInWow64() ? "Wow64" : "32-bit"; #endif if (0 == servicePackMajor) s.AppendFmt("OS: Windows %s build %d %s\r\n", os, buildNumber, arch); else if (0 == servicePackMinor) s.AppendFmt("OS: Windows %s SP%d build %d %s\r\n", os, servicePackMajor, buildNumber, arch); else s.AppendFmt("OS: Windows %s %d.%d build %d %s\r\n", os, servicePackMajor, servicePackMinor, buildNumber, arch); }
virtual void Visit(const WCHAR *name, const WCHAR *url, int level) { if (!url || IsExternalUrl(url)) return; ScopedMem<WCHAR> plainUrl(str::ToPlainUrl(url)); if (added.FindI(plainUrl) != -1) return; ScopedMem<char> urlUtf8(str::conv::ToUtf8(plainUrl)); size_t pageHtmlLen; ScopedMem<unsigned char> pageHtml(doc->GetData(urlUtf8, &pageHtmlLen)); if (!pageHtml) return; html.AppendFmt("<pagebreak page_path=\"%s\" page_marker />", urlUtf8); html.AppendAndFree(doc->ToUtf8(pageHtml, ExtractHttpCharset((const char *)pageHtml.Get(), pageHtmlLen))); added.Append(plainUrl.StealData()); }
static void GetModules(str::Str<char>& s) { HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if (snap == INVALID_HANDLE_VALUE) return; MODULEENTRY32 mod; mod.dwSize = sizeof(mod); BOOL cont = Module32First(snap, &mod); while (cont) { ScopedMem<char> nameA(str::conv::ToUtf8(mod.szModule)); ScopedMem<char> pathA(str::conv::ToUtf8(mod.szExePath)); s.AppendFmt("Module: %08X %06X %-16s %s\r\n", (DWORD)mod.modBaseAddr, (DWORD)mod.modBaseSize, nameA, pathA); cont = Module32Next(snap, &mod); } CloseHandle(snap); }
// returns true if running on wine (winex11.drv is present) // it's not a logical, but convenient place to do it static bool GetModules(str::Str<char>& s) { bool isWine = false; HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if (snap == INVALID_HANDLE_VALUE) return true; MODULEENTRY32 mod; mod.dwSize = sizeof(mod); BOOL cont = Module32First(snap, &mod); while (cont) { ScopedMem<char> nameA(str::conv::ToUtf8(mod.szModule)); if (str::EqI(nameA.Get(), "winex11.drv")) isWine = true; ScopedMem<char> pathA(str::conv::ToUtf8(mod.szExePath)); s.AppendFmt("Module: %p %06X %-16s %s\r\n", mod.modBaseAddr, mod.modBaseSize, nameA.Get(), pathA.Get()); cont = Module32Next(snap, &mod); } CloseHandle(snap); return isWine; }
void GetExceptionInfo(str::Str<char>& s, EXCEPTION_POINTERS *excPointers) { if (!excPointers) return; EXCEPTION_RECORD *excRecord = excPointers->ExceptionRecord; DWORD excCode = excRecord->ExceptionCode; s.AppendFmt("Exception: %08X %s\r\n", (int)excCode, ExceptionNameFromCode(excCode)); s.AppendFmt("Faulting IP: "); GetAddressInfo(s, (DWORD64)excRecord->ExceptionAddress); if ((EXCEPTION_ACCESS_VIOLATION == excCode) || (EXCEPTION_IN_PAGE_ERROR == excCode)) { int readWriteFlag = (int)excRecord->ExceptionInformation[0]; DWORD64 dataVirtAddr = (DWORD64)excRecord->ExceptionInformation[1]; if (0 == readWriteFlag) { s.Append("Fault reading address "); AppendAddress(s, dataVirtAddr); } else if (1 == readWriteFlag) { s.Append("Fault writing address "); AppendAddress(s, dataVirtAddr); } else if (8 == readWriteFlag) { s.Append("DEP violation at address "); AppendAddress(s, dataVirtAddr); } else { s.Append("unknown readWriteFlag: %d", readWriteFlag); } s.Append("\r\n"); } PCONTEXT ctx = excPointers->ContextRecord; s.AppendFmt("\r\nRegisters:\r\n"); #ifdef _WIN64 s.AppendFmt("RAX:%016I64X RBX:%016I64X RCX:%016I64X\r\nRDX:%016I64X RSI:%016I64X RDI:%016I64X\r\n" "R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n", ctx->Rax, ctx->Rbx, ctx->Rcx, ctx->Rdx, ctx->Rsi, ctx->Rdi, ctx->R9,ctx->R10,ctx->R11,ctx->R12,ctx->R13,ctx->R14,ctx->R15); s.AppendFmt("CS:RIP:%04X:%016I64X\r\n", ctx->SegCs, ctx->Rip); s.AppendFmt("SS:RSP:%04X:%016X RBP:%08X\r\n", ctx->SegSs, ctx->Rsp, ctx->Rbp); s.AppendFmt("DS:%04X ES:%04X FS:%04X GS:%04X\r\n", ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs); s.AppendFmt("Flags:%08X\r\n", ctx->EFlags); #else s.AppendFmt("EAX:%08X EBX:%08X ECX:%08X\r\nEDX:%08X ESI:%08X EDI:%08X\r\n", ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx, ctx->Esi, ctx->Edi); s.AppendFmt("CS:EIP:%04X:%08X\r\n", ctx->SegCs, ctx->Eip); s.AppendFmt("SS:ESP:%04X:%08X EBP:%08X\r\n", ctx->SegSs, ctx->Esp, ctx->Ebp); s.AppendFmt("DS:%04X ES:%04X FS:%04X GS:%04X\r\n", ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs); s.AppendFmt("Flags:%08X\r\n", ctx->EFlags); #endif s.Append("\r\nCrashed thread:\r\n"); // it's not really for current thread, but it seems to work GetCallstack(s, *ctx, GetCurrentThread()); }
static void AppendAddress(str::Str<char>& s, DWORD64 addr) { void *p = reinterpret_cast<void*>(addr); s.AppendFmt("%p", p); }