/*++ 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 typedef struct { CComPtr source; CComPtr session; CComPtr scope; CComPtr srcfile; CComPtr framedata; #ifdef BBTFIX CComPtr 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 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; 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 idiaSrcFiles; hr = pdia->session->findFile(NULL, wsz, nsFNameExt, &idiaSrcFiles); if (hr != S_OK) return FALSE; CComPtr 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 idiaEnum; hr = idiaSrcFile->get_compilands(&idiaEnum); if (hr != S_OK) return FALSE; CComPtr idiaSymbol; CComPtr idiaLineNumbers; CComPtr 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 idiaEnumLines; if (hr = pdia->session->findLines(pComp, idiaSource, &idiaEnumLines) != S_OK) { return hr; } if (hr = idiaEnumLines->get_Count(&LineNums) != S_OK) { return hr; } CComPtr 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 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 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 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 idiaSymbols; hr = pdia->session->getSymbolsByAddr(&idiaSymbols); if (hr != S_OK) return NULL; rva = addr ? (DWORD)(addr - mi->BaseOfDll) : 0; CComPtr 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 pEnum; HRESULT hr; ULONG index; CComPtr 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 pEnum; HRESULT hr; ULONG index; CComPtr 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 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 EnumTables; CComPtr 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; }