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 } ); }
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 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)); }
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; } }
public static void RemoveInstructions(ILProcessor p, Instruction first, int count) { var cur = first; for (int i = 0; i < count; i++) { if (cur == null) break; var n = cur.Next; p.Remove(cur); cur = n; } }
void HandleOfType(Instruction instruction, ILProcessor ilProcessor) { //Info.OfType("AssemblyToProcess","TypeClass"); var typeNameInstruction= instruction.Previous; var typeName = GetLdString(typeNameInstruction); var assemblyNameInstruction = typeNameInstruction.Previous; var assemblyName = GetLdString(assemblyNameInstruction); var typeDefinition = GetTypeDefinition(assemblyName, typeName); var typeReference = ModuleDefinition.ImportReference(typeDefinition); ilProcessor.Remove(typeNameInstruction); assemblyNameInstruction.OpCode = OpCodes.Ldtoken; assemblyNameInstruction.Operand = typeReference; instruction.Operand = getTypeFromHandle; }
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 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]); } }
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); } }
private void ReplacePinStructGeneric(MethodDefinition method, ILProcessor ilProcessor, Instruction pinToPatch) { // Next instruction should be a store to the variable that should be pinned var nextStoreInstruction = pinToPatch.Next; int variableIndex; if (nextStoreInstruction.OpCode == OpCodes.Stloc_0) { variableIndex = 0; } else if (nextStoreInstruction.OpCode == OpCodes.Stloc_1) { variableIndex = 1; } else if (nextStoreInstruction.OpCode == OpCodes.Stloc_2) { variableIndex = 2; } else if (nextStoreInstruction.OpCode == OpCodes.Stloc_3) { variableIndex = 3; } else if (nextStoreInstruction.OpCode == OpCodes.Stloc_S) { variableIndex = ((VariableReference)nextStoreInstruction.Operand).Index; } else if (nextStoreInstruction.OpCode == OpCodes.Stloc) { variableIndex = ((VariableReference)nextStoreInstruction.Operand).Index; } else { throw new InvalidOperationException("Could not find a store operation right after Interop.Pin"); } // Transform variable from: // valuetype Struct s // to: // valuetype Struct& modopt([mscorlib]System.Runtime.CompilerServices.IsExplicitlyDereferenced) pinned s, var variable = method.Body.Variables[variableIndex]; variable.VariableType = variable.VariableType .MakeByReferenceType() //.MakeOptionalModifierType(typeof(IsExplicitlyDereferenced)) .MakePinnedType(); // Remove call to Interop.Pin: ilProcessor.Remove(pinToPatch); // Transform all ldloca with this variable into ldloc: for (int index = 0; index < ilProcessor.Body.Instructions.Count; index++) { var instruction = ilProcessor.Body.Instructions[index]; if (instruction.OpCode == OpCodes.Ldloca && ((VariableReference)instruction.Operand).Index == variableIndex) { instruction.OpCode = OpCodes.Ldloc; } else if (instruction.OpCode == OpCodes.Ldloca_S && ((VariableReference)instruction.Operand).Index == variableIndex) { instruction.OpCode = OpCodes.Ldloc_S; } } }
private void ReplacePinStatement(MethodDefinition method, ILProcessor ilProcessor, Instruction fixedtoPatch) { var previousInstruction = fixedtoPatch.Previous; int variableIndex; if (previousInstruction.OpCode == OpCodes.Ldloc_0) { variableIndex = 0; } else if (previousInstruction.OpCode == OpCodes.Ldloc_1) { variableIndex = 1; } else if (previousInstruction.OpCode == OpCodes.Ldloc_2) { variableIndex = 2; } else if (previousInstruction.OpCode == OpCodes.Ldloc_3) { variableIndex = 3; } else if (previousInstruction.OpCode == OpCodes.Ldloc_S) { variableIndex = ((VariableReference)previousInstruction.Operand).Index; } else if (previousInstruction.OpCode == OpCodes.Ldloc) { variableIndex = ((VariableReference)previousInstruction.Operand).Index; } else { throw new InvalidOperationException("Could not find a load operation right before Interop.Pin"); } var variable = ilProcessor.Body.Variables[variableIndex]; variable.VariableType = variable.VariableType.MakePinnedType(); ilProcessor.Remove(previousInstruction); ilProcessor.Remove(fixedtoPatch); }
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 //} } }
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); } }