|
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace AutoDiagrammer
{
public class MethodBodyReader
{
public List<ILInstruction> Instructions = null;
protected byte[] il = null;
private MethodInfo mi = null;
#region il read methods
private int ReadInt16(byte[] _il, ref int position)
{
return ((il[position++] | (il[position++] << 8)));
}
private ushort ReadUInt16(byte[] _il, ref int position)
{
return (ushort)((il[position++] | (il[position++] << 8)));
}
private int ReadInt32(byte[] _il, ref int position)
{
return (((il[position++] | (il[position++] << 8)) | (il[position++] << 0x10)) | (il[position++] << 0x18));
}
private ulong ReadInt64(byte[] _il, ref int position)
{
return (ulong)(((il[position++] | (il[position++] << 8)) | (il[position++] << 0x10)) | (il[position++] << 0x18) | (il[position++] << 0x20) | (il[position++] << 0x28) | (il[position++] << 0x30) | (il[position++] << 0x38));
}
private double ReadDouble(byte[] _il, ref int position)
{
return (((il[position++] | (il[position++] << 8)) | (il[position++] << 0x10)) | (il[position++] << 0x18) | (il[position++] << 0x20) | (il[position++] << 0x28) | (il[position++] << 0x30) | (il[position++] << 0x38));
}
private sbyte ReadSByte(byte[] _il, ref int position)
{
return (sbyte)il[position++];
}
private byte ReadByte(byte[] _il, ref int position)
{
return (byte)il[position++];
}
private Single ReadSingle(byte[] _il, ref int position)
{
return (Single)(((il[position++] | (il[position++] << 8)) | (il[position++] << 0x10)) | (il[position++] << 0x18));
}
#endregion
/// <summary>
/// Constructs the array of ILInstructions according to the IL byte code.
/// </summary>
/// <param name="module"></param>
private void ConstructInstructions(Module module)
{
byte[] il = this.il;
int position = 0;
Instructions = new List<ILInstruction>();
while (position < il.Length)
{
ILInstruction instruction = new ILInstruction();
// get the operation code of the current instruction
OpCode code = OpCodes.Nop;
ushort value = il[position++];
if (value != 0xfe)
{
code = SingleByteOpCodes[(int)value];
}
else
{
value = il[position++];
code = MultiByteOpCodes[(int)value];
value = (ushort)(value | 0xfe00);
}
instruction.Code = code;
instruction.Offset = position - 1;
int metadataToken = 0;
// get the operand of the current operation
switch (code.OperandType)
{
case OperandType.InlineBrTarget:
metadataToken = ReadInt32(il, ref position);
metadataToken += position;
instruction.Operand = metadataToken;
break;
case OperandType.InlineField:
metadataToken = ReadInt32(il, ref position);
instruction.Operand = module.ResolveField(metadataToken);
break;
case OperandType.InlineMethod:
metadataToken = ReadInt32(il, ref position);
try
{
instruction.Operand = module.ResolveMethod(metadataToken);
}
catch
{
instruction.Operand = module.ResolveMember(metadataToken);
}
break;
case OperandType.InlineSig:
metadataToken = ReadInt32(il, ref position);
instruction.Operand = module.ResolveSignature(metadataToken);
break;
case OperandType.InlineTok:
metadataToken = ReadInt32(il, ref position);
try
{
instruction.Operand = module.ResolveType(metadataToken);
}
catch
{
}
// SSS : see what to do here
break;
case OperandType.InlineType:
metadataToken = ReadInt32(il, ref position);
// now we call the ResolveType always using the generic attributes type in order
// to support decompilation of generic methods and classes
// thanks to the guys from code project who commented on this missing feature
instruction.Operand = module.ResolveType(metadataToken, this.mi.DeclaringType.GetGenericArguments(), this.mi.GetGenericArguments());
break;
case OperandType.InlineI:
{
instruction.Operand = ReadInt32(il, ref position);
break;
}
case OperandType.InlineI8:
{
instruction.Operand = ReadInt64(il, ref position);
break;
}
case OperandType.InlineNone:
{
instruction.Operand = null;
break;
}
case OperandType.InlineR:
{
instruction.Operand = ReadDouble(il, ref position);
break;
}
case OperandType.InlineString:
{
metadataToken = ReadInt32(il, ref position);
instruction.Operand = module.ResolveString(metadataToken);
break;
}
case OperandType.InlineSwitch:
{
int count = ReadInt32(il, ref position);
int[] casesAddresses = new int[count];
for (int i = 0; i < count; i++)
{
casesAddresses[i] = ReadInt32(il, ref position);
}
int[] cases = new int[count];
for (int i = 0; i < count; i++)
{
cases[i] = position + casesAddresses[i];
}
break;
}
case OperandType.InlineVar:
{
instruction.Operand = ReadUInt16(il, ref position);
break;
}
case OperandType.ShortInlineBrTarget:
{
instruction.Operand = ReadSByte(il, ref position) + position;
break;
}
case OperandType.ShortInlineI:
{
instruction.Operand = ReadSByte(il, ref position);
break;
}
case OperandType.ShortInlineR:
{
instruction.Operand = ReadSingle(il, ref position);
break;
}
case OperandType.ShortInlineVar:
{
instruction.Operand = ReadByte(il, ref position);
break;
}
default:
{
throw new Exception("Unknown operand type.");
}
}
Instructions.Add(instruction);
}
}
public object GetRefferencedOperand(Module module, int metadataToken)
{
AssemblyName[] assemblyNames = module.Assembly.GetReferencedAssemblies();
for (int i = 0; i < assemblyNames.Length; i++)
{
Module[] modules = Assembly.Load(assemblyNames[i]).GetModules();
for (int j = 0; j < modules.Length; j++)
{
try
{
Type t = modules[j].ResolveType(metadataToken);
return t;
}
catch
{
}
}
}
return null;
//System.Reflection.Assembly.Load(module.Assembly.GetReferencedAssemblies()[3]).GetModules()[0].ResolveType(metadataToken)
}
/// <summary>
/// Gets the IL code of the method
/// </summary>
/// <returns></returns>
public string GetBodyCode()
{
string result = "";
if (Instructions != null)
{
for (int i = 0; i < Instructions.Count; i++)
{
result += Instructions[i].GetCode() + "\n";
}
}
return result;
}
/// <summary>
/// MethodBodyReader constructor
/// </summary>
/// <param name="mi">
/// The System.Reflection defined MethodInfo
/// </param>
public MethodBodyReader(MethodInfo mi)
{
this.mi = mi;
if (mi.GetMethodBody() != null)
{
il = mi.GetMethodBody().GetILAsByteArray();
ConstructInstructions(mi.Module);
}
}
public static Dictionary<int, object> Cache = new Dictionary<int, object>();
public static OpCode[] MultiByteOpCodes;
public static OpCode[] SingleByteOpCodes;
public static Module[] Modules = null;
public static void LoadOpCodes()
{
SingleByteOpCodes = new OpCode[0x100];
MultiByteOpCodes = new OpCode[0x100];
FieldInfo[] infoArray1 = typeof(OpCodes).GetFields();
for (int num1 = 0; num1 < infoArray1.Length; num1++)
{
FieldInfo info1 = infoArray1[num1];
if (info1.FieldType == typeof(OpCode))
{
OpCode code1 = (OpCode)info1.GetValue(null);
ushort num2 = (ushort)code1.Value;
if (num2 < 0x100)
{
SingleByteOpCodes[(int)num2] = code1;
}
else
{
if ((num2 & 0xff00) != 0xfe00)
{
throw new Exception("Invalid OpCode.");
}
MultiByteOpCodes[num2 & 0xff] = code1;
}
}
}
}
/// <summary>
/// Retrieve the friendly name of a type
/// </summary>
/// <param name="typeName">
/// The complete name to the type
/// </param>
/// <returns>
/// The simplified name of the type (i.e. "int" instead f System.Int32)
/// </returns>
public static string ProcessSpecialTypes(string typeName)
{
string result = typeName;
switch (typeName)
{
case "System.string":
case "System.String":
case "String":
result = "string"; break;
case "System.Int32":
case "Int":
case "Int32":
result = "int"; break;
}
return result;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
Both of these at Sussex University UK.
Award(s)
I am lucky enough to have won a few awards for Zany Crazy code articles over the years
- Microsoft C# MVP 2016
- Codeproject MVP 2016
- Microsoft C# MVP 2015
- Codeproject MVP 2015
- Microsoft C# MVP 2014
- Codeproject MVP 2014
- Microsoft C# MVP 2013
- Codeproject MVP 2013
- Microsoft C# MVP 2012
- Codeproject MVP 2012
- Microsoft C# MVP 2011
- Codeproject MVP 2011
- Microsoft C# MVP 2010
- Codeproject MVP 2010
- Microsoft C# MVP 2009
- Codeproject MVP 2009
- Microsoft C# MVP 2008
- Codeproject MVP 2008
- And numerous codeproject awards which you can see over at my blog