/* * symmod.c */ #include #include #include #include // this struct is used to initilaize the module data array for a new module static MODULE_DATA gmd[NUM_MODULE_DATA_ENTRIES] = { {mdHeader, dsNone, dsNone, false, NULL}, {mdSecHdrs, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_UNKNOWN, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_COFF, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_CODEVIEW, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_FPO, dsNone, dsNone, false, NULL}, // true, mdfnGetExecutableImage}, {IMAGE_DEBUG_TYPE_MISC, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_EXCEPTION, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_FIXUP, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_OMAP_TO_SRC, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_OMAP_FROM_SRC, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_BORLAND, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_RESERVED10, dsNone, dsNone, false, NULL}, {IMAGE_DEBUG_TYPE_CLSID, dsNone, dsNone, false, NULL} }; // prototypes - move them later BOOL modload( IN HANDLE hProcess, IN PMODULE_ENTRY mi ); BOOL idd2mi( PPROCESS_ENTRY pe, PIMGHLP_DEBUG_DATA idd, PMODULE_ENTRY mi ); BOOL imgReadLoaded( PIMGHLP_DEBUG_DATA idd ); BOOL imgReadFromDisk( PIMGHLP_DEBUG_DATA idd ); BOOL ReadHeader( PIMGHLP_DEBUG_DATA idd, DWORD datasrc ); BOOL ReadCallerData( PIMGHLP_DEBUG_DATA idd ); BOOL cbFindExe( HANDLE FileHandle, PSTR FileName, PVOID CallerData ); BOOL cbFindDbg( HANDLE FileHandle, PSTR FileName, PVOID CallerData ); BOOL ProcessCvForOmap( PIMGHLP_DEBUG_DATA idd ); void RetrievePdbInfo( PIMGHLP_DEBUG_DATA idd ); DWORD imgset( PMODULE_DATA md, DWORD id, DWORD hint, DWORD src ); BOOL FakePdbName( PIMGHLP_DEBUG_DATA idd ); // inline functions __inline DWORD SectionContains ( HANDLE hp, PIMAGE_SECTION_HEADER pSH, PIMAGE_DATA_DIRECTORY ddir ); // here's the real code BOOL LoadSymbols( HANDLE hp, PMODULE_ENTRY mi, DWORD flags ) { BOOL rc; if (flags & LS_JUST_TEST) { if ((mi->Flags & MIF_DEFERRED_LOAD) && !(mi->Flags & MIF_NO_SYMBOLS)) return false; else return true; } if (flags & LS_QUALIFIED) { if (option(SYMOPT_NO_UNQUALIFIED_LOADS)) { if ((mi->Flags & MIF_DEFERRED_LOAD) && !(mi->Flags & MIF_NO_SYMBOLS)) return false; } } if ((mi->Flags & MIF_DEFERRED_LOAD) && !(mi->Flags & MIF_NO_SYMBOLS)) { rc = modload(hp, mi); if (rc) rc = mi->SymType != SymNone; return rc; } else if (flags & LS_FAIL_IF_LOADED) return false; return true; } // This function exists just to be called by MapDebugInfo legacy code. PIMGHLP_DEBUG_DATA GetIDD( HANDLE hFile, LPSTR FileName, LPSTR SymbolPath, ULONG64 ImageBase, DWORD dwFlags ) { PIMGHLP_DEBUG_DATA idd; BOOL rc = true; SetLastError(NO_ERROR); idd = InitIDD(0, hFile, FileName, SymbolPath, ImageBase, 0, NULL, 0, dwFlags); if (!idd) return NULL; rc = imgReadLoaded(idd); if (idd->error) { SetLastError(idd->error); goto error; } if (!rc) rc = imgReadFromDisk(idd); if (idd->error) { SetLastError(idd->error); goto error; } if (rc) rc = GetDebugData(idd); if (rc) return idd; error: ReleaseDebugData(idd, IMGHLP_FREE_FPO | IMGHLP_FREE_SYMPATH | IMGHLP_FREE_PDATA | IMGHLP_FREE_XDATA); return NULL; } BOOL modload( IN HANDLE hp, IN PMODULE_ENTRY mi ) { IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl; PPROCESS_ENTRY pe; ULONG i; PIMGHLP_DEBUG_DATA idd; ULONG bias; PIMAGE_SYMBOL lpSymbolEntry; PUCHAR lpStringTable; PUCHAR p; BOOL SymbolsLoaded = false; PCHAR CallbackFileName, ImageName; ULONG Size; DWORD cba; BOOL bFixLoadFailure; BOOL bFixPartialLoad; BOOL rc = true; g.LastSymLoadError = SYMLOAD_DEFERRED; SetLastError(NO_ERROR); pe = FindProcessEntry(hp); if (!pe) { SetLastError(ERROR_INVALID_HANDLE); return false; } #ifdef DEBUG if (traceSubName(mi->ModuleName)) // for setting debug breakpoints from DBGHELP_TOKEN dtrace("debug(%s)\n", mi->ModuleName); #endif if (mi->SymType == SymNone) return error(ERROR_MOD_NOT_FOUND); CallbackFileName = mi->LoadedImageName ? mi->LoadedImageName : mi->ImageName ? mi->ImageName : mi->ModuleName; if (DoSymbolCallback(pe, CBA_DEFERRED_SYMBOL_LOAD_CANCEL, mi, &idsl, CallbackFileName)) { pprint(pe, "Symbol loading cancelled\n"); return error(ERROR_CANCELLED); } DoSymbolCallback(pe, CBA_DEFERRED_SYMBOL_LOAD_START, mi, &idsl, CallbackFileName); ImageName = mi->ImageName; bFixLoadFailure = false; bFixPartialLoad = false; load: idd = InitIDD( hp, mi->hFile, ImageName, pe->SymbolSearchPath, mi->BaseOfDll, mi->DllSize, &mi->mld, mi->CallerFlags, 0); if (!idd) return false; // First, try to load the image from the usual sources. If we fail, // allow the caller to fix up the image information and try again. rc = imgReadLoaded(idd); if (!rc && !bFixPartialLoad) { bFixPartialLoad = true; if (DoSymbolCallback(pe, CBA_DEFERRED_SYMBOL_LOAD_PARTIAL, mi, &idsl, CallbackFileName) && idsl.Reparse) { ImageName = idsl.FileName; mi->hFile = idsl.hFile; CallbackFileName = idsl.FileName; ReleaseDebugData(idd, IMGHLP_FREE_FPO | IMGHLP_FREE_SYMPATH | IMGHLP_FREE_PDATA | IMGHLP_FREE_XDATA); goto load; } } // get info from the caller's data struct if (!rc) rc = ReadCallerData(idd); // Okay. Let's try some of the less reliable methods, like searching // for images on disk, etc. if (!rc) rc = imgReadFromDisk(idd); // Load the symbolic information into temp storage. if (rc) rc = GetDebugData(idd); mi->SymLoadError = g.LastSymLoadError; if (idd->error) SetLastError(idd->error); // Load the debug info into the module info struct. __try { EnterCriticalSection(&g.threadlock); if (rc && (rc = idd2mi(pe, idd, mi))) { DoSymbolCallback(pe, CBA_DEFERRED_SYMBOL_LOAD_COMPLETE, mi, &idsl, CallbackFileName); } } __finally { ReleaseDebugData(idd, IMGHLP_FREE_STANDARD); LeaveCriticalSection(&g.threadlock); } // If at this point, we have failed. Let's tell the caller. // Try again, if it indicates we should. Otherwise, let's fail. if (!rc && !bFixLoadFailure) { bFixLoadFailure = true; if (DoSymbolCallback(pe, CBA_DEFERRED_SYMBOL_LOAD_FAILURE, mi, &idsl, CallbackFileName) && idsl.Reparse) { ImageName = idsl.FileName; mi->hFile = idsl.hFile; CallbackFileName = idsl.FileName; goto load; } mi->SymType = SymNone; mi->Flags |= MIF_NO_SYMBOLS; rc = false; } // SymbolStatus function is expensive - call only if needed. if (option(SYMOPT_DEBUG)) { pprint(pe, "%s - %s\n", *mi->AliasName ? mi->AliasName : mi->ModuleName, SymbolStatus(mi, 9)); } return rc; } DWORD64 LoadModule( IN HANDLE hp, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD DllSize, IN HANDLE hFile, IN PMODLOAD_DATA data, IN DWORD flags ) { IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl; PPROCESS_ENTRY pe; PMODULE_ENTRY mi; LPSTR p; DWORD64 ip; #ifdef DEBUG if (traceSubName(ImageName)) // for setting debug breakpoints from DBGHELP_TOKEN dtrace("debug(%s)\n", ImageName); #endif if (BaseOfDll == (DWORD64)-1) return 0; __try { CHAR c; if (ImageName) c = *ImageName; if (ModuleName) c = *ModuleName; } __except(EXCEPTION_EXECUTE_HANDLER) { return error(ERROR_INVALID_PARAMETER); } // It is illegal to load pdb symbols without info to set the base address if (IsPdb(ImageName) && !BaseOfDll) return error(ERROR_INVALID_PARAMETER); // start loading pe = FindProcessEntry(hp); if (!pe) { return 0; } if (BaseOfDll) mi = GetModuleForPC(pe, BaseOfDll, true); else mi = NULL; if (mi) { // // in this case the symbols are already loaded // so the caller really wants the deferred // symbols to be loaded // if ((mi->Flags & MIF_DEFERRED_LOAD) && modload(hp, mi)) return mi->BaseOfDll; else return 0; } // // look to see if there is an overlapping module entry // if (BaseOfDll) { do { mi = GetModuleForPC(pe, BaseOfDll, false); if (mi) { RemoveEntryList(&mi->ListEntry); DoSymbolCallback( pe, CBA_SYMBOLS_UNLOADED, mi, &idsl, mi->LoadedImageName ? mi->LoadedImageName : mi->ImageName ? mi->ImageName : mi->ModuleName ); FreeModuleEntry(pe, mi); } } while(mi); } mi = (PMODULE_ENTRY)MemAlloc(sizeof(MODULE_ENTRY)); if (!mi) return 0; InitModuleEntry(mi); mi->BaseOfDll = BaseOfDll; mi->DllSize = DllSize; mi->hFile = hFile; if (ImageName) { char SplitMod[_MAX_FNAME]; mi->ImageName = StringDup(ImageName); _splitpath( ImageName, NULL, NULL, SplitMod, NULL ); mi->ModuleName[0] = 0; CatString(mi->ModuleName, SplitMod, sizeof(mi->ModuleName)); if (ModuleName && _stricmp( ModuleName, mi->ModuleName ) != 0) { mi->AliasName[0] = 0; CatString(mi->AliasName, ModuleName, sizeof(mi->AliasName)); } else { mi->AliasName[0] = 0; } } else { if (ModuleName) { mi->AliasName[0] = 0; CatString( mi->AliasName, ModuleName, sizeof(mi->AliasName)); } } mi->mod = NULL; mi->cbPdbSymbols = 0; mi->pPdbSymbols = NULL; mi->CallerFlags = flags; if (data) { if (data->ssize != sizeof(MODLOAD_DATA)) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } memcpy(&mi->mld, data, data->ssize); mi->CallerData = MemAlloc(mi->mld.size); if (!mi->CallerData) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } mi->mld.data = mi->CallerData; memcpy(mi->mld.data, data->data, mi->mld.size); } if (option(SYMOPT_DEFERRED_LOADS) && BaseOfDll) { mi->Flags |= MIF_DEFERRED_LOAD; mi->SymType = SymDeferred; } else if (!modload( hp, mi )) { FreeModuleEntry(pe, mi); return 0; } InsertTailList( &pe->ModuleList, &mi->ListEntry); ip = GetIP(pe); if ((mi->BaseOfDll <= ip) && (mi->BaseOfDll + DllSize >= ip)) diaSetModFromIP(pe); #if 0 SrcSrvLoadModule(hp, (*mi->AliasName) ? mi->AliasName : mi->ModuleName, mi->BaseOfDll, mi->stSrcSrv, mi->cbSrcSrv); #else // char sz[MAX_PATH]; // SymGetSourceFile(pe->hProcess, mi->BaseOfDll, "d:\\db\\symsrv\\symstore\\symstore.cpp", sz); #endif return mi->BaseOfDll; } BOOL GetModule( HANDLE hp, LPSTR ModuleName, DWORD64 ImageBase, DWORD ImageSize, PVOID Context ) { LoadModule( hp, ModuleName, NULL, ImageBase, ImageSize, NULL, 0, NULL ); return true; } BOOL idd2mi( PPROCESS_ENTRY pe, PIMGHLP_DEBUG_DATA idd, PMODULE_ENTRY mi ) { ULONG i; idd->flags = mi->Flags; // The following code ONLY works if the dll wasn't rebased // during install. Is it really useful? if (!mi->BaseOfDll) { // // This case occurs when modules are loaded multiple times by // name with no explicit base address. // if (GetModuleForPC( pe, idd->ImageBaseFromImage, true )) { if (idd->ImageBaseFromImage) { pprint(pe, "GetModuleForPC(%p, %I64x, true) failed\n", pe, idd->ImageBaseFromImage, true ); } else { pprint(pe, "No base address for %s: Please specify\n", mi->ImageName); } diaRelease(idd->dia); return false; } mi->BaseOfDll = idd->ImageBaseFromImage; } if (!mi->DllSize) { mi->DllSize = idd->SizeOfImage; } mi->hProcess = idd->hProcess; mi->InProcImageBase = idd->InProcImageBase; mi->CheckSum = idd->CheckSum; mi->TimeDateStamp = idd->TimeDateStamp; mi->MachineType = idd->Machine; mi->ImageType = idd->ImageType; mi->PdbSrc = idd->PdbSrc; mi->ImageSrc = idd->ImageSrc; if (!mi->MachineType && g.MachineType) { mi->MachineType = (USHORT) g.MachineType; } if (idd->dia) { mi->LoadedPdbName = StringDup(idd->PdbFileName); if (!mi->LoadedPdbName) return false; } if (idd->DbgFileMap) { mi->LoadedImageName = StringDup(idd->DbgFilePath); } else if (*idd->ImageFilePath) { mi->LoadedImageName = StringDup(idd->ImageFilePath); } else if (idd->dia) { mi->LoadedImageName = StringDup(idd->PdbFileName); } else { mi->LoadedImageName = StringDup(""); } if (!mi->LoadedImageName) return false; if (idd->fROM) { mi->Flags |= MIF_ROM_IMAGE; } if (!mi->ImageName) { mi->ImageName = StringDup(idd->OriginalImageFileName); if (!mi->ImageName) return false; _splitpath( mi->ImageName, NULL, NULL, mi->ModuleName, NULL ); if (*mi->ImageName) mi->AliasName[0] = 0; } mi->dsExceptions = idd->dsExceptions; if (idd->cFpo) { // // use virtualalloc() because the rtf search function // return a pointer into this memory. we want to make // all of this memory read only so that callers cannot // stomp on imagehlp's data // mi->pFpoData = (PFPO_DATA)VirtualAlloc( NULL, sizeof(FPO_DATA) * idd->cFpo, MEM_COMMIT, PAGE_READWRITE ); if (mi->pFpoData) { mi->dwEntries = idd->cFpo; CopyMemory( mi->pFpoData, idd->pFpo, sizeof(FPO_DATA) * mi->dwEntries ); VirtualProtect( mi->pFpoData, sizeof(FPO_DATA) * mi->dwEntries, PAGE_READONLY, &i ); } } // copy the pdata block from the pdb if (idd->pPData) { mi->pPData = MemAlloc(idd->cbPData); if (mi->pPData) { mi->cPData = idd->cPData; mi->cbPData = idd->cbPData; CopyMemory(mi->pPData, idd->pPData, idd->cbPData); } } if (idd->pXData) { mi->pXData = MemAlloc(idd->cbXData); if (mi->pXData) { mi->cXData = idd->cXData; mi->cbXData = idd->cbXData; CopyMemory(mi->pXData, idd->pXData, idd->cbXData); } } // now the sections mi->NumSections = idd->cCurrentSections; if (idd->fCurrentSectionsMapped) { mi->SectionHdrs = (PIMAGE_SECTION_HEADER) MemAlloc( sizeof(IMAGE_SECTION_HEADER) * mi->NumSections ); if (mi->SectionHdrs) { CopyMemory( mi->SectionHdrs, idd->pCurrentSections, sizeof(IMAGE_SECTION_HEADER) * mi->NumSections ); } } else { mi->SectionHdrs = idd->pCurrentSections; } if (idd->pOriginalSections) { mi->OriginalNumSections = idd->cOriginalSections; mi->OriginalSectionHdrs = idd->pOriginalSections; } else { mi->OriginalNumSections = mi->NumSections; mi->OriginalSectionHdrs = (PIMAGE_SECTION_HEADER) MemAlloc( sizeof(IMAGE_SECTION_HEADER) * mi->NumSections ); if (mi->OriginalSectionHdrs) { CopyMemory( mi->OriginalSectionHdrs, idd->pCurrentSections, sizeof(IMAGE_SECTION_HEADER) * mi->NumSections ); } } // symbols mi->TmpSym.Name = (LPSTR) MemAlloc( TMP_SYM_LEN ); mi->vsTmpSym.Name = (LPSTR) MemAlloc( TMP_SYM_LEN ); if (idd->dia) { mi->SymType = SymPdb; mi->lSymType = SymPdb; mi->loaded = true; } else { if (idd->pMappedCv) { mi->loaded = LoadCodeViewSymbols( mi->hProcess, mi, idd ); } if (!mi->loaded && idd->pMappedCoff) { mi->loaded = LoadCoffSymbols(mi->hProcess, mi, idd); } if (!mi->loaded && idd->cExports) { mi->loaded = LoadExportSymbols( mi, idd ); if (mi->loaded) { mi->PdbSrc = srcNone; } } if (idd->ImageType == dsVirtual) { mi->SymType = SymVirtual; mi->loaded = true; } mi->lSymType = mi->SymType; if (!mi->loaded) { mi->SymType = SymNone; if (mi->lSymType == SymDeferred) mi->lSymType = SymNone; } } mi->dia = idd->dia; mi->pdbdataSig = idd->pdbdataSig; mi->pdbdataAge = idd->pdbdataAge; memcpy(&mi->pdbdataGuid, &idd->pdbdataGuid, sizeof(GUID)); if (idd->pMappedCv) { PSTR pszPdb; ULONG cbLeft; memcpy(&mi->CVRec, idd->pMappedCv, sizeof(mi->CVRec.dwSig)); mi->cvSig = mi->CVRec.dwSig; if (mi->cvSig == NB10_SIG) { memcpy(&mi->CVRec, idd->pMappedCv, sizeof(mi->CVRec.nb10ih)); pszPdb = (PSTR) &mi->CVRec + sizeof(mi->CVRec.nb10ih); cbLeft = sizeof(mi->CVRec) - sizeof(mi->CVRec.nb10ih); CopyString(pszPdb, (PSTR) idd->pMappedCv + sizeof(mi->CVRec.nb10ih), cbLeft); } else { memcpy(&mi->CVRec, idd->pMappedCv, sizeof(mi->CVRec.rsdsih)); pszPdb = (PSTR) &mi->CVRec + sizeof(mi->CVRec.rsdsih); cbLeft = sizeof(mi->CVRec) - sizeof(mi->CVRec.rsdsih); CopyString(pszPdb, (PSTR) idd->pMappedCv + sizeof(mi->CVRec.rsdsih), cbLeft); } } mi->fTypes = idd->fTypes; mi->fLines = idd->fLines; mi->fSymbols = idd->fSymbols; mi->fTypes = idd->fTypes; mi->fPdbUnmatched = idd->fPdbUnmatched; mi->fDbgUnmatched = idd->fDbgUnmatched; ProcessOmapForModule( mi, idd ); mi->Flags &= ~MIF_DEFERRED_LOAD; return true; } PIMGHLP_DEBUG_DATA InitIDD( HANDLE hProcess, HANDLE FileHandle, LPSTR FileName, LPSTR SymbolPath, ULONG64 ImageBase, DWORD SizeOfImage, PMODLOAD_DATA mld, DWORD CallerFlags, ULONG dwFlags ) { PIMGHLP_DEBUG_DATA idd; int len; #ifdef DEBUG if (traceSubName(FileName)) // for setting debug breakpoints from DBGHELP_TOKEN dtrace("debug(%s)\n", FileName); #endif // No File handle and no file name. Bail if (!(CallerFlags & SLMFLAG_VIRTUAL)) { if (!FileHandle && (!FileName || !*FileName)) return NULL; } SetLastError(NO_ERROR); idd = (PIMGHLP_DEBUG_DATA)MemAlloc(sizeof(IMGHLP_DEBUG_DATA)); if (!idd) { SetLastError(ERROR_OUTOFMEMORY); g.LastSymLoadError = SYMLOAD_OUTOFMEMORY; return NULL; } ZeroMemory(idd, sizeof(IMGHLP_DEBUG_DATA)); idd->SizeOfStruct = sizeof(IMGHLP_DEBUG_DATA); idd->md = (PMODULE_DATA)MemAlloc(sizeof(gmd)); if (!idd->md) { SetLastError(ERROR_OUTOFMEMORY); g.LastSymLoadError = SYMLOAD_OUTOFMEMORY; MemFree(idd); return NULL; } memcpy(idd->md, gmd, sizeof(gmd)); // store off parameters idd->pe = FindProcessEntry(hProcess); idd->flags = dwFlags; idd->ImageFileHandle = FileHandle; idd->SizeOfImage = SizeOfImage; idd->CallerFlags = CallerFlags; if (FileName) CopyStrArray(idd->ImageFilePath, FileName); __try { idd->InProcImageBase = ImageBase; idd->hProcess = hProcess; idd->mld = mld; if (FileName) CopyStrArray(idd->ImageName, FileName); if (SymbolPath) { len = strlen(SymbolPath) + 1; idd->SymbolPath = (PCHAR)MemAlloc(len); if (idd->SymbolPath) CopyString(idd->SymbolPath, SymbolPath, len); } } __except (EXCEPTION_EXECUTE_HANDLER) { if (idd) { ReleaseDebugData(idd, IMGHLP_FREE_ALL); idd = NULL; } } return idd; } typedef BOOL (WINAPI *PENUMPROCESSMODULES)(HANDLE, HMODULE *, DWORD, LPDWORD); typedef DWORD (WINAPI *PGETMODULEFILENAMEEXA)(HANDLE, HMODULE, LPSTR, DWORD); typedef BOOL (WINAPI *PGETMODULEINFORMATION)(HANDLE, HMODULE, LPMODULEINFO, DWORD); BOOL GetFileNameFromBase(HANDLE hp, ULONG64 base, char *name, DWORD cbname) { HMODULE hmods[1024]; DWORD cb; unsigned int i; char modname[MAX_PATH]; MODULEINFO mi; static PENUMPROCESSMODULES fnEnumProcessModules = NULL; static PGETMODULEFILENAMEEXA fnGetModuleFileNameEx = NULL; static PGETMODULEINFORMATION fnGetModuleInformation = NULL; if (!hp || hp == INVALID_HANDLE_VALUE || !base || !name || !cbname) return false; // Get the functions from psapi... if (fnEnumProcessModules == (PENUMPROCESSMODULES)-1) return false; if (!fnEnumProcessModules) { HMODULE hmod = LoadLibrary("psapi.dll"); if (!hmod || hmod == INVALID_HANDLE_VALUE) { fnEnumProcessModules = (PENUMPROCESSMODULES)-1; return false; } fnEnumProcessModules = (PENUMPROCESSMODULES)GetProcAddress(hmod, "EnumProcessModules"); if (!fnEnumProcessModules) { fnEnumProcessModules = (PENUMPROCESSMODULES)-1; return false; } fnGetModuleFileNameEx = (PGETMODULEFILENAMEEXA)GetProcAddress(hmod, "GetModuleFileNameExA"); if (!fnGetModuleFileNameEx) { fnGetModuleFileNameEx = (PGETMODULEFILENAMEEXA)-1; return false; } fnGetModuleInformation = (PGETMODULEINFORMATION)GetProcAddress(hmod, "GetModuleInformation"); if (!fnGetModuleInformation) { fnGetModuleInformation = (PGETMODULEINFORMATION)-1; return false; } } // Get a list of all the modules in this process // and the full path to each. if(fnEnumProcessModules(hp, hmods, sizeof(hmods), &cb)) { for (i = 0; i < (cb / sizeof(HMODULE)); i++) { if (!fnGetModuleFileNameEx(hp, hmods[i], modname, sizeof(modname))) continue; if (!fnGetModuleInformation(hp, hmods[i], &mi, sizeof(mi))) continue; if ((ULONG64)mi.lpBaseOfDll != base) continue; CopyString(name, modname, cbname); return true; } } return false; } BOOL imgReadLoaded( PIMGHLP_DEBUG_DATA idd ) { #ifdef DEBUG if (traceSubName(idd->ImageFilePath)) // for setting debug breakpoints from DBGHELP_TOKEN dtrace("debug(%s)\n", idd->ImageFilePath); #endif __try { // if this is a virtual module, we're done if (idd->CallerFlags & SLMFLAG_VIRTUAL) { idd->ImageType = dsVirtual; return true; } // if we were passed a file handle, use it if (idd->ImageFileHandle) { HANDLE fh; if (!DuplicateHandle(GetCurrentProcess(), idd->ImageFileHandle, GetCurrentProcess(), &fh, GENERIC_READ, false, DUPLICATE_SAME_ACCESS )) { return false; } GetFileNameFromBase(idd->hProcess, idd->InProcImageBase, idd->ImageFilePath, sizeof(idd->ImageFilePath)); idd->ImageFileHandle = fh; idd->ImageSrc = srcHandle; if (ReadHeader(idd, dsImage)) return true; } // if we have a base pointer into process memory. See what we can get here. if (idd->InProcImageBase) { if (ReadHeader(idd, dsInProc)) { idd->ImageSrc = srcMemory; return true; } } return false; } __except (EXCEPTION_EXECUTE_HANDLER) { return false; } return true; } BOOL imgReadFromDisk( PIMGHLP_DEBUG_DATA idd ) /* Given: ImageFileHandle - Map the thing. The only time FileHandle s/b non-null is if we're given an image handle. If this is not true, ignore the handle. !ImageFileHandle - Use the filename and search for first the image name, then the .dbg file, and finally a .pdb file. dwFlags: NO_PE64_IMAGES - Return failure if only image is PE64. Used to implement MapDebugInformation() */ { int len; // If the file name is a pdb, let's just store it and move on. if (IsPdb(idd->ImageFilePath)) { CopyStrArray(idd->PdbFileName, idd->ImageFilePath); return true; } // Let's look for the image on disk. if (!option(SYMOPT_NO_IMAGE_SEARCH)) { // otherwise use the file name to open the disk image // only if we didn't have access to in-proc headers pprint(idd->pe, "No header for %s. Searching for image on disk\n", idd->ImageName); idd->ImageFileHandle = FindExecutableImageEx(idd->ImageName, idd->SymbolPath, idd->ImageFilePath, cbFindExe, idd); if (idd->ImageFileHandle) { if (!idd->SizeOfImage) GetFileSize(idd->ImageFileHandle, &idd->SizeOfImage); ReadHeader(idd, dsImage); } } return true; } BOOL NoSymbols( PIMGHLP_DEBUG_DATA idd ) { return (!*idd->PdbFileName && !idd->pMappedCoff && !idd->pMappedCv); } BOOL GetDebugData( PIMGHLP_DEBUG_DATA idd ) { char dbgfile[MAX_PATH + 1]; BOOL rc; // If this is a virtual module, we are done. if (idd->ImageType == dsVirtual) return true; *dbgfile = 0; // Now we look for dbg files on all stripped images and unread headers. if (idd->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { if (*idd->OriginalDbgFileName) CopyStrArray(dbgfile, idd->OriginalDbgFileName); else CopyStrArray(dbgfile, idd->ImageName); pprint(idd->pe, "%s is stripped. Searching for dbg file\n", dbgfile); } else if (!option(SYMOPT_EXACT_SYMBOLS) || option(SYMOPT_LOAD_ANYTHING)) { if (NoSymbols(idd)) { CopyStrArray(dbgfile, idd->ImageName); if (!idd->Characteristics) pprint(idd->pe, "No header for %s. Searching for dbg file\n", dbgfile); else pprint(idd->pe, "No debug info for %s. Searching for dbg file\n", dbgfile); } } if (*dbgfile) { idd->DbgFileHandle = FindDebugInfoFileEx( dbgfile, idd->SymbolPath, idd->DbgFilePath, cbFindDbg, idd); if (!idd->DbgFileHandle) g.LastSymLoadError = SYMLOAD_DBGNOTFOUND; else ReadHeader(idd, dsDbg); } // We don't have an image, dbg, or pdb. Let's just look for any old PDB. if (NoSymbols(idd) && (!option(SYMOPT_EXACT_SYMBOLS) || option(SYMOPT_LOAD_ANYTHING))) { if (FakePdbName(idd)) pprint(idd->pe, "%s missing debug info. Searching for pdb anyway\n", idd->ImageName); } // Get codeview information, either from pdb or within the image. if (*idd->PdbFileName) { rc = diaGetPdb(idd); if (!rc && IsPdb(idd->ImageFilePath)) return false; } else if (idd->pMappedCv) ProcessCvForOmap(idd); return true; } PIMGHLP_DEBUG_DATA InitDebugData( VOID ) { PIMGHLP_DEBUG_DATA idd; idd = (PIMGHLP_DEBUG_DATA)MemAlloc(sizeof(IMGHLP_DEBUG_DATA)); if (!idd) { SetLastError(ERROR_OUTOFMEMORY); g.LastSymLoadError = SYMLOAD_OUTOFMEMORY; return NULL; } ZeroMemory(idd, sizeof(IMGHLP_DEBUG_DATA)); idd->md = (PMODULE_DATA)MemAlloc(sizeof(gmd)); if (!idd->md) { SetLastError(ERROR_OUTOFMEMORY); g.LastSymLoadError = SYMLOAD_OUTOFMEMORY; MemFree(idd); return NULL; } memcpy(idd->md, gmd, sizeof(gmd)); return idd; } void ReleaseDebugData( PIMGHLP_DEBUG_DATA idd, DWORD dwFlags ) { if (!idd) return; if (idd->ImageMap) { UnmapViewOfFile(idd->ImageMap); } if (idd->ImageFileHandle) { CloseHandle(idd->ImageFileHandle); } if (idd->DbgFileMap) { UnmapViewOfFile(idd->DbgFileMap); } if (idd->DbgFileHandle) { CloseHandle(idd->DbgFileHandle); } if ((dwFlags & IMGHLP_FREE_FPO) && idd->pFpo && !idd->fFpoMapped ) { MemFree(idd->pFpo); } if ((dwFlags & IMGHLP_FREE_PDATA) && idd->pPData && !idd->fPDataMapped ) { MemFree(idd->pPData); } if ((dwFlags & IMGHLP_FREE_XDATA) && idd->pXData && !idd->fXDataMapped ) { MemFree(idd->pXData); } if ((dwFlags & IMGHLP_FREE_PDATA) && idd->pMappedCoff && !idd->fCoffMapped ) { MemFree(idd->pMappedCoff); } if ((dwFlags & IMGHLP_FREE_PDATA) && idd->pMappedCv && !idd->fCvMapped ) { MemFree(idd->pMappedCv); } if ((dwFlags & IMGHLP_FREE_OMAPT) && idd->pOmapTo && !idd->fOmapToMapped) { MemFree(idd->pOmapTo); } if ((dwFlags & IMGHLP_FREE_OMAPF) && idd->pOmapFrom && !idd->fOmapFromMapped) { MemFree(idd->pOmapFrom); } if ((dwFlags & IMGHLP_FREE_OSECT) && idd->pOriginalSections ) { MemFree(idd->pOriginalSections); } if ((dwFlags & IMGHLP_FREE_CSECT) && idd->pCurrentSections && !idd->fCurrentSectionsMapped ) { MemFree(idd->pCurrentSections); } if (idd->SymbolPath) { MemFree(idd->SymbolPath); } MemFree(idd->md); MemFree(idd); return; } BOOL ExtMatch( char *fname, char *ext ) { char fext[_MAX_EXT + 1]; if (!fname) return false; _splitpath(fname, NULL, NULL, NULL, fext); if (_strcmpi(fext, ext)) return false; return true; } BOOL ReadHeader( PIMGHLP_DEBUG_DATA idd, DWORD datasrc ) { BOOL status; ULONG cb; IMAGE_DOS_HEADER dh; IMAGE_NT_HEADERS32 nh32; IMAGE_NT_HEADERS64 nh64; PIMAGE_ROM_OPTIONAL_HEADER rom = NULL; IMAGE_SEPARATE_DEBUG_HEADER sdh; PIMAGE_FILE_HEADER fh; PIMAGE_DEBUG_MISC md; ULONG ddva; ULONG shva; ULONG nSections; PIMAGE_SECTION_HEADER psh; IMAGE_DEBUG_DIRECTORY dd; PIMAGE_DATA_DIRECTORY datadir; PCHAR pCV; ULONG i; int nDebugDirs = 0; HANDLE hp; ULONG64 base; IMAGE_ROM_HEADERS ROMImage; DWORD rva; PCHAR filepath; IMAGE_EXPORT_DIRECTORY expdir; DWORD fsize; BOOL rc; USHORT filetype; #ifdef DO_NBO9 ULONG hdrsig; char cvsig[5]; char cvsig2[5]; long cvpos; #endif // setup pointers for grabing data switch (datasrc) { case dsInProc: hp = idd->hProcess; base = idd->InProcImageBase; fsize = 0; filepath = idd->ImageFilePath; idd->PdbSrc = srcCVRec; break; case dsImage: hp = NULL; idd->ImageMap = MapItRO(idd->ImageFileHandle); base = (ULONG64)idd->ImageMap; fsize = GetFileSize(idd->ImageFileHandle, NULL); filepath = idd->ImageFilePath; idd->PdbSrc = srcImagePath; break; case dsDbg: hp = NULL; idd->DbgFileMap = MapItRO(idd->DbgFileHandle); base = (ULONG64)idd->DbgFileMap; fsize = GetFileSize(idd->DbgFileHandle, NULL); filepath = idd->DbgFilePath; idd->PdbSrc = srcDbgPath; break; default: return false; } // some initialization idd->fNeedImage = false; rc = false; ddva = 0; __try { // test the file type status = ReadImageData(hp, base, 0, &filetype, sizeof(filetype)); if (!status) { g.LastSymLoadError = SYMLOAD_HEADERPAGEDOUT; return false; } idd->ImageType = datasrc; if (filetype == IMAGE_SEPARATE_DEBUG_SIGNATURE) goto dbg; if (filetype == IMAGE_DOS_SIGNATURE) { // grab the dos header status = ReadImageData(hp, base, 0, &dh, sizeof(dh)); if (!status) { g.LastSymLoadError = SYMLOAD_HEADERPAGEDOUT; return false; } #ifdef DO_NB09 // test 16 bit image... if (idd->SizeOfImage) { ZeroMemory(cvsig, 5); ZeroMemory(cvsig2, 5); cvpos = 0; status = ReadImageData(hp, base, idd->SizeOfImage - 8, cvsig, 4); status = ReadImageData(hp, base, idd->SizeOfImage - 4, &cvpos, sizeof(cvpos)); status = ReadImageData(hp, base, idd->SizeOfImage - cvpos, cvsig2, 4); if (*cvsig && !strcmp(cvsig, cvsig2)) { pCV = (PCHAR)MemAlloc(cvpos); if (!pCV) return false; status = ReadImageData(hp, base, idd->SizeOfImage - cvpos, pCV, cvpos); idd->pMappedCv = (PCHAR)pCV; idd->cMappedCv = cvpos; return true; } } #endif // grab the pe header #ifdef DO_NB09 status = ReadImageData(hp, base, dh.e_lfanew, &hdrsig, sizeof(hdrsig)); if (!status) { g.LastSymLoadError = SYMLOAD_HEADERPAGEDOUT; return false; } #endif status = ReadImageData(hp, base, dh.e_lfanew, &nh32, sizeof(nh32)); if (!status) { g.LastSymLoadError = SYMLOAD_HEADERPAGEDOUT; return false; } // read header info if (nh32.Signature != IMAGE_NT_SIGNATURE) { // if header is not NT sig, this is a ROM image rom = (PIMAGE_ROM_OPTIONAL_HEADER)&nh32.OptionalHeader; fh = &nh32.FileHeader; shva = dh.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + fh->SizeOfOptionalHeader; } } else if (filetype == IMAGE_FILE_MACHINE_I386) { // This is an X86 ROM image status = ReadImageData(hp, base, 0, &nh32.FileHeader, sizeof(nh32.FileHeader)+sizeof(nh32.OptionalHeader)); if (!status) return false; nh32.Signature = 'ROM '; } else { // This may be a ROM image status = ReadImageData(hp, base, 0, &ROMImage, sizeof(ROMImage)); if (!status) { g.LastSymLoadError = SYMLOAD_HEADERPAGEDOUT; return false; } if ((ROMImage.FileHeader.Machine == IMAGE_FILE_MACHINE_I386) || (ROMImage.FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA) || (ROMImage.FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA64)) { rom = (PIMAGE_ROM_OPTIONAL_HEADER)&ROMImage.OptionalHeader; fh = &ROMImage.FileHeader; shva = sizeof(IMAGE_FILE_HEADER) + fh->SizeOfOptionalHeader; } else { return false; } } if (rom) { if (rom->Magic == IMAGE_ROM_OPTIONAL_HDR_MAGIC) { idd->fROM = true; idd->iohMagic = rom->Magic; idd->ImageBaseFromImage = rom->BaseOfCode; idd->SizeOfImage = rom->SizeOfCode; idd->CheckSum = 0; } else { idd->error = ERROR_BAD_FORMAT; return false; } } else { // otherwise, get info from appropriate header type for 32 or 64 bit if (IsImageMachineType64(nh32.FileHeader.Machine)) { // Reread the header as a 64bit header. status = ReadImageData(hp, base, dh.e_lfanew, &nh64, sizeof(nh64)); if (!status) { g.LastSymLoadError = SYMLOAD_HEADERPAGEDOUT; return false; } fh = &nh64.FileHeader; datadir = nh64.OptionalHeader.DataDirectory; shva = dh.e_lfanew + sizeof(nh64); idd->iohMagic = nh64.OptionalHeader.Magic; idd->fPE64 = true; // seems to be unused if (datasrc == dsImage || datasrc == dsInProc) { idd->ImageBaseFromImage = nh64.OptionalHeader.ImageBase; idd->ImageAlign = nh64.OptionalHeader.SectionAlignment; idd->CheckSum = nh64.OptionalHeader.CheckSum; } idd->SizeOfImage = nh64.OptionalHeader.SizeOfImage; } else { fh = &nh32.FileHeader; datadir = nh32.OptionalHeader.DataDirectory; idd->iohMagic = nh32.OptionalHeader.Magic; if (nh32.Signature == 'ROM ') { shva = sizeof(nh32.FileHeader)+sizeof(nh32.OptionalHeader); } else { shva = dh.e_lfanew + sizeof(nh32); } if (datasrc == dsImage || datasrc == dsInProc) { idd->ImageBaseFromImage = nh32.OptionalHeader.ImageBase; idd->ImageAlign = nh32.OptionalHeader.SectionAlignment; idd->CheckSum = nh32.OptionalHeader.CheckSum; } idd->SizeOfImage = nh32.OptionalHeader.SizeOfImage; } } imgset(idd->md, mdHeader, datasrc, datasrc); // read the section headers nSections = fh->NumberOfSections; psh = (PIMAGE_SECTION_HEADER) MemAlloc(nSections * sizeof(IMAGE_SECTION_HEADER)); if (!psh) goto debugdirs; status = ReadImageData(hp, base, shva, psh, nSections * sizeof(IMAGE_SECTION_HEADER)); if (!status) goto debugdirs; // store off info to return struct idd->pCurrentSections = psh; idd->cCurrentSections = nSections; idd->pImageSections = psh; idd->cImageSections = nSections; idd->Machine = fh->Machine; idd->TimeDateStamp = fh->TimeDateStamp; idd->Characteristics = fh->Characteristics; imgset(idd->md, mdSecHdrs, datasrc, datasrc); // get information from the sections for (i = 0; i < nSections; i++, psh++) { DWORD offset; if (idd->fROM && ((fh->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) == 0) && (!strcmp((LPSTR)psh->Name, ".rdata"))) { nDebugDirs = 1; ddva = psh->VirtualAddress; break; } if (offset = SectionContains(hp, psh, &datadir[IMAGE_DIRECTORY_ENTRY_EXPORT])) { idd->dsExports = datasrc; idd->cExports = datadir[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; idd->oExports = offset; ReadImageData(hp, base, offset, &idd->expdir, sizeof(idd->expdir)); } if (offset = SectionContains(hp, psh, &datadir[IMAGE_DIRECTORY_ENTRY_DEBUG])) { ddva = offset; nDebugDirs = datadir[IMAGE_DIRECTORY_ENTRY_DEBUG].Size / sizeof(IMAGE_DEBUG_DIRECTORY); } } goto debugdirs; dbg: // grab the dbg header status = ReadImageData(hp, base, 0, &sdh, sizeof(sdh)); if (!status) return false; // Only support .dbg files for X86 and Alpha (32 bit). if ((sdh.Machine != IMAGE_FILE_MACHINE_I386) && (sdh.Machine != IMAGE_FILE_MACHINE_ALPHA)) { UnmapViewOfFile(idd->DbgFileMap); idd->DbgFileMap = 0; return false; } idd->ImageAlign = sdh.SectionAlignment; idd->CheckSum = sdh.CheckSum; idd->Machine = sdh.Machine; idd->TimeDateStamp = sdh.TimeDateStamp; idd->Characteristics = sdh.Characteristics; if (!idd->ImageBaseFromImage) { idd->ImageBaseFromImage = sdh.ImageBase; } if (!idd->SizeOfImage) { idd->SizeOfImage = sdh.SizeOfImage; } nSections = sdh.NumberOfSections; psh = (PIMAGE_SECTION_HEADER) MemAlloc(nSections * sizeof(IMAGE_SECTION_HEADER)); if (!psh) goto debugdirs; status = ReadImageData(hp, base, sizeof(IMAGE_SEPARATE_DEBUG_HEADER), psh, nSections * sizeof(IMAGE_SECTION_HEADER)); if (!status) goto debugdirs; idd->pCurrentSections = psh; idd->cCurrentSections = nSections; idd->pDbgSections = psh; idd->cDbgSections = nSections; // idd->ExportedNamesSize = sdh.ExportedNamesSize; if (sdh.DebugDirectorySize) { nDebugDirs = (int)(sdh.DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)); ddva = sizeof(IMAGE_SEPARATE_DEBUG_HEADER) + (sdh.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)) + sdh.ExportedNamesSize; } debugdirs: rc = true; // copy the virtual addr of the debug directories over for MapDebugInformation if (datasrc == dsImage) { idd->ddva = ddva; idd->cdd = nDebugDirs; } // read the debug directories while (nDebugDirs) { status = ReadImageData(hp, base, (ULONG_PTR)ddva, &dd, sizeof(dd)); if (!status) return false; if (!dd.SizeOfData) goto nextdebugdir; // indicate that we found the debug directory imgset(idd->md, dd.Type, datasrc, dsNone); // these debug directories are processed both in-proc and from file switch (dd.Type) { case IMAGE_DEBUG_TYPE_CODEVIEW: // get info on pdb file if (hp) { // in-proc image if (!dd.AddressOfRawData) return false; if (!(pCV = (PCHAR)MemAlloc(dd.SizeOfData))) break; status = ReadImageData(hp, base, dd.AddressOfRawData, pCV, dd.SizeOfData); if (!status) { MemFree(pCV); return false; } } else { // file-base image if (dd.PointerToRawData >= fsize) break; pCV = (PCHAR)base + dd.PointerToRawData; idd->fCvMapped = true; } idd->pMappedCv = (PCHAR)pCV; idd->cMappedCv = dd.SizeOfData; idd->dsCV = datasrc; RetrievePdbInfo(idd); imgset(idd->md, dd.Type, dsNone, datasrc); break; case IMAGE_DEBUG_TYPE_MISC: // on stripped files, find the dbg file // on dbg file, find the original file name if (dd.PointerToRawData < fsize) { md = (PIMAGE_DEBUG_MISC)((PCHAR)base + dd.PointerToRawData); if (md->DataType != IMAGE_DEBUG_MISC_EXENAME) break; if (datasrc == dsDbg) { if (!*idd->OriginalImageFileName) CopyStrArray(idd->OriginalImageFileName, (LPSTR)md->Data); break; } if (fh->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { CopyStrArray(idd->OriginalDbgFileName, (LPSTR)md->Data); idd->DbgTimeDateStamp = dd.TimeDateStamp; } else { CopyStrArray(idd->OriginalImageFileName, (LPSTR)md->Data); } } imgset(idd->md, dd.Type, dsNone, datasrc); break; case IMAGE_DEBUG_TYPE_COFF: if (dd.PointerToRawData < fsize) { // idd->fNeedImage = true; idd->pMappedCoff = (PCHAR)base + dd.PointerToRawData; idd->cMappedCoff = dd.SizeOfData; idd->fCoffMapped = true; idd->dsCoff = datasrc; imgset(idd->md, dd.Type, dsNone, datasrc); } else { idd->fNeedImage = true; } break; } // these debug directories are only processed for disk-based images if (dd.PointerToRawData < fsize) { switch (dd.Type) { case IMAGE_DEBUG_TYPE_FPO: idd->pFpo = (PCHAR)base + dd.PointerToRawData; idd->cFpo = dd.SizeOfData / SIZEOF_RFPO_DATA; idd->fFpoMapped = true; idd->dsFPO = datasrc; imgset(idd->md, dd.Type, dsNone, datasrc); break; case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: idd->pOmapTo = (POMAP)((PCHAR)base + dd.PointerToRawData); idd->cOmapTo = dd.SizeOfData / sizeof(OMAP); idd->fOmapToMapped = true; idd->dsOmapTo = datasrc; imgset(idd->md, dd.Type, dsNone, datasrc); break; case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: idd->pOmapFrom = (POMAP)((PCHAR)base + dd.PointerToRawData); idd->cOmapFrom = dd.SizeOfData / sizeof(OMAP); idd->fOmapFromMapped = true; idd->dsOmapFrom = datasrc; imgset(idd->md, dd.Type, dsNone, datasrc); break; case IMAGE_DEBUG_TYPE_EXCEPTION: idd->dsExceptions = datasrc; imgset(idd->md, dd.Type, dsNone, datasrc); break; } } nextdebugdir: ddva += sizeof(IMAGE_DEBUG_DIRECTORY); nDebugDirs--; } } __except (EXCEPTION_EXECUTE_HANDLER) { // We might have gotten enough information // to be okay. So don't indicate error. } return rc; } BOOL ReadCallerData( PIMGHLP_DEBUG_DATA idd ) { PMODLOAD_DATA mld = idd->mld; PIMAGE_DEBUG_DIRECTORY dd; PCHAR pCV; DWORD cdd; DWORD i; if (!mld) return false; if (!mld->ssize || !mld->size || !mld->data) return false; switch (mld->ssig) { case DBHHEADER_DEBUGDIRS: cdd = mld->size / sizeof(IMAGE_DEBUG_DIRECTORY); dd = (PIMAGE_DEBUG_DIRECTORY)mld->data; for (i = 0; i < cdd; i++, dd++) { if (dd->Type != IMAGE_DEBUG_TYPE_CODEVIEW) continue; pCV = (PCHAR)mld->data + dd->PointerToRawData; idd->fCvMapped = true; idd->pMappedCv = (PCHAR)pCV; idd->cMappedCv = dd->SizeOfData; idd->dsCV = dsCallerData; idd->PdbSignature = 0; idd->PdbAge = 0; RetrievePdbInfo(idd); imgset(idd->md, dd->Type, dsNone, dsCallerData); break; } return true; } return false; } BOOL cbFindExe( HANDLE FileHandle, PSTR FileName, PVOID CallerData ) { PIMGHLP_DEBUG_DATA idd; PIMAGE_FILE_HEADER FileHeader = NULL; PVOID ImageMap = NULL; BOOL rc; if (!CallerData) return true; idd = (PIMGHLP_DEBUG_DATA)CallerData; if (!idd->TimeDateStamp) return true; // Crack the image and let's see what we're working with ImageMap = MapItRO(FileHandle); if (!ImageMap) return true; // Check the first word. We're either looking at a normal PE32/PE64 image, or it's // a ROM image (no DOS stub) or it's a random file. switch (*(PUSHORT)ImageMap) { case IMAGE_FILE_MACHINE_I386: // Must be an X86 ROM image (ie: ntldr) FileHeader = &((PIMAGE_ROM_HEADERS)ImageMap)->FileHeader; // Make sure if (!(FileHeader->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) && idd->iohMagic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) { FileHeader = NULL; } break; case IMAGE_FILE_MACHINE_ALPHA: case IMAGE_FILE_MACHINE_ALPHA64: case IMAGE_FILE_MACHINE_IA64: case IMAGE_FILE_MACHINE_AMD64: // Should be an Alpha/IA64 ROM image (ie: osloader.exe) FileHeader = &((PIMAGE_ROM_HEADERS)ImageMap)->FileHeader; // Make sure if (!(FileHeader->SizeOfOptionalHeader == sizeof(IMAGE_ROM_OPTIONAL_HEADER) && idd->iohMagic == IMAGE_ROM_OPTIONAL_HDR_MAGIC)) { FileHeader = NULL; } break; case IMAGE_DOS_SIGNATURE: { PIMAGE_NT_HEADERS NtHeaders = ImageNtHeader(ImageMap); if (NtHeaders) { FileHeader = &NtHeaders->FileHeader; } } break; default: break; } // default return is a match rc = true; // compare timestamps if (FileHeader && FileHeader->TimeDateStamp != idd->TimeDateStamp) rc = false; idd->ImageSrc = srcSearchPath; // cleanup if (ImageMap) UnmapViewOfFile(ImageMap); return rc; } BOOL cbFindDbg( HANDLE FileHandle, PSTR FileName, PVOID CallerData ) { PIMGHLP_DEBUG_DATA idd; PIMAGE_SEPARATE_DEBUG_HEADER DbgHeader; PVOID FileMap; BOOL rc; rc = true; if (!CallerData) return true; idd = (PIMGHLP_DEBUG_DATA)CallerData; FileMap = MapItRO(FileHandle); if (!FileMap) { return false; } DbgHeader = (PIMAGE_SEPARATE_DEBUG_HEADER)FileMap; // Only support .dbg files for X86 and Alpha (32 bit). if ((DbgHeader->Signature != IMAGE_SEPARATE_DEBUG_SIGNATURE) || ((DbgHeader->Machine != IMAGE_FILE_MACHINE_I386) && (DbgHeader->Machine != IMAGE_FILE_MACHINE_ALPHA))) { rc = false; goto cleanup; } if (idd->DbgTimeDateStamp) rc = (idd->DbgTimeDateStamp == DbgHeader->TimeDateStamp) ? true : false; if (!rc && idd->TimeDateStamp) rc = (idd->TimeDateStamp == DbgHeader->TimeDateStamp) ? true : false; cleanup: if (FileMap) UnmapViewOfFile(FileMap); return rc; } BOOL ProcessCvForOmap( PIMGHLP_DEBUG_DATA idd ) { OMFSignature *omfSig; OMFDirHeader *omfDirHdr; OMFDirEntry *omfDirEntry; OMFSegMap *omfSegMap; OMFSegMapDesc *omfSegMapDesc; DWORD i, j, k, SectionSize; DWORD SectionStart; PIMAGE_SECTION_HEADER Section; if (idd->cOmapFrom) { // If there's omap, we need to generate the original section map omfSig = (OMFSignature *)idd->pMappedCv; omfDirHdr = (OMFDirHeader*) ((PCHAR)idd->pMappedCv + (DWORD)omfSig->filepos); omfDirEntry = (OMFDirEntry*) ((PCHAR)omfDirHdr + sizeof(OMFDirHeader)); if (!omfDirHdr->cDir) { idd->cOmapFrom = 0; idd->cOmapTo = 0; } for (i=0; icDir; i++,omfDirEntry++) { if (omfDirEntry->SubSection == sstSegMap) { omfSegMap = (OMFSegMap*) ((PCHAR)idd->pMappedCv + omfDirEntry->lfo); omfSegMapDesc = (OMFSegMapDesc*)&omfSegMap->rgDesc[0]; SectionStart = *(DWORD *)idd->pOmapFrom; SectionSize = 0; Section = (PIMAGE_SECTION_HEADER) MemAlloc(omfSegMap->cSeg * sizeof(IMAGE_SECTION_HEADER)); if (Section) { for (j=0, k=0; j < omfSegMap->cSeg; j++) { if (omfSegMapDesc[j].frame) { // The linker sets the frame field to the actual section header number. Zero is // used to track absolute symbols that don't exist in a real sections. Section[k].VirtualAddress = SectionStart = SectionStart + ((SectionSize + (idd->ImageAlign-1)) & ~(idd->ImageAlign-1)); Section[k].Misc.VirtualSize = SectionSize = omfSegMapDesc[j].cbSeg; k++; } } idd->pOriginalSections = Section; idd->cOriginalSections = k; } } } } return true; } __inline DWORD SectionContains ( HANDLE hp, PIMAGE_SECTION_HEADER pSH, PIMAGE_DATA_DIRECTORY ddir ) { DWORD rva = 0; if (!ddir->VirtualAddress) return 0; if (ddir->VirtualAddress >= pSH->VirtualAddress) { if ((ddir->VirtualAddress + ddir->Size) <= (pSH->VirtualAddress + pSH->SizeOfRawData)) { rva = ddir->VirtualAddress; if (!hp) rva = rva - pSH->VirtualAddress + pSH->PointerToRawData; } } return rva; } void RetrievePdbInfo( PIMGHLP_DEBUG_DATA idd ) { CHAR szRefDrive[_MAX_DRIVE]; CHAR szRefPath[_MAX_DIR]; PCVDD pcv = (PCVDD)idd->pMappedCv; if (idd->PdbSignature) return; switch (pcv->dwSig) { case '01BN': idd->PdbAge = pcv->nb10i.age; idd->PdbSignature = pcv->nb10i.sig; CopyStrArray(idd->PdbFileName, pcv->nb10i.szPdb); break; case 'SDSR': idd->PdbRSDS = true; idd->PdbAge = pcv->rsdsi.age; memcpy(&idd->PdbGUID, &pcv->rsdsi.guidSig, sizeof(GUID)); CopyStrArray(idd->PdbFileName, pcv->rsdsi.szPdb); break; default: return; } // XXX: get rid of this variable CopyStrArray(idd->PdbReferencePath, ""); } DWORD imgset( PMODULE_DATA md, DWORD id, DWORD hint, DWORD src ) { DWORD i; for (i = 0; i < NUM_MODULE_DATA_ENTRIES; md++, i++) { if (md->id == id) { if (hint != dsNone) md->hint = hint; if (src != dsNone) md->src = src; return i; } } return 0; } BOOL FakePdbName( PIMGHLP_DEBUG_DATA idd ) { CHAR szName[_MAX_FNAME]; // nothing to do if (*idd->PdbFileName) return false; if (idd->PdbSignature) return false; // nothing to work with if (!idd->ImageName) return false; // generate pdb name from image _splitpath(idd->ImageName, NULL, NULL, szName, NULL); if (!*szName) return false; CopyStrArray(idd->PdbFileName, szName); CatStrArray(idd->PdbFileName, ".pdb"); return true; } BOOL IsImageMachineType64( DWORD MachineType ) { switch(MachineType) { case IMAGE_FILE_MACHINE_AXP64: case IMAGE_FILE_MACHINE_IA64: case IMAGE_FILE_MACHINE_AMD64: return true; default: return false; } } ULONG ReadImageData( IN HANDLE hprocess, IN ULONG64 ul, IN ULONG64 addr, OUT LPVOID buffer, IN ULONG size ) { ULONG bytesread; if (hprocess) { ULONG64 base = ul; BOOL rc; rc = ReadInProcMemory(hprocess, base + addr, buffer, size, &bytesread); if (!rc || (bytesread < (ULONG)size)) return 0; } else { PCHAR p = (PCHAR)ul + addr; memcpy(buffer, p, size); } return size; } PVOID MapItRO( HANDLE FileHandle ) { PVOID MappedBase = NULL; if (FileHandle) { HANDLE MappingHandle = CreateFileMapping( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); if (MappingHandle) { MappedBase = MapViewOfFile( MappingHandle, FILE_MAP_READ, 0, 0, 0 ); CloseHandle(MappingHandle); } } return MappedBase; }