|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
dia.c
Abstract:
These routines call VC's new DIA symbol handler.
Author:
Pat Styles (patst) 26-May-2000
Environment:
User Mode
--*/ #define DIA_LIBRARY 1
#include "private.h"
#include "symbols.h"
#include "globals.h"
#include "dia2.h"
#include "diacreate_int.h"
#include "pdb.h"
#include <atlbase.h>
typedef struct { CComPtr<IDiaDataSource> source; CComPtr<IDiaSession> session; CComPtr<IDiaSymbol> scope; CComPtr<IDiaSourceFile> srcfile; CComPtr<IDiaEnumFrameData> framedata; #ifdef BBTFIX
CComPtr<IDiaAddressMap> addrmap; #endif
} DIA, *PDIA;
extern HRESULT STDMETHODCALLTYPE DiaCoCreate( REFCLSID rclsid, REFIID riid, void **ppv);
extern HRESULT STDMETHODCALLTYPE NoOleCoCreate(REFCLSID rclsid, REFIID riid, void **ppv);
#define freeString LocalFree
// used by diaLocatePdb
enum { ipNone = 0, ipFirst, ipLast };
BOOL diaInit() { #ifdef COMDIA
HRESULT hr;
if (!g.fCoInit) hr = CoInitialize(NULL); if (hr != S_OK) return false;
g.fCoInit = true; #endif
return true; }
void diaCleanup() { #ifdef COMDIA
HRESULT hr; if (!g.cProcessList && g.fCoInit) CoUninitialize(); g.fCoInit = false; #endif
}
__inline HRESULT SetDiaError( HRESULT ccode, HRESULT ncode ) { if (ncode == EC_OK) return ncode;
if (ccode != (HRESULT)EC_NOT_FOUND) return ccode;
return ncode; }
__inline BOOL ValidSig( DWORD sig, GUID *guid ) { if (ValidGuid(guid)) return true;
if (sig) return true;
return false; }
typedef struct _DIAERROR { HRESULT hr; char *text; } DIAERROR, *PDIAERROR;
char * diaErrorText( HRESULT hr ) { #define ERROR_MAX 24
static const DIAERROR error[ERROR_MAX] = { {E_PDB_OK, "OK"}, {E_PDB_USAGE, "invalid parameters"}, {E_PDB_OUT_OF_MEMORY, "out of memory"}, {E_PDB_FILE_SYSTEM, "drive not ready"}, {E_PDB_NOT_FOUND, "file not found"}, {E_PDB_INVALID_SIG, "mismatched pdb"}, {E_PDB_INVALID_AGE, "mismatched pdb"}, {E_PDB_PRECOMP_REQUIRED, "E_PDB_PRECOMP_REQUIRED"}, {E_PDB_OUT_OF_TI, "E_PDB_OUT_OF_TI"}, {E_PDB_NOT_IMPLEMENTED, "E_PDB_NOT_IMPLEMENTED"}, {E_PDB_V1_PDB, "E_PDB_V1_PDB"}, {E_PDB_FORMAT, "file system or network error reading pdb"}, {E_PDB_LIMIT, "E_PDB_LIMIT"}, {E_PDB_CORRUPT, "E_PDB_CORRUPT"}, {E_PDB_TI16, "E_PDB_TI16"}, {E_PDB_ACCESS_DENIED, "E_PDB_ACCESS_DENIED"}, {E_PDB_ILLEGAL_TYPE_EDIT, "E_PDB_ILLEGAL_TYPE_EDIT"}, {E_PDB_INVALID_EXECUTABLE, "invalid executable image"}, {E_PDB_DBG_NOT_FOUND, "dbg file not found"}, {E_PDB_NO_DEBUG_INFO, "pdb is stripped of cv info"}, {E_PDB_INVALID_EXE_TIMESTAMP, "image has invalid timestamp"}, {E_PDB_RESERVED, "E_PDB_RESERVED"}, {E_PDB_DEBUG_INFO_NOT_IN_PDB, "pdb has no symbols"}, {E_PDB_MAX, "pdb error 0x%x"} };
static char sz[50];
DWORD i;
for (i = 0; i < ERROR_MAX; i++) { if (hr == error[i].hr) return error[i].text; }
PrintString(sz, DIMA(sz), "dia error 0x%x", hr); return sz; }
void FreeDiaVariant( VARIANT *var ) { if (!var || !var->bstrVal) return;
#ifdef COMDIA
SysFreeString(var->bstrVal); #else
LocalFree(var->bstrVal); #endif
var->vt = VT_EMPTY; }
extern DWORD DIA_VERSION;
DWORD diaVersion( VOID ) { return DIA_VERSION; }
BOOL diaGetPdbInfo( PIMGHLP_DEBUG_DATA idd ) { PDIA pdia; HRESULT hr; DWORD celt; int i; enum SymTagEnum symtag[2] = {SymTagData, SymTagFunction}; enum SymTagEnum typetag[2] = {SymTagTypedef, SymTagUDT};
assert(idd);
// get interface
pdia = (PDIA)idd->dia; if (!pdia) return false;
CComPtr<IDiaSymbol> idiaGlobals;
hr = pdia->session->get_globalScope(&idiaGlobals); if (hr != S_OK) return false;
// get the pdb age and sig
hr = idiaGlobals->get_guid(&idd->pdbdataGuid); if (hr != S_OK) return false; if (GuidIsDword(&idd->pdbdataGuid)) { idd->pdbdataSig = idd->pdbdataGuid.Data1; idd->pdbdataGuid.Data1 = 0; } hr = idiaGlobals->get_age(&idd->pdbdataAge); if (hr != S_OK) return false; // any line numbers?
CComPtr<IDiaEnumSourceFiles> idiaSrcFiles; CComPtr<IDiaSourceFile> idiaSrcFile;
hr = pdia->session->findFile(NULL, NULL, 0, &idiaSrcFiles); if (hr == S_OK) { hr = idiaSrcFiles->Next(1, &idiaSrcFile, &celt); if (hr == S_OK && celt > 0) idd->fLines = true; }
// any symbols ?
CComPtr<IDiaSymbol> idiaSymbol; CComPtr< IDiaEnumSymbols > idiaSymbols; for (i = 0; i < 2; i++) { hr = idiaGlobals->findChildren(symtag[i], NULL, 0, &idiaSymbols); if (hr == S_OK) { hr = idiaSymbols->Next(1, &idiaSymbol, &celt); if (hr == S_OK && celt > 0) { idd->fSymbols = true; break; } } idiaSymbols = NULL; idiaSymbol = NULL; }
// any type info?
idiaSymbols = NULL; idiaSymbol = NULL;
for (i = 0; i < 2; i++) { hr = idiaGlobals->findChildren(typetag[i], NULL, 0, &idiaSymbols); if (hr == S_OK) { hr = idiaSymbols->Next(1, &idiaSymbol, &celt); if (hr == S_OK && celt > 0) { idd->fTypes = true; break; } } idiaSymbols = NULL; idiaSymbol = NULL; }
return true; }
HRESULT diaOpenPdb( PIMGHLP_DEBUG_DATA idd, PSTR szPDB, GUID *PdbGUID, DWORD PdbSignature, DWORD PdbAge, BOOL MatchAnything ) { HRESULT hr; EC hrcode = E_PDB_NOT_FOUND; PDIA pdia; WCHAR wszPDB[_MAX_PATH + 1];
pdia = (PDIA)idd->dia; if (!pdia) return EC_NO_DEBUG_INFO;
ansi2wcs(szPDB, wszPDB, DIMA(wszPDB)); if (!ValidSig(PdbSignature, PdbGUID)) hr = pdia->source->loadDataFromPdb(wszPDB); else hr = pdia->source->loadAndValidateDataFromPdb(wszPDB, ValidGuid(PdbGUID) ? PdbGUID : NULL, PdbSignature, PdbAge); hrcode = SetDiaError(hrcode, hr); if (hr == S_OK) { if (!PdbSignature && !ValidGuid(PdbGUID)) idd->fPdbUnmatched = true; } else { pprint(idd->pe, "%s - %s\n", szPDB, diaErrorText(hr)); if (hr == E_PDB_INVALID_SIG || hr == E_PDB_INVALID_AGE) { if (!ValidSig(PdbSignature, PdbGUID)) { hr = pdia->source->loadDataFromPdb(wszPDB); } else if (!*idd->FoundPdb) CopyStrArray(idd->FoundPdb, szPDB); } else if (hr == E_PDB_NOT_FOUND) { if (!(g.LastSymLoadError & SYMLOAD_PDBERRORMASK)) { g.LastSymLoadError = SYMLOAD_PDBNOTFOUND; } } else { g.LastSymLoadError = (hr << 8) & SYMLOAD_PDBERRORMASK; } }
return hr; }
HRESULT CheckDirForPdbs( PIMGHLP_DEBUG_DATA idd, PSTR path, GUID *PdbGUID, DWORD PdbSignature, DWORD PdbAge ) { WIN32_FIND_DATA fd; HANDLE hf; HRESULT hr; char drive[_MAX_DRIVE + 1]; char dir[_MAX_DIR + 1]; char fname[_MAX_FNAME + 1]; char sfname[_MAX_FNAME + 1]; char ext[_MAX_EXT + 1]; char spath[MAX_PATH + 1];
if (!*path) return E_PDB_NOT_FOUND;
_splitpath(path, drive, dir, fname, ext); ShortNodeName(fname, sfname, DIMA(sfname));
// now search the tree
PrintString(spath, DIMA(spath), "%s%s%s%s\\*", drive, dir, sfname, ext); ZeroMemory(&fd, sizeof(fd)); hf = FindFirstFile(spath, &fd); if (hf == INVALID_HANDLE_VALUE) return E_PDB_NOT_FOUND;
do { if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue; PrintString(spath, DIMA(spath), "%s%s%s%s\\%s", drive, dir, sfname, ext, fd.cFileName); if (isdir(spath)) { EnsureTrailingBackslash(spath); CatStrArray(spath, sfname); CatStrArray(spath, ext); } else if (!IsPdb(spath)) continue; hr = diaOpenPdb(idd, spath, PdbGUID, PdbSignature, PdbAge, false); if (hr == S_OK) { CopyString(path, spath, MAX_PATH + 1); return hr; } } while (FindNextFile(hf, &fd));
// If there is no match, but a file exists in the symbol subdir with
// a matching name, make sure that is what will be picked.
PrintString(spath, DIMA(spath), "%s%s%s%s\\%s%s", drive, dir, sfname, ext, sfname, ext); if (fileexists(spath)) CopyStrArray(idd->FoundPdb, spath); return E_PDB_NOT_FOUND; }
HRESULT diaLocatePdb( PIMGHLP_DEBUG_DATA idd, PSTR szPDB, GUID *PdbGUID, DWORD PdbSignature, DWORD PdbAge, char *szImageExt ) { DWORD pass; EC hrcode = E_PDB_NOT_FOUND; GUID guid; HRESULT hr = E_PDB_NOT_FOUND;
char pdb[MAX_PATH + 1]; char drive[6]; char path[MAX_PATH + 1]; char module[MAX_PATH + 1]; char modbuf[MAX_PATH + 1]; char name[MAX_PATH + 1]; char ext[_MAX_EXT + 1]; char *next; DWORD attrib; DWORD err; BOOL ssrv = true;
#ifdef DEBUG
if (traceSubName(szPDB)) // for setting debug breakpoints from DBGHELP_TOKEN
dtrace("diaLocatePdb(%s)\n", szPDB); #endif
if (!PdbSignature && !IsPdb(idd->ImageFilePath) && !ValidGuid(PdbGUID) && option(SYMOPT_EXACT_SYMBOLS)) { g.LastSymLoadError = SYMLOAD_PDBUNMATCHED; return E_PDB_INVALID_SIG; }
if (!idd->dia) return EC_NO_DEBUG_INFO;
// If the image file name is a pdb, then just try to open it.
// Don't attempt any searching.
if (IsPdb(idd->ImageFilePath)) { CopyStrArray(pdb, idd->ImageFilePath); hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false); if (hr == S_OK) { idd->PdbSrc = srcImagePath; goto done; } return E_PDB_NOT_FOUND; }
// Set up indexes for symbol server
ZeroMemory(&guid, sizeof(GUID)); if (PdbSignature) guid.Data1 = PdbSignature; else if (PdbGUID) memcpy(&guid, PdbGUID, sizeof(GUID));
// get name of pdb
_splitpath(szPDB, NULL, NULL, module, ext); PrintString(name, DIMA(name), "%s%s", module, ".pdb");
// SymbolPath is a semicolon delimited path (reference path first)
next = TokenFromSymbolPath(idd->SymbolPath, path, MAX_PATH + 1); while (*path) {
for (pass = 0; pass < 3; pass++) { if (symsrvPath(path)) { if (pass || !ssrv) break; *pdb = 0; idd->PdbSrc = srcSymSrv; err = symsrvGetFile(idd->pe, path, name, &guid, PdbAge, 0, pdb); if (err == ERROR_NO_DATA) ssrv = false; } else { if (pass && !*szImageExt) break; idd->PdbSrc = srcSearchPath; if (!CreateSymbolPath(pass, path, szImageExt, module, ext, pdb, DIMA(pdb))) { hr = E_PDB_NOT_FOUND; goto done; } if (!pass) { hr = CheckDirForPdbs(idd, pdb, PdbGUID, PdbSignature, PdbAge); if (hr == S_OK) goto done; } }
if (*pdb) { hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false); hrcode = SetDiaError(hrcode, hr); if (hr == S_OK) goto done; } }
next = TokenFromSymbolPath(next, path, MAX_PATH + 1); }
// try the same path as the image
if (idd->ImageFileHandle && *idd->ImageFilePath) { _splitpath(idd->ImageFilePath, drive, path, NULL, NULL); PrintString(pdb, DIMA(pdb), "%s%s%s", drive, path, name); hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false); if (hr == S_OK) idd->PdbSrc = srcImagePath; }
// try the CV Record
if (hr != S_OK && strcmp(pdb, szPDB) && !option(SYMOPT_IGNORE_CVREC)) { CopyStrArray(pdb, szPDB); hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false); if (hr == S_OK) idd->PdbSrc = srcCVRec; }
// try mismatches
if (hr != S_OK && *idd->FoundPdb) { if (option(SYMOPT_LOAD_ANYTHING)) { CopyStrArray(pdb, idd->FoundPdb); hr = diaOpenPdb(idd, pdb, NULL, 0, 0, true); if (hr == S_OK) idd->PdbSrc = srcSearchPath; } idd->LoadInfo &= DSLFLAG_MISMATCHED_PDB; pprint(idd->pe, "%s mismatched pdb for %s\n", hr == S_OK ? "Loaded" : "Couldn't load", *idd->ImageFilePath ? idd->ImageFilePath : name); }
done:
if (hr == S_OK) { // Store the name of the PDB we actually opened for later reference.
strcpy(szPDB, pdb); // SECURITY: Don't know size of target buffer.
SetLastError(NO_ERROR); g.LastSymLoadError = SYMLOAD_OK; }
return hr; }
BOOL diaReadStream( PMODULE_ENTRY mi, char *stream, PBYTE *buf, DWORD *size ) { PDIA pdia; PDB *pdb; HRESULT hr; BOOL rc; LONG cb; Stream *pstream; LONG count = 0;
assert (mi && stream && *stream && buf && size); *size = 0; *buf = 0;
pdia = (PDIA)mi->dia; if (!pdia) return false;
hr = GetRawPdbPtrForDataSource(pdia->source, &pdb); if (hr != S_OK) return false;
rc = PDBOpenStream(pdb, stream, &pstream); if (!rc) return false;
*size = StreamQueryCb(pstream); if (!*size) return false;
*buf = (PBYTE)MemAlloc(*size + 1); if (!*buf) return false;
cb = *size; rc = StreamRead(pstream, 0, *buf, &cb); if (!rc) goto error; if (cb != *size) goto error;
return true;
error: MemFree(*buf); *buf = 0;
return 0; }
DWORD diaReadDebugStream( PVOID dia, char *stream, PBYTE *buf, DWORD *size ) { DWORD celt; LONG count; DWORD cb; HRESULT hr; VARIANT var; PDIA pdia; WCHAR wstream[1000];
CComPtr< IDiaEnumDebugStreams > idiaStreams; CComPtr< IDiaEnumDebugStreamData > idiaStream;
assert (dia && stream && *stream && buf);
pdia = (PDIA)dia; hr = pdia->session->getEnumDebugStreams(&idiaStreams); if (hr != S_OK) return 0;
if (!ansi2wcs(stream, wstream, 1000)) return 0;
var.vt = VT_BSTR; var.bstrVal = wstream; hr = idiaStreams->Item(var, &idiaStream); if (hr != S_OK) return 0;
hr = idiaStream->get_Count(&count); if (hr != S_OK) return 0; if (count < 1) return 0;
hr = idiaStream->Next(count, 0, &cb, NULL, &celt); if (hr != S_OK) return 0; if (cb < 1) return 0;
*buf = (PBYTE)MemAlloc(cb); if (!*buf) return 0;
hr = idiaStream->Next(count, cb, &cb, *buf, &celt); if (hr != S_OK) { MemFree(*buf); *buf = NULL; return 0; }
*size = cb;
return count; }
BOOL diaGetOmaps( PIMGHLP_DEBUG_DATA idd ) { DWORD celt; LONG count; DWORD cb; PBYTE tbuf = NULL; PBYTE fbuf = NULL; HRESULT hr; VARIANT var;
count = diaReadDebugStream(idd->dia, "OMAPTO", &tbuf, &cb); if (count < 1) return false;
idd->cOmapTo = count; idd->pOmapTo = (POMAP)tbuf; idd->fOmapToMapped = false;
count = diaReadDebugStream(idd->dia, "OMAPFROM", &fbuf, &cb); if (count < 1) return false;
idd->cOmapFrom = count; idd->pOmapFrom = (POMAP)fbuf; idd->fOmapFromMapped = false;
return true; }
BOOL diaGetFPOTable( PIMGHLP_DEBUG_DATA idd ) { LONG count; PBYTE buf; DWORD cb;
count = diaReadDebugStream(idd->dia, "FPO", &buf, &cb); if (count < 1) return false;
idd->cFpo = count; idd->pFpo = buf;
return true; }
BOOL diaGetPData( PMODULE_ENTRY mi ) { LONG count; PBYTE buf; DWORD cb;
count = diaReadDebugStream(mi->dia, "PDATA", &buf, &cb); if (count < 1) return false;
mi->dsExceptions = dsDia; mi->cPData = count; mi->cbPData = cb; mi->pPData = buf;
return true; }
BOOL diaGetXData( PMODULE_ENTRY mi ) { DWORD celt; LONG count; DWORD cb; PBYTE buf; HRESULT hr; PDIA pdia; VARIANT var;
CComPtr< IDiaEnumDebugStreams > idiaStreams; CComPtr< IDiaEnumDebugStreamData > idiaStream;
assert (mi && mi->dia);
pdia = (PDIA)mi->dia; if (!pdia) return false;
hr = pdia->session->getEnumDebugStreams(&idiaStreams); if (hr != S_OK) return false;
var.vt = VT_BSTR; var.bstrVal = L"XDATA"; hr = idiaStreams->Item(var, &idiaStream); if (hr != S_OK) return false;
hr = idiaStream->get_Count(&count); if (hr != S_OK) return false; if (count < 1) return true;
hr = idiaStream->Next(count, 0, &cb, NULL, &celt); if (hr != S_OK) return false; if (cb < 1) return true;
CComQIPtr< IDiaImageData, &IID_IDiaImageData > idiaXDataHdr(idiaStream); if (!idiaXDataHdr.p) return false;
DWORD relativeVirtualAddress; if (FAILED(hr = idiaXDataHdr->get_relativeVirtualAddress(&relativeVirtualAddress))) return false;
buf = (PBYTE)MemAlloc(cb + sizeof(DWORD)); if (!buf) return false;
memcpy(buf, &relativeVirtualAddress, sizeof(relativeVirtualAddress));
hr = idiaStream->Next(count, cb, &cb, buf + sizeof(DWORD), &celt); if (hr != S_OK) { MemFree(buf); return false; }
mi->dsExceptions = dsDia; mi->cXData = count; mi->cbXData = cb; mi->pXData = buf;
return true; }
void diaRelease( PVOID dia ) { PDIA pdia = (PDIA)dia; if (pdia) delete pdia; }
#if 1
LONG diaCountGlobals( PMODULE_ENTRY mi ) { PDIA pdia; HRESULT hr; LONG count; LONG rc = 0;
CComPtr< IDiaSymbol > idiaGlobals; CComPtr< IDiaEnumSymbols > idiaSymbols;
if (mi->cGlobals != -1) return mi->cGlobals;
pdia = (PDIA)mi->dia; if (!pdia) return mi->cGlobals;
hr = pdia->session->get_globalScope(&idiaGlobals); if (hr != S_OK) goto exit;
// see if there are any globals at all
hr = idiaGlobals->findChildren(SymTagData, NULL, 0, &idiaSymbols); if (hr != S_OK) goto exit; hr = idiaSymbols->get_Count(&count); if (hr != S_OK) goto exit; rc = count;
idiaSymbols = NULL; hr = idiaGlobals->findChildren(SymTagFunction, NULL, 0, &idiaSymbols); if (hr != S_OK) goto exit; hr = idiaSymbols->get_Count(&count); if (hr != S_OK) goto exit; rc += count;
exit: mi->cGlobals = rc;
return rc; } #endif
BOOL diaGetPdb( PIMGHLP_DEBUG_DATA idd ) { HRESULT hr; PDIA pdia; DWORD cpathlen = 0; DWORD len; CHAR szExt[_MAX_EXT + 1] = {0};
if (idd->dia) { pprint(idd->pe, "redundant pdb call!\n"); return true; }
if (*idd->ImageFilePath) { _splitpath(idd->ImageFilePath, NULL, NULL, NULL, szExt); } else if (*idd->ImageName) { _splitpath(idd->ImageName, NULL, NULL, NULL, szExt); }
// if we have no valid filename, then this must be an executable
if (!*szExt) CopyStrArray(szExt, ".exe");
// get interface to dia
pdia = new DIA; if (!pdia) { hr = E_PDB_OUT_OF_MEMORY; goto error; } idd->dia = pdia;
pdia->source = NULL; #ifdef COMDIA
hr = CoCreateInstance(CLSID_DiaSourceAlt, NULL, CLSCTX_INPROC_SERVER, IID_IDiaDataSource, (void **)&pdia->source); #else
hr = DiaCoCreate(CLSID_DiaSourceAlt, IID_IDiaDataSource, (void **)&pdia->source); #endif
if (hr != S_OK) goto error;
// go ahead and get pdb
SetCriticalErrorMode();
hr = diaLocatePdb(idd, idd->PdbFileName, &idd->PdbGUID, idd->PdbSignature, idd->PdbAge, &szExt[1]);
ResetCriticalErrorMode();
if (hr != S_OK) { hr = S_OK; // error was already handled by diaLocatePdb()
goto error; }
// open the session on the pdb
pdia->session = NULL; hr = pdia->source->openSession(&pdia->session); if (hr != S_OK) goto error;
// Set the module load address so we can use VAs.
hr = pdia->session->put_loadAddress(idd->InProcImageBase); if (hr != S_OK) goto error;
// fixup the address map so that we can translate rva to full addresses
hr = pdia->session->QueryInterface(IID_IDiaAddressMap, (void**)&pdia->addrmap); if (hr != S_OK) goto error;
if (idd->pCurrentSections) { hr = pdia->addrmap->set_imageHeaders(idd->cCurrentSections * sizeof(IMAGE_SECTION_HEADER), (BYTE *)idd->pCurrentSections, false); if (hr != S_OK) goto error; }
// this hack is to fix a problem with v7 pdbs not storing the original image alignment
if (idd->ImageAlign) { hr = pdia->addrmap->put_imageAlign(idd->ImageAlign); if (hr != S_OK) goto error; }
// pass in the omap information and setup the proper image alignment to the original
if (idd->cOmapFrom && idd->pOmapFrom) { hr = pdia->addrmap->put_imageAlign(idd->ImageAlign); if (hr != S_OK) goto error; hr = pdia->addrmap->set_addressMap(idd->cOmapTo, (DiaAddressMapEntry *)idd->pOmapTo, true); if (hr != S_OK) goto error; hr = pdia->addrmap->set_addressMap(idd->cOmapFrom, (DiaAddressMapEntry *)idd->pOmapFrom, false); if (hr != S_OK) goto error; hr = pdia->addrmap->put_addressMapEnabled(true); if (hr != S_OK) goto error; }
hr = pdia->addrmap->put_relativeVirtualAddressEnabled(true); if (hr != S_OK) goto error;
diaGetFPOTable(idd); diaGetOmaps(idd); diaGetPdbInfo(idd);
return true;
error: if (hr != S_OK) pprint(idd->pe, "%s %s\n", idd->PdbFileName, diaErrorText(hr));
diaRelease(pdia); idd->dia = NULL;
return false; }
DWORD64 GetAddressFromRva( PMODULE_ENTRY mi, DWORD rva ) { DWORD64 addr;
assert(mi); addr = rva ? mi->BaseOfDll + rva : 0; return addr; }
DWORD64 GetLineAddressFromRva( PMODULE_ENTRY mi, DWORD rva ) { DWORD64 addr;
assert(mi); addr = rva ? mi->BaseOfDll + rva : 0;
// Line symbol information names the IA64 bundle
// syllables with 0,1,2 whereas the debugger expects
// 0,4,8. Convert.
if (mi->MachineType == IMAGE_FILE_MACHINE_IA64 && (addr & 3)) { addr = (addr & ~3) | ((addr & 3) << 2); }
return addr; }
BOOL diaFillSymbolInfo( PSYMBOL_INFO si, PMODULE_ENTRY mi, IDiaSymbol *idiaSymbol ) { HRESULT hr; BSTR wname=NULL; char name[MAX_SYM_NAME + 1]; char *p; DWORD dw; ULONG64 size; ULONG64 va; BOOL rc; VARIANT value;
CComPtr< IDiaEnumSymbols > idiaValues; CComPtr<IDiaSymbol> idiaValue;
if (!idiaSymbol) return false;
rc = true;
dw = si->MaxNameLen; ZeroMemory(si, sizeof(SYMBOL_INFO)); si->MaxNameLen = dw;
// si->SizeOfStruct = IGNORED;
// si->TypeIndex = NYI;
// si->Reserved = IGNORED;
si->ModBase = mi->BaseOfDll;
hr = idiaSymbol->get_symTag(&si->Tag); if (hr != S_OK) return false;
switch (si->Tag) { case SymTagData: hr = idiaSymbol->get_locationType(&dw); if (hr != S_OK) return false; switch(dw) { case LocIsTLS: // TLS variables have an offset into the TLS data area.
si->Flags = SYMFLAG_TLSREL; hr = idiaSymbol->get_addressOffset(&dw); if (hr != S_OK) return false; si->Address = (ULONG64) (LONG64) (LONG) dw; break;
case LocIsStatic: hr = idiaSymbol->get_relativeVirtualAddress(&dw); si->Address = GetAddressFromRva(mi, dw); if (!si->Address) rc = false; break;
case LocIsEnregistered: hr = idiaSymbol->get_registerId(&si->Register); si->Flags = SYMFLAG_REGISTER; break;
case LocIsRegRel: si->Flags = SYMFLAG_REGREL; hr = idiaSymbol->get_registerId(&si->Register); if (hr != S_OK) return false; hr = idiaSymbol->get_offset((PLONG)&dw); si->Address = (ULONG64) (LONG64) (LONG) dw; break;
case LocIsThisRel: // struct members - get_Offset
default: si->Flags |= 0; break; } break;
case SymTagThunk: hr = idiaSymbol->get_targetRelativeVirtualAddress(&dw); if (hr == S_OK) { si->Value = GetAddressFromRva(mi, dw); si->Flags |= SYMFLAG_THUNK; } // pass through
case SymTagFunction: case SymTagPublicSymbol: hr = idiaSymbol->get_relativeVirtualAddress(&dw); si->Address = GetAddressFromRva(mi, dw); if (si->Address) break; if (option(SYMOPT_ALLOW_ABSOLUTE_SYMBOLS)) { hr = idiaSymbol->get_virtualAddress(&va); si->Address = va; } if (!si->Address) rc = false; break;
case SymTagBlock: hr = idiaSymbol->get_relativeVirtualAddress(&dw); si->Address = GetAddressFromRva(mi, dw); if (!si->Address) rc = false; return rc;
case SymTagAnnotation: // Local data search
hr = idiaSymbol->findChildren(SymTagNull, NULL, nsNone, &idiaValues); if (hr != S_OK || !idiaValues) break; p = si->Name; *p = 0; while (SUCCEEDED(idiaValues->Next(1, &idiaValue, &dw)) && dw == 1) { hr = idiaValue->get_value(&value); if (hr != S_OK) break; wcs2ansi(value.bstrVal, p, si->MaxNameLen - (ULONG)(p - si->Name)); p += strlen(p) + 1; FreeDiaVariant(&value); idiaValue = NULL; } *(p + 1) = 0; hr = idiaSymbol->get_relativeVirtualAddress(&dw); si->Address = GetAddressFromRva(mi, dw); if (!si->Address) rc = false; // There's no name processing for annotations. We're done.
return rc;
default: break; }
if (hr != S_OK) return false;
// check for flags and types
hr = idiaSymbol->get_dataKind(&dw); if (hr == S_OK) { if (dw == DataIsParam) si->Flags |= SYMFLAG_PARAMETER; else if (dw == DataIsConstant) si->Flags = SYMFLAG_CONSTANT; }
hr = idiaSymbol->get_typeId(&dw); if (hr == S_OK) si->TypeIndex = dw;
// get the name
hr = idiaSymbol->get_name(&wname); if (hr != S_OK || !wname) { if (si->Tag != SymTagThunk) return false; PrintString(name, DIMA(name), "thunk@%I64x", si->Address); CopyString(si->Name, name, si->MaxNameLen); } else if (!wname[0]) { rc = false; } else { wcs2ansi(wname, name, MAX_SYM_NAME); if ((si->Tag != SymTagPublicSymbol) && !option(SYMOPT_NO_PUBLICS) && strchr(name, '@')) { rc = false; } if (option(SYMOPT_NO_CPP)) { while (p = strstr(name, "::")) { p[0] = '_'; p[1] = '_'; } } if (*name == '.') si->Flags = SYMFLAG_FUNCTION; if (option(SYMOPT_UNDNAME) && ((si->Tag == SymTagPublicSymbol) || (si->Tag == SymTagThunk))) { SymUnDNameInternal(si->Name, si->MaxNameLen, name, strlen(name), mi->MachineType, true); if (si->MaxNameLen > 0) { CopyStrArray(name, si->Name); } else { name[0] = 0; } } else { CopyString(si->Name, name, si->MaxNameLen); } // let the caller know this is a $$$XXXAA style symbol
if (strlen(name) == 8 && !strncmp(name, "$$$",3) && isxdigit(name[5]) && isxdigit(name[6]) && isxdigit(name[7]) ) { rc = false; } } #ifdef DEBUG
CopyStrArray(name, mi->si.Name); if (traceSubName(name)) // for setting debug breakpoints from DBGHELP_TOKEN
dtrace("debug(%s)\n", name); #endif
if (wname) LocalFree (wname);
// get_length is very expensive on public symbols
if (si->Tag == SymTagPublicSymbol) return rc;
// okay. Get the length.
hr = idiaSymbol->get_length(&size); if (hr == S_OK) si->Size = (ULONG)size; else { CComPtr <IDiaSymbol> pType; if ((hr = idiaSymbol->get_type(&pType)) == S_OK){ hr = pType->get_length(&size); if (hr == S_OK) si->Size = (ULONG)size; } pType = NULL; }
return rc; }
BOOL diaSetModFromIP( PPROCESS_ENTRY pe ) { HRESULT hr; DWORD64 ip; DWORD rva; PDIA pdia;
// get the current IP
ip = GetIP(pe); if (!ip) { pprint(pe, "IP not set!\n"); return false; }
// find and load symbols for the module that matches the IP
pe->ipmi = GetModFromAddr(pe, ip);
if (!pe->ipmi) return false;
if (!pe->ipmi->dia) return false;
pdia = (PDIA)pe->ipmi->dia; rva = (DWORD)(ip - pe->ipmi->BaseOfDll);
CComPtr< IDiaSymbol > idiaScope; hr = pdia->session->findSymbolByRVA(rva, SymTagNull, &idiaScope); if (hr != S_OK) return false;
hr = pdia->session->symsAreEquiv(idiaScope, pdia->scope); if (hr == S_OK) return false;
pdia->scope = idiaScope;
return true; }
PWCHAR ConvertNameForDia( LPSTR name, PWCHAR wname ) { assert (name && wname); if (!name || !*name) return NULL;
ansi2wcs(name, wname, MAX_SYM_NAME);
return wname; }
VOID MakeEmbeddedREStr( PCHAR out, PCHAR in ) { if (*in != '*') *out++ = '*';
for (; *in; in++, out++) *out = *in;
if (*(in - 1) != '*') *out++ = '*';
*out = 0; }
BOOL diaGetLocals( PPROCESS_ENTRY pe, LPCSTR name, PROC callback, PVOID context, BOOL use64, BOOL unicode ) { PMODULE_ENTRY mi; DWORD64 ip; DWORD rva; PDIA pdia; HRESULT hr; DWORD rc; DWORD tag; DWORD scope; DWORD celt; DWORD opt; CHAR symname[MAX_SYM_NAME + 1]; WCHAR wbuf[MAX_SYM_NAME + 1]; PWCHAR wname;
assert(pe);
CComPtr< IDiaSymbol > idiaSymbols;
opt = option(SYMOPT_CASE_INSENSITIVE) ? nsCaseInRegularExpression : nsRegularExpression;
if (option(SYMOPT_PUBLICS_ONLY)) return true;
// get the current scope
mi = pe->ipmi; if (!mi) return false; pdia = (PDIA)mi->dia; if (!pdia) return false;
idiaSymbols = pdia->scope; diaFillSymbolInfo(&mi->si, mi, idiaSymbols);
PrepRE4Srch(name, symname); wname = ConvertNameForDia(symname, wbuf);
// loop through all symbols
for ( ; idiaSymbols != NULL; ) {
CComPtr< IDiaEnumSymbols > idiaEnum; // local data search
hr = idiaSymbols->findChildren(SymTagNull, wname, opt, &idiaEnum); if (hr != S_OK) return false;
idiaSymbols->get_symTag(&scope); if (hr != S_OK) return false;
if (scope == SymTagExe) { // sanity check, never enumerate all exe's symbols
break; } // this walks the local symbol list for the loaded enumeration
CComPtr< IDiaSymbol > idiaSymbol;
for (; SUCCEEDED(hr = idiaEnum->Next( 1, &idiaSymbol, &celt)) && celt == 1; idiaSymbol = NULL) { ULONG DataKind; idiaSymbol->get_symTag(&tag); switch (tag) { case SymTagData: case SymTagFunction: if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) continue; if (!strcmp(mi->si.Name, "`string'")) continue; mi->si.Scope = scope; mi->si.Flags |= SYMFLAG_LOCAL; if (!callback) return true; if (mi->si.Flags & SYMFLAG_CONSTANT) continue; rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode); if (!rc) { mi->code = ERROR_CANCELLED; return rc; } break; default: break; } }
if (callback && scope == SymTagFunction) // stop when at function scope
break;
// move to lexical parent
CComPtr< IDiaSymbol > idiaParent; hr = idiaSymbols->get_lexicalParent(&idiaParent); if (hr != S_OK || !idiaParent) return false;
idiaSymbols = idiaParent; }
// We reached the end. If we enumerating (I.E. callback != NULL)
// then return true. If we are searching for a single match,
// we have failed and should return false;
if (callback) return true; return false; }
int __cdecl CompareAddrs( const void *addr1, const void *addr2 ) { LONGLONG Diff = *(DWORD64 *)addr1 - *(DWORD64 *)addr2;
if (Diff < 0) { return -1; } else if (Diff > 0) { return 1; } else { return 0; } }
PDWORD64 FindAddr( PDWORD64 pAddrs, ULONG cAddrs, DWORD64 addr ) { LONG high; LONG low; LONG i; LONG rc;
low = 0; high = ((LONG)cAddrs) - 1;
while (high >= low) { i = (low + high) >> 1; rc = CompareAddrs(&addr, &pAddrs[i]);
if (rc < 0) high = i - 1; else if (rc > 0) low = i + 1; else return &pAddrs[i]; }
return NULL; }
typedef BOOL (CALLBACK *PSYM_LOCALENUMSYMBOL_CALLBACK)( PSYMBOL_INFO si, ULONG size, IDiaSymbol *idiaObj, PVOID context );
char* dispsymtag( ULONG symtag ) { static char* names[] = { "SymTagNull", "SymTagExe", "SymTagCompiland", "SymTagCompilandDetails", "SymTagCompilandEnv", "SymTagFunction", "SymTagBlock", "SymTagData", "SymTagAnnotation", "SymTagLabel", "SymTagPublicSymbol", "SymTagUDT", "SymTagEnum", "SymTagFunctionType", "SymTagPointerType", "SymTagArrayType", "SymTagBaseType", "SymTagTypedef", "SymTagBaseClass", "SymTagFriend", "SymTagFunctionArgType", "SymTagFuncDebugStart", "SymTagFuncDebugEnd", "SymTagUsingNamespace", "SymTagVTableShape", "SymTagVTable", "SymTagCustom", "SymTagThunk", "SymTagCustomType", "SymTagManagedType", "SymTagDimension", }; if (symtag >= SymTagMax) return "<Invalid>"; else return names[symtag]; }
BOOL diaEnumScope( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, DWORD tag, char *mask, PROC callback, PVOID context, BOOL use64, BOOL unicode, DWORD flags, IDiaSymbol *idiaScope, int depth ) { HRESULT hr; DWORD celt; DWORD stg; BOOL disp; char pad[300];
CComPtr< IDiaEnumSymbols > idiaSymbols; CComPtr<IDiaSymbol> idiaSymbol; ZeroMemory(pad, 300); memset(pad, ' ', depth * 3);
hr = idiaScope->get_symTag(&stg); if (hr != S_OK) return false;
// display all objects within this scope
hr = idiaScope->findChildren(SymTagNull, NULL, 0, &idiaSymbols); if (hr != S_OK) return true;
while (SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1) { disp = true; if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) continue; if (mi->si.Tag == SymTagBlock) CopyString(mi->si.Name, "BLOCK", mi->si.NameLen); if (tag && mi->si.Tag != tag) disp = false; if (strcmpre(mi->si.Name, mask, !option(SYMOPT_CASE_INSENSITIVE))) disp = false; if (disp) peprint(pe, "%s%s: %s\n", pad, dispsymtag(mi->si.Tag), mi->si.Name); diaEnumScope(pe, mi, tag, mask, callback, context, use64, unicode, flags, idiaSymbol, depth + 1); }
return true; }
BOOL diaGetItems( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, PCSTR name, DWORD64 addr, DWORD tag, PROC callback, PVOID context, BOOL use64, BOOL unicode, DWORD flags ) { PDIA pdia; HRESULT hr; CHAR symname[MAX_SYM_NAME + 1];
CComPtr< IDiaSymbol > idiaGlobals;
// check parameters
assert(pe && mi);
if (!callback) return false;
if (!name) name = "*"; PrepRE4Srch(name, symname);
// get a session ...
pdia = (PDIA)mi->dia; if (!pdia) return false;
hr = pdia->session->get_globalScope(&idiaGlobals); if (hr != S_OK) return false;
// ... and enumerate the global scope
return diaEnumScope(pe, mi, tag, symname, callback, context, use64, unicode, flags, idiaGlobals, 1); }
BOOL diaGetSymbolsByTag( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, PCSTR name, DWORD64 addr, DWORD tag, PROC callback, PVOID context, BOOL use64, BOOL unicode, DWORD flags ) { BOOL rc; DWORD opt; BOOL fCase; PWCHAR wname; WCHAR wbuf[MAX_SYM_NAME + 1]; CHAR symname[MAX_SYM_NAME + 1]; PDIA pdia; HRESULT hr; DWORD celt;
CComPtr<IDiaSymbol> idiaSymbol; CComPtr< IDiaSymbol > idiaGlobals; CComPtr< IDiaEnumSymbols > idiaSymbols;
if (flags & SYMENUMFLAG_FULLSRCH) return diaGetItems(pe, mi, name, addr, tag, callback, context, use64, unicode, flags);
// check parameters
if (!name) name = "*";
assert(pe && mi);
if (!callback && !name) return false;
if (option(SYMOPT_CASE_INSENSITIVE)) { opt = nsCaseInsensitive; fCase = false; } else { opt = nsCaseSensitive; fCase = true; };
if (PrepRE4Srch(name, symname)) opt |= nsfRegularExpression;
wname = ConvertNameForDia(symname, wbuf);
// get a session
pdia = (PDIA)mi->dia; if (!pdia) return false;
hr = pdia->session->get_globalScope(&idiaGlobals); if (hr != S_OK) return false;
// presume we find nothing
rc = false;
hr = idiaGlobals->findChildren((enum SymTagEnum)tag, wname, opt, &idiaSymbols); if (hr != S_OK) return false;
for (; SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1; idiaSymbol = NULL) { if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) continue; mi->si.Scope = SymTagExe; if (!callback) return true; if (addr && (mi->si.Address != addr)) continue; if (flags & SYMENUMFLAG_SPEEDSRCH) { PSYM_LOCALENUMSYMBOL_CALLBACK cb = (PSYM_LOCALENUMSYMBOL_CALLBACK)callback; rc = cb(&mi->si, mi->si.Size, idiaSymbol, context); } else rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode); if (!rc) { mi->code = ERROR_CANCELLED; break; } } return rc; }
PSYMBOL_INFO diaGetSymFromToken( PMODULE_ENTRY mi, DWORD token ) { PDIA pdia; HRESULT hr;
CComPtr<IDiaSymbol> idiaSymbol;
// check parameters
assert(mi);
// get a session
pdia = (PDIA)mi->dia; if (!pdia) return NULL;
hr = pdia->session->findSymbolByToken(token, SymTagFunction, &idiaSymbol); if (hr != S_OK) return NULL;
if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) return NULL;
return &mi->si; }
BOOL diaGetGlobals( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPCSTR name, DWORD64 addr, PROC callback, PVOID context, BOOL use64, BOOL unicode ) { PDIA pdia; HRESULT hr; DWORD tag; DWORD celt; DWORD rc; LONG cFuncs; LONG cGlobals = 0; enum SymTagEnum SearchTag; PDWORD64 pGlobals = NULL; PDWORD64 pg = NULL; PWCHAR wname; DWORD opt; WCHAR wbuf[MAX_SYM_NAME + 1]; CHAR symname[MAX_SYM_NAME + 1]; CHAR pname[MAX_SYM_NAME + 1]; BOOL fCase;
CComPtr<IDiaSymbol> idiaSymbol; CComPtr< IDiaSymbol > idiaGlobals; CComPtr< IDiaEnumSymbols > idiaSymbols;
// check parameters
assert(pe && mi && name);
if (!callback && !name) return false;
if (option(SYMOPT_CASE_INSENSITIVE)) { opt = nsCaseInsensitive; fCase = false; } else { opt = nsCaseSensitive; fCase = true; };
if (PrepRE4Srch(name, symname)) opt |= nsfRegularExpression;
wname = ConvertNameForDia(symname, wbuf);
// get a session
pdia = (PDIA)mi->dia; if (!pdia) return false;
hr = pdia->session->get_globalScope(&idiaGlobals); if (hr != S_OK) return false;
// presume we find nothing
rc = false;
// see if there are any globals at all
// skip normal symbols, if so required
if (option(SYMOPT_PUBLICS_ONLY)) goto publics;
// if this is an enumeration, we will have to store a list of the addresses
// of all the symbols we found in the global scope. Later we will compare
// this to the publics so as to eliminate doubles.
if (callback) { hr = idiaGlobals->findChildren(SymTagData, wname, opt, &idiaSymbols); if (hr != S_OK) return false; hr = idiaSymbols->get_Count(&cGlobals); if (hr != S_OK) return false; idiaSymbols = NULL;
hr = idiaGlobals->findChildren(SymTagFunction, wname, opt, &idiaSymbols); if (hr != S_OK) return false; hr = idiaSymbols->get_Count(&cFuncs); if (hr != S_OK) return false; idiaSymbols = NULL; cGlobals += cFuncs;
pGlobals = (PDWORD64)MemAlloc(cGlobals * sizeof(DWORD64)); }
if (callback && (!cGlobals || !pGlobals)) goto publics;
ZeroMemory(pGlobals, cGlobals * sizeof(DWORD64));
// First search for data
SearchTag = SymTagData; hr = idiaGlobals->findChildren(SearchTag, wname, opt, &idiaSymbols); if (hr != S_OK) goto publics;
for (pg = pGlobals; (SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1) || (SearchTag == SymTagData); idiaSymbol = NULL) { ULONG DataKind;
if ((SearchTag == SymTagData) && (FAILED(hr) || celt != 1)) { // Now search for functions
SearchTag = SymTagFunction; idiaSymbols = NULL; hr = idiaGlobals->findChildren(SearchTag, wname, opt, &idiaSymbols); if (hr == S_OK) continue; }
idiaSymbol->get_symTag(&tag); switch (tag) { case SymTagData: case SymTagFunction: assert(!callback || ((LONG)(pg - pGlobals) < cGlobals)); if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) continue; if (!strcmp(mi->si.Name, "`string'")) continue; mi->si.Scope = SymTagExe; if (!callback) return true; if (mi->si.Flags & SYMFLAG_CONSTANT) continue; if (addr && (mi->si.Address != addr)) continue; if (pg) *pg++ = mi->si.Address; rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode); if (!rc) { mi->code = ERROR_CANCELLED; goto exit; } break; default: break; } }
qsort(pGlobals, cGlobals, sizeof(DWORD64), CompareAddrs);
publics: if (option(SYMOPT_NO_PUBLICS)) goto exit; if (option(SYMOPT_AUTO_PUBLICS) && cGlobals && !IsRegularExpression(name)) goto exit;
// now check out the publics table
if (wname) { PrintString(pname, DIMA(pname), "*%s*", symname); MakeEmbeddedREStr(pname, symname); wname = ConvertNameForDia(pname, wbuf); }
idiaSymbols = NULL;
opt |= nsfUndecoratedName | nsfRegularExpression;
hr = idiaGlobals->findChildren(SymTagPublicSymbol, wname, opt, &idiaSymbols); if (hr != S_OK) goto exit;
for (; SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1; idiaSymbol = NULL) { if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) continue; mi->si.Scope = SymTagPublicSymbol; if (!strcmp(mi->si.Name, "`string'")) continue; // publics names are mangled: this tests the undecorated name against the mask
if (*name && strcmpre(mi->si.Name, name, fCase)) continue; if (!callback) return true; if (FindAddr(pGlobals, cGlobals, mi->si.Address)) continue; if (addr && (mi->si.Address != addr)) continue; rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode); if (!rc) { mi->code = ERROR_CANCELLED; goto exit; } }
// We reached the end. If we are not enumerating (I.E. callback == NULL)
// then return the result of the last call to the callback. If we are
// searching for a single match, we have failed and should return false;
exit: MemFree(pGlobals); if (!callback) return false; return rc; }
BOOL diaGetSymbols( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, PCSTR name, PROC callback, PVOID context, BOOL use64, BOOL unicode ) { // ENUMFIX:
LPCSTR pname = (name) ? name : "";
if (mi) { return diaGetGlobals(pe, mi, pname, 0, callback, context, use64, unicode); } else { return diaGetLocals(pe, pname, callback, context, use64, unicode); } }
PSYMBOL_INFO diaFindSymbolByName( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPSTR SymName ) { if (!diaGetSymbols(pe, mi, SymName, NULL, NULL, 0, 0)) return NULL;
if (!mi) mi = pe->ipmi;
return &mi->si; }
BOOL diaEnumerateSymbols( IN PPROCESS_ENTRY pe, IN PMODULE_ENTRY mi, IN PCSTR mask, IN PROC callback, IN PVOID context, IN BOOL use64, IN BOOL unicode ) { return diaGetSymbols(pe, mi, mask, callback, context, use64, unicode); }
BOOL diaEnumSymForAddr( IN PPROCESS_ENTRY pe, IN PMODULE_ENTRY mi, IN DWORD64 addr, IN PROC callback, IN PVOID context, IN BOOL use64, IN BOOL unicode ) { return diaGetGlobals(pe, mi, "", addr, callback, context, use64, unicode); }
PSYMBOL_INFO diaGetSymFromAddr( PMODULE_ENTRY mi, DWORD64 addr, PDWORD64 disp ) { HRESULT hr; PDIA pdia; DWORD rva; DWORD tag; LONG omapadj; BOOL fHitBlock;
// simple sanity check
if (!addr) return NULL;
assert (mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
#ifdef DEBUG
if (traceAddr(addr)) // for debug breakpoints ...
dtrace("found 0x%I64x\n", addr); #endif
rva = (DWORD)(addr - mi->BaseOfDll);
// get the symbol
CComPtr< IDiaSymbol > idiaSymbol = NULL;
fHitBlock = false; if (!option(SYMOPT_PUBLICS_ONLY)) {
hr = pdia->session->findSymbolByRVAEx(rva, SymTagNull, &idiaSymbol, &omapadj); if (hr != S_OK) return NULL;
// if the symbol is a block, keep grabbing the parent
// until we get a function...
idiaSymbol->get_symTag(&tag); while (tag == SymTagBlock) { // SymTagLabel as well?
CComPtr< IDiaSymbol > idiaParent; fHitBlock = true; hr = idiaSymbol->get_lexicalParent(&idiaParent); if (hr != S_OK || !idiaParent) return NULL; idiaSymbol = idiaParent; idiaSymbol->get_symTag(&tag); }
}
if (option(SYMOPT_NO_PUBLICS)) return NULL;
if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) { // return a public symbol
idiaSymbol = NULL; hr = pdia->session->findSymbolByRVAEx(rva, SymTagPublicSymbol, &idiaSymbol, &omapadj); if (hr == S_OK) diaFillSymbolInfo(&mi->si, mi, idiaSymbol); }
if (disp) *disp = (fHitBlock) ? addr - mi->si.Address : omapadj;
return &mi->si; }
PSYMBOL_INFO diaGetSymFromAddrByTag( PMODULE_ENTRY mi, DWORD64 addr, DWORD tag, PDWORD64 disp ) { HRESULT hr; PDIA pdia; DWORD rva; LONG omapadj;
// simple sanity check
if (!addr) return NULL;
assert (mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
rva = (DWORD)(addr - mi->BaseOfDll);
// get the symbol
CComPtr< IDiaSymbol > idiaSymbol = NULL;
hr = pdia->session->findSymbolByRVAEx(rva, (enum SymTagEnum)tag, &idiaSymbol, &omapadj); if (hr != S_OK) return NULL;
diaFillSymbolInfo(&mi->si, mi, idiaSymbol); if (disp) *disp = addr - mi->si.Address;
return &mi->si; }
typedef struct _ENUMOBJS { PPROCESS_ENTRY pe; PMODULE_ENTRY mi; PSYM_ENUMLINES_CALLBACK cb; PCSTR file; PVOID context; } ENUMOBJS, *PENUMOBJS;
BOOL cbEnumObjs( PSYMBOL_INFO si, ULONG size, IDiaSymbol *idiaObj, PVOID context ) { WCHAR wbuf[MAX_PATH + 1]; BSTR wfname = NULL; HRESULT hr; PDIA pdia; PMODULE_ENTRY mi; PENUMOBJS eno = (PENUMOBJS)context; PSYM_ENUMLINES_CALLBACK cb;
WCHAR wsz[_MAX_PATH + 1]; char file[MAX_PATH + 1]; BSTR bstr; DWORD dw; BOOL rc; CComPtr< IDiaEnumSourceFiles > idiaSrcFiles = NULL; CComPtr< IDiaSourceFile > idiaSrcFile = NULL; CComPtr< IDiaEnumLineNumbers > idiaLines = NULL; CComPtr< IDiaLineNumber > idiaLine = NULL;
dtrace("%s\n", si->Name);
// get initial data and store the obj name
pdia = (PDIA)eno->mi->dia; if (!pdia) return false; cb = (PSYM_ENUMLINES_CALLBACK)eno->cb; mi = eno->mi; if (!mi) return false; if (!*si->Name) return false; CopyString(mi->sci.Obj, si->Name, MAX_PATH + 1); mi->sci.ModBase = mi->BaseOfDll;
// prepare the source file name mask
wfname = NULL; if (eno->file && *eno->file) { ansi2wcs(eno->file, wbuf, MAX_PATH); wfname = wbuf; }
// get all the source files
hr = pdia->session->findFile(idiaObj, wfname, nsCaseInsensitive, &idiaSrcFiles); if (hr != S_OK) return false;
while (idiaSrcFiles->Next(1, &idiaSrcFile, &dw) == S_OK) {
hr = idiaSrcFile->get_fileName(&bstr); if (hr != S_OK) break;
rc = wcs2ansi(bstr, mi->sci.FileName, MAX_PATH + 1); LocalFree(bstr); if (!rc || !*mi->sci.FileName) break;
hr = pdia->session->findLines(idiaObj, idiaSrcFile, &idiaLines); if (hr != S_OK) break;
while (idiaLines->Next(1, &idiaLine, &dw) == S_OK) { hr = idiaLine->get_lineNumber(&mi->sci.LineNumber); if (hr != S_OK) return false; hr = idiaLine->get_relativeVirtualAddress(&dw); if (hr != S_OK) return false; mi->sci.Address = dw + mi->BaseOfDll; idiaLine = NULL; if (cb) rc = cb(&mi->sci, context); }
idiaLines = NULL; idiaSrcFile = NULL; }
return true; }
BOOL diaEnumLines( IN PPROCESS_ENTRY pe, IN PMODULE_ENTRY mi, IN PCSTR obj, IN PCSTR file, IN PSYM_ENUMLINES_CALLBACK cb, IN PVOID context ) { ENUMOBJS eno;
eno.pe = pe; eno.mi = mi; eno.cb = cb; eno.file = file; eno.context = context;
return diaGetSymbolsByTag(pe, mi, obj, 0, SymTagCompiland, (PROC)cbEnumObjs, &eno, false, false, SYMENUMFLAG_SPEEDSRCH); }
BOOL diaGetLineFromAddr( PMODULE_ENTRY mi, DWORD64 addr, PDWORD displacement, PSRCCODEINFO sci ) { HRESULT hr; PDIA pdia; DWORD rva; DWORD celt; BSTR bstr; DWORD dw; BOOL rc;
assert(mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
rva = (DWORD)(addr - mi->BaseOfDll);
// On IA64 the slots in a bundle don't have byte addresses.
// The debugger calls them 0,4,8 by default whereas line
// symbols have them as 0,1,2. Convert to line style
// before querying.
if (mi->MachineType == IMAGE_FILE_MACHINE_IA64 && (rva & 0xf)) { switch(rva & 0xf) { case 4: rva -= 3; break; case 8: rva -= 6; break; default: // Invalid slot address.
return false; } }
CComPtr< IDiaEnumLineNumbers > idiaLines = NULL; hr = pdia->session->findLinesByRVA(rva, 1, &idiaLines); if (hr != S_OK) return false;
CComPtr< IDiaLineNumber > idiaLine = NULL; hr = idiaLines->Next(1, &idiaLine, &celt); if (hr != S_OK || !idiaLine) return false;
hr = idiaLine->get_lineNumber(&dw); if (hr != S_OK) return false;
sci->LineNumber = dw;
pdia->srcfile = NULL; hr = idiaLine->get_sourceFile(&pdia->srcfile); if (hr != S_OK) return false;
hr = pdia->srcfile->get_fileName(&bstr); if (hr != S_OK) return false;
*sci->FileName = 0; rc = wcs2ansi(bstr, sci->FileName, DIMA(sci->FileName)); LocalFree(bstr); if (!rc || !*sci->FileName) return false;
hr = idiaLine->get_relativeVirtualAddress(&dw); if (hr != S_OK) return false;
sci->Address = dw + mi->BaseOfDll; *displacement = rva - dw;
return true; }
BOOL diaGetNextLineFromEnum( IDiaEnumLineNumbers *idiaLines, DWORD *line, DWORD *rva ) { HRESULT hr; ULONG ul;
CComPtr< IDiaLineNumber > idiaLine = NULL;
hr = idiaLines->Next(1, &idiaLine, &ul); if (hr != S_OK) return false;
hr = idiaLine->get_lineNumber(line); if (hr != S_OK) return false;
hr = idiaLine->get_relativeVirtualAddress(rva); if (hr != S_OK) return false;
return true; }
BOOL diaGetLineNextPrev( PMODULE_ENTRY mi, PIMAGEHLP_LINE64 line, DWORD direction ) { HRESULT hr; PDIA pdia; DWORD rva; DWORD celt; WCHAR wbuf[MAX_PATH + 1]; BSTR wfname = NULL; DWORD64 bAddr; DWORD trgnum; DWORD num; DWORD dw; DWORD num1 = 0; DWORD num2 = 0; DWORD rva1 = 0; DWORD rva2 = 0; LONG numlines;
// simple sanity checks
assert(mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return false;
assert(direction == NP_NEXT || direction == NP_PREV);
if (line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) return false;
// convert file name for DIA
if (!*line->FileName) return false;
ansi2wcs(line->FileName, wbuf, MAX_PATH); wfname = wbuf;
// save the last found line
bAddr = line->Address;
// all source files in the module that match the 'wfname'
CComPtr< IDiaEnumSourceFiles > idiaSrcFiles = NULL; hr = pdia->session->findFile(NULL, wfname, nsCaseInsensitive, &idiaSrcFiles); if (hr != S_OK) return false;
// the first such file in the list, since we don't use wildcards
CComPtr< IDiaSourceFile > idiaSrcFile = NULL; hr = idiaSrcFiles->Next(1, &idiaSrcFile, &dw); if (hr != S_OK) return false;
// all objs that use this source file
CComPtr< IDiaEnumSymbols > idiaObjs = NULL; hr = idiaSrcFile->get_compilands(&idiaObjs); if (hr != S_OK) return false;
// LOOP THROUGH ALL THE OBJS! AND STORE THE CLOSEST!
num = 0; rva = 0;
// grab the first obj, since we don't care
CComPtr< IDiaSymbol > idiaObj = NULL; CComPtr< IDiaEnumLineNumbers > idiaLines = NULL;
hr = idiaObjs->Next(1, &idiaObj, &celt); if (hr != S_OK) return false;
// get the line for starting with
trgnum = line->LineNumber + direction; hr = pdia->session->findLinesByLinenum(idiaObj, idiaSrcFile, trgnum, 0, &idiaLines); if (hr != S_OK) return false;
hr = idiaLines->get_Count(&numlines); diaGetNextLineFromEnum(idiaLines, &num1, &rva1); if (numlines > 1) diaGetNextLineFromEnum(idiaLines, &num2, &rva2); if (direction == NP_PREV) { num = num1; rva = rva1; } else if (num1 == trgnum) { num = num1; rva = rva1; } else { num = num2; rva = rva2; } if (!num) return false;
if (bAddr == GetLineAddressFromRva(mi, rva)) return false;
line->LineNumber = num; line->Address = GetLineAddressFromRva(mi, rva);
return true; }
#if 0
#define DBG_DIA_LINE 1
#endif
BOOL diaGetLineFromName( PMODULE_ENTRY mi, LPSTR filename, DWORD linenumber, PLONG displacement, PSRCCODEINFO sci, DWORD method ) { HRESULT hr; WCHAR wsz[_MAX_PATH + 1]; char sz[MAX_PATH + 1]; PDIA pdia; DWORD celt; BSTR bstr; DWORD addr; DWORD num; BOOL rc; DWORD flags; LONG cFiles; int i;
CComPtr<IDiaEnumSourceFiles> idiaSrcFiles; CComPtr<IDiaSourceFile> idiaSrcFile; CComPtr<IDiaEnumSymbols> idiaEnum; CComPtr<IDiaSymbol> idiaSymbol; CComPtr<IDiaEnumLineNumbers> idiaLineNumbers; CComPtr<IDiaLineNumber> idiaLineNumber;
assert(mi && mi->dia && filename); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
sciInit(sci);
if (!ansi2wcs(filename, wsz, DIMA(wsz))) return false; if (!*wsz) return false;
flags = (method == mFullPath) ? nsfCaseInsensitive : nsFNameExt;
// get list of matching files and the count of the list
hr = pdia->session->findFile(NULL, wsz, flags, &idiaSrcFiles); if (hr != S_OK) return false; hr = idiaSrcFiles->get_Count(&cFiles); if (hr != S_OK) return false;
*sci->FileName = 0; for (i = 0; i < cFiles; i++) { hr = idiaSrcFiles->Next(1, &idiaSrcFile, &celt); if (hr != S_OK) continue;
hr = idiaSrcFile->get_fileName(&bstr); if (hr != S_OK) continue;
rc = wcs2ansi(bstr, sz, DIMA(sz)); LocalFree(bstr); if (!rc || !*sz) continue;
UpdateBestSrc(filename, sci->FileName, sz); }
if (!*sci->FileName) return false;
// this gives us a list of every .obj that uses this source file
hr = idiaSrcFile->get_compilands(&idiaEnum); if (hr != S_OK) return false;
// we don't support multiple objs, so lets take the first one
hr = idiaEnum->Next(1, &idiaSymbol, &celt); if (hr != S_OK) return false;
// This gets a list of all code items that were created from this source line.
// If we want to fully support inlines and the like, we need to loop all of these
hr = pdia->session->findLinesByLinenum(idiaSymbol, idiaSrcFile, linenumber, 0, &idiaLineNumbers); if (hr != S_OK) return false;
idiaLineNumber = NULL; hr = idiaLineNumbers->Next(1, &idiaLineNumber, &celt); if (hr != S_OK) return false; hr = idiaLineNumber->get_lineNumber(&num); if (hr != S_OK) return false; sci->LineNumber = num; hr = idiaLineNumber->get_relativeVirtualAddress(&addr); if (hr != S_OK) return false; if (!addr) return false;
sci->Address = GetLineAddressFromRva(mi, addr); *displacement = linenumber - num;
return true; }
BOOL MatchSourceFile( PCHAR filename, PCHAR mask ) { PCHAR p;
if (!mask || !*mask) return true;
if (!*filename) return false;
for (p = filename + strlen(filename); p >= filename; p--) { if (*p == '\\' || *p == '/') { p++; break; } }
if (!strcmpre(p, mask, false)) return true;
return false; }
BOOL diaEnumSourceFiles( IN PMODULE_ENTRY mi, IN PCHAR mask, IN PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles, IN PVOID context ) { HRESULT hr; BSTR wname=NULL; char name[_MAX_PATH + 1]; SOURCEFILE sf;
assert(mi && cbSrcFiles);
PDIA pdia; pdia = (PDIA)mi->dia;
sf.ModBase = mi->BaseOfDll ; sf.FileName = name;
CComPtr< IDiaEnumSourceFiles > idiaEnumFiles; hr = pdia->session->findFile(NULL, NULL, nsNone, &idiaEnumFiles); if (hr != S_OK) return false;
ULONG celt; CComPtr <IDiaSourceFile> idiaSource; for (;SUCCEEDED(idiaEnumFiles->Next(1, &idiaSource, &celt)) && (celt == 1);) { hr = idiaSource->get_fileName(&wname); if (hr == S_OK && wname) { wcs2ansi(wname, name, _MAX_PATH); LocalFree (wname); if (MatchSourceFile(name, mask)) { if (!cbSrcFiles(&sf, context)) { mi->code = ERROR_CANCELLED; return false; } } } idiaSource = NULL; }
return true; }
PSYMBOL_INFO diaGetSymNextPrev( PMODULE_ENTRY mi, DWORD64 addr, int direction ) { HRESULT hr; PDIA pdia; DWORD rva; DWORD celt;
assert(mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
CComPtr<IDiaEnumSymbolsByAddr> idiaSymbols; hr = pdia->session->getSymbolsByAddr(&idiaSymbols); if (hr != S_OK) return NULL;
rva = addr ? (DWORD)(addr - mi->BaseOfDll) : 0;
CComPtr<IDiaSymbol> idiaSymbol; hr = idiaSymbols->symbolByRVA(rva, &idiaSymbol); if (hr != S_OK) return NULL;
findsymbol: if (addr) { if (direction < 0) { idiaSymbol = NULL; hr = idiaSymbols->Prev(1, &idiaSymbol, &celt); } else { idiaSymbol = NULL; hr = idiaSymbols->Next(1, &idiaSymbol, &celt); } if (hr != S_OK) return NULL; if (celt != 1) return NULL; }
diaFillSymbolInfo(&mi->si, mi, idiaSymbol); if (!*mi->si.Name) { rva = (DWORD)(mi->si.Address - mi->BaseOfDll); goto findsymbol; }
return &mi->si; }
HRESULT diaGetSymTag(IDiaSymbol *pType, PULONG pTag) { return pType->get_symTag(pTag); }
HRESULT diaGetSymIndexId(IDiaSymbol *pType, PULONG pIndex) { return pType->get_symIndexId(pIndex); }
HRESULT diaGetLexicalParentId(IDiaSymbol *pType, PULONG pIndex) { return pType->get_lexicalParentId(pIndex); }
HRESULT diaGetDataKind(IDiaSymbol *pType, PULONG pKind) { return pType->get_dataKind(pKind); }
HRESULT diaGetSymName(IDiaSymbol *pType, BSTR *pname) { return pType->get_name(pname); }
HRESULT diaGetLength(IDiaSymbol *pType, PULONGLONG pLength) { return pType->get_length(pLength); }
HRESULT diaGetType(IDiaSymbol *pType, IDiaSymbol ** pSymbol) { return pType->get_type(pSymbol); }
HRESULT diaGetBaseType(IDiaSymbol *pType, PULONG pBase) { return pType->get_baseType(pBase); }
HRESULT diaGetArrayIndexTypeId(IDiaSymbol *pType, PULONG pSymbol) { return pType->get_arrayIndexTypeId(pSymbol); }
HRESULT diaGetTypeId(IDiaSymbol *pType, PULONG pTypeId) { return pType->get_typeId(pTypeId); }
HRESULT diaGetCallingConvention(IDiaSymbol *pType, PULONG pConvention) { HRESULT hr;
hr = pType->get_callingConvention(pConvention); if (hr != S_OK) *pConvention = CV_CALL_RESERVED;
return hr; }
HRESULT diaGetChildrenCount(IDiaSymbol *pType, LONG *pCount) { CComPtr <IDiaEnumSymbols> pEnum; HRESULT hr; ULONG index; CComPtr <IDiaSymbol> pSym; ULONG Count;
if ((hr = pType->findChildren(SymTagNull, NULL, nsNone, &pEnum)) != S_OK) { return hr; } return pEnum->get_Count(pCount); }
HRESULT diaFindChildren(IDiaSymbol *pType, TI_FINDCHILDREN_PARAMS *Params) { CComPtr <IDiaEnumSymbols> pEnum; HRESULT hr; ULONG index; CComPtr <IDiaSymbol> pSym; ULONG Count;
if ((hr = pType->findChildren(SymTagNull, NULL, nsNone, &pEnum)) != S_OK) { return hr; }
VARIANT var;
pEnum->Skip(Params->Start); for (Count = Params->Count, index = Params->Start; Count > 0; Count--, index++) { ULONG celt; pSym = NULL; if ((hr = pEnum->Next(1, &pSym, &celt)) != S_OK) { return hr; }
if ((hr = pSym->get_symIndexId(&Params->ChildId[index])) != S_OK) { return hr; } } return S_OK; }
HRESULT diaGetAddressOffset(IDiaSymbol *pType, ULONG *pOff) { return pType->get_addressOffset(pOff); }
HRESULT diaGetOffset(IDiaSymbol *pType, LONG *pOff) { return pType->get_offset(pOff); }
HRESULT diaGetValue(IDiaSymbol *pType, VARIANT *pVar) { return pType->get_value(pVar); }
HRESULT diaGetCount(IDiaSymbol *pType, ULONG *pCount) { return pType->get_count(pCount); }
HRESULT diaGetBitPosition(IDiaSymbol *pType, ULONG *pPos) { return pType->get_bitPosition(pPos); }
HRESULT diaGetVirtualBaseClass(IDiaSymbol *pType, BOOL *pBase) { return pType->get_virtualBaseClass(pBase); }
HRESULT diaGetVirtualTableShapeId(IDiaSymbol *pType, PULONG pShape) { return pType->get_virtualTableShapeId(pShape); }
HRESULT diaGetVirtualBasePointerOffset(IDiaSymbol *pType, LONG *pOff) { return pType->get_virtualBasePointerOffset(pOff); }
HRESULT diaGetClassParentId(IDiaSymbol *pType, ULONG *pCid) { return pType->get_classParentId(pCid); }
HRESULT diaGetNested(IDiaSymbol *pType, BOOL *pNested) { return pType->get_nested(pNested); }
HRESULT diaGetSymAddress(IDiaSymbol *pType, ULONG64 ModBase, PULONG64 pAddr) { ULONG rva; HRESULT Hr;
Hr = pType->get_relativeVirtualAddress(&rva); if (Hr == S_OK) *pAddr = ModBase + rva; return Hr; }
HRESULT diaGetThisAdjust(IDiaSymbol *pType, LONG *pThisAdjust) { return pType->get_thisAdjust(pThisAdjust); }
HRESULT diaGetUdtKind(IDiaSymbol *pType, DWORD *pUdtKind) { return pType->get_udtKind(pUdtKind); }
BOOL diaCompareTypeSym( IN HANDLE hProcess, IN DWORD64 ModBase, IN IDiaSymbol *pType1, IN OUT PULONG TypeId2 ) { PPROCESS_ENTRY ProcessEntry; PDIA pdia; PMODULE_ENTRY mi; CComPtr<IDiaSymbol> pType2;
ProcessEntry = FindProcessEntry( hProcess ); if (!ProcessEntry || !(mi = GetModFromAddr(ProcessEntry, ModBase))) { return false; }
pdia = (PDIA)mi->dia; if (!pdia) { return false; } if (pdia->session->symbolById(*TypeId2, &pType2) != S_OK) { return false; } if (pdia->session->symsAreEquiv(pType1, pType2) != S_OK) { *TypeId2 = 0; } return true; }
BOOL diaFindTypeSym( IN HANDLE hProcess, IN DWORD64 ModBase, IN ULONG TypeId, OUT IDiaSymbol **pType ) { PPROCESS_ENTRY ProcessEntry; PDIA pdia; PMODULE_ENTRY mi;
ProcessEntry = FindProcessEntry( hProcess ); if (!ProcessEntry || !(mi = GetModFromAddr(ProcessEntry, ModBase))) { return false; }
pdia = (PDIA)mi->dia; if (!pdia) { return false; } return pdia->session->symbolById(TypeId, pType) == S_OK; }
#ifdef USE_CACHE
ULONG gHits=0, gLook=0;
void diaInsertInCache( PDIA_CACHE_ENTRY pCache, PDIA_LARGE_DATA plVals, ULONGLONG Module, ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType, PVOID pInfo ) { if (GetType == TI_IS_EQUIV_TO) { // Not cached.
return; }
int start = CACHE_BLOCK * (TypeId % CACHE_BLOCK); int i, found; ULONG len,age; PDIA_LARGE_DATA pLargeVal=NULL;
if (GetType == TI_FINDCHILDREN || GetType == TI_GET_SYMNAME) { for (pLargeVal = plVals, found=i=0, age=0; i<2*CACHE_BLOCK; i++) { if (!plVals[i].Used) { pLargeVal = &plVals[i]; break; } else if (pCache[plVals[i].Index].Age > age) { pLargeVal = &plVals[i]; age = pCache[plVals[i].Index].Age; assert(DIACH_PLVAL == pCache[pLargeVal->Index].Data.type); assert(pLargeVal == pCache[pLargeVal->Index].Data.plVal); } } // } else {
// return;
} // if (!(gLook % 200)) {
// if (GetType == TI_FINDCHILDREN || GetType == TI_GET_SYMNAME) {
// printf("Index \tUsed\tBy\t\tfound %lx\n", pLargeVal);
// for (found=i=0, age=0; i<2*CACHE_BLOCK; i++) {
// printf("%08lx \t%lx\t%lx\n",
// &plVals[i], plVals[i].Used, plVals[i].Index);
// }
// }
// }
for (i=found=start, age=0; i<(start+CACHE_BLOCK); i++) { if (++pCache[i].Age > age) { age = pCache[i].Age; found = i; } } i=found; if (pCache[i].Data.type == DIACH_PLVAL) { assert(pCache[i].Data.plVal->Index == (ULONG) i); pCache[i].Data.plVal->Index = 0; pCache[i].Data.plVal->Used = 0; pCache[i].Data.type = 0; pCache[i].Data.ullVal = 0; } pCache[i].Age = 0; pCache[i].s.DataType = GetType; pCache[i].s.TypeId = TypeId; pCache[i].Module = Module;
switch (GetType) { case TI_GET_SYMTAG: case TI_GET_COUNT: case TI_GET_CHILDRENCOUNT: case TI_GET_BITPOSITION: case TI_GET_VIRTUALBASECLASS: case TI_GET_VIRTUALTABLESHAPEID: case TI_GET_VIRTUALBASEPOINTEROFFSET: case TI_GET_CLASSPARENTID: case TI_GET_TYPEID: case TI_GET_BASETYPE: case TI_GET_ARRAYINDEXTYPEID: case TI_GET_DATAKIND: case TI_GET_ADDRESSOFFSET: case TI_GET_OFFSET: case TI_GET_NESTED: case TI_GET_THISADJUST: case TI_GET_UDTKIND: pCache[i].Data.type = DIACH_ULVAL; pCache[i].Data.ulVal = *((PULONG) pInfo); break;
case TI_GET_LENGTH: case TI_GET_ADDRESS: pCache[i].Data.type = DIACH_ULLVAL; pCache[i].Data.ullVal = *((PULONGLONG) pInfo); break;
case TI_GET_SYMNAME: { len = 2*(1+wcslen(*((BSTR *) pInfo)));
if (pLargeVal && len < sizeof(pLargeVal->Bytes)) { // dtrace("Ins name %08lx %s had %3lx name %ws\n",
// pLargeVal, pLargeVal->Used ? "used" : "free",
// pLargeVal->Index, &pLargeVal->Bytes[0]);
memcpy(&pLargeVal->Bytes[0], *((BSTR *) pInfo), len); pLargeVal->LengthUsed = len;
if (pLargeVal->Used) { pCache[pLargeVal->Index].Data.type = 0; pCache[pLargeVal->Index].Data.ullVal = 0; pCache[pLargeVal->Index].SearchId = 0; } pCache[i].Data.type = DIACH_PLVAL; pCache[i].Data.plVal = pLargeVal; pLargeVal->Index = i; pLargeVal->Used = true; // dtrace(Ins %9I64lx ch %3lx lch %08lx name %ws\n",
// pCache[i].SearchId, i, pLargeVal, &pLargeVal->Bytes[0]);
} else { pCache[i].SearchId = 0; } break; } case TI_FINDCHILDREN: { TI_FINDCHILDREN_PARAMS *pChild = (TI_FINDCHILDREN_PARAMS *) pInfo;
len = sizeof(TI_FINDCHILDREN_PARAMS) + pChild->Count*sizeof(pChild->ChildId[0]) - sizeof(pChild->ChildId);
if (pLargeVal && len < sizeof(pLargeVal->Bytes)) { // dtrace("Ins child %08lx %s had %3lx name %ws\n",
// pLargeVal, pLargeVal->Used ? "used" : "free",
// pLargeVal->Index, &pLargeVal->Bytes[0]);
memcpy(&pLargeVal->Bytes[0], pChild, len); pLargeVal->LengthUsed = len; if (pLargeVal->Used) { pCache[pLargeVal->Index].Data.type = 0; pCache[pLargeVal->Index].Data.ullVal = 0; pCache[pLargeVal->Index].SearchId = 0; } pCache[i].Data.type = DIACH_PLVAL; pCache[i].Data.plVal = pLargeVal; pLargeVal->Index = i; pLargeVal->Used = true; } else { pCache[i].SearchId = 0; } break; } case TI_GET_VALUE: default: pCache[i].Data.type = 0; pCache[i].SearchId = 0; return ; }
}
BOOL diaLookupCache( PDIA_CACHE_ENTRY pCache, ULONG64 Module, ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType, PVOID pInfo ) { if (GetType == TI_IS_EQUIV_TO) { // Not cached.
return false; }
int start = CACHE_BLOCK * (TypeId % CACHE_BLOCK); int i, found; ULONGLONG Search = ((ULONGLONG) GetType << 32) + TypeId;
++gLook;
for (i=start,found=-1; i<(start+CACHE_BLOCK); i++) { if (pCache[i].SearchId == Search && pCache[i].Module == Module) { found = i; break; } } if (found == -1) { return false; }
i=found; pCache[i].Age = 0; switch (pCache[i].Data.type) { case DIACH_ULVAL: *((PULONG) pInfo) = pCache[i].Data.ulVal; break;
case DIACH_ULLVAL: *((PULONGLONG) pInfo) = pCache[i].Data.ullVal; break;
case DIACH_PLVAL: if (GetType == TI_GET_SYMNAME) {
*((BSTR *) pInfo) = (BSTR) LocalAlloc(0, pCache[i].Data.plVal->LengthUsed);
if (*((BSTR *) pInfo)) { memcpy(*((BSTR *) pInfo), &pCache[i].Data.plVal->Bytes[0],pCache[i].Data.plVal->LengthUsed); // dtrace(Lok %9I64lx ch %3lx lch %08lx name %ws\n",
// pCache[i].SearchId,
// i,
// pCache[i].Data.plVal,
// &pCache[i].Data.plVal->Bytes[0]);
} } else if (GetType == TI_FINDCHILDREN) { TI_FINDCHILDREN_PARAMS *pChild = (TI_FINDCHILDREN_PARAMS *) pInfo; TI_FINDCHILDREN_PARAMS *pStored = (TI_FINDCHILDREN_PARAMS *) &pCache[i].Data.plVal->Bytes[0]; // dtrace(Lok %9I64lx ch %3lx lch %08lx child %lx\n",
// pCache[i].SearchId,
// i,
// pCache[i].Data.plVal,
// pStored->Count);
if (pChild->Count == pStored->Count && pChild->Start == pStored->Start) { memcpy(pChild, pStored, pCache[i].Data.plVal->LengthUsed); } } break; default: assert(false); return false; } if (!(++gHits%50)) { // dtrace("%ld %% Hits\n", (gHits * 100) / gLook);
} return true; }
#endif // USE_CACHE
HRESULT #ifdef USE_CACHE
diaGetSymbolInfoEx( #else
diaGetSymbolInfo( #endif // USE_CACHE
IN HANDLE hProcess, IN DWORD64 ModBase, IN ULONG TypeId, IN IMAGEHLP_SYMBOL_TYPE_INFO GetType, OUT PVOID pInfo ) { assert(pInfo); CComPtr <IDiaSymbol> pTypeSym; if (!diaFindTypeSym(hProcess, ModBase, TypeId, &pTypeSym)) { return E_INVALIDARG; }
switch (GetType) { case TI_GET_SYMTAG: return diaGetSymTag(pTypeSym, (PULONG) pInfo); break; case TI_GET_SYMNAME: return diaGetSymName(pTypeSym, (BSTR *) pInfo); break; case TI_GET_LENGTH: return diaGetLength(pTypeSym, (PULONGLONG) pInfo); break; case TI_GET_TYPE: case TI_GET_TYPEID: return diaGetTypeId(pTypeSym, (PULONG) pInfo); break; case TI_GET_BASETYPE: return diaGetBaseType(pTypeSym, (PULONG) pInfo); break; case TI_GET_ARRAYINDEXTYPEID: return diaGetArrayIndexTypeId(pTypeSym, (PULONG) pInfo); break; case TI_FINDCHILDREN: return diaFindChildren(pTypeSym, (TI_FINDCHILDREN_PARAMS *) pInfo); case TI_GET_DATAKIND: return diaGetDataKind(pTypeSym, (PULONG) pInfo); break; case TI_GET_ADDRESSOFFSET: return diaGetAddressOffset(pTypeSym, (PULONG) pInfo); break; case TI_GET_OFFSET: return diaGetOffset(pTypeSym, (PLONG) pInfo); break; case TI_GET_VALUE: return diaGetValue(pTypeSym, (VARIANT *) pInfo); break; case TI_GET_COUNT: return diaGetCount(pTypeSym, (PULONG) pInfo); break; case TI_GET_CHILDRENCOUNT: return diaGetChildrenCount(pTypeSym, (PLONG) pInfo); break; case TI_GET_BITPOSITION: return diaGetBitPosition(pTypeSym, (PULONG) pInfo); break; case TI_GET_VIRTUALBASECLASS: return diaGetVirtualBaseClass(pTypeSym, (BOOL *) pInfo); break; case TI_GET_VIRTUALTABLESHAPEID: return diaGetVirtualTableShapeId(pTypeSym, (PULONG) pInfo); break; case TI_GET_VIRTUALBASEPOINTEROFFSET: return diaGetVirtualBasePointerOffset(pTypeSym, (PLONG) pInfo); break; case TI_GET_CLASSPARENTID: return diaGetClassParentId(pTypeSym, (PULONG) pInfo); break; case TI_GET_NESTED: return diaGetNested(pTypeSym, (PBOOL) pInfo); break; case TI_GET_SYMINDEX: return diaGetSymIndexId(pTypeSym, (PULONG) pInfo); break; case TI_GET_LEXICALPARENT: return diaGetLexicalParentId(pTypeSym, (PULONG) pInfo); break; case TI_GET_ADDRESS: return diaGetSymAddress(pTypeSym, ModBase, (PULONG64) pInfo); case TI_GET_THISADJUST: return diaGetThisAdjust(pTypeSym, (PLONG) pInfo); case TI_GET_UDTKIND: return diaGetUdtKind(pTypeSym, (PDWORD) pInfo); case TI_IS_EQUIV_TO: if (!diaCompareTypeSym(hProcess, ModBase, pTypeSym, (PULONG)pInfo)) { return E_INVALIDARG; } return *(PULONG)pInfo != 0 ? S_OK : S_FALSE; case TI_GET_CALLING_CONVENTION: return diaGetCallingConvention(pTypeSym, (PULONG)pInfo); break;
default: return E_INVALIDARG; } }
#ifdef USE_CACHE
HRESULT diaGetSymbolInfo( IN HANDLE hProcess, IN DWORD64 ModBase, IN ULONG TypeId, IN IMAGEHLP_SYMBOL_TYPE_INFO GetType, OUT PVOID pInfo ) { PPROCESS_ENTRY ProcessEntry;
ProcessEntry = FindProcessEntry( hProcess );
if (!ProcessEntry) { return E_INVALIDARG; } if (!diaLookupCache(ProcessEntry->DiaCache, ModBase, TypeId, GetType, pInfo)) { HRESULT hr = diaGetSymbolInfoEx(hProcess, ModBase, TypeId, GetType, pInfo); if (hr == S_OK) { diaInsertInCache(ProcessEntry->DiaCache, ProcessEntry->DiaLargeData, ModBase, TypeId, GetType, pInfo); } return hr; } return S_OK; } #endif // USE_CACHE
BOOL diaGetTiForUDT( PMODULE_ENTRY ModuleEntry, LPSTR name, PSYMBOL_INFO psi ) { BSTR wname=NULL; PDIA pdia; HRESULT hr; ULONG celt;
if (!ModuleEntry) { return false; }
pdia = (PDIA)ModuleEntry->dia; if (!pdia) return false;
CComPtr< IDiaSymbol > idiaSymbols; hr = pdia->session->get_globalScope(&idiaSymbols);
if (hr != S_OK) return false;
if (name) { wname = AnsiToUnicode(name); }
CComPtr< IDiaEnumSymbols > idiaEnum;
hr = idiaSymbols->findChildren(SymTagNull, wname, nsCaseSensitive, &idiaEnum); if (hr == S_OK) {
CComPtr< IDiaSymbol > idiaSymbol;
if ((hr = idiaEnum->Next( 1, &idiaSymbol, &celt)) == S_OK && celt == 1) { diaFillSymbolInfo(psi, ModuleEntry, idiaSymbol); idiaSymbol->get_symIndexId(&psi->TypeIndex); idiaSymbol = NULL; } }
MemFree(wname);
return hr == S_OK; }
BOOL diaEnumUDT( PMODULE_ENTRY ModuleEntry, LPSTR name, PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, PVOID context ) { BSTR wname=NULL; PDIA pdia; HRESULT hr; ULONG celt; CHAR buff[MAX_SYM_NAME + sizeof(SYMBOL_INFO)]; PSYMBOL_INFO psi=(PSYMBOL_INFO)buff; BOOL rc;
psi->MaxNameLen = MAX_SYM_NAME;
if (!ModuleEntry) { return false; }
pdia = (PDIA)ModuleEntry->dia; if (!pdia) return false;
CComPtr< IDiaSymbol > idiaSymbols; hr = pdia->session->get_globalScope(&idiaSymbols);
if (hr != S_OK) return false;
if (name && *name) { wname = AnsiToUnicode(name); }
CComPtr< IDiaEnumSymbols > idiaEnum;
hr = idiaSymbols->findChildren(SymTagNull, wname, nsCaseSensitive, &idiaEnum); if (hr == S_OK) {
CComPtr< IDiaSymbol > idiaSymbol;
while (SUCCEEDED(idiaEnum->Next( 1, &idiaSymbol, &celt)) && celt == 1) { ULONG tag; idiaSymbol->get_symTag(&tag); switch (tag) { case SymTagEnum: case SymTagTypedef: case SymTagUDT: if (EnumSymbolsCallback) { diaFillSymbolInfo(psi, ModuleEntry, idiaSymbol); idiaSymbol->get_symIndexId(&psi->TypeIndex); rc = EnumSymbolsCallback(psi, 0, context); if (!rc) return true; } break; default: break; } idiaSymbol = NULL; } }
MemFree(wname);
return hr == S_OK; }
BOOL ldiaGetFrameData( IN HANDLE Process, IN ULONGLONG Offset, OUT IDiaFrameData** FrameData ) { PPROCESS_ENTRY ProcessEntry; PDIA Dia; PMODULE_ENTRY Mod;
ProcessEntry = FindProcessEntry(Process); if (!ProcessEntry || !(Mod = GetModFromAddr(ProcessEntry, Offset)) || !(Dia = (PDIA)Mod->dia)) { return false; }
if (Dia->framedata == NULL) {
CComPtr<IDiaEnumTables> EnumTables; CComPtr<IDiaTable> FdTable; VARIANT FdVar;
FdVar.vt = VT_BSTR; FdVar.bstrVal = DiaTable_FrameData;
if (Dia->session->getEnumTables(&EnumTables) != S_OK || EnumTables->Item(FdVar, &FdTable) != S_OK || FdTable->QueryInterface(IID_IDiaEnumFrameData, (void**)&Dia->framedata) != S_OK) { return false; } }
return Dia->framedata->frameByVA(Offset, FrameData) == S_OK; }
BOOL diaGetFrameData( IN HANDLE Process, IN ULONGLONG Offset, OUT IDiaFrameData** FrameData ) { BOOL rc = false;
__try {
EnterCriticalSection(&g.threadlock); rc = ldiaGetFrameData(Process, Offset,FrameData);
} __finally {
LeaveCriticalSection(&g.threadlock); }
return rc; }
// ----------------------------------------------------------------
// for compatibility with GetFileLineOffsets. DON'T CALL THIS CODE!
#if 1
HRESULT diaAddLinesForSourceFile( PMODULE_ENTRY mi, IDiaSourceFile *idiaSource, IDiaSymbol *pComp ) { HRESULT hr; LPSTR SrcFileName = NULL; BSTR wfname = NULL; ULONG SrcFileNameLen = 0; PSOURCE_ENTRY Src; PSOURCE_ENTRY Seg0Src; PSOURCE_LINE SrcLine; PDIA pdia; ULONG celt; LONG LineNums; ULONG CompId; CHAR fname[MAX_PATH + 1]; DWORD rva; ULONG Line;
if (!idiaSource) { return E_INVALIDARG; }
assert((mi != NULL) && (mi->dia));
pdia = (PDIA)mi->dia;
if (pComp->get_symIndexId(&CompId) == S_OK) { }
CComPtr <IDiaEnumLineNumbers> idiaEnumLines;
hr = pdia->session->findLines(pComp, idiaSource, &idiaEnumLines); if (hr != S_OK) return hr;
hr = idiaEnumLines->get_Count(&LineNums); if (hr != S_OK) return hr;
CComPtr <IDiaLineNumber> idiaLine;
if (idiaSource->get_fileName(&wfname) == S_OK && wfname) { wcs2ansi(wfname, fname, MAX_PATH); LocalFree(wfname); SrcFileNameLen = strlen(fname); }
Src = (PSOURCE_ENTRY)MemAlloc(sizeof(SOURCE_ENTRY)+ sizeof(SOURCE_LINE)*LineNums+ SrcFileNameLen + 1);
if (!Src) { return E_OUTOFMEMORY; }
#ifdef DBG_DIA_LINE
dtrace("diaAddLinesForSourceFile : source : %s\n", fname); #endif
// Retrieve line numbers and offsets from raw data and
// process them into current pointers.
SrcLine = (SOURCE_LINE *)(Src+1); Src->LineInfo = SrcLine; Src->ModuleId = CompId; Src->MaxAddr = 0; Src->MinAddr = -1;
Src->Lines = 0; idiaLine = NULL; for (; (hr = idiaEnumLines->Next(1, &idiaLine, &celt)) == S_OK && (celt == 1); ) { hr = idiaLine->get_lineNumber(&Line); if (hr != S_OK) break; hr = idiaLine->get_relativeVirtualAddress(&rva); if (hr != S_OK) break;
SrcLine->Line = Line; SrcLine->Addr = GetLineAddressFromRva(mi, rva);
if (SrcLine->Addr > Src->MaxAddr) { Src->MaxAddr = SrcLine->Addr; } if (SrcLine->Addr < Src->MinAddr) { Src->MinAddr = SrcLine->Addr; } #ifdef DBG_DIA_LINE
dtrace("Add line %lx, Addr %I64lx\n", SrcLine->Line, SrcLine->Addr); #endif
Src->Lines++; SrcLine++; idiaLine = NULL; }
// Stick file name at the very end of the data block so
// it doesn't interfere with alignment.
Src->File = (LPSTR)SrcLine; if (*fname) { memcpy(Src->File, fname, SrcFileNameLen); } Src->File[SrcFileNameLen] = 0;
AddSourceEntry(mi, Src); return S_OK; }
BOOL diaAddLinesForMod( PMODULE_ENTRY mi, IDiaSymbol *diaModule ) { LONG Size; BOOL Ret; PSOURCE_ENTRY Src; ULONG ModId; HRESULT Hr;
if (diaModule->get_symIndexId(&ModId) != S_OK) { return false; } #ifdef DBG_DIA_LINE
dtrace("diaAddLinesForMod : ModId %lx\n", ModId); #endif
// Check and see if we've loaded this information already.
for (Src = mi->SourceFiles; Src != NULL; Src = Src->Next) { // Check module index instead of pointer since there's
// no guarantee the pointer would be the same for different
// lookups.
if (Src->ModuleId == ModId) { return true; } }
PDIA pdia; pdia = (PDIA)mi->dia;
CComPtr< IDiaEnumSourceFiles > idiaEnumFiles; Hr = pdia->session->findFile(diaModule, NULL, nsNone, &idiaEnumFiles); if (Hr != S_OK) { return false; }
ULONG celt; CComPtr <IDiaSourceFile> idiaSource; for (;SUCCEEDED(idiaEnumFiles->Next(1,&idiaSource, &celt)) && (celt == 1);) { diaAddLinesForSourceFile(mi, idiaSource, diaModule); idiaSource = NULL; }
return true; }
BOOL diaAddLinesForModAtAddr( PMODULE_ENTRY mi, DWORD64 Addr ) { BOOL Ret; DWORD Bias; HRESULT hr; PDIA pdia; DWORD rva;
assert(mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
rva = (DWORD)(Addr - mi->BaseOfDll);
CComPtr < IDiaSymbol > pComp; hr = pdia->session->findSymbolByRVA(rva, SymTagCompiland, &pComp); if (hr != S_OK) return false;
Ret = diaAddLinesForMod(mi, pComp);
return Ret; }
BOOL diaAddLinesForAllMod( PMODULE_ENTRY mi ) { HRESULT hr; PDIA pdia; ULONG celt = 1; BOOL Ret;
Ret = false; #ifdef DBG_DIA_LINE
dtrace("diaAddLinesForAllMod : Adding lines for all mods in %s\n", mi->ImageName); #endif
assert(mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
CComPtr <IDiaSymbol> idiaSymbols;
hr = pdia->session->get_globalScope(&idiaSymbols); if (hr != S_OK) return NULL;
CComPtr< IDiaEnumSymbols > idiaMods; hr = pdia->session->findChildren(idiaSymbols,SymTagCompiland, NULL, nsNone, &idiaMods); if (FAILED(hr)) return false;
CComPtr< IDiaSymbol > idiaSymbol;
while (SUCCEEDED(idiaMods->Next( 1, &idiaSymbol, &celt)) && celt == 1) { Ret = diaAddLinesForMod(mi, idiaSymbol); idiaSymbol = NULL; if (!Ret) { break; } }
return Ret; } #endif
|