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.

2450 lines
67 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Engine interface code.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "precomp.hxx"
  9. #pragma hdrstop
  10. #include <dbghelp.h>
  11. #define DBG_CALLBACK 0
  12. #define DBG_INPUT 0
  13. // Windows that change behavior depending on the execution status.
  14. #define UPDATE_EXEC_WINDOWS \
  15. ((1 << CPU_WINDOW) | \
  16. (1 << DISASM_WINDOW) | \
  17. (1 << CMD_WINDOW) | \
  18. (1 << LOCALS_WINDOW) | \
  19. (1 << WATCH_WINDOW) | \
  20. (1 << MEM_WINDOW))
  21. // Windows that use symbol information.
  22. #define UPDATE_SYM_WINDOWS \
  23. ((1 << DOC_WINDOW) | \
  24. (1 << WATCH_WINDOW) | \
  25. (1 << LOCALS_WINDOW) | \
  26. (1 << DISASM_WINDOW) | \
  27. (1 << QUICKW_WINDOW) | \
  28. (1 << CALLS_WINDOW) | \
  29. (1 << EVENT_BIT) | \
  30. (1 << BP_BIT))
  31. // Symbol options that cause visible changes and
  32. // therefore require a refresh. Note that this
  33. // doesn't include options that would cause a visible
  34. // change only after symbol reload as things will
  35. // get refreshed when the load notifications come in.
  36. #define REFRESH_SYMOPT \
  37. (~(SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | \
  38. SYMOPT_LOAD_ANYTHING | SYMOPT_IGNORE_CVREC | \
  39. SYMOPT_NO_UNQUALIFIED_LOADS | SYMOPT_EXACT_SYMBOLS))
  40. //
  41. // Session initialization parameters.
  42. //
  43. // Turn on verbose output or not.
  44. BOOL g_Verbose;
  45. // Dump files to open.
  46. PTSTR g_DumpFiles[MAX_DUMP_FILES];
  47. ULONG g_NumDumpFiles;
  48. PTSTR g_DumpInfoFiles[MAX_DUMP_FILES];
  49. ULONG g_DumpInfoTypes[MAX_DUMP_FILES];
  50. ULONG g_NumDumpInfoFiles;
  51. // Process server to use.
  52. PSTR g_ProcessServer;
  53. // Full command line with exe name.
  54. PSTR g_DebugCommandLine;
  55. PSTR g_ProcessStartDir;
  56. // Process creation flags.
  57. ULONG g_DebugCreateFlags = DEBUG_ONLY_THIS_PROCESS;
  58. // Process ID to attach to or zero.
  59. ULONG g_PidToDebug;
  60. // Process name to attach to or NULL.
  61. PSTR g_ProcNameToDebug;
  62. BOOL g_DetachOnExit;
  63. ULONG g_AttachProcessFlags = DEBUG_ATTACH_DEFAULT;
  64. // Kernel connection options.
  65. ULONG g_AttachKernelFlags = DEBUG_ATTACH_KERNEL_CONNECTION;
  66. PSTR g_KernelConnectOptions;
  67. // Remoting options.
  68. BOOL g_RemoteClient;
  69. ULONG g_HistoryLines = 10000;
  70. //
  71. // Debug engine interfaces for the engine thread.
  72. //
  73. IDebugClient *g_pDbgClient;
  74. IDebugClient2 *g_pDbgClient2;
  75. IDebugControl *g_pDbgControl;
  76. IDebugSymbols *g_pDbgSymbols;
  77. IDebugSymbolGroup *g_pDbgWatchSymbolGroup;
  78. IDebugSymbolGroup *g_pDbgLocalSymbolGroup = NULL;
  79. IDebugRegisters *g_pDbgRegisters;
  80. IDebugDataSpaces *g_pDbgData;
  81. IDebugSystemObjects *g_pDbgSystem;
  82. IDebugSystemObjects3 *g_pDbgSystem3;
  83. //
  84. // Debug engine interfaces for the UI thread.
  85. //
  86. IDebugClient *g_pUiClient;
  87. IDebugControl *g_pUiControl;
  88. IDebugControl3 *g_pUiControl3;
  89. IDebugSymbols *g_pUiSymbols;
  90. IDebugSymbols2 *g_pUiSymbols2;
  91. IDebugSystemObjects *g_pUiSystem;
  92. //
  93. // Debug engine interfaces for private output capture.
  94. //
  95. IDebugClient *g_pOutCapClient;
  96. IDebugControl *g_pOutCapControl;
  97. IDebugSymbols *g_pOutCapSymbols;
  98. //
  99. // Debug engine interfaces for local source file lookup.
  100. //
  101. IDebugClient *g_pLocClient;
  102. IDebugControl *g_pLocControl;
  103. IDebugSymbols *g_pLocSymbols;
  104. IDebugClient *g_pUiLocClient;
  105. IDebugControl *g_pUiLocControl;
  106. IDebugSymbols *g_pUiLocSymbols;
  107. ULONG g_ActualProcType = IMAGE_FILE_MACHINE_UNKNOWN;
  108. char g_ActualProcAbbrevName[32];
  109. ULONG g_CommandSequence;
  110. ULONG g_TargetClass = DEBUG_CLASS_UNINITIALIZED;
  111. ULONG g_TargetClassQual;
  112. BOOL g_Ptr64;
  113. ULONG g_ExecStatus = DEBUG_STATUS_NO_DEBUGGEE;
  114. ULONG g_EngOptModified;
  115. ULONG g_EngineThreadId;
  116. HANDLE g_EngineThread;
  117. PSTR g_InitialCommand;
  118. char g_PromptText[32];
  119. BOOL g_WaitingForEvent;
  120. ULONG g_NumberRadix;
  121. BOOL g_CodeLevelLocked;
  122. BOOL g_IgnoreFilterChange;
  123. BOOL g_IgnoreCodeLevelChange;
  124. BOOL g_IgnoreThreadChange;
  125. ULONG g_LastProcessExitCode;
  126. ULONG g_SymOptions;
  127. ULONG g_TypeOptions;
  128. BOOL g_InputStarted;
  129. BOOL g_Invisible;
  130. BOOL g_HoldWaitOutput;
  131. BOOL g_ScopeChanged;
  132. enum
  133. {
  134. ENDING_NONE,
  135. ENDING_RESTART,
  136. ENDING_STOP,
  137. ENDING_EXIT
  138. };
  139. ULONG g_EndingSession = ENDING_NONE;
  140. void SetLocalScope(PDEBUG_STACK_FRAME);
  141. BOOL g_SessionActive;
  142. void SessionActive(void);
  143. void SessionInactive(void);
  144. StateBuffer g_UiCommandBuffer(MAX_COMMAND_LEN);
  145. StateBuffer g_UiOutputBuffer(128 * 1024);
  146. //----------------------------------------------------------------------------
  147. //
  148. // Default output callbacks implementation, provides IUnknown for
  149. // static classes.
  150. //
  151. //----------------------------------------------------------------------------
  152. STDMETHODIMP
  153. DefOutputCallbacks::QueryInterface(
  154. THIS_
  155. IN REFIID InterfaceId,
  156. OUT PVOID* Interface
  157. )
  158. {
  159. *Interface = NULL;
  160. if (IsEqualIID(InterfaceId, IID_IUnknown) ||
  161. IsEqualIID(InterfaceId, IID_IDebugOutputCallbacks))
  162. {
  163. *Interface = (IDebugOutputCallbacks *)this;
  164. AddRef();
  165. return S_OK;
  166. }
  167. else
  168. {
  169. return E_NOINTERFACE;
  170. }
  171. }
  172. STDMETHODIMP_(ULONG)
  173. DefOutputCallbacks::AddRef(
  174. THIS
  175. )
  176. {
  177. // This class is designed to be static so
  178. // there's no true refcount.
  179. return 1;
  180. }
  181. STDMETHODIMP_(ULONG)
  182. DefOutputCallbacks::Release(
  183. THIS
  184. )
  185. {
  186. // This class is designed to be static so
  187. // there's no true refcount.
  188. return 0;
  189. }
  190. //----------------------------------------------------------------------------
  191. //
  192. // Command window output callbacks.
  193. //
  194. //----------------------------------------------------------------------------
  195. class OutputCallbacks : public DefOutputCallbacks
  196. {
  197. public:
  198. // IDebugOutputCallbacks.
  199. STDMETHOD(Output)(
  200. THIS_
  201. IN ULONG Mask,
  202. IN PCSTR Text
  203. );
  204. };
  205. STDMETHODIMP
  206. OutputCallbacks::Output(
  207. THIS_
  208. IN ULONG Mask,
  209. IN PCSTR Text
  210. )
  211. {
  212. LockUiBuffer(&g_UiOutputBuffer);
  213. HRESULT Status;
  214. ULONG Len;
  215. PSTR DataStart;
  216. Len = sizeof(Mask) + strlen(Text) + 1;
  217. if ((DataStart = (PSTR)g_UiOutputBuffer.AddData(Len)) != NULL)
  218. {
  219. *(ULONG UNALIGNED *)DataStart = Mask;
  220. DataStart += sizeof(Mask);
  221. strcpy(DataStart, Text);
  222. if (!g_HoldWaitOutput || !g_WaitingForEvent)
  223. {
  224. UpdateUi();
  225. }
  226. Status = S_OK;
  227. }
  228. else
  229. {
  230. Status = E_OUTOFMEMORY;
  231. }
  232. UnlockUiBuffer(&g_UiOutputBuffer);
  233. return Status;
  234. }
  235. OutputCallbacks g_OutputCb;
  236. //----------------------------------------------------------------------------
  237. //
  238. // Input callbacks.
  239. //
  240. //----------------------------------------------------------------------------
  241. class InputCallbacks :
  242. public IDebugInputCallbacks
  243. {
  244. public:
  245. // IUnknown.
  246. STDMETHOD(QueryInterface)(
  247. THIS_
  248. IN REFIID InterfaceId,
  249. OUT PVOID* Interface
  250. );
  251. STDMETHOD_(ULONG, AddRef)(
  252. THIS
  253. );
  254. STDMETHOD_(ULONG, Release)(
  255. THIS
  256. );
  257. // IDebugInputCallbacks.
  258. STDMETHOD(StartInput)(
  259. THIS_
  260. IN ULONG BufferSize
  261. );
  262. STDMETHOD(EndInput)(
  263. THIS
  264. );
  265. };
  266. STDMETHODIMP
  267. InputCallbacks::QueryInterface(
  268. THIS_
  269. IN REFIID InterfaceId,
  270. OUT PVOID* Interface
  271. )
  272. {
  273. *Interface = NULL;
  274. if (IsEqualIID(InterfaceId, IID_IUnknown) ||
  275. IsEqualIID(InterfaceId, IID_IDebugInputCallbacks))
  276. {
  277. *Interface = (IDebugInputCallbacks *)this;
  278. AddRef();
  279. return S_OK;
  280. }
  281. else
  282. {
  283. return E_NOINTERFACE;
  284. }
  285. }
  286. STDMETHODIMP_(ULONG)
  287. InputCallbacks::AddRef(
  288. THIS
  289. )
  290. {
  291. // This class is designed to be static so
  292. // there's no true refcount.
  293. return 1;
  294. }
  295. STDMETHODIMP_(ULONG)
  296. InputCallbacks::Release(
  297. THIS
  298. )
  299. {
  300. // This class is designed to be static so
  301. // there's no true refcount.
  302. return 0;
  303. }
  304. STDMETHODIMP
  305. InputCallbacks::StartInput(
  306. THIS_
  307. IN ULONG BufferSize
  308. )
  309. {
  310. HRESULT Status;
  311. //
  312. // Pull the first command input command out
  313. // of the UI's command buffer and use it as input.
  314. //
  315. LockUiBuffer(&g_UiCommandBuffer);
  316. UiCommandData* CmdData =
  317. (UiCommandData*)g_UiCommandBuffer.GetDataBuffer();
  318. UiCommandData* CmdEnd = (UiCommandData*)
  319. ((PBYTE)g_UiCommandBuffer.GetDataBuffer() +
  320. g_UiCommandBuffer.GetDataLen());
  321. while (CmdData < CmdEnd)
  322. {
  323. if (CmdData->Cmd == UIC_CMD_INPUT)
  324. {
  325. break;
  326. }
  327. CmdData = (UiCommandData*)((PBYTE)CmdData + CmdData->Len);
  328. }
  329. #if DBG_INPUT
  330. DebugPrint("StartInput available %d\n", CmdData < CmdEnd);
  331. #endif
  332. if (CmdData < CmdEnd)
  333. {
  334. g_OutputCb.Output(DEBUG_OUTPUT_NORMAL, (PSTR)(CmdData + 1));
  335. g_OutputCb.Output(DEBUG_OUTPUT_NORMAL, "\n");
  336. Status = g_pUiControl->ReturnInput((PSTR)(CmdData + 1));
  337. #if DBG_INPUT
  338. DebugPrint(" ReturnInput status %X\n", Status);
  339. #endif
  340. g_UiCommandBuffer.
  341. RemoveMiddle((ULONG)((PBYTE)CmdData -
  342. (PBYTE)g_UiCommandBuffer.GetDataBuffer()),
  343. CmdData->Len);
  344. }
  345. else
  346. {
  347. g_InputStarted = TRUE;
  348. // Didn't find any input waiting.
  349. // Let the command window know that input is needed.
  350. UpdateBufferWindows(1 << CMD_WINDOW, UPDATE_INPUT_REQUIRED);
  351. }
  352. UnlockUiBuffer(&g_UiCommandBuffer);
  353. return S_OK;
  354. }
  355. STDMETHODIMP
  356. InputCallbacks::EndInput(
  357. THIS
  358. )
  359. {
  360. LockUiBuffer(&g_UiCommandBuffer);
  361. #if DBG_INPUT
  362. DebugPrint("EndInput started %d\n", g_InputStarted);
  363. #endif
  364. g_InputStarted = FALSE;
  365. // Reset the command window's state to what it was.
  366. UpdateBufferWindows(1 << CMD_WINDOW, UPDATE_EXEC);
  367. UnlockUiBuffer(&g_UiCommandBuffer);
  368. return S_OK;
  369. }
  370. InputCallbacks g_InputCb;
  371. //----------------------------------------------------------------------------
  372. //
  373. // Event callbacks.
  374. //
  375. //----------------------------------------------------------------------------
  376. // This is safe to do from the engine thread as
  377. // it just sets a flag.
  378. #define DIRTY_WORKSPACE(Flags) \
  379. if (!g_RemoteClient && \
  380. g_EndingSession == ENDING_NONE && !g_Invisible && g_Workspace != NULL) \
  381. { \
  382. g_Workspace->AddDirty(Flags); \
  383. }
  384. STDMETHODIMP_(ULONG)
  385. EventCallbacks::AddRef(
  386. THIS
  387. )
  388. {
  389. // This class is designed to be static so
  390. // there's no true refcount.
  391. return 1;
  392. }
  393. STDMETHODIMP_(ULONG)
  394. EventCallbacks::Release(
  395. THIS
  396. )
  397. {
  398. // This class is designed to be static so
  399. // there's no true refcount.
  400. return 0;
  401. }
  402. STDMETHODIMP
  403. EventCallbacks::GetInterestMask(
  404. THIS_
  405. OUT PULONG Mask
  406. )
  407. {
  408. *Mask =
  409. DEBUG_EVENT_CREATE_THREAD |
  410. DEBUG_EVENT_EXIT_THREAD |
  411. DEBUG_EVENT_CREATE_PROCESS |
  412. DEBUG_EVENT_EXIT_PROCESS |
  413. DEBUG_EVENT_SESSION_STATUS |
  414. DEBUG_EVENT_CHANGE_DEBUGGEE_STATE |
  415. DEBUG_EVENT_CHANGE_ENGINE_STATE |
  416. DEBUG_EVENT_CHANGE_SYMBOL_STATE;
  417. return S_OK;
  418. }
  419. STDMETHODIMP
  420. EventCallbacks::CreateThread(
  421. THIS_
  422. IN ULONG64 Handle,
  423. IN ULONG64 DataOffset,
  424. IN ULONG64 StartOffset
  425. )
  426. {
  427. ULONG InvFlags =
  428. (1 << PROCESS_THREAD_WINDOW);
  429. #if DBG_CALLBACK
  430. DebugPrint(" CT\n");
  431. #endif
  432. // There's no need to update buffers when we're throwing
  433. // everything away while shutting down a session.
  434. if (g_EndingSession == ENDING_NONE && InvFlags)
  435. {
  436. InvalidateStateBuffers(InvFlags);
  437. UpdateEngine();
  438. }
  439. return DEBUG_STATUS_NO_CHANGE;
  440. }
  441. STDMETHODIMP
  442. EventCallbacks::ExitThread(
  443. THIS_
  444. IN ULONG ExitCode
  445. )
  446. {
  447. ULONG InvFlags =
  448. (1 << PROCESS_THREAD_WINDOW);
  449. #if DBG_CALLBACK
  450. DebugPrint(" ET\n");
  451. #endif
  452. // There's no need to update buffers when we're throwing
  453. // everything away while shutting down a session.
  454. if (g_EndingSession == ENDING_NONE && InvFlags)
  455. {
  456. InvalidateStateBuffers(InvFlags);
  457. UpdateEngine();
  458. }
  459. return DEBUG_STATUS_NO_CHANGE;
  460. }
  461. STDMETHODIMP
  462. EventCallbacks::CreateProcess(
  463. THIS_
  464. IN ULONG64 ImageFileHandle,
  465. IN ULONG64 Handle,
  466. IN ULONG64 BaseOffset,
  467. IN ULONG ModuleSize,
  468. IN PCSTR ModuleName,
  469. IN PCSTR ImageName,
  470. IN ULONG CheckSum,
  471. IN ULONG TimeDateStamp,
  472. IN ULONG64 InitialThreadHandle,
  473. IN ULONG64 ThreadDataOffset,
  474. IN ULONG64 StartOffset
  475. )
  476. {
  477. ULONG InvFlags =
  478. (1 << PROCESS_THREAD_WINDOW);
  479. #if DBG_CALLBACK
  480. DebugPrint("CPR\n");
  481. #endif
  482. // Use this opportunity to get initial insertion
  483. // of any workspace breakpoints and process other workspace
  484. // commands which may be queued.
  485. ProcessEngineCommands(TRUE);
  486. // There's no need to update buffers when we're throwing
  487. // everything away while shutting down a session.
  488. if (g_EndingSession == ENDING_NONE && InvFlags)
  489. {
  490. InvalidateStateBuffers(InvFlags);
  491. UpdateEngine();
  492. }
  493. return DEBUG_STATUS_NO_CHANGE;
  494. }
  495. STDMETHODIMP
  496. EventCallbacks::ExitProcess(
  497. THIS_
  498. IN ULONG ExitCode
  499. )
  500. {
  501. ULONG InvFlags =
  502. (1 << PROCESS_THREAD_WINDOW);
  503. #if DBG_CALLBACK
  504. DebugPrint("EPR\n");
  505. #endif
  506. // There's no need to update buffers when we're throwing
  507. // everything away while shutting down a session.
  508. if (g_EndingSession == ENDING_NONE && InvFlags)
  509. {
  510. InvalidateStateBuffers(InvFlags);
  511. UpdateEngine();
  512. }
  513. g_LastProcessExitCode = ExitCode;
  514. return DEBUG_STATUS_NO_CHANGE;
  515. }
  516. STDMETHODIMP
  517. EventCallbacks::SessionStatus(
  518. THIS_
  519. IN ULONG Status
  520. )
  521. {
  522. #if DBG_CALLBACK
  523. DebugPrint(" SS %X\n", Status);
  524. #endif
  525. switch(Status)
  526. {
  527. case DEBUG_SESSION_ACTIVE:
  528. SessionActive();
  529. break;
  530. case DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE:
  531. case DEBUG_SESSION_END_SESSION_ACTIVE_DETACH:
  532. case DEBUG_SESSION_END:
  533. case DEBUG_SESSION_REBOOT:
  534. case DEBUG_SESSION_HIBERNATE:
  535. SessionInactive();
  536. break;
  537. }
  538. return DEBUG_STATUS_NO_CHANGE;
  539. }
  540. STDMETHODIMP
  541. EventCallbacks::ChangeDebuggeeState(
  542. THIS_
  543. IN ULONG Flags,
  544. IN ULONG64 Argument
  545. )
  546. {
  547. ULONG InvFlags =
  548. (1 << WATCH_WINDOW) |
  549. (1 << LOCALS_WINDOW) |
  550. (1 << DISASM_WINDOW) |
  551. (1 << QUICKW_WINDOW) |
  552. (1 << CALLS_WINDOW);
  553. // Invalidate everything that changed.
  554. if (Flags & DEBUG_CDS_REGISTERS)
  555. {
  556. InvFlags |= (1 << EVENT_BIT) | (1 << CPU_WINDOW);
  557. }
  558. if (Flags & DEBUG_CDS_DATA)
  559. {
  560. InvFlags |=
  561. (1 << MEM_WINDOW);
  562. }
  563. #if DBG_CALLBACK
  564. DebugPrint("CDS %X, arg %I64X, inv %X\n", Flags, Argument, InvFlags);
  565. #endif
  566. // There's no need to update buffers when we're throwing
  567. // everything away while shutting down a session.
  568. if (g_EndingSession == ENDING_NONE)
  569. {
  570. InvalidateStateBuffers(InvFlags);
  571. }
  572. if (InvFlags != 0)
  573. {
  574. UpdateEngine();
  575. }
  576. return S_OK;
  577. }
  578. STDMETHODIMP
  579. EventCallbacks::ChangeEngineState(
  580. THIS_
  581. IN ULONG Flags,
  582. IN ULONG64 Argument
  583. )
  584. {
  585. ULONG InvFlags = 0;
  586. // If the current thread changed we need to get
  587. // new context information for the thread.
  588. if ((Flags & DEBUG_CES_CURRENT_THREAD) &&
  589. !g_IgnoreThreadChange)
  590. {
  591. InvFlags |=
  592. (1 << LOCALS_WINDOW) |
  593. (1 << CPU_WINDOW) |
  594. (1 << DISASM_WINDOW) |
  595. (1 << CALLS_WINDOW) |
  596. (1 << PROCESS_THREAD_WINDOW) |
  597. (1 << EVENT_BIT) |
  598. (1 << BP_BIT);
  599. }
  600. // If the effective processor changed we need to update
  601. // anything related to processor information.
  602. if (Flags & DEBUG_CES_EFFECTIVE_PROCESSOR)
  603. {
  604. InvFlags |=
  605. (1 << CPU_WINDOW) |
  606. (1 << DISASM_WINDOW) |
  607. (1 << CALLS_WINDOW) |
  608. (1 << BP_BIT);
  609. }
  610. // If breakpoints changed we need to update the breakpoint cache.
  611. if (Flags & DEBUG_CES_BREAKPOINTS)
  612. {
  613. InvFlags |= (1 << BP_BIT);
  614. // If it's a bulk edit it's coming from a thread or process exit
  615. // or from a session shutdown rather than a user operation.
  616. // We only want to remember user-driven changes in the workspace.
  617. if (Argument != DEBUG_ANY_ID)
  618. {
  619. InvFlags |= (1 << BP_CMDS_BIT);
  620. DIRTY_WORKSPACE(WSPF_DIRTY_BREAKPOINTS);
  621. }
  622. }
  623. // If the code level changed we need to update the toolbar.
  624. if (Flags & DEBUG_CES_CODE_LEVEL)
  625. {
  626. InvFlags |= (1 << BP_BIT);
  627. // If this isn't a notification due to a change
  628. // from windbg itself the user must have changed
  629. // things via a command. If the user does
  630. // change things from the command window lock
  631. // the code level so that it isn't overridden
  632. // automatically.
  633. if (!g_Invisible && !g_IgnoreCodeLevelChange)
  634. {
  635. g_CodeLevelLocked = TRUE;
  636. PostMessage(g_hwndFrame, WU_UPDATE,
  637. UPDATE_BUFFER, (ULONG)Argument);
  638. }
  639. else
  640. {
  641. // Setting the source mode from the GUI enables
  642. // the source setting to float along with whether
  643. // the GUI can display source code or not.
  644. g_CodeLevelLocked = FALSE;
  645. }
  646. }
  647. if (Flags & DEBUG_CES_EXECUTION_STATUS)
  648. {
  649. // If this notification came from a wait completing
  650. // we want to wake up things thread so that new
  651. // commands can be processed. If it came from inside
  652. // a wait we don't want to wake up as the engine
  653. // may go back to running at any time.
  654. if ((Argument & DEBUG_STATUS_INSIDE_WAIT) == 0 &&
  655. (ULONG)Argument != g_ExecStatus)
  656. {
  657. g_ExecStatus = (ULONG)Argument;
  658. UpdateBufferWindows(UPDATE_EXEC_WINDOWS, UPDATE_EXEC);
  659. if (InvFlags == 0)
  660. {
  661. // Force the loop waiting in DispatchCallbacks to go around.
  662. UpdateEngine();
  663. }
  664. }
  665. }
  666. // If the log file changed we need to update the workspace.
  667. if (Flags & DEBUG_CES_LOG_FILE)
  668. {
  669. DIRTY_WORKSPACE(WSPF_DIRTY_LOG_FILE);
  670. }
  671. // If event filters changed we need to update the filter cache.
  672. if ((Flags & DEBUG_CES_EVENT_FILTERS) &&
  673. !g_IgnoreFilterChange)
  674. {
  675. InvFlags |= (1 << FILTER_BIT);
  676. DIRTY_WORKSPACE(WSPF_DIRTY_FILTERS);
  677. }
  678. if (Flags & DEBUG_CES_RADIX)
  679. {
  680. g_NumberRadix = (ULONG)Argument;
  681. InvFlags |=
  682. (1 << WATCH_WINDOW) |
  683. (1 << LOCALS_WINDOW) |
  684. (1 << CPU_WINDOW);
  685. }
  686. if (Flags & DEBUG_CES_SYSTEMS)
  687. {
  688. InvFlags |=
  689. (1 << PROCESS_THREAD_WINDOW);
  690. }
  691. if (Flags & DEBUG_CES_ASSEMBLY_OPTIONS)
  692. {
  693. InvFlags |=
  694. (1 << DISASM_WINDOW);
  695. if (g_Workspace != NULL)
  696. {
  697. g_Workspace->SetUlong(WSP_GLOBAL_ASSEMBLY_OPTIONS,
  698. (ULONG)Argument);
  699. }
  700. }
  701. if (Flags & DEBUG_CES_EXPRESSION_SYNTAX)
  702. {
  703. InvFlags |=
  704. (1 << LOCALS_WINDOW) |
  705. (1 << WATCH_WINDOW);
  706. if (g_Workspace != NULL)
  707. {
  708. g_Workspace->SetUlong(WSP_GLOBAL_EXPRESSION_SYNTAX,
  709. (ULONG)Argument);
  710. }
  711. }
  712. if (Flags & DEBUG_CES_TEXT_REPLACEMENTS)
  713. {
  714. InvFlags |= (1 << ALIAS_BIT);
  715. DIRTY_WORKSPACE(WSPF_DIRTY_ALIASES);
  716. }
  717. #if DBG_CALLBACK
  718. DebugPrint("CES %X, arg %I64X, inv %X\n", Flags, Argument, InvFlags);
  719. #endif
  720. // There's no need to update buffers when we're throwing
  721. // everything away while shutting down a session.
  722. if (g_EndingSession == ENDING_NONE)
  723. {
  724. InvalidateStateBuffers(InvFlags);
  725. }
  726. if (InvFlags != 0)
  727. {
  728. UpdateEngine();
  729. }
  730. if (InvFlags & (1 << LOCALS_WINDOW))
  731. {
  732. g_ScopeChanged = TRUE;
  733. }
  734. return S_OK;
  735. }
  736. STDMETHODIMP
  737. EventCallbacks::ChangeSymbolState(
  738. THIS_
  739. IN ULONG Flags,
  740. IN ULONG64 Argument
  741. )
  742. {
  743. ULONG InvFlags = 0;
  744. // If module information changed we need to update
  745. // everything that might display or depend on symbols.
  746. if (Flags & (DEBUG_CSS_LOADS |
  747. DEBUG_CSS_UNLOADS))
  748. {
  749. InvFlags |= UPDATE_SYM_WINDOWS | (1 << MODULE_BIT);
  750. // On any generic module load/unload refresh
  751. // windbg's module state. This helps catch stale
  752. // source after explicit .reload commands and
  753. // other global refresh changes.
  754. if (!Argument)
  755. {
  756. UpdateBufferWindows((1 << DOC_WINDOW),
  757. UPDATE_REFRESH_MODULES);
  758. }
  759. }
  760. // If the scope changed we need to update scope-related windows.
  761. if (Flags & DEBUG_CSS_SCOPE)
  762. {
  763. InvFlags |=
  764. (1 << WATCH_WINDOW) |
  765. (1 << LOCALS_WINDOW) |
  766. (1 << CALLS_WINDOW);
  767. }
  768. // If paths changed we need to update
  769. // the event state in case we can suddenly load source.
  770. if (Flags & DEBUG_CSS_PATHS)
  771. {
  772. InvFlags |= (1 << EVENT_BIT);
  773. DIRTY_WORKSPACE(WSPF_DIRTY_PATHS);
  774. }
  775. // If certain options changed we need to update
  776. // everything that might display or depend on symbols.
  777. if (Flags & DEBUG_CSS_SYMBOL_OPTIONS)
  778. {
  779. if ((g_SymOptions ^ (ULONG)Argument) & REFRESH_SYMOPT)
  780. {
  781. InvFlags |= UPDATE_SYM_WINDOWS;
  782. }
  783. g_SymOptions = (ULONG)Argument;
  784. }
  785. // If certain options changed we need to update
  786. // everything that might display or depend on symbols.
  787. if (Flags & DEBUG_CSS_TYPE_OPTIONS)
  788. {
  789. InvFlags |=
  790. (1 << WATCH_WINDOW) |
  791. (1 << LOCALS_WINDOW) |
  792. (1 << CALLS_WINDOW);
  793. if (g_pUiSymbols2 != NULL)
  794. {
  795. g_pUiSymbols2->GetTypeOptions( &g_TypeOptions );
  796. if (g_Workspace != NULL)
  797. {
  798. g_Workspace->SetUlong(WSP_GLOBAL_TYPE_OPTIONS,
  799. g_TypeOptions);
  800. }
  801. }
  802. }
  803. #if DBG_CALLBACK
  804. DebugPrint("CSS %X, arg %I64X, inv %X\n", Flags, Argument, InvFlags);
  805. #endif
  806. // There's no need to update buffers when we're throwing
  807. // everything away while shutting down a session.
  808. if (g_EndingSession == ENDING_NONE)
  809. {
  810. InvalidateStateBuffers(InvFlags);
  811. }
  812. if (InvFlags != 0)
  813. {
  814. UpdateEngine();
  815. }
  816. if (InvFlags & (1 << LOCALS_WINDOW))
  817. {
  818. g_ScopeChanged = TRUE;
  819. }
  820. return S_OK;
  821. }
  822. EventCallbacks g_EventCb;
  823. //----------------------------------------------------------------------------
  824. //
  825. // Inter-thread communication.
  826. //
  827. //----------------------------------------------------------------------------
  828. #define COMMAND_OVERHEAD (sizeof(ULONG64) + sizeof(UiCommandData))
  829. PVOID
  830. StartCommand(UiCommand Cmd, ULONG Len)
  831. {
  832. UiCommandData* Data;
  833. // Round length up to a multiple of ULONG64s for
  834. // alignment.
  835. Len = ((Len + sizeof(ULONG64) - 1) & ~(sizeof(ULONG64) - 1)) +
  836. sizeof(UiCommandData);
  837. if (Len > MAX_COMMAND_LEN)
  838. {
  839. return NULL;
  840. }
  841. LockUiBuffer(&g_UiCommandBuffer);
  842. Data = (UiCommandData *)g_UiCommandBuffer.AddData(Len);
  843. if (Data == NULL)
  844. {
  845. return Data;
  846. }
  847. Data->Cmd = Cmd;
  848. Data->Len = Len;
  849. return Data + 1;
  850. }
  851. void
  852. FinishCommand(void)
  853. {
  854. UnlockUiBuffer(&g_UiCommandBuffer);
  855. // Wake up the engine to process the command.
  856. UpdateEngine();
  857. }
  858. BOOL
  859. AddStringCommand(UiCommand Cmd, PCSTR Str)
  860. {
  861. ULONG StrLen = strlen(Str) + 1;
  862. PSTR Data;
  863. // If we're adding command input we may need
  864. // to send it directly to the engine in response
  865. // to an input request.
  866. if (Cmd == UIC_CMD_INPUT)
  867. {
  868. LockUiBuffer(&g_UiCommandBuffer);
  869. #if DBG_INPUT
  870. DebugPrint("InputStarted started %d\n", g_InputStarted);
  871. #endif
  872. if (g_InputStarted)
  873. {
  874. HRESULT Status;
  875. g_OutputCb.Output(DEBUG_OUTPUT_NORMAL, Str);
  876. g_OutputCb.Output(DEBUG_OUTPUT_NORMAL, "\n");
  877. Status = g_pUiControl->ReturnInput(Str);
  878. #if DBG_INPUT
  879. DebugPrint(" ReturnInput status %X\n", Status);
  880. #endif
  881. g_InputStarted = FALSE;
  882. UnlockUiBuffer(&g_UiCommandBuffer);
  883. return TRUE;
  884. }
  885. }
  886. Data = (PSTR)StartCommand(Cmd, StrLen);
  887. if (Cmd == UIC_CMD_INPUT)
  888. {
  889. UnlockUiBuffer(&g_UiCommandBuffer);
  890. }
  891. if (Data == NULL)
  892. {
  893. return FALSE;
  894. }
  895. memcpy(Data, Str, StrLen);
  896. FinishCommand();
  897. return TRUE;
  898. }
  899. BOOL
  900. AddStringMultiCommand(UiCommand Cmd, PSTR Str, BOOL ForceSplit)
  901. {
  902. //
  903. // Given a string with multiple commands separated
  904. // by newlines, break the string into multiple
  905. // commands, one per line. This allows arbitrarily
  906. // large command strings without running into
  907. // the MAX_COMMAND_LEN limit as long as each individual
  908. // line fits within that limit.
  909. //
  910. while (*Str)
  911. {
  912. PSTR Scan, LastNl;
  913. ULONG Len;
  914. BOOL Status;
  915. Scan = Str + 1;
  916. Len = 1;
  917. LastNl = NULL;
  918. while (*Scan && Len < (MAX_COMMAND_LEN - COMMAND_OVERHEAD))
  919. {
  920. if (*Scan == '\n')
  921. {
  922. LastNl = Scan;
  923. if (ForceSplit)
  924. {
  925. Scan++;
  926. break;
  927. }
  928. }
  929. Scan++;
  930. Len++;
  931. }
  932. // If the rest of the command string doesn't fit
  933. // within the limit it needs to be split.
  934. // If there's no newline to break it at
  935. // the command is too large to be processed.
  936. if (*Scan && !LastNl)
  937. {
  938. return FALSE;
  939. }
  940. // Split if necessary.
  941. if (*Scan)
  942. {
  943. *LastNl = 0;
  944. }
  945. // Add the head (which may be the whole remainder).
  946. Status = AddStringCommand(Cmd, Str);
  947. if (*Scan)
  948. {
  949. *LastNl = '\n';
  950. if (!Status)
  951. {
  952. return FALSE;
  953. }
  954. Str = LastNl + 1;
  955. }
  956. else
  957. {
  958. return Status;
  959. }
  960. }
  961. return TRUE;
  962. }
  963. BOOL __cdecl
  964. PrintStringCommand(UiCommand Cmd, PCSTR Format, ...)
  965. {
  966. char Buf[MAX_COMMAND_LEN - COMMAND_OVERHEAD];
  967. va_list Args;
  968. va_start(Args, Format);
  969. _vsnprintf(Buf, DIMA(Buf), Format, Args);
  970. Buf[DIMA(Buf) - 1] = 0;
  971. va_end(Args);
  972. return AddStringCommand(Cmd, Buf);
  973. }
  974. void
  975. WriteData(UIC_WRITE_DATA_DATA* WriteData)
  976. {
  977. ULONG Written;
  978. switch(WriteData->Type)
  979. {
  980. default:
  981. Assert(!"Unhandled condition");
  982. break;
  983. case PHYSICAL_MEM_TYPE:
  984. g_pDbgData->WritePhysical(WriteData->Offset,
  985. WriteData->Data,
  986. WriteData->Length,
  987. &Written
  988. );
  989. break;
  990. case VIRTUAL_MEM_TYPE:
  991. g_pDbgData->WriteVirtual(WriteData->Offset,
  992. WriteData->Data,
  993. WriteData->Length,
  994. &Written
  995. );
  996. break;
  997. case CONTROL_MEM_TYPE:
  998. g_pDbgData->WriteControl(WriteData->Any.control.Processor,
  999. WriteData->Offset,
  1000. WriteData->Data,
  1001. WriteData->Length,
  1002. &Written
  1003. );
  1004. break;
  1005. case IO_MEM_TYPE:
  1006. g_pDbgData->WriteIo(WriteData->Any.io.interface_type,
  1007. WriteData->Any.io.BusNumber,
  1008. WriteData->Any.io.AddressSpace,
  1009. WriteData->Offset,
  1010. WriteData->Data,
  1011. WriteData->Length,
  1012. &Written
  1013. );
  1014. break;
  1015. case MSR_MEM_TYPE:
  1016. Assert(WriteData->Length == sizeof(ULONG64));
  1017. g_pDbgData->WriteMsr((ULONG)WriteData->Offset,
  1018. *(PULONG64)WriteData->Data
  1019. );
  1020. break;
  1021. case BUS_MEM_TYPE:
  1022. g_pDbgData->WriteBusData(WriteData->Any.bus.bus_type,
  1023. WriteData->Any.bus.BusNumber,
  1024. WriteData->Any.bus.SlotNumber,
  1025. (ULONG)WriteData->Offset,
  1026. WriteData->Data,
  1027. WriteData->Length,
  1028. &Written
  1029. );
  1030. break;
  1031. }
  1032. }
  1033. void
  1034. ProcessWatchCommand(
  1035. UIC_SYMBOL_WIN_DATA *SymWinData
  1036. )
  1037. {
  1038. PDEBUG_SYMBOL_GROUP pSymbolGroup;
  1039. if (!SymWinData->pSymbolGroup ||
  1040. !(pSymbolGroup = *SymWinData->pSymbolGroup))
  1041. {
  1042. return;
  1043. }
  1044. switch (SymWinData->Type)
  1045. {
  1046. case ADD_SYMBOL_WIN:
  1047. if (strlen(SymWinData->u.Add.Name))
  1048. {
  1049. // add only non-empty symbols
  1050. pSymbolGroup->AddSymbol(SymWinData->u.Add.Name,
  1051. &SymWinData->u.Add.Index);
  1052. }
  1053. break;
  1054. case DEL_SYMBOL_WIN_INDEX:
  1055. pSymbolGroup->RemoveSymbolByIndex(SymWinData->u.DelIndex);
  1056. break;
  1057. case DEL_SYMBOL_WIN_NAME:
  1058. pSymbolGroup->RemoveSymbolByName(SymWinData->u.DelName);
  1059. break;
  1060. case QUERY_NUM_SYMBOL_WIN:
  1061. pSymbolGroup->GetNumberSymbols(SymWinData->u.NumWatch);
  1062. break;
  1063. case GET_NAME:
  1064. pSymbolGroup->GetSymbolName(SymWinData->u.GetName.Index,
  1065. SymWinData->u.GetName.Buffer,
  1066. SymWinData->u.GetName.BufferSize,
  1067. SymWinData->u.GetName.NameSize);
  1068. break;
  1069. case GET_PARAMS:
  1070. pSymbolGroup->
  1071. GetSymbolParameters(SymWinData->u.GetParams.Start,
  1072. SymWinData->u.GetParams.Count,
  1073. SymWinData->u.GetParams.SymbolParams);
  1074. break;
  1075. case EXPAND_SYMBOL:
  1076. pSymbolGroup->ExpandSymbol(SymWinData->u.ExpandSymbol.Index,
  1077. SymWinData->u.ExpandSymbol.Expand);
  1078. break;
  1079. case EDIT_SYMBOL:
  1080. pSymbolGroup->WriteSymbol(SymWinData->u.WriteSymbol.Index,
  1081. SymWinData->u.WriteSymbol.Value);
  1082. break;
  1083. case EDIT_TYPE:
  1084. pSymbolGroup->OutputAsType(SymWinData->u.OutputAsType.Index,
  1085. SymWinData->u.OutputAsType.Type);
  1086. break;
  1087. case DEL_SYMBOL_WIN_ALL:
  1088. {
  1089. ULONG nSyms = 0;
  1090. pSymbolGroup->GetNumberSymbols(&nSyms);
  1091. while (nSyms)
  1092. {
  1093. pSymbolGroup->RemoveSymbolByIndex(0);
  1094. pSymbolGroup->GetNumberSymbols(&nSyms);
  1095. }
  1096. }
  1097. }
  1098. }
  1099. void
  1100. ProcessCommand(UiCommandData* CmdData)
  1101. {
  1102. DEBUG_VALUE Val;
  1103. HRESULT Status;
  1104. switch(CmdData->Cmd)
  1105. {
  1106. case UIC_CMD_INPUT:
  1107. case UIC_EXECUTE:
  1108. PSTR Str;
  1109. ULONG StrLen;
  1110. // Make sure the command has a newline at the end.
  1111. Str = (PSTR)(CmdData + 1);
  1112. StrLen = strlen(Str);
  1113. if (StrLen > 0 && Str[StrLen - 1] == '\n')
  1114. {
  1115. // Trim existing newline as we're adding one.
  1116. Str[StrLen - 1] = 0;
  1117. }
  1118. if (g_RemoteClient)
  1119. {
  1120. // Identify self before command.
  1121. g_pDbgClient->OutputIdentity(DEBUG_OUTCTL_ALL_OTHER_CLIENTS,
  1122. DEBUG_OUTPUT_IDENTITY_DEFAULT,
  1123. "[%s] ");
  1124. }
  1125. g_pDbgControl->OutputPrompt(DEBUG_OUTCTL_ALL_CLIENTS, " %s\n", Str);
  1126. g_pDbgControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
  1127. Str, DEBUG_EXECUTE_NOT_LOGGED);
  1128. break;
  1129. case UIC_SILENT_EXECUTE:
  1130. // Execute the command without displaying it.
  1131. g_pDbgControl->Execute(DEBUG_OUTCTL_IGNORE,
  1132. (PCSTR)(CmdData + 1),
  1133. DEBUG_EXECUTE_NOT_LOGGED |
  1134. DEBUG_EXECUTE_NO_REPEAT);
  1135. break;
  1136. case UIC_INVISIBLE_EXECUTE:
  1137. // Execute the command without displaying it and
  1138. // ignore any notifications.
  1139. g_Invisible = TRUE;
  1140. g_pDbgControl->Execute(DEBUG_OUTCTL_IGNORE,
  1141. (PCSTR)(CmdData + 1),
  1142. DEBUG_EXECUTE_NOT_LOGGED |
  1143. DEBUG_EXECUTE_NO_REPEAT);
  1144. g_Invisible = FALSE;
  1145. break;
  1146. case UIC_SET_REG:
  1147. UIC_SET_REG_DATA* SetRegData;
  1148. SetRegData = (UIC_SET_REG_DATA*)(CmdData + 1);
  1149. g_pDbgRegisters->SetValue(SetRegData->Reg, &SetRegData->Val);
  1150. break;
  1151. case UIC_RESTART:
  1152. if (g_RemoteClient)
  1153. {
  1154. g_pDbgControl->
  1155. Output(DEBUG_OUTPUT_ERROR,
  1156. "Only user-mode created processes may be restarted\n");
  1157. }
  1158. else
  1159. {
  1160. if ((Status = g_pDbgClient->
  1161. EndSession(DEBUG_END_ACTIVE_TERMINATE)) != S_OK)
  1162. {
  1163. InternalError(Status, "EndSession");
  1164. }
  1165. else
  1166. {
  1167. g_EndingSession = ENDING_RESTART;
  1168. }
  1169. }
  1170. break;
  1171. case UIC_END_SESSION:
  1172. ULONG OldEnding;
  1173. ULONG OldExec;
  1174. // Mark the session as ending to avoid workspace
  1175. // deadlock problems.
  1176. OldEnding = g_EndingSession;
  1177. OldExec = g_ExecStatus;
  1178. g_EndingSession = ENDING_STOP;
  1179. g_ExecStatus = DEBUG_STATUS_NO_DEBUGGEE;
  1180. if (!g_RemoteClient)
  1181. {
  1182. if ((Status = g_pDbgClient->
  1183. EndSession(DEBUG_END_ACTIVE_TERMINATE)) != S_OK)
  1184. {
  1185. InternalError(Status, "EndSession");
  1186. g_EndingSession = OldEnding;
  1187. g_ExecStatus = OldExec;
  1188. }
  1189. }
  1190. break;
  1191. case UIC_WRITE_DATA:
  1192. WriteData((UIC_WRITE_DATA_DATA*)(CmdData + 1));
  1193. break;
  1194. case UIC_SYMBOL_WIN:
  1195. ProcessWatchCommand((UIC_SYMBOL_WIN_DATA*) (CmdData + 1));
  1196. break;
  1197. case UIC_DISPLAY_CODE:
  1198. FillCodeBuffer(((UIC_DISPLAY_CODE_DATA*)(CmdData + 1))->Offset,
  1199. TRUE);
  1200. break;
  1201. case UIC_DISPLAY_CODE_EXPR:
  1202. if (g_pDbgControl->Evaluate((PSTR)(CmdData + 1), DEBUG_VALUE_INT64,
  1203. &Val, NULL) != S_OK)
  1204. {
  1205. Val.I64 = 0;
  1206. }
  1207. FillCodeBuffer(Val.I64, TRUE);
  1208. break;
  1209. case UIC_SET_SCOPE:
  1210. SetLocalScope(&(((UIC_SET_SCOPE_DATA *)(CmdData + 1))->StackFrame));
  1211. InvalidateStateBuffers(1 << LOCALS_WINDOW);
  1212. break;
  1213. case UIC_SET_FILTER:
  1214. UIC_SET_FILTER_DATA* SetFilter;
  1215. SetFilter = (UIC_SET_FILTER_DATA*)(CmdData + 1);
  1216. if (SetFilter->Index != 0xffffffff)
  1217. {
  1218. DEBUG_SPECIFIC_FILTER_PARAMETERS Params;
  1219. Params.ExecutionOption = SetFilter->Execution;
  1220. Params.ContinueOption = SetFilter->Continue;
  1221. g_pDbgControl->SetSpecificFilterParameters(SetFilter->Index, 1,
  1222. &Params);
  1223. }
  1224. else
  1225. {
  1226. DEBUG_EXCEPTION_FILTER_PARAMETERS Params;
  1227. Params.ExecutionOption = SetFilter->Execution;
  1228. Params.ContinueOption = SetFilter->Continue;
  1229. Params.ExceptionCode = SetFilter->Code;
  1230. g_pDbgControl->SetExceptionFilterParameters(1, &Params);
  1231. }
  1232. break;
  1233. case UIC_SET_FILTER_ARGUMENT:
  1234. UIC_SET_FILTER_ARGUMENT_DATA* SetFilterArg;
  1235. SetFilterArg = (UIC_SET_FILTER_ARGUMENT_DATA*)(CmdData + 1);
  1236. g_pDbgControl->SetSpecificFilterArgument(SetFilterArg->Index,
  1237. SetFilterArg->Argument);
  1238. break;
  1239. case UIC_SET_FILTER_COMMAND:
  1240. UIC_SET_FILTER_COMMAND_DATA* SetFilterCmd;
  1241. SetFilterCmd = (UIC_SET_FILTER_COMMAND_DATA*)(CmdData + 1);
  1242. if (SetFilterCmd->Which == 0)
  1243. {
  1244. g_pDbgControl->SetEventFilterCommand(SetFilterCmd->Index,
  1245. SetFilterCmd->Command);
  1246. }
  1247. else
  1248. {
  1249. g_pDbgControl->SetExceptionFilterSecondCommand
  1250. (SetFilterCmd->Index, SetFilterCmd->Command);
  1251. }
  1252. break;
  1253. case UIC_SET_IP:
  1254. // First, execute the corresponding command to set the
  1255. // register value.
  1256. g_pDbgControl->Execute(DEBUG_OUTCTL_IGNORE,
  1257. (PCSTR)(CmdData + 1),
  1258. DEBUG_EXECUTE_NOT_LOGGED |
  1259. DEBUG_EXECUTE_NO_REPEAT);
  1260. // Now, since we know that IP changed we need
  1261. // to force an update to the current scope.
  1262. g_pDbgSymbols->ResetScope();
  1263. break;
  1264. }
  1265. }
  1266. void
  1267. ProcessEngineCommands(BOOL Internal)
  1268. {
  1269. #if DBG_CALLBACK
  1270. DebugPrint("ProcessEngineCommands\n");
  1271. #endif
  1272. // Check for commands to execute. We do not
  1273. // want to hold the lock while doing so because
  1274. // the commands may include things that cause waits
  1275. // and we don't want to lock out the GUI.
  1276. LockUiBuffer(&g_UiCommandBuffer);
  1277. while (g_UiCommandBuffer.GetDataLen() > 0)
  1278. {
  1279. //
  1280. // Remove the first command from the buffer.
  1281. //
  1282. // Extra char is for forcing a newline on executes.
  1283. char CmdBuf[MAX_COMMAND_LEN + 1];
  1284. UiCommandData* CmdData;
  1285. // Copy command to local buffer.
  1286. CmdData = (UiCommandData*)g_UiCommandBuffer.GetDataBuffer();
  1287. memcpy(CmdBuf, CmdData, CmdData->Len);
  1288. CmdData = (UiCommandData*)CmdBuf;
  1289. // Remove command from queue and release the queue for
  1290. // the UI thread to use again.
  1291. g_UiCommandBuffer.RemoveHead(CmdData->Len);
  1292. UnlockUiBuffer(&g_UiCommandBuffer);
  1293. ProcessCommand(CmdData);
  1294. InterlockedIncrement((PLONG)&g_CommandSequence);
  1295. // Lock the buffer again for the next command retrieval.
  1296. LockUiBuffer(&g_UiCommandBuffer);
  1297. if (g_EndingSession != ENDING_NONE)
  1298. {
  1299. // If we're ending a session just throw away the rest
  1300. // of the commands.
  1301. g_UiCommandBuffer.Empty();
  1302. }
  1303. }
  1304. UnlockUiBuffer(&g_UiCommandBuffer);
  1305. if (!Internal && g_EndingSession == ENDING_NONE)
  1306. {
  1307. ReadStateBuffers();
  1308. }
  1309. }
  1310. //----------------------------------------------------------------------------
  1311. //
  1312. // Engine processing.
  1313. //
  1314. //----------------------------------------------------------------------------
  1315. HRESULT
  1316. InitializeEngineInterfaces(void)
  1317. {
  1318. HRESULT Hr;
  1319. if ((Hr = g_pUiClient->CreateClient(&g_pDbgClient)) != S_OK)
  1320. {
  1321. InternalError(Hr, "Engine CreateClient");
  1322. return Hr;
  1323. }
  1324. if ((Hr = g_pDbgClient->
  1325. QueryInterface(IID_IDebugControl,
  1326. (void **)&g_pDbgControl)) != S_OK ||
  1327. (Hr = g_pDbgClient->
  1328. QueryInterface(IID_IDebugSymbols,
  1329. (void **)&g_pDbgSymbols)) != S_OK ||
  1330. (Hr = g_pDbgClient->
  1331. QueryInterface(IID_IDebugRegisters,
  1332. (void **)&g_pDbgRegisters)) != S_OK ||
  1333. (Hr = g_pDbgClient->
  1334. QueryInterface(IID_IDebugDataSpaces,
  1335. (void **)&g_pDbgData)) != S_OK ||
  1336. (Hr = g_pDbgClient->
  1337. QueryInterface(IID_IDebugSystemObjects,
  1338. (void **)&g_pDbgSystem)) != S_OK)
  1339. {
  1340. if (Hr == RPC_E_VERSION_MISMATCH)
  1341. {
  1342. InformationBox(ERR_Remoting_Version_Mismatch);
  1343. }
  1344. else
  1345. {
  1346. InternalError(Hr, "Engine QueryInterface");
  1347. }
  1348. return Hr;
  1349. }
  1350. //
  1351. // Try and get higher version interfaces.
  1352. //
  1353. if (g_pDbgClient->
  1354. QueryInterface(IID_IDebugClient2,
  1355. (void **)&g_pDbgClient2) != S_OK)
  1356. {
  1357. g_pDbgClient2 = NULL;
  1358. }
  1359. if (g_pDbgClient->
  1360. QueryInterface(IID_IDebugSystemObjects3,
  1361. (void **)&g_pDbgSystem3) != S_OK)
  1362. {
  1363. g_pDbgSystem3 = NULL;
  1364. }
  1365. if (g_RemoteClient)
  1366. {
  1367. // Create a local client to do local source file lookups.
  1368. if ((Hr = g_pUiLocClient->CreateClient(&g_pLocClient)) != S_OK ||
  1369. (Hr = g_pLocClient->
  1370. QueryInterface(IID_IDebugControl,
  1371. (void **)&g_pLocControl)) != S_OK ||
  1372. (Hr = g_pLocClient->
  1373. QueryInterface(IID_IDebugSymbols,
  1374. (void **)&g_pLocSymbols)) != S_OK)
  1375. {
  1376. InternalError(Hr, "Engine local client");
  1377. return Hr;
  1378. }
  1379. }
  1380. else
  1381. {
  1382. g_pLocClient = g_pDbgClient;
  1383. g_pLocClient->AddRef();
  1384. g_pLocControl = g_pDbgControl;
  1385. g_pLocControl->AddRef();
  1386. g_pLocSymbols = g_pDbgSymbols;
  1387. g_pLocSymbols->AddRef();
  1388. }
  1389. // Create separate client for private output capture
  1390. // during state buffer filling. The output capture client
  1391. // sets its output mask to nothing so that it doesn't
  1392. // receive any normal input. During private output capture
  1393. // the output control is set to THIS_CLIENT | OVERRIDE_MASK to force
  1394. // output to just the output capture client.
  1395. if ((Hr = g_pDbgClient->CreateClient(&g_pOutCapClient)) != S_OK ||
  1396. (Hr = g_pOutCapClient->
  1397. QueryInterface(IID_IDebugControl,
  1398. (void **)&g_pOutCapControl)) != S_OK)
  1399. {
  1400. InternalError(Hr, "Engine output capture client");
  1401. return Hr;
  1402. }
  1403. // Set callbacks.
  1404. if ((Hr = g_pDbgClient->SetOutputCallbacks(&g_OutputCb)) != S_OK ||
  1405. (Hr = g_pDbgClient->SetInputCallbacks(&g_InputCb)) != S_OK ||
  1406. (Hr = g_pDbgClient->SetEventCallbacks(&g_EventCb)) != S_OK ||
  1407. (g_RemoteClient &&
  1408. (Hr = g_pLocClient->SetOutputCallbacks(&g_OutputCb))) != S_OK ||
  1409. (Hr = g_pOutCapClient->SetOutputMask(0)) != S_OK ||
  1410. (Hr = g_pOutCapClient->SetOutputCallbacks(&g_OutStateBuf)) != S_OK ||
  1411. (Hr = g_pOutCapClient->
  1412. QueryInterface(IID_IDebugSymbols,
  1413. (void **)&g_pOutCapSymbols)) != S_OK)
  1414. {
  1415. InternalError(Hr, "Engine callbacks");
  1416. return Hr;
  1417. }
  1418. // Create a watch window client
  1419. if ((Hr = g_pOutCapSymbols->
  1420. CreateSymbolGroup(&g_pDbgWatchSymbolGroup)) != S_OK)
  1421. {
  1422. InternalError(Hr, "Engine CreateSymbolGroup");
  1423. return Hr;
  1424. }
  1425. // Create a local window client
  1426. if ((Hr = g_pOutCapSymbols->
  1427. GetScopeSymbolGroup(DEBUG_SCOPE_GROUP_LOCALS,
  1428. NULL, &g_pDbgLocalSymbolGroup)) == E_NOTIMPL)
  1429. {
  1430. // Older version
  1431. Hr = g_pOutCapSymbols->
  1432. GetScopeSymbolGroup(DEBUG_SCOPE_GROUP_ALL,
  1433. NULL, &g_pDbgLocalSymbolGroup);
  1434. }
  1435. if (Hr != S_OK ||
  1436. (Hr = g_FilterTextBuffer->Update()) != S_OK)
  1437. {
  1438. InternalError(Hr, "Engine GetScopeSymbolGroup");
  1439. return Hr;
  1440. }
  1441. if ((Hr = g_pDbgControl->GetRadix(&g_NumberRadix)) != S_OK)
  1442. {
  1443. InternalError(Hr, "Engine GetRadix");
  1444. return Hr;
  1445. }
  1446. if (g_RemoteClient)
  1447. {
  1448. return S_OK;
  1449. }
  1450. //
  1451. // Set up initial state for things that are important
  1452. // when starting the debug session.
  1453. //
  1454. if (g_Verbose)
  1455. {
  1456. DWORD OutMask;
  1457. g_pDbgClient->GetOutputMask(&OutMask);
  1458. OutMask |= DEBUG_OUTPUT_VERBOSE;
  1459. g_pDbgClient->SetOutputMask(OutMask);
  1460. g_pDbgControl->SetLogMask(OutMask);
  1461. }
  1462. // Always load line numbers for source support.
  1463. g_pDbgSymbols->AddSymbolOptions(SYMOPT_LOAD_LINES);
  1464. // Set the source stepping mode
  1465. g_IgnoreCodeLevelChange = TRUE;
  1466. if (GetSrcMode_StatusBar())
  1467. {
  1468. g_pDbgControl->SetCodeLevel(DEBUG_LEVEL_SOURCE);
  1469. }
  1470. else
  1471. {
  1472. g_pDbgControl->SetCodeLevel(DEBUG_LEVEL_ASSEMBLY);
  1473. }
  1474. g_IgnoreCodeLevelChange = FALSE;
  1475. // If this is a user-mode debug session default to
  1476. // initial and final breaks. Don't override settings
  1477. // that were given on the command line, though.
  1478. g_IgnoreFilterChange = TRUE;
  1479. if (g_DebugCommandLine != NULL ||
  1480. g_PidToDebug != 0 ||
  1481. g_ProcNameToDebug != NULL)
  1482. {
  1483. g_pDbgControl->AddEngineOptions((DEBUG_ENGOPT_INITIAL_BREAK |
  1484. DEBUG_ENGOPT_FINAL_BREAK) &
  1485. ~g_EngOptModified);
  1486. }
  1487. else
  1488. {
  1489. g_pDbgControl->RemoveEngineOptions((DEBUG_ENGOPT_INITIAL_BREAK |
  1490. DEBUG_ENGOPT_FINAL_BREAK) &
  1491. ~g_EngOptModified);
  1492. }
  1493. g_IgnoreFilterChange = FALSE;
  1494. return S_OK;
  1495. }
  1496. void
  1497. DiscardEngineState(void)
  1498. {
  1499. LockUiBuffer(&g_UiOutputBuffer);
  1500. g_UiOutputBuffer.Empty();
  1501. UnlockUiBuffer(&g_UiOutputBuffer);
  1502. g_TargetClass = DEBUG_CLASS_UNINITIALIZED;
  1503. g_ExecStatus = DEBUG_STATUS_NO_DEBUGGEE;
  1504. }
  1505. void
  1506. ReleaseEngineInterfaces(void)
  1507. {
  1508. DiscardEngineState();
  1509. RELEASE(g_pLocControl);
  1510. RELEASE(g_pLocSymbols);
  1511. RELEASE(g_pLocClient);
  1512. RELEASE(g_pDbgWatchSymbolGroup);
  1513. RELEASE(g_pDbgLocalSymbolGroup);
  1514. RELEASE(g_pOutCapControl);
  1515. RELEASE(g_pOutCapSymbols);
  1516. RELEASE(g_pOutCapClient);
  1517. RELEASE(g_pDbgControl);
  1518. RELEASE(g_pDbgSymbols);
  1519. RELEASE(g_pDbgRegisters);
  1520. RELEASE(g_pDbgData);
  1521. RELEASE(g_pDbgSystem3);
  1522. RELEASE(g_pDbgSystem);
  1523. RELEASE(g_pDbgClient2);
  1524. RELEASE(g_pDbgClient);
  1525. }
  1526. BOOL
  1527. ExtractWspName(PSTR CommandLine, PSTR Buf, ULONG BufLen)
  1528. {
  1529. PSTR Scan = CommandLine;
  1530. PSTR Start;
  1531. while (isspace(*Scan))
  1532. {
  1533. Scan++;
  1534. }
  1535. if (!*Scan)
  1536. {
  1537. return FALSE;
  1538. }
  1539. else if (*Scan == '"')
  1540. {
  1541. Start = ++Scan;
  1542. // Look for closing quote.
  1543. while (*Scan && *Scan != '"')
  1544. {
  1545. Scan++;
  1546. }
  1547. }
  1548. else
  1549. {
  1550. // Look for whitespace.
  1551. Start = Scan++;
  1552. while (*Scan && !isspace(*Scan))
  1553. {
  1554. Scan++;
  1555. }
  1556. }
  1557. ULONG Len = (ULONG) (ULONG64) (Scan - Start);
  1558. if (Len == 0)
  1559. {
  1560. return FALSE;
  1561. }
  1562. if (Len >= BufLen)
  1563. {
  1564. Len = BufLen - 1;
  1565. }
  1566. memcpy(Buf, Start, Len);
  1567. Buf[Len] = 0;
  1568. return TRUE;
  1569. }
  1570. HRESULT
  1571. StartSession(void)
  1572. {
  1573. TCHAR WspName[MAX_PATH];
  1574. ULONG WspKey;
  1575. PTSTR WspValue;
  1576. HRESULT Hr;
  1577. ULONG i;
  1578. // Reset things to the default priority first.
  1579. // If necessary, priority will be increased in certain code
  1580. // paths later.
  1581. SetPriorityClass(GetCurrentProcess(), g_DefPriority);
  1582. if (!g_RemoteClient)
  1583. {
  1584. if (g_NumDumpFiles)
  1585. {
  1586. WspKey = WSP_NAME_DUMP;
  1587. WspValue = g_DumpFiles[0];
  1588. EngSwitchWorkspace(WspKey, WspValue);
  1589. if (g_NumDumpInfoFiles)
  1590. {
  1591. if (g_pDbgClient2 == NULL)
  1592. {
  1593. ErrorBox(NULL, 0, ERR_Cant_Add_Dump_Info_File);
  1594. Hr = E_NOINTERFACE;
  1595. goto ResetWorkspace;
  1596. }
  1597. for (i = 0; i < g_NumDumpInfoFiles; i++)
  1598. {
  1599. if ((Hr = g_pDbgClient2->AddDumpInformationFile
  1600. (g_DumpInfoFiles[i], g_DumpInfoTypes[i])) != S_OK)
  1601. {
  1602. ErrorBox(NULL, 0, ERR_Add_Dump_Info_File_Failed,
  1603. g_DumpInfoFiles[i], FormatStatusCode(Hr),
  1604. FormatStatus(Hr));
  1605. goto ResetWorkspace;
  1606. }
  1607. }
  1608. }
  1609. for (i = 0; i < g_NumDumpFiles; i++)
  1610. {
  1611. Hr = g_pDbgClient->OpenDumpFile(g_DumpFiles[i]);
  1612. if (Hr != S_OK)
  1613. {
  1614. if ((HRESULT_FACILITY(Hr)) == FACILITY_WIN32)
  1615. {
  1616. // Win32 errors on open generally mean some
  1617. // kind of file error.
  1618. ErrorBox(NULL, 0, ERR_Invalid_Dump_File_Name,
  1619. g_DumpFiles[i], FormatStatusCode(Hr),
  1620. FormatStatus(Hr));
  1621. }
  1622. else
  1623. {
  1624. ErrorBox(NULL, 0, ERR_Unable_To_Open_Dump,
  1625. g_DumpFiles[i], FormatStatusCode(Hr),
  1626. FormatStatus(Hr));
  1627. }
  1628. goto ResetWorkspace;
  1629. }
  1630. }
  1631. }
  1632. else if (g_DebugCommandLine != NULL ||
  1633. g_PidToDebug != 0 ||
  1634. g_ProcNameToDebug != NULL)
  1635. {
  1636. ULONG64 Server = 0;
  1637. ULONG Pid;
  1638. WspKey = WSP_NAME_USER;
  1639. WspValue = g_ProcessServer != NULL ?
  1640. g_ProcessServer : g_WorkspaceDefaultName;
  1641. if (g_DebugCommandLine != NULL)
  1642. {
  1643. if (ExtractWspName(g_DebugCommandLine,
  1644. WspName, sizeof(WspName)))
  1645. {
  1646. WspValue = WspName;
  1647. }
  1648. }
  1649. EngSwitchWorkspace(WspKey, WspValue);
  1650. if (g_ProcessServer != NULL)
  1651. {
  1652. Hr = g_pDbgClient->ConnectProcessServer(g_ProcessServer,
  1653. &Server);
  1654. if (Hr != S_OK)
  1655. {
  1656. ErrorBox(NULL, 0, ERR_Connect_Process_Server,
  1657. g_ProcessServer, FormatStatusCode(Hr),
  1658. FormatStatus(Hr));
  1659. goto ResetWorkspace;
  1660. }
  1661. // Default to not automatically bringing up a disassembly
  1662. // window as it is very expensive to remote all
  1663. // the virtual reads done for it.
  1664. g_WinOptions &= ~WOPT_AUTO_DISASM;
  1665. }
  1666. if (g_ProcNameToDebug != NULL)
  1667. {
  1668. Hr = g_pDbgClient->GetRunningProcessSystemIdByExecutableName
  1669. (Server, g_ProcNameToDebug, DEBUG_GET_PROC_ONLY_MATCH,
  1670. &Pid);
  1671. if (Hr != S_OK)
  1672. {
  1673. if (Hr == S_FALSE)
  1674. {
  1675. ErrorBox(NULL, 0, ERR_Ambiguous_Named_Process,
  1676. g_ProcNameToDebug);
  1677. }
  1678. else
  1679. {
  1680. ErrorBox(NULL, 0, ERR_Get_Named_Process,
  1681. g_ProcNameToDebug, FormatStatusCode(Hr),
  1682. FormatStatus(Hr));
  1683. }
  1684. goto ResetWorkspace;
  1685. }
  1686. }
  1687. else
  1688. {
  1689. Pid = g_PidToDebug;
  1690. }
  1691. if (g_DebugCommandLine != NULL &&
  1692. g_ProcessStartDir != NULL &&
  1693. g_ProcessStartDir[0] != 0)
  1694. {
  1695. sprintf(WspName, ".createdir \"%s\"", g_ProcessStartDir);
  1696. g_pDbgControl->Execute(DEBUG_OUTCTL_IGNORE,
  1697. WspName,
  1698. DEBUG_EXECUTE_NOT_LOGGED);
  1699. }
  1700. Hr = g_pDbgClient->CreateProcessAndAttach(Server,
  1701. g_DebugCommandLine,
  1702. g_DebugCreateFlags,
  1703. Pid,
  1704. g_AttachProcessFlags);
  1705. if (g_DebugCommandLine != NULL &&
  1706. g_ProcessStartDir != NULL &&
  1707. g_ProcessStartDir[0] != 0)
  1708. {
  1709. g_pDbgControl->Execute(DEBUG_OUTCTL_IGNORE,
  1710. ".createdir \"\"",
  1711. DEBUG_EXECUTE_NOT_LOGGED);
  1712. }
  1713. if (Hr != S_OK)
  1714. {
  1715. if (g_DebugCommandLine != NULL)
  1716. {
  1717. ErrorBox(NULL, 0, ERR_Invalid_Process_Create,
  1718. g_DebugCommandLine, FormatStatusCode(Hr),
  1719. FormatStatus(Hr));
  1720. }
  1721. else
  1722. {
  1723. ErrorBox(NULL, 0, ERR_Invalid_Process_Attach,
  1724. Pid, FormatStatusCode(Hr), FormatStatus(Hr));
  1725. }
  1726. goto ResetWorkspace;
  1727. }
  1728. if (g_DetachOnExit &&
  1729. (Hr = g_pDbgClient->
  1730. AddProcessOptions(DEBUG_PROCESS_DETACH_ON_EXIT)) != S_OK)
  1731. {
  1732. ErrorBox(NULL, 0, ERR_No_Detach_On_Exit);
  1733. }
  1734. if (Server != 0)
  1735. {
  1736. g_pDbgClient->DisconnectProcessServer(Server);
  1737. }
  1738. // Bump up our priority so that the debugger stays responsive
  1739. // even when the debuggee is running.
  1740. SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
  1741. }
  1742. else
  1743. {
  1744. // Default to not automatically bringing up a disassembly
  1745. // window as it is very expensive in kernel debugging.
  1746. g_WinOptions &= ~WOPT_AUTO_DISASM;
  1747. WspKey = WSP_NAME_KERNEL;
  1748. WspValue = g_WorkspaceDefaultName;
  1749. EngSwitchWorkspace(WspKey, WspValue);
  1750. Hr = g_pDbgClient->AttachKernel(g_AttachKernelFlags,
  1751. g_KernelConnectOptions);
  1752. if (Hr != S_OK)
  1753. {
  1754. if (g_AttachKernelFlags == DEBUG_ATTACH_LOCAL_KERNEL)
  1755. {
  1756. if (Hr == E_NOTIMPL)
  1757. {
  1758. ErrorBox(NULL, 0, ERR_No_Local_Kernel_Debugging);
  1759. }
  1760. else
  1761. {
  1762. ErrorBox(NULL, 0, ERR_Failed_Local_Kernel_Debugging,
  1763. FormatStatusCode(Hr), FormatStatus(Hr));
  1764. }
  1765. }
  1766. else
  1767. {
  1768. ErrorBox(NULL, 0, ERR_Invalid_Kernel_Attach,
  1769. g_KernelConnectOptions, FormatStatusCode(Hr),
  1770. FormatStatus(Hr));
  1771. }
  1772. goto ResetWorkspace;
  1773. }
  1774. }
  1775. }
  1776. else
  1777. {
  1778. WspKey = WSP_NAME_REMOTE;
  1779. WspValue = g_WorkspaceDefaultName;
  1780. EngSwitchWorkspace(WspKey, WspValue);
  1781. // Use a heuristic of 45 characters per line.
  1782. g_pDbgClient->ConnectSession(DEBUG_CONNECT_SESSION_DEFAULT,
  1783. g_HistoryLines * 45);
  1784. }
  1785. PostMessage(g_hwndFrame, WU_ENGINE_STARTED, 0, S_OK);
  1786. return S_OK;
  1787. ResetWorkspace:
  1788. // We just switched to this workspace but
  1789. // we're failing and we want to abandon it.
  1790. if (g_Workspace != NULL && !g_ExplicitWorkspace)
  1791. {
  1792. // Make sure this doesn't cause a popup.
  1793. g_Workspace->ClearDirty();
  1794. EngSwitchWorkspace(WSP_NAME_BASE,
  1795. g_WorkspaceDefaultName);
  1796. }
  1797. return Hr;
  1798. }
  1799. void
  1800. SetLocalScope(PDEBUG_STACK_FRAME pStackFrame)
  1801. {
  1802. DEBUG_STACK_FRAME LocalFrame;
  1803. if (!pStackFrame)
  1804. {
  1805. // Get and use the default scope
  1806. if (g_pDbgSymbols->ResetScope() != S_OK ||
  1807. g_pDbgSymbols->GetScope(NULL, &LocalFrame, NULL, 0) != S_OK)
  1808. {
  1809. return;
  1810. }
  1811. pStackFrame = &LocalFrame;
  1812. }
  1813. else if (FAILED(g_pDbgSymbols->SetScope(0, pStackFrame, NULL, 0)))
  1814. {
  1815. return;
  1816. }
  1817. }
  1818. void
  1819. SessionActive(void)
  1820. {
  1821. HRESULT Hr;
  1822. // This can get called twice if a remote client connects
  1823. // just as a session is becoming active.
  1824. if (g_SessionActive)
  1825. {
  1826. return;
  1827. }
  1828. g_SessionActive = TRUE;
  1829. if ((Hr = g_pDbgControl->
  1830. GetActualProcessorType(&g_ActualProcType)) != S_OK ||
  1831. FAILED(Hr = g_pDbgControl->
  1832. GetProcessorTypeNames(g_ActualProcType, NULL, 0, NULL,
  1833. g_ActualProcAbbrevName,
  1834. sizeof(g_ActualProcAbbrevName),
  1835. NULL)))
  1836. {
  1837. ErrorExit(g_pDbgClient,
  1838. "Debug target initialization failed, 0x%X\n", Hr);
  1839. }
  1840. // Put in a request for the actual processor register
  1841. // names right now.
  1842. GetRegisterNames(g_ActualProcType);
  1843. if (FAILED(Hr = g_pDbgControl->IsPointer64Bit()))
  1844. {
  1845. ErrorExit(g_pDbgClient,
  1846. "Unable to get debuggee pointer size, 0x%X\n", Hr);
  1847. }
  1848. g_Ptr64 = Hr == S_OK;
  1849. if (!g_RemoteClient &&
  1850. (g_ExplicitWorkspace || g_TargetClass == DEBUG_CLASS_KERNEL) &&
  1851. g_NumDumpFiles == 0)
  1852. {
  1853. if (g_ExplicitWorkspace)
  1854. {
  1855. // Reapply the workspace after a reboot/restart to get
  1856. // breakpoints and other engine state back.
  1857. // Don't restart the session when doing so.
  1858. if (g_Workspace != NULL)
  1859. {
  1860. Workspace* Wsp = g_Workspace;
  1861. g_Workspace = NULL;
  1862. Wsp->Apply(WSP_APPLY_AGAIN);
  1863. g_Workspace = Wsp;
  1864. }
  1865. }
  1866. else
  1867. {
  1868. // The same machine could theoretically debug many different
  1869. // processor types over kernel connections or via different
  1870. // processor dumps. Workspaces contain processor-related
  1871. // information, such as register maps, so allow for different
  1872. // workspaces based on the processor type. This is only
  1873. // done when a default workspace would otherwise be used,
  1874. // though to reduce workspace explosion.
  1875. EngSwitchWorkspace(WSP_NAME_KERNEL, g_ActualProcAbbrevName);
  1876. }
  1877. }
  1878. InvalidateStateBuffers(BUFFERS_ALL);
  1879. UpdateBufferWindows((1 << CPU_WINDOW) | (1 << DOC_WINDOW),
  1880. UPDATE_START_SESSION);
  1881. UpdateEngine();
  1882. }
  1883. void
  1884. SessionInactive(void)
  1885. {
  1886. if (!g_RemoteClient && g_EndingSession != ENDING_STOP)
  1887. {
  1888. EngSwitchWorkspace(WSP_NAME_BASE,
  1889. g_WorkspaceDefaultName);
  1890. }
  1891. g_SessionActive = FALSE;
  1892. g_ActualProcType = IMAGE_FILE_MACHINE_UNKNOWN;
  1893. InvalidateStateBuffers(BUFFERS_ALL);
  1894. UpdateBufferWindows((1 << CPU_WINDOW) | (1 << DOC_WINDOW) |
  1895. (1 << DISASM_WINDOW), UPDATE_END_SESSION);
  1896. UpdateEngine();
  1897. SetPriorityClass(GetCurrentProcess(), g_DefPriority);
  1898. }
  1899. void
  1900. StopOrEndDebugging(void)
  1901. {
  1902. //
  1903. // If the session was started from the command line
  1904. // assume that debugging is done and exit.
  1905. // If the session was started from the UI treat it
  1906. // like a stop debugging request.
  1907. //
  1908. if (g_CommandLineStart)
  1909. {
  1910. EngSwitchWorkspace(WSP_NAME_BASE,
  1911. g_WorkspaceDefaultName);
  1912. g_Exit = TRUE;
  1913. PostMessage(g_hwndFrame, WU_UPDATE, UPDATE_EXIT, 0);
  1914. }
  1915. else
  1916. {
  1917. PostMessage(g_hwndFrame, WM_COMMAND,
  1918. 0xffff0000 | IDM_DEBUG_STOPDEBUGGING, 0);
  1919. g_EndingSession = ENDING_STOP;
  1920. }
  1921. }
  1922. DWORD
  1923. WINAPI
  1924. EngineLoop(LPVOID Param)
  1925. {
  1926. HRESULT Hr;
  1927. if ((Hr = InitializeEngineInterfaces()) != S_OK ||
  1928. (Hr = StartSession()) != S_OK)
  1929. {
  1930. ReleaseEngineInterfaces();
  1931. PostMessage(g_hwndFrame, WU_ENGINE_STARTED, 0, Hr);
  1932. return 0;
  1933. }
  1934. g_EngineThreadId = GetCurrentThreadId();
  1935. Hr = g_pDbgControl->GetDebuggeeType(&g_TargetClass, &g_TargetClassQual);
  1936. if (Hr != S_OK)
  1937. {
  1938. ErrorExit(g_pDbgClient, "Unable to get debuggee type, 0x%X\n", Hr);
  1939. }
  1940. // Set initial execution state.
  1941. if ((Hr = g_pDbgControl->GetExecutionStatus(&g_ExecStatus)) != S_OK)
  1942. {
  1943. ErrorExit(g_pDbgClient, "Unable to get execution status, 0x%X\n", Hr);
  1944. }
  1945. if (g_ExecStatus != DEBUG_STATUS_NO_DEBUGGEE)
  1946. {
  1947. // Session is already active.
  1948. SessionActive();
  1949. }
  1950. UpdateBufferWindows(UPDATE_EXEC_WINDOWS, UPDATE_EXEC);
  1951. if (g_RemoteClient)
  1952. {
  1953. // Request an initial read of everything.
  1954. InvalidateStateBuffers(BUFFERS_ALL);
  1955. ReadStateBuffers();
  1956. // The server may be in an input request, which
  1957. // we would have been notified of back during
  1958. // ConnectSession. If we're still in an input
  1959. // request switch to input mode.
  1960. if (g_InputStarted)
  1961. {
  1962. UpdateBufferWindows(1 << CMD_WINDOW, UPDATE_INPUT_REQUIRED);
  1963. }
  1964. }
  1965. for (;;)
  1966. {
  1967. if (!g_RemoteClient)
  1968. {
  1969. g_WaitingForEvent = TRUE;
  1970. Hr = g_pDbgControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
  1971. g_WaitingForEvent = FALSE;
  1972. if (g_HoldWaitOutput)
  1973. {
  1974. UpdateUi();
  1975. }
  1976. if (FAILED(Hr))
  1977. {
  1978. // The debug session may have ended. If so,
  1979. // stop or end things based on how the session
  1980. // was started.
  1981. if (g_pDbgControl->GetExecutionStatus(&g_ExecStatus) == S_OK &&
  1982. g_ExecStatus == DEBUG_STATUS_NO_DEBUGGEE)
  1983. {
  1984. g_pDbgClient->EndSession(DEBUG_END_PASSIVE);
  1985. StopOrEndDebugging();
  1986. break;
  1987. }
  1988. // Inform the user of the failure and force
  1989. // command processing.
  1990. g_OutputCb.Output(DEBUG_OUTPUT_ERROR, "WaitForEvent failed\n");
  1991. g_ExecStatus = DEBUG_STATUS_BREAK;
  1992. }
  1993. if (g_TargetClass != DEBUG_CLASS_KERNEL ||
  1994. (g_TargetClassQual != DEBUG_DUMP_SMALL &&
  1995. g_TargetClassQual != DEBUG_DUMP_DEFAULT &&
  1996. g_TargetClassQual != DEBUG_DUMP_FULL))
  1997. {
  1998. g_pDbgControl->OutputCurrentState(DEBUG_OUTCTL_ALL_CLIENTS,
  1999. DEBUG_CURRENT_DEFAULT);
  2000. }
  2001. ReadStateBuffers();
  2002. }
  2003. while (!g_Exit &&
  2004. g_EndingSession == ENDING_NONE &&
  2005. (g_RemoteClient || g_ExecStatus == DEBUG_STATUS_BREAK))
  2006. {
  2007. if (!g_InputStarted)
  2008. {
  2009. // Tell the command window to display a prompt to
  2010. // indicate the engine is ready to process commands.
  2011. if (g_pDbgControl->GetPromptText(g_PromptText,
  2012. sizeof(g_PromptText),
  2013. NULL) != S_OK)
  2014. {
  2015. strcpy(g_PromptText, "?Err");
  2016. }
  2017. UpdateBufferWindows(1 << CMD_WINDOW, UPDATE_PROMPT_TEXT);
  2018. PostMessage(g_hwndFrame, WU_ENGINE_IDLE, 0, 0);
  2019. }
  2020. // Wait until engine processing is needed.
  2021. Hr = g_pDbgClient->DispatchCallbacks(INFINITE);
  2022. if (FAILED(Hr))
  2023. {
  2024. if (g_RemoteClient && HRESULT_FACILITY(Hr) == FACILITY_RPC)
  2025. {
  2026. // A remote client was unable to communicate
  2027. // with the server so shut down the session.
  2028. InformationBox(ERR_Client_Disconnect);
  2029. StopOrEndDebugging();
  2030. break;
  2031. }
  2032. else
  2033. {
  2034. // A failure here is a critical problem as
  2035. // something is seriously wrong with the engine
  2036. // if it can't do a normal DispatchCallbacks.
  2037. ErrorExit(g_pDbgClient,
  2038. "Engine thread wait failed, 0x%X\n", Hr);
  2039. }
  2040. }
  2041. if (!g_InputStarted)
  2042. {
  2043. // Take away the prompt while the engine is working.
  2044. g_PromptText[0] = 0;
  2045. UpdateBufferWindows(1 << CMD_WINDOW, UPDATE_PROMPT_TEXT);
  2046. }
  2047. ProcessEngineCommands(FALSE);
  2048. }
  2049. if (g_Exit)
  2050. {
  2051. g_EndingSession = ENDING_EXIT;
  2052. break;
  2053. }
  2054. if (g_EndingSession != ENDING_NONE)
  2055. {
  2056. // Force windows to display empty state.
  2057. InvalidateStateBuffers(BUFFERS_ALL);
  2058. UpdateBufferWindows(BUFFERS_ALL, UPDATE_BUFFER);
  2059. if (g_EndingSession == ENDING_RESTART)
  2060. {
  2061. if (StartSession() != S_OK)
  2062. {
  2063. // If we couldn't restart go into
  2064. // the stop-debugging state.
  2065. g_EndingSession = ENDING_STOP;
  2066. break;
  2067. }
  2068. g_EndingSession = ENDING_NONE;
  2069. }
  2070. else
  2071. {
  2072. break;
  2073. }
  2074. }
  2075. }
  2076. if (g_EndingSession == ENDING_NONE)
  2077. {
  2078. // Wake up the message pump for exit.
  2079. PostMessage(g_hwndFrame, WM_CLOSE, 0, 0);
  2080. }
  2081. ULONG Code;
  2082. if (!g_RemoteClient && g_DebugCommandLine != NULL)
  2083. {
  2084. // Return exit code of last process to exit.
  2085. Code = g_LastProcessExitCode;
  2086. }
  2087. else
  2088. {
  2089. Code = S_OK;
  2090. }
  2091. if (g_pDbgClient)
  2092. {
  2093. if (g_RemoteClient)
  2094. {
  2095. g_pDbgClient->EndSession(DEBUG_END_DISCONNECT);
  2096. }
  2097. else if (g_EndingSession != ENDING_STOP)
  2098. {
  2099. g_pDbgClient->EndSession(DEBUG_END_REENTRANT);
  2100. }
  2101. }
  2102. ReleaseEngineInterfaces();
  2103. g_EngineThreadId = 0;
  2104. if (g_EndingSession != ENDING_STOP)
  2105. {
  2106. //
  2107. // Wait for UI to finish up.
  2108. //
  2109. while (!g_Exit)
  2110. {
  2111. Sleep(50);
  2112. }
  2113. ExitDebugger(g_pDbgClient, Code);
  2114. }
  2115. else
  2116. {
  2117. g_EndingSession = ENDING_NONE;
  2118. }
  2119. return 0;
  2120. }
  2121. void
  2122. UpdateEngine(void)
  2123. {
  2124. if (g_pUiClient != NULL && g_pDbgClient != NULL)
  2125. {
  2126. g_pUiClient->ExitDispatch(g_pDbgClient);
  2127. }
  2128. }