/// <summary> /// Inserts a group of instructions after the target instruction /// </summary> public static void InsertAfter(this Mono.Cecil.Cil.ILProcessor processor, Instruction target, IEnumerable <Instruction> instructions) { foreach (var instruction in instructions.Reverse()) { processor.InsertAfter(target, instruction); } }
void HandleOfParameter(Instruction instruction, ILProcessor ilProcessor) { //Info.OfMethod("AssemblyToProcess","MethodClass","InstanceMethod"); var methodNameInstruction = instruction.Previous; 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 methodDefinition = typeDefinition.Methods.FirstOrDefault(x => x.Name == methodName); if (methodDefinition == null) { throw new WeavingException($"Could not find method named '{methodName}'."); } var methodReference = ModuleDefinition.ImportReference(methodDefinition); ilProcessor.Remove(typeNameInstruction); assemblyNameInstruction.OpCode = OpCodes.Ldtoken; assemblyNameInstruction.Operand = methodReference; instruction.Operand = getMethodFromHandle; ilProcessor.InsertAfter(instruction,Instruction.Create(OpCodes.Castclass,methodInfoType)); }
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 } }
public Instruction InsertAfter(Instruction instruction, ILProcessor processor) { var currentInstruction = instruction; foreach (var newInstruction in Instructions) { processor.InsertAfter(currentInstruction, newInstruction); currentInstruction = newInstruction; } return currentInstruction; }
public static void GetMethod(Instruction i, ILProcessor proc, ModuleDefinition baseModule) { if (i.Operand is FieldReference && ((FieldReference)i.Operand).FullName.Contains("Monocle.Sprite`1<System.Int32> TowerFall.AwardInfo/<>c__DisplayClass") && ((FieldReference)i.Operand).FullName.Contains("::sprite")) { Stored = Instruction.Create(OpCodes.Ldfld, i.Operand as FieldReference); } if (i.OpCode == OpCodes.Callvirt && i.Next.OpCode != OpCodes.Br_S && ((MethodReference)i.Operand).FullName == "System.Void Monocle.Sprite`1<System.Int32>::Add(T,System.Int32)") { TypeDefinition graphicsComponent = baseModule.GetType("Monocle.GraphicsComponent"); var fieldReference = graphicsComponent.Fields.Single(f => f.Name == "Zoom"); var instr = Instruction.Create(OpCodes.Stfld, fieldReference); var ldinstr = Instruction.Create(i.Next.OpCode); proc.InsertAfter(i, instr); proc.InsertAfter(i, proc.Create(OpCodes.Ldc_R4, (float)0.7)); proc.InsertAfter(i, Stored); proc.InsertAfter(i, ldinstr); } }
/// <summary> /// Inserts a list of anonymous instructions after the target instruction /// </summary> public static List <Instruction> InsertAfter(this Mono.Cecil.Cil.ILProcessor processor, Instruction target, params object[] instructions) { var created = new List <Instruction>(); foreach (var anon in instructions.Reverse()) { var ins = AnonymousToInstruction(anon); processor.InsertAfter(target, ins); created.Add(ins); } return(created); }
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)); }
private Instruction AddConditionGoto(ILProcessor ilp, Instruction last, Instruction stateMachineStarting) { var shouldRunSynchronouslyMethod = _engine.GetMethod<Func<ActorCore, bool>> (a => a.ShouldRunSynchronously ()); var loadThis = ilp.Create (OpCodes.Ldarg_0); var loadField = ilp.Create (OpCodes.Ldfld, _actorMixin); var callMethod = ilp.Create (OpCodes.Call, shouldRunSynchronouslyMethod); var gotoNext = ilp.Create (OpCodes.Brtrue_S, stateMachineStarting); ilp.InsertAfter (last, loadThis); ilp.InsertAfter (loadThis, loadField); ilp.InsertAfter (loadField, callMethod); ilp.InsertAfter (callMethod, gotoNext); return gotoNext; }
public static int ToNop(ILProcessor ilp, Instruction ins, bool sameSize) { if (ins == null) return 0; int size = ins.GetSize(); ins.OpCode = OpCodes.Nop; ins.Operand = null; if (sameSize) { for (int i = 1; i < size; i++) { Instruction newIns = ilp.Create(OpCodes.Nop); ilp.InsertAfter(ins, newIns); } } else { size = 1; } return size; }
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; } } }
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 ProcessNameOfCallInstruction(Instruction instruction, ILProcessor ilProcessor) { var instructions = instruction.AsReverseEnumerable().Take(patterns.Value.First().Length).ToArray(); // Take an instruction set with a maximum size of the longest pattern. Boolean possibleMatch = false; PatternInstruction[] patternMatched = null; Func<String> terminal = null; foreach (var pattern in patterns.Value) { possibleMatch = true; terminal = null; for (Int32 i = 0, j = 0; i < pattern.Length && j < instructions.Length; ++i, ++j) { while (pattern[i] is OptionalPatternInstruction && !pattern[i].EligibleOpCodes.Contains(instructions[j].OpCode)) ++i; var patternInstruction = pattern[i]; var currentInstruction = instructions[j]; if (patternInstruction.EligibleOpCodes.Contains(currentInstruction.OpCode) && patternInstruction.IsPredicated(currentInstruction, ilProcessor)) { if (patternInstruction.Terminal != null && terminal == null) terminal = () => patternInstruction.Terminal(currentInstruction, ilProcessor); if (patternInstruction.Action != null) patternInstruction.Action(currentInstruction); } else { possibleMatch = false; break; } } if (possibleMatch && pattern.Count(x => !(x is OptionalPatternInstruction)) <= instructions.Length) { patternMatched = pattern; break; } } if (!possibleMatch) throw GetNotSupportedException(instruction); // The usage of Name.Of is not supported if (terminal == null) throw new NotImplementedException("There is no terminal expression implemented for the matched pattern."); String name; try { name = terminal(); if (IsNullOrWhiteSpace(name)) throw new Exception("Name not found."); } catch { throw GetNotSupportedException(instruction); } // TODO: Remove the anonymous methods generated by lamdba expressions in some uses of Name.Of... ilProcessor.InsertAfter(instruction, Instruction.Create(OpCodes.Ldstr, name)); for (Int32 i = 0, j = 0; i < patternMatched.Length && j < instructions.Length; ++i, ++j) { while (patternMatched[i] is OptionalPatternInstruction && !patternMatched[i].EligibleOpCodes.Contains(instructions[j].OpCode)) ++i; ilProcessor.Remove(instructions[j]); } }
/// <summary> /// stateMachine.mixin = this.mixin; /// </summary> /// <returns>The last instruction added</returns> /// <param name="ilp">Il processor</param> /// <param name="after">Add instructions after this one</param> private Instruction AddSetActorMixin(ILProcessor ilp, Instruction after) { var loadStateMachineVar = ilp.Create (OpCodes.Ldloca_S, ilp.Body.Variables[0]); var loadThis = ilp.Create (OpCodes.Ldarg_0); var loadField = ilp.Create (OpCodes.Ldfld, _actorMixin); var storeField = ilp.Create (OpCodes.Stfld, _stateMachineMixin); ilp.InsertAfter (after, loadStateMachineVar); ilp.InsertAfter (loadStateMachineVar, loadThis); ilp.InsertAfter (loadThis, loadField); ilp.InsertAfter (loadField, storeField); return storeField; }
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; } } }
private void ReplaceIncrementPinnedStructGeneric(MethodDefinition method, ILProcessor ilProcessor, Instruction incrementPinnedToPatch) { var paramT = ((GenericInstanceMethod)incrementPinnedToPatch.Operand).GenericArguments[0]; var sizeOfInst = ilProcessor.Create(OpCodes.Sizeof, paramT); ilProcessor.Replace(incrementPinnedToPatch, sizeOfInst); ilProcessor.InsertAfter(sizeOfInst, ilProcessor.Create(OpCodes.Add)); }
private static void Inject(ILProcessor ilGen, IEnumerable<Instruction> instructions, Instruction instructionToReplace) { Instruction prevInstruction = instructionToReplace; foreach(Instruction currInstruction in instructions) { ilGen.InsertAfter(prevInstruction, currInstruction); prevInstruction = currInstruction; } ilGen.Remove(instructionToReplace); }
void SendWriterPacket(MethodDefinition sendData, ILProcessor processor, VariableDefinition mswriter, OpCode binaryWriter) { // inject the packet contents array after the method updates the packet id. // our signature we look for is the last call to update the Position var offset = sendData.Body.Instructions.Last( x => x.OpCode == OpCodes.Callvirt && (x.Operand as MethodReference).Name == "set_Position" ); VariableDefinition packetContents; sendData.Body.Variables.Add(packetContents = new VariableDefinition("packetContents", this.SourceDefinition.MainModule.Import(typeof(byte[])) )); processor.InsertAfter(offset, new { OpCodes.Ldloc, mswriter }, new { OpCodes.Callvirt, Operand = this.SourceDefinition.MainModule.Import(typeof(MemoryStream) .GetMethods() .Single(x => x.Name == "ToArray" && x.GetParameters().Count() == 0) ) }, new { OpCodes.Stloc, packetContents } ); // replace all instances of NetMessage.buffer[index].writeBuffer with out new packetContents foreach (var writeBuffer in sendData.Body.Instructions.Where( x => x.OpCode == OpCodes.Ldfld && (x.Operand as FieldReference).Name == "writeBuffer" ).ToArray()) { // now remove all calls back to the when the buffer is loaded // remove the writeBuffer // replace the messagebuffer instruction with our packet contents // note: always ensure the writeBuffer is below packetContents VariableDefinition vrbBuffer = packetContents; if (writeBuffer.Offset < offset.Offset) { //Needs a local buffer that gets written into our writer //find the first argument (ldarg.s number) var firstInstruction = writeBuffer.Previous( x => x.OpCode == OpCodes.Ldarg_S && (x.Operand as ParameterReference).Name == "number" ); VariableDefinition localBuffer; sendData.Body.Variables.Add(localBuffer = new VariableDefinition( this.SourceDefinition.MainModule.Import(typeof(byte[])) )); processor.InsertAfter(firstInstruction, //new { OpCodes.Ldc_I4, Operand = 65536 }, new { OpCodes.Newarr, Operand = this.SourceDefinition.MainModule.TypeSystem.Byte }, new { OpCodes.Stloc, Operand = localBuffer }, new { firstInstruction.OpCode, Operand = (ParameterDefinition)firstInstruction.Operand } ); firstInstruction.OpCode = OpCodes.Ldc_I4; firstInstruction.Operand = 65535; //find the position set, as we are starting from 0 with out new array var argPosition = firstInstruction.Next(x => x.OpCode == OpCodes.Ldloc_1); while (argPosition.Next.OpCode != OpCodes.Call) { processor.Remove(argPosition.Next); } argPosition.OpCode = OpCodes.Ldc_I4_0; vrbBuffer = localBuffer; // the local buffer is now in place // we now need to send it off to the writer, instead of simply incrementing // get the method call and skip the result variable and remove all instructions until the branch out var call = writeBuffer.Next( x => x.OpCode == OpCodes.Call && (x.Operand as MethodReference).Name == "CompressTileBlock" ).Next; while (call.Next.OpCode != OpCodes.Br) { processor.Remove(call.Next); } processor.InsertAfter(call, new { OpCode = binaryWriter }, new { OpCodes.Ldloc, localBuffer }, new { OpCodes.Ldc_I4_0 }, new { OpCodes.Ldloc_S, Operand = (VariableDefinition)call.Operand }, new { OpCodes.Callvirt, Operand = this.SourceDefinition.MainModule.Import(typeof(BinaryWriter) .GetMethods() .Single(x => x.Name == "Write" && x.GetParameters().Count() == 3 && x.GetParameters()[0].ParameterType == typeof(byte[]) ) ) } ); } var loadedBuffer = writeBuffer.Previous( x => x.OpCode == OpCodes.Ldsfld && (x.Operand as FieldReference).Name == "buffer" ); while (loadedBuffer.Next != writeBuffer) { processor.Remove(loadedBuffer.Next); } processor.Remove(writeBuffer); loadedBuffer.OpCode = OpCodes.Ldloc; loadedBuffer.Operand = vrbBuffer; //if (writeBuffer.Offset < offset.Offset) //{ // // the local buffer is now in place // // we now need to send it off to the writer, instead of simply incrementing // // remove all tiles AFTER //} } }
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 List<Tuple<Instruction, Instruction>> FixUsingBlocks(ILProcessor ilProcessor, List<Tuple<Instruction, Instruction>> usingBlocks) { // Changes using block from [Inclusive, Exclusive) to [Inclusive, Inclusive] // Also adds a nop after the block as the target to jump to. List<Tuple<Instruction, Instruction>> fixedUsingBlocks = new List<Tuple<Instruction, Instruction>>(usingBlocks.Count); foreach (var groupedEndings in usingBlocks.GroupBy(u => u.Item2)) { var nop = ilProcessor.Create(OpCodes.Nop); ilProcessor.InsertAfter(groupedEndings.Key, nop); foreach (var usingBlock in groupedEndings.OrderBy(u => u.Item1.Offset)) { if (usingBlock.Item2.Next.Next == usingBlock.Item1) { // Empty using - item 2 is before item 1 fixedUsingBlocks.Add(Tuple.Create(nop, nop)); } else { fixedUsingBlocks.Add(Tuple.Create(usingBlock.Item1, usingBlock.Item2)); } } } return fixedUsingBlocks; }
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; }
private Instruction AddEnqueueOps(ILProcessor ilp, Instruction last) { var enqueueMethod = GetEnqueueMethodReference(); var endInstruction = ilp.Body.Instructions.Last (); var loadThis = ilp.Create (OpCodes.Ldarg_0); var loadMixinField = ilp.Create (OpCodes.Ldfld, _actorMixin); var loadStateMachineVar_1 = ilp.Create (OpCodes.Ldloca_S, ilp.Body.Variables[0]); var loadBuilderField = ilp.Create (OpCodes.Ldfld, GetBuilderField ()); var loadStateMachineVar_2 = ilp.Create (OpCodes.Ldloca_S, ilp.Body.Variables[0]); var callMethod = ilp.Create (OpCodes.Call, enqueueMethod); var gotoEnd = ilp.Create (OpCodes.Br, endInstruction); ilp.InsertAfter (last, loadThis); ilp.InsertAfter (loadThis, loadMixinField); ilp.InsertAfter (loadMixinField, loadStateMachineVar_1); ilp.InsertAfter (loadStateMachineVar_1, loadBuilderField); ilp.InsertAfter (loadBuilderField, loadStateMachineVar_2); ilp.InsertAfter (loadStateMachineVar_2, callMethod); ilp.InsertAfter (callMethod, gotoEnd); return gotoEnd; }
private Instruction InsertAfter(ILProcessor il, Instruction target, Instruction instruction) { il.InsertAfter(target, instruction); return instruction; }
private void UnwrapLazyVariable(ILProcessor ilProcessor, Instruction targetInstructin) { ilProcessor.InsertAfter(targetInstructin,Instruction.Create(OpCodes.Blt)); }
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)); }
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 } ); }