protected void GetInstrDetails(ILInstruction instruction, out string name, out Type declType, out string calledId) { name = null; declType = null; calledId = null; if (instruction.Operand is MethodInfo) { MethodInfo mOperand = (MethodInfo)instruction.Operand; declType = mOperand.DeclaringType; name = mOperand.Name; calledId = declType.FullName + " " + RefHelp.GetNameWithParameterList(mOperand); } else if (instruction.Operand is ConstructorInfo) { ConstructorInfo mOperand = (ConstructorInfo)instruction.Operand; declType = mOperand.DeclaringType; name = mOperand.Name; calledId = declType.FullName + " " + RefHelp.GetNameWithParameterList(mOperand); } }
/// <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 = Globals.singleByteOpCodes[(int)value]; } else { value = il[position++]; code = Globals.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; // patched from comments on CP -hwd case OperandType.InlineField: metadataToken = ReadInt32(il, ref position); if (mi is ConstructorInfo) { instruction.Operand = module.ResolveField(metadataToken, mi.DeclaringType.GetGenericArguments(), null); } else { instruction.Operand = module.ResolveField(metadataToken, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()); } break; // patched from comments on CP -hwd case OperandType.InlineMethod: metadataToken = ReadInt32(il, ref position); try { if (mi is ConstructorInfo) { instruction.Operand = module.ResolveMethod(metadataToken, mi.DeclaringType.GetGenericArguments(), null); } else { instruction.Operand = module.ResolveMethod(metadataToken, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()); } } catch { if (mi is ConstructorInfo) { instruction.Operand = module.ResolveMember(metadataToken, mi.DeclaringType.GetGenericArguments(), null); } else { instruction.Operand = module.ResolveMember(metadataToken, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()); } } break; case OperandType.InlineSig: metadataToken = ReadInt32(il, ref position); instruction.Operand = module.ResolveSignature(metadataToken); break; // patched from comments on CP -hwd case OperandType.InlineTok: metadataToken = ReadInt32(il, ref position); //try //{ if (mi is ConstructorInfo) { instruction.Operand = module.ResolveType(metadataToken, mi.DeclaringType.GetGenericArguments(), null); } else { instruction.Operand = module.ResolveType(metadataToken, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()); } //} //catch //{ // int i = 1; //} break; // patched from comments on CP -hwd case OperandType.InlineType: metadataToken = ReadInt32(il, ref position); if (this.mi is MethodInfo) { instruction.Operand = module.ResolveType(metadataToken, this.mi.DeclaringType.GetGenericArguments(), this.mi.GetGenericArguments()); } else if (mi is ConstructorInfo) { instruction.Operand = module.ResolveType(metadataToken, this.mi.DeclaringType.GetGenericArguments(), null); } else { instruction.Operand = module.ResolveType(metadataToken); } 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); } }
/// <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 = Globals.singleByteOpCodes[(int)value]; } else { value = il[position++]; code = Globals.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 { try { instruction.Operand = module.ResolveMember(metadataToken); } catch (Exception) { //Try generic method try { instruction.Operand = module.ResolveMethod(metadataToken, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()); } catch (Exception) { //Try generic member try { instruction.Operand = module.ResolveMember(metadataToken, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()); } catch (Exception) { throw; } } } } 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 try { instruction.Operand = module.ResolveType(metadataToken); } catch (Exception) { 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); } }
/// <summary> /// Determines, how many operands a given CIL instruction will remove from the stack, and how many it will push onto the stack. /// </summary> /// <param name="ili">a CIL instruction</param> /// <param name="method">the method inside whose context the given instruction is executed</param> /// <param name="npop">number of removed stack operands</param> /// <param name="npush">number of stack operands pushed onto the stack</param> public static void GetStackBilance(ILInstruction ili, MethodBase method, out int npop, out int npush) { if (ili.Code.Equals(OpCodes.Ret)) { Type returnType; if (method.IsFunction(out returnType)) npop = 1; else npop = 0; npush = 0; } else if (ili.Code.Equals(OpCodes.Call) || ili.Code.Equals(OpCodes.Calli) || ili.Code.Equals(OpCodes.Callvirt) || ili.Code.Equals(OpCodes.Newobj)) { MethodBase mi = (MethodBase)ili.Operand; ParameterInfo[] pis = mi.GetParameters(); npop = pis.Length; if (ili.Code.Equals(OpCodes.Calli)) ++npop; if (mi.CallingConvention.HasFlag(CallingConventions.HasThis) && !ili.Code.Equals(OpCodes.Newobj)) ++npop; Type returnType; if (mi.IsFunction(out returnType) || ili.Code.Equals(OpCodes.Newobj)) npush = 1; else npush = 0; } else { npop = -StackOperands.GetNumOperands(ili.Code.StackBehaviourPop); npush = StackOperands.GetNumOperands(ili.Code.StackBehaviourPush); } }
private static bool IsLdloc(ILInstruction cili, out int value) { if (cili.Code == OpCodes.Ldloc) { value = (int)cili.Operand; return true; } else if (cili.Code == OpCodes.Ldloc_S) { value = (byte)cili.Operand; return true; } else if (cili.Code == OpCodes.Ldloc_0) { value = 0; return true; } else if (cili.Code == OpCodes.Ldloc_1) { value = 1; return true; } else if (cili.Code == OpCodes.Ldloc_2) { value = 2; return true; } else if (cili.Code == OpCodes.Ldloc_3) { value = 3; return true; } value = int.MaxValue; return false; }
private static bool IsLdc_I(ILInstruction cili, out int value) { if (cili.Code == OpCodes.Ldc_I4) { value = (int)cili.Operand; return true; } else if (cili.Code == OpCodes.Ldc_I4_0) { value = 0; return true; } else if (cili.Code == OpCodes.Ldc_I4_1) { value = 1; return true; } else if (cili.Code == OpCodes.Ldc_I4_2) { value = 2; return true; } else if (cili.Code == OpCodes.Ldc_I4_3) { value = 3; return true; } else if (cili.Code == OpCodes.Ldc_I4_4) { value = 4; return true; } else if (cili.Code == OpCodes.Ldc_I4_5) { value = 5; return true; } else if (cili.Code == OpCodes.Ldc_I4_6) { value = 6; return true; } else if (cili.Code == OpCodes.Ldc_I4_7) { value = 7; return true; } else if (cili.Code == OpCodes.Ldc_I4_8) { value = 8; return true; } else if (cili.Code == OpCodes.Ldc_I4_M1) { value = -1; return true; } else if (cili.Code == OpCodes.Ldc_I4_S) { value = (sbyte)cili.Operand; return true; } value = int.MaxValue; return false; }