public static MemberInfo ResolveMember(Module module, int metadataToken) { Assumes.NotNull(module); Assumes.IsTrue(metadataToken != 0); return module.ResolveMember(metadataToken); }
/// <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); } }
void CopyOpcode(byte[] Bytes, ref int i, ILGenerator Gen, Module Origin, List<int> ExceptionTrinkets, Dictionary<int, Label[]> LabelOrigins) { OpCode Code = GetOpcode(Bytes, ref i); // These are emitted by exception handling copier if an exception // block is imminent. If not, copy them as usual. if(Code == OpCodes.Leave && ExceptionTrinkets.Contains(i + 5)) { i += 4; return; } else if(Code == OpCodes.Leave_S && ExceptionTrinkets.Contains(i + 2)) { // This is a rather tricky one. See the comment preceding the call to MineLabels above. i++; return; } else if(Code == OpCodes.Endfinally && ExceptionTrinkets.Contains(i+1)) return; switch(Code.OperandType) { // If no argument, then re-emit the opcode case OperandType.InlineNone: { Gen.Emit(Code); break; } // If argument is a method, re-emit the method reference case OperandType.InlineMethod: { int Token = BitHelper.ReadInteger(Bytes, ref i); MethodBase Base = Origin.ResolveMethod(Token); if(Base is MethodInfo) Gen.Emit(Code, GrabMethod(Base as MethodInfo)); else if(Base is ConstructorInfo) Gen.Emit(Code, GrabConstructor(Base as ConstructorInfo)); else throw new InvalidOperationException("Inline method is neither method nor constructor."); break; } // Argument is a field reference case OperandType.InlineField: { int Token = BitHelper.ReadInteger(Bytes, ref i); FieldInfo Field = Origin.ResolveField(Token); Gen.Emit(Code, GrabField(Field)); break; } // Argument is a type reference case OperandType.InlineType: { int Token = BitHelper.ReadInteger(Bytes, ref i); Type Ref = Origin.ResolveType(Token); Gen.Emit(Code, GrabType(Ref)); break; } // Argument is an inline string case OperandType.InlineString: { int Token = BitHelper.ReadInteger(Bytes, ref i); string Copy = Origin.ResolveString(Token); Gen.Emit(Code, Copy); break; } // Argument is a metadata token case OperandType.InlineTok: { int Token = BitHelper.ReadInteger(Bytes, ref i); MemberInfo Info = Origin.ResolveMember(Token); if(Info.MemberType == MemberTypes.Field) { if(Code != OpCodes.Ldtoken || !TryReplaceBackingField(Bytes, i, Gen, Origin)) Gen.Emit(Code, GrabField(Info as FieldInfo)); } else if(Info.MemberType == MemberTypes.Method) Gen.Emit(Code, GrabMethod(Info as MethodInfo)); else if(Info.MemberType == MemberTypes.TypeInfo || Info.MemberType == MemberTypes.NestedType) Gen.Emit(Code, GrabType(Info as Type)); else throw new InvalidOperationException("Inline token is neither field, nor method, nor type"); break; } // Argument is a switch map case OperandType.InlineSwitch: { if(!LabelOrigins.ContainsKey(i)) throw new Exception("No switchmap found for RVA "+i.ToString("X")); Label[] Labels = LabelOrigins[i]; i += 4 + Labels.Length*4; Gen.Emit(Code, Labels); break; } // Argument is a single-byte branch target case OperandType.ShortInlineBrTarget: { if(!LabelOrigins.ContainsKey(i)) throw new Exception("No label origin found for RVA "+i.ToString("X")); Gen.Emit(Code, LabelOrigins[i][0]); i++; break; } // Argument is a byte case OperandType.ShortInlineI: case OperandType.ShortInlineVar: { Gen.Emit(Code, Bytes[++i]); break; } // Argument is a short case OperandType.InlineVar: { Gen.Emit(Code, BitHelper.ReadShort(Bytes, ref i)); break; } case OperandType.InlineBrTarget: { if(!LabelOrigins.ContainsKey(i)) throw new Exception("No label origin found for RVA "+i.ToString("X")); Gen.Emit(Code, LabelOrigins[i][0]); i += 4; break; } // Argument is a 32-bit integer case OperandType.InlineI: case OperandType.ShortInlineR: // This is actually a 32-bit float, but we don't care { Gen.Emit(Code, BitHelper.ReadInteger(Bytes, ref i)); break; } // Argument is a 64-bit integer case OperandType.InlineI8: { Gen.Emit(Code, BitHelper.ReadLong(Bytes, ref i)); break; } // Argument is a 64-bit float case OperandType.InlineR: { Gen.Emit(Code, BitHelper.ReadDouble(Bytes, ref i)); break; } // If ever we run across OpCodes.Calli this'll probably happen default: throw new InvalidOperationException("The method copier ran across an unknown opcode."); } }
/// <summary> /// Resolves all MetadataTokens present in <see cref="cgm"/> using the <see cref="manifestModule"/> /// </summary> /// <param name="cgm"></param> /// <param name="manifestModule"></param> /// <param name="memberInfoCache"> /// Optional cache dictionary for use when this is being called within a loop, helps performance. /// </param> /// <param name="ignoreAssemblyFullNames"> /// Optional list of fully-qualified assembly names whose members should NOT be added (e.g. mscorlib). /// </param> /// <param name="maxErrors">The max number of exceptions to be incurred before abandoning.</param> /// <returns>Count of errors encountered, will range from 0 to <see cref="maxErrors"/></returns> public static int ResolveCgMemberMetadataTokens(CgMember cgm, Module manifestModule, Dictionary<int, MemberInfo> memberInfoCache, string[] ignoreAssemblyFullNames, int maxErrors = 5) { if (cgm == null) return maxErrors; if (manifestModule == null) return maxErrors; var errorCount = 0; //for each method, get all invoked metadata tokens foreach (var metadataToken in cgm.opCodeCallsAndCallvirtsMetadatTokens) { try { MemberInfo runtimeMem = null; //resolve invoked metadata token to a member type if (memberInfoCache != null && memberInfoCache.ContainsKey(metadataToken)) { runtimeMem = memberInfoCache[metadataToken]; } else { runtimeMem = manifestModule.ResolveMember(metadataToken); } if (runtimeMem == null) continue; var declaringType = runtimeMem.DeclaringType; var declaringTypeAsmName = declaringType?.AssemblyQualifiedName; if (string.IsNullOrWhiteSpace(declaringTypeAsmName)) continue; if (ignoreAssemblyFullNames != null && ignoreAssemblyFullNames.Any(declaringTypeAsmName.EndsWith)) continue; //add to cache for performance if (memberInfoCache != null && !memberInfoCache.ContainsKey(metadataToken)) memberInfoCache.Add(metadataToken, runtimeMem); var runtimeMi = runtimeMem as MethodInfo; if (runtimeMi != null) { var ncgm = GetAsCgMember(runtimeMi, false); if (ncgm == null) continue; ncgm.MetadataToken = metadataToken; ncgm.DeclaringTypeAsmName = declaringTypeAsmName; cgm.OpCodeCallAndCallvirts.Add(ncgm); continue; } var runtimePi = runtimeMem as PropertyInfo; if (runtimePi != null) { var ncgm = GetAsCgMember(runtimePi, false, null); if (ncgm == null) continue; ncgm.MetadataToken = metadataToken; ncgm.DeclaringTypeAsmName = declaringTypeAsmName; cgm.OpCodeCallAndCallvirts.Add(ncgm); continue; } var runtimeFi = runtimeMem as FieldInfo; if (runtimeFi == null) continue; var fiCgm = GetAsCgMember(runtimeFi, false, null); if (fiCgm == null) continue; fiCgm.MetadataToken = metadataToken; fiCgm.DeclaringTypeAsmName = declaringTypeAsmName; cgm.OpCodeCallAndCallvirts.Add(fiCgm); } catch { errorCount += 1; if (errorCount > maxErrors) break; } } return errorCount; }
private static int _ReadOperand(MethodBase This, OpCode code, int position, byte[] il, Module module, ILInstruction instruction) { int metadataToken; 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.DeclaringType.GetGenericArguments(), This.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: { var count = ReadInt32(il, ref position); var casesAddresses = new int[count]; for (var i = 0; i < count; i++) { casesAddresses[i] = ReadInt32(il, ref position); } var cases = new int[count]; for (var 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: { if (instruction.Code == OpCodes.Ldc_I4_S) { instruction.Operand = ReadSByte(il, ref position); } else { instruction.Operand = ReadByte(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."); } } return(position); }
private object ReadOperand(OpCode code, Module module, ref long localVariableIndex) { object operand = null; switch (code.OperandType) { case OperandType.InlineNone: break; case OperandType.InlineSwitch: int length = stream.ReadInt32(); int[] branches = new int[length]; int[] offsets = new int[length]; for (int i = 0; i < length; i++) { offsets[i] = stream.ReadInt32(); } for (int i = 0; i < length; i++) { branches[i] = (int)stream.BaseStream.Position + offsets[i]; } operand = (object) branches; // Just forget to save readed offsets break; case OperandType.ShortInlineBrTarget: if (code.FlowControl != FlowControl.Branch && code.FlowControl != FlowControl.Cond_Branch) { operand = stream.ReadSByte(); } else { operand = stream.ReadSByte() + stream.BaseStream.Position; } break; case OperandType.InlineBrTarget: operand = stream.ReadInt32()+ stream.BaseStream.Position;; break; case OperandType.ShortInlineI: if (code == OpCodes.Ldc_I4_S) operand = (sbyte)stream.ReadByte(); else operand = stream.ReadByte(); break; case OperandType.InlineI: operand = stream.ReadInt32(); break; case OperandType.ShortInlineR: operand = stream.ReadSingle(); break; case OperandType.InlineR: operand = stream.ReadDouble(); break; case OperandType.InlineI8: operand = stream.ReadInt64(); break; case OperandType.InlineSig: operand = module.ResolveSignature(stream.ReadInt32()); break; case OperandType.InlineString: operand = module.ResolveString(stream.ReadInt32()); break; case OperandType.InlineTok: case OperandType.InlineType: case OperandType.InlineMethod: case OperandType.InlineField: operand = module.ResolveMember(stream.ReadInt32(), typeArgs, methodArgs); break; case OperandType.ShortInlineVar: { int index = stream.ReadByte(); operand = GetVariable(code, index); localVariableIndex = index; } break; case OperandType.InlineVar: { int index = stream.ReadUInt16(); operand = GetVariable(code, index); localVariableIndex = index; } break; default: throw new NotSupportedException(); } return operand; }
/// <summary> /// Resolves the <see cref="tokenId"/>to a <see cref="MemberInfo"/> using /// the <see cref="manifestModule"/> /// </summary> /// <param name="manifestModule"></param> /// <param name="tokenId"></param> /// <param name="mi"></param> /// <param name="msgOut">Inteneded for debug trace from the Console.</param> /// <returns></returns> internal bool TryResolveRtMemberInfo(Module manifestModule, MetadataTokenId tokenId, out MemberInfo mi, StringBuilder msgOut) { mi = null; if (manifestModule == null) return false; try { mi = manifestModule.ResolveMember(tokenId.Id); } catch (SystemException)//does not resolve the token { if (msgOut != null) msgOut.Append(", Message: 'manifest module could not resolve id'"); return false; } return mi != null; }
private IMemberReference FindMemberRef(uint metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) { return(AssemblyManager.FindMember(_netModule.ResolveMember((int)metadataToken, genericTypeArguments, genericMethodArguments))); }