Browse Source

Rewritten IL parsing code for detection of backing fields. Static backing fields are now supported as well.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5166 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
eed2a2f5ca
  1. 1
      src/AddIns/Misc/Debugger/Debugger.Core/Interop/CorDebugExtensionMethods.cs
  2. 129
      src/AddIns/Misc/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
  3. 9
      src/AddIns/Misc/Debugger/Debugger.Core/MetaData/DebugType.cs
  4. 4
      src/AddIns/Misc/Debugger/Debugger.Tests/Tests/ControlFlow_Stepping.cs
  5. 111
      src/AddIns/Misc/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs

1
src/AddIns/Misc/Debugger/Debugger.Core/Interop/CorDebugExtensionMethods.cs

@ -61,7 +61,6 @@ namespace Debugger.Interop.CorDebug @@ -61,7 +61,6 @@ namespace Debugger.Interop.CorDebug
public static unsafe byte[] GetCode(this ICorDebugCode corCode)
{
if (corCode.IsIL() == 0) return null;
byte[] code = new byte[corCode.GetSize()];
fixed(byte* pCode = code)
corCode.GetCode(0, (uint)code.Length, (uint)code.Length, new IntPtr(pCode));

129
src/AddIns/Misc/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs

@ -267,24 +267,19 @@ namespace Debugger.MetaData @@ -267,24 +267,19 @@ namespace Debugger.MetaData
if (this.HasDebuggerAttribute) return true;
}
if (opt.StepOverAllProperties) {
if (this.IsProperty)return true;
if (this.IsPropertyAccessor) return true;
}
if (opt.StepOverSingleLineProperties) {
if (this.IsProperty && this.IsSingleLine) return true;
if (this.IsPropertyAccessor && this.IsSingleLine) return true;
}
if (opt.StepOverFieldAccessProperties) {
if (this.IsProperty && this.BackingField != null) return true;
if (this.IsPropertyAccessor && this.BackingField != null) return true;
}
return false;
}
}
// TODO: More accurate
bool IsProperty {
get {
return this.Name.StartsWith("get_") || this.Name.StartsWith("set_");
}
}
internal bool IsPropertyAccessor { get; set; }
DebugFieldInfo backingFieldCache;
bool getBackingFieldCalled;
@ -305,8 +300,6 @@ namespace Debugger.MetaData @@ -305,8 +300,6 @@ namespace Debugger.MetaData
// Is this method in form 'return this.field;'?
DebugFieldInfo GetBackingField()
{
if (this.IsStatic) return null; // TODO: Make work for static,
// the code size for static is 10/11 opposed to instance 11/12 - the ldarg.0 is missing
if (this.ParameterCount != 0) return null;
ICorDebugCode corCode;
@ -317,90 +310,56 @@ namespace Debugger.MetaData @@ -317,90 +310,56 @@ namespace Debugger.MetaData
}
if (corCode == null) return null;
if (corCode.GetSize() != 7 && corCode.GetSize() != 12 && corCode.GetSize() != 11) return null;
if (corCode.IsIL() == 0) return null;
if (corCode.GetSize() > 12) return null;
byte[] code = corCode.GetCode();
List<byte> code = new List<byte>(corCode.GetCode());
if (code == null) return null;
uint token = 0;
/*
string codeTxt = "";
foreach(byte b in code) {
codeTxt += b.ToString("X2") + " ";
}
process.TraceMessage("Code of " + Name + ": " + codeTxt);
*/
bool success =
(Read(code, 0x00) || true) && // nop || nothing
(Read(code, 0x02, 0x7B) || Read(code, 0x7E)) && // ldarg.0; ldfld || ldsfld
ReadToken(code, ref token) && // <field token>
(Read(code, 0x0A, 0x2B, 0x00, 0x06) || true) && // stloc.0; br.s; offset+00; ldloc.0 || nothing
Read(code, 0x2A); // ret
if (!success) return null;
uint token = 0;
// code generated for 'return this.field'
if (code.Length == 12 &&
code[00] == 0x00 && // nop
code[01] == 0x02 && // ldarg.0
code[02] == 0x7B && // ldfld
code[06] == 0x04 && // <field token>
code[07] == 0x0A && // stloc.0
code[08] == 0x2B && // br.s
code[09] == 0x00 && // offset+00
code[10] == 0x06 && // ldloc.0
code[11] == 0x2A) // ret
{
token = GetTokenFromIL(code, 06);
}
MemberInfo member = declaringType.GetMember(token);
// code generated for getter 'public int Prop { get; [set;] }'
// (same as above, just leading nop is missing)
if (code.Length == 11 &&
code[00] == 0x02 && // ldarg.0
code[01] == 0x7B && // ldfld
code[05] == 0x04 && // <field token>
code[06] == 0x0A && // stloc.0
code[07] == 0x2B && // br.s
code[08] == 0x00 && // offset+00
code[09] == 0x06 && // ldloc.0
code[10] == 0x2A) // ret
{
token = GetTokenFromIL(code, 05);
}
if (member == null) return null;
if (!(member is DebugFieldInfo)) return null;
if (code.Length == 7 &&
code[00] == 0x02 && // ldarg.0
code[01] == 0x7B && // ldfld
code[05] == 0x04 && // <field token>
code[06] == 0x2A) // ret
{
token = GetTokenFromIL(code, 05);
if (this.Process.Options.Verbose) {
this.Process.TraceMessage(string.Format("Found backing field for {0}: {1}", this.FullName, member.Name));
}
if (token != 0) {
// process.TraceMessage("Token: " + token.ToString("x"));
MemberInfo member = declaringType.GetMember(token);
if (member == null) return null;
if (!(member is DebugFieldInfo)) return null;
if (this.Process.Options.Verbose) {
this.Process.TraceMessage(string.Format("Found backing field for {0}: {1}", this.FullName, member.Name));
}
return (DebugFieldInfo)member;
return (DebugFieldInfo)member;
}
// Read expected sequence of bytes
static bool Read(List<byte> code, params byte[] expected)
{
if (code.Count < expected.Length)
return false;
for(int i = 0; i < expected.Length; i++) {
if (code[i] != expected[i])
return false;
}
return null;
code.RemoveRange(0, expected.Length);
return true;
}
/// <summary>
/// Gets token from IL code.
/// </summary>
/// <param name="ilCode">Bytes representing the code.</param>
/// <param name="tokenEndIndex">Index of last byte of the token.</param>
/// <returns>IL token.</returns>
uint GetTokenFromIL(byte[] ilCode, uint tokenEndIndex)
// Read field token
static bool ReadToken(List<byte> code, ref uint token)
{
return ((uint)ilCode[tokenEndIndex] << 24) +
((uint)ilCode[tokenEndIndex - 1] << 16) +
((uint)ilCode[tokenEndIndex - 2] << 8) +
((uint)ilCode[tokenEndIndex - 3]);
if (code.Count < 4)
return false;
if (code[3] != 0x04) // field token
return false;
token = ((uint)code[0]) + ((uint)code[1] << 8) + ((uint)code[2] << 16) + ((uint)code[3] << 24);
code.RemoveRange(0, 4);
return true;
}
bool? isSingleLine;
@ -497,7 +456,7 @@ namespace Debugger.MetaData @@ -497,7 +456,7 @@ namespace Debugger.MetaData
public List<DebugLocalVariableInfo> GetLocalVariables()
{
// TODO: Is this needed?
// Generated constructor may not have any symbols
if (this.SymMethod == null)
return new List<DebugLocalVariableInfo>();

9
src/AddIns/Misc/Debugger/Debugger.Core/MetaData/DebugType.cs

@ -1261,11 +1261,16 @@ namespace Debugger.MetaData @@ -1261,11 +1261,16 @@ namespace Debugger.MetaData
// Load properties
foreach(PropertyProps prop in module.MetaData.EnumPropertyProps((uint)this.MetadataToken)) {
AddMember(new DebugPropertyInfo(
DebugPropertyInfo propInfo = new DebugPropertyInfo(
this,
prop.GetterMethod != 0x06000000 ? GetMethod(prop.GetterMethod) : null,
prop.SetterMethod != 0x06000000 ? GetMethod(prop.SetterMethod) : null
));
);
if (propInfo.GetGetMethod() != null)
((DebugMethodInfo)propInfo.GetGetMethod()).IsPropertyAccessor = true;
if (propInfo.GetSetMethod() != null)
((DebugMethodInfo)propInfo.GetSetMethod()).IsPropertyAccessor = true;
AddMember(propInfo);
}
}

4
src/AddIns/Misc/Debugger/Debugger.Tests/Tests/ControlFlow_Stepping.cs

@ -157,9 +157,7 @@ namespace Debugger.Tests { @@ -157,9 +157,7 @@ namespace Debugger.Tests {
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
process.SelectedStackFrame.StepInto(); // FieldProperty
Assert.AreEqual("Main", process.SelectedStackFrame.MethodInfo.Name);
process.SelectedStackFrame.StepInto(); // CatchExcpetion

111
src/AddIns/Misc/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs

@ -63,10 +63,23 @@ namespace Debugger.Tests @@ -63,10 +63,23 @@ namespace Debugger.Tests
public unsafe class Members
{
public int instanceInt;
public static int staticInt;
public void* voidPtr;
public char SetterOnlyProp { set { ; } }
public const int IntLiteral = 42;
public int InstanceInt {
get { return instanceInt; }
}
public static int StaticInt {
get { return staticInt; }
}
public int AutoProperty { get; set; }
public char this[int i] {
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
@ -208,8 +221,6 @@ namespace Debugger.Tests { @@ -208,8 +221,6 @@ namespace Debugger.Tests {
ObjectDump("MyInterfaceImpl-Members", process.SelectedStackFrame.GetLocalVariableValue("myInterfaceImpl").Type.GetMembers());
PrintLocalVariables();
// TODO: Identity
EndTest();
}
}
@ -224,7 +235,7 @@ namespace Debugger.Tests { @@ -224,7 +235,7 @@ namespace Debugger.Tests {
<ProcessStarted />
<ModuleLoaded>mscorlib.dll (No symbols)</ModuleLoaded>
<ModuleLoaded>DebugType_Tests.exe (Has symbols)</ModuleLoaded>
<DebuggingPaused>Break DebugType_Tests.cs:138,4-138,40</DebuggingPaused>
<DebuggingPaused>Break DebugType_Tests.cs:151,4-151,40</DebuggingPaused>
<DefinedTypes
Capacity="16"
Count="12">
@ -312,10 +323,10 @@ namespace Debugger.Tests { @@ -312,10 +323,10 @@ namespace Debugger.Tests {
Attributes="AutoLayout, AnsiClass, Class, NestedPublic, BeforeFieldInit"
BaseType="System.Object"
FullName="Debugger.Tests.DebugType_Tests+Members"
GetFields="{System.Int32 IntLiteral, System.Void* voidPtr}"
GetMembers="{System.Int32 IntLiteral, System.Void* voidPtr, void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), System.Char SetterOnlyProp, System.Char Item[Int32 i], System.Char Item[String s], void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetMethods="{void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetProperties="{System.Char SetterOnlyProp, System.Char Item[Int32 i], System.Char Item[String s]}"
GetFields="{System.Int32 IntLiteral, System.Int32 instanceInt, System.Int32 staticInt, System.Void* voidPtr}"
GetMembers="{System.Int32 IntLiteral, System.Int32 instanceInt, System.Int32 staticInt, System.Void* voidPtr, void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_InstanceInt(), static System.Int32 Debugger.Tests.DebugType_Tests+Members.get_StaticInt(), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_AutoProperty(), void Debugger.Tests.DebugType_Tests+Members.set_AutoProperty(Int32 value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), System.Char SetterOnlyProp, System.Int32 InstanceInt, System.Int32 StaticInt, System.Int32 AutoProperty, System.Char Item[Int32 i], System.Char Item[String s], void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetMethods="{void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_InstanceInt(), static System.Int32 Debugger.Tests.DebugType_Tests+Members.get_StaticInt(), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_AutoProperty(), void Debugger.Tests.DebugType_Tests+Members.set_AutoProperty(Int32 value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetProperties="{System.Char SetterOnlyProp, System.Int32 InstanceInt, System.Int32 StaticInt, System.Int32 AutoProperty, System.Char Item[Int32 i], System.Char Item[String s]}"
IsClass="True"
IsNested="True">
<GetElementType>null</GetElementType>
@ -345,6 +356,20 @@ namespace Debugger.Tests { @@ -345,6 +356,20 @@ namespace Debugger.Tests {
IsLiteral="True"
Name="IntLiteral" />
</Item>
<Item>
<DebugFieldInfo
Attributes="Public"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FieldType="System.Int32"
Name="instanceInt" />
</Item>
<Item>
<DebugFieldInfo
Attributes="Public, Static"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FieldType="System.Int32"
Name="staticInt" />
</Item>
<Item>
<DebugFieldInfo
Attributes="Public"
@ -352,6 +377,13 @@ namespace Debugger.Tests { @@ -352,6 +377,13 @@ namespace Debugger.Tests {
FieldType="System.Void*"
Name="voidPtr" />
</Item>
<Item>
<DebugFieldInfo
Attributes="Private"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FieldType="System.Int32"
Name="&lt;AutoProperty&gt;k__BackingField" />
</Item>
<Item>
<DebugMethodInfo
Attributes="PrivateScope, Public, HideBySig, SpecialName"
@ -360,6 +392,45 @@ namespace Debugger.Tests { @@ -360,6 +392,45 @@ namespace Debugger.Tests {
GetLocalVariables="{Debugger.Tests.DebugType_Tests+Members this}"
Name="set_SetterOnlyProp" />
</Item>
<Item>
<DebugMethodInfo
Attributes="PrivateScope, Public, HideBySig, SpecialName"
BackingField="System.Int32 instanceInt"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FullName="Debugger.Tests.DebugType_Tests+Members.get_InstanceInt()"
GetLocalVariables="{Debugger.Tests.DebugType_Tests+Members this}"
Name="get_InstanceInt"
ReturnType="System.Int32"
StepOver="True" />
</Item>
<Item>
<DebugMethodInfo
Attributes="PrivateScope, Public, Static, HideBySig, SpecialName"
BackingField="System.Int32 staticInt"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FullName="Debugger.Tests.DebugType_Tests+Members.get_StaticInt()"
Name="get_StaticInt"
ReturnType="System.Int32"
StepOver="True" />
</Item>
<Item>
<DebugMethodInfo
Attributes="PrivateScope, Public, HideBySig, SpecialName"
BackingField="System.Int32 &lt;AutoProperty&gt;k__BackingField"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FullName="Debugger.Tests.DebugType_Tests+Members.get_AutoProperty()"
Name="get_AutoProperty"
ReturnType="System.Int32"
StepOver="True" />
</Item>
<Item>
<DebugMethodInfo
Attributes="PrivateScope, Public, HideBySig, SpecialName"
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
FullName="Debugger.Tests.DebugType_Tests+Members.set_AutoProperty(Int32 value)"
Name="set_AutoProperty"
StepOver="True" />
</Item>
<Item>
<DebugMethodInfo
Attributes="PrivateScope, Public, HideBySig, SpecialName"
@ -400,6 +471,24 @@ namespace Debugger.Tests { @@ -400,6 +471,24 @@ namespace Debugger.Tests {
Name="SetterOnlyProp"
PropertyType="System.Char" />
</Item>
<Item>
<DebugPropertyInfo
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
Name="InstanceInt"
PropertyType="System.Int32" />
</Item>
<Item>
<DebugPropertyInfo
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
Name="StaticInt"
PropertyType="System.Int32" />
</Item>
<Item>
<DebugPropertyInfo
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
Name="AutoProperty"
PropertyType="System.Int32" />
</Item>
<Item>
<DebugPropertyInfo
DeclaringType="Debugger.Tests.DebugType_Tests+Members"
@ -1464,10 +1553,10 @@ namespace Debugger.Tests { @@ -1464,10 +1553,10 @@ namespace Debugger.Tests {
Attributes="AutoLayout, AnsiClass, Class, NestedPublic, BeforeFieldInit"
BaseType="System.Object"
FullName="Debugger.Tests.DebugType_Tests+Members"
GetFields="{System.Int32 IntLiteral, System.Void* voidPtr}"
GetMembers="{System.Int32 IntLiteral, System.Void* voidPtr, void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), System.Char SetterOnlyProp, System.Char Item[Int32 i], System.Char Item[String s], void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetMethods="{void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetProperties="{System.Char SetterOnlyProp, System.Char Item[Int32 i], System.Char Item[String s]}"
GetFields="{System.Int32 IntLiteral, System.Int32 instanceInt, System.Int32 staticInt, System.Void* voidPtr}"
GetMembers="{System.Int32 IntLiteral, System.Int32 instanceInt, System.Int32 staticInt, System.Void* voidPtr, void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_InstanceInt(), static System.Int32 Debugger.Tests.DebugType_Tests+Members.get_StaticInt(), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_AutoProperty(), void Debugger.Tests.DebugType_Tests+Members.set_AutoProperty(Int32 value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), System.Char SetterOnlyProp, System.Int32 InstanceInt, System.Int32 StaticInt, System.Int32 AutoProperty, System.Char Item[Int32 i], System.Char Item[String s], void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetMethods="{void Debugger.Tests.DebugType_Tests+Members.set_SetterOnlyProp(Char value), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_InstanceInt(), static System.Int32 Debugger.Tests.DebugType_Tests+Members.get_StaticInt(), System.Int32 Debugger.Tests.DebugType_Tests+Members.get_AutoProperty(), void Debugger.Tests.DebugType_Tests+Members.set_AutoProperty(Int32 value), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(Int32 i), System.Char Debugger.Tests.DebugType_Tests+Members.get_Item(String s), void Debugger.Tests.DebugType_Tests+Members.set_Item(Int32 i, Char value), void Debugger.Tests.DebugType_Tests+Members..ctor(), void System.Object..ctor(), System.String System.Object.ToString(), System.Boolean System.Object.Equals(Object obj), System.Int32 System.Object.GetHashCode(), System.Type System.Object.GetType()}"
GetProperties="{System.Char SetterOnlyProp, System.Int32 InstanceInt, System.Int32 StaticInt, System.Int32 AutoProperty, System.Char Item[Int32 i], System.Char Item[String s]}"
IsClass="True"
IsNested="True">
<GetElementType>null</GetElementType>

Loading…
Cancel
Save