static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) { ULONG size; MINIDUMP_DIRECTORY* dir; void* stream; DWORD pid = 1; /* by default */ HANDLE hProc = (HANDLE)0x900DBAAD; int i; MINIDUMP_MODULE_LIST* mml; MINIDUMP_MODULE* mm; MINIDUMP_STRING* mds; char exec_name[1024]; char name[1024]; unsigned len; /* fetch PID */ if (MiniDumpReadDumpStream(data->mapping, MiscInfoStream, &dir, &stream, &size)) { MINIDUMP_MISC_INFO* mmi = (MINIDUMP_MISC_INFO*)stream; if (mmi->Flags1 & MINIDUMP_MISC1_PROCESS_ID) pid = mmi->ProcessId; } /* fetch executable name (it's normally the first one in module list) */ strcpy(exec_name, "<minidump-exec>"); /* default */ if (MiniDumpReadDumpStream(data->mapping, ModuleListStream, &dir, &stream, &size)) { mml = (MINIDUMP_MODULE_LIST*)stream; if (mml->NumberOfModules) { char* ptr; mm = &mml->Modules[0]; mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva); len = WideCharToMultiByte(CP_ACP, 0, mds->Buffer, mds->Length / sizeof(WCHAR), name, sizeof(name) - 1, NULL, NULL); name[len] = 0; for (ptr = name + len - 1; ptr >= name; ptr--) { if (*ptr == '/' || *ptr == '\\') { strcpy(exec_name, ptr + 1); break; } } if (ptr < name) strcpy(exec_name, name); } } if (MiniDumpReadDumpStream(data->mapping, SystemInfoStream, &dir, &stream, &size)) { MINIDUMP_SYSTEM_INFO* msi = (MINIDUMP_SYSTEM_INFO*)stream; const char *str; char tmp[128]; dbg_printf("WineDbg starting on minidump on pid %lu\n", pid); switch (msi->ProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_UNKNOWN: str = "Unknown"; break; case PROCESSOR_ARCHITECTURE_INTEL: strcpy(tmp, "Intel "); switch (msi->ProcessorLevel) { case 3: str = "80386"; break; case 4: str = "80486"; break; case 5: str = "Pentium"; break; case 6: str = "Pentium Pro/II"; break; default: str = "???"; break; } strcat(tmp, str); if (msi->ProcessorLevel == 3 || msi->ProcessorLevel == 4) { if (HIWORD(msi->ProcessorRevision) == 0xFF) sprintf(tmp + strlen(tmp), "-%c%d", 'A' + HIBYTE(LOWORD(msi->ProcessorRevision)), LOBYTE(LOWORD(msi->ProcessorRevision))); else sprintf(tmp + strlen(tmp), "-%c%d", 'A' + HIWORD(msi->ProcessorRevision), LOWORD(msi->ProcessorRevision)); } else sprintf(tmp + strlen(tmp), "-%d.%d", HIWORD(msi->ProcessorRevision), LOWORD(msi->ProcessorRevision)); str = tmp; break; case PROCESSOR_ARCHITECTURE_MIPS: str = "Mips"; break; case PROCESSOR_ARCHITECTURE_ALPHA: str = "Alpha"; break; case PROCESSOR_ARCHITECTURE_PPC: str = "PowerPC"; break; default: str = "???"; break; } dbg_printf(" %s was running on #%d %s CPU%s", exec_name, msi->u.s.NumberOfProcessors, str, msi->u.s.NumberOfProcessors < 2 ? "" : "s"); switch (msi->MajorVersion) { case 3: switch (msi->MinorVersion) { case 51: str = "NT 3.51"; break; default: str = "3-????"; break; } break; case 4: switch (msi->MinorVersion) { case 0: str = (msi->PlatformId == VER_PLATFORM_WIN32_NT) ? "NT 4.0" : "95"; break; case 10: str = "98"; break; case 90: str = "ME"; break; default: str = "5-????"; break; } break; case 5: switch (msi->MinorVersion) { case 0: str = "2000"; break; case 1: str = "XP"; break; case 2: str = "Server 2003"; break; default: str = "5-????"; break; } break; default: str = "???"; break; } dbg_printf(" on Windows %s (%lu)\n", str, msi->BuildNumber); /* FIXME CSD: msi->CSDVersionRva */ } dbg_curr_process = dbg_add_process(&be_process_minidump_io, pid, hProc); dbg_curr_pid = pid; dbg_curr_process->pio_data = data; dbg_set_process_name(dbg_curr_process, exec_name); SymInitialize(hProc, NULL, FALSE); if (MiniDumpReadDumpStream(data->mapping, ThreadListStream, &dir, &stream, &size)) { MINIDUMP_THREAD_LIST* mtl = (MINIDUMP_THREAD_LIST*)stream; MINIDUMP_THREAD* mt = &mtl->Threads[0]; dbg_add_thread(dbg_curr_process, mt->ThreadId, NULL, (void*)(DWORD_PTR)mt->Teb); } /* first load ELF modules, then do the PE ones */ if (MiniDumpReadDumpStream(data->mapping, Wine_ElfModuleListStream, &dir, &stream, &size)) { char buffer[MAX_PATH]; mml = (MINIDUMP_MODULE_LIST*)stream; for (i = 0, mm = &mml->Modules[0]; i < mml->NumberOfModules; i++, mm++) { mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva); len = WideCharToMultiByte(CP_ACP, 0, mds->Buffer, mds->Length / sizeof(WCHAR), name, sizeof(name) - 1, NULL, NULL); name[len] = 0; if (SymFindFileInPath(hProc, NULL, name, (void*)(DWORD_PTR)mm->CheckSum, 0, 0, SSRVOPT_DWORD, buffer, validate_file, NULL)) SymLoadModule(hProc, NULL, buffer, NULL, mm->BaseOfImage, mm->SizeOfImage); else SymLoadModuleEx(hProc, NULL, name, NULL, mm->BaseOfImage, mm->SizeOfImage, NULL, SLMFLAG_VIRTUAL); } } if (MiniDumpReadDumpStream(data->mapping, ModuleListStream, &dir, &stream, &size)) { mml = (MINIDUMP_MODULE_LIST*)stream; for (i = 0, mm = &mml->Modules[0]; i < mml->NumberOfModules; i++, mm++) { mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva); len = WideCharToMultiByte(CP_ACP, 0, mds->Buffer, mds->Length / sizeof(WCHAR), name, sizeof(name) - 1, NULL, NULL); name[len] = 0; SymLoadModule(hProc, NULL, name, NULL, mm->BaseOfImage, mm->SizeOfImage); } } if (MiniDumpReadDumpStream(data->mapping, ExceptionStream, &dir, &stream, &size)) { MINIDUMP_EXCEPTION_STREAM* mes = (MINIDUMP_EXCEPTION_STREAM*)stream; if ((dbg_curr_thread = dbg_get_thread(dbg_curr_process, mes->ThreadId))) { ADDRESS64 addr; dbg_curr_tid = mes->ThreadId; dbg_curr_thread->in_exception = TRUE; dbg_curr_thread->excpt_record.ExceptionCode = mes->ExceptionRecord.ExceptionCode; dbg_curr_thread->excpt_record.ExceptionFlags = mes->ExceptionRecord.ExceptionFlags; dbg_curr_thread->excpt_record.ExceptionRecord = (void*)(DWORD_PTR)mes->ExceptionRecord.ExceptionRecord; dbg_curr_thread->excpt_record.ExceptionAddress = (void*)(DWORD_PTR)mes->ExceptionRecord.ExceptionAddress; dbg_curr_thread->excpt_record.NumberParameters = mes->ExceptionRecord.NumberParameters; for (i = 0; i < dbg_curr_thread->excpt_record.NumberParameters; i++) { dbg_curr_thread->excpt_record.ExceptionInformation[i] = mes->ExceptionRecord.ExceptionInformation[i]; } memcpy(&dbg_context, (char*)data->mapping + mes->ThreadContext.Rva, min(sizeof(dbg_context), mes->ThreadContext.DataSize)); memory_get_current_pc(&addr); stack_fetch_frames(); be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0); stack_info(); be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context); stack_backtrace(mes->ThreadId); source_list_from_addr(&addr, 0); } } return start_ok; }
/****************************************************************** * pe_load_dbg_file * * loads a .dbg file */ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module, const char* dbg_name, DWORD timestamp) { char tmp[MAX_PATH]; HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0; const BYTE* dbg_mapping = NULL; const IMAGE_SEPARATE_DEBUG_HEADER* hdr; const IMAGE_DEBUG_DIRECTORY* dbg; BOOL ret = FALSE; WINE_TRACE("Processing DBG file %s\n", debugstr_a(dbg_name)); if (SymFindFileInPath(pcs->handle, NULL, dbg_name, NULL, 0, 0, 0, tmp, dbg_match, NULL) && (hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE && ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) && ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)) { hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping; if (hdr->TimeDateStamp != timestamp) { WINE_ERR("Warning - %s has incorrect internal timestamp\n", debugstr_a(dbg_name)); /* * Well, sometimes this happens to DBG files which ARE REALLY the * right .DBG files but nonetheless this check fails. Anyway, * WINDBG (debugger for Windows by Microsoft) loads debug symbols * which have incorrect timestamps. */ } if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) { /* section headers come immediately after debug header */ const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)(hdr + 1); /* and after that and the exported names comes the debug directory */ dbg = (const IMAGE_DEBUG_DIRECTORY*) (dbg_mapping + sizeof(*hdr) + hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + hdr->ExportedNamesSize); ret = pe_load_debug_directory(pcs, module, dbg_mapping, sectp, hdr->NumberOfSections, dbg, hdr->DebugDirectorySize / sizeof(*dbg)); } else ERR("Wrong signature in .DBG file %s\n", debugstr_a(tmp)); } else WINE_ERR("-Unable to peruse .DBG file %s (%s)\n", debugstr_a(dbg_name), debugstr_a(tmp)); if (dbg_mapping) UnmapViewOfFile(dbg_mapping); if (hMap) CloseHandle(hMap); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return ret; }
int main(int argc, char* argv[]) { // Tell dbghelp to print diagnostics to the debugger output. SymSetOptions(SYMOPT_DEBUG); // Initialize dbghelp const HANDLE fakeProcess = (HANDLE)1; BOOL result = SymInitialize(fakeProcess, NULL, FALSE); #ifdef TESTING // Set a search path and cache directory. If this isn't set // then _NT_SYMBOL_PATH will be used instead. // Force setting it here to make sure that the test succeeds. SymSetSearchPath(fakeProcess, "SRV*c:\\symbolstest*http://msdl.microsoft.com/download/symbols"); // Valid PDB data to test the code. std::string gTextArg = "072FF0EB54D24DFAAE9D13885486EE09"; const char* ageText = "2"; const char* fileName = "kernel32.pdb"; // Valid PE data to test the code fileName = "crypt32.dll"; const char* dateStampText = "4802A0D7"; const char* sizeText = "95000"; //fileName = "chrome_child.dll"; //const char* dateStampText = "5420D824"; //const char* sizeText = "20a6000"; #else if (argc < 4) { printf("Error: insufficient arguments.\n"); printf("Usage: %s guid age pdbname\n", argv[0]); printf("Usage: %s dateStamp size pename\n", argv[0]); printf("Example: %s 6720c31f4ac24f3ab0243e0641a4412f 1 " "chrome_child.dll.pdb\n", argv[0]); printf("Example: %s 4802A0D7 95000 crypt32.dll\n", argv[0]); return 0; } std::string gTextArg = argv[1]; const char* dateStampText = argv[1]; const char* ageText = argv[2]; const char* sizeText = argv[2]; const char* fileName = argv[3]; #endif // Parse the GUID and age from the text GUID g = {}; DWORD age = 0; DWORD dateStamp = 0; DWORD size = 0; // Settings for SymFindFileInPath void* id = nullptr; DWORD flags = 0; DWORD two = 0; const char* ext = strrchr(fileName, '.'); if (!ext) { printf("No extension found on %s. Fatal error.\n", fileName); return 0; } if (_stricmp(ext, ".pdb") == 0) { std::string gText; // Scan the GUID argument and remove all non-hex characters. This allows // passing GUIDs with '-', '{', and '}' characters. for (auto c : gTextArg) { if (isxdigit(c)) { gText.push_back(c); } } printf("Parsing symbol data for a PDB file.\n"); if (gText.size() != 32) { printf("Error: GUIDs must be exactly 32 characters" " (%s was stripped to %s).\n", gTextArg.c_str(), gText.c_str()); return 10; } int count = sscanf_s(gText.substr(0, 8).c_str(), "%x", &g.Data1); DWORD temp; count += sscanf_s(gText.substr(8, 4).c_str(), "%x", &temp); g.Data2 = (unsigned short)temp; count += sscanf_s(gText.substr(12, 4).c_str(), "%x", &temp); g.Data3 = (unsigned short)temp; for (auto i = 0; i < ARRAYSIZE(g.Data4); ++i) { count += sscanf_s(gText.substr(16 + i * 2, 2).c_str(), "%x", &temp); g.Data4[i] = (unsigned char)temp; } count += sscanf_s(ageText, "%x", &age); if (count != 12) { printf("Error: couldn't parse the GUID/age string. Sorry.\n"); return 10; } flags = SSRVOPT_GUIDPTR; id = &g; two = age; printf("Looking for %s %s %s.\n", gText.c_str(), ageText, fileName); } else { printf("Parsing symbol data for a PE (.dll or .exe) file.\n"); if (strlen(dateStampText) != 8) printf("Warning!!! The datestamp (%s) is not eight characters long. " "This is usually wrong.\n", dateStampText); int count = sscanf_s(dateStampText, "%x", &dateStamp); count += sscanf_s(sizeText, "%x", &size); flags = SSRVOPT_DWORDPTR; id = &dateStamp; two = size; printf("Looking for %s %x %x.\n", fileName, dateStamp, two); } char filePath[MAX_PATH] = {}; DWORD three = 0; if (SymFindFileInPath(fakeProcess, NULL, fileName, id, two, three, flags, filePath, NULL, NULL)) { printf("Found symbol file - placed it in %s.\n", filePath); } else { printf("Error: symbols not found - error %u. Are dbghelp.dll and " "symsrv.dll in the same directory as this executable?\n", GetLastError()); printf("Note that symbol server lookups sometimes fail randomly. " "Try again?\n"); } SymCleanup(fakeProcess); return 0; }