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.

1516 lines
34 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <malloc.h>
  5. #include <assert.h>
  6. #include <imagehlp.h>
  7. #include <dbhpriv.h>
  8. #include <cvconst.h>
  9. #include <cmnutil.hpp>
  10. #ifndef true
  11. #define true TRUE
  12. #define false FALSE
  13. #endif
  14. #define MAX_STR 256
  15. #define WILD_UNDERSCORE 1
  16. #define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME)
  17. #define SI_BUFFER_SIZE (sizeof(SYMBOL_INFO) + MAX_SYM_NAME)
  18. BOOL gDisplay = true;
  19. DWORD gcEnum = 0;
  20. DWORD gcAddr = 0;
  21. #define pprintf (gDisplay)&&printf
  22. typedef struct _GENINFO {
  23. HANDLE hp;
  24. char modname[MAX_PATH + 1];
  25. } GENINFO, *PGENINFO;
  26. typedef struct {
  27. char mask[MAX_STR];
  28. DWORD64 base;
  29. } ENUMSYMDATA, *PENUMSYMDATA;
  30. typedef enum
  31. {
  32. cmdQuit = 0,
  33. cmdHelp,
  34. cmdVerbose,
  35. cmdLoad,
  36. cmdUnload,
  37. cmdEnum,
  38. cmdName,
  39. cmdAddr,
  40. cmdBase,
  41. cmdNext,
  42. cmdPrev,
  43. cmdLine,
  44. cmdSymInfo,
  45. cmdDiaVer,
  46. cmdUndec,
  47. cmdFindFile,
  48. cmdEnumSrcFiles,
  49. cmdAdd,
  50. cmdDelete,
  51. cmdSymbolServer,
  52. cmdEnumForAddr,
  53. cmdLocals,
  54. cmdMax
  55. };
  56. typedef BOOL (*CMDPROC)(char *params);
  57. typedef struct _CMD
  58. {
  59. char token[MAX_STR + 1];
  60. char shorttoken[4];
  61. CMDPROC fn;
  62. } CMD, *PCMD;
  63. BOOL fnQuit(char *);
  64. BOOL fnHelp(char *);
  65. BOOL fnVerbose(char *);
  66. BOOL fnLoad(char *);
  67. BOOL fnUnload(char *);
  68. BOOL fnEnum(char *);
  69. BOOL fnName(char *);
  70. BOOL fnAddr(DWORD64 addr);
  71. BOOL fnBase(char *);
  72. BOOL fnNext(char *);
  73. BOOL fnPrev(char *);
  74. BOOL fnLine(char *);
  75. BOOL fnSymInfo(char *);
  76. BOOL fnDiaVer(char *);
  77. BOOL fnUndec(char *);
  78. BOOL fnFindFile(char *);
  79. BOOL fnEnumSrcFiles(char *);
  80. BOOL fnAdd(char *);
  81. BOOL fnDelete(char *);
  82. BOOL fnSymbolServer(char *);
  83. BOOL fnEnumForAddr(char *);
  84. BOOL fnLocals(char *);
  85. CMD gCmd[cmdMax] =
  86. {
  87. {"quit", "q", fnQuit},
  88. {"help", "h", fnHelp},
  89. {"verbose", "v", fnVerbose},
  90. {"load", "l", fnLoad},
  91. {"unload", "u", fnUnload},
  92. {"enum", "x", fnEnum},
  93. {"name", "n", fnName},
  94. {"addr", "a", fnLoad},
  95. {"base", "b", fnBase},
  96. {"next", "t", fnNext},
  97. {"prev", "v", fnPrev},
  98. {"line", "i", fnLine},
  99. {"sym" , "s", fnSymInfo},
  100. {"dia", "d", fnDiaVer},
  101. {"undec", "n", fnUndec},
  102. {"ff", "f", fnFindFile},
  103. {"src", "r", fnEnumSrcFiles},
  104. {"add", "+", fnAdd},
  105. {"del", "-", fnDelete},
  106. {"ss", "y", fnSymbolServer},
  107. {"enumaddr","m", fnEnumForAddr},
  108. {"locals", "z", fnLocals}
  109. };
  110. char gModName[MAX_STR];
  111. char gImageName[MAX_STR];
  112. char gSymbolSearchPath[MAX_STR];
  113. DWORD64 gBase;
  114. DWORD64 gDefaultBase;
  115. DWORD64 gDefaultBaseForVirtualMods;
  116. DWORD gOptions;
  117. HANDLE gHP;
  118. // symbol server stuff
  119. HINSTANCE ghSrv;
  120. PSYMBOLSERVERPROC gfnSymbolServer;
  121. PSYMBOLSERVERCLOSEPROC gfnSymbolServerClose;
  122. PSYMBOLSERVERSETOPTIONSPROC gfnSymbolServerSetOptions;
  123. PSYMBOLSERVERGETOPTIONSPROC gfnSymbolServerGetOptions;
  124. int
  125. WINAPIV
  126. dprintf(
  127. LPSTR Format,
  128. ...
  129. )
  130. {
  131. static char buf[1000] = "DBGHELP: ";
  132. va_list args;
  133. if ((gOptions & SYMOPT_DEBUG) == 0)
  134. return 1;
  135. va_start(args, Format);
  136. _vsnprintf(buf, sizeof(buf)-9, Format, args);
  137. va_end(args);
  138. fputs(buf, stdout);
  139. return 1;
  140. }
  141. __inline int ucase(int c)
  142. {
  143. return (gOptions & SYMOPT_CASE_INSENSITIVE) ? toupper(c) : c;
  144. }
  145. #define MAX_FORMAT_STRINGS 8
  146. char *
  147. dispaddr(
  148. ULONG64 addr
  149. )
  150. /*++
  151. Routine Description:
  152. Format a 64 bit address, showing the high bits or not
  153. according to various flags. This version does not print
  154. leading 0's.
  155. An array of static string buffers is used, returning a different
  156. buffer for each successive call so that it may be used multiple
  157. times in the same dprintf.
  158. Arguments:
  159. addr - Supplies the value to format
  160. Return Value:
  161. A pointer to the string buffer containing the formatted number
  162. --*/
  163. {
  164. static char sz[20];
  165. if ((addr >> 32) != 0)
  166. PrintString(sz, DIMA(sz), "%x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  167. else
  168. PrintString(sz, DIMA(sz), "%x", (ULONG)addr);
  169. return sz;
  170. }
  171. BOOL
  172. validnum(
  173. char *sz
  174. )
  175. {
  176. int c;
  177. for (; *sz; sz++)
  178. {
  179. c = tolower(*sz);
  180. if (c >= '0' && c <= '9')
  181. continue;
  182. if (c >= 'a' && c <= 'f')
  183. continue;
  184. return false;
  185. }
  186. return true;
  187. }
  188. DWORD64
  189. sz2addr(
  190. char *sz
  191. )
  192. {
  193. char *p;
  194. DWORD64 addr = 0;
  195. if (sz && *sz)
  196. {
  197. p = sz;
  198. if (*(p + 1) == 'x' || *(p + 1) == 'X')
  199. p += 2;
  200. if (!validnum(p))
  201. return 0;
  202. if (sscanf(p, "%I64x", &addr) < 1)
  203. return 0;
  204. }
  205. return addr;
  206. }
  207. void dumpsym(
  208. PIMAGEHLP_SYMBOL64 sym
  209. )
  210. {
  211. pprintf(" name : %s\n", sym->Name);
  212. pprintf(" addr : %s\n", dispaddr(sym->Address));
  213. pprintf(" size : %x\n", sym->Size);
  214. pprintf("flags : %x\n", sym->Flags);
  215. }
  216. void dumpsym32(
  217. PIMAGEHLP_SYMBOL sym
  218. )
  219. {
  220. pprintf(" name : %s\n", sym->Name);
  221. pprintf(" addr : %s\n", dispaddr(sym->Address));
  222. pprintf(" size : %x\n", sym->Size);
  223. pprintf("flags : %x\n", sym->Flags);
  224. }
  225. void dumpline(
  226. PIMAGEHLP_LINE64 line
  227. )
  228. {
  229. pprintf("%s %s %d\n", dispaddr(line->Address), line->FileName, line->LineNumber);
  230. }
  231. char* g_SymTagNames[] =
  232. {
  233. "SymTagNull",
  234. "SymTagExe",
  235. "SymTagCompiland",
  236. "SymTagCompilandDetails",
  237. "SymTagCompilandEnv",
  238. "SymTagFunction",
  239. "SymTagBlock",
  240. "SymTagData",
  241. "SymTagAnnotation",
  242. "SymTagLabel",
  243. "SymTagPublicSymbol",
  244. "SymTagUDT",
  245. "SymTagEnum",
  246. "SymTagFunctionType",
  247. "SymTagPointerType",
  248. "SymTagArrayType",
  249. "SymTagBaseType",
  250. "SymTagTypedef",
  251. "SymTagBaseClass",
  252. "SymTagFriend",
  253. "SymTagFunctionArgType",
  254. "SymTagFuncDebugStart",
  255. "SymTagFuncDebugEnd",
  256. "SymTagUsingNamespace",
  257. "SymTagVTableShape",
  258. "SymTagVTable",
  259. "SymTagCustom",
  260. "SymTagThunk",
  261. "SymTagCustomType",
  262. "SymTagManagedType",
  263. "SymTagDimension",
  264. };
  265. char* dispsymtag(
  266. ULONG symtag
  267. )
  268. {
  269. if (symtag >= SymTagMax) {
  270. return "<Invalid>";
  271. } else {
  272. return g_SymTagNames[symtag];
  273. }
  274. }
  275. void dumpsi(
  276. PSYMBOL_INFO si
  277. )
  278. {
  279. pprintf(" name : %s\n", si->Name);
  280. pprintf(" addr : %s\n", dispaddr(si->Address));
  281. pprintf(" size : %x\n", si->Size);
  282. pprintf(" flags : %x\n", si->Flags);
  283. pprintf(" type : %x\n", si->TypeIndex);
  284. pprintf("modbase : %s\n", dispaddr(si->ModBase));
  285. pprintf(" value : %s\n", dispaddr(si->Value));
  286. pprintf(" reg : %x\n", si->Register);
  287. pprintf(" scope : %s (%x)\n", dispsymtag(si->Scope), si->Scope);
  288. pprintf(" tag : %s (%x)\n", dispsymtag(si->Tag), si->Tag);
  289. }
  290. BOOL
  291. MatchPattern(
  292. char *sz,
  293. char *pattern
  294. )
  295. {
  296. char c, p, l;
  297. if (!*pattern)
  298. return true;
  299. for (; ;) {
  300. p = *pattern++;
  301. p = (char)ucase(p);
  302. switch (p) {
  303. case 0: // end of pattern
  304. return *sz ? false : true; // if end of string true
  305. case '*':
  306. while (*sz) { // match zero or more char
  307. if (MatchPattern (sz++, pattern)) {
  308. return true;
  309. }
  310. }
  311. return MatchPattern (sz, pattern);
  312. case '?':
  313. if (*sz++ == 0) { // match any one char
  314. return false; // not end of string
  315. }
  316. break;
  317. case WILD_UNDERSCORE:
  318. while (*sz == '_') {
  319. sz++;
  320. }
  321. break;
  322. case '[':
  323. if ( (c = *sz++) == 0) { // match char set
  324. return false; // syntax
  325. }
  326. c = (CHAR)ucase(c);
  327. l = 0;
  328. while (p = *pattern++) {
  329. if (p == ']') { // if end of char set, then
  330. return false; // no match found
  331. }
  332. if (p == '-') { // check a range of chars?
  333. p = *pattern; // get high limit of range
  334. if (p == 0 || p == ']') {
  335. return false; // syntax
  336. }
  337. if (c >= l && c <= p) {
  338. break; // if in range, move on
  339. }
  340. }
  341. l = p;
  342. if (c == p) { // if char matches this element
  343. break; // move on
  344. }
  345. }
  346. while (p && p != ']') { // got a match in char set
  347. p = *pattern++; // skip to end of set
  348. }
  349. break;
  350. default:
  351. c = *sz++;
  352. if (ucase(c) != p) { // check for exact char
  353. return false; // not a match
  354. }
  355. break;
  356. }
  357. }
  358. }
  359. BOOL
  360. cbEnumSymbols(
  361. PSYMBOL_INFO si,
  362. ULONG size,
  363. PVOID context
  364. )
  365. {
  366. PENUMSYMDATA esd = (PENUMSYMDATA)context;
  367. if (gDisplay)
  368. {
  369. pprintf(" %8s : ", dispaddr(si->Address));
  370. if (si->Flags & SYMF_FORWARDER)
  371. pprintf("%c ", 'F');
  372. else if (si->Flags & SYMF_EXPORT)
  373. pprintf("%c ", 'E');
  374. else
  375. pprintf(" ");
  376. pprintf("%s\n", si->Name);
  377. }
  378. gcEnum++;
  379. gcAddr++;
  380. fnAddr(si->Address + 2);
  381. return true;
  382. }
  383. BOOL
  384. cbEnumSym(
  385. PTSTR name,
  386. DWORD64 address,
  387. ULONG size,
  388. PVOID context
  389. )
  390. {
  391. PENUMSYMDATA esd = (PENUMSYMDATA)context;
  392. if (MatchPattern(name, esd->mask))
  393. pprintf("%s : %s\n", dispaddr(address), name);
  394. return true;
  395. }
  396. BOOL
  397. cbSrcFiles(
  398. PSOURCEFILE pSourceFile,
  399. PVOID UserContext
  400. )
  401. {
  402. DWORD dw;
  403. BOOL rc;
  404. LONG disp;
  405. IMAGEHLP_LINE64 line;
  406. GENINFO *gi = (GENINFO *)UserContext;
  407. if (!pSourceFile)
  408. return false;
  409. if (!strcmp(pSourceFile->FileName, "d:\\pat\\test\\test.c")
  410. || !strcmp(pSourceFile->FileName, "d:\\pat\\lines\\lines.c"))
  411. {
  412. pprintf("%s\n", pSourceFile->FileName);
  413. }
  414. else
  415. pprintf("%s\n", pSourceFile->FileName);
  416. if (!gi)
  417. return true;
  418. line.SizeOfStruct = sizeof(line);
  419. rc = SymGetLineFromName64(gi->hp, gi->modname, pSourceFile->FileName, 1, &disp, &line);
  420. #if 0
  421. for (dw = line.LineNumber + 1; rc; dw = line.LineNumber + 1) {
  422. dumpline(&line);
  423. rc = SymGetLineFromName64(gi->hp, gi->modname, pSourceFile->FileName, dw, &disp, &line);
  424. }
  425. #else
  426. while (rc)
  427. {
  428. dumpline(&line);
  429. rc = SymGetLineNext64(gi->hp, &line);
  430. }
  431. do {
  432. rc = SymGetLinePrev64(gi->hp, &line);
  433. if (rc)
  434. dumpline(&line);
  435. } while (rc);
  436. #endif
  437. return true;
  438. }
  439. BOOL
  440. cbSymbol(
  441. HANDLE hProcess,
  442. ULONG ActionCode,
  443. ULONG64 CallbackData,
  444. ULONG64 UserContext
  445. )
  446. {
  447. PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
  448. PIMAGEHLP_CBA_READ_MEMORY prm;
  449. IMAGEHLP_MODULE64 mi;
  450. PUCHAR p;
  451. ULONG i;
  452. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64) CallbackData;
  453. switch ( ActionCode ) {
  454. case CBA_DEBUG_INFO:
  455. dprintf("%s", (LPSTR)CallbackData);
  456. break;
  457. #if 0
  458. case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
  459. if (fControlC)
  460. {
  461. fControlC = 0;
  462. return true;
  463. }
  464. break;
  465. #endif
  466. case CBA_DEFERRED_SYMBOL_LOAD_START:
  467. dprintf("loading symbols for %s\n", gModName);
  468. break;
  469. case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
  470. if (idsl->FileName && *idsl->FileName)
  471. dprintf( "*** Error: could not load symbols for %s\n", idsl->FileName );
  472. else
  473. dprintf( "*** Error: could not load symbols [MODNAME UNKNOWN]\n");
  474. break;
  475. case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
  476. break;
  477. case CBA_SYMBOLS_UNLOADED:
  478. dprintf("unloaded symbols for %s\n", gModName);
  479. break;
  480. #if 0
  481. case CBA_READ_MEMORY:
  482. prm = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData;
  483. return g_Target->ReadVirtual(prm->addr,
  484. prm->buf,
  485. prm->bytes,
  486. prm->bytesread) == S_OK;
  487. #endif
  488. default:
  489. return false;
  490. }
  491. return false;
  492. }
  493. BOOL fnQuit(char *param)
  494. {
  495. pprintf("goodbye\n");
  496. return false;
  497. }
  498. BOOL fnHelp(char *param)
  499. {
  500. pprintf(" dbh commands :\n");
  501. pprintf("h help : prints this message\n");
  502. pprintf("q quit : quits this program\n");
  503. pprintf("v verbose <on/off> : controls debug spew\n");
  504. pprintf("l load <modname> : loads the requested module\n");
  505. pprintf("u unload : unloads the current module\n");
  506. pprintf("x enum <mask> : enumerates all matching symbols\n");
  507. pprintf("n name <symname> : finds a symbol by it's name\n");
  508. pprintf("a addr <addr> : finds a symbol by it's hex address\n");
  509. pprintf("m enumaddr <addr> : lists all symbols with a certain hex address\n");
  510. pprintf("b base <address> : sets the new default base address\n");
  511. pprintf("t next <add/nam> : finds the symbol after the passed sym\n");
  512. pprintf("v prev <add/nam> : finds the symbol before the passed sym\n");
  513. pprintf("i line <file:#> : finds the matching line number\n");
  514. pprintf("s sym : displays type and location of symbols\n");
  515. pprintf("d dia : displays the DIA version\n");
  516. pprintf("f ff <path> <file> : finds file in path\n");
  517. pprintf("r src <mask> : lists source files\n");
  518. pprintf("+ add <name addr> : adds symbols with passed name and address\n");
  519. pprintf("- del <name/addr> : deletes symbols with passed name or address\n");
  520. pprintf("y ss : executes a symbol server command\n");
  521. pprintf("m enumaddr <addr> : enum all symbols for address\n");
  522. pprintf("z locals <name> : enum all scoped symbols for a named function\n");
  523. return true;
  524. }
  525. BOOL fnVerbose(char *param)
  526. {
  527. int opts = gOptions;
  528. if (!param || !*param)
  529. pprintf("");
  530. else if (!_strcmpi(param, "on"))
  531. opts |= SYMOPT_DEBUG;
  532. else if (!_strcmpi(param, "off"))
  533. opts = gOptions & ~SYMOPT_DEBUG;
  534. else
  535. pprintf("verbose <on//off>\n");
  536. gOptions = SymSetOptions(opts);
  537. pprintf("verbose mode %s.\n", gOptions & SYMOPT_DEBUG ? "on" : "off");
  538. return true;
  539. }
  540. BOOL fnLoad(char *param)
  541. {
  542. char ext[MAX_STR];
  543. char mod[MAX_STR];
  544. char image[MAX_STR];
  545. DWORD flags = 0;
  546. DWORD64 addr = 0;
  547. CopyStrArray(image, (param && *param) ? param : "VIRTUAL");
  548. _splitpath(image, NULL, NULL, mod, ext);
  549. if (!*ext) {
  550. flags = SLMFLAG_VIRTUAL;
  551. addr = gDefaultBaseForVirtualMods;
  552. } else if (!_strcmpi(ext, ".pdb")) {
  553. addr = gDefaultBaseForVirtualMods;
  554. } else {
  555. addr = gDefaultBase;
  556. }
  557. fnUnload(NULL);
  558. CopyStrArray(gModName, mod);
  559. addr = SymLoadModuleEx(gHP,
  560. NULL, // hFile,
  561. param, // ImageName,
  562. mod, // ModuleName,
  563. addr, // BaseOfDll,
  564. 0x1000000, // SizeOfDll
  565. NULL, // Data
  566. flags); // Flags
  567. if (!addr)
  568. {
  569. *gModName = 0;
  570. pprintf("error 0x%x loading %s\n", GetLastError(), param);
  571. return false;
  572. }
  573. if (gBase && !SymUnloadModule64(gHP, gBase))
  574. pprintf("error unloading %s at %s\n", gModName, dispaddr(gBase));
  575. CopyStrArray(gImageName, image);
  576. gBase = addr;
  577. return true;
  578. }
  579. BOOL fnUnload(char *param)
  580. {
  581. if (!gBase)
  582. return true;
  583. if (!SymUnloadModule64(gHP, gBase))
  584. pprintf("error unloading %s at %s\n", gModName, dispaddr(gBase));
  585. gBase = 0;
  586. *gModName = 0;
  587. return true;
  588. }
  589. BOOL fnEnum(char *param)
  590. {
  591. BOOL rc;
  592. ENUMSYMDATA esd;
  593. esd.base = gBase;
  594. CopyStrArray(esd.mask, param ? param : "");
  595. rc = SymEnumSymbols(gHP, gBase, param, cbEnumSymbols, &esd);
  596. if (!rc)
  597. pprintf("error 0x%0 calling SymEnumSymbols()\n", GetLastError());
  598. return true;
  599. }
  600. BOOL fnEnumSrcFiles(char *param)
  601. {
  602. BOOL rc;
  603. GENINFO gi;
  604. gi.hp = gHP;
  605. CopyStrArray(gi.modname, gModName);
  606. rc = SymEnumSourceFiles(gHP, gBase, param, cbSrcFiles, &gi);
  607. if (!rc)
  608. pprintf("error 0x%0 calling SymEnumSourceFiles()\n", GetLastError());
  609. return true;
  610. }
  611. BOOL fnName(char *param)
  612. {
  613. #if 0
  614. BOOL rc;
  615. PIMAGEHLP_SYMBOL64 sym;
  616. char name[MAX_STR];
  617. if (!param || !*param)
  618. {
  619. pprintf("name <symbolname> - finds a symbol by it's name\n");
  620. return true;
  621. }
  622. PrintString(name, DIMA(name), "%s!%s", gModName, param);
  623. sym = malloc(SYM_BUFFER_SIZE);
  624. if (!sym)
  625. return false;
  626. ZeroMemory(sym, SYM_BUFFER_SIZE);
  627. sym->MaxNameLength = MAX_SYM_NAME;
  628. if (SymGetSymFromName64(gHP, name, sym))
  629. if (gDisplay)
  630. dumpsym(sym);
  631. free(sym);
  632. return true;
  633. #else
  634. PSYMBOL_INFO si;
  635. char name[MAX_STR];
  636. if (!param || !*param)
  637. {
  638. pprintf("name <symbolname> - finds a symbol by it's name\n");
  639. return true;
  640. }
  641. PrintString(name, DIMA(name), "%s!%s", gModName, param);
  642. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  643. if (!si)
  644. return false;
  645. ZeroMemory(si, SI_BUFFER_SIZE);
  646. si->MaxNameLen = MAX_SYM_NAME;
  647. if (SymFromName(gHP, name, si))
  648. dumpsi(si);
  649. free(si);
  650. return true;
  651. #endif
  652. }
  653. BOOL fnAddr(DWORD64 addr)
  654. {
  655. BOOL rc;
  656. PIMAGEHLP_SYMBOL64 sym;
  657. DWORD64 disp;
  658. PSYMBOL_INFO si;
  659. IMAGEHLP_LINE64 line;
  660. DWORD ldisp;
  661. if (!addr)
  662. {
  663. pprintf("addr <address> : finds a symbol by it's hex address\n");
  664. return true;
  665. }
  666. #if 0
  667. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  668. if (!sym)
  669. return false;
  670. ZeroMemory(sym, SYM_BUFFER_SIZE);
  671. sym->MaxNameLength = MAX_SYM_NAME;
  672. rc = SymGetSymFromAddr64(gHP, addr, &disp, sym);
  673. if (rc)
  674. {
  675. if (gDisplay)
  676. {
  677. pprintf("%s", sym->Name);
  678. if (disp)
  679. pprintf("+%I64x", disp);
  680. pprintf("\n");
  681. dumpsym(sym);
  682. }
  683. }
  684. free(sym);
  685. line.SizeOfStruct = sizeof(line);
  686. rc = SymGetLineFromAddr64(gHP, addr, &ldisp, &line);
  687. if (rc && gDisplay)
  688. pprintf("%s %d\n", line.FileName, line.LineNumber);
  689. #else
  690. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  691. if (!si)
  692. return false;
  693. ZeroMemory(si, SI_BUFFER_SIZE);
  694. si->MaxNameLen = MAX_SYM_NAME;
  695. rc = SymFromAddr(gHP, addr, &disp, si);
  696. if (rc)
  697. {
  698. pprintf("%s", si->Name);
  699. if (disp)
  700. pprintf("+%I64x", disp);
  701. pprintf("\n");
  702. dumpsi(si);
  703. }
  704. free(si);
  705. line.SizeOfStruct = sizeof(line);
  706. rc = SymGetLineFromAddr64(gHP, addr, &ldisp, &line);
  707. if (rc && gDisplay)
  708. pprintf("%s %d\n", line.FileName, line.LineNumber);
  709. #endif
  710. return true;
  711. }
  712. BOOL fnEnumForAddr(char *param)
  713. {
  714. BOOL rc;
  715. PIMAGEHLP_SYMBOL64 sym;
  716. DWORD64 addr;
  717. DWORD64 disp;
  718. ENUMSYMDATA esd;
  719. addr = sz2addr(param);
  720. if (!addr)
  721. {
  722. pprintf("enumaddr <addr> : lists all symbols with a certain hex address\n");
  723. return true;
  724. }
  725. esd.base = gBase;
  726. CopyStrArray(esd.mask, "");
  727. rc = SymEnumSymbolsForAddr(gHP, addr, cbEnumSymbols, &esd);
  728. if (!rc)
  729. pprintf("error 0x%0 calling SymEnumSymbolsForAddr()\n", GetLastError());
  730. return true;
  731. }
  732. BOOL fnLocals(char *param)
  733. {
  734. BOOL rc;
  735. PSYMBOL_INFO si;
  736. char name[MAX_STR];
  737. IMAGEHLP_STACK_FRAME frame;
  738. ENUMSYMDATA esd;
  739. SYMBOL_INFO_PACKAGE sp;
  740. if (!param || !*param)
  741. {
  742. pprintf("name <symbolname> - finds a symbol by it's name\n");
  743. return true;
  744. }
  745. PrintString(name, DIMA(name), "%s!%s", gModName, param);
  746. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  747. if (!si)
  748. return false;
  749. ZeroMemory(si, SI_BUFFER_SIZE);
  750. si->MaxNameLen = MAX_SYM_NAME;
  751. if (!SymFromName(gHP, name, si))
  752. goto exit;
  753. pprintf("dumping locals for %s...\n", si->Name);
  754. ZeroMemory(&frame, sizeof(frame));
  755. frame.InstructionOffset = si->Address;
  756. SymSetContext(gHP, &frame, NULL);
  757. esd.base = gBase;
  758. CopyStrArray(esd.mask, "*");
  759. if (!SymEnumSymbols(gHP, 0, esd.mask, cbEnumSymbols, &esd))
  760. pprintf("error 0x%0 calling SymEnumSymbols()\n", GetLastError());
  761. exit:
  762. free(si);
  763. return true;
  764. }
  765. PIMAGEHLP_SYMBOL64 SymbolFromName(char *param)
  766. {
  767. BOOL rc;
  768. PIMAGEHLP_SYMBOL64 sym;
  769. char name[MAX_STR];
  770. assert(name & *name);
  771. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  772. if (!sym)
  773. return false;
  774. ZeroMemory(sym, SYM_BUFFER_SIZE);
  775. sym->MaxNameLength = MAX_SYM_NAME;
  776. PrintString(name, DIMA(name), "%s!%s", gModName, param);
  777. rc = SymGetSymFromName64(gHP, name, sym);
  778. if (!rc) {
  779. free(sym);
  780. return NULL;
  781. }
  782. return sym;
  783. }
  784. BOOL fnNextPrev(int direction, char *param)
  785. {
  786. #if 1
  787. BOOL rc;
  788. PIMAGEHLP_SYMBOL64 sym;
  789. DWORD64 addr;
  790. char name[MAX_STR];
  791. addr = sz2addr(param);
  792. if (!addr)
  793. {
  794. sym = SymbolFromName(param);
  795. if (!sym)
  796. return true;
  797. addr = sym->Address;
  798. if (!addr) {
  799. free(sym);
  800. return true;
  801. }
  802. }
  803. else
  804. {
  805. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  806. if (!sym)
  807. return false;
  808. }
  809. if (direction > 0)
  810. rc = SymGetSymNext64(gHP, sym);
  811. else
  812. rc = SymGetSymPrev64(gHP, sym);
  813. if (rc && gDisplay)
  814. dumpsym(sym);
  815. free(sym);
  816. return true;
  817. #else
  818. BOOL rc;
  819. PIMAGEHLP_SYMBOL sym;
  820. DWORD64 addr;
  821. char name[MAX_STR];
  822. DWORD disp;
  823. sym = malloc(SYM_BUFFER_SIZE);
  824. if (!sym)
  825. return false;
  826. sym->MaxNameLength = MAX_STR;
  827. addr = sz2addr(param);
  828. if (!addr)
  829. rc = SymGetSymFromName(gHP, param, sym);
  830. else
  831. rc = SymGetSymFromAddr(gHP, (DWORD)addr, &disp, sym);
  832. if (rc) {
  833. if (direction > 0)
  834. rc = SymGetSymNext(gHP, sym);
  835. else
  836. rc = SymGetSymPrev(gHP, sym);
  837. if (rc & gDisplay)
  838. dumpsym32(sym);
  839. }
  840. free(sym);
  841. return true;
  842. #endif
  843. }
  844. BOOL fnNext(char *param)
  845. {
  846. return fnNextPrev(1, param);
  847. }
  848. BOOL fnPrev(char *param)
  849. {
  850. return fnNextPrev(-1, param);
  851. }
  852. BOOL fnBase(char *param)
  853. {
  854. BOOL rc;
  855. PIMAGEHLP_SYMBOL64 sym;
  856. DWORD64 addr;
  857. DWORD64 disp;
  858. addr = sz2addr(param);
  859. if (!addr)
  860. {
  861. pprintf("base <address> : sets the base address for module loads\n");
  862. return true;
  863. }
  864. gDefaultBase = addr;
  865. gDefaultBaseForVirtualMods = addr;
  866. if (gBase)
  867. fnLoad(gImageName);
  868. return true;
  869. }
  870. BOOL fnLine(char *param)
  871. {
  872. char *file;
  873. DWORD linenum;
  874. BOOL rc;
  875. IMAGEHLP_LINE64 line;
  876. LONG disp;
  877. if (!param || !*param)
  878. return true;
  879. file = param;
  880. while (*param != ':') {
  881. if (!*param)
  882. return true;
  883. param++;
  884. }
  885. *param++ = 0;
  886. linenum = atoi(param);
  887. if (!linenum)
  888. return true;
  889. memset(&line, 0, sizeof(line));
  890. line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
  891. rc = SymGetLineFromName64(gHP,
  892. gModName,
  893. file,
  894. linenum,
  895. &disp,
  896. &line);
  897. if (!rc) {
  898. pprintf("line: error 0x%x looking for %s#%d\n",
  899. GetLastError(),
  900. file,
  901. linenum);
  902. return true;
  903. }
  904. pprintf("file : %s\n", line.FileName);
  905. pprintf("line : %d\n", linenum);
  906. pprintf("addr : %s\n", dispaddr(line.Address));
  907. pprintf("disp : %x\n", disp);
  908. return true;
  909. }
  910. BOOL fnSymInfo(char *param)
  911. {
  912. DBH_MODSYMINFO msi;
  913. if (!gBase)
  914. return true;
  915. msi.function = dbhModSymInfo;
  916. msi.sizeofstruct = sizeof(msi);
  917. msi.addr = gBase;
  918. if (!dbghelp(gHP, (PVOID)&msi))
  919. pprintf("error grabbing symbol info\n");
  920. pprintf("%s: symtype=%x, src=%s\n", gModName, msi.type, msi.file);
  921. return true;
  922. }
  923. BOOL fnDiaVer(char *param)
  924. {
  925. DBH_DIAVERSION dv;
  926. dv.function = dbhDiaVersion;
  927. dv.sizeofstruct = sizeof(dv);
  928. if (!dbghelp(0, (PVOID)&dv))
  929. pprintf("error grabbing dia version info\n");
  930. pprintf("DIA version %d\n", dv.ver);
  931. return true;
  932. }
  933. BOOL fnUndec(char *param)
  934. {
  935. DWORD rc;
  936. char uname[MAX_SYM_NAME + 1];
  937. if (!param || !*param)
  938. {
  939. pprintf("undec <symbolname> - undecorates a C++ mangled symbol name\n");
  940. return true;
  941. }
  942. rc = UnDecorateSymbolName(param, uname, MAX_SYM_NAME, UNDNAME_COMPLETE);
  943. if (!rc) {
  944. pprintf("error 0x%u undecorating %s\n", GetLastError(), param);
  945. } else {
  946. pprintf("%s = %s\n", param, uname);
  947. }
  948. return true;
  949. }
  950. BOOL fnFindFile(char *param)
  951. {
  952. DWORD rc;
  953. char root[MAX_PATH + 1];
  954. char file[MAX_PATH + 1];
  955. char found[MAX_PATH + 1];
  956. if (!param)
  957. {
  958. pprintf("ff <root path> <file name> - finds file in path\n");
  959. return true;
  960. }
  961. rc = sscanf(param, "%s %s", root, file);
  962. if ((rc < 2) || !*root || !*file)
  963. {
  964. pprintf("ff <root path> <file name> - finds file in path\n");
  965. return true;
  966. }
  967. *found = 0;
  968. rc = SearchTreeForFile(root, file, found);
  969. if (!rc) {
  970. pprintf("error 0x%u looking for %s\n", GetLastError(), file);
  971. } else {
  972. pprintf("found %s\n", found);
  973. }
  974. return true;
  975. }
  976. BOOL fnAdd(char *param)
  977. {
  978. BOOL rc;
  979. DWORD64 addr;
  980. DWORD size;
  981. char *p;
  982. char name[MAX_STR];
  983. char *n;
  984. if (!param || !*param) {
  985. pprintf("add <name address> : must specify a symbol name and address.\n");
  986. return true;
  987. }
  988. p = param;
  989. while (isspace(*p)) p++;
  990. *name = 0;
  991. for (n = name; *p; p++, n++) {
  992. if (isspace(*p)) {
  993. *n = 0;
  994. break;
  995. }
  996. *n = *p;
  997. }
  998. addr = 0;
  999. size = 0;
  1000. while (isspace(*p)) p++;
  1001. if (*(p + 1) == 'x' || *(p + 1) == 'X')
  1002. p += 2;
  1003. rc = sscanf(p, "%I64x %x", &addr, &size);
  1004. if ((rc < 2) || !addr || !*name)
  1005. {
  1006. pprintf("add <name address> : must specify a symbol name and address.\n");
  1007. return true;
  1008. }
  1009. rc = SymAddSymbol(gHP, 0, name, addr, size, 0);
  1010. if (!rc)
  1011. pprintf("Error 0x%x trying to add symbol\n", GetLastError());
  1012. return true;
  1013. }
  1014. BOOL fnDelete(char *param)
  1015. {
  1016. BOOL rc;
  1017. DWORD64 addr;
  1018. DWORD err;
  1019. char *name = NULL;
  1020. if (!param || !*param) {
  1021. pprintf("del <name/address> : must specify a symbol name or address to delete.\n");
  1022. return true;
  1023. }
  1024. addr = sz2addr(param);
  1025. if (!addr)
  1026. name = param;
  1027. rc = SymDeleteSymbol(gHP, 0, name, addr, 0);
  1028. if (!rc) {
  1029. err = GetLastError();
  1030. if (err == ERROR_NOT_FOUND)
  1031. pprintf("Couldn't find %s to delete.\n", param);
  1032. else
  1033. pprintf("Error 0x%x trying to delete symbol\n", err);
  1034. }
  1035. return true;
  1036. }
  1037. BOOL fnSymbolServer(char *param)
  1038. {
  1039. DWORD opt = 0;
  1040. DWORD data = 0;
  1041. // initialize server, if needed
  1042. if (ghSrv == (HINSTANCE)INVALID_HANDLE_VALUE)
  1043. return false;
  1044. if (!ghSrv) {
  1045. ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  1046. ghSrv = LoadLibrary("symsrv.dll");
  1047. if (ghSrv) {
  1048. gfnSymbolServer = (PSYMBOLSERVERPROC)GetProcAddress(ghSrv, "SymbolServer");
  1049. if (!gfnSymbolServer) {
  1050. FreeLibrary(ghSrv);
  1051. ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  1052. }
  1053. gfnSymbolServerClose = (PSYMBOLSERVERCLOSEPROC)GetProcAddress(ghSrv, "SymbolServerClose");
  1054. gfnSymbolServerSetOptions = (PSYMBOLSERVERSETOPTIONSPROC)GetProcAddress(ghSrv, "SymbolServerSetOptions");
  1055. gfnSymbolServerGetOptions = (PSYMBOLSERVERGETOPTIONSPROC)GetProcAddress(ghSrv, "SymbolServerGetOptions");
  1056. } else {
  1057. ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  1058. }
  1059. }
  1060. // bail, if we have no valid server
  1061. if (ghSrv == INVALID_HANDLE_VALUE) {
  1062. pprintf("SymSrv load failure.\n");
  1063. return false;
  1064. }
  1065. if (param) {
  1066. if (sscanf(param, "%x %x", &opt, &data) > 0)
  1067. {
  1068. if (opt)
  1069. gfnSymbolServerSetOptions(opt, data);
  1070. }
  1071. }
  1072. opt = (DWORD)gfnSymbolServerGetOptions();
  1073. pprintf("SYMSRV options: 0x%x\n", opt);
  1074. return true;
  1075. }
  1076. char *GetParameters(char *cmd)
  1077. {
  1078. char *p = cmd;
  1079. char *param = NULL;
  1080. while (*p++)
  1081. {
  1082. if (isspace(*p))
  1083. {
  1084. *p++ = 0;
  1085. return *p ? p : NULL;
  1086. }
  1087. }
  1088. return NULL;
  1089. }
  1090. void prompt()
  1091. {
  1092. if (!*gModName)
  1093. pprintf("dbh: ");
  1094. else
  1095. pprintf("%s [%I64x]: ", gModName, gBase);
  1096. }
  1097. int InputLoop()
  1098. {
  1099. char cmd[MAX_STR + 1];
  1100. char *params;
  1101. int i;
  1102. BOOL rc;
  1103. pprintf("\n");
  1104. do
  1105. {
  1106. prompt();
  1107. if (!fgets(cmd, sizeof(cmd), stdin))
  1108. return 0;
  1109. params = GetParameters(cmd);
  1110. for (i = 0; i < cmdMax; i++)
  1111. {
  1112. if (!_strcmpi(cmd, gCmd[i].token) ||
  1113. !_strcmpi(cmd, gCmd[i].shorttoken))
  1114. break;
  1115. }
  1116. if (i == cmdMax)
  1117. {
  1118. pprintf("[%s] is an unrecognized command.\n", cmd);
  1119. rc = true;
  1120. continue;
  1121. }
  1122. else
  1123. rc = gCmd[i].fn(params);
  1124. } while (rc);
  1125. return 0;
  1126. }
  1127. BOOL init()
  1128. {
  1129. int i;
  1130. BOOL rc;
  1131. *gModName = 0;
  1132. gBase = 0;;
  1133. gDefaultBaseForVirtualMods = 0x1000000;
  1134. pprintf("dbh: initializing...\n");
  1135. i = GetEnvironmentVariable("_NT_SYMBOL_PATH", gSymbolSearchPath, MAX_STR);
  1136. if (i < 1)
  1137. *gSymbolSearchPath = 0;
  1138. pprintf("Symbol Path = [%s]\n", gSymbolSearchPath);
  1139. gHP = GetCurrentProcess();
  1140. rc = SymInitialize(gHP, gSymbolSearchPath, false);
  1141. if (!rc)
  1142. {
  1143. pprintf("error 0x%x from SymInitialize()\n", GetLastError());
  1144. return rc;
  1145. }
  1146. rc = SymInitialize(gHP, gSymbolSearchPath, false);
  1147. if (!rc)
  1148. {
  1149. pprintf("error 0x%x from SymInitialize()\n", GetLastError());
  1150. return rc;
  1151. }
  1152. gOptions = SymSetOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_NO_PUBLICS | SYMOPT_DEBUG);
  1153. pprintf("SymOpts = 0x%x\n", gOptions);
  1154. rc = SymRegisterCallback64(gHP, cbSymbol, 0);
  1155. if (!rc)
  1156. {
  1157. pprintf("error 0x%x from SymRegisterCallback64()\n", GetLastError());
  1158. return rc;
  1159. }
  1160. return rc;
  1161. }
  1162. void cleanup()
  1163. {
  1164. int i;
  1165. fnUnload(NULL);
  1166. for (i = 0; i < 50; i++)
  1167. SymCleanup(gHP);
  1168. }
  1169. BOOL cmdline(int argc, char *argv[])
  1170. {
  1171. int i;
  1172. char *p;
  1173. for (i = 1; i < argc; i++)
  1174. {
  1175. p = argv[i];
  1176. switch (*p)
  1177. {
  1178. case '/':
  1179. case '-':
  1180. p++;
  1181. switch (tolower(*p))
  1182. {
  1183. case 's':
  1184. gDisplay = false;
  1185. break;
  1186. default:
  1187. pprintf("%s is an unknown switch\n", argv[i]);
  1188. break;
  1189. }
  1190. break;
  1191. default:
  1192. if (!fnLoad(argv[i]))
  1193. return false;
  1194. break;
  1195. }
  1196. }
  1197. return true;
  1198. }
  1199. #include <crtdbg.h>
  1200. __cdecl
  1201. main(
  1202. int argc,
  1203. char *argv[],
  1204. char *envp[]
  1205. )
  1206. {
  1207. DWORD rc = 0;
  1208. _CrtSetDbgFlag( ( _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF ) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG ) );
  1209. if (!init())
  1210. return 1;
  1211. if (!cmdline(argc, argv))
  1212. return 1;
  1213. fnEnum("*");
  1214. #if 1
  1215. fnEnumSrcFiles("*");
  1216. #endif
  1217. cleanup();
  1218. dprintf("%d symbols enumerated.\n", gcEnum);
  1219. dprintf("%d symbols searched by address.\n", gcAddr);
  1220. _CrtDumpMemoryLeaks();
  1221. return rc;
  1222. }