1878 lines
53 KiB
C
1878 lines
53 KiB
C
#include <private.h>
|
|
#include <symbols.h>
|
|
#include "globals.h"
|
|
|
|
// forward reference
|
|
|
|
void
|
|
RetrievePdbInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD,
|
|
CHAR const *szReference
|
|
);
|
|
|
|
BOOL
|
|
FindDebugInfoFileExCallback(
|
|
HANDLE FileHandle,
|
|
PSTR FileName,
|
|
PVOID CallerData
|
|
);
|
|
|
|
BOOL
|
|
FindExecutableImageExCallback(
|
|
HANDLE FileHandle,
|
|
PSTR FileName,
|
|
PVOID CallerData
|
|
);
|
|
|
|
BOOL
|
|
ProcessDebugInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD,
|
|
DWORD datasrc
|
|
);
|
|
|
|
__inline
|
|
BOOL
|
|
ProcessImageDebugInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
return ProcessDebugInfo(pIDD, dsImage);
|
|
}
|
|
|
|
|
|
__inline
|
|
BOOL
|
|
ProcessInProcDebugInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
return ProcessDebugInfo(pIDD, dsInProc);
|
|
}
|
|
|
|
|
|
__inline
|
|
BOOL
|
|
ProcessDbgDebugInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
return ProcessDebugInfo(pIDD, dsDbg);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ProcessCallerDataDebugInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
PMODLOAD_DATA mld = pIDD->mld;
|
|
PIMAGE_DEBUG_DIRECTORY dd;
|
|
PCHAR pCV;
|
|
DWORD cdd;
|
|
DWORD i;
|
|
|
|
if (!mld)
|
|
return FALSE;
|
|
|
|
if (!mld->ssize
|
|
|| !mld->size
|
|
|| !mld->data)
|
|
return FALSE;
|
|
|
|
if (mld->ssig != DBHHEADER_DEBUGDIRS)
|
|
return FALSE;
|
|
|
|
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;
|
|
pIDD->fCvMapped = TRUE;
|
|
pIDD->pMappedCv = (PCHAR)pCV;
|
|
pIDD->cMappedCv = dd->SizeOfData;
|
|
pIDD->dsCV = dsCallerData;
|
|
pIDD->PdbSignature = 0;
|
|
pIDD->PdbAge = 0;
|
|
RetrievePdbInfo(pIDD, pIDD->ImageFilePath);
|
|
mdSet(pIDD->md, dd->Type, dsNone, dsCallerData);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// functions called by the MODULE_DATA array...
|
|
|
|
BOOL
|
|
mdfnOpenDbgFile(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
dprint("mdfnOpenDbgFile()\n");
|
|
|
|
if (pIDD->DbgFileHandle)
|
|
return TRUE;
|
|
|
|
if (*pIDD->OriginalDbgFileName) {
|
|
pIDD->DbgFileHandle = fnFindDebugInfoFileEx(
|
|
pIDD->OriginalDbgFileName,
|
|
pIDD->SymbolPath,
|
|
pIDD->DbgFilePath,
|
|
FindDebugInfoFileExCallback,
|
|
pIDD,
|
|
fdifRECURSIVE);
|
|
}
|
|
if (!pIDD->DbgFileHandle) {
|
|
pIDD->DbgFileHandle = fnFindDebugInfoFileEx(
|
|
pIDD->ImageName,
|
|
pIDD->SymbolPath,
|
|
pIDD->DbgFilePath,
|
|
FindDebugInfoFileExCallback,
|
|
pIDD,
|
|
fdifRECURSIVE);
|
|
}
|
|
if (!pIDD->DbgFileHandle)
|
|
g.LastSymLoadError = SYMLOAD_DBGNOTFOUND;
|
|
|
|
// if we have a .dbg file. See what we can get from it.
|
|
if (pIDD->DbgFileHandle) {
|
|
ProcessDbgDebugInfo(pIDD);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
mdfnGetExecutableImage(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
dprint("mdfnGetExecutableImage()\n");
|
|
|
|
if (!*pIDD->ImageName)
|
|
return TRUE;
|
|
|
|
if (!pIDD->ImageFileHandle)
|
|
pIDD->ImageFileHandle = FindExecutableImageEx(pIDD->ImageName,
|
|
pIDD->SymbolPath,
|
|
pIDD->ImageFilePath,
|
|
FindExecutableImageExCallback,
|
|
pIDD);
|
|
|
|
if (pIDD->ImageFileHandle)
|
|
ProcessImageDebugInfo(pIDD);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// 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, 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}
|
|
};
|
|
|
|
DWORD
|
|
mdSet(
|
|
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;
|
|
}
|
|
|
|
void
|
|
mdDump(
|
|
PMODULE_DATA md,
|
|
BOOL verbose
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
static PCHAR idstr[] =
|
|
{
|
|
"mdHeader",
|
|
"mdSecHdrs",
|
|
"IMAGE_DEBUG_TYPE_UNKNOWN",
|
|
"IMAGE_DEBUG_TYPE_COFF",
|
|
"IMAGE_DEBUG_TYPE_CODEVIEW",
|
|
"IMAGE_DEBUG_TYPE_FPO",
|
|
"IMAGE_DEBUG_TYPE_MISC",
|
|
"IMAGE_DEBUG_TYPE_EXCEPTION",
|
|
"IMAGE_DEBUG_TYPE_FIXUP",
|
|
"IMAGE_DEBUG_TYPE_OMAP_TO_SRC",
|
|
"IMAGE_DEBUG_TYPE_OMAP_FROM_SRC",
|
|
"IMAGE_DEBUG_TYPE_BORLAND",
|
|
"IMAGE_DEBUG_TYPE_RESERVED10",
|
|
"IMAGE_DEBUG_TYPE_CLSID"
|
|
};
|
|
|
|
static PCHAR dsstr[] =
|
|
{
|
|
"dsNone",
|
|
"dsInProc",
|
|
"dsImage",
|
|
"dsDbg",
|
|
"dsPdb",
|
|
"dsDia"
|
|
};
|
|
|
|
for (i = 0; i < NUM_MODULE_DATA_ENTRIES; md++, i++) {
|
|
if (verbose | md->hint | md->src) {
|
|
dprint("MD:%30s hint=%s src=%s\n",
|
|
idstr[i],
|
|
dsstr[md->hint],
|
|
dsstr[md->src]);
|
|
}
|
|
}
|
|
dprint("\n");
|
|
}
|
|
|
|
BOOL
|
|
GetUnfoundData(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
DWORD i;
|
|
PMODULE_DATA md;
|
|
|
|
for (md = pIDD->md, i = 0; i < NUM_MODULE_DATA_ENTRIES; md++, i++) {
|
|
if (!md->required)
|
|
continue;
|
|
if (md->hint == dsNone)
|
|
continue;
|
|
if (md->src != dsNone)
|
|
continue;
|
|
if (!md->fn)
|
|
continue;
|
|
if (!md->fn(pIDD))
|
|
return FALSE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
void
|
|
CloseSymbolServer(
|
|
VOID
|
|
)
|
|
{
|
|
if (!g.hSrv)
|
|
return;
|
|
|
|
if (g.fnSymbolServerClose)
|
|
g.fnSymbolServerClose();
|
|
|
|
FreeLibrary(g.hSrv);
|
|
|
|
g.hSrv = 0;
|
|
*g.szSrvName = 0;
|
|
g.szSrvParams = NULL;
|
|
g.fnSymbolServer = NULL;
|
|
g.fnSymbolServerClose = NULL;
|
|
g.fnSymbolServerSetOptions = NULL;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ProcessSymbolServerError(
|
|
BOOL success,
|
|
LPCSTR params
|
|
)
|
|
{
|
|
DWORD rc;
|
|
|
|
if (success)
|
|
return NO_ERROR;
|
|
|
|
rc = GetLastError();
|
|
switch(rc)
|
|
{
|
|
case ERROR_FILE_NOT_FOUND: // obvious
|
|
case ERROR_MORE_DATA: // didn't pass any tokens
|
|
break;
|
|
case ERROR_INVALID_NAME:
|
|
CloseSymbolServer();
|
|
g.hSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
|
|
evtprint(NULL, sevProblem, ERROR_INVALID_NAME, NULL, "SYMSRV: %s needs a downstream store.\n", params);
|
|
break;
|
|
case ERROR_FILE_INVALID:
|
|
evtprint(NULL, sevProblem, ERROR_FILE_INVALID, NULL, "SYMSRV: Compressed file needs a downstream store.\n");
|
|
break;
|
|
default:
|
|
dprint("symsrv error 0x%x\n", rc);
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetFileFromSymbolServer(
|
|
IN LPCSTR ServerInfo,
|
|
IN LPCSTR FileName,
|
|
IN GUID *guid,
|
|
IN DWORD two,
|
|
IN DWORD three,
|
|
OUT LPSTR FilePath
|
|
)
|
|
{
|
|
BOOL rc;
|
|
CHAR *params;
|
|
LPCSTR fname;
|
|
|
|
// strip any path information from the filename
|
|
|
|
for (fname = FileName + strlen(FileName); fname > FileName; fname--) {
|
|
if (*fname == '\\') {
|
|
fname++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// initialize server, if needed
|
|
|
|
if (g.hSrv == (HINSTANCE)INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
if (!g.hSrv) {
|
|
g.hSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
|
|
strcpy(g.szSrvName, &ServerInfo[7]);
|
|
if (!*g.szSrvName)
|
|
return FALSE;
|
|
g.szSrvParams = strchr(g.szSrvName, '*');
|
|
if (!g.szSrvParams )
|
|
return FALSE;
|
|
*g.szSrvParams++ = '\0';
|
|
g.hSrv = LoadLibrary(g.szSrvName);
|
|
if (g.hSrv) {
|
|
g.fnSymbolServer = (PSYMBOLSERVERPROC)GetProcAddress(g.hSrv, "SymbolServer");
|
|
if (!g.fnSymbolServer) {
|
|
FreeLibrary(g.hSrv);
|
|
g.hSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
|
|
}
|
|
g.fnSymbolServerClose = (PSYMBOLSERVERCLOSEPROC)GetProcAddress(g.hSrv, "SymbolServerClose");
|
|
g.fnSymbolServerSetOptions = (PSYMBOLSERVERSETOPTIONSPROC)GetProcAddress(g.hSrv, "SymbolServerSetOptions");
|
|
SetSymbolServerOptions(SSRVOPT_RESET, 0);
|
|
SetSymbolServerOptions(SSRVOPT_GUIDPTR, 1);
|
|
} else {
|
|
g.hSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
// bail, if we have no valid server
|
|
|
|
if (g.hSrv == INVALID_HANDLE_VALUE) {
|
|
dprint("SymSrv load failure: %s\n", g.szSrvName);
|
|
return FALSE;
|
|
}
|
|
|
|
params = strchr(ServerInfo, '*');
|
|
if (!params)
|
|
return FALSE;
|
|
params = strchr(params+1, '*');
|
|
if (!params)
|
|
return FALSE;
|
|
SetCriticalErrorMode();
|
|
rc = g.fnSymbolServer(params+1, fname, guid, two, three, FilePath);
|
|
#ifdef GETRIDOFTHISASAP
|
|
if (!rc) {
|
|
SetSymbolServerOptions(SSRVOPT_RESET, 0);
|
|
SetSymbolServerOptions(SSRVOPT_OLDGUIDPTR, 1);
|
|
rc = g.fnSymbolServer(params+1, fname, guid, two, three, FilePath);
|
|
SetSymbolServerOptions(SSRVOPT_RESET, 0);
|
|
SetSymbolServerOptions(SSRVOPT_GUIDPTR, 1);
|
|
}
|
|
#endif
|
|
ResetCriticalErrorMode();
|
|
ProcessSymbolServerError(rc, params+1);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SymbolServerCallback(
|
|
UINT_PTR action,
|
|
ULONG64 data,
|
|
ULONG64 context
|
|
)
|
|
{
|
|
BOOL rc = TRUE;
|
|
char *sz;
|
|
|
|
switch (action) {
|
|
|
|
case SSRVACTION_TRACE:
|
|
sz = (char *)data;
|
|
eprint((char *)data);
|
|
break;
|
|
|
|
default:
|
|
// unsupported
|
|
rc = FALSE;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
void
|
|
SetSymbolServerOptions(
|
|
ULONG_PTR options,
|
|
ULONG64 data
|
|
)
|
|
{
|
|
static ULONG_PTR ssopts = 0;
|
|
static ULONG64 ssdata = 0;
|
|
|
|
if (options != SSRVOPT_RESET) {
|
|
ssopts = options;
|
|
ssdata = data;
|
|
}
|
|
|
|
if (g.fnSymbolServerSetOptions)
|
|
g.fnSymbolServerSetOptions(ssopts, ssdata);
|
|
}
|
|
|
|
|
|
void
|
|
SetSymbolServerCallback(
|
|
BOOL state
|
|
)
|
|
{
|
|
if (state)
|
|
SetSymbolServerOptions(SSRVOPT_CALLBACK, (ULONG64)SymbolServerCallback);
|
|
else
|
|
SetSymbolServerOptions(0, 0);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ProcessOldStyleCodeView(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
OMFSignature *omfSig;
|
|
OMFDirHeader *omfDirHdr;
|
|
OMFDirEntry *omfDirEntry;
|
|
OMFSegMap *omfSegMap;
|
|
OMFSegMapDesc *omfSegMapDesc;
|
|
DWORD i, j, k, SectionSize;
|
|
DWORD SectionStart;
|
|
PIMAGE_SECTION_HEADER Section;
|
|
|
|
if (pIDD->cOmapFrom) {
|
|
// If there's omap, we need to generate the original section map
|
|
|
|
omfSig = (OMFSignature *)pIDD->pMappedCv;
|
|
omfDirHdr = (OMFDirHeader*) ((PCHAR)pIDD->pMappedCv + (DWORD)omfSig->filepos);
|
|
omfDirEntry = (OMFDirEntry*) ((PCHAR)omfDirHdr + sizeof(OMFDirHeader));
|
|
|
|
if (!omfDirHdr->cDir) {
|
|
pIDD->cOmapFrom = 0;
|
|
pIDD->cOmapTo = 0;
|
|
}
|
|
|
|
for (i=0; i<omfDirHdr->cDir; i++,omfDirEntry++) {
|
|
if (omfDirEntry->SubSection == sstSegMap) {
|
|
|
|
omfSegMap = (OMFSegMap*) ((PCHAR)pIDD->pMappedCv + omfDirEntry->lfo);
|
|
|
|
omfSegMapDesc = (OMFSegMapDesc*)&omfSegMap->rgDesc[0];
|
|
|
|
SectionStart = *(DWORD *)pIDD->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 + (pIDD->ImageAlign-1)) & ~(pIDD->ImageAlign-1));
|
|
Section[k].Misc.VirtualSize =
|
|
SectionSize = omfSegMapDesc[j].cbSeg;
|
|
k++;
|
|
}
|
|
}
|
|
|
|
pIDD->pOriginalSections = Section;
|
|
pIDD->cOriginalSections = k;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
__inline
|
|
DWORD
|
|
IsDataInSection (PIMAGE_SECTION_HEADER Section,
|
|
PIMAGE_DATA_DIRECTORY Data
|
|
)
|
|
{
|
|
DWORD RealDataOffset;
|
|
if ((Data->VirtualAddress >= Section->VirtualAddress) &&
|
|
((Data->VirtualAddress + Data->Size) <= (Section->VirtualAddress + Section->SizeOfRawData))) {
|
|
RealDataOffset = (DWORD)(Data->VirtualAddress -
|
|
Section->VirtualAddress +
|
|
Section->PointerToRawData);
|
|
} else {
|
|
RealDataOffset = 0;
|
|
}
|
|
return RealDataOffset;
|
|
}
|
|
|
|
__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 pIDD,
|
|
CHAR const *szReference
|
|
)
|
|
{
|
|
CHAR szRefDrive[_MAX_DRIVE];
|
|
CHAR szRefPath[_MAX_DIR];
|
|
PCVDD pcv = (PCVDD)pIDD->pMappedCv;
|
|
|
|
if (pIDD->PdbSignature)
|
|
return;
|
|
|
|
switch (pcv->dwSig)
|
|
{
|
|
case '01BN':
|
|
pIDD->PdbAge = pcv->nb10i.age;
|
|
pIDD->PdbSignature = pcv->nb10i.sig;
|
|
strcpy(pIDD->PdbFileName, pcv->nb10i.szPdb);
|
|
break;
|
|
case 'SDSR':
|
|
pIDD->PdbRSDS = TRUE;
|
|
pIDD->PdbAge = pcv->rsdsi.age;
|
|
memcpy(&pIDD->PdbGUID, &pcv->rsdsi.guidSig, sizeof(GUID));
|
|
strcpy(pIDD->PdbFileName, pcv->rsdsi.szPdb);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// if there is a path in the CV record - use it
|
|
|
|
if ((g.SymOptions & SYMOPT_IGNORE_CVREC) == 0) {
|
|
_splitpath(szReference, szRefDrive, szRefPath, NULL, NULL);
|
|
_makepath(pIDD->PdbReferencePath, szRefDrive, szRefPath, NULL, NULL);
|
|
if (strlen(szRefPath) > 1) {
|
|
pIDD->PdbReferencePath[strlen(pIDD->PdbReferencePath)-1] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if we have full path info for the image - use it
|
|
|
|
_splitpath(pIDD->ImageName, szRefDrive, szRefPath, NULL, NULL);
|
|
_makepath(pIDD->PdbReferencePath, szRefDrive, szRefPath, NULL, NULL);
|
|
if (strlen(szRefPath) > 1) {
|
|
pIDD->PdbReferencePath[strlen(pIDD->PdbReferencePath)-1] = '\0';
|
|
return;
|
|
}
|
|
|
|
// No path. Put on at least a dot "."
|
|
|
|
strcpy(pIDD->PdbReferencePath, ".");
|
|
}
|
|
|
|
BOOL
|
|
FakePdbName(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
CHAR szName[_MAX_FNAME];
|
|
|
|
if (pIDD->PdbSignature) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pIDD->ImageName)
|
|
return FALSE;
|
|
|
|
_splitpath(pIDD->ImageName, NULL, NULL, szName, NULL);
|
|
if (!*szName)
|
|
return FALSE;
|
|
|
|
strcpy(pIDD->PdbFileName, szName);
|
|
strcat(pIDD->PdbFileName, ".pdb");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
FindDebugInfoFileExCallback(
|
|
HANDLE FileHandle,
|
|
PSTR FileName,
|
|
PVOID CallerData
|
|
)
|
|
{
|
|
PIMGHLP_DEBUG_DATA pIDD;
|
|
PIMAGE_SEPARATE_DEBUG_HEADER DbgHeader;
|
|
PVOID FileMap;
|
|
BOOL rc;
|
|
|
|
rc = TRUE;
|
|
|
|
if (!CallerData)
|
|
return TRUE;
|
|
|
|
pIDD = (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;
|
|
}
|
|
|
|
// ignore checksums, they are bogus
|
|
rc = (pIDD->TimeDateStamp == DbgHeader->TimeDateStamp) ? TRUE : FALSE;
|
|
|
|
cleanup:
|
|
if (FileMap)
|
|
UnmapViewOfFile(FileMap);
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOL
|
|
ProcessDebugInfo(
|
|
PIMGHLP_DEBUG_DATA pIDD,
|
|
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;
|
|
|
|
// setup pointers for grabing data
|
|
|
|
switch (datasrc) {
|
|
case dsInProc:
|
|
hp = pIDD->hProcess;
|
|
base = pIDD->InProcImageBase;
|
|
fsize = 0;
|
|
filepath = pIDD->ImageFilePath;
|
|
pIDD->PdbSrc = srcCVRec;
|
|
break;
|
|
case dsImage:
|
|
hp = NULL;
|
|
pIDD->ImageMap = MapItRO(pIDD->ImageFileHandle);
|
|
base = (ULONG64)pIDD->ImageMap;
|
|
fsize = GetFileSize(pIDD->ImageFileHandle, NULL);
|
|
filepath = pIDD->ImageFilePath;
|
|
pIDD->PdbSrc = srcImagePath;
|
|
break;
|
|
case dsDbg:
|
|
hp = NULL;
|
|
pIDD->DbgFileMap = MapItRO(pIDD->DbgFileHandle);
|
|
base = (ULONG64)pIDD->DbgFileMap;
|
|
fsize = GetFileSize(pIDD->DbgFileHandle, NULL);
|
|
filepath = pIDD->DbgFilePath;
|
|
pIDD->PdbSrc = srcDbgPath;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
// some initialization
|
|
pIDD->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;
|
|
}
|
|
pIDD->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;
|
|
}
|
|
|
|
// grab the pe header
|
|
|
|
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) {
|
|
pIDD->fROM = TRUE;
|
|
pIDD->iohMagic = rom->Magic;
|
|
|
|
pIDD->ImageBaseFromImage = rom->BaseOfCode;
|
|
pIDD->SizeOfImage = rom->SizeOfCode;
|
|
pIDD->CheckSum = 0;
|
|
} else {
|
|
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);
|
|
pIDD->iohMagic = nh64.OptionalHeader.Magic;
|
|
pIDD->fPE64 = TRUE; // seems to be unused
|
|
|
|
if (datasrc == dsImage || datasrc == dsInProc) {
|
|
pIDD->ImageBaseFromImage = nh64.OptionalHeader.ImageBase;
|
|
pIDD->ImageAlign = nh64.OptionalHeader.SectionAlignment;
|
|
pIDD->CheckSum = nh64.OptionalHeader.CheckSum;
|
|
}
|
|
pIDD->SizeOfImage = nh64.OptionalHeader.SizeOfImage;
|
|
}
|
|
else {
|
|
fh = &nh32.FileHeader;
|
|
datadir = nh32.OptionalHeader.DataDirectory;
|
|
pIDD->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) {
|
|
pIDD->ImageBaseFromImage = nh32.OptionalHeader.ImageBase;
|
|
pIDD->ImageAlign = nh32.OptionalHeader.SectionAlignment;
|
|
pIDD->CheckSum = nh32.OptionalHeader.CheckSum;
|
|
}
|
|
pIDD->SizeOfImage = nh32.OptionalHeader.SizeOfImage;
|
|
}
|
|
}
|
|
|
|
mdSet(pIDD->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
|
|
|
|
pIDD->pCurrentSections = psh;
|
|
pIDD->cCurrentSections = nSections;
|
|
pIDD->pImageSections = psh;
|
|
pIDD->cImageSections = nSections;
|
|
pIDD->Machine = fh->Machine;
|
|
pIDD->TimeDateStamp = fh->TimeDateStamp;
|
|
pIDD->Characteristics = fh->Characteristics;
|
|
|
|
mdSet(pIDD->md, mdSecHdrs, datasrc, datasrc);
|
|
|
|
// get information from the sections
|
|
|
|
for (i = 0; i < nSections; i++, psh++) {
|
|
DWORD offset;
|
|
|
|
if (pIDD->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]))
|
|
{
|
|
pIDD->dsExports = datasrc;
|
|
pIDD->cExports = datadir[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
|
pIDD->oExports = offset;
|
|
ReadImageData(hp, base, offset, &pIDD->expdir, sizeof(pIDD->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(pIDD->DbgFileMap);
|
|
pIDD->DbgFileMap = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
pIDD->ImageAlign = sdh.SectionAlignment;
|
|
pIDD->CheckSum = sdh.CheckSum;
|
|
pIDD->Machine = sdh.Machine;
|
|
pIDD->TimeDateStamp = sdh.TimeDateStamp;
|
|
pIDD->Characteristics = sdh.Characteristics;
|
|
if (!pIDD->ImageBaseFromImage) {
|
|
pIDD->ImageBaseFromImage = sdh.ImageBase;
|
|
}
|
|
|
|
if (!pIDD->SizeOfImage) {
|
|
pIDD->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;
|
|
|
|
pIDD->pCurrentSections = psh;
|
|
pIDD->cCurrentSections = nSections;
|
|
pIDD->pDbgSections = psh;
|
|
pIDD->cDbgSections = nSections;
|
|
// pIDD->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) {
|
|
pIDD->ddva = ddva;
|
|
pIDD->cdd = nDebugDirs;
|
|
}
|
|
|
|
// read the debug directories
|
|
|
|
while (nDebugDirs) {
|
|
|
|
status = ReadImageData(hp, base, (ULONG_PTR)ddva, &dd, sizeof(dd));
|
|
if (!status)
|
|
break;
|
|
if (!dd.SizeOfData)
|
|
goto nextdebugdir;
|
|
|
|
// indicate that we found the debug directory
|
|
|
|
mdSet(pIDD->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 && dd.AddressOfRawData) {
|
|
// in-proc image
|
|
if (!(pCV = (PCHAR)MemAlloc(dd.SizeOfData)))
|
|
break;
|
|
status = ReadImageData(hp, base, dd.AddressOfRawData, pCV, dd.SizeOfData);
|
|
if (!status) {
|
|
MemFree(pCV);
|
|
break;
|
|
}
|
|
} else {
|
|
// file-base image
|
|
if (dd.PointerToRawData >= fsize)
|
|
break;
|
|
pCV = (PCHAR)base + dd.PointerToRawData;
|
|
pIDD->fCvMapped = TRUE;
|
|
}
|
|
pIDD->pMappedCv = (PCHAR)pCV;
|
|
pIDD->cMappedCv = dd.SizeOfData;
|
|
pIDD->dsCV = datasrc;
|
|
RetrievePdbInfo(pIDD, filepath);
|
|
mdSet(pIDD->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 (!*pIDD->OriginalImageFileName)
|
|
strncpy(pIDD->OriginalImageFileName, (LPSTR)md->Data, sizeof(pIDD->OriginalImageFileName));
|
|
break;
|
|
}
|
|
if (fh->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
|
|
strncpy(pIDD->OriginalDbgFileName, (LPSTR)md->Data, sizeof(pIDD->OriginalDbgFileName));
|
|
} else {
|
|
strncpy(pIDD->OriginalImageFileName, (LPSTR)md->Data, sizeof(pIDD->OriginalImageFileName));
|
|
}
|
|
}
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_COFF:
|
|
if (dd.PointerToRawData < fsize) {
|
|
// pIDD->fNeedImage = TRUE;
|
|
pIDD->pMappedCoff = (PCHAR)base + dd.PointerToRawData;
|
|
pIDD->cMappedCoff = dd.SizeOfData;
|
|
pIDD->fCoffMapped = TRUE;
|
|
pIDD->dsCoff = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
} else {
|
|
pIDD->fNeedImage = TRUE;
|
|
}
|
|
break;
|
|
#ifdef INPROC_SUPPORT
|
|
case IMAGE_DEBUG_TYPE_FPO:
|
|
if (dd.PointerToRawData < fsize) {
|
|
pIDD->pFpo = (PCHAR)base + dd.PointerToRawData;
|
|
pIDD->cFpo = dd.SizeOfData / SIZEOF_RFPO_DATA;
|
|
pIDD->fFpoMapped = TRUE;
|
|
pIDD->dsFPO = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
} else {
|
|
dprint("found fpo in-process\n");
|
|
}
|
|
break;
|
|
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
|
|
if (dd.PointerToRawData < fsize) {
|
|
pIDD->pOmapTo = (PCHAR)base + dd.PointerToRawData;
|
|
pIDD->cOmapTo = dd.SizeOfData / sizeof(OMAP);
|
|
pIDD->fOmapToMapped = TRUE;
|
|
pIDD->dsOmapTo = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
} else {
|
|
dprint("found found omap-to in-process\n");
|
|
}
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
|
|
if (dd.PointerToRawData < fsize) {
|
|
pIDD->pOmapFrom = (PCHAR)base + dd.PointerToRawData;
|
|
pIDD->cOmapFrom = dd.SizeOfData / sizeof(OMAP);
|
|
pIDD->fOmapFromMapped = TRUE;
|
|
pIDD->dsOmapFrom = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
} else {
|
|
dprint("found omap-from in-process\n");
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
// these debug directories are only processed for disk-based images
|
|
|
|
if (dd.PointerToRawData < fsize) {
|
|
|
|
switch (dd.Type)
|
|
{
|
|
case IMAGE_DEBUG_TYPE_FPO:
|
|
pIDD->pFpo = (PCHAR)base + dd.PointerToRawData;
|
|
pIDD->cFpo = dd.SizeOfData / SIZEOF_RFPO_DATA;
|
|
pIDD->fFpoMapped = TRUE;
|
|
pIDD->dsFPO = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
|
|
pIDD->pOmapTo = (POMAP)((PCHAR)base + dd.PointerToRawData);
|
|
pIDD->cOmapTo = dd.SizeOfData / sizeof(OMAP);
|
|
pIDD->fOmapToMapped = TRUE;
|
|
pIDD->dsOmapTo = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
|
|
pIDD->pOmapFrom = (POMAP)((PCHAR)base + dd.PointerToRawData);
|
|
pIDD->cOmapFrom = dd.SizeOfData / sizeof(OMAP);
|
|
pIDD->fOmapFromMapped = TRUE;
|
|
pIDD->dsOmapFrom = datasrc;
|
|
mdSet(pIDD->md, dd.Type, dsNone, datasrc);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_EXCEPTION:
|
|
pIDD->dsExceptions = datasrc;
|
|
mdSet(pIDD->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
|
|
FigureOutImageName(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
/*
|
|
We got here because we didn't get the image name passed in from the original call
|
|
to GetDebugData AND we were unable to find the MISC data with the name
|
|
Have to figure it out.
|
|
|
|
A couple of options here. First, if the DLL bit is set, try looking for Export
|
|
table. If found, IMAGE_EXPORT_DIRECTORY->Name is a rva pointer to the dll name.
|
|
If it's not found, see if there's a OriginalDbgFileName.
|
|
If so see if the format is <ext>\<filename>.dbg.
|
|
If there's more than one backslash or no backslash, punt and label it with a .dll
|
|
extension.
|
|
Otherwise a splitpath will do the trick.
|
|
If there's no DbgFilePath, see if there's a PDB name. The same rules apply there as
|
|
for .dbg files. Worst case, you s/b able to get the base name and just stick on a
|
|
If this all fails, label it as mod<base address>.
|
|
If the DLL bit is not set, assume an exe and tag it with that extension. The base name
|
|
can be retrieved from DbgFilePath, PdbFilePath, or use just APP.
|
|
*/
|
|
{
|
|
// Quick hack to get Dr. Watson going.
|
|
|
|
CHAR szName[_MAX_FNAME];
|
|
CHAR szExt[_MAX_FNAME];
|
|
|
|
if (pIDD->OriginalDbgFileName[0]) {
|
|
_splitpath(pIDD->OriginalDbgFileName, NULL, NULL, szName, NULL);
|
|
strcpy(pIDD->OriginalImageFileName, szName);
|
|
strcat(pIDD->OriginalImageFileName, pIDD->Characteristics & IMAGE_FILE_DLL ? ".dll" : ".exe");
|
|
} else if (pIDD->ImageName) {
|
|
_splitpath(pIDD->ImageName, NULL, NULL, szName, szExt);
|
|
strcpy(pIDD->OriginalImageFileName, szName);
|
|
if (*szExt) {
|
|
strcat(pIDD->OriginalImageFileName, szExt);
|
|
}
|
|
} else if (pIDD->PdbFileName[0]) {
|
|
_splitpath(pIDD->PdbFileName, NULL, NULL, szName, NULL);
|
|
strcpy(pIDD->OriginalImageFileName, szName);
|
|
strcat(pIDD->OriginalImageFileName, pIDD->Characteristics & IMAGE_FILE_DLL ? ".dll" : ".exe");
|
|
} else {
|
|
sprintf(pIDD->OriginalImageFileName, "MOD%p", pIDD->InProcImageBase);
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindExecutableImageExCallback(
|
|
HANDLE FileHandle,
|
|
PSTR FileName,
|
|
PVOID CallerData
|
|
)
|
|
{
|
|
PIMGHLP_DEBUG_DATA pIDD;
|
|
PIMAGE_FILE_HEADER FileHeader = NULL;
|
|
PVOID ImageMap = NULL;
|
|
BOOL rc;
|
|
|
|
if (!CallerData)
|
|
return TRUE;
|
|
|
|
pIDD = (PIMGHLP_DEBUG_DATA)CallerData;
|
|
if (!pIDD->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) &&
|
|
pIDD->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) &&
|
|
pIDD->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 != pIDD->TimeDateStamp)
|
|
rc = FALSE;
|
|
|
|
pIDD->ImageSrc = srcSearchPath;
|
|
|
|
// cleanup
|
|
|
|
if (ImageMap)
|
|
UnmapViewOfFile(ImageMap);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SymbolInfoFound(
|
|
PIMGHLP_DEBUG_DATA pIDD
|
|
)
|
|
{
|
|
OMFSignature *omfSig;
|
|
|
|
if (pIDD->dia)
|
|
return TRUE;
|
|
|
|
// look for embedded codeview
|
|
|
|
if (pIDD->pMappedCv) {
|
|
omfSig = (OMFSignature*) pIDD->pMappedCv;
|
|
if (*(DWORD *)(omfSig->Signature) == '80BN')
|
|
return TRUE;
|
|
if (*(DWORD *)(omfSig->Signature) == '90BN')
|
|
return TRUE;
|
|
if (*(DWORD *)(omfSig->Signature) == '11BN')
|
|
return TRUE;
|
|
}
|
|
|
|
// look for coff symbols
|
|
|
|
if (pIDD->pMappedCoff)
|
|
return TRUE;
|
|
|
|
// must be no debug info
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL FileNameIsPdb(
|
|
PIMGHLP_DEBUG_DATA pIDD,
|
|
LPSTR FileName
|
|
)
|
|
{
|
|
CHAR drive[_MAX_DRIVE];
|
|
CHAR path[_MAX_DIR];
|
|
char ext[20];
|
|
|
|
_splitpath(FileName, drive, path, NULL, ext);
|
|
if (_strcmpi(ext, ".pdb"))
|
|
return FALSE;
|
|
|
|
strcpy(pIDD->PdbFileName, FileName);
|
|
|
|
|
|
_makepath(pIDD->PdbReferencePath, drive, path, NULL, NULL);
|
|
if (strlen(path) > 1) {
|
|
// Chop off trailing backslash.
|
|
pIDD->PdbReferencePath[strlen(pIDD->PdbReferencePath)-1] = '\0';
|
|
} else {
|
|
// No path. Put on at least a dot "."
|
|
strcpy(pIDD->PdbReferencePath, ".");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PIMGHLP_DEBUG_DATA
|
|
GetDebugData(
|
|
HANDLE hProcess,
|
|
HANDLE FileHandle,
|
|
LPSTR FileName,
|
|
LPSTR SymbolPath,
|
|
ULONG64 ImageBase,
|
|
PMODLOAD_DATA mld,
|
|
ULONG dwFlags
|
|
)
|
|
/*
|
|
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()
|
|
|
|
*/
|
|
{
|
|
PIMGHLP_DEBUG_DATA pIDD;
|
|
|
|
// if (traceSubName(FileName)) // for setting debug breakpoints from DBGHELP_TOKEN
|
|
// dprint("debug(%s)\n", FileName);
|
|
|
|
// No File handle and no file name. Bail
|
|
|
|
if (!FileHandle && (!FileName || !*FileName)) {
|
|
return NULL;
|
|
}
|
|
|
|
SetLastError(NO_ERROR);
|
|
|
|
pIDD = InitDebugData();
|
|
if (!pIDD)
|
|
return NULL;
|
|
|
|
pIDD->flags = dwFlags;
|
|
|
|
__try {
|
|
|
|
// store off parameters
|
|
|
|
pIDD->InProcImageBase = ImageBase;
|
|
pIDD->hProcess = hProcess;
|
|
pIDD->mld = mld;
|
|
|
|
if (FileName && !FileNameIsPdb(pIDD, FileName))
|
|
lstrcpy(pIDD->ImageName, FileName);
|
|
|
|
if (SymbolPath) {
|
|
pIDD->SymbolPath = (PCHAR)MemAlloc(strlen(SymbolPath) + 1);
|
|
if (pIDD->SymbolPath) {
|
|
strcpy(pIDD->SymbolPath, SymbolPath);
|
|
}
|
|
}
|
|
|
|
// if we have a base pointer into process memory. See what we can get here.
|
|
if (pIDD->InProcImageBase) {
|
|
pIDD->fInProcHeader = ProcessInProcDebugInfo(pIDD);
|
|
if (pIDD->fInProcHeader)
|
|
pIDD->ImageSrc = srcMemory;
|
|
}
|
|
|
|
// find disk-based image
|
|
|
|
if (FileHandle) {
|
|
// if passed a handle, save it
|
|
|
|
if (!DuplicateHandle(
|
|
GetCurrentProcess(),
|
|
FileHandle,
|
|
GetCurrentProcess(),
|
|
&pIDD->ImageFileHandle,
|
|
GENERIC_READ,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS
|
|
))
|
|
{
|
|
return NULL;
|
|
}
|
|
pIDD->ImageSrc = srcHandle;
|
|
if (FileName) {
|
|
strcpy(pIDD->ImageFilePath, FileName);
|
|
}
|
|
|
|
} else if (!pIDD->fInProcHeader)
|
|
{
|
|
// otherwise use the file name to open the disk image
|
|
// only if we didn't have access to in-proc headers
|
|
pIDD->ImageFileHandle = FindExecutableImageEx(pIDD->ImageName,
|
|
SymbolPath,
|
|
pIDD->ImageFilePath,
|
|
FindExecutableImageExCallback,
|
|
pIDD);
|
|
}
|
|
|
|
// if we have a file handle. See what we can get here.
|
|
if (pIDD->ImageFileHandle) {
|
|
if (!pIDD->DbgFileHandle && !*pIDD->PdbFileName) {
|
|
ProcessImageDebugInfo(pIDD);
|
|
}
|
|
}
|
|
|
|
// get info from the caller's data struct
|
|
ProcessCallerDataDebugInfo(pIDD);
|
|
|
|
// search for pdb, if indicated or if we have found no image info, so far
|
|
pIDD->DbgFileHandle = 0;
|
|
if (!pIDD->Characteristics || (pIDD->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)) {
|
|
if (*pIDD->OriginalDbgFileName) {
|
|
pIDD->DbgFileHandle = fnFindDebugInfoFileEx(
|
|
pIDD->OriginalDbgFileName,
|
|
pIDD->SymbolPath,
|
|
pIDD->DbgFilePath,
|
|
FindDebugInfoFileExCallback,
|
|
pIDD,
|
|
fdifRECURSIVE);
|
|
}
|
|
if (!pIDD->DbgFileHandle) {
|
|
pIDD->DbgFileHandle = fnFindDebugInfoFileEx(
|
|
pIDD->ImageName,
|
|
pIDD->SymbolPath,
|
|
pIDD->DbgFilePath,
|
|
FindDebugInfoFileExCallback,
|
|
pIDD,
|
|
fdifRECURSIVE);
|
|
}
|
|
if (!pIDD->DbgFileHandle)
|
|
g.LastSymLoadError = SYMLOAD_DBGNOTFOUND;
|
|
}
|
|
|
|
// if we have a .dbg file. See what we can get from it.
|
|
if (pIDD->DbgFileHandle) {
|
|
ProcessDbgDebugInfo(pIDD);
|
|
}
|
|
|
|
// make sure we can process omaps
|
|
if (!pIDD->ImageAlign)
|
|
pIDD->fNeedImage = TRUE;
|
|
|
|
// check one more time to see if information we have acquired
|
|
// indicates we need the image from disk.
|
|
if (FileName && *FileName && pIDD->fNeedImage) {
|
|
pIDD->ImageFileHandle = FindExecutableImageEx(FileName,
|
|
SymbolPath,
|
|
pIDD->ImageFilePath,
|
|
FindExecutableImageExCallback,
|
|
pIDD);
|
|
if (pIDD->ImageFileHandle) {
|
|
ProcessImageDebugInfo(pIDD);
|
|
}
|
|
}
|
|
|
|
// if there's a pdb. Pull what we can from there.
|
|
if (*pIDD->PdbFileName) {
|
|
diaOpenPdb(pIDD);
|
|
|
|
// otherwise, if old codeview, pull from there
|
|
} else if (pIDD->pMappedCv) {
|
|
ProcessOldStyleCodeView(pIDD);
|
|
|
|
// otherwise if we couldn't read from the image info, look for PDB anyway
|
|
} else if (!pIDD->ImageFileHandle && !pIDD->DbgFileHandle) {
|
|
if (FakePdbName(pIDD)) {
|
|
diaOpenPdb(pIDD);
|
|
}
|
|
}
|
|
|
|
// if all else fails, one more try for a dbg
|
|
if (!(pIDD->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
|
|
&& !pIDD->DbgFileHandle
|
|
&& !SymbolInfoFound(pIDD)
|
|
)
|
|
{
|
|
pIDD->DbgFileHandle = fnFindDebugInfoFileEx(
|
|
(*pIDD->OriginalDbgFileName) ? pIDD->OriginalDbgFileName : pIDD->ImageName,
|
|
pIDD->SymbolPath,
|
|
pIDD->DbgFilePath,
|
|
FindDebugInfoFileExCallback,
|
|
pIDD,
|
|
fdifRECURSIVE);
|
|
|
|
// if we have a .dbg file. See what we can get from it.
|
|
if (pIDD->DbgFileHandle) {
|
|
ProcessDbgDebugInfo(pIDD);
|
|
}
|
|
}
|
|
|
|
if (!pIDD->OriginalImageFileName[0]) {
|
|
FigureOutImageName(pIDD);
|
|
}
|
|
|
|
GetUnfoundData(pIDD);
|
|
// mdDump(pIDD->md, FALSE);
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
if (pIDD) {
|
|
ReleaseDebugData(pIDD, IMGHLP_FREE_ALL);
|
|
pIDD = NULL;
|
|
}
|
|
}
|
|
|
|
return pIDD;
|
|
}
|
|
|
|
|
|
PIMGHLP_DEBUG_DATA
|
|
InitDebugData(
|
|
VOID
|
|
)
|
|
{
|
|
PIMGHLP_DEBUG_DATA pIDD;
|
|
|
|
pIDD = (PIMGHLP_DEBUG_DATA)MemAlloc(sizeof(IMGHLP_DEBUG_DATA));
|
|
if (!pIDD) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
g.LastSymLoadError = SYMLOAD_OUTOFMEMORY;
|
|
return NULL;
|
|
}
|
|
|
|
ZeroMemory(pIDD, sizeof(IMGHLP_DEBUG_DATA));
|
|
|
|
pIDD->md = (PMODULE_DATA)MemAlloc(sizeof(gmd));
|
|
if (!pIDD->md) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
g.LastSymLoadError = SYMLOAD_OUTOFMEMORY;
|
|
MemFree(pIDD);
|
|
return NULL;
|
|
}
|
|
memcpy(pIDD->md, gmd, sizeof(gmd));
|
|
|
|
return pIDD;
|
|
}
|
|
|
|
|
|
void
|
|
ReleaseDebugData(
|
|
PIMGHLP_DEBUG_DATA pIDD,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
if (!pIDD)
|
|
return;
|
|
|
|
if (pIDD->ImageMap) {
|
|
UnmapViewOfFile(pIDD->ImageMap);
|
|
}
|
|
|
|
if (pIDD->ImageFileHandle) {
|
|
CloseHandle(pIDD->ImageFileHandle);
|
|
}
|
|
|
|
if (pIDD->DbgFileMap) {
|
|
UnmapViewOfFile(pIDD->DbgFileMap);
|
|
}
|
|
|
|
if (pIDD->DbgFileHandle) {
|
|
CloseHandle(pIDD->DbgFileHandle);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_FPO) &&
|
|
pIDD->pFpo &&
|
|
!pIDD->fFpoMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pFpo);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_PDATA) &&
|
|
pIDD->pPData &&
|
|
!pIDD->fPDataMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pPData);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_XDATA) &&
|
|
pIDD->pXData &&
|
|
!pIDD->fXDataMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pXData);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_PDATA) &&
|
|
pIDD->pMappedCoff &&
|
|
!pIDD->fCoffMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pMappedCoff);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_PDATA) &&
|
|
pIDD->pMappedCv &&
|
|
!pIDD->fCvMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pMappedCv);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_OMAPT) &&
|
|
pIDD->pOmapTo &&
|
|
!pIDD->fOmapToMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pOmapTo);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_OMAPF) &&
|
|
pIDD->pOmapFrom &&
|
|
!pIDD->fOmapFromMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pOmapFrom);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_OSECT) &&
|
|
pIDD->pOriginalSections
|
|
)
|
|
{
|
|
MemFree(pIDD->pOriginalSections);
|
|
}
|
|
|
|
if ((dwFlags & IMGHLP_FREE_CSECT) &&
|
|
pIDD->pCurrentSections &&
|
|
!pIDD->fCurrentSectionsMapped
|
|
)
|
|
{
|
|
MemFree(pIDD->pCurrentSections);
|
|
}
|
|
|
|
if (pIDD->SymbolPath) {
|
|
MemFree(pIDD->SymbolPath);
|
|
}
|
|
|
|
MemFree(pIDD->md);
|
|
|
|
MemFree(pIDD);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef MAP_DEBUG_TEST
|
|
|
|
#if 0
|
|
|
|
void
|
|
__cdecl
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
CHAR szSymPath[4096];
|
|
PIMGHLP_DEBUG_DATA pDebugInfo;
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test1");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test1\\ntoskrnl.exe", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test2");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test2\\ntoskrnl.exe", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test3");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test3\\ntoskrnl.exe", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test4");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test4\\ntoskrnl.exe", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test5");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test5\\ntdll.dll", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test6");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test6\\ntdll.dll", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test7");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test7\\osloader.exe", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test8");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test8\\osloader.exe", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test9");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test9\\msvcrt.dll", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
|
|
strcpy(szSymPath, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test10");
|
|
pDebugInfo = GetDebugData(NULL, NULL, "h:\\nt\\private\\sdktools\\imagehlp\\test\\test10\\msvcrt.dll", szSymPath, 0x1000000, NULL, 0);
|
|
ReleaseDebugData(pDebugInfo, IMGHLP_FREE_ALL);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|