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.

3405 lines
87 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Dot command parsing.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1990-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include <time.h>
  10. #include <locale.h>
  11. #include <dbgver.h>
  12. #define CRASH_BUGCHECK_CODE 0xDEADDEAD
  13. void
  14. ParseSeparateCurrentProcess(PDOT_COMMAND Cmd, DebugClient* Client)
  15. {
  16. HRESULT Status;
  17. ULONG Mode;
  18. char Desc[128];
  19. if (g_SymOptions & SYMOPT_SECURE)
  20. {
  21. error(NOTSECURE);
  22. }
  23. if (!strcmp(Cmd->Name, "abandon"))
  24. {
  25. Mode = SEP_ABANDON;
  26. }
  27. else if (!strcmp(Cmd->Name, "detach"))
  28. {
  29. Mode = SEP_DETACH;
  30. }
  31. else if (!strcmp(Cmd->Name, "kill"))
  32. {
  33. Mode = SEP_TERMINATE;
  34. }
  35. else
  36. {
  37. error(SYNTAX);
  38. }
  39. if (IS_DUMP_TARGET(g_Target))
  40. {
  41. // This will also cause the target to get cleaned
  42. // up as the system will release the only reference.
  43. dprintf("Closing dump file\n");
  44. g_Target->DebuggeeReset(DEBUG_SESSION_END, FALSE);
  45. delete g_Target;
  46. SetToAnyLayers(TRUE);
  47. }
  48. else if ((Status = SeparateCurrentProcess(Mode, Desc)) == S_OK)
  49. {
  50. dprintf("%s\n", Desc);
  51. }
  52. else if (Status == E_NOTIMPL)
  53. {
  54. dprintf("The system doesn't support %s\n", Cmd->Name);
  55. }
  56. else
  57. {
  58. dprintf("Unable to %s, %s\n",
  59. Cmd->Name, FormatStatusCode(Status));
  60. }
  61. }
  62. ULONG64
  63. ParseConnectProcessServer(void)
  64. {
  65. HRESULT Status;
  66. PSTR Srv;
  67. PUSER_DEBUG_SERVICES Services;
  68. CHAR Save;
  69. Srv = StringValue(STRV_SPACE_IS_SEPARATOR |
  70. STRV_TRIM_TRAILING_SPACE, &Save);
  71. Status = DbgRpcConnectServer(Srv, &IID_IUserDebugServices,
  72. (IUnknown**)&Services);
  73. *g_CurCmd = Save;
  74. if (Status != S_OK)
  75. {
  76. ErrOut("Unable to connect to '%s', %s\n \"%s\"\n",
  77. Srv, FormatStatusCode(Status),
  78. FormatStatus(Status));
  79. error(NOTFOUND);
  80. }
  81. return (ULONG_PTR)Services;
  82. }
  83. void
  84. DotAttach(PDOT_COMMAND Cmd, DebugClient* Client)
  85. {
  86. HRESULT Status;
  87. ULONG Pid;
  88. ULONG Flags = DEBUG_ATTACH_DEFAULT;
  89. ULONG64 Server = 0;
  90. if (g_SessionThread != GetCurrentThreadId())
  91. {
  92. error(BADTHREAD);
  93. }
  94. if (g_SymOptions & SYMOPT_SECURE)
  95. {
  96. error(NOTSECURE);
  97. }
  98. while (PeekChar() == '-' || *g_CurCmd == '/')
  99. {
  100. switch(*++g_CurCmd)
  101. {
  102. case 'b':
  103. Flags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
  104. break;
  105. case 'e':
  106. Flags = DEBUG_ATTACH_EXISTING;
  107. break;
  108. case 'p':
  109. if (!strncmp(g_CurCmd, "premote", 7) && isspace(g_CurCmd[7]))
  110. {
  111. g_CurCmd += 7;
  112. Server = ParseConnectProcessServer();
  113. }
  114. else
  115. {
  116. error(SYNTAX);
  117. }
  118. break;
  119. case 'r':
  120. Flags |= DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
  121. break;
  122. case 'v':
  123. Flags = DEBUG_ATTACH_NONINVASIVE;
  124. if (g_CurCmd[1] == 'r')
  125. {
  126. g_CurCmd++;
  127. Flags |= DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND;
  128. }
  129. break;
  130. default:
  131. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  132. break;
  133. }
  134. g_CurCmd++;
  135. }
  136. Pid = (ULONG)GetExpression();
  137. PPENDING_PROCESS Pending;
  138. TargetInfo* Target;
  139. BOOL CreatedTarget;
  140. if ((Status = UserInitialize(Client, Server,
  141. &Target, &CreatedTarget)) == S_OK)
  142. {
  143. Status = Target->StartAttachProcess(Pid, Flags, &Pending);
  144. if (Status == S_OK)
  145. {
  146. dprintf("Attach will occur on next execution\n");
  147. }
  148. else if (CreatedTarget)
  149. {
  150. delete Target;
  151. }
  152. }
  153. else
  154. {
  155. ErrOut("Unable to initialize target, %s\n",
  156. FormatStatusCode(Status));
  157. }
  158. if (Server)
  159. {
  160. ((PUSER_DEBUG_SERVICES)(ULONG_PTR)Server)->Release();
  161. }
  162. }
  163. void
  164. DotBpCmds(PDOT_COMMAND Cmd, DebugClient* Client)
  165. {
  166. ULONG Flags = 0;
  167. ProcessInfo* Process = g_Process;
  168. ULONG Id;
  169. while (PeekChar() == '-')
  170. {
  171. switch(*(++g_CurCmd))
  172. {
  173. case '1':
  174. Flags |= BPCMDS_ONE_LINE;
  175. break;
  176. case 'd':
  177. Flags |= BPCMDS_FORCE_DISABLE;
  178. break;
  179. case 'e':
  180. Flags |= BPCMDS_EXPR_ONLY;
  181. break;
  182. case 'm':
  183. Flags |= BPCMDS_MODULE_HINT;
  184. break;
  185. case 'p':
  186. g_CurCmd++;
  187. Id = (ULONG)GetTermExpression("Process ID missing from");
  188. Process = FindAnyProcessByUserId(Id);
  189. g_CurCmd--;
  190. break;
  191. default:
  192. dprintf("Unknown option '%c'\n", *g_CurCmd);
  193. break;
  194. }
  195. g_CurCmd++;
  196. }
  197. if (!Process)
  198. {
  199. error(BADPROCESS);
  200. }
  201. ListBreakpointsAsCommands(Client, Process, Flags);
  202. }
  203. void
  204. DotBpSync(PDOT_COMMAND Cmd, DebugClient* Client)
  205. {
  206. if (PeekChar() && *g_CurCmd != ';')
  207. {
  208. if (GetExpression())
  209. {
  210. g_EngOptions |= DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS;
  211. }
  212. else
  213. {
  214. g_EngOptions &= ~DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS;
  215. }
  216. }
  217. dprintf("Breakpoint synchronization %s\n",
  218. (g_EngOptions & DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS) ?
  219. "enabled" : "disabled");
  220. }
  221. void
  222. DotBreakin(PDOT_COMMAND Cmd, DebugClient* Client)
  223. {
  224. if (g_DebuggerPlatformId != VER_PLATFORM_WIN32_NT)
  225. {
  226. ErrOut(".breakin not supported on this platform\n");
  227. return;
  228. }
  229. if (g_Target && g_Target->m_SystemVersion <= NT_SVER_NT4)
  230. {
  231. // SysDbgBreakPoint isn't supported, so
  232. // try to use user32's PrivateKDBreakPoint.
  233. if (InitDynamicCalls(&g_User32CallsDesc) == S_OK &&
  234. g_User32Calls.PrivateKDBreakPoint != NULL)
  235. {
  236. g_User32Calls.PrivateKDBreakPoint();
  237. }
  238. else
  239. {
  240. ErrOut(".breakin is not supported on this system\n");
  241. }
  242. }
  243. else
  244. {
  245. NTSTATUS NtStatus;
  246. NtStatus = g_NtDllCalls.NtSystemDebugControl
  247. (SysDbgBreakPoint, NULL, 0, NULL, 0, NULL);
  248. if (NtStatus == STATUS_ACCESS_DENIED)
  249. {
  250. ErrOut(".breakin requires debug privilege\n");
  251. }
  252. else if (NtStatus == STATUS_INVALID_INFO_CLASS)
  253. {
  254. ErrOut(".breakin is not supported on this system\n");
  255. }
  256. else if (!NT_SUCCESS(NtStatus))
  257. {
  258. ErrOut(".breakin failed, 0x%X\n", NtStatus);
  259. }
  260. }
  261. }
  262. void
  263. DotBugCheck(PDOT_COMMAND Cmd, DebugClient* Client)
  264. {
  265. ULONG Code;
  266. ULONG64 Args[4];
  267. if (g_Target->ReadBugCheckData(&Code, Args) == S_OK)
  268. {
  269. dprintf("Bugcheck code %08X\n", Code);
  270. dprintf("Arguments %s %s %s %s\n",
  271. FormatAddr64(Args[0]), FormatAddr64(Args[1]),
  272. FormatAddr64(Args[2]), FormatAddr64(Args[3]));
  273. }
  274. else
  275. {
  276. dprintf("Unable to read bugcheck data\n");
  277. }
  278. }
  279. void
  280. DotCache(PDOT_COMMAND Cmd, DebugClient* Client)
  281. {
  282. if (IS_REMOTE_KERNEL_TARGET(g_Target) ||
  283. (IS_LIVE_USER_TARGET(g_Target) &&
  284. !((LiveUserTargetInfo*)g_Target)->m_Local))
  285. {
  286. if (!g_Process)
  287. {
  288. error(BADPROCESS);
  289. }
  290. g_Process->m_VirtualCache.ParseCommands();
  291. }
  292. else
  293. {
  294. error(SESSIONNOTSUP);
  295. }
  296. }
  297. void
  298. DotChain(PDOT_COMMAND Cmd, DebugClient* Client)
  299. {
  300. OutputExtensions(Client, FALSE);
  301. }
  302. void
  303. DotChildDbg(PDOT_COMMAND Cmd, DebugClient* Client)
  304. {
  305. if (!IS_LIVE_USER_TARGET(g_Target))
  306. {
  307. error(SESSIONNOTSUP);
  308. }
  309. if (g_Process == NULL)
  310. {
  311. error(BADTHREAD);
  312. }
  313. HRESULT Status;
  314. PUSER_DEBUG_SERVICES Services =
  315. ((LiveUserTargetInfo*)g_Target)->m_Services;
  316. ULONG Opts;
  317. Opts = g_Process->m_Options;
  318. if (PeekChar() && *g_CurCmd != ';')
  319. {
  320. ULONG64 Val = GetExpression();
  321. if (Val)
  322. {
  323. Opts &= ~DEBUG_PROCESS_ONLY_THIS_PROCESS;
  324. }
  325. else
  326. {
  327. Opts |= DEBUG_PROCESS_ONLY_THIS_PROCESS;
  328. }
  329. if ((Status = Services->SetProcessOptions(g_Process->m_SysHandle,
  330. Opts)) != S_OK)
  331. {
  332. if (Status == E_NOTIMPL)
  333. {
  334. ErrOut("The system doesn't support changing the flag\n");
  335. }
  336. else
  337. {
  338. ErrOut("Unable to set process options, %s\n",
  339. FormatStatusCode(Status));
  340. }
  341. return;
  342. }
  343. g_Process->m_Options = Opts;
  344. }
  345. dprintf("Processes created by the current process will%s be debugged\n",
  346. (Opts & DEBUG_PROCESS_ONLY_THIS_PROCESS) ? " not" : "");
  347. }
  348. void
  349. DotClients(PDOT_COMMAND Cmd, DebugClient* Client)
  350. {
  351. DebugClient* Cur;
  352. for (Cur = g_Clients; Cur != NULL; Cur = Cur->m_Next)
  353. {
  354. if (Cur->m_Flags & CLIENT_PRIMARY)
  355. {
  356. dprintf("%s, last active %s",
  357. Cur->m_Identity, ctime(&Cur->m_LastActivity));
  358. }
  359. }
  360. }
  361. void
  362. DotCloseHandle(PDOT_COMMAND Cmd, DebugClient* Client)
  363. {
  364. HRESULT Status;
  365. BOOL All = FALSE;
  366. ULONG64 Handle;
  367. ULONG64 Dup;
  368. ULONG HandleCount;
  369. if (!g_Process)
  370. {
  371. error(BADPROCESS);
  372. }
  373. if (!IS_LIVE_USER_TARGET(g_Target))
  374. {
  375. error(SESSIONNOTSUP);
  376. }
  377. PUSER_DEBUG_SERVICES Services =
  378. ((LiveUserTargetInfo*)g_Target)->m_Services;
  379. while (PeekChar() == '-' || *g_CurCmd == '/')
  380. {
  381. switch(*++g_CurCmd)
  382. {
  383. case 'a':
  384. g_CurCmd++;
  385. All = TRUE;
  386. break;
  387. default:
  388. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  389. g_CurCmd++;
  390. break;
  391. }
  392. }
  393. if (!All)
  394. {
  395. Handle = GetExpression();
  396. if ((Status = Services->
  397. DuplicateHandle(g_Process->m_SysHandle, Handle,
  398. SERVICE_HANDLE(GetCurrentProcess()), 0, FALSE,
  399. DUPLICATE_CLOSE_SOURCE |
  400. DUPLICATE_SAME_ACCESS, &Dup)) == S_OK)
  401. {
  402. dprintf("Closed %x\n", (ULONG)Handle);
  403. }
  404. else
  405. {
  406. ErrOut("Possibly closed %x, %s\n",
  407. (ULONG)Handle, FormatStatusCode(Status));
  408. }
  409. return;
  410. }
  411. if (Services->
  412. ReadHandleData(g_Process->m_SysHandle, 0,
  413. DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT,
  414. &HandleCount, sizeof(HandleCount), NULL) != S_OK)
  415. {
  416. ErrOut("Unable to get handle count\n");
  417. return;
  418. }
  419. dprintf("0x%x handles to scan for...\n", HandleCount);
  420. Handle = 4;
  421. while (HandleCount)
  422. {
  423. if (CheckUserInterrupt())
  424. {
  425. WarnOut("-- Interrupted\n");
  426. break;
  427. }
  428. if ((Status = Services->
  429. DuplicateHandle(g_Process->m_SysHandle, Handle,
  430. SERVICE_HANDLE(GetCurrentProcess()), 0, FALSE,
  431. DUPLICATE_CLOSE_SOURCE |
  432. DUPLICATE_SAME_ACCESS, &Dup)) == S_OK)
  433. {
  434. dprintf(" closed %x, 0x%x remaining\n",
  435. (ULONG)Handle, --HandleCount);
  436. }
  437. Handle += 4;
  438. }
  439. }
  440. void
  441. DotContext(PDOT_COMMAND Cmd, DebugClient* Client)
  442. {
  443. if (!g_Machine)
  444. {
  445. error(BADTHREAD);
  446. }
  447. if (PeekChar() && *g_CurCmd != ';')
  448. {
  449. ULONG64 Base = GetExpression();
  450. ULONG NextIdx;
  451. if (g_Machine->SetPageDirectory(g_Thread, PAGE_DIR_USER, Base,
  452. &NextIdx) != S_OK)
  453. {
  454. WarnOut("WARNING: Unable to reset page directory base\n");
  455. }
  456. // Flush the cache as anything we read from user mode is
  457. // no longer valid
  458. g_Process->m_VirtualCache.Empty();
  459. if (Base && !g_Process->m_VirtualCache.m_ForceDecodePTEs &&
  460. IS_REMOTE_KERNEL_TARGET(g_Target))
  461. {
  462. WarnOut("WARNING: "
  463. ".cache forcedecodeptes is not enabled\n");
  464. }
  465. }
  466. else
  467. {
  468. dprintf("User-mode page directory base is %I64x\n",
  469. g_Machine->m_PageDirectories[PAGE_DIR_USER]);
  470. }
  471. }
  472. void
  473. DotCorStack(PDOT_COMMAND Cmd, DebugClient* Client)
  474. {
  475. if (PeekChar() && *g_CurCmd != ';')
  476. {
  477. while (PeekChar() == '-' || *g_CurCmd == '/')
  478. {
  479. switch(*++g_CurCmd)
  480. {
  481. case 'd':
  482. g_DebugCorStack = !g_DebugCorStack;
  483. g_CurCmd++;
  484. break;
  485. default:
  486. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  487. g_CurCmd++;
  488. break;
  489. }
  490. }
  491. g_AllowCorStack = GetExpression() != 0;
  492. }
  493. dprintf("COR-assisted stack walking %s\n",
  494. g_AllowCorStack ? "enabled" : "disabled");
  495. }
  496. void
  497. DotCrash(PDOT_COMMAND Cmd, DebugClient* Client)
  498. {
  499. if (PeekChar())
  500. {
  501. error(SYNTAX);
  502. }
  503. g_LastCommand[0] = '\0';
  504. g_Target->Crash(CRASH_BUGCHECK_CODE);
  505. // Go back to waiting for a state change to
  506. // receive the bugcheck exception.
  507. g_CmdState = 'e';
  508. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  509. DEBUG_STATUS_GO, TRUE);
  510. }
  511. void
  512. DotCreate(PDOT_COMMAND Cmd, DebugClient* Client)
  513. {
  514. HRESULT Status;
  515. PPENDING_PROCESS Pending;
  516. PSTR CmdLine;
  517. PWSTR CmdLineW;
  518. CHAR Save;
  519. ULONG64 Server = 0;
  520. if (g_SessionThread != GetCurrentThreadId())
  521. {
  522. error(BADTHREAD);
  523. }
  524. if (g_SymOptions & SYMOPT_SECURE)
  525. {
  526. error(NOTSECURE);
  527. }
  528. while (PeekChar() == '-' || *g_CurCmd == '/')
  529. {
  530. switch(*++g_CurCmd)
  531. {
  532. case 'p':
  533. if (!strncmp(g_CurCmd, "premote", 7) && isspace(g_CurCmd[7]))
  534. {
  535. g_CurCmd += 7;
  536. Server = ParseConnectProcessServer();
  537. }
  538. else
  539. {
  540. error(SYNTAX);
  541. }
  542. break;
  543. default:
  544. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  545. break;
  546. }
  547. g_CurCmd++;
  548. }
  549. CmdLine = StringValue(STRV_TRIM_TRAILING_SPACE, &Save);
  550. if (AnsiToWide(CmdLine, &CmdLineW) != S_OK)
  551. {
  552. ErrOut("Out of memory\n");
  553. }
  554. else
  555. {
  556. TargetInfo* Target;
  557. BOOL CreatedTarget;
  558. if ((Status = UserInitialize(Client, Server,
  559. &Target, &CreatedTarget)) == S_OK)
  560. {
  561. Status = Target->
  562. StartCreateProcess(CmdLineW, DEBUG_ONLY_THIS_PROCESS,
  563. NULL, NULL, &Pending);
  564. if (Status == S_OK)
  565. {
  566. dprintf("Create will proceed with next execution\n");
  567. }
  568. else if (CreatedTarget)
  569. {
  570. delete Target;
  571. }
  572. }
  573. else
  574. {
  575. ErrOut("Unable to initialize target, %s\n",
  576. FormatStatusCode(Status));
  577. }
  578. FreeWide(CmdLineW);
  579. }
  580. if (Server)
  581. {
  582. ((PUSER_DEBUG_SERVICES)(ULONG_PTR)Server)->Release();
  583. }
  584. *g_CurCmd = Save;
  585. }
  586. void
  587. DotCreateDir(PDOT_COMMAND Cmd, DebugClient* Client)
  588. {
  589. PSTR Str;
  590. char Save;
  591. if (PeekChar() && *g_CurCmd != ';')
  592. {
  593. PWSTR NewStr;
  594. Str = StringValue(STRV_TRIM_TRAILING_SPACE |
  595. STRV_ALLOW_EMPTY_STRING, &Save);
  596. if (!*Str)
  597. {
  598. if (g_StartProcessDir)
  599. {
  600. FreeWide(g_StartProcessDir);
  601. }
  602. g_StartProcessDir = NULL;
  603. }
  604. else if (AnsiToWide(Str, &NewStr) != S_OK)
  605. {
  606. ErrOut("Out of memory\n");
  607. }
  608. else
  609. {
  610. if (g_StartProcessDir)
  611. {
  612. FreeWide(g_StartProcessDir);
  613. }
  614. g_StartProcessDir = NewStr;
  615. }
  616. }
  617. dprintf("Process creation dir: %ws\n",
  618. g_StartProcessDir ? g_StartProcessDir : L"<default>");
  619. }
  620. void
  621. DotCxr(PDOT_COMMAND Cmd, DebugClient* Client)
  622. {
  623. ULONG Flags = 0;
  624. ULONG64 ContextBase = 0;
  625. if (!g_Machine)
  626. {
  627. error(BADTHREAD);
  628. }
  629. if (PeekChar() && *g_CurCmd != ';')
  630. {
  631. ContextBase = GetExpression();
  632. }
  633. if (ContextBase)
  634. {
  635. SetAndOutputVirtualContext(ContextBase,
  636. REGALL_INT32 | REGALL_INT64 |
  637. (g_Machine->m_ExecTypes[0] ==
  638. IMAGE_FILE_MACHINE_I386 ?
  639. REGALL_EXTRA0 : 0));
  640. }
  641. else if (GetCurrentScopeContext())
  642. {
  643. dprintf("Resetting default context\n");
  644. ResetCurrentScope();
  645. }
  646. }
  647. void
  648. DotDrivers(PDOT_COMMAND Cmd, DebugClient* Client)
  649. {
  650. PCSTR ArgsRet;
  651. g_Target->Reload(g_Thread, "-l", &ArgsRet);
  652. }
  653. void
  654. DotDumpCab(PDOT_COMMAND Cmd, DebugClient* Client)
  655. {
  656. char Save;
  657. PCSTR CabName;
  658. ULONG Flags = DEBUG_FORMAT_WRITE_CAB;
  659. if (!IS_DUMP_TARGET(g_Target))
  660. {
  661. error(TARGETNOTSUP);
  662. }
  663. while (PeekChar() == '-' || *g_CurCmd == '/')
  664. {
  665. switch(*++g_CurCmd)
  666. {
  667. case 'a':
  668. Flags |= DEBUG_FORMAT_CAB_SECONDARY_FILES;
  669. g_CurCmd++;
  670. break;
  671. default:
  672. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  673. g_CurCmd++;
  674. break;
  675. }
  676. }
  677. CabName = StringValue(STRV_TRIM_TRAILING_SPACE |
  678. STRV_ESCAPED_CHARACTERS, &Save);
  679. CreateCabFromDump(NULL, CabName, Flags);
  680. }
  681. void
  682. DotDumpDebug(PDOT_COMMAND Cmd, DebugClient* Client)
  683. {
  684. ((DumpTargetInfo *)g_Target)->DumpDebug();
  685. }
  686. void
  687. DotDumpOff(PDOT_COMMAND Cmd, DebugClient* Client)
  688. {
  689. //
  690. // Show the file offset for a VA.
  691. //
  692. ULONG64 Addr = GetExpression();
  693. ULONG64 Offs;
  694. ULONG File;
  695. ULONG Avail;
  696. Offs = ((DumpTargetInfo*)g_Target)->
  697. VirtualToOffset(Addr, &File, &Avail);
  698. dprintf("Virtual %s maps to file %d offset %I64x\n",
  699. FormatAddr64(Addr), File, Offs);
  700. }
  701. void
  702. DotDumpPOff(PDOT_COMMAND Cmd, DebugClient* Client)
  703. {
  704. if (IS_KERNEL_SUMMARY_DUMP(g_Target) || IS_KERNEL_FULL_DUMP(g_Target))
  705. {
  706. //
  707. // Show the file offset for a physical address.
  708. //
  709. ULONG64 Addr = GetExpression();
  710. ULONG Avail;
  711. dprintf("Physical %I64x maps to file offset %I64x\n",
  712. Addr, ((KernelFullSumDumpTargetInfo *)g_Target)->
  713. PhysicalToOffset(Addr, TRUE, &Avail));
  714. }
  715. else
  716. {
  717. error(SESSIONNOTSUP);
  718. }
  719. }
  720. void
  721. DotEcho(PDOT_COMMAND Cmd, DebugClient* Client)
  722. {
  723. CHAR Save;
  724. PSTR Str;
  725. Str = StringValue(STRV_TRIM_TRAILING_SPACE |
  726. STRV_ALLOW_EMPTY_STRING, &Save);
  727. dprintf("%s\n", Str);
  728. *g_CurCmd = Save;
  729. }
  730. void
  731. DotEchoTimestamps(PDOT_COMMAND Cmd, DebugClient* Client)
  732. {
  733. g_EchoEventTimestamps = !g_EchoEventTimestamps;
  734. dprintf("Event timestamps are now %s\n",
  735. g_EchoEventTimestamps ? "enabled" : "disabled");
  736. }
  737. void
  738. DotEcxr(PDOT_COMMAND Cmd, DebugClient* Client)
  739. {
  740. CROSS_PLATFORM_CONTEXT Context;
  741. HRESULT Status;
  742. Status = E_UNEXPECTED;
  743. if (!g_Target || !g_Machine ||
  744. (Status = g_Target->GetExceptionContext(&Context)) != S_OK)
  745. {
  746. ErrOut("Unable to get exception context, 0x%X\n", Status);
  747. }
  748. else
  749. {
  750. SetAndOutputContext(&Context, FALSE, REGALL_INT32 | REGALL_INT64 |
  751. (g_Machine->
  752. m_ExecTypes[0] == IMAGE_FILE_MACHINE_I386 ?
  753. REGALL_EXTRA0 : 0));
  754. }
  755. }
  756. void
  757. DotEffMach(PDOT_COMMAND Cmd, DebugClient* Client)
  758. {
  759. if (PeekChar() != ';' && *g_CurCmd)
  760. {
  761. PSTR Name = g_CurCmd;
  762. while (*g_CurCmd && *g_CurCmd != ';' && !isspace(*g_CurCmd))
  763. {
  764. g_CurCmd++;
  765. }
  766. if (*g_CurCmd)
  767. {
  768. *g_CurCmd++ = 0;
  769. }
  770. ULONG Machine;
  771. if (Name[0] == '.' && Name[1] == 0)
  772. {
  773. // Reset to target machine.
  774. Machine = g_Target->m_MachineType;
  775. }
  776. else if (Name[0] == '#' && Name[1] == 0)
  777. {
  778. // Reset to executing machine.
  779. Machine = g_EventMachine->m_ExecTypes[0];
  780. }
  781. else
  782. {
  783. for (Machine = 0; Machine < MACHIDX_COUNT; Machine++)
  784. {
  785. if (!_strcmpi(Name,
  786. g_Target->m_Machines[Machine]->m_AbbrevName))
  787. {
  788. break;
  789. }
  790. }
  791. if (Machine >= MACHIDX_COUNT)
  792. {
  793. ErrOut("Unknown machine '%s'\n", Name);
  794. return;
  795. }
  796. Machine = g_Target->m_Machines[Machine]->m_ExecTypes[0];
  797. }
  798. g_Target->SetEffMachine(Machine, TRUE);
  799. g_Machine = g_Target->m_EffMachine;
  800. }
  801. if (g_Machine != NULL)
  802. {
  803. dprintf("Effective machine: %s (%s)\n",
  804. g_Machine->m_FullName, g_Machine->m_AbbrevName);
  805. }
  806. else
  807. {
  808. dprintf("No effective machine\n");
  809. }
  810. }
  811. void
  812. DotEnableLongStatus(PDOT_COMMAND Cmd, DebugClient* Client)
  813. {
  814. g_EnableLongStatus = (BOOL)GetExpression();
  815. if (g_EnableLongStatus)
  816. {
  817. g_TypeOptions |= DEBUG_TYPEOPTS_LONGSTATUS_DISPLAY;
  818. }
  819. else
  820. {
  821. g_TypeOptions &= ~DEBUG_TYPEOPTS_LONGSTATUS_DISPLAY;
  822. }
  823. // Callback to update locals and watch window
  824. NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
  825. }
  826. void
  827. DotEnableUnicode(PDOT_COMMAND Cmd, DebugClient* Client)
  828. {
  829. g_EnableUnicode = (BOOL)GetExpression();
  830. if (g_EnableUnicode)
  831. {
  832. g_TypeOptions |= DEBUG_TYPEOPTS_UNICODE_DISPLAY;
  833. }
  834. else
  835. {
  836. g_TypeOptions &= ~DEBUG_TYPEOPTS_UNICODE_DISPLAY;
  837. }
  838. // Callback to update locals and watch window
  839. NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
  840. }
  841. void
  842. DotForceRadixOutput(PDOT_COMMAND Cmd, DebugClient* Client)
  843. {
  844. g_PrintDefaultRadix = (BOOL) GetExpression();
  845. if (g_PrintDefaultRadix)
  846. {
  847. g_TypeOptions |= DEBUG_TYPEOPTS_FORCERADIX_OUTPUT;
  848. }
  849. else
  850. {
  851. g_TypeOptions &= ~DEBUG_TYPEOPTS_FORCERADIX_OUTPUT;
  852. }
  853. // Callback to update locals and watch window
  854. NotifyChangeSymbolState(DEBUG_CSS_TYPE_OPTIONS, 0, NULL);
  855. }
  856. void
  857. DotEndSrv(PDOT_COMMAND Cmd, DebugClient* Client)
  858. {
  859. if (DbgRpcDisableServer((ULONG)GetExpression()) == S_OK)
  860. {
  861. dprintf("Server told to exit. Actual exit may be delayed until\n"
  862. "the next connection attempt.\n");
  863. }
  864. else
  865. {
  866. ErrOut("No such server\n");
  867. }
  868. }
  869. void
  870. DotEndPSrv(PDOT_COMMAND Cmd, DebugClient* Client)
  871. {
  872. if (IS_LIVE_USER_TARGET(g_Target) &&
  873. !((LiveUserTargetInfo*)g_Target)->m_Local)
  874. {
  875. ((LiveUserTargetInfo*)g_Target)->m_Services->Uninitialize(TRUE);
  876. dprintf("Server told to exit\n");
  877. }
  878. else
  879. {
  880. error(SESSIONNOTSUP);
  881. }
  882. }
  883. void
  884. DotEnumTag(PDOT_COMMAND Cmd, DebugClient* Client)
  885. {
  886. HRESULT Status;
  887. ULONG64 Handle;
  888. if ((Status = Client->StartEnumTagged(&Handle)) != S_OK)
  889. {
  890. ErrOut("Unable to start enumeration, %s\n",
  891. FormatStatusCode(Status));
  892. return;
  893. }
  894. GUID Tag;
  895. ULONG Size;
  896. UCHAR Buffer[16];
  897. ULONG Total;
  898. ULONG Left;
  899. ULONG Offs;
  900. while (Client->GetNextTagged(Handle, &Tag, &Size) == S_OK)
  901. {
  902. if (CheckUserInterrupt())
  903. {
  904. dprintf("-- Interrupted\n");
  905. break;
  906. }
  907. dprintf("{%08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X} "
  908. "- 0x%x bytes\n",
  909. Tag.Data1, Tag.Data2, Tag.Data3,
  910. Tag.Data4[0], Tag.Data4[1], Tag.Data4[2],
  911. Tag.Data4[3], Tag.Data4[4], Tag.Data4[5],
  912. Tag.Data4[6], Tag.Data4[7], Size);
  913. Offs = 0;
  914. Left = Size;
  915. while (Left > 0)
  916. {
  917. ULONG Req;
  918. if (Left > sizeof(Buffer))
  919. {
  920. Req = sizeof(Buffer);
  921. }
  922. else
  923. {
  924. Req = Left;
  925. }
  926. if (Client->ReadTagged(&Tag, Offs, Buffer, Req, &Total) != S_OK)
  927. {
  928. ErrOut(" Unable to read data\n");
  929. break;
  930. }
  931. ULONG i;
  932. dprintf(" ");
  933. for (i = 0; i < Req; i++)
  934. {
  935. dprintf(" %02X", Buffer[i]);
  936. }
  937. while (i < sizeof(Buffer))
  938. {
  939. dprintf(" ");
  940. i++;
  941. }
  942. dprintf(" ");
  943. for (i = 0; i < Req; i++)
  944. {
  945. dprintf("%c", isprint(Buffer[i]) ? Buffer[i] : '.');
  946. }
  947. dprintf("\n");
  948. Offs += Req;
  949. Left -= Req;
  950. }
  951. }
  952. Client->EndEnumTagged(Handle);
  953. }
  954. void
  955. DotEvents(PDOT_COMMAND Cmd, DebugClient* Client)
  956. {
  957. HRESULT Status;
  958. if (PeekChar() && *g_CurCmd != ';')
  959. {
  960. ULONG Relation = DEBUG_EINDEX_FROM_CURRENT;
  961. ULONG Index = 1;
  962. while (PeekChar() == '-' || *g_CurCmd == '/')
  963. {
  964. switch(*++g_CurCmd)
  965. {
  966. case '-':
  967. g_CurCmd++;
  968. Relation = DEBUG_EINDEX_FROM_CURRENT;
  969. Index = -(LONG)GetExpression();
  970. break;
  971. case '+':
  972. g_CurCmd++;
  973. Relation = DEBUG_EINDEX_FROM_CURRENT;
  974. Index = (ULONG)GetExpression();
  975. break;
  976. case 'e':
  977. g_CurCmd++;
  978. Relation = DEBUG_EINDEX_FROM_END;
  979. Index = (ULONG)GetExpression();
  980. break;
  981. case 's':
  982. g_CurCmd++;
  983. Relation = DEBUG_EINDEX_FROM_START;
  984. Index = (ULONG)GetExpression();
  985. break;
  986. default:
  987. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  988. g_CurCmd++;
  989. break;
  990. }
  991. }
  992. if ((Status = Client->
  993. SetNextEventIndex(Relation, Index, &Index)) != S_OK)
  994. {
  995. ErrOut("Unable to set next event index, %s\n",
  996. FormatStatusCode(Status));
  997. }
  998. else
  999. {
  1000. dprintf("Next event index will be %d\n", Index);
  1001. }
  1002. }
  1003. else
  1004. {
  1005. ULONG Num, Cur;
  1006. if (FAILED(Status = Client->GetNumberEvents(&Num)) ||
  1007. (Status = Client->GetCurrentEventIndex(&Cur)) != S_OK)
  1008. {
  1009. dprintf("Unable to get event information, %s\n",
  1010. FormatStatusCode(Status));
  1011. }
  1012. else
  1013. {
  1014. for (ULONG i = 0; i < Num; i++)
  1015. {
  1016. char Name[64];
  1017. if (FAILED(Client->
  1018. GetEventIndexDescription(i, DEBUG_EINDEX_NAME,
  1019. Name, sizeof(Name), NULL)))
  1020. {
  1021. strcpy(Name, "<Error>");
  1022. }
  1023. dprintf("%c%2d - %s\n",
  1024. i == Cur ? '.' : ' ', i, Name);
  1025. }
  1026. }
  1027. }
  1028. }
  1029. void
  1030. DotEventStr(PDOT_COMMAND Cmd, DebugClient* Client)
  1031. {
  1032. if (!g_EventThread ||
  1033. !g_EventThread->m_EventStrings)
  1034. {
  1035. ErrOut("No event strings\n");
  1036. }
  1037. else
  1038. {
  1039. g_EventThread->OutputEventStrings();
  1040. }
  1041. }
  1042. void
  1043. DotExePath(PDOT_COMMAND Cmd, DebugClient* Client)
  1044. {
  1045. if (PeekChar())
  1046. {
  1047. if (ChangePath(&g_ExecutableImageSearchPath,
  1048. g_CurCmd, Cmd->Name[7] == '+',
  1049. DEBUG_CSS_PATHS) != S_OK)
  1050. {
  1051. // This command uses the whole string.
  1052. *g_CurCmd = 0;
  1053. return;
  1054. }
  1055. *g_CurCmd = 0;
  1056. }
  1057. if (g_ExecutableImageSearchPath == NULL)
  1058. {
  1059. dprintf("No exectutable image search path\n");
  1060. }
  1061. else
  1062. {
  1063. dprintf("Executable image search path is: %s\n",
  1064. g_ExecutableImageSearchPath);
  1065. CheckPath(g_ExecutableImageSearchPath);
  1066. }
  1067. }
  1068. void
  1069. DotExpr(PDOT_COMMAND Cmd, DebugClient* Client)
  1070. {
  1071. if (PeekChar() && *g_CurCmd != ';')
  1072. {
  1073. ULONG i;
  1074. char Save;
  1075. PCSTR Name;
  1076. while (PeekChar() == '-' || *g_CurCmd == '/')
  1077. {
  1078. switch(*++g_CurCmd)
  1079. {
  1080. case 'q':
  1081. g_CurCmd++;
  1082. dprintf("Available expression evaluators:\n");
  1083. for (i = 0; i < EVAL_COUNT; i++)
  1084. {
  1085. EvalExpression* Eval = GetEvaluator(i, FALSE);
  1086. dprintf("%s - %s\n",
  1087. Eval->m_AbbrevName,
  1088. Eval->m_FullName);
  1089. ReleaseEvaluator(Eval);
  1090. }
  1091. dprintf("\n");
  1092. break;
  1093. case 's':
  1094. g_CurCmd++;
  1095. Name = StringValue(STRV_SPACE_IS_SEPARATOR, &Save);
  1096. if (SetExprSyntaxByName(Name) != S_OK)
  1097. {
  1098. dprintf("No evaluator named '%s'\n", Name);
  1099. }
  1100. *g_CurCmd = Save;
  1101. break;
  1102. default:
  1103. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1104. g_CurCmd++;
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. EvalExpression* Eval = GetCurEvaluator();
  1110. dprintf("Current expression evaluator: %s - %s\n",
  1111. Eval->m_AbbrevName, Eval->m_FullName);
  1112. ReleaseEvaluator(Eval);
  1113. }
  1114. void
  1115. DotExr(PDOT_COMMAND Cmd, DebugClient* Client)
  1116. {
  1117. ULONG64 ExrAddress = GetExpression();
  1118. ULONG i;
  1119. char Buffer[256];
  1120. ULONG64 Displacement;
  1121. EXCEPTION_RECORD64 Exr64;
  1122. EXCEPTION_RECORD32 Exr32;
  1123. EXCEPTION_RECORD64 *Exr = &Exr64;
  1124. HRESULT Status = S_OK;
  1125. EVENT_FILTER* Filter;
  1126. if (ExrAddress == (ULONG64) -1)
  1127. {
  1128. if (g_LastEventType == DEBUG_EVENT_EXCEPTION)
  1129. {
  1130. Exr64 = g_LastEventInfo.Exception.ExceptionRecord;
  1131. }
  1132. else
  1133. {
  1134. ErrOut("Last event was not an exception\n");
  1135. return;
  1136. }
  1137. }
  1138. else if (g_Target->m_Machine->m_Ptr64)
  1139. {
  1140. Status = CurReadAllVirtual(ExrAddress, &Exr64, sizeof(Exr64));
  1141. }
  1142. else
  1143. {
  1144. Status = CurReadAllVirtual(ExrAddress, &Exr32, sizeof(Exr32));
  1145. ExceptionRecord32To64(&Exr32, &Exr64);
  1146. }
  1147. if (Status != S_OK)
  1148. {
  1149. dprintf64("Cannot read Exception record @ %p\n", ExrAddress);
  1150. return;
  1151. }
  1152. GetSymbol(Exr->ExceptionAddress, &Buffer[0], DIMA(Buffer),
  1153. &Displacement);
  1154. if (*Buffer)
  1155. {
  1156. dprintf64("ExceptionAddress: %p (%s",
  1157. Exr->ExceptionAddress,
  1158. Buffer);
  1159. if (Displacement)
  1160. {
  1161. dprintf64("+0x%p)\n", Displacement);
  1162. }
  1163. else
  1164. {
  1165. dprintf64(")\n");
  1166. }
  1167. }
  1168. else
  1169. {
  1170. dprintf64("ExceptionAddress: %p\n", Exr->ExceptionAddress);
  1171. }
  1172. dprintf(" ExceptionCode: %08lx", Exr->ExceptionCode);
  1173. Filter = GetSpecificExceptionFilter(Exr->ExceptionCode);
  1174. if (Filter)
  1175. {
  1176. dprintf(" (%s)\n", Filter->Name);
  1177. }
  1178. else
  1179. {
  1180. dprintf("\n");
  1181. }
  1182. dprintf(" ExceptionFlags: %08lx\n", Exr->ExceptionFlags);
  1183. dprintf("NumberParameters: %d\n", Exr->NumberParameters);
  1184. if (Exr->NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS)
  1185. {
  1186. Exr->NumberParameters = EXCEPTION_MAXIMUM_PARAMETERS;
  1187. }
  1188. for (i = 0; i < Exr->NumberParameters; i++)
  1189. {
  1190. dprintf64(" Parameter[%d]: %p\n", i, Exr->ExceptionInformation[i]);
  1191. }
  1192. //
  1193. // Known Exception processing:
  1194. //
  1195. switch(Exr->ExceptionCode)
  1196. {
  1197. case STATUS_ACCESS_VIOLATION:
  1198. if (Exr->NumberParameters == 2)
  1199. {
  1200. dprintf64("Attempt to %s address %p\n",
  1201. (Exr->ExceptionInformation[0] ?
  1202. "write to" : "read from"),
  1203. Exr->ExceptionInformation[1]);
  1204. }
  1205. break;
  1206. case STATUS_IN_PAGE_ERROR:
  1207. if (Exr->NumberParameters == 3)
  1208. {
  1209. dprintf64("Inpage operation failed at %p, due to I/O error %p\n",
  1210. Exr->ExceptionInformation[1],
  1211. Exr->ExceptionInformation[2]);
  1212. }
  1213. break;
  1214. case STATUS_INVALID_HANDLE:
  1215. case STATUS_HANDLE_NOT_CLOSABLE:
  1216. dprintf64("Thread tried to close a handle that was "
  1217. "invalid or illegal to close\n");
  1218. break;
  1219. case STATUS_POSSIBLE_DEADLOCK:
  1220. if (Exr->NumberParameters == 1)
  1221. {
  1222. RTL_CRITICAL_SECTION64 CritSec64;
  1223. RTL_CRITICAL_SECTION32 CritSec32;
  1224. GetSymbol(Exr->ExceptionInformation[0],
  1225. Buffer, DIMA(Buffer), &Displacement);
  1226. if (*Buffer)
  1227. {
  1228. dprintf64("Critical section at %p (%s+%p)",
  1229. Exr->ExceptionInformation[0],
  1230. Buffer,
  1231. Displacement);
  1232. }
  1233. else
  1234. {
  1235. dprintf64("Critical section at %p",
  1236. Exr->ExceptionInformation[0]);
  1237. }
  1238. if (g_Target->m_Machine->m_Ptr64)
  1239. {
  1240. Status = CurReadAllVirtual(Exr->ExceptionInformation[0],
  1241. &CritSec64, sizeof(CritSec64));
  1242. }
  1243. else
  1244. {
  1245. Status = CurReadAllVirtual(Exr->ExceptionInformation[0],
  1246. &CritSec32, sizeof(CritSec32));
  1247. if (Status == S_OK)
  1248. {
  1249. CritSec64.OwningThread = CritSec32.OwningThread;
  1250. }
  1251. }
  1252. if (Status == S_OK)
  1253. {
  1254. dprintf64("is owned by thread %p,\n"
  1255. "causing this thread to raise an exception",
  1256. CritSec64.OwningThread);
  1257. }
  1258. dprintf("\n");
  1259. }
  1260. break;
  1261. }
  1262. }
  1263. void
  1264. DotFnEnt(PDOT_COMMAND Cmd, DebugClient* Client)
  1265. {
  1266. if (!IS_CUR_MACHINE_ACCESSIBLE())
  1267. {
  1268. error(BADTHREAD);
  1269. }
  1270. BOOL SymDirect = FALSE;
  1271. while (PeekChar() == '-' || *g_CurCmd == '/')
  1272. {
  1273. switch(*++g_CurCmd)
  1274. {
  1275. case 's':
  1276. SymDirect = TRUE;
  1277. break;
  1278. default:
  1279. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1280. break;
  1281. }
  1282. g_CurCmd++;
  1283. }
  1284. ULONG64 Addr = GetExpression();
  1285. PVOID FnEnt;
  1286. if (SymDirect)
  1287. {
  1288. FnEnt = SymFunctionTableAccess64(g_Process->m_SymHandle, Addr);
  1289. }
  1290. else
  1291. {
  1292. FnEnt = SwFunctionTableAccess(g_Process->m_SymHandle, Addr);
  1293. }
  1294. if (FnEnt == NULL)
  1295. {
  1296. ErrOut("No function entry for %s\n", FormatAddr64(Addr));
  1297. return;
  1298. }
  1299. dprintf("%s function entry %s for:\n",
  1300. SymDirect ? "Symbol" : "Debugger", FormatAddr64((ULONG_PTR)FnEnt));
  1301. ListNearSymbols(Addr);
  1302. dprintf("\n");
  1303. g_Machine->OutputFunctionEntry(FnEnt);
  1304. }
  1305. void
  1306. DotFormats(PDOT_COMMAND Cmd, DebugClient* Client)
  1307. {
  1308. LONG64 Value;
  1309. LONG Val32;
  1310. BOOL Use64;
  1311. // If this command is really .formats then display
  1312. // everything, otherwise just display the basic
  1313. // expression result for ?.
  1314. BOOL Verbose = Cmd != NULL;
  1315. Value = GetExpression();
  1316. // Allow 64-bit expressions to be evaluated even on
  1317. // 32-bit platforms since they can also use 64-bit numbers.
  1318. Use64 = NeedUpper(Value) || !g_Machine || g_Machine->m_Ptr64;
  1319. Val32 = (LONG)Value;
  1320. if (!Verbose)
  1321. {
  1322. if (Use64)
  1323. {
  1324. dprintf("Evaluate expression: %I64d = %08x`%08x\n",
  1325. Value, (ULONG)(Value >> 32), Val32);
  1326. }
  1327. else
  1328. {
  1329. dprintf("Evaluate expression: %d = %08x\n",
  1330. Val32, Val32);
  1331. }
  1332. }
  1333. else
  1334. {
  1335. dprintf("Evaluate expression:\n");
  1336. if (Use64)
  1337. {
  1338. dprintf(" Hex: %08x`%08x\n", (ULONG)(Value >> 32), Val32);
  1339. dprintf(" Decimal: %I64d\n", Value);
  1340. }
  1341. else
  1342. {
  1343. dprintf(" Hex: %08x\n", Val32);
  1344. dprintf(" Decimal: %d\n", Val32);
  1345. }
  1346. ULONG Shift = Use64 ? 63 : 30;
  1347. dprintf(" Octal: ");
  1348. for (;;)
  1349. {
  1350. dprintf("%c", ((Value >> Shift) & 7) + '0');
  1351. if (Shift == 0)
  1352. {
  1353. break;
  1354. }
  1355. Shift -= 3;
  1356. }
  1357. dprintf("\n");
  1358. Shift = Use64 ? 63 : 31;
  1359. dprintf(" Binary: ");
  1360. for (;;)
  1361. {
  1362. if ((Shift & 7) == 7)
  1363. {
  1364. dprintf(" ");
  1365. }
  1366. dprintf("%c", ((Value >> Shift) & 1) + '0');
  1367. if (Shift == 0)
  1368. {
  1369. break;
  1370. }
  1371. Shift--;
  1372. }
  1373. dprintf("\n");
  1374. Shift = Use64 ? 56 : 24;
  1375. dprintf(" Chars: ");
  1376. for (;;)
  1377. {
  1378. Val32 = (LONG)((Value >> Shift) & 0xff);
  1379. if (Val32 >= ' ' && Val32 <= 127)
  1380. {
  1381. dprintf("%c", Val32);
  1382. }
  1383. else
  1384. {
  1385. dprintf(".");
  1386. }
  1387. if (Shift == 0)
  1388. {
  1389. break;
  1390. }
  1391. Shift -= 8;
  1392. }
  1393. Val32 = (LONG)Value;
  1394. dprintf("\n");
  1395. dprintf(" Time: %s\n", Use64 ? LONG64FileTimeToStr(Value) : TimeToStr(Val32) );
  1396. dprintf(" Float: low %hg high %hg\n",
  1397. *(float*)&Value, *((float*)&Value + 1));
  1398. dprintf(" Double: %g\n", *(double*)&Value);
  1399. }
  1400. }
  1401. void
  1402. DotFrame(PDOT_COMMAND Cmd, DebugClient* Client)
  1403. {
  1404. PDEBUG_STACK_FRAME StackFrame;
  1405. ULONG Traced = 0, Frame = 0;
  1406. if (PeekChar())
  1407. {
  1408. Frame = (ULONG) GetExpression();
  1409. StackFrame = (PDEBUG_STACK_FRAME)
  1410. malloc(sizeof(DEBUG_STACK_FRAME) * (Frame + 1));
  1411. if (!StackFrame)
  1412. {
  1413. error(NOMEMORY);
  1414. }
  1415. Traced = StackTrace(Client, 0, 0, 0, STACK_ALL_DEFAULT,
  1416. StackFrame, Frame + 1, 0, 0, FALSE);
  1417. if (Traced <= Frame)
  1418. {
  1419. ErrOut("Cannot find frame 0x%lx, previous scope unchanged\n",
  1420. Frame);
  1421. return;
  1422. }
  1423. // Do not change the previous context
  1424. SetCurrentScope(&StackFrame[Frame], NULL, 0);
  1425. }
  1426. PrintStackFrame(&GetCurrentScope()->Frame, NULL,
  1427. DEBUG_STACK_FRAME_ADDRESSES |
  1428. DEBUG_STACK_FRAME_NUMBERS |
  1429. DEBUG_STACK_SOURCE_LINE);
  1430. }
  1431. BOOL
  1432. CALLBACK
  1433. GetFirstLocalOffset(PSYMBOL_INFO SymInfo,
  1434. ULONG Size,
  1435. PVOID Context)
  1436. {
  1437. PULONG Offset = (PULONG) Context;
  1438. if (SymInfo->Flags & SYMFLAG_REGREL)
  1439. {
  1440. *Offset = (ULONG)SymInfo->Address;
  1441. }
  1442. else
  1443. {
  1444. *Offset = 0;
  1445. return TRUE;
  1446. }
  1447. return FALSE;
  1448. }
  1449. void
  1450. DotFrameEbpFix(PDOT_COMMAND Cmd, DebugClient* Client)
  1451. {
  1452. //
  1453. // This adjusts the SAVED_EBP value in stackframe by
  1454. // looking at parameter's offset and actual address. Using
  1455. // these it back-caclulates what ebp value could be right for the frame.
  1456. //
  1457. if (g_Machine->m_ExecTypes[0] != IMAGE_FILE_MACHINE_I386)
  1458. {
  1459. error(SESSIONNOTSUP);
  1460. }
  1461. if (!g_ScopeBuffer.Frame.FuncTableEntry)
  1462. {
  1463. // No need to do this for NON-FPO calls.
  1464. goto Show;
  1465. }
  1466. if (((PFPO_DATA)g_ScopeBuffer.Frame.FuncTableEntry)->cdwParams == 0)
  1467. {
  1468. // We cannot do this for calls without any parameters.
  1469. ErrOut("Parameters required\n");
  1470. return;
  1471. }
  1472. IMAGEHLP_SYMBOL64 ImgSym;
  1473. ULONG Param1Offset;
  1474. ULONG64 Displacement;
  1475. ImgSym.MaxNameLength = 1;
  1476. if (g_ScopeBuffer.Frame.InstructionOffset &&
  1477. SymGetSymFromAddr64(g_Process->m_SymHandle,
  1478. g_ScopeBuffer.Frame.InstructionOffset,
  1479. &Displacement,
  1480. &ImgSym))
  1481. {
  1482. IMAGEHLP_STACK_FRAME StackFrame;
  1483. // SetCurrentScope to this function address, not the return address
  1484. // since we only want to enumerate the parameters
  1485. g_EngNotify++;
  1486. StackFrame.InstructionOffset = ImgSym.Address;
  1487. SymSetContext(g_Process->m_SymHandle,&StackFrame, NULL);
  1488. // Enumerate locals and save the offset for first one
  1489. EnumerateLocals(GetFirstLocalOffset, &Param1Offset);
  1490. if (Param1Offset)
  1491. {
  1492. // Params start after 2 dwords from farame offset
  1493. SAVE_EBP(&g_ScopeBuffer.Frame) =
  1494. ((ULONG) g_ScopeBuffer.Frame.FrameOffset + 2*sizeof(DWORD) -
  1495. Param1Offset) + 0xEB00000000; // EBP tag
  1496. }
  1497. // Reset the scope back to original
  1498. SymSetContext(g_Process->m_SymHandle,
  1499. (PIMAGEHLP_STACK_FRAME)&g_ScopeBuffer.Frame, NULL);
  1500. g_EngNotify--;
  1501. }
  1502. Show:
  1503. PrintStackFrame(&GetCurrentScope()->Frame, NULL,
  1504. DEBUG_STACK_FRAME_ADDRESSES |
  1505. DEBUG_STACK_FRAME_NUMBERS |
  1506. DEBUG_STACK_SOURCE_LINE);
  1507. }
  1508. void
  1509. DotImgScan(PDOT_COMMAND Cmd, DebugClient* Client)
  1510. {
  1511. ULONG64 Handle = 0;
  1512. MEMORY_BASIC_INFORMATION64 Info;
  1513. BOOL Verbose = FALSE;
  1514. BOOL AllRegions = TRUE;
  1515. BOOL ReloadIfPossible = FALSE;
  1516. ADDR Start;
  1517. ULONG64 Length;
  1518. //
  1519. // Scan virtual memory looking for image headers.
  1520. //
  1521. while (PeekChar() == '-' || *g_CurCmd == '/')
  1522. {
  1523. switch(*++g_CurCmd)
  1524. {
  1525. case 'l':
  1526. g_CurCmd++;
  1527. ReloadIfPossible = TRUE;
  1528. break;
  1529. case 'r':
  1530. g_CurCmd++;
  1531. Length = 0x10000;
  1532. GetRange(&Start, &Length, 1, SEGREG_DATA,
  1533. 0x7fffffff);
  1534. AllRegions = FALSE;
  1535. Info.BaseAddress = Flat(Start);
  1536. Info.RegionSize = Length;
  1537. break;
  1538. case 'v':
  1539. g_CurCmd++;
  1540. Verbose = TRUE;
  1541. break;
  1542. default:
  1543. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1544. g_CurCmd++;
  1545. break;
  1546. }
  1547. }
  1548. while ((AllRegions && g_Target->
  1549. QueryMemoryRegion(g_Process, &Handle, FALSE, &Info) == S_OK) ||
  1550. (!AllRegions && Info.RegionSize))
  1551. {
  1552. ULONG64 Addr;
  1553. if (Verbose)
  1554. {
  1555. dprintf("*** Checking %s - %s\n",
  1556. FormatAddr64(Info.BaseAddress),
  1557. FormatAddr64(Info.BaseAddress + Info.RegionSize - 1));
  1558. FlushCallbacks();
  1559. }
  1560. //
  1561. // Check for MZ at the beginning of every page.
  1562. //
  1563. Addr = Info.BaseAddress;
  1564. while (Addr < Info.BaseAddress + Info.RegionSize)
  1565. {
  1566. USHORT ShortSig;
  1567. ULONG Done;
  1568. if (g_Target->
  1569. ReadVirtual(g_Process, Addr, &ShortSig, sizeof(ShortSig),
  1570. &Done) == S_OK &&
  1571. Done == sizeof(ShortSig) &&
  1572. ShortSig == IMAGE_DOS_SIGNATURE)
  1573. {
  1574. IMAGE_NT_HEADERS64 NtHdr;
  1575. char Name[MAX_IMAGE_PATH];
  1576. if (AllRegions)
  1577. {
  1578. dprintf("MZ at %s, prot %08X, type %08X",
  1579. FormatAddr64(Addr), Info.Protect, Info.Type);
  1580. }
  1581. else
  1582. {
  1583. dprintf("MZ at %s", FormatAddr64(Addr));
  1584. }
  1585. if (g_Target->ReadImageNtHeaders(g_Process, Addr,
  1586. &NtHdr) == S_OK)
  1587. {
  1588. dprintf(" - size %x\n", NtHdr.OptionalHeader.SizeOfImage);
  1589. if (GetModnameFromImage(g_Process, Addr, NULL,
  1590. Name, DIMA(Name), TRUE))
  1591. {
  1592. dprintf(" Name: %s\n", Name);
  1593. if (ReloadIfPossible)
  1594. {
  1595. char ReloadCmd[MAX_IMAGE_PATH];
  1596. PCSTR ArgsRet;
  1597. PrintString(ReloadCmd, DIMA(ReloadCmd),
  1598. "%s=0x%s,0x%x",
  1599. Name, FormatAddr64(Addr),
  1600. NtHdr.OptionalHeader.SizeOfImage);
  1601. if (g_Target->Reload(g_Thread, ReloadCmd,
  1602. &ArgsRet) == S_OK)
  1603. {
  1604. dprintf(" Loaded %s module\n", Name);
  1605. }
  1606. }
  1607. }
  1608. }
  1609. else
  1610. {
  1611. dprintf("\n");
  1612. }
  1613. FlushCallbacks();
  1614. }
  1615. if (CheckUserInterrupt())
  1616. {
  1617. WarnOut(" Aborted\n");
  1618. return;
  1619. }
  1620. Addr += g_Machine->m_PageSize;
  1621. }
  1622. Info.RegionSize = 0;
  1623. }
  1624. }
  1625. void
  1626. DotKdFiles(PDOT_COMMAND Cmd, DebugClient* Client)
  1627. {
  1628. ((ConnLiveKernelTargetInfo*)g_Target)->m_Transport->ParseKdFileAssoc();
  1629. }
  1630. void
  1631. DotKdTrans(PDOT_COMMAND Cmd, DebugClient* Client)
  1632. {
  1633. ((ConnLiveKernelTargetInfo*)g_Target)->m_Transport->OutputInfo();
  1634. }
  1635. void
  1636. DotKFrames(PDOT_COMMAND Cmd, DebugClient* Client)
  1637. {
  1638. g_DefaultStackTraceDepth = (ULONG)GetExpression();
  1639. dprintf("Default stack trace depth is 0n%d frames\n",
  1640. g_DefaultStackTraceDepth);
  1641. }
  1642. PCSTR
  1643. EventProcThreadString(void)
  1644. {
  1645. if (IS_USER_TARGET(g_EventTarget))
  1646. {
  1647. static char s_Buf[64];
  1648. PrintString(s_Buf, DIMA(s_Buf), "%x.%x: ",
  1649. g_EventProcessSysId, g_EventThreadSysId);
  1650. return s_Buf;
  1651. }
  1652. else
  1653. {
  1654. return "";
  1655. }
  1656. }
  1657. void
  1658. DotLastEvent(PDOT_COMMAND Cmd, DebugClient* Client)
  1659. {
  1660. dprintf("Last event: %s%s\n",
  1661. EventProcThreadString(), g_LastEventDesc);
  1662. }
  1663. void
  1664. DotLocale(PDOT_COMMAND Cmd, DebugClient* Client)
  1665. {
  1666. PSTR LocaleStr;
  1667. CHAR Save;
  1668. if (PeekChar() && *g_CurCmd != ';')
  1669. {
  1670. LocaleStr = StringValue(STRV_ESCAPED_CHARACTERS |
  1671. STRV_TRIM_TRAILING_SPACE,
  1672. &Save);
  1673. }
  1674. else
  1675. {
  1676. LocaleStr = NULL;
  1677. }
  1678. dprintf("Locale: %s\n", setlocale(LC_ALL, LocaleStr));
  1679. if (LocaleStr != NULL)
  1680. {
  1681. *g_CurCmd = Save;
  1682. }
  1683. }
  1684. void
  1685. DotLogAppend(PDOT_COMMAND Cmd, DebugClient* Client)
  1686. {
  1687. ParseLogOpen(TRUE);
  1688. }
  1689. void
  1690. DotLogClose(PDOT_COMMAND Cmd, DebugClient* Client)
  1691. {
  1692. CloseLogFile();
  1693. }
  1694. void
  1695. DotLogFile(PDOT_COMMAND Cmd, DebugClient* Client)
  1696. {
  1697. if (g_LogFile >= 0)
  1698. {
  1699. dprintf("Log '%s' open%s\n",
  1700. g_OpenLogFileName,
  1701. g_OpenLogFileAppended ? " for append" : "");
  1702. }
  1703. else
  1704. {
  1705. dprintf("No log file open\n");
  1706. }
  1707. }
  1708. void
  1709. DotLogOpen(PDOT_COMMAND Cmd, DebugClient* Client)
  1710. {
  1711. ParseLogOpen(FALSE);
  1712. }
  1713. void
  1714. DotNetSyms(PDOT_COMMAND Cmd, DebugClient* Client)
  1715. {
  1716. char Save;
  1717. PSTR Str;
  1718. Str = StringValue(0, &Save);
  1719. if (_stricmp(Str, "1") == 0 ||
  1720. _stricmp(Str, "true") == 0 ||
  1721. _stricmp(Str, "yes") == 0)
  1722. {
  1723. g_EngOptions |= DEBUG_ENGOPT_ALLOW_NETWORK_PATHS;
  1724. g_EngOptions &= ~DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS;
  1725. }
  1726. else if (_stricmp(Str, "0") == 0 ||
  1727. _stricmp(Str, "false") == 0 ||
  1728. _stricmp(Str, "no") == 0)
  1729. {
  1730. g_EngOptions |= DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS;
  1731. g_EngOptions &= ~DEBUG_ENGOPT_ALLOW_NETWORK_PATHS;
  1732. }
  1733. *g_CurCmd = Save;
  1734. if (g_EngOptions & DEBUG_ENGOPT_ALLOW_NETWORK_PATHS)
  1735. {
  1736. dprintf("netsyms = yes\n");
  1737. }
  1738. else if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
  1739. {
  1740. dprintf("netsyms = no\n");
  1741. }
  1742. else
  1743. {
  1744. dprintf("netsyms = don't care\n");
  1745. }
  1746. }
  1747. void
  1748. DotNoEngErr(PDOT_COMMAND Cmd, DebugClient* Client)
  1749. {
  1750. // Internal command to clear out the error suppression
  1751. // flags in case we want to rerun operations and check
  1752. // for errors that may be in suppression mode.
  1753. g_EngErr = 0;
  1754. }
  1755. void
  1756. DotNoShell(PDOT_COMMAND Cmd, DebugClient* Client)
  1757. {
  1758. g_EngOptions |= DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS;
  1759. dprintf("Shell commands disabled\n");
  1760. }
  1761. void
  1762. DotNoVersion(PDOT_COMMAND Cmd, DebugClient* Client)
  1763. {
  1764. dprintf("Extension DLL system version checking is disabled\n");
  1765. g_EnvDbgOptions |= OPTION_NOVERSIONCHECK;
  1766. }
  1767. void
  1768. DotOCommand(PDOT_COMMAND Cmd, DebugClient* Client)
  1769. {
  1770. if (PeekChar() != ';' && *g_CurCmd)
  1771. {
  1772. ULONG BufLen;
  1773. BufLen = MAX_PATH;
  1774. while (PeekChar() == '-' || *g_CurCmd == '/')
  1775. {
  1776. switch(*++g_CurCmd)
  1777. {
  1778. case 'd':
  1779. BufLen = 0;
  1780. break;
  1781. default:
  1782. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1783. break;
  1784. }
  1785. g_CurCmd++;
  1786. }
  1787. if (BufLen)
  1788. {
  1789. ULONG Len;
  1790. CHAR Save;
  1791. PSTR Pat = StringValue(STRV_ESCAPED_CHARACTERS, &Save);
  1792. Len = strlen(Pat);
  1793. if (Len >= BufLen)
  1794. {
  1795. error(OVERFLOW);
  1796. }
  1797. memcpy(g_OutputCommandRedirectPrefix, Pat, Len + 1);
  1798. g_OutputCommandRedirectPrefixLen = Len;
  1799. *g_CurCmd = Save;
  1800. }
  1801. else
  1802. {
  1803. g_OutputCommandRedirectPrefixLen = 0;
  1804. }
  1805. }
  1806. if (g_OutputCommandRedirectPrefixLen)
  1807. {
  1808. dprintf("Treat output prefixed with '%s' as a command\n",
  1809. g_OutputCommandRedirectPrefix);
  1810. }
  1811. else
  1812. {
  1813. dprintf("Output command redirection inactive\n");
  1814. }
  1815. }
  1816. void
  1817. DotOFilter(PDOT_COMMAND Cmd, DebugClient* Client)
  1818. {
  1819. if (PeekChar() != ';' && *g_CurCmd)
  1820. {
  1821. g_OutFilterResult = TRUE;
  1822. while (PeekChar() == '-' || *g_CurCmd == '/')
  1823. {
  1824. switch(*++g_CurCmd)
  1825. {
  1826. case '!':
  1827. g_OutFilterResult = FALSE;
  1828. break;
  1829. default:
  1830. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1831. break;
  1832. }
  1833. g_CurCmd++;
  1834. }
  1835. CHAR Save;
  1836. PSTR Pat = StringValue(STRV_TRIM_TRAILING_SPACE |
  1837. STRV_ESCAPED_CHARACTERS |\
  1838. STRV_ALLOW_EMPTY_STRING, &Save);
  1839. if (strlen(Pat) + 1 > sizeof(g_OutFilterPattern))
  1840. {
  1841. error(OVERFLOW);
  1842. }
  1843. CopyString(g_OutFilterPattern, Pat, DIMA(g_OutFilterPattern));
  1844. *g_CurCmd = Save;
  1845. _strupr(g_OutFilterPattern);
  1846. }
  1847. if (g_OutFilterPattern[0])
  1848. {
  1849. dprintf("Only display debuggee output that %s '%s'\n",
  1850. g_OutFilterResult ? "matches" : "doesn't match",
  1851. g_OutFilterPattern);
  1852. }
  1853. else
  1854. {
  1855. dprintf("No debuggee output filter set\n");
  1856. }
  1857. }
  1858. void
  1859. DotOpenDump(PDOT_COMMAND Cmd, DebugClient* Client)
  1860. {
  1861. PSTR FileName;
  1862. PWSTR FileWide;
  1863. char Save;
  1864. TargetInfo* Target;
  1865. if (g_SymOptions & SYMOPT_SECURE)
  1866. {
  1867. error(NOTSECURE);
  1868. }
  1869. FileName = StringValue(STRV_TRIM_TRAILING_SPACE |
  1870. STRV_ESCAPED_CHARACTERS, &Save);
  1871. if (AnsiToWide(FileName, &FileWide) != S_OK)
  1872. {
  1873. ErrOut("Unable to convert filename\n");
  1874. }
  1875. else
  1876. {
  1877. // Error messages are displayed by DumpInitialize.
  1878. if (DumpInitialize(Client, FileWide, 0, &Target) == S_OK)
  1879. {
  1880. dprintf("Opened '%s'\n", FileName);
  1881. }
  1882. FreeWide(FileWide);
  1883. }
  1884. *g_CurCmd = Save;
  1885. }
  1886. void
  1887. DotOutMask(PDOT_COMMAND Cmd, DebugClient* Client)
  1888. {
  1889. // Private internal command for debugging the debugger.
  1890. ULONG Expr = (ULONG)GetExpression();
  1891. if (Cmd->Name[7] == '-')
  1892. {
  1893. Client->m_OutMask &= ~Expr;
  1894. }
  1895. else
  1896. {
  1897. Client->m_OutMask |= Expr;
  1898. }
  1899. dprintf("Client %p mask is %X\n", Client, Client->m_OutMask);
  1900. CollectOutMasks();
  1901. // Also update the log mask as people usually
  1902. // want to see the same things in the log.
  1903. g_LogMask = Client->m_OutMask;
  1904. }
  1905. void
  1906. DotPCache(PDOT_COMMAND Cmd, DebugClient* Client)
  1907. {
  1908. g_Target->m_PhysicalCache.ParseCommands();
  1909. }
  1910. void
  1911. DotReboot(PDOT_COMMAND Cmd, DebugClient* Client)
  1912. {
  1913. if (PeekChar())
  1914. {
  1915. error(SYNTAX);
  1916. }
  1917. // Null out .reboot command.
  1918. g_LastCommand[0] = '\0';
  1919. g_Target->Reboot();
  1920. // The target is no longer accepting commands
  1921. // so reset the command state.
  1922. g_CmdState = 'i';
  1923. }
  1924. void
  1925. DotReCxr(PDOT_COMMAND Cmd, DebugClient* Client)
  1926. {
  1927. while (PeekChar() == '-')
  1928. {
  1929. switch(*++g_CurCmd)
  1930. {
  1931. case 'f':
  1932. g_Target->FlushRegContext();
  1933. break;
  1934. default:
  1935. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  1936. break;
  1937. }
  1938. g_CurCmd++;
  1939. }
  1940. if (g_Machine)
  1941. {
  1942. g_Machine->InvalidateContext();
  1943. }
  1944. }
  1945. void
  1946. DotReload(PDOT_COMMAND Cmd, DebugClient* Client)
  1947. {
  1948. g_Target->Reload(g_Thread, g_CurCmd, (PCSTR*)&g_CurCmd);
  1949. ClearStoredTypes(0);
  1950. }
  1951. void
  1952. DotSecure(PDOT_COMMAND Cmd, DebugClient* Client)
  1953. {
  1954. if (PeekChar() && *g_CurCmd != ';')
  1955. {
  1956. // Ignore argument.
  1957. if (GetExpression())
  1958. {
  1959. if (SetSymOptions(g_SymOptions | SYMOPT_SECURE) != S_OK)
  1960. {
  1961. ErrOut("ERROR: Unable to enter secure mode.\n"
  1962. "Secure mode requires no sessions and "
  1963. "no remote clients.\n");
  1964. }
  1965. else
  1966. {
  1967. dprintf("Entered secure mode\n");
  1968. }
  1969. }
  1970. }
  1971. dprintf("Secure mode %sabled\n",
  1972. (g_SymOptions & SYMOPT_SECURE) ? "en" : "dis");
  1973. }
  1974. void
  1975. EnumServers(BOOL ShowComputerName)
  1976. {
  1977. ULONG Id;
  1978. char Desc[4 * MAX_PARAM_VALUE];
  1979. PVOID Cookie = NULL;
  1980. BOOL Any = FALSE;
  1981. char CompName[MAX_COMPUTERNAME_LENGTH + 1];
  1982. if (ShowComputerName)
  1983. {
  1984. ULONG CompSize = sizeof(CompName);
  1985. if (!GetComputerName(CompName, &CompSize))
  1986. {
  1987. PrintString(CompName, DIMA(CompName),
  1988. "<Win32 Error %d>", GetLastError());
  1989. }
  1990. }
  1991. while (Cookie =
  1992. DbgRpcEnumActiveServers(Cookie, &Id, Desc, sizeof(Desc)))
  1993. {
  1994. dprintf("%d - %s", Id, Desc);
  1995. if (ShowComputerName)
  1996. {
  1997. dprintf(",Server=%s", CompName);
  1998. }
  1999. dprintf("\n");
  2000. Any = TRUE;
  2001. }
  2002. if (!Any)
  2003. {
  2004. dprintf("No active servers\n");
  2005. }
  2006. }
  2007. void
  2008. DotServer(PDOT_COMMAND Cmd, DebugClient* Client)
  2009. {
  2010. HRESULT Status;
  2011. // Skip whitespace.
  2012. if (PeekChar() == 0)
  2013. {
  2014. ErrOut("Usage: .server tcp:port=<Socket> OR "
  2015. ".server npipe:pipe=<PipeName>\n");
  2016. }
  2017. else
  2018. {
  2019. Status = ClientStartServer(g_CurCmd, TRUE);
  2020. if (Status != S_OK)
  2021. {
  2022. ErrOut("Unable to start server, %s\n \"%s\"\n",
  2023. FormatStatusCode(Status), FormatStatus(Status));
  2024. }
  2025. else
  2026. {
  2027. dprintf("Server started. Client can connect with any of:\n");
  2028. EnumServers(TRUE);
  2029. }
  2030. *g_CurCmd = 0;
  2031. }
  2032. }
  2033. void
  2034. DotServers(PDOT_COMMAND Cmd, DebugClient* Client)
  2035. {
  2036. EnumServers(FALSE);
  2037. }
  2038. void
  2039. DotShell(PDOT_COMMAND Cmd, DebugClient* Client)
  2040. {
  2041. ShellProcess Shell;
  2042. PSTR InFile = NULL;
  2043. PSTR OutFile = NULL;
  2044. PSTR ErrFile = NULL;
  2045. PSTR* File;
  2046. if ((g_EngOptions & DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS) ||
  2047. (g_SymOptions & SYMOPT_SECURE))
  2048. {
  2049. ErrOut(".shell has been disabled\n");
  2050. return;
  2051. }
  2052. if (AnySystemProcesses(TRUE))
  2053. {
  2054. ErrOut(".shell: can't create a process while debugging CSRSS.\n");
  2055. return;
  2056. }
  2057. for (;;)
  2058. {
  2059. if (PeekChar() == '-')
  2060. {
  2061. g_CurCmd++;
  2062. switch(*g_CurCmd)
  2063. {
  2064. case 'e':
  2065. File = &ErrFile;
  2066. goto ParseFile;
  2067. case 'i':
  2068. File = &InFile;
  2069. goto ParseFile;
  2070. case 'o':
  2071. File = &OutFile;
  2072. ParseFile:
  2073. g_CurCmd++;
  2074. if (*g_CurCmd == '-')
  2075. {
  2076. *File = "nul";
  2077. g_CurCmd++;
  2078. }
  2079. else
  2080. {
  2081. char LastSave;
  2082. *File = StringValue(STRV_SPACE_IS_SEPARATOR |
  2083. STRV_ESCAPED_CHARACTERS,
  2084. &LastSave);
  2085. if (LastSave)
  2086. {
  2087. g_CurCmd++;
  2088. }
  2089. else
  2090. {
  2091. *g_CurCmd = LastSave;
  2092. }
  2093. }
  2094. break;
  2095. case 't':
  2096. Shell.m_DefaultTimeout = (ULONG)GetExpression() * 1000;
  2097. break;
  2098. default:
  2099. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  2100. g_CurCmd++;
  2101. break;
  2102. }
  2103. }
  2104. else
  2105. {
  2106. break;
  2107. }
  2108. }
  2109. // If either output file was specified singly give
  2110. // the output file the name and let the error file
  2111. // get set to a duplicate of it.
  2112. if (ErrFile && !OutFile)
  2113. {
  2114. OutFile = ErrFile;
  2115. ErrFile = NULL;
  2116. }
  2117. Shell.Start(g_CurCmd, InFile, OutFile, ErrFile);
  2118. // Command uses the whole string so we're done.
  2119. *g_CurCmd = 0;
  2120. }
  2121. void
  2122. DotSleep(PDOT_COMMAND Cmd, DebugClient* Client)
  2123. {
  2124. ULONG WaitStatus;
  2125. ULONG Millis = (ULONG)
  2126. GetExpressionDesc("Number of milliseconds missing from");
  2127. // This command is intended for use with ntsd/cdb -d
  2128. // when being at the prompt locks up the target machine.
  2129. // If you want to use the target machine for something,
  2130. // such as copy symbols, there's no easy way to get it
  2131. // running again without resuming the program. By
  2132. // sleeping you can return control to the target machine
  2133. // without changing the session state.
  2134. // The sleep is done with a wait on a named event so
  2135. // that it can be interrupted from a different process.
  2136. ResetEvent(g_SleepPidEvent);
  2137. WaitStatus = WaitForSingleObject(g_SleepPidEvent, Millis);
  2138. if (WaitStatus == WAIT_OBJECT_0)
  2139. {
  2140. dprintf("Sleep interrupted\n");
  2141. }
  2142. else if (WaitStatus != WAIT_TIMEOUT)
  2143. {
  2144. ErrOut("Sleep failed, %s\n",
  2145. FormatStatusCode(WIN32_LAST_STATUS()));
  2146. }
  2147. }
  2148. void
  2149. DotSrcPath(PDOT_COMMAND Cmd, DebugClient* Client)
  2150. {
  2151. if (PeekChar())
  2152. {
  2153. if (ChangePath(&g_SrcPath, g_CurCmd, Cmd->Name[7] == '+',
  2154. DEBUG_CSS_PATHS) != S_OK)
  2155. {
  2156. // This command uses the whole string.
  2157. *g_CurCmd = 0;
  2158. return;
  2159. }
  2160. *g_CurCmd = 0;
  2161. }
  2162. if (g_SrcPath == NULL)
  2163. {
  2164. dprintf("No source search path\n");
  2165. }
  2166. else
  2167. {
  2168. dprintf("Source search path is: %s\n", g_SrcPath);
  2169. CheckPath(g_SrcPath);
  2170. }
  2171. }
  2172. void
  2173. DotSymPath(PDOT_COMMAND Cmd, DebugClient* Client)
  2174. {
  2175. ChangeSymPath(g_CurCmd, Cmd->Name[7] == '+', NULL, 0);
  2176. // Command uses the whole string.
  2177. *g_CurCmd = 0;
  2178. }
  2179. void
  2180. DotSxCmds(PDOT_COMMAND Cmd, DebugClient* Client)
  2181. {
  2182. ULONG Flags = 0;
  2183. while (PeekChar() == '-')
  2184. {
  2185. switch(*(++g_CurCmd))
  2186. {
  2187. case '1':
  2188. Flags |= SXCMDS_ONE_LINE;
  2189. break;
  2190. default:
  2191. dprintf("Unknown option '%c'\n", *g_CurCmd);
  2192. break;
  2193. }
  2194. g_CurCmd++;
  2195. }
  2196. ListFiltersAsCommands(Client, Flags);
  2197. }
  2198. void
  2199. DotSymFix(PDOT_COMMAND Cmd, DebugClient* Client)
  2200. {
  2201. char Path[MAX_PATH * 2];
  2202. PSTR SrvName;
  2203. char LocalStore[MAX_PATH + 1];
  2204. strcpy(Path, "SRV*");
  2205. if (IsInternalPackage())
  2206. {
  2207. // Use the internal symbol server.
  2208. // A local cache is not required.
  2209. SrvName = "\\\\symbols\\symbols";
  2210. }
  2211. else
  2212. {
  2213. // Use the public Microsoft symbol server.
  2214. // This requires a local cache, so default
  2215. // if one isn't given.
  2216. SrvName = "http://msdl.microsoft.com/download/symbols";
  2217. if (!PeekChar() || *g_CurCmd == ';')
  2218. {
  2219. if (!CatString(Path, "*", DIMA(Path)))
  2220. {
  2221. error(OVERFLOW);
  2222. }
  2223. if (SymGetHomeDirectory(hdSym, LocalStore, DIMA(LocalStore)))
  2224. {
  2225. WarnOut("No local cache given, using %s\n", LocalStore);
  2226. }
  2227. }
  2228. }
  2229. if (PeekChar() && *g_CurCmd != ';')
  2230. {
  2231. char Save;
  2232. PSTR Str = StringValue(0, &Save);
  2233. if (!CatString(Path, Str, DIMA(Path)) ||
  2234. !CatString(Path, "*", DIMA(Path)))
  2235. {
  2236. error(OVERFLOW);
  2237. }
  2238. *g_CurCmd = Save;
  2239. }
  2240. if (!CatString(Path, SrvName, DIMA(Path)))
  2241. {
  2242. error(OVERFLOW);
  2243. }
  2244. ChangeSymPath(Path, Cmd->Name[6] == '+', NULL, 0);
  2245. }
  2246. void
  2247. DotSymOpt(PDOT_COMMAND Cmd, DebugClient* Client)
  2248. {
  2249. ULONG Flags = (ULONG)GetExpression();
  2250. if (Cmd->Name[6] == '+')
  2251. {
  2252. Flags |= g_SymOptions;
  2253. }
  2254. else
  2255. {
  2256. Flags = g_SymOptions & ~Flags;
  2257. }
  2258. if (SetSymOptions(Flags) != S_OK)
  2259. {
  2260. ErrOut("Invalid symbol options\n");
  2261. }
  2262. else
  2263. {
  2264. dprintf("Symbol options are %X\n", Flags);
  2265. }
  2266. }
  2267. void
  2268. DotTList(PDOT_COMMAND Cmd, DebugClient* Client)
  2269. {
  2270. BOOL ListCurrent = FALSE;
  2271. BOOL Verbose = FALSE;
  2272. if (!IS_LIVE_USER_TARGET(g_Target))
  2273. {
  2274. error(SESSIONNOTSUP);
  2275. }
  2276. if (g_SymOptions & SYMOPT_SECURE)
  2277. {
  2278. error(NOTSECURE);
  2279. }
  2280. while (PeekChar() == '-' || *g_CurCmd == '/')
  2281. {
  2282. switch(*++g_CurCmd)
  2283. {
  2284. case 'c':
  2285. if (g_Process == NULL)
  2286. {
  2287. error(BADPROCESS);
  2288. }
  2289. ListCurrent = TRUE;
  2290. break;
  2291. case 'v':
  2292. Verbose = TRUE;
  2293. break;
  2294. default:
  2295. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  2296. break;
  2297. }
  2298. g_CurCmd++;
  2299. }
  2300. PUSER_DEBUG_SERVICES Services =
  2301. ((LiveUserTargetInfo*)g_Target)->m_Services;
  2302. #define MAX_IDS 1024
  2303. ULONG Ids[MAX_IDS];
  2304. HRESULT Status;
  2305. ULONG IdCount;
  2306. ULONG i;
  2307. WCHAR DescBuf[2 * MAX_PATH];
  2308. PWSTR Desc;
  2309. ULONG DescLen;
  2310. if (ListCurrent)
  2311. {
  2312. Ids[0] = g_Process->m_SystemId;
  2313. IdCount = 1;
  2314. }
  2315. else
  2316. {
  2317. if ((Status = Services->GetProcessIds(Ids, MAX_IDS, &IdCount)) != S_OK)
  2318. {
  2319. ErrOut("Unable to get process list, %s\n",
  2320. FormatStatusCode(Status));
  2321. return;
  2322. }
  2323. if (IdCount > MAX_IDS)
  2324. {
  2325. WarnOut("Process list missing %d processes\n",
  2326. IdCount - MAX_IDS);
  2327. IdCount = MAX_IDS;
  2328. }
  2329. }
  2330. if (Verbose)
  2331. {
  2332. Desc = DescBuf;
  2333. DescLen = sizeof(DescBuf);
  2334. }
  2335. else
  2336. {
  2337. Desc = NULL;
  2338. DescLen = 0;
  2339. }
  2340. for (i = 0; i < IdCount; i++)
  2341. {
  2342. WCHAR ExeName[MAX_PATH];
  2343. int Space;
  2344. if (Ids[i] < 10)
  2345. {
  2346. Space = 3;
  2347. }
  2348. else if (Ids[i] < 100)
  2349. {
  2350. Space = 2;
  2351. }
  2352. else if (Ids[i] < 1000)
  2353. {
  2354. Space = 1;
  2355. }
  2356. else
  2357. {
  2358. Space = 0;
  2359. }
  2360. dprintf("%.*s", Space, " ");
  2361. if (FAILED(Status = Services->
  2362. GetProcessDescriptionW(Ids[i], DEBUG_PROC_DESC_DEFAULT,
  2363. ExeName, sizeof(ExeName), NULL,
  2364. Desc, DescLen, NULL)))
  2365. {
  2366. ErrOut("0n%d Error %s\n", Ids[i], FormatStatusCode(Status));
  2367. }
  2368. else if (Ids[i] >= 0x80000000)
  2369. {
  2370. dprintf("0x%x %ws\n", Ids[i], ExeName);
  2371. }
  2372. else
  2373. {
  2374. dprintf("0n%d %ws\n", Ids[i], ExeName);
  2375. }
  2376. if (Desc && Desc[0])
  2377. {
  2378. dprintf(" %ws\n", Desc);
  2379. }
  2380. }
  2381. }
  2382. void
  2383. DotTime(PDOT_COMMAND Cmd, DebugClient* Client)
  2384. {
  2385. if (!g_Target)
  2386. {
  2387. error(BADSYSTEM);
  2388. }
  2389. g_Target->OutputTime();
  2390. }
  2391. void
  2392. DotTrap(PDOT_COMMAND Cmd, DebugClient* Client)
  2393. {
  2394. ULONG64 Addr = 0;
  2395. if (PeekChar() && *g_CurCmd != ';')
  2396. {
  2397. Addr = GetExpression();
  2398. }
  2399. if (Addr)
  2400. {
  2401. CROSS_PLATFORM_CONTEXT Context;
  2402. if (g_Target->m_Machine->GetContextFromTrapFrame(Addr, &Context,
  2403. TRUE) == S_OK)
  2404. {
  2405. g_Target->m_Machine->SetAndOutputTrapFrame(Addr, &Context);
  2406. }
  2407. }
  2408. else if (GetCurrentScopeContext())
  2409. {
  2410. dprintf("Resetting default context\n");
  2411. ResetCurrentScope();
  2412. }
  2413. }
  2414. void
  2415. DotTss(PDOT_COMMAND Cmd, DebugClient* Client)
  2416. {
  2417. ULONG Sel = 0;
  2418. BOOL Extended = FALSE;
  2419. if (PeekChar() && *g_CurCmd != ';')
  2420. {
  2421. Sel = (ULONG)GetExpression();
  2422. // If user specified a 2nd parameter, doesn't matter
  2423. // what it is, dump the portions of the TSS not covered
  2424. // by the trap frame dump.
  2425. if (PeekChar() && *g_CurCmd != ';')
  2426. {
  2427. Extended = TRUE;
  2428. g_CurCmd += strlen(g_CurCmd);
  2429. }
  2430. }
  2431. if (Sel)
  2432. {
  2433. CROSS_PLATFORM_CONTEXT Context;
  2434. DESCRIPTOR64 SelDesc;
  2435. //
  2436. // Lookup task selector.
  2437. //
  2438. if (g_Target->GetSelDescriptor
  2439. (g_Thread, g_Machine, Sel, &SelDesc) != S_OK)
  2440. {
  2441. ErrOut("Unable to get descriptor for selector %x\n",
  2442. Sel);
  2443. return;
  2444. }
  2445. if (X86_DESC_TYPE(SelDesc.Flags) != 9 &&
  2446. X86_DESC_TYPE(SelDesc.Flags) != 0xb)
  2447. {
  2448. ErrOut("%x is not a 32-bit TSS selector\n", Sel);
  2449. return;
  2450. }
  2451. if (g_Target->m_Machine->
  2452. GetContextFromTaskSegment(SelDesc.Base, &Context,
  2453. TRUE) == S_OK)
  2454. {
  2455. g_Target->m_Machine->
  2456. SetAndOutputTaskSegment(SelDesc.Base, &Context,
  2457. Extended);
  2458. }
  2459. }
  2460. else if (GetCurrentScopeContext())
  2461. {
  2462. dprintf("Resetting default context\n");
  2463. ResetCurrentScope();
  2464. }
  2465. }
  2466. void
  2467. DotTTime(PDOT_COMMAND Cmd, DebugClient* Client)
  2468. {
  2469. if (!g_Thread)
  2470. {
  2471. error(BADSYSTEM);
  2472. }
  2473. g_Thread->OutputTimes();
  2474. }
  2475. void
  2476. LoadTxtSym(FILE* File, PSTR FileName, ULONG64 Base, ULONG Size)
  2477. {
  2478. char Line[MAX_SYMBOL_LEN];
  2479. ImageInfo* Image;
  2480. BOOL Absolute = FALSE;
  2481. if (!fgets(Line, DIMA(Line), File) ||
  2482. strcmp(Line, "TEXTSYM format | V1.0\n") != 0)
  2483. {
  2484. ErrOut("Not a TEXTSYM 1.0 file\n");
  2485. return;
  2486. }
  2487. Image = new ImageInfo(g_Process, FileName, Base, TRUE);
  2488. if (!Image)
  2489. {
  2490. ErrOut("Unable to create module\n");
  2491. return;
  2492. }
  2493. Image->m_SizeOfImage = Size;
  2494. CreateModuleNameFromPath(FileName, Image->m_ModuleName);
  2495. strcpy(Image->m_OriginalModuleName, Image->m_ModuleName);
  2496. if (!SymLoadModuleEx(g_Process->m_SymHandle, NULL,
  2497. Image->m_ImagePath,
  2498. Image->m_ModuleName, Image->m_BaseOfImage,
  2499. Image->m_SizeOfImage, NULL, SLMFLAG_VIRTUAL))
  2500. {
  2501. ErrOut("Unable to add module\n");
  2502. delete Image;
  2503. return;
  2504. }
  2505. for (;;)
  2506. {
  2507. PSTR Scan;
  2508. ULONG64 Addr;
  2509. if (!fgets(Line, DIMA(Line), File))
  2510. {
  2511. break;
  2512. }
  2513. if (strncmp(Line, "GLOBAL | ", 9) != 0)
  2514. {
  2515. continue;
  2516. }
  2517. // Remove newline.
  2518. Scan = Line + strlen(Line) - 1;
  2519. if (*Scan == '\n')
  2520. {
  2521. *Scan = 0;
  2522. }
  2523. Scan = Line + 9;
  2524. if (!sscanf(Scan, "%I64x", &Addr))
  2525. {
  2526. ErrOut("Unable to read address at %.16s\n", Scan);
  2527. break;
  2528. }
  2529. if (Absolute && (Addr < Base || Addr >= Base + Size))
  2530. {
  2531. ErrOut("Address %I64x out of image bounds\n", Addr);
  2532. continue;
  2533. }
  2534. Scan += 26;
  2535. if (!SymAddSymbol(g_Process->m_SymHandle,
  2536. Image->m_BaseOfImage,
  2537. Scan, Addr + Base, 0, 0))
  2538. {
  2539. ErrOut("Unable to add '%s' at %I64x\n", Scan, Addr);
  2540. }
  2541. }
  2542. }
  2543. void
  2544. DotTxtSym(PDOT_COMMAND Cmd, DebugClient* Client)
  2545. {
  2546. PSTR FileName;
  2547. char Save;
  2548. ULONG64 Base;
  2549. ULONG Size;
  2550. FILE* File;
  2551. //
  2552. // XXX drewb.
  2553. // At the moment the IA64 firmware symbols come in
  2554. // a couple of trivial text formats. In order to
  2555. // help them out we added this simple command to
  2556. // create a fake module and populate it from the
  2557. // text files. This should be removed when
  2558. // no longer necessary.
  2559. //
  2560. FileName = StringValue(STRV_SPACE_IS_SEPARATOR |
  2561. STRV_ESCAPED_CHARACTERS, &Save);
  2562. File = fopen(FileName, "r");
  2563. if (!File)
  2564. {
  2565. ErrOut("Unable to open '%s', Win32 error %d\n",
  2566. FileName, GetLastError());
  2567. *g_CurCmd = 0;
  2568. return;
  2569. }
  2570. if (Save == '"')
  2571. {
  2572. Save = *++g_CurCmd;
  2573. }
  2574. if (isspace(Save))
  2575. {
  2576. g_CurCmd++;
  2577. Save = PeekChar();
  2578. }
  2579. __try
  2580. {
  2581. if (Save != '=')
  2582. {
  2583. error(SYNTAX);
  2584. }
  2585. g_CurCmd++;
  2586. Base = GetExpression();
  2587. if (PeekChar() != ',')
  2588. {
  2589. error(SYNTAX);
  2590. }
  2591. g_CurCmd++;
  2592. Size = (ULONG)GetExpression();
  2593. LoadTxtSym(File, FileName, Base, Size);
  2594. }
  2595. __except(CommandExceptionFilter(GetExceptionInformation()))
  2596. {
  2597. *g_CurCmd = 0;
  2598. }
  2599. fclose(File);
  2600. }
  2601. void
  2602. DotWake(PDOT_COMMAND Cmd, DebugClient* Client)
  2603. {
  2604. ULONG Pid = (ULONG)GetExpression();
  2605. if (!SetPidEvent(Pid, OPEN_EXISTING))
  2606. {
  2607. ErrOut("Process %d is not a sleeping debugger\n", Pid);
  2608. }
  2609. }
  2610. void
  2611. DotWriteMem(PDOT_COMMAND Cmd, DebugClient* Client)
  2612. {
  2613. if (!g_Process)
  2614. {
  2615. error(BADPROCESS);
  2616. }
  2617. PSTR FileName, FileNameEnd;
  2618. char Save;
  2619. HANDLE File;
  2620. ADDR Addr;
  2621. ULONG64 Len;
  2622. char Buf[2048];
  2623. BOOL Err = FALSE;
  2624. FileName = StringValue(STRV_SPACE_IS_SEPARATOR |
  2625. STRV_ESCAPED_CHARACTERS, &Save);
  2626. FileNameEnd = g_CurCmd;
  2627. *g_CurCmd = Save;
  2628. Len = 0x10000;
  2629. GetRange(&Addr, &Len, 1, SEGREG_DATA, DEFAULT_RANGE_LIMIT);
  2630. *FileNameEnd = 0;
  2631. File = CreateFile(FileName, GENERIC_WRITE, 0, NULL,
  2632. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  2633. if (File == INVALID_HANDLE_VALUE)
  2634. {
  2635. ErrOut("Unable to create file\n");
  2636. return;
  2637. }
  2638. dprintf("Writing %s bytes", FormatDisp64(Len));
  2639. FlushCallbacks();
  2640. while (Len > 0)
  2641. {
  2642. ULONG Req, Done;
  2643. Req = sizeof(Buf);
  2644. if (Req > Len)
  2645. {
  2646. Req = (ULONG)Len;
  2647. }
  2648. if (CurReadVirtual(Flat(Addr), Buf, Req, &Done) != S_OK ||
  2649. Done != Req)
  2650. {
  2651. dprintf("\n");
  2652. ErrOut("Unable to read memory at %s, file is incomplete\n",
  2653. FormatAddr64(Flat(Addr)));
  2654. Err = TRUE;
  2655. break;
  2656. }
  2657. if (!WriteFile(File, Buf, Req, &Done, NULL) ||
  2658. Done != Req)
  2659. {
  2660. dprintf("\n");
  2661. ErrOut("Unable to write data from %s, file is incomplete\n",
  2662. FormatAddr64(Flat(Addr)));
  2663. Err = TRUE;
  2664. break;
  2665. }
  2666. AddrAdd(&Addr, Done);
  2667. Len -= Done;
  2668. dprintf(".");
  2669. FlushCallbacks();
  2670. }
  2671. CloseHandle(File);
  2672. if (!Err)
  2673. {
  2674. dprintf("\n");
  2675. }
  2676. }
  2677. #define MODE_USER 0x00000001
  2678. #define MODE_KERNEL 0x00000002
  2679. #define _MODE_UK (MODE_USER | MODE_KERNEL)
  2680. #define MODE_LIVE 0x00000004
  2681. #define MODE_DUMP 0x00000008
  2682. #define _MODE_LD (MODE_LIVE | MODE_DUMP)
  2683. #define MODE_LOCAL 0x00000010
  2684. #define MODE_REMOTE 0x00000020
  2685. #define MODE_REMOTE_CONN 0x00000040
  2686. #define _MODE_LR (MODE_LOCAL | MODE_REMOTE | MODE_REMOTE_CONN)
  2687. #define MODE_BANG 0x20000000
  2688. #define MODE_INTERNAL 0x40000000
  2689. #define MODE_UNINIT 0x80000000
  2690. #define ANY (0xffff | MODE_UNINIT)
  2691. #define AIT (_MODE_UK | _MODE_LD | _MODE_LR)
  2692. #define AUT (MODE_USER | _MODE_LD | _MODE_LR)
  2693. #define LLU (MODE_USER | MODE_LIVE | MODE_LOCAL)
  2694. #define LUT (MODE_USER | MODE_LIVE | _MODE_LR)
  2695. #define AKT (MODE_KERNEL | _MODE_LD | _MODE_LR)
  2696. #define LKT (MODE_KERNEL | MODE_LIVE | _MODE_LR)
  2697. #define RKT (MODE_KERNEL | MODE_LIVE | MODE_REMOTE | MODE_REMOTE_CONN)
  2698. #define CKT (MODE_KERNEL | MODE_LIVE | MODE_REMOTE_CONN)
  2699. #define ADT (_MODE_UK | MODE_DUMP | _MODE_LR)
  2700. ULONG
  2701. CurrentMode(void)
  2702. {
  2703. ULONG Mode = 0;
  2704. if (IS_USER_TARGET(g_Target))
  2705. {
  2706. Mode |= MODE_USER;
  2707. if (IS_DUMP_TARGET(g_Target) ||
  2708. ((LiveUserTargetInfo*)g_Target)->m_Local)
  2709. {
  2710. Mode |= MODE_LOCAL;
  2711. }
  2712. else
  2713. {
  2714. Mode |= MODE_REMOTE;
  2715. }
  2716. }
  2717. else if (IS_KERNEL_TARGET(g_Target))
  2718. {
  2719. Mode |= MODE_KERNEL;
  2720. if (IS_CONN_KERNEL_TARGET(g_Target))
  2721. {
  2722. Mode |= MODE_REMOTE_CONN;
  2723. }
  2724. else if (IS_REMOTE_KERNEL_TARGET(g_Target))
  2725. {
  2726. Mode |= MODE_REMOTE;
  2727. }
  2728. else
  2729. {
  2730. Mode |= MODE_LOCAL;
  2731. }
  2732. }
  2733. else
  2734. {
  2735. return MODE_UNINIT;
  2736. }
  2737. if (IS_DUMP_TARGET(g_Target))
  2738. {
  2739. Mode |= MODE_DUMP;
  2740. }
  2741. else
  2742. {
  2743. Mode |= MODE_LIVE;
  2744. }
  2745. return Mode;
  2746. }
  2747. void DotHelp(PDOT_COMMAND Cmd, DebugClient* Client);
  2748. // These must be in alphabetical order.
  2749. DOT_COMMAND g_DotCommands[] =
  2750. {
  2751. LUT, "abandon", "", "abandon the current process",
  2752. ParseSeparateCurrentProcess,
  2753. ANY | MODE_INTERNAL, "aliascmds", "", "", DotAliasCmds,
  2754. ANY, "asm", "[<options>]", "set disassembly options", DotAsm,
  2755. ANY, "asm-", "[<options>]", "clear disassembly options", DotAsm,
  2756. ANY, "attach", "<proc>", "attach to <proc> at next execution", DotAttach,
  2757. ANY | MODE_INTERNAL, "bpcmds", "", "", DotBpCmds,
  2758. LUT, "bpsync", "[0|1]", "special breakpoint behavior for "
  2759. "multithreaded debuggees", DotBpSync,
  2760. LUT, "breakin", "", "break into KD", DotBreakin,
  2761. AKT, "bugcheck", "", "display the bugcheck code and parameters "
  2762. "for a crashed system", DotBugCheck,
  2763. AIT, "cache", "[<options>]", "virtual memory cache control", DotCache,
  2764. ANY | MODE_BANG, "chain", "", "list current extensions", DotChain,
  2765. LUT, "childdbg", "<0|1>", "turn child process debugging on or off",
  2766. DotChildDbg,
  2767. ANY, "clients", "", "list currently active clients", DotClients,
  2768. LUT, "closehandle", "[<options>] [<handle>]", "close the given handle",
  2769. DotCloseHandle,
  2770. AKT, "context", "[<address>]", "set page directory base", DotContext,
  2771. ANY | MODE_INTERNAL, "corstack", "[0|1]", "toggle COR stack assistance",
  2772. DotCorStack,
  2773. LKT, "crash", "", "cause target to bugcheck", DotCrash,
  2774. ANY, "create", "<command line>", "create a new process", DotCreate,
  2775. ANY, "createdir", "[<path>]", "current directory for process create",
  2776. DotCreateDir,
  2777. AIT, "cxr", "<address>", "dump context record at specified address\n"
  2778. "k* after this gives cxr stack", DotCxr,
  2779. AIT, "detach", "", "detach from the current process/dump",
  2780. ParseSeparateCurrentProcess,
  2781. AIT, "dump", "[<options>] <filename>", "create a dump file on the "
  2782. "host system", DotDump,
  2783. ADT, "dumpcab", "[<options>] <filename>", "create a CAB for an open dump",
  2784. DotDumpCab,
  2785. ADT, "dumpdebug", "", "display detailed information about the dump file",
  2786. DotDumpDebug,
  2787. ADT | MODE_INTERNAL, "dumpoff", "", "", DotDumpOff,
  2788. ADT | MODE_INTERNAL, "dumppoff", "", "", DotDumpPOff,
  2789. AIT | MODE_BANG, "drivers", "", "display the list of loaded modules "
  2790. "(same as .reload -l)", DotDrivers,
  2791. ANY, "echo", "[\"<string>\"|<string>]", "echo string", DotEcho,
  2792. ANY, "echotimestamps", "[0|1]", "toggle timestamp output on events",
  2793. DotEchoTimestamps,
  2794. AIT, "ecxr", "", "dump context record for current exception", DotEcxr,
  2795. AIT, "effmach", "[<machine>]", "change current machine type", DotEffMach,
  2796. ANY, "enable_long_status", "[0|1]", "dump LONG types in default base",
  2797. DotEnableLongStatus,
  2798. ANY, "enable_unicode", "[0|1]", "dump USHORT array/pointers "
  2799. "and unicode strings", DotEnableUnicode,
  2800. ANY, "endsrv", "<id>", "disable the given engine server", DotEndSrv,
  2801. LLU, "endpsrv", "", "cause the current session's "
  2802. "process server to exit", DotEndPSrv,
  2803. AIT, "enumtag", "", "enumerate available tagged data", DotEnumTag,
  2804. ANY, "eventlog", "", "display log of recent events", DotEventLog,
  2805. AIT, "events", "", "display and select available events", DotEvents,
  2806. AIT, "eventstr", "", "display any event strings registered by debuggee",
  2807. DotEventStr,
  2808. ANY | MODE_BANG, "exepath", "[<dir>[;...]]", "set executable search path",
  2809. DotExePath,
  2810. ANY | MODE_BANG, "exepath+", "[<dir>[;...]]",
  2811. "append executable search path", DotExePath,
  2812. ANY, "expr", "", "control expression evaluator", DotExpr,
  2813. AIT, "exr", "<address>", "dump exception record at specified address",
  2814. DotExr,
  2815. AIT, "fiber", "<address>", "sets context of fiber at address\n"
  2816. "resets context if no address specified", DotFiber,
  2817. AIT, "fnent", "<address>", "dump function entry for the "
  2818. "given code address", DotFnEnt,
  2819. AIT, "frame", "[<frame>]", "set current stack frame for locals", DotFrame,
  2820. AIT | MODE_INTERNAL, "frame_ebpfix", "", "", DotFrameEbpFix,
  2821. ANY, "formats", "<expr>", "displays expression result in many formats",
  2822. DotFormats,
  2823. ANY, "force_radix_output", "[0|1]", "dump integer types in default base",
  2824. DotForceRadixOutput,
  2825. ANY, "help", "", "display this help", DotHelp,
  2826. AIT, "imgscan", "<options>", "scan memory for PE images", DotImgScan,
  2827. CKT, "kdfiles", "<file>", "control debuggee remote file loading",
  2828. DotKdFiles,
  2829. CKT, "kdtrans", "", "display current KD transport information", DotKdTrans,
  2830. ANY, "kframes", "<count>", "set default stack trace depth", DotKFrames,
  2831. LUT, "kill", "", "kill the current process",
  2832. ParseSeparateCurrentProcess,
  2833. RKT, "kill", "", "kill a process on the target", DotKernelKill,
  2834. ANY, "lastevent", "", "display the last event that occurred", DotLastEvent,
  2835. ANY | MODE_BANG, "lines", "", "toggle line symbol loading", DotLines,
  2836. ANY | MODE_BANG, "load", "<name>",
  2837. "add this extension DLL to the list of known DLLs", NULL,
  2838. ANY, "locale", "[<locale>]", "set the current locale", DotLocale,
  2839. ANY, "logfile", "", "display log status", DotLogFile,
  2840. ANY, "logopen", "[<file>]", "open new log file", DotLogOpen,
  2841. ANY, "logappend", "[<file>]", "append to log file", DotLogAppend,
  2842. ANY, "logclose", "", "close log file", DotLogClose,
  2843. ANY, "netsyms", "[0|1]", "allow/disallow net symbol paths", DotNetSyms,
  2844. ANY | MODE_INTERNAL, "noengerr", "", "", DotNoEngErr,
  2845. ANY, "noshell", "", "disable shell commands", DotNoShell,
  2846. ANY | MODE_BANG, "noversion", "", "disable extension version checking",
  2847. DotNoVersion,
  2848. ANY, "ofilter", "<pattern>", "filter debuggee output against "
  2849. "the given pattern", DotOFilter,
  2850. LUT, "ocommand", "<prefix>", "treat output with the given prefix "
  2851. "as a command", DotOCommand,
  2852. ANY, "opendump", "<file>", "open a dump file", DotOpenDump,
  2853. ANY, "outmask", "<mask>", "set bits in the current output mask",
  2854. DotOutMask,
  2855. ANY, "outmask-", "<mask>", "clear bits in the current output mask",
  2856. DotOutMask,
  2857. LKT, "pagein", "[<options>] <addr>", "page in user-mode data", DotPageIn,
  2858. RKT, "pcache", "[<options>]", "physical memory cache control", DotPCache,
  2859. AIT, "process", "[<address>]", "sets implicit process\n"
  2860. "resets default if no address specified", DotProcess,
  2861. RKT, "reboot", "", "reboot target", DotReboot,
  2862. AIT | MODE_INTERNAL, "recxr", "", "", DotReCxr,
  2863. AIT | MODE_BANG, "reload", "[<image.ext>[=<address>,<size>]]",
  2864. "reload symbols", DotReload,
  2865. ANY, "remote", "<pipename>", "start remote.exe server", NULL,
  2866. ANY, "secure", "[0|1]", "disallow operations dangerous for the host",
  2867. DotSecure,
  2868. ANY, "server", "<options>", "start engine server", DotServer,
  2869. ANY, "servers", "", "list active remoting servers", DotServers,
  2870. ANY | MODE_BANG, "setdll", "<name>", "debugger will search for extensions "
  2871. "in this DLL first", NULL,
  2872. ANY, "shell", "[<command>]", "execute shell command", DotShell,
  2873. ANY, "sleep", "<milliseconds>", "debugger sleeps for given duration\n"
  2874. "useful for allowing access to a machine that's\n"
  2875. "broken in on an ntsd -d", DotSleep,
  2876. ANY | MODE_BANG, "srcpath", "[<dir>[;...]]", "set source search path",
  2877. DotSrcPath,
  2878. ANY | MODE_BANG, "srcpath+", "[<dir>[;...]]", "append source search path",
  2879. DotSrcPath,
  2880. ANY | MODE_INTERNAL, "sxcmds", "", "", DotSxCmds,
  2881. ANY | MODE_BANG, "symfix", "[<localsym>]", "fix symbol search path",
  2882. DotSymFix,
  2883. ANY | MODE_BANG, "symfix+", "[<localsym>]",
  2884. "append fixed symbol search path", DotSymFix,
  2885. ANY, "symopt+", "<flags>", "set symbol options", DotSymOpt,
  2886. ANY, "symopt-", "<flags>", "clear symbol options", DotSymOpt,
  2887. ANY | MODE_BANG, "sympath", "[<dir>[;...]]", "set symbol search path",
  2888. DotSymPath,
  2889. ANY | MODE_BANG, "sympath+", "[<dir>[;...]]", "append symbol search path",
  2890. DotSymPath,
  2891. AIT, "thread", "[<address>]", "sets context of thread at address\n"
  2892. "resets default context if no address specified", DotThread,
  2893. AIT, "time", "", "displays session time information", DotTime,
  2894. AIT, "ttime", "", "displays thread time information", DotTTime,
  2895. LUT, "tlist", "", "list running processes", DotTList,
  2896. AKT, "trap", "<address>", "dump a trap frame", DotTrap,
  2897. AKT, "tss", "<selector>", "dump a Task State Segment", DotTss,
  2898. ANY | MODE_INTERNAL, "txtsym", "", "", DotTxtSym,
  2899. ANY | MODE_BANG, "unload", "<name>", "remove this extension DLL from the "
  2900. "list of extension DLLs", NULL,
  2901. ANY | MODE_BANG, "unloadall", "", "remove all extension DLLs from the "
  2902. "list of extensions DLLs", NULL,
  2903. ANY, "wake", "", "wake up a .sleep'ing debugger", DotWake,
  2904. AIT, "writemem", "<file> <range>", "write raw memory to a file",
  2905. DotWriteMem,
  2906. };
  2907. void
  2908. DotHelp(PDOT_COMMAND Cmd, DebugClient* Client)
  2909. {
  2910. ULONG Mode = CurrentMode();
  2911. dprintf(". commands:\n");
  2912. for (Cmd = g_DotCommands;
  2913. Cmd < g_DotCommands + DIMA(g_DotCommands);
  2914. Cmd++)
  2915. {
  2916. if (!(Cmd->Mode & MODE_INTERNAL) &&
  2917. (Cmd->Mode & Mode) == Mode)
  2918. {
  2919. PSTR Desc;
  2920. int StartBlanks;
  2921. dprintf(" .%s", Cmd->Name);
  2922. StartBlanks = 4 + strlen(Cmd->Name);
  2923. if (*Cmd->Args)
  2924. {
  2925. dprintf(" %s", Cmd->Args);
  2926. StartBlanks += 1 + strlen(Cmd->Args);
  2927. }
  2928. dprintf(" - ");
  2929. StartBlanks += 3;
  2930. Desc = Cmd->Desc;
  2931. while (*Desc)
  2932. {
  2933. PSTR Nl;
  2934. Nl = strchr(Desc, '\n');
  2935. if (Nl)
  2936. {
  2937. dprintf("%.*s%.*s",
  2938. (int)(Nl - Desc) + 1, Desc,
  2939. StartBlanks, g_Blanks);
  2940. Desc = Nl + 1;
  2941. }
  2942. else
  2943. {
  2944. dprintf("%s", Desc);
  2945. break;
  2946. }
  2947. }
  2948. dprintf("\n");
  2949. }
  2950. }
  2951. dprintf("\nUse \".hh <command>\" or open debugger.chm in the debuggers "
  2952. "directory to get\n"
  2953. "detailed documentation on a command.\n");
  2954. dprintf("\n");
  2955. }
  2956. #define MAX_DOT_COMMAND 32
  2957. BOOL
  2958. DotCommand(DebugClient* Client, BOOL Bang)
  2959. {
  2960. ULONG Index = 0;
  2961. char Cmd[MAX_DOT_COMMAND];
  2962. char Ch;
  2963. // Read in up to the first few alpha characters into
  2964. // Cmd, converting to lower case.
  2965. while (Index < MAX_DOT_COMMAND)
  2966. {
  2967. Ch = (char)tolower(*g_CurCmd);
  2968. if ((Ch >= 'a' && Ch <= 'z') || Ch == '-' || Ch == '+' || Ch == '_')
  2969. {
  2970. Cmd[Index++] = Ch;
  2971. g_CurCmd++;
  2972. }
  2973. else
  2974. {
  2975. break;
  2976. }
  2977. }
  2978. // If all characters read, then too big, else terminate.
  2979. if (Index == MAX_DOT_COMMAND)
  2980. {
  2981. return FALSE;
  2982. }
  2983. Cmd[Index] = '\0';
  2984. DOT_COMMAND* DotCmd;
  2985. ULONG Mode = CurrentMode();
  2986. if (Bang)
  2987. {
  2988. Mode |= MODE_BANG;
  2989. }
  2990. for (DotCmd = g_DotCommands;
  2991. DotCmd < g_DotCommands + DIMA(g_DotCommands);
  2992. DotCmd++)
  2993. {
  2994. if (DotCmd->Func &&
  2995. (DotCmd->Mode & Mode) == Mode &&
  2996. !strcmp(Cmd, DotCmd->Name))
  2997. {
  2998. DotCmd->Func(DotCmd, Client);
  2999. return TRUE;
  3000. }
  3001. }
  3002. return FALSE;
  3003. }