/extras/MonoDevelop.Debugger.Win32/CorApi2/debug/Debugger.cs
C# | 1034 lines | 783 code | 103 blank | 148 comment | 42 complexity | 653ddbf313df972af272978883df81ae MD5 | raw file
- //---------------------------------------------------------------------
- // This file is part of the CLR Managed Debugger (mdbg) Sample.
- //
- // Copyright (C) Microsoft Corporation. All rights reserved.
- //---------------------------------------------------------------------
- using System;
- using System.Collections;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- #if !MDBG_FAKE_COM
- using System.Runtime.InteropServices.ComTypes;
- #endif
- using System.Threading;
- using System.Text;
- using System.Security.Permissions;
- using System.Globalization;
- using System.Collections.Generic;
-
-
- using Microsoft.Samples.Debugging.CorDebug.NativeApi;
- using Microsoft.Win32.SafeHandles;
-
- [assembly:CLSCompliant(true)]
- [assembly:System.Runtime.InteropServices.ComVisible(false)]
- [assembly:SecurityPermission(SecurityAction.RequestMinimum, Unrestricted=true)]
-
- namespace Microsoft.Samples.Debugging.CorDebug
- {
- /**
- * Wraps the native CLR Debugger.
- * Note that we don't derive the class from WrapperBase, becuase this
- * class will never be returned in any callback.
- */
- public sealed class CorDebugger : MarshalByRefObject
- {
- private const int MaxVersionStringLength = 256; // == MAX_PATH
- public const int CREATE_REDIRECT_STD = 0x40000000;
-
- public static string GetDebuggerVersionFromFile(string pathToExe)
- {
- Debug.Assert( !string.IsNullOrEmpty(pathToExe) );
- if( string.IsNullOrEmpty(pathToExe) )
- throw new ArgumentException("Value cannot be null or empty.", "pathToExe");
- int neededSize;
- StringBuilder sb = new StringBuilder(MaxVersionStringLength);
- NativeMethods.GetRequestedRuntimeVersion(pathToExe, sb, sb.Capacity, out neededSize);
- return sb.ToString();
- }
-
- public static string GetDebuggerVersionFromPid(int pid)
- {
- using(ProcessSafeHandle ph = NativeMethods.OpenProcess((int)(NativeMethods.ProcessAccessOptions.PROCESS_VM_READ |
- NativeMethods.ProcessAccessOptions.PROCESS_QUERY_INFORMATION |
- NativeMethods.ProcessAccessOptions.PROCESS_DUP_HANDLE |
- NativeMethods.ProcessAccessOptions.SYNCHRONIZE),
- false, // inherit handle
- pid) )
- {
- if( ph.IsInvalid )
- throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
- int neededSize;
- StringBuilder sb = new StringBuilder(MaxVersionStringLength);
- NativeMethods.GetVersionFromProcess(ph, sb, sb.Capacity, out neededSize);
- return sb.ToString();
- }
- }
-
- public static string GetDefaultDebuggerVersion()
- {
- int size;
- NativeMethods.GetCORVersion(null,0,out size);
- Debug.Assert(size>0);
- StringBuilder sb = new StringBuilder(size);
- int hr = NativeMethods.GetCORVersion(sb,sb.Capacity,out size);
- Marshal.ThrowExceptionForHR(hr);
- return sb.ToString();
- }
-
-
- /// <summary>Creates a debugger wrapper from Guid.</summary>
- public CorDebugger(Guid debuggerGuid)
- {
- ICorDebug rawDebuggingAPI;
- NativeMethods.CoCreateInstance(ref debuggerGuid,
- IntPtr.Zero, // pUnkOuter
- 1, // CLSCTX_INPROC_SERVER
- ref NativeMethods.IIDICorDebug,
- out rawDebuggingAPI);
- InitFromICorDebug(rawDebuggingAPI);
- }
- /// <summary>Creates a debugger interface that is able debug requested verison of CLR</summary>
- /// <param name="debuggerVerison">Version number of the debugging interface.</param>
- /// <remarks>The version number is usually retrieved either by calling one of following mscoree functions:
- /// GetCorVerison, GetRequestedRuntimeVersion or GetVersionFromProcess.</remarks>
- public CorDebugger (string debuggerVersion)
- {
- InitFromVersion(debuggerVersion);
- }
-
- ~CorDebugger()
- {
- if(m_debugger!=null)
- try
- {
- Terminate();
- }
- catch
- {
- // sometimes we cannot terminate because GC collects object in wrong
- // order. But since the whole process is shutting down, we really
- // don't care.
- // TODO: we need to define IDisposable pattern to CorDebug so that we are able to
- // dispose stuff in correct order.
- }
- }
-
- #if CORAPI_EXPOSE_RAW_INTERFACES
- [CLSCompliant(false)]
- public ICorDebug Raw
- {
- get
- {
- return m_debugger;
- }
- }
- #endif
-
- /**
- * Closes the debugger. After this method is called, it is an error
- * to call any other methods on this object.
- */
- public void Terminate ()
- {
- Debug.Assert(m_debugger!=null);
- ICorDebug d= m_debugger;
- m_debugger = null;
- d.Terminate ();
- }
-
- /**
- * Specify the callback object to use for managed events.
- */
- internal void SetManagedHandler (ICorDebugManagedCallback managedCallback)
- {
- m_debugger.SetManagedHandler (managedCallback);
- }
-
- /**
- * Specify the callback object to use for unmanaged events.
- */
- internal void SetUnmanagedHandler (ICorDebugUnmanagedCallback nativeCallback)
- {
- m_debugger.SetUnmanagedHandler (nativeCallback);
- }
-
- /**
- * Launch a process under the control of the debugger.
- *
- * Parameters are the same as the Win32 CreateProcess call.
- */
- public CorProcess CreateProcess (
- String applicationName,
- String commandLine
- )
- {
- return CreateProcess (applicationName, commandLine, ".");
- }
-
- /**
- * Launch a process under the control of the debugger.
- *
- * Parameters are the same as the Win32 CreateProcess call.
- */
- public CorProcess CreateProcess (
- String applicationName,
- String commandLine,
- String currentDirectory
- )
- {
- return CreateProcess (applicationName, commandLine, currentDirectory, null, 0);
- }
-
- /**
- * Launch a process under the control of the debugger.
- *
- * Parameters are the same as the Win32 CreateProcess call.
- */
- public CorProcess CreateProcess (
- String applicationName,
- String commandLine,
- String currentDirectory,
- IDictionary<string,string> environment
- )
- {
- return CreateProcess (applicationName, commandLine, currentDirectory, environment, 0);
- }
-
- /**
- * Launch a process under the control of the debugger.
- *
- * Parameters are the same as the Win32 CreateProcess call.
- */
- public CorProcess CreateProcess (
- String applicationName,
- String commandLine,
- String currentDirectory,
- IDictionary<string,string> environment,
- int flags
- )
- {
- PROCESS_INFORMATION pi = new PROCESS_INFORMATION ();
-
- STARTUPINFO si = new STARTUPINFO ();
- si.cb = Marshal.SizeOf(si);
-
- // initialize safe handles
- SafeFileHandle outReadPipe = null, errorReadPipe = null;
- if ((flags & CREATE_REDIRECT_STD) != 0) {
- CreateHandles (si, out outReadPipe, out errorReadPipe);
- flags &= ~CREATE_REDIRECT_STD;
- }
- else {
- si.hStdInput = new SafeFileHandle (IntPtr.Zero, false);
- si.hStdOutput = new SafeFileHandle (IntPtr.Zero, false);
- si.hStdError = new SafeFileHandle (IntPtr.Zero, false);
- }
-
- IntPtr env = IntPtr.Zero;
- if (environment != null) {
- string senv = null;
- foreach (KeyValuePair<string, string> var in environment) {
- senv += var.Key + "=" + var.Value + "\0";
- }
- senv += "\0";
- env = Marshal.StringToHGlobalAnsi (senv);
- }
-
- CorProcess ret;
-
- //constrained execution region (Cer)
- System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
- try
- {
- }
- finally
- {
- ret = CreateProcess (
- applicationName,
- commandLine,
- null,
- null,
- true, // inherit handles
- flags, // creation flags
- env, // environment
- currentDirectory,
- si, // startup info
- ref pi, // process information
- CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS);
- NativeMethods.CloseHandle (pi.hProcess);
- NativeMethods.CloseHandle (pi.hThread);
- }
-
- if (env != IntPtr.Zero)
- Marshal.FreeHGlobal (env);
-
- if (outReadPipe != null) {
-
- // Close pipe handles (do not continue to modify the parent).
- // You need to make sure that no handles to the write end of the
- // output pipe are maintained in this process or else the pipe will
- // not close when the child process exits and the ReadFile will hang.
-
- si.hStdInput.Close ();
- si.hStdOutput.Close ();
- si.hStdError.Close ();
-
- ret.TrackStdOutput (outReadPipe, errorReadPipe);
- }
-
- return ret;
- }
-
- void CreateHandles (STARTUPINFO si, out SafeFileHandle outReadPipe, out SafeFileHandle errorReadPipe)
- {
- si.dwFlags |= 0x00000100; /*STARTF_USESTDHANDLES*/
- SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES ();
- sa.bInheritHandle = true;
- IntPtr curProc = NativeMethods.GetCurrentProcess ();
-
- SafeFileHandle outWritePipe, outReadPipeTmp;
- if (!NativeMethods.CreatePipe (out outReadPipeTmp, out outWritePipe, sa, 0))
- throw new Exception ("Pipe creation failed");
-
- // Create the child error pipe.
- SafeFileHandle errorWritePipe, errorReadPipeTmp;
- if (!NativeMethods.CreatePipe (out errorReadPipeTmp, out errorWritePipe, sa, 0))
- throw new Exception ("Pipe creation failed");
-
- // Create new output read and error read handles. Set
- // the Properties to FALSE. Otherwise, the child inherits the
- // properties and, as a result, non-closeable handles to the pipes
- // are created.
- if (!NativeMethods.DuplicateHandle (curProc, outReadPipeTmp, curProc, out outReadPipe, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS))
- throw new Exception ("Pipe creation failed");
- if (!NativeMethods.DuplicateHandle (curProc, errorReadPipeTmp, curProc, out errorReadPipe, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS))
- throw new Exception ("Pipe creation failed");
-
- NativeMethods.CloseHandle (curProc);
-
- // Close inheritable copies of the handles you do not want to be
- // inherited.
- outReadPipeTmp.Close ();
- errorReadPipeTmp.Close ();
-
- si.hStdInput = NativeMethods.GetStdHandle (NativeMethods.STD_INPUT_HANDLE);
- si.hStdOutput = outWritePipe;
- si.hStdError = errorWritePipe;
- }
-
- /**
- * Launch a process under the control of the debugger.
- *
- * Parameters are the same as the Win32 CreateProcess call.
- *
- * The caller should remember to execute:
- *
- * Microsoft.Win32.Interop.Windows.CloseHandle (
- * processInformation.hProcess);
- *
- * after CreateProcess returns.
- */
- [CLSCompliant(false)]
- public CorProcess CreateProcess (
- String applicationName,
- String commandLine,
- SECURITY_ATTRIBUTES processAttributes,
- SECURITY_ATTRIBUTES threadAttributes,
- bool inheritHandles,
- int creationFlags,
- IntPtr environment, // <strip>@TODO fix the environment</strip>
- String currentDirectory,
- STARTUPINFO startupInfo,
- ref PROCESS_INFORMATION processInformation,
- CorDebugCreateProcessFlags debuggingFlags)
- {
- /*
- * If commandLine is: <c:\a b\a arg1 arg2> and c:\a.exe does not exist,
- * then without this logic, "c:\a b\a.exe" would be tried next.
- * To prevent this ambiguity, this forces the user to quote if the path
- * has spaces in it: <"c:\a b\a" arg1 arg2>
- */
- if(null == applicationName && !commandLine.StartsWith("\""))
- {
- int firstSpace = commandLine.IndexOf(" ");
- if(firstSpace != -1)
- commandLine = String.Format(CultureInfo.InvariantCulture, "\"{0}\" {1}", commandLine.Substring(0,firstSpace), commandLine.Substring(firstSpace, commandLine.Length-firstSpace));
- }
-
- ICorDebugProcess proc = null;
-
- m_debugger.CreateProcess (
- applicationName,
- commandLine,
- processAttributes,
- threadAttributes,
- inheritHandles ? 1 : 0,
- (uint) creationFlags,
- environment,
- currentDirectory,
- startupInfo,
- processInformation,
- debuggingFlags,
- out proc);
-
- return CorProcess.GetCorProcess(proc);
- }
-
- /**
- * Attach to an active process
- */
- public CorProcess DebugActiveProcess (int processId, bool win32Attach)
- {
- ICorDebugProcess proc = null;
- m_debugger.DebugActiveProcess ((uint)processId, win32Attach ? 1 : 0, out proc);
- return CorProcess.GetCorProcess(proc);
- }
-
- /**
- * Enumerate all processes currently being debugged.
- */
- public IEnumerable Processes
- {
- get
- {
- ICorDebugProcessEnum eproc = null;
- m_debugger.EnumerateProcesses (out eproc);
- return new CorProcessEnumerator (eproc);
- }
- }
-
- /**
- * Get the Process object for the given PID.
- */
- public CorProcess GetProcess (int processId)
- {
- ICorDebugProcess proc = null;
- m_debugger.GetProcess ((uint) processId, out proc);
- return CorProcess.GetCorProcess(proc);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // CorDebugger private implement part
- //
- ////////////////////////////////////////////////////////////////////////////////
-
- // called by constructors during initialization
- private void InitFromVersion(string debuggerVersion)
- {
- if( debuggerVersion.StartsWith("v1") )
- {
- throw new ArgumentException( "Can't debug a version 1 CLR process (\"" + debuggerVersion +
- "\"). Run application in a version 2 CLR, or use a version 1 debugger instead." );
- }
-
- ICorDebug rawDebuggingAPI;
- #if MDBG_FAKE_COM
- // TODO: Ideally, there wouldn't be any difference in the corapi code for MDBG_FAKE_COM.
- // This would require puting this initialization logic into the wrapper and interop assembly, which doesn't seem right.
- // We should also release this pUnk, but doing that here would be difficult and we aren't done with it until
- // we shutdown anyway.
- IntPtr pUnk = NativeMethods.CreateDebuggingInterfaceFromVersion((int)CorDebuggerVersion.Whidbey, debuggerVersion);
- rawDebuggingAPI = new NativeApi.CorDebugClass(pUnk);
- #else
- int apiVersion = debuggerVersion.StartsWith ("v4") ? 4 : 3;
- rawDebuggingAPI = NativeMethods.CreateDebuggingInterfaceFromVersion (apiVersion, debuggerVersion);
- #endif
- InitFromICorDebug(rawDebuggingAPI);
- }
-
- private void InitFromICorDebug(ICorDebug rawDebuggingAPI)
- {
- Debug.Assert(rawDebuggingAPI!=null);
- if( rawDebuggingAPI==null )
- throw new ArgumentException("Cannot be null.","rawDebugggingAPI");
-
- m_debugger = rawDebuggingAPI;
- m_debugger.Initialize ();
- m_debugger.SetManagedHandler (new ManagedCallback(this));
- #if MDBG_FEATURE_INTEROP
- try
- {
- m_debugger.SetUnmanagedHandler(new UnmanagedCallback(this));
- }
- catch(NotImplementedException)
- {
- }
- #endif
- }
-
- /**
- * Helper for invoking events. Checks to make sure that handlers
- * are hooked up to a handler before the handler is invoked.
- *
- * We want to allow maximum flexibility by our callers. As such,
- * we don't require that they call <code>e.Controller.Continue</code>,
- * nor do we require that this class call it. <b>Someone</b> needs
- * to call it, however.
- *
- * Consequently, if an exception is thrown and the process is stopped,
- * the process is continued automatically.
- */
- void InternalFireEvent(ManagedCallbackType callbackType,CorEventArgs e)
- {
- CorProcess owner;
- CorController c = e.Controller;
- Debug.Assert(c!=null);
- if(c is CorProcess)
- owner = (CorProcess)c ;
- else
- {
- Debug.Assert(c is CorAppDomain);
- owner = (c as CorAppDomain).Process;
- }
- Debug.Assert(owner!=null);
- try
- {
- owner.DispatchEvent(callbackType,e);
- }
- finally
- {
- if(e.Continue)
- {
- #if MDBG_FEATURE_INTEROP
- // this is special case for interop debugging
- // where we continue from OOB native event in which
- // case we have to call Continue with true (OOBound).
- if( (e is CorNativeStopEventArgs)
- && (e as CorNativeStopEventArgs).IsOutOfBand )
- e.Controller.Continue(true);
- else
- #endif
- e.Controller.Continue(false);
- }
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ManagedCallback
- //
- ////////////////////////////////////////////////////////////////////////////////
-
- /**
- * This is the object that gets passed to the debugger. It's
- * the intermediate "source" of the events, which repackages
- * the event arguments into a more approprate form and forwards
- * the call to the appropriate function.
- */
- private class ManagedCallback : ICorDebugManagedCallback, ICorDebugManagedCallback2
- {
- public ManagedCallback (CorDebugger outer)
- {
- m_outer = outer;
- }
-
- void ICorDebugManagedCallback.Breakpoint (ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugBreakpoint breakpoint)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnBreakpoint,
- new CorBreakpointEventArgs (appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread),
- breakpoint==null?null:new CorFunctionBreakpoint ((ICorDebugFunctionBreakpoint)breakpoint)
- ));
- }
-
- void ICorDebugManagedCallback.StepComplete ( ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugStepper stepper,
- CorDebugStepReason stepReason)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnStepComplete,
- new CorStepCompleteEventArgs (appDomain==null?null:new CorAppDomain (appDomain),
- thread==null?null:new CorThread (thread),
- stepper==null?null:new CorStepper(stepper),
- stepReason));
- }
-
- void ICorDebugManagedCallback.Break (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnBreak,
- new CorThreadEventArgs (
- appDomain==null?null:new CorAppDomain (appDomain),
- thread==null?null:new CorThread (thread)));
- }
-
- void ICorDebugManagedCallback.Exception (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- int unhandled)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnException,
- new CorExceptionEventArgs (
- appDomain==null?null:new CorAppDomain (appDomain),
- thread==null?null:new CorThread (thread),
- !(unhandled == 0)));
- }
- /* pass false if ``unhandled'' is 0 -- mapping TRUE to true, etc. */
-
- void ICorDebugManagedCallback.EvalComplete (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugEval eval)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnEvalComplete,
- new CorEvalEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread),
- eval==null?null:new CorEval(eval)));
- }
-
- void ICorDebugManagedCallback.EvalException (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugEval eval)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnEvalException,
- new CorEvalEventArgs (
- appDomain==null?null:new CorAppDomain (appDomain),
- thread==null?null:new CorThread (thread),
- eval==null?null:new CorEval (eval)));
- }
-
- void ICorDebugManagedCallback.CreateProcess (
- ICorDebugProcess process)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnCreateProcess,
- new CorProcessEventArgs (
- process==null?null:CorProcess.GetCorProcess(process)));
- }
-
- void ICorDebugManagedCallback.ExitProcess (
- ICorDebugProcess process)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnProcessExit,
- new CorProcessEventArgs (
- process==null?null:CorProcess.GetCorProcess(process)));
- }
-
- void ICorDebugManagedCallback.CreateThread (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnCreateThread,
- new CorThreadEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread)));
- }
-
- void ICorDebugManagedCallback.ExitThread (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnThreadExit,
- new CorThreadEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread)));
- }
-
- void ICorDebugManagedCallback.LoadModule (
- ICorDebugAppDomain appDomain,
- ICorDebugModule managedModule)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnModuleLoad,
- new CorModuleEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- managedModule==null?null:new CorModule (managedModule)));
- }
-
- void ICorDebugManagedCallback.UnloadModule (
- ICorDebugAppDomain appDomain,
- ICorDebugModule managedModule)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnModuleUnload,
- new CorModuleEventArgs (
- appDomain==null?null:new CorAppDomain (appDomain),
- managedModule==null?null:new CorModule (managedModule)));
- }
-
- void ICorDebugManagedCallback.LoadClass (
- ICorDebugAppDomain appDomain,
- ICorDebugClass c)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnClassLoad,
- new CorClassEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- c==null?null:new CorClass (c)));
- }
-
- void ICorDebugManagedCallback.UnloadClass (
- ICorDebugAppDomain appDomain,
- ICorDebugClass c)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnClassUnload,
- new CorClassEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- c==null?null:new CorClass (c)));
- }
-
- void ICorDebugManagedCallback.DebuggerError (
- ICorDebugProcess process,
- int errorHR,
- uint errorCode)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnDebuggerError,
- new CorDebuggerErrorEventArgs (
- process==null?null:CorProcess.GetCorProcess (process),
- errorHR,
- (int) errorCode));
- }
-
- void ICorDebugManagedCallback.LogMessage (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- int level,
- string logSwitchName,
- string message)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnLogMessage,
- new CorLogMessageEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread),
- level, logSwitchName, message));
- }
-
- void ICorDebugManagedCallback.LogSwitch (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- int level,
- uint reason,
- string logSwitchName,
- string parentName)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnLogSwitch,
- new CorLogSwitchEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread),
- level, (int) reason, logSwitchName, parentName));
- }
-
- void ICorDebugManagedCallback.CreateAppDomain (
- ICorDebugProcess process,
- ICorDebugAppDomain appDomain)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnCreateAppDomain,
- new CorAppDomainEventArgs (
- process==null?null:CorProcess.GetCorProcess(process),
- appDomain==null?null:new CorAppDomain(appDomain)));
- }
-
- void ICorDebugManagedCallback.ExitAppDomain (
- ICorDebugProcess process,
- ICorDebugAppDomain appDomain)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnAppDomainExit,
- new CorAppDomainEventArgs (
- process==null?null:CorProcess.GetCorProcess(process),
- appDomain==null?null:new CorAppDomain (appDomain)));
- }
-
- void ICorDebugManagedCallback.LoadAssembly (
- ICorDebugAppDomain appDomain,
- ICorDebugAssembly assembly)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnAssemblyLoad,
- new CorAssemblyEventArgs (
- appDomain==null?null:new CorAppDomain (appDomain),
- assembly==null?null:new CorAssembly (assembly)));
- }
-
- void ICorDebugManagedCallback.UnloadAssembly (
- ICorDebugAppDomain appDomain,
- ICorDebugAssembly assembly)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnAssemblyUnload,
- new CorAssemblyEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- assembly==null?null:new CorAssembly (assembly)));
- }
-
- void ICorDebugManagedCallback.ControlCTrap (ICorDebugProcess process)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnControlCTrap,
- new CorProcessEventArgs (
- process==null?null:CorProcess.GetCorProcess(process)
- ));
- }
-
- void ICorDebugManagedCallback.NameChange (
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnNameChange,
- new CorThreadEventArgs (
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread)));
- }
-
- // TODO: Enable support for dynamic modules (reflection emit) with FAKE_COM?
- // Rotor doesn't have ISymbolBinder2 or IStream, so we may have to add them
- void ICorDebugManagedCallback.UpdateModuleSymbols (
- ICorDebugAppDomain appDomain,
- ICorDebugModule managedModule,
- #if MDBG_FAKE_COM
- IntPtr stream)
- #else
- IStream stream)
- #endif
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnUpdateModuleSymbols,
- new CorUpdateModuleSymbolsEventArgs(
- appDomain==null?null:new CorAppDomain(appDomain),
- managedModule==null?null:new CorModule (managedModule),
- stream));
- }
-
- void ICorDebugManagedCallback.EditAndContinueRemap(
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugFunction managedFunction,
- int isAccurate)
- {
- Debug.Assert(false); //OBSOLETE callback
- }
-
-
- void ICorDebugManagedCallback.BreakpointSetError(
- ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugBreakpoint breakpoint,
- UInt32 errorCode)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnBreakpointSetError,
- new CorBreakpointSetErrorEventArgs(
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread(thread),
- null, // <strip>@TODO breakpoint==null?null:new CorBreakpoint(breakpoint),</strip>
- (int)errorCode));
- }
-
- void ICorDebugManagedCallback2.FunctionRemapOpportunity(ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugFunction oldFunction,
- ICorDebugFunction newFunction,
- uint oldILoffset)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnFunctionRemapOpportunity,
- new CorFunctionRemapOpportunityEventArgs(
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread),
- oldFunction==null?null:new CorFunction(oldFunction),
- newFunction==null?null:new CorFunction(newFunction),
- (int)oldILoffset
- ));
- }
-
- void ICorDebugManagedCallback2.FunctionRemapComplete(ICorDebugAppDomain appDomain,
- ICorDebugThread thread,
- ICorDebugFunction managedFunction)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnFunctionRemapComplete,
- new CorFunctionRemapCompleteEventArgs(
- appDomain==null?null:new CorAppDomain(appDomain),
- thread==null?null:new CorThread (thread),
- managedFunction==null?null:new CorFunction(managedFunction)
- ));
- }
-
- void ICorDebugManagedCallback2.CreateConnection(ICorDebugProcess process,uint connectionId, ref ushort connectionName)
- {
- // <strip>@TODO - </strip>Not Implemented
- Debug.Assert(false);
- }
-
- void ICorDebugManagedCallback2.ChangeConnection(ICorDebugProcess process,uint connectionId)
- {
- // <strip>@TODO -</strip> Not Implemented
- Debug.Assert(false);
- }
-
- void ICorDebugManagedCallback2.DestroyConnection(ICorDebugProcess process,uint connectionId)
- {
- // <strip>@TODO - </strip>Not Implemented
- Debug.Assert(false);
- }
-
- void ICorDebugManagedCallback2.Exception(ICorDebugAppDomain ad, ICorDebugThread thread,
- ICorDebugFrame frame, uint offset,
- CorDebugExceptionCallbackType eventType, uint flags) //@TODO flags should not be UINT
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnException2,
- new CorException2EventArgs(
- ad==null?null:new CorAppDomain(ad),
- thread==null?null:new CorThread (thread),
- frame==null?null:new CorFrame(frame),
- (int)offset,
- eventType,
- (int)flags
- ));
- }
-
- void ICorDebugManagedCallback2.ExceptionUnwind(ICorDebugAppDomain ad, ICorDebugThread thread,
- CorDebugExceptionUnwindCallbackType eventType, uint flags)
- {
- m_outer.InternalFireEvent(ManagedCallbackType.OnExceptionUnwind2,
- new CorExceptionUnwind2EventArgs(
- ad==null?null:new CorAppDomain(ad),
- thread==null?null:new CorThread (thread),
- eventType,
- (int)flags
- ));
- }
-
- // Get process from controller
- private CorProcess GetProcessFromController(ICorDebugController pController)
- {
- CorProcess p;
- ICorDebugProcess p2 = pController as ICorDebugProcess;
- if (p2 != null)
- {
- p = CorProcess.GetCorProcess(p2);
- }
- else
- {
- ICorDebugAppDomain a2 = (ICorDebugAppDomain) pController;
- p = new CorAppDomain(a2).Process;
- }
- return p;
- }
-
- void ICorDebugManagedCallback2.MDANotification(ICorDebugController pController,
- ICorDebugThread thread,
- ICorDebugMDA pMDA)
- {
- CorMDA c = new CorMDA(pMDA);
- string szName = c.Name;
- CorDebugMDAFlags f = c.Flags;
- CorProcess p = GetProcessFromController(pController);
-
-
- m_outer.InternalFireEvent(ManagedCallbackType.OnMDANotification,
- new CorMDAEventArgs (c,
- thread==null?null:new CorThread (thread),
- p));
- }
-
- private CorDebugger m_outer;
- }
-
-
-
- #if MDBG_FEATURE_INTEROP
- private class UnmanagedCallback : ICorDebugUnmanagedCallback
- {
- public UnmanagedCallback (CorDebugger outer)
- {
- Debug.Assert(outer!=null);
- m_outer = outer;
- }
-
- #if !FIXED_BUG21115 //<strip>@TODO remove once we'll be able to call Continue from Win32 callbakck.</strip>
- private struct Win32NativeEvent
- {
- public Win32NativeEvent(CorProcess process,CorDebugger outer,int threadId,DEBUG_EVENT debugEvent)
- {
- Debug.Assert(process!=null);
- Debug.Assert(outer!=null);
- m_process = process;
- m_outer = outer;
- m_threadId = threadId;
- m_debugEvent = debugEvent;
- }
- private CorProcess m_process;
- private CorDebugger m_outer;
- private int m_threadId;
- private DEBUG_EVENT m_debugEvent;
-
- // This is always dispatched on the W32ET. That thread can't do anything useful so we
- // hand off to another thread.
- static public void DispatchEvent(Win32NativeEvent event_)
- {
- // If Mdbg has mutliple debuggees, they'll share this.
- lock(g_lock)
- {
- if( g_workToDo == null )
- {
- g_workToDo = new AutoResetEvent(false);
- g_callWorkDone = new AutoResetEvent(true);
- Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Win32NativeEvent.Dispatch));
- t.IsBackground = true;
- t.Start();
- }
- }
-
- g_callWorkDone.WaitOne();
- g_event = event_;
- g_workToDo.Set();
-
- // We now return without waiting for the DispatchThread to finish
- }
-
- // Statics
- static private object g_lock = new object();
- static private AutoResetEvent g_callWorkDone=null;
- static private AutoResetEvent g_workToDo = null;
- static private Win32NativeEvent g_event;
-
- // This is called on a separate thread from the W32ET. MDbg shares this thread across all debuggees
- // (in the same way ICorDebug shares the RCET)
- public static void Dispatch()
- {
- while(true)
- {
- try
- {
- g_workToDo.WaitOne();
-
- g_event.m_outer.InternalFireEvent(ManagedCallbackType.OnNativeStop,
- new CorNativeStopEventArgs (g_event.m_process,
- g_event.m_threadId,
- g_event.m_debugEvent,
- false /*not OOB event*/));
- }
- finally
- {
- g_callWorkDone.Set();
- }
- }
- }
- }
- #endif
- void Microsoft.Samples.Debugging.CorDebug.NativeApi.ICorDebugUnmanagedCallback.DebugEvent(DEBUG_EVENT debugEvent, int isOutOfBand)
- {
- try
- {
- CorProcess corProcess = m_outer.GetProcess((int)debugEvent.dwProcessId);
- string callArgs = NativeDebugEvent.DebugEventToString(corProcess,debugEvent);
- Trace.WriteLine("UnmanagedCallback::DebugEvent(fOutOfBand="+isOutOfBand+")" + callArgs);
-
- // Should never get Out-Of-Band Native BPs. <strip>(@TODO could happen in interop debugging scenarios)</strip>
- if( ((NativeDebugEventCode)debugEvent.dwDebugEventCode == NativeDebugEventCode.EXCEPTION_DEBUG_EVENT) &&
- (debugEvent.Exception.ExceptionRecord.ExceptionCode == 0x80000003) && (isOutOfBand != 0) )
- {
- Debug.Assert(false,"ERROR: Out-Of-Band native breakpoint recieved!");
- }
-
- // Should never get In-Of-Band ExitThread Event (for Whidbey, not true in Everett)
- if( ((NativeDebugEventCode)debugEvent.dwDebugEventCode == NativeDebugEventCode.EXIT_THREAD_DEBUG_EVENT) &&
- (isOutOfBand == 0) )
- {
- Debug.Assert(false,"ERROR: In-Band ExitThread unamanged event received!");
- }
-
- // dispatch the event
- if(isOutOfBand!=0)
- {
- /* note that in this event debugger cannot use any managed debuggger API,
- * therefore it in effect cannot stop.
- * The CorNativeStopEventArgs class has a check that Continue cannot be set to false
- * in this case.
-