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 140f31aab3..552408c620 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 @@ -7,11 +7,11 @@ using System; using System.Collections.Generic; - using Debugger.MetaData; using Debugger.Wrappers.CorDebug; using Debugger.Wrappers.CorSym; using Debugger.Wrappers.MetaData; +using System.Runtime.InteropServices; namespace Debugger { @@ -189,6 +189,7 @@ namespace Debugger /// public void SetJustMyCodeStatus(bool isMyCode, bool obeyAttributes) { + DateTime start = Util.HighPrecisionTimer.Now; uint unused = 0; if (isMyCode) { corModule.CastTo().SetJMCStatus(1, 0, ref unused); @@ -214,9 +215,36 @@ namespace Debugger } } } + // Mark generated constructors as non-user code + if (this.HasSymbols) { + foreach(TypeDefProps typeDef in metaData.EnumTypeDefProps()) { + foreach(MethodProps methodDef in metaData.EnumMethodPropsWithName(typeDef.Token, ".ctor")) { + try { + this.SymReader.GetMethod(methodDef.Token); + } catch (COMException) { + // Symbols not found + ICorDebugFunction2 corFunction = corModule.GetFunctionFromToken(methodDef.Token).CastTo(); + corFunction.SetJMCStatus(0 /* false */); + this.Process.TraceMessage("Constructor of {0} marked as non-user code", metaData.GetTypeDefProps(methodDef.ClassToken).Name); + } + } + foreach(MethodProps methodDef in metaData.EnumMethodPropsWithName(typeDef.Token, ".cctor")) { + try { + this.SymReader.GetMethod(methodDef.Token); + } catch (COMException) { + // Symbols not found + ICorDebugFunction2 corFunction = corModule.GetFunctionFromToken(methodDef.Token).CastTo(); + corFunction.SetJMCStatus(0 /* false */); + this.Process.TraceMessage("Static constructor of {0} marked as non-user code", metaData.GetTypeDefProps(methodDef.ClassToken).Name); + } + } + } + } } else { corModule.CastTo().SetJMCStatus(0, 0, ref unused); } + DateTime end = Util.HighPrecisionTimer.Now; + this.Process.TraceMessage("Set Just-My-Code for module \"{0}\" ({1} ms)", this.Filename, (end - start).TotalMilliseconds); } public void ApplyChanges(byte[] metadata, byte[] il) 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 db6a485b74..d3038f29ed 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 @@ -143,7 +143,9 @@ namespace Debugger } /// Returns value representing the System.Threading.Thread object - /// The value is null while the thread is being created (the CreateThread callback). + /// The value is null while the thread is being created (the CreateThread callback) and + /// it may stay null during the run of the program. (probaly until the debuggee accesses + /// the System.Threading.Thread object which forces the creation) public Value RuntimeValue { get { process.AssertPaused(); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/SourcecodeSegment.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/SourcecodeSegment.cs index f16e5209ff..e23a65c68e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/SourcecodeSegment.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/SourcecodeSegment.cs @@ -7,9 +7,11 @@ using System; using System.Collections.Generic; +using System.IO; + using Debugger.Wrappers.CorDebug; using Debugger.Wrappers.CorSym; -using System.IO; +using System.Runtime.InteropServices; namespace Debugger { @@ -235,7 +237,14 @@ namespace Debugger ISymUnmanagedReader symReader = module.SymReader; if (symReader == null) return null; // No symbols - ISymUnmanagedMethod symMethod = symReader.GetMethod(corFunction.Token); + ISymUnmanagedMethod symMethod; + try { + symMethod = symReader.GetMethod(corFunction.Token); + } catch (COMException) { + // Can not find the method + // eg. Compiler generated constructors are not in symbol store + return null; + } if (symMethod == null) return null; uint sequencePointCount = symMethod.SequencePointCount; 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 b41d64acfc..5b197a60f6 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 @@ -129,7 +129,15 @@ namespace Debugger if (stepper.PauseWhenComplete) { if (process.SelectedThread.MostRecentStackFrame.HasSymbols) { - pauseOnNextExit = true; + // JMC is ignored by the API during StepOut - Compensate + if (process.Debugger.JustMyCodeEnabled && + stepper.Operation == Stepper.StepperOperation.StepOut && + !process.SelectedThread.MostRecentStackFrame.MethodInfo.IsMyCode) { + process.TraceMessage(" - stepping out non-user code at " + process.SelectedThread.MostRecentStackFrame.ToString()); + new Stepper(process.SelectedThread.MostRecentStackFrame, "Stepper out of non-user code").StepOut(); + } else { + pauseOnNextExit = true; + } } else { // This can only happen when JMC is disabled (ie NET1.1 or StepOut) if (stepper.Operation == Stepper.StepperOperation.StepOut) { @@ -137,8 +145,9 @@ namespace Debugger process.TraceMessage(" - stepping out of code without symbols at " + process.SelectedThread.MostRecentStackFrame.ToString()); new Stepper(process.SelectedThread.MostRecentStackFrame, "Stepper out of code without symbols").StepOut(); } else { - // NET1.1: There is extra step over stepper, just keep going + // JMC is disabled: There is extra step over stepper, we could just keep going process.TraceMessage(" - leaving code without symbols"); + new Stepper(process.SelectedThread.MostRecentStackFrame, "Stepper out of code without symbols").StepOut(); } } } 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 977e894935..c8e1077d1f 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 @@ -83,6 +83,15 @@ namespace Debugger.MetaData } } + public bool IsMyCode { + get { + return this.CorFunction.CastTo().JMCStatus != 0; + } + set { + this.CorFunction.CastTo().SetJMCStatus(value ? 1 : 0); + } + } + internal MethodInfo(DebugType declaringType, MethodProps methodProps):base (declaringType) { this.methodProps = methodProps; 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 index 7ba859dd23..df6013fa29 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebuggerAttributes.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebuggerAttributes.cs @@ -14,17 +14,27 @@ namespace Debugger.Tests.TestPrograms { public static void Main() { - System.Diagnostics.Debug.WriteLine("Start"); System.Diagnostics.Debugger.Break(); Internal(); IgnoredClass.Internal(); - System.Diagnostics.Debug.WriteLine("End"); + StepOut1(); + IgnoredClass.Internal_Pass(); + new DefaultCtorClass().Target(); + } + + [DebuggerStepThrough] + static void StepOut1() + { + StepOut2(); + } + + static void StepOut2() + { } [DebuggerStepThrough] static void Internal() { - System.Diagnostics.Debug.WriteLine("Internal"); } [DebuggerNonUserCode] @@ -32,7 +42,26 @@ namespace Debugger.Tests.TestPrograms { public static void Internal() { - System.Diagnostics.Debug.WriteLine("Internal"); + } + + public static void Internal_Pass() + { + NotIgnoredClass.Target(); + } + } + + public class NotIgnoredClass + { + public static void Target() + { + } + } + + public class DefaultCtorClass + { + public void Target() + { + } } } @@ -51,11 +80,29 @@ namespace Debugger.Tests { { StartTest("DebuggerAttributes.cs"); - process.SelectedStackFrame.StepInto(); - process.SelectedStackFrame.StepInto(); - Assert.AreEqual(process.SelectedStackFrame.MethodInfo.Name, "Main"); - process.SelectedStackFrame.StepInto(); - Assert.AreEqual(process.SelectedStackFrame.MethodInfo.Name, "Main"); + 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(); + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + 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(); + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + 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(); + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); + process.SelectedStackFrame.StepOver(); // Finish the step out + Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name); EndTest(); } @@ -71,17 +118,19 @@ namespace Debugger.Tests { mscorlib.dll (No symbols) DebuggerAttributes.exe (Has symbols) - System.dll (No symbols) - System.Configuration.dll (No symbols) - System.Xml.dll (No symbols) - Start\r\n Break StepComplete - Internal\r\n StepComplete - Internal\r\n StepComplete - End\r\n + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete + StepComplete 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 93a83cadfd..cc0639be4e 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 @@ -145,6 +145,7 @@ 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" @@ -208,6 +209,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>.GenericMethod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -271,6 +273,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>.StaticMetod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -334,6 +337,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericClass<System.Int32,System.String>.StaticGenericMethod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -397,6 +401,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>.Metod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -460,6 +465,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>.GenericMethod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -523,6 +529,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>.StaticMetod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -586,6 +593,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>" FullName="Debugger.Tests.TestPrograms.GenericStruct<System.Int32,System.String>.StaticGenericMethod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Metadata.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Metadata.cs index 4c83034103..8f360f90e2 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Metadata.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Metadata.cs @@ -142,6 +142,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.get_privateProperty" IsInternal="False" + IsMyCode="True" IsPrivate="True" IsProtected="False" IsPublic="False" @@ -155,6 +156,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.get_publicProperty" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -168,6 +170,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.get_protectedProperty" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="True" IsPublic="False" @@ -181,6 +184,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.get_internalProperty" IsInternal="True" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="False" @@ -194,6 +198,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.get_staticProperty" IsInternal="False" + IsMyCode="True" IsPrivate="True" IsProtected="False" IsPublic="False" @@ -207,6 +212,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.privateMethod" IsInternal="False" + IsMyCode="True" IsPrivate="True" IsProtected="False" IsPublic="False" @@ -220,6 +226,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.publicMethod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -233,6 +240,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.protectedMethod" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="True" IsPublic="False" @@ -246,6 +254,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.internalMethod" IsInternal="True" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="False" @@ -259,6 +268,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.staticMethod" IsInternal="False" + IsMyCode="True" IsPrivate="True" IsProtected="False" IsPublic="False" @@ -272,6 +282,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata.Main" IsInternal="False" + IsMyCode="True" IsPrivate="False" IsProtected="False" IsPublic="True" @@ -285,6 +296,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.Metadata" FullName="Debugger.Tests.TestPrograms.Metadata..ctor" IsInternal="False" + IsMyCode="False" IsPrivate="False" IsProtected="False" IsPublic="True"