void CreateCustomAttribute(string attrName, out TypeReference attrType, Mono.Collections.Generic.Collection <TypeDefinition> types) { attrName = "java.attr." + attrName; if (typeMap.TryGetValue(attrName, out attrType)) { typeMap.Remove(attrName); } else { var attrTypeDef = CreateCustomAttribute(attrName); types.Add(attrTypeDef); attrType = attrTypeDef; } }
static Instruction findNextRet(Mono.Collections.Generic.Collection <Instruction> instructions, Instruction pos) { bool posFound = false; for (int i = 0; i < instructions.Count; i++) { if (posFound && instructions[i].OpCode == OpCodes.Ret) { return(instructions[i]); } else if (instructions[i] == pos) { posFound = true; } } return(null); }
public static string[] GetGenericName(Mono.Collections.Generic.Collection <TypeReference> types, int offset, int count, bool bFull) { string[] results = new string[count]; for (int i = 0; i < count; i++) { int pos = i + offset; if (types[pos].IsGenericInstance) { results[i] = GetGenericName(types[pos], bFull); } else { results[i] = GetTypeName(types[pos]); } } return(results); }
public MethodInfo(AssemblyInfo assembly, MethodDefinition methodDef, SourceFile source) { this.Assembly = assembly; this.methodDef = methodDef; this.source = source; Mono.Collections.Generic.Collection <SequencePoint> sps = DebugInformation.SequencePoints; if (sps == null || sps.Count < 1) { return; } SequencePoint start = sps[0]; SequencePoint end = sps[0]; foreach (SequencePoint sp in sps) { if (sp.StartLine < start.StartLine) { start = sp; } else if (sp.StartLine == start.StartLine && sp.StartColumn < start.StartColumn) { start = sp; } if (sp.EndLine > end.EndLine) { end = sp; } else if (sp.EndLine == end.EndLine && sp.EndColumn > end.EndColumn) { end = sp; } } StartLocation = new SourceLocation(this, start); EndLocation = new SourceLocation(this, end); }
/// <summary> /// Update the given method IL to include the interception logic /// </summary> /// <param name="method">Method</param> /// <param name="typeImp">Static Type to add logic for caching method info to</param> /// <param name="cctorIL">Static IL Processor</param> /// <param name="attrs">Custom Attribute for the given method</param> /// <param name="aspects">Collection of aspect discovered for the given method</param> /// <param name="type">Original Method Type to use for inteception logic</param> private void UpdateMethodIL(MethodDefinition method, TypeDefinition typeImp, ILProcessor cctorIL, IEnumerable <CustomAttribute> attrs, Dictionary <string, FieldDefinition> aspects, TypeDefinition type) { //Check if aspect ignore var ignoreAspect = method.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(AspectIgnoreAttribute).FullName); var methAttrs = attrs; // No Aspect required if (ignoreAspect || !methAttrs.Any()) { return; } var origMethod = CloneMethod(method, type); type.Methods.Add(origMethod); var declaringType = method.DeclaringType; var returnType = method.ReturnType; var isGeneric = declaringType.HasGenericParameters; var isStatic = method.IsStatic; var parameterOffset = isStatic ? 0 : 1; var isTask = returnType.FullName.StartsWith("Task`1") || returnType.FullName == typeof(Task).FullName; //Define method info var methodField = new FieldDefinition("_meth_" + (++Counter), FieldAttributes.Public | FieldAttributes.Static, ModuleDefinition.Import(typeof(System.Reflection.MethodBase))); cctorIL.Emit(OpCodes.Ldtoken, method); if (isGeneric) { cctorIL.Emit(OpCodes.Ldtoken, declaringType); } cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(System.Reflection.MethodBase).GetMethod("GetMethodFromHandle", isGeneric ? new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) } : new Type[] { typeof(RuntimeMethodHandle) } ))); cctorIL.Emit(OpCodes.Stsfld, methodField); typeImp.Fields.Add(methodField); var paramType = ModuleDefinition.Import(typeof(AspectMethodParameterInfo)); var paramCtor = ModuleDefinition.Import(paramType.Resolve().GetConstructors().First()); //Define method parameters var paramsLocal = new VariableDefinition(ModuleDefinition.Import(typeof(List <AspectMethodParameterInfo>))); var paramsField = new FieldDefinition("_meth_param" + (++Counter), FieldAttributes.Public | FieldAttributes.Static, ModuleDefinition.Import(typeof(ReadOnlyCollection <AspectMethodParameterInfo>))); var paramAdd = ModuleDefinition.Import(typeof(List <AspectMethodParameterInfo>).GetMethod("Add", new[] { typeof(AspectMethodParameterInfo) })); var methodAttributesField = new FieldDefinition("_meth_attr_" + (++Counter), FieldAttributes.Public | FieldAttributes.Static, ModuleDefinition.Import(typeof(IList <Attribute>))); cctorIL.Emit(OpCodes.Ldtoken, method); if (isGeneric) { cctorIL.Emit(OpCodes.Ldtoken, declaringType); } cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(System.Reflection.MethodBase).GetMethod("GetMethodFromHandle", isGeneric ? new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) } : new Type[] { typeof(RuntimeMethodHandle) } ))); cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("GetAttributes"))); cctorIL.Emit(OpCodes.Stsfld, methodAttributesField); typeImp.Fields.Add(methodAttributesField); typeImp.Fields.Add(paramsField); // Add params local for method parameter information cctorIL.Body.Variables.Add(paramsLocal); cctorIL.Emit(OpCodes.Newobj, ModuleDefinition.Import(typeof(List <AspectMethodParameterInfo>).GetConstructor(Type.EmptyTypes))); cctorIL.Emit(OpCodes.Stloc, paramsLocal); foreach (var param in method.Parameters) { var paramName = param.Name; var paramLocal = new VariableDefinition(paramType); cctorIL.Body.Variables.Add(paramLocal); cctorIL.Emit(OpCodes.Newobj, paramCtor); cctorIL.Emit(OpCodes.Stloc, paramLocal); //Set parameter name cctorIL.Emit(OpCodes.Ldloc, paramLocal); cctorIL.Emit(OpCodes.Ldstr, paramName); cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("Name").GetSetMethod())); //Set parameter isRef cctorIL.Emit(OpCodes.Ldloc, paramLocal); cctorIL.Emit(OpCodes.Ldc_I4, param.ParameterType.IsByReference ? 1 : 0); cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("IsRef").GetSetMethod())); //Set parameter type cctorIL.Emit(OpCodes.Ldloc, paramLocal); if ((param.ParameterType.ContainsGenericParameter || param.ParameterType.HasGenericParameters || param.ParameterType.IsGenericParameter)) { cctorIL.Emit(OpCodes.Ldnull); } else { cctorIL.Emit(OpCodes.Ldtoken, param.ParameterType); cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }))); } cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("Type").GetSetMethod())); //Set parameter attributes cctorIL.Emit(OpCodes.Ldloc, paramLocal); cctorIL.Emit(OpCodes.Ldtoken, method); if (isGeneric) { cctorIL.Emit(OpCodes.Ldtoken, declaringType); } cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(System.Reflection.MethodBase).GetMethod("GetMethodFromHandle", isGeneric ? new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) } : new Type[] { typeof(RuntimeMethodHandle) } ))); cctorIL.Emit(OpCodes.Ldc_I4, param.Index); cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("GetParameterAttributes"))); cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("Attributes").GetSetMethod())); //Add parameter to list cctorIL.Emit(OpCodes.Ldloc, paramsLocal); cctorIL.Emit(OpCodes.Ldloc, paramLocal); cctorIL.Emit(OpCodes.Callvirt, paramAdd); } cctorIL.Emit(OpCodes.Ldloc, paramsLocal); cctorIL.Emit(OpCodes.Newobj, ModuleDefinition.Import(typeof(ReadOnlyCollection <AspectMethodParameterInfo>).GetConstructor(new[] { typeof(IList <AspectMethodParameterInfo>) }))); cctorIL.Emit(OpCodes.Stsfld, paramsField); var oldBody = method.Body; var newBody = new MethodBody(method); var ret = Instruction.Create(OpCodes.Ret); ret.SequencePoint = oldBody.Instructions.Last().SequencePoint; Instruction local = null; VariableDefinition result = returnType == TypeSystem.Void ? null : new VariableDefinition(returnType); var instructions = oldBody.Instructions; var count = instructions.Count; var startIndex = 0; var usedVariables = new List <VariableDefinition>(); var usedHash = new HashSet <int>(); var il = newBody.GetILProcessor(); //Add initial logic for constructors if (!declaringType.IsSequentialLayout && declaringType.IsClass && method.IsConstructor) { for (var i = 0; i < count; i++) { var instruction = instructions[i]; var opCode = instruction.OpCode.ToString(); var variable = instruction.Operand as VariableReference; if (variable != null && !usedHash.Contains(variable.Index)) { usedHash.Add(variable.Index); usedVariables.Add(variable.Resolve()); } else if (opCode.IndexOf("stloc", StringComparison.OrdinalIgnoreCase) >= 0) { var token = opCode.Split('.'); var index = Int32.Parse(token[1]); if (!usedHash.Contains(index)) { usedHash.Add(index); usedVariables.Add(oldBody.Variables[index]); } } if (instruction.OpCode == OpCodes.Call && (instruction.Operand as MethodReference).Resolve().IsConstructor) { startIndex = i + 1; il.Append(instruction); break; } il.Append(instruction); } } if (origMethod != null) { oldBody.Variables.Clear(); foreach (var variable in usedVariables) { newBody.Variables.Add(variable); } } else { foreach (var variable in oldBody.Variables) { newBody.Variables.Add(variable); } } //Add new variable for result if needed if (result != null) { newBody.Variables.Add(result); } //Define method context var aspectMethodInfo = ModuleDefinition.Import(typeof(AspectMethodInfo)); var context = new VariableDefinition(aspectMethodInfo); var aspectMethodInfoCtor = ModuleDefinition.Import(aspectMethodInfo.Resolve().GetConstructors().First()); //Add variable for context newBody.Variables.Add(context); //Create context instance il.Emit(OpCodes.Newobj, aspectMethodInfoCtor); il.Emit(OpCodes.Stloc, context); //Set method info to context il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldsfld, methodField); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Method").GetSetMethod())); //Set method attributes to context il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldsfld, methodAttributesField); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Attributes").GetSetMethod())); //Set instance to context if (!isStatic) { il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldarg_0); if (declaringType.IsValueType) { il.Emit(OpCodes.Ldobj, declaringType); il.Emit(OpCodes.Box, declaringType); } il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Instance").GetSetMethod())); } //Set parameters to context il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldsfld, paramsField); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Parameters").GetSetMethod())); var argumentsLocal = new VariableDefinition(ModuleDefinition.Import(typeof(List <object>))); newBody.Variables.Add(argumentsLocal); var argumentsAdd = ModuleDefinition.Import(typeof(List <object>).GetMethod("Add", new[] { typeof(object) })); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Arguments").GetGetMethod())); il.Emit(OpCodes.Stloc, argumentsLocal); //Set arguments to context foreach (var param in method.Parameters) { //Set argument value il.Emit(OpCodes.Ldloc, argumentsLocal); if (param.IsOut) { il.Emit(OpCodes.Ldnull); } else { il.Emit(OpCodes.Ldarg, param.Index + parameterOffset); if (param.ParameterType.IsByReference) { var elementType = param.ParameterType.GetElementType(); if (!elementType.IsValueType) { il.Emit(OpCodes.Ldind_Ref); } else if (elementType.FullName == ModuleDefinition.Import(typeof(int)).FullName) { il.Emit(OpCodes.Ldind_I4); } else if (elementType.FullName == ModuleDefinition.Import(typeof(byte)).FullName) { il.Emit(OpCodes.Ldind_I1); } else if (elementType.FullName == ModuleDefinition.Import(typeof(short)).FullName) { il.Emit(OpCodes.Ldind_I2); } else if (elementType.FullName == ModuleDefinition.Import(typeof(long)).FullName) { il.Emit(OpCodes.Ldind_I8); } else if (elementType.FullName == ModuleDefinition.Import(typeof(float)).FullName) { il.Emit(OpCodes.Ldind_R4); } else if (elementType.FullName == ModuleDefinition.Import(typeof(double)).FullName) { il.Emit(OpCodes.Ldind_R8); } else if (elementType.FullName == ModuleDefinition.Import(typeof(ushort)).FullName) { il.Emit(OpCodes.Ldind_U2); } else if (elementType.FullName == ModuleDefinition.Import(typeof(uint)).FullName) { il.Emit(OpCodes.Ldind_U4); } if (elementType.IsValueType) { il.Emit(OpCodes.Box, elementType); } } if (param.ParameterType.IsValueType || (param.ParameterType.ContainsGenericParameter || param.ParameterType.HasGenericParameters || param.ParameterType.IsGenericParameter)) { il.Emit(OpCodes.Box, param.ParameterType); } } il.Emit(OpCodes.Callvirt, argumentsAdd); } //Call on intercept for context foreach (var attr in methAttrs) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnEnter"))); } } var startFinally = Instruction.Create(OpCodes.Nop); il.Append(startFinally); //Call clone method here var startInvoke = Instruction.Create(OpCodes.Nop); var continueLabel = Instruction.Create(OpCodes.Nop); il.Append(startInvoke); //Execute if continue of context is true il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Continue").GetGetMethod())); il.Emit(OpCodes.Brfalse, continueLabel); //Load this if (!isStatic) { il.Emit(OpCodes.Ldarg_0); } //Load Arguments for (var i = 0; i < method.Parameters.Count; i++) { il.Emit(OpCodes.Ldarg, parameterOffset + i); } //Invoke clone if (origMethod != null) { var cloneMethod = ToGenericMethod(origMethod, declaringType); var invokeInstruction = Instruction.Create(isStatic || declaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, cloneMethod); il.Append(invokeInstruction); } else { instructions = new Mono.Collections.Generic.Collection <Instruction>(instructions.Skip(startIndex).ToList()); instructions = new Mono.Collections.Generic.Collection <Instruction>(instructions.Take(instructions.Count - 1).ToList()); foreach (var instruction in instructions) { il.Append(instruction); } } if (result == null) { //Call on success for context foreach (var attr in methAttrs) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnSuccess"))); } } //end of continue check il.Append(continueLabel); } else if (result != null) { //Create ldloc for local local = Instruction.Create(OpCodes.Ldloc, result); //Store result il.Emit(OpCodes.Stloc, result); //Set continuation for exception if (isTask) { MethodReference handleTaskError = ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("HandleTaskError")); //handle on error for task foreach (var attr in methAttrs) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldloc, result); il.Emit(OpCodes.Call, handleTaskError); il.Emit(OpCodes.Stloc, result); } } } //Set result to context il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldloc, result); if (returnType.IsValueType || (returnType.ContainsGenericParameter || returnType.HasGenericParameters || returnType.IsGenericInstance)) { il.Emit(OpCodes.Box, returnType); } il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Returns").GetSetMethod())); if (isTask) { MethodReference handleTaskSuccess = ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("HandleTaskSuccess")); //Handle on success for task foreach (var attr in methAttrs) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldloc, result); il.Emit(OpCodes.Call, handleTaskSuccess); il.Emit(OpCodes.Stloc, result); } } } else { //Call on success for context foreach (var attr in methAttrs) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnSuccess"))); } } } if (isTask) { MethodReference handleTaskExit = ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("HandleTaskExit")); //Handle on exit for task foreach (var attr in methAttrs.Reverse()) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldloc, result); il.Emit(OpCodes.Call, handleTaskExit); il.Emit(OpCodes.Stloc, result); } } } //end of continue check il.Append(continueLabel); //Update return value if needed if (!isTask) { GenericInstanceMethod genReturn = new GenericInstanceMethod(ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("GetReturn"))); genReturn.GenericArguments.Add(returnType); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Call, genReturn); il.Emit(OpCodes.Stloc, result); } } il.Emit(OpCodes.Leave, local ?? ret); //catch var catRet = Instruction.Create(OpCodes.Nop); var exLocal = new VariableDefinition(ModuleDefinition.Import(typeof(Exception))); newBody.Variables.Add(exLocal); il.Append(catRet); il.Emit(OpCodes.Stloc, exLocal); //Set exception to context il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Ldloc, exLocal); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Exception").GetSetMethod())); //Call on error for context foreach (var attr in methAttrs) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnError"))); } } var throwLabel = Instruction.Create(OpCodes.Nop); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("ReThrow").GetGetMethod())); il.Emit(OpCodes.Brfalse, throwLabel); il.Emit(OpCodes.Rethrow); il.Append(throwLabel); var endCatch = Instruction.Create(OpCodes.Leave, local ?? ret); il.Emit(OpCodes.Leave, endCatch); il.Append(endCatch); //finally var finallyRet = Instruction.Create(OpCodes.Nop); il.Append(finallyRet); if (!isTask) { //Call on exit for context foreach (var attr in methAttrs.Reverse()) { FieldDefinition def; if (aspects.TryGetValue(attr.AttributeType.FullName, out def)) { il.Emit(OpCodes.Ldsfld, def); il.Emit(OpCodes.Ldloc, context); il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnExit"))); var nop = Instruction.Create(OpCodes.Nop); var lastItem = instructions.LastOrDefault(x => x.SequencePoint != null); if (lastItem != null) { nop.SequencePoint = lastItem.SequencePoint; } il.Append(nop); } } } il.Emit(OpCodes.Endfinally); if (result != null) { il.Append(local); } il.Append(ret); var @catch = new ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = startInvoke, TryEnd = catRet, HandlerStart = catRet, HandlerEnd = endCatch, CatchType = ModuleDefinition.Import(typeof(Exception)) }; var @finally = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = startFinally, TryEnd = finallyRet, HandlerStart = finallyRet, HandlerEnd = local ?? ret }; newBody.ExceptionHandlers.Add(@catch); newBody.ExceptionHandlers.Add(@finally); newBody.InitLocals = true; newBody.OptimizeMacros(); method.Body = newBody; // Mark the re-written method (if not already marked) so that the debugger doesn't try to stop in generated code. if (!method.CustomAttributes.Any(attr => attr.Constructor.FullName == debuggerStepThroughAttributeCtor.FullName)) { method.CustomAttributes.Add(new CustomAttribute(debuggerStepThroughAttributeCtor)); } }
/// <summary> /// Create a clone of given method and add to the specified type /// </summary> /// <param name="method">Method</param> /// <param name="type">Type</param> /// <returns>MethodDefinition</returns> private MethodDefinition CloneMethod(MethodDefinition method, TypeDefinition type) { var methodAttribute = MethodAttributes.Private; if (method.IsStatic) { methodAttribute |= MethodAttributes.Static; } var meth = new MethodDefinition(method.Name + "_☈_", methodAttribute, method.ReturnType); meth.CallingConvention = method.CallingConvention; meth.ImplAttributes = method.ImplAttributes; meth.IsGetter = method.IsGetter; meth.IsSetter = method.IsSetter; meth.HasThis = method.HasThis; var body = meth.Body; var oldBody = method.Body; var il = body.GetILProcessor(); var instructions = oldBody.Instructions; var count = instructions.Count; var startIndex = 0; if (method.HasGenericParameters) { foreach (var generic in method.GenericParameters) { var genericParameter = new GenericParameter(generic.Name, meth); generic.Constraints.ToList().ForEach(x => genericParameter.Constraints.Add(x)); generic.CustomAttributes.ToList().ForEach(x => genericParameter.CustomAttributes.Add(x)); genericParameter.Attributes = generic.Attributes; generic.GenericParameters.ToList().ForEach(x => genericParameter.GenericParameters.Add(new GenericParameter(x.Name, meth))); meth.GenericParameters.Add(genericParameter); } } foreach (var param in method.Parameters) { var paramAttributes = param.Attributes; paramAttributes &= ~ParameterAttributes.HasDefault; meth.Parameters.Add(new ParameterDefinition(param.Name, paramAttributes, param.ParameterType)); } foreach (var variable in method.Body.Variables) { body.Variables.Add(variable); } if (!method.DeclaringType.IsSequentialLayout && method.DeclaringType.IsClass && method.IsConstructor) { for (var i = 0; i < count; i++) { var instruction = instructions[i]; if (instruction.OpCode == OpCodes.Call && (instruction.Operand as MethodReference).Resolve().IsConstructor) { startIndex = i + 1; break; } } } instructions = new Mono.Collections.Generic.Collection <Instruction>(instructions.Skip(startIndex).ToList()); foreach (var instruction in instructions) { il.Append(instruction); } foreach (var handler in oldBody.ExceptionHandlers) { body.ExceptionHandlers.Add(handler); } body.InitLocals = true; body.OptimizeMacros(); return(meth); }
public static void Test() { string path = "./Library/ScriptAssemblies/Assembly-CSharp.dll"; AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(path); bool haveInjected = false; if (assembly.MainModule.Types.Any(t => t.Name == "__HOTFIXE_FLAG")) { Debug.Log("had injected!"); haveInjected = true; } TypeReference objType = assembly.MainModule.Import(typeof(object)); assembly.MainModule.Types.Add(new TypeDefinition("__HOTFIX_GEN", "__HOTFIXE_FLAG", Mono.Cecil.TypeAttributes.Class, objType)); var AAAttribute = assembly.MainModule.Types.Single(t => t.FullName == "HotFixAttribute"); List <TypeDefinition> hotfix_delegates = (from module in assembly.Modules from type in module.Types where type.CustomAttributes.Any(ca => ca.AttributeType == AAAttribute) select type).ToList(); /*var hotfixAttributeType = assembly.MainModule.Types.Single(t => t.FullName == "AAAttribute"); * foreach (var type in (from module in assembly.Modules from type in module.Types select type)) * { * Debug.Log("OK"); * } */ List <MethodDefinition> ms = (from module in assembly.Modules from type in module.Types from method in type.Methods where method.Name == "InjectMethod" select method).ToList(); //List<MethodDefinition> testCalls = (from module in assembly.Modules // from type in module.Types // from method in type.Methods // where type.FullName=="TT.TestChangeMethod" && method.Name == "testCall" // select method).ToList(); //MethodDefinition testCall = testCalls [0]; var voidType = assembly.MainModule.Import(typeof(void)); foreach (TypeDefinition td in hotfix_delegates) { Mono.Collections.Generic.Collection <MethodDefinition> methods = td.Methods; foreach (MethodDefinition method in methods) { //构造函数,和基本返回类型不处理 if (!haveInjected && !method.IsConstructor && (!method.ReturnType.IsValueType)) { //方法的参数的个数 int param_count = method.Parameters.Count + (method.IsStatic ? 0 : 1); string name = (td.FullName + "_" + method.Name); name = name.Replace(".", "_"); var insertPoint = method.Body.Instructions[0]; var processor = method.Body.GetILProcessor(); if (method.IsConstructor) { insertPoint = findNextRet(method.Body.Instructions, insertPoint); } Instruction para = processor.Create(OpCodes.Ldstr, name); processor.InsertBefore(insertPoint, para); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, param_count)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Newarr, objType)); for (int i = 0; i < param_count; i++) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Dup)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, i)); if (i < ldargs.Length) { //将参数装入列表 processor.InsertBefore(insertPoint, processor.Create(ldargs[i])); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg, (short)i)); } int index = i; if (!method.IsStatic) { index -= 1; } if (index >= 0 && method.Parameters[index].ParameterType.IsValueType) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Box, method.Parameters[index].ParameterType)); } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stelem_Ref)); } Instruction ii = processor.Create(OpCodes.Call, ms[0].GetElementMethod()); processor.InsertBefore(insertPoint, ii); //处理结果 var keyVPType = assembly.MainModule.Import(typeof(KeyValuePair <bool, object>)); var mr = new VariableDefinition(keyVPType); method.Body.Variables.Add(mr); method.Body.InitLocals = true; processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stloc, mr)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloca_S, mr)); var met = assembly.MainModule.Import(typeof(KeyValuePair <bool, object>).GetMethod("get_Key")); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, met)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Brfalse, insertPoint)); if (method.ReturnType.FullName == voidType.FullName) { //如果返回时空,则弹出所有的栈。已经没有栈了,上面的判断用过了。 //processor.InsertBefore(insertPoint,processor.Create(OpCodes.Pop)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloca_S, mr)); met = assembly.MainModule.Import(typeof(KeyValuePair <bool, object>).GetMethod("get_Value")); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, met)); //返回类型转换。 //if(method.ReturnType.IsValueType) //{ //基础类型,不处理。 //processor.InsertBefore(insertPoint,processor.Create(OpCodes.Unbox_Any,method.ReturnType)); //}else{ //processor.InsertBefore(insertPoint,processor.Create(OpCodes.Castclass,method.ReturnType)); //} } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ret)); //直接复制testCall从stloc.0直到第一个return开始的部分 /*bool start = false; * foreach(Instruction ins in testCall.Body.Instructions) * { * if(ins.OpCode == OpCodes.Stloc_0) * { * //复制开始 * start = true; * } * if(start) * { * processor.InsertBefore(insertPoint,ins); * } * if(ins.OpCode == OpCodes.Ret) * { * //结束复制 * break; * } * }*/ Debug.Log("canFix : " + name); } } } if (!haveInjected) { assembly.Write(path); } }
static void PrepareExceptions(Mono.Collections.Generic.Collection <ExceptionHandler> excHandlers, Dictionary <int, List <string> > excStrings) { if (excHandlers == null) { foreach (var kvp in excStrings) { if (kvp.Value.Count == 0) { kvp.Value.Add(" }"); } } return; } var prevBlock = (First : -1, Last : -1); var currBlock = prevBlock; List <string> strs; foreach (var exc in excHandlers) { currBlock = (exc.TryStart.Offset, exc.TryEnd.Offset); if (currBlock != prevBlock) { if (!excStrings.TryGetValue(currBlock.First, out strs)) { strs = new List <string>(); } strs.Insert(0, $"try {{ // {currBlock.First:X4}..{currBlock.Last:X4}"); excStrings[currBlock.First] = strs; prevBlock = currBlock; } if (exc.HandlerStart != null) { if (!excStrings.TryGetValue(exc.HandlerStart.Offset, out strs)) { strs = new List <string>(); } string str; if (exc.HandlerType == ExceptionHandlerType.Catch) { str = $"catch ({exc.CatchType.FullName})"; } else if (exc.HandlerType == ExceptionHandlerType.Filter) { str = "filter handler"; } else if (exc.HandlerType == ExceptionHandlerType.Finally) { str = "finally"; } else if (exc.HandlerType == ExceptionHandlerType.Fault) { str = "fault handler"; } else { str = "unknown handler"; } strs.Add($" }} {str} in block {currBlock.First:X4}..{currBlock.Last:X4} {{"); excStrings[exc.HandlerStart.Offset] = strs; } if (exc.FilterStart != null) { if (!excStrings.TryGetValue(exc.FilterStart.Offset, out strs)) { strs = new List <string>(); } strs.Add($" }} filter condition in block {currBlock.First:X4}..{currBlock.Last:X4} {{"); excStrings[exc.FilterStart.Offset] = strs; } if (exc.HandlerEnd != null) { if (!excStrings.TryGetValue(exc.HandlerEnd.Offset, out strs)) { excStrings[exc.HandlerEnd.Offset] = new List <string>(); } } } }
static bool HasNullableReferenceType(this Mono.Collections.Generic.Collection <CustomAttribute> value, string attributeTypeName) => value.Where(a => a.AttributeType.Name == attributeTypeName) .SelectMany(a => a.ConstructorArguments) .Where(ca => ca.Type.FullName == SystemByteFullTypeName) .Where(ca => (byte)ca.Value == NullableAnnotated) .Any();