static void DumpType(IDiaSymbol *symbol, int deep) { IDiaEnumSymbols * enumChilds = NULL; HRESULT hr; const char * nameStr = NULL; const char * type; LONG offset; ULONGLONG length; ULONG celt = 0; ULONG symtag; DWORD locType; bool typeSeen; #if 0 if (deep > 2) return; #endif if (symbol->get_symTag(&symtag) != S_OK) return; nameStr = GetTypeName(symbol); g_typesSeen.Intern(nameStr, &typeSeen); if (typeSeen) return; symbol->get_length(&length); symbol->get_offset(&offset); if (SymTagData == symtag) { if (symbol->get_locationType(&locType) != S_OK) return; // must be a symbol in optimized code // TODO: use get_offsetInUdt (http://msdn.microsoft.com/en-us/library/dd997149.aspx) ? // TODO: use get_type (http://msdn.microsoft.com/en-US/library/cwx3656b(v=vs.80).aspx) ? // TODO: see what else we can get http://msdn.microsoft.com/en-US/library/w8ae4k32(v=vs.80).aspx if (LocIsThisRel == locType) { g_report.AppendFmt("%s%s|%d\n", spaces(deep), nameStr, (int)offset); } } else if (SymTagUDT == symtag) { // TODO: why is it always "struct" even for classes? type = GetUdtType(symbol); g_report.AppendFmt("%s%s|%s|%d\n", spaces(deep), type, nameStr, (int)length); hr = symbol->findChildren(SymTagNull, NULL, nsNone, &enumChilds); if (!SUCCEEDED(hr)) return; IDiaSymbol* child; while (SUCCEEDED(enumChilds->Next(1, &child, &celt)) && (celt == 1)) { DumpType(child, deep+1); child->Release(); } enumChilds->Release(); } else { if (symbol->get_locationType(&locType) != S_OK) return; // must be a symbol in optimized code // TODO: assert? } }
static void GetGraphicsDriverInfo(str::Str<char>& s) { // the info is in registry in: // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000\ // Device Description REG_SZ (same as DriverDesc, so we don't read it) // DriverDesc REG_SZ // DriverVersion REG_SZ // UserModeDriverName REG_MULTI_SZ // // There can be more than one driver, they are in 0000, 0001 etc. for (int i=0; ; i++) { ScopedMem<WCHAR> key(str::Format(GFX_DRIVER_KEY_FMT, i)); ScopedMem<WCHAR> v1(ReadRegStr(HKEY_LOCAL_MACHINE, key, L"DriverDesc")); // I assume that if I can't read the value, there are no more drivers if (!v1) break; ScopedMem<char> v1a(str::conv::ToUtf8(v1)); s.AppendFmt("Graphics driver %d\r\n", i); s.AppendFmt(" DriverDesc: %s\r\n", v1.Get()); v1.Set(ReadRegStr(HKEY_LOCAL_MACHINE, key, L"DriverVersion")); if (v1) { v1a.Set(str::conv::ToUtf8(v1)); s.AppendFmt(" DriverVersion: %s\r\n", v1a.Get()); } v1.Set(ReadRegStr(HKEY_LOCAL_MACHINE, key, L"UserModeDriverName")); if (v1) { v1a.Set(str::conv::ToUtf8(v1)); s.AppendFmt(" UserModeDriverName: %s\r\n", v1a.Get()); } } }
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); }
static void AppendVal(const char *val, char escapeChar, bool compact, str::Str<char>& res) { const char *start = val; const char *s = start; char escaped = 0; while (*s) { char c = *s++; if (escapeChar == c) escaped = escapeChar; else if (']' == c) escaped = ']'; else if ('[' == c) escaped = '['; else if ('\n' == c) escaped = 'n'; else if ('\r' == c) escaped = 'r'; if (0 == escaped) continue; size_t len = s - start - 1; res.Append(start, len); res.Append(escapeChar); res.Append(escaped); start = s; escaped = 0; } size_t len = s - start; res.Append(start, len); if (!compact) res.Append(NL); }
static void DumpSection(IDiaSectionContrib *item) { DWORD sectionNo; DWORD offset; DWORD length; item->get_addressSection(§ionNo); item->get_addressOffset(&offset); item->get_length(&length); //DWORD compilandId; //item->get_compilandId(&compilandId); const char *sectionType = GetSectionType(item); const char *objFileName = GetObjFileName(item); if (g_compact) { // type | sectionNo | length | offset | objFileId int objFileId = InternString(objFileName); g_report.AppendFmt("%s|%d|%d|%d|%d\n", sectionType, sectionNo, length, offset, objFileId); } else { // type | sectionNo | length | offset | objFile g_report.AppendFmt("%s|%d|%d|%d|%s\n", sectionType, sectionNo, length, offset, objFileName); } }
static void GetOsVersion(str::Str<char>& s) { OSVERSIONINFOEX ver; ZeroMemory(&ver, sizeof(ver)); ver.dwOSVersionInfoSize = sizeof(ver); #pragma warning(push) #pragma warning(disable: 4996) // 'GetVersionEx': was declared deprecated // starting with Windows 8.1, GetVersionEx will report a wrong version number // unless the OS's GUID has been explicitly added to the compatibility manifest BOOL ok = GetVersionEx((OSVERSIONINFO*)&ver); #pragma warning(pop) if (!ok) return; const char *os = OsNameFromVer(ver); int servicePackMajor = ver.wServicePackMajor; int servicePackMinor = ver.wServicePackMinor; int buildNumber = ver.dwBuildNumber & 0xFFFF; #ifdef _WIN64 const char *arch = "64-bit"; #else const 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); }
static void PrettyPrintNode(TxtNode *curr, int nest, str::Str<char>& res) { if (TextNode == curr->type) { PrettyPrintKeyVal(curr, nest, res); return; } if (StructNode == curr->type) { PrettyPrintKeyVal(curr, nest, res); res.Append(" + [\n"); } else if (nest >= 0) { CrashIf(ArrayNode != curr->type); AppendNest(res, nest); res.Append("[\n"); } TxtNode *child; for (size_t i = 0; i < curr->children->Count(); i++) { child = curr->children->At(i); PrettyPrintNode(child, nest + 1, res); } if (nest >= 0) { AppendNest(res, nest); res.Append("]\n"); } }
static void AppendAddress(str::Str<char>& s, DWORD64 addr) { #ifdef _WIN64 s.AppendFmt("%016I64X", addr); #else s.AppendFmt("%08X", (DWORD)addr); #endif }
// the result doesn't have to be free()d but is only valid until the next call to this function static const char *GetTypeName(IDiaSymbol *symbol) { static str::Str<char> strTmp; BSTR name = NULL; symbol->get_name(&name); BStrToString(strTmp, name, "<noname>", true); SysFreeStringSafe(name); return strTmp.Get(); }
static const char *GetSourceFileName(IDiaSymbol *symbol) { static str::Str<char> strTmp; BSTR name = 0; symbol->get_sourceFileName(&name); BStrToString(strTmp, name, "<nosrcfile>"); SysFreeStringSafe(name); return strTmp.Get(); }
static const char *GetLibraryName(IDiaSymbol *symbol) { static str::Str<char> strTmp; BSTR name = 0; symbol->get_libraryName(&name); BStrToString(strTmp, name, "<nolibfile>"); SysFreeStringSafe(name); return strTmp.Get(); }
static void AppendNewline(str::Str<WCHAR>& extracted, Vec<RectI>& coords, const WCHAR *lineSep) { if (extracted.Count() > 0 && ' ' == extracted.Last()) { extracted.Pop(); coords.Pop(); } extracted.Append(lineSep); coords.AppendBlanks(str::Len(lineSep)); }
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"); }
void GetProgramInfo(str::Str<char>& s) { s.AppendFmt("Ver: %s", QM(CURR_VERSION)); #ifdef SVN_PRE_RELEASE_VER s.AppendFmt(".%s pre-release", QM(SVN_PRE_RELEASE_VER)); #endif #ifdef DEBUG s.Append(" dbg"); #endif s.Append("\r\n"); }
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 PrettyPrintKeyVal(TxtNode *curr, int nest, str::Str<char>& res) { AppendNest(res, nest); if (curr->keyStart) { AppendWsTrimEnd(res, curr->keyStart, curr->keyEnd); if (StructNode != curr->type) res.Append(" + "); } AppendWsTrimEnd(res, curr->valStart, curr->valEnd); if (StructNode != curr->type) res.Append("\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); } }
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()); }
// the result doesn't have to be free()d but is only valid until the next call to this function static const char *GetObjFileName(IDiaSectionContrib *item) { static str::Str<char> strTmp; BSTR name = 0; IDiaSymbol * compiland = 0; item->get_compiland(&compiland); if (compiland) { compiland->get_name(&name); compiland->Release(); } BStrToString(strTmp, name, "<noobjfile>"); SysFreeStringSafe(name); return strTmp.Get(); }
static void AppendNest(str::Str<char>& s, int nest) { while (nest > 0) { s.Append(" "); --nest; } }
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); }
char *GetHtml() { // first add the homepage const char *index = doc->GetHomePath(); ScopedMem<WCHAR> url(doc->ToStr(index)); Visit(NULL, url, 0); // then add all pages linked to from the table of contents doc->ParseToc(this); // finally add all the remaining HTML files Vec<char *> *paths = doc->GetAllPaths(); for (size_t i = 0; i < paths->Count(); i++) { char *path = paths->At(i); if (str::EndsWithI(path, ".htm") || str::EndsWithI(path, ".html")) { if (*path == '/') path++; url.Set(str::conv::FromUtf8(path)); Visit(NULL, url, -1); } } FreeVecMembers(*paths); delete paths; return html.StealData(); }
static void DumpTypes(IDiaSession *session) { IDiaSymbol * globalScope = NULL; IDiaEnumSymbols * enumSymbols = NULL; IDiaSymbol * symbol = NULL; HRESULT hr = session->get_globalScope(&globalScope); if (FAILED(hr)) return; AddReportSepLine(); g_report.Append("Types:\n"); DWORD flags = nsfCaseInsensitive|nsfUndecoratedName; // nsNone ? hr = globalScope->findChildren(SymTagUDT, 0, flags, &enumSymbols); if (FAILED(hr)) goto Exit; ULONG celt = 0; for (;;) { hr = enumSymbols->Next(1, &symbol, &celt); if (FAILED(hr) || (celt != 1)) break; DumpType(symbol, 0); symbol->Release(); } Exit: UnkReleaseSafe(enumSymbols); UnkReleaseSafe(globalScope); }
static bool GetStackFrameInfo(str::Str<char>& s, STACKFRAME64 *stackFrame, CONTEXT *ctx, HANDLE hThread) { #if defined(_WIN64) int machineType = IMAGE_FILE_MACHINE_AMD64; #else int machineType = IMAGE_FILE_MACHINE_I386; #endif BOOL ok = _StackWalk64(machineType, GetCurrentProcess(), hThread, stackFrame, ctx, NULL, _SymFunctionTableAccess64, _SymGetModuleBase64, NULL); if (!ok) return false; DWORD64 addr = stackFrame->AddrPC.Offset; if (0 == addr) return true; if (addr == stackFrame->AddrReturn.Offset) { s.Append("GetStackFrameInfo(): addr == stackFrame->AddrReturn.Offset"); return false; } GetAddressInfo(s, addr); return true; }
bool DjVuEngineImpl::ExtractPageText(miniexp_t item, const WCHAR *lineSep, str::Str<WCHAR>& extracted, Vec<RectI>& coords) { miniexp_t type = miniexp_car(item); if (!miniexp_symbolp(type)) return false; item = miniexp_cdr(item); if (!miniexp_numberp(miniexp_car(item))) return false; int x0 = miniexp_to_int(miniexp_car(item)); item = miniexp_cdr(item); if (!miniexp_numberp(miniexp_car(item))) return false; int y0 = miniexp_to_int(miniexp_car(item)); item = miniexp_cdr(item); if (!miniexp_numberp(miniexp_car(item))) return false; int x1 = miniexp_to_int(miniexp_car(item)); item = miniexp_cdr(item); if (!miniexp_numberp(miniexp_car(item))) return false; int y1 = miniexp_to_int(miniexp_car(item)); item = miniexp_cdr(item); RectI rect = RectI::FromXY(x0, y0, x1, y1); miniexp_t str = miniexp_car(item); if (miniexp_stringp(str) && !miniexp_cdr(item)) { if (type != miniexp_symbol("char") && type != miniexp_symbol("word") || coords.Count() > 0 && rect.y < coords.Last().y - coords.Last().dy * 0.8) { AppendNewline(extracted, coords, lineSep); } const char *content = miniexp_to_str(str); WCHAR *value = str::conv::FromUtf8(content); if (value) { size_t len = str::Len(value); // TODO: split the rectangle into individual parts per glyph for (size_t i = 0; i < len; i++) coords.Append(RectI(rect.x, rect.y, rect.dx, rect.dy)); extracted.AppendAndFree(value); } if (miniexp_symbol("word") == type) { extracted.Append(' '); coords.Append(RectI(rect.x + rect.dx, rect.y, 2, rect.dy)); } item = miniexp_cdr(item); } while (miniexp_consp(str)) { ExtractPageText(str, lineSep, extracted, coords); item = miniexp_cdr(item); str = miniexp_car(item); } return !item; }
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); }
void BStrToString(str::Str<char>& strInOut, BSTR str, char *defString, bool stripWhitespace) { strInOut.Reset(); if (!str) { strInOut.Append(defString); return; } OLECHAR c; int len = SysStringLen(str); for (int i=0; i<len; i++) { c = str[i]; if (stripWhitespace && isspace(c)) continue; if (c < 32 || c >= 128) c = '?'; strInOut.Append((char)c); } }
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 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 = NULL; BOOL ok = _SymFromAddr(GetCurrentProcess(), addr, &symDisp, symInfo); if (ok) symName = &(symInfo->Name[0]); char module[MAX_PATH] = { 0 }; DWORD section, 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); 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"); }
// the result doesn't have to be free()d but is only valid until the next call to this function static const char *GetUndecoratedSymbolName(IDiaSymbol *symbol, const char *defName = "<noname>") { static str::Str<char> strTmp; BSTR name = NULL; #if 0 DWORD undecorateOptions = UNDNAME_COMPLETE; #else DWORD undecorateOptions = UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ALLOCATION_MODEL | UNDNAME_NO_ALLOCATION_LANGUAGE | UNDNAME_NO_THISTYPE | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_THROW_SIGNATURES | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_RETURN_UDT_MODEL | UNDNAME_NO_ECSU; #endif if (S_OK == symbol->get_undecoratedNameEx(undecorateOptions, &name)) { BStrToString(strTmp, name, "", true); if (str::Eq(strTmp.Get(), "`string'")) return "*str"; strTmp.Replace("(void)", "()"); // more ideas for undecoration: // http://google-breakpad.googlecode.com/svn/trunk/src/common/windows/pdb_source_line_writer.cc } else { // Unfortunately it does happen that get_undecoratedNameEx() fails // e.g. for RememberDefaultWindowPosition() in Sumatra code symbol->get_name(&name); BStrToString(strTmp, name, defName, true); } SysFreeStringSafe(name); return strTmp.Get(); }