23 changed files with 311 additions and 341 deletions
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Runtime.CompilerServices; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using Debugger.Interop.CorDebug; |
||||
|
||||
namespace Debugger |
||||
{ |
||||
public static class Util |
||||
{ |
||||
// Type-safe box because ConditionalWeakTable requires reference type
|
||||
class Box<T> |
||||
{ |
||||
public T Value; |
||||
|
||||
public static implicit operator Box<T>(T value) |
||||
{ |
||||
return new Box<T> { Value = value }; |
||||
} |
||||
} |
||||
|
||||
static ConditionalWeakTable<IUnresolvedMember, Box<bool>> hasStepOverAttribute = new ConditionalWeakTable<IUnresolvedMember, Box<bool>>(); |
||||
|
||||
public static bool HasStepOverAttribute(this IMethod method) |
||||
{ |
||||
return hasStepOverAttribute.GetValue(method.UnresolvedMember, delegate { |
||||
string[] debuggerAttributes = { |
||||
typeof(System.Diagnostics.DebuggerStepThroughAttribute).FullName, |
||||
typeof(System.Diagnostics.DebuggerNonUserCodeAttribute).FullName, |
||||
typeof(System.Diagnostics.DebuggerHiddenAttribute).FullName |
||||
}; |
||||
if (method.Attributes.Any(a => debuggerAttributes.Contains(a.AttributeType.FullName))) |
||||
return true; |
||||
if (method.DeclaringType.GetDefinition().Attributes.Any(a => debuggerAttributes.Contains(a.AttributeType.FullName))) |
||||
return true; |
||||
return false; |
||||
}).Value; |
||||
} |
||||
|
||||
static ConditionalWeakTable<IUnresolvedMember, Box<uint>> backingFieldToken = new ConditionalWeakTable<IUnresolvedMember, Box<uint>>(); |
||||
|
||||
/// <summary> Is this method in form 'return this.field;'? </summary>
|
||||
public static uint GetBackingFieldToken(this IMethod method) |
||||
{ |
||||
return backingFieldToken.GetValue(method.UnresolvedMember, delegate { |
||||
ICorDebugCode corCode; |
||||
try { |
||||
corCode = method.ToCorFunction().GetILCode(); |
||||
} catch (System.Runtime.InteropServices.COMException) { |
||||
return 0; |
||||
} |
||||
|
||||
if (corCode == null || corCode.IsIL() == 0 || corCode.GetSize() > 12) { |
||||
return 0; |
||||
} |
||||
|
||||
List<byte> code = new List<byte>(corCode.GetCode()); |
||||
|
||||
uint token = 0; |
||||
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 0; |
||||
} |
||||
|
||||
return token; |
||||
}).Value; |
||||
} |
||||
|
||||
// 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; |
||||
} |
||||
code.RemoveRange(0, expected.Length); |
||||
return true; |
||||
} |
||||
|
||||
// Read field token
|
||||
static bool ReadToken(List<byte> code, ref uint token) |
||||
{ |
||||
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; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue