Browse Source

Completely rewritten the sate management for Process.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2900 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 18 years ago
parent
commit
a7edbf180a
  1. 8
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/CallStackPad.cs
  2. 6
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs
  3. 8
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/RunningThreadsPad.cs
  4. 85
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs
  5. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/DynamicTreeDebuggerRow.cs
  6. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/TreeViewNode.cs
  7. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
  8. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs
  9. 252
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs
  10. 10
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-Threads.cs
  11. 111
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs
  12. 6
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs
  13. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs
  14. 4
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/DebuggeeState.cs
  15. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Exception.cs
  16. 6
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/Expression.cs
  17. 3
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/MTA2STA.cs
  18. 85
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs
  19. 4
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTestsBase.cs
  20. 2
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Exception.cs
  21. 2
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/ExceptionCustom.cs
  22. 2
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs
  23. 2
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/StackOverflow.cs

8
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/CallStackPad.cs

@ -91,16 +91,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -91,16 +91,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
protected override void SelectProcess(Debugger.Process process)
{
if (debuggedProcess != null) {
debuggedProcess.DebuggeeStateChanged -= debuggedProcess_DebuggeeStateChanged;
debuggedProcess.Paused -= debuggedProcess_Paused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.DebuggeeStateChanged += debuggedProcess_DebuggeeStateChanged;
debuggedProcess.Paused += debuggedProcess_Paused;
}
RefreshPad();
}
void debuggedProcess_DebuggeeStateChanged(object sender, ProcessEventArgs e)
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
RefreshPad();
}
@ -112,7 +112,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -112,7 +112,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
if (frame.HasSymbols) {
if (debuggedProcess.SelectedThread != null) {
debuggedProcess.SelectedThread.SelectedStackFrame = frame;
debuggedProcess.OnDebuggeeStateChanged(); // Force refresh of pads
debuggedProcess.OnPaused(); // Force refresh of pads
}
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWithoutSymbols}", "${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}");

6
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs

@ -207,16 +207,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -207,16 +207,16 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
protected override void SelectProcess(Debugger.Process process)
{
if (debuggedProcess != null) {
debuggedProcess.DebuggeeStateChanged -= debuggedProcess_DebuggeeStateChanged;
debuggedProcess.Paused -= debuggedProcess_Paused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.DebuggeeStateChanged += debuggedProcess_DebuggeeStateChanged;
debuggedProcess.Paused += debuggedProcess_Paused;
}
RefreshPad();
}
void debuggedProcess_DebuggeeStateChanged(object sender, ProcessEventArgs e)
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
RefreshPad();
}

8
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/RunningThreadsPad.cs

@ -96,19 +96,19 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -96,19 +96,19 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
protected override void SelectProcess(Debugger.Process process)
{
if (debuggedProcess != null) {
debuggedProcess.DebuggeeStateChanged -= debuggedProcess_DebuggeeStateChanged;
debuggedProcess.Paused -= debuggedProcess_Paused;
debuggedProcess.ThreadStarted -= debuggedProcess_ThreadStarted;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.DebuggeeStateChanged += debuggedProcess_DebuggeeStateChanged;
debuggedProcess.Paused += debuggedProcess_Paused;
debuggedProcess.ThreadStarted += debuggedProcess_ThreadStarted;
}
runningThreadsList.Items.Clear();
RefreshPad();
}
void debuggedProcess_DebuggeeStateChanged(object sender, ProcessEventArgs e)
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
RefreshPad();
}
@ -132,7 +132,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -132,7 +132,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
if (debuggedProcess.IsPaused) {
if (debuggedProcess != null) {
debuggedProcess.SelectedThread = (Thread)(runningThreadsList.SelectedItems[0].Tag);
debuggedProcess.OnDebuggeeStateChanged(); // Force refresh of pads
debuggedProcess.OnPaused(); // Force refresh of pads
}
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.Threads.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.Threads.ThreadSwitch}");

85
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs

@ -206,7 +206,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -206,7 +206,7 @@ namespace ICSharpCode.SharpDevelop.Services
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
MessageService.ShowMessage(errorCannotStepNoActiveFunction, "${res:XML.MainMenu.DebugMenu.StepInto}");
} else {
debuggedProcess.SelectedStackFrame.StepInto();
debuggedProcess.SelectedStackFrame.AsyncStepInto();
}
}
@ -219,7 +219,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -219,7 +219,7 @@ namespace ICSharpCode.SharpDevelop.Services
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
MessageService.ShowMessage(errorCannotStepNoActiveFunction, "${res:XML.MainMenu.DebugMenu.StepOver}");
} else {
debuggedProcess.SelectedStackFrame.StepOver();
debuggedProcess.SelectedStackFrame.AsyncStepOver();
}
}
@ -232,7 +232,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -232,7 +232,7 @@ namespace ICSharpCode.SharpDevelop.Services
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
MessageService.ShowMessage(errorCannotStepNoActiveFunction, "${res:XML.MainMenu.DebugMenu.StepOut}");
} else {
debuggedProcess.SelectedStackFrame.StepOut();
debuggedProcess.SelectedStackFrame.AsyncStepOut();
}
}
@ -305,12 +305,6 @@ namespace ICSharpCode.SharpDevelop.Services @@ -305,12 +305,6 @@ namespace ICSharpCode.SharpDevelop.Services
public bool CanSetInstructionPointer(string filename, int line, int column)
{
if (debuggedProcess.SelectedThread.CurrentException != null) {
if (!debuggedProcess.SelectedThread.CurrentException.Intercept()) {
// For example, happens on stack overflow
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.ExceptionForm.Error.CannotInterceptException}", "${res:MainWindow.Windows.Debug.ExceptionForm.Title}");
}
}
if (debuggedProcess != null && debuggedProcess.IsPaused && debuggedProcess.SelectedStackFrame != null) {
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.CanSetIP(filename, line, column);
return seg != null;
@ -426,17 +420,15 @@ namespace ICSharpCode.SharpDevelop.Services @@ -426,17 +420,15 @@ namespace ICSharpCode.SharpDevelop.Services
public void SelectProcess(Debugger.Process process)
{
if (debuggedProcess != null) {
debuggedProcess.DebuggingPaused -= debuggedProcess_DebuggingPaused;
debuggedProcess.Paused -= debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown -= debuggedProcess_ExceptionThrown;
debuggedProcess.DebuggeeStateChanged -= debuggedProcess_DebuggeeStateChanged;
debuggedProcess.DebuggingResumed -= debuggedProcess_DebuggingResumed;
debuggedProcess.Resumed -= debuggedProcess_DebuggingResumed;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.DebuggingPaused += debuggedProcess_DebuggingPaused;
debuggedProcess.Paused += debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown += debuggedProcess_ExceptionThrown;
debuggedProcess.DebuggeeStateChanged += debuggedProcess_DebuggeeStateChanged;
debuggedProcess.DebuggingResumed += debuggedProcess_DebuggingResumed;
debuggedProcess.Resumed += debuggedProcess_DebuggingResumed;
}
JumpToCurrentLine();
OnProcessSelected(new ProcessEventArgs(process));
@ -445,57 +437,53 @@ namespace ICSharpCode.SharpDevelop.Services @@ -445,57 +437,53 @@ namespace ICSharpCode.SharpDevelop.Services
void debuggedProcess_DebuggingPaused(object sender, ProcessEventArgs e)
{
OnIsProcessRunningChanged(EventArgs.Empty);
JumpToCurrentLine();
if (currentTooltipRow != null && currentTooltipRow.IsShown) {
AbstractNode updatedNode = Debugger.AddIn.TreeModel.Util.CreateNode(currentTooltipExpression);
try {
currentTooltipRow.SetContentRecursive(updatedNode);
} catch (AbortedBecauseDebugeeStateExpiredException) {
}
}
}
void debuggedProcess_DebuggingResumed(object sender, ProcessEventArgs e)
{
DebuggerService.RemoveCurrentLineMarker();
}
void debuggedProcess_ExceptionThrown(object sender, ExceptionEventArgs e)
{
if (!e.Exception.IsUnhandled) {
// Ignore the exception
e.Continue = true;
e.Process.AsyncContinue();
return;
}
JumpToCurrentLine();
Debugger.Process process = this.DebuggedProcess;
ExceptionForm.Result result = ExceptionForm.Show(e.Exception);
// If the process was killed while the exception form was shown
if (process.HasExpired) return;
if (e.Process.HasExpired) return;
switch (result) {
case ExceptionForm.Result.Break:
e.Continue = false;
// Need to intercept now so that we can evaluate properties in local variables pad
if (!e.Process.SelectedThread.CurrentException.Intercept()) {
// For example, happens on stack overflow
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.ExceptionForm.Error.CannotInterceptException}", "${res:MainWindow.Windows.Debug.ExceptionForm.Title}");
}
break;
case ExceptionForm.Result.Continue:
e.Continue = true;
e.Process.AsyncContinue();
break;
case ExceptionForm.Result.Terminate:
process.Terminate();
e.Process.Terminate();
break;
}
}
void debuggedProcess_DebuggeeStateChanged(object sender, ProcessEventArgs e)
{
JumpToCurrentLine();
if (currentTooltipRow != null && currentTooltipRow.IsShown) {
AbstractNode updatedNode = Debugger.AddIn.TreeModel.Util.CreateNode(currentTooltipExpression);
try {
currentTooltipRow.SetContentRecursive(updatedNode);
} catch (AbortedBecauseDebugeeStateExpiredException) {
}
}
}
void debuggedProcess_DebuggingResumed(object sender, ProcessEventArgs e)
{
if (!e.Process.Evaluating) {
DebuggerService.RemoveCurrentLineMarker();
}
}
public void JumpToCurrentLine()
{
WorkbenchSingleton.MainForm.Activate();
@ -507,20 +495,5 @@ namespace ICSharpCode.SharpDevelop.Services @@ -507,20 +495,5 @@ namespace ICSharpCode.SharpDevelop.Services
}
}
}
public static void DoInPausedState(MethodInvoker action)
{
Debugger.Process process = ((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess;
if (process.IsPaused) {
action();
} else {
EventHandler<ProcessEventArgs> onDebuggingPaused = null;
onDebuggingPaused = delegate {
action();
process.DebuggingPaused -= onDebuggingPaused;
};
process.DebuggingPaused += onDebuggingPaused;
}
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/DynamicTreeDebuggerRow.cs

@ -83,7 +83,7 @@ namespace Debugger.AddIn.TreeModel @@ -83,7 +83,7 @@ namespace Debugger.AddIn.TreeModel
}
// Repaint and process user commands
DebugeeState state = process.DebugeeState;
DebuggeeState state = process.DebuggeeState;
Util.DoEvents();
if (process.IsRunning || state.HasExpired) {
throw new AbortedBecauseDebugeeStateExpiredException();

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/TreeViewNode.cs

@ -70,7 +70,7 @@ namespace Debugger.AddIn.TreeModel @@ -70,7 +70,7 @@ namespace Debugger.AddIn.TreeModel
}
this.Tree.Invalidate();
// Repaint and process user commands
DebugeeState state = localVarPad.Process.DebugeeState;
DebuggeeState state = localVarPad.Process.DebuggeeState;
Util.DoEvents();
if (localVarPad.Process.IsRunning || state.HasExpired) {
throw new AbortedBecauseDebugeeStateExpiredException();

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj

@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
<Compile Include="Src\Control\Stepper.cs" />
<Compile Include="Src\Control\Thread.cs" />
<Compile Include="Src\Debugger\Breakpoint.cs" />
<Compile Include="Src\Debugger\DebugeeState.cs" />
<Compile Include="Src\Debugger\DebuggeeState.cs" />
<Compile Include="Src\Debugger\DebuggerException.cs" />
<Compile Include="Src\Debugger\DebuggerObject.cs" />
<Compile Include="Src\Debugger\Exception.cs" />

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs

@ -115,7 +115,7 @@ namespace Debugger @@ -115,7 +115,7 @@ namespace Debugger
}
process.NotifyEvaluationStarted(newEval);
process.AsyncContinue();
process.AsyncContinue_KeepDebuggeeState();
return newEval;
}

252
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs

@ -12,14 +12,113 @@ namespace Debugger @@ -12,14 +12,113 @@ namespace Debugger
{
public partial class Process
{
bool pauseOnHandledException = false;
// Order:
// Update PauseSession
// Update DebugSession
// Raise event
#region Events
public event EventHandler<ProcessEventArgs> Paused;
public event EventHandler<ProcessEventArgs> Resumed;
// HACK: public
public virtual void OnPaused()
{
TraceMessage ("Debugger event: OnPaused()");
if (Paused != null) {
Paused(this, new ProcessEventArgs(this));
}
}
protected virtual void OnResumed()
{
TraceMessage ("Debugger event: OnResumed()");
if (Resumed != null) {
Resumed(this, new ProcessEventArgs(this));
}
}
#endregion
#region PauseSession
PauseSession pauseSession;
/// <summary>
/// Indentification of the current debugger session. This value changes whenever debugger is continued
/// </summary>
public PauseSession PauseSession {
get {
return pauseSession;
}
}
internal void CreatePauseSession(PausedReason pauseReason)
{
if (pauseSession != null) {
throw new DebuggerException("Pause session already created");
}
pauseSession = new PauseSession(pauseReason);
}
internal void ExpirePauseSession()
{
if (pauseSession == null) {
throw new DebuggerException("Pause session already expired");
}
PauseSession oldPauseSession = pauseSession;
pauseSession = null;
oldPauseSession.NotifyHasExpired();
}
#endregion
#region DebugeeState
DebuggeeState debuggeeState;
/// <summary>
/// Indentification of the state of the debugee. This value changes whenever the state of the debugee significatntly changes
/// </summary>
public DebuggeeState DebuggeeState {
get {
return debuggeeState;
}
}
internal void CreateDebuggeeState()
{
if (debuggeeState != null) {
throw new DebuggerException("Debugee state already created");
}
if (pauseSession == null) {
throw new DebuggerException("Pause session must exist");
}
debuggeeState = new DebuggeeState(this);
}
internal void ExpireDebuggeeState()
{
if (debuggeeState == null) {
throw new DebuggerException("Debugee state already expired");
}
if (pauseSession != null) {
throw new DebuggerException("Pause session must not exist");
}
DebuggeeState oldDebugeeState = debuggeeState;
debuggeeState = null;
oldDebugeeState.NotifyHasExpired();
}
DebugeeState debugeeState;
#endregion
#region Exceptions
bool pauseOnHandledException = false;
public event EventHandler<ExceptionEventArgs> ExceptionThrown;
public event EventHandler<ProcessEventArgs> DebuggingResumed;
public event EventHandler<ProcessEventArgs> DebuggingPaused;
public event EventHandler<ProcessEventArgs> DebuggeeStateChanged;
public bool PauseOnHandledException {
get {
@ -30,99 +129,124 @@ namespace Debugger @@ -30,99 +129,124 @@ namespace Debugger
}
}
protected virtual void OnExceptionThrown(ExceptionEventArgs e)
protected internal virtual void OnExceptionThrown(ExceptionEventArgs e)
{
TraceMessage ("Debugger event: OnExceptionThrown()");
if (ExceptionThrown != null) {
ExceptionThrown(this, e);
}
}
internal virtual void OnDebuggingResumed()
#endregion
internal void AssertPaused()
{
TraceMessage ("Debugger event: OnDebuggingResumed()");
if (DebuggingResumed != null) {
DebuggingResumed(this, new ProcessEventArgs(this));
if (IsRunning) {
throw new DebuggerException("Process is not paused.");
}
}
protected virtual void OnDebuggingPaused()
internal void AssertRunning()
{
TraceMessage ("Debugger event: OnDebuggingPaused (" + PausedReason.ToString() + ")");
if (DebuggingPaused != null) {
DebuggingPaused(this, new ProcessEventArgs(this));
if (IsPaused) {
throw new DebuggerException("Process is not running.");
}
}
// HACK: should not be public
public virtual void OnDebuggeeStateChanged()
{
TraceMessage ("Debugger event: OnDebuggeeStateChanged (" + PausedReason.ToString() + ")");
if (DebuggeeStateChanged != null) {
DebuggeeStateChanged(this, new ProcessEventArgs(this));
public bool IsRunning {
get {
return pauseSession == null;
}
}
public StackFrame SelectedStackFrame {
public bool IsPaused {
get {
if (SelectedThread == null) {
return null;
} else {
return SelectedThread.SelectedStackFrame;
}
return !IsRunning;
}
}
/// <summary>
/// Indentification of the state of the debugee. This value changes whenever the state of the debugee significatntly changes
/// </summary>
public DebugeeState DebugeeState {
get {
return debugeeState;
public void Break()
{
AssertRunning();
corProcess.Stop(5000); // TODO: Hardcoded value
CreatePauseSession(PausedReason.ForcedBreak);
CreateDebuggeeState();
SelectMostRecentStackFrameWithLoadedSymbols();
DisableAllSteppers();
OnPaused();
}
#region Convenience methods
public void Continue()
{
AsyncContinue();
WaitForPause();
}
#endregion
public void AsyncContinue()
{
AssertPaused();
if (callbackInterface.IsInCallback) {
throw new DebuggerException("Can not continue from within callback.");
}
ExpirePauseSession();
ExpireDebuggeeState();
OnResumed();
corProcess.Continue(0);
}
/// <summary>
/// The reason why the debugger is paused.
/// Thows an DebuggerException if debugger is not paused.
/// </summary>
public PausedReason PausedReason {
get {
AssertPaused();
return PauseSession.PausedReason;
internal void AsyncContinue_KeepDebuggeeState()
{
AssertPaused();
if (callbackInterface.IsInCallback) {
throw new DebuggerException("Can not continue from within callback.");
}
ExpirePauseSession();
corProcess.Continue(0);
}
public void Terminate()
{
// Resume stoped tread
if (this.IsPaused) {
// We might get more callbacks so we should maintain consistent sate
AsyncContinue(); // TODO: Remove this...
}
// Expose race condition - drain callback queue
System.Threading.Thread.Sleep(0);
// Stop&terminate - both must be called
corProcess.Stop(5000); // TODO: ...and this
corProcess.Terminate(0);
}
internal void Pause(bool debuggeeStateChanged)
internal void SelectMostRecentStackFrameWithLoadedSymbols()
{
if (this.SelectedThread == null && this.Threads.Count > 0) {
this.SelectedThread = this.Threads[0];
}
if (this.SelectedThread != null) {
// Disable all steppers - do not Deactivate since stack frame tracking still needs them
foreach(Stepper s in this.SelectedThread.Steppers) {
s.PauseWhenComplete = false;
}
this.SelectedThread.SelectedStackFrame = this.SelectedThread.MostRecentStackFrameWithLoadedSymbols;
}
if (debuggeeStateChanged) {
if (debugeeState != null) {
debugeeState.NotifyHasExpired();
}
debugeeState = new DebugeeState(this);
OnDebuggeeStateChanged();
// The process might have been resumed by the event
}
if (IsPaused) {
OnDebuggingPaused();
if (PausedReason == PausedReason.Exception) {
ExceptionEventArgs args = new ExceptionEventArgs(this, SelectedThread.CurrentException);
OnExceptionThrown(args);
if (args.Continue) {
this.AsyncContinue();
}
}
internal void DisableAllSteppers()
{
foreach(Thread thread in this.Threads) {
foreach(Stepper stepper in thread.Steppers) {
stepper.PauseWhenComplete = false;
}
}
}

10
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-Threads.cs

@ -14,6 +14,7 @@ namespace Debugger @@ -14,6 +14,7 @@ namespace Debugger
{
public partial class Process
{
Thread selectedThread;
List<Thread> threadCollection = new List<Thread>();
public event EventHandler<ThreadEventArgs> ThreadStarted;
@ -25,6 +26,15 @@ namespace Debugger @@ -25,6 +26,15 @@ namespace Debugger
}
}
public Thread SelectedThread {
get {
return selectedThread;
}
set {
selectedThread = value;
}
}
public IList<Thread> Threads {
get {
List<Thread> threads = new List<Thread>();

111
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs

@ -19,8 +19,7 @@ namespace Debugger @@ -19,8 +19,7 @@ namespace Debugger
ICorDebugProcess corProcess;
ManagedCallback callbackInterface;
Thread selectedThread;
PauseSession pauseSession;
#region IExpirable
bool hasExpired = false;
@ -39,23 +38,17 @@ namespace Debugger @@ -39,23 +38,17 @@ namespace Debugger
if (Expired != null) {
Expired(this, new ProcessEventArgs(this));
}
if (DebuggeeState != null) {
ExpireDebuggeeState();
}
if (PauseSession != null) {
ExpirePauseSession();
}
debugger.RemoveProcess(this);
}
}
/// <summary>
/// Indentification of the current debugger session. This value changes whenever debugger is continued
/// </summary>
public PauseSession PauseSession {
get {
return pauseSession;
}
}
internal void NotifyPaused(PauseSession pauseSession)
{
this.pauseSession = pauseSession;
}
#endregion
public NDebugger Debugger {
get {
@ -76,21 +69,12 @@ namespace Debugger @@ -76,21 +69,12 @@ namespace Debugger
this.callbackInterface = new ManagedCallback(this);
}
internal ICorDebugProcess CorProcess {
get {
return corProcess;
}
}
public Thread SelectedThread {
get {
return selectedThread;
}
set {
selectedThread = value;
}
}
static public Process CreateProcess(NDebugger debugger, string filename, string workingDirectory, string arguments)
{
@ -134,80 +118,19 @@ namespace Debugger @@ -134,80 +118,19 @@ namespace Debugger
return new Process(debugger, outProcess);
}
public void Break()
{
AssertRunning();
corProcess.Stop(5000); // TODO: Hardcoded value
pauseSession = new PauseSession(PausedReason.ForcedBreak);
Pause(true);
}
public void Continue()
{
AsyncContinue();
WaitForPause();
}
public void AsyncContinue()
{
AssertPaused();
pauseSession.NotifyHasExpired();
pauseSession = null;
OnDebuggingResumed();
corProcess.Continue(0);
}
public void Terminate()
{
// Resume stoped tread
if (this.IsPaused) {
// We might get more callbacks so we should maintain consistent sate
this.AsyncContinue(); // TODO: Remove this...
}
// Expose race condition - drain callback queue
System.Threading.Thread.Sleep(0);
// Stop&terminate - both must be called
corProcess.Stop(5000); // TODO: ...and this
corProcess.Terminate(0);
}
public bool IsRunning {
get {
return pauseSession == null;
}
}
public bool IsPaused {
public string DebuggeeVersion {
get {
return !IsRunning;
}
}
public void AssertPaused()
{
if (IsRunning) {
throw new DebuggerException("Process is not paused.");
}
}
public void AssertRunning()
{
if (IsPaused) {
throw new DebuggerException("Process is not running.");
return debugger.DebuggeeVersion;
}
}
public string DebuggeeVersion {
public StackFrame SelectedStackFrame {
get {
return debugger.DebuggeeVersion;
if (SelectedThread == null) {
return null;
} else {
return SelectedThread.SelectedStackFrame;
}
}
}

6
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs

@ -314,8 +314,10 @@ namespace Debugger @@ -314,8 +314,10 @@ namespace Debugger
} else {
// invalidates all frames and chains for the current thread
CorILFrame.SetIP((uint)ilOffset);
process.NotifyPaused(new PauseSession(PausedReason.SetIP));
process.Pause(false);
process.ExpirePauseSession();
process.CreatePauseSession(PausedReason.SetIP);
process.SelectMostRecentStackFrameWithLoadedSymbols();
process.OnPaused();
}
} catch {
return null;

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs

@ -250,8 +250,8 @@ namespace Debugger @@ -250,8 +250,8 @@ namespace Debugger
public StackFrame SelectedStackFrame {
get {
// Forum-20456: Do not return expired StackFrame
if (selectedStackFrame != null && selectedStackFrame.HasExpired) return null;
if (process.IsRunning) return null;
return selectedStackFrame;
}
set {

4
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/DebugeeState.cs → src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/DebuggeeState.cs

@ -13,7 +13,7 @@ namespace Debugger @@ -13,7 +13,7 @@ namespace Debugger
/// Unique identifier of the state of the debugee.
/// Changes when debuggee is stepped, but not when properity is evaluated.
/// </summary>
public class DebugeeState: IExpirable
public class DebuggeeState: IExpirable
{
Process process;
bool hasExpired = false;
@ -43,7 +43,7 @@ namespace Debugger @@ -43,7 +43,7 @@ namespace Debugger
}
}
public DebugeeState(Process process)
public DebuggeeState(Process process)
{
this.process = process;
}

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Exception.cs

@ -114,7 +114,7 @@ namespace Debugger @@ -114,7 +114,7 @@ namespace Debugger
}
thread.CurrentException = null;
Process.AsyncContinue();
Process.AsyncContinue_KeepDebuggeeState();
Process.WaitForPause();
return true;
}
@ -122,18 +122,8 @@ namespace Debugger @@ -122,18 +122,8 @@ namespace Debugger
public class ExceptionEventArgs: ProcessEventArgs
{
bool @continue;
Exception exception;
public bool Continue {
get {
return @continue;
}
set {
@continue = value;
}
}
public Exception Exception {
get {
return exception;

6
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/Expression.cs

@ -17,7 +17,7 @@ namespace Debugger.Expressions @@ -17,7 +17,7 @@ namespace Debugger.Expressions
public abstract partial class Expression: DebuggerObject
{
static Dictionary<Expression, Value> expressionCache;
static DebugeeState expressionCache_debuggerState;
static DebuggeeState expressionCache_debuggerState;
static Thread expressionCache_thread;
static int expressionCache_stackDepth;
@ -39,12 +39,12 @@ namespace Debugger.Expressions @@ -39,12 +39,12 @@ namespace Debugger.Expressions
Value GetFromCache(StackFrame context)
{
if (expressionCache == null ||
expressionCache_debuggerState != context.Process.DebugeeState ||
expressionCache_debuggerState != context.Process.DebuggeeState ||
expressionCache_thread != context.Thread ||
expressionCache_stackDepth != context.Depth)
{
expressionCache = new Dictionary<Expression, Value>();
expressionCache_debuggerState = context.Process.DebugeeState;
expressionCache_debuggerState = context.Process.DebuggeeState;
expressionCache_thread = context.Thread;
expressionCache_stackDepth = context.Depth;
context.Process.TraceMessage("Expression cache cleared");

3
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/MTA2STA.cs

@ -142,7 +142,8 @@ namespace Debugger.Interop @@ -142,7 +142,8 @@ namespace Debugger.Interop
if (!hasReturnValue && callMethod == CallMethod.HiddenFormWithTimeout) {
// Give it 5 seconds to run
if (!callDone.WaitOne(5000, true)) {
System.Console.WriteLine("Call time out! Continuing...");
System.Console.WriteLine("Call time out! (continuing)");
System.Console.WriteLine(new System.Diagnostics.StackTrace(true).ToString());
}
} else {
callDone.WaitOne();

85
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs

@ -25,6 +25,7 @@ namespace Debugger @@ -25,6 +25,7 @@ namespace Debugger
{
Process process;
bool pauseProcessInsteadOfContinue;
bool isInCallback = false;
[Debugger.Tests.Ignore]
public Process Process {
@ -33,6 +34,10 @@ namespace Debugger @@ -33,6 +34,10 @@ namespace Debugger
}
}
public bool IsInCallback {
get { return isInCallback; }
}
public ManagedCallback(Process process)
{
this.process = process;
@ -40,28 +45,28 @@ namespace Debugger @@ -40,28 +45,28 @@ namespace Debugger
void EnterCallback(PausedReason pausedReason, string name, ICorDebugProcess pProcess)
{
isInCallback = true;
process.TraceMessage("Callback: " + name);
System.Diagnostics.Debug.Assert(process.CorProcess == pProcess);
// Check state
if (process.IsRunning ||
// After break is pressed we may receive some messages that were already queued
process.PauseSession.PausedReason == PausedReason.ForcedBreak ||
// ExitProcess may be called at any time when debuggee is killed
name == "ExitProcess") {
if (process.IsPaused && process.PauseSession.PausedReason == PausedReason.ForcedBreak && name != "ExitProcess") {
process.TraceMessage("Processing post-break callback");
// Continue the break, process is still breaked because of the callback
process.AsyncContinue();
pauseProcessInsteadOfContinue = true;
} else {
pauseProcessInsteadOfContinue = false;
}
process.NotifyPaused(new PauseSession(pausedReason));
} else {
throw new DebuggerException("Invalid state at the start of callback");
// After break is pressed we may receive some messages that were already queued
if (process.IsPaused && process.PauseSession.PausedReason == PausedReason.ForcedBreak) {
process.TraceMessage("Processing post-break callback");
// Continue the break, process is still breaked because of the callback
process.ExpirePauseSession();
process.CorProcess.Continue(0);
pauseProcessInsteadOfContinue = true;
process.CreatePauseSession(pausedReason);
return;
}
if (process.IsRunning) {
process.CreatePauseSession(pausedReason);
return;
}
throw new DebuggerException("Invalid state at the start of callback");
}
void EnterCallback(PausedReason pausedReason, string name, ICorDebugAppDomain pAppDomain)
@ -78,10 +83,15 @@ namespace Debugger @@ -78,10 +83,15 @@ namespace Debugger
void ExitCallback_Continue()
{
if (pauseProcessInsteadOfContinue) {
pauseProcessInsteadOfContinue = false;
ExitCallback_Paused();
} else {
process.AsyncContinue();
return;
}
process.ExpirePauseSession();
process.CorProcess.Continue(0);
isInCallback = false;
}
void ExitCallback_Paused()
@ -89,8 +99,36 @@ namespace Debugger @@ -89,8 +99,36 @@ namespace Debugger
if (process.Evaluating) {
// Ignore events during property evaluation
ExitCallback_Continue();
return;
}
process.SelectMostRecentStackFrameWithLoadedSymbols();
process.DisableAllSteppers();
if (process.PauseSession.PausedReason == PausedReason.EvalComplete ||
process.PauseSession.PausedReason == PausedReason.ExceptionIntercepted) {
// Keep debugge state
// Do not raise events
} else {
process.Pause(process.PauseSession.PausedReason != PausedReason.EvalComplete);
process.CreateDebuggeeState();
// Raise the pause event outside the callback
process.Debugger.MTA2STA.AsyncCall(RaiseEvents);
}
isInCallback = false;
}
void RaiseEvents()
{
if (process.PauseSession.PausedReason == PausedReason.Exception) {
ExceptionEventArgs args = new ExceptionEventArgs(process, process.SelectedThread.CurrentException);
process.OnExceptionThrown(args);
// The event could have resumed the process
}
if (process.IsPaused) {
process.OnPaused();
// The event could have resumed the process
}
}
@ -383,7 +421,8 @@ namespace Debugger @@ -383,7 +421,8 @@ namespace Debugger
public void ExitProcess(ICorDebugProcess pProcess)
{
EnterCallback(PausedReason.Other, "ExitProcess", pProcess);
// ExitProcess may be called at any time when debuggee is killed
process.TraceMessage("Callback: ExitProcess");
process.NotifyHasExpired();
}

4
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTestsBase.cs

@ -139,8 +139,8 @@ namespace Debugger.Tests @@ -139,8 +139,8 @@ namespace Debugger.Tests
process.ModuleLoaded += delegate(object sender, ModuleEventArgs e) {
LogEvent("ModuleLoaded", e.Module.Filename).SetAttribute("symbols", e.Module.SymbolsLoaded.ToString());
};
process.DebuggingPaused += delegate(object sender, ProcessEventArgs e) {
LogEvent("DebuggingPaused", e.Process.PausedReason.ToString());
process.Paused += delegate(object sender, ProcessEventArgs e) {
LogEvent("DebuggingPaused", e.Process.PauseSession.PausedReason.ToString());
};
// process.DebuggingResumed += delegate(object sender, ProcessEventArgs e) {
// LogEvent("DebuggingResumed", e.Process.PausedReason.ToString());

2
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Exception.cs

@ -40,8 +40,8 @@ namespace Debugger.Tests { @@ -40,8 +40,8 @@ namespace Debugger.Tests {
<ProcessStarted />
<ModuleLoaded symbols="False">mscorlib.dll</ModuleLoaded>
<ModuleLoaded symbols="True">Exception.exe</ModuleLoaded>
<DebuggingPaused>Exception</DebuggingPaused>
<ExceptionThrown>test</ExceptionThrown>
<DebuggingPaused>Exception</DebuggingPaused>
<ProcessExited />
</Test>
</DebuggerTests>

2
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/ExceptionCustom.cs

@ -48,8 +48,8 @@ namespace Debugger.Tests { @@ -48,8 +48,8 @@ namespace Debugger.Tests {
<ProcessStarted />
<ModuleLoaded symbols="False">mscorlib.dll</ModuleLoaded>
<ModuleLoaded symbols="True">ExceptionCustom.exe</ModuleLoaded>
<DebuggingPaused>Exception</DebuggingPaused>
<ExceptionThrown>test</ExceptionThrown>
<DebuggingPaused>Exception</DebuggingPaused>
<ProcessExited />
</Test>
</DebuggerTests>

2
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs

@ -627,7 +627,6 @@ namespace Debugger.Tests { @@ -627,7 +627,6 @@ namespace Debugger.Tests {
</Item>
</SelectedStackFrame-GetArguments>
<DebuggingPaused>Break</DebuggingPaused>
<DebuggingPaused>EvalComplete</DebuggingPaused>
<Prop Type="Value" ToString="gClass.Prop = 0">
<ArrayDimensions exception="Value is not an array" />
<ArrayLenght exception="Value is not an array" />
@ -643,7 +642,6 @@ namespace Debugger.Tests { @@ -643,7 +642,6 @@ namespace Debugger.Tests {
<PrimitiveValue>0</PrimitiveValue>
<Type>System.Int32</Type>
</Prop>
<DebuggingPaused>EvalComplete</DebuggingPaused>
<StaticProp Type="Value" ToString="Debugger.Tests.TestPrograms.GenericClass&lt;System.Int32,System.String&gt;.StaticProp = 0">
<ArrayDimensions exception="Value is not an array" />
<ArrayLenght exception="Value is not an array" />

2
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/StackOverflow.cs

@ -50,8 +50,8 @@ namespace Debugger.Tests { @@ -50,8 +50,8 @@ namespace Debugger.Tests {
<ModuleLoaded symbols="False">mscorlib.dll</ModuleLoaded>
<ModuleLoaded symbols="True">StackOverflow.exe</ModuleLoaded>
<DebuggingPaused>Break</DebuggingPaused>
<DebuggingPaused>Exception</DebuggingPaused>
<ExceptionThrown>&lt;null&gt;</ExceptionThrown>
<DebuggingPaused>Exception</DebuggingPaused>
<LastStackFrame Type="StackFrame" ToString="Debugger.Tests.TestPrograms.StackOverflow.Fun">
<ArgumentCount>1</ArgumentCount>
<Depth>0</Depth>

Loading…
Cancel
Save