Merge pull request #82 from MichalStrehovsky/methodilDebug

Debugger proxy for MethodIL class
This commit is contained in:
Michal Strehovský 2015-10-21 10:31:33 -07:00
Родитель 51db0bf96c e3582c5a0c
Коммит 515b6d7ded
4 изменённых файлов: 276 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,195 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Internal.IL
{
public static class ILDisassember
{
private static byte ReadILByte(byte[] _ilBytes, ref int _currentOffset)
{
return _ilBytes[_currentOffset++];
}
private static UInt16 ReadILUInt16(byte[] _ilBytes, ref int _currentOffset)
{
UInt16 val = (UInt16)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8));
_currentOffset += 2;
return val;
}
private static UInt32 ReadILUInt32(byte[] _ilBytes, ref int _currentOffset)
{
UInt32 val = (UInt32)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24));
_currentOffset += 4;
return val;
}
private static int ReadILToken(byte[] _ilBytes, ref int _currentOffset)
{
return (int)ReadILUInt32(_ilBytes, ref _currentOffset);
}
private static ulong ReadILUInt64(byte[] _ilBytes, ref int _currentOffset)
{
ulong value = ReadILUInt32(_ilBytes, ref _currentOffset);
value |= (((ulong)ReadILUInt32(_ilBytes, ref _currentOffset)) << 32);
return value;
}
private static unsafe float ReadILFloat(byte[] _ilBytes, ref int _currentOffset)
{
uint value = ReadILUInt32(_ilBytes, ref _currentOffset);
return *(float*)(&value);
}
private static unsafe double ReadILDouble(byte[] _ilBytes, ref int _currentOffset)
{
ulong value = ReadILUInt64(_ilBytes, ref _currentOffset);
return *(double*)(&value);
}
public static string FormatOffset(int offset)
{
return "IL_" + offset.ToString("X4");
}
public static string Disassemble(Func<int, string> tokenResolver, byte[] instructionStream, ref int offset)
{
string opCodeName = "";
again:
ILOpcode opCode = (ILOpcode)ReadILByte(instructionStream, ref offset);
if (opCode == ILOpcode.prefix1)
{
opCode = (ILOpcode)(0x100 + ReadILByte(instructionStream, ref offset));
}
opCodeName += opCode.ToString();
opCodeName = opCodeName.Replace("_", ".");
switch (opCode)
{
case ILOpcode.ldarg_s:
case ILOpcode.ldarga_s:
case ILOpcode.starg_s:
case ILOpcode.ldloc_s:
case ILOpcode.ldloca_s:
case ILOpcode.stloc_s:
case ILOpcode.ldc_i4_s:
return opCodeName + " " + ReadILByte(instructionStream, ref offset);
case ILOpcode.unaligned:
opCodeName += " " + ReadILByte(instructionStream, ref offset) + " ";
goto again;
case ILOpcode.ldarg:
case ILOpcode.ldarga:
case ILOpcode.starg:
case ILOpcode.ldloc:
case ILOpcode.ldloca:
case ILOpcode.stloc:
return opCodeName + " " + ReadILUInt16(instructionStream, ref offset);
case ILOpcode.ldc_i4:
return opCodeName + " " + ReadILUInt32(instructionStream, ref offset);
case ILOpcode.ldc_r4:
return opCodeName + " " + ReadILFloat(instructionStream, ref offset);
case ILOpcode.ldc_i8:
return opCodeName + " " + ReadILUInt64(instructionStream, ref offset);
case ILOpcode.ldc_r8:
return opCodeName + " " + ReadILDouble(instructionStream, ref offset);
case ILOpcode.jmp:
case ILOpcode.call:
case ILOpcode.calli:
case ILOpcode.callvirt:
case ILOpcode.cpobj:
case ILOpcode.ldobj:
case ILOpcode.ldstr:
case ILOpcode.newobj:
case ILOpcode.castclass:
case ILOpcode.isinst:
case ILOpcode.unbox:
case ILOpcode.ldfld:
case ILOpcode.ldflda:
case ILOpcode.stfld:
case ILOpcode.ldsfld:
case ILOpcode.ldsflda:
case ILOpcode.stsfld:
case ILOpcode.stobj:
case ILOpcode.box:
case ILOpcode.newarr:
case ILOpcode.ldelema:
case ILOpcode.ldelem:
case ILOpcode.stelem:
case ILOpcode.unbox_any:
case ILOpcode.refanyval:
case ILOpcode.mkrefany:
case ILOpcode.ldtoken:
case ILOpcode.ldftn:
case ILOpcode.ldvirtftn:
case ILOpcode.initobj:
case ILOpcode.constrained:
case ILOpcode.sizeof_:
return opCodeName + " " + tokenResolver(ReadILToken(instructionStream, ref offset));
case ILOpcode.br_s:
case ILOpcode.leave_s:
case ILOpcode.brfalse_s:
case ILOpcode.brtrue_s:
case ILOpcode.beq_s:
case ILOpcode.bge_s:
case ILOpcode.bgt_s:
case ILOpcode.ble_s:
case ILOpcode.blt_s:
case ILOpcode.bne_un_s:
case ILOpcode.bge_un_s:
case ILOpcode.bgt_un_s:
case ILOpcode.ble_un_s:
case ILOpcode.blt_un_s:
return opCodeName + " " + FormatOffset((sbyte)ReadILByte(instructionStream, ref offset) + offset);
case ILOpcode.br:
case ILOpcode.leave:
case ILOpcode.brfalse:
case ILOpcode.brtrue:
case ILOpcode.beq:
case ILOpcode.bge:
case ILOpcode.bgt:
case ILOpcode.ble:
case ILOpcode.blt:
case ILOpcode.bne_un:
case ILOpcode.bge_un:
case ILOpcode.bgt_un:
case ILOpcode.ble_un:
case ILOpcode.blt_un:
return opCodeName + " " + FormatOffset((int)ReadILUInt32(instructionStream, ref offset) + offset);
case ILOpcode.switch_:
{
opCodeName = "switch (";
uint count = ReadILUInt32(instructionStream, ref offset);
int jmpBase = offset + (int)(4 * count);
for (uint i = 0; i < count; i++)
{
if (i != 0)
opCodeName += ", ";
int delta = (int)ReadILUInt32(instructionStream, ref offset);
opCodeName += FormatOffset(jmpBase + delta);
}
opCodeName += ")";
return opCodeName;
}
default:
return opCodeName;
}
}
}
}

Просмотреть файл

@ -85,6 +85,7 @@ namespace Internal.IL
}
}
[System.Diagnostics.DebuggerTypeProxy(typeof(MethodILDebugView))]
public abstract class MethodIL
{
public abstract byte[] GetILBytes();

Просмотреть файл

@ -0,0 +1,74 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Internal.TypeSystem;
using System;
using System.Text;
namespace Internal.IL
{
internal sealed class MethodILDebugView
{
private readonly MethodIL _methodIL;
public MethodILDebugView(MethodIL methodIL)
{
_methodIL = methodIL;
}
public string Disassembly
{
get
{
byte[] ilBytes = _methodIL.GetILBytes() ?? Array.Empty<byte>();
StringBuilder sb = new StringBuilder();
sb.Append("// Code size: ");
sb.Append(ilBytes.Length);
sb.AppendLine();
sb.Append(".maxstack ");
sb.Append(_methodIL.GetMaxStack());
sb.AppendLine();
TypeDesc[] locals = _methodIL.GetLocals();
if (locals != null && locals.Length > 0)
{
sb.Append(".locals ");
if (_methodIL.GetInitLocals())
sb.Append("init ");
sb.Append("(");
for (int i = 0; i < locals.Length; i++)
{
if (i != 0)
{
sb.AppendLine(",");
sb.Append(' ', 4);
}
sb.Append(locals[i].ToString());
sb.Append(" ");
sb.Append("V_");
sb.Append(i);
}
sb.AppendLine(")");
}
sb.AppendLine();
int offset = 0;
Func<int, string> resolver = token => _methodIL.GetObject(token).ToString();
while (offset < ilBytes.Length)
{
sb.Append(ILDisassember.FormatOffset(offset));
sb.Append(": ");
sb.AppendLine(ILDisassember.Disassemble(resolver, ilBytes, ref offset));
}
return sb.ToString();
}
}
}
}

Просмотреть файл

@ -94,6 +94,12 @@
<Compile Include="$(CommonPath)\TypeSystem\IL\MethodIL.cs">
<Link>IL\MethodIL.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\TypeSystem\IL\MethodILDebugView.cs">
<Link>IL\MethodILDebugView.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\TypeSystem\IL\ILDisassember.cs">
<Link>IL\ILDisassember.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\TypeSystem\IL\ILImporter.cs">
<Link>IL\ILImporter.cs</Link>
</Compile>