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.

1381 lines
30 KiB

  1. /*
  2. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  4. * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. * PARTICULAR PURPOSE.
  6. *
  7. * Copyright (C) 2002. Microsoft Corporation. All rights reserved.
  8. *
  9. * dbh.c
  10. *
  11. * This file implements a command line utility that shows how to
  12. * use the dbghelp API to query symbolic information from an image
  13. * or pdb file.
  14. *
  15. * Requires dbghelp.dll version 6.1 or greater.
  16. */
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <malloc.h>
  21. #include <assert.h>
  22. #include <dbghelp.h>
  23. #include <strsafe.h>
  24. // general #defines
  25. #define DIMAT(Array, EltType) (sizeof(Array) / sizeof(EltType))
  26. #define DIMA(Array) DIMAT(Array, (Array)[0])
  27. #ifndef true
  28. #define true TRUE
  29. #define false FALSE
  30. #endif
  31. #define MAX_STR 256
  32. #define WILD_UNDERSCORE 1
  33. #define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME)
  34. #define SI_BUFFER_SIZE (sizeof(SYMBOL_INFO) + MAX_SYM_NAME)
  35. // for calling SymEnumSymbols
  36. typedef struct {
  37. char mask[MAX_STR];
  38. DWORD64 base;
  39. } ENUMSYMDATA, *PENUMSYMDATA;
  40. // available commands
  41. typedef enum
  42. {
  43. cmdQuit = 0,
  44. cmdHelp,
  45. cmdVerbose,
  46. cmdLoad,
  47. cmdUnload,
  48. cmdEnum,
  49. cmdName,
  50. cmdAddr,
  51. cmdBase,
  52. cmdNext,
  53. cmdPrev,
  54. cmdLine,
  55. cmdLineNext,
  56. cmdLinePrev,
  57. cmdUndec,
  58. cmdFindFile,
  59. cmdAdd,
  60. cmdDelete,
  61. cmdEnumForAddr,
  62. cmdLocals,
  63. cmdType,
  64. cmdInfo,
  65. cmdMax
  66. };
  67. // this struct associates commands with functions
  68. typedef BOOL (*CMDPROC)(char *params);
  69. typedef struct _CMD
  70. {
  71. char token[MAX_STR + 1];
  72. char shorttoken[4];
  73. CMDPROC fn;
  74. } CMD, *PCMD;
  75. // and here are the functions
  76. BOOL fnQuit(char *);
  77. BOOL fnHelp(char *);
  78. BOOL fnVerbose(char *);
  79. BOOL fnLoad(char *);
  80. BOOL fnUnload(char *);
  81. BOOL fnEnum(char *);
  82. BOOL fnName(char *);
  83. BOOL fnAddr(char *);
  84. BOOL fnBase(char *);
  85. BOOL fnNext(char *);
  86. BOOL fnPrev(char *);
  87. BOOL fnLine(char *);
  88. BOOL fnLineNext(char *);
  89. BOOL fnLinePrev(char *);
  90. BOOL fnUndec(char *);
  91. BOOL fnFindFile(char *);
  92. BOOL fnAdd(char *);
  93. BOOL fnDelete(char *);
  94. BOOL fnEnumForAddr(char *);
  95. BOOL fnLocals(char *);
  96. BOOL fnType(char *);
  97. BOOL fnInfo(char *);
  98. // array of command structs
  99. CMD gCmd[cmdMax] =
  100. {
  101. {"addr", "a", fnAddr},
  102. {"base", "b", fnBase},
  103. // {"", "c", fn},
  104. // {"", "d", fn},
  105. // {"elines", "e", fnEnumLines},
  106. {"ff", "f", fnFindFile},
  107. // {"", "g", fn},
  108. // {"", "h", fn},
  109. {"info", "i", fnInfo},
  110. {"linenext","j", fnLineNext},
  111. {"lineprev","k", fnLinePrev},
  112. {"line", "l", fnLine},
  113. {"enumaddr","m", fnEnumForAddr},
  114. {"name", "n", fnName},
  115. // {"obj", "o", fnObj},
  116. {"prev", "p", fnPrev},
  117. {"quit", "q", fnQuit},
  118. // {"src", "r", fnEnumSrcFiles},
  119. {"next", "s", fnNext},
  120. {"type", "t", fnType},
  121. {"unload", "u", fnUnload},
  122. {"verbose", "v", fnVerbose},
  123. // {"", "w", fn},
  124. {"enum", "x", fnEnum},
  125. // {"ss", "y", fnSymbolServer},
  126. {"locals", "z", fnLocals},
  127. {"add", "+", fnAdd},
  128. {"del", "-", fnDelete},
  129. {"help", "?", fnHelp},
  130. {"undec", "", fnUndec},
  131. {"load", "", fnLoad},
  132. // {"map", "", fnMap},
  133. // {"multi", "", fnMulti},
  134. // {"etag", "", fnEnumTag},
  135. };
  136. // globals
  137. char gModName[MAX_STR] = "";
  138. char gImageName[MAX_STR];
  139. char gSymbolSearchPath[MAX_STR];
  140. DWORD64 gBase;
  141. DWORD64 gDefaultBase;
  142. DWORD64 gDefaultBaseForVirtualMods;
  143. DWORD gOptions;
  144. HANDLE gTID;
  145. IMAGEHLP_LINE64 gLine;
  146. char gExecCmd[MAX_STR] = "";
  147. char gSrcFileName[MAX_PATH + 1] = "";
  148. char gObj[MAX_PATH + 1] = "";
  149. // Use this to display verbose information, when
  150. // the -v switch is used.
  151. int
  152. dprintf(
  153. LPSTR Format,
  154. ...
  155. )
  156. {
  157. static char buf[1000] = "";
  158. va_list args;
  159. if ((gOptions & SYMOPT_DEBUG) == 0)
  160. return 1;
  161. va_start(args, Format);
  162. StringCchVPrintf(buf, DIMA(buf), Format, args);
  163. va_end(args);
  164. fputs(buf, stdout);
  165. return 1;
  166. }
  167. __inline int ucase(int c)
  168. {
  169. return (gOptions & SYMOPT_CASE_INSENSITIVE) ? toupper(c) : c;
  170. }
  171. #define MAX_FORMAT_STRINGS 8
  172. char *
  173. _dispaddr(
  174. ULONG64 addr,
  175. BOOL pad
  176. )
  177. {
  178. static char sz[20];
  179. if ((addr >> 32) != 0)
  180. StringCchPrintf(sz, DIMA(sz), "%8x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  181. else
  182. StringCchPrintf(sz, DIMA(sz), pad ? " %8x" : "%8x", (ULONG)addr);
  183. return sz;
  184. }
  185. #define dispaddr(addr) _dispaddr(addr, false)
  186. BOOL
  187. validnum(
  188. char *sz
  189. )
  190. {
  191. int c;
  192. for (; *sz; sz++)
  193. {
  194. c = tolower(*sz);
  195. if (c >= '0' && c <= '9')
  196. continue;
  197. if (c >= 'a' && c <= 'f')
  198. continue;
  199. return false;
  200. }
  201. return true;
  202. }
  203. DWORD64
  204. sz2addr(
  205. char *sz
  206. )
  207. {
  208. char *p;
  209. DWORD64 addr = 0;
  210. if (sz && *sz)
  211. {
  212. p = sz;
  213. if (*(p + 1) == 'x' || *(p + 1) == 'X')
  214. p += 2;
  215. if (!validnum(p))
  216. return 0;
  217. if (sscanf(p, "%I64x", &addr) < 1)
  218. return 0;
  219. }
  220. return addr;
  221. }
  222. void _dumpsym(
  223. PIMAGEHLP_SYMBOL64 sym,
  224. BOOL pad
  225. )
  226. {
  227. printf(" name : %s\n", sym->Name);
  228. printf(" addr : %s\n", _dispaddr(sym->Address, pad));
  229. printf(" size : %x\n", sym->Size);
  230. printf("flags : %x\n", sym->Flags);
  231. }
  232. #define dumpsym(sym) _dumpsym(sym, false)
  233. void dumpsym32(
  234. PIMAGEHLP_SYMBOL sym
  235. )
  236. {
  237. printf(" name : %s\n", sym->Name);
  238. printf(" addr : %s\n", dispaddr(sym->Address));
  239. printf(" size : %x\n", sym->Size);
  240. printf("flags : %x\n", sym->Flags);
  241. }
  242. void dumpLine(
  243. PIMAGEHLP_LINE64 line
  244. )
  245. {
  246. printf("file : %s\n", line->FileName);
  247. printf("line : %d\n", line->LineNumber);
  248. printf("addr : %s\n", dispaddr(line->Address));
  249. }
  250. #ifndef _WIN64
  251. void dumpdbi(
  252. PIMAGE_DEBUG_INFORMATION dbi
  253. )
  254. {
  255. printf(" List : 0x%x\n", dbi->List);
  256. printf(" ImageBase : 0x%x\n", dbi->ImageBase);
  257. printf(" SizeOfImage : 0x%x\n", dbi->SizeOfImage);
  258. printf(" SizeOfCoffSymbols : 0x%x\n", dbi->SizeOfCoffSymbols);
  259. printf(" CoffSymbols : 0x%x\n", dbi->CoffSymbols);
  260. printf(" ImageFilePath : %s\n", dbi->ImageFilePath);
  261. printf(" ImageFileName : %s\n", dbi->ImageFileName);
  262. }
  263. #endif
  264. // This stuff displays the symbol tag descriptions.
  265. #ifndef SymTagMax
  266. // normally found in cvconst.h which ships with Visual Studio
  267. #define SymTagMax 0x1f
  268. #endif
  269. char* g_SymTagNames[] =
  270. {
  271. "SymTagNull",
  272. "SymTagExe",
  273. "SymTagCompiland",
  274. "SymTagCompilandDetails",
  275. "SymTagCompilandEnv",
  276. "SymTagFunction",
  277. "SymTagBlock",
  278. "SymTagData",
  279. "SymTagAnnotation",
  280. "SymTagLabel",
  281. "SymTagPublicSymbol",
  282. "SymTagUDT",
  283. "SymTagEnum",
  284. "SymTagFunctionType",
  285. "SymTagPointerType",
  286. "SymTagArrayType",
  287. "SymTagBaseType",
  288. "SymTagTypedef",
  289. "SymTagBaseClass",
  290. "SymTagFriend",
  291. "SymTagFunctionArgType",
  292. "SymTagFuncDebugStart",
  293. "SymTagFuncDebugEnd",
  294. "SymTagUsingNamespace",
  295. "SymTagVTableShape",
  296. "SymTagVTable",
  297. "SymTagCustom",
  298. "SymTagThunk",
  299. "SymTagCustomType",
  300. "SymTagManagedType",
  301. "SymTagDimension",
  302. };
  303. char* dispsymtag(
  304. ULONG symtag
  305. )
  306. {
  307. if (symtag >= SymTagMax) {
  308. return "<Invalid>";
  309. } else {
  310. return g_SymTagNames[symtag];
  311. }
  312. }
  313. void dumpsi(
  314. PSYMBOL_INFO si
  315. )
  316. {
  317. printf(" name : %s\n", si->Name);
  318. printf(" addr : %s\n", dispaddr(si->Address));
  319. printf(" size : %x\n", si->Size);
  320. printf(" flags : %x\n", si->Flags);
  321. printf(" type : %x\n", si->TypeIndex);
  322. printf("modbase : %s\n", dispaddr(si->ModBase));
  323. printf(" value : %s\n", dispaddr(si->Value));
  324. printf(" reg : %x\n", si->Register);
  325. printf(" scope : %s (%x)\n", dispsymtag(si->Scope), si->Scope);
  326. printf(" tag : %s (%x)\n", dispsymtag(si->Tag), si->Tag);
  327. }
  328. BOOL
  329. CALLBACK
  330. cbEnumSymbols(
  331. PSYMBOL_INFO si,
  332. ULONG size,
  333. PVOID context
  334. )
  335. {
  336. PENUMSYMDATA esd = (PENUMSYMDATA)context;
  337. printf(" %8s : ", _dispaddr(si->Address, true));
  338. if (si->Flags & SYMF_FORWARDER)
  339. printf("%c ", 'F');
  340. else if (si->Flags & SYMF_EXPORT)
  341. printf("%c ", 'E');
  342. else
  343. printf(" ");
  344. printf("%s\n", si->Name);
  345. return true;
  346. }
  347. BOOL
  348. cbSrcFiles(
  349. PSOURCEFILE pSourceFile,
  350. PVOID UserContext
  351. )
  352. {
  353. if (!pSourceFile)
  354. return false;
  355. printf("%s\n", pSourceFile->FileName);
  356. return true;
  357. }
  358. BOOL
  359. CALLBACK
  360. cbSymbol(
  361. HANDLE hProcess,
  362. ULONG ActionCode,
  363. ULONG64 CallbackData,
  364. ULONG64 UserContext
  365. )
  366. {
  367. PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
  368. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64) CallbackData;
  369. switch ( ActionCode )
  370. {
  371. case CBA_DEBUG_INFO:
  372. printf("%s", (LPSTR)CallbackData);
  373. break;
  374. default:
  375. return false;
  376. }
  377. return false;
  378. }
  379. // exit this program
  380. BOOL fnQuit(char *param)
  381. {
  382. printf("goodbye\n");
  383. return false;
  384. }
  385. // display command help
  386. BOOL fnHelp(char *param)
  387. {
  388. printf(" dbh commands :\n");
  389. printf("? help : prints this message\n");
  390. printf("q quit : quits this program\n");
  391. printf("v verbose <on/off> : controls debug spew\n");
  392. printf(" load <modname> : loads the requested module\n");
  393. printf("u unload : unloads the current module\n");
  394. printf("x enum <mask> : enumerates all matching symbols\n");
  395. printf("n name <symname> : finds a symbol by it's name\n");
  396. printf("a addr <addr> : finds a symbol by it's hex address\n");
  397. printf("m enumaddr <addr> : lists all symbols with a certain hex address\n");
  398. printf("b base <address> : sets the new default base address\n");
  399. printf("s next <add/nam> : finds the symbol after the passed sym\n");
  400. printf("p prev <add/nam> : finds the symbol before the passed sym\n");
  401. printf("l line <file:#> : finds the matching line number\n");
  402. printf("j linenext : goes to the next line after the current\n");
  403. printf("k lineprev : goes to the line previous to the current\n");
  404. printf("f ff <path> <file> : finds file in path\n");
  405. printf("+ add <name addr> : adds symbols with passed name and address\n");
  406. printf("- del <name/addr> : deletes symbols with passed name or address\n");
  407. printf("m enumaddr <addr> : enum all symbols for address\n");
  408. printf("z locals <name> : enum all scoped symbols for a named function\n");
  409. printf("t type <name> : lists the type information for the symbol\n");
  410. printf("i info : displays information about the loaded module\n");
  411. printf(" undec <name> : undecorates a given symbol name\n");
  412. return true;
  413. }
  414. // display debug spew from debughlp
  415. BOOL fnVerbose(char *param)
  416. {
  417. int opts = gOptions;
  418. if (!param || !*param)
  419. printf("");
  420. else if (!_strcmpi(param, "on"))
  421. opts |= SYMOPT_DEBUG;
  422. else if (!_strcmpi(param, "off"))
  423. opts = gOptions & ~SYMOPT_DEBUG;
  424. else
  425. printf("verbose <on//off>\n");
  426. gOptions = SymSetOptions(opts);
  427. printf("verbose mode %s.\n", gOptions & SYMOPT_DEBUG ? "on" : "off");
  428. return true;
  429. }
  430. // load an image
  431. BOOL fnLoad(char *param)
  432. {
  433. char ext[MAX_STR];
  434. char mod[MAX_STR];
  435. DWORD flags = 0;
  436. DWORD64 addr = 0;
  437. DWORD size = 0x1000000;
  438. HANDLE hf = NULL;
  439. BOOL dontopen = false;
  440. if (!*param)
  441. {
  442. printf("load <modname> - you must specify a module to load\n");
  443. return true;
  444. }
  445. _splitpath(param, NULL, NULL, mod, ext);
  446. if (!*ext) {
  447. flags = SLMFLAG_VIRTUAL;
  448. addr = gDefaultBaseForVirtualMods;
  449. } else if (!_strcmpi(ext, ".pdb")) {
  450. addr = gDefaultBaseForVirtualMods;
  451. dontopen = true;
  452. } else {
  453. addr = gDefaultBase;
  454. }
  455. fnUnload(NULL);
  456. StringCchCopy(gModName, DIMA(gModName), mod);
  457. // you can do this with or without an open file handle
  458. if (!dontopen) {
  459. hf = CreateFile(param,
  460. GENERIC_READ,
  461. 0,
  462. NULL,
  463. OPEN_EXISTING,
  464. 0,
  465. 0);
  466. size = GetFileSize(hf, NULL);
  467. }
  468. addr = SymLoadModuleEx(gTID,
  469. hf, // hFile,
  470. param, // ImageName,
  471. mod, // ModuleName,
  472. addr, // BaseOfDll,
  473. size, // SizeOfDll
  474. NULL, // Data
  475. flags); // Flags
  476. if (!addr)
  477. {
  478. *gModName = 0;
  479. printf("error 0x%x loading %s.\n", GetLastError(), param);
  480. return true;
  481. }
  482. StringCchCopy(gImageName, DIMA(gImageName), param);
  483. gBase = addr;
  484. if (hf != INVALID_HANDLE_VALUE)
  485. CloseHandle(hf);
  486. return true;
  487. }
  488. // unload the image
  489. BOOL fnUnload(char *param)
  490. {
  491. if (!gBase)
  492. return true;
  493. if (!SymUnloadModule64(gTID, gBase))
  494. printf("error unloading %s at %s\n", gModName, dispaddr(gBase));
  495. gBase = 0;
  496. *gModName = 0;
  497. return true;
  498. }
  499. // enumerate the symbols
  500. BOOL fnEnum(char *param)
  501. {
  502. BOOL rc;
  503. ENUMSYMDATA esd;
  504. esd.base = gBase;
  505. StringCchCopy(esd.mask, MAX_STR, param ? param : "");
  506. rc = SymEnumSymbols(gTID, gBase, param, cbEnumSymbols, &esd);
  507. if (!rc)
  508. printf("error 0x%x calling SymEnumSymbols()\n", GetLastError());
  509. return true;
  510. }
  511. // search for a symbol by name
  512. BOOL fnName(char *param)
  513. {
  514. SYMBOL_INFO_PACKAGE sip; // this struct saves allocation code
  515. char name[MAX_STR];
  516. if (!param || !*param)
  517. {
  518. printf("name <symbolname> - finds a symbol by it's name\n");
  519. return true;
  520. }
  521. StringCchPrintf(name, DIMA(name), "%s!%s", gModName, param);
  522. ZeroMemory(&sip, sizeof(sip));
  523. sip.si.MaxNameLen = MAX_SYM_NAME;
  524. if (SymFromName(gTID, name, &sip.si))
  525. dumpsi(&sip.si);
  526. return true;
  527. }
  528. // search for a symbol by address
  529. BOOL fnAddr(char *param)
  530. {
  531. BOOL rc;
  532. DWORD64 addr;
  533. DWORD64 disp;
  534. PSYMBOL_INFO si;
  535. addr = sz2addr(param);
  536. if (!addr)
  537. {
  538. printf("addr <address> : finds a symbol by it's hex address\n");
  539. return true;
  540. }
  541. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  542. if (!si)
  543. return false;
  544. ZeroMemory(si, SI_BUFFER_SIZE);
  545. si->MaxNameLen = MAX_SYM_NAME;
  546. rc = SymFromAddr(gTID, addr, &disp, si);
  547. if (rc)
  548. {
  549. printf("%s", si->Name);
  550. if (disp)
  551. printf("+%I64x", disp);
  552. printf("\n");
  553. dumpsi(si);
  554. }
  555. free(si);
  556. return true;
  557. }
  558. // enumerate all symbols with the passed address
  559. BOOL fnEnumForAddr(char *param)
  560. {
  561. BOOL rc;
  562. DWORD64 addr;
  563. ENUMSYMDATA esd;
  564. addr = sz2addr(param);
  565. if (!addr)
  566. {
  567. printf("enumaddr <addr> : lists all symbols with a certain hex address\n");
  568. return true;
  569. }
  570. esd.base = gBase;
  571. StringCchCopy(esd.mask, MAX_STR, "");
  572. rc = SymEnumSymbolsForAddr(gTID, addr, cbEnumSymbols, &esd);
  573. if (!rc)
  574. printf("error 0x%0 calling SymEnumSymbolsForAddr()\n", GetLastError());
  575. return true;
  576. }
  577. // find locals for passed symbol
  578. BOOL fnLocals(char *param)
  579. {
  580. PSYMBOL_INFO si;
  581. char name[MAX_STR];
  582. IMAGEHLP_STACK_FRAME frame;
  583. ENUMSYMDATA esd;
  584. if (!param || !*param)
  585. {
  586. printf("locals <symbolname> - finds all locals a function\n");
  587. return true;
  588. }
  589. StringCchPrintf(name, DIMA(name), "%s!%s", gModName, param);
  590. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  591. if (!si)
  592. return false;
  593. ZeroMemory(si, SI_BUFFER_SIZE);
  594. si->MaxNameLen = MAX_SYM_NAME;
  595. if (!SymFromName(gTID, name, si))
  596. goto exit;
  597. printf("dumping locals for %s...\n", si->Name);
  598. ZeroMemory(&frame, sizeof(frame));
  599. frame.InstructionOffset = si->Address;
  600. SymSetContext(gTID, &frame, NULL);
  601. esd.base = gBase;
  602. StringCchCopy(esd.mask, MAX_STR, "*");
  603. if (!SymEnumSymbols(gTID, 0, esd.mask, cbEnumSymbols, &esd))
  604. printf("error 0x%0 calling SymEnumSymbols()\n", GetLastError());
  605. exit:
  606. free(si);
  607. return true;
  608. }
  609. // obtain simple type information
  610. BOOL fnType(char *param)
  611. {
  612. PSYMBOL_INFO si;
  613. if (!param || !*param)
  614. {
  615. printf("type <typename> - finds type info\n");
  616. return true;
  617. }
  618. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  619. if (!si)
  620. return false;
  621. ZeroMemory(si, SI_BUFFER_SIZE);
  622. si->MaxNameLen = MAX_SYM_NAME;
  623. if (SymGetTypeFromName(gTID, gBase, param, si))
  624. dumpsi(si);
  625. free(si);
  626. return true;
  627. }
  628. // get module information
  629. BOOL fnInfo(char *param)
  630. {
  631. IMAGEHLP_MODULE64 mi;
  632. static char *symtypes[NumSymTypes] =
  633. {
  634. "SymNone",
  635. "SymCoff",
  636. "SymCv",
  637. "SymPdb",
  638. "SymExport",
  639. "SymDeferred",
  640. "SymSym",
  641. "SymDia",
  642. "SymVirtual"
  643. };
  644. ZeroMemory((void *)&mi, sizeof(mi));
  645. mi.SizeOfStruct = sizeof(mi);
  646. if (!SymGetModuleInfo64(gTID, gBase, &mi))
  647. {
  648. printf("error 0x%x calling SymGetModuleInfo64()\n", GetLastError());
  649. return true;
  650. }
  651. printf(" SizeOfStruct : 0x%x\n", mi.SizeOfStruct);
  652. printf(" BaseOfImage : 0x%i64x\n", mi.BaseOfImage);
  653. printf(" ImageSize : 0x%x\n", mi.ImageSize);
  654. printf(" TimeDateStamp : 0x%x\n", mi.TimeDateStamp);
  655. printf(" CheckSum : 0x%x\n", mi.CheckSum);
  656. printf(" NumSyms : 0x%x\n", mi.NumSyms);
  657. printf(" SymType : %s\n", symtypes[mi.SymType]);
  658. printf(" ModuleName : %s\n", mi.ModuleName);
  659. printf(" ImageName : %s\n", mi.ImageName);
  660. printf(" LoadedImageName : %s\n", mi.LoadedImageName);
  661. return true;
  662. }
  663. PIMAGEHLP_SYMBOL64 SymbolFromName(char *param)
  664. {
  665. BOOL rc;
  666. PIMAGEHLP_SYMBOL64 sym;
  667. char name[MAX_STR];
  668. if (!name || !*name)
  669. return NULL;
  670. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  671. if (!sym)
  672. return false;
  673. ZeroMemory(sym, SYM_BUFFER_SIZE);
  674. sym->MaxNameLength = MAX_SYM_NAME;
  675. StringCchPrintf(name, DIMA(name), "%s!%s", gModName, param);
  676. rc = SymGetSymFromName64(gTID, name, sym);
  677. if (!rc) {
  678. free(sym);
  679. return NULL;
  680. }
  681. return sym;
  682. }
  683. // worker function for the SymNext and SymPrev stuff
  684. BOOL fnNextPrev(int direction, char *param)
  685. {
  686. BOOL rc;
  687. PIMAGEHLP_SYMBOL64 sym;
  688. DWORD64 addr;
  689. addr = sz2addr(param);
  690. if (!addr)
  691. {
  692. sym = SymbolFromName(param);
  693. if (!sym)
  694. return true;
  695. addr = sym->Address;
  696. if (!addr) {
  697. free(sym);
  698. return true;
  699. }
  700. }
  701. else
  702. {
  703. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  704. if (!sym)
  705. return false;
  706. rc = SymGetSymFromAddr64(gTID, addr, NULL, sym);
  707. if (!rc)
  708. return true;
  709. }
  710. if (direction > 0)
  711. rc = SymGetSymNext64(gTID, sym);
  712. else
  713. rc = SymGetSymPrev64(gTID, sym);
  714. if (rc)
  715. dumpsym(sym);
  716. free(sym);
  717. return true;
  718. }
  719. // find the next symbol
  720. BOOL fnNext(char *param)
  721. {
  722. return fnNextPrev(1, param);
  723. }
  724. // find the previous symbol
  725. BOOL fnPrev(char *param)
  726. {
  727. return fnNextPrev(-1, param);
  728. }
  729. // set the module base and reload, if needed
  730. BOOL fnBase(char *param)
  731. {
  732. DWORD64 addr;
  733. addr = sz2addr(param);
  734. if (!addr)
  735. {
  736. printf("base <address> : sets the base address for module loads\n");
  737. return true;
  738. }
  739. gDefaultBase = addr;
  740. gDefaultBaseForVirtualMods = addr;
  741. if (gBase)
  742. fnLoad(gImageName);
  743. return true;
  744. }
  745. // search for a line by it's name
  746. BOOL fnLine(char *param)
  747. {
  748. char *file;
  749. DWORD linenum;
  750. BOOL rc;
  751. IMAGEHLP_LINE64 line;
  752. LONG disp;
  753. if (!param || !*param)
  754. return true;
  755. file = param;
  756. while (*param != ':') {
  757. if (!*param)
  758. return true;
  759. param++;
  760. }
  761. *param++ = 0;
  762. linenum = atoi(param);
  763. if (!linenum)
  764. return true;
  765. memset(&line, 0, sizeof(line));
  766. line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
  767. rc = SymGetLineFromName64(gTID,
  768. gModName,
  769. file,
  770. linenum,
  771. &disp,
  772. &line);
  773. if (!rc) {
  774. printf("line: error 0x%x looking for %s#%d\n",
  775. GetLastError(),
  776. file,
  777. linenum);
  778. return true;
  779. }
  780. dumpLine(&line);
  781. printf("disp : %x\n", disp);
  782. // save for future next/prev calls
  783. memcpy(&gLine, &line, sizeof(gLine));
  784. return true;
  785. }
  786. // worker function for the LineNext and LinePrev stuff
  787. BOOL lineNextPrev(BOOL prev)
  788. {
  789. BOOL rc;
  790. IMAGEHLP_LINE64 line;
  791. if (!gLine.SizeOfStruct)
  792. return true;
  793. memcpy(&line, &gLine, sizeof(line));
  794. if (prev)
  795. rc = SymGetLinePrev64(gTID, &line);
  796. else
  797. rc = SymGetLineNext64(gTID, &line);
  798. if (!rc) {
  799. printf("line: error 0x%x looking for %s#%d\n",
  800. GetLastError(),
  801. line.FileName,
  802. line.LineNumber);
  803. return true;
  804. }
  805. dumpLine(&line);
  806. // save for future next/prev calls
  807. memcpy(&gLine, &line, sizeof(gLine));
  808. return true;
  809. }
  810. // find the next line
  811. BOOL fnLineNext(char *param)
  812. {
  813. return lineNextPrev(false);
  814. }
  815. // find the previous line
  816. BOOL fnLinePrev(char *param)
  817. {
  818. return lineNextPrev(true);
  819. }
  820. // undecorate a symbol name
  821. BOOL fnUndec(char *param)
  822. {
  823. DWORD rc;
  824. char uname[MAX_SYM_NAME + 1];
  825. if (!param || !*param)
  826. {
  827. printf("undec <symbolname> - undecorates a C++ mangled symbol name\n");
  828. return true;
  829. }
  830. rc = UnDecorateSymbolName(param, uname, MAX_SYM_NAME, UNDNAME_COMPLETE);
  831. if (!rc)
  832. printf("error 0x%u undecorating %s\n", GetLastError(), param);
  833. else
  834. printf("%s =\n%s\n", param, uname);
  835. return true;
  836. }
  837. // search for a file in a tree
  838. BOOL fnFindFile(char *param)
  839. {
  840. DWORD rc;
  841. char root[MAX_PATH + 1];
  842. char file[MAX_PATH + 1];
  843. char found[MAX_PATH + 1];
  844. if (!param)
  845. {
  846. printf("ff <root path> <file name> - finds file in path\n");
  847. return true;
  848. }
  849. rc = sscanf(param, "%s %s", root, file);
  850. if ((rc < 2) || !*root || !*file)
  851. {
  852. printf("ff <root path> <file name> - finds file in path\n");
  853. return true;
  854. }
  855. *found = 0;
  856. rc = SearchTreeForFile(root, file, found);
  857. if (!rc) {
  858. printf("error 0x%u looking for %s\n", GetLastError(), file);
  859. } else {
  860. printf("found %s\n", found);
  861. }
  862. return true;
  863. }
  864. // create a virtual symbol
  865. BOOL fnAdd(char *param)
  866. {
  867. BOOL rc;
  868. DWORD64 addr;
  869. DWORD size;
  870. char *p;
  871. char name[MAX_STR];
  872. char *n;
  873. if (!param || !*param) {
  874. printf("add <name address> : must specify a symbol name, address, and size.\n");
  875. return true;
  876. }
  877. p = param;
  878. while (isspace(*p)) p++;
  879. *name = 0;
  880. for (n = name; *p; p++, n++) {
  881. if (isspace(*p)) {
  882. *n = 0;
  883. break;
  884. }
  885. *n = *p;
  886. }
  887. addr = 0;
  888. size = 0;
  889. while (isspace(*p)) p++;
  890. if (*(p + 1) == 'x' || *(p + 1) == 'X')
  891. p += 2;
  892. rc = sscanf(p, "%I64x %x", &addr, &size);
  893. if ((rc < 2) || !addr || !*name)
  894. {
  895. printf("add <name address> : must specify a symbol name, address, and size.\n");
  896. return true;
  897. }
  898. rc = SymAddSymbol(gTID, 0, name, addr, size, 0);
  899. if (!rc)
  900. printf("Error 0x%x trying to add symbol\n", GetLastError());
  901. return true;
  902. }
  903. // delete a virtual symbol
  904. BOOL fnDelete(char *param)
  905. {
  906. BOOL rc;
  907. DWORD64 addr;
  908. DWORD err;
  909. char *name = NULL;
  910. if (!param || !*param) {
  911. printf("del <name/address> : must specify a symbol name or address to delete.\n");
  912. return true;
  913. }
  914. addr = sz2addr(param);
  915. if (!addr)
  916. name = param;
  917. rc = SymDeleteSymbol(gTID, 0, name, addr, 0);
  918. if (!rc) {
  919. err = GetLastError();
  920. if (err == ERROR_NOT_FOUND)
  921. printf("Couldn't find %s to delete.\n", param);
  922. else
  923. printf("Error 0x%x trying to delete symbol\n", err);
  924. }
  925. return true;
  926. }
  927. // read the command line
  928. char *GetParameters(char *cmd)
  929. {
  930. char *p = cmd;
  931. char *param = NULL;
  932. while (*p++)
  933. {
  934. if (isspace(*p))
  935. {
  936. *p++ = 0;
  937. return *p ? p : NULL;
  938. }
  939. }
  940. return NULL;
  941. }
  942. void prompt()
  943. {
  944. if (!*gModName)
  945. printf("dbh: ");
  946. else
  947. printf("%s [%I64x]: ", gModName, gBase);
  948. }
  949. char *
  950. getstr(
  951. char *buf,
  952. int size
  953. )
  954. {
  955. char *rc;
  956. rc = fgets(buf, size, stdin);
  957. if (!rc)
  958. return 0;
  959. while (*buf)
  960. {
  961. switch (*buf)
  962. {
  963. case 0xa:
  964. *buf = 0;
  965. // pass through
  966. case 0:
  967. return rc;
  968. }
  969. buf++;
  970. }
  971. return rc;
  972. }
  973. int InputLoop()
  974. {
  975. char cmd[MAX_STR + 1];
  976. char *params;
  977. int i;
  978. BOOL rc;
  979. do
  980. {
  981. rc = true;
  982. prompt();
  983. if (*gExecCmd) {
  984. StringCchCopy(cmd, DIMA(cmd), gExecCmd);
  985. printf(cmd);
  986. printf("\n");
  987. } else if (!getstr(cmd, sizeof(cmd)))
  988. return 0;
  989. params = GetParameters(cmd);
  990. for (i = 0; i < cmdMax; i++)
  991. {
  992. if (!_strcmpi(cmd, gCmd[i].token)
  993. || !_strcmpi(cmd, gCmd[i].shorttoken))
  994. {
  995. break;
  996. }
  997. }
  998. if (i == cmdMax)
  999. printf("[%s] is an unrecognized command.\n", cmd);
  1000. else
  1001. rc = gCmd[i].fn(params);
  1002. if (*gExecCmd)
  1003. rc = false;
  1004. } while (rc);
  1005. return 0;
  1006. }
  1007. BOOL init()
  1008. {
  1009. int i;
  1010. BOOL rc;
  1011. *gModName = 0;
  1012. gBase = 0;;
  1013. gDefaultBaseForVirtualMods = 0x1000000;
  1014. gDefaultBase = 0x1000000;
  1015. ZeroMemory(&gLine, sizeof(gLine));
  1016. dprintf("dbh: initializing...\n");
  1017. i = GetEnvironmentVariable("_NT_SYMBOL_PATH", gSymbolSearchPath, MAX_STR);
  1018. if (i < 1)
  1019. *gSymbolSearchPath = 0;
  1020. dprintf("Symbol Path = [%s]\n", gSymbolSearchPath);
  1021. gTID = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
  1022. rc = SymInitialize(gTID, gSymbolSearchPath, false);
  1023. if (!rc)
  1024. {
  1025. printf("error 0x%x from SymInitialize()\n", GetLastError());
  1026. return rc;
  1027. }
  1028. rc = SymInitialize(gTID, gSymbolSearchPath, false);
  1029. if (!rc)
  1030. {
  1031. printf("error 0x%x from SymInitialize()\n", GetLastError());
  1032. return rc;
  1033. }
  1034. gOptions = SymSetOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_AUTO_PUBLICS);
  1035. dprintf("SymOpts = 0x%x\n", gOptions);
  1036. rc = SymRegisterCallback64(gTID, cbSymbol, 0);
  1037. if (!rc)
  1038. {
  1039. printf("error 0x%x from SymRegisterCallback64()\n", GetLastError());
  1040. return rc;
  1041. }
  1042. return rc;
  1043. }
  1044. void cleanup()
  1045. {
  1046. int i;
  1047. fnUnload(NULL);
  1048. for (i = 0; i < 50; i++)
  1049. SymCleanup(gTID);
  1050. }
  1051. BOOL cmdline(int argc, char *argv[])
  1052. {
  1053. int i;
  1054. char *p;
  1055. for (i = 1; i < argc; i++)
  1056. {
  1057. p = argv[i];
  1058. switch (*p)
  1059. {
  1060. case '/':
  1061. case '-':
  1062. p++;
  1063. switch (tolower(*p))
  1064. {
  1065. case 'v':
  1066. fnVerbose("on");
  1067. break;
  1068. default:
  1069. printf("%s is an unknown switch\n", argv[i]);
  1070. break;
  1071. }
  1072. break;
  1073. default:
  1074. if (*gModName) {
  1075. StringCchCat(gExecCmd, DIMA(gExecCmd), argv[i]);
  1076. StringCchCat(gExecCmd, DIMA(gExecCmd), " ");
  1077. } else
  1078. fnLoad(argv[i]);
  1079. break;
  1080. }
  1081. }
  1082. return true;
  1083. }
  1084. #include <crtdbg.h>
  1085. __cdecl
  1086. main(
  1087. int argc,
  1088. char *argv[],
  1089. char *envp[]
  1090. )
  1091. {
  1092. DWORD rc;
  1093. _CrtSetDbgFlag( ( _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF ) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG ) );
  1094. if (!init())
  1095. return 1;
  1096. cmdline(argc, argv);
  1097. rc = InputLoop();
  1098. cleanup();
  1099. _CrtDumpMemoryLeaks();
  1100. return rc;
  1101. }