Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3943 lines
94 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. dia.c
  5. Abstract:
  6. These routines call VC's new DIA symbol handler.
  7. Author:
  8. Pat Styles (patst) 26-May-2000
  9. Environment:
  10. User Mode
  11. --*/
  12. #define DIA_LIBRARY 1
  13. #include "private.h"
  14. #include "symbols.h"
  15. #include "globals.h"
  16. #include "dia2.h"
  17. #include "diacreate_int.h"
  18. #include "pdb.h"
  19. #include <atlbase.h>
  20. typedef struct {
  21. CComPtr<IDiaDataSource> source;
  22. CComPtr<IDiaSession> session;
  23. CComPtr<IDiaSymbol> scope;
  24. CComPtr<IDiaSourceFile> srcfile;
  25. CComPtr<IDiaEnumFrameData> framedata;
  26. #ifdef BBTFIX
  27. CComPtr<IDiaAddressMap> addrmap;
  28. #endif
  29. } DIA, *PDIA;
  30. extern HRESULT STDMETHODCALLTYPE DiaCoCreate(
  31. REFCLSID rclsid,
  32. REFIID riid,
  33. void **ppv);
  34. extern HRESULT STDMETHODCALLTYPE NoOleCoCreate(REFCLSID rclsid,
  35. REFIID riid,
  36. void **ppv);
  37. #define freeString LocalFree
  38. // used by diaLocatePdb
  39. enum {
  40. ipNone = 0,
  41. ipFirst,
  42. ipLast
  43. };
  44. BOOL diaInit()
  45. {
  46. #ifdef COMDIA
  47. HRESULT hr;
  48. if (!g.fCoInit)
  49. hr = CoInitialize(NULL);
  50. if (hr != S_OK)
  51. return false;
  52. g.fCoInit = true;
  53. #endif
  54. return true;
  55. }
  56. void diaCleanup()
  57. {
  58. #ifdef COMDIA
  59. HRESULT hr;
  60. if (!g.cProcessList && g.fCoInit)
  61. CoUninitialize();
  62. g.fCoInit = false;
  63. #endif
  64. }
  65. __inline
  66. HRESULT
  67. SetDiaError(
  68. HRESULT ccode,
  69. HRESULT ncode
  70. )
  71. {
  72. if (ncode == EC_OK)
  73. return ncode;
  74. if (ccode != (HRESULT)EC_NOT_FOUND)
  75. return ccode;
  76. return ncode;
  77. }
  78. __inline
  79. BOOL
  80. ValidSig(
  81. DWORD sig,
  82. GUID *guid
  83. )
  84. {
  85. if (ValidGuid(guid))
  86. return true;
  87. if (sig)
  88. return true;
  89. return false;
  90. }
  91. typedef struct _DIAERROR {
  92. HRESULT hr;
  93. char *text;
  94. } DIAERROR, *PDIAERROR;
  95. char *
  96. diaErrorText(
  97. HRESULT hr
  98. )
  99. {
  100. #define ERROR_MAX 24
  101. static const DIAERROR error[ERROR_MAX] =
  102. {
  103. {E_PDB_OK, "OK"},
  104. {E_PDB_USAGE, "invalid parameters"},
  105. {E_PDB_OUT_OF_MEMORY, "out of memory"},
  106. {E_PDB_FILE_SYSTEM, "drive not ready"},
  107. {E_PDB_NOT_FOUND, "file not found"},
  108. {E_PDB_INVALID_SIG, "mismatched pdb"},
  109. {E_PDB_INVALID_AGE, "mismatched pdb"},
  110. {E_PDB_PRECOMP_REQUIRED, "E_PDB_PRECOMP_REQUIRED"},
  111. {E_PDB_OUT_OF_TI, "E_PDB_OUT_OF_TI"},
  112. {E_PDB_NOT_IMPLEMENTED, "E_PDB_NOT_IMPLEMENTED"},
  113. {E_PDB_V1_PDB, "E_PDB_V1_PDB"},
  114. {E_PDB_FORMAT, "file system or network error reading pdb"},
  115. {E_PDB_LIMIT, "E_PDB_LIMIT"},
  116. {E_PDB_CORRUPT, "E_PDB_CORRUPT"},
  117. {E_PDB_TI16, "E_PDB_TI16"},
  118. {E_PDB_ACCESS_DENIED, "E_PDB_ACCESS_DENIED"},
  119. {E_PDB_ILLEGAL_TYPE_EDIT, "E_PDB_ILLEGAL_TYPE_EDIT"},
  120. {E_PDB_INVALID_EXECUTABLE, "invalid executable image"},
  121. {E_PDB_DBG_NOT_FOUND, "dbg file not found"},
  122. {E_PDB_NO_DEBUG_INFO, "pdb is stripped of cv info"},
  123. {E_PDB_INVALID_EXE_TIMESTAMP, "image has invalid timestamp"},
  124. {E_PDB_RESERVED, "E_PDB_RESERVED"},
  125. {E_PDB_DEBUG_INFO_NOT_IN_PDB, "pdb has no symbols"},
  126. {E_PDB_MAX, "pdb error 0x%x"}
  127. };
  128. static char sz[50];
  129. DWORD i;
  130. for (i = 0; i < ERROR_MAX; i++) {
  131. if (hr == error[i].hr)
  132. return error[i].text;
  133. }
  134. PrintString(sz, DIMA(sz), "dia error 0x%x", hr);
  135. return sz;
  136. }
  137. void
  138. FreeDiaVariant(
  139. VARIANT *var
  140. )
  141. {
  142. if (!var || !var->bstrVal)
  143. return;
  144. #ifdef COMDIA
  145. SysFreeString(var->bstrVal);
  146. #else
  147. LocalFree(var->bstrVal);
  148. #endif
  149. var->vt = VT_EMPTY;
  150. }
  151. extern DWORD DIA_VERSION;
  152. DWORD
  153. diaVersion(
  154. VOID
  155. )
  156. {
  157. return DIA_VERSION;
  158. }
  159. BOOL
  160. diaGetPdbInfo(
  161. PIMGHLP_DEBUG_DATA idd
  162. )
  163. {
  164. PDIA pdia;
  165. HRESULT hr;
  166. DWORD celt;
  167. int i;
  168. enum SymTagEnum symtag[2] = {SymTagData, SymTagFunction};
  169. enum SymTagEnum typetag[2] = {SymTagTypedef, SymTagUDT};
  170. assert(idd);
  171. // get interface
  172. pdia = (PDIA)idd->dia;
  173. if (!pdia)
  174. return false;
  175. CComPtr<IDiaSymbol> idiaGlobals;
  176. hr = pdia->session->get_globalScope(&idiaGlobals);
  177. if (hr != S_OK)
  178. return false;
  179. // get the pdb age and sig
  180. hr = idiaGlobals->get_guid(&idd->pdbdataGuid);
  181. if (hr != S_OK)
  182. return false;
  183. if (GuidIsDword(&idd->pdbdataGuid)) {
  184. idd->pdbdataSig = idd->pdbdataGuid.Data1;
  185. idd->pdbdataGuid.Data1 = 0;
  186. }
  187. hr = idiaGlobals->get_age(&idd->pdbdataAge);
  188. if (hr != S_OK)
  189. return false;
  190. // any line numbers?
  191. CComPtr<IDiaEnumSourceFiles> idiaSrcFiles;
  192. CComPtr<IDiaSourceFile> idiaSrcFile;
  193. hr = pdia->session->findFile(NULL, NULL, 0, &idiaSrcFiles);
  194. if (hr == S_OK) {
  195. hr = idiaSrcFiles->Next(1, &idiaSrcFile, &celt);
  196. if (hr == S_OK && celt > 0)
  197. idd->fLines = true;
  198. }
  199. // any symbols ?
  200. CComPtr<IDiaSymbol> idiaSymbol;
  201. CComPtr< IDiaEnumSymbols > idiaSymbols;
  202. for (i = 0; i < 2; i++) {
  203. hr = idiaGlobals->findChildren(symtag[i], NULL, 0, &idiaSymbols);
  204. if (hr == S_OK) {
  205. hr = idiaSymbols->Next(1, &idiaSymbol, &celt);
  206. if (hr == S_OK && celt > 0) {
  207. idd->fSymbols = true;
  208. break;
  209. }
  210. }
  211. idiaSymbols = NULL;
  212. idiaSymbol = NULL;
  213. }
  214. // any type info?
  215. idiaSymbols = NULL;
  216. idiaSymbol = NULL;
  217. for (i = 0; i < 2; i++) {
  218. hr = idiaGlobals->findChildren(typetag[i], NULL, 0, &idiaSymbols);
  219. if (hr == S_OK) {
  220. hr = idiaSymbols->Next(1, &idiaSymbol, &celt);
  221. if (hr == S_OK && celt > 0) {
  222. idd->fTypes = true;
  223. break;
  224. }
  225. }
  226. idiaSymbols = NULL;
  227. idiaSymbol = NULL;
  228. }
  229. return true;
  230. }
  231. HRESULT
  232. diaOpenPdb(
  233. PIMGHLP_DEBUG_DATA idd,
  234. PSTR szPDB,
  235. GUID *PdbGUID,
  236. DWORD PdbSignature,
  237. DWORD PdbAge,
  238. BOOL MatchAnything
  239. )
  240. {
  241. HRESULT hr;
  242. EC hrcode = E_PDB_NOT_FOUND;
  243. PDIA pdia;
  244. WCHAR wszPDB[_MAX_PATH + 1];
  245. pdia = (PDIA)idd->dia;
  246. if (!pdia)
  247. return EC_NO_DEBUG_INFO;
  248. ansi2wcs(szPDB, wszPDB, DIMA(wszPDB));
  249. if (!ValidSig(PdbSignature, PdbGUID))
  250. hr = pdia->source->loadDataFromPdb(wszPDB);
  251. else
  252. hr = pdia->source->loadAndValidateDataFromPdb(wszPDB,
  253. ValidGuid(PdbGUID) ? PdbGUID : NULL,
  254. PdbSignature,
  255. PdbAge);
  256. hrcode = SetDiaError(hrcode, hr);
  257. if (hr == S_OK) {
  258. if (!PdbSignature && !ValidGuid(PdbGUID))
  259. idd->fPdbUnmatched = true;
  260. } else {
  261. pprint(idd->pe, "%s - %s\n", szPDB, diaErrorText(hr));
  262. if (hr == E_PDB_INVALID_SIG || hr == E_PDB_INVALID_AGE) {
  263. if (!ValidSig(PdbSignature, PdbGUID)) {
  264. hr = pdia->source->loadDataFromPdb(wszPDB);
  265. } else if (!*idd->FoundPdb)
  266. CopyStrArray(idd->FoundPdb, szPDB);
  267. } else if (hr == E_PDB_NOT_FOUND) {
  268. if (!(g.LastSymLoadError & SYMLOAD_PDBERRORMASK)) {
  269. g.LastSymLoadError = SYMLOAD_PDBNOTFOUND;
  270. }
  271. } else {
  272. g.LastSymLoadError = (hr << 8) & SYMLOAD_PDBERRORMASK;
  273. }
  274. }
  275. return hr;
  276. }
  277. HRESULT
  278. CheckDirForPdbs(
  279. PIMGHLP_DEBUG_DATA idd,
  280. PSTR path,
  281. GUID *PdbGUID,
  282. DWORD PdbSignature,
  283. DWORD PdbAge
  284. )
  285. {
  286. WIN32_FIND_DATA fd;
  287. HANDLE hf;
  288. HRESULT hr;
  289. char drive[_MAX_DRIVE + 1];
  290. char dir[_MAX_DIR + 1];
  291. char fname[_MAX_FNAME + 1];
  292. char sfname[_MAX_FNAME + 1];
  293. char ext[_MAX_EXT + 1];
  294. char spath[MAX_PATH + 1];
  295. if (!*path)
  296. return E_PDB_NOT_FOUND;
  297. _splitpath(path, drive, dir, fname, ext);
  298. ShortNodeName(fname, sfname, DIMA(sfname));
  299. // now search the tree
  300. PrintString(spath, DIMA(spath), "%s%s%s%s\\*", drive, dir, sfname, ext);
  301. ZeroMemory(&fd, sizeof(fd));
  302. hf = FindFirstFile(spath, &fd);
  303. if (hf == INVALID_HANDLE_VALUE)
  304. return E_PDB_NOT_FOUND;
  305. do {
  306. if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))
  307. continue;
  308. PrintString(spath, DIMA(spath), "%s%s%s%s\\%s", drive, dir, sfname, ext, fd.cFileName);
  309. if (isdir(spath)) {
  310. EnsureTrailingBackslash(spath);
  311. CatStrArray(spath, sfname);
  312. CatStrArray(spath, ext);
  313. } else if (!IsPdb(spath))
  314. continue;
  315. hr = diaOpenPdb(idd, spath, PdbGUID, PdbSignature, PdbAge, false);
  316. if (hr == S_OK) {
  317. CopyString(path, spath, MAX_PATH + 1);
  318. return hr;
  319. }
  320. } while (FindNextFile(hf, &fd));
  321. // If there is no match, but a file exists in the symbol subdir with
  322. // a matching name, make sure that is what will be picked.
  323. PrintString(spath, DIMA(spath), "%s%s%s%s\\%s%s", drive, dir, sfname, ext, sfname, ext);
  324. if (fileexists(spath))
  325. CopyStrArray(idd->FoundPdb, spath);
  326. return E_PDB_NOT_FOUND;
  327. }
  328. HRESULT
  329. diaLocatePdb(
  330. PIMGHLP_DEBUG_DATA idd,
  331. PSTR szPDB,
  332. GUID *PdbGUID,
  333. DWORD PdbSignature,
  334. DWORD PdbAge,
  335. char *szImageExt
  336. )
  337. {
  338. DWORD pass;
  339. EC hrcode = E_PDB_NOT_FOUND;
  340. GUID guid;
  341. HRESULT hr = E_PDB_NOT_FOUND;
  342. char pdb[MAX_PATH + 1];
  343. char drive[6];
  344. char path[MAX_PATH + 1];
  345. char module[MAX_PATH + 1];
  346. char modbuf[MAX_PATH + 1];
  347. char name[MAX_PATH + 1];
  348. char ext[_MAX_EXT + 1];
  349. char *next;
  350. DWORD attrib;
  351. DWORD err;
  352. BOOL ssrv = true;
  353. #ifdef DEBUG
  354. if (traceSubName(szPDB)) // for setting debug breakpoints from DBGHELP_TOKEN
  355. dtrace("diaLocatePdb(%s)\n", szPDB);
  356. #endif
  357. if (!PdbSignature
  358. && !IsPdb(idd->ImageFilePath)
  359. && !ValidGuid(PdbGUID)
  360. && option(SYMOPT_EXACT_SYMBOLS))
  361. {
  362. g.LastSymLoadError = SYMLOAD_PDBUNMATCHED;
  363. return E_PDB_INVALID_SIG;
  364. }
  365. if (!idd->dia)
  366. return EC_NO_DEBUG_INFO;
  367. // If the image file name is a pdb, then just try to open it.
  368. // Don't attempt any searching.
  369. if (IsPdb(idd->ImageFilePath)) {
  370. CopyStrArray(pdb, idd->ImageFilePath);
  371. hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false);
  372. if (hr == S_OK) {
  373. idd->PdbSrc = srcImagePath;
  374. goto done;
  375. }
  376. return E_PDB_NOT_FOUND;
  377. }
  378. // Set up indexes for symbol server
  379. ZeroMemory(&guid, sizeof(GUID));
  380. if (PdbSignature)
  381. guid.Data1 = PdbSignature;
  382. else if (PdbGUID)
  383. memcpy(&guid, PdbGUID, sizeof(GUID));
  384. // get name of pdb
  385. _splitpath(szPDB, NULL, NULL, module, ext);
  386. PrintString(name, DIMA(name), "%s%s", module, ".pdb");
  387. // SymbolPath is a semicolon delimited path (reference path first)
  388. next = TokenFromSymbolPath(idd->SymbolPath, path, MAX_PATH + 1);
  389. while (*path) {
  390. for (pass = 0; pass < 3; pass++) {
  391. if (symsrvPath(path)) {
  392. if (pass || !ssrv)
  393. break;
  394. *pdb = 0;
  395. idd->PdbSrc = srcSymSrv;
  396. err = symsrvGetFile(idd->pe,
  397. path,
  398. name,
  399. &guid,
  400. PdbAge,
  401. 0,
  402. pdb);
  403. if (err == ERROR_NO_DATA)
  404. ssrv = false;
  405. } else {
  406. if (pass && !*szImageExt)
  407. break;
  408. idd->PdbSrc = srcSearchPath;
  409. if (!CreateSymbolPath(pass, path, szImageExt, module, ext, pdb, DIMA(pdb))) {
  410. hr = E_PDB_NOT_FOUND;
  411. goto done;
  412. }
  413. if (!pass) {
  414. hr = CheckDirForPdbs(idd, pdb, PdbGUID, PdbSignature, PdbAge);
  415. if (hr == S_OK)
  416. goto done;
  417. }
  418. }
  419. if (*pdb) {
  420. hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false);
  421. hrcode = SetDiaError(hrcode, hr);
  422. if (hr == S_OK)
  423. goto done;
  424. }
  425. }
  426. next = TokenFromSymbolPath(next, path, MAX_PATH + 1);
  427. }
  428. // try the same path as the image
  429. if (idd->ImageFileHandle && *idd->ImageFilePath) {
  430. _splitpath(idd->ImageFilePath, drive, path, NULL, NULL);
  431. PrintString(pdb, DIMA(pdb), "%s%s%s", drive, path, name);
  432. hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false);
  433. if (hr == S_OK)
  434. idd->PdbSrc = srcImagePath;
  435. }
  436. // try the CV Record
  437. if (hr != S_OK && strcmp(pdb, szPDB) && !option(SYMOPT_IGNORE_CVREC)) {
  438. CopyStrArray(pdb, szPDB);
  439. hr = diaOpenPdb(idd, pdb, PdbGUID, PdbSignature, PdbAge, false);
  440. if (hr == S_OK)
  441. idd->PdbSrc = srcCVRec;
  442. }
  443. // try mismatches
  444. if (hr != S_OK && *idd->FoundPdb) {
  445. if (option(SYMOPT_LOAD_ANYTHING)) {
  446. CopyStrArray(pdb, idd->FoundPdb);
  447. hr = diaOpenPdb(idd, pdb, NULL, 0, 0, true);
  448. if (hr == S_OK)
  449. idd->PdbSrc = srcSearchPath;
  450. }
  451. idd->LoadInfo &= DSLFLAG_MISMATCHED_PDB;
  452. pprint(idd->pe, "%s mismatched pdb for %s\n",
  453. hr == S_OK ? "Loaded" : "Couldn't load",
  454. *idd->ImageFilePath ? idd->ImageFilePath : name);
  455. }
  456. done:
  457. if (hr == S_OK) {
  458. // Store the name of the PDB we actually opened for later reference.
  459. strcpy(szPDB, pdb); // SECURITY: Don't know size of target buffer.
  460. SetLastError(NO_ERROR);
  461. g.LastSymLoadError = SYMLOAD_OK;
  462. }
  463. return hr;
  464. }
  465. BOOL
  466. diaReadStream(
  467. PMODULE_ENTRY mi,
  468. char *stream,
  469. PBYTE *buf,
  470. DWORD *size
  471. )
  472. {
  473. PDIA pdia;
  474. PDB *pdb;
  475. HRESULT hr;
  476. BOOL rc;
  477. LONG cb;
  478. Stream *pstream;
  479. LONG count = 0;
  480. assert (mi && stream && *stream && buf && size);
  481. *size = 0;
  482. *buf = 0;
  483. pdia = (PDIA)mi->dia;
  484. if (!pdia)
  485. return false;
  486. hr = GetRawPdbPtrForDataSource(pdia->source, &pdb);
  487. if (hr != S_OK)
  488. return false;
  489. rc = PDBOpenStream(pdb, stream, &pstream);
  490. if (!rc)
  491. return false;
  492. *size = StreamQueryCb(pstream);
  493. if (!*size)
  494. return false;
  495. *buf = (PBYTE)MemAlloc(*size + 1);
  496. if (!*buf)
  497. return false;
  498. cb = *size;
  499. rc = StreamRead(pstream, 0, *buf, &cb);
  500. if (!rc)
  501. goto error;
  502. if (cb != *size)
  503. goto error;
  504. return true;
  505. error:
  506. MemFree(*buf);
  507. *buf = 0;
  508. return 0;
  509. }
  510. DWORD
  511. diaReadDebugStream(
  512. PVOID dia,
  513. char *stream,
  514. PBYTE *buf,
  515. DWORD *size
  516. )
  517. {
  518. DWORD celt;
  519. LONG count;
  520. DWORD cb;
  521. HRESULT hr;
  522. VARIANT var;
  523. PDIA pdia;
  524. WCHAR wstream[1000];
  525. CComPtr< IDiaEnumDebugStreams > idiaStreams;
  526. CComPtr< IDiaEnumDebugStreamData > idiaStream;
  527. assert (dia && stream && *stream && buf);
  528. pdia = (PDIA)dia;
  529. hr = pdia->session->getEnumDebugStreams(&idiaStreams);
  530. if (hr != S_OK)
  531. return 0;
  532. if (!ansi2wcs(stream, wstream, 1000))
  533. return 0;
  534. var.vt = VT_BSTR;
  535. var.bstrVal = wstream;
  536. hr = idiaStreams->Item(var, &idiaStream);
  537. if (hr != S_OK)
  538. return 0;
  539. hr = idiaStream->get_Count(&count);
  540. if (hr != S_OK)
  541. return 0;
  542. if (count < 1)
  543. return 0;
  544. hr = idiaStream->Next(count, 0, &cb, NULL, &celt);
  545. if (hr != S_OK)
  546. return 0;
  547. if (cb < 1)
  548. return 0;
  549. *buf = (PBYTE)MemAlloc(cb);
  550. if (!*buf)
  551. return 0;
  552. hr = idiaStream->Next(count, cb, &cb, *buf, &celt);
  553. if (hr != S_OK) {
  554. MemFree(*buf);
  555. *buf = NULL;
  556. return 0;
  557. }
  558. *size = cb;
  559. return count;
  560. }
  561. BOOL
  562. diaGetOmaps(
  563. PIMGHLP_DEBUG_DATA idd
  564. )
  565. {
  566. DWORD celt;
  567. LONG count;
  568. DWORD cb;
  569. PBYTE tbuf = NULL;
  570. PBYTE fbuf = NULL;
  571. HRESULT hr;
  572. VARIANT var;
  573. count = diaReadDebugStream(idd->dia, "OMAPTO", &tbuf, &cb);
  574. if (count < 1)
  575. return false;
  576. idd->cOmapTo = count;
  577. idd->pOmapTo = (POMAP)tbuf;
  578. idd->fOmapToMapped = false;
  579. count = diaReadDebugStream(idd->dia, "OMAPFROM", &fbuf, &cb);
  580. if (count < 1)
  581. return false;
  582. idd->cOmapFrom = count;
  583. idd->pOmapFrom = (POMAP)fbuf;
  584. idd->fOmapFromMapped = false;
  585. return true;
  586. }
  587. BOOL
  588. diaGetFPOTable(
  589. PIMGHLP_DEBUG_DATA idd
  590. )
  591. {
  592. LONG count;
  593. PBYTE buf;
  594. DWORD cb;
  595. count = diaReadDebugStream(idd->dia, "FPO", &buf, &cb);
  596. if (count < 1)
  597. return false;
  598. idd->cFpo = count;
  599. idd->pFpo = buf;
  600. return true;
  601. }
  602. BOOL
  603. diaGetPData(
  604. PMODULE_ENTRY mi
  605. )
  606. {
  607. LONG count;
  608. PBYTE buf;
  609. DWORD cb;
  610. count = diaReadDebugStream(mi->dia, "PDATA", &buf, &cb);
  611. if (count < 1)
  612. return false;
  613. mi->dsExceptions = dsDia;
  614. mi->cPData = count;
  615. mi->cbPData = cb;
  616. mi->pPData = buf;
  617. return true;
  618. }
  619. BOOL
  620. diaGetXData(
  621. PMODULE_ENTRY mi
  622. )
  623. {
  624. DWORD celt;
  625. LONG count;
  626. DWORD cb;
  627. PBYTE buf;
  628. HRESULT hr;
  629. PDIA pdia;
  630. VARIANT var;
  631. CComPtr< IDiaEnumDebugStreams > idiaStreams;
  632. CComPtr< IDiaEnumDebugStreamData > idiaStream;
  633. assert (mi && mi->dia);
  634. pdia = (PDIA)mi->dia;
  635. if (!pdia)
  636. return false;
  637. hr = pdia->session->getEnumDebugStreams(&idiaStreams);
  638. if (hr != S_OK)
  639. return false;
  640. var.vt = VT_BSTR;
  641. var.bstrVal = L"XDATA";
  642. hr = idiaStreams->Item(var, &idiaStream);
  643. if (hr != S_OK)
  644. return false;
  645. hr = idiaStream->get_Count(&count);
  646. if (hr != S_OK)
  647. return false;
  648. if (count < 1)
  649. return true;
  650. hr = idiaStream->Next(count, 0, &cb, NULL, &celt);
  651. if (hr != S_OK)
  652. return false;
  653. if (cb < 1)
  654. return true;
  655. CComQIPtr< IDiaImageData, &IID_IDiaImageData > idiaXDataHdr(idiaStream);
  656. if (!idiaXDataHdr.p)
  657. return false;
  658. DWORD relativeVirtualAddress;
  659. if (FAILED(hr = idiaXDataHdr->get_relativeVirtualAddress(&relativeVirtualAddress)))
  660. return false;
  661. buf = (PBYTE)MemAlloc(cb + sizeof(DWORD));
  662. if (!buf)
  663. return false;
  664. memcpy(buf, &relativeVirtualAddress, sizeof(relativeVirtualAddress));
  665. hr = idiaStream->Next(count, cb, &cb, buf + sizeof(DWORD), &celt);
  666. if (hr != S_OK) {
  667. MemFree(buf);
  668. return false;
  669. }
  670. mi->dsExceptions = dsDia;
  671. mi->cXData = count;
  672. mi->cbXData = cb;
  673. mi->pXData = buf;
  674. return true;
  675. }
  676. void
  677. diaRelease(
  678. PVOID dia
  679. )
  680. {
  681. PDIA pdia = (PDIA)dia;
  682. if (pdia)
  683. delete pdia;
  684. }
  685. #if 1
  686. LONG
  687. diaCountGlobals(
  688. PMODULE_ENTRY mi
  689. )
  690. {
  691. PDIA pdia;
  692. HRESULT hr;
  693. LONG count;
  694. LONG rc = 0;
  695. CComPtr< IDiaSymbol > idiaGlobals;
  696. CComPtr< IDiaEnumSymbols > idiaSymbols;
  697. if (mi->cGlobals != -1)
  698. return mi->cGlobals;
  699. pdia = (PDIA)mi->dia;
  700. if (!pdia)
  701. return mi->cGlobals;
  702. hr = pdia->session->get_globalScope(&idiaGlobals);
  703. if (hr != S_OK)
  704. goto exit;
  705. // see if there are any globals at all
  706. hr = idiaGlobals->findChildren(SymTagData, NULL, 0, &idiaSymbols);
  707. if (hr != S_OK)
  708. goto exit;
  709. hr = idiaSymbols->get_Count(&count);
  710. if (hr != S_OK)
  711. goto exit;
  712. rc = count;
  713. idiaSymbols = NULL;
  714. hr = idiaGlobals->findChildren(SymTagFunction, NULL, 0, &idiaSymbols);
  715. if (hr != S_OK)
  716. goto exit;
  717. hr = idiaSymbols->get_Count(&count);
  718. if (hr != S_OK)
  719. goto exit;
  720. rc += count;
  721. exit:
  722. mi->cGlobals = rc;
  723. return rc;
  724. }
  725. #endif
  726. BOOL
  727. diaGetPdb(
  728. PIMGHLP_DEBUG_DATA idd
  729. )
  730. {
  731. HRESULT hr;
  732. PDIA pdia;
  733. DWORD cpathlen = 0;
  734. DWORD len;
  735. CHAR szExt[_MAX_EXT + 1] = {0};
  736. if (idd->dia) {
  737. pprint(idd->pe, "redundant pdb call!\n");
  738. return true;
  739. }
  740. if (*idd->ImageFilePath) {
  741. _splitpath(idd->ImageFilePath, NULL, NULL, NULL, szExt);
  742. } else if (*idd->ImageName) {
  743. _splitpath(idd->ImageName, NULL, NULL, NULL, szExt);
  744. }
  745. // if we have no valid filename, then this must be an executable
  746. if (!*szExt)
  747. CopyStrArray(szExt, ".exe");
  748. // get interface to dia
  749. pdia = new DIA;
  750. if (!pdia) {
  751. hr = E_PDB_OUT_OF_MEMORY;
  752. goto error;
  753. }
  754. idd->dia = pdia;
  755. pdia->source = NULL;
  756. #ifdef COMDIA
  757. hr = CoCreateInstance(CLSID_DiaSourceAlt, NULL, CLSCTX_INPROC_SERVER, IID_IDiaDataSource, (void **)&pdia->source);
  758. #else
  759. hr = DiaCoCreate(CLSID_DiaSourceAlt, IID_IDiaDataSource, (void **)&pdia->source);
  760. #endif
  761. if (hr != S_OK)
  762. goto error;
  763. // go ahead and get pdb
  764. SetCriticalErrorMode();
  765. hr = diaLocatePdb(idd,
  766. idd->PdbFileName,
  767. &idd->PdbGUID,
  768. idd->PdbSignature,
  769. idd->PdbAge,
  770. &szExt[1]);
  771. ResetCriticalErrorMode();
  772. if (hr != S_OK) {
  773. hr = S_OK; // error was already handled by diaLocatePdb()
  774. goto error;
  775. }
  776. // open the session on the pdb
  777. pdia->session = NULL;
  778. hr = pdia->source->openSession(&pdia->session);
  779. if (hr != S_OK)
  780. goto error;
  781. // Set the module load address so we can use VAs.
  782. hr = pdia->session->put_loadAddress(idd->InProcImageBase);
  783. if (hr != S_OK)
  784. goto error;
  785. // fixup the address map so that we can translate rva to full addresses
  786. hr = pdia->session->QueryInterface(IID_IDiaAddressMap, (void**)&pdia->addrmap);
  787. if (hr != S_OK)
  788. goto error;
  789. if (idd->pCurrentSections) {
  790. hr = pdia->addrmap->set_imageHeaders(idd->cCurrentSections * sizeof(IMAGE_SECTION_HEADER),
  791. (BYTE *)idd->pCurrentSections,
  792. false);
  793. if (hr != S_OK)
  794. goto error;
  795. }
  796. // this hack is to fix a problem with v7 pdbs not storing the original image alignment
  797. if (idd->ImageAlign) {
  798. hr = pdia->addrmap->put_imageAlign(idd->ImageAlign);
  799. if (hr != S_OK)
  800. goto error;
  801. }
  802. // pass in the omap information and setup the proper image alignment to the original
  803. if (idd->cOmapFrom && idd->pOmapFrom) {
  804. hr = pdia->addrmap->put_imageAlign(idd->ImageAlign);
  805. if (hr != S_OK)
  806. goto error;
  807. hr = pdia->addrmap->set_addressMap(idd->cOmapTo, (DiaAddressMapEntry *)idd->pOmapTo, true);
  808. if (hr != S_OK)
  809. goto error;
  810. hr = pdia->addrmap->set_addressMap(idd->cOmapFrom, (DiaAddressMapEntry *)idd->pOmapFrom, false);
  811. if (hr != S_OK)
  812. goto error;
  813. hr = pdia->addrmap->put_addressMapEnabled(true);
  814. if (hr != S_OK)
  815. goto error;
  816. }
  817. hr = pdia->addrmap->put_relativeVirtualAddressEnabled(true);
  818. if (hr != S_OK)
  819. goto error;
  820. diaGetFPOTable(idd);
  821. diaGetOmaps(idd);
  822. diaGetPdbInfo(idd);
  823. return true;
  824. error:
  825. if (hr != S_OK)
  826. pprint(idd->pe, "%s %s\n", idd->PdbFileName, diaErrorText(hr));
  827. diaRelease(pdia);
  828. idd->dia = NULL;
  829. return false;
  830. }
  831. DWORD64
  832. GetAddressFromRva(
  833. PMODULE_ENTRY mi,
  834. DWORD rva
  835. )
  836. {
  837. DWORD64 addr;
  838. assert(mi);
  839. addr = rva ? mi->BaseOfDll + rva : 0;
  840. return addr;
  841. }
  842. DWORD64
  843. GetLineAddressFromRva(
  844. PMODULE_ENTRY mi,
  845. DWORD rva
  846. )
  847. {
  848. DWORD64 addr;
  849. assert(mi);
  850. addr = rva ? mi->BaseOfDll + rva : 0;
  851. // Line symbol information names the IA64 bundle
  852. // syllables with 0,1,2 whereas the debugger expects
  853. // 0,4,8. Convert.
  854. if (mi->MachineType == IMAGE_FILE_MACHINE_IA64 && (addr & 3)) {
  855. addr = (addr & ~3) | ((addr & 3) << 2);
  856. }
  857. return addr;
  858. }
  859. BOOL
  860. diaFillSymbolInfo(
  861. PSYMBOL_INFO si,
  862. PMODULE_ENTRY mi,
  863. IDiaSymbol *idiaSymbol
  864. )
  865. {
  866. HRESULT hr;
  867. BSTR wname=NULL;
  868. char name[MAX_SYM_NAME + 1];
  869. char *p;
  870. DWORD dw;
  871. ULONG64 size;
  872. ULONG64 va;
  873. BOOL rc;
  874. VARIANT value;
  875. CComPtr< IDiaEnumSymbols > idiaValues;
  876. CComPtr<IDiaSymbol> idiaValue;
  877. if (!idiaSymbol)
  878. return false;
  879. rc = true;
  880. dw = si->MaxNameLen;
  881. ZeroMemory(si, sizeof(SYMBOL_INFO));
  882. si->MaxNameLen = dw;
  883. // si->SizeOfStruct = IGNORED;
  884. // si->TypeIndex = NYI;
  885. // si->Reserved = IGNORED;
  886. si->ModBase = mi->BaseOfDll;
  887. hr = idiaSymbol->get_symTag(&si->Tag);
  888. if (hr != S_OK)
  889. return false;
  890. switch (si->Tag)
  891. {
  892. case SymTagData:
  893. hr = idiaSymbol->get_locationType(&dw);
  894. if (hr != S_OK)
  895. return false;
  896. switch(dw)
  897. {
  898. case LocIsTLS:
  899. // TLS variables have an offset into the TLS data area.
  900. si->Flags = SYMFLAG_TLSREL;
  901. hr = idiaSymbol->get_addressOffset(&dw);
  902. if (hr != S_OK)
  903. return false;
  904. si->Address = (ULONG64) (LONG64) (LONG) dw;
  905. break;
  906. case LocIsStatic:
  907. hr = idiaSymbol->get_relativeVirtualAddress(&dw);
  908. si->Address = GetAddressFromRva(mi, dw);
  909. if (!si->Address)
  910. rc = false;
  911. break;
  912. case LocIsEnregistered:
  913. hr = idiaSymbol->get_registerId(&si->Register);
  914. si->Flags = SYMFLAG_REGISTER;
  915. break;
  916. case LocIsRegRel:
  917. si->Flags = SYMFLAG_REGREL;
  918. hr = idiaSymbol->get_registerId(&si->Register);
  919. if (hr != S_OK)
  920. return false;
  921. hr = idiaSymbol->get_offset((PLONG)&dw);
  922. si->Address = (ULONG64) (LONG64) (LONG) dw;
  923. break;
  924. case LocIsThisRel:
  925. // struct members - get_Offset
  926. default:
  927. si->Flags |= 0;
  928. break;
  929. }
  930. break;
  931. case SymTagThunk:
  932. hr = idiaSymbol->get_targetRelativeVirtualAddress(&dw);
  933. if (hr == S_OK) {
  934. si->Value = GetAddressFromRva(mi, dw);
  935. si->Flags |= SYMFLAG_THUNK;
  936. }
  937. // pass through
  938. case SymTagFunction:
  939. case SymTagPublicSymbol:
  940. hr = idiaSymbol->get_relativeVirtualAddress(&dw);
  941. si->Address = GetAddressFromRva(mi, dw);
  942. if (si->Address)
  943. break;
  944. if (option(SYMOPT_ALLOW_ABSOLUTE_SYMBOLS)) {
  945. hr = idiaSymbol->get_virtualAddress(&va);
  946. si->Address = va;
  947. }
  948. if (!si->Address)
  949. rc = false;
  950. break;
  951. case SymTagBlock:
  952. hr = idiaSymbol->get_relativeVirtualAddress(&dw);
  953. si->Address = GetAddressFromRva(mi, dw);
  954. if (!si->Address)
  955. rc = false;
  956. return rc;
  957. case SymTagAnnotation:
  958. // Local data search
  959. hr = idiaSymbol->findChildren(SymTagNull, NULL, nsNone, &idiaValues);
  960. if (hr != S_OK || !idiaValues)
  961. break;
  962. p = si->Name;
  963. *p = 0;
  964. while (SUCCEEDED(idiaValues->Next(1, &idiaValue, &dw)) && dw == 1) {
  965. hr = idiaValue->get_value(&value);
  966. if (hr != S_OK)
  967. break;
  968. wcs2ansi(value.bstrVal, p, si->MaxNameLen - (ULONG)(p - si->Name));
  969. p += strlen(p) + 1;
  970. FreeDiaVariant(&value);
  971. idiaValue = NULL;
  972. }
  973. *(p + 1) = 0;
  974. hr = idiaSymbol->get_relativeVirtualAddress(&dw);
  975. si->Address = GetAddressFromRva(mi, dw);
  976. if (!si->Address)
  977. rc = false;
  978. // There's no name processing for annotations. We're done.
  979. return rc;
  980. default:
  981. break;
  982. }
  983. if (hr != S_OK)
  984. return false;
  985. // check for flags and types
  986. hr = idiaSymbol->get_dataKind(&dw);
  987. if (hr == S_OK) {
  988. if (dw == DataIsParam)
  989. si->Flags |= SYMFLAG_PARAMETER;
  990. else if (dw == DataIsConstant)
  991. si->Flags = SYMFLAG_CONSTANT;
  992. }
  993. hr = idiaSymbol->get_typeId(&dw);
  994. if (hr == S_OK)
  995. si->TypeIndex = dw;
  996. // get the name
  997. hr = idiaSymbol->get_name(&wname);
  998. if (hr != S_OK || !wname) {
  999. if (si->Tag != SymTagThunk)
  1000. return false;
  1001. PrintString(name, DIMA(name), "thunk@%I64x", si->Address);
  1002. CopyString(si->Name, name, si->MaxNameLen);
  1003. } else if (!wname[0]) {
  1004. rc = false;
  1005. } else {
  1006. wcs2ansi(wname, name, MAX_SYM_NAME);
  1007. if ((si->Tag != SymTagPublicSymbol)
  1008. && !option(SYMOPT_NO_PUBLICS)
  1009. && strchr(name, '@')) {
  1010. rc = false;
  1011. }
  1012. if (option(SYMOPT_NO_CPP)) {
  1013. while (p = strstr(name, "::")) {
  1014. p[0] = '_';
  1015. p[1] = '_';
  1016. }
  1017. }
  1018. if (*name == '.')
  1019. si->Flags = SYMFLAG_FUNCTION;
  1020. if (option(SYMOPT_UNDNAME)
  1021. && ((si->Tag == SymTagPublicSymbol) || (si->Tag == SymTagThunk)))
  1022. {
  1023. SymUnDNameInternal(si->Name,
  1024. si->MaxNameLen,
  1025. name,
  1026. strlen(name),
  1027. mi->MachineType,
  1028. true);
  1029. if (si->MaxNameLen > 0) {
  1030. CopyStrArray(name, si->Name);
  1031. } else {
  1032. name[0] = 0;
  1033. }
  1034. } else {
  1035. CopyString(si->Name, name, si->MaxNameLen);
  1036. }
  1037. // let the caller know this is a $$$XXXAA style symbol
  1038. if (strlen(name) == 8 && !strncmp(name, "$$$",3) &&
  1039. isxdigit(name[5]) && isxdigit(name[6]) && isxdigit(name[7]) ) {
  1040. rc = false;
  1041. }
  1042. }
  1043. #ifdef DEBUG
  1044. CopyStrArray(name, mi->si.Name);
  1045. if (traceSubName(name)) // for setting debug breakpoints from DBGHELP_TOKEN
  1046. dtrace("debug(%s)\n", name);
  1047. #endif
  1048. if (wname)
  1049. LocalFree (wname);
  1050. // get_length is very expensive on public symbols
  1051. if (si->Tag == SymTagPublicSymbol)
  1052. return rc;
  1053. // okay. Get the length.
  1054. hr = idiaSymbol->get_length(&size);
  1055. if (hr == S_OK)
  1056. si->Size = (ULONG)size;
  1057. else {
  1058. CComPtr <IDiaSymbol> pType;
  1059. if ((hr = idiaSymbol->get_type(&pType)) == S_OK){
  1060. hr = pType->get_length(&size);
  1061. if (hr == S_OK)
  1062. si->Size = (ULONG)size;
  1063. }
  1064. pType = NULL;
  1065. }
  1066. return rc;
  1067. }
  1068. BOOL
  1069. diaSetModFromIP(
  1070. PPROCESS_ENTRY pe
  1071. )
  1072. {
  1073. HRESULT hr;
  1074. DWORD64 ip;
  1075. DWORD rva;
  1076. PDIA pdia;
  1077. // get the current IP
  1078. ip = GetIP(pe);
  1079. if (!ip) {
  1080. pprint(pe, "IP not set!\n");
  1081. return false;
  1082. }
  1083. // find and load symbols for the module that matches the IP
  1084. pe->ipmi = GetModFromAddr(pe, ip);
  1085. if (!pe->ipmi)
  1086. return false;
  1087. if (!pe->ipmi->dia)
  1088. return false;
  1089. pdia = (PDIA)pe->ipmi->dia;
  1090. rva = (DWORD)(ip - pe->ipmi->BaseOfDll);
  1091. CComPtr< IDiaSymbol > idiaScope;
  1092. hr = pdia->session->findSymbolByRVA(rva, SymTagNull, &idiaScope);
  1093. if (hr != S_OK)
  1094. return false;
  1095. hr = pdia->session->symsAreEquiv(idiaScope, pdia->scope);
  1096. if (hr == S_OK)
  1097. return false;
  1098. pdia->scope = idiaScope;
  1099. return true;
  1100. }
  1101. PWCHAR
  1102. ConvertNameForDia(
  1103. LPSTR name,
  1104. PWCHAR wname
  1105. )
  1106. {
  1107. assert (name && wname);
  1108. if (!name || !*name)
  1109. return NULL;
  1110. ansi2wcs(name, wname, MAX_SYM_NAME);
  1111. return wname;
  1112. }
  1113. VOID
  1114. MakeEmbeddedREStr(
  1115. PCHAR out,
  1116. PCHAR in
  1117. )
  1118. {
  1119. if (*in != '*')
  1120. *out++ = '*';
  1121. for (; *in; in++, out++)
  1122. *out = *in;
  1123. if (*(in - 1) != '*')
  1124. *out++ = '*';
  1125. *out = 0;
  1126. }
  1127. BOOL
  1128. diaGetLocals(
  1129. PPROCESS_ENTRY pe,
  1130. LPCSTR name,
  1131. PROC callback,
  1132. PVOID context,
  1133. BOOL use64,
  1134. BOOL unicode
  1135. )
  1136. {
  1137. PMODULE_ENTRY mi;
  1138. DWORD64 ip;
  1139. DWORD rva;
  1140. PDIA pdia;
  1141. HRESULT hr;
  1142. DWORD rc;
  1143. DWORD tag;
  1144. DWORD scope;
  1145. DWORD celt;
  1146. DWORD opt;
  1147. CHAR symname[MAX_SYM_NAME + 1];
  1148. WCHAR wbuf[MAX_SYM_NAME + 1];
  1149. PWCHAR wname;
  1150. assert(pe);
  1151. CComPtr< IDiaSymbol > idiaSymbols;
  1152. opt = option(SYMOPT_CASE_INSENSITIVE) ? nsCaseInRegularExpression : nsRegularExpression;
  1153. if (option(SYMOPT_PUBLICS_ONLY))
  1154. return true;
  1155. // get the current scope
  1156. mi = pe->ipmi;
  1157. if (!mi)
  1158. return false;
  1159. pdia = (PDIA)mi->dia;
  1160. if (!pdia)
  1161. return false;
  1162. idiaSymbols = pdia->scope;
  1163. diaFillSymbolInfo(&mi->si, mi, idiaSymbols);
  1164. PrepRE4Srch(name, symname);
  1165. wname = ConvertNameForDia(symname, wbuf);
  1166. // loop through all symbols
  1167. for ( ; idiaSymbols != NULL; ) {
  1168. CComPtr< IDiaEnumSymbols > idiaEnum;
  1169. // local data search
  1170. hr = idiaSymbols->findChildren(SymTagNull, wname, opt, &idiaEnum);
  1171. if (hr != S_OK)
  1172. return false;
  1173. idiaSymbols->get_symTag(&scope);
  1174. if (hr != S_OK)
  1175. return false;
  1176. if (scope == SymTagExe) { // sanity check, never enumerate all exe's symbols
  1177. break;
  1178. }
  1179. // this walks the local symbol list for the loaded enumeration
  1180. CComPtr< IDiaSymbol > idiaSymbol;
  1181. for (;
  1182. SUCCEEDED(hr = idiaEnum->Next( 1, &idiaSymbol, &celt)) && celt == 1;
  1183. idiaSymbol = NULL)
  1184. {
  1185. ULONG DataKind;
  1186. idiaSymbol->get_symTag(&tag);
  1187. switch (tag)
  1188. {
  1189. case SymTagData:
  1190. case SymTagFunction:
  1191. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol))
  1192. continue;
  1193. if (!strcmp(mi->si.Name, "`string'"))
  1194. continue;
  1195. mi->si.Scope = scope;
  1196. mi->si.Flags |= SYMFLAG_LOCAL;
  1197. if (!callback)
  1198. return true;
  1199. if (mi->si.Flags & SYMFLAG_CONSTANT)
  1200. continue;
  1201. rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode);
  1202. if (!rc) {
  1203. mi->code = ERROR_CANCELLED;
  1204. return rc;
  1205. }
  1206. break;
  1207. default:
  1208. break;
  1209. }
  1210. }
  1211. if (callback && scope == SymTagFunction) // stop when at function scope
  1212. break;
  1213. // move to lexical parent
  1214. CComPtr< IDiaSymbol > idiaParent;
  1215. hr = idiaSymbols->get_lexicalParent(&idiaParent);
  1216. if (hr != S_OK || !idiaParent)
  1217. return false;
  1218. idiaSymbols = idiaParent;
  1219. }
  1220. // We reached the end. If we enumerating (I.E. callback != NULL)
  1221. // then return true. If we are searching for a single match,
  1222. // we have failed and should return false;
  1223. if (callback)
  1224. return true;
  1225. return false;
  1226. }
  1227. int __cdecl
  1228. CompareAddrs(
  1229. const void *addr1,
  1230. const void *addr2
  1231. )
  1232. {
  1233. LONGLONG Diff = *(DWORD64 *)addr1 - *(DWORD64 *)addr2;
  1234. if (Diff < 0) {
  1235. return -1;
  1236. } else if (Diff > 0) {
  1237. return 1;
  1238. } else {
  1239. return 0;
  1240. }
  1241. }
  1242. PDWORD64
  1243. FindAddr(
  1244. PDWORD64 pAddrs,
  1245. ULONG cAddrs,
  1246. DWORD64 addr
  1247. )
  1248. {
  1249. LONG high;
  1250. LONG low;
  1251. LONG i;
  1252. LONG rc;
  1253. low = 0;
  1254. high = ((LONG)cAddrs) - 1;
  1255. while (high >= low) {
  1256. i = (low + high) >> 1;
  1257. rc = CompareAddrs(&addr, &pAddrs[i]);
  1258. if (rc < 0)
  1259. high = i - 1;
  1260. else if (rc > 0)
  1261. low = i + 1;
  1262. else
  1263. return &pAddrs[i];
  1264. }
  1265. return NULL;
  1266. }
  1267. typedef BOOL
  1268. (CALLBACK *PSYM_LOCALENUMSYMBOL_CALLBACK)(
  1269. PSYMBOL_INFO si,
  1270. ULONG size,
  1271. IDiaSymbol *idiaObj,
  1272. PVOID context
  1273. );
  1274. char* dispsymtag(
  1275. ULONG symtag
  1276. )
  1277. {
  1278. static char* names[] =
  1279. {
  1280. "SymTagNull",
  1281. "SymTagExe",
  1282. "SymTagCompiland",
  1283. "SymTagCompilandDetails",
  1284. "SymTagCompilandEnv",
  1285. "SymTagFunction",
  1286. "SymTagBlock",
  1287. "SymTagData",
  1288. "SymTagAnnotation",
  1289. "SymTagLabel",
  1290. "SymTagPublicSymbol",
  1291. "SymTagUDT",
  1292. "SymTagEnum",
  1293. "SymTagFunctionType",
  1294. "SymTagPointerType",
  1295. "SymTagArrayType",
  1296. "SymTagBaseType",
  1297. "SymTagTypedef",
  1298. "SymTagBaseClass",
  1299. "SymTagFriend",
  1300. "SymTagFunctionArgType",
  1301. "SymTagFuncDebugStart",
  1302. "SymTagFuncDebugEnd",
  1303. "SymTagUsingNamespace",
  1304. "SymTagVTableShape",
  1305. "SymTagVTable",
  1306. "SymTagCustom",
  1307. "SymTagThunk",
  1308. "SymTagCustomType",
  1309. "SymTagManagedType",
  1310. "SymTagDimension",
  1311. };
  1312. if (symtag >= SymTagMax)
  1313. return "<Invalid>";
  1314. else
  1315. return names[symtag];
  1316. }
  1317. BOOL
  1318. diaEnumScope(
  1319. PPROCESS_ENTRY pe,
  1320. PMODULE_ENTRY mi,
  1321. DWORD tag,
  1322. char *mask,
  1323. PROC callback,
  1324. PVOID context,
  1325. BOOL use64,
  1326. BOOL unicode,
  1327. DWORD flags,
  1328. IDiaSymbol *idiaScope,
  1329. int depth
  1330. )
  1331. {
  1332. HRESULT hr;
  1333. DWORD celt;
  1334. DWORD stg;
  1335. BOOL disp;
  1336. char pad[300];
  1337. CComPtr< IDiaEnumSymbols > idiaSymbols;
  1338. CComPtr<IDiaSymbol> idiaSymbol;
  1339. ZeroMemory(pad, 300);
  1340. memset(pad, ' ', depth * 3);
  1341. hr = idiaScope->get_symTag(&stg);
  1342. if (hr != S_OK)
  1343. return false;
  1344. // display all objects within this scope
  1345. hr = idiaScope->findChildren(SymTagNull, NULL, 0, &idiaSymbols);
  1346. if (hr != S_OK)
  1347. return true;
  1348. while (SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1) {
  1349. disp = true;
  1350. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol))
  1351. continue;
  1352. if (mi->si.Tag == SymTagBlock)
  1353. CopyString(mi->si.Name, "BLOCK", mi->si.NameLen);
  1354. if (tag && mi->si.Tag != tag)
  1355. disp = false;
  1356. if (strcmpre(mi->si.Name, mask, !option(SYMOPT_CASE_INSENSITIVE)))
  1357. disp = false;
  1358. if (disp)
  1359. peprint(pe, "%s%s: %s\n", pad, dispsymtag(mi->si.Tag), mi->si.Name);
  1360. diaEnumScope(pe,
  1361. mi,
  1362. tag,
  1363. mask,
  1364. callback,
  1365. context,
  1366. use64,
  1367. unicode,
  1368. flags,
  1369. idiaSymbol,
  1370. depth + 1);
  1371. }
  1372. return true;
  1373. }
  1374. BOOL
  1375. diaGetItems(
  1376. PPROCESS_ENTRY pe,
  1377. PMODULE_ENTRY mi,
  1378. PCSTR name,
  1379. DWORD64 addr,
  1380. DWORD tag,
  1381. PROC callback,
  1382. PVOID context,
  1383. BOOL use64,
  1384. BOOL unicode,
  1385. DWORD flags
  1386. )
  1387. {
  1388. PDIA pdia;
  1389. HRESULT hr;
  1390. CHAR symname[MAX_SYM_NAME + 1];
  1391. CComPtr< IDiaSymbol > idiaGlobals;
  1392. // check parameters
  1393. assert(pe && mi);
  1394. if (!callback)
  1395. return false;
  1396. if (!name)
  1397. name = "*";
  1398. PrepRE4Srch(name, symname);
  1399. // get a session ...
  1400. pdia = (PDIA)mi->dia;
  1401. if (!pdia)
  1402. return false;
  1403. hr = pdia->session->get_globalScope(&idiaGlobals);
  1404. if (hr != S_OK)
  1405. return false;
  1406. // ... and enumerate the global scope
  1407. return diaEnumScope(pe,
  1408. mi,
  1409. tag,
  1410. symname,
  1411. callback,
  1412. context,
  1413. use64,
  1414. unicode,
  1415. flags,
  1416. idiaGlobals,
  1417. 1);
  1418. }
  1419. BOOL
  1420. diaGetSymbolsByTag(
  1421. PPROCESS_ENTRY pe,
  1422. PMODULE_ENTRY mi,
  1423. PCSTR name,
  1424. DWORD64 addr,
  1425. DWORD tag,
  1426. PROC callback,
  1427. PVOID context,
  1428. BOOL use64,
  1429. BOOL unicode,
  1430. DWORD flags
  1431. )
  1432. {
  1433. BOOL rc;
  1434. DWORD opt;
  1435. BOOL fCase;
  1436. PWCHAR wname;
  1437. WCHAR wbuf[MAX_SYM_NAME + 1];
  1438. CHAR symname[MAX_SYM_NAME + 1];
  1439. PDIA pdia;
  1440. HRESULT hr;
  1441. DWORD celt;
  1442. CComPtr<IDiaSymbol> idiaSymbol;
  1443. CComPtr< IDiaSymbol > idiaGlobals;
  1444. CComPtr< IDiaEnumSymbols > idiaSymbols;
  1445. if (flags & SYMENUMFLAG_FULLSRCH)
  1446. return diaGetItems(pe, mi, name, addr, tag, callback, context, use64, unicode, flags);
  1447. // check parameters
  1448. if (!name)
  1449. name = "*";
  1450. assert(pe && mi);
  1451. if (!callback && !name)
  1452. return false;
  1453. if (option(SYMOPT_CASE_INSENSITIVE)) {
  1454. opt = nsCaseInsensitive;
  1455. fCase = false;
  1456. } else {
  1457. opt = nsCaseSensitive;
  1458. fCase = true;
  1459. };
  1460. if (PrepRE4Srch(name, symname))
  1461. opt |= nsfRegularExpression;
  1462. wname = ConvertNameForDia(symname, wbuf);
  1463. // get a session
  1464. pdia = (PDIA)mi->dia;
  1465. if (!pdia)
  1466. return false;
  1467. hr = pdia->session->get_globalScope(&idiaGlobals);
  1468. if (hr != S_OK)
  1469. return false;
  1470. // presume we find nothing
  1471. rc = false;
  1472. hr = idiaGlobals->findChildren((enum SymTagEnum)tag, wname, opt, &idiaSymbols);
  1473. if (hr != S_OK)
  1474. return false;
  1475. for (;
  1476. SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1;
  1477. idiaSymbol = NULL)
  1478. {
  1479. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol))
  1480. continue;
  1481. mi->si.Scope = SymTagExe;
  1482. if (!callback)
  1483. return true;
  1484. if (addr && (mi->si.Address != addr))
  1485. continue;
  1486. if (flags & SYMENUMFLAG_SPEEDSRCH) {
  1487. PSYM_LOCALENUMSYMBOL_CALLBACK cb = (PSYM_LOCALENUMSYMBOL_CALLBACK)callback;
  1488. rc = cb(&mi->si, mi->si.Size, idiaSymbol, context);
  1489. } else
  1490. rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode);
  1491. if (!rc) {
  1492. mi->code = ERROR_CANCELLED;
  1493. break;
  1494. }
  1495. }
  1496. return rc;
  1497. }
  1498. PSYMBOL_INFO
  1499. diaGetSymFromToken(
  1500. PMODULE_ENTRY mi,
  1501. DWORD token
  1502. )
  1503. {
  1504. PDIA pdia;
  1505. HRESULT hr;
  1506. CComPtr<IDiaSymbol> idiaSymbol;
  1507. // check parameters
  1508. assert(mi);
  1509. // get a session
  1510. pdia = (PDIA)mi->dia;
  1511. if (!pdia)
  1512. return NULL;
  1513. hr = pdia->session->findSymbolByToken(token, SymTagFunction, &idiaSymbol);
  1514. if (hr != S_OK)
  1515. return NULL;
  1516. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol))
  1517. return NULL;
  1518. return &mi->si;
  1519. }
  1520. BOOL
  1521. diaGetGlobals(
  1522. PPROCESS_ENTRY pe,
  1523. PMODULE_ENTRY mi,
  1524. LPCSTR name,
  1525. DWORD64 addr,
  1526. PROC callback,
  1527. PVOID context,
  1528. BOOL use64,
  1529. BOOL unicode
  1530. )
  1531. {
  1532. PDIA pdia;
  1533. HRESULT hr;
  1534. DWORD tag;
  1535. DWORD celt;
  1536. DWORD rc;
  1537. LONG cFuncs;
  1538. LONG cGlobals = 0;
  1539. enum SymTagEnum SearchTag;
  1540. PDWORD64 pGlobals = NULL;
  1541. PDWORD64 pg = NULL;
  1542. PWCHAR wname;
  1543. DWORD opt;
  1544. WCHAR wbuf[MAX_SYM_NAME + 1];
  1545. CHAR symname[MAX_SYM_NAME + 1];
  1546. CHAR pname[MAX_SYM_NAME + 1];
  1547. BOOL fCase;
  1548. CComPtr<IDiaSymbol> idiaSymbol;
  1549. CComPtr< IDiaSymbol > idiaGlobals;
  1550. CComPtr< IDiaEnumSymbols > idiaSymbols;
  1551. // check parameters
  1552. assert(pe && mi && name);
  1553. if (!callback && !name)
  1554. return false;
  1555. if (option(SYMOPT_CASE_INSENSITIVE)) {
  1556. opt = nsCaseInsensitive;
  1557. fCase = false;
  1558. } else {
  1559. opt = nsCaseSensitive;
  1560. fCase = true;
  1561. };
  1562. if (PrepRE4Srch(name, symname))
  1563. opt |= nsfRegularExpression;
  1564. wname = ConvertNameForDia(symname, wbuf);
  1565. // get a session
  1566. pdia = (PDIA)mi->dia;
  1567. if (!pdia)
  1568. return false;
  1569. hr = pdia->session->get_globalScope(&idiaGlobals);
  1570. if (hr != S_OK)
  1571. return false;
  1572. // presume we find nothing
  1573. rc = false;
  1574. // see if there are any globals at all
  1575. // skip normal symbols, if so required
  1576. if (option(SYMOPT_PUBLICS_ONLY))
  1577. goto publics;
  1578. // if this is an enumeration, we will have to store a list of the addresses
  1579. // of all the symbols we found in the global scope. Later we will compare
  1580. // this to the publics so as to eliminate doubles.
  1581. if (callback) {
  1582. hr = idiaGlobals->findChildren(SymTagData, wname, opt, &idiaSymbols);
  1583. if (hr != S_OK)
  1584. return false;
  1585. hr = idiaSymbols->get_Count(&cGlobals);
  1586. if (hr != S_OK)
  1587. return false;
  1588. idiaSymbols = NULL;
  1589. hr = idiaGlobals->findChildren(SymTagFunction, wname, opt, &idiaSymbols);
  1590. if (hr != S_OK)
  1591. return false;
  1592. hr = idiaSymbols->get_Count(&cFuncs);
  1593. if (hr != S_OK)
  1594. return false;
  1595. idiaSymbols = NULL;
  1596. cGlobals += cFuncs;
  1597. pGlobals = (PDWORD64)MemAlloc(cGlobals * sizeof(DWORD64));
  1598. }
  1599. if (callback && (!cGlobals || !pGlobals))
  1600. goto publics;
  1601. ZeroMemory(pGlobals, cGlobals * sizeof(DWORD64));
  1602. // First search for data
  1603. SearchTag = SymTagData;
  1604. hr = idiaGlobals->findChildren(SearchTag, wname, opt, &idiaSymbols);
  1605. if (hr != S_OK)
  1606. goto publics;
  1607. for (pg = pGlobals;
  1608. (SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1) || (SearchTag == SymTagData);
  1609. idiaSymbol = NULL)
  1610. {
  1611. ULONG DataKind;
  1612. if ((SearchTag == SymTagData) && (FAILED(hr) || celt != 1)) {
  1613. // Now search for functions
  1614. SearchTag = SymTagFunction;
  1615. idiaSymbols = NULL;
  1616. hr = idiaGlobals->findChildren(SearchTag, wname, opt, &idiaSymbols);
  1617. if (hr == S_OK)
  1618. continue;
  1619. }
  1620. idiaSymbol->get_symTag(&tag);
  1621. switch (tag)
  1622. {
  1623. case SymTagData:
  1624. case SymTagFunction:
  1625. assert(!callback || ((LONG)(pg - pGlobals) < cGlobals));
  1626. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol))
  1627. continue;
  1628. if (!strcmp(mi->si.Name, "`string'"))
  1629. continue;
  1630. mi->si.Scope = SymTagExe;
  1631. if (!callback)
  1632. return true;
  1633. if (mi->si.Flags & SYMFLAG_CONSTANT)
  1634. continue;
  1635. if (addr && (mi->si.Address != addr))
  1636. continue;
  1637. if (pg)
  1638. *pg++ = mi->si.Address;
  1639. rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode);
  1640. if (!rc) {
  1641. mi->code = ERROR_CANCELLED;
  1642. goto exit;
  1643. }
  1644. break;
  1645. default:
  1646. break;
  1647. }
  1648. }
  1649. qsort(pGlobals, cGlobals, sizeof(DWORD64), CompareAddrs);
  1650. publics:
  1651. if (option(SYMOPT_NO_PUBLICS))
  1652. goto exit;
  1653. if (option(SYMOPT_AUTO_PUBLICS) && cGlobals && !IsRegularExpression(name))
  1654. goto exit;
  1655. // now check out the publics table
  1656. if (wname) {
  1657. PrintString(pname, DIMA(pname), "*%s*", symname);
  1658. MakeEmbeddedREStr(pname, symname);
  1659. wname = ConvertNameForDia(pname, wbuf);
  1660. }
  1661. idiaSymbols = NULL;
  1662. opt |= nsfUndecoratedName | nsfRegularExpression;
  1663. hr = idiaGlobals->findChildren(SymTagPublicSymbol, wname, opt, &idiaSymbols);
  1664. if (hr != S_OK)
  1665. goto exit;
  1666. for (;
  1667. SUCCEEDED(hr = idiaSymbols->Next( 1, &idiaSymbol, &celt)) && celt == 1;
  1668. idiaSymbol = NULL)
  1669. {
  1670. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol))
  1671. continue;
  1672. mi->si.Scope = SymTagPublicSymbol;
  1673. if (!strcmp(mi->si.Name, "`string'"))
  1674. continue;
  1675. // publics names are mangled: this tests the undecorated name against the mask
  1676. if (*name && strcmpre(mi->si.Name, name, fCase))
  1677. continue;
  1678. if (!callback)
  1679. return true;
  1680. if (FindAddr(pGlobals, cGlobals, mi->si.Address))
  1681. continue;
  1682. if (addr && (mi->si.Address != addr))
  1683. continue;
  1684. rc = DoEnumCallback(pe, &mi->si, mi->si.Size, callback, context, use64, unicode);
  1685. if (!rc) {
  1686. mi->code = ERROR_CANCELLED;
  1687. goto exit;
  1688. }
  1689. }
  1690. // We reached the end. If we are not enumerating (I.E. callback == NULL)
  1691. // then return the result of the last call to the callback. If we are
  1692. // searching for a single match, we have failed and should return false;
  1693. exit:
  1694. MemFree(pGlobals);
  1695. if (!callback)
  1696. return false;
  1697. return rc;
  1698. }
  1699. BOOL
  1700. diaGetSymbols(
  1701. PPROCESS_ENTRY pe,
  1702. PMODULE_ENTRY mi,
  1703. PCSTR name,
  1704. PROC callback,
  1705. PVOID context,
  1706. BOOL use64,
  1707. BOOL unicode
  1708. )
  1709. {
  1710. // ENUMFIX:
  1711. LPCSTR pname = (name) ? name : "";
  1712. if (mi) {
  1713. return diaGetGlobals(pe, mi, pname, 0, callback, context, use64, unicode);
  1714. } else {
  1715. return diaGetLocals(pe, pname, callback, context, use64, unicode);
  1716. }
  1717. }
  1718. PSYMBOL_INFO
  1719. diaFindSymbolByName(
  1720. PPROCESS_ENTRY pe,
  1721. PMODULE_ENTRY mi,
  1722. LPSTR SymName
  1723. )
  1724. {
  1725. if (!diaGetSymbols(pe, mi, SymName, NULL, NULL, 0, 0))
  1726. return NULL;
  1727. if (!mi)
  1728. mi = pe->ipmi;
  1729. return &mi->si;
  1730. }
  1731. BOOL
  1732. diaEnumerateSymbols(
  1733. IN PPROCESS_ENTRY pe,
  1734. IN PMODULE_ENTRY mi,
  1735. IN PCSTR mask,
  1736. IN PROC callback,
  1737. IN PVOID context,
  1738. IN BOOL use64,
  1739. IN BOOL unicode
  1740. )
  1741. {
  1742. return diaGetSymbols(pe, mi, mask, callback, context, use64, unicode);
  1743. }
  1744. BOOL
  1745. diaEnumSymForAddr(
  1746. IN PPROCESS_ENTRY pe,
  1747. IN PMODULE_ENTRY mi,
  1748. IN DWORD64 addr,
  1749. IN PROC callback,
  1750. IN PVOID context,
  1751. IN BOOL use64,
  1752. IN BOOL unicode
  1753. )
  1754. {
  1755. return diaGetGlobals(pe, mi, "", addr, callback, context, use64, unicode);
  1756. }
  1757. PSYMBOL_INFO
  1758. diaGetSymFromAddr(
  1759. PMODULE_ENTRY mi,
  1760. DWORD64 addr,
  1761. PDWORD64 disp
  1762. )
  1763. {
  1764. HRESULT hr;
  1765. PDIA pdia;
  1766. DWORD rva;
  1767. DWORD tag;
  1768. LONG omapadj;
  1769. BOOL fHitBlock;
  1770. // simple sanity check
  1771. if (!addr)
  1772. return NULL;
  1773. assert (mi && mi->dia);
  1774. pdia = (PDIA)mi->dia;
  1775. if (!pdia)
  1776. return NULL;
  1777. #ifdef DEBUG
  1778. if (traceAddr(addr)) // for debug breakpoints ...
  1779. dtrace("found 0x%I64x\n", addr);
  1780. #endif
  1781. rva = (DWORD)(addr - mi->BaseOfDll);
  1782. // get the symbol
  1783. CComPtr< IDiaSymbol > idiaSymbol = NULL;
  1784. fHitBlock = false;
  1785. if (!option(SYMOPT_PUBLICS_ONLY)) {
  1786. hr = pdia->session->findSymbolByRVAEx(rva, SymTagNull, &idiaSymbol, &omapadj);
  1787. if (hr != S_OK)
  1788. return NULL;
  1789. // if the symbol is a block, keep grabbing the parent
  1790. // until we get a function...
  1791. idiaSymbol->get_symTag(&tag);
  1792. while (tag == SymTagBlock) { // SymTagLabel as well?
  1793. CComPtr< IDiaSymbol > idiaParent;
  1794. fHitBlock = true;
  1795. hr = idiaSymbol->get_lexicalParent(&idiaParent);
  1796. if (hr != S_OK || !idiaParent)
  1797. return NULL;
  1798. idiaSymbol = idiaParent;
  1799. idiaSymbol->get_symTag(&tag);
  1800. }
  1801. }
  1802. if (option(SYMOPT_NO_PUBLICS))
  1803. return NULL;
  1804. if (!diaFillSymbolInfo(&mi->si, mi, idiaSymbol)) {
  1805. // return a public symbol
  1806. idiaSymbol = NULL;
  1807. hr = pdia->session->findSymbolByRVAEx(rva, SymTagPublicSymbol, &idiaSymbol, &omapadj);
  1808. if (hr == S_OK)
  1809. diaFillSymbolInfo(&mi->si, mi, idiaSymbol);
  1810. }
  1811. if (disp)
  1812. *disp = (fHitBlock) ? addr - mi->si.Address : omapadj;
  1813. return &mi->si;
  1814. }
  1815. PSYMBOL_INFO
  1816. diaGetSymFromAddrByTag(
  1817. PMODULE_ENTRY mi,
  1818. DWORD64 addr,
  1819. DWORD tag,
  1820. PDWORD64 disp
  1821. )
  1822. {
  1823. HRESULT hr;
  1824. PDIA pdia;
  1825. DWORD rva;
  1826. LONG omapadj;
  1827. // simple sanity check
  1828. if (!addr)
  1829. return NULL;
  1830. assert (mi && mi->dia);
  1831. pdia = (PDIA)mi->dia;
  1832. if (!pdia)
  1833. return NULL;
  1834. rva = (DWORD)(addr - mi->BaseOfDll);
  1835. // get the symbol
  1836. CComPtr< IDiaSymbol > idiaSymbol = NULL;
  1837. hr = pdia->session->findSymbolByRVAEx(rva, (enum SymTagEnum)tag, &idiaSymbol, &omapadj);
  1838. if (hr != S_OK)
  1839. return NULL;
  1840. diaFillSymbolInfo(&mi->si, mi, idiaSymbol);
  1841. if (disp)
  1842. *disp = addr - mi->si.Address;
  1843. return &mi->si;
  1844. }
  1845. typedef struct _ENUMOBJS {
  1846. PPROCESS_ENTRY pe;
  1847. PMODULE_ENTRY mi;
  1848. PSYM_ENUMLINES_CALLBACK cb;
  1849. PCSTR file;
  1850. PVOID context;
  1851. } ENUMOBJS, *PENUMOBJS;
  1852. BOOL
  1853. cbEnumObjs(
  1854. PSYMBOL_INFO si,
  1855. ULONG size,
  1856. IDiaSymbol *idiaObj,
  1857. PVOID context
  1858. )
  1859. {
  1860. WCHAR wbuf[MAX_PATH + 1];
  1861. BSTR wfname = NULL;
  1862. HRESULT hr;
  1863. PDIA pdia;
  1864. PMODULE_ENTRY mi;
  1865. PENUMOBJS eno = (PENUMOBJS)context;
  1866. PSYM_ENUMLINES_CALLBACK cb;
  1867. WCHAR wsz[_MAX_PATH + 1];
  1868. char file[MAX_PATH + 1];
  1869. BSTR bstr;
  1870. DWORD dw;
  1871. BOOL rc;
  1872. CComPtr< IDiaEnumSourceFiles > idiaSrcFiles = NULL;
  1873. CComPtr< IDiaSourceFile > idiaSrcFile = NULL;
  1874. CComPtr< IDiaEnumLineNumbers > idiaLines = NULL;
  1875. CComPtr< IDiaLineNumber > idiaLine = NULL;
  1876. dtrace("%s\n", si->Name);
  1877. // get initial data and store the obj name
  1878. pdia = (PDIA)eno->mi->dia;
  1879. if (!pdia)
  1880. return false;
  1881. cb = (PSYM_ENUMLINES_CALLBACK)eno->cb;
  1882. mi = eno->mi;
  1883. if (!mi)
  1884. return false;
  1885. if (!*si->Name)
  1886. return false;
  1887. CopyString(mi->sci.Obj, si->Name, MAX_PATH + 1);
  1888. mi->sci.ModBase = mi->BaseOfDll;
  1889. // prepare the source file name mask
  1890. wfname = NULL;
  1891. if (eno->file && *eno->file) {
  1892. ansi2wcs(eno->file, wbuf, MAX_PATH);
  1893. wfname = wbuf;
  1894. }
  1895. // get all the source files
  1896. hr = pdia->session->findFile(idiaObj, wfname, nsCaseInsensitive, &idiaSrcFiles);
  1897. if (hr != S_OK)
  1898. return false;
  1899. while (idiaSrcFiles->Next(1, &idiaSrcFile, &dw) == S_OK) {
  1900. hr = idiaSrcFile->get_fileName(&bstr);
  1901. if (hr != S_OK)
  1902. break;
  1903. rc = wcs2ansi(bstr, mi->sci.FileName, MAX_PATH + 1);
  1904. LocalFree(bstr);
  1905. if (!rc || !*mi->sci.FileName)
  1906. break;
  1907. hr = pdia->session->findLines(idiaObj, idiaSrcFile, &idiaLines);
  1908. if (hr != S_OK)
  1909. break;
  1910. while (idiaLines->Next(1, &idiaLine, &dw) == S_OK) {
  1911. hr = idiaLine->get_lineNumber(&mi->sci.LineNumber);
  1912. if (hr != S_OK)
  1913. return false;
  1914. hr = idiaLine->get_relativeVirtualAddress(&dw);
  1915. if (hr != S_OK)
  1916. return false;
  1917. mi->sci.Address = dw + mi->BaseOfDll;
  1918. idiaLine = NULL;
  1919. if (cb)
  1920. rc = cb(&mi->sci, context);
  1921. }
  1922. idiaLines = NULL;
  1923. idiaSrcFile = NULL;
  1924. }
  1925. return true;
  1926. }
  1927. BOOL
  1928. diaEnumLines(
  1929. IN PPROCESS_ENTRY pe,
  1930. IN PMODULE_ENTRY mi,
  1931. IN PCSTR obj,
  1932. IN PCSTR file,
  1933. IN PSYM_ENUMLINES_CALLBACK cb,
  1934. IN PVOID context
  1935. )
  1936. {
  1937. ENUMOBJS eno;
  1938. eno.pe = pe;
  1939. eno.mi = mi;
  1940. eno.cb = cb;
  1941. eno.file = file;
  1942. eno.context = context;
  1943. return diaGetSymbolsByTag(pe,
  1944. mi,
  1945. obj,
  1946. 0,
  1947. SymTagCompiland,
  1948. (PROC)cbEnumObjs,
  1949. &eno,
  1950. false,
  1951. false,
  1952. SYMENUMFLAG_SPEEDSRCH);
  1953. }
  1954. BOOL
  1955. diaGetLineFromAddr(
  1956. PMODULE_ENTRY mi,
  1957. DWORD64 addr,
  1958. PDWORD displacement,
  1959. PSRCCODEINFO sci
  1960. )
  1961. {
  1962. HRESULT hr;
  1963. PDIA pdia;
  1964. DWORD rva;
  1965. DWORD celt;
  1966. BSTR bstr;
  1967. DWORD dw;
  1968. BOOL rc;
  1969. assert(mi && mi->dia);
  1970. pdia = (PDIA)mi->dia;
  1971. if (!pdia)
  1972. return NULL;
  1973. rva = (DWORD)(addr - mi->BaseOfDll);
  1974. // On IA64 the slots in a bundle don't have byte addresses.
  1975. // The debugger calls them 0,4,8 by default whereas line
  1976. // symbols have them as 0,1,2. Convert to line style
  1977. // before querying.
  1978. if (mi->MachineType == IMAGE_FILE_MACHINE_IA64 && (rva & 0xf)) {
  1979. switch(rva & 0xf) {
  1980. case 4:
  1981. rva -= 3;
  1982. break;
  1983. case 8:
  1984. rva -= 6;
  1985. break;
  1986. default:
  1987. // Invalid slot address.
  1988. return false;
  1989. }
  1990. }
  1991. CComPtr< IDiaEnumLineNumbers > idiaLines = NULL;
  1992. hr = pdia->session->findLinesByRVA(rva, 1, &idiaLines);
  1993. if (hr != S_OK)
  1994. return false;
  1995. CComPtr< IDiaLineNumber > idiaLine = NULL;
  1996. hr = idiaLines->Next(1, &idiaLine, &celt);
  1997. if (hr != S_OK || !idiaLine)
  1998. return false;
  1999. hr = idiaLine->get_lineNumber(&dw);
  2000. if (hr != S_OK)
  2001. return false;
  2002. sci->LineNumber = dw;
  2003. pdia->srcfile = NULL;
  2004. hr = idiaLine->get_sourceFile(&pdia->srcfile);
  2005. if (hr != S_OK)
  2006. return false;
  2007. hr = pdia->srcfile->get_fileName(&bstr);
  2008. if (hr != S_OK)
  2009. return false;
  2010. *sci->FileName = 0;
  2011. rc = wcs2ansi(bstr, sci->FileName, DIMA(sci->FileName));
  2012. LocalFree(bstr);
  2013. if (!rc || !*sci->FileName)
  2014. return false;
  2015. hr = idiaLine->get_relativeVirtualAddress(&dw);
  2016. if (hr != S_OK)
  2017. return false;
  2018. sci->Address = dw + mi->BaseOfDll;
  2019. *displacement = rva - dw;
  2020. return true;
  2021. }
  2022. BOOL
  2023. diaGetNextLineFromEnum(
  2024. IDiaEnumLineNumbers *idiaLines,
  2025. DWORD *line,
  2026. DWORD *rva
  2027. )
  2028. {
  2029. HRESULT hr;
  2030. ULONG ul;
  2031. CComPtr< IDiaLineNumber > idiaLine = NULL;
  2032. hr = idiaLines->Next(1, &idiaLine, &ul);
  2033. if (hr != S_OK)
  2034. return false;
  2035. hr = idiaLine->get_lineNumber(line);
  2036. if (hr != S_OK)
  2037. return false;
  2038. hr = idiaLine->get_relativeVirtualAddress(rva);
  2039. if (hr != S_OK)
  2040. return false;
  2041. return true;
  2042. }
  2043. BOOL
  2044. diaGetLineNextPrev(
  2045. PMODULE_ENTRY mi,
  2046. PIMAGEHLP_LINE64 line,
  2047. DWORD direction
  2048. )
  2049. {
  2050. HRESULT hr;
  2051. PDIA pdia;
  2052. DWORD rva;
  2053. DWORD celt;
  2054. WCHAR wbuf[MAX_PATH + 1];
  2055. BSTR wfname = NULL;
  2056. DWORD64 bAddr;
  2057. DWORD trgnum;
  2058. DWORD num;
  2059. DWORD dw;
  2060. DWORD num1 = 0;
  2061. DWORD num2 = 0;
  2062. DWORD rva1 = 0;
  2063. DWORD rva2 = 0;
  2064. LONG numlines;
  2065. // simple sanity checks
  2066. assert(mi && mi->dia);
  2067. pdia = (PDIA)mi->dia;
  2068. if (!pdia)
  2069. return false;
  2070. assert(direction == NP_NEXT || direction == NP_PREV);
  2071. if (line->SizeOfStruct != sizeof(IMAGEHLP_LINE64))
  2072. return false;
  2073. // convert file name for DIA
  2074. if (!*line->FileName)
  2075. return false;
  2076. ansi2wcs(line->FileName, wbuf, MAX_PATH);
  2077. wfname = wbuf;
  2078. // save the last found line
  2079. bAddr = line->Address;
  2080. // all source files in the module that match the 'wfname'
  2081. CComPtr< IDiaEnumSourceFiles > idiaSrcFiles = NULL;
  2082. hr = pdia->session->findFile(NULL, wfname, nsCaseInsensitive, &idiaSrcFiles);
  2083. if (hr != S_OK)
  2084. return false;
  2085. // the first such file in the list, since we don't use wildcards
  2086. CComPtr< IDiaSourceFile > idiaSrcFile = NULL;
  2087. hr = idiaSrcFiles->Next(1, &idiaSrcFile, &dw);
  2088. if (hr != S_OK)
  2089. return false;
  2090. // all objs that use this source file
  2091. CComPtr< IDiaEnumSymbols > idiaObjs = NULL;
  2092. hr = idiaSrcFile->get_compilands(&idiaObjs);
  2093. if (hr != S_OK)
  2094. return false;
  2095. // LOOP THROUGH ALL THE OBJS! AND STORE THE CLOSEST!
  2096. num = 0;
  2097. rva = 0;
  2098. // grab the first obj, since we don't care
  2099. CComPtr< IDiaSymbol > idiaObj = NULL;
  2100. CComPtr< IDiaEnumLineNumbers > idiaLines = NULL;
  2101. hr = idiaObjs->Next(1, &idiaObj, &celt);
  2102. if (hr != S_OK)
  2103. return false;
  2104. // get the line for starting with
  2105. trgnum = line->LineNumber + direction;
  2106. hr = pdia->session->findLinesByLinenum(idiaObj, idiaSrcFile, trgnum, 0, &idiaLines);
  2107. if (hr != S_OK)
  2108. return false;
  2109. hr = idiaLines->get_Count(&numlines);
  2110. diaGetNextLineFromEnum(idiaLines, &num1, &rva1);
  2111. if (numlines > 1)
  2112. diaGetNextLineFromEnum(idiaLines, &num2, &rva2);
  2113. if (direction == NP_PREV) {
  2114. num = num1;
  2115. rva = rva1;
  2116. } else if (num1 == trgnum) {
  2117. num = num1;
  2118. rva = rva1;
  2119. } else {
  2120. num = num2;
  2121. rva = rva2;
  2122. }
  2123. if (!num)
  2124. return false;
  2125. if (bAddr == GetLineAddressFromRva(mi, rva))
  2126. return false;
  2127. line->LineNumber = num;
  2128. line->Address = GetLineAddressFromRva(mi, rva);
  2129. return true;
  2130. }
  2131. #if 0
  2132. #define DBG_DIA_LINE 1
  2133. #endif
  2134. BOOL
  2135. diaGetLineFromName(
  2136. PMODULE_ENTRY mi,
  2137. LPSTR filename,
  2138. DWORD linenumber,
  2139. PLONG displacement,
  2140. PSRCCODEINFO sci,
  2141. DWORD method
  2142. )
  2143. {
  2144. HRESULT hr;
  2145. WCHAR wsz[_MAX_PATH + 1];
  2146. char sz[MAX_PATH + 1];
  2147. PDIA pdia;
  2148. DWORD celt;
  2149. BSTR bstr;
  2150. DWORD addr;
  2151. DWORD num;
  2152. BOOL rc;
  2153. DWORD flags;
  2154. LONG cFiles;
  2155. int i;
  2156. CComPtr<IDiaEnumSourceFiles> idiaSrcFiles;
  2157. CComPtr<IDiaSourceFile> idiaSrcFile;
  2158. CComPtr<IDiaEnumSymbols> idiaEnum;
  2159. CComPtr<IDiaSymbol> idiaSymbol;
  2160. CComPtr<IDiaEnumLineNumbers> idiaLineNumbers;
  2161. CComPtr<IDiaLineNumber> idiaLineNumber;
  2162. assert(mi && mi->dia && filename);
  2163. pdia = (PDIA)mi->dia;
  2164. if (!pdia)
  2165. return NULL;
  2166. sciInit(sci);
  2167. if (!ansi2wcs(filename, wsz, DIMA(wsz)))
  2168. return false;
  2169. if (!*wsz)
  2170. return false;
  2171. flags = (method == mFullPath) ? nsfCaseInsensitive : nsFNameExt;
  2172. // get list of matching files and the count of the list
  2173. hr = pdia->session->findFile(NULL, wsz, flags, &idiaSrcFiles);
  2174. if (hr != S_OK)
  2175. return false;
  2176. hr = idiaSrcFiles->get_Count(&cFiles);
  2177. if (hr != S_OK)
  2178. return false;
  2179. *sci->FileName = 0;
  2180. for (i = 0; i < cFiles; i++) {
  2181. hr = idiaSrcFiles->Next(1, &idiaSrcFile, &celt);
  2182. if (hr != S_OK)
  2183. continue;
  2184. hr = idiaSrcFile->get_fileName(&bstr);
  2185. if (hr != S_OK)
  2186. continue;
  2187. rc = wcs2ansi(bstr, sz, DIMA(sz));
  2188. LocalFree(bstr);
  2189. if (!rc || !*sz)
  2190. continue;
  2191. UpdateBestSrc(filename, sci->FileName, sz);
  2192. }
  2193. if (!*sci->FileName)
  2194. return false;
  2195. // this gives us a list of every .obj that uses this source file
  2196. hr = idiaSrcFile->get_compilands(&idiaEnum);
  2197. if (hr != S_OK)
  2198. return false;
  2199. // we don't support multiple objs, so lets take the first one
  2200. hr = idiaEnum->Next(1, &idiaSymbol, &celt);
  2201. if (hr != S_OK)
  2202. return false;
  2203. // This gets a list of all code items that were created from this source line.
  2204. // If we want to fully support inlines and the like, we need to loop all of these
  2205. hr = pdia->session->findLinesByLinenum(idiaSymbol, idiaSrcFile, linenumber, 0, &idiaLineNumbers);
  2206. if (hr != S_OK)
  2207. return false;
  2208. idiaLineNumber = NULL;
  2209. hr = idiaLineNumbers->Next(1, &idiaLineNumber, &celt);
  2210. if (hr != S_OK)
  2211. return false;
  2212. hr = idiaLineNumber->get_lineNumber(&num);
  2213. if (hr != S_OK)
  2214. return false;
  2215. sci->LineNumber = num;
  2216. hr = idiaLineNumber->get_relativeVirtualAddress(&addr);
  2217. if (hr != S_OK)
  2218. return false;
  2219. if (!addr)
  2220. return false;
  2221. sci->Address = GetLineAddressFromRva(mi, addr);
  2222. *displacement = linenumber - num;
  2223. return true;
  2224. }
  2225. BOOL
  2226. MatchSourceFile(
  2227. PCHAR filename,
  2228. PCHAR mask
  2229. )
  2230. {
  2231. PCHAR p;
  2232. if (!mask || !*mask)
  2233. return true;
  2234. if (!*filename)
  2235. return false;
  2236. for (p = filename + strlen(filename); p >= filename; p--) {
  2237. if (*p == '\\' || *p == '/') {
  2238. p++;
  2239. break;
  2240. }
  2241. }
  2242. if (!strcmpre(p, mask, false))
  2243. return true;
  2244. return false;
  2245. }
  2246. BOOL
  2247. diaEnumSourceFiles(
  2248. IN PMODULE_ENTRY mi,
  2249. IN PCHAR mask,
  2250. IN PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
  2251. IN PVOID context
  2252. )
  2253. {
  2254. HRESULT hr;
  2255. BSTR wname=NULL;
  2256. char name[_MAX_PATH + 1];
  2257. SOURCEFILE sf;
  2258. assert(mi && cbSrcFiles);
  2259. PDIA pdia;
  2260. pdia = (PDIA)mi->dia;
  2261. sf.ModBase = mi->BaseOfDll ;
  2262. sf.FileName = name;
  2263. CComPtr< IDiaEnumSourceFiles > idiaEnumFiles;
  2264. hr = pdia->session->findFile(NULL, NULL, nsNone, &idiaEnumFiles);
  2265. if (hr != S_OK)
  2266. return false;
  2267. ULONG celt;
  2268. CComPtr <IDiaSourceFile> idiaSource;
  2269. for (;SUCCEEDED(idiaEnumFiles->Next(1, &idiaSource, &celt)) && (celt == 1);) {
  2270. hr = idiaSource->get_fileName(&wname);
  2271. if (hr == S_OK && wname) {
  2272. wcs2ansi(wname, name, _MAX_PATH);
  2273. LocalFree (wname);
  2274. if (MatchSourceFile(name, mask)) {
  2275. if (!cbSrcFiles(&sf, context)) {
  2276. mi->code = ERROR_CANCELLED;
  2277. return false;
  2278. }
  2279. }
  2280. }
  2281. idiaSource = NULL;
  2282. }
  2283. return true;
  2284. }
  2285. PSYMBOL_INFO
  2286. diaGetSymNextPrev(
  2287. PMODULE_ENTRY mi,
  2288. DWORD64 addr,
  2289. int direction
  2290. )
  2291. {
  2292. HRESULT hr;
  2293. PDIA pdia;
  2294. DWORD rva;
  2295. DWORD celt;
  2296. assert(mi && mi->dia);
  2297. pdia = (PDIA)mi->dia;
  2298. if (!pdia)
  2299. return NULL;
  2300. CComPtr<IDiaEnumSymbolsByAddr> idiaSymbols;
  2301. hr = pdia->session->getSymbolsByAddr(&idiaSymbols);
  2302. if (hr != S_OK)
  2303. return NULL;
  2304. rva = addr ? (DWORD)(addr - mi->BaseOfDll) : 0;
  2305. CComPtr<IDiaSymbol> idiaSymbol;
  2306. hr = idiaSymbols->symbolByRVA(rva, &idiaSymbol);
  2307. if (hr != S_OK)
  2308. return NULL;
  2309. findsymbol:
  2310. if (addr) {
  2311. if (direction < 0) {
  2312. idiaSymbol = NULL;
  2313. hr = idiaSymbols->Prev(1, &idiaSymbol, &celt);
  2314. } else {
  2315. idiaSymbol = NULL;
  2316. hr = idiaSymbols->Next(1, &idiaSymbol, &celt);
  2317. }
  2318. if (hr != S_OK)
  2319. return NULL;
  2320. if (celt != 1)
  2321. return NULL;
  2322. }
  2323. diaFillSymbolInfo(&mi->si, mi, idiaSymbol);
  2324. if (!*mi->si.Name) {
  2325. rva = (DWORD)(mi->si.Address - mi->BaseOfDll);
  2326. goto findsymbol;
  2327. }
  2328. return &mi->si;
  2329. }
  2330. HRESULT
  2331. diaGetSymTag(IDiaSymbol *pType, PULONG pTag)
  2332. {
  2333. return pType->get_symTag(pTag);
  2334. }
  2335. HRESULT
  2336. diaGetSymIndexId(IDiaSymbol *pType, PULONG pIndex)
  2337. {
  2338. return pType->get_symIndexId(pIndex);
  2339. }
  2340. HRESULT
  2341. diaGetLexicalParentId(IDiaSymbol *pType, PULONG pIndex)
  2342. {
  2343. return pType->get_lexicalParentId(pIndex);
  2344. }
  2345. HRESULT
  2346. diaGetDataKind(IDiaSymbol *pType, PULONG pKind)
  2347. {
  2348. return pType->get_dataKind(pKind);
  2349. }
  2350. HRESULT
  2351. diaGetSymName(IDiaSymbol *pType, BSTR *pname)
  2352. {
  2353. return pType->get_name(pname);
  2354. }
  2355. HRESULT
  2356. diaGetLength(IDiaSymbol *pType, PULONGLONG pLength)
  2357. {
  2358. return pType->get_length(pLength);
  2359. }
  2360. HRESULT
  2361. diaGetType(IDiaSymbol *pType, IDiaSymbol ** pSymbol)
  2362. {
  2363. return pType->get_type(pSymbol);
  2364. }
  2365. HRESULT
  2366. diaGetBaseType(IDiaSymbol *pType, PULONG pBase)
  2367. {
  2368. return pType->get_baseType(pBase);
  2369. }
  2370. HRESULT
  2371. diaGetArrayIndexTypeId(IDiaSymbol *pType, PULONG pSymbol)
  2372. {
  2373. return pType->get_arrayIndexTypeId(pSymbol);
  2374. }
  2375. HRESULT
  2376. diaGetTypeId(IDiaSymbol *pType, PULONG pTypeId)
  2377. {
  2378. return pType->get_typeId(pTypeId);
  2379. }
  2380. HRESULT
  2381. diaGetCallingConvention(IDiaSymbol *pType, PULONG pConvention)
  2382. {
  2383. HRESULT hr;
  2384. hr = pType->get_callingConvention(pConvention);
  2385. if (hr != S_OK)
  2386. *pConvention = CV_CALL_RESERVED;
  2387. return hr;
  2388. }
  2389. HRESULT
  2390. diaGetChildrenCount(IDiaSymbol *pType, LONG *pCount)
  2391. {
  2392. CComPtr <IDiaEnumSymbols> pEnum;
  2393. HRESULT hr;
  2394. ULONG index;
  2395. CComPtr <IDiaSymbol> pSym;
  2396. ULONG Count;
  2397. if ((hr = pType->findChildren(SymTagNull, NULL, nsNone, &pEnum)) != S_OK) {
  2398. return hr;
  2399. }
  2400. return pEnum->get_Count(pCount);
  2401. }
  2402. HRESULT
  2403. diaFindChildren(IDiaSymbol *pType, TI_FINDCHILDREN_PARAMS *Params)
  2404. {
  2405. CComPtr <IDiaEnumSymbols> pEnum;
  2406. HRESULT hr;
  2407. ULONG index;
  2408. CComPtr <IDiaSymbol> pSym;
  2409. ULONG Count;
  2410. if ((hr = pType->findChildren(SymTagNull, NULL, nsNone, &pEnum)) != S_OK) {
  2411. return hr;
  2412. }
  2413. VARIANT var;
  2414. pEnum->Skip(Params->Start);
  2415. for (Count = Params->Count, index = Params->Start; Count > 0; Count--, index++) {
  2416. ULONG celt;
  2417. pSym = NULL;
  2418. if ((hr = pEnum->Next(1, &pSym, &celt)) != S_OK) {
  2419. return hr;
  2420. }
  2421. if ((hr = pSym->get_symIndexId(&Params->ChildId[index])) != S_OK) {
  2422. return hr;
  2423. }
  2424. }
  2425. return S_OK;
  2426. }
  2427. HRESULT
  2428. diaGetAddressOffset(IDiaSymbol *pType, ULONG *pOff)
  2429. {
  2430. return pType->get_addressOffset(pOff);
  2431. }
  2432. HRESULT
  2433. diaGetOffset(IDiaSymbol *pType, LONG *pOff)
  2434. {
  2435. return pType->get_offset(pOff);
  2436. }
  2437. HRESULT
  2438. diaGetValue(IDiaSymbol *pType, VARIANT *pVar)
  2439. {
  2440. return pType->get_value(pVar);
  2441. }
  2442. HRESULT
  2443. diaGetCount(IDiaSymbol *pType, ULONG *pCount)
  2444. {
  2445. return pType->get_count(pCount);
  2446. }
  2447. HRESULT
  2448. diaGetBitPosition(IDiaSymbol *pType, ULONG *pPos)
  2449. {
  2450. return pType->get_bitPosition(pPos);
  2451. }
  2452. HRESULT
  2453. diaGetVirtualBaseClass(IDiaSymbol *pType, BOOL *pBase)
  2454. {
  2455. return pType->get_virtualBaseClass(pBase);
  2456. }
  2457. HRESULT
  2458. diaGetVirtualTableShapeId(IDiaSymbol *pType, PULONG pShape)
  2459. {
  2460. return pType->get_virtualTableShapeId(pShape);
  2461. }
  2462. HRESULT
  2463. diaGetVirtualBasePointerOffset(IDiaSymbol *pType, LONG *pOff)
  2464. {
  2465. return pType->get_virtualBasePointerOffset(pOff);
  2466. }
  2467. HRESULT
  2468. diaGetClassParentId(IDiaSymbol *pType, ULONG *pCid)
  2469. {
  2470. return pType->get_classParentId(pCid);
  2471. }
  2472. HRESULT
  2473. diaGetNested(IDiaSymbol *pType, BOOL *pNested)
  2474. {
  2475. return pType->get_nested(pNested);
  2476. }
  2477. HRESULT
  2478. diaGetSymAddress(IDiaSymbol *pType, ULONG64 ModBase, PULONG64 pAddr)
  2479. {
  2480. ULONG rva;
  2481. HRESULT Hr;
  2482. Hr = pType->get_relativeVirtualAddress(&rva);
  2483. if (Hr == S_OK) *pAddr = ModBase + rva;
  2484. return Hr;
  2485. }
  2486. HRESULT
  2487. diaGetThisAdjust(IDiaSymbol *pType, LONG *pThisAdjust)
  2488. {
  2489. return pType->get_thisAdjust(pThisAdjust);
  2490. }
  2491. HRESULT
  2492. diaGetUdtKind(IDiaSymbol *pType, DWORD *pUdtKind)
  2493. {
  2494. return pType->get_udtKind(pUdtKind);
  2495. }
  2496. BOOL
  2497. diaCompareTypeSym(
  2498. IN HANDLE hProcess,
  2499. IN DWORD64 ModBase,
  2500. IN IDiaSymbol *pType1,
  2501. IN OUT PULONG TypeId2
  2502. )
  2503. {
  2504. PPROCESS_ENTRY ProcessEntry;
  2505. PDIA pdia;
  2506. PMODULE_ENTRY mi;
  2507. CComPtr<IDiaSymbol> pType2;
  2508. ProcessEntry = FindProcessEntry( hProcess );
  2509. if (!ProcessEntry || !(mi = GetModFromAddr(ProcessEntry, ModBase))) {
  2510. return false;
  2511. }
  2512. pdia = (PDIA)mi->dia;
  2513. if (!pdia) {
  2514. return false;
  2515. }
  2516. if (pdia->session->symbolById(*TypeId2, &pType2) != S_OK) {
  2517. return false;
  2518. }
  2519. if (pdia->session->symsAreEquiv(pType1, pType2) != S_OK) {
  2520. *TypeId2 = 0;
  2521. }
  2522. return true;
  2523. }
  2524. BOOL
  2525. diaFindTypeSym(
  2526. IN HANDLE hProcess,
  2527. IN DWORD64 ModBase,
  2528. IN ULONG TypeId,
  2529. OUT IDiaSymbol **pType
  2530. )
  2531. {
  2532. PPROCESS_ENTRY ProcessEntry;
  2533. PDIA pdia;
  2534. PMODULE_ENTRY mi;
  2535. ProcessEntry = FindProcessEntry( hProcess );
  2536. if (!ProcessEntry || !(mi = GetModFromAddr(ProcessEntry, ModBase))) {
  2537. return false;
  2538. }
  2539. pdia = (PDIA)mi->dia;
  2540. if (!pdia) {
  2541. return false;
  2542. }
  2543. return pdia->session->symbolById(TypeId, pType) == S_OK;
  2544. }
  2545. #ifdef USE_CACHE
  2546. ULONG gHits=0, gLook=0;
  2547. void
  2548. diaInsertInCache(
  2549. PDIA_CACHE_ENTRY pCache,
  2550. PDIA_LARGE_DATA plVals,
  2551. ULONGLONG Module,
  2552. ULONG TypeId,
  2553. IMAGEHLP_SYMBOL_TYPE_INFO GetType,
  2554. PVOID pInfo
  2555. )
  2556. {
  2557. if (GetType == TI_IS_EQUIV_TO) {
  2558. // Not cached.
  2559. return;
  2560. }
  2561. int start = CACHE_BLOCK * (TypeId % CACHE_BLOCK);
  2562. int i, found;
  2563. ULONG len,age;
  2564. PDIA_LARGE_DATA pLargeVal=NULL;
  2565. if (GetType == TI_FINDCHILDREN || GetType == TI_GET_SYMNAME) {
  2566. for (pLargeVal = plVals, found=i=0, age=0; i<2*CACHE_BLOCK; i++) {
  2567. if (!plVals[i].Used) {
  2568. pLargeVal = &plVals[i];
  2569. break;
  2570. } else if (pCache[plVals[i].Index].Age > age) {
  2571. pLargeVal = &plVals[i];
  2572. age = pCache[plVals[i].Index].Age;
  2573. assert(DIACH_PLVAL == pCache[pLargeVal->Index].Data.type);
  2574. assert(pLargeVal == pCache[pLargeVal->Index].Data.plVal);
  2575. }
  2576. }
  2577. // } else {
  2578. // return;
  2579. }
  2580. // if (!(gLook % 200)) {
  2581. // if (GetType == TI_FINDCHILDREN || GetType == TI_GET_SYMNAME) {
  2582. // printf("Index \tUsed\tBy\t\tfound %lx\n", pLargeVal);
  2583. // for (found=i=0, age=0; i<2*CACHE_BLOCK; i++) {
  2584. // printf("%08lx \t%lx\t%lx\n",
  2585. // &plVals[i], plVals[i].Used, plVals[i].Index);
  2586. // }
  2587. // }
  2588. // }
  2589. for (i=found=start, age=0; i<(start+CACHE_BLOCK); i++) {
  2590. if (++pCache[i].Age > age) {
  2591. age = pCache[i].Age; found = i;
  2592. }
  2593. }
  2594. i=found;
  2595. if (pCache[i].Data.type == DIACH_PLVAL) {
  2596. assert(pCache[i].Data.plVal->Index == (ULONG) i);
  2597. pCache[i].Data.plVal->Index = 0;
  2598. pCache[i].Data.plVal->Used = 0;
  2599. pCache[i].Data.type = 0;
  2600. pCache[i].Data.ullVal = 0;
  2601. }
  2602. pCache[i].Age = 0;
  2603. pCache[i].s.DataType = GetType;
  2604. pCache[i].s.TypeId = TypeId;
  2605. pCache[i].Module = Module;
  2606. switch (GetType) {
  2607. case TI_GET_SYMTAG:
  2608. case TI_GET_COUNT:
  2609. case TI_GET_CHILDRENCOUNT:
  2610. case TI_GET_BITPOSITION:
  2611. case TI_GET_VIRTUALBASECLASS:
  2612. case TI_GET_VIRTUALTABLESHAPEID:
  2613. case TI_GET_VIRTUALBASEPOINTEROFFSET:
  2614. case TI_GET_CLASSPARENTID:
  2615. case TI_GET_TYPEID:
  2616. case TI_GET_BASETYPE:
  2617. case TI_GET_ARRAYINDEXTYPEID:
  2618. case TI_GET_DATAKIND:
  2619. case TI_GET_ADDRESSOFFSET:
  2620. case TI_GET_OFFSET:
  2621. case TI_GET_NESTED:
  2622. case TI_GET_THISADJUST:
  2623. case TI_GET_UDTKIND:
  2624. pCache[i].Data.type = DIACH_ULVAL;
  2625. pCache[i].Data.ulVal = *((PULONG) pInfo);
  2626. break;
  2627. case TI_GET_LENGTH:
  2628. case TI_GET_ADDRESS:
  2629. pCache[i].Data.type = DIACH_ULLVAL;
  2630. pCache[i].Data.ullVal = *((PULONGLONG) pInfo);
  2631. break;
  2632. case TI_GET_SYMNAME: {
  2633. len = 2*(1+wcslen(*((BSTR *) pInfo)));
  2634. if (pLargeVal &&
  2635. len < sizeof(pLargeVal->Bytes)) {
  2636. // dtrace("Ins name %08lx %s had %3lx name %ws\n",
  2637. // pLargeVal, pLargeVal->Used ? "used" : "free",
  2638. // pLargeVal->Index, &pLargeVal->Bytes[0]);
  2639. memcpy(&pLargeVal->Bytes[0], *((BSTR *) pInfo), len);
  2640. pLargeVal->LengthUsed = len;
  2641. if (pLargeVal->Used) {
  2642. pCache[pLargeVal->Index].Data.type = 0;
  2643. pCache[pLargeVal->Index].Data.ullVal = 0;
  2644. pCache[pLargeVal->Index].SearchId = 0;
  2645. }
  2646. pCache[i].Data.type = DIACH_PLVAL;
  2647. pCache[i].Data.plVal = pLargeVal;
  2648. pLargeVal->Index = i;
  2649. pLargeVal->Used = true;
  2650. // dtrace(Ins %9I64lx ch %3lx lch %08lx name %ws\n",
  2651. // pCache[i].SearchId, i, pLargeVal, &pLargeVal->Bytes[0]);
  2652. } else {
  2653. pCache[i].SearchId = 0;
  2654. }
  2655. break;
  2656. }
  2657. case TI_FINDCHILDREN: {
  2658. TI_FINDCHILDREN_PARAMS *pChild = (TI_FINDCHILDREN_PARAMS *) pInfo;
  2659. len = sizeof(TI_FINDCHILDREN_PARAMS) + pChild->Count*sizeof(pChild->ChildId[0]) - sizeof(pChild->ChildId);
  2660. if (pLargeVal &&
  2661. len < sizeof(pLargeVal->Bytes)) {
  2662. // dtrace("Ins child %08lx %s had %3lx name %ws\n",
  2663. // pLargeVal, pLargeVal->Used ? "used" : "free",
  2664. // pLargeVal->Index, &pLargeVal->Bytes[0]);
  2665. memcpy(&pLargeVal->Bytes[0], pChild, len);
  2666. pLargeVal->LengthUsed = len;
  2667. if (pLargeVal->Used) {
  2668. pCache[pLargeVal->Index].Data.type = 0;
  2669. pCache[pLargeVal->Index].Data.ullVal = 0;
  2670. pCache[pLargeVal->Index].SearchId = 0;
  2671. }
  2672. pCache[i].Data.type = DIACH_PLVAL;
  2673. pCache[i].Data.plVal = pLargeVal;
  2674. pLargeVal->Index = i;
  2675. pLargeVal->Used = true;
  2676. } else {
  2677. pCache[i].SearchId = 0;
  2678. }
  2679. break;
  2680. }
  2681. case TI_GET_VALUE:
  2682. default:
  2683. pCache[i].Data.type = 0;
  2684. pCache[i].SearchId = 0;
  2685. return ;
  2686. }
  2687. }
  2688. BOOL
  2689. diaLookupCache(
  2690. PDIA_CACHE_ENTRY pCache,
  2691. ULONG64 Module,
  2692. ULONG TypeId,
  2693. IMAGEHLP_SYMBOL_TYPE_INFO GetType,
  2694. PVOID pInfo
  2695. )
  2696. {
  2697. if (GetType == TI_IS_EQUIV_TO) {
  2698. // Not cached.
  2699. return false;
  2700. }
  2701. int start = CACHE_BLOCK * (TypeId % CACHE_BLOCK);
  2702. int i, found;
  2703. ULONGLONG Search = ((ULONGLONG) GetType << 32) + TypeId;
  2704. ++gLook;
  2705. for (i=start,found=-1; i<(start+CACHE_BLOCK); i++) {
  2706. if (pCache[i].SearchId == Search &&
  2707. pCache[i].Module == Module) {
  2708. found = i;
  2709. break;
  2710. }
  2711. }
  2712. if (found == -1) {
  2713. return false;
  2714. }
  2715. i=found;
  2716. pCache[i].Age = 0;
  2717. switch (pCache[i].Data.type) {
  2718. case DIACH_ULVAL:
  2719. *((PULONG) pInfo) = pCache[i].Data.ulVal;
  2720. break;
  2721. case DIACH_ULLVAL:
  2722. *((PULONGLONG) pInfo) = pCache[i].Data.ullVal;
  2723. break;
  2724. case DIACH_PLVAL:
  2725. if (GetType == TI_GET_SYMNAME) {
  2726. *((BSTR *) pInfo) = (BSTR) LocalAlloc(0, pCache[i].Data.plVal->LengthUsed);
  2727. if (*((BSTR *) pInfo)) {
  2728. memcpy(*((BSTR *) pInfo), &pCache[i].Data.plVal->Bytes[0],pCache[i].Data.plVal->LengthUsed);
  2729. // dtrace(Lok %9I64lx ch %3lx lch %08lx name %ws\n",
  2730. // pCache[i].SearchId,
  2731. // i,
  2732. // pCache[i].Data.plVal,
  2733. // &pCache[i].Data.plVal->Bytes[0]);
  2734. }
  2735. } else if (GetType == TI_FINDCHILDREN) {
  2736. TI_FINDCHILDREN_PARAMS *pChild = (TI_FINDCHILDREN_PARAMS *) pInfo;
  2737. TI_FINDCHILDREN_PARAMS *pStored = (TI_FINDCHILDREN_PARAMS *) &pCache[i].Data.plVal->Bytes[0];
  2738. // dtrace(Lok %9I64lx ch %3lx lch %08lx child %lx\n",
  2739. // pCache[i].SearchId,
  2740. // i,
  2741. // pCache[i].Data.plVal,
  2742. // pStored->Count);
  2743. if (pChild->Count == pStored->Count &&
  2744. pChild->Start == pStored->Start) {
  2745. memcpy(pChild, pStored, pCache[i].Data.plVal->LengthUsed);
  2746. }
  2747. }
  2748. break;
  2749. default:
  2750. assert(false);
  2751. return false;
  2752. }
  2753. if (!(++gHits%50)) {
  2754. // dtrace("%ld %% Hits\n", (gHits * 100) / gLook);
  2755. }
  2756. return true;
  2757. }
  2758. #endif // USE_CACHE
  2759. HRESULT
  2760. #ifdef USE_CACHE
  2761. diaGetSymbolInfoEx(
  2762. #else
  2763. diaGetSymbolInfo(
  2764. #endif // USE_CACHE
  2765. IN HANDLE hProcess,
  2766. IN DWORD64 ModBase,
  2767. IN ULONG TypeId,
  2768. IN IMAGEHLP_SYMBOL_TYPE_INFO GetType,
  2769. OUT PVOID pInfo
  2770. )
  2771. {
  2772. assert(pInfo);
  2773. CComPtr <IDiaSymbol> pTypeSym;
  2774. if (!diaFindTypeSym(hProcess, ModBase, TypeId, &pTypeSym)) {
  2775. return E_INVALIDARG;
  2776. }
  2777. switch (GetType) {
  2778. case TI_GET_SYMTAG:
  2779. return diaGetSymTag(pTypeSym, (PULONG) pInfo);
  2780. break;
  2781. case TI_GET_SYMNAME:
  2782. return diaGetSymName(pTypeSym, (BSTR *) pInfo);
  2783. break;
  2784. case TI_GET_LENGTH:
  2785. return diaGetLength(pTypeSym, (PULONGLONG) pInfo);
  2786. break;
  2787. case TI_GET_TYPE:
  2788. case TI_GET_TYPEID:
  2789. return diaGetTypeId(pTypeSym, (PULONG) pInfo);
  2790. break;
  2791. case TI_GET_BASETYPE:
  2792. return diaGetBaseType(pTypeSym, (PULONG) pInfo);
  2793. break;
  2794. case TI_GET_ARRAYINDEXTYPEID:
  2795. return diaGetArrayIndexTypeId(pTypeSym, (PULONG) pInfo);
  2796. break;
  2797. case TI_FINDCHILDREN:
  2798. return diaFindChildren(pTypeSym, (TI_FINDCHILDREN_PARAMS *) pInfo);
  2799. case TI_GET_DATAKIND:
  2800. return diaGetDataKind(pTypeSym, (PULONG) pInfo);
  2801. break;
  2802. case TI_GET_ADDRESSOFFSET:
  2803. return diaGetAddressOffset(pTypeSym, (PULONG) pInfo);
  2804. break;
  2805. case TI_GET_OFFSET:
  2806. return diaGetOffset(pTypeSym, (PLONG) pInfo);
  2807. break;
  2808. case TI_GET_VALUE:
  2809. return diaGetValue(pTypeSym, (VARIANT *) pInfo);
  2810. break;
  2811. case TI_GET_COUNT:
  2812. return diaGetCount(pTypeSym, (PULONG) pInfo);
  2813. break;
  2814. case TI_GET_CHILDRENCOUNT:
  2815. return diaGetChildrenCount(pTypeSym, (PLONG) pInfo);
  2816. break;
  2817. case TI_GET_BITPOSITION:
  2818. return diaGetBitPosition(pTypeSym, (PULONG) pInfo);
  2819. break;
  2820. case TI_GET_VIRTUALBASECLASS:
  2821. return diaGetVirtualBaseClass(pTypeSym, (BOOL *) pInfo);
  2822. break;
  2823. case TI_GET_VIRTUALTABLESHAPEID:
  2824. return diaGetVirtualTableShapeId(pTypeSym, (PULONG) pInfo);
  2825. break;
  2826. case TI_GET_VIRTUALBASEPOINTEROFFSET:
  2827. return diaGetVirtualBasePointerOffset(pTypeSym, (PLONG) pInfo);
  2828. break;
  2829. case TI_GET_CLASSPARENTID:
  2830. return diaGetClassParentId(pTypeSym, (PULONG) pInfo);
  2831. break;
  2832. case TI_GET_NESTED:
  2833. return diaGetNested(pTypeSym, (PBOOL) pInfo);
  2834. break;
  2835. case TI_GET_SYMINDEX:
  2836. return diaGetSymIndexId(pTypeSym, (PULONG) pInfo);
  2837. break;
  2838. case TI_GET_LEXICALPARENT:
  2839. return diaGetLexicalParentId(pTypeSym, (PULONG) pInfo);
  2840. break;
  2841. case TI_GET_ADDRESS:
  2842. return diaGetSymAddress(pTypeSym, ModBase, (PULONG64) pInfo);
  2843. case TI_GET_THISADJUST:
  2844. return diaGetThisAdjust(pTypeSym, (PLONG) pInfo);
  2845. case TI_GET_UDTKIND:
  2846. return diaGetUdtKind(pTypeSym, (PDWORD) pInfo);
  2847. case TI_IS_EQUIV_TO:
  2848. if (!diaCompareTypeSym(hProcess, ModBase, pTypeSym, (PULONG)pInfo)) {
  2849. return E_INVALIDARG;
  2850. }
  2851. return *(PULONG)pInfo != 0 ? S_OK : S_FALSE;
  2852. case TI_GET_CALLING_CONVENTION:
  2853. return diaGetCallingConvention(pTypeSym, (PULONG)pInfo);
  2854. break;
  2855. default:
  2856. return E_INVALIDARG;
  2857. }
  2858. }
  2859. #ifdef USE_CACHE
  2860. HRESULT
  2861. diaGetSymbolInfo(
  2862. IN HANDLE hProcess,
  2863. IN DWORD64 ModBase,
  2864. IN ULONG TypeId,
  2865. IN IMAGEHLP_SYMBOL_TYPE_INFO GetType,
  2866. OUT PVOID pInfo
  2867. )
  2868. {
  2869. PPROCESS_ENTRY ProcessEntry;
  2870. ProcessEntry = FindProcessEntry( hProcess );
  2871. if (!ProcessEntry) {
  2872. return E_INVALIDARG;
  2873. }
  2874. if (!diaLookupCache(ProcessEntry->DiaCache, ModBase, TypeId, GetType, pInfo)) {
  2875. HRESULT hr = diaGetSymbolInfoEx(hProcess, ModBase, TypeId, GetType, pInfo);
  2876. if (hr == S_OK) {
  2877. diaInsertInCache(ProcessEntry->DiaCache, ProcessEntry->DiaLargeData,
  2878. ModBase, TypeId, GetType, pInfo);
  2879. }
  2880. return hr;
  2881. }
  2882. return S_OK;
  2883. }
  2884. #endif // USE_CACHE
  2885. BOOL
  2886. diaGetTiForUDT(
  2887. PMODULE_ENTRY ModuleEntry,
  2888. LPSTR name,
  2889. PSYMBOL_INFO psi
  2890. )
  2891. {
  2892. BSTR wname=NULL;
  2893. PDIA pdia;
  2894. HRESULT hr;
  2895. ULONG celt;
  2896. if (!ModuleEntry) {
  2897. return false;
  2898. }
  2899. pdia = (PDIA)ModuleEntry->dia;
  2900. if (!pdia)
  2901. return false;
  2902. CComPtr< IDiaSymbol > idiaSymbols;
  2903. hr = pdia->session->get_globalScope(&idiaSymbols);
  2904. if (hr != S_OK)
  2905. return false;
  2906. if (name) {
  2907. wname = AnsiToUnicode(name);
  2908. }
  2909. CComPtr< IDiaEnumSymbols > idiaEnum;
  2910. hr = idiaSymbols->findChildren(SymTagNull, wname, nsCaseSensitive, &idiaEnum);
  2911. if (hr == S_OK) {
  2912. CComPtr< IDiaSymbol > idiaSymbol;
  2913. if ((hr = idiaEnum->Next( 1, &idiaSymbol, &celt)) == S_OK && celt == 1) {
  2914. diaFillSymbolInfo(psi, ModuleEntry, idiaSymbol);
  2915. idiaSymbol->get_symIndexId(&psi->TypeIndex);
  2916. idiaSymbol = NULL;
  2917. }
  2918. }
  2919. MemFree(wname);
  2920. return hr == S_OK;
  2921. }
  2922. BOOL
  2923. diaEnumUDT(
  2924. PMODULE_ENTRY ModuleEntry,
  2925. LPSTR name,
  2926. PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
  2927. PVOID context
  2928. )
  2929. {
  2930. BSTR wname=NULL;
  2931. PDIA pdia;
  2932. HRESULT hr;
  2933. ULONG celt;
  2934. CHAR buff[MAX_SYM_NAME + sizeof(SYMBOL_INFO)];
  2935. PSYMBOL_INFO psi=(PSYMBOL_INFO)buff;
  2936. BOOL rc;
  2937. psi->MaxNameLen = MAX_SYM_NAME;
  2938. if (!ModuleEntry) {
  2939. return false;
  2940. }
  2941. pdia = (PDIA)ModuleEntry->dia;
  2942. if (!pdia)
  2943. return false;
  2944. CComPtr< IDiaSymbol > idiaSymbols;
  2945. hr = pdia->session->get_globalScope(&idiaSymbols);
  2946. if (hr != S_OK)
  2947. return false;
  2948. if (name && *name) {
  2949. wname = AnsiToUnicode(name);
  2950. }
  2951. CComPtr< IDiaEnumSymbols > idiaEnum;
  2952. hr = idiaSymbols->findChildren(SymTagNull, wname, nsCaseSensitive, &idiaEnum);
  2953. if (hr == S_OK) {
  2954. CComPtr< IDiaSymbol > idiaSymbol;
  2955. while (SUCCEEDED(idiaEnum->Next( 1, &idiaSymbol, &celt)) && celt == 1) {
  2956. ULONG tag;
  2957. idiaSymbol->get_symTag(&tag);
  2958. switch (tag)
  2959. {
  2960. case SymTagEnum:
  2961. case SymTagTypedef:
  2962. case SymTagUDT:
  2963. if (EnumSymbolsCallback) {
  2964. diaFillSymbolInfo(psi, ModuleEntry, idiaSymbol);
  2965. idiaSymbol->get_symIndexId(&psi->TypeIndex);
  2966. rc = EnumSymbolsCallback(psi, 0, context);
  2967. if (!rc)
  2968. return true;
  2969. }
  2970. break;
  2971. default:
  2972. break;
  2973. }
  2974. idiaSymbol = NULL;
  2975. }
  2976. }
  2977. MemFree(wname);
  2978. return hr == S_OK;
  2979. }
  2980. BOOL
  2981. ldiaGetFrameData(
  2982. IN HANDLE Process,
  2983. IN ULONGLONG Offset,
  2984. OUT IDiaFrameData** FrameData
  2985. )
  2986. {
  2987. PPROCESS_ENTRY ProcessEntry;
  2988. PDIA Dia;
  2989. PMODULE_ENTRY Mod;
  2990. ProcessEntry = FindProcessEntry(Process);
  2991. if (!ProcessEntry ||
  2992. !(Mod = GetModFromAddr(ProcessEntry, Offset)) ||
  2993. !(Dia = (PDIA)Mod->dia)) {
  2994. return false;
  2995. }
  2996. if (Dia->framedata == NULL) {
  2997. CComPtr<IDiaEnumTables> EnumTables;
  2998. CComPtr<IDiaTable> FdTable;
  2999. VARIANT FdVar;
  3000. FdVar.vt = VT_BSTR;
  3001. FdVar.bstrVal = DiaTable_FrameData;
  3002. if (Dia->session->getEnumTables(&EnumTables) != S_OK ||
  3003. EnumTables->Item(FdVar, &FdTable) != S_OK ||
  3004. FdTable->QueryInterface(IID_IDiaEnumFrameData,
  3005. (void**)&Dia->framedata) != S_OK) {
  3006. return false;
  3007. }
  3008. }
  3009. return Dia->framedata->frameByVA(Offset, FrameData) == S_OK;
  3010. }
  3011. BOOL
  3012. diaGetFrameData(
  3013. IN HANDLE Process,
  3014. IN ULONGLONG Offset,
  3015. OUT IDiaFrameData** FrameData
  3016. )
  3017. {
  3018. BOOL rc = false;
  3019. __try {
  3020. EnterCriticalSection(&g.threadlock);
  3021. rc = ldiaGetFrameData(Process, Offset,FrameData);
  3022. } __finally {
  3023. LeaveCriticalSection(&g.threadlock);
  3024. }
  3025. return rc;
  3026. }
  3027. // ----------------------------------------------------------------
  3028. // for compatibility with GetFileLineOffsets. DON'T CALL THIS CODE!
  3029. #if 1
  3030. HRESULT
  3031. diaAddLinesForSourceFile(
  3032. PMODULE_ENTRY mi,
  3033. IDiaSourceFile *idiaSource,
  3034. IDiaSymbol *pComp
  3035. )
  3036. {
  3037. HRESULT hr;
  3038. LPSTR SrcFileName = NULL;
  3039. BSTR wfname = NULL;
  3040. ULONG SrcFileNameLen = 0;
  3041. PSOURCE_ENTRY Src;
  3042. PSOURCE_ENTRY Seg0Src;
  3043. PSOURCE_LINE SrcLine;
  3044. PDIA pdia;
  3045. ULONG celt;
  3046. LONG LineNums;
  3047. ULONG CompId;
  3048. CHAR fname[MAX_PATH + 1];
  3049. DWORD rva;
  3050. ULONG Line;
  3051. if (!idiaSource) {
  3052. return E_INVALIDARG;
  3053. }
  3054. assert((mi != NULL) && (mi->dia));
  3055. pdia = (PDIA)mi->dia;
  3056. if (pComp->get_symIndexId(&CompId) == S_OK) {
  3057. }
  3058. CComPtr <IDiaEnumLineNumbers> idiaEnumLines;
  3059. hr = pdia->session->findLines(pComp, idiaSource, &idiaEnumLines);
  3060. if (hr != S_OK)
  3061. return hr;
  3062. hr = idiaEnumLines->get_Count(&LineNums);
  3063. if (hr != S_OK)
  3064. return hr;
  3065. CComPtr <IDiaLineNumber> idiaLine;
  3066. if (idiaSource->get_fileName(&wfname) == S_OK && wfname) {
  3067. wcs2ansi(wfname, fname, MAX_PATH);
  3068. LocalFree(wfname);
  3069. SrcFileNameLen = strlen(fname);
  3070. }
  3071. Src = (PSOURCE_ENTRY)MemAlloc(sizeof(SOURCE_ENTRY)+
  3072. sizeof(SOURCE_LINE)*LineNums+
  3073. SrcFileNameLen + 1);
  3074. if (!Src) {
  3075. return E_OUTOFMEMORY;
  3076. }
  3077. #ifdef DBG_DIA_LINE
  3078. dtrace("diaAddLinesForSourceFile : source : %s\n", fname);
  3079. #endif
  3080. // Retrieve line numbers and offsets from raw data and
  3081. // process them into current pointers.
  3082. SrcLine = (SOURCE_LINE *)(Src+1);
  3083. Src->LineInfo = SrcLine;
  3084. Src->ModuleId = CompId;
  3085. Src->MaxAddr = 0;
  3086. Src->MinAddr = -1;
  3087. Src->Lines = 0;
  3088. idiaLine = NULL;
  3089. for (; (hr = idiaEnumLines->Next(1, &idiaLine, &celt)) == S_OK && (celt == 1); ) {
  3090. hr = idiaLine->get_lineNumber(&Line);
  3091. if (hr != S_OK)
  3092. break;
  3093. hr = idiaLine->get_relativeVirtualAddress(&rva);
  3094. if (hr != S_OK)
  3095. break;
  3096. SrcLine->Line = Line;
  3097. SrcLine->Addr = GetLineAddressFromRva(mi, rva);
  3098. if (SrcLine->Addr > Src->MaxAddr) {
  3099. Src->MaxAddr = SrcLine->Addr;
  3100. }
  3101. if (SrcLine->Addr < Src->MinAddr) {
  3102. Src->MinAddr = SrcLine->Addr;
  3103. }
  3104. #ifdef DBG_DIA_LINE
  3105. dtrace("Add line %lx, Addr %I64lx\n", SrcLine->Line, SrcLine->Addr);
  3106. #endif
  3107. Src->Lines++;
  3108. SrcLine++;
  3109. idiaLine = NULL;
  3110. }
  3111. // Stick file name at the very end of the data block so
  3112. // it doesn't interfere with alignment.
  3113. Src->File = (LPSTR)SrcLine;
  3114. if (*fname) {
  3115. memcpy(Src->File, fname, SrcFileNameLen);
  3116. }
  3117. Src->File[SrcFileNameLen] = 0;
  3118. AddSourceEntry(mi, Src);
  3119. return S_OK;
  3120. }
  3121. BOOL
  3122. diaAddLinesForMod(
  3123. PMODULE_ENTRY mi,
  3124. IDiaSymbol *diaModule
  3125. )
  3126. {
  3127. LONG Size;
  3128. BOOL Ret;
  3129. PSOURCE_ENTRY Src;
  3130. ULONG ModId;
  3131. HRESULT Hr;
  3132. if (diaModule->get_symIndexId(&ModId) != S_OK) {
  3133. return false;
  3134. }
  3135. #ifdef DBG_DIA_LINE
  3136. dtrace("diaAddLinesForMod : ModId %lx\n", ModId);
  3137. #endif
  3138. // Check and see if we've loaded this information already.
  3139. for (Src = mi->SourceFiles; Src != NULL; Src = Src->Next) {
  3140. // Check module index instead of pointer since there's
  3141. // no guarantee the pointer would be the same for different
  3142. // lookups.
  3143. if (Src->ModuleId == ModId) {
  3144. return true;
  3145. }
  3146. }
  3147. PDIA pdia;
  3148. pdia = (PDIA)mi->dia;
  3149. CComPtr< IDiaEnumSourceFiles > idiaEnumFiles;
  3150. Hr = pdia->session->findFile(diaModule, NULL, nsNone, &idiaEnumFiles);
  3151. if (Hr != S_OK) {
  3152. return false;
  3153. }
  3154. ULONG celt;
  3155. CComPtr <IDiaSourceFile> idiaSource;
  3156. for (;SUCCEEDED(idiaEnumFiles->Next(1,&idiaSource, &celt)) && (celt == 1);) {
  3157. diaAddLinesForSourceFile(mi, idiaSource, diaModule);
  3158. idiaSource = NULL;
  3159. }
  3160. return true;
  3161. }
  3162. BOOL
  3163. diaAddLinesForModAtAddr(
  3164. PMODULE_ENTRY mi,
  3165. DWORD64 Addr
  3166. )
  3167. {
  3168. BOOL Ret;
  3169. DWORD Bias;
  3170. HRESULT hr;
  3171. PDIA pdia;
  3172. DWORD rva;
  3173. assert(mi && mi->dia);
  3174. pdia = (PDIA)mi->dia;
  3175. if (!pdia)
  3176. return NULL;
  3177. rva = (DWORD)(Addr - mi->BaseOfDll);
  3178. CComPtr < IDiaSymbol > pComp;
  3179. hr = pdia->session->findSymbolByRVA(rva, SymTagCompiland, &pComp);
  3180. if (hr != S_OK)
  3181. return false;
  3182. Ret = diaAddLinesForMod(mi, pComp);
  3183. return Ret;
  3184. }
  3185. BOOL
  3186. diaAddLinesForAllMod(
  3187. PMODULE_ENTRY mi
  3188. )
  3189. {
  3190. HRESULT hr;
  3191. PDIA pdia;
  3192. ULONG celt = 1;
  3193. BOOL Ret;
  3194. Ret = false;
  3195. #ifdef DBG_DIA_LINE
  3196. dtrace("diaAddLinesForAllMod : Adding lines for all mods in %s\n", mi->ImageName);
  3197. #endif
  3198. assert(mi && mi->dia);
  3199. pdia = (PDIA)mi->dia;
  3200. if (!pdia)
  3201. return NULL;
  3202. CComPtr <IDiaSymbol> idiaSymbols;
  3203. hr = pdia->session->get_globalScope(&idiaSymbols);
  3204. if (hr != S_OK)
  3205. return NULL;
  3206. CComPtr< IDiaEnumSymbols > idiaMods;
  3207. hr = pdia->session->findChildren(idiaSymbols,SymTagCompiland, NULL, nsNone, &idiaMods);
  3208. if (FAILED(hr))
  3209. return false;
  3210. CComPtr< IDiaSymbol > idiaSymbol;
  3211. while (SUCCEEDED(idiaMods->Next( 1, &idiaSymbol, &celt)) && celt == 1) {
  3212. Ret = diaAddLinesForMod(mi, idiaSymbol);
  3213. idiaSymbol = NULL;
  3214. if (!Ret) {
  3215. break;
  3216. }
  3217. }
  3218. return Ret;
  3219. }
  3220. #endif