diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj index 4b2a265cb6..386a0c912d 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj @@ -66,6 +66,7 @@ + @@ -87,4 +88,4 @@ - + \ No newline at end of file diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/MTA2STA.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/MTA2STA.cs index 50f083a9ef..c508467a5c 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/MTA2STA.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/MTA2STA.cs @@ -25,6 +25,7 @@ namespace DebuggerInterop.Core static object OnlyOneAtTimeLock = new Object(); static object DataLock = new Object(); + object returnValue; public MTA2STA() { @@ -37,7 +38,7 @@ namespace DebuggerInterop.Core System.Console.WriteLine("MTA2STA: " + msg); } - public void CallInSTA (object targetObject, string functionName, object[] functionParameters) + public object CallInSTA (object targetObject, string functionName, object[] functionParameters) { lock (OnlyOneAtTimeLock) { TraceMsg("call to process: " + functionName + " {"); @@ -63,6 +64,7 @@ namespace DebuggerInterop.Core TraceMsg("} // MTA2STA: call processed: " + functionName); } + return returnValue; } void PerformCall(object sender, EventArgs e) @@ -105,11 +107,12 @@ namespace DebuggerInterop.Core } } TraceMsg ("Invoke " + functionName + "{"); + returnValue = null; try { if (targetObject is Type) { - method.Invoke(null, outputParams); + returnValue = method.Invoke(null, outputParams); } else { - method.Invoke(targetObject, outputParams); + returnValue = method.Invoke(targetObject, outputParams); } } catch (System.Exception exception) { System.Diagnostics.Debug.Fail("Invoke of " + functionName + " failed.", exception.ToString()); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/NDebugger.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/NDebugger.cs index f2aa0dde58..ad13d2a3bc 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/NDebugger.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/NDebugger.cs @@ -40,48 +40,21 @@ namespace DebuggerLibrary } } - static ICorDebug corDebug; static ManagedCallback managedCallback; static ManagedCallbackProxy managedCallbackProxy; - static bool isProcessRunning; - static ICorDebugProcess mainProcess; - static Thread mainThread; - static Thread currentThread; + static Process mainProcess; public static bool CatchHandledExceptions = false; - #region Public propeties - - static public SourcecodeSegment NextStatement { - get{ - try { - return CurrentThread.NextStatement; - } catch (CurrentThreadNotAviableException) { - System.Diagnostics.Debug.Fail("Unable to get NextStatement. CurrentThreadNotAviableException"); - throw new NextStatementNotAviableException(); - } - } - } - - static public VariableCollection LocalVariables { - get{ - Thread thread; - try { - thread = CurrentThread; - } - catch (CurrentThreadNotAviableException) { - //System.Diagnostics.Debug.Fail("Unable to get LocalVariables. CurrentThreadNotAviableException"); - return new VariableCollection (); - } - return thread.LocalVariables; - } + static internal ICorDebug CorDebug { + get { + return corDebug; + } } - #endregion - - static internal ICorDebugProcess MainProcess { + static internal Process CurrentProcess { get { return mainProcess; } @@ -101,41 +74,6 @@ namespace DebuggerLibrary } } } - - public static Thread MainThread { - get { - return mainThread; - } - set { - mainThread = value; - } - } - - static public Thread CurrentThread { - get { - if (!IsDebugging) throw new CurrentThreadNotAviableException(); - if (IsProcessRunning) throw new CurrentThreadNotAviableException(); - if (currentThread != null) return currentThread; - if (mainThread != null) return mainThread; - throw new CurrentThreadNotAviableException(); - } - set { - currentThread = value; - if (mainThread == null) { - mainThread = value; - } - if (managedCallback.HandlingCallback == false) { - OnDebuggingPaused(PausedReason.CurrentThreadChanged); - } - } - } - - static internal ICorDebugProcess corProcess { - get { - if (MainProcess != null) return MainProcess; - throw new UnableToGetPropertyException(null, "corProcess", "Make sure debuger is attached to process"); - } - } internal static ManagedCallback ManagedCallback { get { @@ -184,10 +122,7 @@ namespace DebuggerLibrary ClearThreads(); - MainProcess = null; - mainThread = null; - currentThread = null; - isProcessRunning = false; + CurrentProcess = null; GC.Collect(GC.MaxGeneration); GC.WaitForPendingFinalizers(); @@ -303,6 +238,13 @@ namespace DebuggerLibrary #region Execution control + static internal void Continue(ICorDebugAppDomain pAppDomain) + { + ICorDebugProcess outProcess; + pAppDomain.GetProcess(out outProcess); + outProcess.Continue(0); + } + static public void StartWithoutDebugging(System.Diagnostics.ProcessStartInfo psi) { System.Diagnostics.Process process; @@ -310,184 +252,118 @@ namespace DebuggerLibrary process.StartInfo = psi; process.Start(); } - - static MTA2STA m2s = new MTA2STA(); static public void Start(string filename, string workingDirectory, string arguments) { - if (IsDebugging) { - System.Diagnostics.Debug.Fail("Invalid operation"); - return; - } - m2s.CallInSTA(typeof(NDebugger), "StartInternal", new Object[] {filename, workingDirectory, arguments}); - return; + CurrentProcess = Process.CreateProcess(filename, workingDirectory, arguments); } - static public unsafe void StartInternal(string filename, string workingDirectory, string arguments) - { - TraceMessage("Executing " + filename); - - _SECURITY_ATTRIBUTES secAttr = new _SECURITY_ATTRIBUTES(); - secAttr.bInheritHandle = 0; - secAttr.lpSecurityDescriptor = IntPtr.Zero; - secAttr.nLength = (uint)sizeof(_SECURITY_ATTRIBUTES); //=12? - - uint[] processStartupInfo = new uint[17]; - processStartupInfo[0] = sizeof(uint) * 17; - uint[] processInfo = new uint[4]; - ICorDebugProcess outProcess; - fixed (uint* pprocessStartupInfo = processStartupInfo) - fixed (uint* pprocessInfo = processInfo) - corDebug.CreateProcess( - filename, // lpApplicationName - null, // lpCommandLine - ref secAttr, // lpProcessAttributes - ref secAttr, // lpThreadAttributes - 1,//TRUE // bInheritHandles - 0, // dwCreationFlags - IntPtr.Zero, // lpEnvironment - null, // lpCurrentDirectory - (uint)pprocessStartupInfo, // lpStartupInfo - (uint)pprocessInfo, // lpProcessInformation, - CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS, // debuggingFlags - out outProcess // ppProcess - ); - - isProcessRunning = true; - MainProcess = outProcess; - } + #endregion - static public void Break() + public void ToggleBreakpointAt(string fileName, int line, int column) { - if (!IsDebugging || !IsProcessRunning) { - System.Diagnostics.Debug.Fail("Invalid operation"); - return; + // Check if there is breakpoint on that line + foreach (Breakpoint breakpoint in Breakpoints) { + // TODO check filename too + if (breakpoint.SourcecodeSegment.StartLine == line) { + RemoveBreakpoint(breakpoint); + return; + } } - corProcess.Stop(5000); // TODO: Hardcoded value - - isProcessRunning = false; - OnDebuggingPaused(PausedReason.Break); - OnIsProcessRunningChanged(); - } + // Add the breakpoint + Breakpoint addedBreakpoint = AddBreakpoint(fileName, line, column); - static public void StepInto() - { - try { - CurrentThread.StepInto(); - } catch (CurrentThreadNotAviableException) { - System.Diagnostics.Debug.Fail("Unable to prerform step. CurrentThreadNotAviableException"); + // Check if it wasn't forced to move to different line with breakpoint + foreach (Breakpoint breakpoint in Breakpoints) { + if (breakpoint != addedBreakpoint) { // Only the old ones + if (breakpoint.SourcecodeSegment.StartLine == addedBreakpoint.SourcecodeSegment.StartLine) { + // Whops! We have two breakpoint on signle line, delete one + RemoveBreakpoint(addedBreakpoint); + return; + } + } } } - static public void StepOver() - { - try { - CurrentThread.StepOver(); - } catch (CurrentThreadNotAviableException) { - System.Diagnostics.Debug.Fail("Unable to prerform step. CurrentThreadNotAviableException"); + + static public bool IsProcessRunning { + get { + if (!IsDebugging) return false; + return CurrentProcess.IsProcessRunning; + } + set { + if (CurrentProcess == null) return; + CurrentProcess.IsProcessRunning = value; } } - static public void StepOut() - { - try { - CurrentThread.StepOut(); - } catch (CurrentThreadNotAviableException) { - System.Diagnostics.Debug.Fail("Unable to prerform step. CurrentThreadNotAviableException"); + static public bool IsDebugging { + get { + return (CurrentProcess != null); } } - static internal void Continue(ICorDebugAppDomain pAppDomain) - { - ICorDebugProcess outProcess; - pAppDomain.GetProcess(out outProcess); - if (MainProcess != outProcess) throw new DebuggerException("Request to continue AppDomain that does not belog to current process"); - Continue(); + static public Thread CurrentThread { + get { + return CurrentProcess.CurrentThread; + } + set { + CurrentProcess.CurrentThread = value; + } } - static public void Continue() - { - if (!IsDebugging || IsProcessRunning) { - System.Diagnostics.Debug.Fail("Invalid operation"); - return; + static public Thread MainThread { + get { + return CurrentProcess.MainThread; } - - bool abort = false; - OnDebuggingIsResuming(ref abort); - if (abort == true) return; - - isProcessRunning = true; - if (managedCallback.HandlingCallback == false) { - OnDebuggingResumed(); - OnIsProcessRunningChanged(); + set { + CurrentProcess.MainThread = value; } - - corProcess.Continue(0); } - static public void Terminate() - { - if (!IsDebugging) { - System.Diagnostics.Debug.Fail("Invalid operation"); - return; + static public SourcecodeSegment NextStatement { + get{ + return CurrentProcess.NextStatement; } + } - int running; - corProcess.IsRunning(out running); - // Resume stoped tread - if (running == 0) { - Continue(); // TODO: Remove this... + static public VariableCollection LocalVariables { + get{ + return CurrentProcess.LocalVariables; } - // Stop&terminate - both must be called - corProcess.Stop(5000); // TODO: ...and this - corProcess.Terminate(0); } - static public bool IsProcessRunning { - get { - if (!IsDebugging) return false; - return isProcessRunning; - } - set { - isProcessRunning = value; - } + static public void Break() + { + CurrentProcess.Break(); } - static public bool IsDebugging { - get { - return (MainProcess != null); - } + static public void StepInto() + { + CurrentProcess.StepInto(); } - #endregion + static public void StepOver() + { + CurrentProcess.StepOver(); + } - public void ToggleBreakpointAt(string fileName, int line, int column) + static public void StepOut() { - // Check if there is breakpoint on that line - foreach (Breakpoint breakpoint in Breakpoints) { - // TODO check filename too - if (breakpoint.SourcecodeSegment.StartLine == line) { - RemoveBreakpoint(breakpoint); - return; - } - } + CurrentProcess.StepOut(); + } - // Add the breakpoint - Breakpoint addedBreakpoint = AddBreakpoint(fileName, line, column); + static public void Continue() + { + CurrentProcess.Continue(); + } - // Check if it wasn't forced to move to different line with breakpoint - foreach (Breakpoint breakpoint in Breakpoints) { - if (breakpoint != addedBreakpoint) { // Only the old ones - if (breakpoint.SourcecodeSegment.StartLine == addedBreakpoint.SourcecodeSegment.StartLine) { - // Whops! We have two breakpoint on signle line, delete one - RemoveBreakpoint(addedBreakpoint); - return; - } - } - } + static public void Terminate() + { + CurrentProcess.Terminate(); } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs new file mode 100644 index 0000000000..e634525a2f --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs @@ -0,0 +1,212 @@ +// +// +// + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; + +using DebuggerInterop.Core; +using DebuggerInterop.MetaData; + +namespace DebuggerLibrary +{ + public class Process + { + ICorDebugProcess corProcess; + + Thread mainThread; + Thread currentThread; + bool isProcessRunning; + + internal Process(ICorDebugProcess corProcess) + { + this.corProcess = corProcess; + } + + internal ICorDebugProcess CorProcess { + get { + return corProcess; + } + } + + public Thread CurrentThread { + get { + if (IsProcessRunning) throw new CurrentThreadNotAviableException(); + if (currentThread != null) return currentThread; + if (mainThread != null) return mainThread; + throw new CurrentThreadNotAviableException(); + } + set { + currentThread = value; + if (mainThread == null) { + mainThread = value; + } + if (NDebugger.ManagedCallback.HandlingCallback == false) { + NDebugger.OnDebuggingPaused(PausedReason.CurrentThreadChanged); + } + } + } + + public Thread MainThread { + get { + return mainThread; + } + set { + mainThread = value; + } + } + + public SourcecodeSegment NextStatement { + get{ + try { + return CurrentThread.NextStatement; + } catch (CurrentThreadNotAviableException) { + System.Diagnostics.Debug.Fail("Unable to get NextStatement. CurrentThreadNotAviableException"); + throw new NextStatementNotAviableException(); + } + } + } + + public VariableCollection LocalVariables { + get{ + Thread thread; + try { + thread = CurrentThread; + } + catch (CurrentThreadNotAviableException) { + //System.Diagnostics.Debug.Fail("Unable to get LocalVariables. CurrentThreadNotAviableException"); + return new VariableCollection (); + } + return thread.LocalVariables; + } + } + + static public Process CreateProcess(string filename, string workingDirectory, string arguments) + { + MTA2STA m2s = new MTA2STA(); + Process createdProcess = null; + createdProcess = (Process)m2s.CallInSTA(typeof(Process), "StartInternal", new Object[] {filename, workingDirectory, arguments}); + return createdProcess; + } + + static public unsafe Process StartInternal(string filename, string workingDirectory, string arguments) + { + NDebugger.TraceMessage("Executing " + filename); + + _SECURITY_ATTRIBUTES secAttr = new _SECURITY_ATTRIBUTES(); + secAttr.bInheritHandle = 0; + secAttr.lpSecurityDescriptor = IntPtr.Zero; + secAttr.nLength = (uint)sizeof(_SECURITY_ATTRIBUTES); //=12? + + uint[] processStartupInfo = new uint[17]; + processStartupInfo[0] = sizeof(uint) * 17; + uint[] processInfo = new uint[4]; + + ICorDebugProcess outProcess; + + fixed (uint* pprocessStartupInfo = processStartupInfo) + fixed (uint* pprocessInfo = processInfo) + NDebugger.CorDebug.CreateProcess( + filename, // lpApplicationName + null, // lpCommandLine + ref secAttr, // lpProcessAttributes + ref secAttr, // lpThreadAttributes + 1,//TRUE // bInheritHandles + 0, // dwCreationFlags + IntPtr.Zero, // lpEnvironment + null, // lpCurrentDirectory + (uint)pprocessStartupInfo, // lpStartupInfo + (uint)pprocessInfo, // lpProcessInformation, + CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS, // debuggingFlags + out outProcess // ppProcess + ); + + return new Process(outProcess); + } + + public void Break() + { + if (!IsProcessRunning) { + System.Diagnostics.Debug.Fail("Invalid operation"); + return; + } + + corProcess.Stop(5000); // TODO: Hardcoded value + + isProcessRunning = false; + NDebugger.OnDebuggingPaused(PausedReason.Break); + NDebugger.OnIsProcessRunningChanged(); + } + + public void StepInto() + { + try { + CurrentThread.StepInto(); + } catch (CurrentThreadNotAviableException) { + System.Diagnostics.Debug.Fail("Unable to prerform step. CurrentThreadNotAviableException"); + } + } + + public void StepOver() + { + try { + CurrentThread.StepOver(); + } catch (CurrentThreadNotAviableException) { + System.Diagnostics.Debug.Fail("Unable to prerform step. CurrentThreadNotAviableException"); + } + } + + public void StepOut() + { + try { + CurrentThread.StepOut(); + } catch (CurrentThreadNotAviableException) { + System.Diagnostics.Debug.Fail("Unable to prerform step. CurrentThreadNotAviableException"); + } + } + + public void Continue() + { + if (IsProcessRunning) { + System.Diagnostics.Debug.Fail("Invalid operation"); + return; + } + + bool abort = false; + NDebugger.OnDebuggingIsResuming(ref abort); + if (abort == true) return; + + isProcessRunning = true; + if (NDebugger.ManagedCallback.HandlingCallback == false) { + NDebugger.OnDebuggingResumed(); + NDebugger.OnIsProcessRunningChanged(); + } + + corProcess.Continue(0); + } + + public void Terminate() + { + int running; + corProcess.IsRunning(out running); + // Resume stoped tread + if (running == 0) { + Continue(); // TODO: Remove this... + } + // Stop&terminate - both must be called + corProcess.Stop(5000); // TODO: ...and this + corProcess.Terminate(0); + } + + public bool IsProcessRunning { + get { + return isProcessRunning; + } + set { + isProcessRunning = value; + } + } + } +}