Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2688 lines
80 KiB

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