You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2231 lines
61 KiB
2231 lines
61 KiB
/*
|
|
* symmod.c
|
|
*/
|
|
|
|
#include <private.h>
|
|
#include <symbols.h>
|
|
#include <globals.h>
|
|
#include <psapi.h>
|
|
|
|
// 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; i<omfDirHdr->cDir; 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;
|
|
}
|