diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
index f6df8750d2..a7331b5eb0 100644
--- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
+++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
@@ -31,7 +31,7 @@ namespace Debugger.AddIn.TreeModel
foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) {
yield return new ExpressionNode(ExpressionNode.GetImageForParameter(), par.Name, par.GetExpression());
}
- foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables()) {
+ foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) {
yield return new ExpressionNode(ExpressionNode.GetImageForLocalVariable(), locVar.Name, locVar.GetExpression());
}
if (stackFrame.Thread.CurrentException != null) {
diff --git a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs
index 494972ffbe..42c974b1ca 100644
--- a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs
+++ b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs
@@ -140,7 +140,7 @@ namespace Debugger
process.TraceMessage(" - ignored");
} else if (thread.CurrentStepIn != null &&
thread.CurrentStepIn.StackFrame.Equals(currentStackFrame) &&
- thread.CurrentStepIn.IsInStepRanges((int)currentStackFrame.CorInstructionPtr)) {
+ thread.CurrentStepIn.IsInStepRanges((int)currentStackFrame.IP)) {
Stepper.StepIn(currentStackFrame, thread.CurrentStepIn.StepRanges, "finishing step in");
process.TraceMessage(" - finishing step in");
} else if (currentStackFrame.MethodInfo.StepOver) {
diff --git a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs
index 439e1aaf38..1906b6d4c0 100644
--- a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs
+++ b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs
@@ -31,13 +31,19 @@ namespace Debugger.MetaData
}
public string Name { get; internal set; }
+ /// IL offset of the start of the variable scope (inclusive)
+ public int StartOffset { get; private set; }
+ /// IL offset of the end of the variable scope (exclusive)
+ public int EndOffset { get; private set; }
public bool IsThis { get; internal set; }
public bool IsCaptured { get; internal set; }
- public DebugLocalVariableInfo(string name, int localIndex, DebugType localType, ValueGetter getter)
+ public DebugLocalVariableInfo(string name, int localIndex, int startOffset, int endOffset, DebugType localType, ValueGetter getter)
{
this.Name = name;
this.localIndex = localIndex;
+ this.StartOffset = startOffset;
+ this.EndOffset = endOffset;
this.localType = localType;
this.getter = getter;
}
diff --git a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
index ce5e484499..8f77c86ce6 100644
--- a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
+++ b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
@@ -443,30 +443,51 @@ namespace Debugger.MetaData
}
}
- public DebugLocalVariableInfo GetLocalVariable(string name)
+ public DebugLocalVariableInfo GetLocalVariable(int offset, string name)
{
- foreach(DebugLocalVariableInfo loc in GetLocalVariables()) {
+ foreach(DebugLocalVariableInfo loc in GetLocalVariables(offset)) {
if (loc.Name == name)
return loc;
}
return null;
}
+ [Debugger.Tests.Ignore]
+ public DebugLocalVariableInfo GetLocalVariableThis()
+ {
+ foreach(DebugLocalVariableInfo loc in GetLocalVariables()) {
+ if (loc.IsThis)
+ return loc;
+ }
+ return null;
+ }
+
+ /// Get local variables valid at the given IL offset
+ public IEnumerable GetLocalVariables(int offset)
+ {
+ foreach (DebugLocalVariableInfo varInfo in GetLocalVariables()) {
+ if (varInfo.StartOffset <= offset && offset < varInfo.EndOffset) {
+ yield return varInfo;
+ }
+ }
+ }
+
List localVariables;
public List GetLocalVariables()
{
+ if (localVariables != null) return localVariables;
+
// Generated constructor may not have any symbols
if (this.SymMethod == null)
return new List();
-
- if (localVariables != null) return localVariables;
localVariables = GetLocalVariablesInScope(this.SymMethod.GetRootScope());
if (declaringType.IsDisplayClass || declaringType.IsYieldEnumerator) {
// Get display class from self
AddCapturedLocalVariables(
localVariables,
+ 0, int.MaxValue,
delegate(StackFrame context) {
return context.GetThisValue();
},
@@ -478,6 +499,7 @@ namespace Debugger.MetaData
if (fieldInfo.Name.StartsWith("CS$")) {
AddCapturedLocalVariables(
localVariables,
+ 0, int.MaxValue,
delegate(StackFrame context) {
return context.GetThisValue().GetFieldValue(fieldInfoCopy);
},
@@ -491,6 +513,7 @@ namespace Debugger.MetaData
DebugLocalVariableInfo thisVar = new DebugLocalVariableInfo(
"this",
-1,
+ 0, int.MaxValue,
declaringType,
delegate(StackFrame context) {
return context.GetThisValue();
@@ -503,7 +526,7 @@ namespace Debugger.MetaData
return localVariables;
}
- static void AddCapturedLocalVariables(List vars, ValueGetter getCaptureClass, DebugType captureClassType)
+ static void AddCapturedLocalVariables(List vars, int scopeStartOffset, int scopeEndOffset, ValueGetter getCaptureClass, DebugType captureClassType)
{
if (captureClassType.IsDisplayClass || captureClassType.IsYieldEnumerator) {
foreach(DebugFieldInfo fieldInfo in captureClassType.GetFields()) {
@@ -512,6 +535,8 @@ namespace Debugger.MetaData
DebugLocalVariableInfo locVar = new DebugLocalVariableInfo(
fieldInfo.Name,
-1,
+ scopeStartOffset,
+ scopeEndOffset,
(DebugType)fieldInfo.FieldType,
delegate(StackFrame context) {
return getCaptureClass(context).GetFieldValue(fieldInfoCopy);
@@ -559,6 +584,8 @@ namespace Debugger.MetaData
if (locVarType.IsDisplayClass) {
AddCapturedLocalVariables(
vars,
+ (int)symScope.GetStartOffset(),
+ (int)symScope.GetEndOffset(),
delegate(StackFrame context) {
return GetLocalVariableValue(context, symVarCopy);
},
@@ -569,6 +596,9 @@ namespace Debugger.MetaData
DebugLocalVariableInfo locVar = new DebugLocalVariableInfo(
symVar.GetName(),
(int)symVar.GetAddressField1(),
+ // symVar also has Get*Offset methods, but the are not implemented
+ (int)symScope.GetStartOffset(),
+ (int)symScope.GetEndOffset(),
locVarType,
delegate(StackFrame context) {
return GetLocalVariableValue(context, symVarCopy);
diff --git a/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs b/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs
index cc4d103b4e..edaf3aabf9 100644
--- a/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs
+++ b/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs
@@ -392,7 +392,7 @@ namespace ICSharpCode.NRefactory.Visitors
if (par != null)
return new TypedValue(par.GetValue(context), (DebugType)par.ParameterType);
- DebugLocalVariableInfo loc = context.MethodInfo.GetLocalVariable(identifier);
+ DebugLocalVariableInfo loc = context.MethodInfo.GetLocalVariable(context.IP, identifier);
if (loc != null)
return new TypedValue(loc.GetValue(context), (DebugType)loc.LocalType);
@@ -562,10 +562,9 @@ namespace ICSharpCode.NRefactory.Visitors
TypedValue GetThisValue()
{
// This is needed so that captured 'this' is supported
- foreach(DebugLocalVariableInfo locVar in context.MethodInfo.GetLocalVariables()) {
- if (locVar.IsThis)
- return new TypedValue(locVar.GetValue(context), (DebugType)locVar.LocalType);
- }
+ DebugLocalVariableInfo thisVar = context.MethodInfo.GetLocalVariableThis();
+ if (thisVar != null)
+ return new TypedValue(thisVar.GetValue(context), (DebugType)thisVar.LocalType);
return null;
}
diff --git a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs
index 41144da9f3..64c7af15e0 100644
--- a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs
+++ b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs
@@ -232,7 +232,7 @@ namespace Debugger
/// 'ILStart <= ILOffset <= ILEnd' and this range includes at least
/// the returned area of source code. (May incude some extra compiler generated IL too)
///
- internal static SourcecodeSegment Resolve(Module module, ICorDebugFunction corFunction, uint offset)
+ internal static SourcecodeSegment Resolve(Module module, ICorDebugFunction corFunction, int offset)
{
ISymUnmanagedReader symReader = module.SymReader;
if (symReader == null) return null; // No symbols
@@ -253,7 +253,7 @@ namespace Debugger
// Get i for which: offsets[i] <= offset < offsets[i + 1]
// or fallback to first element if offset < offsets[0]
for (int i = (int)sequencePointCount - 1; i >= 0; i--) { // backwards
- if (sequencePoints[i].Offset <= offset || i == 0) {
+ if ((int)sequencePoints[i].Offset <= offset || i == 0) {
// Set inforamtion about current IL range
int codeSize = (int)corFunction.GetILCode().GetSize();
diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs
index 339ed81014..2976e1be53 100644
--- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs
+++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs
@@ -133,16 +133,17 @@ namespace Debugger
}
}
- internal uint CorInstructionPtr {
+ [Debugger.Tests.Ignore]
+ public int IP {
get {
uint corInstructionPtr;
CorDebugMappingResult mappingResult;
CorILFrame.GetIP(out corInstructionPtr, out mappingResult);
- return corInstructionPtr;
+ return (int)corInstructionPtr;
}
}
- SourcecodeSegment GetSegmentForOffet(uint offset)
+ SourcecodeSegment GetSegmentForOffet(int offset)
{
return SourcecodeSegment.Resolve(this.MethodInfo.DebugModule, corFunction, offset);
}
@@ -232,7 +233,7 @@ namespace Debugger
///
public SourcecodeSegment NextStatement {
get {
- return GetSegmentForOffet(CorInstructionPtr);
+ return GetSegmentForOffet(IP);
}
}
@@ -282,6 +283,8 @@ namespace Debugger
///
/// Gets the instance of the class asociated with the current frame.
/// That is, 'this' in C#.
+ /// Note that for delegates and enumerators this returns the instance of the display class.
+ /// The get the captured this, use GetLocalVariableThis.
///
[Debugger.Tests.Ignore]
public Value GetThisValue()
@@ -367,12 +370,22 @@ namespace Debugger
/// Null if not found
public Value GetLocalVariableValue(string name)
{
- DebugLocalVariableInfo loc = this.MethodInfo.GetLocalVariable(name);
+ DebugLocalVariableInfo loc = this.MethodInfo.GetLocalVariable(this.IP, name);
if (loc == null)
return null;
return loc.GetValue(this);
}
+ /// Get instance of 'this'. It works well with delegates and enumerators.
+ [Debugger.Tests.Ignore]
+ public Value GetLocalVariableThis()
+ {
+ DebugLocalVariableInfo thisVar = this.MethodInfo.GetLocalVariableThis();
+ if (thisVar != null)
+ return thisVar.GetValue(this);
+ return null;
+ }
+
public override bool Equals(object obj)
{
StackFrame other = obj as StackFrame;
diff --git a/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj b/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj
index 28e6a7ad12..a424db6663 100644
--- a/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj
+++ b/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj
@@ -1,4 +1,5 @@
-
+
+
Library
Debugger.Tests
@@ -55,6 +56,7 @@
+
@@ -80,4 +82,4 @@
-
+
\ No newline at end of file
diff --git a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs
index cc3ef923be..56681830b8 100644
--- a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs
+++ b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs
@@ -35,6 +35,17 @@ namespace Debugger.Tests
protected XmlElement snapshotNode;
protected int shapshotID;
+ public StackFrame SelectedStackFrame {
+ get {
+ return process.SelectedStackFrame;
+ }
+ }
+
+ public void Continue()
+ {
+ process.Continue();
+ }
+
[TestFixtureSetUp]
public virtual void TestFixtureSetUp()
{
diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs
index 549fac3ecf..4af8a1de76 100644
--- a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs
+++ b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs
@@ -73,11 +73,11 @@ namespace Debugger.Tests {
public void DebugType_CompilerGeneratedClasses()
{
StartTest();
- PrintLocalVariables("YieldLocalVariables");
+ DumpLocalVariables("YieldLocalVariables");
process.Continue();
- PrintLocalVariables("OutterDelegateLocalVariables");
+ DumpLocalVariables("OutterDelegateLocalVariables");
process.Continue();
- PrintLocalVariables("InnterDelegateLocalVariables");
+ DumpLocalVariables("InnterDelegateLocalVariables");
Eval("nestedDelegArg");
Eval("instanceField");
Eval("staticField");
diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs
index 28c467ef7a..9c08ec24f1 100644
--- a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs
+++ b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs
@@ -188,16 +188,16 @@ namespace Debugger.Tests {
public Value Value { get; set; }
}
- void PrintLocalVariables()
+ void DumpLocalVariables()
{
- PrintLocalVariables("LocalVariables");
+ DumpLocalVariables("LocalVariables");
}
- void PrintLocalVariables(string msg)
+ void DumpLocalVariables(string msg)
{
ObjectDump(
msg,
- process.SelectedStackFrame.MethodInfo.GetLocalVariables().Select(v => new LocalVariable() { Name = v.Name, Type = v.LocalType, Value = v.GetValue(process.SelectedStackFrame) })
+ SelectedStackFrame.MethodInfo.GetLocalVariables(SelectedStackFrame.IP).Select(v => new LocalVariable() { Name = v.Name, Type = v.LocalType, Value = v.GetValue(process.SelectedStackFrame)})
);
}
@@ -219,7 +219,7 @@ namespace Debugger.Tests {
ObjectDump("Members", process.SelectedStackFrame.GetLocalVariableValue("members").Type.GetMembers(DebugType.BindingFlagsAllDeclared));
ObjectDump("Access-Members", process.SelectedStackFrame.GetLocalVariableValue("access").Type.GetMembers());
ObjectDump("MyInterfaceImpl-Members", process.SelectedStackFrame.GetLocalVariableValue("myInterfaceImpl").Type.GetMembers());
- PrintLocalVariables();
+ DumpLocalVariables();
EndTest();
}
diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs
index 302f4eac3e..a85c7bdf2d 100644
--- a/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs
+++ b/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs
@@ -208,8 +208,8 @@ namespace Debugger.Tests {
// Test member hiding / overloading
- Value myClass = process.SelectedStackFrame.GetLocalVariableValue("myClass").GetPermanentReference();
- Expression myClassExpr = process.SelectedStackFrame.MethodInfo.GetLocalVariable("myClass").GetExpression();
+ Value myClass = SelectedStackFrame.GetLocalVariableValue("myClass").GetPermanentReference();
+ Expression myClassExpr = SelectedStackFrame.MethodInfo.GetLocalVariable(SelectedStackFrame.IP, "myClass").GetExpression();
List expressions = new List();
foreach(MemberInfo memberInfo in myClass.Type.GetFieldsAndNonIndexedProperties(DebugType.BindingFlagsAll)) {
@@ -254,9 +254,9 @@ namespace Debugger.Tests {
// Type equality
- DebugLocalVariableInfo loc = process.SelectedStackFrame.MethodInfo.GetLocalVariable("list");
+ DebugLocalVariableInfo loc = SelectedStackFrame.MethodInfo.GetLocalVariable(SelectedStackFrame.IP, "list");
Type locType = loc.LocalType;
- Type valType = loc.GetValue(process.SelectedStackFrame).Type;
+ Type valType = loc.GetValue(SelectedStackFrame).Type;
ObjectDump("TypesIdentitcal", object.ReferenceEquals(locType, valType));
ObjectDump("TypesEqual", locType == valType);
diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs
new file mode 100644
index 0000000000..0bb4572c7a
--- /dev/null
+++ b/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs
@@ -0,0 +1,115 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace Debugger.Tests
+{
+ public class StackFrame_Tests
+ {
+ public static void Main()
+ {
+ for (int i = 10; i < 11; i++) {
+ System.Diagnostics.Debugger.Break();
+ }
+ for (short i = 20; i < 21; i++) {
+ System.Diagnostics.Debugger.Break();
+ }
+
+ System.Diagnostics.Debugger.Break();
+
+ int j = 30;
+
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+}
+
+#if TEST_CODE
+namespace Debugger.Tests {
+ public partial class DebuggerTests
+ {
+ [NUnit.Framework.Test]
+ public void StackFrame_Tests()
+ {
+ StartTest();
+
+ // Test scoping
+ DumpLocalVariables("Loop1");
+ Continue();
+ DumpLocalVariables("Loop2");
+ Continue();
+ DumpLocalVariables("None");
+ Continue();
+ DumpLocalVariables("NewVarDefined");
+
+ EndTest();
+ }
+ }
+}
+#endif
+
+#if EXPECTED_OUTPUT
+
+
+
+
+ mscorlib.dll (No symbols)
+ StackFrame_Tests.exe (Has symbols)
+ Break StackFrame_Tests.cs:17,5-17,41
+
+ -
+
+
+ -
+
+
+
+ Break StackFrame_Tests.cs:20,5-20,41
+
+ -
+
+
+ -
+
+
+
+ Break StackFrame_Tests.cs:23,4-23,40
+
+ -
+
+
+
+ Break StackFrame_Tests.cs:27,4-27,40
+
+ -
+
+
+
+
+
+
+#endif // EXPECTED_OUTPUT
\ No newline at end of file
diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs
index af8df77a44..87ef0b6119 100644
--- a/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs
+++ b/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs
@@ -42,7 +42,7 @@ namespace Debugger.Tests {
{
StartTest();
- PrintLocalVariables();
+ DumpLocalVariables();
Value array = process.SelectedStackFrame.GetLocalVariableValue("array").GetPermanentReference();
ObjectDump("array.Length", array.GetMemberValue("Length"));