PageRenderTime 1261ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/extras/MonoDevelop.Debugger.Win32/CorApi2/debug/Debugger.cs

https://github.com/jfcantin/monodevelop
C# | 1034 lines | 783 code | 103 blank | 148 comment | 42 complexity | 653ddbf313df972af272978883df81ae MD5 | raw file
  1. //---------------------------------------------------------------------
  2. // This file is part of the CLR Managed Debugger (mdbg) Sample.
  3. //
  4. // Copyright (C) Microsoft Corporation. All rights reserved.
  5. //---------------------------------------------------------------------
  6. using System;
  7. using System.Collections;
  8. using System.Diagnostics;
  9. using System.Runtime.InteropServices;
  10. #if !MDBG_FAKE_COM
  11. using System.Runtime.InteropServices.ComTypes;
  12. #endif
  13. using System.Threading;
  14. using System.Text;
  15. using System.Security.Permissions;
  16. using System.Globalization;
  17. using System.Collections.Generic;
  18. using Microsoft.Samples.Debugging.CorDebug.NativeApi;
  19. using Microsoft.Win32.SafeHandles;
  20. [assembly:CLSCompliant(true)]
  21. [assembly:System.Runtime.InteropServices.ComVisible(false)]
  22. [assembly:SecurityPermission(SecurityAction.RequestMinimum, Unrestricted=true)]
  23. namespace Microsoft.Samples.Debugging.CorDebug
  24. {
  25. /**
  26. * Wraps the native CLR Debugger.
  27. * Note that we don't derive the class from WrapperBase, becuase this
  28. * class will never be returned in any callback.
  29. */
  30. public sealed class CorDebugger : MarshalByRefObject
  31. {
  32. private const int MaxVersionStringLength = 256; // == MAX_PATH
  33. public const int CREATE_REDIRECT_STD = 0x40000000;
  34. public static string GetDebuggerVersionFromFile(string pathToExe)
  35. {
  36. Debug.Assert( !string.IsNullOrEmpty(pathToExe) );
  37. if( string.IsNullOrEmpty(pathToExe) )
  38. throw new ArgumentException("Value cannot be null or empty.", "pathToExe");
  39. int neededSize;
  40. StringBuilder sb = new StringBuilder(MaxVersionStringLength);
  41. NativeMethods.GetRequestedRuntimeVersion(pathToExe, sb, sb.Capacity, out neededSize);
  42. return sb.ToString();
  43. }
  44. public static string GetDebuggerVersionFromPid(int pid)
  45. {
  46. using(ProcessSafeHandle ph = NativeMethods.OpenProcess((int)(NativeMethods.ProcessAccessOptions.PROCESS_VM_READ |
  47. NativeMethods.ProcessAccessOptions.PROCESS_QUERY_INFORMATION |
  48. NativeMethods.ProcessAccessOptions.PROCESS_DUP_HANDLE |
  49. NativeMethods.ProcessAccessOptions.SYNCHRONIZE),
  50. false, // inherit handle
  51. pid) )
  52. {
  53. if( ph.IsInvalid )
  54. throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
  55. int neededSize;
  56. StringBuilder sb = new StringBuilder(MaxVersionStringLength);
  57. NativeMethods.GetVersionFromProcess(ph, sb, sb.Capacity, out neededSize);
  58. return sb.ToString();
  59. }
  60. }
  61. public static string GetDefaultDebuggerVersion()
  62. {
  63. int size;
  64. NativeMethods.GetCORVersion(null,0,out size);
  65. Debug.Assert(size>0);
  66. StringBuilder sb = new StringBuilder(size);
  67. int hr = NativeMethods.GetCORVersion(sb,sb.Capacity,out size);
  68. Marshal.ThrowExceptionForHR(hr);
  69. return sb.ToString();
  70. }
  71. /// <summary>Creates a debugger wrapper from Guid.</summary>
  72. public CorDebugger(Guid debuggerGuid)
  73. {
  74. ICorDebug rawDebuggingAPI;
  75. NativeMethods.CoCreateInstance(ref debuggerGuid,
  76. IntPtr.Zero, // pUnkOuter
  77. 1, // CLSCTX_INPROC_SERVER
  78. ref NativeMethods.IIDICorDebug,
  79. out rawDebuggingAPI);
  80. InitFromICorDebug(rawDebuggingAPI);
  81. }
  82. /// <summary>Creates a debugger interface that is able debug requested verison of CLR</summary>
  83. /// <param name="debuggerVerison">Version number of the debugging interface.</param>
  84. /// <remarks>The version number is usually retrieved either by calling one of following mscoree functions:
  85. /// GetCorVerison, GetRequestedRuntimeVersion or GetVersionFromProcess.</remarks>
  86. public CorDebugger (string debuggerVersion)
  87. {
  88. InitFromVersion(debuggerVersion);
  89. }
  90. ~CorDebugger()
  91. {
  92. if(m_debugger!=null)
  93. try
  94. {
  95. Terminate();
  96. }
  97. catch
  98. {
  99. // sometimes we cannot terminate because GC collects object in wrong
  100. // order. But since the whole process is shutting down, we really
  101. // don't care.
  102. // TODO: we need to define IDisposable pattern to CorDebug so that we are able to
  103. // dispose stuff in correct order.
  104. }
  105. }
  106. #if CORAPI_EXPOSE_RAW_INTERFACES
  107. [CLSCompliant(false)]
  108. public ICorDebug Raw
  109. {
  110. get
  111. {
  112. return m_debugger;
  113. }
  114. }
  115. #endif
  116. /**
  117. * Closes the debugger. After this method is called, it is an error
  118. * to call any other methods on this object.
  119. */
  120. public void Terminate ()
  121. {
  122. Debug.Assert(m_debugger!=null);
  123. ICorDebug d= m_debugger;
  124. m_debugger = null;
  125. d.Terminate ();
  126. }
  127. /**
  128. * Specify the callback object to use for managed events.
  129. */
  130. internal void SetManagedHandler (ICorDebugManagedCallback managedCallback)
  131. {
  132. m_debugger.SetManagedHandler (managedCallback);
  133. }
  134. /**
  135. * Specify the callback object to use for unmanaged events.
  136. */
  137. internal void SetUnmanagedHandler (ICorDebugUnmanagedCallback nativeCallback)
  138. {
  139. m_debugger.SetUnmanagedHandler (nativeCallback);
  140. }
  141. /**
  142. * Launch a process under the control of the debugger.
  143. *
  144. * Parameters are the same as the Win32 CreateProcess call.
  145. */
  146. public CorProcess CreateProcess (
  147. String applicationName,
  148. String commandLine
  149. )
  150. {
  151. return CreateProcess (applicationName, commandLine, ".");
  152. }
  153. /**
  154. * Launch a process under the control of the debugger.
  155. *
  156. * Parameters are the same as the Win32 CreateProcess call.
  157. */
  158. public CorProcess CreateProcess (
  159. String applicationName,
  160. String commandLine,
  161. String currentDirectory
  162. )
  163. {
  164. return CreateProcess (applicationName, commandLine, currentDirectory, null, 0);
  165. }
  166. /**
  167. * Launch a process under the control of the debugger.
  168. *
  169. * Parameters are the same as the Win32 CreateProcess call.
  170. */
  171. public CorProcess CreateProcess (
  172. String applicationName,
  173. String commandLine,
  174. String currentDirectory,
  175. IDictionary<string,string> environment
  176. )
  177. {
  178. return CreateProcess (applicationName, commandLine, currentDirectory, environment, 0);
  179. }
  180. /**
  181. * Launch a process under the control of the debugger.
  182. *
  183. * Parameters are the same as the Win32 CreateProcess call.
  184. */
  185. public CorProcess CreateProcess (
  186. String applicationName,
  187. String commandLine,
  188. String currentDirectory,
  189. IDictionary<string,string> environment,
  190. int flags
  191. )
  192. {
  193. PROCESS_INFORMATION pi = new PROCESS_INFORMATION ();
  194. STARTUPINFO si = new STARTUPINFO ();
  195. si.cb = Marshal.SizeOf(si);
  196. // initialize safe handles
  197. SafeFileHandle outReadPipe = null, errorReadPipe = null;
  198. if ((flags & CREATE_REDIRECT_STD) != 0) {
  199. CreateHandles (si, out outReadPipe, out errorReadPipe);
  200. flags &= ~CREATE_REDIRECT_STD;
  201. }
  202. else {
  203. si.hStdInput = new SafeFileHandle (IntPtr.Zero, false);
  204. si.hStdOutput = new SafeFileHandle (IntPtr.Zero, false);
  205. si.hStdError = new SafeFileHandle (IntPtr.Zero, false);
  206. }
  207. IntPtr env = IntPtr.Zero;
  208. if (environment != null) {
  209. string senv = null;
  210. foreach (KeyValuePair<string, string> var in environment) {
  211. senv += var.Key + "=" + var.Value + "\0";
  212. }
  213. senv += "\0";
  214. env = Marshal.StringToHGlobalAnsi (senv);
  215. }
  216. CorProcess ret;
  217. //constrained execution region (Cer)
  218. System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
  219. try
  220. {
  221. }
  222. finally
  223. {
  224. ret = CreateProcess (
  225. applicationName,
  226. commandLine,
  227. null,
  228. null,
  229. true, // inherit handles
  230. flags, // creation flags
  231. env, // environment
  232. currentDirectory,
  233. si, // startup info
  234. ref pi, // process information
  235. CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS);
  236. NativeMethods.CloseHandle (pi.hProcess);
  237. NativeMethods.CloseHandle (pi.hThread);
  238. }
  239. if (env != IntPtr.Zero)
  240. Marshal.FreeHGlobal (env);
  241. if (outReadPipe != null) {
  242. // Close pipe handles (do not continue to modify the parent).
  243. // You need to make sure that no handles to the write end of the
  244. // output pipe are maintained in this process or else the pipe will
  245. // not close when the child process exits and the ReadFile will hang.
  246. si.hStdInput.Close ();
  247. si.hStdOutput.Close ();
  248. si.hStdError.Close ();
  249. ret.TrackStdOutput (outReadPipe, errorReadPipe);
  250. }
  251. return ret;
  252. }
  253. void CreateHandles (STARTUPINFO si, out SafeFileHandle outReadPipe, out SafeFileHandle errorReadPipe)
  254. {
  255. si.dwFlags |= 0x00000100; /*STARTF_USESTDHANDLES*/
  256. SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES ();
  257. sa.bInheritHandle = true;
  258. IntPtr curProc = NativeMethods.GetCurrentProcess ();
  259. SafeFileHandle outWritePipe, outReadPipeTmp;
  260. if (!NativeMethods.CreatePipe (out outReadPipeTmp, out outWritePipe, sa, 0))
  261. throw new Exception ("Pipe creation failed");
  262. // Create the child error pipe.
  263. SafeFileHandle errorWritePipe, errorReadPipeTmp;
  264. if (!NativeMethods.CreatePipe (out errorReadPipeTmp, out errorWritePipe, sa, 0))
  265. throw new Exception ("Pipe creation failed");
  266. // Create new output read and error read handles. Set
  267. // the Properties to FALSE. Otherwise, the child inherits the
  268. // properties and, as a result, non-closeable handles to the pipes
  269. // are created.
  270. if (!NativeMethods.DuplicateHandle (curProc, outReadPipeTmp, curProc, out outReadPipe, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS))
  271. throw new Exception ("Pipe creation failed");
  272. if (!NativeMethods.DuplicateHandle (curProc, errorReadPipeTmp, curProc, out errorReadPipe, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS))
  273. throw new Exception ("Pipe creation failed");
  274. NativeMethods.CloseHandle (curProc);
  275. // Close inheritable copies of the handles you do not want to be
  276. // inherited.
  277. outReadPipeTmp.Close ();
  278. errorReadPipeTmp.Close ();
  279. si.hStdInput = NativeMethods.GetStdHandle (NativeMethods.STD_INPUT_HANDLE);
  280. si.hStdOutput = outWritePipe;
  281. si.hStdError = errorWritePipe;
  282. }
  283. /**
  284. * Launch a process under the control of the debugger.
  285. *
  286. * Parameters are the same as the Win32 CreateProcess call.
  287. *
  288. * The caller should remember to execute:
  289. *
  290. * Microsoft.Win32.Interop.Windows.CloseHandle (
  291. * processInformation.hProcess);
  292. *
  293. * after CreateProcess returns.
  294. */
  295. [CLSCompliant(false)]
  296. public CorProcess CreateProcess (
  297. String applicationName,
  298. String commandLine,
  299. SECURITY_ATTRIBUTES processAttributes,
  300. SECURITY_ATTRIBUTES threadAttributes,
  301. bool inheritHandles,
  302. int creationFlags,
  303. IntPtr environment, // <strip>@TODO fix the environment</strip>
  304. String currentDirectory,
  305. STARTUPINFO startupInfo,
  306. ref PROCESS_INFORMATION processInformation,
  307. CorDebugCreateProcessFlags debuggingFlags)
  308. {
  309. /*
  310. * If commandLine is: <c:\a b\a arg1 arg2> and c:\a.exe does not exist,
  311. * then without this logic, "c:\a b\a.exe" would be tried next.
  312. * To prevent this ambiguity, this forces the user to quote if the path
  313. * has spaces in it: <"c:\a b\a" arg1 arg2>
  314. */
  315. if(null == applicationName && !commandLine.StartsWith("\""))
  316. {
  317. int firstSpace = commandLine.IndexOf(" ");
  318. if(firstSpace != -1)
  319. commandLine = String.Format(CultureInfo.InvariantCulture, "\"{0}\" {1}", commandLine.Substring(0,firstSpace), commandLine.Substring(firstSpace, commandLine.Length-firstSpace));
  320. }
  321. ICorDebugProcess proc = null;
  322. m_debugger.CreateProcess (
  323. applicationName,
  324. commandLine,
  325. processAttributes,
  326. threadAttributes,
  327. inheritHandles ? 1 : 0,
  328. (uint) creationFlags,
  329. environment,
  330. currentDirectory,
  331. startupInfo,
  332. processInformation,
  333. debuggingFlags,
  334. out proc);
  335. return CorProcess.GetCorProcess(proc);
  336. }
  337. /**
  338. * Attach to an active process
  339. */
  340. public CorProcess DebugActiveProcess (int processId, bool win32Attach)
  341. {
  342. ICorDebugProcess proc = null;
  343. m_debugger.DebugActiveProcess ((uint)processId, win32Attach ? 1 : 0, out proc);
  344. return CorProcess.GetCorProcess(proc);
  345. }
  346. /**
  347. * Enumerate all processes currently being debugged.
  348. */
  349. public IEnumerable Processes
  350. {
  351. get
  352. {
  353. ICorDebugProcessEnum eproc = null;
  354. m_debugger.EnumerateProcesses (out eproc);
  355. return new CorProcessEnumerator (eproc);
  356. }
  357. }
  358. /**
  359. * Get the Process object for the given PID.
  360. */
  361. public CorProcess GetProcess (int processId)
  362. {
  363. ICorDebugProcess proc = null;
  364. m_debugger.GetProcess ((uint) processId, out proc);
  365. return CorProcess.GetCorProcess(proc);
  366. }
  367. ////////////////////////////////////////////////////////////////////////////////
  368. //
  369. // CorDebugger private implement part
  370. //
  371. ////////////////////////////////////////////////////////////////////////////////
  372. // called by constructors during initialization
  373. private void InitFromVersion(string debuggerVersion)
  374. {
  375. if( debuggerVersion.StartsWith("v1") )
  376. {
  377. throw new ArgumentException( "Can't debug a version 1 CLR process (\"" + debuggerVersion +
  378. "\"). Run application in a version 2 CLR, or use a version 1 debugger instead." );
  379. }
  380. ICorDebug rawDebuggingAPI;
  381. #if MDBG_FAKE_COM
  382. // TODO: Ideally, there wouldn't be any difference in the corapi code for MDBG_FAKE_COM.
  383. // This would require puting this initialization logic into the wrapper and interop assembly, which doesn't seem right.
  384. // We should also release this pUnk, but doing that here would be difficult and we aren't done with it until
  385. // we shutdown anyway.
  386. IntPtr pUnk = NativeMethods.CreateDebuggingInterfaceFromVersion((int)CorDebuggerVersion.Whidbey, debuggerVersion);
  387. rawDebuggingAPI = new NativeApi.CorDebugClass(pUnk);
  388. #else
  389. int apiVersion = debuggerVersion.StartsWith ("v4") ? 4 : 3;
  390. rawDebuggingAPI = NativeMethods.CreateDebuggingInterfaceFromVersion (apiVersion, debuggerVersion);
  391. #endif
  392. InitFromICorDebug(rawDebuggingAPI);
  393. }
  394. private void InitFromICorDebug(ICorDebug rawDebuggingAPI)
  395. {
  396. Debug.Assert(rawDebuggingAPI!=null);
  397. if( rawDebuggingAPI==null )
  398. throw new ArgumentException("Cannot be null.","rawDebugggingAPI");
  399. m_debugger = rawDebuggingAPI;
  400. m_debugger.Initialize ();
  401. m_debugger.SetManagedHandler (new ManagedCallback(this));
  402. #if MDBG_FEATURE_INTEROP
  403. try
  404. {
  405. m_debugger.SetUnmanagedHandler(new UnmanagedCallback(this));
  406. }
  407. catch(NotImplementedException)
  408. {
  409. }
  410. #endif
  411. }
  412. /**
  413. * Helper for invoking events. Checks to make sure that handlers
  414. * are hooked up to a handler before the handler is invoked.
  415. *
  416. * We want to allow maximum flexibility by our callers. As such,
  417. * we don't require that they call <code>e.Controller.Continue</code>,
  418. * nor do we require that this class call it. <b>Someone</b> needs
  419. * to call it, however.
  420. *
  421. * Consequently, if an exception is thrown and the process is stopped,
  422. * the process is continued automatically.
  423. */
  424. void InternalFireEvent(ManagedCallbackType callbackType,CorEventArgs e)
  425. {
  426. CorProcess owner;
  427. CorController c = e.Controller;
  428. Debug.Assert(c!=null);
  429. if(c is CorProcess)
  430. owner = (CorProcess)c ;
  431. else
  432. {
  433. Debug.Assert(c is CorAppDomain);
  434. owner = (c as CorAppDomain).Process;
  435. }
  436. Debug.Assert(owner!=null);
  437. try
  438. {
  439. owner.DispatchEvent(callbackType,e);
  440. }
  441. finally
  442. {
  443. if(e.Continue)
  444. {
  445. #if MDBG_FEATURE_INTEROP
  446. // this is special case for interop debugging
  447. // where we continue from OOB native event in which
  448. // case we have to call Continue with true (OOBound).
  449. if( (e is CorNativeStopEventArgs)
  450. && (e as CorNativeStopEventArgs).IsOutOfBand )
  451. e.Controller.Continue(true);
  452. else
  453. #endif
  454. e.Controller.Continue(false);
  455. }
  456. }
  457. }
  458. ////////////////////////////////////////////////////////////////////////////////
  459. //
  460. // ManagedCallback
  461. //
  462. ////////////////////////////////////////////////////////////////////////////////
  463. /**
  464. * This is the object that gets passed to the debugger. It's
  465. * the intermediate "source" of the events, which repackages
  466. * the event arguments into a more approprate form and forwards
  467. * the call to the appropriate function.
  468. */
  469. private class ManagedCallback : ICorDebugManagedCallback, ICorDebugManagedCallback2
  470. {
  471. public ManagedCallback (CorDebugger outer)
  472. {
  473. m_outer = outer;
  474. }
  475. void ICorDebugManagedCallback.Breakpoint (ICorDebugAppDomain appDomain,
  476. ICorDebugThread thread,
  477. ICorDebugBreakpoint breakpoint)
  478. {
  479. m_outer.InternalFireEvent(ManagedCallbackType.OnBreakpoint,
  480. new CorBreakpointEventArgs (appDomain==null?null:new CorAppDomain(appDomain),
  481. thread==null?null:new CorThread (thread),
  482. breakpoint==null?null:new CorFunctionBreakpoint ((ICorDebugFunctionBreakpoint)breakpoint)
  483. ));
  484. }
  485. void ICorDebugManagedCallback.StepComplete ( ICorDebugAppDomain appDomain,
  486. ICorDebugThread thread,
  487. ICorDebugStepper stepper,
  488. CorDebugStepReason stepReason)
  489. {
  490. m_outer.InternalFireEvent(ManagedCallbackType.OnStepComplete,
  491. new CorStepCompleteEventArgs (appDomain==null?null:new CorAppDomain (appDomain),
  492. thread==null?null:new CorThread (thread),
  493. stepper==null?null:new CorStepper(stepper),
  494. stepReason));
  495. }
  496. void ICorDebugManagedCallback.Break (
  497. ICorDebugAppDomain appDomain,
  498. ICorDebugThread thread)
  499. {
  500. m_outer.InternalFireEvent(ManagedCallbackType.OnBreak,
  501. new CorThreadEventArgs (
  502. appDomain==null?null:new CorAppDomain (appDomain),
  503. thread==null?null:new CorThread (thread)));
  504. }
  505. void ICorDebugManagedCallback.Exception (
  506. ICorDebugAppDomain appDomain,
  507. ICorDebugThread thread,
  508. int unhandled)
  509. {
  510. m_outer.InternalFireEvent(ManagedCallbackType.OnException,
  511. new CorExceptionEventArgs (
  512. appDomain==null?null:new CorAppDomain (appDomain),
  513. thread==null?null:new CorThread (thread),
  514. !(unhandled == 0)));
  515. }
  516. /* pass false if ``unhandled'' is 0 -- mapping TRUE to true, etc. */
  517. void ICorDebugManagedCallback.EvalComplete (
  518. ICorDebugAppDomain appDomain,
  519. ICorDebugThread thread,
  520. ICorDebugEval eval)
  521. {
  522. m_outer.InternalFireEvent(ManagedCallbackType.OnEvalComplete,
  523. new CorEvalEventArgs (
  524. appDomain==null?null:new CorAppDomain(appDomain),
  525. thread==null?null:new CorThread (thread),
  526. eval==null?null:new CorEval(eval)));
  527. }
  528. void ICorDebugManagedCallback.EvalException (
  529. ICorDebugAppDomain appDomain,
  530. ICorDebugThread thread,
  531. ICorDebugEval eval)
  532. {
  533. m_outer.InternalFireEvent(ManagedCallbackType.OnEvalException,
  534. new CorEvalEventArgs (
  535. appDomain==null?null:new CorAppDomain (appDomain),
  536. thread==null?null:new CorThread (thread),
  537. eval==null?null:new CorEval (eval)));
  538. }
  539. void ICorDebugManagedCallback.CreateProcess (
  540. ICorDebugProcess process)
  541. {
  542. m_outer.InternalFireEvent(ManagedCallbackType.OnCreateProcess,
  543. new CorProcessEventArgs (
  544. process==null?null:CorProcess.GetCorProcess(process)));
  545. }
  546. void ICorDebugManagedCallback.ExitProcess (
  547. ICorDebugProcess process)
  548. {
  549. m_outer.InternalFireEvent(ManagedCallbackType.OnProcessExit,
  550. new CorProcessEventArgs (
  551. process==null?null:CorProcess.GetCorProcess(process)));
  552. }
  553. void ICorDebugManagedCallback.CreateThread (
  554. ICorDebugAppDomain appDomain,
  555. ICorDebugThread thread)
  556. {
  557. m_outer.InternalFireEvent(ManagedCallbackType.OnCreateThread,
  558. new CorThreadEventArgs (
  559. appDomain==null?null:new CorAppDomain(appDomain),
  560. thread==null?null:new CorThread (thread)));
  561. }
  562. void ICorDebugManagedCallback.ExitThread (
  563. ICorDebugAppDomain appDomain,
  564. ICorDebugThread thread)
  565. {
  566. m_outer.InternalFireEvent(ManagedCallbackType.OnThreadExit,
  567. new CorThreadEventArgs (
  568. appDomain==null?null:new CorAppDomain(appDomain),
  569. thread==null?null:new CorThread (thread)));
  570. }
  571. void ICorDebugManagedCallback.LoadModule (
  572. ICorDebugAppDomain appDomain,
  573. ICorDebugModule managedModule)
  574. {
  575. m_outer.InternalFireEvent(ManagedCallbackType.OnModuleLoad,
  576. new CorModuleEventArgs (
  577. appDomain==null?null:new CorAppDomain(appDomain),
  578. managedModule==null?null:new CorModule (managedModule)));
  579. }
  580. void ICorDebugManagedCallback.UnloadModule (
  581. ICorDebugAppDomain appDomain,
  582. ICorDebugModule managedModule)
  583. {
  584. m_outer.InternalFireEvent(ManagedCallbackType.OnModuleUnload,
  585. new CorModuleEventArgs (
  586. appDomain==null?null:new CorAppDomain (appDomain),
  587. managedModule==null?null:new CorModule (managedModule)));
  588. }
  589. void ICorDebugManagedCallback.LoadClass (
  590. ICorDebugAppDomain appDomain,
  591. ICorDebugClass c)
  592. {
  593. m_outer.InternalFireEvent(ManagedCallbackType.OnClassLoad,
  594. new CorClassEventArgs (
  595. appDomain==null?null:new CorAppDomain(appDomain),
  596. c==null?null:new CorClass (c)));
  597. }
  598. void ICorDebugManagedCallback.UnloadClass (
  599. ICorDebugAppDomain appDomain,
  600. ICorDebugClass c)
  601. {
  602. m_outer.InternalFireEvent(ManagedCallbackType.OnClassUnload,
  603. new CorClassEventArgs (
  604. appDomain==null?null:new CorAppDomain(appDomain),
  605. c==null?null:new CorClass (c)));
  606. }
  607. void ICorDebugManagedCallback.DebuggerError (
  608. ICorDebugProcess process,
  609. int errorHR,
  610. uint errorCode)
  611. {
  612. m_outer.InternalFireEvent(ManagedCallbackType.OnDebuggerError,
  613. new CorDebuggerErrorEventArgs (
  614. process==null?null:CorProcess.GetCorProcess (process),
  615. errorHR,
  616. (int) errorCode));
  617. }
  618. void ICorDebugManagedCallback.LogMessage (
  619. ICorDebugAppDomain appDomain,
  620. ICorDebugThread thread,
  621. int level,
  622. string logSwitchName,
  623. string message)
  624. {
  625. m_outer.InternalFireEvent(ManagedCallbackType.OnLogMessage,
  626. new CorLogMessageEventArgs (
  627. appDomain==null?null:new CorAppDomain(appDomain),
  628. thread==null?null:new CorThread (thread),
  629. level, logSwitchName, message));
  630. }
  631. void ICorDebugManagedCallback.LogSwitch (
  632. ICorDebugAppDomain appDomain,
  633. ICorDebugThread thread,
  634. int level,
  635. uint reason,
  636. string logSwitchName,
  637. string parentName)
  638. {
  639. m_outer.InternalFireEvent(ManagedCallbackType.OnLogSwitch,
  640. new CorLogSwitchEventArgs (
  641. appDomain==null?null:new CorAppDomain(appDomain),
  642. thread==null?null:new CorThread (thread),
  643. level, (int) reason, logSwitchName, parentName));
  644. }
  645. void ICorDebugManagedCallback.CreateAppDomain (
  646. ICorDebugProcess process,
  647. ICorDebugAppDomain appDomain)
  648. {
  649. m_outer.InternalFireEvent(ManagedCallbackType.OnCreateAppDomain,
  650. new CorAppDomainEventArgs (
  651. process==null?null:CorProcess.GetCorProcess(process),
  652. appDomain==null?null:new CorAppDomain(appDomain)));
  653. }
  654. void ICorDebugManagedCallback.ExitAppDomain (
  655. ICorDebugProcess process,
  656. ICorDebugAppDomain appDomain)
  657. {
  658. m_outer.InternalFireEvent(ManagedCallbackType.OnAppDomainExit,
  659. new CorAppDomainEventArgs (
  660. process==null?null:CorProcess.GetCorProcess(process),
  661. appDomain==null?null:new CorAppDomain (appDomain)));
  662. }
  663. void ICorDebugManagedCallback.LoadAssembly (
  664. ICorDebugAppDomain appDomain,
  665. ICorDebugAssembly assembly)
  666. {
  667. m_outer.InternalFireEvent(ManagedCallbackType.OnAssemblyLoad,
  668. new CorAssemblyEventArgs (
  669. appDomain==null?null:new CorAppDomain (appDomain),
  670. assembly==null?null:new CorAssembly (assembly)));
  671. }
  672. void ICorDebugManagedCallback.UnloadAssembly (
  673. ICorDebugAppDomain appDomain,
  674. ICorDebugAssembly assembly)
  675. {
  676. m_outer.InternalFireEvent(ManagedCallbackType.OnAssemblyUnload,
  677. new CorAssemblyEventArgs (
  678. appDomain==null?null:new CorAppDomain(appDomain),
  679. assembly==null?null:new CorAssembly (assembly)));
  680. }
  681. void ICorDebugManagedCallback.ControlCTrap (ICorDebugProcess process)
  682. {
  683. m_outer.InternalFireEvent(ManagedCallbackType.OnControlCTrap,
  684. new CorProcessEventArgs (
  685. process==null?null:CorProcess.GetCorProcess(process)
  686. ));
  687. }
  688. void ICorDebugManagedCallback.NameChange (
  689. ICorDebugAppDomain appDomain,
  690. ICorDebugThread thread)
  691. {
  692. m_outer.InternalFireEvent(ManagedCallbackType.OnNameChange,
  693. new CorThreadEventArgs (
  694. appDomain==null?null:new CorAppDomain(appDomain),
  695. thread==null?null:new CorThread (thread)));
  696. }
  697. // TODO: Enable support for dynamic modules (reflection emit) with FAKE_COM?
  698. // Rotor doesn't have ISymbolBinder2 or IStream, so we may have to add them
  699. void ICorDebugManagedCallback.UpdateModuleSymbols (
  700. ICorDebugAppDomain appDomain,
  701. ICorDebugModule managedModule,
  702. #if MDBG_FAKE_COM
  703. IntPtr stream)
  704. #else
  705. IStream stream)
  706. #endif
  707. {
  708. m_outer.InternalFireEvent(ManagedCallbackType.OnUpdateModuleSymbols,
  709. new CorUpdateModuleSymbolsEventArgs(
  710. appDomain==null?null:new CorAppDomain(appDomain),
  711. managedModule==null?null:new CorModule (managedModule),
  712. stream));
  713. }
  714. void ICorDebugManagedCallback.EditAndContinueRemap(
  715. ICorDebugAppDomain appDomain,
  716. ICorDebugThread thread,
  717. ICorDebugFunction managedFunction,
  718. int isAccurate)
  719. {
  720. Debug.Assert(false); //OBSOLETE callback
  721. }
  722. void ICorDebugManagedCallback.BreakpointSetError(
  723. ICorDebugAppDomain appDomain,
  724. ICorDebugThread thread,
  725. ICorDebugBreakpoint breakpoint,
  726. UInt32 errorCode)
  727. {
  728. m_outer.InternalFireEvent(ManagedCallbackType.OnBreakpointSetError,
  729. new CorBreakpointSetErrorEventArgs(
  730. appDomain==null?null:new CorAppDomain(appDomain),
  731. thread==null?null:new CorThread(thread),
  732. null, // <strip>@TODO breakpoint==null?null:new CorBreakpoint(breakpoint),</strip>
  733. (int)errorCode));
  734. }
  735. void ICorDebugManagedCallback2.FunctionRemapOpportunity(ICorDebugAppDomain appDomain,
  736. ICorDebugThread thread,
  737. ICorDebugFunction oldFunction,
  738. ICorDebugFunction newFunction,
  739. uint oldILoffset)
  740. {
  741. m_outer.InternalFireEvent(ManagedCallbackType.OnFunctionRemapOpportunity,
  742. new CorFunctionRemapOpportunityEventArgs(
  743. appDomain==null?null:new CorAppDomain(appDomain),
  744. thread==null?null:new CorThread (thread),
  745. oldFunction==null?null:new CorFunction(oldFunction),
  746. newFunction==null?null:new CorFunction(newFunction),
  747. (int)oldILoffset
  748. ));
  749. }
  750. void ICorDebugManagedCallback2.FunctionRemapComplete(ICorDebugAppDomain appDomain,
  751. ICorDebugThread thread,
  752. ICorDebugFunction managedFunction)
  753. {
  754. m_outer.InternalFireEvent(ManagedCallbackType.OnFunctionRemapComplete,
  755. new CorFunctionRemapCompleteEventArgs(
  756. appDomain==null?null:new CorAppDomain(appDomain),
  757. thread==null?null:new CorThread (thread),
  758. managedFunction==null?null:new CorFunction(managedFunction)
  759. ));
  760. }
  761. void ICorDebugManagedCallback2.CreateConnection(ICorDebugProcess process,uint connectionId, ref ushort connectionName)
  762. {
  763. // <strip>@TODO - </strip>Not Implemented
  764. Debug.Assert(false);
  765. }
  766. void ICorDebugManagedCallback2.ChangeConnection(ICorDebugProcess process,uint connectionId)
  767. {
  768. // <strip>@TODO -</strip> Not Implemented
  769. Debug.Assert(false);
  770. }
  771. void ICorDebugManagedCallback2.DestroyConnection(ICorDebugProcess process,uint connectionId)
  772. {
  773. // <strip>@TODO - </strip>Not Implemented
  774. Debug.Assert(false);
  775. }
  776. void ICorDebugManagedCallback2.Exception(ICorDebugAppDomain ad, ICorDebugThread thread,
  777. ICorDebugFrame frame, uint offset,
  778. CorDebugExceptionCallbackType eventType, uint flags) //@TODO flags should not be UINT
  779. {
  780. m_outer.InternalFireEvent(ManagedCallbackType.OnException2,
  781. new CorException2EventArgs(
  782. ad==null?null:new CorAppDomain(ad),
  783. thread==null?null:new CorThread (thread),
  784. frame==null?null:new CorFrame(frame),
  785. (int)offset,
  786. eventType,
  787. (int)flags
  788. ));
  789. }
  790. void ICorDebugManagedCallback2.ExceptionUnwind(ICorDebugAppDomain ad, ICorDebugThread thread,
  791. CorDebugExceptionUnwindCallbackType eventType, uint flags)
  792. {
  793. m_outer.InternalFireEvent(ManagedCallbackType.OnExceptionUnwind2,
  794. new CorExceptionUnwind2EventArgs(
  795. ad==null?null:new CorAppDomain(ad),
  796. thread==null?null:new CorThread (thread),
  797. eventType,
  798. (int)flags
  799. ));
  800. }
  801. // Get process from controller
  802. private CorProcess GetProcessFromController(ICorDebugController pController)
  803. {
  804. CorProcess p;
  805. ICorDebugProcess p2 = pController as ICorDebugProcess;
  806. if (p2 != null)
  807. {
  808. p = CorProcess.GetCorProcess(p2);
  809. }
  810. else
  811. {
  812. ICorDebugAppDomain a2 = (ICorDebugAppDomain) pController;
  813. p = new CorAppDomain(a2).Process;
  814. }
  815. return p;
  816. }
  817. void ICorDebugManagedCallback2.MDANotification(ICorDebugController pController,
  818. ICorDebugThread thread,
  819. ICorDebugMDA pMDA)
  820. {
  821. CorMDA c = new CorMDA(pMDA);
  822. string szName = c.Name;
  823. CorDebugMDAFlags f = c.Flags;
  824. CorProcess p = GetProcessFromController(pController);
  825. m_outer.InternalFireEvent(ManagedCallbackType.OnMDANotification,
  826. new CorMDAEventArgs (c,
  827. thread==null?null:new CorThread (thread),
  828. p));
  829. }
  830. private CorDebugger m_outer;
  831. }
  832. #if MDBG_FEATURE_INTEROP
  833. private class UnmanagedCallback : ICorDebugUnmanagedCallback
  834. {
  835. public UnmanagedCallback (CorDebugger outer)
  836. {
  837. Debug.Assert(outer!=null);
  838. m_outer = outer;
  839. }
  840. #if !FIXED_BUG21115 //<strip>@TODO remove once we'll be able to call Continue from Win32 callbakck.</strip>
  841. private struct Win32NativeEvent
  842. {
  843. public Win32NativeEvent(CorProcess process,CorDebugger outer,int threadId,DEBUG_EVENT debugEvent)
  844. {
  845. Debug.Assert(process!=null);
  846. Debug.Assert(outer!=null);
  847. m_process = process;
  848. m_outer = outer;
  849. m_threadId = threadId;
  850. m_debugEvent = debugEvent;
  851. }
  852. private CorProcess m_process;
  853. private CorDebugger m_outer;
  854. private int m_threadId;
  855. private DEBUG_EVENT m_debugEvent;
  856. // This is always dispatched on the W32ET. That thread can't do anything useful so we
  857. // hand off to another thread.
  858. static public void DispatchEvent(Win32NativeEvent event_)
  859. {
  860. // If Mdbg has mutliple debuggees, they'll share this.
  861. lock(g_lock)
  862. {
  863. if( g_workToDo == null )
  864. {
  865. g_workToDo = new AutoResetEvent(false);
  866. g_callWorkDone = new AutoResetEvent(true);
  867. Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Win32NativeEvent.Dispatch));
  868. t.IsBackground = true;
  869. t.Start();
  870. }
  871. }
  872. g_callWorkDone.WaitOne();
  873. g_event = event_;
  874. g_workToDo.Set();
  875. // We now return without waiting for the DispatchThread to finish
  876. }
  877. // Statics
  878. static private object g_lock = new object();
  879. static private AutoResetEvent g_callWorkDone=null;
  880. static private AutoResetEvent g_workToDo = null;
  881. static private Win32NativeEvent g_event;
  882. // This is called on a separate thread from the W32ET. MDbg shares this thread across all debuggees
  883. // (in the same way ICorDebug shares the RCET)
  884. public static void Dispatch()
  885. {
  886. while(true)
  887. {
  888. try
  889. {
  890. g_workToDo.WaitOne();
  891. g_event.m_outer.InternalFireEvent(ManagedCallbackType.OnNativeStop,
  892. new CorNativeStopEventArgs (g_event.m_process,
  893. g_event.m_threadId,
  894. g_event.m_debugEvent,
  895. false /*not OOB event*/));
  896. }
  897. finally
  898. {
  899. g_callWorkDone.Set();
  900. }
  901. }
  902. }
  903. }
  904. #endif
  905. void Microsoft.Samples.Debugging.CorDebug.NativeApi.ICorDebugUnmanagedCallback.DebugEvent(DEBUG_EVENT debugEvent, int isOutOfBand)
  906. {
  907. try
  908. {
  909. CorProcess corProcess = m_outer.GetProcess((int)debugEvent.dwProcessId);
  910. string callArgs = NativeDebugEvent.DebugEventToString(corProcess,debugEvent);
  911. Trace.WriteLine("UnmanagedCallback::DebugEvent(fOutOfBand="+isOutOfBand+")" + callArgs);
  912. // Should never get Out-Of-Band Native BPs. <strip>(@TODO could happen in interop debugging scenarios)</strip>
  913. if( ((NativeDebugEventCode)debugEvent.dwDebugEventCode == NativeDebugEventCode.EXCEPTION_DEBUG_EVENT) &&
  914. (debugEvent.Exception.ExceptionRecord.ExceptionCode == 0x80000003) && (isOutOfBand != 0) )
  915. {
  916. Debug.Assert(false,"ERROR: Out-Of-Band native breakpoint recieved!");
  917. }
  918. // Should never get In-Of-Band ExitThread Event (for Whidbey, not true in Everett)
  919. if( ((NativeDebugEventCode)debugEvent.dwDebugEventCode == NativeDebugEventCode.EXIT_THREAD_DEBUG_EVENT) &&
  920. (isOutOfBand == 0) )
  921. {
  922. Debug.Assert(false,"ERROR: In-Band ExitThread unamanged event received!");
  923. }
  924. // dispatch the event
  925. if(isOutOfBand!=0)
  926. {
  927. /* note that in this event debugger cannot use any managed debuggger API,
  928. * therefore it in effect cannot stop.
  929. * The CorNativeStopEventArgs class has a check that Continue cannot be set to false
  930. * in this case.