static void dbgHelpLoad(LPCWSTR name, DbgHelp* dest) { HMODULE hMod = wenforce(LoadLibrary(name), L"Could not load " + std::wstring(name)); IMPORT(StackWalk64); IMPORT(SymFunctionTableAccess64); IMPORT(SymGetModuleBase64); IMPORT(SymCleanup); IMPORT(SymEnumerateModulesW64); IMPORT(SymSetSearchPathW); IMPORT(SymInitializeW); IMPORT(SymSetOptions); IMPORT(SymGetOptions); IMPORT(SymGetModuleInfoW64); IMPORT(SymFromAddrW); IMPORT(SymGetLineFromAddrW64); IMPORT(SymRegisterCallbackW64); IMPORT(SymRefreshModuleList); IMPORT(SymLoadModuleExW); IMPORT(SymSetDbgPrint); // Custom Wine extension IMPORT(MiniDumpWriteDump); }
void SymbolInfo::loadSymbols(HANDLE process_handle_, bool download) { process_handle = process_handle_; wxBusyCursor busy; is64BitProcess = Is64BitProcess(process_handle); DWORD options = dbgHelpMs.SymGetOptions(); #ifdef _WIN64 if(!is64BitProcess) { options |= SYMOPT_INCLUDE_32BIT_MODULES; } #endif options |= SYMOPT_LOAD_LINES | SYMOPT_DEBUG; dbgHelpMs.SymSetOptions(options); dbgHelpGcc.SymSetOptions(options); #ifdef _WIN64 dbgHelpGccWow64.SymSetOptions(options); #endif std::wstring sympath; // Add the program's own directory to the search path. // Useful if someone's copied the EXE and PDB to a different machine or location. wchar_t szExePath[MAX_PATH] = L""; DWORD pathsize = MAX_PATH; BOOL gotImageName = FALSE; #ifdef _WIN64 // GetModuleFileNameEx doesn't always work across 64->32 bit boundaries. // Use QueryFullProcessImageName if we have it. { typedef BOOL WINAPI QueryFullProcessImageNameFn(HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize); QueryFullProcessImageNameFn *fn = (QueryFullProcessImageNameFn *)GetProcAddress(GetModuleHandle(L"kernel32"),"QueryFullProcessImageNameW"); if (fn) gotImageName = fn(process_handle, 0, szExePath, &pathsize); } #endif if (!gotImageName) gotImageName = GetModuleFileNameEx(process_handle, NULL, szExePath, pathsize); if (gotImageName) { // Convert the EXE path to its containing folder and append the // resulting folder to the symbol search path. wchar_t *p = wcsrchr(szExePath, '\\'); if (p != NULL) { *p = '\0'; sympath += std::wstring(L";") + szExePath; } } prefs.AdjustSymbolPath(sympath, download); for( int n=0;n<4;n++ ) { wenforce(dbgHelpMs.SymInitializeW(process_handle, L"", FALSE), "SymInitialize"); // Hook the debug output, so we actually can provide a clue as to // what's happening. dbgHelpMs.SymRegisterCallbackW64(process_handle, symCallback, NULL); // Add our PDB search paths. wenforce(dbgHelpMs.SymSetSearchPathW(process_handle, sympath.c_str()), "SymSetSearchPathW"); // Load symbol information for all modules. // Normally SymInitialize would do this, but we instead do it ourselves afterwards // so that we can hook the debug output for it. wenforce(dbgHelpMs.SymRefreshModuleList(process_handle), "SymRefreshModuleList"); wenforce(dbgHelpMs.SymEnumerateModulesW64(process_handle, EnumModules, this), "SymEnumerateModules64"); if (!modules.empty()) break; // Sometimes the module enumeration will fail (no error code, but no modules // will be returned). If we try again a little later it seems to work. // I suspect this may be if we try and enum modules too early on, before the process // has really had a chance to 'get going'. // Perhaps a better solution generally would be to manually load module symbols on demand, // as each sample comes in? That'd also solve the problem of modules getting loaded/unloaded // mid-profile. Yes, I'll probably do that some day. Sleep(100); dbgHelpMs.SymCleanup(process_handle); } DbgHelp *gcc = &dbgHelpGcc; #ifdef _WIN64 // We can't use the regular dbghelpw to profile 32-bit applications, // as it's got compiled-in things that assume 64-bit. So we instead have // a special Wow64 build, which is compiled as 64-bit code but using 32-bit // definitions. We load that instead. if (!is64BitProcess) gcc = &dbgHelpGccWow64; #endif // Now that we've loaded all the modules and debug info for the regular stuff, // we initialize the GCC dbghelp and let it have a go at the ones we couldn't do. wenforce(gcc->SymInitializeW(process_handle, NULL, FALSE), "SymInitialize"); gcc->SymSetDbgPrint(&symWineCallback); for (size_t n=0;n<modules.size();n++) { Module &mod = modules[n]; IMAGEHLP_MODULEW64 info; info.SizeOfStruct = sizeof(info); if (!dbgHelpMs.SymGetModuleInfoW64(process_handle, mod.base_addr, &info)) continue; // If we have a module with no symbol information from the MS dbghelp, // let the gcc one handle it instead. if (info.SymType == SymNone) { gcc->SymLoadModuleExW(process_handle, NULL, info.ImageName, info.ModuleName, info.BaseOfImage, info.ImageSize, NULL, 0); mod.dbghelp = gcc; } } if (g_symLog) g_symLog(L"\nFinished.\n"); sortModules(); }