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.

2380 lines
68 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Callback notification routines.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. //----------------------------------------------------------------------------
  10. //
  11. // APC support for dispatching event callbacks on the proper thread.
  12. //
  13. //----------------------------------------------------------------------------
  14. struct AnyApcData
  15. {
  16. AnyApcData(ULONG Mask, PCSTR Name)
  17. {
  18. m_Mask = Mask;
  19. m_Name = Name;
  20. }
  21. ULONG m_Mask;
  22. PCSTR m_Name;
  23. virtual ULONG Dispatch(DebugClient* Client) = 0;
  24. };
  25. struct BreakpointEventApcData : public AnyApcData
  26. {
  27. BreakpointEventApcData()
  28. : AnyApcData(DEBUG_EVENT_BREAKPOINT,
  29. "IDebugEventCallbacks::Breakpoint")
  30. {
  31. }
  32. Breakpoint* m_Bp;
  33. virtual ULONG Dispatch(DebugClient* Client)
  34. {
  35. if ((m_Bp->m_Flags & DEBUG_BREAKPOINT_ADDER_ONLY) == 0 ||
  36. Client == m_Bp->m_Adder)
  37. {
  38. return Client->m_EventCb->
  39. Breakpoint(m_Bp);
  40. }
  41. else
  42. {
  43. return DEBUG_STATUS_NO_CHANGE;
  44. }
  45. }
  46. };
  47. struct ExceptionEventApcData : public AnyApcData
  48. {
  49. ExceptionEventApcData()
  50. : AnyApcData(DEBUG_EVENT_EXCEPTION,
  51. "IDebugEventCallbacks::Exception")
  52. {
  53. }
  54. PEXCEPTION_RECORD64 m_Record;
  55. ULONG m_FirstChance;
  56. virtual ULONG Dispatch(DebugClient* Client)
  57. {
  58. return Client->m_EventCb->
  59. Exception(m_Record, m_FirstChance);
  60. }
  61. };
  62. struct CreateThreadEventApcData : public AnyApcData
  63. {
  64. CreateThreadEventApcData()
  65. : AnyApcData(DEBUG_EVENT_CREATE_THREAD,
  66. "IDebugEventCallbacks::CreateThread")
  67. {
  68. }
  69. ULONG64 m_Handle;
  70. ULONG64 m_DataOffset;
  71. ULONG64 m_StartOffset;
  72. virtual ULONG Dispatch(DebugClient* Client)
  73. {
  74. return Client->m_EventCb->
  75. CreateThread(m_Handle, m_DataOffset, m_StartOffset);
  76. }
  77. };
  78. struct ExitThreadEventApcData : public AnyApcData
  79. {
  80. ExitThreadEventApcData()
  81. : AnyApcData(DEBUG_EVENT_EXIT_THREAD,
  82. "IDebugEventCallbacks::ExitThread")
  83. {
  84. }
  85. ULONG m_ExitCode;
  86. virtual ULONG Dispatch(DebugClient* Client)
  87. {
  88. return Client->m_EventCb->
  89. ExitThread(m_ExitCode);
  90. }
  91. };
  92. struct CreateProcessEventApcData : public AnyApcData
  93. {
  94. CreateProcessEventApcData()
  95. : AnyApcData(DEBUG_EVENT_CREATE_PROCESS,
  96. "IDebugEventCallbacks::CreateProcess")
  97. {
  98. }
  99. ULONG64 m_ImageFileHandle;
  100. ULONG64 m_Handle;
  101. ULONG64 m_BaseOffset;
  102. ULONG m_ModuleSize;
  103. PCSTR m_ModuleName;
  104. PCSTR m_ImageName;
  105. ULONG m_CheckSum;
  106. ULONG m_TimeDateStamp;
  107. ULONG64 m_InitialThreadHandle;
  108. ULONG64 m_ThreadDataOffset;
  109. ULONG64 m_StartOffset;
  110. virtual ULONG Dispatch(DebugClient* Client)
  111. {
  112. return Client->m_EventCb->
  113. CreateProcess(m_ImageFileHandle, m_Handle, m_BaseOffset,
  114. m_ModuleSize, m_ModuleName, m_ImageName,
  115. m_CheckSum, m_TimeDateStamp, m_InitialThreadHandle,
  116. m_ThreadDataOffset, m_StartOffset);
  117. }
  118. };
  119. struct ExitProcessEventApcData : public AnyApcData
  120. {
  121. ExitProcessEventApcData()
  122. : AnyApcData(DEBUG_EVENT_EXIT_PROCESS,
  123. "IDebugEventCallbacks::ExitProcess")
  124. {
  125. }
  126. ULONG m_ExitCode;
  127. virtual ULONG Dispatch(DebugClient* Client)
  128. {
  129. return Client->m_EventCb->
  130. ExitProcess(m_ExitCode);
  131. }
  132. };
  133. struct LoadModuleEventApcData : public AnyApcData
  134. {
  135. LoadModuleEventApcData()
  136. : AnyApcData(DEBUG_EVENT_LOAD_MODULE,
  137. "IDebugEventCallbacks::LoadModule")
  138. {
  139. }
  140. ULONG64 m_ImageFileHandle;
  141. ULONG64 m_BaseOffset;
  142. ULONG m_ModuleSize;
  143. PCSTR m_ModuleName;
  144. PCSTR m_ImageName;
  145. ULONG m_CheckSum;
  146. ULONG m_TimeDateStamp;
  147. virtual ULONG Dispatch(DebugClient* Client)
  148. {
  149. return Client->m_EventCb->
  150. LoadModule(m_ImageFileHandle, m_BaseOffset, m_ModuleSize,
  151. m_ModuleName, m_ImageName, m_CheckSum,
  152. m_TimeDateStamp);
  153. }
  154. };
  155. struct UnloadModuleEventApcData : public AnyApcData
  156. {
  157. UnloadModuleEventApcData()
  158. : AnyApcData(DEBUG_EVENT_UNLOAD_MODULE,
  159. "IDebugEventCallbacks::UnloadModule")
  160. {
  161. }
  162. PCSTR m_ImageBaseName;
  163. ULONG64 m_BaseOffset;
  164. virtual ULONG Dispatch(DebugClient* Client)
  165. {
  166. return Client->m_EventCb->
  167. UnloadModule(m_ImageBaseName, m_BaseOffset);
  168. }
  169. };
  170. struct SystemErrorEventApcData : public AnyApcData
  171. {
  172. SystemErrorEventApcData()
  173. : AnyApcData(DEBUG_EVENT_SYSTEM_ERROR,
  174. "IDebugEventCallbacks::SystemError")
  175. {
  176. }
  177. ULONG m_Error;
  178. ULONG m_Level;
  179. virtual ULONG Dispatch(DebugClient* Client)
  180. {
  181. return Client->m_EventCb->
  182. SystemError(m_Error, m_Level);
  183. }
  184. };
  185. struct SessionStatusApcData : public AnyApcData
  186. {
  187. SessionStatusApcData()
  188. : AnyApcData(DEBUG_EVENT_SESSION_STATUS,
  189. "IDebugEventCallbacks::SessionStatus")
  190. {
  191. }
  192. ULONG m_Status;
  193. virtual ULONG Dispatch(DebugClient* Client)
  194. {
  195. return Client->m_EventCb->
  196. SessionStatus(m_Status);
  197. }
  198. };
  199. ULONG
  200. ApcDispatch(DebugClient* Client, AnyApcData* ApcData, ULONG EventStatus)
  201. {
  202. DBG_ASSERT(Client->m_EventCb != NULL);
  203. HRESULT Vote;
  204. __try
  205. {
  206. Vote = ApcData->Dispatch(Client);
  207. }
  208. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  209. NULL, ApcData->m_Name))
  210. {
  211. Vote = DEBUG_STATUS_NO_CHANGE;
  212. }
  213. return MergeVotes(EventStatus, Vote);
  214. }
  215. void APIENTRY
  216. EventApc(ULONG_PTR Param)
  217. {
  218. AnyApcData* ApcData = (AnyApcData*)Param;
  219. ULONG Tid = GetCurrentThreadId();
  220. DebugClient* Client;
  221. ULONG EventStatus = DEBUG_STATUS_NO_CHANGE;
  222. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  223. {
  224. if (Client->m_ThreadId == Tid &&
  225. (Client->m_EventInterest & ApcData->m_Mask))
  226. {
  227. EventStatus = ApcDispatch(Client, ApcData, EventStatus);
  228. }
  229. }
  230. if (WaitForSingleObject(g_EventStatusWaiting, INFINITE) !=
  231. WAIT_OBJECT_0)
  232. {
  233. ErrOut("Unable to wait for StatusWaiting, %d\n",
  234. GetLastError());
  235. EventStatus = WIN32_LAST_STATUS();
  236. }
  237. g_EventStatus = EventStatus;
  238. if (!SetEvent(g_EventStatusReady))
  239. {
  240. ErrOut("Unable to set StatusReady, %d\n",
  241. GetLastError());
  242. g_EventStatus = WIN32_LAST_STATUS();
  243. }
  244. }
  245. ULONG
  246. SendEvent(AnyApcData* ApcData, ULONG EventStatus)
  247. {
  248. DebugClient* Client;
  249. ULONG NumQueued = 0;
  250. ULONG TidDone = 0;
  251. static ULONG s_TidSending = 0;
  252. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  253. {
  254. // Only queue one APC per thread regardless of how
  255. // many clients. The APC function will deliver the
  256. // callback to all clients on that thread.
  257. if (Client->m_ThreadId != TidDone &&
  258. (Client->m_EventInterest & ApcData->m_Mask))
  259. {
  260. // SessionStatus callbacks are made at unusual
  261. // times so do not do full call preparation.
  262. if (TidDone == 0 &&
  263. ApcData->m_Mask != DEBUG_EVENT_SESSION_STATUS)
  264. {
  265. PrepareForCalls(DEBUG_STATUS_INSIDE_WAIT);
  266. }
  267. if (Client->m_ThreadId == GetCurrentThreadId())
  268. {
  269. // Don't hold the engine lock while the client
  270. // is called.
  271. SUSPEND_ENGINE();
  272. EventStatus = ApcDispatch(Client, ApcData, EventStatus);
  273. RESUME_ENGINE();
  274. }
  275. else if (QueueUserAPC(EventApc, Client->m_Thread,
  276. (ULONG_PTR)ApcData))
  277. {
  278. TidDone = Client->m_ThreadId;
  279. NumQueued++;
  280. }
  281. else
  282. {
  283. ErrOut("Unable to deliver callback, %d\n", GetLastError());
  284. }
  285. }
  286. }
  287. if (NumQueued == 0)
  288. {
  289. // No APCs queued.
  290. return EventStatus;
  291. }
  292. // This function's use of global data is only safe as
  293. // long as a single send is active at once. Synchronous
  294. // sends are almost exclusively sent by the session thread
  295. // so competition to send is very rare, therefore we
  296. // don't really attempt to handle it.
  297. if (s_TidSending != 0)
  298. {
  299. return E_FAIL;
  300. }
  301. s_TidSending = GetCurrentThreadId();
  302. // Leave the lock while waiting.
  303. SUSPEND_ENGINE();
  304. while (NumQueued-- > 0)
  305. {
  306. if (!SetEvent(g_EventStatusWaiting))
  307. {
  308. // If the event can't be set everything is hosed
  309. // and threads may be stuck waiting so we
  310. // just panic.
  311. ErrOut("Unable to set StatusWaiting, %d\n",
  312. GetLastError());
  313. EventStatus = WIN32_LAST_STATUS();
  314. break;
  315. }
  316. for (;;)
  317. {
  318. ULONG Wait;
  319. Wait = WaitForSingleObjectEx(g_EventStatusReady,
  320. INFINITE, TRUE);
  321. if (Wait == WAIT_OBJECT_0)
  322. {
  323. EventStatus = MergeVotes(EventStatus, g_EventStatus);
  324. break;
  325. }
  326. else if (Wait != WAIT_IO_COMPLETION)
  327. {
  328. ErrOut("Unable to wait for StatusReady, %d\n",
  329. GetLastError());
  330. EventStatus = WIN32_LAST_STATUS();
  331. NumQueued = 0;
  332. break;
  333. }
  334. }
  335. }
  336. RESUME_ENGINE();
  337. s_TidSending = 0;
  338. return EventStatus;
  339. }
  340. //----------------------------------------------------------------------------
  341. //
  342. // Event callbacks.
  343. //
  344. //----------------------------------------------------------------------------
  345. ULONG g_EngNotify;
  346. ULONG
  347. ExecuteEventCommand(ULONG EventStatus, DebugClient* Client, PCSTR Command)
  348. {
  349. if (Command == NULL)
  350. {
  351. return EventStatus;
  352. }
  353. // Don't output any noise while processing event
  354. // command strings.
  355. BOOL OldOutReg = g_OciOutputRegs;
  356. g_OciOutputRegs = FALSE;
  357. PrepareForCalls(DEBUG_STATUS_INSIDE_WAIT);
  358. // Stop execution as soon as the execution status
  359. // changes.
  360. g_EngStatus |= ENG_STATUS_NO_AUTO_WAIT;
  361. Execute(Client, Command, DEBUG_EXECUTE_NOT_LOGGED);
  362. g_EngStatus &= ~ENG_STATUS_NO_AUTO_WAIT;
  363. g_OciOutputRegs = OldOutReg;
  364. // Translate the continuation status from
  365. // the state the engine was left in by the command.
  366. if (IS_RUNNING(g_CmdState))
  367. {
  368. // If the command left the engine running override
  369. // the incoming event status. This allows a user
  370. // to create conditional commands that can resume
  371. // execution even when the basic setting may be to break.
  372. return g_ExecutionStatusRequest;
  373. }
  374. else
  375. {
  376. return EventStatus;
  377. }
  378. }
  379. HRESULT
  380. NotifyBreakpointEvent(ULONG Vote, Breakpoint* Bp)
  381. {
  382. ULONG EventStatus;
  383. g_LastEventType = DEBUG_EVENT_BREAKPOINT;
  384. g_LastEventInfo.Breakpoint.Id = Bp->m_Id;
  385. g_LastEventExtraData = &g_LastEventInfo;
  386. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.Breakpoint);
  387. sprintf(g_LastEventDesc, "Hit breakpoint %d", Bp->m_Id);
  388. // Execute breakpoint command first if one exists.
  389. if (Bp->m_Command != NULL)
  390. {
  391. EventStatus = ExecuteEventCommand(DEBUG_STATUS_NO_CHANGE,
  392. Bp->m_Adder, Bp->m_Command);
  393. }
  394. else
  395. {
  396. if ((Bp->m_Flags & (BREAKPOINT_HIDDEN |
  397. DEBUG_BREAKPOINT_ADDER_ONLY)) == 0)
  398. {
  399. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_PREFIX);
  400. dprintf("Breakpoint %u hit\n", Bp->m_Id);
  401. }
  402. EventStatus = DEBUG_STATUS_NO_CHANGE;
  403. }
  404. BreakpointEventApcData ApcData;
  405. ApcData.m_Bp = Bp;
  406. EventStatus = SendEvent(&ApcData, EventStatus);
  407. // If there weren't any votes default to breaking in.
  408. if (EventStatus == DEBUG_STATUS_NO_CHANGE)
  409. {
  410. EventStatus = DEBUG_STATUS_BREAK;
  411. }
  412. // Fold command status into votes from previous breakpoints.
  413. return MergeVotes(Vote, EventStatus);
  414. }
  415. void
  416. ProcessVcppException(PEXCEPTION_RECORD64 Record)
  417. {
  418. EXCEPTION_VISUALCPP_DEBUG_INFO64 Info64;
  419. EXCEPTION_VISUALCPP_DEBUG_INFO64* Info;
  420. // If this is a 32-bit system we need to convert
  421. // back to a 32-bit exception record so that
  422. // we can properly reconstruct the info from
  423. // the arguments.
  424. if (!g_Machine->m_Ptr64)
  425. {
  426. EXCEPTION_RECORD32 Record32;
  427. EXCEPTION_VISUALCPP_DEBUG_INFO32* Info32;
  428. ExceptionRecord64To32(Record, &Record32);
  429. Info32 = (EXCEPTION_VISUALCPP_DEBUG_INFO32*)
  430. Record32.ExceptionInformation;
  431. Info = &Info64;
  432. Info->dwType = Info32->dwType;
  433. switch(Info->dwType)
  434. {
  435. case VCPP_DEBUG_SET_NAME:
  436. Info->SetName.szName = EXTEND64(Info32->SetName.szName);
  437. Info->SetName.dwThreadID = Info32->SetName.dwThreadID;
  438. Info->SetName.dwFlags = Info32->SetName.dwFlags;
  439. break;
  440. }
  441. }
  442. else
  443. {
  444. Info = (EXCEPTION_VISUALCPP_DEBUG_INFO64*)
  445. Record->ExceptionInformation;
  446. }
  447. PTHREAD_INFO Thread;
  448. switch(Info->dwType)
  449. {
  450. case VCPP_DEBUG_SET_NAME:
  451. if (Info->SetName.dwThreadID == -1)
  452. {
  453. Thread = g_EventThread;
  454. }
  455. else
  456. {
  457. Thread = FindThreadBySystemId(NULL, Info->SetName.dwThreadID);
  458. }
  459. if (Thread != NULL)
  460. {
  461. DWORD Read;
  462. if (g_Target->ReadVirtual(Info->SetName.szName, Thread->Name,
  463. MAX_THREAD_NAME - 1, &Read) != S_OK)
  464. {
  465. Thread->Name[0] = 0;
  466. }
  467. else
  468. {
  469. Thread->Name[Read] = 0;
  470. }
  471. }
  472. break;
  473. }
  474. }
  475. HRESULT
  476. NotifyExceptionEvent(PEXCEPTION_RECORD64 Record,
  477. ULONG FirstChance, BOOL OutputDone)
  478. {
  479. ULONG EventStatus;
  480. EVENT_FILTER* Filter;
  481. EVENT_COMMAND* Command;
  482. PDEBUG_EXCEPTION_FILTER_PARAMETERS Params;
  483. g_LastEventType = DEBUG_EVENT_EXCEPTION;
  484. g_LastEventInfo.Exception.ExceptionRecord = *Record;
  485. g_LastEventInfo.Exception.FirstChance = FirstChance;
  486. g_LastEventExtraData = &g_LastEventInfo;
  487. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.Exception);
  488. sprintf(g_LastEventDesc, "Exception %X, %s chance",
  489. Record->ExceptionCode, FirstChance ? "first" : "second");
  490. if (Record->ExceptionCode == STATUS_VCPP_EXCEPTION)
  491. {
  492. // Handle special VC++ exceptions as they
  493. // pass information from the debuggee to the debugger.
  494. ProcessVcppException(Record);
  495. }
  496. Filter = GetSpecificExceptionFilter(Record->ExceptionCode);
  497. if (Filter == NULL)
  498. {
  499. // Use the default filter for name and handling.
  500. Filter = &g_EventFilters[FILTER_DEFAULT_EXCEPTION];
  501. GetOtherExceptionParameters(Record->ExceptionCode,
  502. &Params, &Command);
  503. }
  504. else
  505. {
  506. Params = &Filter->Params;
  507. Command = &Filter->Command;
  508. }
  509. g_EngDefer |= ENG_DEFER_EXCEPTION_HANDLING;
  510. g_EventExceptionFilter = Params;
  511. g_ExceptionFirstChance = FirstChance;
  512. if (Params->ExecutionOption != DEBUG_FILTER_IGNORE)
  513. {
  514. if (!OutputDone)
  515. {
  516. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_PREFIX);
  517. dprintf("%s", Filter->Name);
  518. if (Filter->OutArgFormat != NULL)
  519. {
  520. dprintf(Filter->OutArgFormat,
  521. Record->ExceptionInformation[Filter->OutArgIndex]);
  522. }
  523. dprintf(" - code %08lx (%s)\n",
  524. Record->ExceptionCode,
  525. FirstChance ? "first chance" : "!!! second chance !!!");
  526. }
  527. if (Params->ExecutionOption == DEBUG_FILTER_BREAK ||
  528. (Params->ExecutionOption == DEBUG_FILTER_SECOND_CHANCE_BREAK &&
  529. !FirstChance))
  530. {
  531. EventStatus = DEBUG_STATUS_BREAK;
  532. }
  533. else
  534. {
  535. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  536. }
  537. }
  538. else
  539. {
  540. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  541. }
  542. // If this is the initial breakpoint execute the
  543. // initial breakpoint command.
  544. if ((g_EngStatus & ENG_STATUS_AT_INITIAL_BREAK) &&
  545. IS_EFEXECUTION_BREAK(g_EventFilters[DEBUG_FILTER_INITIAL_BREAKPOINT].
  546. Params.ExecutionOption))
  547. {
  548. EventStatus = ExecuteEventCommand
  549. (EventStatus,
  550. g_EventFilters[DEBUG_FILTER_INITIAL_BREAKPOINT].Command.Client,
  551. g_EventFilters[DEBUG_FILTER_INITIAL_BREAKPOINT].
  552. Command.Command[0]);
  553. }
  554. EventStatus = ExecuteEventCommand(EventStatus,
  555. Command->Client,
  556. Command->Command[FirstChance ? 0 : 1]);
  557. ExceptionEventApcData ApcData;
  558. ApcData.m_Record = Record;
  559. ApcData.m_FirstChance = FirstChance;
  560. return SendEvent(&ApcData, EventStatus);
  561. }
  562. HRESULT
  563. NotifyCreateThreadEvent(ULONG64 Handle,
  564. ULONG64 DataOffset,
  565. ULONG64 StartOffset,
  566. ULONG Flags)
  567. {
  568. PPROCESS_INFO Process;
  569. StartOutLine(DEBUG_OUTPUT_VERBOSE, OUT_LINE_NO_PREFIX);
  570. VerbOut("*** Create thread %x:%x\n",
  571. g_EventProcessSysId, g_EventThreadSysId);
  572. if ((Process = FindProcessBySystemId(g_EventProcessSysId)) == NULL)
  573. {
  574. ErrOut("Unable to find system process %x\n", g_EventProcessSysId);
  575. if (g_EngNotify == 0)
  576. {
  577. // Put in a placeholder description to make it easy
  578. // to identify this case.
  579. g_LastEventType = DEBUG_EVENT_CREATE_THREAD;
  580. sprintf(g_LastEventDesc, "Create unowned thread %x for %x",
  581. g_EventThreadSysId, g_EventProcessSysId);
  582. }
  583. // Can't really continue the notification.
  584. return DEBUG_STATUS_BREAK;
  585. }
  586. PTHREAD_INFO Thread;
  587. // There's a small window when attaching during process creation where
  588. // it's possible to get two create thread events for the
  589. // same thread. Check and see if this process already has
  590. // a thread with the given ID and handle.
  591. // If a process attach times out and the process is examined,
  592. // there's a possibility that the attach may succeed later,
  593. // yielding events for processes and threads already created
  594. // by examination. In that case just check for an ID match
  595. // as the handles will be different.
  596. for (Thread = Process->ThreadHead;
  597. Thread != NULL;
  598. Thread = Thread->Next)
  599. {
  600. if (((Process->Flags & ENG_PROC_EXAMINED) ||
  601. Thread->Handle == Handle) &&
  602. Thread->SystemId == g_EventThreadSysId)
  603. {
  604. // We already know about this thread, just
  605. // ignore the event.
  606. if ((Process->Flags & ENG_PROC_EXAMINED) == 0)
  607. {
  608. WarnOut("WARNING: Duplicate thread create event for %x:%x\n",
  609. g_EventProcessSysId, g_EventThreadSysId);
  610. }
  611. return DEBUG_STATUS_IGNORE_EVENT;
  612. }
  613. }
  614. if (AddThread(Process, g_EventThreadSysId, Handle,
  615. DataOffset, StartOffset, Flags) == NULL)
  616. {
  617. ErrOut("Unable to allocate thread record for create thread event\n");
  618. ErrOut("Thread %x:%x will be lost\n",
  619. g_EventProcessSysId, g_EventThreadSysId);
  620. if (g_EngNotify == 0)
  621. {
  622. // Put in a placeholder description to make it easy
  623. // to identify this case.
  624. g_LastEventType = DEBUG_EVENT_CREATE_THREAD;
  625. sprintf(g_LastEventDesc, "Can't create thread %x for %x",
  626. g_EventThreadSysId, g_EventProcessSysId);
  627. }
  628. // Can't really continue the notification.
  629. return DEBUG_STATUS_BREAK;
  630. }
  631. // Look up infos now that they've been added.
  632. FindEventProcessThread();
  633. if (g_EventProcess == NULL || g_EventThread == NULL)
  634. {
  635. // This should never happen with the above failure
  636. // checks but handle it just in case.
  637. ErrOut("Create thread unable to locate process or thread %x:%x\n",
  638. g_EventProcessSysId, g_EventThreadSysId);
  639. return DEBUG_STATUS_BREAK;
  640. }
  641. VerbOut("Thread created: %lx.%lx\n",
  642. g_EventProcessSysId, g_EventThreadSysId);
  643. if (g_EngNotify > 0)
  644. {
  645. // This call is just to update internal thread state.
  646. // Do not make real callbacks.
  647. return DEBUG_STATUS_NO_CHANGE;
  648. }
  649. OutputProcessInfo("*** Create thread ***");
  650. g_LastEventType = DEBUG_EVENT_CREATE_THREAD;
  651. sprintf(g_LastEventDesc, "Create thread %d:%x",
  652. g_EventThread->UserId, g_EventThreadSysId);
  653. // Always update breakpoints to account for the new thread.
  654. SuspendExecution();
  655. RemoveBreakpoints();
  656. g_UpdateDataBreakpoints = TRUE;
  657. g_DataBreakpointsChanged = TRUE;
  658. ULONG EventStatus;
  659. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_CREATE_THREAD];
  660. EventStatus =
  661. IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) ?
  662. DEBUG_STATUS_BREAK : DEBUG_STATUS_IGNORE_EVENT;
  663. EventStatus = ExecuteEventCommand(EventStatus,
  664. Filter->Command.Client,
  665. Filter->Command.Command[0]);
  666. CreateThreadEventApcData ApcData;
  667. ApcData.m_Handle = Handle;
  668. ApcData.m_DataOffset = DataOffset;
  669. ApcData.m_StartOffset = StartOffset;
  670. return SendEvent(&ApcData, EventStatus);
  671. }
  672. HRESULT
  673. NotifyExitThreadEvent(ULONG ExitCode)
  674. {
  675. StartOutLine(DEBUG_OUTPUT_VERBOSE, OUT_LINE_NO_PREFIX);
  676. VerbOut("*** Exit thread\n");
  677. g_EngDefer |= ENG_DEFER_DELETE_EXITED;
  678. // There's a small possibility that exit events can
  679. // be delivered when the engine is not expecting them.
  680. // When attaching to a process that's exiting it's possible
  681. // to get an exit but no create. When restarting it's
  682. // possible that not all events were successfully drained.
  683. // Protect this code from faulting in that case.
  684. if (g_EventThread == NULL)
  685. {
  686. WarnOut("WARNING: Unknown thread exit: %lx.%lx\n",
  687. g_EventProcessSysId, g_EventThreadSysId);
  688. }
  689. else
  690. {
  691. g_EventThread->Exited = TRUE;
  692. }
  693. VerbOut("Thread exited: %lx.%lx, code %X\n",
  694. g_EventProcessSysId, g_EventThreadSysId, ExitCode);
  695. g_LastEventType = DEBUG_EVENT_EXIT_THREAD;
  696. g_LastEventInfo.ExitThread.ExitCode = ExitCode;
  697. g_LastEventExtraData = &g_LastEventInfo;
  698. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.ExitThread);
  699. if (g_EventThread == NULL)
  700. {
  701. sprintf(g_LastEventDesc, "Exit thread ???:%x, code %X",
  702. g_EventThreadSysId, ExitCode);
  703. }
  704. else
  705. {
  706. sprintf(g_LastEventDesc, "Exit thread %d:%x, code %X",
  707. g_EventThread->UserId, g_EventThreadSysId, ExitCode);
  708. }
  709. ULONG EventStatus;
  710. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_EXIT_THREAD];
  711. EventStatus =
  712. IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) ?
  713. DEBUG_STATUS_BREAK : DEBUG_STATUS_IGNORE_EVENT;
  714. // If we were stepping on this thread then force a breakin
  715. // so it's clear to the user that the thread exited.
  716. if (g_EventThread != NULL &&
  717. (g_StepTraceBp->m_Flags & DEBUG_BREAKPOINT_ENABLED) &&
  718. (g_StepTraceBp->m_MatchThread == g_EventThread ||
  719. g_DeferBp->m_MatchThread == g_EventThread))
  720. {
  721. WarnOut("WARNING: Step/trace thread exited\n");
  722. g_WatchFunctions.End(NULL);
  723. EventStatus = DEBUG_STATUS_BREAK;
  724. // Ensure that p/t isn't repeated.
  725. g_LastCommand[0] = 0;
  726. }
  727. EventStatus = ExecuteEventCommand(EventStatus,
  728. Filter->Command.Client,
  729. Filter->Command.Command[0]);
  730. ExitThreadEventApcData ApcData;
  731. ApcData.m_ExitCode = ExitCode;
  732. return SendEvent(&ApcData, EventStatus);
  733. }
  734. HRESULT
  735. NotifyCreateProcessEvent(ULONG64 ImageFileHandle,
  736. ULONG64 Handle,
  737. ULONG64 BaseOffset,
  738. ULONG ModuleSize,
  739. PSTR ModuleName,
  740. PSTR ImageName,
  741. ULONG CheckSum,
  742. ULONG TimeDateStamp,
  743. ULONG64 InitialThreadHandle,
  744. ULONG64 ThreadDataOffset,
  745. ULONG64 StartOffset,
  746. ULONG Flags,
  747. ULONG Options,
  748. ULONG InitialThreadFlags)
  749. {
  750. StartOutLine(DEBUG_OUTPUT_VERBOSE, OUT_LINE_NO_PREFIX);
  751. VerbOut("*** Create process %x\n", g_EventProcessSysId);
  752. PPROCESS_INFO Process;
  753. // If a process attach times out and the process is examined,
  754. // there's a possibility that the attach may succeed later,
  755. // yielding events for processes and threads already created
  756. // by examination. In that case just check for an ID match
  757. // as the handles will be different.
  758. for (Process = g_ProcessHead;
  759. Process != NULL;
  760. Process = Process->Next)
  761. {
  762. if (((Process->Flags & ENG_PROC_EXAMINED) ||
  763. Process->FullHandle == Handle) &&
  764. Process->SystemId == g_EventProcessSysId)
  765. {
  766. // We already know about this process, just
  767. // ignore the event.
  768. if ((Process->Flags & ENG_PROC_EXAMINED) == 0)
  769. {
  770. WarnOut("WARNING: Duplicate process create event for %x\n",
  771. g_EventProcessSysId);
  772. }
  773. return DEBUG_STATUS_IGNORE_EVENT;
  774. }
  775. }
  776. if (AddProcess(g_EventProcessSysId, Handle, g_EventThreadSysId,
  777. InitialThreadHandle, ThreadDataOffset, StartOffset,
  778. Flags, Options, InitialThreadFlags) == NULL)
  779. {
  780. ErrOut("Unable to allocate process record for create process event\n");
  781. ErrOut("Process %x will be lost\n", g_EventProcessSysId);
  782. if (g_EngNotify == 0)
  783. {
  784. // Put in a placeholder description to make it easy
  785. // to identify this case.
  786. g_LastEventType = DEBUG_EVENT_CREATE_PROCESS;
  787. sprintf(g_LastEventDesc, "Can't create process %x",
  788. g_EventProcessSysId);
  789. }
  790. // Can't really continue the notification.
  791. return DEBUG_STATUS_BREAK;
  792. }
  793. // Look up infos now that they've been added.
  794. FindEventProcessThread();
  795. if (g_EventProcess == NULL || g_EventThread == NULL)
  796. {
  797. // This should never happen with the above failure
  798. // checks but handle it just in case.
  799. ErrOut("Create process unable to locate process or thread %x:%x\n",
  800. g_EventProcessSysId, g_EventThreadSysId);
  801. return DEBUG_STATUS_BREAK;
  802. }
  803. VerbOut("Process created: %lx.%lx\n",
  804. g_EventProcessSysId, g_EventThreadSysId);
  805. if (g_EngNotify > 0)
  806. {
  807. // This call is just to update internal process state.
  808. // Do not make real callbacks.
  809. g_EngStatus |= ENG_STATUS_PROCESSES_ADDED;
  810. return DEBUG_STATUS_NO_CHANGE;
  811. }
  812. OutputProcessInfo("*** Create process ***");
  813. g_LastEventType = DEBUG_EVENT_CREATE_PROCESS;
  814. sprintf(g_LastEventDesc, "Create process %d:%x",
  815. g_EventProcess->UserId, g_EventProcessSysId);
  816. // Simulate a load module event for the process but do
  817. // not send it to the client.
  818. g_EngNotify++;
  819. NotifyLoadModuleEvent(ImageFileHandle, BaseOffset, ModuleSize,
  820. ModuleName, ImageName, CheckSum, TimeDateStamp);
  821. g_EngNotify--;
  822. ULONG EventStatus;
  823. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_CREATE_PROCESS];
  824. BOOL MatchesEvent;
  825. MatchesEvent = BreakOnThisImageTail(ImageName, Filter->Argument);
  826. EventStatus =
  827. (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  828. MatchesEvent) ?
  829. DEBUG_STATUS_BREAK : DEBUG_STATUS_IGNORE_EVENT;
  830. if (MatchesEvent)
  831. {
  832. EventStatus = ExecuteEventCommand(EventStatus,
  833. Filter->Command.Client,
  834. Filter->Command.Command[0]);
  835. }
  836. g_EngStatus |= ENG_STATUS_PROCESSES_ADDED;
  837. CreateProcessEventApcData ApcData;
  838. ApcData.m_ImageFileHandle = ImageFileHandle;
  839. ApcData.m_Handle = Handle;
  840. ApcData.m_BaseOffset = BaseOffset;
  841. ApcData.m_ModuleSize = ModuleSize;
  842. ApcData.m_ModuleName = ModuleName;
  843. ApcData.m_ImageName = ImageName;
  844. ApcData.m_CheckSum = CheckSum;
  845. ApcData.m_TimeDateStamp = TimeDateStamp;
  846. ApcData.m_InitialThreadHandle = InitialThreadHandle;
  847. ApcData.m_ThreadDataOffset = ThreadDataOffset;
  848. ApcData.m_StartOffset = StartOffset;
  849. return SendEvent(&ApcData, EventStatus);
  850. }
  851. HRESULT
  852. NotifyExitProcessEvent(ULONG ExitCode)
  853. {
  854. StartOutLine(DEBUG_OUTPUT_VERBOSE, OUT_LINE_NO_PREFIX);
  855. VerbOut("*** Exit process\n");
  856. g_EngDefer |= ENG_DEFER_DELETE_EXITED;
  857. // There's a small possibility that exit events can
  858. // be delivered when the engine is not expecting them.
  859. // When attaching to a process that's exiting it's possible
  860. // to get an exit but no create. When restarting it's
  861. // possible that not all events were successfully drained.
  862. // Protect this code from faulting in that case.
  863. if (g_EventProcess == NULL)
  864. {
  865. WarnOut("WARNING: Unknown process exit: %lx.%lx\n",
  866. g_EventProcessSysId, g_EventThreadSysId);
  867. }
  868. else
  869. {
  870. g_EventProcess->Exited = TRUE;
  871. }
  872. VerbOut("Process exited: %lx.%lx, code %X\n",
  873. g_EventProcessSysId, g_EventThreadSysId, ExitCode);
  874. g_LastEventType = DEBUG_EVENT_EXIT_PROCESS;
  875. g_LastEventInfo.ExitProcess.ExitCode = ExitCode;
  876. g_LastEventExtraData = &g_LastEventInfo;
  877. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.ExitProcess);
  878. if (g_EventProcess == NULL)
  879. {
  880. sprintf(g_LastEventDesc, "Exit process ???:%x, code %X",
  881. g_EventProcessSysId, ExitCode);
  882. }
  883. else
  884. {
  885. sprintf(g_LastEventDesc, "Exit process %d:%x, code %X",
  886. g_EventProcess->UserId, g_EventProcessSysId, ExitCode);
  887. }
  888. ULONG EventStatus;
  889. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_EXIT_PROCESS];
  890. BOOL MatchesEvent;
  891. if (g_EventProcess && g_EventProcess->ExecutableImage)
  892. {
  893. MatchesEvent =
  894. BreakOnThisImageTail(g_EventProcess->ExecutableImage->ImagePath,
  895. Filter->Argument);
  896. }
  897. else
  898. {
  899. // If this process doesn't have a specific name always break.
  900. MatchesEvent = TRUE;
  901. }
  902. EventStatus =
  903. ((g_EngOptions & DEBUG_ENGOPT_FINAL_BREAK) ||
  904. (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  905. MatchesEvent)) ?
  906. DEBUG_STATUS_BREAK : DEBUG_STATUS_IGNORE_EVENT;
  907. if (MatchesEvent)
  908. {
  909. EventStatus = ExecuteEventCommand(EventStatus,
  910. Filter->Command.Client,
  911. Filter->Command.Command[0]);
  912. }
  913. ExitProcessEventApcData ApcData;
  914. ApcData.m_ExitCode = ExitCode;
  915. return SendEvent(&ApcData, EventStatus);
  916. }
  917. HRESULT
  918. NotifyLoadModuleEvent(ULONG64 ImageFileHandle,
  919. ULONG64 BaseOffset,
  920. ULONG ModuleSize,
  921. PSTR ModuleName,
  922. PSTR ImagePathName,
  923. ULONG CheckSum,
  924. ULONG TimeDateStamp)
  925. {
  926. MODULE_INFO_ENTRY ModEntry = {0};
  927. ModEntry.NamePtr = ImagePathName;
  928. ModEntry.File = (HANDLE)ImageFileHandle;
  929. ModEntry.Base = BaseOffset;
  930. ModEntry.Size = ModuleSize;
  931. ModEntry.CheckSum = CheckSum;
  932. ModEntry.ModuleName = ModuleName;
  933. ModEntry.TimeDateStamp = TimeDateStamp;
  934. AddImage(&ModEntry, FALSE);
  935. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_LOAD_MODULE];
  936. //
  937. // ntsd has always shown mod loads by default.
  938. //
  939. if (IS_USER_TARGET())
  940. {
  941. //if (Filter->Params.ExecutionOption == DEBUG_FILTER_OUTPUT)
  942. {
  943. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_PREFIX);
  944. dprintf("ModLoad: %s %s %-8s\n",
  945. FormatAddr64(BaseOffset),
  946. FormatAddr64(BaseOffset + ModuleSize),
  947. ImagePathName);
  948. }
  949. }
  950. OutputProcessInfo("*** Load dll ***");
  951. if (g_EngNotify > 0)
  952. {
  953. g_EngStatus |= ENG_STATUS_MODULES_LOADED;
  954. return DEBUG_STATUS_IGNORE_EVENT;
  955. }
  956. g_LastEventType = DEBUG_EVENT_LOAD_MODULE;
  957. g_LastEventInfo.LoadModule.Base = BaseOffset;
  958. g_LastEventExtraData = &g_LastEventInfo;
  959. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.LoadModule);
  960. sprintf(g_LastEventDesc, "Load module %.*s at %s",
  961. MAX_IMAGE_PATH - 32, ImagePathName,
  962. FormatAddr64(BaseOffset));
  963. ULONG EventStatus;
  964. BOOL MatchesEvent;
  965. if ((g_EngStatus & ENG_STATUS_MODULES_LOADED) == 0)
  966. {
  967. g_EngStatus |= ENG_STATUS_AT_INITIAL_MODULE_LOAD;
  968. }
  969. MatchesEvent = BreakOnThisImageTail(ImagePathName, Filter->Argument);
  970. if ((IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  971. MatchesEvent) ||
  972. ((g_EngOptions & DEBUG_ENGOPT_INITIAL_MODULE_BREAK) &&
  973. (g_EngStatus & ENG_STATUS_MODULES_LOADED) == 0))
  974. {
  975. EventStatus = DEBUG_STATUS_BREAK;
  976. }
  977. else
  978. {
  979. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  980. }
  981. // If this is the very first module load give breakpoints
  982. // a chance to get established. Execute the initial
  983. // module command if there is one.
  984. if (g_EngStatus & ENG_STATUS_AT_INITIAL_MODULE_LOAD)
  985. {
  986. // On NT4 boot the breakpoint update and context management caused
  987. // by this seems to hit the system at a fragile time and
  988. // usually causes a bugcheck 50, so don't do it. Win2K seems
  989. // to be able to handle it, so allow it there.
  990. if (IS_USER_TARGET() || g_ActualSystemVersion != NT_SVER_NT4)
  991. {
  992. SuspendExecution();
  993. RemoveBreakpoints();
  994. if (IS_EFEXECUTION_BREAK(g_EventFilters
  995. [DEBUG_FILTER_INITIAL_MODULE_LOAD].
  996. Params.ExecutionOption))
  997. {
  998. EventStatus = ExecuteEventCommand
  999. (EventStatus,
  1000. g_EventFilters[DEBUG_FILTER_INITIAL_MODULE_LOAD].
  1001. Command.Client,
  1002. g_EventFilters[DEBUG_FILTER_INITIAL_MODULE_LOAD].
  1003. Command.Command[0]);
  1004. }
  1005. }
  1006. }
  1007. if (MatchesEvent)
  1008. {
  1009. EventStatus = ExecuteEventCommand(EventStatus,
  1010. Filter->Command.Client,
  1011. Filter->Command.Command[0]);
  1012. }
  1013. g_EngStatus |= ENG_STATUS_MODULES_LOADED;
  1014. LoadModuleEventApcData ApcData;
  1015. ApcData.m_ImageFileHandle = ImageFileHandle;
  1016. ApcData.m_BaseOffset = BaseOffset;
  1017. ApcData.m_ModuleSize = ModuleSize;
  1018. ApcData.m_ModuleName = ModuleName;
  1019. ApcData.m_ImageName = ImagePathName;
  1020. ApcData.m_CheckSum = CheckSum;
  1021. ApcData.m_TimeDateStamp = TimeDateStamp;
  1022. EventStatus = SendEvent(&ApcData, EventStatus);
  1023. if (EventStatus > DEBUG_STATUS_GO_NOT_HANDLED &&
  1024. IS_KERNEL_TARGET() && g_ActualSystemVersion == NT_SVER_NT4)
  1025. {
  1026. WarnOut("WARNING: Any modification to state may cause bugchecks.\n");
  1027. WarnOut(" The debugger will not write "
  1028. "any register changes.\n");
  1029. }
  1030. return EventStatus;
  1031. }
  1032. HRESULT
  1033. NotifyUnloadModuleEvent(PCSTR ImageBaseName,
  1034. ULONG64 BaseOffset)
  1035. {
  1036. PDEBUG_IMAGE_INFO Image = NULL;
  1037. // First try to look up the image by the base offset
  1038. // as that's the most reliable identifier.
  1039. if (BaseOffset)
  1040. {
  1041. Image = GetImageByOffset(g_EventProcess, BaseOffset);
  1042. }
  1043. // Next try to look up the image by the full name given.
  1044. if (!Image && ImageBaseName)
  1045. {
  1046. Image = GetImageByName(g_EventProcess, ImageBaseName,
  1047. INAME_IMAGE_PATH);
  1048. // Finally try to look up the image by the tail of the name given.
  1049. if (!Image)
  1050. {
  1051. Image = GetImageByName(g_EventProcess, PathTail(ImageBaseName),
  1052. INAME_IMAGE_PATH_TAIL);
  1053. }
  1054. }
  1055. if (Image)
  1056. {
  1057. ImageBaseName = Image->ImagePath;
  1058. BaseOffset = Image->BaseOfImage;
  1059. Image->Unloaded = TRUE;
  1060. g_EngDefer |= ENG_DEFER_DELETE_EXITED;
  1061. }
  1062. g_LastEventType = DEBUG_EVENT_UNLOAD_MODULE;
  1063. g_LastEventInfo.UnloadModule.Base = BaseOffset;
  1064. g_LastEventExtraData = &g_LastEventInfo;
  1065. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.UnloadModule);
  1066. sprintf(g_LastEventDesc, "Unload module %.*s at %s",
  1067. MAX_IMAGE_PATH - 32, ImageBaseName ? ImageBaseName : "<not found>",
  1068. FormatAddr64(BaseOffset));
  1069. ULONG EventStatus;
  1070. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_UNLOAD_MODULE];
  1071. BOOL MatchesEvent;
  1072. if (Filter->Params.ExecutionOption == DEBUG_FILTER_OUTPUT)
  1073. {
  1074. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_PREFIX);
  1075. dprintf("%s\n", g_LastEventDesc);
  1076. }
  1077. MatchesEvent = BreakOnThisDllUnload(BaseOffset);
  1078. if (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  1079. MatchesEvent)
  1080. {
  1081. EventStatus = DEBUG_STATUS_BREAK;
  1082. }
  1083. else
  1084. {
  1085. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  1086. }
  1087. if (MatchesEvent)
  1088. {
  1089. EventStatus = ExecuteEventCommand(EventStatus,
  1090. Filter->Command.Client,
  1091. Filter->Command.Command[0]);
  1092. }
  1093. UnloadModuleEventApcData ApcData;
  1094. ApcData.m_ImageBaseName = ImageBaseName;
  1095. ApcData.m_BaseOffset = BaseOffset;
  1096. return SendEvent(&ApcData, EventStatus);
  1097. }
  1098. HRESULT
  1099. NotifySystemErrorEvent(ULONG Error,
  1100. ULONG Level)
  1101. {
  1102. g_LastEventType = DEBUG_EVENT_SYSTEM_ERROR;
  1103. g_LastEventInfo.SystemError.Error = Error;
  1104. g_LastEventInfo.SystemError.Level = Level;
  1105. g_LastEventExtraData = &g_LastEventInfo;
  1106. g_LastEventExtraDataSize = sizeof(g_LastEventInfo.SystemError);
  1107. sprintf(g_LastEventDesc, "System error %d.%d",
  1108. Error, Level);
  1109. if (Level <= g_SystemErrorOutput)
  1110. {
  1111. char ErrorString[_MAX_PATH];
  1112. va_list Args;
  1113. StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_PREFIX);
  1114. dprintf("%s - %s: ", Level == SLE_WARNING ?
  1115. "WARNING" : "ERROR", g_EventProcess->ImageHead->ImagePath);
  1116. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  1117. FORMAT_MESSAGE_IGNORE_INSERTS,
  1118. NULL,
  1119. Error,
  1120. 0,
  1121. ErrorString,
  1122. sizeof(ErrorString),
  1123. &Args);
  1124. dprintf("%s", ErrorString);
  1125. }
  1126. ULONG EventStatus;
  1127. EVENT_FILTER* Filter = &g_EventFilters[DEBUG_FILTER_SYSTEM_ERROR];
  1128. if (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) ||
  1129. Level <= g_SystemErrorBreak)
  1130. {
  1131. EventStatus = DEBUG_STATUS_BREAK;
  1132. }
  1133. else
  1134. {
  1135. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  1136. }
  1137. EventStatus = ExecuteEventCommand(EventStatus,
  1138. Filter->Command.Client,
  1139. Filter->Command.Command[0]);
  1140. SystemErrorEventApcData ApcData;
  1141. ApcData.m_Error = Error;
  1142. ApcData.m_Level = Level;
  1143. return SendEvent(&ApcData, EventStatus);
  1144. }
  1145. HRESULT
  1146. NotifySessionStatus(ULONG Status)
  1147. {
  1148. SessionStatusApcData ApcData;
  1149. ApcData.m_Status = Status;
  1150. return SendEvent(&ApcData, DEBUG_STATUS_NO_CHANGE);
  1151. }
  1152. void
  1153. NotifyChangeDebuggeeState(ULONG Flags, ULONG64 Argument)
  1154. {
  1155. if (g_EngNotify > 0)
  1156. {
  1157. // Notifications are being suppressed.
  1158. return;
  1159. }
  1160. DebugClient* Client;
  1161. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1162. {
  1163. if (Client->m_EventInterest & DEBUG_EVENT_CHANGE_DEBUGGEE_STATE)
  1164. {
  1165. HRESULT Status;
  1166. DBG_ASSERT(Client->m_EventCb != NULL);
  1167. __try
  1168. {
  1169. Status = Client->m_EventCb->
  1170. ChangeDebuggeeState(Flags, Argument);
  1171. }
  1172. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1173. NULL, "IDebugEventCallbacks::"
  1174. "ChangeDebuggeeState"))
  1175. {
  1176. Status = E_FAIL;
  1177. }
  1178. if (HRESULT_FACILITY(Status) == FACILITY_RPC)
  1179. {
  1180. Client->Destroy();
  1181. }
  1182. }
  1183. }
  1184. }
  1185. void
  1186. NotifyChangeEngineState(ULONG Flags, ULONG64 Argument, BOOL HaveEngineLock)
  1187. {
  1188. if (g_EngNotify > 0)
  1189. {
  1190. // Notifications are being suppressed.
  1191. return;
  1192. }
  1193. DebugClient* Client;
  1194. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1195. {
  1196. if (Client->m_EventInterest & DEBUG_EVENT_CHANGE_ENGINE_STATE)
  1197. {
  1198. HRESULT Status;
  1199. DBG_ASSERT(Client->m_EventCb != NULL);
  1200. __try
  1201. {
  1202. Status = Client->m_EventCb->
  1203. ChangeEngineState(Flags, Argument);
  1204. }
  1205. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1206. NULL, "IDebugEventCallbacks::"
  1207. "ChangeEngineState"))
  1208. {
  1209. Status = E_FAIL;
  1210. }
  1211. if (HRESULT_FACILITY(Status) == FACILITY_RPC)
  1212. {
  1213. Client->Destroy();
  1214. }
  1215. }
  1216. }
  1217. }
  1218. void
  1219. NotifyChangeSymbolState(ULONG Flags, ULONG64 Argument, PPROCESS_INFO Process)
  1220. {
  1221. if (g_EngNotify > 0)
  1222. {
  1223. // Notifications are being suppressed.
  1224. return;
  1225. }
  1226. if ((Flags & (DEBUG_CSS_LOADS | DEBUG_CSS_UNLOADS)) &&
  1227. Process)
  1228. {
  1229. // Reevaluate any offset expressions to account
  1230. // for the change in symbols.
  1231. EvaluateOffsetExpressions(Process, Flags);
  1232. }
  1233. DebugClient* Client;
  1234. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1235. {
  1236. if (Client->m_EventInterest & DEBUG_EVENT_CHANGE_SYMBOL_STATE)
  1237. {
  1238. HRESULT Status;
  1239. DBG_ASSERT(Client->m_EventCb != NULL);
  1240. __try
  1241. {
  1242. Status = Client->m_EventCb->
  1243. ChangeSymbolState(Flags, Argument);
  1244. }
  1245. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1246. NULL, "IDebugEventCallbacks::"
  1247. "ChangeSymbolState"))
  1248. {
  1249. Status = E_FAIL;
  1250. }
  1251. if (HRESULT_FACILITY(Status) == FACILITY_RPC)
  1252. {
  1253. Client->Destroy();
  1254. }
  1255. }
  1256. }
  1257. }
  1258. //----------------------------------------------------------------------------
  1259. //
  1260. // Input callbacks.
  1261. //
  1262. //----------------------------------------------------------------------------
  1263. ULONG
  1264. GetInput(PCSTR Prompt,
  1265. PSTR Buffer,
  1266. ULONG BufferSize)
  1267. {
  1268. DebugClient* Client;
  1269. ULONG Len;
  1270. HRESULT Status;
  1271. // Do not suspend the engine lock as this may be called
  1272. // in the middle of an operation.
  1273. // Start a new sequence for this input.
  1274. g_InputSequence = 0;
  1275. g_InputSizeRequested = BufferSize;
  1276. if (Prompt != NULL && Prompt[0] != 0)
  1277. {
  1278. dprintf("%s", Prompt);
  1279. }
  1280. // Don't hold the engine locked while waiting.
  1281. SUSPEND_ENGINE();
  1282. // Begin the input process by notifying all
  1283. // clients with input callbacks that input
  1284. // is needed.
  1285. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1286. {
  1287. // Update the input sequence for all clients so that
  1288. // clients that don't have input callbacks can still
  1289. // return input. This is necessary in some threading cases.
  1290. Client->m_InputSequence = 1;
  1291. if (Client->m_InputCb != NULL)
  1292. {
  1293. __try
  1294. {
  1295. Status = Client->m_InputCb->StartInput(BufferSize);
  1296. }
  1297. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1298. NULL, "IDebugInputCallbacks::"
  1299. "StartInput"))
  1300. {
  1301. Status = E_FAIL;
  1302. }
  1303. if (Status != S_OK)
  1304. {
  1305. if (HRESULT_FACILITY(Status) == FACILITY_RPC)
  1306. {
  1307. Client->Destroy();
  1308. }
  1309. else
  1310. {
  1311. Len = 0;
  1312. ErrOut("Client %N refused StartInput, 0x%X\n",
  1313. Client, Status);
  1314. goto End;
  1315. }
  1316. }
  1317. }
  1318. }
  1319. // Wait for input to be returned.
  1320. if (WaitForSingleObject(g_InputEvent, INFINITE) != WAIT_OBJECT_0)
  1321. {
  1322. Len = 0;
  1323. Status = WIN32_LAST_STATUS();
  1324. ErrOut("Input event wait failed, 0x%X\n", Status);
  1325. }
  1326. else
  1327. {
  1328. ULONG CopyLen;
  1329. Len = strlen(g_InputBuffer) + 1;
  1330. CopyLen = min(Len, BufferSize);
  1331. memcpy(Buffer, g_InputBuffer, CopyLen);
  1332. Buffer[BufferSize - 1] = 0;
  1333. }
  1334. End:
  1335. RESUME_ENGINE();
  1336. g_InputSizeRequested = 0;
  1337. // Notify all clients that input process is done.
  1338. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1339. {
  1340. Client->m_InputSequence = 0xffffffff;
  1341. if (Client->m_InputCb != NULL)
  1342. {
  1343. __try
  1344. {
  1345. Client->m_InputCb->EndInput();
  1346. }
  1347. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1348. NULL, "IDebugInputCallbacks::"
  1349. "EndInput"))
  1350. {
  1351. }
  1352. }
  1353. }
  1354. return Len;
  1355. }
  1356. //----------------------------------------------------------------------------
  1357. //
  1358. // Output callbacks.
  1359. //
  1360. //----------------------------------------------------------------------------
  1361. char g_OutBuffer[OUT_BUFFER_SIZE], g_FormatBuffer[OUT_BUFFER_SIZE];
  1362. char g_OutFilterPattern[MAX_IMAGE_PATH];
  1363. BOOL g_OutFilterResult = TRUE;
  1364. ULONG g_AllOutMask;
  1365. // Don't split up entries if they'll result in data so
  1366. // small that the extra callbacks are worse than the wasted space.
  1367. #define MIN_HISTORY_ENTRY_SIZE (256 + sizeof(OutHistoryEntryHeader))
  1368. PSTR g_OutHistory;
  1369. ULONG g_OutHistoryActualSize;
  1370. ULONG g_OutHistoryRequestedSize = 512 * 1024;
  1371. ULONG g_OutHistWriteMask;
  1372. OutHistoryEntry g_OutHistRead, g_OutHistWrite;
  1373. ULONG g_OutHistoryMask;
  1374. ULONG g_OutHistoryUsed;
  1375. ULONG g_OutputControl = DEBUG_OUTCTL_ALL_CLIENTS;
  1376. DebugClient* g_OutputClient;
  1377. BOOL g_BufferOutput;
  1378. // The kernel silently truncates DbgPrints longer than
  1379. // 512 characters so don't buffer any more than that.
  1380. #define BUFFERED_OUTPUT_SIZE 512
  1381. // Largest delay allowed in TimedFlushCallbacks, in ticks.
  1382. #define MAX_FLUSH_DELAY 250
  1383. ULONG g_BufferedOutputMask;
  1384. char g_BufferedOutput[BUFFERED_OUTPUT_SIZE];
  1385. ULONG g_BufferedOutputUsed;
  1386. ULONG g_LastFlushTicks;
  1387. void
  1388. CollectOutMasks(void)
  1389. {
  1390. DebugClient* Client;
  1391. g_AllOutMask = 0;
  1392. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1393. {
  1394. if (Client->m_OutputCb != NULL)
  1395. {
  1396. g_AllOutMask |= Client->m_OutMask;
  1397. }
  1398. }
  1399. }
  1400. BOOL
  1401. PushOutCtl(ULONG OutputControl, DebugClient* Client,
  1402. OutCtlSave* Save)
  1403. {
  1404. BOOL Status;
  1405. FlushCallbacks();
  1406. Save->OutputControl = g_OutputControl;
  1407. Save->Client = g_OutputClient;
  1408. Save->BufferOutput = g_BufferOutput;
  1409. Save->OutputWidth = g_OutputWidth;
  1410. Save->OutputLinePrefix = g_OutputLinePrefix;
  1411. if (OutputControl == DEBUG_OUTCTL_AMBIENT)
  1412. {
  1413. // Leave settings unchanged.
  1414. Status = TRUE;
  1415. }
  1416. else
  1417. {
  1418. ULONG SendMask = OutputControl & DEBUG_OUTCTL_SEND_MASK;
  1419. if (
  1420. #if DEBUG_OUTCTL_THIS_CLIENT > 0
  1421. SendMask < DEBUG_OUTCTL_THIS_CLIENT ||
  1422. #endif
  1423. SendMask > DEBUG_OUTCTL_LOG_ONLY ||
  1424. (OutputControl & ~(DEBUG_OUTCTL_SEND_MASK |
  1425. DEBUG_OUTCTL_NOT_LOGGED |
  1426. DEBUG_OUTCTL_OVERRIDE_MASK)))
  1427. {
  1428. Status = FALSE;
  1429. }
  1430. else
  1431. {
  1432. g_OutputControl = OutputControl;
  1433. g_OutputClient = Client;
  1434. g_BufferOutput = TRUE;
  1435. if (Client != NULL)
  1436. {
  1437. g_OutputWidth = Client->m_OutputWidth;
  1438. g_OutputLinePrefix = Client->m_OutputLinePrefix;
  1439. }
  1440. Status = TRUE;
  1441. }
  1442. }
  1443. return Status;
  1444. }
  1445. void
  1446. PopOutCtl(OutCtlSave* Save)
  1447. {
  1448. FlushCallbacks();
  1449. g_OutputControl = Save->OutputControl;
  1450. g_OutputClient = Save->Client;
  1451. g_BufferOutput = Save->BufferOutput;
  1452. g_OutputWidth = Save->OutputWidth;
  1453. g_OutputLinePrefix = Save->OutputLinePrefix;
  1454. }
  1455. void
  1456. SendOutput(ULONG Mask, PCSTR Text)
  1457. {
  1458. ULONG OutTo = g_OutputControl & DEBUG_OUTCTL_SEND_MASK;
  1459. HRESULT Status;
  1460. if (OutTo == DEBUG_OUTCTL_THIS_CLIENT)
  1461. {
  1462. if (g_OutputClient->m_OutputCb != NULL &&
  1463. ((g_OutputControl & DEBUG_OUTCTL_OVERRIDE_MASK) ||
  1464. (Mask & g_OutputClient->m_OutMask)))
  1465. {
  1466. __try
  1467. {
  1468. Status = g_OutputClient->m_OutputCb->Output(Mask, Text);
  1469. }
  1470. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1471. NULL, "IDebugOutputCallbacks::"
  1472. "Output"))
  1473. {
  1474. Status = E_FAIL;
  1475. }
  1476. if (HRESULT_FACILITY(Status) == FACILITY_RPC)
  1477. {
  1478. g_OutputClient->Destroy();
  1479. }
  1480. }
  1481. }
  1482. else
  1483. {
  1484. DebugClient* Client;
  1485. for (Client = g_Clients; Client != NULL; Client = Client->m_Next)
  1486. {
  1487. if ((OutTo == DEBUG_OUTCTL_ALL_CLIENTS ||
  1488. Client != g_OutputClient) &&
  1489. Client->m_OutputCb != NULL &&
  1490. ((g_OutputControl & DEBUG_OUTCTL_OVERRIDE_MASK) ||
  1491. (Client->m_OutMask & Mask)))
  1492. {
  1493. __try
  1494. {
  1495. Status = Client->m_OutputCb->Output(Mask, Text);
  1496. }
  1497. __except(ExtensionExceptionFilter(GetExceptionInformation(),
  1498. NULL,
  1499. "IDebugOutputCallbacks::"
  1500. "Output"))
  1501. {
  1502. Status = E_FAIL;
  1503. }
  1504. if (HRESULT_FACILITY(Status) == FACILITY_RPC)
  1505. {
  1506. Client->Destroy();
  1507. }
  1508. }
  1509. }
  1510. }
  1511. }
  1512. void
  1513. BufferOutput(ULONG Mask, PCSTR Text, ULONG Len)
  1514. {
  1515. EnterCriticalSection(&g_QuickLock);
  1516. if (Mask != g_BufferedOutputMask ||
  1517. g_BufferedOutputUsed + Len >= BUFFERED_OUTPUT_SIZE)
  1518. {
  1519. FlushCallbacks();
  1520. if (Len >= BUFFERED_OUTPUT_SIZE)
  1521. {
  1522. SendOutput(Mask, Text);
  1523. LeaveCriticalSection(&g_QuickLock);
  1524. return;
  1525. }
  1526. g_BufferedOutputMask = Mask;
  1527. }
  1528. memcpy(g_BufferedOutput + g_BufferedOutputUsed, Text, Len + 1);
  1529. g_BufferedOutputUsed += Len;
  1530. LeaveCriticalSection(&g_QuickLock);
  1531. }
  1532. void
  1533. FlushCallbacks(void)
  1534. {
  1535. EnterCriticalSection(&g_QuickLock);
  1536. if (g_BufferedOutputUsed > 0)
  1537. {
  1538. SendOutput(g_BufferedOutputMask, g_BufferedOutput);
  1539. g_BufferedOutputMask = 0;
  1540. g_BufferedOutputUsed = 0;
  1541. g_LastFlushTicks = GetTickCount();
  1542. }
  1543. LeaveCriticalSection(&g_QuickLock);
  1544. }
  1545. void
  1546. TimedFlushCallbacks(void)
  1547. {
  1548. EnterCriticalSection(&g_QuickLock);
  1549. if (g_BufferedOutputUsed > 0)
  1550. {
  1551. ULONG Ticks = GetTickCount();
  1552. // Flush if the last flush was a "long" time ago.
  1553. if (g_LastFlushTicks == 0 ||
  1554. g_LastFlushTicks > Ticks ||
  1555. (Ticks - g_LastFlushTicks) > MAX_FLUSH_DELAY)
  1556. {
  1557. FlushCallbacks();
  1558. }
  1559. }
  1560. LeaveCriticalSection(&g_QuickLock);
  1561. }
  1562. #if 0
  1563. #define DBGHIST(Args) g_NtDllCalls.DbgPrint Args
  1564. #else
  1565. #define DBGHIST(Args)
  1566. #endif
  1567. void
  1568. WriteHistoryEntry(ULONG Mask, PCSTR Text, ULONG Len)
  1569. {
  1570. PSTR Buf;
  1571. DBG_ASSERT((PSTR)g_OutHistWrite + sizeof(OutHistoryEntryHeader) +
  1572. Len + 1 <= g_OutHistory + g_OutHistoryActualSize);
  1573. if (Mask != g_OutHistWriteMask)
  1574. {
  1575. // Start new entry.
  1576. g_OutHistWrite->Mask = Mask;
  1577. g_OutHistWriteMask = Mask;
  1578. Buf = (PSTR)(g_OutHistWrite + 1);
  1579. g_OutHistoryUsed += sizeof(OutHistoryEntryHeader);
  1580. DBGHIST((" Write new "));
  1581. }
  1582. else
  1583. {
  1584. // Merge with previous entry.
  1585. Buf = (PSTR)g_OutHistWrite - 1;
  1586. g_OutHistoryUsed--;
  1587. DBGHIST((" Merge old "));
  1588. }
  1589. DBGHIST(("entry %p:%X, %d\n", g_OutHistWrite, Mask, Len));
  1590. // Len does not include the terminator here so
  1591. // always append a terminator.
  1592. memcpy(Buf, Text, Len);
  1593. Buf += Len;
  1594. *Buf++ = 0;
  1595. g_OutHistWrite = (OutHistoryEntry)Buf;
  1596. g_OutHistoryUsed += Len + 1;
  1597. DBG_ASSERT(g_OutHistoryUsed <= g_OutHistoryActualSize);
  1598. }
  1599. void
  1600. AddToOutputHistory(ULONG Mask, PCSTR Text, ULONG Len)
  1601. {
  1602. if (Len == 0 || g_OutHistoryRequestedSize == 0)
  1603. {
  1604. return;
  1605. }
  1606. if (g_OutHistory == NULL)
  1607. {
  1608. // Output history buffer hasn't been allocated yet,
  1609. // so go ahead and do it now.
  1610. g_OutHistory = (PSTR)malloc(g_OutHistoryRequestedSize);
  1611. if (g_OutHistory == NULL)
  1612. {
  1613. return;
  1614. }
  1615. // Reserve space for a trailing header as terminator.
  1616. g_OutHistoryActualSize = g_OutHistoryRequestedSize -
  1617. sizeof(OutHistoryEntryHeader);
  1618. }
  1619. ULONG TotalLen = Len + sizeof(OutHistoryEntryHeader) + 1;
  1620. DBGHIST(("Add %X, %d\n", Mask, Len));
  1621. if (TotalLen > g_OutHistoryActualSize)
  1622. {
  1623. Text += TotalLen - g_OutHistoryActualSize;
  1624. TotalLen = g_OutHistoryActualSize;
  1625. Len = TotalLen - sizeof(OutHistoryEntryHeader) - 1;
  1626. }
  1627. if (g_OutHistWrite == NULL)
  1628. {
  1629. g_OutHistRead = (OutHistoryEntry)g_OutHistory;
  1630. g_OutHistWrite = (OutHistoryEntry)g_OutHistory;
  1631. g_OutHistWriteMask = 0;
  1632. }
  1633. while (Len > 0)
  1634. {
  1635. ULONG Left;
  1636. if (g_OutHistoryUsed == 0 || g_OutHistWrite > g_OutHistRead)
  1637. {
  1638. Left = g_OutHistoryActualSize -
  1639. (ULONG)((PSTR)g_OutHistWrite - g_OutHistory);
  1640. if (TotalLen > Left)
  1641. {
  1642. // See if it's worth splitting this request to
  1643. // fill the space at the end of the buffer.
  1644. if (Left >= MIN_HISTORY_ENTRY_SIZE &&
  1645. (TotalLen - Left) >= MIN_HISTORY_ENTRY_SIZE)
  1646. {
  1647. ULONG Used = Left - sizeof(OutHistoryEntryHeader) - 1;
  1648. // Pack as much data as possible into the
  1649. // end of the buffer.
  1650. WriteHistoryEntry(Mask, Text, Used);
  1651. Text += Used;
  1652. Len -= Used;
  1653. TotalLen -= Used;
  1654. }
  1655. // Terminate the buffer and wrap around. A header's
  1656. // worth of space is reserved at the buffer end so
  1657. // there should always be enough space for this.
  1658. DBG_ASSERT((ULONG)((PSTR)g_OutHistWrite - g_OutHistory) <=
  1659. g_OutHistoryActualSize);
  1660. g_OutHistWrite->Mask = 0;
  1661. g_OutHistWriteMask = 0;
  1662. g_OutHistWrite = (OutHistoryEntry)g_OutHistory;
  1663. Left = (ULONG)((PUCHAR)g_OutHistRead - (PUCHAR)g_OutHistWrite);
  1664. }
  1665. }
  1666. else
  1667. {
  1668. Left = (ULONG)((PUCHAR)g_OutHistRead - (PUCHAR)g_OutHistWrite);
  1669. }
  1670. if (TotalLen > Left)
  1671. {
  1672. ULONG Need = TotalLen - Left;
  1673. // Advance the read pointer to make room.
  1674. while (Need > 0)
  1675. {
  1676. PSTR EntText = (PSTR)(g_OutHistRead + 1);
  1677. ULONG EntTextLen = strlen(EntText);
  1678. ULONG EntTotal =
  1679. sizeof(OutHistoryEntryHeader) + EntTextLen + 1;
  1680. if (EntTotal <= Need ||
  1681. EntTotal - Need < MIN_HISTORY_ENTRY_SIZE)
  1682. {
  1683. DBGHIST((" Remove %p:%X, %d\n", g_OutHistRead,
  1684. g_OutHistRead->Mask, EntTextLen));
  1685. // Remove the whole entry.
  1686. g_OutHistRead = (OutHistoryEntry)
  1687. ((PUCHAR)g_OutHistRead + EntTotal);
  1688. DBG_ASSERT((ULONG)((PSTR)g_OutHistRead - g_OutHistory) <=
  1689. g_OutHistoryActualSize);
  1690. if (g_OutHistRead->Mask == 0)
  1691. {
  1692. g_OutHistRead = (OutHistoryEntry)g_OutHistory;
  1693. }
  1694. Need -= EntTotal <= Need ? EntTotal : Need;
  1695. DBG_ASSERT(g_OutHistoryUsed >= EntTotal);
  1696. g_OutHistoryUsed -= EntTotal;
  1697. }
  1698. else
  1699. {
  1700. OutHistoryEntryHeader EntHdr = *g_OutHistRead;
  1701. DBGHIST((" Trim %p:%X, %d\n", g_OutHistRead,
  1702. g_OutHistRead->Mask, EntTextLen));
  1703. // Remove part of the head of the entry.
  1704. g_OutHistRead = (OutHistoryEntry)
  1705. ((PUCHAR)g_OutHistRead + Need);
  1706. DBG_ASSERT((ULONG)
  1707. ((PSTR)g_OutHistRead + (EntTotal - Need) -
  1708. g_OutHistory) <= g_OutHistoryActualSize);
  1709. *g_OutHistRead = EntHdr;
  1710. DBG_ASSERT(g_OutHistoryUsed >= Need);
  1711. g_OutHistoryUsed -= Need;
  1712. Need = 0;
  1713. }
  1714. DBGHIST((" Advance read to %p:%X\n",
  1715. g_OutHistRead, g_OutHistRead->Mask));
  1716. }
  1717. }
  1718. else
  1719. {
  1720. WriteHistoryEntry(Mask, Text, Len);
  1721. break;
  1722. }
  1723. }
  1724. DBGHIST(("History read %p, write %p, used %d\n",
  1725. g_OutHistRead, g_OutHistWrite, g_OutHistoryUsed));
  1726. }
  1727. void
  1728. SendOutputHistory(DebugClient* Client, ULONG HistoryLimit)
  1729. {
  1730. if (g_OutHistRead == NULL ||
  1731. Client->m_OutputCb == NULL ||
  1732. (Client->m_OutMask & g_OutHistoryMask) == 0 ||
  1733. HistoryLimit == 0)
  1734. {
  1735. return;
  1736. }
  1737. FlushCallbacks();
  1738. OutHistoryEntry Ent;
  1739. ULONG Total;
  1740. ULONG Len;
  1741. Ent = g_OutHistRead;
  1742. Total = 0;
  1743. while (Ent != g_OutHistWrite)
  1744. {
  1745. if (Ent->Mask == 0)
  1746. {
  1747. Ent = (OutHistoryEntry)g_OutHistory;
  1748. }
  1749. PSTR Text = (PSTR)(Ent + 1);
  1750. Len = strlen(Text);
  1751. Total += Len;
  1752. Ent = (OutHistoryEntry)(Text + Len + 1);
  1753. }
  1754. DBGHIST(("Total history %X\n", Total));
  1755. Ent = g_OutHistRead;
  1756. while (Ent != g_OutHistWrite)
  1757. {
  1758. if (Ent->Mask == 0)
  1759. {
  1760. Ent = (OutHistoryEntry)g_OutHistory;
  1761. }
  1762. PSTR Text = (PSTR)(Ent + 1);
  1763. Len = strlen(Text);
  1764. if (Total - Len <= HistoryLimit)
  1765. {
  1766. PSTR Part = Text;
  1767. if (Total > HistoryLimit)
  1768. {
  1769. Part += Total - HistoryLimit;
  1770. }
  1771. DBGHIST(("Send %p:%X, %d\n",
  1772. Ent, Ent->Mask, strlen(Part)));
  1773. Client->m_OutputCb->Output(Ent->Mask, Part);
  1774. }
  1775. Total -= Len;
  1776. Ent = (OutHistoryEntry)(Text + Len + 1);
  1777. }
  1778. }
  1779. void
  1780. StartOutLine(ULONG Mask, ULONG Flags)
  1781. {
  1782. if ((Flags & OUT_LINE_NO_TIMESTAMP) == 0 &&
  1783. g_EchoEventTimestamps)
  1784. {
  1785. MaskOut(Mask, "%s: ", TimeToStr((ULONG)time(NULL)));
  1786. }
  1787. if ((Flags & OUT_LINE_NO_PREFIX) == 0 &&
  1788. g_OutputLinePrefix)
  1789. {
  1790. MaskOut(Mask, "%s", g_OutputLinePrefix);
  1791. }
  1792. }
  1793. //
  1794. // Translates various printf formats to account for the target platform.
  1795. //
  1796. // This looks for %p type format and truncates the top 4 bytes of the ULONG64
  1797. // address argument if the debugee is a 32 bit machine.
  1798. // The %p is replaced by %I64x in format string.
  1799. //
  1800. BOOL
  1801. TranslateFormat(
  1802. LPSTR formatOut,
  1803. LPCSTR format,
  1804. va_list args,
  1805. ULONG formatOutSize
  1806. )
  1807. {
  1808. #define Duplicate(j,i) (formatOut[j++] = format[i++])
  1809. ULONG minSize = strlen(format), i = 0, j = 0;
  1810. CHAR c;
  1811. BOOL TypeFormat = FALSE;
  1812. BOOL FormatChanged = FALSE;
  1813. do
  1814. {
  1815. c = format[i];
  1816. if (c=='%')
  1817. {
  1818. TypeFormat = !TypeFormat;
  1819. }
  1820. if (TypeFormat)
  1821. {
  1822. switch (c)
  1823. {
  1824. case 'c': case 'C': case 'i': case 'd':
  1825. case 'o': case 'u': case 'x': case 'X':
  1826. Duplicate(j,i);
  1827. va_arg(args, int);
  1828. TypeFormat = FALSE;
  1829. break;
  1830. case 'e': case 'E': case 'f': case 'g':
  1831. case 'G':
  1832. Duplicate(j,i);
  1833. va_arg(args, double);
  1834. TypeFormat = FALSE;
  1835. break;
  1836. case 'n':
  1837. Duplicate(j,i);
  1838. va_arg(args, int*);
  1839. TypeFormat = FALSE;
  1840. break;
  1841. case 'N':
  1842. // Native pointer, turns into %p.
  1843. formatOut[j++] = 'p';
  1844. FormatChanged = TRUE;
  1845. i++;
  1846. va_arg(args, void*);
  1847. TypeFormat = FALSE;
  1848. break;
  1849. case 's': case 'S':
  1850. Duplicate(j,i);
  1851. va_arg(args, char*);
  1852. TypeFormat = FALSE;
  1853. break;
  1854. case 'I':
  1855. if ((format[i+1] == '6') && (format[i+2] == '4'))
  1856. {
  1857. Duplicate(j,i);
  1858. Duplicate(j,i);
  1859. va_arg(args, ULONG64);
  1860. TypeFormat = FALSE;
  1861. }
  1862. // dprintf("I64 a0 %lx, off %lx\n", args.a0, args.offset);
  1863. Duplicate(j,i);
  1864. break;
  1865. case 'z': case 'Z':
  1866. // unicode string
  1867. Duplicate(j,i);
  1868. va_arg(args, void*);
  1869. TypeFormat = FALSE;
  1870. break;
  1871. case 'p':
  1872. case 'P':
  1873. minSize +=3;
  1874. if (format[i-1] == '%')
  1875. {
  1876. minSize++;
  1877. if (g_Machine->m_Ptr64)
  1878. {
  1879. minSize += 2;
  1880. if (minSize > formatOutSize)
  1881. {
  1882. return FALSE;
  1883. }
  1884. formatOut[j++] = '0';
  1885. formatOut[j++] = '1';
  1886. formatOut[j++] = '6';
  1887. }
  1888. else
  1889. {
  1890. if (minSize > formatOutSize)
  1891. {
  1892. return FALSE;
  1893. }
  1894. formatOut[j++] = '0';
  1895. formatOut[j++] = '8';
  1896. }
  1897. }
  1898. if (minSize > formatOutSize)
  1899. {
  1900. return FALSE;
  1901. }
  1902. formatOut[j++] = 'I';
  1903. formatOut[j++] = '6';
  1904. formatOut[j++] = '4';
  1905. formatOut[j++] = (c == 'p') ? 'x' : 'X'; ++i;
  1906. FormatChanged = TRUE;
  1907. if (!g_Machine->m_Ptr64)
  1908. {
  1909. PULONG64 Arg;
  1910. #ifdef _M_ALPHA
  1911. Arg = (PULONG64) ((args.a0)+args.offset);
  1912. //dprintf("a0 %lx, off %lx\n", args.a0, args.offset);
  1913. #else
  1914. Arg = (PULONG64) (args);
  1915. #endif
  1916. //
  1917. // Truncate signextended addresses
  1918. //
  1919. *Arg = (ULONG64) (ULONG) *Arg;
  1920. }
  1921. va_arg(args, ULONG64);
  1922. TypeFormat = FALSE;
  1923. break;
  1924. default:
  1925. Duplicate(j,i);
  1926. } /* switch */
  1927. }
  1928. else
  1929. {
  1930. Duplicate(j,i);
  1931. }
  1932. }
  1933. while (format[i] != '\0');
  1934. formatOut[j] = '\0';
  1935. return FormatChanged;
  1936. #undef Duplicate
  1937. }
  1938. void
  1939. MaskOutVa(ULONG Mask, PCSTR Format, va_list Args, BOOL Translate)
  1940. {
  1941. int Len;
  1942. ULONG OutTo = g_OutputControl & DEBUG_OUTCTL_SEND_MASK;
  1943. HRESULT Status;
  1944. // Reject output as quickly as possible to avoid
  1945. // doing the format translation and sprintf.
  1946. if (OutTo == DEBUG_OUTCTL_IGNORE ||
  1947. (((g_OutputControl & DEBUG_OUTCTL_NOT_LOGGED) ||
  1948. (Mask & g_OutHistoryMask) == 0) &&
  1949. ((g_OutputControl & DEBUG_OUTCTL_NOT_LOGGED) ||
  1950. (Mask & g_LogMask) == 0 ||
  1951. g_LogFile == -1) &&
  1952. (OutTo == DEBUG_OUTCTL_LOG_ONLY ||
  1953. ((g_OutputControl & DEBUG_OUTCTL_OVERRIDE_MASK) == 0 &&
  1954. (OutTo == DEBUG_OUTCTL_THIS_CLIENT &&
  1955. ((Mask & g_OutputClient->m_OutMask) == 0 ||
  1956. g_OutputClient->m_OutputCb == NULL)) ||
  1957. (Mask & g_AllOutMask) == 0))))
  1958. {
  1959. return;
  1960. }
  1961. // Do not suspend the engine lock as this may be called
  1962. // in the middle of an operation.
  1963. EnterCriticalSection(&g_QuickLock);
  1964. __try
  1965. {
  1966. if (Translate &&
  1967. TranslateFormat(g_FormatBuffer, Format, Args, OUT_BUFFER_SIZE - 1))
  1968. {
  1969. Len = _vsnprintf(g_OutBuffer, OUT_BUFFER_SIZE - 1,
  1970. g_FormatBuffer, Args);
  1971. }
  1972. else
  1973. {
  1974. Len = _vsnprintf(g_OutBuffer, OUT_BUFFER_SIZE - 1, Format, Args);
  1975. }
  1976. // Check and see if this output is filtered away.
  1977. if ((Mask & DEBUG_OUTPUT_DEBUGGEE) &&
  1978. g_OutFilterPattern[0] &&
  1979. !(MatchPattern(g_OutBuffer, g_OutFilterPattern) ==
  1980. g_OutFilterResult))
  1981. {
  1982. __leave;
  1983. }
  1984. // If the caller doesn't think this output should
  1985. // be logged it probably also shouldn't go in the
  1986. // history.
  1987. if ((g_OutputControl & DEBUG_OUTCTL_NOT_LOGGED) == 0 &&
  1988. (Mask & g_OutHistoryMask))
  1989. {
  1990. AddToOutputHistory(Mask, g_OutBuffer, Len);
  1991. }
  1992. if ((g_OutputControl & DEBUG_OUTCTL_NOT_LOGGED) == 0 &&
  1993. (Mask & g_LogMask) &&
  1994. g_LogFile != -1)
  1995. {
  1996. _write(g_LogFile, g_OutBuffer, Len);
  1997. }
  1998. if (OutTo == DEBUG_OUTCTL_LOG_ONLY)
  1999. {
  2000. __leave;
  2001. }
  2002. if (g_BufferOutput)
  2003. {
  2004. BufferOutput(Mask, g_OutBuffer, Len);
  2005. }
  2006. else
  2007. {
  2008. SendOutput(Mask, g_OutBuffer);
  2009. }
  2010. }
  2011. __except(EXCEPTION_EXECUTE_HANDLER)
  2012. {
  2013. OutputDebugStringA("Exception in MaskOutVa\n");
  2014. }
  2015. LeaveCriticalSection(&g_QuickLock);
  2016. }
  2017. void __cdecl
  2018. MaskOut(ULONG Mask, PCSTR Format, ...)
  2019. {
  2020. va_list Args;
  2021. va_start(Args, Format);
  2022. MaskOutVa(Mask, Format, Args, TRUE);
  2023. va_end(Args);
  2024. }
  2025. void __cdecl
  2026. dprintf(PCSTR Format, ...)
  2027. {
  2028. va_list Args;
  2029. va_start(Args, Format);
  2030. MaskOutVa(DEBUG_OUTPUT_NORMAL, Format, Args, FALSE);
  2031. va_end(Args);
  2032. }
  2033. #define OUT_FN(Name, Mask) \
  2034. void __cdecl \
  2035. Name(PCSTR Format, ...) \
  2036. { \
  2037. va_list Args; \
  2038. va_start(Args, Format); \
  2039. MaskOutVa(Mask, Format, Args, TRUE); \
  2040. va_end(Args); \
  2041. }
  2042. OUT_FN(dprintf64, DEBUG_OUTPUT_NORMAL)
  2043. OUT_FN(ErrOut, DEBUG_OUTPUT_ERROR)
  2044. OUT_FN(WarnOut, DEBUG_OUTPUT_WARNING)
  2045. OUT_FN(VerbOut, DEBUG_OUTPUT_VERBOSE)
  2046. OUT_FN(BpOut, DEBUG_IOUTPUT_BREAKPOINT)
  2047. OUT_FN(EventOut, DEBUG_IOUTPUT_EVENT)
  2048. OUT_FN(KdOut, DEBUG_IOUTPUT_KD_PROTOCOL)