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.

1724 lines
38 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. cmdEnumSrcFiles,
  60. cmdAdd,
  61. cmdDelete,
  62. cmdSymbolServer,
  63. cmdEnumForAddr,
  64. cmdLocals,
  65. cmdMapDBI,
  66. cmdMulti,
  67. cmdType,
  68. cmdInfo,
  69. cmdObj,
  70. cmdEnumLines,
  71. cmdEnumTag,
  72. cmdMax
  73. };
  74. // this struct associates commands with functions
  75. typedef BOOL (*CMDPROC)(char *params);
  76. typedef struct _CMD
  77. {
  78. char token[MAX_STR + 1];
  79. char shorttoken[4];
  80. CMDPROC fn;
  81. } CMD, *PCMD;
  82. // and here are the functions
  83. BOOL fnQuit(char *);
  84. BOOL fnHelp(char *);
  85. BOOL fnVerbose(char *);
  86. BOOL fnLoad(char *);
  87. BOOL fnUnload(char *);
  88. BOOL fnEnum(char *);
  89. BOOL fnName(char *);
  90. BOOL fnAddr(char *);
  91. BOOL fnBase(char *);
  92. BOOL fnNext(char *);
  93. BOOL fnPrev(char *);
  94. BOOL fnLine(char *);
  95. BOOL fnLineNext(char *);
  96. BOOL fnLinePrev(char *);
  97. BOOL fnUndec(char *);
  98. BOOL fnFindFile(char *);
  99. BOOL fnEnumSrcFiles(char *);
  100. BOOL fnAdd(char *);
  101. BOOL fnDelete(char *);
  102. BOOL fnSymbolServer(char *);
  103. BOOL fnEnumForAddr(char *);
  104. BOOL fnLocals(char *);
  105. BOOL fnMap(char *);
  106. BOOL fnMulti(char *);
  107. BOOL fnType(char *);
  108. BOOL fnInfo(char *);
  109. BOOL fnObj(char *);
  110. BOOL fnEnumLines(char *);
  111. BOOL fnEnumTag(char *);
  112. // array of command structs
  113. CMD gCmd[cmdMax] =
  114. {
  115. {"addr", "a", fnAddr},
  116. {"base", "b", fnBase},
  117. // {"", "c", fn},
  118. // {"", "d", fn},
  119. {"elines", "e", fnEnumLines},
  120. {"ff", "f", fnFindFile},
  121. // {"", "g", fn},
  122. // {"", "h", fn},
  123. {"info", "i", fnInfo},
  124. {"linenext","j", fnLineNext},
  125. {"lineprev","k", fnLinePrev},
  126. {"line", "l", fnLine},
  127. {"enumaddr","m", fnEnumForAddr},
  128. {"name", "n", fnName},
  129. {"obj", "o", fnObj},
  130. {"prev", "p", fnPrev},
  131. {"quit", "q", fnQuit},
  132. {"src", "r", fnEnumSrcFiles},
  133. {"next", "s", fnNext},
  134. {"type", "t", fnType},
  135. {"unload", "u", fnUnload},
  136. {"verbose", "v", fnVerbose},
  137. // {"", "w", fn},
  138. {"enum", "x", fnEnum},
  139. {"ss", "y", fnSymbolServer},
  140. {"locals", "z", fnLocals},
  141. {"add", "+", fnAdd},
  142. {"del", "-", fnDelete},
  143. {"help", "?", fnHelp},
  144. {"undec", "", fnUndec},
  145. {"load", "", fnLoad},
  146. {"map", "", fnMap},
  147. {"multi", "", fnMulti},
  148. {"etag", "", fnEnumTag},
  149. };
  150. // globals
  151. char gModName[MAX_STR] = "";
  152. char gImageName[MAX_STR];
  153. char gSymbolSearchPath[MAX_STR];
  154. DWORD64 gBase;
  155. DWORD64 gDefaultBase;
  156. DWORD64 gDefaultBaseForVirtualMods;
  157. DWORD gOptions;
  158. HANDLE gTID;
  159. IMAGEHLP_LINE64 gLine;
  160. char gExecCmd[MAX_STR] = "";
  161. char gSrcFileName[MAX_PATH + 1] = "";
  162. char gObj[MAX_PATH + 1] = "";
  163. // REMOVE
  164. // symbol server stuff
  165. HINSTANCE ghSrv;
  166. PSYMBOLSERVERPROC gfnSymbolServer;
  167. PSYMBOLSERVERCLOSEPROC gfnSymbolServerClose;
  168. PSYMBOLSERVERSETOPTIONSPROC gfnSymbolServerSetOptions;
  169. PSYMBOLSERVERGETOPTIONSPROC gfnSymbolServerGetOptions;
  170. // REMOVE END
  171. // Use this to display verbose information, when
  172. // the -v switch is used.
  173. int
  174. dprintf(
  175. LPSTR Format,
  176. ...
  177. )
  178. {
  179. static char buf[1000] = "";
  180. va_list args;
  181. if ((gOptions & SYMOPT_DEBUG) == 0)
  182. return 1;
  183. va_start(args, Format);
  184. #if 0
  185. _vsnprintf(buf, sizeof(buf), Format, args);
  186. #else
  187. StringCchVPrintf(buf, DIMA(buf), Format, args);
  188. #endif
  189. va_end(args);
  190. fputs(buf, stdout);
  191. return 1;
  192. }
  193. __inline int ucase(int c)
  194. {
  195. return (gOptions & SYMOPT_CASE_INSENSITIVE) ? toupper(c) : c;
  196. }
  197. #define MAX_FORMAT_STRINGS 8
  198. char *
  199. _dispaddr(
  200. ULONG64 addr,
  201. BOOL pad
  202. )
  203. {
  204. static char sz[20];
  205. #if 0
  206. if ((addr >> 32) != 0)
  207. sprintf(sz, "%8x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  208. else
  209. sprintf(sz, pad ? " %8x" : "%8x", (ULONG)addr);
  210. #else
  211. if ((addr >> 32) != 0)
  212. StringCchPrintf(sz, DIMA(sz), "%8x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  213. else
  214. StringCchPrintf(sz, DIMA(sz), pad ? " %8x" : "%8x", (ULONG)addr);
  215. #endif
  216. return sz;
  217. }
  218. #define dispaddr(addr) _dispaddr(addr, false)
  219. BOOL
  220. validnum(
  221. char *sz
  222. )
  223. {
  224. int c;
  225. for (; *sz; sz++)
  226. {
  227. c = tolower(*sz);
  228. if (c >= '0' && c <= '9')
  229. continue;
  230. if (c >= 'a' && c <= 'f')
  231. continue;
  232. return false;
  233. }
  234. return true;
  235. }
  236. DWORD64
  237. sz2addr(
  238. char *sz
  239. )
  240. {
  241. char *p;
  242. DWORD64 addr = 0;
  243. if (sz && *sz)
  244. {
  245. p = sz;
  246. if (*(p + 1) == 'x' || *(p + 1) == 'X')
  247. p += 2;
  248. if (!validnum(p))
  249. return 0;
  250. if (sscanf(p, "%I64x", &addr) < 1)
  251. return 0;
  252. }
  253. return addr;
  254. }
  255. void _dumpsym(
  256. PIMAGEHLP_SYMBOL64 sym,
  257. BOOL pad
  258. )
  259. {
  260. printf(" name : %s\n", sym->Name);
  261. printf(" addr : %s\n", _dispaddr(sym->Address, pad));
  262. printf(" size : %x\n", sym->Size);
  263. printf("flags : %x\n", sym->Flags);
  264. }
  265. #define dumpsym(sym) _dumpsym(sym, false)
  266. void dumpsym32(
  267. PIMAGEHLP_SYMBOL sym
  268. )
  269. {
  270. printf(" name : %s\n", sym->Name);
  271. printf(" addr : %s\n", dispaddr(sym->Address));
  272. printf(" size : %x\n", sym->Size);
  273. printf("flags : %x\n", sym->Flags);
  274. }
  275. void dumpLine(
  276. PIMAGEHLP_LINE64 line
  277. )
  278. {
  279. printf("file : %s\n", line->FileName);
  280. printf("line : %d\n", line->LineNumber);
  281. printf("addr : %s\n", dispaddr(line->Address));
  282. }
  283. #ifndef _WIN64
  284. void dumpdbi(
  285. PIMAGE_DEBUG_INFORMATION dbi
  286. )
  287. {
  288. printf(" List : 0x%x\n", dbi->List);
  289. printf(" ImageBase : 0x%x\n", dbi->ImageBase);
  290. printf(" SizeOfImage : 0x%x\n", dbi->SizeOfImage);
  291. printf(" SizeOfCoffSymbols : 0x%x\n", dbi->SizeOfCoffSymbols);
  292. printf(" CoffSymbols : 0x%x\n", dbi->CoffSymbols);
  293. printf(" ImageFilePath : %s\n", dbi->ImageFilePath);
  294. printf(" ImageFileName : %s\n", dbi->ImageFileName);
  295. }
  296. #endif
  297. // This stuff displays the symbol tag descriptions.
  298. #ifndef SymTagMax
  299. // normally found in cvconst.h which ships with Visual Studio
  300. #define SymTagMax 0x1f
  301. #endif
  302. char* g_SymTagNames[] =
  303. {
  304. "SymTagNull",
  305. "SymTagExe",
  306. "SymTagCompiland",
  307. "SymTagCompilandDetails",
  308. "SymTagCompilandEnv",
  309. "SymTagFunction",
  310. "SymTagBlock",
  311. "SymTagData",
  312. "SymTagAnnotation",
  313. "SymTagLabel",
  314. "SymTagPublicSymbol",
  315. "SymTagUDT",
  316. "SymTagEnum",
  317. "SymTagFunctionType",
  318. "SymTagPointerType",
  319. "SymTagArrayType",
  320. "SymTagBaseType",
  321. "SymTagTypedef",
  322. "SymTagBaseClass",
  323. "SymTagFriend",
  324. "SymTagFunctionArgType",
  325. "SymTagFuncDebugStart",
  326. "SymTagFuncDebugEnd",
  327. "SymTagUsingNamespace",
  328. "SymTagVTableShape",
  329. "SymTagVTable",
  330. "SymTagCustom",
  331. "SymTagThunk",
  332. "SymTagCustomType",
  333. "SymTagManagedType",
  334. "SymTagDimension",
  335. };
  336. char* dispsymtag(
  337. ULONG symtag
  338. )
  339. {
  340. if (symtag >= SymTagMax) {
  341. return "<Invalid>";
  342. } else {
  343. return g_SymTagNames[symtag];
  344. }
  345. }
  346. void dumpsi(
  347. PSYMBOL_INFO si
  348. )
  349. {
  350. printf(" name : %s\n", si->Name);
  351. printf(" addr : %s\n", dispaddr(si->Address));
  352. printf(" size : %x\n", si->Size);
  353. printf(" flags : %x\n", si->Flags);
  354. printf(" type : %x\n", si->TypeIndex);
  355. printf("modbase : %s\n", dispaddr(si->ModBase));
  356. printf(" value : %s\n", dispaddr(si->Value));
  357. printf(" reg : %x\n", si->Register);
  358. printf(" scope : %s (%x)\n", dispsymtag(si->Scope), si->Scope);
  359. printf(" tag : %s (%x)\n", dispsymtag(si->Tag), si->Tag);
  360. }
  361. BOOL
  362. CALLBACK
  363. cbEnumSymbols(
  364. PSYMBOL_INFO si,
  365. ULONG size,
  366. PVOID context
  367. )
  368. {
  369. PENUMSYMDATA esd = (PENUMSYMDATA)context;
  370. printf(" %8s : ", _dispaddr(si->Address, true));
  371. if (si->Flags & SYMF_FORWARDER)
  372. printf("%c ", 'F');
  373. else if (si->Flags & SYMF_EXPORT)
  374. printf("%c ", 'E');
  375. else
  376. printf(" ");
  377. printf("%s\n", si->Name);
  378. return true;
  379. }
  380. BOOL
  381. CALLBACK
  382. cbEnumObjs(
  383. PSYMBOL_INFO si,
  384. ULONG size,
  385. PVOID context
  386. )
  387. {
  388. PENUMSYMDATA esd = (PENUMSYMDATA)context;
  389. printf("%s\n", si->Name);
  390. return true;
  391. }
  392. BOOL
  393. cbSrcFiles(
  394. PSOURCEFILE pSourceFile,
  395. PVOID UserContext
  396. )
  397. {
  398. if (!pSourceFile)
  399. return false;
  400. printf("%s\n", pSourceFile->FileName);
  401. return true;
  402. }
  403. BOOL
  404. CALLBACK
  405. cbEnumLines(
  406. PSRCCODEINFO sci,
  407. PVOID context
  408. )
  409. {
  410. static int cnt;
  411. if (!sci)
  412. return false;
  413. if (strcmp(gObj, sci->Obj) )
  414. {
  415. StringCchCopy(gObj, DIMA(gObj), sci->Obj);
  416. printf("\nOBJ:%s", sci->Obj);
  417. }
  418. if (strcmp(gSrcFileName, sci->FileName))
  419. {
  420. StringCchCopy(gSrcFileName, DIMA(gSrcFileName), sci->FileName);
  421. printf("\n %s ", sci->FileName);
  422. cnt = 0;
  423. }
  424. if (cnt > 15)
  425. cnt = 0;
  426. if (!cnt)
  427. printf("\n ");
  428. printf(" %d", sci->LineNumber);
  429. cnt++;
  430. return true;
  431. }
  432. BOOL
  433. CALLBACK
  434. cbSymbol(
  435. HANDLE hProcess,
  436. ULONG ActionCode,
  437. ULONG64 CallbackData,
  438. ULONG64 UserContext
  439. )
  440. {
  441. PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
  442. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64) CallbackData;
  443. switch ( ActionCode )
  444. {
  445. case CBA_DEBUG_INFO:
  446. printf("%s", (LPSTR)CallbackData);
  447. break;
  448. default:
  449. return false;
  450. }
  451. return false;
  452. }
  453. // exit this program
  454. BOOL fnQuit(char *param)
  455. {
  456. printf("goodbye\n");
  457. return false;
  458. }
  459. // display command help
  460. BOOL fnHelp(char *param)
  461. {
  462. printf(" dbh commands :\n");
  463. printf("? help : prints this message\n");
  464. printf("q quit : quits this program\n");
  465. printf("v verbose <on/off> : controls debug spew\n");
  466. printf(" load <modname> : loads the requested module\n");
  467. printf("u unload : unloads the current module\n");
  468. printf("x enum <mask> : enumerates all matching symbols\n");
  469. printf("n name <symname> : finds a symbol by it's name\n");
  470. printf("a addr <addr> : finds a symbol by it's hex address\n");
  471. printf("m enumaddr <addr> : lists all symbols with a certain hex address\n");
  472. printf("b base <address> : sets the new default base address\n");
  473. printf("s next <add/nam> : finds the symbol after the passed sym\n");
  474. printf("p prev <add/nam> : finds the symbol before the passed sym\n");
  475. printf("l line <file:#> : finds the matching line number\n");
  476. printf("j linenext : goes to the next line after the current\n");
  477. printf("k lineprev : goes to the line previous to the current\n");
  478. printf("f ff <path> <file> : finds file in path\n");
  479. printf("r src <mask> : lists source files\n");
  480. printf("+ add <name addr> : adds symbols with passed name and address\n");
  481. printf("- del <name/addr> : deletes symbols with passed name or address\n");
  482. printf("y ss : executes a symbol server command\n");
  483. printf("m enumaddr <addr> : enum all symbols for address\n");
  484. printf("z locals <name> : enum all scoped symbols for a named function\n");
  485. printf(" map <name> : call MapDebugInfo on the named file\n");
  486. printf(" multi <name> : loads the requested module 1000 times\n");
  487. printf("t type <name> : lists the type information for the symbol\n");
  488. printf("i info : displays information about the loaded module\n");
  489. printf("o obj : displays object files in the loaded module\n");
  490. printf("e elines : enumerates lines for an obj and source file\n");
  491. printf(" etag <tag> <mask> : enumerates all symbols for a matching SymTag\n");
  492. printf(" undec <name> : undecorates a given symbol name\n");
  493. return true;
  494. }
  495. // display debug spew from debughlp
  496. BOOL fnVerbose(char *param)
  497. {
  498. int opts = gOptions;
  499. if (!param || !*param)
  500. printf("");
  501. else if (!_strcmpi(param, "on"))
  502. opts |= SYMOPT_DEBUG;
  503. else if (!_strcmpi(param, "off"))
  504. opts = gOptions & ~SYMOPT_DEBUG;
  505. else
  506. printf("verbose <on//off>\n");
  507. gOptions = SymSetOptions(opts);
  508. printf("verbose mode %s.\n", gOptions & SYMOPT_DEBUG ? "on" : "off");
  509. return true;
  510. }
  511. // load an image
  512. BOOL fnLoad(char *param)
  513. {
  514. char ext[MAX_STR];
  515. char mod[MAX_STR];
  516. DWORD flags = 0;
  517. DWORD64 addr = 0;
  518. DWORD size = 0x1000000;
  519. HANDLE hf = NULL;
  520. BOOL dontopen = false;
  521. if (!*param)
  522. {
  523. printf("load <modname> - you must specify a module to load\n");
  524. return true;
  525. }
  526. _splitpath(param, NULL, NULL, mod, ext);
  527. if (!*ext) {
  528. flags = SLMFLAG_VIRTUAL;
  529. addr = gDefaultBaseForVirtualMods;
  530. } else if (!_strcmpi(ext, ".pdb")) {
  531. addr = gDefaultBaseForVirtualMods;
  532. dontopen = true;
  533. } else {
  534. addr = gDefaultBase;
  535. }
  536. fnUnload(NULL);
  537. StringCchCopy(gModName, DIMA(gModName), mod);
  538. // you can do this with or without an open file handle
  539. if (!dontopen) {
  540. hf = CreateFile(param,
  541. GENERIC_READ,
  542. 0,
  543. NULL,
  544. OPEN_EXISTING,
  545. 0,
  546. 0);
  547. size = GetFileSize(hf, NULL);
  548. }
  549. addr = SymLoadModuleEx(gTID,
  550. hf, // hFile,
  551. param, // ImageName,
  552. mod, // ModuleName,
  553. addr, // BaseOfDll,
  554. size, // SizeOfDll
  555. NULL, // Data
  556. flags); // Flags
  557. if (!addr)
  558. {
  559. *gModName = 0;
  560. printf("error 0x%x loading %s.\n", GetLastError(), param);
  561. return true;
  562. }
  563. StringCchCopy(gImageName, DIMA(gImageName), param);
  564. gBase = addr;
  565. if (hf != INVALID_HANDLE_VALUE)
  566. CloseHandle(hf);
  567. return true;
  568. }
  569. // unload the image
  570. BOOL fnUnload(char *param)
  571. {
  572. if (!gBase)
  573. return true;
  574. if (!SymUnloadModule64(gTID, gBase))
  575. printf("error unloading %s at %s\n", gModName, dispaddr(gBase));
  576. gBase = 0;
  577. *gModName = 0;
  578. return true;
  579. }
  580. // enumerate the symbols
  581. BOOL fnEnum(char *param)
  582. {
  583. BOOL rc;
  584. ENUMSYMDATA esd;
  585. esd.base = gBase;
  586. StringCchCopy(esd.mask, MAX_STR, param ? param : "");
  587. rc = SymEnumSymbols(gTID, gBase, param, cbEnumSymbols, &esd);
  588. if (!rc)
  589. printf("error 0x%x calling SymEnumSymbols()\n", GetLastError());
  590. return true;
  591. }
  592. // enumerate the source files
  593. BOOL fnEnumSrcFiles(char *param)
  594. {
  595. BOOL rc;
  596. rc = SymEnumSourceFiles(gTID, gBase, param, cbSrcFiles, NULL);
  597. if (!rc)
  598. printf("error 0x%0 calling SymEnumSourceFiles()\n", GetLastError());
  599. return true;
  600. }
  601. // search for a symbol by name
  602. BOOL fnName(char *param)
  603. {
  604. SYMBOL_INFO_PACKAGE sip; // this struct saves allocation code
  605. char name[MAX_STR];
  606. if (!param || !*param)
  607. {
  608. printf("name <symbolname> - finds a symbol by it's name\n");
  609. return true;
  610. }
  611. StringCchPrintf(name, DIMA(name), "%s!%s", gModName, param);
  612. ZeroMemory(&sip, sizeof(sip));
  613. sip.si.MaxNameLen = MAX_SYM_NAME;
  614. if (SymFromName(gTID, name, &sip.si))
  615. dumpsi(&sip.si);
  616. return true;
  617. }
  618. // search for a symbol by address
  619. BOOL fnAddr(char *param)
  620. {
  621. BOOL rc;
  622. DWORD64 addr;
  623. DWORD64 disp;
  624. PSYMBOL_INFO si;
  625. addr = sz2addr(param);
  626. if (!addr)
  627. {
  628. printf("addr <address> : finds a symbol by it's hex address\n");
  629. return true;
  630. }
  631. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  632. if (!si)
  633. return false;
  634. ZeroMemory(si, SI_BUFFER_SIZE);
  635. si->MaxNameLen = MAX_SYM_NAME;
  636. rc = SymFromAddr(gTID, addr, &disp, si);
  637. if (rc)
  638. {
  639. printf("%s", si->Name);
  640. if (disp)
  641. printf("+%I64x", disp);
  642. printf("\n");
  643. dumpsi(si);
  644. }
  645. free(si);
  646. return true;
  647. }
  648. // enumerate all symbols with the passed address
  649. BOOL fnEnumForAddr(char *param)
  650. {
  651. BOOL rc;
  652. DWORD64 addr;
  653. ENUMSYMDATA esd;
  654. addr = sz2addr(param);
  655. if (!addr)
  656. {
  657. printf("enumaddr <addr> : lists all symbols with a certain hex address\n");
  658. return true;
  659. }
  660. esd.base = gBase;
  661. StringCchCopy(esd.mask, MAX_STR, "");
  662. rc = SymEnumSymbolsForAddr(gTID, addr, cbEnumSymbols, &esd);
  663. if (!rc)
  664. printf("error 0x%0 calling SymEnumSymbolsForAddr()\n", GetLastError());
  665. return true;
  666. }
  667. // find locals for passed symbol
  668. BOOL fnLocals(char *param)
  669. {
  670. PSYMBOL_INFO si;
  671. char name[MAX_STR];
  672. IMAGEHLP_STACK_FRAME frame;
  673. ENUMSYMDATA esd;
  674. if (!param || !*param)
  675. {
  676. printf("locals <symbolname> - finds all locals a function\n");
  677. return true;
  678. }
  679. StringCchPrintf(name, DIMA(name), "%s!%s", gModName, param);
  680. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  681. if (!si)
  682. return false;
  683. ZeroMemory(si, SI_BUFFER_SIZE);
  684. si->MaxNameLen = MAX_SYM_NAME;
  685. if (!SymFromName(gTID, name, si))
  686. goto exit;
  687. printf("dumping locals for %s...\n", si->Name);
  688. ZeroMemory(&frame, sizeof(frame));
  689. frame.InstructionOffset = si->Address;
  690. SymSetContext(gTID, &frame, NULL);
  691. esd.base = gBase;
  692. StringCchCopy(esd.mask, MAX_STR, "*");
  693. if (!SymEnumSymbols(gTID, 0, esd.mask, cbEnumSymbols, &esd))
  694. printf("error 0x%0 calling SymEnumSymbols()\n", GetLastError());
  695. exit:
  696. free(si);
  697. return true;
  698. }
  699. // REMOVE
  700. // Call MapDebugInfo. You should never do this.
  701. // I just put this in to test my compatibility
  702. // with old imagehlp clients.
  703. BOOL fnMap(char *param)
  704. {
  705. #ifndef _WIN64
  706. PIMAGE_DEBUG_INFORMATION dbi;
  707. if (!*param)
  708. {
  709. printf("no image specified\n");
  710. return true;
  711. }
  712. dbi = MapDebugInformation(NULL, // HANDLE FileHandle,
  713. param,
  714. gSymbolSearchPath,
  715. 0); // DWORD ImageBase
  716. if (!dbi)
  717. {
  718. printf("error 0x%x calling MapDebugInformation on %s\n", GetLastError(), param);
  719. return true;
  720. }
  721. dumpdbi(dbi);
  722. if (!UnmapDebugInformation(dbi))
  723. printf("error 0x%x calling UnmapDebugInformation on %s\n", GetLastError(), param);
  724. #else
  725. printf("MapDebugInfo is not supported on 64 bit platforms.\n");
  726. #endif
  727. return true;
  728. }
  729. // REMOVE END
  730. // REMOVE
  731. // use this to look for leaks in dbghelp
  732. BOOL fnMulti(char *param)
  733. {
  734. int i;
  735. for (i = 0; i < 1000; i++)
  736. {
  737. if (!fnLoad(param))
  738. return false;
  739. if (!fnUnload(param))
  740. return false;
  741. }
  742. return true;
  743. }
  744. // REMOVE END
  745. // obtain simple type information
  746. BOOL fnType(char *param)
  747. {
  748. PSYMBOL_INFO si;
  749. if (!param || !*param)
  750. {
  751. printf("type <typename> - finds type info\n");
  752. return true;
  753. }
  754. si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
  755. if (!si)
  756. return false;
  757. ZeroMemory(si, SI_BUFFER_SIZE);
  758. si->MaxNameLen = MAX_SYM_NAME;
  759. if (SymGetTypeFromName(gTID, gBase, param, si))
  760. dumpsi(si);
  761. free(si);
  762. return true;
  763. }
  764. // get module information
  765. BOOL fnInfo(char *param)
  766. {
  767. IMAGEHLP_MODULE64 mi;
  768. static char *symtypes[NumSymTypes] =
  769. {
  770. "SymNone",
  771. "SymCoff",
  772. "SymCv",
  773. "SymPdb",
  774. "SymExport",
  775. "SymDeferred",
  776. "SymSym",
  777. "SymDia",
  778. "SymVirtual"
  779. };
  780. ZeroMemory((void *)&mi, sizeof(mi));
  781. mi.SizeOfStruct = sizeof(mi);
  782. if (!SymGetModuleInfo64(gTID, gBase, &mi))
  783. {
  784. printf("error 0x%x calling SymGetModuleInfo64()\n", GetLastError());
  785. return true;
  786. }
  787. printf(" SizeOfStruct : 0x%x\n", mi.SizeOfStruct);
  788. printf(" BaseOfImage : 0x%i64x\n", mi.BaseOfImage);
  789. printf(" ImageSize : 0x%x\n", mi.ImageSize);
  790. printf(" TimeDateStamp : 0x%x\n", mi.TimeDateStamp);
  791. printf(" CheckSum : 0x%x\n", mi.CheckSum);
  792. printf(" NumSyms : 0x%x\n", mi.NumSyms);
  793. printf(" SymType : %s\n", symtypes[mi.SymType]);
  794. printf(" ModuleName : %s\n", mi.ModuleName);
  795. printf(" ImageName : %s\n", mi.ImageName);
  796. printf(" LoadedImageName : %s\n", mi.LoadedImageName);
  797. printf(" LoadedPdbName : %s\n", mi.LoadedPdbName);
  798. printf(" CVSig : 0x%x\n", mi.CVSig);
  799. printf(" CVData : %s\n", mi.CVData);
  800. printf(" PdbSig : 0x%x\n", mi.PdbSig);
  801. printf(" PdbSig70 : 0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
  802. mi.PdbSig70.Data1,
  803. mi.PdbSig70.Data2,
  804. mi.PdbSig70.Data3,
  805. mi.PdbSig70.Data4[0],
  806. mi.PdbSig70.Data4[1],
  807. mi.PdbSig70.Data4[2],
  808. mi.PdbSig70.Data4[3],
  809. mi.PdbSig70.Data4[4],
  810. mi.PdbSig70.Data4[5],
  811. mi.PdbSig70.Data4[6],
  812. mi.PdbSig70.Data4[7]);
  813. printf(" PdbAge : 0x%x\n", mi.PdbAge);
  814. printf(" PdbUnmatched : %s\n", mi.PdbUnmatched ? "true" : "false");
  815. printf(" DbgUnmatched : %s\n", mi.DbgUnmatched ? "true" : "false");
  816. printf(" LineNumbers : %s\n", mi.LineNumbers ? "true" : "false");
  817. printf(" GlobalSymbols : %s\n", mi.GlobalSymbols ? "true" : "false");
  818. printf(" TypeInfo : %s\n", mi.TypeInfo ? "true" : "false");
  819. return true;
  820. }
  821. // enumerate objs within a module
  822. BOOL fnObj(char *param)
  823. {
  824. #if 0
  825. BOOL rc;
  826. ENUMSYMDATA esd;
  827. esd.base = gBase;
  828. StringCchCopy(esd.mask, MAX_STR, param ? param : "");
  829. rc = SymEnumObjs(gTID, gBase, param, cbEnumObjs, &esd);
  830. if (!rc)
  831. printf("error 0x%x calling SymEnumObjs()\n", GetLastError());
  832. #else
  833. printf("not implemented\n");
  834. #endif
  835. return true;
  836. }
  837. // enumerate lines within an image
  838. BOOL fnEnumLines(char *param)
  839. {
  840. BOOL rc;
  841. ENUMSYMDATA esd;
  842. esd.base = gBase;
  843. StringCchCopy(esd.mask, MAX_STR, param ? param : "");
  844. *gSrcFileName = 0;
  845. *gObj = 0;
  846. rc = SymEnumLines(gTID, gBase, param, NULL, cbEnumLines, &esd);
  847. if (!rc)
  848. printf("error 0x%x calling SymEnumLines()\n", GetLastError());
  849. else
  850. printf("\n");
  851. return true;
  852. }
  853. // REMOVE
  854. // Deep search mechanism. Don't call this.
  855. // The API is not finished yet and it will
  856. // be renamed when completed.
  857. BOOL fnEnumTag(char *param)
  858. {
  859. #if 0
  860. DWORD tag;
  861. char mask[4098];
  862. ENUMSYMDATA esd;
  863. *mask = 0;
  864. if (sscanf(param, "%x %s", &tag, mask) < 1) {
  865. printf("etags : must specify a symtag. A mask is optional\n");
  866. return true;
  867. }
  868. printf("symtag:%x mask:%s\n", tag, mask);
  869. esd.base = gBase;
  870. StringCchCopy(esd.mask, MAX_STR, param ? param : "");
  871. if (!SymEnumSymbolsByTag(gTID,
  872. gBase,
  873. tag,
  874. *mask ? mask : NULL,
  875. SYMENUMFLAG_FULLSRCH,
  876. cbEnumSymbols,
  877. &esd))
  878. printf("error 0x%0 calling SymEnumSymbolsByTag()\n", GetLastError());
  879. #else
  880. printf("not implemented\n");
  881. #endif
  882. return true;
  883. }
  884. // REMOVE END
  885. PIMAGEHLP_SYMBOL64 SymbolFromName(char *param)
  886. {
  887. BOOL rc;
  888. PIMAGEHLP_SYMBOL64 sym;
  889. char name[MAX_STR];
  890. if (!name || !*name)
  891. return NULL;
  892. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  893. if (!sym)
  894. return false;
  895. ZeroMemory(sym, SYM_BUFFER_SIZE);
  896. sym->MaxNameLength = MAX_SYM_NAME;
  897. StringCchPrintf(name, DIMA(name), "%s!%s", gModName, param);
  898. rc = SymGetSymFromName64(gTID, name, sym);
  899. if (!rc) {
  900. free(sym);
  901. return NULL;
  902. }
  903. return sym;
  904. }
  905. // worker function for the SymNext and SymPrev stuff
  906. BOOL fnNextPrev(int direction, char *param)
  907. {
  908. BOOL rc;
  909. PIMAGEHLP_SYMBOL64 sym;
  910. DWORD64 addr;
  911. addr = sz2addr(param);
  912. if (!addr)
  913. {
  914. sym = SymbolFromName(param);
  915. if (!sym)
  916. return true;
  917. addr = sym->Address;
  918. if (!addr) {
  919. free(sym);
  920. return true;
  921. }
  922. }
  923. else
  924. {
  925. sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
  926. if (!sym)
  927. return false;
  928. rc = SymGetSymFromAddr64(gTID, addr, NULL, sym);
  929. if (!rc)
  930. return true;
  931. }
  932. if (direction > 0)
  933. rc = SymGetSymNext64(gTID, sym);
  934. else
  935. rc = SymGetSymPrev64(gTID, sym);
  936. if (rc)
  937. dumpsym(sym);
  938. free(sym);
  939. return true;
  940. }
  941. // find the next symbol
  942. BOOL fnNext(char *param)
  943. {
  944. return fnNextPrev(1, param);
  945. }
  946. // find the previous symbol
  947. BOOL fnPrev(char *param)
  948. {
  949. return fnNextPrev(-1, param);
  950. }
  951. // set the module base and reload, if needed
  952. BOOL fnBase(char *param)
  953. {
  954. DWORD64 addr;
  955. addr = sz2addr(param);
  956. if (!addr)
  957. {
  958. printf("base <address> : sets the base address for module loads\n");
  959. return true;
  960. }
  961. gDefaultBase = addr;
  962. gDefaultBaseForVirtualMods = addr;
  963. if (gBase)
  964. fnLoad(gImageName);
  965. return true;
  966. }
  967. // search for a line by it's name
  968. BOOL fnLine(char *param)
  969. {
  970. char *file;
  971. DWORD linenum;
  972. BOOL rc;
  973. IMAGEHLP_LINE64 line;
  974. LONG disp;
  975. if (!param || !*param)
  976. return true;
  977. file = param;
  978. while (*param != ':') {
  979. if (!*param)
  980. return true;
  981. param++;
  982. }
  983. *param++ = 0;
  984. linenum = atoi(param);
  985. if (!linenum)
  986. return true;
  987. memset(&line, 0, sizeof(line));
  988. line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
  989. rc = SymGetLineFromName64(gTID,
  990. gModName,
  991. file,
  992. linenum,
  993. &disp,
  994. &line);
  995. if (!rc) {
  996. printf("line: error 0x%x looking for %s#%d\n",
  997. GetLastError(),
  998. file,
  999. linenum);
  1000. return true;
  1001. }
  1002. dumpLine(&line);
  1003. printf("disp : %x\n", disp);
  1004. // save for future next/prev calls
  1005. memcpy(&gLine, &line, sizeof(gLine));
  1006. return true;
  1007. }
  1008. // worker function for the LineNext and LinePrev stuff
  1009. BOOL lineNextPrev(BOOL prev)
  1010. {
  1011. BOOL rc;
  1012. IMAGEHLP_LINE64 line;
  1013. if (!gLine.SizeOfStruct)
  1014. return true;
  1015. memcpy(&line, &gLine, sizeof(line));
  1016. if (prev)
  1017. rc = SymGetLinePrev64(gTID, &line);
  1018. else
  1019. rc = SymGetLineNext64(gTID, &line);
  1020. if (!rc) {
  1021. printf("line: error 0x%x looking for %s#%d\n",
  1022. GetLastError(),
  1023. line.FileName,
  1024. line.LineNumber);
  1025. return true;
  1026. }
  1027. dumpLine(&line);
  1028. // save for future next/prev calls
  1029. memcpy(&gLine, &line, sizeof(gLine));
  1030. return true;
  1031. }
  1032. // find the next line
  1033. BOOL fnLineNext(char *param)
  1034. {
  1035. return lineNextPrev(false);
  1036. }
  1037. // find the previous line
  1038. BOOL fnLinePrev(char *param)
  1039. {
  1040. return lineNextPrev(true);
  1041. }
  1042. // undecorate a symbol name
  1043. BOOL fnUndec(char *param)
  1044. {
  1045. DWORD rc;
  1046. char uname[MAX_SYM_NAME + 1];
  1047. if (!param || !*param)
  1048. {
  1049. printf("undec <symbolname> - undecorates a C++ mangled symbol name\n");
  1050. return true;
  1051. }
  1052. rc = UnDecorateSymbolName(param, uname, MAX_SYM_NAME, UNDNAME_COMPLETE);
  1053. if (!rc)
  1054. printf("error 0x%u undecorating %s\n", GetLastError(), param);
  1055. else
  1056. printf("%s =\n%s\n", param, uname);
  1057. return true;
  1058. }
  1059. // search for a file in a tree
  1060. BOOL fnFindFile(char *param)
  1061. {
  1062. DWORD rc;
  1063. char root[MAX_PATH + 1];
  1064. char file[MAX_PATH + 1];
  1065. char found[MAX_PATH + 1];
  1066. if (!param)
  1067. {
  1068. printf("ff <root path> <file name> - finds file in path\n");
  1069. return true;
  1070. }
  1071. rc = sscanf(param, "%s %s", root, file);
  1072. if ((rc < 2) || !*root || !*file)
  1073. {
  1074. printf("ff <root path> <file name> - finds file in path\n");
  1075. return true;
  1076. }
  1077. *found = 0;
  1078. rc = SearchTreeForFile(root, file, found);
  1079. if (!rc) {
  1080. printf("error 0x%u looking for %s\n", GetLastError(), file);
  1081. } else {
  1082. printf("found %s\n", found);
  1083. }
  1084. return true;
  1085. }
  1086. // create a virtual symbol
  1087. BOOL fnAdd(char *param)
  1088. {
  1089. BOOL rc;
  1090. DWORD64 addr;
  1091. DWORD size;
  1092. char *p;
  1093. char name[MAX_STR];
  1094. char *n;
  1095. if (!param || !*param) {
  1096. printf("add <name address> : must specify a symbol name, address, and size.\n");
  1097. return true;
  1098. }
  1099. p = param;
  1100. while (isspace(*p)) p++;
  1101. *name = 0;
  1102. for (n = name; *p; p++, n++) {
  1103. if (isspace(*p)) {
  1104. *n = 0;
  1105. break;
  1106. }
  1107. *n = *p;
  1108. }
  1109. addr = 0;
  1110. size = 0;
  1111. while (isspace(*p)) p++;
  1112. if (*(p + 1) == 'x' || *(p + 1) == 'X')
  1113. p += 2;
  1114. rc = sscanf(p, "%I64x %x", &addr, &size);
  1115. if ((rc < 2) || !addr || !*name)
  1116. {
  1117. printf("add <name address> : must specify a symbol name, address, and size.\n");
  1118. return true;
  1119. }
  1120. rc = SymAddSymbol(gTID, 0, name, addr, size, 0);
  1121. if (!rc)
  1122. printf("Error 0x%x trying to add symbol\n", GetLastError());
  1123. return true;
  1124. }
  1125. // delete a virtual symbol
  1126. BOOL fnDelete(char *param)
  1127. {
  1128. BOOL rc;
  1129. DWORD64 addr;
  1130. DWORD err;
  1131. char *name = NULL;
  1132. if (!param || !*param) {
  1133. printf("del <name/address> : must specify a symbol name or address to delete.\n");
  1134. return true;
  1135. }
  1136. addr = sz2addr(param);
  1137. if (!addr)
  1138. name = param;
  1139. rc = SymDeleteSymbol(gTID, 0, name, addr, 0);
  1140. if (!rc) {
  1141. err = GetLastError();
  1142. if (err == ERROR_NOT_FOUND)
  1143. printf("Couldn't find %s to delete.\n", param);
  1144. else
  1145. printf("Error 0x%x trying to delete symbol\n", err);
  1146. }
  1147. return true;
  1148. }
  1149. // REMOVE
  1150. // This command is of no use. It exists just for testing
  1151. // the symbol server. You should use the symbol server
  1152. // through dbghelp. If you need to get a file directly,
  1153. // call SymFindFileInPath().
  1154. BOOL fnSymbolServer(char *param)
  1155. {
  1156. DWORD opt = 0;
  1157. DWORD data = 0;
  1158. // initialize server, if needed
  1159. if (ghSrv == (HINSTANCE)INVALID_HANDLE_VALUE)
  1160. return false;
  1161. if (!ghSrv) {
  1162. ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  1163. ghSrv = LoadLibrary("symsrv.dll");
  1164. if (ghSrv) {
  1165. gfnSymbolServer = (PSYMBOLSERVERPROC)GetProcAddress(ghSrv, "SymbolServer");
  1166. if (!gfnSymbolServer) {
  1167. FreeLibrary(ghSrv);
  1168. ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  1169. }
  1170. gfnSymbolServerClose = (PSYMBOLSERVERCLOSEPROC)GetProcAddress(ghSrv, "SymbolServerClose");
  1171. gfnSymbolServerSetOptions = (PSYMBOLSERVERSETOPTIONSPROC)GetProcAddress(ghSrv, "SymbolServerSetOptions");
  1172. gfnSymbolServerGetOptions = (PSYMBOLSERVERGETOPTIONSPROC)GetProcAddress(ghSrv, "SymbolServerGetOptions");
  1173. } else {
  1174. ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  1175. }
  1176. }
  1177. // bail, if we have no valid server
  1178. if (ghSrv == INVALID_HANDLE_VALUE
  1179. || !gfnSymbolServerClose
  1180. || !gfnSymbolServerSetOptions
  1181. || !gfnSymbolServerGetOptions)
  1182. {
  1183. printf("SymSrv load failure.\n");
  1184. return false;
  1185. }
  1186. if (param)
  1187. {
  1188. if (sscanf(param, "%x %x", &opt, &data) > 1)
  1189. {
  1190. if (opt)
  1191. gfnSymbolServerSetOptions(opt, data);
  1192. }
  1193. }
  1194. opt = (DWORD)gfnSymbolServerGetOptions();
  1195. printf("SYMSRV options: 0x%x\n", opt);
  1196. return true;
  1197. }
  1198. // REMOVE END
  1199. // read the command line
  1200. char *GetParameters(char *cmd)
  1201. {
  1202. char *p = cmd;
  1203. char *param = NULL;
  1204. while (*p++)
  1205. {
  1206. if (isspace(*p))
  1207. {
  1208. *p++ = 0;
  1209. return *p ? p : NULL;
  1210. }
  1211. }
  1212. return NULL;
  1213. }
  1214. void prompt()
  1215. {
  1216. if (!*gModName)
  1217. printf("dbh: ");
  1218. else
  1219. printf("%s [%I64x]: ", gModName, gBase);
  1220. }
  1221. char *
  1222. getstr(
  1223. char *buf,
  1224. int size
  1225. )
  1226. {
  1227. char *rc;
  1228. rc = fgets(buf, size, stdin);
  1229. if (!rc)
  1230. return 0;
  1231. while (*buf)
  1232. {
  1233. switch (*buf)
  1234. {
  1235. case 0xa:
  1236. *buf = 0;
  1237. // pass through
  1238. case 0:
  1239. return rc;
  1240. }
  1241. buf++;
  1242. }
  1243. return rc;
  1244. }
  1245. int InputLoop()
  1246. {
  1247. char cmd[MAX_STR + 1];
  1248. char *params;
  1249. int i;
  1250. BOOL rc;
  1251. do
  1252. {
  1253. rc = true;
  1254. prompt();
  1255. if (*gExecCmd) {
  1256. StringCchCopy(cmd, DIMA(cmd), gExecCmd);
  1257. printf(cmd);
  1258. printf("\n");
  1259. } else if (!getstr(cmd, sizeof(cmd)))
  1260. return 0;
  1261. params = GetParameters(cmd);
  1262. for (i = 0; i < cmdMax; i++)
  1263. {
  1264. if (!_strcmpi(cmd, gCmd[i].token)
  1265. || !_strcmpi(cmd, gCmd[i].shorttoken))
  1266. {
  1267. break;
  1268. }
  1269. }
  1270. if (i == cmdMax)
  1271. printf("[%s] is an unrecognized command.\n", cmd);
  1272. else
  1273. rc = gCmd[i].fn(params);
  1274. if (*gExecCmd)
  1275. rc = false;
  1276. } while (rc);
  1277. return 0;
  1278. }
  1279. BOOL init()
  1280. {
  1281. int i;
  1282. BOOL rc;
  1283. *gModName = 0;
  1284. gBase = 0;;
  1285. gDefaultBaseForVirtualMods = 0x1000000;
  1286. gDefaultBase = 0x1000000;
  1287. ZeroMemory(&gLine, sizeof(gLine));
  1288. dprintf("dbh: initializing...\n");
  1289. i = GetEnvironmentVariable("_NT_SYMBOL_PATH", gSymbolSearchPath, MAX_STR);
  1290. if (i < 1)
  1291. *gSymbolSearchPath = 0;
  1292. dprintf("Symbol Path = [%s]\n", gSymbolSearchPath);
  1293. gTID = (HANDLE)(ULONG_PTR)GetCurrentThreadId();
  1294. rc = SymInitialize(gTID, gSymbolSearchPath, false);
  1295. if (!rc)
  1296. {
  1297. printf("error 0x%x from SymInitialize()\n", GetLastError());
  1298. return rc;
  1299. }
  1300. rc = SymInitialize(gTID, gSymbolSearchPath, false);
  1301. if (!rc)
  1302. {
  1303. printf("error 0x%x from SymInitialize()\n", GetLastError());
  1304. return rc;
  1305. }
  1306. gOptions = SymSetOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_AUTO_PUBLICS);
  1307. dprintf("SymOpts = 0x%x\n", gOptions);
  1308. rc = SymRegisterCallback64(gTID, cbSymbol, 0);
  1309. if (!rc)
  1310. {
  1311. printf("error 0x%x from SymRegisterCallback64()\n", GetLastError());
  1312. return rc;
  1313. }
  1314. return rc;
  1315. }
  1316. void cleanup()
  1317. {
  1318. int i;
  1319. fnUnload(NULL);
  1320. for (i = 0; i < 50; i++)
  1321. SymCleanup(gTID);
  1322. }
  1323. BOOL cmdline(int argc, char *argv[])
  1324. {
  1325. int i;
  1326. char *p;
  1327. for (i = 1; i < argc; i++)
  1328. {
  1329. p = argv[i];
  1330. switch (*p)
  1331. {
  1332. case '/':
  1333. case '-':
  1334. p++;
  1335. switch (tolower(*p))
  1336. {
  1337. case 'v':
  1338. fnVerbose("on");
  1339. break;
  1340. default:
  1341. printf("%s is an unknown switch\n", argv[i]);
  1342. break;
  1343. }
  1344. break;
  1345. default:
  1346. if (*gModName) {
  1347. StringCchCat(gExecCmd, DIMA(gExecCmd), argv[i]);
  1348. StringCchCat(gExecCmd, DIMA(gExecCmd), " ");
  1349. } else
  1350. fnLoad(argv[i]);
  1351. break;
  1352. }
  1353. }
  1354. return true;
  1355. }
  1356. #include <crtdbg.h>
  1357. __cdecl
  1358. main(
  1359. int argc,
  1360. char *argv[],
  1361. char *envp[]
  1362. )
  1363. {
  1364. DWORD rc;
  1365. _CrtSetDbgFlag( ( _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF ) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG ) );
  1366. if (!init())
  1367. return 1;
  1368. cmdline(argc, argv);
  1369. rc = InputLoop();
  1370. cleanup();
  1371. _CrtDumpMemoryLeaks();
  1372. return rc;
  1373. }