|
|
/*++
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 <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( VOID ) { return TRUE; }
BOOL ValidGUID( GUID *guid ) { int i;
if (!guid) return FALSE;
if (guid->Data1) return TRUE; if (guid->Data2) return TRUE; if (guid->Data3) return TRUE; for (i = 0; i < 8; i++) { if (guid->Data4[i]) return TRUE; }
return FALSE; }
__inline HRESULT SetDiaError( HRESULT ccode, HRESULT ncode ) { if (ncode == EC_OK) return ncode;
if (ccode != 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, "disk error"}, {E_PDB_NOT_FOUND, "file not found"}, {E_PDB_INVALID_SIG, "unmatched pdb"}, {E_PDB_INVALID_AGE, "unmatched 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; }
sprintf(sz, "dia error 0x%x", hr); return sz; }
extern DWORD DIA_VERSION;
DWORD diaVersion( VOID ) { return DIA_VERSION; }
HRESULT diaLocatePdb( PIMGHLP_DEBUG_DATA pIDD, PSTR szPDB, GUID *PdbGUID, DWORD PdbSignature, DWORD PdbAge, char *SymbolPath, char *szImageExt, int ip ) { char szError[cbErrMax] = ""; char szPDBSansPath[_MAX_FNAME]; char szPDBExt[_MAX_EXT]; char szPDBLocal[_MAX_PATH]; char szDbgPath[PDB_MAX_PATH]; char *SemiColon; DWORD pass; EC hrcode = E_PDB_NOT_FOUND; BOOL symsrv = TRUE; char szPDBName[_MAX_PATH]; char *SavedSymbolPath = SymbolPath; GUID guid; WCHAR wszPDB[_MAX_PATH + 1]; WCHAR wszError[cbErrMax]; WCHAR wszPDBLocal[_MAX_PATH + 1]; PDIA pdia; HRESULT hr; BOOL ssfile; BOOL refpath; BOOL first;
// if (traceSubName(szPDB)) // for setting debug breakpoints from DBGHELP_TOKEN
// dprint("diaLocatePdb(%s)\n", szPDB);
ZeroMemory(&guid, sizeof(GUID));
if (!PdbSignature && !ValidGUID(PdbGUID) && (g.SymOptions & SYMOPT_EXACT_SYMBOLS)) { g.LastSymLoadError = SYMLOAD_PDBUNMATCHED; return E_PDB_INVALID_SIG; }
// SymbolPath is a semicolon delimited path (reference path first)
strcpy (szPDBLocal, szPDB); _splitpath(szPDBLocal, NULL, NULL, szPDBSansPath, szPDBExt);
pdia = (PDIA)pIDD->dia; if (!pdia) return !S_OK;
first = TRUE; do { SemiColon = strchr(SymbolPath, ';');
if (SemiColon) { *SemiColon = '\0'; }
if (first) { refpath = (ip == ipFirst); first = FALSE; } else if (!SemiColon) { refpath = (ip == ipLast); } else { refpath = FALSE; } if (refpath) { pass = 2; ip = ipNone;; } else { pass = 0; }
if (SymbolPath) { do_again: ssfile = FALSE; if (!_strnicmp(SymbolPath, "SYMSRV*", 7)) {
*szPDBLocal = 0; sprintf(szPDBName, "%s%s", szPDBSansPath, ".pdb"); if (symsrv) { ssfile = TRUE; if (PdbSignature) guid.Data1 = PdbSignature; else if (PdbGUID) memcpy(&guid, PdbGUID, sizeof(GUID)); GetFileFromSymbolServer(SymbolPath, szPDBName, &guid, PdbAge, 0, szPDBLocal); symsrv = FALSE; }
} else {
strcpy(szPDBLocal, SymbolPath); EnsureTrailingBackslash(szPDBLocal);
// search order is ...
//
// %dir%\symbols\%ext%\%file%
// %dir%\%ext%\%file%
// %dir%\%file%
switch (pass) { case 0: strcat(szPDBLocal, "symbols"); EnsureTrailingBackslash(szPDBLocal); // pass through
case 1: strcat(szPDBLocal, szImageExt); // pass through
default: EnsureTrailingBackslash(szPDBLocal); break; }
strcat(szPDBLocal, szPDBSansPath); strcat(szPDBLocal, szPDBExt); }
if (*szPDBLocal) {
ansi2wcs(szPDBLocal, wszPDBLocal, lengthof(wszPDBLocal)); dprint("diaLocatePDB-> Looking for %s... ", szPDBLocal); if (!ValidSig(PdbSignature, PdbGUID)) { hr = pdia->source->loadDataFromPdb(wszPDBLocal); } else { hr = pdia->source->loadAndValidateDataFromPdb(wszPDBLocal, ValidGUID(PdbGUID) ? PdbGUID : NULL, PdbSignature, PdbAge); }
hrcode = SetDiaError(hrcode, hr); if (hr == S_OK) { if (ssfile) pIDD->PdbSrc = srcSymSrv; else if (refpath) pIDD->PdbSrc = pIDD->PdbSrc; else pIDD->PdbSrc = srcSearchPath; if (!PdbSignature && !ValidGUID(PdbGUID)) eprint("unknown pdb sig "); break; } else { if (hr == E_PDB_INVALID_SIG || hr == E_PDB_INVALID_AGE) { eprint("%s ", diaErrorText(hr)); if (!ValidSig(PdbSignature, PdbGUID)) { hr = pdia->source->loadDataFromPdb(wszPDBLocal); if (hr == S_OK) break; } eprint("\n"); } else if (hr == E_PDB_NOT_FOUND) { eprint("%s\n", diaErrorText(hr)); if (!(g.LastSymLoadError & SYMLOAD_PDBERRORMASK)) { g.LastSymLoadError = SYMLOAD_PDBNOTFOUND; } } else { eprint("%s\n", diaErrorText(hr)); g.LastSymLoadError = (hr << 8) & SYMLOAD_PDBERRORMASK; }
if (pass < 2) { pass++; goto do_again; } } refpath = FALSE; } }
if (SemiColon) { *SemiColon = ';'; SemiColon++; symsrv = TRUE; }
SymbolPath = SemiColon; } while (SemiColon);
if (hr != S_OK) { strcpy(szPDBLocal, szPDB); ansi2wcs(szPDBLocal, wszPDBLocal, lengthof(wszPDB)); dprint("diaLocatePDB-> Looking for %s... ", szPDBLocal); hr = pdia->source->loadAndValidateDataFromPdb(wszPDBLocal, ValidGUID(PdbGUID) ? PdbGUID : NULL, PdbSignature, PdbAge); if (hr != S_OK) { if (hr == E_PDB_INVALID_SIG || hr == E_PDB_INVALID_AGE) { eprint("%s ", diaErrorText(hr)); if (!ValidSig(PdbSignature, PdbGUID)) { hr = pdia->source->loadDataFromPdb(wszPDBLocal); } if (hr != S_OK) eprint("\n"); } else if (hr == E_PDB_NOT_FOUND) { eprint("%s\n", diaErrorText(hr)); if (!(g.LastSymLoadError & SYMLOAD_PDBERRORMASK)) { g.LastSymLoadError = SYMLOAD_PDBNOTFOUND; } } else { eprint("%s\n", diaErrorText(hr)); g.LastSymLoadError = (hr << 8) & SYMLOAD_PDBERRORMASK; } } else { pIDD->PdbSrc = srcCVRec; } }
if (hr == S_OK) { eprint("OK\n"); // Store the name of the PDB we actually opened for later reference.
strcpy(szPDB, szPDBLocal); SetLastError(NO_ERROR); g.LastSymLoadError = SYMLOAD_OK; }
if (hr != S_OK && (PdbSignature || ValidGUID(PdbGUID)) && (g.SymOptions & SYMOPT_LOAD_ANYTHING)) return diaLocatePdb(pIDD, szPDB, NULL, 0, 0, SavedSymbolPath, szImageExt, ipNone);
return hr; }
BOOL diaGetFPOTable( PIMGHLP_DEBUG_DATA pIDD ) { DWORD celt; LONG count; DWORD cb; PBYTE buf; HRESULT hr; PDIA pdia; VARIANT var;
CComPtr< IDiaEnumDebugStreams > idiaStreams; CComPtr< IDiaEnumDebugStreamData > idiaStream;
assert (pIDD && pIDD->dia);
pdia = (PDIA)pIDD->dia;
hr = pdia->session->getEnumDebugStreams(&idiaStreams); if (hr != S_OK) return FALSE;
var.vt = VT_BSTR; var.bstrVal = L"FPO"; 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;
buf = (PBYTE)MemAlloc(cb); if (!buf) return FALSE;
hr = idiaStream->Next(count, cb, &cb, buf, &celt); if (hr != S_OK) { MemFree(buf); return FALSE; }
pIDD->cFpo = count; pIDD->pFpo = buf;
return TRUE; }
BOOL diaGetPData( 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;
hr = pdia->session->getEnumDebugStreams(&idiaStreams); if (hr != S_OK) return FALSE;
var.vt = VT_BSTR; var.bstrVal = L"PDATA"; 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;
buf = (PBYTE)MemAlloc(cb); if (!buf) return FALSE;
hr = idiaStream->Next(count, cb, &cb, buf, &celt); if (hr != S_OK) { MemFree(buf); 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; }
BOOL diaGetOmaps( PIMGHLP_DEBUG_DATA pIDD ) { DWORD celt; LONG count; DWORD cb; PBYTE tbuf = NULL; PBYTE fbuf = NULL; HRESULT hr; PDIA pdia; VARIANT var;
CComPtr< IDiaEnumDebugStreams > idiaStreams; CComPtr< IDiaEnumDebugStreamData > idiaStream;
assert (pIDD && pIDD->dia);
pdia = (PDIA)pIDD->dia;
hr = pdia->session->getEnumDebugStreams(&idiaStreams); if (hr != S_OK) return FALSE;
var.vt = VT_BSTR; var.bstrVal = L"OMAPTO"; 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;
tbuf = (PBYTE)MemAlloc(cb); if (!tbuf) return FALSE;
hr = idiaStream->Next(count, cb, &cb, tbuf, &celt); if (hr != S_OK) goto CleanReturnFalse;
pIDD->cOmapTo = count; pIDD->pOmapTo = (POMAP)tbuf;
idiaStream = NULL;
var.vt = VT_BSTR; var.bstrVal = L"OMAPFROM"; 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;
fbuf = (PBYTE)MemAlloc(cb); if (!fbuf) return FALSE;
hr = idiaStream->Next(count, cb, &cb, fbuf, &celt); if (hr != S_OK) goto CleanReturnFalse;
pIDD->cOmapFrom = count; pIDD->pOmapFrom = (POMAP)fbuf;
return TRUE;
CleanReturnFalse: MemFree(tbuf); MemFree(fbuf); return FALSE; }
void diaRelease( PVOID dia ) { PDIA pdia = (PDIA)dia; delete pdia; }
BOOL diaOpenPdb( PIMGHLP_DEBUG_DATA pIDD ) { HRESULT hr; PDIA pdia; PCHAR szLocalSymbolPath = NULL; DWORD cpathlen = 0; CHAR szExt[_MAX_EXT] = {0}; int ip;
if (pIDD->SymbolPath) cpathlen = strlen(pIDD->SymbolPath); szLocalSymbolPath = (PCHAR)MemAlloc(cpathlen + strlen(pIDD->PdbReferencePath) + 2); if (!szLocalSymbolPath) { return FALSE; } *szLocalSymbolPath = 0;
ip = ipNone; if (pIDD->ImageSrc != srcSymSrv) strcpy(szLocalSymbolPath, pIDD->PdbReferencePath); if (*szLocalSymbolPath) { if (pIDD->SymbolPath) strcat(szLocalSymbolPath, ";"); ip = ipFirst; } if (pIDD->SymbolPath) strcat(szLocalSymbolPath, pIDD->SymbolPath); if (pIDD->ImageSrc == srcSymSrv) { if (pIDD->PdbReferencePath) { if (*szLocalSymbolPath) strcat(szLocalSymbolPath, ";"); strcat(szLocalSymbolPath, pIDD->PdbReferencePath); ip = ipLast; } }
if (*pIDD->ImageFilePath) { _splitpath(pIDD->ImageFilePath, NULL, NULL, NULL, szExt); } else if (*pIDD->ImageName) { _splitpath(pIDD->ImageName, NULL, NULL, NULL, szExt); }
// if we have no valid filename, then this must be an executable
if (!*szExt) strcpy(szExt, ".exe");
// get interface to dia
pdia = new DIA; if (!pdia) { hr = E_PDB_OUT_OF_MEMORY; goto error; } pIDD->dia = pdia;
pdia->source = NULL; hr = DiaCoCreate(CLSID_DiaSourceAlt, IID_IDiaDataSource, (void **)&pdia->source); if (hr != S_OK) goto error;
// go ahead and get pdb
SetCriticalErrorMode();
hr = diaLocatePdb(pIDD, pIDD->PdbFileName, &pIDD->PdbGUID, pIDD->PdbSignature, pIDD->PdbAge, szLocalSymbolPath, &szExt[1], ip);
ResetCriticalErrorMode();
MemFree(szLocalSymbolPath); szLocalSymbolPath = NULL;
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(pIDD->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 (pIDD->pCurrentSections) { hr = pdia->addrmap->set_imageHeaders(pIDD->cCurrentSections * sizeof(IMAGE_SECTION_HEADER), (BYTE *)pIDD->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 (pIDD->ImageAlign) { hr = pdia->addrmap->put_imageAlign(pIDD->ImageAlign); if (hr != S_OK) goto error; }
// pass in the omap information and setup the proper image alignment to the original
if (pIDD->cOmapFrom && pIDD->pOmapFrom) { hr = pdia->addrmap->put_imageAlign(pIDD->ImageAlign); if (hr != S_OK) goto error; hr = pdia->addrmap->set_addressMap(pIDD->cOmapTo, (DiaAddressMapEntry *)pIDD->pOmapTo, TRUE); if (hr != S_OK) goto error; hr = pdia->addrmap->set_addressMap(pIDD->cOmapFrom, (DiaAddressMapEntry *)pIDD->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(pIDD); diaGetOmaps(pIDD);
return TRUE;
error: if (hr) dprint("%s\n", pIDD->PdbFileName, diaErrorText(hr));
MemFree(szLocalSymbolPath);
if (pdia) { diaRelease(pdia); pIDD->dia = NULL; } return FALSE; }
DWORD64 GetAddressFromRva( PMODULE_ENTRY mi, DWORD rva ) { DWORD64 addr;
assert(mi); addr = rva ? mi->BaseOfDll + rva : 0; return addr; }
BOOL diaFillSymbolInfo( PSYMBOL_INFO si, PMODULE_ENTRY mi, IDiaSymbol *idiaSymbol ) { HRESULT hr; BSTR wname=NULL; CHAR name[MAX_SYM_NAME + 1]; VARIANT var; // DWORD tag;
DWORD dw; ULONG64 size; BOOL rc;
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 LocIsStatic: case LocIsTLS: 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 = IMAGEHLP_SYMBOL_INFO_REGISTER; LookupRegID(si->Register, mi->MachineType,&si->Register) ; break;
case LocIsRegRel: si->Flags = IMAGEHLP_SYMBOL_INFO_REGRELATIVE; hr = idiaSymbol->get_registerId(&si->Register); if (hr != S_OK) return FALSE; hr = idiaSymbol->get_offset((PLONG)&dw); LookupRegID(si->Register, mi->MachineType,&si->Register) ; si->Address = (ULONG64) (LONG64) (LONG) dw; break;
case LocIsThisRel: // struct members - get_Offset
default: si->Flags |= 0; break; } break;
case SymTagFunction: case SymTagPublicSymbol: case SymTagThunk: hr = idiaSymbol->get_relativeVirtualAddress(&dw); si->Address = GetAddressFromRva(mi, dw); if (!si->Address) rc = FALSE; break;
default: break; }
if (hr != S_OK) return FALSE;
hr = idiaSymbol->get_dataKind(&dw); if (hr == S_OK) { if (dw == DataIsParam) si->Flags |= IMAGEHLP_SYMBOL_INFO_PARAMETER; else if (dw == DataIsConstant) si->Flags = IMAGEHLP_SYMBOL_INFO_CONSTANT; }
hr = idiaSymbol->get_typeId(&dw); if (hr == S_OK) si->TypeIndex = dw;
hr = idiaSymbol->get_name(&wname); if (hr != S_OK || !wname) return FALSE; if (!wname[0]) { rc = FALSE; } else { wcs2ansi(wname, name, MAX_SYM_NAME); if (*name == '.') si->Flags = IMAGEHLP_SYMBOL_FUNCTION; // if (traceSubName(name)) // for setting debug breakpoints from DBGHELP_TOKEN
// dprint("debug(%s)\n", name);
if (g.SymOptions & SYMOPT_UNDNAME) SymUnDNameInternal(si->Name, si->MaxNameLen, name, strlen(name), mi->MachineType, si->Tag == SymTagPublicSymbol); else strcpy(si->Name, name);
// let the caller know this is a $$$XXXAA style symbol
if (strlen(si->Name) == 8 && !strncmp(si->Name, "$$$",3) && isxdigit(si->Name[5]) && isxdigit(si->Name[6]) && isxdigit(si->Name[7]) ) { rc = FALSE; } } if (wname) LocalFree (wname);
// if (traceSubName(name)) // for setting debug breakpoints from DBGHELP_TOKEN
// dprint("debug(%s)\n", name);
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); pdia->scope = NULL; // delete previous scope
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) { // pprint(pe, "Scope changed [0x%x]\n", rva);
pdia->scope = idiaScope; return TRUE; }
return FALSE; }
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 PrepareForCPPMatch( LPSTR in, LPSTR out ) { LPSTR p;
assert(in && out);
if (strlen(in) > MAX_SYM_NAME) return FALSE;
for (; *in; in++, out++) { if (*in == '_' && *(in + 1) == '_') { strcpy(out, "[_:][_:]"); out += 7; in++; } else { *out = *in; } } *out = 0;
return TRUE; }
BOOL diaGetLocals( PPROCESS_ENTRY pe, LPSTR 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 = (g.SymOptions & SYMOPT_CASE_INSENSITIVE) ? nsCaseInRegularExpression : nsRegularExpression;
// get the current scope
mi = pe->ipmi; if (!mi) return FALSE; pdia = (PDIA)mi->dia; if (!pdia) return FALSE;
idiaSymbols = pdia->scope;
if (!PrepareForCPPMatch(name, symname)) return FALSE; 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 |= IMAGEHLP_SYMBOL_INFO_LOCAL; if (!callback) return TRUE; if (mi->si.Flags & IMAGEHLP_SYMBOL_INFO_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; }
BOOL diaGetGlobals( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPSTR name, 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 (!PrepareForCPPMatch(name, symname)) return FALSE; wname = ConvertNameForDia(symname, wbuf);
if (g.SymOptions & SYMOPT_CASE_INSENSITIVE) { opt = nsCaseInRegularExpression; fCase = FALSE; } else { opt = nsRegularExpression; fCase = TRUE; };
// get a session
pdia = (PDIA)mi->dia; if (!pdia) return FALSE;
hr = pdia->session->get_globalScope(&idiaGlobals); if (hr != S_OK) return FALSE;
// 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;
if (pGlobals) 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) goto publics; 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 & IMAGEHLP_SYMBOL_INFO_CONSTANT) 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: // now check out the publics table
if (wname) { sprintf(pname, "*%s*", symname); MakeEmbeddedREStr(pname, symname); wname = ConvertNameForDia(pname, wbuf); }
idiaSymbols = NULL;
opt |= nsfUndecoratedName;
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; 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, LPSTR name, PROC callback, PVOID context, BOOL use64, BOOL unicode ) { // ENUMFIX:
LPSTR pname = (name) ? name : "";
if (mi) { return diaGetGlobals(pe, mi, pname, callback, context, use64, unicode); } else { return diaGetLocals(pe, pname, callback, context, use64, unicode); } }
PSYMBOL_ENTRY diaFindSymbolByName( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPSTR SymName ) { SYMPTR sym; char sz[MAX_SYM_NAME + 1];
if (!diaGetSymbols(pe, mi, SymName, NULL, NULL, 0, 0)) return NULL;
if (!mi) mi = pe->ipmi;
CopySymbolEntryFromSymbolInfo(&mi->TmpSym, &mi->si);
return &mi->TmpSym; }
BOOL diaEnumerateSymbols( IN PPROCESS_ENTRY pe, IN PMODULE_ENTRY mi, IN LPSTR mask, IN PROC callback, IN PVOID context, IN BOOL use64, IN BOOL unicode ) { return diaGetSymbols(pe, mi, mask, callback, context, use64, unicode); }
PSYMBOL_ENTRY diaGetSymFromAddr( DWORD64 addr, PMODULE_ENTRY mi, 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;
// if (traceAddr(addr)) // for debug breakpoints ...
// dprint("found 0x%I64x\n", addr);
rva = (DWORD)(addr - mi->BaseOfDll);
// get the symbol
CComPtr< IDiaSymbol > idiaSymbol; 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...
fHitBlock = FALSE; 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 (!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); else eprint(" couldn't match name! disp=0x%x rva=0x%x addr=0x%I64x\n", omapadj, rva, addr); }
CopySymbolEntryFromSymbolInfo(&mi->TmpSym, &mi->si);
if (disp) *disp = (fHitBlock) ? addr - mi->si.Address : omapadj;
return &mi->TmpSym; }
BOOL diaGetLineFromAddr( PMODULE_ENTRY mi, DWORD64 addr, PDWORD displacement, PIMAGEHLP_LINE64 line ) { 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;
if (line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) return FALSE;
rva = (DWORD)(addr - mi->BaseOfDll);
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;
// line->Key = 0;
hr = idiaLine->get_lineNumber(&dw); if (hr != S_OK) return FALSE;
line->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;
*mi->SrcFile = 0; rc = wcs2ansi(bstr, mi->SrcFile, lengthof(mi->SrcFile)); if (!rc || !*mi->SrcFile) { LocalFree(bstr); return FALSE; }
LocalFree(bstr);
line->FileName = mi->SrcFile;
hr = idiaLine->get_relativeVirtualAddress(&dw); if (hr != S_OK) return FALSE;
line->Address = dw + mi->BaseOfDll; *displacement = rva - dw;
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; DWORD lineno; DWORD dw;
// simple sanity checks
assert(mi && mi->dia); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
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;
// all source files in the module that match the 'wfname'
CComPtr< IDiaEnumSourceFiles > idiaFiles = NULL; hr = pdia->session->findFile(NULL, wfname, nsCaseInsensitive, &idiaFiles); if (hr != S_OK) return FALSE;
// the first such file in the list, since we don't use wildcards
CComPtr< IDiaSourceFile > idiaFile = NULL; hr = idiaFiles->Next(1, &idiaFile, &dw); if (hr != S_OK) return FALSE;
// all objs that use this source file
CComPtr< IDiaEnumSymbols > idiaObjs = NULL; hr = idiaFile->get_compilands(&idiaObjs); if (hr != S_OK) return FALSE;
// LOOP THROUGH ALL THE OBJS! AND STORE THE CLOSEST!
lineno = 0; rva = 0;
// grab the first obj, since we don't care
CComPtr< IDiaSymbol > idiaObj = NULL; CComPtr< IDiaLineNumber > idiaLine = NULL; CComPtr< IDiaEnumLineNumbers > idiaLines = NULL;
hr = idiaObjs->Next(1, &idiaObj, &celt); if (hr != S_OK) return FALSE;
while (celt) { // get the line for starting with
hr = pdia->session->findLinesByLinenum(idiaObj, idiaFile, line->LineNumber + direction, 0, &idiaLines); if (hr == S_OK) { hr = idiaLines->Next(1, &idiaLine, &dw); if (hr == S_OK) { hr = idiaLine->get_lineNumber(&dw); if (hr == S_OK) { if (!lineno) { lineno = dw; hr = idiaLine->get_relativeVirtualAddress(&rva); } else if (direction == NP_NEXT) { if (dw < lineno) lineno = dw; hr = idiaLine->get_relativeVirtualAddress(&rva); } else if (dw > lineno) { lineno = dw; hr = idiaLine->get_relativeVirtualAddress(&rva); } } } } idiaObj = NULL; idiaObjs->Next(1, &idiaObj, &celt); }
if (!lineno) return FALSE;
// Line->Key = SrcLine;
line->LineNumber = lineno; line->Address = GetAddressFromRva(mi, rva);
return TRUE; }
#if 0
#define DBG_DIA_LINE 1
#endif
// #define DIA_LINE_NAME 1
BOOL diaGetLineFromName( PMODULE_ENTRY mi, LPSTR filename, DWORD linenumber, PLONG displacement, PIMAGEHLP_LINE64 line ) { HRESULT hr; WCHAR wsz[_MAX_PATH + 1]; PDIA pdia; DWORD celt; BSTR bstr; DWORD addr; DWORD num; BOOL rc;
#if DIA_LINE_NAME
assert(mi && mi->dia && filename); pdia = (PDIA)mi->dia; if (!pdia) return NULL;
if (line->SizeOfStruct != sizeof(IMAGEHLP_LINE64)) return FALSE;
if (!*filename) return FALSE;
if (!ansi2wcs(filename, wsz, lengthof(wsz))) return FALSE; if (!*wsz) return FALSE;
CComPtr<IDiaEnumSourceFiles> idiaSrcFiles; hr = pdia->session->findFile(NULL, wsz, nsFNameExt, &idiaSrcFiles); if (hr != S_OK) return FALSE;
CComPtr<IDiaSourceFile> idiaSrcFile; hr = idiaSrcFiles->Next(1, &idiaSrcFile, &celt); if (hr != S_OK) return FALSE;
hr = idiaSrcFile->get_fileName(&bstr); if (hr != S_OK) return FALSE;
rc = wcs2ansi(bstr, mi->SrcFile, lengthof(mi->SrcFile)); if (!rc || !*mi->SrcFile) { LocalFree(bstr); return FALSE; }
LocalFree(bstr);
line->FileName = mi->SrcFile;
// this gives us a list of every .obj that uses this source file
CComPtr<IDiaEnumSymbols> idiaEnum; hr = idiaSrcFile->get_compilands(&idiaEnum); if (hr != S_OK) return FALSE;
CComPtr<IDiaSymbol> idiaSymbol; CComPtr<IDiaEnumLineNumbers> idiaLineNumbers; CComPtr<IDiaLineNumber> idiaLineNumber;
// walk through the .obj's
hr = idiaEnum->Next(1, &idiaSymbol, &celt); while (hr == S_OK) { // 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) break;
idiaLineNumber = NULL; hr = idiaLineNumbers->Next(1, &idiaLineNumber, &celt); if (hr != S_OK) break; hr = idiaLineNumber->get_lineNumber(&num); if (hr != S_OK) break; line->LineNumber = num; hr = idiaLineNumber->get_relativeVirtualAddress(&addr); if (hr != S_OK) break; if (addr) { line->Address = mi->BaseOfDll + addr; *displacement = linenumber - num; return TRUE; } idiaSymbol = NULL; hr = idiaEnum->Next(1, &idiaSymbol, &celt); } #endif
return FALSE; }
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;
if (hr = pdia->session->findLines(pComp, idiaSource, &idiaEnumLines) != S_OK) {
return hr; }
if (hr = idiaEnumLines->get_Count(&LineNums) != 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
dprint("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 = mi->BaseOfDll + rva;
// 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 && (SrcLine->Addr & 3)) { SrcLine->Addr = (SrcLine->Addr & ~3) | ((SrcLine->Addr & 3) << 2); }
if (SrcLine->Addr > Src->MaxAddr) { Src->MaxAddr = SrcLine->Addr; } if (SrcLine->Addr < Src->MinAddr) { Src->MinAddr = SrcLine->Addr; } #ifdef DBG_DIA_LINE
dprint("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
dprint("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 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; }
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
dprint("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; }
PSYMBOL_ENTRY 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; }
CopySymbolEntryFromSymbolInfo(&mi->TmpSym, &mi->si);
return &mi->TmpSym; }
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 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); }
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 ) { 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: 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)) { // dprint("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; // dprint(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)) { // dprint("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 ) { 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); // dprint(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]; // dprint(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)) { // dprint("%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); 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) { 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 S_OK; } break; default: break; } idiaSymbol = NULL; } }
MemFree(wname); return hr == S_OK; }
BOOL diaGetFrameData( 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; }
|