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

550 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. event.cxx
  5. Abstract:
  6. This file contains the routines to track and handle
  7. debugger events.
  8. Author:
  9. Jason Hartman (JasonHa) 2000-11-20
  10. Environment:
  11. User Mode
  12. --*/
  13. #include "precomp.hxx"
  14. BOOL gbSymbolsNotLoaded = TRUE;
  15. ULONG UniqueTargetState = INVALID_UNIQUE_STATE;
  16. #if DBG && 0
  17. ULONG
  18. DbgEventPrint(
  19. IN PCHAR Format,
  20. ...
  21. )
  22. {
  23. va_list arglist;
  24. va_start(arglist, Format);
  25. return vDbgPrintExWithPrefix("Event: ", -1, 0, Format, arglist);
  26. }
  27. #else
  28. #define DbgEventPrint
  29. #endif
  30. typedef struct {
  31. PDEBUG_CLIENT Client;
  32. BOOL ParamsRead;
  33. } MonitorThreadParams;
  34. DWORD WINAPI EventMonitorThread(MonitorThreadParams *);
  35. class EventMonitorCallbacks : public DebugBaseEventCallbacks
  36. {
  37. private:
  38. ULONG RefCount;
  39. public:
  40. EventMonitorCallbacks()
  41. {
  42. RefCount = 1;
  43. }
  44. // IUnknown
  45. STDMETHOD_(ULONG, AddRef)(
  46. THIS
  47. )
  48. {
  49. RefCount++;
  50. return RefCount;
  51. }
  52. STDMETHOD_(ULONG, Release)(
  53. THIS
  54. )
  55. {
  56. RefCount--;
  57. if (RefCount == 0)
  58. {
  59. delete this;
  60. return 0;
  61. }
  62. return RefCount;
  63. }
  64. // IDebugEventCallbacks.
  65. STDMETHOD(GetInterestMask)(
  66. THIS_
  67. OUT PULONG Mask
  68. )
  69. {
  70. DbgEventPrint("GetInterestMask\n");
  71. if (Mask != NULL)
  72. {
  73. *Mask = DEBUG_EVENT_SESSION_STATUS |
  74. DEBUG_EVENT_CHANGE_DEBUGGEE_STATE |
  75. DEBUG_EVENT_CHANGE_ENGINE_STATE |
  76. DEBUG_EVENT_CHANGE_SYMBOL_STATE |
  77. DEBUG_EVENT_UNLOAD_MODULE;
  78. }
  79. return S_OK;
  80. }
  81. STDMETHOD(Breakpoint)(
  82. THIS_
  83. IN PDEBUG_BREAKPOINT Bp
  84. )
  85. {
  86. DbgEventPrint("BP\n");
  87. return DEBUG_STATUS_NO_CHANGE;
  88. }
  89. STDMETHOD(Exception)(
  90. THIS_
  91. IN PEXCEPTION_RECORD64 Exception,
  92. IN ULONG FirstChance
  93. )
  94. {
  95. DbgEventPrint("Exception\n");
  96. return DEBUG_STATUS_NO_CHANGE;
  97. }
  98. STDMETHOD(CreateThread)(
  99. THIS_
  100. IN ULONG64 Handle,
  101. IN ULONG64 DataOffset,
  102. IN ULONG64 StartOffset
  103. )
  104. {
  105. DbgEventPrint("CreateThread\n");
  106. return DEBUG_STATUS_NO_CHANGE;
  107. }
  108. STDMETHOD(ExitThread)(
  109. THIS_
  110. IN ULONG ExitCode
  111. )
  112. {
  113. DbgEventPrint("ExitThread\n");
  114. return DEBUG_STATUS_NO_CHANGE;
  115. }
  116. STDMETHOD(CreateProcess)(
  117. THIS_
  118. IN ULONG64 ImageFileHandle,
  119. IN ULONG64 Handle,
  120. IN ULONG64 BaseOffset,
  121. IN ULONG ModuleSize,
  122. IN PCSTR ModuleName,
  123. IN PCSTR ImageName,
  124. IN ULONG CheckSum,
  125. IN ULONG TimeDateStamp,
  126. IN ULONG64 InitialThreadHandle,
  127. IN ULONG64 ThreadDataOffset,
  128. IN ULONG64 StartOffset
  129. )
  130. {
  131. DbgEventPrint("CreateProcess\n");
  132. return DEBUG_STATUS_NO_CHANGE;
  133. }
  134. STDMETHOD(ExitProcess)(
  135. THIS_
  136. IN ULONG ExitCode
  137. )
  138. {
  139. DbgEventPrint("ExitProcess\n");
  140. return DEBUG_STATUS_NO_CHANGE;
  141. }
  142. STDMETHOD(LoadModule)(
  143. THIS_
  144. IN ULONG64 ImageFileHandle,
  145. IN ULONG64 BaseOffset,
  146. IN ULONG ModuleSize,
  147. IN PCSTR ModuleName,
  148. IN PCSTR ImageName,
  149. IN ULONG CheckSum,
  150. IN ULONG TimeDateStamp
  151. )
  152. {
  153. DbgEventPrint("LoadModule:\n"
  154. " ModuleName: %s\n"
  155. " ImageName: %s\n"
  156. " BaseOffset: %I64x\n",
  157. ModuleName, ImageName, BaseOffset);
  158. return DEBUG_STATUS_NO_CHANGE;
  159. }
  160. STDMETHOD(UnloadModule)(
  161. THIS_
  162. IN PCSTR ImageBaseName,
  163. IN ULONG64 BaseOffset
  164. )
  165. {
  166. // Don't use Image base name for now - Debugger bug
  167. //DbgEventPrint("UnloadModule %s @ %I64x\n", ImageBaseName, BaseOffset);
  168. DbgEventPrint("UnloadModule ? @ %I64x\n", BaseOffset);
  169. return DEBUG_STATUS_NO_CHANGE;
  170. }
  171. STDMETHOD(SystemError)(
  172. THIS_
  173. IN ULONG Error,
  174. IN ULONG Level
  175. )
  176. {
  177. DbgEventPrint("SystemError(%lu, %lu)\n", Error, Level);
  178. return DEBUG_STATUS_NO_CHANGE;
  179. }
  180. STDMETHOD(SessionStatus)(
  181. THIS_
  182. IN ULONG Status
  183. )
  184. {
  185. DbgEventPrint("SessionStatus(%lu)\n", Status);
  186. if (Status == DEBUG_SESSION_ACTIVE) DbgEventPrint("DEBUG_SESSION_ACTIVE\n");
  187. if (Status == DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE) DbgEventPrint("DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE\n");
  188. if (Status == DEBUG_SESSION_END_SESSION_ACTIVE_DETACH) DbgEventPrint("DEBUG_SESSION_END_SESSION_ACTIVE_DETACH\n");
  189. if (Status == DEBUG_SESSION_END_SESSION_PASSIVE) DbgEventPrint("DEBUG_SESSION_END_SESSION_PASSIVE\n");
  190. if (Status == DEBUG_SESSION_END) DbgEventPrint("DEBUG_SESSION_END\n");
  191. if (Status == DEBUG_SESSION_REBOOT) DbgEventPrint("DEBUG_SESSION_REBOOT\n");
  192. if (Status == DEBUG_SESSION_HIBERNATE) DbgEventPrint("DEBUG_SESSION_HIBERNATE\n");
  193. if (Status == DEBUG_SESSION_FAILURE) DbgEventPrint("DEBUG_SESSION_FAILURE\n");
  194. return DEBUG_STATUS_NO_CHANGE;
  195. }
  196. STDMETHOD(ChangeDebuggeeState)(
  197. THIS_
  198. IN ULONG Flags,
  199. IN ULONG64 Argument
  200. )
  201. {
  202. DbgEventPrint("ChangeDebuggeeState(0x%lx, 0x%I64x)\n", Flags, Argument);
  203. if (Flags == DEBUG_CDS_ALL)
  204. {
  205. DbgEventPrint("DEBUG_CDS_ALL\n");
  206. UniqueTargetState++;
  207. }
  208. else
  209. {
  210. if (Flags & DEBUG_CDS_REGISTERS) DbgEventPrint("DEBUG_CDS_REGISTERS\n");
  211. if (Flags & DEBUG_CDS_DATA)
  212. {
  213. DbgEventPrint("DEBUG_CDS_DATA\n");
  214. UniqueTargetState++;
  215. }
  216. }
  217. if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
  218. return S_OK;
  219. }
  220. STDMETHOD(ChangeEngineState)(
  221. THIS_
  222. IN ULONG Flags,
  223. IN ULONG64 Argument
  224. )
  225. {
  226. //DbgEventPrint("ChangeEngineState(0x%lx, 0x%I64x)\n", Flags, Argument);
  227. if (Flags == DEBUG_CES_ALL)
  228. {
  229. DbgEventPrint("DEBUG_CES_ALL\n");
  230. UniqueTargetState++;
  231. if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
  232. }
  233. else
  234. {
  235. if (Flags & DEBUG_CES_CURRENT_THREAD) DbgEventPrint("DEBUG_CES_CURRENT_THREAD\n");
  236. if (Flags & DEBUG_CES_EFFECTIVE_PROCESSOR) DbgEventPrint("DEBUG_CES_EFFECTIVE_PROCESSOR\n");
  237. if (Flags & DEBUG_CES_BREAKPOINTS) DbgEventPrint("DEBUG_CES_BREAKPOINTS\n");
  238. if (Flags & DEBUG_CES_CODE_LEVEL) DbgEventPrint("DEBUG_CES_CODE_LEVEL\n");
  239. if (Flags & DEBUG_CES_EXECUTION_STATUS)
  240. {
  241. DbgEventPrint("DEBUG_CES_EXECUTION_STATUS\n");
  242. switch (Argument & DEBUG_STATUS_MASK)
  243. {
  244. case DEBUG_STATUS_NO_CHANGE: DbgPrint("Exec Status: DEBUG_STATUS_NO_CHANGE\n"); break;
  245. case DEBUG_STATUS_GO: DbgPrint("Exec Status: DEBUG_STATUS_GO\n"); break;
  246. case DEBUG_STATUS_GO_HANDLED: DbgPrint("Exec Status: DEBUG_STATUS_GO_HANDLED\n"); break;
  247. case DEBUG_STATUS_GO_NOT_HANDLED: DbgPrint("Exec Status: DEBUG_STATUS_GO_NOT_HANDLED\n"); break;
  248. case DEBUG_STATUS_STEP_OVER: DbgPrint("Exec Status: DEBUG_STATUS_STEP_OVER\n"); break;
  249. case DEBUG_STATUS_STEP_INTO: DbgPrint("Exec Status: DEBUG_STATUS_STEP_INTO\n"); break;
  250. case DEBUG_STATUS_BREAK: DbgPrint("Exec Status: DEBUG_STATUS_BREAK\n"); break;
  251. case DEBUG_STATUS_NO_DEBUGGEE: DbgPrint("Exec Status: DEBUG_STATUS_NO_DEBUGGEE\n"); break;
  252. case DEBUG_STATUS_STEP_BRANCH: DbgPrint("Exec Status: DEBUG_STATUS_STEP_BRANCH\n"); break;
  253. case DEBUG_STATUS_IGNORE_EVENT: DbgPrint("Exec Status: DEBUG_STATUS_IGNORE_EVENT\n"); break;
  254. default: DbgPrint("Exec Status: Unknown\n"); break;
  255. }
  256. if (Argument & DEBUG_STATUS_INSIDE_WAIT) DbgPrint("Exec Status: DEBUG_STATUS_INSIDE_WAIT\n");
  257. if ((Argument & DEBUG_STATUS_MASK) != DEBUG_STATUS_NO_CHANGE)
  258. {
  259. UniqueTargetState++;
  260. if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
  261. }
  262. }
  263. if (Flags & DEBUG_CES_ENGINE_OPTIONS) DbgEventPrint("DEBUG_CES_ENGINE_OPTIONS\n");
  264. if (Flags & DEBUG_CES_LOG_FILE) DbgEventPrint("DEBUG_CES_LOG_FILE\n");
  265. //if (Flags & DEBUG_CES_RADIX) DbgEventPrint("DEBUG_CES_RADIX\n");
  266. if (Flags & DEBUG_CES_EVENT_FILTERS) DbgEventPrint("DEBUG_CES_EVENT_FILTERS\n");
  267. if (Flags & DEBUG_CES_PROCESS_OPTIONS) DbgEventPrint("DEBUG_CES_PROCESS_OPTIONS\n");
  268. if (Flags & DEBUG_CES_EXTENSIONS) DbgEventPrint("DEBUG_CES_EXTENSIONS\n");
  269. }
  270. return S_OK;
  271. }
  272. STDMETHOD(ChangeSymbolState)(
  273. THIS_
  274. IN ULONG Flags,
  275. IN ULONG64 Argument
  276. )
  277. {
  278. DbgEventPrint("ChangeSymbolState(0x%lx, 0x%I64x)\n", Flags, Argument);
  279. gbSymbolsNotLoaded = gbSymbolsNotLoaded || (Flags & DEBUG_CSS_UNLOADS);
  280. UniqueTargetState++;
  281. if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
  282. return S_OK;
  283. }
  284. };
  285. typedef enum {
  286. NO_DISPATCHING,
  287. NEED_DISPATCH,
  288. DISPATCHED
  289. } MonitorState;
  290. LONG g_MonitorState = NO_DISPATCHING;
  291. PDEBUG_CLIENT g_pMonitorClient = NULL;
  292. BOOL g_MonitorThreadSet = FALSE;
  293. DWORD
  294. WINAPI
  295. EventMonitorThread(
  296. MonitorThreadParams *Params
  297. )
  298. {
  299. HRESULT hr = S_OK;
  300. PDEBUG_CLIENT Client;
  301. MonitorThreadParams ParamCopy;
  302. HMODULE hModule = NULL;
  303. TCHAR ModulePath[256];
  304. if (Params != NULL && Params->Client != NULL)
  305. {
  306. ASSERTMSG("EventMonitorThread not started with NEED_DISPATCH.\n", g_MonitorState == NEED_DISPATCH);
  307. if (GetModuleFileName(ghDllInst, ModulePath, sizeof(ModulePath)/sizeof(TCHAR)) == 0)
  308. {
  309. DbgPrint("EventMonitorThread failed to get Module path.\n");
  310. hr = S_FALSE;
  311. }
  312. else
  313. {
  314. // LoadLibrary so we have a reference while this thread lives
  315. hModule = LoadLibrary(ModulePath);
  316. if (hModule != ghDllInst)
  317. {
  318. DbgPrint("EventMonitorThread retrieving an hModule different from ghDllInst.\n");
  319. hr = S_FALSE;
  320. }
  321. }
  322. if (hr == S_OK)
  323. {
  324. Params->Client->AddRef();
  325. ParamCopy = *Params;
  326. Params->ParamsRead = TRUE;
  327. Params = &ParamCopy;
  328. hr = Params->Client->CreateClient(&Client);
  329. DbgPrint("EventMonitorThread created client %p.\n", Client);
  330. Params->Client->Release();
  331. if (hr == S_OK)
  332. {
  333. EventMonitorCallbacks *EventMonitor = new EventMonitorCallbacks;
  334. if (EventMonitor != NULL)
  335. {
  336. hr = Client->SetEventCallbacks(EventMonitor);
  337. if (hr == S_OK)
  338. {
  339. // Pass monitoring client back to caller.
  340. Client->AddRef();
  341. if (InterlockedCompareExchangePointer((PVOID*)&g_pMonitorClient, Client, NULL) == NULL &&
  342. InterlockedCompareExchange(&g_MonitorState, DISPATCHED, NEED_DISPATCH) == NEED_DISPATCH)
  343. {
  344. DbgPrint("EventMonitorThread dispatching for client %p.\n", Client);
  345. UniqueTargetState++;
  346. hr = Client->DispatchCallbacks(INFINITE);
  347. }
  348. else
  349. {
  350. // Another EventMonitorThread has already started or
  351. // ReleaseEventCallbacks has already been called; so,
  352. // release this client and
  353. // NULL global monitor client if we set it
  354. DbgPrint("EventMonitorThread exiting instead of dispatching for client %p.\n", Client);
  355. InterlockedCompareExchangePointer((PVOID*)&g_pMonitorClient, NULL, Client);
  356. Client->Release();
  357. }
  358. }
  359. else
  360. {
  361. OutputControl OutCtl(Client);
  362. OutCtl.OutErr("EventMonitorThread callbacks setup failed, %s.\n", pszHRESULT(hr));
  363. }
  364. EventMonitor->Release();
  365. }
  366. else
  367. {
  368. hr = E_OUTOFMEMORY;
  369. }
  370. Client->Release();
  371. }
  372. }
  373. }
  374. else
  375. {
  376. hr = E_INVALIDARG;
  377. }
  378. DbgPrint("EventMonitorThread calling ExitThread().\n");
  379. FreeLibraryAndExitThread(hModule, (DWORD)hr);
  380. }
  381. void
  382. ReleaseEventCallbacks(
  383. PDEBUG_CLIENT Client
  384. )
  385. {
  386. if (g_MonitorThreadSet)
  387. {
  388. if (InterlockedExchange(&g_MonitorState, NO_DISPATCHING) == DISPATCHED)
  389. {
  390. PDEBUG_CLIENT pMonitorClient;
  391. pMonitorClient = (PDEBUG_CLIENT)InterlockedExchangePointer((PVOID *)&g_pMonitorClient, NULL);
  392. ASSERTMSG("g_MonitorState shows g_pMonitorClient should be set.\n", pMonitorClient != NULL);
  393. if (Client == NULL)
  394. {
  395. if (GetDebugClient(&Client) != S_OK)
  396. {
  397. Client = pMonitorClient;
  398. Client->AddRef();
  399. }
  400. }
  401. else
  402. {
  403. Client->AddRef();
  404. }
  405. Client->ExitDispatch(pMonitorClient);
  406. pMonitorClient->Release();
  407. Client->Release();
  408. }
  409. g_MonitorThreadSet = FALSE;
  410. }
  411. }
  412. HRESULT
  413. SetEventCallbacks(
  414. PDEBUG_CLIENT Client
  415. )
  416. {
  417. HRESULT hr = S_FALSE;
  418. if (!g_MonitorThreadSet)
  419. {
  420. MonitorThreadParams NewThreadParams = { Client, FALSE };
  421. HANDLE hThread;
  422. DWORD ThreadID;
  423. LONG PrevMonitorState;
  424. PrevMonitorState = InterlockedExchange(&g_MonitorState, NEED_DISPATCH);
  425. ASSERTMSG("Previous EventMonitor thread was never shutdown properly.\n", PrevMonitorState != DISPATCHED);
  426. ASSERTMSG("Previous EventMonitor thread never completed setup.\n", PrevMonitorState != NEED_DISPATCH);
  427. g_pMonitorClient = NULL;
  428. hThread = CreateThread(NULL,
  429. 0,
  430. (LPTHREAD_START_ROUTINE)EventMonitorThread,
  431. &NewThreadParams,
  432. 0,
  433. &ThreadID);
  434. if (hThread)
  435. {
  436. // Default ExitCode to STILL_ACTIVE since it doesn't matter
  437. // if the Params were read before we started checking.
  438. DWORD ExitCode = STILL_ACTIVE;
  439. while (!NewThreadParams.ParamsRead)
  440. {
  441. ExitCode = 0;
  442. if (!GetExitCodeThread(hThread, &ExitCode))
  443. DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
  444. if (ExitCode != STILL_ACTIVE)
  445. {
  446. break;
  447. }
  448. SleepEx(10, TRUE);
  449. }
  450. if (ExitCode == STILL_ACTIVE)
  451. {
  452. hr = S_OK;
  453. g_MonitorThreadSet = TRUE;
  454. }
  455. CloseHandle(hThread);
  456. }
  457. }
  458. return hr;
  459. }
  460. HRESULT
  461. EventCallbacksReady(
  462. PDEBUG_CLIENT Client
  463. )
  464. {
  465. return (g_MonitorThreadSet && g_MonitorState == DISPATCHED) ? S_OK : S_FALSE;
  466. }