Source code of Windows XP (NT5)
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.

3513 lines
98 KiB

  1. /*** ntcmd.cpp - command processor for NT debugger
  2. *
  3. * Copyright <C> 1990-2001, Microsoft Corporation
  4. *
  5. * Purpose:
  6. * To determine if the command processor should be invoked, and
  7. * if so, to parse and execute those commands entered.
  8. *
  9. *************************************************************************/
  10. #include "ntsdp.hpp"
  11. #include <time.h>
  12. #include <dbgver.h>
  13. ULONG g_X86BiosBaseAddress;
  14. #define CRASH_BUGCHECK_CODE 0xDEADDEAD
  15. API_VERSION g_NtsdApiVersion =
  16. {
  17. BUILD_MAJOR_VERSION, BUILD_MINOR_VERSION, API_VERSION_NUMBER, 0
  18. };
  19. API_VERSION g_DbgHelpAV;
  20. // Set if registers should be displayed by default in OutCurInfo.
  21. BOOL g_OciOutputRegs;
  22. ULONG g_DefaultStackTraceDepth = 20;
  23. BOOL g_EchoEventTimestamps;
  24. BOOL g_SwitchedProcs;
  25. // Last command executed.
  26. CHAR g_LastCommand[MAX_COMMAND];
  27. // state variables for top-level command processing
  28. PSTR g_CommandStart; // start of command buffer
  29. PSTR g_CurCmd; // current pointer in command buffer
  30. ULONG g_PromptLength = 8; // size of prompt string
  31. ADDR g_UnasmDefault; // default unassembly address
  32. ADDR g_AssemDefault; // default assembly address
  33. ULONG g_DefaultRadix = 16; // default input base
  34. CHAR g_SymbolSuffix = 'n'; // suffix to add to symbol if search
  35. // failure - 'n'-none 'a'-'w'-append
  36. CHAR g_CmdState = 'i'; // state of present command processing
  37. // 'i'-init; 'g'-go; 't'-trace
  38. // 'p'-step; 'c'-cmd; 'b'-branch trace
  39. int g_RedoCount = 0;
  40. BOOL DotCommand(DebugClient* Client);
  41. void EvaluateExp(BOOL Verbose);
  42. void SetSuffix(void);
  43. void
  44. StackTrace(
  45. PSTR arg
  46. );
  47. VOID
  48. DumpExr(
  49. ULONG64 Exr
  50. );
  51. void
  52. CallBugCheckExtension(DebugClient* Client)
  53. {
  54. HRESULT Status = E_FAIL;
  55. if (Client == NULL)
  56. {
  57. // Use the session client.
  58. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  59. {
  60. if ((Client->m_Flags & (CLIENT_REMOTE | CLIENT_PRIMARY)) ==
  61. CLIENT_PRIMARY)
  62. {
  63. break;
  64. }
  65. }
  66. if (Client == NULL)
  67. {
  68. Client = g_Clients;
  69. }
  70. }
  71. if (Client != NULL)
  72. {
  73. char ExtName[32];
  74. // Extension name has to be in writable memory as it
  75. // gets lower-cased.
  76. strcpy(ExtName, "AnalyzeBugCheck");
  77. // See if any existing extension DLLs are interested
  78. // in analyzing this bugcheck.
  79. CallAnyExtension(Client, NULL, ExtName, "",
  80. FALSE, FALSE, &Status);
  81. }
  82. if (Status != S_OK)
  83. {
  84. if (Client == NULL)
  85. {
  86. WarnOut("WARNING: Unable to locate a client for "
  87. "bugcheck analysis\n");
  88. }
  89. dprintf("*******************************************************************************\n");
  90. dprintf("* *\n");
  91. dprintf("* Bugcheck Analysis *\n");
  92. dprintf("* *\n");
  93. dprintf("*******************************************************************************\n");
  94. Execute(Client, ".bugcheck", DEBUG_EXECUTE_DEFAULT);
  95. dprintf("\n");
  96. Execute(Client, "kb", DEBUG_EXECUTE_DEFAULT);
  97. dprintf("\n");
  98. }
  99. }
  100. BOOL
  101. dotFrame(
  102. )
  103. {
  104. PDEBUG_STACK_FRAME pStackFrame;
  105. ULONG Traced = 0, Frame = 0;
  106. if (PeekChar())
  107. {
  108. Frame = (ULONG) GetExpression();
  109. }
  110. else
  111. {
  112. return TRUE;
  113. }
  114. pStackFrame = (PDEBUG_STACK_FRAME)
  115. malloc(sizeof(DEBUG_STACK_FRAME) * (Frame + 1));
  116. if (!pStackFrame)
  117. {
  118. return FALSE;
  119. }
  120. Traced = StackTrace(0, 0, 0, pStackFrame, Frame + 1, 0, 0, FALSE);
  121. if (Traced <= Frame)
  122. {
  123. return FALSE;
  124. }
  125. // Do not change the previous context
  126. SetCurrentScope(&pStackFrame[Frame], NULL, 0);
  127. return TRUE;
  128. }
  129. VOID
  130. HandleBPWithStatus(
  131. VOID
  132. )
  133. {
  134. ULONG Status = (ULONG)g_Machine->GetArgReg();
  135. switch(Status)
  136. {
  137. case DBG_STATUS_CONTROL_C:
  138. case DBG_STATUS_SYSRQ:
  139. if ((g_EngOptions & DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION) == 0 &&
  140. !g_QuietMode)
  141. {
  142. dprintf("*******************************************************************************\n");
  143. dprintf("* *\n");
  144. if (Status == DBG_STATUS_SYSRQ)
  145. {
  146. dprintf("* You are seeing this message because you pressed the SysRq/PrintScreen *\n");
  147. dprintf("* key on your test machine's keyboard. *\n");
  148. }
  149. if (Status == DBG_STATUS_DEBUG_CONTROL)
  150. {
  151. dprintf("* You are seeing this message because you typed in .breakin from ntsd. *\n");
  152. }
  153. if (Status == DBG_STATUS_CONTROL_C)
  154. {
  155. dprintf("* You are seeing this message because you pressed either *\n");
  156. dprintf("* CTRL+C (if you run kd.exe) or, *\n");
  157. dprintf("* CTRL+BREAK (if you run WinDBG), *\n");
  158. dprintf("* on your debugger machine's keyboard. *\n");
  159. }
  160. dprintf("* *\n");
  161. dprintf("* THIS IS NOT A BUG OR A SYSTEM CRASH *\n");
  162. dprintf("* *\n");
  163. dprintf("* If you did not intend to break into the debugger, press the \"g\" key, then *\n");
  164. dprintf("* press the \"Enter\" key now. This message might immediately reappear. If it *\n");
  165. dprintf("* does, press \"g\" and \"Enter\" again. *\n");
  166. dprintf("* *\n");
  167. dprintf("*******************************************************************************\n");
  168. }
  169. break;
  170. case DBG_STATUS_BUGCHECK_FIRST:
  171. ErrOut("\nA fatal system error has occurred.\n");
  172. ErrOut("Debugger entered on first try; "
  173. "Bugcheck callbacks have not been invoked.\n");
  174. // Fall through.
  175. case DBG_STATUS_BUGCHECK_SECOND:
  176. ErrOut("\nA fatal system error has occurred.\n\n");
  177. CallBugCheckExtension(NULL);
  178. break;
  179. case DBG_STATUS_FATAL:
  180. // hals call KeEnterDebugger when they panic.
  181. break;
  182. }
  183. return;
  184. }
  185. /*** InitNtCmd - one-time debugger initialization
  186. *
  187. * Purpose:
  188. * To perform the one-time initialization of global
  189. * variables used in the debugger.
  190. *
  191. * Input:
  192. * None.
  193. *
  194. * Output:
  195. * None.
  196. *
  197. * Exceptions:
  198. * None.
  199. *
  200. *************************************************************************/
  201. HRESULT
  202. InitNtCmd(DebugClient* Client)
  203. {
  204. HRESULT Status;
  205. if ((Status = InitReg()) != S_OK)
  206. {
  207. return Status;
  208. }
  209. g_DbgHelpAV = *ImagehlpApiVersionEx(&g_NtsdApiVersion);
  210. if (g_DbgHelpAV.Revision < g_NtsdApiVersion.Revision)
  211. {
  212. //
  213. // bad version match
  214. //
  215. if ((g_EngOptions & DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION) == 0)
  216. {
  217. ErrOut("dbghelp.dll has a version mismatch with the debugger\n\n");
  218. OutputVersionInformation(Client);
  219. return E_FAIL;
  220. }
  221. else
  222. {
  223. WarnOut( "dbghelp.dll has a version mismatch "
  224. "with the debugger\n\n" );
  225. }
  226. }
  227. g_LastCommand[0] = '\0';
  228. return S_OK;
  229. }
  230. #define MAX_PROMPT 32
  231. HRESULT
  232. GetPromptText(PSTR Buffer, ULONG BufferSize, PULONG TextSize)
  233. {
  234. char Prompt[MAX_PROMPT];
  235. PSTR Text = Prompt;
  236. if (IS_LOCAL_KERNEL_TARGET())
  237. {
  238. strcpy(Text, "lkd");
  239. Text += 3;
  240. }
  241. else if (IS_KERNEL_TARGET())
  242. {
  243. if (g_X86InVm86)
  244. {
  245. strcpy(Text, "vm");
  246. Text += 2;
  247. }
  248. else if (g_X86InCode16)
  249. {
  250. strcpy(Text, "16");
  251. Text += 2;
  252. }
  253. else if (g_TargetMachineType == IMAGE_FILE_MACHINE_AMD64 &&
  254. !g_Amd64InCode64)
  255. {
  256. strcpy(Text, "32");
  257. Text += 2;
  258. }
  259. if (g_CurrentProcess == NULL ||
  260. g_CurrentProcess->CurrentThread == NULL ||
  261. ((IS_KERNEL_FULL_DUMP() || IS_KERNEL_SUMMARY_DUMP()) &&
  262. KdDebuggerData.KiProcessorBlock == 0))
  263. {
  264. strcpy(Text, "?: kd");
  265. Text += 5;
  266. }
  267. else if (g_TargetNumberProcessors > 1)
  268. {
  269. sprintf(Text, "%d: kd", CURRENT_PROC);
  270. Text += strlen(Text);
  271. }
  272. else
  273. {
  274. strcpy(Text, "kd");
  275. Text += 2;
  276. }
  277. }
  278. else if (IS_USER_TARGET())
  279. {
  280. if (g_CurrentProcess != NULL)
  281. {
  282. sprintf(Text, "%1ld", g_CurrentProcess->UserId);
  283. Text += strlen(Text);
  284. *Text++ = ':';
  285. if (g_CurrentProcess->CurrentThread != NULL)
  286. {
  287. sprintf(Text, "%03ld",
  288. g_CurrentProcess->CurrentThread->UserId);
  289. Text += strlen(Text);
  290. }
  291. else
  292. {
  293. strcpy(Text, "???");
  294. Text += 3;
  295. }
  296. }
  297. else
  298. {
  299. strcpy(Text, "?:???");
  300. Text += 5;
  301. }
  302. }
  303. else
  304. {
  305. strcpy(Text, "NoTarget");
  306. Text += 8;
  307. }
  308. if (g_Machine && g_EffMachine != g_TargetMachineType)
  309. {
  310. *Text++ = ':';
  311. strcpy(Text, g_Machine->m_AbbrevName);
  312. Text += strlen(Text);
  313. }
  314. *Text++ = '>';
  315. *Text = 0;
  316. return FillStringBuffer(Prompt, (ULONG)(Text - Prompt) + 1,
  317. Buffer, BufferSize, TextSize);
  318. }
  319. void
  320. OutputPrompt(PCSTR Format, va_list Args)
  321. {
  322. char Prompt[MAX_PROMPT];
  323. GetPromptText(Prompt, sizeof(Prompt), NULL);
  324. g_PromptLength = strlen(Prompt);
  325. MaskOut(DEBUG_OUTPUT_PROMPT, "%s", Prompt);
  326. // Include space after >.
  327. g_PromptLength++;
  328. if (Format != NULL)
  329. {
  330. MaskOutVa(DEBUG_OUTPUT_PROMPT, Format, Args, TRUE);
  331. }
  332. }
  333. DWORD
  334. CommandExceptionFilter(PEXCEPTION_POINTERS Info)
  335. {
  336. if (Info->ExceptionRecord->ExceptionCode >=
  337. (COMMAND_EXCEPTION_BASE + OVERFLOW) &&
  338. Info->ExceptionRecord->ExceptionCode
  339. <= (COMMAND_EXCEPTION_BASE + UNIMPLEMENT))
  340. {
  341. // This is a legitimate command error code exception.
  342. return EXCEPTION_EXECUTE_HANDLER;
  343. }
  344. else
  345. {
  346. // This is some other exception that the command
  347. // filter isn't supposed to handle.
  348. ErrOut("Non-command exception %X at %s in command filter\n",
  349. Info->ExceptionRecord->ExceptionCode,
  350. FormatAddr64((ULONG64)Info->ExceptionRecord->ExceptionAddress));
  351. return EXCEPTION_CONTINUE_SEARCH;
  352. }
  353. }
  354. void
  355. ParseLoadModules(void)
  356. {
  357. PDEBUG_IMAGE_INFO Image;
  358. PSTR Pattern;
  359. CHAR Save;
  360. BOOL AnyMatched = FALSE;
  361. Pattern =
  362. StringValue(STRV_SPACE_IS_SEPARATOR | STRV_TRIM_TRAILING_SPACE |
  363. STRV_ESCAPED_CHARACTERS, &Save);
  364. _strupr(Pattern);
  365. for (Image = g_ProcessHead->ImageHead; Image; Image = Image->Next)
  366. {
  367. if (MatchPattern(Image->ModuleName, Pattern))
  368. {
  369. IMAGEHLP_MODULE64 ModInfo;
  370. AnyMatched = TRUE;
  371. ModInfo.SizeOfStruct = sizeof(ModInfo);
  372. if (!SymGetModuleInfo64(g_CurrentProcess->Handle,
  373. Image->BaseOfImage, &ModInfo) ||
  374. ModInfo.SymType == SymDeferred)
  375. {
  376. if (!SymLoadModule64(g_CurrentProcess->Handle,
  377. NULL, NULL, NULL,
  378. Image->BaseOfImage, 0))
  379. {
  380. ErrOut("Symbol load for %s failed\n", Image->ModuleName);
  381. }
  382. else
  383. {
  384. dprintf("Symbols loaded for %s\n", Image->ModuleName);
  385. }
  386. }
  387. else
  388. {
  389. dprintf("Symbols already loaded for %s\n", Image->ModuleName);
  390. }
  391. }
  392. if (CheckUserInterrupt())
  393. {
  394. break;
  395. }
  396. }
  397. if (!AnyMatched)
  398. {
  399. WarnOut("No modules matched '%s'\n", Pattern);
  400. }
  401. *g_CurCmd = Save;
  402. }
  403. void
  404. ParseProcessorCommands(void)
  405. {
  406. ULONG Proc;
  407. if (IS_KERNEL_TRIAGE_DUMP())
  408. {
  409. ErrOut("Can't switch processors on a Triage dump\n");
  410. error(SYNTAX);
  411. }
  412. Proc = 0;
  413. while (*g_CurCmd >= '0' && *g_CurCmd <= '9')
  414. {
  415. Proc = Proc * 10 + (*g_CurCmd - '0');
  416. g_CurCmd++;
  417. }
  418. *g_CurCmd = 0;
  419. if (Proc < g_TargetNumberProcessors)
  420. {
  421. if (Proc != g_RegContextProcessor)
  422. {
  423. if (IS_DUMP_TARGET())
  424. {
  425. SetCurrentProcessorThread(Proc, FALSE);
  426. }
  427. else
  428. {
  429. g_SwitchProcessor = Proc + 1;
  430. g_CmdState = 's';
  431. }
  432. ResetCurrentScope();
  433. }
  434. }
  435. else
  436. {
  437. ErrOut("%d is not a valid processor number\n", Proc);
  438. }
  439. }
  440. /*** CmdHelp - displays the legal commands
  441. *
  442. * Purpose:
  443. * Show user the debuger commands.
  444. *
  445. * Input:
  446. * none
  447. *
  448. * Output:
  449. * None.
  450. *
  451. *************************************************************************/
  452. VOID
  453. CmdHelp(
  454. VOID
  455. )
  456. {
  457. char buf[16];
  458. // Commands available on all platforms and in all modes.
  459. dprintf("\nOpen debugger.chm for complete debugger documentation\n\n");
  460. dprintf("A [<address>] - assemble\n");
  461. dprintf("BC[<bp>] - clear breakpoint(s)\n");
  462. dprintf("BD[<bp>] - disable breakpoint(s)\n");
  463. dprintf("BE[<bp>] - enable breakpoint(s)\n");
  464. dprintf("BL - list breakpoints\n");
  465. dprintf("[thread]BP[#] <address> - set breakpoint\n");
  466. dprintf("C <range> <address> [passes] [command] - compare\n");
  467. dprintf("D[type][<range>] - dump memory\n");
  468. dprintf("DL[B] <address> <maxcount> <size> - dump linked list\n");
  469. dprintf("#[processor] DT [-n|y] [[mod!]name] [[-n|y]fields]\n");
  470. dprintf(" [address] [-l list] [-a[]|c|i|o|r[#]|v] - \n");
  471. dprintf(" dump using type information\n");
  472. dprintf("E[type] <address> [<list>] - enter\n");
  473. dprintf("F <range> <list> - fill\n");
  474. dprintf("[thread]G [=<address> [<address>...]] - go\n");
  475. dprintf("[thread]GH [=<address> [<address>...]] - "
  476. "go with exception handled\n");
  477. dprintf("[thread]GN [=<address> [<address>...]] - "
  478. "go with exception not handled\n");
  479. dprintf("J<expr> [']cmd1['];[']cmd2['] - conditional execution\n");
  480. dprintf("[thread|processor]K[B] <count> - stacktrace\n");
  481. dprintf("KD [<count>] - stack trace with raw data\n");
  482. dprintf("[thread|processor] KV [ <count> | =<reg> ] - "
  483. "stacktrace with FPO data\n");
  484. dprintf("L{+|-}[l|o|s|t|*] - Control source options\n");
  485. dprintf("LD [<module>] - refresh module information\n");
  486. dprintf("LM[k|l|u|v] - list modules\n");
  487. dprintf("LN <expr> - list nearest symbols\n");
  488. dprintf("LS[.] [<first>][,<count>] - List source file lines\n");
  489. dprintf("LSA <addr>[,<first>][,<count>] - "
  490. "List source file lines at addr\n");
  491. dprintf("LSC - Show current source file and line\n");
  492. dprintf("LSF[-] <file> - Load or unload a source file for browsing\n");
  493. dprintf("M <range> <address> - move\n");
  494. dprintf("N [<radix>] - set / show radix\n");
  495. dprintf("[thread]P[R] [=<addr>] [<value>] - program step\n");
  496. dprintf("Q - quit\n");
  497. dprintf("\n");
  498. GetInput("Hit Enter...", buf, sizeof(buf) - 1);
  499. dprintf("\n");
  500. dprintf("[thread|processor]R[F][L][M <expr>] [[<reg> [= <expr>]]] - "
  501. "reg/flag\n");
  502. dprintf("Rm[?] [<expr>] - Control prompt register output mask\n");
  503. dprintf("S <range> <list> - search\n");
  504. dprintf("SQ[e|d] - set quiet mode\n");
  505. dprintf("SS <n | a | w> - set symbol suffix\n");
  506. dprintf("SX [e|d|i|n [<event>|*|<expr>]] - event filtering\n");
  507. dprintf("[thread]T[R] [=<address>] [<expr>] - trace\n");
  508. dprintf("U [<range>] - unassemble\n");
  509. dprintf("version - show debuggee and debugger version\n");
  510. dprintf("vertarget - show debuggee version\n");
  511. dprintf("X [<*|module>!]<*|symbol> - view symbols\n");
  512. dprintf("<commands>; [processor] z(<expression>) - do while true\n");
  513. dprintf("~ - list threads status\n");
  514. dprintf("~#s - set default thread\n");
  515. dprintf("~[.|#|*|ddd]f - freeze thread\n");
  516. dprintf("~[.|#|*|ddd]u - unfreeze thread\n");
  517. dprintf("~[.|#|ddd]k[expr] - backtrace stack\n");
  518. dprintf("| - list processes status\n");
  519. dprintf("|#s - set default process\n");
  520. dprintf("|#<command> - default process override\n");
  521. dprintf("? <expr> - display expression\n");
  522. dprintf("? - command help\n");
  523. dprintf("#<string> [address] - search for a string in the dissasembly\n");
  524. dprintf("$< <filename> - take input from a command file\n");
  525. dprintf("<Enter> - repeat previous command\n");
  526. dprintf("; - command separator\n");
  527. dprintf("*|$ - comment mark\n");
  528. dprintf("\n");
  529. GetInput("Hit Enter...", buf, sizeof(buf) - 1);
  530. dprintf("\n");
  531. dprintf("<expr> unary ops: + - not by wo dwo qwo poi hi low\n");
  532. dprintf(" binary ops: + - * / mod(%%) and(&) xor(^) or(|)\n");
  533. dprintf(" comparisons: == (=) < > !=\n");
  534. dprintf(" operands: number in current radix, "
  535. "public symbol, <reg>\n");
  536. dprintf("<type> : b (byte), w (word), d[s] (doubleword [with symbols]),\n");
  537. dprintf(" a (ascii), c (dword and Char), u (unicode), l (list)\n");
  538. dprintf(" f (float), D (double), s|S (ascii/unicode string)\n");
  539. dprintf(" q (quadword)\n");
  540. dprintf("<pattern> : [(nt | <dll-name>)!]<var-name> "
  541. "(<var-name> can include ? and *)\n");
  542. dprintf("<event> : ct, et, ld, av, cc (see documentation for full list)\n");
  543. dprintf("<radix> : 8, 10, 16\n");
  544. dprintf("<reg> : $u0-$u9, $ea, $exp, $ra, $p\n");
  545. dprintf("<addr> : %%<32-bit address>\n");
  546. dprintf("<range> : <address> <address>\n");
  547. dprintf(" : <address> L <count>\n");
  548. dprintf("<list> : <byte> [<byte> ...]\n");
  549. if (IS_KERNEL_TARGET())
  550. {
  551. dprintf("\n");
  552. dprintf("Kernel-mode options:\n");
  553. dprintf("~<processor>s - change current processor\n");
  554. dprintf("I<b|w|d> <port> - read I/O port\n");
  555. dprintf("O<b|w|d> <port> <expr> - write I/O\n");
  556. dprintf("RDMSR <MSR> - read MSR\n");
  557. dprintf("SO [<options>] - set kernel debugging options\n");
  558. dprintf("UX [<address>] - disassemble X86 BIOS code\n");
  559. dprintf("WRMSR <MSR> - write MSR\n");
  560. dprintf(".cache [size] - set vmem cache size\n");
  561. dprintf(".reboot - reboot target machine\n");
  562. }
  563. switch(g_EffMachine)
  564. {
  565. case IMAGE_FILE_MACHINE_I386:
  566. dprintf("\n");
  567. dprintf("x86 options:\n");
  568. dprintf("BA[#] <e|r|w|i><1|2|4> <addr> - addr bp\n");
  569. dprintf("DG <selector> - dump selector\n");
  570. dprintf("KB = <base> <stack> <ip> - stacktrace from specific state\n");
  571. dprintf("<reg> : [e]ax, [e]bx, [e]cx, [e]dx, [e]si, [e]di, "
  572. "[e]bp, [e]sp, [e]ip, [e]fl,\n");
  573. dprintf(" al, ah, bl, bh, cl, ch, dl, dh, "
  574. "cs, ds, es, fs, gs, ss\n");
  575. dprintf(" dr0, dr1, dr2, dr3, dr6, dr7\n");
  576. if (IS_KERNEL_TARGET())
  577. {
  578. dprintf(" cr0, cr2, cr3, cr4\n");
  579. dprintf(" gdtr, gdtl, idtr, idtl, tr, ldtr\n");
  580. }
  581. else
  582. {
  583. dprintf(" fpcw, fpsw, fptw, st0-st7, mm0-mm7\n");
  584. }
  585. dprintf(" xmm0-xmm7\n");
  586. dprintf("<flag> : iopl, of, df, if, tf, sf, zf, af, pf, cf\n");
  587. dprintf("<addr> : #<16-bit protect-mode [seg:]address>,\n");
  588. dprintf(" &<V86-mode [seg:]address>\n");
  589. break;
  590. case IMAGE_FILE_MACHINE_IA64:
  591. dprintf("\n");
  592. dprintf("IA64 options:\n");
  593. dprintf("BA[#] <r|w><1|2|4|8> <addr> - addr bp\n");
  594. dprintf("<reg> : r2-r31, f2-f127, gp, sp, intnats, preds, brrp, brs0-brs4, brt0, brt1,\n");
  595. dprintf(" dbi0-dbi7, dbd0-dbd7, kpfc0-kpfc7, kpfd0-kpfd7, h16-h31, unat, lc, ec,\n");
  596. dprintf(" ccv, dcr, pfs, bsp, bspstore, rsc, rnat, ipsr, iip, ifs, kr0-kr7, itc,\n");
  597. dprintf(" itm, iva, pta, isr, ifa, itir, iipa, iim, iha, lid, ivr, tpr, eoi,\n");
  598. dprintf(" irr0-irr3, itv, pmv, lrr0, lrr1, cmcv, rr0-rr7, pkr0-pkr15, tri0-tri7,\n");
  599. dprintf(" trd0-trd7\n");
  600. break;
  601. case IMAGE_FILE_MACHINE_ALPHA:
  602. case IMAGE_FILE_MACHINE_AXP64:
  603. dprintf("\n");
  604. dprintf("Alpha options:\n");
  605. dprintf("<reg> : zero, at, v0, a0-a5, t0-t12, s0-s5, fp, gp, sp, ra\n");
  606. dprintf(" fpcr, fir, psr, int0-int5, f0-f31\n");
  607. break;
  608. case IMAGE_FILE_MACHINE_AMD64:
  609. dprintf("\n");
  610. dprintf("x86-64 options:\n");
  611. dprintf("BA[#] <e|r|w|i><1|2|4> <addr> - addr bp\n");
  612. dprintf("DG <selector> - dump selector\n");
  613. dprintf("KB = <base> <stack> <ip> - stacktrace from specific state\n");
  614. dprintf("<reg> : [r|e]ax, [r|e]bx, [r|e]cx, [r|e]dx, [r|e]si, [r|e]di, "
  615. "[r|e]bp, [r|e]sp, [r|e]ip, [e]fl,\n");
  616. dprintf(" r8-r15 with b/w/d subregisters\n");
  617. dprintf(" al, ah, bl, bh, cl, ch, dl, dh, "
  618. "cs, ds, es, fs, gs, ss\n");
  619. dprintf(" sil, dil, bpl, spl\n");
  620. dprintf(" dr0, dr1, dr2, dr3, dr6, dr7\n");
  621. if (IS_KERNEL_TARGET())
  622. {
  623. dprintf(" cr0, cr2, cr3, cr4\n");
  624. dprintf(" gdtr, gdtl, idtr, idtl, tr, ldtr\n");
  625. }
  626. else
  627. {
  628. dprintf(" fpcw, fpsw, fptw, st0-st7, mm0-mm7\n");
  629. }
  630. dprintf(" xmm0-xmm15\n");
  631. dprintf("<flag> : iopl, of, df, if, tf, sf, zf, af, pf, cf\n");
  632. dprintf("<addr> : #<16-bit protect-mode [seg:]address>,\n");
  633. dprintf(" &<V86-mode [seg:]address>\n");
  634. break;
  635. }
  636. dprintf("\nOpen debugger.chm for complete debugger documentation\n\n");
  637. }
  638. /*** ProcessCommands - high-level command processor
  639. *
  640. * Purpose:
  641. * If no command string remains, the user is prompted to
  642. * input one. Once input, this routine parses the string
  643. * into commands and their operands. Error checking is done
  644. * on both commands and operands. Multiple commands may be
  645. * input by separating them with semicolons. Once a command
  646. * is parsefd, the appropriate routine (type fnXXXXX) is called
  647. * to execute the command.
  648. *
  649. * Input:
  650. * g_CurCmd = pointer to the next command in the string
  651. *
  652. * Output:
  653. * None.
  654. *
  655. * Exceptions:
  656. * error exit: SYNTAX - command type or operand error
  657. * normal exit: termination on 'q' command
  658. *
  659. *************************************************************************/
  660. HRESULT
  661. ProcessCommands(DebugClient* Client, BOOL Nested)
  662. {
  663. UCHAR ch;
  664. ADDR addr1;
  665. ADDR addr2;
  666. ULONG64 value1;
  667. ULONG64 value2;
  668. ULONG count;
  669. STACK_TRACE_TYPE traceType;
  670. BOOL fLength;
  671. UCHAR list[STRLISTSIZE];
  672. ULONG size;
  673. PSTR SavedCurCmd;
  674. ULONGLONG valueL;
  675. PPROCESS_INFO pProcessPrevious = NULL;
  676. BOOL parseProcess = FALSE;
  677. CHAR buf[MAX_COMMAND];
  678. HRESULT Status = S_FALSE;
  679. CROSS_PLATFORM_CONTEXT Context;
  680. ULONG State;
  681. if (g_CurrentProcess == NULL ||
  682. g_CurrentProcess->CurrentThread == NULL)
  683. {
  684. WarnOut("WARNING: The debugger does not have a current "
  685. "process or thread\n");
  686. WarnOut("WARNING: Many commands will not work\n");
  687. }
  688. if (!Nested)
  689. {
  690. g_SwitchedProcs = FALSE;
  691. }
  692. do
  693. {
  694. ch = *g_CurCmd++;
  695. if (ch == '\0' ||
  696. (ch == ';' && (g_EngStatus & ENG_STATUS_USER_INTERRUPT)))
  697. {
  698. if (!Nested)
  699. {
  700. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  701. g_BreakpointsSuspended = FALSE;
  702. }
  703. Status = S_OK;
  704. // Back up to terminating character in
  705. // case command processing is reentered without
  706. // resetting things.
  707. g_CurCmd--;
  708. break;
  709. }
  710. EVALUATE:
  711. while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' ||
  712. ch == ';')
  713. {
  714. ch = *g_CurCmd++;
  715. }
  716. if (IS_KERNEL_TARGET())
  717. {
  718. if (g_TargetNumberProcessors > MAXIMUM_PROCESSORS)
  719. {
  720. WarnOut("WARNING: Number of processors corrupted - using 1\n");
  721. g_TargetNumberProcessors = 1;
  722. }
  723. if (ch >= '0' && ch <= '9')
  724. {
  725. if (IS_KERNEL_TRIAGE_DUMP())
  726. {
  727. ErrOut("Can't switch processors on a Triage dump\n");
  728. error(SYNTAX);
  729. }
  730. value1 = 0;
  731. SavedCurCmd = g_CurCmd;
  732. while (ch >= '0' && ch <= '9')
  733. {
  734. value1 = value1 * 10 + (ch - '0');
  735. ch = *SavedCurCmd++;
  736. }
  737. ch = (UCHAR)tolower(ch);
  738. if (ch == 'r' || ch == 'k' || ch == 'z' ||
  739. (ch == 'd' && tolower(*SavedCurCmd) == 't'))
  740. {
  741. if (value1 < g_TargetNumberProcessors)
  742. {
  743. if (value1 != g_RegContextProcessor)
  744. {
  745. SaveSetCurrentProcessorThread((ULONG)value1);
  746. g_SwitchedProcs = TRUE;
  747. }
  748. }
  749. else
  750. {
  751. error(BADRANGE);
  752. }
  753. }
  754. else
  755. {
  756. error(SYNTAX);
  757. }
  758. g_CurCmd = SavedCurCmd;
  759. }
  760. }
  761. g_PrefixSymbols = FALSE;
  762. switch (ch = (UCHAR)tolower(ch))
  763. {
  764. case '?':
  765. if ((ch = PeekChar()) == '\0' || ch == ';')
  766. {
  767. CmdHelp();
  768. }
  769. else
  770. {
  771. EvaluateExp(FALSE);
  772. }
  773. break;
  774. case '$':
  775. if ( *g_CurCmd++ == '<')
  776. {
  777. ExecuteCommandFile(Client, (PCSTR)g_CurCmd,
  778. DEBUG_EXECUTE_ECHO);
  779. }
  780. *g_CurCmd = 0;
  781. break;
  782. case '~':
  783. if (IS_USER_TARGET())
  784. {
  785. if (Nested)
  786. {
  787. ErrOut("Ignoring recursive thread command\n");
  788. break;
  789. }
  790. parseThreadCmds(Client);
  791. }
  792. else
  793. {
  794. ParseProcessorCommands();
  795. }
  796. break;
  797. case '|':
  798. if (IS_KERNEL_TARGET())
  799. {
  800. break;
  801. }
  802. if (!parseProcess)
  803. {
  804. parseProcess = TRUE;
  805. pProcessPrevious = g_CurrentProcess;
  806. }
  807. parseProcessCmds();
  808. if (!*g_CurCmd)
  809. {
  810. parseProcess = FALSE;
  811. }
  812. else
  813. {
  814. ch = *g_CurCmd++;
  815. goto EVALUATE;
  816. }
  817. break;
  818. case '.':
  819. SavedCurCmd = g_CurCmd;
  820. strcpy(buf, g_CurCmd);
  821. if (!DotCommand(Client))
  822. {
  823. g_CurCmd = SavedCurCmd;
  824. strcpy(g_CurCmd, buf);
  825. fnBangCmd(Client, g_CurCmd, &g_CurCmd, TRUE);
  826. }
  827. break;
  828. case '!':
  829. fnBangCmd(Client, g_CurCmd, &g_CurCmd, FALSE);
  830. break;
  831. case '*':
  832. while (*g_CurCmd != '\0')
  833. {
  834. g_CurCmd++;
  835. }
  836. break;
  837. case '#':
  838. g_PrefixSymbols = TRUE;
  839. igrep();
  840. g_PrefixSymbols = FALSE;
  841. while (*g_CurCmd != '\0')
  842. {
  843. g_CurCmd++;
  844. }
  845. break;
  846. case 'a':
  847. //
  848. // Alias command or just default to pre-existing
  849. // assemble command.
  850. //
  851. ch = *g_CurCmd++;
  852. switch (tolower(ch))
  853. {
  854. // Alias list
  855. case 'l':
  856. ListAliases();
  857. break;
  858. // Alias set
  859. case 's':
  860. ParseSetAlias();
  861. break;
  862. // Alias delete
  863. case 'd':
  864. ParseDeleteAlias();
  865. break;
  866. // Pre-existing assemble command
  867. default:
  868. if ((ch = PeekChar()) != '\0' && ch != ';')
  869. {
  870. GetAddrExpression(SEGREG_CODE, &g_AssemDefault);
  871. }
  872. fnAssemble(&g_AssemDefault);
  873. break;
  874. }
  875. break;
  876. case 'b':
  877. ch = *g_CurCmd++;
  878. ch = (UCHAR)tolower(ch);
  879. if (!IS_EXECUTION_POSSIBLE())
  880. {
  881. error(SESSIONNOTSUP);
  882. }
  883. switch(ch)
  884. {
  885. case 'p':
  886. case 'u':
  887. case 'a':
  888. case 'i':
  889. case 'w':
  890. ParseBpCmd(Client, ch, NULL);
  891. break;
  892. case 'c':
  893. case 'd':
  894. case 'e':
  895. value1 = GetIdList();
  896. ChangeBreakpointState(Client, g_CurrentProcess,
  897. (ULONG)value1, ch);
  898. break;
  899. case 'l':
  900. if (PeekChar() != ';' && *g_CurCmd)
  901. {
  902. value1 = GetIdList();
  903. }
  904. else
  905. {
  906. value1 = ALL_ID_LIST;
  907. }
  908. ListBreakpoints(Client, g_CurrentProcess, (ULONG)value1);
  909. break;
  910. default:
  911. error(SYNTAX);
  912. break;
  913. }
  914. break;
  915. case 'c':
  916. GetRange(&addr1, &value2, 1, SEGREG_DATA);
  917. GetAddrExpression(SEGREG_DATA, &addr2);
  918. fnCompareMemory(&addr1, (ULONG)value2, &addr2);
  919. break;
  920. case 'd':
  921. parseDumpCommand();
  922. break;
  923. case 'e':
  924. parseEnterCommand();
  925. break;
  926. case 'f':
  927. ParseFillMemory();
  928. break;
  929. case 'g':
  930. parseGoCmd(NULL, FALSE);
  931. break;
  932. case 'i':
  933. ch = (UCHAR)tolower(*g_CurCmd);
  934. g_CurCmd++;
  935. if (ch != 'b' && ch != 'w' && ch != 'd')
  936. {
  937. error(SYNTAX);
  938. }
  939. if (IS_USER_TARGET() || IS_DUMP_TARGET())
  940. {
  941. error(SESSIONNOTSUP);
  942. }
  943. fnInputIo((ULONG)GetExpression(), ch);
  944. break;
  945. case 'j':
  946. PSTR pch, Start;
  947. if (GetExpression())
  948. {
  949. pch = g_CurCmd;
  950. // Find a semicolon or a quote
  951. while (*pch && *pch != ';' && *pch != '\'')
  952. {
  953. pch++;
  954. }
  955. if (*pch == ';')
  956. {
  957. *pch = 0;
  958. }
  959. else if (*pch)
  960. {
  961. *pch = ' ';
  962. // Find the closing quote
  963. while (*pch && *pch != '\'')
  964. {
  965. pch++;
  966. }
  967. *pch = 0;
  968. }
  969. }
  970. else
  971. {
  972. Start = pch = g_CurCmd;
  973. // Find a semicolon or a quote
  974. while (*pch && *pch != ';' && *pch != '\'')
  975. {
  976. pch++;
  977. }
  978. if (*pch == ';')
  979. {
  980. Start = ++pch;
  981. }
  982. else if (*pch)
  983. {
  984. pch++;
  985. while (*pch && *pch++ != '\'')
  986. {
  987. // Empty.
  988. }
  989. while (*pch && (*pch == ';' || *pch == ' '))
  990. {
  991. pch++;
  992. }
  993. Start = pch;
  994. }
  995. while (*pch && *pch != ';' && *pch != '\'')
  996. {
  997. pch++;
  998. }
  999. if (*pch == ';')
  1000. {
  1001. *pch = 0;
  1002. }
  1003. else if (*pch)
  1004. {
  1005. *pch = ' ';
  1006. // Find the closing quote
  1007. while (*pch && *pch != '\'')
  1008. {
  1009. pch++;
  1010. }
  1011. *pch = 0;
  1012. }
  1013. g_CurCmd = Start;
  1014. }
  1015. ch = *g_CurCmd++;
  1016. goto EVALUATE;
  1017. case 'k':
  1018. {
  1019. if (IS_LOCAL_KERNEL_TARGET())
  1020. {
  1021. error(SESSIONNOTSUP);
  1022. }
  1023. if (!IS_CONTEXT_ACCESSIBLE())
  1024. {
  1025. error(BADTHREAD);
  1026. }
  1027. DEBUG_SCOPE_STATE SaveCurrCtxtState = g_ScopeBuffer.State;
  1028. value1 = 0;
  1029. if (g_SwitchedProcs)
  1030. {
  1031. g_ScopeBuffer.State = ScopeDefault;
  1032. }
  1033. PCROSS_PLATFORM_CONTEXT ScopeContext;
  1034. if (ScopeContext = GetCurrentScopeContext())
  1035. {
  1036. g_Machine->PushContext(ScopeContext);
  1037. }
  1038. if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
  1039. {
  1040. value2 = GetRegVal64(X86_EIP);
  1041. }
  1042. else
  1043. {
  1044. value2 = 0;
  1045. }
  1046. count = g_DefaultStackTraceDepth;
  1047. ParseStackTrace(&traceType, &addr2, &value1, &value2, &count);
  1048. if (ScopeContext)
  1049. {
  1050. g_Machine->PopContext();
  1051. }
  1052. if (count >= 0x10000)
  1053. {
  1054. ErrOut("Requested number of stack frames (0x%x) is too large! "
  1055. "The maximum number is 0xffff.\n",
  1056. count);
  1057. error(BADRANGE);
  1058. }
  1059. DoStackTrace( addr2.off, value1, value2, count, traceType );
  1060. if (g_SwitchedProcs)
  1061. {
  1062. RestoreCurrentProcessorThread();
  1063. g_SwitchedProcs = FALSE;
  1064. g_ScopeBuffer.State = SaveCurrCtxtState;
  1065. }
  1066. break;
  1067. }
  1068. case 'l':
  1069. ch = (UCHAR)tolower(*g_CurCmd);
  1070. if (ch == 'n')
  1071. {
  1072. g_CurCmd++;
  1073. if ((ch = PeekChar()) != '\0' && ch != ';')
  1074. {
  1075. GetAddrExpression(SEGREG_CODE, &addr1);
  1076. }
  1077. else
  1078. {
  1079. PCROSS_PLATFORM_CONTEXT ScopeContext =
  1080. GetCurrentScopeContext();
  1081. if (ScopeContext)
  1082. {
  1083. g_Machine->PushContext(ScopeContext);
  1084. }
  1085. g_Machine->GetPC(&addr1);
  1086. if (ScopeContext)
  1087. {
  1088. g_Machine->PopContext();
  1089. }
  1090. }
  1091. fnListNear(Flat(addr1));
  1092. }
  1093. else if (ch == '+' || ch == '-')
  1094. {
  1095. g_CurCmd++;
  1096. ParseSrcOptCmd(ch);
  1097. }
  1098. else if (ch == 's')
  1099. {
  1100. g_CurCmd++;
  1101. ch = (UCHAR)tolower(*g_CurCmd);
  1102. if (ch == 'f')
  1103. {
  1104. g_CurCmd++;
  1105. ParseSrcLoadCmd();
  1106. }
  1107. else if (ch == 'p')
  1108. {
  1109. g_CurCmd++;
  1110. ParseOciSrcCmd();
  1111. }
  1112. else
  1113. {
  1114. ParseSrcListCmd(ch);
  1115. }
  1116. }
  1117. else if (ch == 'm')
  1118. {
  1119. ParseDumpModuleTable();
  1120. }
  1121. else if (ch == 'd')
  1122. {
  1123. g_CurCmd++;
  1124. ParseLoadModules();
  1125. }
  1126. else
  1127. {
  1128. error(SYNTAX);
  1129. }
  1130. break;
  1131. case 'm':
  1132. {
  1133. ADDR TempAddr;
  1134. GetRange(&addr1, &value2, 1, SEGREG_DATA);
  1135. GetAddrExpression(SEGREG_DATA, &TempAddr);
  1136. fnMoveMemory(&addr1, (ULONG)value2, &TempAddr);
  1137. }
  1138. break;
  1139. case 'n':
  1140. if ((ch = PeekChar()) != '\0' && ch != ';')
  1141. {
  1142. if (ch == '8')
  1143. {
  1144. g_CurCmd++;
  1145. g_DefaultRadix = 8;
  1146. }
  1147. else if (ch == '1')
  1148. {
  1149. ch = *++g_CurCmd;
  1150. if (ch == '0' || ch == '6')
  1151. {
  1152. g_CurCmd++;
  1153. g_DefaultRadix = 10 + ch - '0';
  1154. }
  1155. else
  1156. {
  1157. error(SYNTAX);
  1158. }
  1159. }
  1160. else
  1161. {
  1162. error(SYNTAX);
  1163. }
  1164. NotifyChangeEngineState(DEBUG_CES_RADIX, g_DefaultRadix,
  1165. TRUE);
  1166. }
  1167. dprintf("base is %ld\n", g_DefaultRadix);
  1168. break;
  1169. case 'o':
  1170. ch = (UCHAR)tolower(*g_CurCmd);
  1171. g_CurCmd++;
  1172. if (ch == 'b')
  1173. {
  1174. value2 = 1;
  1175. }
  1176. else if (ch == 'w')
  1177. {
  1178. value2 = 2;
  1179. }
  1180. else if (ch == 'd')
  1181. {
  1182. value2 = 4;
  1183. }
  1184. else
  1185. {
  1186. error(SYNTAX);
  1187. }
  1188. if (IS_USER_TARGET() || IS_DUMP_TARGET())
  1189. {
  1190. error(SESSIONNOTSUP);
  1191. }
  1192. value1 = GetExpression();
  1193. value2 = HexValue((ULONG)value2);
  1194. fnOutputIo((ULONG)value1, (ULONG)value2, ch);
  1195. break;
  1196. case 'w':
  1197. case 'p':
  1198. case 't':
  1199. if (IS_KERNEL_TARGET())
  1200. {
  1201. if (ch == 'w' &&
  1202. tolower(g_CurCmd[0]) == 'r' &&
  1203. tolower(g_CurCmd[1]) == 'm' &&
  1204. tolower(g_CurCmd[2]) == 's' &&
  1205. tolower(g_CurCmd[3]) == 'r')
  1206. {
  1207. g_CurCmd +=4;
  1208. value1 = GetExpression();
  1209. if (g_Target->WriteMsr ((ULONG)value1,
  1210. HexValue(8)) != S_OK)
  1211. {
  1212. ErrOut ("no such msr\n");
  1213. }
  1214. break;
  1215. }
  1216. }
  1217. parseStepTrace(NULL, FALSE, ch);
  1218. break;
  1219. case 'q':
  1220. UCHAR QuitArgument;
  1221. QuitArgument = (UCHAR)tolower(PeekChar());
  1222. if ((IS_LIVE_USER_TARGET() && QuitArgument == 'd') ||
  1223. QuitArgument == 'k' || QuitArgument == 'q')
  1224. {
  1225. g_CurCmd++;
  1226. }
  1227. if (PeekChar() != 0)
  1228. {
  1229. error(SYNTAX);
  1230. }
  1231. if (QuitArgument != 'q' &&
  1232. Client != NULL &&
  1233. (Client->m_Flags & CLIENT_REMOTE))
  1234. {
  1235. ErrOut("Exit a remote client with Ctrl-b<enter>.\nIf you "
  1236. "really want the server to quit use 'qq'.\n");
  1237. break;
  1238. }
  1239. // Detach if requested.
  1240. if (QuitArgument == 'd')
  1241. {
  1242. DBG_ASSERT(IS_LIVE_USER_TARGET());
  1243. // If detach isn't supported warn the user
  1244. // and abort the quit.
  1245. if (((UserTargetInfo*)g_Target)->m_Services->
  1246. DetachProcess(0) != S_OK)
  1247. {
  1248. ErrOut("The system doesn't support detach\n");
  1249. break;
  1250. }
  1251. if (g_SessionThread &&
  1252. GetCurrentThreadId() != g_SessionThread)
  1253. {
  1254. ErrOut("Detach can only be done by the server\n");
  1255. break;
  1256. }
  1257. HRESULT DetachStatus;
  1258. if (FAILED(DetachStatus = DetachProcesses()))
  1259. {
  1260. ErrOut("Detach failed, 0x%X\n", DetachStatus);
  1261. }
  1262. }
  1263. else if ((g_GlobalProcOptions &
  1264. DEBUG_PROCESS_DETACH_ON_EXIT) ||
  1265. (g_AllProcessFlags & ENG_PROC_EXAMINED))
  1266. {
  1267. HRESULT PrepareStatus;
  1268. // We need to restart the program before we
  1269. // quit so that it's put back in a running state.
  1270. PrepareStatus = PrepareForSeparation();
  1271. if (PrepareStatus != S_OK)
  1272. {
  1273. ErrOut("Unable to prepare process for detach, "
  1274. "0x%X\n", PrepareStatus);
  1275. break;
  1276. }
  1277. }
  1278. dprintf("quit:\n");
  1279. // Force engine into a no-debuggee state
  1280. // to indicate quit.
  1281. g_CmdState = 'q';
  1282. g_EngStatus |= ENG_STATUS_STOP_SESSION;
  1283. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  1284. DEBUG_STATUS_NO_DEBUGGEE, TRUE);
  1285. break;
  1286. case 'r':
  1287. if (IS_KERNEL_TARGET())
  1288. {
  1289. if (tolower(g_CurCmd[0]) == 'd' &&
  1290. tolower(g_CurCmd[1]) == 'm' &&
  1291. tolower(g_CurCmd[2]) == 's' &&
  1292. tolower(g_CurCmd[3]) == 'r')
  1293. {
  1294. g_CurCmd +=4;
  1295. value1 = GetExpression();
  1296. if (g_Target->ReadMsr((ULONG)value1, &valueL) == S_OK)
  1297. {
  1298. dprintf ("msr[%x] = %08x:%08x\n",
  1299. (ULONG)value1, (ULONG) (valueL >> 32),
  1300. (ULONG) valueL);
  1301. }
  1302. else
  1303. {
  1304. ErrOut ("no such msr\n");
  1305. }
  1306. break;
  1307. }
  1308. }
  1309. PCROSS_PLATFORM_CONTEXT ScopeContext;
  1310. if (ScopeContext = GetCurrentScopeContext())
  1311. {
  1312. dprintf("Last set context:\n");
  1313. g_Machine->PushContext(ScopeContext);
  1314. }
  1315. __try
  1316. {
  1317. ParseRegCmd();
  1318. }
  1319. __finally
  1320. {
  1321. if (ScopeContext)
  1322. {
  1323. g_Machine->PopContext();
  1324. }
  1325. if (g_SwitchedProcs)
  1326. {
  1327. RestoreCurrentProcessorThread();
  1328. g_SwitchedProcs = FALSE;
  1329. }
  1330. }
  1331. break;
  1332. case 's':
  1333. ch = (UCHAR)tolower(*g_CurCmd);
  1334. if (ch == 's')
  1335. {
  1336. g_CurCmd++;
  1337. SetSuffix();
  1338. }
  1339. else if (ch == 'q')
  1340. {
  1341. g_CurCmd++;
  1342. ch = (UCHAR)tolower(*g_CurCmd);
  1343. if (ch == 'e')
  1344. {
  1345. g_QuietMode = TRUE;
  1346. g_CurCmd++;
  1347. }
  1348. else if (ch == 'd')
  1349. {
  1350. g_QuietMode = FALSE;
  1351. g_CurCmd++;
  1352. }
  1353. else
  1354. {
  1355. g_QuietMode = !g_QuietMode;
  1356. }
  1357. dprintf("Quiet mode is %s\n", g_QuietMode ? "ON" : "OFF");
  1358. }
  1359. else if (ch == 'x')
  1360. {
  1361. g_CurCmd++;
  1362. ParseSetEventFilter(Client);
  1363. }
  1364. else if (IS_KERNEL_TARGET() && ch == 'o')
  1365. {
  1366. PSTR pch = ++g_CurCmd;
  1367. while ((*pch != '\0') && (*pch != ';'))
  1368. {
  1369. pch++;
  1370. }
  1371. ch = *pch;
  1372. *pch = '\0';
  1373. ReadDebugOptions(FALSE, (*g_CurCmd == '\0' ?
  1374. NULL : g_CurCmd));
  1375. *pch = ch;
  1376. g_CurCmd = pch;
  1377. }
  1378. else
  1379. {
  1380. // s, s-w, s-d, s-q.
  1381. ParseSearchMemory();
  1382. }
  1383. break;
  1384. case 'u':
  1385. g_PrefixSymbols = TRUE;
  1386. ch = (UCHAR)tolower(*g_CurCmd);
  1387. if (IS_KERNEL_TARGET() && ch == 'x')
  1388. {
  1389. g_CurCmd += 1;
  1390. }
  1391. value1 = Flat(g_UnasmDefault);
  1392. value2 = (g_EffMachine == IMAGE_FILE_MACHINE_IA64) ? 9 : 8;
  1393. fLength = GetRange(&g_UnasmDefault, &value2, 0, SEGREG_CODE);
  1394. if (IS_KERNEL_TARGET() && ch == 'x')
  1395. {
  1396. ADDR addr;
  1397. char text[MAX_DISASM_LEN];
  1398. if (g_X86BiosBaseAddress == 0)
  1399. {
  1400. g_X86BiosBaseAddress =
  1401. (ULONG)ExtGetExpression("hal!HalpEisaMemoryBase");
  1402. ADDRFLAT(&addr, g_X86BiosBaseAddress);
  1403. GetMemString(&addr, (PUCHAR)&g_X86BiosBaseAddress, 4);
  1404. }
  1405. addr = g_UnasmDefault;
  1406. addr.flat += (g_X86BiosBaseAddress + (addr.seg<<4));
  1407. addr.off = addr.flat;
  1408. addr.type = ADDR_V86 | INSTR_POINTER;
  1409. for (value2 = 0; value2 < 8; value2++)
  1410. {
  1411. g_X86Machine.Disassemble( &addr, text, TRUE );
  1412. addr.flat = addr.off;
  1413. dprintf("%s", text );
  1414. }
  1415. g_UnasmDefault = addr;
  1416. g_UnasmDefault.off -=
  1417. (g_X86BiosBaseAddress + (addr.seg<<4));
  1418. g_UnasmDefault.flat = g_UnasmDefault.off;
  1419. }
  1420. else
  1421. {
  1422. fnUnassemble(&g_UnasmDefault,
  1423. value2,
  1424. fLength);
  1425. }
  1426. break;
  1427. case 'v':
  1428. if (_stricmp(g_CurCmd, "ertarget") == 0)
  1429. {
  1430. g_CurCmd += strlen(g_CurCmd);
  1431. g_Target->OutputVersion();
  1432. }
  1433. else if (_stricmp(g_CurCmd, "ersion") == 0)
  1434. {
  1435. g_CurCmd += strlen(g_CurCmd);
  1436. // Print target version, then debugger version.
  1437. g_Target->OutputVersion();
  1438. OutputVersionInformation(Client);
  1439. }
  1440. else
  1441. {
  1442. error(SYNTAX);
  1443. }
  1444. break;
  1445. case 'x':
  1446. ParseExamine();
  1447. break;
  1448. case ';':
  1449. case '\0':
  1450. g_CurCmd--;
  1451. break;
  1452. case 'z':
  1453. // Works like do{ cmds }while(Cond);
  1454. // Eg. p;z(eax<2);
  1455. if (CheckUserInterrupt())
  1456. {
  1457. // Eat the expression also to prevent
  1458. // spurious extra character errors.
  1459. GetExpression();
  1460. g_RedoCount = 0;
  1461. break;
  1462. }
  1463. if (GetExpression())
  1464. {
  1465. g_CurCmd = g_CommandStart;
  1466. ++g_RedoCount;
  1467. dprintf("redo [%d] %s\n", g_RedoCount, g_CurCmd );
  1468. FlushCallbacks();
  1469. ch = *g_CurCmd++;
  1470. goto EVALUATE;
  1471. }
  1472. else
  1473. {
  1474. g_RedoCount = 0;
  1475. }
  1476. break;
  1477. default:
  1478. error(SYNTAX);
  1479. break;
  1480. }
  1481. do
  1482. {
  1483. ch = *g_CurCmd++;
  1484. } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
  1485. if (ch != ';' && ch != '\0')
  1486. {
  1487. error(EXTRACHARS);
  1488. }
  1489. g_CurCmd--;
  1490. }
  1491. while (g_CmdState == 'c');
  1492. if (Status == S_FALSE)
  1493. {
  1494. PSTR Scan = g_CurCmd;
  1495. // We switched to a non-'c' cmdState so the
  1496. // loop was exited. Check and see if we're
  1497. // also at the end of the command as that will
  1498. // take precedence in what the return value is.
  1499. while (*Scan == ' ' || *Scan == '\t' || *Scan == ';')
  1500. {
  1501. Scan++;
  1502. }
  1503. Status = *Scan ? S_FALSE : S_OK;
  1504. }
  1505. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  1506. return Status;
  1507. }
  1508. HRESULT
  1509. ProcessCommandsAndCatch(DebugClient* Client)
  1510. {
  1511. HRESULT Status;
  1512. __try
  1513. {
  1514. Status = ProcessCommands(Client, FALSE);
  1515. }
  1516. __except(CommandExceptionFilter(GetExceptionInformation()))
  1517. {
  1518. g_CurCmd = g_CommandStart;
  1519. *g_CurCmd = '\0';
  1520. g_LastCommand[0] = '\0';
  1521. Status = E_FAIL;
  1522. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  1523. }
  1524. return Status;
  1525. }
  1526. /*** fnEvaluateExp - evaluate expression
  1527. *
  1528. * Purpose:
  1529. * Function for the "?<exp>" command.
  1530. *
  1531. * Evaluate the expression and output it in both
  1532. * hexadecimal and decimal.
  1533. *
  1534. * Input:
  1535. * g_CurCmd - pointer to operand in command line
  1536. *
  1537. * Output:
  1538. * None.
  1539. *
  1540. *************************************************************************/
  1541. void
  1542. EvaluateExp (
  1543. BOOL Verbose
  1544. )
  1545. {
  1546. LONG64 Value;
  1547. LONG Val32;
  1548. BOOL Use64;
  1549. Value = GetExpression();
  1550. // Allow 64-bit expressions to be evaluated even on
  1551. // 32-bit platforms since they can also use 64-bit numbers.
  1552. Use64 = g_Machine->m_Ptr64 || NeedUpper(Value);
  1553. Val32 = (LONG)Value;
  1554. if (!Verbose)
  1555. {
  1556. if (Use64)
  1557. {
  1558. dprintf("Evaluate expression: %I64d = %08x`%08x\n",
  1559. Value, (ULONG)(Value >> 32), Val32);
  1560. }
  1561. else
  1562. {
  1563. dprintf("Evaluate expression: %d = %08x\n",
  1564. Val32, Val32);
  1565. }
  1566. }
  1567. else
  1568. {
  1569. dprintf("Evaluate expression:\n");
  1570. if (Use64)
  1571. {
  1572. dprintf(" Hex: %08x`%08x\n", (ULONG)(Value >> 32), Val32);
  1573. dprintf(" Decimal: %I64d\n", Value);
  1574. }
  1575. else
  1576. {
  1577. dprintf(" Hex: %08x\n", Val32);
  1578. dprintf(" Decimal: %d\n", Val32);
  1579. }
  1580. ULONG Shift = Use64 ? 63 : 30;
  1581. dprintf(" Octal: ");
  1582. for (;;)
  1583. {
  1584. dprintf("%c", ((Value >> Shift) & 7) + '0');
  1585. if (Shift == 0)
  1586. {
  1587. break;
  1588. }
  1589. Shift -= 3;
  1590. }
  1591. dprintf("\n");
  1592. Shift = Use64 ? 63 : 31;
  1593. dprintf(" Binary: ");
  1594. for (;;)
  1595. {
  1596. if ((Shift & 7) == 7)
  1597. {
  1598. dprintf(" ");
  1599. }
  1600. dprintf("%c", ((Value >> Shift) & 1) + '0');
  1601. if (Shift == 0)
  1602. {
  1603. break;
  1604. }
  1605. Shift--;
  1606. }
  1607. dprintf("\n");
  1608. Shift = Use64 ? 56 : 24;
  1609. dprintf(" Chars: ");
  1610. for (;;)
  1611. {
  1612. Val32 = (LONG)((Value >> Shift) & 0xff);
  1613. if (Val32 >= ' ' && Val32 <= 127)
  1614. {
  1615. dprintf("%c", Val32);
  1616. }
  1617. else
  1618. {
  1619. dprintf(".");
  1620. }
  1621. if (Shift == 0)
  1622. {
  1623. break;
  1624. }
  1625. Shift -= 8;
  1626. }
  1627. dprintf("\n");
  1628. }
  1629. }
  1630. void
  1631. ScanForImages(void)
  1632. {
  1633. ULONG64 Handle = 0;
  1634. MEMORY_BASIC_INFORMATION64 Info;
  1635. BOOL Verbose = FALSE;
  1636. //
  1637. // Scan virtual memory looking for image headers.
  1638. //
  1639. while (g_Target->QueryMemoryRegion(&Handle, FALSE, &Info) == S_OK)
  1640. {
  1641. ULONG64 Addr;
  1642. if (Verbose)
  1643. {
  1644. dprintf("Checking %s - %s\n",
  1645. FormatAddr64(Info.BaseAddress),
  1646. FormatAddr64(Info.BaseAddress + Info.RegionSize - 1));
  1647. FlushCallbacks();
  1648. }
  1649. //
  1650. // Check for MZ at the beginning of every page.
  1651. //
  1652. Addr = Info.BaseAddress;
  1653. while (Addr < Info.BaseAddress + Info.RegionSize)
  1654. {
  1655. USHORT ShortSig;
  1656. ULONG Done;
  1657. if (g_Target->ReadVirtual(Addr, &ShortSig, sizeof(ShortSig),
  1658. &Done) == S_OK &&
  1659. Done == sizeof(ShortSig) &&
  1660. ShortSig == IMAGE_DOS_SIGNATURE)
  1661. {
  1662. dprintf(" MZ at %s, prot %08X, type %08X\n",
  1663. FormatAddr64(Addr), Info.Protect, Info.Type);
  1664. FlushCallbacks();
  1665. }
  1666. if (CheckUserInterrupt())
  1667. {
  1668. WarnOut(" Aborted\n");
  1669. return;
  1670. }
  1671. Addr += g_Machine->m_PageSize;
  1672. }
  1673. }
  1674. }
  1675. void
  1676. OutputMemRegion(ULONG64 Addr)
  1677. {
  1678. ULONG64 Handle = Addr;
  1679. MEMORY_BASIC_INFORMATION64 Info;
  1680. if (g_Target->QueryMemoryRegion(&Handle, TRUE, &Info) == S_OK)
  1681. {
  1682. dprintf("Region %s - %s, prot %08X, type %08X\n",
  1683. FormatAddr64(Info.BaseAddress),
  1684. FormatAddr64(Info.BaseAddress + Info.RegionSize - 1),
  1685. Info.Protect, Info.Type);
  1686. }
  1687. else
  1688. {
  1689. dprintf("No region contains %s\n", FormatAddr64(Addr));
  1690. }
  1691. }
  1692. void
  1693. SetEffMachineByName(void)
  1694. {
  1695. if (PeekChar() != ';' && *g_CurCmd)
  1696. {
  1697. PSTR Name = g_CurCmd;
  1698. while (*g_CurCmd && *g_CurCmd != ';' && !isspace(*g_CurCmd))
  1699. {
  1700. g_CurCmd++;
  1701. }
  1702. if (*g_CurCmd)
  1703. {
  1704. *g_CurCmd++ = 0;
  1705. }
  1706. ULONG Machine;
  1707. if (Name[0] == '.' && Name[1] == 0)
  1708. {
  1709. // Reset to target machine.
  1710. Machine = g_TargetMachineType;
  1711. }
  1712. else if (Name[0] == '#' && Name[1] == 0)
  1713. {
  1714. // Reset to executing machine.
  1715. Machine = g_TargetExecMachine;
  1716. }
  1717. else
  1718. {
  1719. for (Machine = 0; Machine < MACHIDX_COUNT; Machine++)
  1720. {
  1721. if (!_strcmpi(Name, g_AllMachines[Machine]->m_AbbrevName))
  1722. {
  1723. break;
  1724. }
  1725. }
  1726. if (Machine >= MACHIDX_COUNT)
  1727. {
  1728. ErrOut("Unknown machine '%s'\n", Name);
  1729. return;
  1730. }
  1731. Machine = g_AllMachines[Machine]->m_ExecTypes[0];
  1732. }
  1733. SetEffMachine(Machine, TRUE);
  1734. }
  1735. if (g_Machine != NULL)
  1736. {
  1737. dprintf("Effective machine: %s (%s)\n",
  1738. g_Machine->m_FullName, g_Machine->m_AbbrevName);
  1739. }
  1740. else
  1741. {
  1742. dprintf("No effective machine\n");
  1743. }
  1744. }
  1745. void
  1746. ListProcesses(void)
  1747. {
  1748. BOOL ListCurrent = FALSE;
  1749. BOOL Verbose = FALSE;
  1750. if (!IS_LIVE_USER_TARGET())
  1751. {
  1752. error(SESSIONNOTSUP);
  1753. }
  1754. while (PeekChar() == '-' || *g_CurCmd == '/')
  1755. {
  1756. switch(*++g_CurCmd)
  1757. {
  1758. case 'c':
  1759. if (g_CurrentProcess == NULL)
  1760. {
  1761. error(BADPROCESS);
  1762. }
  1763. ListCurrent = TRUE;
  1764. break;
  1765. case 'v':
  1766. Verbose = TRUE;
  1767. break;
  1768. default:
  1769. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1770. break;
  1771. }
  1772. g_CurCmd++;
  1773. }
  1774. PUSER_DEBUG_SERVICES Services = ((UserTargetInfo*)g_Target)->m_Services;
  1775. #define MAX_IDS 1024
  1776. ULONG Ids[MAX_IDS];
  1777. HRESULT Status;
  1778. ULONG IdCount;
  1779. ULONG i;
  1780. char DescBuf[2 * MAX_PATH];
  1781. PSTR Desc;
  1782. ULONG DescLen;
  1783. if (ListCurrent)
  1784. {
  1785. Ids[0] = g_CurrentProcess->SystemId;
  1786. IdCount = 1;
  1787. }
  1788. else
  1789. {
  1790. if ((Status = Services->GetProcessIds(Ids, MAX_IDS, &IdCount)) != S_OK)
  1791. {
  1792. ErrOut("Unable to get process list, %s\n",
  1793. FormatStatusCode(Status));
  1794. return;
  1795. }
  1796. if (IdCount > MAX_IDS)
  1797. {
  1798. WarnOut("Process list missing %d processes\n",
  1799. IdCount - MAX_IDS);
  1800. IdCount = MAX_IDS;
  1801. }
  1802. }
  1803. if (Verbose)
  1804. {
  1805. Desc = DescBuf;
  1806. DescLen = sizeof(DescBuf);
  1807. }
  1808. else
  1809. {
  1810. Desc = NULL;
  1811. DescLen = 0;
  1812. }
  1813. for (i = 0; i < IdCount; i++)
  1814. {
  1815. char ExeName[MAX_PATH];
  1816. int Space;
  1817. if (Ids[i] < 10)
  1818. {
  1819. Space = 3;
  1820. }
  1821. else if (Ids[i] < 100)
  1822. {
  1823. Space = 2;
  1824. }
  1825. else if (Ids[i] < 1000)
  1826. {
  1827. Space = 1;
  1828. }
  1829. else
  1830. {
  1831. Space = 0;
  1832. }
  1833. dprintf("%.*s", Space, " ");
  1834. if (FAILED(Status = Services->
  1835. GetProcessDescription(Ids[i], DEBUG_PROC_DESC_DEFAULT,
  1836. ExeName, sizeof(ExeName), NULL,
  1837. Desc, DescLen, NULL)))
  1838. {
  1839. ErrOut("0n%d Error %s\n", Ids[i], FormatStatusCode(Status));
  1840. }
  1841. else if (Ids[i] >= 0x80000000)
  1842. {
  1843. dprintf("0x%x %s\n", Ids[i], ExeName);
  1844. }
  1845. else
  1846. {
  1847. dprintf("0n%d %s\n", Ids[i], ExeName);
  1848. }
  1849. if (Desc && Desc[0])
  1850. {
  1851. dprintf(" %s\n", Desc);
  1852. }
  1853. }
  1854. }
  1855. void
  1856. EchoString(void)
  1857. {
  1858. CHAR Save;
  1859. PSTR Str;
  1860. Str = StringValue(STRV_TRIM_TRAILING_SPACE, &Save);
  1861. dprintf("%s\n", Str);
  1862. *g_CurCmd = Save;
  1863. }
  1864. void
  1865. ParseAttachProcess(void)
  1866. {
  1867. ULONG Pid;
  1868. ULONG Flags = DEBUG_ATTACH_DEFAULT;
  1869. while (PeekChar() == '-' || *g_CurCmd == '/')
  1870. {
  1871. switch(*++g_CurCmd)
  1872. {
  1873. case 'e':
  1874. Flags = DEBUG_ATTACH_EXISTING;
  1875. break;
  1876. case 'v':
  1877. Flags = DEBUG_ATTACH_NONINVASIVE;
  1878. break;
  1879. default:
  1880. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1881. break;
  1882. }
  1883. g_CurCmd++;
  1884. }
  1885. Pid = (ULONG)GetExpression();
  1886. PPENDING_PROCESS Pending;
  1887. HRESULT Status;
  1888. Status = StartAttachProcess(Pid, Flags, &Pending);
  1889. if (Status == S_OK)
  1890. {
  1891. dprintf("Attach will occur on next execution\n");
  1892. }
  1893. }
  1894. void
  1895. ParseOutputFunctionEntry(void)
  1896. {
  1897. if (!IS_MACHINE_ACCESSIBLE())
  1898. {
  1899. error(BADTHREAD);
  1900. }
  1901. BOOL SymDirect = FALSE;
  1902. while (PeekChar() == '-' || *g_CurCmd == '/')
  1903. {
  1904. switch(*++g_CurCmd)
  1905. {
  1906. case 's':
  1907. SymDirect = TRUE;
  1908. break;
  1909. default:
  1910. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1911. break;
  1912. }
  1913. g_CurCmd++;
  1914. }
  1915. ULONG64 Addr = GetExpression();
  1916. PVOID FnEnt;
  1917. if (SymDirect)
  1918. {
  1919. FnEnt = SymFunctionTableAccess64(g_CurrentProcess->Handle, Addr);
  1920. }
  1921. else
  1922. {
  1923. FnEnt = SwFunctionTableAccess(g_CurrentProcess->Handle, Addr);
  1924. }
  1925. if (FnEnt == NULL)
  1926. {
  1927. ErrOut("No function entry for %s\n", FormatAddr64(Addr));
  1928. return;
  1929. }
  1930. dprintf("%s function entry %s for:\n",
  1931. SymDirect ? "Symbol" : "Debugger", FormatAddr64((ULONG_PTR)FnEnt));
  1932. fnListNear(Addr);
  1933. dprintf("\n");
  1934. g_Machine->OutputFunctionEntry(FnEnt);
  1935. }
  1936. void
  1937. ParseOutputFilter(void)
  1938. {
  1939. if (PeekChar() != ';' && *g_CurCmd)
  1940. {
  1941. g_OutFilterResult = TRUE;
  1942. while (PeekChar() == '-' || *g_CurCmd == '/')
  1943. {
  1944. switch(*++g_CurCmd)
  1945. {
  1946. case '!':
  1947. g_OutFilterResult = FALSE;
  1948. break;
  1949. default:
  1950. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1951. break;
  1952. }
  1953. g_CurCmd++;
  1954. }
  1955. CHAR Save;
  1956. PSTR Pat = StringValue(STRV_TRIM_TRAILING_SPACE |
  1957. STRV_ESCAPED_CHARACTERS, &Save);
  1958. if (strlen(Pat) + 1 > sizeof(g_OutFilterPattern))
  1959. {
  1960. error(OVERFLOW);
  1961. }
  1962. strcpy(g_OutFilterPattern, Pat);
  1963. *g_CurCmd = Save;
  1964. _strupr(g_OutFilterPattern);
  1965. }
  1966. if (g_OutFilterPattern[0])
  1967. {
  1968. dprintf("Only display debuggee output that %s '%s'\n",
  1969. g_OutFilterResult ? "matches" : "doesn't match",
  1970. g_OutFilterPattern);
  1971. }
  1972. else
  1973. {
  1974. dprintf("No debuggee output filter set\n");
  1975. }
  1976. }
  1977. void
  1978. ParseSeparateCurrentProcess(PSTR Command)
  1979. {
  1980. HRESULT Status;
  1981. ULONG Mode;
  1982. char Desc[128];
  1983. if (!strcmp(Command, "abandon"))
  1984. {
  1985. Mode = SEP_ABANDON;
  1986. }
  1987. else if (!strcmp(Command, "detach"))
  1988. {
  1989. Mode = SEP_DETACH;
  1990. }
  1991. else if (!strcmp(Command, "kill"))
  1992. {
  1993. Mode = SEP_TERMINATE;
  1994. }
  1995. else
  1996. {
  1997. error(SYNTAX);
  1998. }
  1999. if ((Status = SeparateCurrentProcess(Mode, Desc)) == S_OK)
  2000. {
  2001. dprintf("%s\n", Desc);
  2002. }
  2003. else if (Status == E_NOTIMPL)
  2004. {
  2005. dprintf("The system doesn't support %s\n", Command);
  2006. }
  2007. else
  2008. {
  2009. dprintf("Unable to %s, %s\n",
  2010. Command, FormatStatusCode(Status));
  2011. }
  2012. }
  2013. void
  2014. ParseSetChildDebug(void)
  2015. {
  2016. if (!IS_LIVE_USER_TARGET())
  2017. {
  2018. error(SESSIONNOTSUP);
  2019. }
  2020. if (g_CurrentProcess == NULL)
  2021. {
  2022. error(BADTHREAD);
  2023. }
  2024. HRESULT Status;
  2025. PUSER_DEBUG_SERVICES Services = ((UserTargetInfo*)g_Target)->m_Services;
  2026. ULONG Opts;
  2027. Opts = g_CurrentProcess->Options;
  2028. if (PeekChar() && *g_CurCmd != ';')
  2029. {
  2030. ULONG64 Val = GetExpression();
  2031. if (Val)
  2032. {
  2033. Opts &= ~DEBUG_PROCESS_ONLY_THIS_PROCESS;
  2034. }
  2035. else
  2036. {
  2037. Opts |= DEBUG_PROCESS_ONLY_THIS_PROCESS;
  2038. }
  2039. if ((Status = Services->SetProcessOptions(g_CurrentProcess->FullHandle,
  2040. Opts)) != S_OK)
  2041. {
  2042. if (Status == E_NOTIMPL)
  2043. {
  2044. ErrOut("The system doesn't support changing the flag\n");
  2045. }
  2046. else
  2047. {
  2048. ErrOut("Unable to set process options, %s\n",
  2049. FormatStatusCode(Status));
  2050. }
  2051. return;
  2052. }
  2053. g_CurrentProcess->Options = Opts;
  2054. }
  2055. dprintf("Processes created by the current process will%s be debugged\n",
  2056. (Opts & DEBUG_PROCESS_ONLY_THIS_PROCESS) ? " not" : "");
  2057. }
  2058. /*** fnDotCmdHelp - displays the legal dot commands
  2059. *
  2060. * Purpose:
  2061. * Show user the dot commands.
  2062. *
  2063. * Input:
  2064. * none
  2065. *
  2066. * Output:
  2067. * None.
  2068. *
  2069. *************************************************************************/
  2070. VOID
  2071. fnDotCmdHelp(
  2072. VOID
  2073. )
  2074. {
  2075. dprintf(". commands:\n");
  2076. dprintf(" .abandon - abandon the current process\n");
  2077. dprintf(" .asm[-] [options...] - change disassembly options\n");
  2078. if (IS_LIVE_USER_TARGET())
  2079. {
  2080. dprintf(" .attach <proc> - attach to <proc> at next execution\n");
  2081. dprintf(" .breakin - break into KD\n");
  2082. }
  2083. if (IS_KERNEL_TARGET())
  2084. {
  2085. dprintf(" .bugcheck - display the bugcheck code and parameters for a crashed\n");
  2086. dprintf(" system\n");
  2087. }
  2088. dprintf(" .chain - list current extensions\n");
  2089. dprintf(" .childdbg <0|~0> - turn child process debugging on or off\n");
  2090. dprintf(" .clients - list currently active clients\n");
  2091. if (IS_KERNEL_TARGET())
  2092. {
  2093. dprintf(" .context [<address>] - set page directory base\n");
  2094. dprintf(" .crash - cause target to bugcheck\n");
  2095. }
  2096. if (IS_LIVE_USER_TARGET())
  2097. {
  2098. dprintf(" .create <command line> - create a new process\n");
  2099. }
  2100. dprintf(" .cxr <address> - dump context record at specified address\n"
  2101. " k* after this gives cxr stack\n");
  2102. if (IS_LIVE_USER_TARGET())
  2103. {
  2104. dprintf(" .detach - detach from the current process\n");
  2105. }
  2106. dprintf(" .dump [options] filename - create a dump file on the host system\n");
  2107. dprintf(" .echo [\"string\"|string] - Echo string\n");
  2108. dprintf(" .ecxr - dump context record for current exception\n");
  2109. dprintf(" .enable_unicode [0/1] - dump USHORT array/pointers and unicode strings\n");
  2110. if (IS_REMOTE_USER_TARGET())
  2111. {
  2112. dprintf(" .endpsrv - cause the current session's process server to exit\n");
  2113. }
  2114. dprintf(" .exepath [dir[;...]] - set executable search path\n");
  2115. dprintf(" .exepath+ [dir[;...]] - append executable search path\n");
  2116. dprintf(" .exr <address> - dump exception record at specified address\n");
  2117. dprintf(" .fnent <address> - dump function entry for the given code address\n");
  2118. dprintf(" .formats <expr> - displays expression result in many formats\n");
  2119. dprintf(" .help - display this help\n");
  2120. dprintf(" .kframes <count> - set default stack trace depth\n");
  2121. if (IS_LIVE_USER_TARGET())
  2122. {
  2123. dprintf(" .kill - kill the current process\n");
  2124. }
  2125. dprintf(" .lastevent - display the last event that occurred\n");
  2126. dprintf(" .lines - toggle line symbol loading\n");
  2127. dprintf(" .logfile - display log status\n");
  2128. dprintf(" .logopen [<file>] - open new log file\n");
  2129. dprintf(" .logappend [<file>] - append to log file\n");
  2130. dprintf(" .logclose - close log file\n");
  2131. dprintf(" .noshell - Disable shell commands\n");
  2132. dprintf(" .noversion - disable extension version checking\n");
  2133. dprintf(" .ofilter <pattern> - filter debuggee output against the given pattern\n");
  2134. dprintf(" .process [<address>] - Sets implicit process\n"
  2135. " Resets default if no address specified.\n");
  2136. if (IS_REMOTE_KERNEL_TARGET())
  2137. {
  2138. dprintf(" .reboot - reboot target\n");
  2139. }
  2140. dprintf(" .reload [filename[=<address>]] - reload symbols\n");
  2141. dprintf(" .remote <pipename> - start remote.exe server\n");
  2142. dprintf(" .server <options> - start engine server\n");
  2143. dprintf(" .sleep <milliseconds> - debugger sleeps for given duration\n");
  2144. dprintf(" Useful for allowing access to a machine that's broken in on an ntsd -d.\n");
  2145. dprintf(" .srcpath [dir[;...]] - set source search path\n");
  2146. dprintf(" .srcpath+ [dir[;...]] - append source search path\n");
  2147. dprintf(" .sympath [dir[;...]] - set symbol search path\n");
  2148. dprintf(" .sympath+ [dir[;...]] - append symbol search path\n");
  2149. dprintf(" .shell [<command>] - execute shell command\n");
  2150. if (IS_LIVE_USER_TARGET())
  2151. {
  2152. dprintf(" .tlist - list running processes\n");
  2153. }
  2154. if (IS_KERNEL_TARGET())
  2155. {
  2156. dprintf(" .trap <address> - Dump a trap frame\n");
  2157. if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
  2158. {
  2159. dprintf(" .tss <selector> - Dump a Task State Segment\n");
  2160. }
  2161. }
  2162. dprintf(" .thread [<address>] - Sets context of thread at address\n"
  2163. " Resets default context if no address specified.\n");
  2164. dprintf("\n");
  2165. dprintf("The following can be used with any extension module:\n");
  2166. dprintf(" .load\n");
  2167. dprintf(" .setdll\n");
  2168. dprintf(" .unload\n");
  2169. dprintf(" .unloadall\n");
  2170. dprintf("\n");
  2171. }
  2172. /*** fnDotCommand - parse and execute dot command
  2173. *
  2174. * Purpose:
  2175. * Parse and execute all commands starting with a dot ('.').
  2176. *
  2177. * Input:
  2178. * g_CurCmd - pointer to character after dot in command line
  2179. *
  2180. * Output:
  2181. * None.
  2182. *
  2183. *************************************************************************/
  2184. #define MAX_DOT_COMMAND 16
  2185. BOOL
  2186. DotCommand(
  2187. DebugClient* Client
  2188. )
  2189. {
  2190. ULONG index = 0;
  2191. char chCmd[MAX_DOT_COMMAND];
  2192. UCHAR ch;
  2193. ADDR tempAddr;
  2194. HRESULT Status;
  2195. ULONG64 Value;
  2196. // read in up to the first few alpha characters into
  2197. // chCmd, converting to lower case
  2198. while (index < MAX_DOT_COMMAND)
  2199. {
  2200. ch = (UCHAR)tolower(*g_CurCmd);
  2201. if ((ch >= 'a' && ch <= 'z') || ch == '-' || ch == '+' || ch == '_')
  2202. {
  2203. chCmd[index++] = ch;
  2204. g_CurCmd++;
  2205. }
  2206. else
  2207. {
  2208. break;
  2209. }
  2210. }
  2211. // if all characters read, then too big, else terminate
  2212. if (index == MAX_DOT_COMMAND)
  2213. {
  2214. error(SYNTAX);
  2215. }
  2216. chCmd[index] = '\0';
  2217. // test for the commands
  2218. if (!strcmp(chCmd, "asm") || !strcmp(chCmd, "asm-"))
  2219. {
  2220. ChangeAsmOptions(chCmd[3] != '-', g_CurCmd);
  2221. // Command uses the whole string so we're done.
  2222. *g_CurCmd = 0;
  2223. }
  2224. else if (!strcmp(chCmd, "x"))
  2225. {
  2226. dprintf("Pending %X, process %X\n",
  2227. g_AllPendingFlags, g_AllProcessFlags);
  2228. }
  2229. else if (!strcmp(chCmd, "bpcmds"))
  2230. {
  2231. ULONG Flags = 0;
  2232. PPROCESS_INFO Process = g_CurrentProcess;
  2233. ULONG Id;
  2234. while (PeekChar() == '-')
  2235. {
  2236. switch(*(++g_CurCmd))
  2237. {
  2238. case '1':
  2239. Flags |= BPCMDS_ONE_LINE;
  2240. break;
  2241. case 'd':
  2242. Flags |= BPCMDS_FORCE_DISABLE;
  2243. break;
  2244. case 'e':
  2245. Flags |= BPCMDS_EXPR_ONLY;
  2246. break;
  2247. case 'm':
  2248. Flags |= BPCMDS_MODULE_HINT;
  2249. break;
  2250. case 'p':
  2251. g_CurCmd++;
  2252. Id = (ULONG)GetTermExprDesc("Process ID missing from");
  2253. Process = FindProcessByUserId(Id);
  2254. if (!Process)
  2255. {
  2256. error(BADPROCESS);
  2257. }
  2258. g_CurCmd--;
  2259. break;
  2260. default:
  2261. dprintf("Unknown option '%c'\n", *g_CurCmd);
  2262. break;
  2263. }
  2264. g_CurCmd++;
  2265. }
  2266. // Internal command only.
  2267. ListBreakpointsAsCommands(Client, Process, Flags);
  2268. }
  2269. else if (!strcmp(chCmd, "bpsync"))
  2270. {
  2271. if (PeekChar() && *g_CurCmd != ';')
  2272. {
  2273. if (GetExpression())
  2274. {
  2275. g_EngOptions |= DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS;
  2276. }
  2277. else
  2278. {
  2279. g_EngOptions &= ~DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS;
  2280. }
  2281. }
  2282. dprintf("Breakpoint synchronization %s\n",
  2283. (g_EngOptions & DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS) ?
  2284. "enabled" : "disabled");
  2285. }
  2286. else if (!strcmp(chCmd, "childdbg"))
  2287. {
  2288. ParseSetChildDebug();
  2289. }
  2290. else if (!strcmp(chCmd, "clients"))
  2291. {
  2292. DebugClient* Cur;
  2293. for (Cur = g_Clients; Cur != NULL; Cur = Cur->m_Next)
  2294. {
  2295. if (Cur->m_Flags & CLIENT_PRIMARY)
  2296. {
  2297. dprintf("%s, last active %s",
  2298. Cur->m_Identity, ctime(&Cur->m_LastActivity));
  2299. }
  2300. }
  2301. }
  2302. else if (!strcmp(chCmd, "cxr"))
  2303. {
  2304. ULONG Flags = 0;
  2305. ULONG64 ContextBase = 0;
  2306. if (PeekChar())
  2307. {
  2308. ContextBase = GetExpression();
  2309. }
  2310. if (ContextBase)
  2311. {
  2312. OutputVirtualContext(ContextBase, REGALL_INT32 | REGALL_INT64 |
  2313. (g_EffMachine == IMAGE_FILE_MACHINE_I386 ?
  2314. REGALL_EXTRA0 : 0));
  2315. }
  2316. else if (GetCurrentScopeContext())
  2317. {
  2318. dprintf("Resetting default context\n");
  2319. ResetCurrentScope();
  2320. }
  2321. }
  2322. else if (!strcmp(chCmd, "dump"))
  2323. {
  2324. ParseDumpFileCommand();
  2325. }
  2326. else if (!strcmp(chCmd, "dumpdebug"))
  2327. {
  2328. if (IS_DUMP_TARGET())
  2329. {
  2330. //
  2331. // Dump detailed statistics to debug dump files
  2332. //
  2333. ((DumpTargetInfo *)g_Target)->DumpDebug();
  2334. }
  2335. else
  2336. {
  2337. error(SESSIONNOTSUP);
  2338. }
  2339. }
  2340. else if (!strcmp(chCmd, "dumpoff"))
  2341. {
  2342. if (IS_DUMP_TARGET())
  2343. {
  2344. //
  2345. // Show the file offset for a VA.
  2346. //
  2347. ULONG64 Addr = GetExpression();
  2348. ULONG64 Offs;
  2349. ULONG File;
  2350. ULONG Avail;
  2351. Offs = ((DumpTargetInfo*)g_Target)->
  2352. VirtualToOffset(Addr, &File, &Avail);
  2353. dprintf("Virtual %s maps to file %d offset %I64x\n",
  2354. FormatAddr64(Addr), File, Offs);
  2355. }
  2356. else
  2357. {
  2358. error(SESSIONNOTSUP);
  2359. }
  2360. }
  2361. else if (!strcmp(chCmd, "dumppoff"))
  2362. {
  2363. if (IS_KERNEL_SUMMARY_DUMP() || IS_KERNEL_FULL_DUMP())
  2364. {
  2365. //
  2366. // Show the file offset for a physical address.
  2367. //
  2368. ULONG64 Addr = GetExpression();
  2369. ULONG Avail;
  2370. dprintf("Physical %I64x maps to file offset %I64x\n",
  2371. Addr, ((KernelFullSumDumpTargetInfo *)g_Target)->
  2372. PhysicalToOffset(Addr, &Avail));
  2373. }
  2374. else
  2375. {
  2376. error(SESSIONNOTSUP);
  2377. }
  2378. }
  2379. else if (!strcmp(chCmd, "echo"))
  2380. {
  2381. EchoString();
  2382. }
  2383. else if (!strcmp(chCmd, "ecxr"))
  2384. {
  2385. CROSS_PLATFORM_CONTEXT Context;
  2386. if ((Status = g_Target->GetExceptionContext(&Context)) != S_OK)
  2387. {
  2388. ErrOut("Unable to get exception context, 0x%X\n", Status);
  2389. }
  2390. else
  2391. {
  2392. OutputContext(&Context, REGALL_INT32 | REGALL_INT64 |
  2393. (g_EffMachine == IMAGE_FILE_MACHINE_I386 ?
  2394. REGALL_EXTRA0 : 0));
  2395. }
  2396. }
  2397. else if (!strcmp(chCmd, "effmach"))
  2398. {
  2399. SetEffMachineByName();
  2400. }
  2401. else if (!strcmp(chCmd, "enable_unicode"))
  2402. {
  2403. g_EnableUnicode = (BOOL) GetExpression();
  2404. if (g_EnableUnicode)
  2405. {
  2406. g_TypeOptions |= DEBUG_TYPEOPTS_UNICODE_DISPLAY;
  2407. } else
  2408. {
  2409. g_TypeOptions &= ~DEBUG_TYPEOPTS_UNICODE_DISPLAY;
  2410. }
  2411. // Callback to update locals and watch window
  2412. NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
  2413. }
  2414. else if (IS_REMOTE_USER_TARGET() && !strcmp(chCmd, "endpsrv"))
  2415. {
  2416. ((UserTargetInfo*)g_Target)->m_Services->Uninitialize(TRUE);
  2417. dprintf("Server told to exit\n");
  2418. }
  2419. else if (!strcmp(chCmd, "exr"))
  2420. {
  2421. DumpExr(GetExpression());
  2422. }
  2423. else if (!strcmp(chCmd, "esplog"))
  2424. {
  2425. extern ULONG g_EspLog[];
  2426. extern PULONG g_EspLogCur;
  2427. ULONG i;
  2428. PULONG Cur = g_EspLogCur;
  2429. // XXX drewb - Temporary log to try and catch some
  2430. // SET_OF_INVALID_CONTEXT bugchecks occurring randomly on x86.
  2431. for (i = 0; i < 32; i++)
  2432. {
  2433. if (Cur <= g_EspLog)
  2434. {
  2435. Cur = g_EspLog + 64;
  2436. }
  2437. Cur -= 2;
  2438. if ((*Cur & 0x80000000) == 0)
  2439. {
  2440. // Unused slot.
  2441. break;
  2442. }
  2443. if (*Cur & 0x40000000)
  2444. {
  2445. dprintf("%2d: Set proc %2d: %08X\n",
  2446. i, *Cur & 0xffff, Cur[1]);
  2447. }
  2448. else
  2449. {
  2450. dprintf("%2d: Get proc %2d: %08X\n",
  2451. i, *Cur & 0xffff, Cur[1]);
  2452. }
  2453. }
  2454. }
  2455. else if (!strcmp(chCmd, "eventlog"))
  2456. {
  2457. OutputEventLog();
  2458. }
  2459. else if (!strcmp(chCmd, "fnent"))
  2460. {
  2461. ParseOutputFunctionEntry();
  2462. }
  2463. else if (!strcmp(chCmd, "formats"))
  2464. {
  2465. EvaluateExp(TRUE);
  2466. }
  2467. else if (!_stricmp( chCmd, "frame" ))
  2468. {
  2469. dotFrame();
  2470. PrintStackFrame(&GetCurrentScope()->Frame,
  2471. DEBUG_STACK_FRAME_ADDRESSES |
  2472. DEBUG_STACK_FRAME_NUMBERS |
  2473. DEBUG_STACK_SOURCE_LINE);
  2474. }
  2475. else if (!strcmp(chCmd, "help"))
  2476. {
  2477. fnDotCmdHelp();
  2478. }
  2479. else if (!strcmp(chCmd, "imgscan"))
  2480. {
  2481. ScanForImages();
  2482. }
  2483. #if _ENABLE_DOT_K_COMMANDS
  2484. else if (chCmd[0] == 'k')
  2485. {
  2486. fnStackTrace(&chCmd[1]);
  2487. }
  2488. #endif
  2489. else if (IS_CONN_KERNEL_TARGET() && !strcmp(chCmd, "kdtrans"))
  2490. {
  2491. g_DbgKdTransport->OutputInfo();
  2492. }
  2493. else if (IS_CONN_KERNEL_TARGET() && !strcmp(chCmd, "kdfiles"))
  2494. {
  2495. ParseKdFileAssoc();
  2496. }
  2497. else if (!strcmp(chCmd, "kframes"))
  2498. {
  2499. g_DefaultStackTraceDepth = (ULONG)GetExpression();
  2500. dprintf("Default stack trace depth is 0n%d frames\n",
  2501. g_DefaultStackTraceDepth);
  2502. }
  2503. else if (!strcmp(chCmd, "lastevent"))
  2504. {
  2505. dprintf("Last event: %s\n", g_LastEventDesc);
  2506. }
  2507. else if (!strcmp(chCmd, "logappend"))
  2508. {
  2509. fnLogOpen(TRUE);
  2510. }
  2511. else if (!strcmp(chCmd, "logclose"))
  2512. {
  2513. fnLogClose();
  2514. }
  2515. else if (!strcmp(chCmd, "logfile"))
  2516. {
  2517. if (g_LogFile >= 0)
  2518. {
  2519. dprintf("Log '%s' open%s\n",
  2520. g_OpenLogFileName,
  2521. g_OpenLogFileAppended ? " for append" : "");
  2522. }
  2523. else
  2524. {
  2525. dprintf("No log file open\n");
  2526. }
  2527. }
  2528. else if (!strcmp(chCmd, "logopen"))
  2529. {
  2530. fnLogOpen(FALSE);
  2531. }
  2532. else if (!strcmp(chCmd, "memregion"))
  2533. {
  2534. OutputMemRegion(GetExpression());
  2535. }
  2536. else if (!strcmp(chCmd, "noengerr"))
  2537. {
  2538. // Internal command to clear out the error suppression
  2539. // flags in case we want to rerun operations and check
  2540. // for errors that may be in suppression mode.
  2541. g_EngErr = 0;
  2542. }
  2543. else if (!strcmp(chCmd, "noshell"))
  2544. {
  2545. g_EngOptions |= DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS;
  2546. dprintf("Shell commands disabled\n");
  2547. }
  2548. else if (!strcmp(chCmd, "ofilter"))
  2549. {
  2550. ParseOutputFilter();
  2551. }
  2552. else if (!strcmp(chCmd, "outmask") ||
  2553. !strcmp(chCmd, "outmask-"))
  2554. {
  2555. // Private internal command for debugging the debugger.
  2556. ULONG Expr = (ULONG)GetExpression();
  2557. if (chCmd[7] == '-')
  2558. {
  2559. Client->m_OutMask &= ~Expr;
  2560. }
  2561. else
  2562. {
  2563. Client->m_OutMask |= Expr;
  2564. }
  2565. dprintf("Client %p mask is %X\n", Client, Client->m_OutMask);
  2566. CollectOutMasks();
  2567. }
  2568. else if (!strcmp(chCmd, "echotimestamps"))
  2569. {
  2570. g_EchoEventTimestamps = !g_EchoEventTimestamps;
  2571. dprintf("Event timestamps are now %s\n",
  2572. g_EchoEventTimestamps ? "enabled" : "disabled");
  2573. }
  2574. else if (!strcmp(chCmd, "process"))
  2575. {
  2576. ParseSetImplicitProcess();
  2577. }
  2578. else if (!strcmp(chCmd, "server"))
  2579. {
  2580. // Skip whitespace.
  2581. if (PeekChar() == 0)
  2582. {
  2583. ErrOut("Usage: .server tcp:port=<Socket> OR "
  2584. ".server npipe:pipe=<PipeName>\n");
  2585. }
  2586. else
  2587. {
  2588. Status = Client->StartServer(g_CurCmd);
  2589. if (Status != S_OK)
  2590. {
  2591. ErrOut("Unable to start server, 0x%X\n", Status);
  2592. }
  2593. else
  2594. {
  2595. dprintf("Server started with '%s'\n", g_CurCmd);
  2596. }
  2597. *g_CurCmd = 0;
  2598. }
  2599. }
  2600. else if (!strcmp(chCmd, "shell"))
  2601. {
  2602. fnShell(g_CurCmd);
  2603. // Command uses the whole string so we're done.
  2604. *g_CurCmd = 0;
  2605. }
  2606. else if (!strcmp(chCmd, "sleep"))
  2607. {
  2608. ULONG WaitStatus;
  2609. ULONG Millis =
  2610. (ULONG)GetExprDesc("Number of milliseconds missing from");
  2611. // This command is intended for use with ntsd/cdb -d
  2612. // when being at the prompt locks up the target machine.
  2613. // If you want to use the target machine for something,
  2614. // such as copy symbols, there's no easy way to get it
  2615. // running again without resuming the program. By
  2616. // sleeping you can return control to the target machine
  2617. // without changing the session state.
  2618. // The sleep is done with a wait on a named event so
  2619. // that it can be interrupted from a different process.
  2620. ResetEvent(g_SleepPidEvent);
  2621. WaitStatus = WaitForSingleObject(g_SleepPidEvent, Millis);
  2622. if (WaitStatus == WAIT_OBJECT_0)
  2623. {
  2624. dprintf("Sleep interrupted\n");
  2625. }
  2626. else if (WaitStatus != WAIT_TIMEOUT)
  2627. {
  2628. ErrOut("Sleep failed, %s\n",
  2629. FormatStatusCode(WIN32_LAST_STATUS()));
  2630. }
  2631. }
  2632. else if (!strcmp(chCmd, "sxcmds"))
  2633. {
  2634. ULONG Flags = 0;
  2635. while (PeekChar() == '-')
  2636. {
  2637. switch(*(++g_CurCmd))
  2638. {
  2639. case '1':
  2640. Flags |= SXCMDS_ONE_LINE;
  2641. break;
  2642. default:
  2643. dprintf("Unknown option '%c'\n", *g_CurCmd);
  2644. break;
  2645. }
  2646. g_CurCmd++;
  2647. }
  2648. // Internal command only.
  2649. ListFiltersAsCommands(Client, Flags);
  2650. }
  2651. else if (!strcmp(chCmd, "symopt+") ||
  2652. !strcmp(chCmd, "symopt-"))
  2653. {
  2654. ULONG Flags = (ULONG)GetExpression();
  2655. if (chCmd[6] == '+')
  2656. {
  2657. Flags |= g_SymOptions;
  2658. }
  2659. else
  2660. {
  2661. Flags = g_SymOptions & ~Flags;
  2662. }
  2663. dprintf("Symbol options are %X\n", Flags);
  2664. SetSymOptions(Flags);
  2665. }
  2666. else if (!strcmp(chCmd, "thread"))
  2667. {
  2668. ParseSetImplicitThread();
  2669. }
  2670. else if (!strcmp(chCmd, "time"))
  2671. {
  2672. g_Target->OutputTime();
  2673. }
  2674. else if (!strcmp(chCmd, "wake"))
  2675. {
  2676. ULONG Pid = (ULONG)GetExpression();
  2677. if (!SetPidEvent(Pid, OPEN_EXISTING))
  2678. {
  2679. ErrOut("Process %d is not a sleeping debugger\n", Pid);
  2680. }
  2681. }
  2682. else if ((IS_REMOTE_KERNEL_TARGET() || IS_REMOTE_USER_TARGET()) &&
  2683. !strcmp(chCmd, "cache"))
  2684. {
  2685. g_VirtualCache.ParseCommands();
  2686. }
  2687. else if (IS_REMOTE_KERNEL_TARGET() &&
  2688. !strcmp(chCmd, "pcache"))
  2689. {
  2690. g_PhysicalCache.ParseCommands();
  2691. }
  2692. else if (IS_KERNEL_TARGET())
  2693. {
  2694. if (!strcmp(chCmd, "trap"))
  2695. {
  2696. ULONG64 frame = 0 ;
  2697. CROSS_PLATFORM_CONTEXT Context;
  2698. if (PeekChar())
  2699. {
  2700. frame = GetExpression();
  2701. }
  2702. if (frame)
  2703. {
  2704. g_TargetMachine->DisplayTrapFrame(frame, &Context);
  2705. SetCurrentScope(&g_LastRegFrame, &Context, sizeof(Context));
  2706. }
  2707. else if (GetCurrentScopeContext())
  2708. {
  2709. dprintf("Resetting default context\n");
  2710. ResetCurrentScope();
  2711. }
  2712. }
  2713. else if ((g_EffMachine == IMAGE_FILE_MACHINE_I386) &&
  2714. !strcmp(chCmd, "tss"))
  2715. {
  2716. g_X86Machine.DumpTSS();
  2717. }
  2718. else if (!IS_LOCAL_KERNEL_TARGET())
  2719. {
  2720. if (!strcmp(chCmd, "bugcheck"))
  2721. {
  2722. ULONG Code;
  2723. ULONG64 Args[4];
  2724. g_Target->ReadBugCheckData(&Code, Args);
  2725. dprintf("Bugcheck code %08X\n", Code);
  2726. dprintf("Arguments %s %s %s %s\n",
  2727. FormatAddr64(Args[0]), FormatAddr64(Args[1]),
  2728. FormatAddr64(Args[2]), FormatAddr64(Args[3]));
  2729. }
  2730. else if (!IS_DUMP_TARGET())
  2731. {
  2732. if (!strcmp(chCmd, "pagein"))
  2733. {
  2734. ParsePageIn();
  2735. }
  2736. else if (!strcmp(chCmd, "reboot") && ch == '\0')
  2737. {
  2738. // null out .reboot command
  2739. g_LastCommand[0] = '\0';
  2740. g_Target->Reboot();
  2741. }
  2742. else if (IS_CONN_KERNEL_TARGET() &&
  2743. !strcmp(chCmd, "crash"))
  2744. {
  2745. g_LastCommand[0] = '\0';
  2746. DbgKdCrash( CRASH_BUGCHECK_CODE );
  2747. // Go back to waiting for a state change to
  2748. // receive the bugcheck exception.
  2749. g_CmdState = 's';
  2750. }
  2751. else
  2752. {
  2753. return FALSE;
  2754. }
  2755. }
  2756. else
  2757. {
  2758. return FALSE;
  2759. }
  2760. }
  2761. else
  2762. {
  2763. return FALSE;
  2764. }
  2765. }
  2766. else if (IS_LIVE_USER_TARGET())
  2767. {
  2768. if (!strcmp(chCmd, "abandon") ||
  2769. !strcmp(chCmd, "detach") ||
  2770. !strcmp(chCmd, "kill"))
  2771. {
  2772. ParseSeparateCurrentProcess(chCmd);
  2773. }
  2774. else if (!strcmp(chCmd, "attach"))
  2775. {
  2776. ParseAttachProcess();
  2777. }
  2778. else if (!strcmp(chCmd, "breakin"))
  2779. {
  2780. if (g_DebuggerPlatformId == VER_PLATFORM_WIN32_NT)
  2781. {
  2782. if (g_SystemVersion <= NT_SVER_NT4)
  2783. {
  2784. // SysDbgBreakPoint isn't supported, so
  2785. // try to use user32's PrivateKDBreakPoint.
  2786. if (InitDynamicCalls(&g_User32CallsDesc) == S_OK &&
  2787. g_User32Calls.PrivateKDBreakPoint != NULL)
  2788. {
  2789. g_User32Calls.PrivateKDBreakPoint();
  2790. }
  2791. else
  2792. {
  2793. ErrOut(".breakin is not supported on this system\n");
  2794. }
  2795. }
  2796. else
  2797. {
  2798. NTSTATUS NtStatus;
  2799. NtStatus = g_NtDllCalls.NtSystemDebugControl
  2800. (SysDbgBreakPoint, NULL, 0, NULL, 0, NULL);
  2801. if (NtStatus == STATUS_ACCESS_DENIED)
  2802. {
  2803. ErrOut(".breakin requires debug privilege\n");
  2804. }
  2805. else if (NtStatus == STATUS_INVALID_INFO_CLASS)
  2806. {
  2807. ErrOut(".breakin is not supported on this system\n");
  2808. }
  2809. else if (!NT_SUCCESS(NtStatus))
  2810. {
  2811. ErrOut(".breakin failed, 0x%X\n", NtStatus);
  2812. }
  2813. }
  2814. }
  2815. else
  2816. {
  2817. ErrOut(".breakin not supported on this platform\n");
  2818. }
  2819. }
  2820. else if (!strcmp(chCmd, "create"))
  2821. {
  2822. PPENDING_PROCESS Pending;
  2823. PSTR CmdLine;
  2824. CHAR Save;
  2825. CmdLine = StringValue(STRV_TRIM_TRAILING_SPACE, &Save);
  2826. Status = StartCreateProcess(CmdLine, DEBUG_ONLY_THIS_PROCESS,
  2827. &Pending);
  2828. if (Status == S_OK)
  2829. {
  2830. dprintf("Create will proceed with next execution\n");
  2831. }
  2832. *g_CurCmd = Save;
  2833. }
  2834. else if (!strcmp(chCmd, "tlist"))
  2835. {
  2836. ListProcesses();
  2837. }
  2838. else
  2839. {
  2840. return FALSE;
  2841. }
  2842. }
  2843. else
  2844. {
  2845. // Target not set yet.
  2846. return FALSE;
  2847. }
  2848. return TRUE;
  2849. }
  2850. VOID
  2851. ParseStackTrace (
  2852. PSTACK_TRACE_TYPE pTraceType,
  2853. PADDR StartFP,
  2854. PULONG64 Esp,
  2855. PULONG64 Eip,
  2856. PULONG Count
  2857. )
  2858. {
  2859. UCHAR ch;
  2860. ch = PeekChar();
  2861. *pTraceType = STACK_TRACE_TYPE_DEFAULT;
  2862. if (tolower(ch) == 'b')
  2863. {
  2864. g_CurCmd++;
  2865. *pTraceType = STACK_TRACE_TYPE_KB;
  2866. }
  2867. else if (tolower(ch) == 'v')
  2868. {
  2869. g_CurCmd++;
  2870. *pTraceType = STACK_TRACE_TYPE_KV;
  2871. }
  2872. else if (tolower(ch) == 'd')
  2873. {
  2874. g_CurCmd++;
  2875. *pTraceType = STACK_TRACE_TYPE_KD;
  2876. }
  2877. else if (tolower(ch) == 'p')
  2878. {
  2879. g_CurCmd++;
  2880. *pTraceType = STACK_TRACE_TYPE_KP;
  2881. }
  2882. ch = PeekChar();
  2883. if (tolower(ch) == 'n')
  2884. {
  2885. g_CurCmd++;
  2886. *pTraceType = (STACK_TRACE_TYPE) (*pTraceType + STACK_TRACE_TYPE_KN);
  2887. }
  2888. if (!PeekChar() && GetCurrentScopeContext())
  2889. {
  2890. dprintf(" *** Stack trace for last set context - .thread resets it\n");
  2891. }
  2892. if (PeekChar() == '=')
  2893. {
  2894. g_CurCmd++;
  2895. GetAddrExpression(SEGREG_STACK, StartFP);
  2896. }
  2897. else if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
  2898. {
  2899. g_Machine->GetFP(StartFP);
  2900. }
  2901. else
  2902. {
  2903. ADDRFLAT(StartFP, 0);
  2904. }
  2905. *Count = g_DefaultStackTraceDepth;
  2906. if (g_EffMachine == IMAGE_FILE_MACHINE_I386 &&
  2907. (ch = PeekChar()) != '\0' && ch != ';')
  2908. {
  2909. //
  2910. // If only one more value it's the count
  2911. //
  2912. *Count = (ULONG)GetExpression();
  2913. if ((ch = PeekChar()) != '\0' && ch != ';')
  2914. {
  2915. //
  2916. // More then one value, set extra value for special
  2917. // FPO backtrace
  2918. //
  2919. *Eip = GetExpression();
  2920. *Esp = *Count;
  2921. *Count = g_DefaultStackTraceDepth;
  2922. }
  2923. }
  2924. if ((ch = PeekChar()) != '\0' && ch != ';')
  2925. {
  2926. *Count = (ULONG)GetExpression();
  2927. if ((LONG)*Count < 1)
  2928. {
  2929. g_CurCmd++;
  2930. error(SYNTAX);
  2931. }
  2932. }
  2933. }
  2934. void
  2935. SetSuffix(void)
  2936. {
  2937. UCHAR ch;
  2938. ch = PeekChar();
  2939. ch = (UCHAR)tolower(ch);
  2940. if (ch == ';' || ch == '\0')
  2941. {
  2942. if (g_SymbolSuffix == 'n')
  2943. {
  2944. dprintf("n - no suffix\n");
  2945. }
  2946. else if (g_SymbolSuffix == 'a')
  2947. {
  2948. dprintf("a - ascii\n");
  2949. }
  2950. else
  2951. {
  2952. dprintf("w - wide\n");
  2953. }
  2954. }
  2955. else if (ch == 'n' || ch == 'a' || ch == 'w')
  2956. {
  2957. g_SymbolSuffix = ch;
  2958. g_CurCmd++;
  2959. }
  2960. else
  2961. {
  2962. error(SYNTAX);
  2963. }
  2964. }
  2965. void
  2966. OutputVersionInformation(DebugClient* Client)
  2967. {
  2968. char Buf[MAX_PATH];
  2969. DBH_DIAVERSION DiaVer;
  2970. //
  2971. // Print out the connection options if we are doing live debugging.
  2972. //
  2973. if (IS_KERNEL_TARGET())
  2974. {
  2975. switch(g_TargetClassQualifier)
  2976. {
  2977. case DEBUG_KERNEL_CONNECTION:
  2978. g_DbgKdTransport->GetParameters(Buf, sizeof(Buf));
  2979. break;
  2980. case DEBUG_KERNEL_LOCAL:
  2981. strcpy(Buf, "Local Debugging");
  2982. break;
  2983. case DEBUG_KERNEL_EXDI_DRIVER:
  2984. strcpy(Buf, "eXDI Debugging");
  2985. break;
  2986. default:
  2987. strcpy(Buf, "Dump File");
  2988. break;
  2989. }
  2990. dprintf("Connection options: %s\n", Buf);
  2991. }
  2992. dprintf("Command line: '%s'\n", GetCommandLine());
  2993. dprintf("dbgeng: ");
  2994. OutputModuleIdInfo(NULL, "dbgeng.dll", NULL);
  2995. dprintf("dbghelp: ");
  2996. OutputModuleIdInfo(NULL, "dbghelp.dll", NULL);
  2997. DiaVer.function = dbhDiaVersion;
  2998. DiaVer.sizeofstruct = sizeof(DiaVer);
  2999. if (dbghelp(NULL, &DiaVer))
  3000. {
  3001. dprintf(" DIA version: %d\n", DiaVer.ver);
  3002. }
  3003. // Dump information about the IA64 support DLLs if they're
  3004. // loaded. Don't bother forcing them to load.
  3005. if (GetModuleHandle("decem.dll") != NULL)
  3006. {
  3007. dprintf("decem: ");
  3008. OutputModuleIdInfo(NULL, "decem.dll", NULL);
  3009. }
  3010. OutputExtensions(Client, TRUE);
  3011. }
  3012. VOID
  3013. DumpExr(
  3014. ULONG64 ExrAddress
  3015. )
  3016. {
  3017. ULONG i;
  3018. CHAR Buffer[256];
  3019. ULONG64 displacement;
  3020. EXCEPTION_RECORD64 Exr64;
  3021. EXCEPTION_RECORD32 Exr32;
  3022. EXCEPTION_RECORD64 *Exr = &Exr64;
  3023. ULONG BytesRead;
  3024. HRESULT hr = S_OK;
  3025. if (ExrAddress == (ULONG64) -1)
  3026. {
  3027. if (g_LastEventType == DEBUG_EVENT_EXCEPTION)
  3028. {
  3029. Exr64 = g_LastEventInfo.Exception.ExceptionRecord;
  3030. }
  3031. else
  3032. {
  3033. ErrOut("Last event was not an exception\n");
  3034. return;
  3035. }
  3036. }
  3037. else if (g_TargetMachine->m_Ptr64)
  3038. {
  3039. hr = g_Target->ReadVirtual(ExrAddress,
  3040. &Exr64,
  3041. sizeof(Exr64),
  3042. &BytesRead);
  3043. }
  3044. else
  3045. {
  3046. hr = g_Target->ReadVirtual(ExrAddress,
  3047. &Exr32,
  3048. sizeof(Exr32),
  3049. &BytesRead);
  3050. ExceptionRecord32To64(&Exr32, &Exr64);
  3051. }
  3052. if (hr != S_OK)
  3053. {
  3054. dprintf64("Cannot read Exception record @ %p\n", ExrAddress);
  3055. return;
  3056. }
  3057. GetSymbolStdCall(Exr->ExceptionAddress, &Buffer[0], sizeof(Buffer),
  3058. &displacement, NULL);
  3059. if (*Buffer)
  3060. {
  3061. dprintf64("ExceptionAddress: %p (%s",
  3062. Exr->ExceptionAddress,
  3063. Buffer);
  3064. if (displacement)
  3065. {
  3066. dprintf64("+0x%p)\n", displacement);
  3067. }
  3068. else
  3069. {
  3070. dprintf64(")\n");
  3071. }
  3072. }
  3073. else
  3074. {
  3075. dprintf64("ExceptionAddress: %p\n", Exr->ExceptionAddress);
  3076. }
  3077. dprintf(" ExceptionCode: %08lx\n", Exr->ExceptionCode);
  3078. dprintf(" ExceptionFlags: %08lx\n", Exr->ExceptionFlags);
  3079. dprintf("NumberParameters: %d\n", Exr->NumberParameters);
  3080. if (Exr->NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS)
  3081. {
  3082. Exr->NumberParameters = EXCEPTION_MAXIMUM_PARAMETERS;
  3083. }
  3084. for (i = 0; i < Exr->NumberParameters; i++)
  3085. {
  3086. dprintf64(" Parameter[%d]: %p\n", i, Exr->ExceptionInformation[i]);
  3087. }
  3088. //
  3089. // Known Exception processing:
  3090. //
  3091. switch ( Exr->ExceptionCode )
  3092. {
  3093. case STATUS_ACCESS_VIOLATION:
  3094. if ( Exr->NumberParameters == 2 )
  3095. {
  3096. dprintf64("Attempt to %s address %p\n",
  3097. (Exr->ExceptionInformation[0] ?
  3098. "write to" : "read from"),
  3099. Exr->ExceptionInformation[1] );
  3100. }
  3101. break;
  3102. case STATUS_IN_PAGE_ERROR:
  3103. if ( Exr->NumberParameters == 3 )
  3104. {
  3105. dprintf64("Inpage operation failed at %p, due to I/O error %p\n",
  3106. Exr->ExceptionInformation[1],
  3107. Exr->ExceptionInformation[2] );
  3108. }
  3109. break;
  3110. case STATUS_INVALID_HANDLE:
  3111. case STATUS_HANDLE_NOT_CLOSABLE:
  3112. dprintf64( "Thread tried to close a handle that was "
  3113. "invalid or illegal to close\n");
  3114. break;
  3115. case STATUS_POSSIBLE_DEADLOCK:
  3116. if ( Exr->NumberParameters == 1 )
  3117. {
  3118. RTL_CRITICAL_SECTION64 CritSec64;
  3119. RTL_CRITICAL_SECTION32 CritSec32;
  3120. ULONG Result ;
  3121. GetSymbolStdCall( Exr->ExceptionInformation[0],
  3122. &Buffer[0], sizeof(Buffer),
  3123. &displacement, NULL );
  3124. if ( *Buffer )
  3125. {
  3126. dprintf64("Critical section at %p (%s+%p)",
  3127. Exr->ExceptionInformation[0],
  3128. Buffer,
  3129. displacement );
  3130. }
  3131. else
  3132. {
  3133. dprintf64("Critical section at %p",
  3134. Exr->ExceptionInformation[0] );
  3135. }
  3136. if (g_TargetMachine->m_Ptr64)
  3137. {
  3138. hr = g_Target->ReadVirtual(Exr->ExceptionInformation[0],
  3139. &CritSec64,
  3140. sizeof(CritSec64),
  3141. &BytesRead);
  3142. }
  3143. else
  3144. {
  3145. hr = g_Target->ReadVirtual(Exr->ExceptionInformation[0],
  3146. &CritSec32,
  3147. sizeof(CritSec32),
  3148. &BytesRead);
  3149. if (hr == S_OK)
  3150. {
  3151. CritSec64.OwningThread = CritSec32.OwningThread;
  3152. }
  3153. }
  3154. if (hr == S_OK)
  3155. {
  3156. dprintf64("is owned by thread %p,\n"
  3157. "causing this thread to raise an exception",
  3158. CritSec64.OwningThread );
  3159. }
  3160. dprintf("\n");
  3161. }
  3162. break;
  3163. default:
  3164. break;
  3165. }
  3166. }