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.

5517 lines
164 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Event waiting and processing.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include <common.ver>
  10. // An event can be signalled on certain events for
  11. // synchronizing other programs with the debugger.
  12. HANDLE g_EventToSignal;
  13. // When both creating a debuggee process and attaching
  14. // the debuggee is left suspended until the attach
  15. // succeeds. At that point the created process's thread
  16. // is resumed.
  17. ULONG64 g_ThreadToResume;
  18. ULONG g_ExecutionStatusRequest = DEBUG_STATUS_NO_CHANGE;
  19. // Currently in seconds.
  20. ULONG g_PendingBreakInTimeoutLimit = 30;
  21. // Set when events occur. Can't always be retrieved from
  22. // g_Event{Process|Thread}->SystemId since the events may be creation events
  23. // where the info structures haven't been created yet.
  24. ULONG g_EventThreadSysId;
  25. ULONG g_EventProcessSysId;
  26. ULONG g_LastEventType;
  27. char g_LastEventDesc[MAX_IMAGE_PATH + 64];
  28. PVOID g_LastEventExtraData;
  29. ULONG g_LastEventExtraDataSize;
  30. LAST_EVENT_INFO g_LastEventInfo;
  31. // Set when lookups are done during event handling.
  32. PTHREAD_INFO g_EventThread;
  33. PPROCESS_INFO g_EventProcess;
  34. // This is zero for events without a PC.
  35. ULONG64 g_EventPc;
  36. PDEBUG_EXCEPTION_FILTER_PARAMETERS g_EventExceptionFilter;
  37. ULONG g_ExceptionFirstChance;
  38. ULONG g_SystemErrorOutput = SLE_ERROR;
  39. ULONG g_SystemErrorBreak = SLE_ERROR;
  40. ULONG g_SuspendedExecutionStatus;
  41. CHAR g_SuspendedCmdState;
  42. PDBGKD_ANY_CONTROL_REPORT g_ControlReport;
  43. PCHAR g_StateChangeData;
  44. CHAR g_StateChangeBuffer[2 * PACKET_MAX_SIZE];
  45. DBGKD_ANY_WAIT_STATE_CHANGE g_StateChange;
  46. DBGKD_ANY_CONTROL_SET g_ControlSet;
  47. ULONG64 g_SystemRangeStart;
  48. ULONG64 g_SystemCallVirtualAddress;
  49. ULONG g_SwitchProcessor;
  50. KDDEBUGGER_DATA64 KdDebuggerData;
  51. ULONG64 g_KdDebuggerDataBlock;
  52. char g_CreateProcessBreakName[FILTER_MAX_ARGUMENT];
  53. char g_ExitProcessBreakName[FILTER_MAX_ARGUMENT];
  54. char g_LoadDllBreakName[FILTER_MAX_ARGUMENT];
  55. char g_UnloadDllBaseName[FILTER_MAX_ARGUMENT];
  56. ULONG64 g_UnloadDllBase;
  57. char g_OutEventFilterPattern[FILTER_MAX_ARGUMENT];
  58. DEBUG_EXCEPTION_FILTER_PARAMETERS
  59. g_OtherExceptionList[OTHER_EXCEPTION_LIST_MAX];
  60. EVENT_COMMAND g_OtherExceptionCommands[OTHER_EXCEPTION_LIST_MAX];
  61. ULONG g_NumOtherExceptions;
  62. char g_EventLog[512];
  63. PSTR g_EventLogEnd = g_EventLog;
  64. EVENT_FILTER g_EventFilters[] =
  65. {
  66. //
  67. // Debug events.
  68. //
  69. "Create thread", "ct", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  70. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  71. NULL, NULL, NULL, 0, 0, NULL, 0,
  72. "Exit thread", "et", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  73. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  74. NULL, NULL, NULL, 0, 0, NULL, 0,
  75. "Create process", "cpr", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  76. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  77. NULL, NULL, NULL, 0, 0, g_CreateProcessBreakName, 0,
  78. "Exit process", "epr", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  79. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  80. NULL, NULL, NULL, 0, 0, g_ExitProcessBreakName, 0,
  81. "Load module", "ld", NULL, NULL, 0, DEBUG_FILTER_OUTPUT,
  82. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  83. NULL, NULL, NULL, 0, 0, g_LoadDllBreakName, 0,
  84. "Unload module", "ud", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  85. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  86. NULL, NULL, NULL, 0, 0, g_UnloadDllBaseName, 0,
  87. "System error", "ser", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  88. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  89. NULL, NULL, NULL, 0, 0, NULL, 0,
  90. "Initial breakpoint", "ibp", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  91. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, 0,
  92. NULL, NULL, NULL, 0, 0, NULL, 0,
  93. "Initial module load", "iml", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  94. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, 0,
  95. NULL, NULL, NULL, 0, 0, NULL, 0,
  96. "Debuggee output", "out", NULL, NULL, 0, DEBUG_FILTER_OUTPUT,
  97. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, 0,
  98. NULL, NULL, NULL, 0, 0, g_OutEventFilterPattern, 0,
  99. // Default exception filter.
  100. "Unknown exception", NULL, NULL, NULL, 0, DEBUG_FILTER_SECOND_CHANCE_BREAK,
  101. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, 0,
  102. NULL, NULL, NULL, 0, 0, NULL, 0,
  103. //
  104. // Specific exceptions.
  105. //
  106. "Access violation", "av", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  107. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_ACCESS_VIOLATION,
  108. NULL, NULL, NULL, 0, 0, NULL, 0,
  109. "Break instruction exception", "bpe", "bpec", NULL, 0, DEBUG_FILTER_BREAK,
  110. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, STATUS_BREAKPOINT,
  111. NULL, NULL, NULL, 0, 0, NULL, 0,
  112. "C++ EH exception", "eh", NULL, NULL, 0, DEBUG_FILTER_SECOND_CHANCE_BREAK,
  113. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_CPP_EH_EXCEPTION,
  114. NULL, NULL, NULL, 0, 0, NULL, 0,
  115. "Control-Break exception", "cce", "cc", NULL, 0, DEBUG_FILTER_BREAK,
  116. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, DBG_CONTROL_BREAK,
  117. NULL, NULL, NULL, 0, 0, NULL, 0,
  118. "Control-C exception", "cce", "cc", NULL, 0, DEBUG_FILTER_BREAK,
  119. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, DBG_CONTROL_C,
  120. NULL, NULL, NULL, 0, 0, NULL, 0,
  121. "Data misaligned", "dm", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  122. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_DATATYPE_MISALIGNMENT,
  123. NULL, NULL, NULL, 0, 0, NULL, 0,
  124. "Illegal instruction", "ii", NULL, NULL, 0, DEBUG_FILTER_SECOND_CHANCE_BREAK,
  125. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_ILLEGAL_INSTRUCTION,
  126. NULL, NULL, NULL, 0, 0, NULL, 0,
  127. "In-page I/O error", "ip", NULL, " %I64x", 2, DEBUG_FILTER_BREAK,
  128. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_IN_PAGE_ERROR,
  129. NULL, NULL, NULL, 0, 0, NULL, 0,
  130. "Integer divide-by-zero", "dz", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  131. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_INTEGER_DIVIDE_BY_ZERO,
  132. NULL, NULL, NULL, 0, 0, NULL, 0,
  133. "Integer overflow", "iov", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  134. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_INTEGER_OVERFLOW,
  135. NULL, NULL, NULL, 0, 0, NULL, 0,
  136. "Invalid handle", "ch", "hc", NULL, 0, DEBUG_FILTER_BREAK,
  137. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_INVALID_HANDLE,
  138. NULL, NULL, NULL, 0, 0, NULL, 0,
  139. "Invalid lock sequence", "lsq", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  140. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_INVALID_LOCK_SEQUENCE,
  141. NULL, NULL, NULL, 0, 0, NULL, 0,
  142. "Invalid system call", "isc", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  143. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_INVALID_SYSTEM_SERVICE,
  144. NULL, NULL, NULL, 0, 0, NULL, 0,
  145. "Port disconnected", "3c", NULL, NULL, 0, DEBUG_FILTER_SECOND_CHANCE_BREAK,
  146. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_PORT_DISCONNECTED,
  147. NULL, NULL, NULL, 0, 0, NULL, 0,
  148. "Single step exception", "sse", "ssec", NULL, 0, DEBUG_FILTER_BREAK,
  149. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, STATUS_SINGLE_STEP,
  150. NULL, NULL, NULL, 0, 0, NULL, 0,
  151. "Stack overflow", "sov", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  152. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_STACK_OVERFLOW,
  153. NULL, NULL, NULL, 0, 0, NULL, 0,
  154. "Visual C++ exception", "vcpp", NULL, NULL, 0, DEBUG_FILTER_IGNORE,
  155. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, STATUS_VCPP_EXCEPTION,
  156. NULL, NULL, NULL, 0, 0, NULL, 0,
  157. "Wake debugger", "wkd", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  158. DEBUG_FILTER_GO_NOT_HANDLED, 0, 0, 0, STATUS_WAKE_SYSTEM_DEBUGGER,
  159. NULL, NULL, NULL, 0, 0, NULL, 0,
  160. "WOW64 breakpoint", "wob", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  161. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, STATUS_WX86_BREAKPOINT,
  162. NULL, NULL, NULL, 0, 0, NULL, 0,
  163. "WOW64 single step exception", "wos", NULL, NULL, 0, DEBUG_FILTER_BREAK,
  164. DEBUG_FILTER_GO_HANDLED, 0, 0, 0, STATUS_WX86_SINGLE_STEP,
  165. NULL, NULL, NULL, 0, 0, NULL, 0,
  166. };
  167. void
  168. ClearEventLog(void)
  169. {
  170. g_EventLogEnd = g_EventLog;
  171. *g_EventLogEnd = 0;
  172. }
  173. void
  174. OutputEventLog(void)
  175. {
  176. if (g_EventLogEnd > g_EventLog)
  177. {
  178. dprintf("%s", g_EventLog);
  179. }
  180. else
  181. {
  182. dprintf("Event log is empty\n");
  183. }
  184. dprintf("Last event: %s\n", g_LastEventDesc);
  185. }
  186. void
  187. LogEventDesc(PSTR Desc, ULONG ProcId, ULONG ThreadId)
  188. {
  189. // Extra space for newline and terminator.
  190. int Len = strlen(Desc) + 2;
  191. if (IS_USER_TARGET())
  192. {
  193. // Space for process and thread IDs.
  194. Len += 16;
  195. }
  196. if (Len > sizeof(g_EventLog))
  197. {
  198. Len = sizeof(g_EventLog);
  199. }
  200. int Avail = (int)(sizeof(g_EventLog) - (g_EventLogEnd - g_EventLog));
  201. if (g_EventLogEnd > g_EventLog && Len > Avail)
  202. {
  203. PSTR Save = g_EventLog;
  204. int Need = Len - Avail;
  205. while (Need > 0)
  206. {
  207. PSTR Scan = strchr(Save, '\n');
  208. if (Scan == NULL)
  209. {
  210. break;
  211. }
  212. Scan++;
  213. Need -= (int)(Scan - Save);
  214. Save = Scan;
  215. }
  216. if (Need > 0)
  217. {
  218. // Couldn't make enough space so throw
  219. // everything away.
  220. g_EventLogEnd = g_EventLog;
  221. *g_EventLogEnd = 0;
  222. }
  223. else
  224. {
  225. Need = strlen(Save);
  226. memmove(g_EventLog, Save, Need + 1);
  227. g_EventLogEnd = g_EventLog + Need;
  228. }
  229. }
  230. Avail = (int)(sizeof(g_EventLog) - (g_EventLogEnd - g_EventLog));
  231. if (IS_USER_TARGET())
  232. {
  233. sprintf(g_EventLogEnd, "%04x.%04x: ", ProcId, ThreadId);
  234. Avail -= strlen(g_EventLogEnd);
  235. g_EventLogEnd += strlen(g_EventLogEnd);
  236. }
  237. strncat(g_EventLogEnd, Desc, Avail);
  238. g_EventLogEnd += strlen(g_EventLogEnd);
  239. *g_EventLogEnd++ = '\n';
  240. *g_EventLogEnd = 0;
  241. }
  242. void
  243. DiscardLastEventInfo(void)
  244. {
  245. if (g_LastEventDesc[0])
  246. {
  247. LogEventDesc(g_LastEventDesc, g_EventProcessSysId, g_EventThreadSysId);
  248. }
  249. g_LastEventType = 0;
  250. g_LastEventDesc[0] = 0;
  251. g_LastEventExtraData = NULL;
  252. g_LastEventExtraDataSize = 0;
  253. }
  254. void
  255. DiscardLastEvent(void)
  256. {
  257. // Do this before clearing the other information so
  258. // it's available for the log.
  259. DiscardLastEventInfo();
  260. g_EngDefer &= ~ENG_DEFER_CONTINUE_EVENT;
  261. g_EventProcessSysId = 0;
  262. g_EventThreadSysId = 0;
  263. g_EventPc = 0;
  264. // Clear any cached memory read during the last event.
  265. InvalidateMemoryCaches();
  266. }
  267. ULONG
  268. EventStatusToContinue(ULONG EventStatus)
  269. {
  270. switch(EventStatus)
  271. {
  272. case DEBUG_STATUS_GO_NOT_HANDLED:
  273. return DBG_EXCEPTION_NOT_HANDLED;
  274. case DEBUG_STATUS_GO_HANDLED:
  275. return DBG_EXCEPTION_HANDLED;
  276. case DEBUG_STATUS_NO_CHANGE:
  277. case DEBUG_STATUS_IGNORE_EVENT:
  278. case DEBUG_STATUS_GO:
  279. case DEBUG_STATUS_STEP_OVER:
  280. case DEBUG_STATUS_STEP_INTO:
  281. case DEBUG_STATUS_STEP_BRANCH:
  282. return DBG_CONTINUE;
  283. default:
  284. DBG_ASSERT(FALSE);
  285. return DBG_CONTINUE;
  286. }
  287. }
  288. HRESULT
  289. PrepareForWait(ULONG Flags, PULONG ContinueStatus)
  290. {
  291. HRESULT Status;
  292. Status = PrepareForExecution(g_ExecutionStatusRequest);
  293. if (Status != S_OK)
  294. {
  295. // If S_FALSE, we're at a hard breakpoint so the only thing that
  296. // happens is that the PC is adjusted and the "wait"
  297. // can succeed immediately.
  298. // Otherwise we failed execution preparation. Either way
  299. // we need to try and prepare for calls.
  300. PrepareForCalls(0);
  301. return FAILED(Status) ? Status : S_OK;
  302. }
  303. *ContinueStatus = EventStatusToContinue(g_ExecutionStatusRequest);
  304. g_EngStatus |= ENG_STATUS_WAITING;
  305. return S_OK;
  306. }
  307. DWORD
  308. GetContinueStatus(ULONG FirstChance, ULONG Continue)
  309. {
  310. if (!FirstChance || Continue == DEBUG_FILTER_GO_HANDLED)
  311. {
  312. return DBG_EXCEPTION_HANDLED;
  313. }
  314. else
  315. {
  316. return DBG_EXCEPTION_NOT_HANDLED;
  317. }
  318. }
  319. void
  320. ProcessDeferredWork(PULONG ContinueStatus)
  321. {
  322. if (g_EngDefer & ENG_DEFER_SET_EVENT)
  323. {
  324. // This event signalling is used by the system
  325. // to synchronize with the debugger when starting
  326. // the debugger via AeDebug. The -e parameter
  327. // to ntsd sets this value.
  328. // It could potentially be used in other situations.
  329. if (g_EventToSignal != NULL)
  330. {
  331. SetEvent(g_EventToSignal);
  332. g_EventToSignal = NULL;
  333. }
  334. g_EngDefer &= ~ENG_DEFER_SET_EVENT;
  335. }
  336. if (g_EngDefer & ENG_DEFER_RESUME_THREAD)
  337. {
  338. DBG_ASSERT(IS_LIVE_USER_TARGET());
  339. ((UserTargetInfo*)g_Target)->m_Services->
  340. ResumeThreads(1, &g_ThreadToResume, NULL);
  341. g_ThreadToResume = 0;
  342. g_EngDefer &= ~ENG_DEFER_RESUME_THREAD;
  343. }
  344. if (g_EngDefer & ENG_DEFER_EXCEPTION_HANDLING)
  345. {
  346. if (*ContinueStatus == DBG_CONTINUE)
  347. {
  348. if (g_EventExceptionFilter != NULL)
  349. {
  350. // A user-visible exception occurred so check on how it
  351. // should be handled.
  352. *ContinueStatus =
  353. GetContinueStatus(g_ExceptionFirstChance,
  354. g_EventExceptionFilter->ContinueOption);
  355. }
  356. else
  357. {
  358. // An internal exception occurred, such as a single-step.
  359. // Force the continue status.
  360. *ContinueStatus = g_ExceptionFirstChance;
  361. }
  362. }
  363. g_EngDefer &= ~ENG_DEFER_EXCEPTION_HANDLING;
  364. }
  365. // If output was deferred but the wait was exited anyway
  366. // a stale defer flag will be left. Make sure it's cleared.
  367. g_EngDefer &= ~ENG_DEFER_OUTPUT_CURRENT_INFO;
  368. // Clear at-initial flags. If the incoming event
  369. // turns out to be one of them it'll turn on the flag.
  370. g_EngStatus &= ~(ENG_STATUS_AT_INITIAL_BREAK |
  371. ENG_STATUS_AT_INITIAL_MODULE_LOAD);
  372. }
  373. BOOL
  374. SuspendExecution(void)
  375. {
  376. if (g_EngStatus & ENG_STATUS_SUSPENDED)
  377. {
  378. // Nothing to do.
  379. return FALSE;
  380. }
  381. g_LastSelector = -1; // Prevent stale selector values
  382. SuspendAllThreads();
  383. // Don't notify on any state changes as
  384. // PrepareForCalls will do a blanket notify later.
  385. g_EngNotify++;
  386. // If we have an event thread select it.
  387. if (g_EventThread != NULL)
  388. {
  389. DBG_ASSERT(g_RegContextThread == NULL);
  390. ChangeRegContext(g_EventThread);
  391. }
  392. // First set the effective machine to the true
  393. // processor type so that real processor information
  394. // can be examined to determine any possible
  395. // alternate execution states.
  396. // No need to notify here as another SetEffMachine
  397. // is coming up.
  398. SetEffMachine(g_TargetMachineType, FALSE);
  399. if (g_EngStatus & ENG_STATUS_STATE_CHANGED)
  400. {
  401. g_Machine->InitializeContext(g_EventPc, g_ControlReport);
  402. g_EngStatus &= ~ENG_STATUS_STATE_CHANGED;
  403. }
  404. if (!IS_DUMP_TARGET())
  405. {
  406. g_Machine->QuietSetTraceMode(TRACE_NONE);
  407. }
  408. // Now determine the executing code type and
  409. // make that the effective machine.
  410. if (IS_CONTEXT_POSSIBLE())
  411. {
  412. g_TargetExecMachine = g_Machine->ExecutingMachine();
  413. }
  414. else
  415. {
  416. // Local kernel debugging doesn't deal with contexts
  417. // as everything would be in the context of the debugger.
  418. // It's safe to just assume the executing machine
  419. // is the target machine, plus this avoids unwanted
  420. // context access.
  421. g_TargetExecMachine = g_TargetMachineType;
  422. }
  423. SetEffMachine(g_TargetExecMachine, TRUE);
  424. // Trace flag should always be clear at this point.
  425. g_EngDefer &= ~ENG_DEFER_HARDWARE_TRACING;
  426. g_EngNotify--;
  427. g_EngStatus |= ENG_STATUS_SUSPENDED;
  428. g_SuspendedExecutionStatus = GetExecutionStatus();
  429. g_SuspendedCmdState = g_CmdState;
  430. g_ContextChanged = FALSE;
  431. return TRUE;
  432. }
  433. HRESULT
  434. ResumeExecution(void)
  435. {
  436. if ((g_EngStatus & ENG_STATUS_SUSPENDED) == 0)
  437. {
  438. // Nothing to do.
  439. return S_OK;
  440. }
  441. if (g_Machine->GetTraceMode() != TRACE_NONE)
  442. {
  443. g_EngDefer |= ENG_DEFER_HARDWARE_TRACING;
  444. }
  445. if (IS_REMOTE_KERNEL_TARGET())
  446. {
  447. g_Machine->KdUpdateControlSet(&g_ControlSet);
  448. g_EngDefer |= ENG_DEFER_UPDATE_CONTROL_SET;
  449. }
  450. // Flush context.
  451. ChangeRegContext(NULL);
  452. // Make sure stale values aren't held across
  453. // executions.
  454. ResetImplicitData();
  455. FlushMachinePerExecutionCaches();
  456. if (!ResumeAllThreads())
  457. {
  458. ChangeRegContext(g_EventThread);
  459. return E_FAIL;
  460. }
  461. g_EngStatus &= ~ENG_STATUS_SUSPENDED;
  462. return S_OK;
  463. }
  464. void
  465. PrepareForCalls(ULONG64 ExtraStatusFlags)
  466. {
  467. BOOL HardBrkpt = FALSE;
  468. ADDR PcAddr;
  469. BOOL Changed = FALSE;
  470. // If there's no event then execution didn't really
  471. // occur so there's no need to suspend. This will happen
  472. // when a debuggee exits or during errors on execution
  473. // preparation.
  474. if (g_EventThreadSysId != 0)
  475. {
  476. if (SuspendExecution())
  477. {
  478. Changed = TRUE;
  479. }
  480. }
  481. else
  482. {
  483. g_CmdState = 'c';
  484. // Force notification in this case to ensure
  485. // that clients know the engine is not running.
  486. Changed = TRUE;
  487. }
  488. if (RemoveBreakpoints())
  489. {
  490. Changed = TRUE;
  491. }
  492. if (g_CmdState != 'c')
  493. {
  494. g_CmdState = 'c';
  495. Changed = TRUE;
  496. if (!IS_CONTEXT_ACCESSIBLE())
  497. {
  498. ADDRFLAT(&PcAddr, 0);
  499. }
  500. else
  501. {
  502. g_Machine->GetPC(&PcAddr);
  503. if (IS_KERNEL_TARGET())
  504. {
  505. HardBrkpt = g_Machine->IsBreakpointInstruction(&PcAddr);
  506. }
  507. }
  508. g_DumpDefault = g_UnasmDefault = g_AssemDefault = PcAddr;
  509. }
  510. g_EngStatus |= ENG_STATUS_PREPARED_FOR_CALLS;
  511. if (HardBrkpt &&
  512. Flat(PcAddr) == KdDebuggerData.BreakpointWithStatus)
  513. {
  514. HandleBPWithStatus();
  515. }
  516. if (Changed)
  517. {
  518. if (IS_MACHINE_ACCESSIBLE())
  519. {
  520. ResetCurrentScopeLazy();
  521. }
  522. // This can produce many notifications. Callers should
  523. // suppress notification when they can to avoid multiple
  524. // notifications during a single operation.
  525. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  526. DEBUG_STATUS_BREAK | ExtraStatusFlags, TRUE);
  527. NotifyChangeDebuggeeState(DEBUG_CDS_ALL, 0);
  528. NotifyExtensions(DEBUG_NOTIFY_SESSION_ACCESSIBLE, 0);
  529. }
  530. else if (ExtraStatusFlags == 0)
  531. {
  532. // We're exiting a wait so force the current execution
  533. // status to be sent to let everybody know that a
  534. // wait is finishing.
  535. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  536. DEBUG_STATUS_BREAK, TRUE);
  537. }
  538. }
  539. HRESULT
  540. PrepareForExecution(ULONG NewStatus)
  541. {
  542. ADDR PcAddr;
  543. BOOL fHardBrkpt = FALSE;
  544. PTHREAD_INFO StepThread = NULL;
  545. ZeroMemory(&g_PrevRelatedPc, sizeof(g_PrevRelatedPc));
  546. // If all processes have exited we don't have any way
  547. // to manipulate the debuggee so we must fail immediately.
  548. if ((g_EngStatus & ENG_STATUS_PROCESSES_ADDED) &&
  549. !ANY_PROCESSES())
  550. {
  551. return E_UNEXPECTED;
  552. }
  553. StepAgain:
  554. // Display current information on intermediate steps where
  555. // the debugger UI isn't even invoked.
  556. if ((g_EngDefer & ENG_DEFER_OUTPUT_CURRENT_INFO) &&
  557. (g_EngStatus & ENG_STATUS_STOP_SESSION) == 0)
  558. {
  559. OutCurInfo(OCI_SYMBOL | OCI_DISASM | OCI_ALLOW_EA |
  560. OCI_ALLOW_REG | OCI_ALLOW_SOURCE | OCI_IGNORE_STATE,
  561. g_Machine->m_AllMask, DEBUG_OUTPUT_PROMPT_REGISTERS);
  562. g_EngDefer &= ~ENG_DEFER_OUTPUT_CURRENT_INFO;
  563. }
  564. // Don't notify on any state changes as
  565. // PrepareForCalls will do a blanket notify later.
  566. g_EngNotify++;
  567. if (g_EngStatus & ENG_STATUS_SUSPENDED)
  568. {
  569. if (g_CmdState != 's')
  570. {
  571. if (NewStatus != DEBUG_STATUS_IGNORE_EVENT)
  572. {
  573. SetExecutionStatus(NewStatus);
  574. DBG_ASSERT(IS_RUNNING(g_CmdState));
  575. }
  576. else
  577. {
  578. NewStatus = g_SuspendedExecutionStatus;
  579. g_CmdState = g_SuspendedCmdState;
  580. }
  581. }
  582. if ((g_StepTraceBp->m_Flags & DEBUG_BREAKPOINT_ENABLED) &&
  583. g_StepTraceBp->m_MatchThread)
  584. {
  585. StepThread = g_StepTraceBp->m_MatchThread;
  586. // Check and see if we need to fake a step/trace
  587. // event when artificially moving beyond a hard-coded
  588. // break instruction.
  589. if (!StepThread->Process->Exited)
  590. {
  591. MachineInfo* Machine = g_Machine;
  592. ChangeRegContext(StepThread);
  593. Machine->GetPC(&PcAddr);
  594. fHardBrkpt = Machine->IsBreakpointInstruction(&PcAddr);
  595. if (fHardBrkpt)
  596. {
  597. g_WatchBeginCurFunc = 1;
  598. Machine->AdjustPCPastBreakpointInstruction
  599. (&PcAddr, DEBUG_BREAKPOINT_CODE);
  600. if (Flat(*g_StepTraceBp->GetAddr()) != OFFSET_TRACE)
  601. {
  602. ULONG NextMachine;
  603. Machine->GetNextOffset(g_StepTraceCmdState == 'p',
  604. g_StepTraceBp->GetAddr(),
  605. &NextMachine);
  606. g_StepTraceBp->SetProcType(NextMachine);
  607. }
  608. GetCurrentMemoryOffsets(&g_StepTraceInRangeStart,
  609. &g_StepTraceInRangeEnd);
  610. if (StepTracePass(&PcAddr))
  611. {
  612. // If the step was passed over go back
  613. // and update things based on the adjusted PC.
  614. g_EngNotify--;
  615. goto StepAgain;
  616. }
  617. }
  618. }
  619. }
  620. // If the last event was a hard-coded breakpoint exception
  621. // we need to move the event thread beyond the break instruction.
  622. // Note that if we continued stepping on that thread it was
  623. // handled above, so we only do this if it's a different
  624. // thread or we're not stepping.
  625. // If the continuation status is not-handled then
  626. // we need to let the int3 get hit again. If we're
  627. // exiting, though, we don't want to do this.
  628. if (g_EventThread != NULL &&
  629. !g_EventThread->Process->Exited &&
  630. !IS_LOCAL_KERNEL_TARGET() &&
  631. g_CmdState != 's' &&
  632. g_EventThread != StepThread &&
  633. (NewStatus != DEBUG_STATUS_GO_NOT_HANDLED ||
  634. (g_EngStatus & ENG_STATUS_STOP_SESSION)))
  635. {
  636. ChangeRegContext(g_EventThread);
  637. g_Machine->GetPC(&PcAddr);
  638. if (g_Machine->IsBreakpointInstruction(&PcAddr))
  639. {
  640. g_Machine->AdjustPCPastBreakpointInstruction
  641. (&PcAddr, DEBUG_BREAKPOINT_CODE);
  642. }
  643. if (StepThread != NULL)
  644. {
  645. ChangeRegContext(StepThread);
  646. }
  647. }
  648. }
  649. HRESULT Status;
  650. if (g_EngStatus & ENG_STATUS_STOP_SESSION)
  651. {
  652. // If we're stopping don't insert breakpoints in
  653. // case we're detaching from the process. In
  654. // that case we want threads to run normally.
  655. Status = S_OK;
  656. }
  657. else
  658. {
  659. Status = InsertBreakpoints();
  660. }
  661. // Resume notification now that modifications are done.
  662. g_EngNotify--;
  663. if (Status != S_OK)
  664. {
  665. return Status;
  666. }
  667. if ((Status = ResumeExecution()) != S_OK)
  668. {
  669. return Status;
  670. }
  671. g_TargetExecMachine = IMAGE_FILE_MACHINE_UNKNOWN;
  672. g_EngStatus &= ~ENG_STATUS_PREPARED_FOR_CALLS;
  673. if (g_CmdState != 's')
  674. {
  675. // Now that we've resumed execution notify about the change.
  676. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  677. NewStatus, TRUE);
  678. NotifyExtensions(DEBUG_NOTIFY_SESSION_INACCESSIBLE, 0);
  679. }
  680. if (fHardBrkpt && StepThread != NULL)
  681. {
  682. // We're stepping over a hard breakpoint. This is
  683. // done entirely by the debugger so no debug event
  684. // is associated with it. Instead we simply update
  685. // the PC and return from the Wait without actually waiting.
  686. // Step/trace events have empty event info.
  687. DiscardLastEventInfo();
  688. g_EventThreadSysId = StepThread->SystemId;
  689. g_EventProcessSysId = StepThread->Process->SystemId;
  690. FindEventProcessThread();
  691. return S_FALSE;
  692. }
  693. // Once we resume execution the processes and threads
  694. // can change so we must flush our notion of what's current.
  695. g_CurrentProcess = NULL;
  696. g_EventProcess = NULL;
  697. g_EventThread = NULL;
  698. if (g_EngDefer & ENG_DEFER_DELETE_EXITED)
  699. {
  700. // Reap any threads and processes that have terminated since
  701. // we last executed.
  702. if (DeleteExitedInfos())
  703. {
  704. OutputProcessInfo("*** exit cleanup ***");
  705. }
  706. g_EngDefer &= ~ENG_DEFER_DELETE_EXITED;
  707. // If all processes have exited we're done.
  708. if (!ANY_PROCESSES())
  709. {
  710. if (IS_LIVE_USER_TARGET())
  711. {
  712. // If there's an outstanding event continue it.
  713. if (g_EngDefer & ENG_DEFER_CONTINUE_EVENT)
  714. {
  715. ((UserTargetInfo*)g_Target)->m_Services->
  716. ContinueEvent(DBG_CONTINUE);
  717. DiscardLastEvent();
  718. }
  719. }
  720. DiscardMachine(DEBUG_SESSION_END);
  721. return E_UNEXPECTED;
  722. }
  723. }
  724. return S_OK;
  725. }
  726. HRESULT
  727. PrepareForSeparation(void)
  728. {
  729. HRESULT Status;
  730. ULONG OldStop = g_EngStatus & ENG_STATUS_STOP_SESSION;
  731. //
  732. // The debugger is going to separate from the
  733. // debuggee, such as during a detach operation.
  734. // Get the debuggee running again so that it
  735. // will go on without the debugger.
  736. //
  737. g_EngStatus |= ENG_STATUS_STOP_SESSION;
  738. Status = PrepareForExecution(DEBUG_STATUS_GO_HANDLED);
  739. if (g_ProcessHead == NULL)
  740. {
  741. // All processes are gone so don't consider
  742. // it an error if we couldn't resume execution.
  743. Status = S_OK;
  744. }
  745. g_EngStatus = (g_EngStatus & ~ENG_STATUS_STOP_SESSION) | OldStop;
  746. return Status;
  747. }
  748. void
  749. FindEventProcessThread(void)
  750. {
  751. //
  752. // If these lookups fail other processes and
  753. // threads cannot be substituted for the correct
  754. // ones as that may cause modifications to the
  755. // wrong data structures. For example, if a
  756. // thread exit comes in it cannot be processed
  757. // with any other process or thread as that would
  758. // delete the wrong thread.
  759. //
  760. g_EventProcess = FindProcessBySystemId(g_EventProcessSysId);
  761. if (g_EventProcess == NULL)
  762. {
  763. ErrOut("ERROR: Unable to find system process %X\n",
  764. g_EventProcessSysId);
  765. ErrOut("ERROR: The process being debugged has either exited "
  766. "or cannot be accessed\n");
  767. ErrOut("ERROR: Many commands will not work properly\n");
  768. }
  769. else
  770. {
  771. g_EventThread = FindThreadBySystemId(g_EventProcess,
  772. g_EventThreadSysId);
  773. if (g_EventThread == NULL)
  774. {
  775. ErrOut("ERROR: Unable to find system thread %X\n",
  776. g_EventThreadSysId);
  777. ErrOut("ERROR: The thread being debugged has either exited "
  778. "or cannot be accessed\n");
  779. ErrOut("ERROR: Many commands will not work properly\n");
  780. }
  781. }
  782. g_CurrentProcess = g_EventProcess;
  783. if (g_CurrentProcess != NULL)
  784. {
  785. g_CurrentProcess->CurrentThread = g_EventThread;
  786. DBG_ASSERT(g_EventThread == NULL ||
  787. g_EventThread->Process == g_CurrentProcess);
  788. }
  789. }
  790. static int VoteWeight[] =
  791. {
  792. 0, // DEBUG_STATUS_NO_CHANGE
  793. 2, // DEBUG_STATUS_GO
  794. 3, // DEBUG_STATUS_GO_HANDLED
  795. 4, // DEBUG_STATUS_GO_NOT_HANDLED
  796. 6, // DEBUG_STATUS_STEP_OVER
  797. 7, // DEBUG_STATUS_STEP_INTO
  798. 8, // DEBUG_STATUS_BREAK
  799. 9, // DEBUG_STATUS_NO_DEBUGGEE
  800. 5, // DEBUG_STATUS_STEP_BRANCH
  801. 1, // DEBUG_STATUS_IGNORE_EVENT
  802. };
  803. ULONG
  804. MergeVotes(ULONG Cur, ULONG Vote)
  805. {
  806. // If the vote is actually an error code display a message.
  807. if (FAILED(Vote))
  808. {
  809. ErrOut("Callback failed with %X\n", Vote);
  810. return Cur;
  811. }
  812. // Ignore invalid votes.
  813. if (
  814. (
  815. #if DEBUG_STATUS_NO_CHANGE > 0
  816. Vote < DEBUG_STATUS_NO_CHANGE ||
  817. #endif
  818. Vote > DEBUG_STATUS_BREAK) &&
  819. (Vote < DEBUG_STATUS_STEP_BRANCH ||
  820. Vote > DEBUG_STATUS_IGNORE_EVENT))
  821. {
  822. ErrOut("Callback returned invalid vote %X\n", Vote);
  823. return Cur;
  824. }
  825. // Votes are biased towards executing as little
  826. // as possible.
  827. // Break overrides all other votes.
  828. // Step into overrides step over.
  829. // Step over overrides step branch.
  830. // Step branch overrides go.
  831. // Go not-handled overrides go handled.
  832. // Go handled overrides plain go.
  833. // Plain go overrides ignore event.
  834. // Anything overrides no change.
  835. if (VoteWeight[Vote] > VoteWeight[Cur])
  836. {
  837. Cur = Vote;
  838. }
  839. return Cur;
  840. }
  841. ULONG
  842. ProcessBreakpointOrStepException(PEXCEPTION_RECORD64 Record,
  843. ULONG FirstChance)
  844. {
  845. ADDR BpAddr;
  846. ULONG BreakType;
  847. ULONG EventStatus;
  848. SuspendExecution();
  849. // Default breakpoint address to the current PC as that's
  850. // where the majority are at.
  851. g_Machine->GetPC(&BpAddr);
  852. // Check whether the exception is a breakpoint.
  853. BreakType = g_Machine->IsBreakpointOrStepException(Record, FirstChance,
  854. &BpAddr,
  855. &g_PrevRelatedPc);
  856. if (BreakType & EXBS_BREAKPOINT_ANY)
  857. {
  858. // It's a breakpoint of some kind.
  859. EventOut("*** breakpoint exception\n");
  860. EventStatus = CheckBreakpointOrStepTrace(&BpAddr, BreakType);
  861. }
  862. else
  863. {
  864. // It's a true single step or taken branch exception.
  865. // We still need to check breakpoints as we may have stepped
  866. // to an instruction which has a breakpoint.
  867. EventOut("*** single step or taken branch exception\n");
  868. EventStatus = CheckBreakpointOrStepTrace(&BpAddr, EXBS_BREAKPOINT_ANY);
  869. }
  870. if (EventStatus == DEBUG_STATUS_NO_CHANGE)
  871. {
  872. // The break/step exception wasn't recognized
  873. // as a debugger-specific event so handle it as
  874. // a regular exception. The default states for
  875. // break/step exceptions are to break in so
  876. // this will do the right thing, plus it allows
  877. // people to ignore or notify for them if they want.
  878. EventStatus = NotifyExceptionEvent(Record, FirstChance, FALSE);
  879. }
  880. else
  881. {
  882. // Force the exception to be handled.
  883. g_EngDefer |= ENG_DEFER_EXCEPTION_HANDLING;
  884. g_EventExceptionFilter = NULL;
  885. g_ExceptionFirstChance = DBG_EXCEPTION_HANDLED;
  886. }
  887. return EventStatus;
  888. }
  889. ULONG
  890. CheckBreakpointOrStepTrace(PADDR BpAddr, ULONG BreakType)
  891. {
  892. ULONG EventStatus;
  893. Breakpoint* Bp;
  894. ULONG BreakHitType;
  895. BOOL BpHit;
  896. BpHit = FALSE;
  897. Bp = NULL;
  898. EventStatus = DEBUG_STATUS_NO_CHANGE;
  899. // Multiple breakpoints can be hit at the same address.
  900. // Process all possible hits. Do not do notifications
  901. // while walking the list as the callbacks may modify
  902. // the list. Instead just mark the breakpoint as
  903. // needing notification in the next pass.
  904. for (;;)
  905. {
  906. Bp = CheckBreakpointHit(g_EventProcess, Bp, BpAddr, BreakType, -1,
  907. g_CmdState != 'g' ?
  908. DEBUG_BREAKPOINT_GO_ONLY : 0,
  909. &BreakHitType, TRUE);
  910. if (Bp == NULL)
  911. {
  912. break;
  913. }
  914. if (BreakHitType == BREAKPOINT_HIT)
  915. {
  916. Bp->m_Flags |= BREAKPOINT_NOTIFY;
  917. }
  918. else
  919. {
  920. // This breakpoint was hit but the hit was ignored.
  921. // Vote to continue execution.
  922. EventStatus = MergeVotes(EventStatus, DEBUG_STATUS_IGNORE_EVENT);
  923. }
  924. BpHit = TRUE;
  925. Bp = Bp->m_Next;
  926. if (Bp == NULL)
  927. {
  928. break;
  929. }
  930. }
  931. if (!BpHit)
  932. {
  933. // If no breakpoints were recognized check for an internal
  934. // breakpoint.
  935. EventStatus = CheckStepTrace(BpAddr, EventStatus);
  936. //
  937. // If the breakpoint wasn't for a step/trace
  938. // it's a hard breakpoint and should be
  939. // handled as a normal exception.
  940. //
  941. if (!g_EventProcess->InitialBreakDone)
  942. {
  943. g_EngStatus |= ENG_STATUS_AT_INITIAL_BREAK;
  944. }
  945. // We've seen the initial break for this process.
  946. g_EventProcess->InitialBreakDone = TRUE;
  947. // If we were waiting for a break-in exception we've got it.
  948. g_EngStatus &= ~ENG_STATUS_PENDING_BREAK_IN;
  949. if (EventStatus == DEBUG_STATUS_NO_CHANGE)
  950. {
  951. if (!g_EventProcess->InitialBreak)
  952. {
  953. // Refresh breakpoints even though we're not
  954. // stopping. This gives saved breakpoints
  955. // a chance to become active.
  956. RemoveBreakpoints();
  957. EventStatus = DEBUG_STATUS_GO;
  958. g_EventProcess->InitialBreak = TRUE;
  959. }
  960. else if ((!g_EventProcess->InitialBreakWx86) &&
  961. (g_TargetMachineType != g_EffMachine) &&
  962. (g_EffMachine == IMAGE_FILE_MACHINE_I386))
  963. {
  964. // Allow skipping of both the target machine
  965. // initial break and emulated machine initial breaks.
  966. RemoveBreakpoints();
  967. EventStatus = DEBUG_STATUS_GO;
  968. g_EventProcess->InitialBreakWx86 = TRUE;
  969. }
  970. }
  971. }
  972. else
  973. {
  974. // A breakpoint was recognized. We need to
  975. // refresh the breakpoint status since we'll
  976. // probably need to defer the reinsertion of
  977. // the breakpoint we're sitting on.
  978. RemoveBreakpoints();
  979. // Now do event callbacks for any breakpoints that need it.
  980. EventStatus = NotifyHitBreakpoints(EventStatus);
  981. }
  982. if (g_ThreadToResume != 0)
  983. {
  984. g_EngDefer |= ENG_DEFER_RESUME_THREAD;
  985. }
  986. return EventStatus;
  987. }
  988. ULONG
  989. CheckStepTrace(PADDR PcAddr, ULONG DefaultStatus)
  990. {
  991. BOOL WatchStepOver = FALSE;
  992. ULONG uOciFlags;
  993. ULONG NextMachine;
  994. if ((g_StepTraceBp->m_Flags & DEBUG_BREAKPOINT_ENABLED) &&
  995. Flat(*g_StepTraceBp->GetAddr()) != OFFSET_TRACE)
  996. {
  997. NotFlat(*g_StepTraceBp->GetAddr());
  998. ComputeFlatAddress(g_StepTraceBp->GetAddr(), NULL);
  999. }
  1000. // We do not check ENG_THREAD_TRACE_SET here because
  1001. // this event detection is only for proper user-initiated
  1002. // step/trace events. Such an event must occur immediately
  1003. // after the t/p/b, otherwise we cannot be sure that
  1004. // it's actually a debugger event and not an app-generated
  1005. // single-step exception.
  1006. // In user mode we restrict the step/trace state
  1007. // to a single thread to try and be as precise
  1008. // as possible. This isn't done in kernel mode
  1009. // since kernel mode "threads" are currently
  1010. // just placeholders for processors. It is
  1011. // possible for a context switch to occur at any
  1012. // time while stepping, meaning a true system
  1013. // thread could move from one processor to another.
  1014. // The processor state, including the single-step
  1015. // flag, will be moved with the thread so single
  1016. // step exceptions will come from the new processor
  1017. // rather than this one, meaning we would ignore
  1018. // it if we used "thread" restrictions. Instead,
  1019. // just assume any single-step exception while in
  1020. // p/t mode is a debugger step.
  1021. if ((g_StepTraceBp->m_Flags & DEBUG_BREAKPOINT_ENABLED) &&
  1022. g_StepTraceBp->m_Process == g_EventProcess &&
  1023. ((IS_KERNEL_TARGET() && IS_STEP_TRACE(g_CmdState)) ||
  1024. g_StepTraceBp->m_MatchThread == g_EventThread) &&
  1025. (Flat(*g_StepTraceBp->GetAddr()) == OFFSET_TRACE ||
  1026. AddrEqu(*g_StepTraceBp->GetAddr(), *PcAddr)))
  1027. {
  1028. ADDR CurrentSP;
  1029. // step/trace event occurred
  1030. // Update breakpoint status since we may need to step
  1031. // again and step/trace is updated when breakpoints
  1032. // are inserted.
  1033. RemoveBreakpoints();
  1034. uOciFlags = OCI_DISASM | OCI_ALLOW_REG | OCI_ALLOW_SOURCE |
  1035. OCI_ALLOW_EA;
  1036. if (g_EngStatus & (ENG_STATUS_PENDING_BREAK_IN |
  1037. ENG_STATUS_USER_INTERRUPT))
  1038. {
  1039. g_WatchFunctions.End(PcAddr);
  1040. return DEBUG_STATUS_BREAK;
  1041. }
  1042. if (IS_KERNEL_TARGET() && g_WatchInitialSP)
  1043. {
  1044. g_Machine->GetSP(&CurrentSP);
  1045. if ((Flat(CurrentSP) + 0x1500 < g_WatchInitialSP) ||
  1046. (g_WatchInitialSP + 0x1500 < Flat(CurrentSP)))
  1047. {
  1048. return DEBUG_STATUS_IGNORE_EVENT;
  1049. }
  1050. }
  1051. if (g_StepTraceInRangeStart != -1 &&
  1052. Flat(*PcAddr) >= g_StepTraceInRangeStart &&
  1053. Flat(*PcAddr) < g_StepTraceInRangeEnd)
  1054. {
  1055. // test if step/trace range active
  1056. // if so, compute the next offset and pass through
  1057. g_Machine->GetNextOffset(g_StepTraceCmdState == 'p',
  1058. g_StepTraceBp->GetAddr(),
  1059. &NextMachine);
  1060. g_StepTraceBp->SetProcType(NextMachine);
  1061. if (g_WatchWhole)
  1062. {
  1063. g_WatchBeginCurFunc = Flat(*g_StepTraceBp->GetAddr());
  1064. g_WatchEndCurFunc = 0;
  1065. }
  1066. return DEBUG_STATUS_IGNORE_EVENT;
  1067. }
  1068. // active step/trace event - note event if count is zero
  1069. if (!StepTracePass(PcAddr) ||
  1070. (g_WatchFunctions.IsStarted() && AddrEqu(g_WatchTarget, *PcAddr) &&
  1071. (!IS_KERNEL_TARGET() || Flat(CurrentSP) >= g_WatchInitialSP)))
  1072. {
  1073. g_WatchFunctions.End(PcAddr);
  1074. return DEBUG_STATUS_BREAK;
  1075. }
  1076. if (g_WatchFunctions.IsStarted())
  1077. {
  1078. if (g_WatchTrace)
  1079. {
  1080. g_Target->
  1081. ProcessWatchTraceEvent((PDBGKD_TRACE_DATA)
  1082. g_StateChangeData, *PcAddr);
  1083. }
  1084. goto skipit;
  1085. }
  1086. if (g_SrcOptions & SRCOPT_STEP_SOURCE)
  1087. {
  1088. goto skipit;
  1089. }
  1090. // more remaining events to occur, but output
  1091. // the instruction (optionally with registers)
  1092. // compute the step/trace address for next event
  1093. OutCurInfo(uOciFlags, g_Machine->m_AllMask,
  1094. DEBUG_OUTPUT_PROMPT_REGISTERS);
  1095. skipit:
  1096. g_Machine->GetNextOffset(g_StepTraceCmdState == 'p' || WatchStepOver,
  1097. g_StepTraceBp->GetAddr(),
  1098. &NextMachine);
  1099. g_StepTraceBp->SetProcType(NextMachine);
  1100. GetCurrentMemoryOffsets(&g_StepTraceInRangeStart,
  1101. &g_StepTraceInRangeEnd);
  1102. return DEBUG_STATUS_IGNORE_EVENT;
  1103. }
  1104. // Carry out deferred breakpoint work if necessary.
  1105. // We need to check the thread deferred-bp flag here as
  1106. // other events may occur before the thread with deferred
  1107. // work gets to execute again, in which case the setting
  1108. // of g_DeferDefined may have changed.
  1109. if ((g_EventThread != NULL &&
  1110. (g_EventThread->Flags & ENG_THREAD_DEFER_BP_TRACE)) ||
  1111. (g_DeferDefined &&
  1112. g_DeferBp->m_Process == g_EventProcess &&
  1113. (Flat(*g_DeferBp->GetAddr()) == OFFSET_TRACE ||
  1114. AddrEqu(*g_DeferBp->GetAddr(), *PcAddr))))
  1115. {
  1116. if ((g_EngOptions & DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS) &&
  1117. IS_USER_TARGET() &&
  1118. g_SelectExecutionThread == SELTHREAD_INTERNAL_THREAD &&
  1119. g_SelectedThread == g_EventThread)
  1120. {
  1121. // The engine internally restricted execution to
  1122. // this particular thread in order to manage
  1123. // breakpoints in multithreaded conditions.
  1124. // The deferred work will be finished before
  1125. // we resume so we can drop the lock.
  1126. g_SelectExecutionThread = SELTHREAD_ANY;
  1127. g_SelectedThread = NULL;
  1128. }
  1129. // Deferred breakpoints are refreshed on breakpoint
  1130. // insertion so make sure that insertion happens
  1131. // when things restart.
  1132. RemoveBreakpoints();
  1133. return DEBUG_STATUS_IGNORE_EVENT;
  1134. }
  1135. // If the event was unrecognized return the default status.
  1136. return DefaultStatus;
  1137. }
  1138. void
  1139. AnalyzeDeadlock(PEXCEPTION_RECORD64 Record, ULONG FirstChance)
  1140. {
  1141. CHAR Symbol[MAX_SYMBOL_LEN];
  1142. DWORD64 Displacement;
  1143. PTHREAD_INFO pThreadOwner = NULL;
  1144. DWORD TID = 0;
  1145. ADDR addrCritSec;
  1146. RTL_CRITICAL_SECTION CritSec;
  1147. char szBangCritsec[32];
  1148. // poking around inside NT's user-mode RTL_CRITICAL_SECTION and
  1149. // RTL_RESOURCE structures.
  1150. //
  1151. // Get the symbolic name of the routine which
  1152. // raised the exception to see if it matches
  1153. // one of the expected ones in ntdll.
  1154. //
  1155. GetSymbolStdCall((ULONG64)Record->ExceptionAddress,
  1156. Symbol,
  1157. sizeof(Symbol),
  1158. &Displacement,
  1159. NULL
  1160. );
  1161. if ( !_stricmp("ntdll!RtlpWaitForCriticalSection", Symbol))
  1162. {
  1163. //
  1164. // If the first parameter is a pointer to the critsect as it
  1165. // should be, switch to the owning thread before bringing
  1166. // up the prompt. This way it's obvious where the problem
  1167. // is.
  1168. //
  1169. if (Record->ExceptionInformation[0])
  1170. {
  1171. ADDRFLAT(&addrCritSec, Record->ExceptionInformation[0]);
  1172. if (GetMemString(&addrCritSec, (PUCHAR)&CritSec, sizeof(CritSec)))
  1173. {
  1174. if (NULL == CritSec.DebugInfo)
  1175. {
  1176. dprintf("Critsec %s was deleted or was never initialized.\n",
  1177. FormatAddr64(Record->ExceptionInformation[0]));
  1178. }
  1179. else if (CritSec.LockCount < -1)
  1180. {
  1181. dprintf("Critsec %s was left when not owned, corrupted.\n",
  1182. FormatAddr64(Record->ExceptionInformation[0]));
  1183. }
  1184. else
  1185. {
  1186. TID = (DWORD)((ULONG_PTR)CritSec.OwningThread);
  1187. pThreadOwner = FindThreadBySystemId(g_CurrentProcess, TID);
  1188. }
  1189. }
  1190. }
  1191. if (pThreadOwner)
  1192. {
  1193. dprintf("Critsec %s owned by thread %d (.%x) "
  1194. "caused thread %d (.%x)\n"
  1195. " to timeout entering it. "
  1196. "Breaking in on owner thread, ask\n"
  1197. " yourself why it has held this "
  1198. "critsec long enough to deadlock.\n"
  1199. " Use `~%ds` to switch back to timeout thread.\n",
  1200. FormatAddr64(Record->ExceptionInformation[0]),
  1201. pThreadOwner->UserId,
  1202. pThreadOwner->SystemId,
  1203. g_CurrentProcess->CurrentThread->UserId,
  1204. g_CurrentProcess->CurrentThread->SystemId,
  1205. g_CurrentProcess->CurrentThread->UserId);
  1206. g_EventThread = pThreadOwner;
  1207. SetPromptThread(pThreadOwner, 0);
  1208. }
  1209. else if (TID)
  1210. {
  1211. dprintf("Critsec %s ABANDONED owner thread ID is .%x, "
  1212. "no such thread.\n",
  1213. FormatAddr64(Record->ExceptionInformation[0]),
  1214. TID);
  1215. }
  1216. if (!FirstChance)
  1217. {
  1218. dprintf("!!! second chance !!!\n");
  1219. }
  1220. //
  1221. // do a !critsec for them
  1222. //
  1223. if (Record->ExceptionInformation[0])
  1224. {
  1225. sprintf(szBangCritsec, "critsec %s",
  1226. FormatAddr64(Record->ExceptionInformation[0]));
  1227. dprintf("!%s\n", szBangCritsec);
  1228. fnBangCmd(NULL, szBangCritsec, NULL, FALSE);
  1229. }
  1230. }
  1231. else if ( !_stricmp("ntdll!RtlAcquireResourceShared", Symbol) ||
  1232. !_stricmp("ntdll!RtlAcquireResourceExclusive", Symbol) ||
  1233. !_stricmp("ntdll!RtlConvertSharedToExclusive", Symbol) )
  1234. {
  1235. dprintf("deadlock in %s ",
  1236. 1 + strstr(Symbol, "!")
  1237. );
  1238. GetSymbolStdCall(Record->ExceptionInformation[0],
  1239. Symbol,
  1240. sizeof(Symbol),
  1241. &Displacement,
  1242. NULL);
  1243. dprintf("Resource %s", Symbol);
  1244. if (Displacement)
  1245. {
  1246. dprintf("+%s", FormatDisp64(Displacement));
  1247. }
  1248. dprintf(" (%s)\n",
  1249. FormatAddr64(Record->ExceptionInformation[0]));
  1250. if (!FirstChance)
  1251. {
  1252. dprintf("!!! second chance !!!\n");
  1253. }
  1254. // Someone who uses RTL_RESOURCEs might write a !resource
  1255. // for ntsdexts.dll like !critsec.
  1256. }
  1257. else
  1258. {
  1259. dprintf("Possible Deadlock in %s ",
  1260. Symbol
  1261. );
  1262. GetSymbolStdCall(Record->ExceptionInformation[0],
  1263. Symbol,
  1264. sizeof(Symbol),
  1265. &Displacement,
  1266. NULL);
  1267. dprintf("Lock %s", Symbol);
  1268. if (Displacement)
  1269. {
  1270. dprintf("+%s", FormatDisp64(Displacement));
  1271. }
  1272. dprintf(" (%s)\n",
  1273. FormatAddr64(Record->ExceptionInformation[0]));
  1274. if (!FirstChance)
  1275. {
  1276. dprintf("!!! second chance !!!\n");
  1277. }
  1278. }
  1279. }
  1280. void
  1281. OutputDeadlock(PEXCEPTION_RECORD64 Record, ULONG FirstChance)
  1282. {
  1283. CHAR Symbol[MAX_SYMBOL_LEN];
  1284. DWORD64 Displacement;
  1285. GetSymbolStdCall(Record->ExceptionInformation[0],
  1286. Symbol,
  1287. sizeof(Symbol),
  1288. &Displacement,
  1289. NULL);
  1290. dprintf("Possible Deadlock Lock %s+%s at %s\n",
  1291. Symbol,
  1292. FormatDisp64(Displacement),
  1293. FormatAddr64(Record->ExceptionInformation[0]));
  1294. if (!FirstChance)
  1295. {
  1296. dprintf("!!! second chance !!!\n");
  1297. }
  1298. }
  1299. void
  1300. GetEventName(ULONG64 ImageFile, ULONG64 ImageBase,
  1301. ULONG64 NamePtr, WORD Unicode,
  1302. PSTR NameBuffer, ULONG BufferSize)
  1303. {
  1304. SIZE_T BytesRead;
  1305. char TempName[MAX_IMAGE_PATH];
  1306. if (NamePtr != 0)
  1307. {
  1308. if (g_Target->ReadPointer(g_TargetMachine, NamePtr, &NamePtr) != S_OK)
  1309. {
  1310. NamePtr = 0;
  1311. }
  1312. }
  1313. if (NamePtr != 0)
  1314. {
  1315. ULONG Done;
  1316. if (g_Target->ReadVirtual(NamePtr, TempName, sizeof(TempName),
  1317. &Done) != S_OK ||
  1318. Done != sizeof(TempName))
  1319. {
  1320. NamePtr = 0;
  1321. }
  1322. }
  1323. if (NamePtr != 0)
  1324. {
  1325. //
  1326. // We have a name.
  1327. //
  1328. if (Unicode)
  1329. {
  1330. if (!WideCharToMultiByte(
  1331. CP_ACP,
  1332. WC_COMPOSITECHECK,
  1333. (LPWSTR)TempName,
  1334. -1,
  1335. NameBuffer,
  1336. BufferSize,
  1337. NULL,
  1338. NULL
  1339. ))
  1340. {
  1341. //
  1342. // Unicode -> ANSI conversion failed.
  1343. //
  1344. NameBuffer[0] = 0;
  1345. }
  1346. }
  1347. else
  1348. {
  1349. strncpy(NameBuffer, TempName, BufferSize);
  1350. NameBuffer[BufferSize - 1] = 0;
  1351. }
  1352. }
  1353. else
  1354. {
  1355. //
  1356. // We don't have a name, so look in the image.
  1357. // A file handle will only be provided here in the
  1358. // local case so it's safe to case to HANDLE.
  1359. //
  1360. if (!GetModnameFromImage(ImageBase, OS_HANDLE(ImageFile),
  1361. NameBuffer, BufferSize))
  1362. {
  1363. NameBuffer[0] = 0;
  1364. }
  1365. }
  1366. if (!NameBuffer[0])
  1367. {
  1368. if (!GetModNameFromLoaderList(g_TargetMachine, 0,
  1369. ImageBase, NameBuffer, BufferSize,
  1370. TRUE))
  1371. {
  1372. // Buffer should be big enough for this simple name.
  1373. DBG_ASSERT(BufferSize >= 32);
  1374. sprintf(NameBuffer, "image%p", (PVOID)(ULONG_PTR)ImageBase);
  1375. }
  1376. }
  1377. else
  1378. {
  1379. // If the name given doesn't have a full path try
  1380. // and locate a full path in the loader list.
  1381. if ((((NameBuffer[0] < 'a' || NameBuffer[0] > 'z') &&
  1382. (NameBuffer[0] < 'A' || NameBuffer[0] > 'Z')) ||
  1383. NameBuffer[1] != ':') &&
  1384. (NameBuffer[0] != '\\' || NameBuffer[1] != '\\'))
  1385. {
  1386. GetModNameFromLoaderList(g_TargetMachine, 0,
  1387. ImageBase, NameBuffer, BufferSize,
  1388. TRUE);
  1389. }
  1390. }
  1391. }
  1392. //----------------------------------------------------------------------------
  1393. //
  1394. // ConnLiveKernelTargetInfo::WaitForEvent.
  1395. //
  1396. //----------------------------------------------------------------------------
  1397. HRESULT
  1398. ConnLiveKernelTargetInfo::WaitForEvent(ULONG Flags, ULONG Timeout)
  1399. {
  1400. HRESULT Status;
  1401. ULONG EventStatus;
  1402. NTSTATUS NtStatus;
  1403. ULONG ContinueStatus;
  1404. BOOL SwitchedProcessors;
  1405. // Timeouts can't easily be supported at the moment and
  1406. // aren't really necessary.
  1407. if (Timeout != INFINITE)
  1408. {
  1409. return E_NOTIMPL;
  1410. }
  1411. Status = PrepareForWait(Flags, &ContinueStatus);
  1412. if ((g_EngStatus & ENG_STATUS_WAITING) == 0)
  1413. {
  1414. return Status;
  1415. }
  1416. EventOut("> Executing\n");
  1417. for (;;)
  1418. {
  1419. EventOut(">> Waiting\n");
  1420. SwitchedProcessors = FALSE;
  1421. // Don't process deferred work if this is
  1422. // just a processor switch.
  1423. if (g_CmdState != 's')
  1424. {
  1425. ProcessDeferredWork(&ContinueStatus);
  1426. }
  1427. if (g_EventProcessSysId)
  1428. {
  1429. EventOut(">> Continue with %X\n", ContinueStatus);
  1430. if (g_CmdState == 's')
  1431. {
  1432. // This can either be a real processor switch or
  1433. // a rewait for state change. Check the switch
  1434. // processor to be sure.
  1435. if (g_SwitchProcessor)
  1436. {
  1437. DbgKdSwitchActiveProcessor(g_SwitchProcessor - 1);
  1438. g_SwitchProcessor = 0;
  1439. SwitchedProcessors = TRUE;
  1440. }
  1441. }
  1442. else
  1443. {
  1444. if (g_EngDefer & ENG_DEFER_UPDATE_CONTROL_SET)
  1445. {
  1446. NtStatus = DbgKdContinue2(ContinueStatus, g_ControlSet);
  1447. g_EngDefer &= ~ENG_DEFER_UPDATE_CONTROL_SET;
  1448. }
  1449. else
  1450. {
  1451. NtStatus = DbgKdContinue(ContinueStatus);
  1452. }
  1453. if (!NT_SUCCESS(NtStatus))
  1454. {
  1455. ErrOut("DbgKdContinue failed with status %X\n", NtStatus);
  1456. Status = HRESULT_FROM_NT(NtStatus);
  1457. goto Exit;
  1458. }
  1459. }
  1460. }
  1461. DiscardLastEvent();
  1462. if (!IS_MACHINE_SET() &&
  1463. (g_EngOptions & DEBUG_ENGOPT_INITIAL_BREAK) &&
  1464. IS_CONN_KERNEL_TARGET())
  1465. {
  1466. // Ask for a breakin to be sent once the
  1467. // code gets into resync.
  1468. g_DbgKdTransport->m_SyncBreakIn = TRUE;
  1469. }
  1470. // When waiting for confirmation of a processor switch don't
  1471. // yield the engine lock in order to prevent other clients
  1472. // from trying to do things with the target while it's
  1473. // switching.
  1474. NtStatus = DbgKdWaitStateChange(&g_StateChange, g_StateChangeBuffer,
  1475. sizeof(g_StateChangeBuffer) - 2,
  1476. !SwitchedProcessors);
  1477. if (!NT_SUCCESS(NtStatus))
  1478. {
  1479. ErrOut("DbgKdWaitStateChange failed: %08lx\n", NtStatus);
  1480. Status = HRESULT_FROM_NT(NtStatus);
  1481. goto Exit;
  1482. }
  1483. EventOut(">>> State change event %X, proc %d of %d\n",
  1484. g_StateChange.NewState, g_StateChange.Processor,
  1485. g_StateChange.NumberProcessors);
  1486. g_EngStatus |= ENG_STATUS_STATE_CHANGED;
  1487. if (!IS_MACHINE_SET())
  1488. {
  1489. dprintf("Kernel Debugger connection established.%s\n",
  1490. (g_EngOptions & DEBUG_ENGOPT_INITIAL_BREAK) ?
  1491. " (Initial Breakpoint requested)" : ""
  1492. );
  1493. // Initial connection after a fresh boot may only report
  1494. // a single processor as the others haven't started yet.
  1495. g_TargetNumberProcessors = g_StateChange.NumberProcessors;
  1496. Status = InitializeMachine(g_TargetMachineType);
  1497. if (Status != S_OK)
  1498. {
  1499. ErrOut("Unable to initialize target machine information\n");
  1500. goto Exit;
  1501. }
  1502. CreateKernelProcessAndThreads();
  1503. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  1504. g_EventThreadSysId = VIRTUAL_THREAD_ID(g_StateChange.Processor);
  1505. FindEventProcessThread();
  1506. //
  1507. // Load kernel symbols.
  1508. //
  1509. VerifyKernelBase(TRUE);
  1510. g_Target->OutputVersion();
  1511. RemoveAllKernelBreakpoints();
  1512. }
  1513. else
  1514. {
  1515. // Initial connection after a fresh boot may only report
  1516. // a single processor as the others haven't started yet.
  1517. // Pick up any additional processors.
  1518. if (g_StateChange.NumberProcessors > g_TargetNumberProcessors)
  1519. {
  1520. AddKernelThreads(g_TargetNumberProcessors,
  1521. g_StateChange.NumberProcessors -
  1522. g_TargetNumberProcessors);
  1523. g_TargetNumberProcessors = g_StateChange.NumberProcessors;
  1524. }
  1525. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  1526. g_EventThreadSysId = VIRTUAL_THREAD_ID(g_StateChange.Processor);
  1527. FindEventProcessThread();
  1528. }
  1529. g_EventPc = g_StateChange.ProgramCounter;
  1530. g_ControlReport = &g_StateChange.AnyControlReport;
  1531. g_StateChangeData = g_StateChangeBuffer;
  1532. if (g_EventThread)
  1533. {
  1534. g_EventThread->DataOffset = g_StateChange.Thread;
  1535. }
  1536. EventStatus = ProcessStateChange(&g_StateChange, g_StateChangeData);
  1537. EventOut(">>> StateChange event status %X\n", EventStatus);
  1538. if (EventStatus == DEBUG_STATUS_NO_DEBUGGEE)
  1539. {
  1540. // Machine has rebooted or something else
  1541. // which breaks the connection. Forget the
  1542. // connection and go back to waiting.
  1543. ContinueStatus = DBG_CONTINUE;
  1544. }
  1545. else if (EventStatus == DEBUG_STATUS_BREAK ||
  1546. SwitchedProcessors)
  1547. {
  1548. // If the event handlers requested a break return
  1549. // to the caller. This path is also taken
  1550. // when switching processors to guarantee that
  1551. // the target doesn't start running when the
  1552. // user just wanted a processor switch.
  1553. Status = S_OK;
  1554. goto Exit;
  1555. }
  1556. else
  1557. {
  1558. // We're resuming execution so reverse any
  1559. // command preparation that may have occurred
  1560. // while processing the event.
  1561. if ((Status = PrepareForExecution(EventStatus)) != S_OK)
  1562. {
  1563. goto Exit;
  1564. }
  1565. ContinueStatus = EventStatusToContinue(EventStatus);
  1566. }
  1567. }
  1568. Exit:
  1569. g_EngStatus &= ~ENG_STATUS_WAITING;
  1570. // Control is passing back to the caller so the engine must
  1571. // be ready for command processing.
  1572. PrepareForCalls(0);
  1573. // If we did switch processors automatically
  1574. // update the page directory for the new processor.
  1575. if (SwitchedProcessors)
  1576. {
  1577. if (g_TargetMachine->SetDefaultPageDirectories(PAGE_DIR_ALL) != S_OK)
  1578. {
  1579. WarnOut("WARNING: Unable to reset page directories\n");
  1580. }
  1581. }
  1582. EventOut("> Wait returning %X\n", Status);
  1583. return Status;
  1584. }
  1585. DWORD64
  1586. GetKernelModuleBase(
  1587. ULONG64 Address
  1588. )
  1589. {
  1590. LIST_ENTRY64 List64;
  1591. ULONG64 Next64;
  1592. ULONG64 ListHead;
  1593. NTSTATUS Status;
  1594. KLDR_DATA_TABLE_ENTRY64 DataTableBuffer;
  1595. if ((ListHead = KdDebuggerData.PsLoadedModuleList) == 0)
  1596. {
  1597. return 0;
  1598. }
  1599. if (g_Target->ReadListEntry(g_TargetMachine,
  1600. KdDebuggerData.PsLoadedModuleList,
  1601. &List64) != S_OK)
  1602. {
  1603. return 0;
  1604. }
  1605. if ((Next64 = List64.Flink) == 0)
  1606. {
  1607. return 0;
  1608. }
  1609. while (Next64 != ListHead)
  1610. {
  1611. if (g_Target->ReadLoaderEntry(g_TargetMachine,
  1612. Next64, &DataTableBuffer) != S_OK)
  1613. {
  1614. break;
  1615. }
  1616. Next64 = DataTableBuffer.InLoadOrderLinks.Flink;
  1617. if ((Address >= (ULONG64)DataTableBuffer.DllBase) &&
  1618. (Address < (ULONG64)DataTableBuffer.DllBase +
  1619. DataTableBuffer.SizeOfImage) )
  1620. {
  1621. return (DWORD64)DataTableBuffer.DllBase;
  1622. }
  1623. }
  1624. return 0;
  1625. }
  1626. HRESULT
  1627. LoadKdDataBlock(
  1628. BOOL NotLive
  1629. )
  1630. /*++
  1631. Routine Description:
  1632. This routine get the kernel's debugger data block.
  1633. Arguments:
  1634. UseSymbol - Instread of reading the information over the wire, use the
  1635. symbol information to get the data.
  1636. This is less reliable, but is necessary for crash dumps.
  1637. --*/
  1638. {
  1639. HRESULT Status;
  1640. LIST_ENTRY64 List64;
  1641. ULONG64 DataList;
  1642. ULONG Result;
  1643. ULONG Size = 0;
  1644. KDDEBUGGER_DATA32 LocalData32;
  1645. KDDEBUGGER_DATA64 LocalData64;
  1646. g_TargetBuildLabName[0] = 0;
  1647. if (NotLive)
  1648. {
  1649. if (!g_KdDebuggerDataBlock)
  1650. {
  1651. if ( (GetOffsetFromSym( "nt!KdDebuggerDataBlock",
  1652. (PULONG64) &List64, NULL)) &&
  1653. (List64.Flink) )
  1654. {
  1655. g_KdDebuggerDataBlock = List64.Flink;
  1656. }
  1657. else
  1658. {
  1659. if (g_SystemVersion > NT_SVER_NT4)
  1660. {
  1661. // Only print an error for win2k and above to avoid
  1662. // error output in "normal" circumstances.
  1663. ErrOut("KdDebuggerDataBlock not available !\n");
  1664. }
  1665. return E_FAIL;
  1666. }
  1667. }
  1668. }
  1669. else
  1670. {
  1671. if (!g_KdVersion.DebuggerDataList)
  1672. {
  1673. // This is always the case in early loader situations
  1674. // so suppress duplicate error messages.
  1675. if ((g_EngErr & ENG_ERR_DEBUGGER_DATA) == 0)
  1676. {
  1677. ErrOut("Debugger data list address is NULL\n");
  1678. }
  1679. return E_FAIL;
  1680. }
  1681. if ((Status = g_Target->ReadListEntry(g_TargetMachine,
  1682. g_KdVersion.DebuggerDataList,
  1683. &List64)) != S_OK)
  1684. {
  1685. ErrOut("Unable to get address of debugger data list\n");
  1686. return Status;
  1687. }
  1688. g_KdDebuggerDataBlock = List64.Flink;
  1689. }
  1690. //
  1691. // Get the Size of the KDDEBUGGER_DATA block
  1692. //
  1693. if (DbgKdApi64)
  1694. {
  1695. DBGKD_DEBUG_DATA_HEADER64 Header;
  1696. Status = g_Target->ReadVirtual(g_KdDebuggerDataBlock, &Header,
  1697. sizeof(Header), &Result);
  1698. if (Status == S_OK && Result == sizeof(Header))
  1699. {
  1700. Size = Header.Size;
  1701. }
  1702. }
  1703. else
  1704. {
  1705. DBGKD_DEBUG_DATA_HEADER32 Header;
  1706. Status = g_Target->ReadVirtual(g_KdDebuggerDataBlock, &Header,
  1707. sizeof(Header), &Result);
  1708. if (Status == S_OK && Result == sizeof(Header))
  1709. {
  1710. Size = Header.Size;
  1711. }
  1712. }
  1713. //
  1714. // Only read as much of the data block as we can hold in the debugger.
  1715. //
  1716. if (Size == 0)
  1717. {
  1718. // The data block is not present in older triage dumps
  1719. // so don't give an error message for an expected
  1720. // condition.
  1721. if (!IS_KERNEL_TRIAGE_DUMP())
  1722. {
  1723. ErrOut("KdDebuggerDataBlock Size field is 0 - "
  1724. "can not read datablock further\n");
  1725. }
  1726. return E_FAIL;
  1727. }
  1728. if (Size > sizeof(KDDEBUGGER_DATA64))
  1729. {
  1730. Size = sizeof(KDDEBUGGER_DATA64);
  1731. }
  1732. //
  1733. // Now read the data
  1734. //
  1735. if (DbgKdApi64)
  1736. {
  1737. Status = g_Target->ReadVirtual(g_KdDebuggerDataBlock, &LocalData64,
  1738. Size, &Result);
  1739. if (Status != S_OK || Result != Size)
  1740. {
  1741. ErrOut("KdDebuggerDataBlock Could not be read\n");
  1742. return Status == S_OK ? E_FAIL : Status;
  1743. }
  1744. if (g_TargetMachine->m_Ptr64)
  1745. {
  1746. memcpy(&KdDebuggerData, &LocalData64, Size);
  1747. }
  1748. else
  1749. {
  1750. //
  1751. // Sign extended for X86
  1752. //
  1753. //
  1754. // Extend the header so it doesn't get whacked
  1755. //
  1756. ListEntry32To64((PLIST_ENTRY32)(&LocalData64.Header.List),
  1757. &(KdDebuggerData.Header.List));
  1758. KdDebuggerData.Header.OwnerTag = LocalData64.Header.OwnerTag;
  1759. KdDebuggerData.Header.Size = LocalData64.Header.Size;
  1760. //
  1761. // Sign extend all the 32 bits values to 64 bit
  1762. //
  1763. #define UIP(f) if (FIELD_OFFSET(KDDEBUGGER_DATA64, f) < Size) \
  1764. { \
  1765. KdDebuggerData.f = \
  1766. (ULONG64)(LONG64)(LONG)(LocalData64.f); \
  1767. }
  1768. #define CP(f) KdDebuggerData.f = LocalData64.f;
  1769. UIP(KernBase);
  1770. UIP(BreakpointWithStatus);
  1771. UIP(SavedContext);
  1772. CP(ThCallbackStack);
  1773. CP(NextCallback);
  1774. CP(FramePointer);
  1775. CP(PaeEnabled);
  1776. UIP(KiCallUserMode);
  1777. UIP(KeUserCallbackDispatcher);
  1778. UIP(PsLoadedModuleList);
  1779. UIP(PsActiveProcessHead);
  1780. UIP(PspCidTable);
  1781. UIP(ExpSystemResourcesList);
  1782. UIP(ExpPagedPoolDescriptor);
  1783. UIP(ExpNumberOfPagedPools);
  1784. UIP(KeTimeIncrement);
  1785. UIP(KeBugCheckCallbackListHead);
  1786. UIP(KiBugcheckData);
  1787. UIP(IopErrorLogListHead);
  1788. UIP(ObpRootDirectoryObject);
  1789. UIP(ObpTypeObjectType);
  1790. UIP(MmSystemCacheStart);
  1791. UIP(MmSystemCacheEnd);
  1792. UIP(MmSystemCacheWs);
  1793. UIP(MmPfnDatabase);
  1794. UIP(MmSystemPtesStart);
  1795. UIP(MmSystemPtesEnd);
  1796. UIP(MmSubsectionBase);
  1797. UIP(MmNumberOfPagingFiles);
  1798. UIP(MmLowestPhysicalPage);
  1799. UIP(MmHighestPhysicalPage);
  1800. UIP(MmNumberOfPhysicalPages);
  1801. UIP(MmMaximumNonPagedPoolInBytes);
  1802. UIP(MmNonPagedSystemStart);
  1803. UIP(MmNonPagedPoolStart);
  1804. UIP(MmNonPagedPoolEnd);
  1805. UIP(MmPagedPoolStart);
  1806. UIP(MmPagedPoolEnd);
  1807. UIP(MmPagedPoolInformation);
  1808. CP(MmPageSize);
  1809. UIP(MmSizeOfPagedPoolInBytes);
  1810. UIP(MmTotalCommitLimit);
  1811. UIP(MmTotalCommittedPages);
  1812. UIP(MmSharedCommit);
  1813. UIP(MmDriverCommit);
  1814. UIP(MmProcessCommit);
  1815. UIP(MmPagedPoolCommit);
  1816. UIP(MmExtendedCommit);
  1817. UIP(MmZeroedPageListHead);
  1818. UIP(MmFreePageListHead);
  1819. UIP(MmStandbyPageListHead);
  1820. UIP(MmModifiedPageListHead);
  1821. UIP(MmModifiedNoWritePageListHead);
  1822. UIP(MmAvailablePages);
  1823. UIP(MmResidentAvailablePages);
  1824. UIP(PoolTrackTable);
  1825. UIP(NonPagedPoolDescriptor);
  1826. UIP(MmHighestUserAddress);
  1827. UIP(MmSystemRangeStart);
  1828. UIP(MmUserProbeAddress);
  1829. UIP(KdPrintCircularBuffer);
  1830. UIP(KdPrintCircularBufferEnd);
  1831. UIP(KdPrintWritePointer);
  1832. UIP(KdPrintRolloverCount);
  1833. UIP(MmLoadedUserImageList);
  1834. // NT 5.1 additions
  1835. UIP(NtBuildLab);
  1836. UIP(KiNormalSystemCall);
  1837. // NT 5.0 QFE additions
  1838. UIP(KiProcessorBlock);
  1839. UIP(MmUnloadedDrivers);
  1840. UIP(MmLastUnloadedDriver);
  1841. UIP(MmTriageActionTaken);
  1842. UIP(MmSpecialPoolTag);
  1843. UIP(KernelVerifier);
  1844. UIP(MmVerifierData);
  1845. UIP(MmAllocatedNonPagedPool);
  1846. UIP(MmPeakCommitment);
  1847. UIP(MmTotalCommitLimitMaximum);
  1848. UIP(CmNtCSDVersion);
  1849. // NT 5.1 additions
  1850. UIP(MmPhysicalMemoryBlock);
  1851. UIP(MmSessionBase);
  1852. UIP(MmSessionSize);
  1853. UIP(MmSystemParentTablePage);
  1854. }
  1855. }
  1856. else
  1857. {
  1858. if (Size != sizeof(LocalData32))
  1859. {
  1860. ErrOut("Someone changed the definition of KDDEBUGGER_DATA32 - "
  1861. "please fix\n");
  1862. return E_FAIL;
  1863. }
  1864. Status = g_Target->ReadVirtual(g_KdDebuggerDataBlock, &LocalData32,
  1865. sizeof(LocalData32), &Result);
  1866. if (Status != S_OK || Result != sizeof(LocalData32))
  1867. {
  1868. ErrOut("KdDebuggerDataBlock Could not be read\n");
  1869. return Status == S_OK ? E_FAIL : Status;
  1870. }
  1871. else
  1872. {
  1873. //
  1874. // Convert all the 32 bits fields to 64 bit
  1875. //
  1876. #undef UIP
  1877. #undef CP
  1878. #define UIP(f) KdDebuggerData.f = EXTEND64(LocalData32.f)
  1879. #define CP(f) KdDebuggerData.f = (LocalData32.f)
  1880. //
  1881. // Extend the header so it doesn't get whacked
  1882. //
  1883. ListEntry32To64((PLIST_ENTRY32)(&LocalData32.Header.List),
  1884. &(KdDebuggerData.Header.List));
  1885. KdDebuggerData.Header.OwnerTag = LocalData32.Header.OwnerTag;
  1886. KdDebuggerData.Header.Size = LocalData32.Header.Size;
  1887. UIP(KernBase);
  1888. UIP(BreakpointWithStatus);
  1889. UIP(SavedContext);
  1890. CP(ThCallbackStack);
  1891. CP(NextCallback);
  1892. CP(FramePointer);
  1893. CP(PaeEnabled);
  1894. UIP(KiCallUserMode);
  1895. UIP(KeUserCallbackDispatcher);
  1896. UIP(PsLoadedModuleList);
  1897. UIP(PsActiveProcessHead);
  1898. UIP(PspCidTable);
  1899. UIP(ExpSystemResourcesList);
  1900. UIP(ExpPagedPoolDescriptor);
  1901. UIP(ExpNumberOfPagedPools);
  1902. UIP(KeTimeIncrement);
  1903. UIP(KeBugCheckCallbackListHead);
  1904. UIP(KiBugcheckData);
  1905. UIP(IopErrorLogListHead);
  1906. UIP(ObpRootDirectoryObject);
  1907. UIP(ObpTypeObjectType);
  1908. UIP(MmSystemCacheStart);
  1909. UIP(MmSystemCacheEnd);
  1910. UIP(MmSystemCacheWs);
  1911. UIP(MmPfnDatabase);
  1912. UIP(MmSystemPtesStart);
  1913. UIP(MmSystemPtesEnd);
  1914. UIP(MmSubsectionBase);
  1915. UIP(MmNumberOfPagingFiles);
  1916. UIP(MmLowestPhysicalPage);
  1917. UIP(MmHighestPhysicalPage);
  1918. UIP(MmNumberOfPhysicalPages);
  1919. UIP(MmMaximumNonPagedPoolInBytes);
  1920. UIP(MmNonPagedSystemStart);
  1921. UIP(MmNonPagedPoolStart);
  1922. UIP(MmNonPagedPoolEnd);
  1923. UIP(MmPagedPoolStart);
  1924. UIP(MmPagedPoolEnd);
  1925. UIP(MmPagedPoolInformation);
  1926. CP(MmPageSize);
  1927. UIP(MmSizeOfPagedPoolInBytes);
  1928. UIP(MmTotalCommitLimit);
  1929. UIP(MmTotalCommittedPages);
  1930. UIP(MmSharedCommit);
  1931. UIP(MmDriverCommit);
  1932. UIP(MmProcessCommit);
  1933. UIP(MmPagedPoolCommit);
  1934. UIP(MmExtendedCommit);
  1935. UIP(MmZeroedPageListHead);
  1936. UIP(MmFreePageListHead);
  1937. UIP(MmStandbyPageListHead);
  1938. UIP(MmModifiedPageListHead);
  1939. UIP(MmModifiedNoWritePageListHead);
  1940. UIP(MmAvailablePages);
  1941. UIP(MmResidentAvailablePages);
  1942. UIP(PoolTrackTable);
  1943. UIP(NonPagedPoolDescriptor);
  1944. UIP(MmHighestUserAddress);
  1945. UIP(MmSystemRangeStart);
  1946. UIP(MmUserProbeAddress);
  1947. UIP(KdPrintCircularBuffer);
  1948. UIP(KdPrintCircularBufferEnd);
  1949. UIP(KdPrintWritePointer);
  1950. UIP(KdPrintRolloverCount);
  1951. UIP(MmLoadedUserImageList);
  1952. //
  1953. // DO NOT ADD ANY FIELDS HERE
  1954. // The 32 bit structure should not be changed
  1955. //
  1956. }
  1957. }
  1958. // Read build lab information if possible.
  1959. Result = 0;
  1960. if (KdDebuggerData.NtBuildLab != 0)
  1961. {
  1962. ULONG PreLen;
  1963. strcpy(g_TargetBuildLabName, "Built by: ");
  1964. PreLen = strlen(g_TargetBuildLabName);
  1965. if (g_Target->ReadVirtual(KdDebuggerData.NtBuildLab,
  1966. g_TargetBuildLabName + PreLen,
  1967. sizeof(g_TargetBuildLabName) - PreLen - 1,
  1968. &Result) == S_OK &&
  1969. Result >= 2)
  1970. {
  1971. Result += PreLen;
  1972. }
  1973. }
  1974. DBG_ASSERT(Result < sizeof(g_TargetBuildLabName));
  1975. g_TargetBuildLabName[Result] = 0;
  1976. //
  1977. // Reset specific fields base on the build lab names
  1978. // NOTE: lab names can be of different cases, so you must do case
  1979. // insensitive compares.
  1980. //
  1981. char BuildLabName[272];
  1982. strcpy(BuildLabName, g_TargetBuildLabName);
  1983. _strlwr(BuildLabName);
  1984. if (strstr(BuildLabName, "lab01"))
  1985. {
  1986. if ((g_TargetBuildNumber > 2405) &&
  1987. (g_TargetMachineType == IMAGE_FILE_MACHINE_I386))
  1988. {
  1989. g_TargetMachine->m_OffsetKThreadNextProcessor =
  1990. X86_NT51_KTHREAD_NEXTPROCESSOR_OFFSET;
  1991. }
  1992. }
  1993. //
  1994. // Sanity check and Debug output.
  1995. //
  1996. if (KdDebuggerData.Header.OwnerTag != KDBG_TAG)
  1997. {
  1998. dprintf("\nKdDebuggerData.Header.OwnerTag is wrong !!!\n");
  1999. }
  2000. KdOut("LoadKdDataBlock %08lx\n", Status);
  2001. KdOut("KernBase %s\n",
  2002. FormatAddr64(KdDebuggerData.KernBase));
  2003. KdOut("BreakpointWithStatus %s\n",
  2004. FormatAddr64(KdDebuggerData.BreakpointWithStatus));
  2005. KdOut("SavedContext %s\n",
  2006. FormatAddr64(KdDebuggerData.SavedContext));
  2007. KdOut("ThCallbackStack %08lx\n",
  2008. KdDebuggerData.ThCallbackStack);
  2009. KdOut("NextCallback %08lx\n",
  2010. KdDebuggerData.NextCallback);
  2011. KdOut("FramePointer %08lx\n",
  2012. KdDebuggerData.FramePointer);
  2013. KdOut("PaeEnabled %08lx\n",
  2014. KdDebuggerData.PaeEnabled);
  2015. KdOut("KiCallUserMode %s\n",
  2016. FormatAddr64(KdDebuggerData.KiCallUserMode));
  2017. KdOut("KeUserCallbackDispatcher %s\n",
  2018. FormatAddr64(KdDebuggerData.KeUserCallbackDispatcher));
  2019. KdOut("PsLoadedModuleList %s\n",
  2020. FormatAddr64(KdDebuggerData.PsLoadedModuleList));
  2021. KdOut("PsActiveProcessHead %s\n",
  2022. FormatAddr64(KdDebuggerData.PsActiveProcessHead));
  2023. KdOut("MmPageSize %s\n",
  2024. FormatAddr64(KdDebuggerData.MmPageSize));
  2025. KdOut("MmLoadedUserImageList %s\n",
  2026. FormatAddr64(KdDebuggerData.MmLoadedUserImageList));
  2027. KdOut("MmSystemRangeStart %s\n",
  2028. FormatAddr64(KdDebuggerData.MmSystemRangeStart));
  2029. KdOut("KiProcessorBlock %s\n",
  2030. FormatAddr64(KdDebuggerData.KiProcessorBlock));
  2031. return Status;
  2032. }
  2033. BOOL
  2034. VerifyKernelBase (
  2035. IN BOOL LoadImage
  2036. )
  2037. {
  2038. PDEBUG_IMAGE_INFO p;
  2039. //
  2040. // User mode dumps have no kernel information.
  2041. //
  2042. if (IS_USER_TARGET())
  2043. {
  2044. return FALSE;
  2045. }
  2046. //
  2047. // Ask host for version information
  2048. //
  2049. if (!IS_DUMP_TARGET())
  2050. {
  2051. //
  2052. // Force load of KD data block
  2053. //
  2054. if (g_SystemVersion <= NT_SVER_NT4)
  2055. {
  2056. KdDebuggerData.PsLoadedModuleList =
  2057. EXTEND64(g_KdVersion.PsLoadedModuleList);
  2058. KdDebuggerData.KernBase = g_KdVersion.KernBase;
  2059. }
  2060. else
  2061. {
  2062. if (LoadKdDataBlock(FALSE) != STATUS_SUCCESS)
  2063. {
  2064. goto VerifyError;
  2065. }
  2066. //
  2067. // The version and KdDebuggerData blocks should agree on
  2068. // the version !
  2069. //
  2070. if ((g_KdVersion.KernBase != KdDebuggerData.KernBase) ||
  2071. (g_KdVersion.PsLoadedModuleList !=
  2072. KdDebuggerData.PsLoadedModuleList))
  2073. {
  2074. ErrOut("Debugger can not determine kernel base address\n");
  2075. }
  2076. }
  2077. }
  2078. if (LoadImage)
  2079. {
  2080. //
  2081. // Verify only one kernel image loaded & it's at the correct base
  2082. // For crashdump we may not have the KernBase at this point.
  2083. //
  2084. for (p = g_ProcessHead->ImageHead;
  2085. p && KdDebuggerData.KernBase;
  2086. p = p->Next)
  2087. {
  2088. if (p->BaseOfImage == KdDebuggerData.KernBase)
  2089. {
  2090. //
  2091. // Already loaded with current base address
  2092. //
  2093. DelImageByBase(g_CurrentProcess, p->BaseOfImage);
  2094. break;
  2095. }
  2096. }
  2097. //
  2098. // If acceptable kernel image was not found load one now
  2099. //
  2100. // Wow ! possible recursive call to bangReload - that's OK though :-)
  2101. // ... as long as we only call with "NT"
  2102. //
  2103. if (g_Target->Reload(KERNEL_MODULE_NAME) == E_INVALIDARG)
  2104. {
  2105. // The most likely cause of this is missing paths.
  2106. // We don't necessarily need a path to load
  2107. // the kernel, so try again and ignore path problems.
  2108. g_Target->Reload("-P "KERNEL_MODULE_NAME);
  2109. }
  2110. }
  2111. //
  2112. // After the kernel mode symbols are loaded, we can now try to load
  2113. // the DataBlock from the dump file.
  2114. //
  2115. if (IS_DUMP_TARGET() &&
  2116. (!IS_KERNEL_TRIAGE_DUMP() || g_TriageDumpHasDebuggerData))
  2117. {
  2118. LoadKdDataBlock(TRUE);
  2119. }
  2120. if (g_TargetMachineType == IMAGE_FILE_MACHINE_IA64)
  2121. {
  2122. //
  2123. // Try to determine the kernel base virtual mapping address
  2124. // for IA64. This should be done as early as possible
  2125. // to enable later virtual translations to work.
  2126. //
  2127. if (!IS_KERNEL_TRIAGE_DUMP())
  2128. {
  2129. if (!KdDebuggerData.MmSystemParentTablePage)
  2130. {
  2131. GetOffsetFromSym("nt!MmSystemParentTablePage",
  2132. &KdDebuggerData.MmSystemParentTablePage,
  2133. NULL);
  2134. }
  2135. if (KdDebuggerData.MmSystemParentTablePage)
  2136. {
  2137. ADDR Addr;
  2138. ULONG64 SysPtp;
  2139. ADDRFLAT(&Addr, KdDebuggerData.MmSystemParentTablePage);
  2140. if (GetMemQword(&Addr, &SysPtp))
  2141. {
  2142. g_Ia64Machine.
  2143. SetKernelPageDirectory(SysPtp << IA64_VALID_PFN_SHIFT);
  2144. }
  2145. }
  2146. }
  2147. //
  2148. // Get the system call address from the debugger data block
  2149. // Added around build 2204.
  2150. // Default to symbols otherwise.
  2151. //
  2152. g_SystemCallVirtualAddress = 0;
  2153. if (KdDebuggerData.KiNormalSystemCall)
  2154. {
  2155. g_Target->ReadPointer(g_TargetMachine,
  2156. KdDebuggerData.KiNormalSystemCall,
  2157. &g_SystemCallVirtualAddress);
  2158. }
  2159. if (!g_SystemCallVirtualAddress)
  2160. {
  2161. g_SystemCallVirtualAddress =
  2162. ExtGetExpression( "nt!KiNormalSystemCall" );
  2163. }
  2164. if (!g_SystemCallVirtualAddress)
  2165. {
  2166. g_SystemCallVirtualAddress =
  2167. ExtGetExpression( "nt!.KiNormalSystemCall" );
  2168. }
  2169. if (!g_SystemCallVirtualAddress)
  2170. {
  2171. WarnOut("Could not get KiNormalSystemCall address\n");
  2172. }
  2173. }
  2174. //
  2175. // Now that we have symbols and a data block try to
  2176. // get CmNtCSDVersion, first from the data block and
  2177. // then from the symbols if necessary.
  2178. //
  2179. // If we didn't get unloaded driver information try to
  2180. // get it from symbols.
  2181. //
  2182. //
  2183. if (!IS_KERNEL_TRIAGE_DUMP())
  2184. {
  2185. if (!KdDebuggerData.CmNtCSDVersion)
  2186. {
  2187. GetOffsetFromSym("nt!CmNtCSDVersion",
  2188. &KdDebuggerData.CmNtCSDVersion,
  2189. NULL);
  2190. }
  2191. if (KdDebuggerData.CmNtCSDVersion)
  2192. {
  2193. ADDR Addr;
  2194. ULONG CmNtCSDVersion;
  2195. ADDRFLAT(&Addr, KdDebuggerData.CmNtCSDVersion);
  2196. if (GetMemDword(&Addr, &CmNtCSDVersion))
  2197. {
  2198. SetTargetNtCsdVersion(CmNtCSDVersion);
  2199. }
  2200. }
  2201. if (KdDebuggerData.MmUnloadedDrivers == 0)
  2202. {
  2203. GetOffsetFromSym("nt!MmUnloadedDrivers",
  2204. &KdDebuggerData.MmUnloadedDrivers,
  2205. NULL);
  2206. }
  2207. if (KdDebuggerData.MmLastUnloadedDriver == 0)
  2208. {
  2209. GetOffsetFromSym("nt!MmLastUnloadedDriver",
  2210. &KdDebuggerData.MmLastUnloadedDriver,
  2211. NULL);
  2212. }
  2213. if (KdDebuggerData.KiProcessorBlock == 0)
  2214. {
  2215. GetOffsetFromSym("nt!KiProcessorBlock",
  2216. &KdDebuggerData.KiProcessorBlock,
  2217. NULL);
  2218. }
  2219. if (KdDebuggerData.MmPhysicalMemoryBlock == 0)
  2220. {
  2221. GetOffsetFromSym("nt!MmPhysicalMemoryBlock",
  2222. &KdDebuggerData.MmPhysicalMemoryBlock,
  2223. NULL);
  2224. }
  2225. }
  2226. //
  2227. // Try to get the start of system memory.
  2228. // This may be zero because we are looking at an NT 4 system, so try
  2229. // looking it up using symbols.
  2230. //
  2231. if (!KdDebuggerData.MmSystemRangeStart)
  2232. {
  2233. GetOffsetFromSym("nt!MmSystemRangeStart",
  2234. &KdDebuggerData.MmSystemRangeStart,
  2235. NULL);
  2236. }
  2237. if (KdDebuggerData.MmSystemRangeStart)
  2238. {
  2239. g_Target->ReadPointer(g_TargetMachine,
  2240. KdDebuggerData.MmSystemRangeStart,
  2241. &g_SystemRangeStart);
  2242. }
  2243. //
  2244. // If we did not have symbols, at least pick a default value.
  2245. //
  2246. if (!g_SystemRangeStart)
  2247. {
  2248. g_SystemRangeStart = 0xFFFFFFFF80000000;
  2249. }
  2250. if (KdDebuggerData.KernBase < g_SystemRangeStart)
  2251. {
  2252. ErrOut("KdDebuggerData.KernBase < g_SystemRangeStart\n");
  2253. }
  2254. return TRUE;
  2255. VerifyError:
  2256. // This is always the case in early loader situations
  2257. // so suppress duplicate error messages.
  2258. if ((g_EngErr & ENG_ERR_DEBUGGER_DATA) == 0)
  2259. {
  2260. WarnOut("Kernel base address could not be determined. "
  2261. "Please try to reconnect with .reload\n");
  2262. g_EngErr |= ENG_ERR_DEBUGGER_DATA;
  2263. }
  2264. return FALSE;
  2265. }
  2266. #define EXCEPTION_CODE StateChange->u.Exception.ExceptionRecord.ExceptionCode
  2267. #define FIRST_CHANCE StateChange->u.Exception.FirstChance
  2268. ULONG
  2269. ProcessStateChange(PDBGKD_ANY_WAIT_STATE_CHANGE StateChange,
  2270. PCHAR StateChangeData)
  2271. {
  2272. ULONG EventStatus;
  2273. //
  2274. // If the reported instruction stream contained breakpoints
  2275. // the kernel automatically removed them. We need to
  2276. // ensure that breakpoints get reinserted properly if
  2277. // that's the case.
  2278. //
  2279. ULONG Count;
  2280. switch(g_TargetMachineType)
  2281. {
  2282. case IMAGE_FILE_MACHINE_IA64:
  2283. Count = g_ControlReport->IA64ControlReport.InstructionCount;
  2284. break;
  2285. case IMAGE_FILE_MACHINE_ALPHA:
  2286. case IMAGE_FILE_MACHINE_AXP64:
  2287. Count = g_ControlReport->AlphaControlReport.InstructionCount;
  2288. break;
  2289. case IMAGE_FILE_MACHINE_I386:
  2290. Count = g_ControlReport->X86ControlReport.InstructionCount;
  2291. break;
  2292. case IMAGE_FILE_MACHINE_AMD64:
  2293. Count = g_ControlReport->Amd64ControlReport.InstructionCount;
  2294. break;
  2295. }
  2296. if (CheckBreakpointInsertedInRange(g_ProcessHead,
  2297. g_EventPc, g_EventPc + Count - 1))
  2298. {
  2299. SuspendExecution();
  2300. RemoveBreakpoints();
  2301. }
  2302. if (StateChange->NewState == DbgKdExceptionStateChange)
  2303. {
  2304. //
  2305. // Read the system range start address from the target system.
  2306. //
  2307. if (g_SystemRangeStart == 0)
  2308. {
  2309. VerifyKernelBase(FALSE);
  2310. }
  2311. EventOut("Exception %X at %p\n", EXCEPTION_CODE, g_EventPc);
  2312. if (EXCEPTION_CODE == STATUS_BREAKPOINT ||
  2313. EXCEPTION_CODE == STATUS_SINGLE_STEP ||
  2314. EXCEPTION_CODE == STATUS_WX86_BREAKPOINT ||
  2315. EXCEPTION_CODE == STATUS_WX86_SINGLE_STEP)
  2316. {
  2317. EventStatus = ProcessBreakpointOrStepException
  2318. (&StateChange->u.Exception.ExceptionRecord,
  2319. StateChange->u.Exception.FirstChance);
  2320. }
  2321. else if (EXCEPTION_CODE == STATUS_WAKE_SYSTEM_DEBUGGER)
  2322. {
  2323. // The target has requested that the debugger
  2324. // become active so just break in.
  2325. EventStatus = DEBUG_STATUS_BREAK;
  2326. }
  2327. else
  2328. {
  2329. EventStatus =
  2330. NotifyExceptionEvent(&StateChange->u.Exception.ExceptionRecord,
  2331. StateChange->u.Exception.FirstChance,
  2332. FALSE);
  2333. }
  2334. }
  2335. else if (StateChange->NewState == DbgKdLoadSymbolsStateChange)
  2336. {
  2337. if (StateChange->u.LoadSymbols.UnloadSymbols)
  2338. {
  2339. if (StateChange->u.LoadSymbols.PathNameLength == 0 &&
  2340. StateChange->u.LoadSymbols.ProcessId == 0)
  2341. {
  2342. if (StateChange->u.LoadSymbols.BaseOfDll == (ULONG64)KD_REBOOT ||
  2343. StateChange->u.LoadSymbols.BaseOfDll == (ULONG64)KD_HIBERNATE)
  2344. {
  2345. DbgKdContinue(DBG_CONTINUE);
  2346. ResetConnection(StateChange->u.LoadSymbols.BaseOfDll ==
  2347. KD_REBOOT ? DEBUG_SESSION_REBOOT :
  2348. DEBUG_SESSION_HIBERNATE);
  2349. EventStatus = DEBUG_STATUS_NO_DEBUGGEE;
  2350. }
  2351. else
  2352. {
  2353. ErrOut("Invalid module unload state change\n");
  2354. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  2355. }
  2356. }
  2357. else
  2358. {
  2359. EventStatus = NotifyUnloadModuleEvent
  2360. (StateChangeData, StateChange->u.LoadSymbols.BaseOfDll);
  2361. }
  2362. }
  2363. else
  2364. {
  2365. PDEBUG_IMAGE_INFO pImage;
  2366. CHAR fname[_MAX_FNAME];
  2367. CHAR ext[_MAX_EXT];
  2368. CHAR ImageName[256];
  2369. CHAR ModName[256];
  2370. LPSTR pModName = ModName;
  2371. LPSTR p;
  2372. ModName[0] = '\0';
  2373. _splitpath( StateChangeData, NULL, NULL, fname, ext );
  2374. sprintf( ImageName, "%s%s", fname, ext );
  2375. if (_stricmp(ext, ".sys") == 0)
  2376. {
  2377. pImage = g_EventProcess ? g_EventProcess->ImageHead : NULL;
  2378. while (pImage)
  2379. {
  2380. if (_stricmp(ImageName, pImage->ImagePath) == 0)
  2381. {
  2382. ModName[0] = 'c';
  2383. strcpy( &ModName[1], ImageName );
  2384. p = strchr( ModName, '.' );
  2385. if (p)
  2386. {
  2387. *p = '\0';
  2388. }
  2389. ModName[8] = '\0';
  2390. break;
  2391. }
  2392. pImage = pImage->Next;
  2393. }
  2394. }
  2395. else if (StateChange->u.LoadSymbols.BaseOfDll ==
  2396. KdDebuggerData.KernBase)
  2397. {
  2398. //
  2399. // Recognize the kernel module.
  2400. //
  2401. pModName = KERNEL_MODULE_NAME;
  2402. }
  2403. EventStatus = NotifyLoadModuleEvent(
  2404. 0, StateChange->u.LoadSymbols.BaseOfDll,
  2405. StateChange->u.LoadSymbols.SizeOfImage,
  2406. *pModName ? pModName : NULL, ImageName,
  2407. StateChange->u.LoadSymbols.CheckSum, 0);
  2408. }
  2409. }
  2410. else if (StateChange->NewState == DbgKdCommandStringStateChange)
  2411. {
  2412. PSTR Command;
  2413. //
  2414. // The state change data has two strings one after
  2415. // the other. The first is a name string identifying
  2416. // the originator of the command. The second is
  2417. // the command itself.
  2418. //
  2419. Command = StateChangeData + strlen(StateChangeData) + 1;
  2420. _snprintf(g_LastEventDesc, sizeof(g_LastEventDesc) - 1,
  2421. "%.48s command: '%.192s'",
  2422. StateChangeData, Command);
  2423. EventStatus = ExecuteEventCommand(DEBUG_STATUS_NO_CHANGE, NULL,
  2424. Command);
  2425. // Break in if the command didn't explicitly continuation.
  2426. if (EventStatus == DEBUG_STATUS_NO_CHANGE)
  2427. {
  2428. EventStatus = DEBUG_STATUS_BREAK;
  2429. }
  2430. }
  2431. else
  2432. {
  2433. //
  2434. // Invalid NewState in state change record.
  2435. //
  2436. ErrOut("\nUNEXPECTED STATE CHANGE %08lx\n\n",
  2437. StateChange->NewState);
  2438. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  2439. }
  2440. return EventStatus;
  2441. }
  2442. #undef EXCEPTION_CODE
  2443. #undef FIRST_CHANCE
  2444. void
  2445. ResetConnection(ULONG Reason)
  2446. {
  2447. if (Reason == DEBUG_SESSION_REBOOT)
  2448. {
  2449. dprintf("Shutdown occurred...unloading all symbol tables.\n");
  2450. }
  2451. else
  2452. {
  2453. dprintf("Hibernate occurred\n");
  2454. }
  2455. DiscardMachine(Reason);
  2456. }
  2457. void
  2458. CreateKernelProcessAndThreads(void)
  2459. {
  2460. g_EngNotify++;
  2461. // Create the fake kernel process.
  2462. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  2463. g_EventThreadSysId = VIRTUAL_THREAD_ID(0);
  2464. NotifyCreateProcessEvent(0, (ULONG64)VIRTUAL_PROCESS_HANDLE, 0, 0,
  2465. NULL, NULL, 0, 0,
  2466. (ULONG64)VIRTUAL_THREAD_HANDLE(0), 0, 0, 0,
  2467. DEBUG_PROCESS_ONLY_THIS_PROCESS, 0);
  2468. // Create any remaining threads.
  2469. AddKernelThreads(1, g_TargetNumberProcessors - 1);
  2470. g_EngNotify--;
  2471. // Don't leave event variables set as these
  2472. // weren't true events.
  2473. g_EventProcessSysId = 0;
  2474. g_EventThreadSysId = 0;
  2475. g_EventProcess = NULL;
  2476. g_EventThread = NULL;
  2477. }
  2478. void
  2479. AddKernelThreads(ULONG Start, ULONG Count)
  2480. {
  2481. g_EngNotify++;
  2482. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  2483. while (Count-- > 0)
  2484. {
  2485. g_EventThreadSysId = VIRTUAL_THREAD_ID(Start);
  2486. NotifyCreateThreadEvent((ULONG64)VIRTUAL_THREAD_HANDLE(Start), 0,
  2487. 0, 0);
  2488. Start++;
  2489. }
  2490. g_EngNotify--;
  2491. }
  2492. //----------------------------------------------------------------------------
  2493. //
  2494. // LocalLiveKernelTargetInfo::WaitForEvent.
  2495. //
  2496. //----------------------------------------------------------------------------
  2497. HRESULT
  2498. LocalLiveKernelTargetInfo::WaitForEvent(ULONG Flags, ULONG Timeout)
  2499. {
  2500. HRESULT Status;
  2501. ULONG i;
  2502. ULONG ContinueStatus;
  2503. SYSTEM_INFO SystemInfo;
  2504. if (g_EngStatus & ENG_STATUS_PROCESSES_ADDED)
  2505. {
  2506. // A wait has already been done. Local kernels
  2507. // can only generate a single event so further
  2508. // waiting is not possible.
  2509. return E_UNEXPECTED;
  2510. }
  2511. // Even though local kernels don't really wait the standard
  2512. // preparation still needs to be done to set things
  2513. // up and generate the usual callbacks. The continuation
  2514. // part of things is simply ignored.
  2515. Status = PrepareForWait(Flags, &ContinueStatus);
  2516. if (FAILED(Status))
  2517. {
  2518. return Status;
  2519. }
  2520. GetSystemInfo(&SystemInfo);
  2521. g_TargetNumberProcessors = SystemInfo.dwNumberOfProcessors;
  2522. g_Target->GetKdVersion();
  2523. // This is the first wait. Simulate any
  2524. // necessary events such as process and thread
  2525. // creations and image loads.
  2526. Status = InitializeMachine(g_TargetMachineType);
  2527. if (Status != S_OK)
  2528. {
  2529. ErrOut("Unable to initialize target machine information\n");
  2530. return Status;
  2531. }
  2532. // Don't give real callbacks for processes/threads as
  2533. // they're just faked in the kernel case.
  2534. g_EngNotify++;
  2535. CreateKernelProcessAndThreads();
  2536. // Load kernel version information and symbols.
  2537. VerifyKernelBase(TRUE);
  2538. g_Target->OutputVersion();
  2539. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  2540. // Current process always starts at zero.
  2541. g_EventThreadSysId = VIRTUAL_THREAD_ID(0);
  2542. // Clear the global state change just in case somebody's
  2543. // directly accessing it somewhere.
  2544. ZeroMemory(&g_StateChange, sizeof(g_StateChange));
  2545. g_StateChangeData = g_StateChangeBuffer;
  2546. g_StateChangeBuffer[0] = 0;
  2547. // Do not provide a control report; this will force
  2548. // such information to come from context retrieval.
  2549. g_ControlReport = NULL;
  2550. // There isn't a current PC, let it be discovered.
  2551. g_EventPc = 0;
  2552. g_EngStatus |= ENG_STATUS_STATE_CHANGED;
  2553. // The engine is now initialized so a real event
  2554. // can be generated.
  2555. g_EngNotify--;
  2556. FindEventProcessThread();
  2557. Status = S_OK;
  2558. g_EngStatus &= ~ENG_STATUS_WAITING;
  2559. // Control is passing back to the caller so the engine must
  2560. // be ready for command processing.
  2561. PrepareForCalls(0);
  2562. EventOut("> Wait returning %X\n", Status);
  2563. return Status;
  2564. }
  2565. //----------------------------------------------------------------------------
  2566. //
  2567. // ExdiLiveKernelTargetInfo::WaitForEvent.
  2568. //
  2569. //----------------------------------------------------------------------------
  2570. HRESULT
  2571. ExdiLiveKernelTargetInfo::WaitForEvent(ULONG Flags, ULONG Timeout)
  2572. {
  2573. HRESULT Status;
  2574. ULONG EventStatus;
  2575. ULONG ContinueStatus;
  2576. // eXDI deals with hardware exceptions, not software
  2577. // exceptions, so there's no concept of handled/not-handled
  2578. // and first/second-chance.
  2579. Status = PrepareForWait(Flags, &ContinueStatus);
  2580. if ((g_EngStatus & ENG_STATUS_WAITING) == 0)
  2581. {
  2582. return Status;
  2583. }
  2584. EventOut("> Executing\n");
  2585. for (;;)
  2586. {
  2587. EventOut(">> Waiting\n");
  2588. ProcessDeferredWork(&ContinueStatus);
  2589. if (g_EventProcessSysId)
  2590. {
  2591. EventOut(">> Continue with %X\n", ContinueStatus);
  2592. if (g_EngDefer & ENG_DEFER_HARDWARE_TRACING)
  2593. {
  2594. // Processor trace flag was set. eXDI can change
  2595. // the trace flag itself, though, so use the
  2596. // official eXDI stepping methods rather than
  2597. // rely on the trace flag. This will result
  2598. // in a single instruction execution, after
  2599. // which the trace flag will be clear so
  2600. // go ahead and clear the defer flag.
  2601. Status = m_Server->DoSingleStep();
  2602. if (Status == S_OK)
  2603. {
  2604. g_EngDefer &= ~ENG_DEFER_HARDWARE_TRACING;
  2605. }
  2606. }
  2607. else
  2608. {
  2609. Status = m_Server->Run();
  2610. }
  2611. if (Status != S_OK)
  2612. {
  2613. ErrOut("IeXdiServer::Run failed, 0x%X\n", Status);
  2614. goto Exit;
  2615. }
  2616. }
  2617. DiscardLastEvent();
  2618. DWORD Cookie;
  2619. if ((Status = m_Server->StartNotifyingRunChg(&m_RunChange,
  2620. &Cookie)) != S_OK)
  2621. {
  2622. ErrOut("IeXdiServer::StartNotifyingRunChg failed, 0x%X\n",
  2623. Status);
  2624. goto Exit;
  2625. }
  2626. RUN_STATUS_TYPE RunStatus;
  2627. if ((Status = m_Server->
  2628. GetRunStatus(&RunStatus, &m_RunChange.m_HaltReason,
  2629. &m_RunChange.m_ExecAddress,
  2630. &m_RunChange.m_ExceptionCode)) != S_OK)
  2631. {
  2632. ErrOut("IeXdiServer::GetRunStatus failed, 0x%X\n",
  2633. Status);
  2634. goto Exit;
  2635. }
  2636. DWORD WaitStatus;
  2637. if (RunStatus == rsRunning)
  2638. {
  2639. SUSPEND_ENGINE();
  2640. // We need to run a message pump so COM
  2641. // can deliver calls properly.
  2642. for (;;)
  2643. {
  2644. if (g_EngStatus & ENG_STATUS_EXIT_CURRENT_WAIT)
  2645. {
  2646. WaitStatus = WAIT_FAILED;
  2647. SetLastError(ERROR_IO_PENDING);
  2648. break;
  2649. }
  2650. WaitStatus = MsgWaitForMultipleObjects(1, &m_RunChange.m_Event,
  2651. FALSE, Timeout,
  2652. QS_ALLEVENTS);
  2653. if (WaitStatus == WAIT_OBJECT_0 + 1)
  2654. {
  2655. MSG Msg;
  2656. if (GetMessage(&Msg, NULL, 0, 0))
  2657. {
  2658. TranslateMessage(&Msg);
  2659. DispatchMessage(&Msg);
  2660. }
  2661. }
  2662. else
  2663. {
  2664. // We either successfully waited, timed-out or failed.
  2665. // Break out to handle it.
  2666. break;
  2667. }
  2668. }
  2669. RESUME_ENGINE();
  2670. }
  2671. else
  2672. {
  2673. WaitStatus = WAIT_OBJECT_0;
  2674. }
  2675. m_Server->StopNotifyingRunChg(Cookie);
  2676. // Make sure we're not leaving the event set.
  2677. ResetEvent(m_RunChange.m_Event);
  2678. if (WaitStatus == WAIT_TIMEOUT)
  2679. {
  2680. Status = S_FALSE;
  2681. goto Exit;
  2682. }
  2683. else if (WaitStatus != WAIT_OBJECT_0)
  2684. {
  2685. Status = WIN32_LAST_STATUS();
  2686. ErrOut("WaitForSingleObject failed, 0x%X\n", Status);
  2687. goto Exit;
  2688. }
  2689. EventOut(">>> RunChange halt reason %d\n",
  2690. m_RunChange.m_HaltReason);
  2691. g_EngStatus |= ENG_STATUS_STATE_CHANGED;
  2692. if (!IS_MACHINE_SET())
  2693. {
  2694. dprintf("Kernel Debugger connection established\n");
  2695. g_TargetNumberProcessors = 1;
  2696. // eXDI kernels are always treated as Win2K so
  2697. // it's assumed it uses the 64-bit API.
  2698. if (m_KdSupport == EXDI_KD_NONE)
  2699. {
  2700. DbgKdApi64 = TRUE;
  2701. g_SystemVersion = NT_SVER_W2K;
  2702. }
  2703. g_Target->GetKdVersion();
  2704. Status = InitializeMachine(m_ExpectedMachine);
  2705. if (Status != S_OK)
  2706. {
  2707. ErrOut("Unable to initialize target machine information\n");
  2708. goto Exit;
  2709. }
  2710. CreateKernelProcessAndThreads();
  2711. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  2712. g_EventThreadSysId = VIRTUAL_THREAD_ID(0);
  2713. FindEventProcessThread();
  2714. //
  2715. // Load kernel symbols.
  2716. //
  2717. if (g_ActualSystemVersion > NT_SVER_START &&
  2718. g_ActualSystemVersion < NT_SVER_END)
  2719. {
  2720. VerifyKernelBase(TRUE);
  2721. }
  2722. else
  2723. {
  2724. // Initialize some debugger data fields from known
  2725. // information as there isn't a real data block.
  2726. KdDebuggerData.MmPageSize = g_Machine->m_PageSize;
  2727. if (g_TargetMachineType == IMAGE_FILE_MACHINE_AMD64)
  2728. {
  2729. // AMD64 always operates in PAE mode.
  2730. KdDebuggerData.PaeEnabled = TRUE;
  2731. }
  2732. }
  2733. g_Target->OutputVersion();
  2734. }
  2735. else
  2736. {
  2737. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  2738. g_EventThreadSysId = VIRTUAL_THREAD_ID(0);
  2739. FindEventProcessThread();
  2740. }
  2741. g_EventPc = m_RunChange.m_ExecAddress;
  2742. g_ControlReport = NULL;
  2743. g_StateChangeData = NULL;
  2744. EventStatus = ProcessRunChange(m_RunChange.m_HaltReason,
  2745. m_RunChange.m_ExceptionCode);
  2746. EventOut(">>> RunChange event status %X\n", EventStatus);
  2747. if (EventStatus == DEBUG_STATUS_NO_DEBUGGEE)
  2748. {
  2749. // Machine has rebooted or something else
  2750. // which breaks the connection. Forget the
  2751. // connection and go back to waiting.
  2752. ContinueStatus = DBG_CONTINUE;
  2753. }
  2754. else if (EventStatus == DEBUG_STATUS_BREAK)
  2755. {
  2756. // If the event handlers requested a break return
  2757. // to the caller.
  2758. Status = S_OK;
  2759. goto Exit;
  2760. }
  2761. else
  2762. {
  2763. // We're resuming execution so reverse any
  2764. // command preparation that may have occurred
  2765. // while processing the event.
  2766. if ((Status = PrepareForExecution(EventStatus)) != S_OK)
  2767. {
  2768. goto Exit;
  2769. }
  2770. ContinueStatus = EventStatusToContinue(EventStatus);
  2771. }
  2772. }
  2773. Exit:
  2774. g_EngStatus &= ~ENG_STATUS_WAITING;
  2775. // Control is passing back to the caller so the engine must
  2776. // be ready for command processing.
  2777. PrepareForCalls(0);
  2778. EventOut("> Wait returning %X\n", Status);
  2779. return Status;
  2780. }
  2781. ULONG
  2782. ProcessRunChange(ULONG HaltReason, ULONG ExceptionCode)
  2783. {
  2784. ULONG EventStatus;
  2785. EXCEPTION_RECORD64 Record;
  2786. switch(HaltReason)
  2787. {
  2788. case hrUser:
  2789. case hrUnknown:
  2790. // User requested break in.
  2791. // Unknown breakin also seems to be the status at power-up.
  2792. EventStatus = DEBUG_STATUS_BREAK;
  2793. break;
  2794. case hrException:
  2795. // Fake an exception record.
  2796. ZeroMemory(&Record, sizeof(Record));
  2797. // The exceptions reported are hardware exceptions so
  2798. // there's no easy mapping to NT exception codes.
  2799. // Just report them as access violations.
  2800. Record.ExceptionCode = STATUS_ACCESS_VIOLATION;
  2801. Record.ExceptionAddress = g_EventPc;
  2802. // Hardware exceptions are always severe so always
  2803. // report them as second-chance.
  2804. EventStatus = NotifyExceptionEvent(&Record, FALSE, FALSE);
  2805. break;
  2806. case hrBp:
  2807. // Fake a breakpoint exception record.
  2808. ZeroMemory(&Record, sizeof(Record));
  2809. Record.ExceptionCode = STATUS_BREAKPOINT;
  2810. Record.ExceptionAddress = g_EventPc;
  2811. EventStatus = ProcessBreakpointOrStepException(&Record, TRUE);
  2812. break;
  2813. case hrStep:
  2814. // Fake a single-step exception record.
  2815. ZeroMemory(&Record, sizeof(Record));
  2816. Record.ExceptionCode = STATUS_SINGLE_STEP;
  2817. Record.ExceptionAddress = g_EventPc;
  2818. EventStatus = ProcessBreakpointOrStepException(&Record, TRUE);
  2819. break;
  2820. default:
  2821. ErrOut("Unknown HALT_REASON %d\n", HaltReason);
  2822. EventStatus = DEBUG_STATUS_BREAK;
  2823. break;
  2824. }
  2825. return EventStatus;
  2826. }
  2827. //----------------------------------------------------------------------------
  2828. //
  2829. // UserTargetInfo::WaitForEvent.
  2830. //
  2831. //----------------------------------------------------------------------------
  2832. void
  2833. SynthesizeWakeEvent(LPDEBUG_EVENT64 Event,
  2834. ULONG ProcessId, ULONG ThreadId)
  2835. {
  2836. // Fake up an event.
  2837. ZeroMemory(Event, sizeof(*Event));
  2838. Event->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
  2839. Event->dwProcessId = ProcessId;
  2840. Event->dwThreadId = ThreadId;
  2841. Event->u.Exception.ExceptionRecord.ExceptionCode =
  2842. STATUS_WAKE_SYSTEM_DEBUGGER;
  2843. Event->u.Exception.dwFirstChance = TRUE;
  2844. }
  2845. #define THREADS_ALLOC 256
  2846. HRESULT
  2847. CreateNonInvasiveProcessAndThreads(PUSER_DEBUG_SERVICES Services,
  2848. ULONG ProcessId, ULONG Flags, ULONG Options,
  2849. PULONG InitialThreadId)
  2850. {
  2851. ULONG64 Process;
  2852. PUSER_THREAD_INFO Threads, ThreadBuffer;
  2853. ULONG ThreadsAlloc = 0;
  2854. ULONG ThreadCount;
  2855. HRESULT Status;
  2856. //
  2857. // Retrieve process and thread information. This
  2858. // requires a thread buffer of unknown size and
  2859. // so involves a bit of trial and error.
  2860. //
  2861. for (;;)
  2862. {
  2863. ThreadsAlloc += THREADS_ALLOC;
  2864. ThreadBuffer = new USER_THREAD_INFO[ThreadsAlloc];
  2865. if (ThreadBuffer == NULL)
  2866. {
  2867. return E_OUTOFMEMORY;
  2868. }
  2869. if ((Status = Services->GetProcessInfo(ProcessId, &Process,
  2870. ThreadBuffer, ThreadsAlloc,
  2871. &ThreadCount)) != S_OK)
  2872. {
  2873. delete ThreadBuffer;
  2874. return Status;
  2875. }
  2876. if (ThreadCount <= ThreadsAlloc)
  2877. {
  2878. break;
  2879. }
  2880. }
  2881. //
  2882. // Create the process and thread structures from
  2883. // the retrieved data.
  2884. //
  2885. Threads = ThreadBuffer;
  2886. g_EngNotify++;
  2887. // Create the fake kernel process and initial thread.
  2888. g_EventProcessSysId = ProcessId;
  2889. g_EventThreadSysId = Threads->Id;
  2890. *InitialThreadId = Threads->Id;
  2891. NotifyCreateProcessEvent(0, Process, 0, 0, NULL, NULL, 0, 0,
  2892. Threads->Handle, 0, 0,
  2893. Flags | ENG_PROC_THREAD_CLOSE_HANDLE,
  2894. Options, ENG_PROC_THREAD_CLOSE_HANDLE);
  2895. // Create any remaining threads.
  2896. while (--ThreadCount > 0)
  2897. {
  2898. Threads++;
  2899. g_EventThreadSysId = Threads->Id;
  2900. NotifyCreateThreadEvent(Threads->Handle, 0, 0,
  2901. ENG_PROC_THREAD_CLOSE_HANDLE);
  2902. }
  2903. g_EngNotify--;
  2904. delete ThreadBuffer;
  2905. // Don't leave event variables set as these
  2906. // weren't true events.
  2907. g_EventProcessSysId = 0;
  2908. g_EventThreadSysId = 0;
  2909. g_EventProcess = NULL;
  2910. g_EventThread = NULL;
  2911. return S_OK;
  2912. }
  2913. HRESULT
  2914. ExamineActiveProcess(PUSER_DEBUG_SERVICES Services,
  2915. ULONG ProcessId, ULONG Flags, ULONG Options,
  2916. LPDEBUG_EVENT64 Event)
  2917. {
  2918. HRESULT Status;
  2919. ULONG InitialThreadId;
  2920. if ((Status = CreateNonInvasiveProcessAndThreads
  2921. (Services, ProcessId, Flags, Options, &InitialThreadId)) != S_OK)
  2922. {
  2923. ErrOut("Unable to examine process id %d, %s\n",
  2924. ProcessId, FormatStatusCode(Status));
  2925. return Status;
  2926. }
  2927. if (Flags & ENG_PROC_EXAMINED)
  2928. {
  2929. WarnOut("WARNING: Process %d is not attached as a debuggee\n",
  2930. ProcessId);
  2931. WarnOut(" The process can be examined but debug "
  2932. "events will not be received\n");
  2933. }
  2934. SynthesizeWakeEvent(Event, ProcessId, InitialThreadId);
  2935. return S_OK;
  2936. }
  2937. // When waiting for an attach we check process status relatively
  2938. // frequently. The overall timeout limit is also hard-coded
  2939. // as we expect some sort of debug event to always be delivered
  2940. // quickly.
  2941. #define ATTACH_PENDING_TIMEOUT 100
  2942. #define ATTACH_PENDING_TIMEOUT_LIMIT 600
  2943. // When not waiting for an attach the wait only waits one second,
  2944. // then checks to see if things have changed in a way that
  2945. // affects the wait. All timeouts are given in multiples of
  2946. // this interval.
  2947. #define DEFAULT_WAIT_TIMEOUT 1000
  2948. // A message is printed after this timeout interval to
  2949. // let the user know a break-in is pending.
  2950. #define PENDING_BREAK_IN_MESSAGE_TIMEOUT_LIMIT 3
  2951. HRESULT
  2952. UserTargetInfo::WaitForEvent(ULONG Flags, ULONG Timeout)
  2953. {
  2954. DEBUG_EVENT64 Event;
  2955. DWORD ContinueStatus;
  2956. HRESULT Status;
  2957. ULONG EventStatus;
  2958. ULONG UseTimeout = Timeout;
  2959. ULONG TimeoutCount = 0;
  2960. ULONG EventUsed;
  2961. ULONG ContinueDefer;
  2962. PPENDING_PROCESS Pending;
  2963. ULONG PendingFlags, PendingOptions;
  2964. ULONG ExamineResumeProcId = 0;
  2965. // Fail if there isn't a debuggee.
  2966. if (!ANY_PROCESSES())
  2967. {
  2968. return E_UNEXPECTED;
  2969. }
  2970. Status = PrepareForWait(Flags, &ContinueStatus);
  2971. if ((g_EngStatus & ENG_STATUS_WAITING) == 0)
  2972. {
  2973. return Status;
  2974. }
  2975. if (g_AllPendingFlags & ENG_PROC_ANY_ATTACH)
  2976. {
  2977. dprintf("*** wait with pending attach\n");
  2978. }
  2979. EventOut("> Executing\n");
  2980. for (;;)
  2981. {
  2982. EventOut(">> Waiting\n");
  2983. ProcessDeferredWork(&ContinueStatus);
  2984. if (g_EngDefer & ENG_DEFER_CONTINUE_EVENT)
  2985. {
  2986. for (;;)
  2987. {
  2988. EventOut(">> Continue with %X\n", ContinueStatus);
  2989. if ((Status = m_Services->
  2990. ContinueEvent(ContinueStatus)) == S_OK)
  2991. {
  2992. break;
  2993. }
  2994. //
  2995. // If we got an out of memory error, wait again
  2996. //
  2997. if (Status != E_OUTOFMEMORY)
  2998. {
  2999. ErrOut("IUserDebugServices::ContinueEvent failed "
  3000. "with status 0x%X\n", Status);
  3001. goto Exit;
  3002. }
  3003. }
  3004. }
  3005. DiscardLastEvent();
  3006. PendingFlags = 0;
  3007. PendingOptions = DEBUG_PROCESS_ONLY_THIS_PROCESS;
  3008. if (g_AllPendingFlags & ENG_PROC_ANY_ATTACH)
  3009. {
  3010. // If we're attaching noninvasively or reattaching
  3011. // and still haven't done the work go ahead and do it now.
  3012. if (g_AllPendingFlags & ENG_PROC_ANY_EXAMINE)
  3013. {
  3014. Pending = FindPendingProcessByFlags(ENG_PROC_ANY_EXAMINE);
  3015. if (Pending == NULL)
  3016. {
  3017. DBG_ASSERT(FALSE);
  3018. goto Exit;
  3019. }
  3020. if ((Status = ExamineActiveProcess
  3021. (m_Services, Pending->Id, Pending->Flags,
  3022. Pending->Options, &Event)) != S_OK)
  3023. {
  3024. goto Exit;
  3025. }
  3026. // If we just started examining a process we
  3027. // suspended all the threads during enumeration.
  3028. // We need to resume them after the normal
  3029. // SuspendExecution suspend to get the suspend
  3030. // count back to normal.
  3031. ExamineResumeProcId = Pending->Id;
  3032. PendingFlags = Pending->Flags;
  3033. PendingOptions = Pending->Options;
  3034. RemovePendingProcess(Pending);
  3035. EventUsed = sizeof(Event);
  3036. // This event is not a real continuable event.
  3037. ContinueDefer = 0;
  3038. goto WaitDone;
  3039. }
  3040. // While waiting for an attach we need to periodically
  3041. // check and see if the process has exited so we
  3042. // need to force a reasonably small timeout.
  3043. UseTimeout = min(Timeout, ATTACH_PENDING_TIMEOUT);
  3044. }
  3045. else
  3046. {
  3047. // We might be waiting on a break-in. Keep timeouts moderate
  3048. // to deal with apps hung with a lock that prevents
  3049. // the break from happening. The timeout is
  3050. // still long enough so that no substantial amount
  3051. // of CPU time is consumed.
  3052. UseTimeout = min(Timeout, DEFAULT_WAIT_TIMEOUT);
  3053. }
  3054. SUSPEND_ENGINE();
  3055. if (g_EngStatus & ENG_STATUS_EXIT_CURRENT_WAIT)
  3056. {
  3057. Status = E_PENDING;
  3058. }
  3059. else
  3060. {
  3061. Status = m_Services->
  3062. WaitForEvent(UseTimeout, &Event, sizeof(Event), &EventUsed);
  3063. }
  3064. RESUME_ENGINE();
  3065. ContinueDefer = ENG_DEFER_CONTINUE_EVENT;
  3066. WaitDone:
  3067. if (Status == S_OK)
  3068. {
  3069. if (EventUsed == sizeof(DEBUG_EVENT32))
  3070. {
  3071. DEBUG_EVENT32 Event32 = *(DEBUG_EVENT32*)&Event;
  3072. DebugEvent32To64(&Event32, &Event);
  3073. }
  3074. else if (EventUsed != sizeof(DEBUG_EVENT64))
  3075. {
  3076. ErrOut("Event data corrupt\n");
  3077. Status = E_FAIL;
  3078. goto Exit;
  3079. }
  3080. g_EngDefer |= ContinueDefer;
  3081. EventOut(">>> Debug event %u for %X.%X\n",
  3082. Event.dwDebugEventCode, Event.dwProcessId,
  3083. Event.dwThreadId);
  3084. g_EventProcessSysId = Event.dwProcessId;
  3085. g_EventThreadSysId = Event.dwThreadId;
  3086. // Look up the process and thread infos in the cases
  3087. // where they already exist.
  3088. if (Event.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT &&
  3089. Event.dwDebugEventCode != CREATE_THREAD_DEBUG_EVENT)
  3090. {
  3091. FindEventProcessThread();
  3092. }
  3093. g_EngStatus |= ENG_STATUS_STATE_CHANGED;
  3094. if (Event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
  3095. {
  3096. // If we're being notified of a new process take
  3097. // out the pending record for the process.
  3098. Pending = FindPendingProcessById(g_EventProcessSysId);
  3099. if (Pending == NULL &&
  3100. (g_AllPendingFlags & ENG_PROC_SYSTEM))
  3101. {
  3102. // Assume that this is the system process
  3103. // as we attached under a fake process ID so
  3104. // we can't check for a true match.
  3105. Pending = FindPendingProcessById(CSRSS_PROCESS_ID);
  3106. }
  3107. if (Pending != NULL)
  3108. {
  3109. PendingFlags = Pending->Flags;
  3110. PendingOptions = Pending->Options;
  3111. if (Pending->Flags & ENG_PROC_ATTACHED)
  3112. {
  3113. VerbOut("*** attach succeeded\n");
  3114. UseTimeout = Timeout;
  3115. // If we're completing a full attach
  3116. // we are now a fully active debugger.
  3117. PendingFlags &= ~ENG_PROC_EXAMINED;
  3118. // Expect a break-in.
  3119. g_EngStatus |= ENG_STATUS_PENDING_BREAK_IN;
  3120. TimeoutCount = 0;
  3121. }
  3122. RemovePendingProcess(Pending);
  3123. }
  3124. }
  3125. if (!IS_MACHINE_SET())
  3126. {
  3127. ULONG Machine;
  3128. if ((Status = m_Services->
  3129. GetTargetInfo(&Machine,
  3130. &g_TargetNumberProcessors,
  3131. &g_TargetPlatformId,
  3132. &g_TargetBuildNumber,
  3133. &g_TargetCheckedBuild,
  3134. g_TargetServicePackString,
  3135. sizeof(g_TargetServicePackString),
  3136. g_TargetBuildLabName,
  3137. sizeof(g_TargetBuildLabName))) != S_OK)
  3138. {
  3139. ErrOut("Unable to retrieve target machine "
  3140. "information\n");
  3141. goto Exit;
  3142. }
  3143. SetTargetSystemVersionAndBuild(g_TargetBuildNumber,
  3144. g_TargetPlatformId);
  3145. DbgKdApi64 = g_SystemVersion > NT_SVER_NT4;
  3146. if ((Status = InitializeMachine(Machine)) != S_OK)
  3147. {
  3148. ErrOut("Unable to initialize target machine "
  3149. "information\n");
  3150. goto Exit;
  3151. }
  3152. }
  3153. if (PendingFlags & ENG_PROC_ANY_EXAMINE)
  3154. {
  3155. // We're examining the process rather than
  3156. // debugging it, so no module load events
  3157. // are going to come through. Reload from
  3158. // the system module list. This needs
  3159. // to work even if there isn't a path.
  3160. g_Target->Reload("-s -P");
  3161. }
  3162. if ((Event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT ||
  3163. Event.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) &&
  3164. (m_ServiceFlags & DBGSVC_CLOSE_PROC_THREAD_HANDLES))
  3165. {
  3166. PendingFlags |= ENG_PROC_THREAD_CLOSE_HANDLE;
  3167. }
  3168. EventStatus = ProcessDebugEvent(&Event,
  3169. PendingFlags, PendingOptions);
  3170. EventOut(">>> DebugEvent status %X\n", EventStatus);
  3171. // If the event handlers requested a break return
  3172. // to the caller.
  3173. if (EventStatus == DEBUG_STATUS_BREAK)
  3174. {
  3175. Status = S_OK;
  3176. goto Exit;
  3177. }
  3178. else
  3179. {
  3180. // We're resuming execution so reverse any
  3181. // command preparation that may have occurred
  3182. // while processing the event.
  3183. // If we just started examining a process we
  3184. // can resume things as it's OK to execute.
  3185. if (ExamineResumeProcId)
  3186. {
  3187. SuspendResumeThreads(FindProcessBySystemId
  3188. (ExamineResumeProcId), FALSE, NULL);
  3189. ExamineResumeProcId = 0;
  3190. }
  3191. if ((Status = PrepareForExecution(EventStatus)) != S_OK)
  3192. {
  3193. goto Exit;
  3194. }
  3195. ContinueStatus = EventStatusToContinue(EventStatus);
  3196. }
  3197. }
  3198. else
  3199. {
  3200. if (Status == S_FALSE)
  3201. {
  3202. TimeoutCount++;
  3203. if (g_AllPendingFlags & ENG_PROC_ATTACHED)
  3204. {
  3205. VerifyPendingProcesses();
  3206. if (!ANY_PROCESSES())
  3207. {
  3208. Status = E_FAIL;
  3209. goto Exit;
  3210. }
  3211. if (TimeoutCount == ATTACH_PENDING_TIMEOUT_LIMIT)
  3212. {
  3213. // Assume that the process has some kind
  3214. // of lock that's preventing the attach
  3215. // from succeeding and just do a soft attach.
  3216. AddExamineToPendingAttach();
  3217. TimeoutCount = 0;
  3218. }
  3219. }
  3220. else if (g_EngStatus & ENG_STATUS_PENDING_BREAK_IN)
  3221. {
  3222. if (TimeoutCount == PENDING_BREAK_IN_MESSAGE_TIMEOUT_LIMIT)
  3223. {
  3224. dprintf("Break-in sent, waiting %d seconds...\n",
  3225. (g_PendingBreakInTimeoutLimit *
  3226. DEFAULT_WAIT_TIMEOUT) / 1000);
  3227. }
  3228. else if (TimeoutCount >= g_PendingBreakInTimeoutLimit)
  3229. {
  3230. // Assume that the process has some kind
  3231. // of lock that's preventing the break-in
  3232. // exception from coming through and
  3233. // just suspend to let the user look at things.
  3234. WarnOut("WARNING: Break-in timed out, suspending.\n");
  3235. WarnOut(" This is usually caused by another "
  3236. "thread holding the loader lock\n");
  3237. SynthesizeWakeEvent(&Event, g_ProcessHead->SystemId,
  3238. g_ProcessHead->ThreadHead->
  3239. SystemId);
  3240. EventUsed = sizeof(Event);
  3241. ContinueDefer = 0;
  3242. TimeoutCount = 0;
  3243. g_EngStatus &= ~ENG_STATUS_PENDING_BREAK_IN;
  3244. Status = S_OK;
  3245. goto WaitDone;
  3246. }
  3247. }
  3248. else if (Timeout != INFINITE &&
  3249. Timeout <= UseTimeout)
  3250. {
  3251. Status = S_FALSE;
  3252. goto Exit;
  3253. }
  3254. if (Timeout != INFINITE)
  3255. {
  3256. // Update overall timeout. This
  3257. // isn't incredibly accurate but it
  3258. // doesn't really need to be.
  3259. Timeout -= UseTimeout;
  3260. }
  3261. // Loop back to waiting.
  3262. }
  3263. else if (Status == E_OUTOFMEMORY)
  3264. {
  3265. // If we got an out of memory error, wait again
  3266. }
  3267. else
  3268. {
  3269. ErrOut("IUserDebugServices::WaitForEvent failed "
  3270. "with status 0x%X\n", Status);
  3271. goto Exit;
  3272. }
  3273. }
  3274. }
  3275. Exit:
  3276. g_EngStatus &= ~ENG_STATUS_WAITING;
  3277. // Control is passing back to the caller so the engine must
  3278. // be ready for command processing.
  3279. PrepareForCalls(0);
  3280. // If we have an extra suspend count from examining resume it out now
  3281. // that any normal suspends have been done and it's safe
  3282. // to remove the excess suspend.
  3283. if (ExamineResumeProcId)
  3284. {
  3285. SuspendResumeThreads(FindProcessBySystemId(ExamineResumeProcId),
  3286. FALSE, NULL);
  3287. }
  3288. EventOut("> Wait returning %X\n", Status);
  3289. return Status;
  3290. }
  3291. /*** ProcessDebugEvent - main dispatch table
  3292. *
  3293. * Purpose:
  3294. * As debug events come in, they each have to be handled in a unique
  3295. * manner. This routine does all of the processing required for each
  3296. * event.
  3297. *
  3298. * Also this routine serves the callback mechanism for VDM debug events
  3299. * using the VDMDBG.DLL apis (they require the ability of calling back
  3300. * into the debugger).
  3301. *
  3302. * Significant events include creation and termination of processes
  3303. * and threads, and events such as breakpoints.
  3304. *
  3305. * Data structures for processes and threads are created and
  3306. * maintained for use by the program.
  3307. *
  3308. *************************************************************************/
  3309. ULONG
  3310. ProcessDebugEvent(DEBUG_EVENT64* Event,
  3311. ULONG PendingFlags, ULONG PendingOptions)
  3312. {
  3313. ULONG EventStatus;
  3314. PSTR ImagePath;
  3315. CHAR NameBuffer[MAX_IMAGE_PATH];
  3316. ULONG ModuleSize, CheckSum, TimeDateStamp;
  3317. char ModuleName[MAX_MODULE];
  3318. switch(Event->dwDebugEventCode)
  3319. {
  3320. case CREATE_PROCESS_DEBUG_EVENT:
  3321. // We don't have a process yet but
  3322. // getting the name can involve reading process
  3323. // memory, which in some cases currently wants
  3324. // g_CurrentProcess set. Hack up a temporary
  3325. // process with just the handle.
  3326. PROCESS_INFO TempProcess;
  3327. THREAD_INFO TempThread;
  3328. memset(&TempProcess, 0, sizeof(TempProcess));
  3329. memset(&TempThread, 0, sizeof(TempThread));
  3330. TempProcess.FullHandle = Event->u.CreateProcessInfo.hProcess;
  3331. TempProcess.Handle = (HANDLE)(ULONG_PTR)TempProcess.FullHandle;
  3332. TempThread.Handle = Event->u.CreateProcessInfo.hThread;
  3333. TempThread.Process = &TempProcess;
  3334. g_CurrentProcess = &TempProcess;
  3335. g_CurrentProcess->ThreadHead = &TempThread;
  3336. g_CurrentProcess->CurrentThread = &TempThread;
  3337. GetEventName(Event->u.CreateProcessInfo.hFile,
  3338. Event->u.CreateProcessInfo.lpBaseOfImage,
  3339. Event->u.CreateProcessInfo.lpImageName,
  3340. Event->u.CreateProcessInfo.fUnicode,
  3341. NameBuffer, sizeof(NameBuffer));
  3342. GetHeaderInfo((ULONG64)Event->u.CreateProcessInfo.lpBaseOfImage,
  3343. &CheckSum, &TimeDateStamp, &ModuleSize);
  3344. CreateModuleNameFromPath(NameBuffer, ModuleName);
  3345. LoadWow64ExtsIfNeeded();
  3346. // Clear the temporary process setting.
  3347. g_CurrentProcess = NULL;
  3348. EventStatus = NotifyCreateProcessEvent(
  3349. (ULONG64)Event->u.CreateProcessInfo.hFile,
  3350. (ULONG64)Event->u.CreateProcessInfo.hProcess,
  3351. (ULONG64)Event->u.CreateProcessInfo.lpBaseOfImage,
  3352. ModuleSize, ModuleName, NameBuffer, CheckSum, TimeDateStamp,
  3353. (ULONG64)Event->u.CreateProcessInfo.hThread,
  3354. (ULONG64)Event->u.CreateProcessInfo.lpThreadLocalBase,
  3355. (ULONG64)Event->u.CreateProcessInfo.lpStartAddress,
  3356. PendingFlags, PendingOptions,
  3357. (PendingFlags & ENG_PROC_THREAD_CLOSE_HANDLE) ?
  3358. ENG_PROC_THREAD_CLOSE_HANDLE : 0);
  3359. break;
  3360. case EXIT_PROCESS_DEBUG_EVENT:
  3361. if (g_EventProcess == NULL)
  3362. {
  3363. // Assume that this unmatched exit process event is a leftover
  3364. // from a previous restart and just ignore it.
  3365. WarnOut("Ignoring unknown process exit for %X\n",
  3366. g_EventProcessSysId);
  3367. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  3368. }
  3369. else
  3370. {
  3371. EventStatus =
  3372. NotifyExitProcessEvent(Event->u.ExitProcess.dwExitCode);
  3373. }
  3374. break;
  3375. case CREATE_THREAD_DEBUG_EVENT:
  3376. EventStatus = NotifyCreateThreadEvent(
  3377. (ULONG64)Event->u.CreateThread.hThread,
  3378. (ULONG64)Event->u.CreateThread.lpThreadLocalBase,
  3379. (ULONG64)Event->u.CreateThread.lpStartAddress,
  3380. PendingFlags);
  3381. break;
  3382. case EXIT_THREAD_DEBUG_EVENT:
  3383. EventStatus = NotifyExitThreadEvent(Event->u.ExitThread.dwExitCode);
  3384. break;
  3385. case LOAD_DLL_DEBUG_EVENT:
  3386. GetEventName(Event->u.LoadDll.hFile,
  3387. Event->u.LoadDll.lpBaseOfDll,
  3388. Event->u.LoadDll.lpImageName,
  3389. Event->u.LoadDll.fUnicode,
  3390. NameBuffer, sizeof(NameBuffer));
  3391. GetHeaderInfo((ULONG64)Event->u.LoadDll.lpBaseOfDll,
  3392. &CheckSum, &TimeDateStamp, &ModuleSize);
  3393. CreateModuleNameFromPath(NameBuffer, ModuleName);
  3394. EventStatus = NotifyLoadModuleEvent(
  3395. (ULONG64)Event->u.LoadDll.hFile,
  3396. (ULONG64)Event->u.LoadDll.lpBaseOfDll,
  3397. ModuleSize, ModuleName, NameBuffer, CheckSum, TimeDateStamp);
  3398. break;
  3399. case UNLOAD_DLL_DEBUG_EVENT:
  3400. EventStatus = NotifyUnloadModuleEvent(
  3401. NULL, (ULONG64)Event->u.UnloadDll.lpBaseOfDll);
  3402. break;
  3403. case OUTPUT_DEBUG_STRING_EVENT:
  3404. EventStatus = OutputEventDebugString(&Event->u.DebugString);
  3405. break;
  3406. case RIP_EVENT:
  3407. EventStatus = NotifySystemErrorEvent(Event->u.RipInfo.dwError,
  3408. Event->u.RipInfo.dwType);
  3409. break;
  3410. case EXCEPTION_DEBUG_EVENT:
  3411. EventStatus = ProcessEventException(Event);
  3412. break;
  3413. default:
  3414. WarnOut("Unknown event number 0x%08lx\n",
  3415. Event->dwDebugEventCode);
  3416. EventStatus = DEBUG_STATUS_BREAK;
  3417. break;
  3418. }
  3419. return EventStatus;
  3420. }
  3421. typedef BOOL (__stdcall * PFN_SWITCHDESKTOP)(HDESK hDesktop);
  3422. typedef HDESK (__stdcall *PFN_GETTHREADDESKTOP)(DWORD dwThreadId);
  3423. typedef BOOL (__stdcall *PFN_CLOSEDESKTOP)(HDESK hDesktop);
  3424. PFN_SWITCHDESKTOP g_SwitchDesktop;
  3425. PFN_GETTHREADDESKTOP g_GetThreadDesktop;
  3426. PFN_CLOSEDESKTOP g_CloseDesktop;
  3427. BOOL g_InitUserApis;
  3428. BOOL g_UserApisAvailable;
  3429. #define ISTS() (!!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer)))
  3430. #define FIRST_CHANCE Event->u.Exception.dwFirstChance
  3431. ULONG
  3432. ProcessEventException(DEBUG_EVENT64* Event)
  3433. {
  3434. ULONG ExceptionCode;
  3435. ULONG EventStatus;
  3436. BOOL OutputDone = FALSE;
  3437. ExceptionCode = Event->u.Exception.ExceptionRecord.ExceptionCode;
  3438. g_EventPc = (ULONG64)
  3439. Event->u.Exception.ExceptionRecord.ExceptionAddress;
  3440. EventOut("Exception %X at %p\n", ExceptionCode, g_EventPc);
  3441. //
  3442. // If we are debugging a crashed process, force the
  3443. // desktop we are on to the front so the user will know
  3444. // what happened.
  3445. //
  3446. if (g_EventToSignal != NULL &&
  3447. !ISTS() &&
  3448. !SYSTEM_PROCESSES())
  3449. {
  3450. if (!g_InitUserApis)
  3451. {
  3452. HINSTANCE hUser = LoadLibrary("user32.dll");
  3453. if (hUser)
  3454. {
  3455. g_SwitchDesktop = (PFN_SWITCHDESKTOP)
  3456. GetProcAddress(hUser, "SwitchDesktop");
  3457. g_GetThreadDesktop = (PFN_GETTHREADDESKTOP)
  3458. GetProcAddress(hUser, "GetThreadDesktop");
  3459. g_CloseDesktop = (PFN_CLOSEDESKTOP)
  3460. GetProcAddress(hUser, "CloseDesktop");
  3461. if (g_SwitchDesktop && g_GetThreadDesktop &&
  3462. g_CloseDesktop)
  3463. {
  3464. g_UserApisAvailable = TRUE;
  3465. }
  3466. }
  3467. g_InitUserApis = TRUE;
  3468. }
  3469. if (g_UserApisAvailable)
  3470. {
  3471. HDESK hDesk;
  3472. hDesk = g_GetThreadDesktop(::GetCurrentThreadId());
  3473. g_SwitchDesktop(hDesk);
  3474. g_CloseDesktop(hDesk);
  3475. }
  3476. }
  3477. if (g_EventThread == NULL)
  3478. {
  3479. ErrOut("ERROR: Exception %X occurred on unknown thread\n",
  3480. ExceptionCode);
  3481. return DEBUG_STATUS_BREAK;
  3482. }
  3483. if (ExceptionCode == STATUS_VDM_EVENT)
  3484. {
  3485. ULONG ulRet = VDMEvent(Event);
  3486. switch(ulRet)
  3487. {
  3488. case VDMEVENT_NOT_HANDLED:
  3489. EventStatus = DEBUG_STATUS_GO_NOT_HANDLED;
  3490. break;
  3491. case VDMEVENT_HANDLED:
  3492. EventStatus = DEBUG_STATUS_GO_HANDLED;
  3493. break;
  3494. default:
  3495. // Give vdm code the option of mutating this into
  3496. // a standard exception (like STATUS_BREAKPOINT)
  3497. ExceptionCode = ulRet;
  3498. break;
  3499. }
  3500. }
  3501. switch (ExceptionCode)
  3502. {
  3503. case STATUS_BREAKPOINT:
  3504. case STATUS_SINGLE_STEP:
  3505. case STATUS_WX86_BREAKPOINT:
  3506. case STATUS_WX86_SINGLE_STEP:
  3507. EventStatus = ProcessBreakpointOrStepException
  3508. (&Event->u.Exception.ExceptionRecord, FIRST_CHANCE);
  3509. break;
  3510. case STATUS_VDM_EVENT:
  3511. // do nothing, it's already handled
  3512. EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  3513. break;
  3514. case STATUS_ACCESS_VIOLATION:
  3515. if (FIRST_CHANCE &&
  3516. (g_EngOptions & DEBUG_ENGOPT_IGNORE_LOADER_EXCEPTIONS))
  3517. {
  3518. CHAR chSymBuffer[MAX_SYMBOL_LEN];
  3519. LPSTR s;
  3520. ULONG64 displacement;
  3521. //
  3522. // This option allows new 3.51 binaries to run under
  3523. // this debugger on old 3.1, 3.5 systems and avoid stopping
  3524. // at access violations inside LDR that will be handled
  3525. // by the LDR anyway.
  3526. //
  3527. GetSymbolStdCall((ULONG64)(Event->u.Exception.ExceptionRecord.
  3528. ExceptionAddress),
  3529. chSymBuffer,
  3530. sizeof(chSymBuffer),
  3531. &displacement,
  3532. NULL);
  3533. s = (LPSTR)chSymBuffer;
  3534. if (!_strnicmp( s, "ntdll!", 6 ))
  3535. {
  3536. s += 6;
  3537. if (*s == '_') s += 1;
  3538. if (!_stricmp( s, "LdrpSnapThunk" ) ||
  3539. !_stricmp( s, "LdrpWalkImportDescriptor" ))
  3540. {
  3541. EventStatus = DEBUG_STATUS_GO_NOT_HANDLED;
  3542. break;
  3543. }
  3544. }
  3545. }
  3546. goto NotifyException;
  3547. case STATUS_POSSIBLE_DEADLOCK:
  3548. if (g_TargetPlatformId == VER_PLATFORM_WIN32_NT)
  3549. {
  3550. DBG_ASSERT(IS_USER_TARGET());
  3551. AnalyzeDeadlock(&Event->u.Exception.ExceptionRecord,
  3552. FIRST_CHANCE);
  3553. }
  3554. else
  3555. {
  3556. OutputDeadlock(&Event->u.Exception.ExceptionRecord,
  3557. FIRST_CHANCE);
  3558. }
  3559. OutputDone = TRUE;
  3560. goto NotifyException;
  3561. default:
  3562. {
  3563. NotifyException:
  3564. EventStatus =
  3565. NotifyExceptionEvent(&Event->u.Exception.ExceptionRecord,
  3566. Event->u.Exception.dwFirstChance,
  3567. OutputDone);
  3568. }
  3569. break;
  3570. }
  3571. //
  3572. // Do this for all exceptions, just in case some other
  3573. // thread caused an exception before we get around to
  3574. // handling the breakpoint event.
  3575. //
  3576. g_EngDefer |= ENG_DEFER_SET_EVENT;
  3577. return EventStatus;
  3578. }
  3579. #undef FIRST_CHANCE
  3580. #define INPUT_API_SIG 0xdefaced
  3581. typedef struct _hdi
  3582. {
  3583. DWORD dwSignature;
  3584. BYTE cLength;
  3585. BYTE cStatus;
  3586. } HDI;
  3587. ULONG
  3588. OutputEventDebugString(OUTPUT_DEBUG_STRING_INFO64* Info)
  3589. {
  3590. LPSTR Str, StrOffset, Str2;
  3591. BOOL b;
  3592. ULONG dwNumberOfBytesRead;
  3593. HDI hdi;
  3594. DWORD dwInputSig;
  3595. ULONG EventStatus = DEBUG_STATUS_IGNORE_EVENT;
  3596. if (Info->nDebugStringLength == 0)
  3597. {
  3598. return EventStatus;
  3599. }
  3600. Str = (PSTR)calloc(1, Info->nDebugStringLength);
  3601. if (Str == NULL)
  3602. {
  3603. ErrOut("Unable to allocate debug output buffer\n");
  3604. return EventStatus;
  3605. }
  3606. if (g_Target->ReadVirtual(Info->lpDebugStringData, Str,
  3607. Info->nDebugStringLength,
  3608. &dwNumberOfBytesRead) == S_OK &&
  3609. (dwNumberOfBytesRead == (SIZE_T)Info->nDebugStringLength))
  3610. {
  3611. //
  3612. // Special processing for hacky debug input string
  3613. //
  3614. if (g_Target->ReadVirtual(Info->lpDebugStringData +
  3615. Info->nDebugStringLength,
  3616. &hdi, sizeof(hdi),
  3617. &dwNumberOfBytesRead) == S_OK &&
  3618. dwNumberOfBytesRead == sizeof(hdi) &&
  3619. hdi.dwSignature == INPUT_API_SIG)
  3620. {
  3621. StartOutLine(DEBUG_OUTPUT_DEBUGGEE_PROMPT, OUT_LINE_NO_PREFIX);
  3622. MaskOut(DEBUG_OUTPUT_DEBUGGEE_PROMPT, "%s", Str);
  3623. Str2 = (PSTR)calloc(1, hdi.cLength + 1);
  3624. if (Str2)
  3625. {
  3626. GetInput(NULL, Str2, hdi.cLength);
  3627. g_Target->WriteVirtual(Info->lpDebugStringData + 6,
  3628. Str2, (DWORD)hdi.cLength, NULL);
  3629. free(Str2);
  3630. }
  3631. else
  3632. {
  3633. ErrOut("Unable to allocate prompt buffer\n");
  3634. }
  3635. }
  3636. else
  3637. {
  3638. StartOutLine(DEBUG_OUTPUT_DEBUGGEE, OUT_LINE_NO_PREFIX);
  3639. MaskOut(DEBUG_OUTPUT_DEBUGGEE, "%s", Str);
  3640. EVENT_FILTER* Filter =
  3641. &g_EventFilters[DEBUG_FILTER_DEBUGGEE_OUTPUT];
  3642. if (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  3643. BreakOnThisOutString(Str))
  3644. {
  3645. EventStatus = DEBUG_STATUS_BREAK;
  3646. }
  3647. }
  3648. }
  3649. else
  3650. {
  3651. ErrOut("Unable to read debug output string, %d\n",
  3652. GetLastError());
  3653. }
  3654. free(Str);
  3655. return EventStatus;
  3656. }
  3657. //----------------------------------------------------------------------------
  3658. //
  3659. // DumpTargetInfo::WaitForEvent.
  3660. //
  3661. //----------------------------------------------------------------------------
  3662. HRESULT
  3663. DumpTargetInfo::WaitForEvent(ULONG Flags, ULONG Timeout)
  3664. {
  3665. HRESULT Status;
  3666. ULONG i;
  3667. ULONG ContinueStatus;
  3668. BOOL HaveContext = FALSE;
  3669. if (g_EngStatus & ENG_STATUS_PROCESSES_ADDED)
  3670. {
  3671. // A wait has already been done. Crash dumps
  3672. // can only generate a single event so further
  3673. // waiting is not possible.
  3674. return E_UNEXPECTED;
  3675. }
  3676. // Even though dumps don't really wait the standard
  3677. // preparation still needs to be done to set things
  3678. // up and generate the usual callbacks. The continuation
  3679. // part of things is simply ignored.
  3680. Status = PrepareForWait(Flags, &ContinueStatus);
  3681. if (FAILED(Status))
  3682. {
  3683. return Status;
  3684. }
  3685. // This is the first wait. Simulate any
  3686. // necessary events such as process and thread
  3687. // creations and image loads.
  3688. Status = InitializeMachine(g_TargetMachineType);
  3689. if (Status != S_OK)
  3690. {
  3691. ErrOut("Unable to initialize target machine information\n");
  3692. return Status;
  3693. }
  3694. // Don't give real callbacks for processes/threads as
  3695. // they're just faked in the dump case.
  3696. g_EngNotify++;
  3697. if (IS_KERNEL_TARGET())
  3698. {
  3699. ULONG CurProc;
  3700. CreateKernelProcessAndThreads();
  3701. // Load kernel symbols.
  3702. VerifyKernelBase(TRUE);
  3703. g_Target->OutputVersion();
  3704. if (!IS_KERNEL_TRIAGE_DUMP())
  3705. {
  3706. if (g_TargetMachineType == IMAGE_FILE_MACHINE_ALPHA ||
  3707. g_TargetMachineType == IMAGE_FILE_MACHINE_AXP64)
  3708. {
  3709. // Try and get the symbol for KiPcrBaseAddress.
  3710. if (!GetOffsetFromSym("nt!KiPcrBaseAddress",
  3711. &g_DumpKiPcrBaseAddress,
  3712. NULL))
  3713. {
  3714. // Not a critical failure.
  3715. g_DumpKiPcrBaseAddress = 0;
  3716. }
  3717. }
  3718. if (KdDebuggerData.KiProcessorBlock)
  3719. {
  3720. ULONG PtrSize = g_TargetMachine->m_Ptr64 ?
  3721. sizeof(ULONG64) : sizeof(ULONG);
  3722. for (i = 0; i < g_TargetNumberProcessors; i++)
  3723. {
  3724. Status = ReadPointer(g_TargetMachine,
  3725. KdDebuggerData.KiProcessorBlock +
  3726. i * PtrSize,
  3727. &(g_DumpKiProcessors[i]));
  3728. if ((Status != S_OK) || !g_DumpKiProcessors[i])
  3729. {
  3730. ErrOut("KiProcessorBlock[%d] could not be read\n", i);
  3731. Status = E_FAIL;
  3732. g_EngNotify--;
  3733. goto Exit;
  3734. }
  3735. }
  3736. HaveContext = TRUE;
  3737. }
  3738. }
  3739. else
  3740. {
  3741. HaveContext = TRUE;
  3742. }
  3743. CurProc = ((KernelDumpTargetInfo*)this)->GetCurrentProcessor();
  3744. if (CurProc == (ULONG)-1)
  3745. {
  3746. WarnOut("Could not determine the current processor, "
  3747. "using zero\n");
  3748. CurProc = 0;
  3749. }
  3750. if (HaveContext)
  3751. {
  3752. g_EventProcessSysId = VIRTUAL_PROCESS_ID;
  3753. g_EventThreadSysId = VIRTUAL_THREAD_ID(CurProc);
  3754. }
  3755. // Clear the global state change just in case somebody's
  3756. // directly accessing it somewhere.
  3757. ZeroMemory(&g_StateChange, sizeof(g_StateChange));
  3758. g_StateChangeData = g_StateChangeBuffer;
  3759. g_StateChangeBuffer[0] = 0;
  3760. if ((g_TargetMachineType == IMAGE_FILE_MACHINE_I386 ||
  3761. g_TargetMachineType == IMAGE_FILE_MACHINE_IA64) &&
  3762. !IS_KERNEL_TRIAGE_DUMP() &&
  3763. HaveContext)
  3764. {
  3765. //
  3766. // Reset the page directory correctly since NT 4 stores
  3767. // the wrong CR3 value in the context.
  3768. //
  3769. // IA64 dumps start out with just the kernel page
  3770. // directory set so update everything.
  3771. //
  3772. FindEventProcessThread();
  3773. ChangeRegContext(g_EventThread);
  3774. if (g_TargetMachine->
  3775. SetDefaultPageDirectories(PAGE_DIR_ALL) != S_OK)
  3776. {
  3777. WarnOut("WARNING: Unable to reset page directories\n");
  3778. }
  3779. ChangeRegContext(NULL);
  3780. // Flush the cache just in case as vmem mappings changed.
  3781. g_VirtualCache.Empty();
  3782. }
  3783. }
  3784. else
  3785. {
  3786. ULONG Suspend;
  3787. ULONG64 Teb;
  3788. UserDumpTargetInfo* UserDump = (UserDumpTargetInfo*)g_Target;
  3789. g_Target->OutputVersion();
  3790. // Create the process.
  3791. g_EventProcessSysId = UserDump->m_EventProcess;
  3792. if (UserDump->GetThreadInfo(0, &g_EventThreadSysId,
  3793. &Suspend, &Teb) != S_OK)
  3794. {
  3795. // Dump doesn't contain thread information so
  3796. // fake it.
  3797. g_EventThreadSysId = VIRTUAL_THREAD_ID(0);
  3798. Suspend = 0;
  3799. Teb = 0;
  3800. }
  3801. EventOut("User dump process %x.%x with %u threads\n",
  3802. g_EventProcessSysId, g_EventThreadSysId,
  3803. UserDump->m_ThreadCount);
  3804. NotifyCreateProcessEvent(0, (ULONG64)VIRTUAL_PROCESS_HANDLE, 0, 0,
  3805. NULL, NULL, 0, 0,
  3806. (ULONG64)VIRTUAL_THREAD_HANDLE(0),
  3807. Teb, 0, 0, DEBUG_PROCESS_ONLY_THIS_PROCESS,
  3808. 0);
  3809. // Update thread suspend count from dump info.
  3810. g_EventThread->SuspendCount = Suspend;
  3811. // Create any remaining threads.
  3812. for (i = 1; i < UserDump->m_ThreadCount; i++)
  3813. {
  3814. UserDump->GetThreadInfo(i, &g_EventThreadSysId, &Suspend, &Teb);
  3815. EventOut("User dump thread %d: %x\n", i, g_EventThreadSysId);
  3816. NotifyCreateThreadEvent((ULONG64)VIRTUAL_THREAD_HANDLE(i),
  3817. Teb, 0, 0);
  3818. // Update thread suspend count from dump info.
  3819. g_EventThread->SuspendCount = Suspend;
  3820. }
  3821. g_EventThreadSysId = UserDump->m_EventThread;
  3822. HaveContext = TRUE;
  3823. EventOut("User dump event on %x.%x\n",
  3824. g_EventProcessSysId, g_EventThreadSysId);
  3825. }
  3826. // Do not provide a control report; this will force
  3827. // such information to come from context retrieval.
  3828. g_ControlReport = NULL;
  3829. g_EventPc = (ULONG64)g_DumpException.ExceptionAddress;
  3830. if (HaveContext)
  3831. {
  3832. FindEventProcessThread();
  3833. ChangeRegContext(g_EventThread);
  3834. }
  3835. //
  3836. // Go ahead and reload all the symbols.
  3837. // This is especially important for minidumps because without
  3838. // symbols and the executable image, we can't unassemble the
  3839. // current instruction.
  3840. //
  3841. Status = g_Target->Reload(HaveContext ? "" : "-P");
  3842. ChangeRegContext(NULL);
  3843. if (HaveContext && Status != S_OK)
  3844. {
  3845. g_EngNotify--;
  3846. goto Exit;
  3847. }
  3848. if (IS_USER_TARGET())
  3849. {
  3850. PDEBUG_IMAGE_INFO Image;
  3851. // Try and look up the build lab information from kernel32.
  3852. Image = GetImageByName(g_ProcessHead, "kernel32", INAME_MODULE);
  3853. if (Image != NULL)
  3854. {
  3855. char Item[64];
  3856. ULONG PreLen;
  3857. sprintf(Item, "\\StringFileInfo\\%04x%04x\\FileVersion",
  3858. VER_VERSION_TRANSLATION);
  3859. strcpy(g_TargetBuildLabName, "kernel32.dll version: ");
  3860. PreLen = strlen(g_TargetBuildLabName);
  3861. if (FAILED(GetImageVersionInformation
  3862. (Image->ImagePath, Image->BaseOfImage,
  3863. Item, g_TargetBuildLabName + PreLen,
  3864. sizeof(g_TargetBuildLabName) - PreLen, NULL)))
  3865. {
  3866. g_TargetBuildLabName[0] = 0;
  3867. }
  3868. }
  3869. }
  3870. g_EngStatus |= ENG_STATUS_STATE_CHANGED;
  3871. // The engine is now initialized so a real event
  3872. // can be generated.
  3873. g_EngNotify--;
  3874. NotifyExceptionEvent(&g_DumpException, g_DumpExceptionFirstChance,
  3875. g_DumpException.ExceptionCode ==
  3876. STATUS_BREAKPOINT ||
  3877. g_DumpException.ExceptionCode ==
  3878. STATUS_WX86_BREAKPOINT);
  3879. Status = S_OK;
  3880. Exit:
  3881. g_EngStatus &= ~ENG_STATUS_WAITING;
  3882. // Control is passing back to the caller so the engine must
  3883. // be ready for command processing.
  3884. PrepareForCalls(0);
  3885. #if 0
  3886. // this is now doe in condbg/windbg
  3887. // Run the bugcheck analyzers if this dump has a bugcheck.
  3888. if (Status == S_OK && HaveContext && IS_KERNEL_TARGET())
  3889. {
  3890. ULONG Code;
  3891. ULONG64 Args[4];
  3892. if (ReadBugCheckData(&Code, Args) == S_OK &&
  3893. Code != 0)
  3894. {
  3895. CallBugCheckExtension(NULL);
  3896. }
  3897. }
  3898. #endif
  3899. EventOut("> Wait returning %X\n", Status);
  3900. return Status;
  3901. }
  3902. //----------------------------------------------------------------------------
  3903. //
  3904. // Event filters.
  3905. //
  3906. //----------------------------------------------------------------------------
  3907. void ParseImageTail(PSTR Buffer, ULONG BufferSize)
  3908. {
  3909. int i;
  3910. char ch;
  3911. Buffer[0] = '\0';
  3912. i = 0;
  3913. while (ch = (char)tolower(*g_CurCmd))
  3914. {
  3915. if (ch == ' ' || ch == '\t' || ch == ';')
  3916. {
  3917. break;
  3918. }
  3919. // Only capture the path tail.
  3920. if (IS_SLASH(ch) || ch == ':')
  3921. {
  3922. i = 0;
  3923. }
  3924. else
  3925. {
  3926. Buffer[i++] = ch;
  3927. if (i == BufferSize - 1)
  3928. {
  3929. // don't overrun the buffer
  3930. break;
  3931. }
  3932. }
  3933. g_CurCmd++;
  3934. }
  3935. Buffer[i] = '\0';
  3936. }
  3937. void
  3938. ParseUnloadDllBreakAddr(void)
  3939. /*++
  3940. Routine Description:
  3941. Called after 'sxe ud' has been parsed. This routine detects an
  3942. optional DLL base address after the 'sxe ud', which tells the debugger
  3943. to run until that specific DLL is unloaded, not just the next DLL.
  3944. Arguments:
  3945. None.
  3946. Return Value:
  3947. None.
  3948. --*/
  3949. {
  3950. UCHAR ch;
  3951. g_UnloadDllBase = 0;
  3952. g_UnloadDllBaseName[0] = 0;
  3953. while (ch = (UCHAR)tolower(*g_CurCmd))
  3954. {
  3955. if (ch == ' ')
  3956. {
  3957. break;
  3958. }
  3959. // Skip leading ':'
  3960. if (ch != ':')
  3961. {
  3962. // Get the base address
  3963. g_UnloadDllBase = GetExpression();
  3964. sprintf(g_UnloadDllBaseName, "0x%s",
  3965. FormatAddr64(g_UnloadDllBase));
  3966. break;
  3967. }
  3968. g_CurCmd++;
  3969. }
  3970. }
  3971. void
  3972. ParseOutFilterPattern(void)
  3973. {
  3974. int i;
  3975. char ch;
  3976. i = 0;
  3977. while (ch = (char)tolower(*g_CurCmd))
  3978. {
  3979. if (ch == ' ')
  3980. {
  3981. break;
  3982. }
  3983. if (ch == ':')
  3984. {
  3985. i = 0;
  3986. }
  3987. else
  3988. {
  3989. g_OutEventFilterPattern[i++] = (char)toupper(ch);
  3990. if (i == sizeof(g_OutEventFilterPattern) - 1)
  3991. {
  3992. // Don't overrun the buffer.
  3993. break;
  3994. }
  3995. }
  3996. g_CurCmd++;
  3997. }
  3998. g_OutEventFilterPattern[i] = 0;
  3999. }
  4000. BOOL
  4001. BreakOnThisImageTail(PCSTR ImagePath, PCSTR FilterArg)
  4002. {
  4003. //
  4004. // No filter specified so break on all events.
  4005. //
  4006. if (!FilterArg || !FilterArg[0])
  4007. {
  4008. return TRUE;
  4009. }
  4010. //
  4011. // Some kind of error looking up the image path. Break anyhow.
  4012. //
  4013. if (!ImagePath || !ImagePath[0])
  4014. {
  4015. return TRUE;
  4016. }
  4017. PCSTR Tail = PathTail(ImagePath);
  4018. //
  4019. // Specified name may not have an extension. Break
  4020. // on the first event whose name matches regardless of its extension if
  4021. // the break name did not have one.
  4022. //
  4023. if (_strnicmp(Tail, FilterArg, strlen(FilterArg)) == 0)
  4024. {
  4025. return TRUE;
  4026. }
  4027. else if (MatchPattern((PSTR)Tail, (PSTR)FilterArg))
  4028. {
  4029. return TRUE;
  4030. }
  4031. return FALSE;
  4032. }
  4033. BOOL
  4034. BreakOnThisDllUnload(
  4035. ULONG64 DllBase
  4036. )
  4037. {
  4038. // 'sxe ud' with no base address specified. Break on all DLL unloads
  4039. if (g_UnloadDllBase == 0)
  4040. {
  4041. return TRUE;
  4042. }
  4043. // 'sxe ud' with base address specified. Break if this
  4044. // DLL's base address matches the one specified
  4045. return g_UnloadDllBase == DllBase;
  4046. }
  4047. BOOL
  4048. BreakOnThisOutString(PCSTR OutString)
  4049. {
  4050. if (!g_OutEventFilterPattern[0])
  4051. {
  4052. // No pattern means always break.
  4053. return TRUE;
  4054. }
  4055. return MatchPattern((PSTR)OutString, g_OutEventFilterPattern);
  4056. }
  4057. EVENT_FILTER*
  4058. GetSpecificExceptionFilter(ULONG Code)
  4059. {
  4060. ULONG i;
  4061. EVENT_FILTER* Filter;
  4062. Filter = g_EventFilters + FILTER_EXCEPTION_FIRST;
  4063. for (i = FILTER_EXCEPTION_FIRST; i <= FILTER_EXCEPTION_LAST; i++)
  4064. {
  4065. if (i != FILTER_DEFAULT_EXCEPTION &&
  4066. Filter->Params.ExceptionCode == Code)
  4067. {
  4068. return Filter;
  4069. }
  4070. Filter++;
  4071. }
  4072. return NULL;
  4073. }
  4074. void GetOtherExceptionParameters(ULONG Code,
  4075. PDEBUG_EXCEPTION_FILTER_PARAMETERS* Params,
  4076. EVENT_COMMAND** Command)
  4077. {
  4078. ULONG Index;
  4079. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  4080. {
  4081. if (Code == g_OtherExceptionList[Index].ExceptionCode)
  4082. {
  4083. *Params = g_OtherExceptionList + Index;
  4084. *Command = g_OtherExceptionCommands + Index;
  4085. return;
  4086. }
  4087. }
  4088. *Params = &g_EventFilters[FILTER_DEFAULT_EXCEPTION].Params;
  4089. *Command = &g_EventFilters[FILTER_DEFAULT_EXCEPTION].Command;
  4090. }
  4091. ULONG
  4092. SetOtherExceptionParameters(PDEBUG_EXCEPTION_FILTER_PARAMETERS Params,
  4093. EVENT_COMMAND* Command)
  4094. {
  4095. ULONG Index;
  4096. if (g_EventFilters[FILTER_DEFAULT_EXCEPTION].
  4097. Params.ExecutionOption == Params->ExecutionOption &&
  4098. g_EventFilters[FILTER_DEFAULT_EXCEPTION].
  4099. Params.ContinueOption == Params->ContinueOption &&
  4100. !memcmp(&g_EventFilters[FILTER_DEFAULT_EXCEPTION].Command,
  4101. Command, sizeof(*Command)))
  4102. {
  4103. // Exception state same as global state clears entry
  4104. // in list if there.
  4105. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  4106. {
  4107. if (Params->ExceptionCode ==
  4108. g_OtherExceptionList[Index].ExceptionCode)
  4109. {
  4110. g_NumOtherExceptions--;
  4111. memmove(g_OtherExceptionList + Index,
  4112. g_OtherExceptionList + Index + 1,
  4113. (g_NumOtherExceptions - Index) *
  4114. sizeof(g_OtherExceptionList[0]));
  4115. memmove(g_OtherExceptionCommands + Index,
  4116. g_OtherExceptionCommands + Index + 1,
  4117. (g_NumOtherExceptions - Index) *
  4118. sizeof(g_OtherExceptionCommands[0]));
  4119. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS,
  4120. DEBUG_ANY_ID, TRUE);
  4121. break;
  4122. }
  4123. }
  4124. }
  4125. else
  4126. {
  4127. // Exception state different from global state is added
  4128. // to list if not already there.
  4129. for (Index = 0; Index < g_NumOtherExceptions; Index++)
  4130. {
  4131. if (Params->ExceptionCode ==
  4132. g_OtherExceptionList[Index].ExceptionCode)
  4133. {
  4134. break;
  4135. }
  4136. }
  4137. if (Index == g_NumOtherExceptions)
  4138. {
  4139. if (g_NumOtherExceptions == OTHER_EXCEPTION_LIST_MAX)
  4140. {
  4141. return LISTSIZE;
  4142. }
  4143. Index = g_NumOtherExceptions++;
  4144. }
  4145. g_OtherExceptionList[Index] = *Params;
  4146. g_OtherExceptionCommands[Index] = *Command;
  4147. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, Index, TRUE);
  4148. }
  4149. return 0;
  4150. }
  4151. ULONG
  4152. SetEventFilterExecution(EVENT_FILTER* Filter, ULONG Execution)
  4153. {
  4154. ULONG Index = (ULONG)(Filter - g_EventFilters);
  4155. // Non-exception events don't have second chances so
  4156. // demote second-chance break to output. This matches
  4157. // the intuitive expectation that sxd will disable
  4158. // the break.
  4159. if (
  4160. #if DEBUG_FILTER_CREATE_THREAD > 0
  4161. Index >= DEBUG_FILTER_CREATE_THREAD &&
  4162. #endif
  4163. Index <= DEBUG_FILTER_SYSTEM_ERROR &&
  4164. Execution == DEBUG_FILTER_SECOND_CHANCE_BREAK)
  4165. {
  4166. Execution = DEBUG_FILTER_OUTPUT;
  4167. }
  4168. Filter->Params.ExecutionOption = Execution;
  4169. Filter->Flags |= FILTER_CHANGED_EXECUTION;
  4170. // Collect any additional arguments.
  4171. switch(Index)
  4172. {
  4173. case DEBUG_FILTER_CREATE_PROCESS:
  4174. case DEBUG_FILTER_EXIT_PROCESS:
  4175. case DEBUG_FILTER_LOAD_MODULE:
  4176. ParseImageTail(Filter->Argument, FILTER_MAX_ARGUMENT);
  4177. break;
  4178. case DEBUG_FILTER_UNLOAD_MODULE:
  4179. ParseUnloadDllBreakAddr();
  4180. break;
  4181. case DEBUG_FILTER_DEBUGGEE_OUTPUT:
  4182. ParseOutFilterPattern();
  4183. break;
  4184. }
  4185. return 0;
  4186. }
  4187. ULONG
  4188. SetEventFilterContinue(EVENT_FILTER* Filter, ULONG Continue)
  4189. {
  4190. Filter->Params.ContinueOption = Continue;
  4191. Filter->Flags |= FILTER_CHANGED_CONTINUE;
  4192. return 0;
  4193. }
  4194. ULONG
  4195. SetEventFilterCommand(DebugClient* Client, EVENT_FILTER* Filter,
  4196. EVENT_COMMAND* EventCommand, PSTR* Command)
  4197. {
  4198. if (Command[0] != NULL &&
  4199. ChangeString(&EventCommand->Command[0], &EventCommand->CommandSize[0],
  4200. Command[0][0] ? Command[0] : NULL) != S_OK)
  4201. {
  4202. return MEMORY;
  4203. }
  4204. if (Command[1] != NULL)
  4205. {
  4206. if (Filter != NULL &&
  4207. #if FILTER_SPECIFIC_FIRST > 0
  4208. (ULONG)(Filter - g_EventFilters) >= FILTER_SPECIFIC_FIRST &&
  4209. #endif
  4210. (ULONG)(Filter - g_EventFilters) <= FILTER_SPECIFIC_LAST)
  4211. {
  4212. WarnOut("Second-chance command for specific event ignored\n");
  4213. }
  4214. else if (ChangeString(&EventCommand->Command[1],
  4215. &EventCommand->CommandSize[1],
  4216. Command[1][0] ? Command[1] : NULL) != S_OK)
  4217. {
  4218. return MEMORY;
  4219. }
  4220. }
  4221. if (Command[0] != NULL || Command[1] != NULL)
  4222. {
  4223. if (Filter != NULL)
  4224. {
  4225. Filter->Flags |= FILTER_CHANGED_COMMAND;
  4226. }
  4227. EventCommand->Client = Client;
  4228. }
  4229. return 0;
  4230. }
  4231. #define EXEC_TO_CONT(Option) \
  4232. ((Option) == DEBUG_FILTER_BREAK ? \
  4233. DEBUG_FILTER_GO_HANDLED : DEBUG_FILTER_GO_NOT_HANDLED)
  4234. ULONG
  4235. SetEventFilterEither(DebugClient* Client, EVENT_FILTER* Filter,
  4236. ULONG Option, BOOL ContinueOption,
  4237. PSTR* Command)
  4238. {
  4239. ULONG Status;
  4240. if (Option != DEBUG_FILTER_REMOVE)
  4241. {
  4242. if (ContinueOption)
  4243. {
  4244. Status = SetEventFilterContinue(Filter, EXEC_TO_CONT(Option));
  4245. }
  4246. else
  4247. {
  4248. Status = SetEventFilterExecution(Filter, Option);
  4249. }
  4250. if (Status != 0)
  4251. {
  4252. return Status;
  4253. }
  4254. }
  4255. return SetEventFilterCommand(Client, Filter, &Filter->Command, Command);
  4256. }
  4257. ULONG
  4258. SetEventFilterByName(DebugClient* Client,
  4259. ULONG Option, BOOL ForceContinue, PSTR* Command)
  4260. {
  4261. PSTR Start = g_CurCmd;
  4262. char Name[8];
  4263. int i;
  4264. char Ch;
  4265. // Collect name.
  4266. i = 0;
  4267. while (i < sizeof(Name) - 1)
  4268. {
  4269. Ch = *g_CurCmd++;
  4270. if (!__iscsym(Ch))
  4271. {
  4272. g_CurCmd--;
  4273. break;
  4274. }
  4275. Name[i++] = (CHAR)tolower(Ch);
  4276. }
  4277. Name[i] = 0;
  4278. // Skip any whitespace after the name.
  4279. while (isspace(*g_CurCmd))
  4280. {
  4281. g_CurCmd++;
  4282. }
  4283. EVENT_FILTER* Filter;
  4284. BOOL Match = FALSE;
  4285. ULONG MatchIndex = DEBUG_ANY_ID;
  4286. ULONG Status = 0;
  4287. // Multiple filters can be altered if they share names.
  4288. Filter = g_EventFilters;
  4289. for (i = 0; i < FILTER_COUNT; i++)
  4290. {
  4291. if (Filter->ExecutionAbbrev != NULL &&
  4292. !strcmp(Name, Filter->ExecutionAbbrev))
  4293. {
  4294. Status = SetEventFilterEither(Client,
  4295. Filter, Option, ForceContinue,
  4296. Command);
  4297. if (Status != 0)
  4298. {
  4299. goto Exit;
  4300. }
  4301. if (!Match)
  4302. {
  4303. MatchIndex = i;
  4304. Match = TRUE;
  4305. }
  4306. else if (MatchIndex != (ULONG)i)
  4307. {
  4308. // Multiple matches.
  4309. MatchIndex = DEBUG_ANY_ID;
  4310. }
  4311. }
  4312. if (Filter->ContinueAbbrev != NULL &&
  4313. !strcmp(Name, Filter->ContinueAbbrev))
  4314. {
  4315. // Translate execution-style option to continue-style option.
  4316. Status = SetEventFilterEither(Client,
  4317. Filter, Option, TRUE, Command);
  4318. if (Status != 0)
  4319. {
  4320. goto Exit;
  4321. }
  4322. if (!Match)
  4323. {
  4324. MatchIndex = i;
  4325. Match = TRUE;
  4326. }
  4327. else if (MatchIndex != (ULONG)i)
  4328. {
  4329. // Multiple matches.
  4330. MatchIndex = DEBUG_ANY_ID;
  4331. }
  4332. }
  4333. Filter++;
  4334. }
  4335. if (!Match)
  4336. {
  4337. ULONG64 ExceptionCode;
  4338. // Name is unrecognized. Assume it's an exception code.
  4339. g_CurCmd = Start;
  4340. ExceptionCode = GetExpression();
  4341. if (NeedUpper(ExceptionCode))
  4342. {
  4343. return OVERFLOW;
  4344. }
  4345. DEBUG_EXCEPTION_FILTER_PARAMETERS Params, *CurParams;
  4346. EVENT_COMMAND EventCommand, *CurEventCommand;
  4347. GetOtherExceptionParameters((ULONG)ExceptionCode,
  4348. &CurParams, &CurEventCommand);
  4349. Params = *CurParams;
  4350. if (Option != DEBUG_FILTER_REMOVE)
  4351. {
  4352. if (ForceContinue)
  4353. {
  4354. Params.ContinueOption = EXEC_TO_CONT(Option);
  4355. }
  4356. else
  4357. {
  4358. Params.ExecutionOption = Option;
  4359. }
  4360. }
  4361. Params.ExceptionCode = (ULONG)ExceptionCode;
  4362. EventCommand = *CurEventCommand;
  4363. Status = SetEventFilterCommand(Client, NULL, &EventCommand, Command);
  4364. if (Status != 0)
  4365. {
  4366. return Status;
  4367. }
  4368. return SetOtherExceptionParameters(&Params, &EventCommand);
  4369. }
  4370. Exit:
  4371. if (Match)
  4372. {
  4373. if (SyncOptionsWithFilters())
  4374. {
  4375. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS |
  4376. DEBUG_CES_ENGINE_OPTIONS,
  4377. DEBUG_ANY_ID, TRUE);
  4378. }
  4379. else
  4380. {
  4381. NotifyChangeEngineState(DEBUG_CES_EVENT_FILTERS, MatchIndex, TRUE);
  4382. }
  4383. }
  4384. return Status;
  4385. }
  4386. char* g_EfExecutionNames[] =
  4387. {
  4388. "break", "second-chance break", "output", "ignore",
  4389. };
  4390. char* g_EfContinueNames[] =
  4391. {
  4392. "handled", "not handled",
  4393. };
  4394. void
  4395. ListEventFilters(void)
  4396. {
  4397. EVENT_FILTER* Filter;
  4398. ULONG i;
  4399. BOOL SetOption = TRUE;
  4400. Filter = g_EventFilters;
  4401. for (i = 0; i < FILTER_COUNT; i++)
  4402. {
  4403. if (Filter->ExecutionAbbrev != NULL)
  4404. {
  4405. dprintf("%4s - %s - %s",
  4406. Filter->ExecutionAbbrev, Filter->Name,
  4407. g_EfExecutionNames[Filter->Params.ExecutionOption]);
  4408. if (i >= FILTER_EXCEPTION_FIRST &&
  4409. Filter->ContinueAbbrev == NULL)
  4410. {
  4411. dprintf(" - %s\n",
  4412. g_EfContinueNames[Filter->Params.ContinueOption]);
  4413. }
  4414. else
  4415. {
  4416. dprintf("\n");
  4417. }
  4418. if (Filter->Command.Command[0] != NULL)
  4419. {
  4420. dprintf(" Command: \"%s\"\n",
  4421. Filter->Command.Command[0]);
  4422. }
  4423. if (Filter->Command.Command[1] != NULL)
  4424. {
  4425. dprintf(" Second command: \"%s\"\n",
  4426. Filter->Command.Command[1]);
  4427. }
  4428. }
  4429. if (Filter->ContinueAbbrev != NULL)
  4430. {
  4431. dprintf("%4s - %s continue - %s\n",
  4432. Filter->ContinueAbbrev, Filter->Name,
  4433. g_EfContinueNames[Filter->Params.ContinueOption]);
  4434. }
  4435. switch(i)
  4436. {
  4437. case DEBUG_FILTER_CREATE_PROCESS:
  4438. case DEBUG_FILTER_EXIT_PROCESS:
  4439. case DEBUG_FILTER_LOAD_MODULE:
  4440. case DEBUG_FILTER_UNLOAD_MODULE:
  4441. if (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  4442. Filter->Argument[0])
  4443. {
  4444. dprintf(" (only break for %s)\n", Filter->Argument);
  4445. }
  4446. break;
  4447. case DEBUG_FILTER_DEBUGGEE_OUTPUT:
  4448. if (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  4449. g_OutEventFilterPattern[0])
  4450. {
  4451. dprintf(" (only break for %s matches)\n",
  4452. g_OutEventFilterPattern);
  4453. }
  4454. break;
  4455. }
  4456. Filter++;
  4457. }
  4458. Filter = &g_EventFilters[FILTER_DEFAULT_EXCEPTION];
  4459. dprintf("\n * - Other exception - %s - %s\n",
  4460. g_EfExecutionNames[Filter->Params.ExecutionOption],
  4461. g_EfContinueNames[Filter->Params.ContinueOption]);
  4462. if (Filter->Command.Command[0] != NULL)
  4463. {
  4464. dprintf(" Command: \"%s\"\n",
  4465. Filter->Command.Command[0]);
  4466. }
  4467. if (Filter->Command.Command[1] != NULL)
  4468. {
  4469. dprintf(" Second command: \"%s\"\n",
  4470. Filter->Command.Command[1]);
  4471. }
  4472. if (g_NumOtherExceptions > 0)
  4473. {
  4474. dprintf(" Exception option for:\n");
  4475. for (i = 0; i < g_NumOtherExceptions; i++)
  4476. {
  4477. dprintf(" %08lx - %s - %s\n",
  4478. g_OtherExceptionList[i].ExceptionCode,
  4479. g_EfExecutionNames[g_OtherExceptionList[i].
  4480. ExecutionOption],
  4481. g_EfContinueNames[g_OtherExceptionList[i].
  4482. ContinueOption]);
  4483. if (g_OtherExceptionCommands[i].Command[0] != NULL)
  4484. {
  4485. dprintf(" Command: \"%s\"\n",
  4486. g_OtherExceptionCommands[i].Command[0]);
  4487. }
  4488. if (g_OtherExceptionCommands[i].Command[1] != NULL)
  4489. {
  4490. dprintf(" Second command: \"%s\"\n",
  4491. g_OtherExceptionCommands[i].Command[1]);
  4492. }
  4493. }
  4494. }
  4495. }
  4496. void
  4497. ParseSetEventFilter(DebugClient* Client)
  4498. {
  4499. UCHAR Ch;
  4500. // Verify that exception constants are properly updated.
  4501. DBG_ASSERT(!strcmp(g_EventFilters[FILTER_EXCEPTION_FIRST - 1].Name,
  4502. "Debuggee output"));
  4503. DBG_ASSERT(DIMA(g_EventFilters) == FILTER_COUNT);
  4504. Ch = PeekChar();
  4505. if (Ch == '\0')
  4506. {
  4507. ListEventFilters();
  4508. }
  4509. else
  4510. {
  4511. ULONG Option;
  4512. Ch = (UCHAR)tolower(Ch);
  4513. g_CurCmd++;
  4514. switch(Ch)
  4515. {
  4516. case 'd':
  4517. Option = DEBUG_FILTER_SECOND_CHANCE_BREAK;
  4518. break;
  4519. case 'e':
  4520. Option = DEBUG_FILTER_BREAK;
  4521. break;
  4522. case 'i':
  4523. Option = DEBUG_FILTER_IGNORE;
  4524. break;
  4525. case 'n':
  4526. Option = DEBUG_FILTER_OUTPUT;
  4527. break;
  4528. case '-':
  4529. // Special value to indicate "don't change the option".
  4530. // Used for just changing commands.
  4531. Option = DEBUG_FILTER_REMOVE;
  4532. break;
  4533. default:
  4534. error(SYNTAX);
  4535. break;
  4536. }
  4537. BOOL ForceContinue;
  4538. PSTR Command[2];
  4539. ULONG Which;
  4540. ForceContinue = FALSE;
  4541. Command[0] = NULL;
  4542. Command[1] = NULL;
  4543. for (;;)
  4544. {
  4545. while (isspace(PeekChar()))
  4546. {
  4547. g_CurCmd++;
  4548. }
  4549. if (*g_CurCmd == '-' || *g_CurCmd == '/')
  4550. {
  4551. switch(tolower(*(++g_CurCmd)))
  4552. {
  4553. case 'c':
  4554. if (*(++g_CurCmd) == '2')
  4555. {
  4556. Which = 1;
  4557. g_CurCmd++;
  4558. }
  4559. else
  4560. {
  4561. Which = 0;
  4562. }
  4563. if (PeekChar() != '"')
  4564. {
  4565. error(SYNTAX);
  4566. }
  4567. if (Command[Which] != NULL)
  4568. {
  4569. error(SYNTAX);
  4570. }
  4571. Command[Which] = ++g_CurCmd;
  4572. while (*g_CurCmd && *g_CurCmd != '"')
  4573. {
  4574. g_CurCmd++;
  4575. }
  4576. if (*g_CurCmd != '"')
  4577. {
  4578. error(SYNTAX);
  4579. }
  4580. *g_CurCmd = 0;
  4581. break;
  4582. case 'h':
  4583. ForceContinue = TRUE;
  4584. break;
  4585. default:
  4586. error(SYNTAX);
  4587. }
  4588. g_CurCmd++;
  4589. }
  4590. else
  4591. {
  4592. break;
  4593. }
  4594. }
  4595. ULONG Status;
  4596. if (*g_CurCmd == '*')
  4597. {
  4598. g_CurCmd++;
  4599. Status = SetEventFilterEither
  4600. (Client, &g_EventFilters[FILTER_DEFAULT_EXCEPTION],
  4601. Option, ForceContinue, Command);
  4602. if (Status == 0)
  4603. {
  4604. g_NumOtherExceptions = 0;
  4605. }
  4606. }
  4607. else
  4608. {
  4609. Status = SetEventFilterByName(Client,
  4610. Option, ForceContinue, Command);
  4611. }
  4612. if (Status != 0)
  4613. {
  4614. error(Status);
  4615. }
  4616. }
  4617. }
  4618. char
  4619. ExecutionChar(ULONG Execution)
  4620. {
  4621. switch(Execution)
  4622. {
  4623. case DEBUG_FILTER_BREAK:
  4624. return 'e';
  4625. case DEBUG_FILTER_SECOND_CHANCE_BREAK:
  4626. return 'd';
  4627. case DEBUG_FILTER_OUTPUT:
  4628. return 'n';
  4629. case DEBUG_FILTER_IGNORE:
  4630. return 'i';
  4631. }
  4632. return 0;
  4633. }
  4634. char
  4635. ContinueChar(ULONG Continue)
  4636. {
  4637. switch(Continue)
  4638. {
  4639. case DEBUG_FILTER_GO_HANDLED:
  4640. return 'e';
  4641. case DEBUG_FILTER_GO_NOT_HANDLED:
  4642. return 'd';
  4643. }
  4644. return 0;
  4645. }
  4646. void
  4647. ListFiltersAsCommands(DebugClient* Client, ULONG Flags)
  4648. {
  4649. ULONG i;
  4650. EVENT_FILTER* Filter = g_EventFilters;
  4651. for (i = 0; i < FILTER_COUNT; i++)
  4652. {
  4653. if (Filter->Flags & FILTER_CHANGED_EXECUTION)
  4654. {
  4655. PCSTR Abbrev = Filter->ExecutionAbbrev != NULL ?
  4656. Filter->ExecutionAbbrev : "*";
  4657. dprintf("sx%c %s",
  4658. ExecutionChar(Filter->Params.ExecutionOption), Abbrev);
  4659. switch(i)
  4660. {
  4661. case DEBUG_FILTER_CREATE_PROCESS:
  4662. case DEBUG_FILTER_EXIT_PROCESS:
  4663. case DEBUG_FILTER_LOAD_MODULE:
  4664. case DEBUG_FILTER_UNLOAD_MODULE:
  4665. case DEBUG_FILTER_DEBUGGEE_OUTPUT:
  4666. if (IS_EFEXECUTION_BREAK(Filter->Params.ExecutionOption) &&
  4667. Filter->Argument[0])
  4668. {
  4669. dprintf(":%s", Filter->Argument);
  4670. }
  4671. break;
  4672. }
  4673. dprintf(" ;%c", (Flags & SXCMDS_ONE_LINE) ? ' ' : '\n');
  4674. }
  4675. if (Filter->Flags & FILTER_CHANGED_CONTINUE)
  4676. {
  4677. PCSTR Abbrev = Filter->ContinueAbbrev;
  4678. if (Abbrev == NULL)
  4679. {
  4680. Abbrev = Filter->ExecutionAbbrev != NULL ?
  4681. Filter->ExecutionAbbrev : "*";
  4682. }
  4683. dprintf("sx%c -h %s ;%c",
  4684. ContinueChar(Filter->Params.ContinueOption), Abbrev,
  4685. (Flags & SXCMDS_ONE_LINE) ? ' ' : '\n');
  4686. }
  4687. if (Filter->Flags & FILTER_CHANGED_COMMAND)
  4688. {
  4689. PCSTR Abbrev = Filter->ExecutionAbbrev != NULL ?
  4690. Filter->ExecutionAbbrev : "*";
  4691. dprintf("sx-");
  4692. if (Filter->Command.Command[0] != NULL)
  4693. {
  4694. dprintf(" -c \"%s\"", Filter->Command.Command[0]);
  4695. }
  4696. if (Filter->Command.Command[1] != NULL)
  4697. {
  4698. dprintf(" -c2 \"%s\"", Filter->Command.Command[1]);
  4699. }
  4700. dprintf(" %s ;%c", Abbrev,
  4701. (Flags & SXCMDS_ONE_LINE) ? ' ' : '\n');
  4702. }
  4703. Filter++;
  4704. }
  4705. PDEBUG_EXCEPTION_FILTER_PARAMETERS Other = g_OtherExceptionList;
  4706. EVENT_COMMAND* EventCommand = g_OtherExceptionCommands;
  4707. for (i = 0; i < g_NumOtherExceptions; i++)
  4708. {
  4709. dprintf("sx%c 0x%x ;%c",
  4710. ExecutionChar(Other->ExecutionOption), Other->ExceptionCode,
  4711. (Flags & SXCMDS_ONE_LINE) ? ' ' : '\n');
  4712. dprintf("sx%c -h 0x%x ;%c",
  4713. ContinueChar(Other->ContinueOption), Other->ExceptionCode,
  4714. (Flags & SXCMDS_ONE_LINE) ? ' ' : '\n');
  4715. if (EventCommand->Command[0] != NULL ||
  4716. EventCommand->Command[1] != NULL)
  4717. {
  4718. dprintf("sx-");
  4719. if (EventCommand->Command[0] != NULL)
  4720. {
  4721. dprintf(" -c \"%s\"", EventCommand->Command[0]);
  4722. }
  4723. if (EventCommand->Command[1] != NULL)
  4724. {
  4725. dprintf(" -c2 \"%s\"", EventCommand->Command[1]);
  4726. }
  4727. dprintf(" 0x%x ;%c", Other->ExceptionCode,
  4728. (Flags & SXCMDS_ONE_LINE) ? ' ' : '\n');
  4729. }
  4730. Other++;
  4731. EventCommand++;
  4732. }
  4733. if (Flags & SXCMDS_ONE_LINE)
  4734. {
  4735. dprintf("\n");
  4736. }
  4737. }
  4738. struct SHARED_FILTER_AND_OPTION
  4739. {
  4740. ULONG FilterIndex;
  4741. ULONG OptionBit;
  4742. };
  4743. SHARED_FILTER_AND_OPTION g_SharedFilterOptions[] =
  4744. {
  4745. DEBUG_FILTER_INITIAL_BREAKPOINT, DEBUG_ENGOPT_INITIAL_BREAK,
  4746. DEBUG_FILTER_INITIAL_MODULE_LOAD, DEBUG_ENGOPT_INITIAL_MODULE_BREAK,
  4747. DEBUG_FILTER_EXIT_PROCESS, DEBUG_ENGOPT_FINAL_BREAK,
  4748. };
  4749. BOOL
  4750. SyncFiltersWithOptions(void)
  4751. {
  4752. ULONG ExOption;
  4753. BOOL Changed = FALSE;
  4754. ULONG i;
  4755. for (i = 0; i < DIMA(g_SharedFilterOptions); i++)
  4756. {
  4757. ExOption = (g_EngOptions & g_SharedFilterOptions[i].OptionBit) ?
  4758. DEBUG_FILTER_BREAK : DEBUG_FILTER_IGNORE;
  4759. if (g_EventFilters[g_SharedFilterOptions[i].FilterIndex].
  4760. Params.ExecutionOption != ExOption)
  4761. {
  4762. g_EventFilters[g_SharedFilterOptions[i].FilterIndex].
  4763. Params.ExecutionOption = ExOption;
  4764. Changed = TRUE;
  4765. }
  4766. }
  4767. return Changed;
  4768. }
  4769. BOOL
  4770. SyncOptionsWithFilters(void)
  4771. {
  4772. ULONG Bit;
  4773. BOOL Changed = FALSE;
  4774. ULONG i;
  4775. for (i = 0; i < DIMA(g_SharedFilterOptions); i++)
  4776. {
  4777. Bit = IS_EFEXECUTION_BREAK
  4778. (g_EventFilters[g_SharedFilterOptions[i].FilterIndex].
  4779. Params.ExecutionOption) ?
  4780. g_SharedFilterOptions[i].OptionBit : 0;
  4781. if ((g_EngOptions & g_SharedFilterOptions[i].OptionBit) ^ Bit)
  4782. {
  4783. g_EngOptions =
  4784. (g_EngOptions & ~g_SharedFilterOptions[i].OptionBit) | Bit;
  4785. Changed = TRUE;
  4786. }
  4787. }
  4788. return Changed;
  4789. }