static void InjectWriteIl(List<Instruction> writeTimeIl, ILProcessor ilProcessor, Instruction beforeThis) { foreach (var instruction in writeTimeIl) { ilProcessor.InsertBefore(beforeThis, instruction); } ilProcessor.InsertBefore(beforeThis, Instruction.Create(OpCodes.Endfinally)); }
private void InterceptMethod(ILProcessor processor, TypeReference typeReference, Instruction instruction, string name) { var typeDefinition = typeReference.Resolve(); var attributeConstructor = typeDefinition.Methods.First(x => x.Name == ".ctor"); var attributeMethod = typeDefinition.Methods.First(x => x.Name == name); processor.InsertBefore(instruction, processor.Create(OpCodes.Newobj, attributeConstructor)); processor.InsertBefore(instruction, processor.Create(OpCodes.Call, _getCurrentMethod)); processor.InsertBefore(instruction, processor.Create(OpCodes.Call, attributeMethod)); }
public void ModifyAssembly(string fileName) { MethodInfo writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); // ReaderParameters { ReadWrite = true } is necessary to later write the file using (ModuleDefinition module = ModuleDefinition.ReadModule(fileName, new ReaderParameters { ReadWrite = true })) { // Modify the assembly TypeDefinition[] types = module.Types.ToArray(); MethodReference methodReference = module.ImportReference(writeLineMethod); foreach (var type in types) { foreach (MethodDefinition methodToChange in type.Methods) { string sentence = String.Concat("Code added in ", methodToChange.Name); Mono.Cecil.Cil.ILProcessor ilProcessor = methodToChange.Body.GetILProcessor(); Mono.Cecil.Cil.Instruction loadStringInstruction = ilProcessor.Create(OpCodes.Ldstr, sentence); Mono.Cecil.Cil.Instruction callInstruction = ilProcessor.Create(OpCodes.Call, methodReference); Mono.Cecil.Cil.Instruction methodFirstInstruction = methodToChange.Body.Instructions[0]; ilProcessor.InsertBefore(methodFirstInstruction, loadStringInstruction); ilProcessor.InsertAfter(loadStringInstruction, callInstruction); } } module.Write(); // Write to the same file that was used to open the file } }
private void ProcessPredicateCreationPattern(ILProcessor il, Instruction queryInvocation) { MethodReference predicateMethod = GetMethodReferenceFromInlinePredicatePattern(queryInvocation); Instruction ldftn = GetNthPrevious(queryInvocation, 2); il.InsertBefore(ldftn, il.Create(OpCodes.Dup)); il.InsertBefore(queryInvocation, il.Create(OpCodes.Ldtoken, predicateMethod)); // At this point the stack is like this: // runtime method handle, delegate reference, target object, ObjectContainer il.Replace(queryInvocation, il.Create(OpCodes.Call, InstantiateGenericMethod( _NativeQueryHandler_ExecuteInstrumentedDelegateQuery, GetQueryCallExtent(queryInvocation)))); }
void InjectNewWriter(MethodDefinition sendData, ILProcessor processor, out VariableDefinition mswriter, out OpCode binaryWriter) { var buffer = sendData.Body.Instructions.First( x => x.OpCode == OpCodes.Ldsfld && (x.Operand as FieldReference).Name == "buffer" ); while (!(buffer.Next.OpCode == OpCodes.Callvirt && (buffer.Next.Operand as MethodReference).Name == "set_Position")) { processor.Remove(buffer.Next); } processor.Remove(buffer.Next); //processor.Remove(buffer); //VariableDefinition mswriter; sendData.Body.Variables.Add(mswriter = new VariableDefinition("mswriter", this.SourceDefinition.MainModule.Import(typeof(MemoryStream)) )); var res = processor.InsertBefore(buffer.Previous.Previous, new { OpCodes.Newobj, Operand = this.SourceDefinition.MainModule.Import(typeof(MemoryStream) .GetConstructors() .Single(x => x.GetParameters().Count() == 0) ) }, new { OpCodes.Stloc, Operand = mswriter }, new { OpCodes.Ldloc, Operand = mswriter } ); buffer.Previous.Previous.ReplaceTransfer(res[0], sendData); processor.Remove(buffer.Previous); processor.Remove(buffer.Previous); buffer.OpCode = OpCodes.Newobj; buffer.Operand = this.SourceDefinition.MainModule.Import(typeof(BinaryWriter) .GetConstructors() .Single(x => x.GetParameters().Count() == 1) ); if (buffer.Next.OpCode != OpCodes.Ldloc_1) { throw new NotSupportedException("Expected Ldloc_1"); } /*var*/ binaryWriter = buffer.Next.OpCode; processor.InsertAfter(buffer, new { OpCodes.Stloc_1 } ); }
/// <summary> /// Inserts a list of anonymous instructions before the target instruction /// </summary> public static List <Instruction> InsertBefore(this Mono.Cecil.Cil.ILProcessor processor, Instruction target, params object[] instructions) { var created = new List <Instruction>(); foreach (var anon in instructions) { var ins = AnonymousToInstruction(anon); processor.InsertBefore(target, ins); created.Add(ins); } return(created); }
private void ProcessCachedStaticFieldPattern(ILProcessor il, Instruction queryInvocation) { MethodReference predicateMethod = GetMethodReferenceFromStaticFieldPattern(queryInvocation); il.InsertBefore(queryInvocation, il.Create(OpCodes.Ldtoken, predicateMethod)); // At this point the stack is like this: // runtime method handle, delegate reference, ObjectContainer il.Replace(queryInvocation, il.Create(OpCodes.Call, InstantiateGenericMethod( _NativeQueryHandler_ExecuteInstrumentedStaticDelegateQuery, GetQueryCallExtent(queryInvocation)))); }
void HandleOfProperty(Instruction instruction, ILProcessor ilProcessor, Func<PropertyDefinition, MethodDefinition> func) { var propertyNameInstruction = instruction.Previous; var propertyName = GetLdString(propertyNameInstruction); var typeNameInstruction = propertyNameInstruction.Previous; var typeName = GetLdString(typeNameInstruction); var assemblyNameInstruction = typeNameInstruction.Previous; var assemblyName = GetLdString(assemblyNameInstruction); var typeDefinition = GetTypeDefinition(assemblyName, typeName); var property = typeDefinition.Properties.FirstOrDefault(x => x.Name == propertyName); if (property == null) { throw new WeavingException($"Could not find property named '{propertyName}'.") { SequencePoint = instruction.SequencePoint }; } var methodDefinition = func(property); if (methodDefinition == null) { throw new WeavingException($"Could not find property named '{propertyName}'.") { SequencePoint = instruction.SequencePoint }; } ilProcessor.Remove(typeNameInstruction); ilProcessor.Remove(propertyNameInstruction); assemblyNameInstruction.OpCode = OpCodes.Ldtoken; assemblyNameInstruction.Operand = methodDefinition; if (typeDefinition.HasGenericParameters) { var typeReference = ModuleDefinition.ImportReference(typeDefinition); ilProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Ldtoken, typeReference)); instruction.Operand = getMethodFromHandleGeneric; } else { instruction.Operand = getMethodFromHandle; } ilProcessor.InsertAfter(instruction, Instruction.Create(OpCodes.Castclass, methodInfoType)); }
void HandleOfField(Instruction instruction, ILProcessor ilProcessor) { //Info.OfField("AssemblyToProcess","MethodClass","Field"); var fieldNameInstruction = instruction.Previous; var fieldName = GetLdString(fieldNameInstruction); var typeNameInstruction = fieldNameInstruction.Previous; var typeName = GetLdString(typeNameInstruction); var assemblyNameInstruction = typeNameInstruction.Previous; var assemblyName = GetLdString(assemblyNameInstruction); var typeDefinition = GetTypeDefinition(assemblyName, typeName); var fieldDefinition = typeDefinition.Fields.FirstOrDefault(x => x.Name == fieldName); if (fieldDefinition == null) { throw new WeavingException($"Could not find field named '{fieldName}'.") { SequencePoint = instruction.SequencePoint }; } var fieldReference = ModuleDefinition.ImportReference(fieldDefinition); ilProcessor.Remove(typeNameInstruction); ilProcessor.Remove(fieldNameInstruction); assemblyNameInstruction.OpCode = OpCodes.Ldtoken; assemblyNameInstruction.Operand = fieldReference; if (typeDefinition.HasGenericParameters) { var typeReference = ModuleDefinition.ImportReference(typeDefinition); ilProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Ldtoken,typeReference)); instruction.Operand = getFieldFromHandleGeneric; } else { instruction.Operand = getFieldFromHandle; } }
private void ReplaceFixedArrayStatement(MethodDefinition method, ILProcessor ilProcessor, Instruction fixedtoPatch) { var paramT = ((GenericInstanceMethod)fixedtoPatch.Operand).GenericArguments[0]; // Preparing locals // local(0) T* method.Body.Variables.Add(new VariableDefinition("pin", new PinnedType(new ByReferenceType(paramT)))); int index = method.Body.Variables.Count - 1; Instruction ldlocFixed; Instruction stlocFixed; switch (index) { case 0: stlocFixed = ilProcessor.Create(OpCodes.Stloc_0); ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_0); break; case 1: stlocFixed = ilProcessor.Create(OpCodes.Stloc_1); ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_1); break; case 2: stlocFixed = ilProcessor.Create(OpCodes.Stloc_2); ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_2); break; case 3: stlocFixed = ilProcessor.Create(OpCodes.Stloc_3); ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_3); break; default: stlocFixed = ilProcessor.Create(OpCodes.Stloc, index); ldlocFixed = ilProcessor.Create(OpCodes.Ldloc, index); break; } var instructionLdci40 = ilProcessor.Create(OpCodes.Ldc_I4_0); ilProcessor.InsertBefore(fixedtoPatch, instructionLdci40); var instructionLdElema = ilProcessor.Create(OpCodes.Ldelema, paramT); ilProcessor.InsertBefore(fixedtoPatch, instructionLdElema); ilProcessor.InsertBefore(fixedtoPatch, stlocFixed); ilProcessor.Replace(fixedtoPatch, ldlocFixed); }
private InvocationResult OnInvocation (MethodDefinition method, ILProcessor processor, Instruction i, MethodReference mr) { Mono.Cecil.GenericParameter genPar = null; if (!mr.FullName.Contains ("<")) { //if(Verbosity >= 8) - shouldn't be reached Console.WriteLine ("[UNREACHABLE] Skipping method that contains no <"); return InvocationResult.Skipped; } if (mr.FullName.Contains (" System.")) { // REVIEW - does AOT somehow support some of these cases? if (Verbosity >= Verbosities.Skipping) Console.WriteLine ("Skipping method invocation that contains ' System.': [[" + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name + "]]"); return InvocationResult.Failed; } #if CUSTOM // Custom blacklist if(!mr.FullName.Contains(" LionFire.") && !mr.FullName.Contains(" Dycen.")) { if(Verbosity >= Verbosities.Skipping)Console.WriteLine("Skipping method that is not LionFire or Dycen:" + mr.FullName + " in " + method.DeclaringType.FullName + "."+ method.Name); //continue; return InvocationResult.Skipped } #endif var genPars = mr.Resolve ().GenericParameters; // Console.WriteLine("TEMP2 - " + genPars.Count); // var genPars = mr.GetGenericParameters(method.Module); // Console.WriteLine("TEMP " + mr.Name); // Console.WriteLine("TEMP genPars.Count " + genPars.Count); if (genPars.Count != 1) { if (Verbosity >= Verbosities.Warning) Console.WriteLine ("[NS] Replacing methods with more than 1 generic parameter not supported: " + genPars.Count + ": " + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name); return InvocationResult.Failed; } else { genPar = genPars [0]; // var resolved = genPar.Resolve(); // Console.WriteLine("NEW -- <" + (resolved == null ? "null" : resolved.Name) + ">"); if (Verbosity >= 10) Console.WriteLine ("NEW |- <" + genPar + ">"); } #region string genericParameter = ...; string genericParameter; Type genericTypeParameter; TypeDefinition genericTypeParameterDefinition = null; { string n = mr.FullName.Split (' ') [1]; n = n.Split (new string[]{"::"}, StringSplitOptions.RemoveEmptyEntries) [1]; int startI = n.IndexOf ('<') + 1; int stack = 0; int endI = startI + 1; while (stack > 0 || n[endI] != '>') { if (n [endI] == '<') stack++; if (n [endI] == '>') stack--; endI++; } int length = endI - startI; genericParameter = n.Substring (startI, length); // if(genericParameter.StartsWith("!!")) // { // int genParAliasIndex = Convert.ToInt32(genericParameter.Substring(2)); // // var genParAlias = genPars[genParAliasIndex]; // // // genericParameter = genParAlias.FullName; // Console.WriteLine("NEW - Generic method alias param: " + genericParameter); // } // if(genericParameter.Contains("<") || genericParameter.Contains(">")) // { // Console.WriteLine("Unsupported generic method ("+mr.FullName+") with generic parameter: " + genericParameter); // skipped++; // continue; // } if (Verbosity >= 8) Console.WriteLine ("Generic method param: " + genericParameter); genericTypeParameter = Type.GetType (genericParameter, false); //if(genericTypeParameter == null) { foreach (ModuleDefinition modDef in ads.SelectMany(assDef => assDef.Modules)) { // foreach(var modType in modDef.Types) // { // Console.WriteLine("ccc - " + modType); // } genericTypeParameterDefinition = modDef.Types.Where (td => td.FullName == genericParameter // && !td.IsGenericInstance ).FirstOrDefault (); if (genericTypeParameterDefinition != null) { if (Verbosity >= 9) Console.WriteLine ("TODO - got genTD: " + genericTypeParameterDefinition); break; } } if (genericTypeParameterDefinition == null) { if (Verbosity >= 8) Console.WriteLine (" x Could not get TypeDefinition for " + genericParameter); // No continue, this is not a problem } if (genericTypeParameter == null && genericTypeParameterDefinition == null) { if (Verbosity >= Verbosities.Error) { Console.WriteLine (" x - Failed to get Type for " + genericParameter + " in invocation: " + mr.FullName + " in method " + method.FullName); } skipped++; return InvocationResult.Failed; } } } #endregion #if ONLY_VOID_OR_GENPARM // OLD, now other return types are supported if they are the same as replaced method string matchingReturnType = "!!0"; // genericTypeParameter.FullName; if(mr.ReturnType.FullName != "System.Void" && mr.ReturnType.FullName != matchingReturnType) // && mr.ReturnType.FullName != genericTypeParameter.FullName) { if(Verbosity >= 3) Console.WriteLine(" x generic method doesn't return System.Void or '" +matchingReturnType+ "': " + mr.FullName+ ", but instead: " + mr.ReturnType.FullName); continue; } #endif // if(Verbosity >= 9) Console.WriteLine("mr: " + mr.Name); TypeDefinition tr = mr.DeclaringType.Resolve (); MethodDefinition replacementMethod = null; // if(mr.DeclaringType.Name == "MultiType") // { // foreach(MethodDefinition replacementMethod_ in // tr.Methods) // { // Console.WriteLine("z " + replacementMethod_.Name + " " + replacementMethod_.FullName); // } // } bool noCast = false; foreach (MethodDefinition replacementMethod_ in tr.Methods.Where(mr_ => mr_.Name == mr.Name && !mr_.HasGenericParameters)) { noCast = false; // TODO: Verify parameters if (!replacementMethod_.HasParameters) continue; if (replacementMethod_.Parameters.Count != mr.Parameters.Count + 1) { if (Verbosity >= 8) Console.WriteLine (" [x? param count] - (alt) candidate replacement method has wrong parameter count: " + replacementMethod_.FullName + " [[" + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name + "]]"); continue; } // Console.WriteLine("Replacement param type: "+ replacementMethod_.Parameters[0].ParameterType.FullName); if (replacementMethod_.Parameters [replacementMethod_.Parameters.Count - 1].ParameterType.FullName != "System.Type") { if (Verbosity >= 8) Console.WriteLine (" [x? param type] - (alt) candidate replacement does not have Type parameter at the end of parameters : " + replacementMethod_.FullName + " [[" + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name + "]]"); continue; } if (mr.ReturnType.FullName == replacementMethod_.ReturnType.Resolve ().FullName) { noCast = true; if (Verbosity >= 9) Console.WriteLine (" - (alt) generic method and alt method return same type:: " + mr.ReturnType.FullName); } else if (mr.ReturnType.FullName != "System.Void") { // Replacement must return object if (replacementMethod_.ReturnType.Resolve ().FullName != "System.Object") { if (Verbosity >= 3) Console.WriteLine (" [x? return] (alt) generic method returns T but candidate replacement method does not return System.Object: " + replacementMethod_.FullName + " [[" + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name + "]]"); continue; } } if (Verbosity >= 8) Console.WriteLine ("FOUND ALTERNATE METHOD: " + replacementMethod_); replacementMethod = replacementMethod_; break; // FUTURE: don't break here, keep going to see if there are multiple (ambiguous) matches and throw/output error } if (replacementMethod == null) { if (!(" " + mr.FullName).Contains (" System.")) { if (Verbosity >= Verbosities.Warning) Console.WriteLine ("[__] No alternate found for [[" + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name + "]]"); // + mr.DeclaringType.FullName+"." +mr.Name + "(...)"); } skipped++; return InvocationResult.Failed; } // if(mr.Name != "TestMethod") continue; // TEMP if (Verbosity >= Verbosities.Success) Console.WriteLine (" O Replacing " + mr.FullName + " " + mr.GenericParameters.Count + " generic parameters" + " " + mr.Parameters.Count + " parameters" + " | " + mr.GetElementMethod ().FullName + "" + " | " + mr.GetElementMethod ().HasGenericParameters + "" + " | " + mr.GetElementMethod ().GenericParameters [0].Name + "" ); // if(Verbosity >= 6) // Console.WriteLine("Resolved non-specific generic method: " + mr.FullName); // if(Verbosity >= 8) Console.WriteLine("RESOLVED TYPE: " + genericTypeParameter); // var typeModuleDefinition = ModuleDefinition.ReadModule(type.Module.Assembly.Location); // var typeDefinition = typeModuleDefinition.Types.Where(td => td.FullName == genericParameter).FirstOrDefault(); // if(typeDefinition != null && Verbosity >= 5) // { // Console.WriteLine("Resolved typeDefinition: " + typeDefinition); // } // else // { // Console.WriteLine("Failed to resolve typeDefinition: " + type.FullName); //// foreach(var td in ModuleDefinition.ReadModule(type.Module.Assembly.Location).Types) //// { //// Console.WriteLine(" ... " + td.FullName); //// } // continue; // } // method.Module.Import(type); // try removing this // IMetadataScope scope = method.Module; // var typeRef = new TypeReference(type.Namespace, type.Name, typeModuleDefinition, scope, type.IsValueType); // Console.WriteLine("TypeRef: "+ typeRef); // method.Module.Import(type); var replacementMethodImported = method.Module.Import (replacementMethod); // IL_0000: ldtoken Rewriter.TestClass if (genericTypeParameter != null) { processor.InsertBefore (i, processor.Create (OpCodes.Ldtoken, method.Module.Import (genericTypeParameter))); } else { processor.InsertBefore (i, processor.Create (OpCodes.Ldtoken, method.Module.Import (genericTypeParameterDefinition))); } // IL_0005: call class [mscorlib]System.Type class // [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) var gtfh = typeof(Type).GetMethod ("GetTypeFromHandle"); MethodReference gtfhRef = method.Module.Import (gtfh, mr); processor.InsertBefore (i, processor.Create (OpCodes.Call, gtfhRef)); // IL_000a: call void class Rewriter.TestClass::TestMethod(class [mscorlib]System.Type) var callMethod = processor.Create (i.OpCode, replacementMethodImported); processor.InsertAfter (i, callMethod); #region Cast the result, if it exists if (mr.ReturnType.FullName != "System.Void" && !noCast) { string castAssembly; string castType; if (genericTypeParameter != null) { castAssembly = genericTypeParameter.Assembly.GetName (false).Name; castType = "[" + castAssembly + "]" + genericTypeParameter.FullName; } else if (genericTypeParameterDefinition != null) { castAssembly = ""; castType = genericTypeParameterDefinition.ToString (); // var resolvedGTPD = genericTypeParameterDefinition.Resolve(); // resolvedGTPD.FullName } else { castType = "???"; Console.WriteLine ("INTERNAL ERROR - genericTypeParameter not set for " + mr.FullName + ". genericTypeParameterDefinition:" + genericTypeParameterDefinition.Resolve ()); return InvocationResult.Failed; } // castAssembly = castAssembly.Substring(castAssembly.IndexOf(",")); if (Verbosity > 8) Console.WriteLine ("CAST to " + castType + " | " + genericTypeParameterDefinition); var importedGenericType = mr.Module.Import (genericTypeParameterDefinition); processor.InsertAfter (callMethod, processor.Create (OpCodes.Castclass, importedGenericType)); } #endregion processor.Remove (i); replaced++; // if(Verbosity >= Verbosities.Success) // Console.WriteLine(" - " + ((MethodReference)i.Operand).Name + " replaced with " + replacementMethod.FullName); // mr.GetGenericParameters(null); // // if(method.GenericParameters.Count == 0) return; // // if(method.GenericParameters.Count > 1) // { // Console.WriteLine("Warning: cannot handle more than one generic parameter yet: " + // method.DeclaringType.FullName + "." + method.Name); // return; // } // // var body = method.Body; // body.Instructions // if(method.GenericParameters.Count == 1) // { // } return InvocationResult.Succeeded; }
private static void MoveInstructions(Instruction start, Instruction end, Instruction insertionPoint, ILProcessor il) { IList<Instruction> toBeMoved = new List<Instruction>(); Instruction boundary = end.Next; while(start != boundary) { toBeMoved.Add(start); Instruction next = start.Next; il.Remove(start); start = next; } foreach (Instruction instruction in toBeMoved) { il.InsertBefore(insertionPoint, instruction); } }
public static void InjectInstructionsBefore(ILProcessor p, Instruction before, IEnumerable<Instruction> commands) { var instructions = commands.ToList(); /* * following stuff is from http://eatplayhate.wordpress.com/2010/07/18/mono-cecil-vs-obfuscation-fight/ * and should redirect jumps?! */ var method = p.Body.Method; var oldTarget = before; var newTarget = instructions[0]; var isNewCode = false; for (int j = 0; j < method.Body.Instructions.Count; j++) { var inst = method.Body.Instructions[j]; if (inst == newTarget) { isNewCode = true; } if (inst == before) { isNewCode = false; } if (!isNewCode) { if ((inst.OpCode.FlowControl == FlowControl.Branch || inst.OpCode.FlowControl == FlowControl.Cond_Branch) && inst.Operand == oldTarget) inst.Operand = newTarget; } } foreach (ExceptionHandler v in method.Body.ExceptionHandlers) { if (v.FilterStart == oldTarget) v.FilterStart = newTarget; if (v.HandlerEnd == oldTarget) v.HandlerEnd = newTarget; if (v.HandlerStart == oldTarget) v.HandlerStart = newTarget; if (v.TryEnd == oldTarget) v.TryEnd = newTarget; if (v.TryStart == oldTarget) v.TryStart = newTarget; } //update: We now insert after changing, so trgs in the currently inserted code are not changed foreach (var instruction in instructions) { p.InsertBefore(before, instruction); } }
public static void MethodPrepend(ILProcessor il, Instruction first, IEnumerable<Instruction> instructions) { foreach (var instr in instructions) il.InsertBefore(first, instr); }
private static void Instrument ( AssemblyDefinition assembly, TypeDefinition type, Instruction instruction, MethodReference countReference, MethodDefinition method, ILProcessor worker, string lastLine, InstrumentConfig config, TextWriter writer, ref int instrumentIndex) { //if the previous instruction is a Prefix instruction then this instruction MUST go with it. //we cannot put an instruction between the two. if (instruction.Previous != null && instruction.Previous.OpCode.OpCodeType == OpCodeType.Prefix) return; if (config.HasOffset (method.FullName, instruction.Offset)) return; if (lastLine != null && config.HasLine (method.FullName, lastLine)) { return; } var lineNumStart = -1; var lineNumEnd = -1; if (instruction.SequencePoint != null) { lineNumStart = instruction.SequencePoint.StartLine; lineNumEnd = instruction.SequencePoint.EndLine; } var parentTypeRef = type; while (parentTypeRef.DeclaringType != null) parentTypeRef = parentTypeRef.DeclaringType; var line = string.Join ("\t", assembly.Name, //0 parentTypeRef.FullName,//1 method.FullName, //2 lineNumStart, //3 lineNumEnd, //4 instruction.Offset, //5 instruction.ToString ().Replace ("\n", " "), //6 instruction.SequencePoint?.Document.Url); //7 writer.WriteLine (line); var pathParamLoadInstruction = worker.Create (OpCodes.Ldstr, config.HitsPathPrefix); var lineParamLoadInstruction = worker.Create (OpCodes.Ldc_I4, instrumentIndex); var registerInstruction = worker.Create (OpCodes.Call, countReference); //inserting method before instruction because after will not happen after a method Ret instruction worker.InsertBefore (instruction, pathParamLoadInstruction); worker.InsertAfter (pathParamLoadInstruction, lineParamLoadInstruction); worker.InsertAfter (lineParamLoadInstruction, registerInstruction); ++instrumentIndex; //change try/finally etc to point to our first instruction if they referenced the one we inserted before foreach (var handler in method.Body.ExceptionHandlers) { if (handler.FilterStart == instruction) handler.FilterStart = pathParamLoadInstruction; if (handler.TryStart == instruction) handler.TryStart = pathParamLoadInstruction; if (handler.TryEnd == instruction) handler.TryEnd = pathParamLoadInstruction; if (handler.HandlerStart == instruction) handler.HandlerStart = pathParamLoadInstruction; if (handler.HandlerEnd == instruction) handler.HandlerEnd = pathParamLoadInstruction; } //change instructions with a target instruction if they referenced the one we inserted before to be our first instruction foreach (var iteratedInstruction in method.Body.Instructions) { var operand = iteratedInstruction.Operand; if (operand == instruction) { iteratedInstruction.Operand = pathParamLoadInstruction; continue; } if (!(operand is Instruction [])) continue; var operands = (Instruction [])operand; for (var i = 0; i < operands.Length; ++i) { if (operands [i] == instruction) operands [i] = pathParamLoadInstruction; } } }
/// <summary> /// Inserts the given instructions before the current (this) instruction using the given processor /// </summary> public static void InsertBefore(this Instruction instruction, ILProcessor processor, IEnumerable<Instruction> instructions) { foreach (var newInstruction in instructions) { processor.InsertBefore(instruction, newInstruction); } }
private void InsertCall(ILProcessor proc, MethodReference mr) { //by design argument count-equivalence, as many args must be loaded on the stack var ldargs = mr.Parameters.Select((_, i) => proc.Create(OpCodes.Ldarg, i+1)).ToList(); var returnIns = _methodDefinition.Body.Instructions.Last(); foreach (var ldarg in ldargs) proc.InsertBefore(returnIns, ldarg); var call = proc.Create(OpCodes.Call, mr); proc.InsertBefore(returnIns, call); }
public bool EmitRecord(ILProcessor processor, MethodDefinition method, Instruction instr) { var filename = instr.SequencePoint.Document.Url; var start = instr.SequencePoint.StartLine; var end = instr.SequencePoint.EndLine; var fieldName = "instrument_" + this.GetHash(filename, start, end); if (!this.m_RecorderDefinition.Fields.Any(x => x.Name == fieldName)) { // Create the field. var fieldDef = new FieldDefinition( fieldName, FieldAttributes.Public | FieldAttributes.Static, this.m_MainModule.Import(typeof(bool))); this.m_RecorderDefinition.Fields.Add(fieldDef); this.m_Mappings.Add(fieldName, new InstrumentationInfo { Filename = filename, Start = start, End = end, FieldDef = fieldDef }); } var field = this.m_RecorderDefinition.Fields.First(x => x.Name == fieldName); var insertBoolOp = processor.Create(OpCodes.Ldc_I4_1); var setFieldOp = processor.Create(OpCodes.Stsfld, field); processor.InsertBefore(instr, insertBoolOp); processor.InsertAfter(insertBoolOp, setFieldOp); return true; }
internal static void EncapsulateMethodBodyWithTryFinallyBlock(this ILProcessor ilProcessor, Instruction firstInstruction, Action <ILProcessor, Instruction> insertBeforReturn) { var body = ilProcessor.Body; if (body.Method.IsConstructor && !body.Method.IsStatic) { var ctor = GetFirstConstructorInstruction(body); if (ctor != null) { if (body.Instructions.IndexOf(ctor) > 2) { var lastInstruction = body.Instructions.Last(); var firtLDarg0BeforeCtor = ctor.GetFirstPreviousLdarg_0(); if (firstInstruction != firtLDarg0BeforeCtor) { EncapsulateWithTryCatch(ilProcessor, firstInstruction, firtLDarg0BeforeCtor); } if (ctor.GetFirstNotNopInstruction().Equals(lastInstruction)) { insertBeforReturn(ilProcessor, lastInstruction); return; } } if (firstInstruction.Next.OpCode != OpCodes.Nop) { firstInstruction = Instruction.Create(OpCodes.Nop); ilProcessor.InsertAfter(ctor, firstInstruction); } } } var returnStart = ilProcessor.FixReturns(); var beforeReturn = Instruction.Create(OpCodes.Endfinally); ilProcessor.InsertBefore(returnStart, beforeReturn); if (body.Instructions.First().Equals(firstInstruction)) { Instruction tryStart = Instruction.Create(OpCodes.Nop); ilProcessor.InsertBefore(firstInstruction, tryStart); } Instruction finallyStart = Instruction.Create(OpCodes.Nop); ilProcessor.InsertBefore(beforeReturn, finallyStart); insertBeforReturn(ilProcessor, beforeReturn); var handler = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = firstInstruction, TryEnd = finallyStart, HandlerStart = finallyStart, HandlerEnd = returnStart, }; body.ExceptionHandlers.Add(handler); }
private void ReplaceAddPinnedStructGeneric(MethodDefinition method, ILProcessor ilProcessor, Instruction incrementPinnedToPatch) { var paramT = ((GenericInstanceMethod)incrementPinnedToPatch.Operand).GenericArguments[0]; var sizeOfInst = ilProcessor.Create(OpCodes.Sizeof, paramT); ilProcessor.Replace(incrementPinnedToPatch, sizeOfInst); var instructionAdd = ilProcessor.Create(OpCodes.Add); ilProcessor.InsertAfter(sizeOfInst, instructionAdd); ilProcessor.InsertBefore(instructionAdd, ilProcessor.Create(OpCodes.Mul)); }
private static void Instrument(Instruction instruction, MethodReference countReference, MethodDefinition method, ILProcessor worker, string lastLine, InstrumentConfig config, TextWriter writer, ref int instrumentIndex) { //if the previous instruction is a Prefix instruction then this instruction MUST go with it. //we cannot put an instruction between the two. if (instruction.Previous != null && instruction.Previous.OpCode.OpCodeType == OpCodeType.Prefix) return; if (config.HasOffset(method.FullName, instruction.Offset)) return; if (lastLine != null && config.HasLine(method.FullName, lastLine)) { return; } var lineNum = -1; if (instruction.SequencePoint != null) lineNum = instruction.SequencePoint.StartLine; var line = string.Join(", ", "Method: " + method.FullName, "Line: " + lineNum, "Offset: " + instruction.Offset, "Instruction: " + instruction); writer.WriteLine(line); var pathParamLoadInstruction = worker.Create(OpCodes.Ldstr, config.HitsPath); var lineParamLoadInstruction = worker.Create(OpCodes.Ldc_I4, instrumentIndex); var registerInstruction = worker.Create(OpCodes.Call, countReference); //inserting method before instruction because after will not happen after a method Ret instruction worker.InsertBefore(instruction, pathParamLoadInstruction); worker.InsertAfter(pathParamLoadInstruction, lineParamLoadInstruction); worker.InsertAfter(lineParamLoadInstruction, registerInstruction); ++instrumentIndex; //change try/finally etc to point to our first instruction if they referenced the one we inserted before foreach (var handler in method.Body.ExceptionHandlers) { if (handler.FilterStart == instruction) handler.FilterStart = pathParamLoadInstruction; if (handler.TryStart == instruction) handler.TryStart = pathParamLoadInstruction; if (handler.TryEnd == instruction) handler.TryEnd = pathParamLoadInstruction; if (handler.HandlerStart == instruction) handler.HandlerStart = pathParamLoadInstruction; if (handler.HandlerEnd == instruction) handler.HandlerEnd = pathParamLoadInstruction; } //change instructions with a target instruction if they referenced the one we inserted before to be our first instruction foreach (var iteratedInstruction in method.Body.Instructions) { var operand = iteratedInstruction.Operand; if (operand == instruction) { iteratedInstruction.Operand = pathParamLoadInstruction; continue; } if (!(operand is Instruction[])) continue; var operands = (Instruction[])operand; for (var i = 0; i < operands.Length; ++i) { if (operands[i] == instruction) operands[i] = pathParamLoadInstruction; } } }
static void Append (ILProcessor il, IEnumerable<Instruction> instructions) { var method_instructions = il.Body.Instructions; var last = method_instructions [method_instructions.Count - 1]; foreach (var instruction in instructions) il.InsertBefore (last, instruction); }
void HandleOfMethod(Instruction instruction, ILProcessor ilProcessor, MethodReference ofMethodReference) { //Info.OfMethod("AssemblyToProcess","MethodClass","InstanceMethod"); Instruction methodNameInstruction; List<string> parameters; Instruction parametersInstruction = null; if (ofMethodReference.Parameters.Count == 4) { parametersInstruction = instruction.Previous; parameters = GetLdString(parametersInstruction) .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .ToList(); methodNameInstruction = parametersInstruction.Previous; } else { methodNameInstruction = instruction.Previous; parameters = new List<string>(); } var methodName = GetLdString(methodNameInstruction); var typeNameInstruction = methodNameInstruction.Previous; var typeName = GetLdString(typeNameInstruction); var assemblyNameInstruction = typeNameInstruction.Previous; var assemblyName = GetLdString(assemblyNameInstruction); var typeDefinition = GetTypeDefinition(assemblyName, typeName); var methodDefinitions = typeDefinition.FindMethodDefinitions(methodName, parameters); if (methodDefinitions.Count == 0) { throw new WeavingException($"Could not find method named '{methodName}'.") { SequencePoint = instruction.SequencePoint }; } if (methodDefinitions.Count > 1) { throw new WeavingException($"More than one method named '{methodName}' found.") { SequencePoint = instruction.SequencePoint }; } var methodReference = ModuleDefinition.ImportReference(methodDefinitions[0]); ilProcessor.Remove(typeNameInstruction); ilProcessor.Remove(methodNameInstruction); if (parametersInstruction != null) { ilProcessor.Remove(parametersInstruction); } assemblyNameInstruction.OpCode = OpCodes.Ldtoken; assemblyNameInstruction.Operand = methodReference; if (typeDefinition.HasGenericParameters) { var typeReference = ModuleDefinition.ImportReference(typeDefinition); ilProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Ldtoken, typeReference)); instruction.Operand = getMethodFromHandleGeneric; } else { instruction.Operand = getMethodFromHandle; } ilProcessor.InsertAfter(instruction, Instruction.Create(OpCodes.Castclass, methodInfoType)); }
private void WeaveOnException(MethodDefinition targetMethod, ILProcessor ilp, VariableDefinition aspectInstance, VariableDefinition correlation, Instruction addAfter) { if (_onException != null) { targetMethod.Body.InitLocals = true; var exceptionType = targetMethod.Module.Import(typeof(Exception)); var onExceptionInstructions = GetOnExceptionInstructions(targetMethod, ilp, aspectInstance, correlation, exceptionType).ToArray(); var tryEnd = ilp.Body.Instructions.Last(); var returns = false; if (tryEnd.OpCode == OpCodes.Ret) { returns = true; var nopOrLoad = tryEnd.Previous; if (nopOrLoad.OpCode == OpCodes.Nop) { var leaveToNop = ilp.Create(OpCodes.Leave_S, nopOrLoad); ilp.InsertBefore(nopOrLoad, leaveToNop); tryEnd = nopOrLoad; } else { var nopOrBreak = nopOrLoad.Previous; if (nopOrBreak.OpCode == OpCodes.Br_S) { var nop = ilp.Create(OpCodes.Nop); ilp.InsertBefore(nopOrBreak, nop); ilp.Remove(nopOrBreak); var leave = ilp.Create(OpCodes.Leave_S, nop); ilp.InsertBefore(nop, leave); tryEnd = nop; } else { tryEnd = nopOrBreak; } } } else { var nop = ilp.Create(OpCodes.Nop); ilp.Append(nop); tryEnd = nop; } var insertPoint = tryEnd.Previous; ilp.InsertInstructionsAfter(insertPoint, onExceptionInstructions); if (!returns) { ilp.Remove(tryEnd); } tryEnd = insertPoint.Next; var exceptionHandler = new ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = addAfter != null ? addAfter.Next : ilp.Body.Instructions.First(), TryEnd = tryEnd, HandlerStart = tryEnd, HandlerEnd = returns ? onExceptionInstructions.Last().Next : null, CatchType = exceptionType }; targetMethod.Body.ExceptionHandlers.Add(exceptionHandler); } }