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.

2730 lines
56 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Debug client implementation.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include "dbgver.h"
  10. #define VER_STRING(Specific) \
  11. "\n" \
  12. "Microsoft (R) Windows " Specific \
  13. " Version " VER_PRODUCTVERSION_STR \
  14. "\n" VER_LEGALCOPYRIGHT_STR \
  15. "\n" \
  16. "\n"
  17. PCHAR g_Win9xVersionString = VER_STRING("9x User-Mode Debugger");
  18. PCHAR g_WinKernelVersionString = VER_STRING("Kernel Debugger");
  19. PCHAR g_WinUserVersionString = VER_STRING("User-Mode Debugger");
  20. BOOL g_QuietMode;
  21. ULONG g_OutputWidth = 80;
  22. PCSTR g_OutputLinePrefix;
  23. // The platform ID of the machine running the debugger. Note
  24. // that this may be different from g_TargetPlatformId, which
  25. // is the platform ID of the machine being debugged.
  26. ULONG g_DebuggerPlatformId;
  27. CRITICAL_SECTION g_QuickLock;
  28. CRITICAL_SECTION g_EngineLock;
  29. ULONG g_EngineNesting;
  30. // Events and storage space for returning event callback
  31. // status from an APC.
  32. HANDLE g_EventStatusWaiting;
  33. HANDLE g_EventStatusReady;
  34. ULONG g_EventStatus;
  35. // Named event to sleep on.
  36. HANDLE g_SleepPidEvent;
  37. //----------------------------------------------------------------------------
  38. //
  39. // DebugClient.
  40. //
  41. //----------------------------------------------------------------------------
  42. // List of all clients.
  43. DebugClient* g_Clients;
  44. char g_InputBuffer[INPUT_BUFFER_SIZE];
  45. ULONG g_InputSequence;
  46. HANDLE g_InputEvent;
  47. ULONG g_InputSizeRequested;
  48. // The thread that created the current session.
  49. ULONG g_SessionThread;
  50. PPENDING_PROCESS g_ProcessPending;
  51. ULONG g_EngOptions;
  52. ULONG g_EngStatus;
  53. ULONG g_EngDefer;
  54. ULONG g_EngErr;
  55. // Some options set through the process options apply to
  56. // all processes and some are per-process. The global
  57. // options are collected here.
  58. ULONG g_GlobalProcOptions;
  59. #if DBG
  60. ULONG g_EnvOutMask;
  61. #endif
  62. DebugClient::DebugClient(void)
  63. {
  64. m_Next = NULL;
  65. m_Prev = NULL;
  66. m_Refs = 1;
  67. m_Flags = 0;
  68. m_ThreadId = ::GetCurrentThreadId();
  69. m_Thread = NULL;
  70. m_EventCb = NULL;
  71. m_EventInterest = 0;
  72. m_DispatchSema = NULL;
  73. m_InputCb = NULL;
  74. m_InputSequence = 0xffffffff;
  75. m_OutputCb = NULL;
  76. #if DBG
  77. m_OutMask = DEFAULT_OUT_MASK | g_EnvOutMask;
  78. #else
  79. m_OutMask = DEFAULT_OUT_MASK;
  80. #endif
  81. m_OutputWidth = 80;
  82. m_OutputLinePrefix = NULL;
  83. }
  84. DebugClient::~DebugClient(void)
  85. {
  86. // Most of the work is done in Destroy.
  87. if (m_Flags & CLIENT_IN_LIST)
  88. {
  89. Unlink();
  90. }
  91. }
  92. void
  93. DebugClient::Destroy(void)
  94. {
  95. // Clients cannot arbitrarily be removed from the client list
  96. // or their memory deleted due to the possibility of a callback
  97. // loop occurring at the same time. Instead clients are left
  98. // in the list and zeroed out to prevent further callbacks
  99. // from occurring.
  100. // XXX drewb - This memory needs to be reclaimed at some
  101. // point, but there's no simple safe time to do so since
  102. // callbacks can occur at any time. Clients are very small
  103. // right now so the leakage is negligible.
  104. m_Flags = (m_Flags & ~(CLIENT_REMOTE | CLIENT_PRIMARY)) |
  105. CLIENT_DESTROYED;
  106. // Remove any references from breakpoints this client
  107. // added.
  108. PPROCESS_INFO Process;
  109. Breakpoint* Bp;
  110. for (Process = g_ProcessHead; Process; Process = Process->Next)
  111. {
  112. for (Bp = Process->Breakpoints; Bp != NULL; Bp = Bp->m_Next)
  113. {
  114. if (Bp->m_Adder == this)
  115. {
  116. Bp->m_Adder = NULL;
  117. }
  118. }
  119. }
  120. if (m_Thread != NULL)
  121. {
  122. CloseHandle(m_Thread);
  123. m_Thread = NULL;
  124. }
  125. m_EventInterest = 0;
  126. RELEASE(m_EventCb);
  127. if (m_DispatchSema != NULL)
  128. {
  129. CloseHandle(m_DispatchSema);
  130. m_DispatchSema = NULL;
  131. }
  132. RELEASE(m_InputCb);
  133. m_InputSequence = 0xffffffff;
  134. RELEASE(m_OutputCb);
  135. m_OutMask = 0;
  136. CollectOutMasks();
  137. }
  138. STDMETHODIMP
  139. DebugClient::QueryInterface(
  140. THIS_
  141. IN REFIID InterfaceId,
  142. OUT PVOID* Interface
  143. )
  144. {
  145. HRESULT Status;
  146. *Interface = NULL;
  147. Status = S_OK;
  148. // Interface specific casts are necessary in order to
  149. // get the right vtable pointer in our multiple
  150. // inheritance scheme.
  151. if (DbgIsEqualIID(InterfaceId, IID_IUnknown) ||
  152. DbgIsEqualIID(InterfaceId, IID_IDebugClient) ||
  153. DbgIsEqualIID(InterfaceId, IID_IDebugClient2))
  154. {
  155. *Interface = (IDebugClientN *)this;
  156. }
  157. else if (DbgIsEqualIID(InterfaceId, IID_IDebugAdvanced))
  158. {
  159. *Interface = (IDebugAdvancedN *)this;
  160. }
  161. else if (DbgIsEqualIID(InterfaceId, IID_IDebugControl) ||
  162. DbgIsEqualIID(InterfaceId, IID_IDebugControl2))
  163. {
  164. *Interface = (IDebugControlN *)this;
  165. }
  166. else if (DbgIsEqualIID(InterfaceId, IID_IDebugDataSpaces) ||
  167. DbgIsEqualIID(InterfaceId, IID_IDebugDataSpaces2))
  168. {
  169. *Interface = (IDebugDataSpacesN *)this;
  170. }
  171. else if (DbgIsEqualIID(InterfaceId, IID_IDebugRegisters))
  172. {
  173. *Interface = (IDebugRegistersN *)this;
  174. }
  175. else if (DbgIsEqualIID(InterfaceId, IID_IDebugSymbols) ||
  176. DbgIsEqualIID(InterfaceId, IID_IDebugSymbols2))
  177. {
  178. *Interface = (IDebugSymbolsN *)this;
  179. }
  180. else if (DbgIsEqualIID(InterfaceId, IID_IDebugSystemObjects) ||
  181. DbgIsEqualIID(InterfaceId, IID_IDebugSystemObjects2))
  182. {
  183. *Interface = (IDebugSystemObjectsN *)this;
  184. }
  185. else if (DbgIsEqualIID(InterfaceId, IID_IDebugSymbolGroup))
  186. {
  187. *Interface = (IDebugSymbolGroupN *)this;
  188. }
  189. else
  190. {
  191. Status = E_NOINTERFACE;
  192. }
  193. if (Status == S_OK)
  194. {
  195. AddRef();
  196. }
  197. return Status;
  198. }
  199. STDMETHODIMP_(ULONG)
  200. DebugClient::AddRef(
  201. THIS
  202. )
  203. {
  204. return InterlockedIncrement((PLONG)&m_Refs);
  205. }
  206. STDMETHODIMP_(ULONG)
  207. DebugClient::Release(
  208. THIS
  209. )
  210. {
  211. LONG Refs = InterlockedDecrement((PLONG)&m_Refs);
  212. if (Refs == 0)
  213. {
  214. Destroy();
  215. }
  216. return Refs;
  217. }
  218. STDMETHODIMP
  219. DebugClient::AttachKernel(
  220. THIS_
  221. IN ULONG Flags,
  222. IN OPTIONAL PCSTR ConnectOptions
  223. )
  224. {
  225. ULONG Qual;
  226. if (
  227. #if DEBUG_ATTACH_KERNEL_CONNECTION > 0
  228. Flags < DEBUG_ATTACH_KERNEL_CONNECTION ||
  229. #endif
  230. Flags > DEBUG_ATTACH_EXDI_DRIVER)
  231. {
  232. return E_INVALIDARG;
  233. }
  234. if (Flags == DEBUG_ATTACH_LOCAL_KERNEL)
  235. {
  236. if (ConnectOptions != NULL)
  237. {
  238. return E_INVALIDARG;
  239. }
  240. if (g_DebuggerPlatformId != VER_PLATFORM_WIN32_NT)
  241. {
  242. return E_UNEXPECTED;
  243. }
  244. Qual = DEBUG_KERNEL_LOCAL;
  245. }
  246. else if (Flags == DEBUG_ATTACH_EXDI_DRIVER)
  247. {
  248. Qual = DEBUG_KERNEL_EXDI_DRIVER;
  249. }
  250. else
  251. {
  252. Qual = DEBUG_KERNEL_CONNECTION;
  253. }
  254. ENTER_ENGINE();
  255. HRESULT Status = LiveKernelInitialize(this, Qual, ConnectOptions);
  256. if (Status == S_OK)
  257. {
  258. InitializePrimary();
  259. }
  260. LEAVE_ENGINE();
  261. return Status;
  262. }
  263. STDMETHODIMP
  264. DebugClient::GetKernelConnectionOptions(
  265. THIS_
  266. OUT OPTIONAL PSTR Buffer,
  267. IN ULONG BufferSize,
  268. OUT OPTIONAL PULONG OptionsSize
  269. )
  270. {
  271. if (!IS_CONN_KERNEL_TARGET() ||
  272. g_DbgKdTransport == NULL)
  273. {
  274. return E_UNEXPECTED;
  275. }
  276. if (BufferSize == 0)
  277. {
  278. return E_INVALIDARG;
  279. }
  280. ENTER_ENGINE();
  281. #define MIN_BUFFER_SIZE (2 * (MAX_PARAM_NAME + MAX_PARAM_VALUE + 16))
  282. char MinBuf[MIN_BUFFER_SIZE];
  283. PSTR Buf;
  284. ULONG BufSize;
  285. if (Buffer == NULL || BufferSize < MIN_BUFFER_SIZE)
  286. {
  287. Buf = MinBuf;
  288. BufSize = MIN_BUFFER_SIZE;
  289. }
  290. else
  291. {
  292. Buf = Buffer;
  293. BufSize = BufferSize;
  294. }
  295. HRESULT Status;
  296. if (g_DbgKdTransport->GetParameters(Buf, BufSize))
  297. {
  298. BufSize = strlen(Buf);
  299. Status = S_OK;
  300. }
  301. else
  302. {
  303. // Just guess on the necessary size.
  304. BufSize *= 2;
  305. Status = S_FALSE;
  306. }
  307. if (Buffer != NULL && Buf != Buffer)
  308. {
  309. strcpy(Buffer, Buf);
  310. }
  311. if (OptionsSize != NULL)
  312. {
  313. *OptionsSize = BufSize;
  314. }
  315. LEAVE_ENGINE();
  316. return Status;
  317. }
  318. STDMETHODIMP
  319. DebugClient::SetKernelConnectionOptions(
  320. THIS_
  321. IN PCSTR Options
  322. )
  323. {
  324. if (!IS_CONN_KERNEL_TARGET() ||
  325. g_DbgKdTransport == NULL)
  326. {
  327. return E_UNEXPECTED;
  328. }
  329. // This method is reentrant.
  330. if (!_strcmpi(Options, "resync"))
  331. {
  332. g_DbgKdTransport->m_Resync = TRUE;
  333. }
  334. else if (!_strcmpi(Options, "cycle_speed"))
  335. {
  336. g_DbgKdTransport->CycleSpeed();
  337. }
  338. else
  339. {
  340. return E_NOINTERFACE;
  341. }
  342. return S_OK;
  343. }
  344. DBGRPC_SIMPLE_FACTORY(LiveUserDebugServices, IID_IUserDebugServices, \
  345. "Remote Process Server", (TRUE))
  346. LiveUserDebugServicesFactory g_LiveUserDebugServicesFactory;
  347. STDMETHODIMP
  348. DebugClient::StartProcessServer(
  349. THIS_
  350. IN ULONG Flags,
  351. IN PCSTR Options,
  352. IN PVOID Reserved
  353. )
  354. {
  355. if (Flags <= DEBUG_CLASS_KERNEL || Flags > DEBUG_CLASS_USER_WINDOWS)
  356. {
  357. return E_INVALIDARG;
  358. }
  359. // XXX drewb - Turn reserved into public IUserDebugServices
  360. // parameter so that a server can be started over arbitrary services.
  361. if (Reserved != NULL)
  362. {
  363. return E_NOTIMPL;
  364. }
  365. HRESULT Status;
  366. ENTER_ENGINE();
  367. DbgRpcClientObjectFactory* Factory;
  368. switch(Flags)
  369. {
  370. case DEBUG_CLASS_USER_WINDOWS:
  371. Factory = &g_LiveUserDebugServicesFactory;
  372. break;
  373. default:
  374. DBG_ASSERT(FALSE);
  375. break;
  376. }
  377. Status = DbgRpcCreateServer(Options, Factory);
  378. LEAVE_ENGINE();
  379. return Status;
  380. }
  381. STDMETHODIMP
  382. DebugClient::ConnectProcessServer(
  383. THIS_
  384. IN PCSTR RemoteOptions,
  385. OUT PULONG64 Server
  386. )
  387. {
  388. HRESULT Status;
  389. ENTER_ENGINE();
  390. PUSER_DEBUG_SERVICES Services;
  391. if ((Status = DbgRpcConnectServer(RemoteOptions, &IID_IUserDebugServices,
  392. (IUnknown**)&Services)) == S_OK)
  393. {
  394. *Server = (ULONG64)(ULONG_PTR)Services;
  395. }
  396. LEAVE_ENGINE();
  397. return Status;
  398. }
  399. STDMETHODIMP
  400. DebugClient::DisconnectProcessServer(
  401. THIS_
  402. IN ULONG64 Server
  403. )
  404. {
  405. ENTER_ENGINE();
  406. ((PUSER_DEBUG_SERVICES)Server)->Release();
  407. LEAVE_ENGINE();
  408. return S_OK;
  409. }
  410. STDMETHODIMP
  411. DebugClient::GetRunningProcessSystemIds(
  412. THIS_
  413. IN ULONG64 Server,
  414. OUT OPTIONAL /* size_is(Count) */ PULONG Ids,
  415. IN ULONG Count,
  416. OUT OPTIONAL PULONG ActualCount
  417. )
  418. {
  419. HRESULT Status;
  420. ENTER_ENGINE();
  421. Status = SERVER_SERVICES(Server)->
  422. GetProcessIds(Ids, Count, ActualCount);
  423. LEAVE_ENGINE();
  424. return Status;
  425. }
  426. STDMETHODIMP
  427. DebugClient::GetRunningProcessSystemIdByExecutableName(
  428. THIS_
  429. IN ULONG64 Server,
  430. IN PCSTR ExeName,
  431. IN ULONG Flags,
  432. OUT PULONG Id
  433. )
  434. {
  435. if (Flags & ~(DEBUG_GET_PROC_DEFAULT |
  436. DEBUG_GET_PROC_FULL_MATCH |
  437. DEBUG_GET_PROC_ONLY_MATCH))
  438. {
  439. return E_INVALIDARG;
  440. }
  441. HRESULT Status;
  442. ENTER_ENGINE();
  443. Status = SERVER_SERVICES(Server)->
  444. GetProcessIdByExecutableName(ExeName, Flags, Id);
  445. LEAVE_ENGINE();
  446. return Status;
  447. }
  448. STDMETHODIMP
  449. DebugClient::GetRunningProcessDescription(
  450. THIS_
  451. IN ULONG64 Server,
  452. IN ULONG SystemId,
  453. IN ULONG Flags,
  454. OUT OPTIONAL PSTR ExeName,
  455. IN ULONG ExeNameSize,
  456. OUT OPTIONAL PULONG ActualExeNameSize,
  457. OUT OPTIONAL PSTR Description,
  458. IN ULONG DescriptionSize,
  459. OUT OPTIONAL PULONG ActualDescriptionSize
  460. )
  461. {
  462. HRESULT Status;
  463. if (Flags & ~(DEBUG_PROC_DESC_DEFAULT |
  464. DEBUG_PROC_DESC_NO_PATHS))
  465. {
  466. return E_INVALIDARG;
  467. }
  468. ENTER_ENGINE();
  469. Status = SERVER_SERVICES(Server)->
  470. GetProcessDescription(SystemId, Flags, ExeName, ExeNameSize,
  471. ActualExeNameSize, Description, DescriptionSize,
  472. ActualDescriptionSize);
  473. LEAVE_ENGINE();
  474. return Status;
  475. }
  476. #define ALL_ATTACH_FLAGS \
  477. (DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_EXISTING)
  478. STDMETHODIMP
  479. DebugClient::AttachProcess(
  480. THIS_
  481. IN ULONG64 Server,
  482. IN ULONG ProcessId,
  483. IN ULONG AttachFlags
  484. )
  485. {
  486. HRESULT Status;
  487. if ((AttachFlags & ~ALL_ATTACH_FLAGS) ||
  488. (AttachFlags & (DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_EXISTING)) ==
  489. (DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_EXISTING))
  490. {
  491. return E_INVALIDARG;
  492. }
  493. ENTER_ENGINE();
  494. BOOL InitTarget = FALSE;
  495. if (!IS_TARGET_SET())
  496. {
  497. Status = UserInitialize(this, Server);
  498. InitTarget = TRUE;
  499. }
  500. if (IS_LIVE_USER_TARGET())
  501. {
  502. PPENDING_PROCESS Pending;
  503. Status = StartAttachProcess(ProcessId, AttachFlags, &Pending);
  504. if (Status == S_OK)
  505. {
  506. InitializePrimary();
  507. }
  508. else if (InitTarget)
  509. {
  510. DiscardTarget(DEBUG_SESSION_END_SESSION_PASSIVE);
  511. }
  512. }
  513. else if (!InitTarget)
  514. {
  515. Status = E_UNEXPECTED;
  516. }
  517. LEAVE_ENGINE();
  518. return Status;
  519. }
  520. STDMETHODIMP
  521. DebugClient::CreateProcess(
  522. THIS_
  523. IN ULONG64 Server,
  524. IN PSTR CommandLine,
  525. IN ULONG CreateFlags
  526. )
  527. {
  528. HRESULT Status;
  529. ENTER_ENGINE();
  530. BOOL InitTarget = FALSE;
  531. if (!IS_TARGET_SET())
  532. {
  533. Status = UserInitialize(this, Server);
  534. InitTarget = TRUE;
  535. }
  536. if (IS_LIVE_USER_TARGET())
  537. {
  538. PPENDING_PROCESS Pending;
  539. Status = StartCreateProcess(CommandLine, CreateFlags, &Pending);
  540. if (Status == S_OK)
  541. {
  542. InitializePrimary();
  543. }
  544. else if (InitTarget)
  545. {
  546. DiscardTarget(DEBUG_SESSION_END_SESSION_PASSIVE);
  547. }
  548. }
  549. else if (!InitTarget)
  550. {
  551. Status = E_UNEXPECTED;
  552. }
  553. LEAVE_ENGINE();
  554. return Status;
  555. }
  556. STDMETHODIMP
  557. DebugClient::CreateProcessAndAttach(
  558. THIS_
  559. IN ULONG64 Server,
  560. IN OPTIONAL PSTR CommandLine,
  561. IN ULONG CreateFlags,
  562. IN ULONG ProcessId,
  563. IN ULONG AttachFlags
  564. )
  565. {
  566. if ((CommandLine == NULL && ProcessId == 0) ||
  567. (AttachFlags & ~ALL_ATTACH_FLAGS))
  568. {
  569. return E_INVALIDARG;
  570. }
  571. HRESULT Status;
  572. ENTER_ENGINE();
  573. BOOL InitTarget = FALSE;
  574. if (!IS_TARGET_SET())
  575. {
  576. Status = UserInitialize(this, Server);
  577. InitTarget = TRUE;
  578. }
  579. if (IS_LIVE_USER_TARGET())
  580. {
  581. PPENDING_PROCESS PendCreate, PendAttach;
  582. if (CommandLine != NULL)
  583. {
  584. if (ProcessId != 0)
  585. {
  586. CreateFlags |= CREATE_SUSPENDED;
  587. }
  588. if ((Status = StartCreateProcess(CommandLine, CreateFlags,
  589. &PendCreate)) != S_OK)
  590. {
  591. goto EH_Discard;
  592. }
  593. }
  594. if (ProcessId != 0)
  595. {
  596. if ((Status = StartAttachProcess(ProcessId, AttachFlags,
  597. &PendAttach)) != S_OK)
  598. {
  599. goto EH_Discard;
  600. }
  601. // If we previously created a process we need to wake
  602. // it up when we attach since we created it suspended.
  603. if (CommandLine != NULL)
  604. {
  605. g_ThreadToResume = PendCreate->InitialThreadHandle;
  606. }
  607. }
  608. InitializePrimary();
  609. }
  610. else if (!InitTarget)
  611. {
  612. Status = E_UNEXPECTED;
  613. }
  614. LEAVE_ENGINE();
  615. return Status;
  616. EH_Discard:
  617. DiscardTarget(DEBUG_SESSION_END_SESSION_PASSIVE);
  618. LEAVE_ENGINE();
  619. return Status;
  620. }
  621. STDMETHODIMP
  622. DebugClient::GetProcessOptions(
  623. THIS_
  624. OUT PULONG Options
  625. )
  626. {
  627. HRESULT Status;
  628. ENTER_ENGINE();
  629. if (!IS_LIVE_USER_TARGET())
  630. {
  631. Status = E_UNEXPECTED;
  632. }
  633. else
  634. {
  635. Status = S_OK;
  636. *Options = g_GlobalProcOptions;
  637. if (g_CurrentProcess != NULL)
  638. {
  639. *Options |= g_CurrentProcess->Options;
  640. }
  641. }
  642. LEAVE_ENGINE();
  643. return Status;
  644. }
  645. #define PROCESS_ALL \
  646. (DEBUG_PROCESS_DETACH_ON_EXIT | DEBUG_PROCESS_ONLY_THIS_PROCESS)
  647. #define PROCESS_GLOBAL \
  648. (DEBUG_PROCESS_DETACH_ON_EXIT)
  649. HRESULT
  650. ChangeProcessOptions(ULONG Options, ULONG OptFn)
  651. {
  652. if (Options & ~PROCESS_ALL)
  653. {
  654. return E_INVALIDARG;
  655. }
  656. if (!IS_LIVE_USER_TARGET())
  657. {
  658. return E_UNEXPECTED;
  659. }
  660. HRESULT Status;
  661. ENTER_ENGINE();
  662. ULONG NewPer, OldPer;
  663. ULONG NewGlobal;
  664. switch(OptFn)
  665. {
  666. case OPTFN_ADD:
  667. if (Options & ~PROCESS_GLOBAL)
  668. {
  669. if (g_CurrentProcess == NULL)
  670. {
  671. Status = E_UNEXPECTED;
  672. goto Exit;
  673. }
  674. OldPer = g_CurrentProcess->Options;
  675. NewPer = OldPer | (Options & ~PROCESS_GLOBAL);
  676. }
  677. else
  678. {
  679. NewPer = 0;
  680. OldPer = 0;
  681. }
  682. NewGlobal = g_GlobalProcOptions | (Options & PROCESS_GLOBAL);
  683. break;
  684. case OPTFN_REMOVE:
  685. if (Options & ~PROCESS_GLOBAL)
  686. {
  687. if (g_CurrentProcess == NULL)
  688. {
  689. Status = E_UNEXPECTED;
  690. goto Exit;
  691. }
  692. OldPer = g_CurrentProcess->Options;
  693. NewPer = OldPer & ~(Options & ~PROCESS_GLOBAL);
  694. }
  695. else
  696. {
  697. NewPer = 0;
  698. OldPer = 0;
  699. }
  700. NewGlobal = g_GlobalProcOptions & ~(Options & PROCESS_GLOBAL);
  701. break;
  702. case OPTFN_SET:
  703. // Always require a process in this case as otherwise
  704. // there's no way to know whether a call to SetProcessOptions
  705. // is actually necessary or not.
  706. if (g_CurrentProcess == NULL)
  707. {
  708. Status = E_UNEXPECTED;
  709. goto Exit;
  710. }
  711. OldPer = g_CurrentProcess->Options;
  712. NewPer = Options & ~PROCESS_GLOBAL;
  713. NewGlobal = Options & PROCESS_GLOBAL;
  714. break;
  715. }
  716. PUSER_DEBUG_SERVICES Services = ((UserTargetInfo*)g_Target)->m_Services;
  717. BOOL Notify = FALSE;
  718. if (NewGlobal ^ g_GlobalProcOptions)
  719. {
  720. // Global options can only be changed by the session thread.
  721. if (::GetCurrentThreadId() != g_SessionThread)
  722. {
  723. Status = E_UNEXPECTED;
  724. goto Exit;
  725. }
  726. if ((Status = Services->SetDebugObjectOptions(0, NewGlobal)) != S_OK)
  727. {
  728. goto Exit;
  729. }
  730. Notify = TRUE;
  731. g_GlobalProcOptions = NewGlobal;
  732. }
  733. if (NewPer ^ OldPer)
  734. {
  735. if ((Status = Services->
  736. SetProcessOptions(g_CurrentProcess->FullHandle, NewPer)) != S_OK)
  737. {
  738. goto Exit;
  739. }
  740. g_CurrentProcess->Options = NewPer;
  741. Notify = TRUE;
  742. }
  743. if (Notify)
  744. {
  745. NotifyChangeEngineState(DEBUG_CES_PROCESS_OPTIONS,
  746. NewPer | NewGlobal, FALSE);
  747. }
  748. Exit:
  749. LEAVE_ENGINE();
  750. return Status;
  751. }
  752. STDMETHODIMP
  753. DebugClient::AddProcessOptions(
  754. THIS_
  755. IN ULONG Options
  756. )
  757. {
  758. return ChangeProcessOptions(Options, OPTFN_ADD);
  759. }
  760. STDMETHODIMP
  761. DebugClient::RemoveProcessOptions(
  762. THIS_
  763. IN ULONG Options
  764. )
  765. {
  766. return ChangeProcessOptions(Options, OPTFN_REMOVE);
  767. }
  768. STDMETHODIMP
  769. DebugClient::SetProcessOptions(
  770. THIS_
  771. IN ULONG Options
  772. )
  773. {
  774. return ChangeProcessOptions(Options, OPTFN_SET);
  775. }
  776. STDMETHODIMP
  777. DebugClient::OpenDumpFile(
  778. THIS_
  779. IN PCSTR DumpFile
  780. )
  781. {
  782. ENTER_ENGINE();
  783. HRESULT Status;
  784. if (g_SessionThread != 0)
  785. {
  786. // A session is already active.
  787. Status = E_UNEXPECTED;
  788. goto EH_Exit;
  789. }
  790. ULONG Class, Qual;
  791. if ((Status = InitNtCmd(this)) != S_OK)
  792. {
  793. goto EH_Exit;
  794. }
  795. //
  796. // Automatically expand CAB files.
  797. //
  798. PCSTR OpenFile = DumpFile;
  799. char CabDumpFile[2 * MAX_PATH];
  800. INT_PTR CabDumpFh = -1;
  801. PSTR Ext;
  802. Ext = strrchr(DumpFile, '.');
  803. if (Ext != NULL && _stricmp(Ext, ".cab") == 0)
  804. {
  805. // Expand the first .dmp or .mdmp file in the CAB.
  806. // Mark it as delete-on-close so it always gets
  807. // cleaned up regardless of how the process exits.
  808. if (ExpandDumpCab(DumpFile, _O_CREAT | _O_EXCL | _O_TEMPORARY,
  809. CabDumpFile, &CabDumpFh) == S_OK)
  810. {
  811. OpenFile = CabDumpFile;
  812. dprintf("Extracted %s\n", OpenFile);
  813. }
  814. }
  815. Status = DmpInitialize(OpenFile);
  816. if (CabDumpFh >= 0)
  817. {
  818. // We expanded a file from a CAB and can close it
  819. // now because it was either reopened or we need
  820. // to get rid of it.
  821. _close((int)CabDumpFh);
  822. }
  823. if (Status != S_OK)
  824. {
  825. ErrOut("Could not initialize dump file [%s], %s\n \"%s\"\n",
  826. DumpFile, FormatStatusCode(Status),
  827. FormatStatusArgs(Status, &DumpFile));
  828. goto EH_Exit;
  829. }
  830. g_Target = g_DumpTargets[g_DumpType];
  831. Status = InitializeTarget();
  832. if (Status != S_OK)
  833. {
  834. DmpUninitialize();
  835. }
  836. else
  837. {
  838. dprintf("%s", IS_KERNEL_TARGET() ? g_WinKernelVersionString :
  839. g_WinUserVersionString);
  840. InitializePrimary();
  841. }
  842. EH_Exit:
  843. LEAVE_ENGINE();
  844. return Status;
  845. }
  846. STDMETHODIMP
  847. DebugClient::WriteDumpFile(
  848. THIS_
  849. IN PCSTR DumpFile,
  850. IN ULONG Qualifier
  851. )
  852. {
  853. return WriteDumpFile2(DumpFile, Qualifier, DEBUG_FORMAT_DEFAULT, NULL);
  854. }
  855. #define ALL_CONNECT_SESSION_FLAGS \
  856. (DEBUG_CONNECT_SESSION_NO_VERSION | \
  857. DEBUG_CONNECT_SESSION_NO_ANNOUNCE)
  858. STDMETHODIMP
  859. DebugClient::ConnectSession(
  860. THIS_
  861. IN ULONG Flags,
  862. IN ULONG HistoryLimit
  863. )
  864. {
  865. if (Flags & ~ALL_CONNECT_SESSION_FLAGS)
  866. {
  867. return E_INVALIDARG;
  868. }
  869. ENTER_ENGINE();
  870. OutCtlSave OldCtl;
  871. PushOutCtl(DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_NOT_LOGGED,
  872. this, &OldCtl);
  873. if ((Flags & DEBUG_CONNECT_SESSION_NO_VERSION) == 0)
  874. {
  875. if (IS_KERNEL_TARGET())
  876. {
  877. dprintf("%s", g_WinKernelVersionString);
  878. }
  879. else if (g_TargetPlatformId != VER_PLATFORM_WIN32_NT)
  880. {
  881. dprintf("%s", g_Win9xVersionString);
  882. }
  883. else
  884. {
  885. dprintf("%s", g_WinUserVersionString);
  886. }
  887. }
  888. SendOutputHistory(this, HistoryLimit);
  889. // If we're in the middle of an input request and
  890. // a new client has joined immediately start
  891. // the input cycle for it.
  892. ULONG InputRequest = g_InputSizeRequested;
  893. if (InputRequest > 0)
  894. {
  895. m_InputSequence = 1;
  896. if (m_InputCb != NULL)
  897. {
  898. m_InputCb->StartInput(InputRequest);
  899. }
  900. }
  901. PopOutCtl(&OldCtl);
  902. if ((Flags & DEBUG_CONNECT_SESSION_NO_ANNOUNCE) == 0)
  903. {
  904. InitializePrimary();
  905. dprintf("%s connected at %s", m_Identity, ctime(&m_LastActivity));
  906. }
  907. LEAVE_ENGINE();
  908. return S_OK;
  909. }
  910. DBGRPC_SIMPLE_FACTORY(DebugClient, IID_IDebugClient, \
  911. "Debugger Server", ())
  912. DebugClientFactory g_DebugClientFactory;
  913. STDMETHODIMP
  914. DebugClient::StartServer(
  915. THIS_
  916. IN PCSTR Options
  917. )
  918. {
  919. HRESULT Status;
  920. ENTER_ENGINE();
  921. Status = DbgRpcCreateServer(Options, &g_DebugClientFactory);
  922. if (Status == S_OK)
  923. {
  924. // Turn on output history collection.
  925. g_OutHistoryMask = DEFAULT_OUT_HISTORY_MASK;
  926. }
  927. LEAVE_ENGINE();
  928. return Status;
  929. }
  930. STDMETHODIMP
  931. DebugClient::OutputServers(
  932. THIS_
  933. IN ULONG OutputControl,
  934. IN PCSTR Machine,
  935. IN ULONG Flags
  936. )
  937. {
  938. if (Flags & ~DEBUG_SERVERS_ALL)
  939. {
  940. return E_INVALIDARG;
  941. }
  942. HRESULT Status;
  943. ENTER_ENGINE();
  944. OutCtlSave OldCtl;
  945. if (!PushOutCtl(OutputControl, this, &OldCtl))
  946. {
  947. Status = E_INVALIDARG;
  948. }
  949. else
  950. {
  951. LONG RegStatus;
  952. HKEY RegKey;
  953. HKEY Key;
  954. Status = S_OK;
  955. if ((RegStatus = RegConnectRegistry(Machine, HKEY_LOCAL_MACHINE,
  956. &RegKey)) != ERROR_SUCCESS)
  957. {
  958. Status = HRESULT_FROM_WIN32(RegStatus);
  959. goto Pop;
  960. }
  961. if ((RegStatus = RegOpenKeyEx(RegKey, DEBUG_SERVER_KEY,
  962. 0, KEY_ALL_ACCESS,
  963. &Key)) != ERROR_SUCCESS)
  964. {
  965. // Don't report not-found as an error since it just
  966. // means there's nothing to enumerate.
  967. if (RegStatus != ERROR_FILE_NOT_FOUND)
  968. {
  969. Status = HRESULT_FROM_WIN32(RegStatus);
  970. }
  971. goto RegClose;
  972. }
  973. ULONG Index;
  974. char Name[32];
  975. char Value[2 * MAX_PARAM_VALUE];
  976. ULONG NameLen, ValueLen;
  977. ULONG Type;
  978. Index = 0;
  979. for (;;)
  980. {
  981. NameLen = sizeof(Name);
  982. ValueLen = sizeof(Value);
  983. if ((RegStatus = RegEnumValue(Key, Index, Name, &NameLen,
  984. NULL, &Type, (LPBYTE)Value,
  985. &ValueLen)) != ERROR_SUCCESS)
  986. {
  987. // Done with the enumeration.
  988. break;
  989. }
  990. if (Type != REG_SZ)
  991. {
  992. // Only string values should be present.
  993. Status = E_FAIL;
  994. break;
  995. }
  996. BOOL Output;
  997. Output = FALSE;
  998. if (!strncmp(Value, "Debugger Server", 15))
  999. {
  1000. if (Flags & DEBUG_SERVERS_DEBUGGER)
  1001. {
  1002. Output = TRUE;
  1003. }
  1004. }
  1005. else if (Flags & DEBUG_SERVERS_PROCESS)
  1006. {
  1007. Output = TRUE;
  1008. }
  1009. if (Output)
  1010. {
  1011. dprintf("%s\n", Value);
  1012. }
  1013. Index++;
  1014. }
  1015. RegCloseKey(Key);
  1016. RegClose:
  1017. RegCloseKey(RegKey);
  1018. Pop:
  1019. PopOutCtl(&OldCtl);
  1020. }
  1021. LEAVE_ENGINE();
  1022. return Status;
  1023. }
  1024. STDMETHODIMP
  1025. DebugClient::TerminateProcesses(
  1026. THIS
  1027. )
  1028. {
  1029. if (!IS_LIVE_USER_TARGET())
  1030. {
  1031. return E_UNEXPECTED;
  1032. }
  1033. HRESULT Status;
  1034. ENTER_ENGINE();
  1035. Status = ::TerminateProcesses();
  1036. LEAVE_ENGINE();
  1037. return Status;
  1038. }
  1039. STDMETHODIMP
  1040. DebugClient::DetachProcesses(
  1041. THIS
  1042. )
  1043. {
  1044. if (!IS_LIVE_USER_TARGET())
  1045. {
  1046. return E_UNEXPECTED;
  1047. }
  1048. HRESULT Status;
  1049. ENTER_ENGINE();
  1050. Status = ::DetachProcesses();
  1051. LEAVE_ENGINE();
  1052. return Status;
  1053. }
  1054. STDMETHODIMP
  1055. DebugClient::EndSession(
  1056. THIS_
  1057. IN ULONG Flags
  1058. )
  1059. {
  1060. if (
  1061. #if DEBUG_END_PASSIVE > 0
  1062. Flags < DEBUG_END_PASSIVE ||
  1063. #endif
  1064. Flags > DEBUG_END_REENTRANT)
  1065. {
  1066. return E_INVALIDARG;
  1067. }
  1068. if (Flags == DEBUG_END_REENTRANT)
  1069. {
  1070. // If somebody's doing a reentrant end that means
  1071. // the process is going away so we can clean up
  1072. // any running server registration entries.
  1073. DbgRpcDeregisterServers();
  1074. }
  1075. if (!IS_TARGET_SET())
  1076. {
  1077. return E_UNEXPECTED;
  1078. }
  1079. HRESULT Status = S_OK;
  1080. if (Flags == DEBUG_END_REENTRANT)
  1081. {
  1082. goto Reenter;
  1083. }
  1084. ENTER_ENGINE();
  1085. if (IS_LIVE_USER_TARGET())
  1086. {
  1087. // If this is an active end, terminate or detach.
  1088. if (Flags == DEBUG_END_ACTIVE_TERMINATE)
  1089. {
  1090. Status = ::TerminateProcesses();
  1091. if (FAILED(Status))
  1092. {
  1093. goto Leave;
  1094. }
  1095. }
  1096. else if (Flags == DEBUG_END_ACTIVE_DETACH)
  1097. {
  1098. Status = ::DetachProcesses();
  1099. if (FAILED(Status))
  1100. {
  1101. goto Leave;
  1102. }
  1103. }
  1104. }
  1105. Reenter:
  1106. if (IS_LIVE_USER_TARGET() && SYSTEM_PROCESSES() &&
  1107. (g_GlobalProcOptions & DEBUG_PROCESS_DETACH_ON_EXIT) == 0)
  1108. {
  1109. //
  1110. // If we try to quit while debugging CSRSS, raise an
  1111. // error.
  1112. //
  1113. if (Flags != DEBUG_END_REENTRANT)
  1114. {
  1115. ErrOut("(%d): FATAL ERROR: Exiting Debugger while debugging CSR\n",
  1116. ::GetCurrentProcessId());
  1117. }
  1118. g_NtDllCalls.DbgPrint("(%d): FATAL ERROR: "
  1119. "Exiting Debugger while debugging CSR\n",
  1120. ::GetCurrentProcessId());
  1121. if (g_DebuggerPlatformId == VER_PLATFORM_WIN32_NT)
  1122. {
  1123. g_NtDllCalls.NtSystemDebugControl
  1124. (SysDbgBreakPoint, NULL, 0, NULL, 0, 0);
  1125. }
  1126. DebugBreak();
  1127. }
  1128. if (Flags != DEBUG_END_REENTRANT)
  1129. {
  1130. DiscardTarget(Flags == DEBUG_END_ACTIVE_TERMINATE ?
  1131. DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE :
  1132. (Flags == DEBUG_END_ACTIVE_DETACH ?
  1133. DEBUG_SESSION_END_SESSION_ACTIVE_DETACH :
  1134. DEBUG_SESSION_END_SESSION_PASSIVE));
  1135. }
  1136. Leave:
  1137. if (Flags != DEBUG_END_REENTRANT)
  1138. {
  1139. LEAVE_ENGINE();
  1140. }
  1141. return Status;
  1142. }
  1143. STDMETHODIMP
  1144. DebugClient::GetExitCode(
  1145. THIS_
  1146. OUT PULONG Code
  1147. )
  1148. {
  1149. ENTER_ENGINE();
  1150. HRESULT Status;
  1151. if (!IS_LIVE_USER_TARGET() || g_CurrentProcess == NULL)
  1152. {
  1153. Status = E_UNEXPECTED;
  1154. }
  1155. else
  1156. {
  1157. Status = ((UserTargetInfo*)g_Target)->m_Services->
  1158. GetProcessExitCode(g_CurrentProcess->FullHandle, Code);
  1159. }
  1160. LEAVE_ENGINE();
  1161. return Status;
  1162. }
  1163. STDMETHODIMP
  1164. DebugClient::DispatchCallbacks(
  1165. THIS_
  1166. IN ULONG Timeout
  1167. )
  1168. {
  1169. DWORD Wait;
  1170. // This constitutes interesting activity.
  1171. m_LastActivity = time(NULL);
  1172. // Do not hold the engine lock while waiting.
  1173. for (;;)
  1174. {
  1175. Wait = WaitForSingleObjectEx(m_DispatchSema, Timeout, TRUE);
  1176. if (Wait == WAIT_OBJECT_0)
  1177. {
  1178. return S_OK;
  1179. }
  1180. else if (Wait == WAIT_TIMEOUT)
  1181. {
  1182. return S_FALSE;
  1183. }
  1184. else if (Wait != WAIT_IO_COMPLETION)
  1185. {
  1186. return WIN32_LAST_STATUS();
  1187. }
  1188. }
  1189. }
  1190. STDMETHODIMP
  1191. DebugClient::ExitDispatch(
  1192. THIS_
  1193. IN PDEBUG_CLIENT Client
  1194. )
  1195. {
  1196. // This method is reentrant.
  1197. if (!ReleaseSemaphore(((DebugClient*)(IDebugClientN*)Client)->
  1198. m_DispatchSema, 1, NULL))
  1199. {
  1200. return WIN32_LAST_STATUS();
  1201. }
  1202. else
  1203. {
  1204. return S_OK;
  1205. }
  1206. }
  1207. STDMETHODIMP
  1208. DebugClient::CreateClient(
  1209. THIS_
  1210. OUT PDEBUG_CLIENT* Client
  1211. )
  1212. {
  1213. HRESULT Status;
  1214. ENTER_ENGINE();
  1215. DebugClient* DbgClient = new DebugClient;
  1216. if (DbgClient == NULL)
  1217. {
  1218. Status = E_OUTOFMEMORY;
  1219. }
  1220. else
  1221. {
  1222. if ((Status = DbgClient->Initialize()) == S_OK)
  1223. {
  1224. DbgClient->Link();
  1225. *Client = (PDEBUG_CLIENT)(IDebugClientN*)DbgClient;
  1226. }
  1227. else
  1228. {
  1229. DbgClient->Release();
  1230. }
  1231. }
  1232. LEAVE_ENGINE();
  1233. return Status;
  1234. }
  1235. STDMETHODIMP
  1236. DebugClient::GetInputCallbacks(
  1237. THIS_
  1238. OUT PDEBUG_INPUT_CALLBACKS* Callbacks
  1239. )
  1240. {
  1241. ENTER_ENGINE();
  1242. *Callbacks = m_InputCb;
  1243. m_InputCb->AddRef();
  1244. LEAVE_ENGINE();
  1245. return S_OK;
  1246. }
  1247. STDMETHODIMP
  1248. DebugClient::SetInputCallbacks(
  1249. THIS_
  1250. IN PDEBUG_INPUT_CALLBACKS Callbacks
  1251. )
  1252. {
  1253. ENTER_ENGINE();
  1254. TRANSFER(m_InputCb, Callbacks);
  1255. LEAVE_ENGINE();
  1256. return S_OK;
  1257. }
  1258. STDMETHODIMP
  1259. DebugClient::GetOutputCallbacks(
  1260. THIS_
  1261. OUT PDEBUG_OUTPUT_CALLBACKS* Callbacks
  1262. )
  1263. {
  1264. ENTER_ENGINE();
  1265. *Callbacks = m_OutputCb;
  1266. m_OutputCb->AddRef();
  1267. LEAVE_ENGINE();
  1268. return S_OK;
  1269. }
  1270. STDMETHODIMP
  1271. DebugClient::SetOutputCallbacks(
  1272. THIS_
  1273. IN PDEBUG_OUTPUT_CALLBACKS Callbacks
  1274. )
  1275. {
  1276. ENTER_ENGINE();
  1277. TRANSFER(m_OutputCb, Callbacks);
  1278. CollectOutMasks();
  1279. LEAVE_ENGINE();
  1280. return S_OK;
  1281. }
  1282. STDMETHODIMP
  1283. DebugClient::GetOutputMask(
  1284. THIS_
  1285. OUT PULONG Mask
  1286. )
  1287. {
  1288. // This method is reentrant.
  1289. *Mask = m_OutMask;
  1290. return S_OK;
  1291. }
  1292. STDMETHODIMP
  1293. DebugClient::SetOutputMask(
  1294. THIS_
  1295. IN ULONG Mask
  1296. )
  1297. {
  1298. // This method is reentrant.
  1299. m_OutMask = Mask;
  1300. CollectOutMasks();
  1301. return S_OK;
  1302. }
  1303. STDMETHODIMP
  1304. DebugClient::GetOtherOutputMask(
  1305. THIS_
  1306. IN PDEBUG_CLIENT Client,
  1307. OUT PULONG Mask
  1308. )
  1309. {
  1310. return Client->GetOutputMask(Mask);
  1311. }
  1312. STDMETHODIMP
  1313. DebugClient::SetOtherOutputMask(
  1314. THIS_
  1315. IN PDEBUG_CLIENT Client,
  1316. IN ULONG Mask
  1317. )
  1318. {
  1319. return Client->SetOutputMask(Mask);
  1320. }
  1321. STDMETHODIMP
  1322. DebugClient::GetOutputWidth(
  1323. THIS_
  1324. OUT PULONG Columns
  1325. )
  1326. {
  1327. ENTER_ENGINE();
  1328. *Columns = m_OutputWidth;
  1329. LEAVE_ENGINE();
  1330. return S_OK;
  1331. }
  1332. STDMETHODIMP
  1333. DebugClient::SetOutputWidth(
  1334. THIS_
  1335. IN ULONG Columns
  1336. )
  1337. {
  1338. if (Columns < 1)
  1339. {
  1340. return E_INVALIDARG;
  1341. }
  1342. ENTER_ENGINE();
  1343. m_OutputWidth = Columns;
  1344. LEAVE_ENGINE();
  1345. return S_OK;
  1346. }
  1347. STDMETHODIMP
  1348. DebugClient::GetOutputLinePrefix(
  1349. THIS_
  1350. OUT OPTIONAL PSTR Buffer,
  1351. IN ULONG BufferSize,
  1352. OUT OPTIONAL PULONG PrefixSize
  1353. )
  1354. {
  1355. HRESULT Status;
  1356. ENTER_ENGINE();
  1357. Status = FillStringBuffer(m_OutputLinePrefix, 0,
  1358. Buffer, BufferSize, PrefixSize);
  1359. LEAVE_ENGINE();
  1360. return S_OK;
  1361. }
  1362. STDMETHODIMP
  1363. DebugClient::SetOutputLinePrefix(
  1364. THIS_
  1365. IN OPTIONAL PCSTR Prefix
  1366. )
  1367. {
  1368. HRESULT Status;
  1369. ENTER_ENGINE();
  1370. ULONG Len;
  1371. Status = ChangeString((PSTR*)&m_OutputLinePrefix, &Len, Prefix);
  1372. LEAVE_ENGINE();
  1373. return Status;
  1374. }
  1375. STDMETHODIMP
  1376. DebugClient::GetIdentity(
  1377. THIS_
  1378. OUT OPTIONAL PSTR Buffer,
  1379. IN ULONG BufferSize,
  1380. OUT OPTIONAL PULONG IdentitySize
  1381. )
  1382. {
  1383. return FillStringBuffer(m_Identity, 0,
  1384. Buffer, BufferSize, IdentitySize);
  1385. }
  1386. STDMETHODIMP
  1387. DebugClient::OutputIdentity(
  1388. THIS_
  1389. IN ULONG OutputControl,
  1390. IN ULONG Flags,
  1391. IN PCSTR Format
  1392. )
  1393. {
  1394. HRESULT Status;
  1395. if (Flags != DEBUG_OUTPUT_IDENTITY_DEFAULT)
  1396. {
  1397. return E_INVALIDARG;
  1398. }
  1399. ENTER_ENGINE();
  1400. OutCtlSave OldCtl;
  1401. if (!PushOutCtl(OutputControl, this, &OldCtl))
  1402. {
  1403. Status = E_INVALIDARG;
  1404. }
  1405. else
  1406. {
  1407. dprintf(Format, m_Identity);
  1408. Status = S_OK;
  1409. PopOutCtl(&OldCtl);
  1410. }
  1411. LEAVE_ENGINE();
  1412. return Status;
  1413. }
  1414. STDMETHODIMP
  1415. DebugClient::GetEventCallbacks(
  1416. THIS_
  1417. OUT PDEBUG_EVENT_CALLBACKS* Callbacks
  1418. )
  1419. {
  1420. ENTER_ENGINE();
  1421. *Callbacks = m_EventCb;
  1422. m_EventCb->AddRef();
  1423. LEAVE_ENGINE();
  1424. return S_OK;
  1425. }
  1426. STDMETHODIMP
  1427. DebugClient::SetEventCallbacks(
  1428. THIS_
  1429. IN PDEBUG_EVENT_CALLBACKS Callbacks
  1430. )
  1431. {
  1432. ENTER_ENGINE();
  1433. HRESULT Status;
  1434. ULONG Interest;
  1435. if (Callbacks != NULL)
  1436. {
  1437. Status = Callbacks->GetInterestMask(&Interest);
  1438. }
  1439. else
  1440. {
  1441. Status = S_OK;
  1442. Interest = 0;
  1443. }
  1444. if (Status == S_OK)
  1445. {
  1446. TRANSFER(m_EventCb, Callbacks);
  1447. m_EventInterest = Interest;
  1448. }
  1449. LEAVE_ENGINE();
  1450. return Status;
  1451. }
  1452. STDMETHODIMP
  1453. DebugClient::FlushCallbacks(
  1454. THIS
  1455. )
  1456. {
  1457. ::FlushCallbacks();
  1458. return S_OK;
  1459. }
  1460. STDMETHODIMP
  1461. DebugClient::WriteDumpFile2(
  1462. THIS_
  1463. IN PCSTR DumpFile,
  1464. IN ULONG Qualifier,
  1465. IN ULONG FormatFlags,
  1466. IN OPTIONAL PCSTR Comment
  1467. )
  1468. {
  1469. HRESULT Status;
  1470. if ((IS_KERNEL_TARGET() &&
  1471. (Qualifier < DEBUG_KERNEL_SMALL_DUMP ||
  1472. Qualifier > DEBUG_KERNEL_FULL_DUMP)) ||
  1473. (IS_USER_TARGET() &&
  1474. (Qualifier < DEBUG_USER_WINDOWS_SMALL_DUMP ||
  1475. Qualifier > DEBUG_USER_WINDOWS_DUMP)))
  1476. {
  1477. return E_INVALIDARG;
  1478. }
  1479. ENTER_ENGINE();
  1480. Status = ::WriteDumpFile(DumpFile, Qualifier, FormatFlags, Comment);
  1481. LEAVE_ENGINE();
  1482. return Status;
  1483. }
  1484. STDMETHODIMP
  1485. DebugClient::AddDumpInformationFile(
  1486. THIS_
  1487. IN PCSTR InfoFile,
  1488. IN ULONG Type
  1489. )
  1490. {
  1491. HRESULT Status;
  1492. if (Type != DEBUG_DUMP_FILE_PAGE_FILE_DUMP)
  1493. {
  1494. return E_INVALIDARG;
  1495. }
  1496. ENTER_ENGINE();
  1497. // This method must be called before OpenDumpFile.
  1498. if (IS_TARGET_SET())
  1499. {
  1500. Status = E_UNEXPECTED;
  1501. }
  1502. else
  1503. {
  1504. Status = AddDumpInfoFile(InfoFile, DUMP_INFO_PAGE_FILE,
  1505. 64 * 1024);
  1506. }
  1507. LEAVE_ENGINE();
  1508. return Status;
  1509. }
  1510. STDMETHODIMP
  1511. DebugClient::EndProcessServer(
  1512. THIS_
  1513. IN ULONG64 Server
  1514. )
  1515. {
  1516. return ((IUserDebugServices*)Server)->
  1517. Uninitialize(TRUE);
  1518. }
  1519. STDMETHODIMP
  1520. DebugClient::WaitForProcessServerEnd(
  1521. THIS_
  1522. IN ULONG Timeout
  1523. )
  1524. {
  1525. HRESULT Status;
  1526. ENTER_ENGINE();
  1527. if (g_UserServicesUninitialized)
  1528. {
  1529. Status = S_OK;
  1530. }
  1531. else
  1532. {
  1533. //
  1534. // This could be done with an event to get true
  1535. // waiting but precision isn't that important.
  1536. //
  1537. HRESULT Status = S_FALSE;
  1538. while (Timeout)
  1539. {
  1540. ULONG UseTimeout;
  1541. UseTimeout = min(1000, Timeout);
  1542. Sleep(UseTimeout);
  1543. if (g_UserServicesUninitialized)
  1544. {
  1545. Status = S_OK;
  1546. break;
  1547. }
  1548. if (Timeout != INFINITE)
  1549. {
  1550. Timeout -= UseTimeout;
  1551. }
  1552. }
  1553. }
  1554. LEAVE_ENGINE();
  1555. return Status;
  1556. }
  1557. STDMETHODIMP
  1558. DebugClient::IsKernelDebuggerEnabled(
  1559. THIS
  1560. )
  1561. {
  1562. HRESULT Status;
  1563. ENTER_ENGINE();
  1564. if (g_DebuggerPlatformId != VER_PLATFORM_WIN32_NT)
  1565. {
  1566. Status = E_UNEXPECTED;
  1567. }
  1568. else
  1569. {
  1570. NTSTATUS NtStatus;
  1571. SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo;
  1572. NtStatus = g_NtDllCalls.
  1573. NtQuerySystemInformation(SystemKernelDebuggerInformation,
  1574. &KdInfo, sizeof(KdInfo), NULL);
  1575. if (NT_SUCCESS(NtStatus))
  1576. {
  1577. Status = KdInfo.KernelDebuggerEnabled ? S_OK : S_FALSE;
  1578. }
  1579. else
  1580. {
  1581. Status = HRESULT_FROM_NT(NtStatus);
  1582. }
  1583. }
  1584. LEAVE_ENGINE();
  1585. return Status;
  1586. }
  1587. STDMETHODIMP
  1588. DebugClient::TerminateCurrentProcess(
  1589. THIS
  1590. )
  1591. {
  1592. HRESULT Status;
  1593. ENTER_ENGINE();
  1594. Status = SeparateCurrentProcess(SEP_TERMINATE, NULL);
  1595. LEAVE_ENGINE();
  1596. return Status;
  1597. }
  1598. STDMETHODIMP
  1599. DebugClient::DetachCurrentProcess(
  1600. THIS
  1601. )
  1602. {
  1603. HRESULT Status;
  1604. ENTER_ENGINE();
  1605. Status = SeparateCurrentProcess(SEP_DETACH, NULL);
  1606. LEAVE_ENGINE();
  1607. return Status;
  1608. }
  1609. STDMETHODIMP
  1610. DebugClient::AbandonCurrentProcess(
  1611. THIS
  1612. )
  1613. {
  1614. HRESULT Status;
  1615. ENTER_ENGINE();
  1616. Status = SeparateCurrentProcess(SEP_ABANDON, NULL);
  1617. LEAVE_ENGINE();
  1618. return Status;
  1619. }
  1620. HRESULT
  1621. DebugClient::Initialize(void)
  1622. {
  1623. m_DispatchSema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
  1624. if (m_DispatchSema == NULL)
  1625. {
  1626. return WIN32_LAST_STATUS();
  1627. }
  1628. if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
  1629. GetCurrentProcess(), &m_Thread,
  1630. 0, FALSE, DUPLICATE_SAME_ACCESS))
  1631. {
  1632. return WIN32_LAST_STATUS();
  1633. }
  1634. // If we're requesting input allow this client
  1635. // to return input immediately.
  1636. if (g_InputSizeRequested > 0)
  1637. {
  1638. m_InputSequence = 1;
  1639. }
  1640. return S_OK;
  1641. }
  1642. void
  1643. DebugClient::InitializePrimary(void)
  1644. {
  1645. m_Flags |= CLIENT_PRIMARY;
  1646. if ((m_Flags & CLIENT_REMOTE) == 0)
  1647. {
  1648. // Can't call GetClientIdentity here as it uses
  1649. // many system APIs and therefore can cause trouble
  1650. // when debugging system processes such as LSA.
  1651. strcpy(m_Identity, "HostMachine\\HostUser");
  1652. }
  1653. m_LastActivity = time(NULL);
  1654. }
  1655. void
  1656. DebugClient::Link(void)
  1657. {
  1658. EnterCriticalSection(&g_QuickLock);
  1659. // Keep list grouped by thread ID.
  1660. DebugClient* Cur;
  1661. for (Cur = g_Clients; Cur != NULL; Cur = Cur->m_Next)
  1662. {
  1663. if (Cur->m_ThreadId == m_ThreadId)
  1664. {
  1665. break;
  1666. }
  1667. }
  1668. m_Prev = Cur;
  1669. if (Cur != NULL)
  1670. {
  1671. m_Next = Cur->m_Next;
  1672. Cur->m_Next = this;
  1673. }
  1674. else
  1675. {
  1676. // No ID match so just put it in the front.
  1677. m_Next = g_Clients;
  1678. g_Clients = this;
  1679. }
  1680. if (m_Next != NULL)
  1681. {
  1682. m_Next->m_Prev = this;
  1683. }
  1684. m_Flags |= CLIENT_IN_LIST;
  1685. LeaveCriticalSection(&g_QuickLock);
  1686. }
  1687. void
  1688. DebugClient::Unlink(void)
  1689. {
  1690. EnterCriticalSection(&g_QuickLock);
  1691. m_Flags &= ~CLIENT_IN_LIST;
  1692. if (m_Next != NULL)
  1693. {
  1694. m_Next->m_Prev = m_Prev;
  1695. }
  1696. if (m_Prev != NULL)
  1697. {
  1698. m_Prev->m_Next = m_Next;
  1699. }
  1700. else
  1701. {
  1702. g_Clients = m_Next;
  1703. }
  1704. LeaveCriticalSection(&g_QuickLock);
  1705. }
  1706. //----------------------------------------------------------------------------
  1707. //
  1708. // Initialize/uninitalize functions.
  1709. //
  1710. //----------------------------------------------------------------------------
  1711. ULONG NTAPI
  1712. Win9xDbgPrompt( char *Prompt, char *buffer, ULONG cb)
  1713. {
  1714. return gets(buffer) ? strlen(buffer) : 0;
  1715. }
  1716. ULONG __cdecl
  1717. Win9xDbgPrint( char *Text, ... )
  1718. {
  1719. char Temp[OUT_BUFFER_SIZE];
  1720. va_list valist;
  1721. va_start(valist, Text);
  1722. wvsprintf(Temp, Text, valist);
  1723. OutputDebugString(Temp);
  1724. va_end(valist);
  1725. return 0;
  1726. }
  1727. HRESULT
  1728. OneTimeInitialization(void)
  1729. {
  1730. static BOOL Init = FALSE;
  1731. if (Init)
  1732. {
  1733. return S_OK;
  1734. }
  1735. // This function is called exactly once at the first
  1736. // DebugCreate for a process. It should perform any
  1737. // global one-time initialization necessary.
  1738. // Nothing initialized here will be explicitly cleaned
  1739. // up, instead it should all be the kind of thing
  1740. // that can wait for process cleanup.
  1741. HRESULT Status = S_OK;
  1742. // These sizes are hard-coded into the remoting script
  1743. // so verify them to ensure no mismatch.
  1744. C_ASSERT(sizeof(DEBUG_BREAKPOINT_PARAMETERS) == 56);
  1745. C_ASSERT(sizeof(DEBUG_STACK_FRAME) == 128);
  1746. C_ASSERT(sizeof(DEBUG_VALUE) == 32);
  1747. C_ASSERT(sizeof(DEBUG_REGISTER_DESCRIPTION) == 32);
  1748. C_ASSERT(sizeof(DEBUG_SYMBOL_PARAMETERS) == 32);
  1749. C_ASSERT(sizeof(DEBUG_MODULE_PARAMETERS) == 64);
  1750. C_ASSERT(sizeof(DEBUG_SPECIFIC_FILTER_PARAMETERS) == 20);
  1751. C_ASSERT(sizeof(DEBUG_EXCEPTION_FILTER_PARAMETERS) == 24);
  1752. C_ASSERT(sizeof(EXCEPTION_RECORD64) == 152);
  1753. C_ASSERT(sizeof(MEMORY_BASIC_INFORMATION64) == 48);
  1754. SYSTEM_INFO SystemInfo;
  1755. GetSystemInfo(&SystemInfo);
  1756. g_DumpCacheGranularity = SystemInfo.dwAllocationGranularity;
  1757. // Get the debugger host system's OS type. Note that
  1758. // this may be different from g_TargetPlatformId, which
  1759. // is the OS type of the debug target.
  1760. OSVERSIONINFO OsVersionInfo;
  1761. OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
  1762. if (!GetVersionEx(&OsVersionInfo))
  1763. {
  1764. Status = WIN32_LAST_STATUS();
  1765. goto EH_Fail;
  1766. }
  1767. g_DebuggerPlatformId = OsVersionInfo.dwPlatformId;
  1768. if (g_DebuggerPlatformId == VER_PLATFORM_WIN32_NT)
  1769. {
  1770. if ((Status = InitDynamicCalls(&g_NtDllCallsDesc)) != S_OK)
  1771. {
  1772. goto EH_Fail;
  1773. }
  1774. }
  1775. else
  1776. {
  1777. g_NtDllCalls.DbgPrint = Win9xDbgPrint;
  1778. g_NtDllCalls.DbgPrompt = Win9xDbgPrompt;
  1779. }
  1780. if ((Status = InitDynamicCalls(&g_Kernel32CallsDesc)) != S_OK)
  1781. {
  1782. goto EH_Fail;
  1783. }
  1784. if ((Status = InitDynamicCalls(&g_Advapi32CallsDesc)) != S_OK)
  1785. {
  1786. goto EH_Fail;
  1787. }
  1788. ULONG SvcFlags;
  1789. if ((Status = g_LiveUserDebugServices.Initialize(&SvcFlags)) != S_OK)
  1790. {
  1791. goto EH_Fail;
  1792. }
  1793. g_InputEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1794. if (g_InputEvent == NULL)
  1795. {
  1796. Status = WIN32_LAST_STATUS();
  1797. goto EH_Fail;
  1798. }
  1799. g_EventStatusWaiting = CreateEvent(NULL, FALSE, FALSE, NULL);
  1800. if (g_EventStatusWaiting == NULL)
  1801. {
  1802. Status = WIN32_LAST_STATUS();
  1803. goto EH_InputEvent;
  1804. }
  1805. g_EventStatusReady = CreateEvent(NULL, FALSE, FALSE, NULL);
  1806. if (g_EventStatusReady == NULL)
  1807. {
  1808. Status = WIN32_LAST_STATUS();
  1809. goto EH_EventStatusWaiting;
  1810. }
  1811. g_SleepPidEvent = CreatePidEvent(GetCurrentProcessId(), CREATE_NEW);
  1812. if (g_SleepPidEvent == NULL)
  1813. {
  1814. Status = E_FAIL;
  1815. goto EH_EventStatusReady;
  1816. }
  1817. if ((Status = InitializeAllAccessSecObj()) != S_OK)
  1818. {
  1819. goto EH_SleepPidEvent;
  1820. }
  1821. __try
  1822. {
  1823. InitializeCriticalSection(&g_QuickLock);
  1824. }
  1825. __except(EXCEPTION_EXECUTE_HANDLER)
  1826. {
  1827. Status = HRESULT_FROM_NT(GetExceptionCode());
  1828. goto EH_AllAccessObj;
  1829. }
  1830. __try
  1831. {
  1832. InitializeCriticalSection(&g_EngineLock);
  1833. }
  1834. __except(EXCEPTION_EXECUTE_HANDLER)
  1835. {
  1836. Status = HRESULT_FROM_NT(GetExceptionCode());
  1837. goto EH_QuickLock;
  1838. }
  1839. g_SrcPath = getenv("_NT_SOURCE_PATH");
  1840. if (g_SrcPath != NULL)
  1841. {
  1842. // This path must be in allocated space.
  1843. // If this fails it's not catastrophic.
  1844. g_SrcPath = _strdup(g_SrcPath);
  1845. }
  1846. // Initialize default machines. This is to make machine
  1847. // information available early for querying. Things
  1848. // will get reinitialized every time the true target
  1849. // machine type is discovered.
  1850. InitializeMachines(IMAGE_FILE_MACHINE_UNKNOWN);
  1851. // Set default symbol options.
  1852. SymSetOptions(g_SymOptions);
  1853. if (getenv("KDQUIET"))
  1854. {
  1855. g_QuietMode = TRUE;
  1856. }
  1857. else
  1858. {
  1859. g_QuietMode = FALSE;
  1860. }
  1861. ReadDebugOptions(TRUE, NULL);
  1862. PCSTR Env;
  1863. #if DBG
  1864. // Get default out mask from environment variables.
  1865. Env = getenv("DBGENG_OUT_MASK");
  1866. if (Env != NULL)
  1867. {
  1868. ULONG Mask = strtoul(Env, NULL, 0);
  1869. g_EnvOutMask |= Mask;
  1870. g_LogMask |= Mask;
  1871. }
  1872. #endif
  1873. Env = getenv("_NT_DEBUG_HISTORY_SIZE");
  1874. if (Env != NULL)
  1875. {
  1876. g_OutHistoryRequestedSize = atoi(Env) * 1024;
  1877. }
  1878. InitKdFileAssoc();
  1879. Init = TRUE;
  1880. return S_OK;
  1881. EH_QuickLock:
  1882. DeleteCriticalSection(&g_QuickLock);
  1883. EH_AllAccessObj:
  1884. DeleteAllAccessSecObj();
  1885. EH_SleepPidEvent:
  1886. CloseHandle(g_SleepPidEvent);
  1887. g_SleepPidEvent = NULL;
  1888. EH_EventStatusReady:
  1889. CloseHandle(g_EventStatusReady);
  1890. g_EventStatusReady = NULL;
  1891. EH_EventStatusWaiting:
  1892. CloseHandle(g_EventStatusWaiting);
  1893. g_EventStatusWaiting = NULL;
  1894. EH_InputEvent:
  1895. CloseHandle(g_InputEvent);
  1896. g_InputEvent = NULL;
  1897. EH_Fail:
  1898. return Status;
  1899. }
  1900. STDAPI
  1901. DebugConnect(
  1902. IN PCSTR RemoteOptions,
  1903. IN REFIID InterfaceId,
  1904. OUT PVOID* Interface
  1905. )
  1906. {
  1907. HRESULT Status;
  1908. if ((Status = OneTimeInitialization()) != S_OK)
  1909. {
  1910. return Status;
  1911. }
  1912. IUnknown* Client;
  1913. if ((Status = DbgRpcConnectServer(RemoteOptions, &IID_IDebugClient,
  1914. &Client)) != S_OK)
  1915. {
  1916. return Status;
  1917. }
  1918. Status = Client->QueryInterface(InterfaceId, Interface);
  1919. Client->Release();
  1920. return Status;
  1921. }
  1922. STDAPI
  1923. DebugCreate(
  1924. IN REFIID InterfaceId,
  1925. OUT PVOID* Interface
  1926. )
  1927. {
  1928. HRESULT Status;
  1929. if ((Status = OneTimeInitialization()) != S_OK)
  1930. {
  1931. return Status;
  1932. }
  1933. DebugClient* Client = new DebugClient;
  1934. if (Client == NULL)
  1935. {
  1936. Status = E_OUTOFMEMORY;
  1937. }
  1938. else
  1939. {
  1940. if ((Status = Client->Initialize()) == S_OK)
  1941. {
  1942. Status = Client->QueryInterface(InterfaceId, Interface);
  1943. if (Status == S_OK)
  1944. {
  1945. Client->Link();
  1946. }
  1947. }
  1948. Client->Release();
  1949. }
  1950. return Status;
  1951. }
  1952. HRESULT
  1953. LiveKernelInitialize(DebugClient* Client, ULONG Qual, PCSTR Options)
  1954. {
  1955. HRESULT Status;
  1956. if (g_SessionThread != 0)
  1957. {
  1958. // A session is already active.
  1959. return E_UNEXPECTED;
  1960. }
  1961. if ((Status = InitNtCmd(Client)) != S_OK)
  1962. {
  1963. return Status;
  1964. }
  1965. g_TargetClass = DEBUG_CLASS_KERNEL;
  1966. g_TargetClassQualifier = Qual;
  1967. if (Qual == DEBUG_KERNEL_CONNECTION)
  1968. {
  1969. g_Target = &g_ConnLiveKernelTarget;
  1970. }
  1971. else if (Qual == DEBUG_KERNEL_LOCAL)
  1972. {
  1973. //
  1974. // We need to get the debug privilege to enable local kernel debugging
  1975. //
  1976. if ((Status = EnableDebugPrivilege()) != S_OK)
  1977. {
  1978. ErrOut("Unable to enable debug privilege, %s\n \"%s\"\n",
  1979. FormatStatusCode(Status), FormatStatus(Status));
  1980. return Status;
  1981. }
  1982. g_Target = &g_LocalLiveKernelTarget;
  1983. }
  1984. else
  1985. {
  1986. g_Target = &g_ExdiLiveKernelTarget;
  1987. }
  1988. // These options only need to stay valid until Initialize.
  1989. ((LiveKernelTargetInfo*)g_Target)->m_ConnectOptions = Options;
  1990. Status = InitializeTarget();
  1991. if (Status != S_OK)
  1992. {
  1993. return Status;
  1994. }
  1995. if (IS_REMOTE_KERNEL_TARGET())
  1996. {
  1997. //
  1998. // Check environment variables for configuration settings
  1999. //
  2000. PCHAR CacheEnv = getenv("_NT_DEBUG_CACHE_SIZE");
  2001. if (CacheEnv != NULL)
  2002. {
  2003. g_VirtualCache.m_MaxSize = atol(CacheEnv);
  2004. g_PhysicalCache.m_MaxSize = g_VirtualCache.m_MaxSize;
  2005. }
  2006. g_VirtualCache.m_DecodePTEs = TRUE;
  2007. }
  2008. // Other target configuration information is retrieved in various
  2009. // places during KD init.
  2010. dprintf("%s", g_WinKernelVersionString);
  2011. if (IS_CONN_KERNEL_TARGET())
  2012. {
  2013. dprintf("Waiting to reconnect...\n");
  2014. }
  2015. return S_OK;
  2016. }
  2017. HRESULT
  2018. UserInitialize(DebugClient* Client, ULONG64 Server)
  2019. {
  2020. HRESULT Status;
  2021. PUSER_DEBUG_SERVICES Services;
  2022. ULONG Qual;
  2023. if ((Status = InitNtCmd(Client)) != S_OK)
  2024. {
  2025. return Status;
  2026. }
  2027. if (Server == 0)
  2028. {
  2029. Services = new LiveUserDebugServices(FALSE);
  2030. if (Services == NULL)
  2031. {
  2032. return E_OUTOFMEMORY;
  2033. }
  2034. Qual = DEBUG_USER_WINDOWS_PROCESS;
  2035. g_Target = &g_LocalUserTarget;
  2036. }
  2037. else
  2038. {
  2039. Services = (PUSER_DEBUG_SERVICES)Server;
  2040. Services->AddRef();
  2041. Qual = DEBUG_USER_WINDOWS_PROCESS_SERVER;
  2042. g_Target = &g_RemoteUserTarget;
  2043. }
  2044. if ((Status = Services->
  2045. Initialize(&((UserTargetInfo*)g_Target)->m_ServiceFlags)) == S_OK)
  2046. {
  2047. g_TargetClass = DEBUG_CLASS_USER_WINDOWS;
  2048. g_TargetClassQualifier = Qual;
  2049. ((UserTargetInfo*)g_Target)->m_Services = Services;
  2050. Status = InitializeTarget();
  2051. if (Status == S_OK)
  2052. {
  2053. g_VirtualCache.m_DecodePTEs = FALSE;
  2054. dprintf("%s", g_WinUserVersionString);
  2055. return S_OK;
  2056. }
  2057. }
  2058. // Error path
  2059. if (Qual == DEBUG_USER_WINDOWS_PROCESS)
  2060. {
  2061. delete(Services);
  2062. }
  2063. return Status;
  2064. }
  2065. HRESULT
  2066. InitializeTarget(void)
  2067. {
  2068. HRESULT Status;
  2069. DBG_ASSERT(g_SessionThread == 0);
  2070. g_SessionThread = GetCurrentThreadId();
  2071. if ((Status = g_Target->Initialize()) != S_OK)
  2072. {
  2073. DiscardTarget(DEBUG_SESSION_END_SESSION_PASSIVE);
  2074. }
  2075. return Status;
  2076. }
  2077. HRESULT
  2078. InitializeMachine(ULONG Machine)
  2079. {
  2080. HRESULT Status;
  2081. // Dump initialization initializes machines so
  2082. // don't reinitialize them.
  2083. if (g_TargetMachineType == IMAGE_FILE_MACHINE_UNKNOWN)
  2084. {
  2085. InitializeMachines(Machine);
  2086. }
  2087. SetEffMachine(Machine, TRUE);
  2088. // Executing machine is not set as code execution
  2089. // status is unknown. The executing machine will
  2090. // be updated when a wait completes.
  2091. Status = BreakpointInit();
  2092. if (Status != S_OK)
  2093. {
  2094. InitializeMachines(IMAGE_FILE_MACHINE_UNKNOWN);
  2095. SetEffMachine(IMAGE_FILE_MACHINE_UNKNOWN, TRUE);
  2096. return Status;
  2097. }
  2098. // X86 prefers registers to be displayed at the prompt unless
  2099. // we're on a kernel connection where it would force a context
  2100. // load all the time.
  2101. if (Machine == IMAGE_FILE_MACHINE_I386 &&
  2102. (IS_DUMP_TARGET() || IS_USER_TARGET()))
  2103. {
  2104. g_OciOutputRegs = TRUE;
  2105. }
  2106. g_MachineInitialized = TRUE;
  2107. //
  2108. // Load extensions after this is set so Extensions can query information
  2109. // during machine initialization
  2110. //
  2111. LoadMachineExtensions();
  2112. // Now that all initialization is done, send initial
  2113. // notification that a debuggee exists.
  2114. NotifySessionStatus(DEBUG_SESSION_ACTIVE);
  2115. NotifyChangeDebuggeeState(DEBUG_CDS_ALL, 0);
  2116. NotifyExtensions(DEBUG_NOTIFY_SESSION_ACTIVE, 0);
  2117. return S_OK;
  2118. }
  2119. void
  2120. DiscardTarget(ULONG Reason)
  2121. {
  2122. if (g_MachineInitialized)
  2123. {
  2124. DiscardMachine(Reason);
  2125. }
  2126. g_Target->Uninitialize();
  2127. g_SessionThread = 0;
  2128. g_TargetClass = DEBUG_CLASS_UNINITIALIZED;
  2129. g_Target = &g_UnexpectedTarget;
  2130. g_TargetClassQualifier = 0;
  2131. g_ThreadToResume = NULL;
  2132. g_GlobalProcOptions = 0;
  2133. g_NextProcessUserId = 0;
  2134. g_EngStatus = 0;
  2135. g_EngDefer = 0;
  2136. g_EngErr = 0;
  2137. g_OutHistRead = NULL;
  2138. g_OutHistWrite = NULL;
  2139. g_OutHistoryMask = 0;
  2140. g_OutHistoryUsed = 0;
  2141. }
  2142. void
  2143. DiscardMachine(ULONG Reason)
  2144. {
  2145. g_MachineInitialized = FALSE;
  2146. g_CmdState = 'i';
  2147. g_ExecutionStatusRequest = DEBUG_STATUS_NO_CHANGE;
  2148. PPROCESS_INFO Process;
  2149. for (Process = g_ProcessHead;
  2150. Process != NULL;
  2151. Process = Process->Next)
  2152. {
  2153. Process->Exited = TRUE;
  2154. }
  2155. // Breakpoint removal must wait until all processes are marked as
  2156. // exited to avoid asserts on breakpoints that are inserted.
  2157. RemoveAllBreakpoints(Reason);
  2158. DeleteExitedInfos();
  2159. DiscardPendingProcesses();
  2160. g_NumUnloadedModules = 0;
  2161. g_VirtualCache.SetForceDecodePtes(FALSE);
  2162. DiscardLastEvent();
  2163. ClearEventLog();
  2164. ZeroMemory(&g_LastEventInfo, sizeof(g_LastEventInfo));
  2165. g_EventProcess = NULL;
  2166. g_EventThread = NULL;
  2167. g_CurrentProcess = NULL;
  2168. ResetImplicitData();
  2169. g_OciOutputRegs = FALSE;
  2170. DbgKdApi64 = FALSE;
  2171. ZeroMemory(&KdDebuggerData, sizeof(KdDebuggerData));
  2172. g_KdMaxPacketType = 0;
  2173. g_KdMaxStateChange = 0;
  2174. g_KdMaxManipulate = 0;
  2175. g_SystemVersion = SVER_INVALID;
  2176. g_ActualSystemVersion = SVER_INVALID;
  2177. g_TargetCheckedBuild = 0;
  2178. g_TargetBuildNumber = 0;
  2179. g_TargetServicePackString[0] = 0;
  2180. g_TargetServicePackNumber = 0;
  2181. g_TargetPlatformId = 0;
  2182. g_TargetBuildLabName[0] = 0;
  2183. InitializeMachines(IMAGE_FILE_MACHINE_UNKNOWN);
  2184. g_TargetExecMachine = IMAGE_FILE_MACHINE_UNKNOWN;
  2185. SetEffMachine(IMAGE_FILE_MACHINE_UNKNOWN, FALSE);
  2186. g_TargetNumberProcessors = 0;
  2187. EXTDLL* Ext = g_ExtDlls;
  2188. EXTDLL* ExtNext;
  2189. while (Ext != NULL)
  2190. {
  2191. ExtNext = Ext->Next;
  2192. if (!Ext->UserLoaded)
  2193. {
  2194. UnloadExtensionDll(Ext);
  2195. }
  2196. else
  2197. {
  2198. DeferExtensionDll(Ext);
  2199. }
  2200. Ext = ExtNext;
  2201. }
  2202. free(g_ExtensionSearchPath);
  2203. g_ExtensionSearchPath = NULL;
  2204. g_WatchBeginCurFunc = 1;
  2205. g_WatchEndCurFunc = 0;
  2206. g_WatchTrace = FALSE;
  2207. g_WatchInitialSP = 0;
  2208. g_StepTraceInRangeStart = (ULONG64)-1;
  2209. g_StepTraceInRangeEnd = 0;
  2210. g_EngStatus &= ~(ENG_STATUS_SUSPENDED |
  2211. ENG_STATUS_BREAKPOINTS_INSERTED |
  2212. ENG_STATUS_PROCESSES_ADDED |
  2213. ENG_STATUS_STATE_CHANGED |
  2214. ENG_STATUS_MODULES_LOADED |
  2215. ENG_STATUS_PREPARED_FOR_CALLS |
  2216. ENG_STATUS_NO_AUTO_WAIT |
  2217. ENG_STATUS_PENDING_BREAK_IN |
  2218. ENG_STATUS_AT_INITIAL_BREAK |
  2219. ENG_STATUS_AT_INITIAL_MODULE_LOAD |
  2220. ENG_STATUS_EXIT_CURRENT_WAIT |
  2221. ENG_STATUS_USER_INTERRUPT);
  2222. g_EngDefer &= ~(ENG_DEFER_EXCEPTION_HANDLING |
  2223. ENG_DEFER_UPDATE_CONTROL_SET |
  2224. ENG_DEFER_HARDWARE_TRACING |
  2225. ENG_DEFER_OUTPUT_CURRENT_INFO |
  2226. ENG_DEFER_CONTINUE_EVENT);
  2227. g_EngErr &= ~(ENG_ERR_DEBUGGER_DATA);
  2228. g_SwitchProcessor = 0;
  2229. g_LastSelector = -1;
  2230. g_RegContextThread = NULL;
  2231. g_RegContextProcessor = -1;
  2232. ULONG i;
  2233. for (i = 0; i < MACHIDX_COUNT; i++)
  2234. {
  2235. if (g_AllMachines[i] != NULL)
  2236. {
  2237. g_AllMachines[i]->InvalidateContext();
  2238. }
  2239. }
  2240. if (IS_CONN_KERNEL_TARGET())
  2241. {
  2242. g_DbgKdTransport->Restart();
  2243. }
  2244. ::FlushCallbacks();
  2245. // Send final notification that debuggee is gone.
  2246. // This must be done after all the work as the lock
  2247. // will be suspended during the callbacks, allowing
  2248. // other threads in, so the state must be consistent.
  2249. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  2250. DEBUG_STATUS_NO_DEBUGGEE, TRUE);
  2251. NotifySessionStatus(Reason);
  2252. NotifyExtensions(DEBUG_NOTIFY_SESSION_INACTIVE, 0);
  2253. }
  2254. //----------------------------------------------------------------------------
  2255. //
  2256. // DbgRpcClientObject implementation.
  2257. //
  2258. //----------------------------------------------------------------------------
  2259. HRESULT
  2260. DebugClient::Initialize(PSTR Identity, PVOID* Interface)
  2261. {
  2262. HRESULT Status;
  2263. m_Flags |= CLIENT_REMOTE;
  2264. if ((Status = Initialize()) != S_OK)
  2265. {
  2266. return Status;
  2267. }
  2268. strcpy(m_Identity, Identity);
  2269. *Interface = (IDebugClientN*)this;
  2270. return S_OK;
  2271. }
  2272. void
  2273. DebugClient::Finalize(void)
  2274. {
  2275. Link();
  2276. // Take a reference on this object for the RPC client
  2277. // thread to hold.
  2278. AddRef();
  2279. }
  2280. void
  2281. DebugClient::Uninitialize(void)
  2282. {
  2283. // Directly destroy the client object rather than releasing
  2284. // as the remote client may have exited without politely
  2285. // cleaning up references.
  2286. Destroy();
  2287. }