From 55e8e0bd7e0ce9bbe8fb247d1d34bd44128f3944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Wed, 16 Jul 2008 00:29:36 +0000 Subject: [PATCH] Rewritten the stepping engine; Extensive unit test for stepping git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3229 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Options/DebuggingOptions.cs | 35 +-- .../Src/Options/DebuggingOptionsPanel.cs | 6 +- .../Src/Options/DebuggingSymbolsPanel.cs | 8 +- .../Project/Src/Service/WindowsDebugger.cs | 11 + .../Project/Src/Control/Module.cs | 143 +--------- .../Project/Src/Control/NDebugger.cs | 22 ++ .../Src/Control/Process-StateControl.cs | 3 +- .../Project/Src/Control/StackFrame.cs | 37 ++- .../Project/Src/Control/Stepper.cs | 127 +++++---- .../Project/Src/Control/Thread.cs | 6 + .../Project/Src/Debugger/Options.cs | 56 +--- .../Project/Src/Internal/ManagedCallback.cs | 35 ++- .../Project/Src/Metadata/DebugType.cs | 16 +- .../Project/Src/Metadata/MethodInfo.cs | 131 ++++++++- .../Project/Debugger.Tests.csproj | 1 - .../Src/TestPrograms/DebuggerAttributes.cs | 160 ----------- .../Project/Src/TestPrograms/Generics.cs | 32 +-- .../Project/Src/TestPrograms/Metadata.cs | 48 ++-- .../Project/Src/TestPrograms/Stepping.cs | 269 ++++++++++++++---- 19 files changed, 579 insertions(+), 567 deletions(-) delete mode 100644 src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebuggerAttributes.cs diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptions.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptions.cs index 314de92003..36d20fa23a 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptions.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptions.cs @@ -20,35 +20,10 @@ namespace ICSharpCode.SharpDevelop.Services } } - bool iCorDebugVisualizerEnabled; - bool showValuesInHexadecimal; - bool showArgumentNames; - bool showArgumentValues; - bool showExternalMethods; - - public bool ICorDebugVisualizerEnabled { - get { return iCorDebugVisualizerEnabled; } - set { iCorDebugVisualizerEnabled = value; } - } - - public bool ShowValuesInHexadecimal { - get { return showValuesInHexadecimal; } - set { showValuesInHexadecimal = value; } - } - - public bool ShowArgumentNames { - get { return showArgumentNames; } - set { showArgumentNames = value; } - } - - public bool ShowArgumentValues { - get { return showArgumentValues; } - set { showArgumentValues = value; } - } - - public bool ShowExternalMethods { - get { return showExternalMethods; } - set { showExternalMethods = value; } - } + public bool ICorDebugVisualizerEnabled; + public bool ShowValuesInHexadecimal; + public bool ShowArgumentNames; + public bool ShowArgumentValues; + public bool ShowExternalMethods; } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptionsPanel.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptionsPanel.cs index ba2f1ee975..ee41b00044 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptionsPanel.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingOptionsPanel.cs @@ -5,11 +5,11 @@ // $Revision$ // +using Debugger; using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; - using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Services; @@ -55,6 +55,10 @@ namespace ICSharpCode.SharpDevelop.Gui.OptionPanels opt.StepOverSingleLineProperties = stepOverSingleLineProperties.Checked; opt.StepOverFieldAccessProperties = stepOverFieldAccessProperties.Checked; + Process proc = WindowsDebugger.CurrentProcess; + if (proc != null) { + proc.Debugger.ResetJustMyCodeStatus(); + } return true; } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingSymbolsPanel.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingSymbolsPanel.cs index b34e4ad1d8..20c8074a7f 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingSymbolsPanel.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Options/DebuggingSymbolsPanel.cs @@ -5,11 +5,11 @@ // $Revision$ // +using Debugger; using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; - using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Services; @@ -37,7 +37,11 @@ namespace ICSharpCode.SharpDevelop.Gui.OptionPanels public override bool StorePanelContents() { DebuggingOptions.Instance.SymbolsSearchPaths = pathList.GetList(); - + Process proc = WindowsDebugger.CurrentProcess; + if (proc != null) { + proc.Debugger.ReloadModuleSymbols(); + proc.Debugger.ResetJustMyCodeStatus(); + } return true; } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs index 0af552690c..1fa0daa9fd 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs @@ -93,6 +93,17 @@ namespace ICSharpCode.SharpDevelop.Services } } + public static Debugger.Process CurrentProcess { + get { + WindowsDebugger dbgr = DebuggerService.CurrentDebugger as WindowsDebugger; + if (dbgr != null && dbgr.DebuggedProcess != null) { + return dbgr.DebuggedProcess; + } else { + return null; + } + } + } + protected virtual void OnProcessSelected(ProcessEventArgs e) { if (ProcessSelected != null) { diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Module.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Module.cs index 15f3a518b7..be6cd698d8 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Module.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Module.cs @@ -176,9 +176,11 @@ namespace Debugger fullPath = pModule.Name; LoadSymbols(process.Options.SymbolsSearchPaths); - SetJustMyCodeStatus(); + + ResetJustMyCodeStatus(); } + /// Try to load the debugging symbols (.pdb) from the given path public void LoadSymbols(string[] searchPath) { if (symReader == null) { @@ -189,146 +191,17 @@ namespace Debugger } } - /// - /// Finds all classes and methods marked with DebuggerNonUserCode attribute - /// and marks them for JMC so that they are not stepped into - /// - public void SetJustMyCodeStatus() + /// Sets all code as being 'my code'. The code will be gradually + /// set to not-user-code as encountered acording to stepping options + public void ResetJustMyCodeStatus() { - DateTime start, end; uint unused = 0; - - if (!this.Process.Options.EnableJustMyCode) { - corModule.CastTo().SetJMCStatus(1, 0, ref unused); - return; - } - - if (!this.HasSymbols) { + if (this.Process.Options.StepOverNoSymbols && !this.HasSymbols) { + // Optimization - set the code as non-user right away corModule.CastTo().SetJMCStatus(0, 0, ref unused); return; } - - this.Process.TraceMessage("JMC for " + this.Filename); - start = Util.HighPrecisionTimer.Now; - // By default the code is my code corModule.CastTo().SetJMCStatus(1, 0, ref unused); - end = Util.HighPrecisionTimer.Now; - this.Process.TraceMessage(" * Defualt ({0} ms)", (end - start).TotalMilliseconds); - - start = Util.HighPrecisionTimer.Now; - // Apply non-user code attributes - if (this.Process.Options.StepOverDebuggerAttributes) { - foreach(CustomAttributeProps ca in metaData.EnumCustomAttributeProps(0, 0)) { - MemberRefProps constructorMethod = metaData.GetMemberRefProps(ca.Type); - TypeRefProps attributeType = metaData.GetTypeRefProps(constructorMethod.DeclaringType); - if (attributeType.Name == "System.Diagnostics.DebuggerStepThroughAttribute" || - attributeType.Name == "System.Diagnostics.DebuggerNonUserCodeAttribute" || - attributeType.Name == "System.Diagnostics.DebuggerHiddenAttribute") - { - if (ca.Owner >> 24 == 0x02) { // TypeDef - ICorDebugClass2 corClass = corModule.GetClassFromToken(ca.Owner).CastTo(); - corClass.SetJMCStatus(0 /* false */); - if (this.Process.Options.Verbose) { - this.Process.TraceMessage("Class {0} marked as non-user code", metaData.GetTypeDefProps(ca.Owner).Name); - } - } - if (ca.Owner >> 24 == 0x06) { // MethodDef - DisableJustMyCode(ca.Owner); - } - } - } - } - end = Util.HighPrecisionTimer.Now; - this.Process.TraceMessage(" * Attributes ({0} ms)", (end - start).TotalMilliseconds); - - start = Util.HighPrecisionTimer.Now; - // Mark all methods without symbols as non-user code - if (this.Process.Options.StepOverDebuggerAttributes) { // TODO: Remove - foreach(uint typeDef in metaData.EnumTypeDefs()) { - foreach(uint methodDef in metaData.EnumMethods(typeDef)) { - if (!HasMethodSymbols(methodDef)) { - DisableJustMyCode(methodDef); - } - } - } - } - end = Util.HighPrecisionTimer.Now; - this.Process.TraceMessage(" * All functions ({0} ms)", (end - start).TotalMilliseconds); - - start = Util.HighPrecisionTimer.Now; - // Skip properties - if (this.Process.Options.StepOverAllProperties) { - foreach(uint typeDef in metaData.EnumTypeDefs()) { - foreach(PropertyProps prop in metaData.EnumPropertyProps(typeDef)) { - if ((prop.GetterMethod & 0xFFFFFF) != 0) { - if (!Process.Options.StepOverSingleLineProperties || IsSingleLine(prop.GetterMethod)) { - DisableJustMyCode(prop.GetterMethod); - } - } - if ((prop.SetterMethod & 0xFFFFFF) != 0) { - if (!Process.Options.StepOverSingleLineProperties || IsSingleLine(prop.SetterMethod)) { - DisableJustMyCode(prop.SetterMethod); - } - } - } - } - } - end = Util.HighPrecisionTimer.Now; - this.Process.TraceMessage(" * Properties ({0} ms)", (end - start).TotalMilliseconds); - -// this.Process.TraceMessage("Set Just-My-Code for module \"{0}\" ({1} ms)", this.Filename, (end - start).TotalMilliseconds); - } - - bool HasMethodSymbols(uint methodDef) - { - try { - return this.SymReader.GetMethod(methodDef) != null; - } catch (COMException) { - // Symbols not found - return false; - } - } - - void DisableJustMyCode(uint methodDef) - { - MethodProps methodProps = metaData.GetMethodProps(methodDef); - TypeDefProps typeProps = metaData.GetTypeDefProps(methodProps.ClassToken); - - ICorDebugFunction2 corFunction = corModule.GetFunctionFromToken(methodProps.Token).CastTo(); - corFunction.SetJMCStatus(0 /* false */); - if (this.Process.Options.Verbose) { - this.Process.TraceMessage("Funciton {0}.{1} marked as non-user code", typeProps.Name, methodProps.Name); - } - } - - bool IsSingleLine(uint methodDef) - { - ISymUnmanagedMethod symMethod; - try { - symMethod = this.SymReader.GetMethod(methodDef); - } catch (COMException) { - return false; // No symbols - can not determine - } - List seqPoints = new List(symMethod.SequencePoints); - seqPoints.Sort(); - - // Remove initial "{" - if (seqPoints.Count > 0 && - seqPoints[0].Line == seqPoints[0].EndLine && - seqPoints[0].EndColumn - seqPoints[0].Column <= 1) { - seqPoints.RemoveAt(0); - } - - // Remove last "}" - int listIndex = seqPoints.Count - 1; - if (seqPoints.Count > 0 && - seqPoints[listIndex].Line == seqPoints[listIndex].EndLine && - seqPoints[listIndex].EndColumn - seqPoints[listIndex].Column <= 1) { - seqPoints.RemoveAt(listIndex); - } - - // Is single line - return seqPoints.Count == 0 || seqPoints[0].Line == seqPoints[seqPoints.Count - 1].EndLine; } public void ApplyChanges(byte[] metadata, byte[] il) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger.cs index 1a2324310a..0a3c42068c 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger.cs @@ -204,6 +204,28 @@ namespace Debugger } } } + + /// Try to load module symbols using the search path defined in the options + public void ReloadModuleSymbols() + { + foreach(Process process in this.Processes) { + foreach(Module module in process.Modules) { + module.LoadSymbols(process.Options.SymbolsSearchPaths); + } + } + TraceMessage("Reloaded symbols"); + } + + /// Reset the just my code status of modules. Use this after changing any stepping options. + public void ResetJustMyCodeStatus() + { + foreach(Process process in this.Processes) { + foreach(Module module in process.Modules) { + module.ResetJustMyCodeStatus(); + } + } + TraceMessage("Just my code reseted"); + } } [Serializable] diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs index 09ce5919f3..ca0fe243ca 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs @@ -273,8 +273,9 @@ namespace Debugger internal void DisableAllSteppers() { foreach(Thread thread in this.Threads) { + thread.CurrentStepIn = null; foreach(Stepper stepper in thread.Steppers) { - stepper.PauseWhenComplete = false; + stepper.Ignore = true; } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs index 10ba9da187..e96f33769d 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs @@ -169,7 +169,7 @@ namespace Debugger /// Step out of the stack frame public void AsyncStepOut() { - new Stepper(this, "StackFrame step out").StepOut(); + Stepper.StepOut(this, "normal"); process.AsyncContinue(DebuggeeStateAction.Clear); } @@ -186,9 +186,17 @@ namespace Debugger } if (stepIn) { - new Stepper(this, "StackFrame step in").StepIn(nextSt.StepRanges); + Stepper stepInStepper = Stepper.StepIn(this, nextSt.StepRanges, "normal"); + this.Thread.CurrentStepIn = stepInStepper; + Stepper clearCurrentStepIn = Stepper.StepOut(this, "clear current step in"); + clearCurrentStepIn.StepComplete += delegate { + if (this.Thread.CurrentStepIn == stepInStepper) { + this.Thread.CurrentStepIn = null; + } + }; + clearCurrentStepIn.Ignore = true; } else { - new Stepper(this, "StackFrame step over").StepOver(nextSt.StepRanges); + Stepper.StepOver(this, nextSt.StepRanges, "normal"); } process.AsyncContinue(DebuggeeStateAction.Clear); @@ -378,5 +386,28 @@ namespace Debugger } #endregion + + public override bool Equals(object obj) + { + StackFrame other = obj as StackFrame; + return + other != null && + other.Thread == this.Thread && + other.ChainIndex == this.ChainIndex && + other.FrameIndex == this.FrameIndex && + other.MethodInfo == this.methodInfo; + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked { + if (thread != null) hashCode += 1000000009 * thread.GetHashCode(); + if (methodInfo != null) hashCode += 1000000093 * methodInfo.GetHashCode(); + hashCode += 1000000097 * chainIndex.GetHashCode(); + hashCode += 1000000103 * frameIndex.GetHashCode(); + } + return hashCode; + } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Stepper.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Stepper.cs index 37c04f64e2..0650fce1c4 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Stepper.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Stepper.cs @@ -11,83 +11,67 @@ using Debugger.Wrappers.CorDebug; namespace Debugger { - public class Stepper + enum StepperOperation {StepIn, StepOver, StepOut}; + + class Stepper { - public enum StepperOperation {Idle, StepIn, StepOver, StepOut}; - StackFrame stackFrame; + StepperOperation operation; + int[] stepRanges; string name; + ICorDebugStepper corStepper; - StepperOperation operation = StepperOperation.Idle; - bool pauseWhenComplete = true; + bool ignore; public event EventHandler StepComplete; [Debugger.Tests.Ignore] public Process Process { - get { - return stackFrame.Process; - } + get { return stackFrame.Process; } } public StackFrame StackFrame { - get { - return stackFrame; - } - } - - public string Name { - get { - return name; - } + get { return stackFrame; } } public StepperOperation Operation { - get { - return operation; - } + get { return operation; } } - public bool PauseWhenComplete { - get { - return pauseWhenComplete; - } - set { - pauseWhenComplete = value; - } + public int[] StepRanges { + get { return stepRanges; } } - public bool JustMyCode { - set { - if (value) { - corStepper.SetUnmappedStopMask(CorDebugUnmappedStop.STOP_NONE); - corStepper.CastTo().SetJMC(1); - } else { - corStepper.SetUnmappedStopMask(CorDebugUnmappedStop.STOP_NONE); - corStepper.CastTo().SetJMC(0); - } - } + public string Name { + get { return name; } } - public Stepper(StackFrame stackFrame, string name): this(stackFrame) - { - this.name = name; + public bool Ignore { + get { return ignore; } + set { ignore = value; } } - public Stepper(StackFrame stackFrame) + private Stepper(StackFrame stackFrame, StepperOperation operation, int[] stepRanges, string name, bool justMyCode) { this.stackFrame = stackFrame; + this.operation = operation; + this.stepRanges = stepRanges; + this.name = name; - corStepper = stackFrame.CorILFrame.CreateStepper(); - - this.JustMyCode = Process.Options.EnableJustMyCode; + this.corStepper = stackFrame.CorILFrame.CreateStepper(); + this.ignore = false; + this.StackFrame.Thread.Steppers.Add(this); - stackFrame.Thread.Steppers.Add(this); + if (justMyCode) { + corStepper.SetUnmappedStopMask(CorDebugUnmappedStop.STOP_NONE); + corStepper.CastTo().SetJMC(1); + } } - protected internal virtual void OnStepComplete() { + protected internal virtual void OnStepComplete(CorDebugStepReason reason) { + this.corStepper = null; if (StepComplete != null) { - StepComplete(this, new StepperEventArgs(this)); + StepComplete(this, new StepperEventArgs(this, reason)); } } @@ -96,45 +80,62 @@ namespace Debugger return this.corStepper == corStepper; } - public void StepOut() + internal bool IsInStepRanges(int offset) + { + for(int i = 0; i < stepRanges.Length / 2; i++) { + if (stepRanges[2*i] <= offset && offset < stepRanges[2*i + 1]) { + return true; + } + } + return false; + } + + public static Stepper StepOut(StackFrame stackFrame, string name) { - operation = StepperOperation.StepOut; - JustMyCode = false; // Needed for multiple events. See docs\Stepping.txt - corStepper.StepOut(); + // JMC off - Needed for multiple events. See docs\Stepping.txt + Stepper stepper = new Stepper(stackFrame, StepperOperation.StepOut, null, name, false); + stepper.corStepper.StepOut(); + return stepper; } - public void StepIn(int[] ranges) + public static Stepper StepIn(StackFrame stackFrame, int[] stepRanges, string name) { - operation = StepperOperation.StepIn; - corStepper.StepRange(true /* step in */, ranges); + Stepper stepper = new Stepper(stackFrame, StepperOperation.StepIn, stepRanges, name, stackFrame.Process.Options.EnableJustMyCode); + stepper.corStepper.StepRange(true /* step in */, stepRanges); + return stepper; } - public void StepOver(int[] ranges) + public static Stepper StepOver(StackFrame stackFrame, int[] stepRanges, string name) { - operation = StepperOperation.StepOver; - corStepper.StepRange(false /* step over */, ranges); + Stepper stepper = new Stepper(stackFrame, StepperOperation.StepOver, stepRanges, name, stackFrame.Process.Options.EnableJustMyCode); + stepper.corStepper.StepRange(false /* step over */, stepRanges); + return stepper; } public override string ToString() { - return string.Format("{0} in {1} pause={2} \"{3}\"", Operation, StackFrame.ToString(), PauseWhenComplete, name); + return string.Format("{0} from {1} name=\"{2}\"", this.Operation, this.StackFrame.ToString(), this.Name); } } [Serializable] - public class StepperEventArgs: ProcessEventArgs + class StepperEventArgs: ProcessEventArgs { Stepper stepper; + CorDebugStepReason reason; public Stepper Stepper { - get { - return stepper; - } + get { return stepper; } + } + + public CorDebugStepReason Reason { + get { return reason; } } - public StepperEventArgs(Stepper stepper): base(stepper.Process) + public StepperEventArgs(Stepper stepper, CorDebugStepReason reason): base(stepper.Process) { this.stepper = stepper; + this.reason = reason; } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs index a31080e831..d9050458ec 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs @@ -23,6 +23,7 @@ namespace Debugger ICorDebugThread corThread; bool hasExited = false; + Stepper currentStepIn; List steppers = new List(); StackFrame selectedStackFrame; @@ -50,6 +51,11 @@ namespace Debugger private set { hasExited = value; } } + internal Stepper CurrentStepIn { + get { return currentStepIn; } + set { currentStepIn = value; } + } + /// From time to time the thread may be in invalid state. public bool IsInValidState { get { diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Options.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Options.cs index 6f7e01935b..c28a5e4e5c 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Options.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Options.cs @@ -10,53 +10,13 @@ namespace Debugger { public class Options { - bool enableJustMyCode = true; - bool stepOverNoSymbols = true; - bool stepOverDebuggerAttributes = true; - bool stepOverAllProperties = false; - bool stepOverSingleLineProperties = false; - bool stepOverFieldAccessProperties = true; - bool verbose = false; - string[] symbolsSearchPaths = new string[0]; - - public bool EnableJustMyCode { - get { return enableJustMyCode; } - set { enableJustMyCode = value; } - } - - public bool StepOverNoSymbols { - get { return stepOverNoSymbols; } - set { stepOverNoSymbols = value; } - } - - public bool StepOverDebuggerAttributes { - get { return stepOverDebuggerAttributes; } - set { stepOverDebuggerAttributes = value; } - } - - public bool StepOverAllProperties { - get { return stepOverAllProperties; } - set { stepOverAllProperties = value; } - } - - public bool StepOverSingleLineProperties { - get { return stepOverSingleLineProperties; } - set { stepOverSingleLineProperties = value; } - } - - public bool StepOverFieldAccessProperties { - get { return stepOverFieldAccessProperties; } - set { stepOverFieldAccessProperties = value; } - } - - public bool Verbose { - get { return verbose; } - set { verbose = value; } - } - - public string[] SymbolsSearchPaths { - get { return symbolsSearchPaths; } - set { symbolsSearchPaths = value; } - } + public bool EnableJustMyCode = true; + public bool StepOverNoSymbols = true; + public bool StepOverDebuggerAttributes = true; + public bool StepOverAllProperties = false; + public bool StepOverSingleLineProperties = false; + public bool StepOverFieldAccessProperties = true; + public bool Verbose = false; + public string[] SymbolsSearchPaths = new string[0]; } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs index 417d095c20..6ffeb86607 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs @@ -12,6 +12,7 @@ // Replace with: // \1\2\n\1{\n\1\tEnterCallback(PausedReason.Other, "\3");\n\1\t\n\1\tExitCallback_Continue();\n\1} +using Debugger.MetaData; using System; using System.Runtime.InteropServices; using Debugger.Wrappers.CorDebug; @@ -125,20 +126,34 @@ namespace Debugger Thread thread = process.GetThread(pThread); Stepper stepper = thread.GetStepper(pStepper); - process.TraceMessage(" - stepper info: " + stepper.ToString()); + StackFrame currentStackFrame = process.SelectedThread.MostRecentStackFrame; + process.TraceMessage(" - stopped at {0} because of {1}", currentStackFrame.MethodInfo.FullName, stepper.ToString()); thread.Steppers.Remove(stepper); - stepper.OnStepComplete(); - - if (stepper.PauseWhenComplete) { - if (process.SelectedThread.MostRecentStackFrame.HasSymbols && - process.SelectedThread.MostRecentStackFrame.MethodInfo.IsMyCode) { - // This is a good place, let's stay here - pauseOnNextExit = true; + stepper.OnStepComplete(reason); + + if (stepper.Ignore) { + // The stepper is ignored + process.TraceMessage(" - ignored"); + } else if (thread.CurrentStepIn != null && + thread.CurrentStepIn.StackFrame.Equals(currentStackFrame) && + thread.CurrentStepIn.IsInStepRanges((int)currentStackFrame.CorInstructionPtr)) { + Stepper.StepIn(currentStackFrame, thread.CurrentStepIn.StepRanges, "finishing step in"); + process.TraceMessage(" - finishing step in"); + } else if (currentStackFrame.MethodInfo.StepOver) { + if (process.Options.EnableJustMyCode) { + currentStackFrame.MethodInfo.MarkAsNonUserCode(); + process.TraceMessage(" - method {0} marked as non user code", currentStackFrame.MethodInfo.FullName); + Stepper.StepIn(currentStackFrame, new int[] {0, int.MaxValue}, "seeking user code"); + process.TraceMessage(" - seeking user code"); } else { - // Continue stepping to leave this place - + Stepper.StepOut(currentStackFrame, "stepping out of non-user code"); + process.TraceMessage(" - stepping out of non-user code"); } + } else { + // User-code method + pauseOnNextExit = true; + process.TraceMessage(" - pausing in user code"); } ExitCallback(); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs index 67c194a658..683ec6eb40 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs @@ -30,7 +30,6 @@ namespace Debugger.MetaData string fullName; // Class/ValueType specific - ICorDebugClass corClass; Module module; TypeDefProps classProps; @@ -81,7 +80,7 @@ namespace Debugger.MetaData /// Only applicable to class or value type! /// [Debugger.Tests.Ignore] - public uint MetadataToken { + public uint Token { get { AssertClassOrValueType(); return classProps.Token; @@ -326,9 +325,8 @@ namespace Debugger.MetaData this.corElementType = (CorElementType)corType.Type; if (this.IsClass || this.IsValueType) { - this.corClass = corType.Class; - this.module = process.GetModule(corClass.Module); - this.classProps = module.MetaData.GetTypeDefProps(corClass.Token); + this.module = process.GetModule(corType.Class.Module); + this.classProps = module.MetaData.GetTypeDefProps(corType.Class.Token); } if (this.IsClass || this.IsValueType || this.IsArray || this.IsPointer) { @@ -489,7 +487,7 @@ namespace Debugger.MetaData void LoadMemberInfo() { // Load interfaces - foreach(InterfaceImplProps implProps in module.MetaData.EnumInterfaceImplProps(this.MetadataToken)) { + foreach(InterfaceImplProps implProps in module.MetaData.EnumInterfaceImplProps(this.Token)) { if ((implProps.Interface & 0xFF000000) == (uint)CorTokenType.TypeDef || (implProps.Interface & 0xFF000000) == (uint)CorTokenType.TypeRef) { @@ -498,13 +496,13 @@ namespace Debugger.MetaData } // Load fields - foreach(FieldProps field in module.MetaData.EnumFieldProps(this.MetadataToken)) { + foreach(FieldProps field in module.MetaData.EnumFieldProps(this.Token)) { if (field.IsStatic && field.IsLiteral) continue; // Skip static literals TODO: Why? members.Add(new FieldInfo(this, field)); }; // Load methods - foreach(MethodProps m in module.MetaData.EnumMethodProps(this.MetadataToken)) { + foreach(MethodProps m in module.MetaData.EnumMethodProps(this.Token)) { members.Add(new MethodInfo(this, m)); } @@ -581,7 +579,7 @@ namespace Debugger.MetaData if (this.IsClass || this.IsValueType) { return (other.IsClass || other.IsValueType) && other.Module == this.Module && - other.MetadataToken == this.MetadataToken; + other.Token == this.Token; } if (this.IsPointer) { return other.IsPointer && diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs index df141e556a..f1b471d080 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs @@ -20,7 +20,6 @@ namespace Debugger.MetaData public class MethodInfo: MemberInfo { MethodProps methodProps; - FieldInfo backingField; /// Gets the name of this method public override string Name { @@ -29,10 +28,6 @@ namespace Debugger.MetaData } } - internal FieldInfo BackingField { - get { return backingField; } - } - /// Gets a value indicating whether this member has the private access modifier public override bool IsPrivate { get { return methodProps.IsPrivate; } @@ -83,26 +78,59 @@ namespace Debugger.MetaData } } - public bool IsMyCode { + /// Gets value indicating whether this method should be stepped over + /// accoring to current options + public bool StepOver { get { - return this.CorFunction.CastTo().JMCStatus != 0; - } - set { - this.CorFunction.CastTo().SetJMCStatus(value ? 1 : 0); + Options opt = this.Process.Options; + if (opt.StepOverNoSymbols) { + if (this.SymMethod == null) return true; + } + if (opt.StepOverDebuggerAttributes) { + if (this.HasDebuggerAttribute) return true; + } + if (opt.StepOverAllProperties) { + if (this.IsProperty)return true; + } + if (opt.StepOverSingleLineProperties) { + if (this.IsProperty && this.IsSingleLine) return true; + } + if (opt.StepOverFieldAccessProperties) { + if (this.IsProperty && this.BackingField != null) return true; + } + return false; } } internal MethodInfo(DebugType declaringType, MethodProps methodProps):base (declaringType) { this.methodProps = methodProps; - - this.backingField = GetBackingField(); + } + + // TODO: More accurate + bool IsProperty { + get { + return this.Name.StartsWith("get_") || this.Name.StartsWith("set_"); + } + } + + FieldInfo backingFieldCache; + bool getBackingFieldCalled; + + internal FieldInfo BackingField { + get { + if (!getBackingFieldCalled) { + backingFieldCache = GetBackingField(); + getBackingFieldCalled = true; + } + return backingFieldCache; + } } // Is this method in form 'return this.field;'? FieldInfo GetBackingField() { - if (this.IsStatic) return null; + if (this.IsStatic) return null; // TODO: Make work for static if (this.ParameterCount != 0) return null; ICorDebugCode corCode; @@ -177,6 +205,83 @@ namespace Debugger.MetaData return null; } + bool? isSingleLineCache; + + bool IsSingleLine { + get { + // Note symbols might get loaded manually later by the user + ISymUnmanagedMethod symMethod = this.SymMethod; + if (symMethod == null) return false; // No symbols - can not determine + + if (isSingleLineCache.HasValue) return isSingleLineCache.Value; + + List seqPoints = new List(symMethod.SequencePoints); + seqPoints.Sort(); + + // Remove initial "{" + if (seqPoints.Count > 0 && + seqPoints[0].Line == seqPoints[0].EndLine && + seqPoints[0].EndColumn - seqPoints[0].Column <= 1) { + seqPoints.RemoveAt(0); + } + + // Remove last "}" + int listIndex = seqPoints.Count - 1; + if (seqPoints.Count > 0 && + seqPoints[listIndex].Line == seqPoints[listIndex].EndLine && + seqPoints[listIndex].EndColumn - seqPoints[listIndex].Column <= 1) { + seqPoints.RemoveAt(listIndex); + } + + // Is single line + isSingleLineCache = seqPoints.Count == 0 || seqPoints[0].Line == seqPoints[seqPoints.Count - 1].EndLine; + return isSingleLineCache.Value; + } + } + + bool? hasDebuggerAttributeCache; + + bool HasDebuggerAttribute { + get { + if (hasDebuggerAttributeCache.HasValue) return hasDebuggerAttributeCache.Value; + + MetaDataImport metaData = this.Module.MetaData; + hasDebuggerAttributeCache = false; + // Look on the method + foreach(CustomAttributeProps ca in metaData.EnumCustomAttributeProps(methodProps.Token, 0)) { + MemberRefProps constructorMethod = metaData.GetMemberRefProps(ca.Type); + TypeRefProps attributeType = metaData.GetTypeRefProps(constructorMethod.DeclaringType); + if (attributeType.Name == "System.Diagnostics.DebuggerStepThroughAttribute" || + attributeType.Name == "System.Diagnostics.DebuggerNonUserCodeAttribute" || + attributeType.Name == "System.Diagnostics.DebuggerHiddenAttribute") + { + hasDebuggerAttributeCache = true; + } + } + // Look on the type + foreach(CustomAttributeProps ca in metaData.EnumCustomAttributeProps(this.DeclaringType.Token, 0)) { + MemberRefProps constructorMethod = metaData.GetMemberRefProps(ca.Type); + TypeRefProps attributeType = metaData.GetTypeRefProps(constructorMethod.DeclaringType); + if (attributeType.Name == "System.Diagnostics.DebuggerStepThroughAttribute" || + attributeType.Name == "System.Diagnostics.DebuggerNonUserCodeAttribute" || + attributeType.Name == "System.Diagnostics.DebuggerHiddenAttribute") + { + hasDebuggerAttributeCache = true; + } + } + return hasDebuggerAttributeCache.Value; + } + } + + internal void MarkAsNonUserCode() + { + this.CorFunction.CastTo().SetJMCStatus(0 /* false */); + + if (this.Process.Options.Verbose) { + this.Process.TraceMessage("Funciton {0} marked as non-user code", this.FullName); + } + } + /// /// Get a method from a managed type, method name and argument count /// diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj index 25ba44b1bb..a848676e8b 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj @@ -46,7 +46,6 @@ - diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebuggerAttributes.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebuggerAttributes.cs deleted file mode 100644 index 2c9cfabf94..0000000000 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebuggerAttributes.cs +++ /dev/null @@ -1,160 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Diagnostics; - -namespace Debugger.Tests.TestPrograms -{ - public class DebuggerAttributes - { - public static void Main() - { - System.Diagnostics.Debugger.Break(); - Internal(); - IgnoredClass.Internal(); - StepOut1(); - IgnoredClass.Internal_Pass(); - new DefaultCtorClass().Target(); - int s = ShortProperty; - int l = LongProperty; - } - - [DebuggerStepThrough] - static void StepOut1() - { - StepOut2(); - } - - static void StepOut2() - { - } - - [DebuggerStepThrough] - static void Internal() - { - } - - [DebuggerNonUserCode] - public class IgnoredClass - { - public static void Internal() - { - } - - public static void Internal_Pass() - { - NotIgnoredClass.Target(); - } - } - - public class NotIgnoredClass - { - public static void Target() - { - } - } - - public class DefaultCtorClass - { - public void Target() - { - - } - } - - public static int ShortProperty { - get { - return 1; - } - } - - public static int LongProperty { - get { - return - 1; - } - } - } -} - -#if TEST_CODE -namespace Debugger.Tests { - using NUnit.Framework; - using Debugger.Wrappers.CorDebug; - using Debugger.Wrappers.MetaData; - - public partial class DebuggerTests - { - //[NUnit.Framework.Test] - public void DebuggerAttributes() - { - StartTest("DebuggerAttributes.cs"); - - process.SelectedStackFrame.StepInto(); // Break command - process.SelectedStackFrame.StepInto(); // Internal - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepInto(); // IgnoredClass.Internal - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepInto(); // StepOut1 - Assert.AreEqual("StepOut2", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepOut(); - process.SelectedStackFrame.StepOver(); // Finish the step out - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepInto(); // IgnoredClass.Internal_Pass - Assert.AreEqual("Target", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepOut(); - process.SelectedStackFrame.StepOver(); // Finish the step out - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepInto(); // Generated default constructor - Assert.AreEqual("Target", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepOut(); - process.SelectedStackFrame.StepOver(); // Finish the step out - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepInto(); // ShortProperty - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepInto(); // LongProperty - Assert.AreEqual("get_LongProperty", process.SelectedStackFrame.MethodInfo.Name); - process.SelectedStackFrame.StepOut(); - process.SelectedStackFrame.StepOver(); // Finish the step out - Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); - - EndTest(); - } - } -} -#endif - -#if EXPECTED_OUTPUT - - - - - mscorlib.dll (No symbols) - DebuggerAttributes.exe (Has symbols) - Break - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - StepComplete - - - -#endif // EXPECTED_OUTPUT \ No newline at end of file diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs index 571a9fb6f3..73e6e82c34 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs @@ -146,14 +146,14 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>.Metod" IsInternal="False" - IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" IsSpecialName="False" IsStatic="False" Module="Generics.exe" - Name="Metod"> + Name="Metod" + StepOver="False"> + Name="GenericMethod" + StepOver="False"> + Name="StaticMetod" + StepOver="False"> + Name="StaticGenericMethod" + StepOver="False"> + Name="Metod" + StepOver="False"> + Name="GenericMethod" + StepOver="False"> + Name="StaticMetod" + StepOver="False"> + Name="StaticGenericMethod" + StepOver="False"> + Name="get_privateProperty" + StepOver="False" /> + Name="get_publicProperty" + StepOver="False" /> + Name="get_protectedProperty" + StepOver="False" /> + Name="get_internalProperty" + StepOver="False" /> + Name="get_staticProperty" + StepOver="False" /> + Name="privateMethod" + StepOver="False" /> + Name="publicMethod" + StepOver="False" /> + Name="protectedMethod" + StepOver="False" /> + Name="internalMethod" + StepOver="False" /> + Name="staticMethod" + StepOver="False" /> + Name="Main" + StepOver="False" /> + Name=".ctor" + StepOver="True" /> using System; +using System.Diagnostics; namespace Debugger.Tests.TestPrograms { public class Stepping { - public static void Main() + [DebuggerStepThrough] + static void StepRoot() { - System.Diagnostics.Debugger.Break(); - System.Diagnostics.Debug.WriteLine("1"); // Step over external code - Sub(); // Step in internal code - Sub2(); // Step over internal code + IgnoredClass.StepLeft(); + StepRight(); + } + + [DebuggerNonUserCode] + public class IgnoredClass { + public static void StepLeft() {} } - public static void Sub() - { // Step in noop - System.Diagnostics.Debug.WriteLine("2"); // Step in external code - System.Diagnostics.Debug.WriteLine("3"); // Step out - System.Diagnostics.Debug.WriteLine("4"); + static void StepRight() {} + + public class DefaultCtorClass { + public void Target() {} + } + + public static int ShortProperty { + get { + return 1; + } + } + + static int field = 1; + + public static int FieldProperty { + get { + return + field; + } + } + + [DebuggerNonUserCode] + static void ZigZag1() + { + try { + ZigZag2(); + } catch (System.Exception) { + try { + ZigZag2(); + } catch (System.Exception) { + } + } + } + + static void ZigZag2() + { // ... we end up here + System.Diagnostics.Debug.Write("ZigZag2"); + ZigZag3(); // Stepping in here ... + } + + [DebuggerNonUserCode] + static void ZigZag3() + { + throw new System.Exception(); + } + + [DebuggerNonUserCode] + static void CatchExcpetion() + { + try { + ThrowExcpetion(); + } catch (System.Exception) { + } } - public static void Sub2() + [DebuggerNonUserCode] + static void ThrowExcpetion() { - System.Diagnostics.Debug.WriteLine("5"); + throw new System.Exception(); + } + + static event EventHandler MyEvent; + [DebuggerNonUserCode] + static void Event1(object sender, EventArgs e) {} + static void Event2(object sender, EventArgs e) {} + [DebuggerNonUserCode] + static void Event3(object sender, EventArgs e) {} + static void Event4(object sender, EventArgs e) {} + + public static void Main() + { + MyEvent += Event1; + MyEvent += Event2; + MyEvent += Event3; + MyEvent += Event4; + System.Diagnostics.Debugger.Break(); + string theasnwer = 42.ToString(); + StepRoot(); + new DefaultCtorClass().Target(); + int s = ShortProperty; + int f = FieldProperty; + CatchExcpetion(); + ZigZag1(); + MyEvent(null, EventArgs.Empty); } } } #if TEST_CODE namespace Debugger.Tests { + using NUnit.Framework; + using Debugger.Wrappers.CorDebug; + using Debugger.Wrappers.MetaData; + public partial class DebuggerTests { [NUnit.Framework.Test] @@ -42,31 +125,72 @@ namespace Debugger.Tests { { StartTest("Stepping.cs"); - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepOver(); // Debugger.Break - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepOver(); // Debug.WriteLine 1 - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepInto(); // Method Sub - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepInto(); // '{' - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); + SourcecodeSegment start = process.SelectedStackFrame.NextStatement; - process.SelectedStackFrame.StepInto(); // Debug.WriteLine 2 - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepOut(); // Method Sub - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepOver(); // Method Sub - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); - - process.SelectedStackFrame.StepOver(); // Method Sub2 - ObjectDumpToString("NextStatement", process.SelectedStackFrame.NextStatement); + foreach (bool jmcEnabled in new bool[] {true, true, false}) { + ObjectDump("Log", "Starting run with JMC=" + jmcEnabled.ToString()); + + process.SelectedStackFrame.SetIP(start.Filename, start.StartLine + 1, start.StartColumn); + + process.Options.EnableJustMyCode = jmcEnabled; + process.Options.StepOverSingleLineProperties = true; + process.Options.StepOverFieldAccessProperties = true; + + process.SelectedStackFrame.StepInto(); // 42.ToString() + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + + if (jmcEnabled) { + process.SelectedStackFrame.StepInto(); // StepRoot + Assert.AreEqual("StepRight", process.SelectedStackFrame.MethodInfo.Name); + process.SelectedStackFrame.StepOut(); + process.SelectedStackFrame.StepOver(); // Finish the step out + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + } else { + process.SelectedStackFrame.StepInto(); // StepRoot + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + } + + process.SelectedStackFrame.StepInto(); // Generated default constructor + Assert.AreEqual("Target", process.SelectedStackFrame.MethodInfo.Name); + process.SelectedStackFrame.StepOut(); + process.SelectedStackFrame.StepOver(); // Finish the step out + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + + process.SelectedStackFrame.StepInto(); // ShortProperty + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + + // TODO: Does not work for static + // process.SelectedStackFrame.StepInto(); // FieldProperty + process.SelectedStackFrame.StepOver(); // FieldProperty + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + + process.SelectedStackFrame.StepInto(); // CatchExcpetion + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + + if (jmcEnabled) { + process.SelectedStackFrame.StepInto(); // ZigZag1 + process.SelectedStackFrame.StepOver(); + process.SelectedStackFrame.StepOver(); + Assert.AreEqual("ZigZag2", process.SelectedStackFrame.MethodInfo.Name); + process.SelectedStackFrame.StepInto(); + Assert.AreEqual("ZigZag2", process.SelectedStackFrame.MethodInfo.Name); + Assert.AreEqual(3, process.SelectedStackFrame.NextStatement.StartColumn); + process.SelectedStackFrame.StepOut(); + process.SelectedStackFrame.StepOver(); // Finish the step out + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + } else { + process.SelectedStackFrame.StepInto(); // ZigZag1 + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + } + + process.SelectedStackFrame.StepInto(); // MyEvent + Assert.AreEqual("Event2", process.SelectedStackFrame.MethodInfo.Name); + process.SelectedStackFrame.StepOut(); + Assert.AreEqual("Event4", process.SelectedStackFrame.MethodInfo.Name); + process.SelectedStackFrame.StepOut(); + process.SelectedStackFrame.StepOver(); // Finish the step out + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + } EndTest(); } @@ -82,32 +206,75 @@ namespace Debugger.Tests { mscorlib.dll (No symbols) Stepping.exe (Has symbols) - System.dll (No symbols) Break - Stepping.cs:16,4-16,40 + Starting run with JMC=True + SetIP + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + System.dll (No symbols) + StepComplete StepComplete - Stepping.cs:17,4-17,44 System.Configuration.dll (No symbols) System.Xml.dll (No symbols) - 1\r\n + ZigZag2 + StepComplete + StepComplete + ZigZag2 + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + Starting run with JMC=True + SetIP + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + ZigZag2 + StepComplete + StepComplete + ZigZag2 + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + Starting run with JMC=False + SetIP + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete StepComplete - Stepping.cs:18,4-18,10 StepComplete - Stepping.cs:23,3-23,4 + ZigZag2 + ZigZag2 StepComplete - Stepping.cs:24,4-24,44 - 2\r\n StepComplete - Stepping.cs:25,4-25,44 - 3\r\n - 4\r\n StepComplete - Stepping.cs:18,4-18,10 StepComplete - Stepping.cs:19,4-19,11 - 5\r\n StepComplete - Stepping.cs:20,3-20,4