Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2355 lines
63 KiB

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