Beispiel #1
0
        private VariableDefinition StoreVariablesInObjectArray(RewriteContext context, List <VariableDefinition> variables)
        {
            var arrayVariable = new VariableDefinition(context.Method.Module.Import(typeof(Object[])));

            context.Processor.Body.Variables.Add(arrayVariable);

            context.Insert(Instruction.Create(OpCodes.Ldc_I4, variables.Count));
            context.Insert(Instruction.Create(OpCodes.Newarr, context.Method.Module.Import(typeof(Object))));

            context.Insert(Instruction.Create(OpCodes.Stloc, arrayVariable));

            for (int i = 0; i < variables.Count; ++i)
            {
                VariableDefinition variable     = variables[i];
                TypeReference      variableType = variable.VariableType;

                context.Insert(Instruction.Create(OpCodes.Ldloc, arrayVariable));
                context.Insert(Instruction.Create(OpCodes.Ldc_I4, i));
                context.Insert(Instruction.Create(OpCodes.Ldloc, variable));

                if (variableType.IsByReference)
                {
                    variableType = StripByReference(context, variable.VariableType);
                    context.Insert(Instruction.Create(OpCodes.Ldobj, variableType));
                }

                if (variableType.IsValueType)
                {
                    context.Insert(Instruction.Create(OpCodes.Box, variableType));
                }

                context.Insert(Instruction.Create(OpCodes.Stelem_Ref));
            }

            return(arrayVariable);
        }
Beispiel #2
0
 private static TypeReference StripByReference(RewriteContext context, TypeReference type)
 {
     return(context.Method.Module.Import(type.Resolve()));
 }
Beispiel #3
0
        public bool Rewrite(Configuration configuration, MethodDefinition method,
            IRewriteTargetMatcher rewriteTargetMatcher)
        {
            bool rewritten = false;

            if (method.Body == null)
            {
                return rewritten;
            }

            ILProcessor processor = method.Body.GetILProcessor();

            // Iterate copy of initial instructions without modifications
            foreach (var instruction in method.Body.Instructions.ToList())
            {
                MethodReference calledMethod;
                if (_instructionHelper.TryGetCall(instruction, out calledMethod))
                {
                    List<IRewriteTarget> targets = rewriteTargetMatcher.GetMatchingTargets(calledMethod).ToList();

                    if (targets.Count == 0)
                    {
                        continue;
                    }

                    RewriteContext context = new RewriteContext(configuration,
                        processor, instruction, targets, calledMethod);
                    RewriteInstruction(context);

                    rewritten = true;
                }
            }

            return rewritten;
        }
Beispiel #4
0
 private static void PushMethod(RewriteContext context, MethodReference method)
 {
     context.Insert(Instruction.Create(OpCodes.Ldtoken, method));
     context.Insert(Instruction.Create(OpCodes.Call, context.Method.Module.Import(GetMethodFromHandleMethod)));
 }
Beispiel #5
0
        private List<VariableDefinition> StoreArgumentsInVariables(RewriteContext context)
        {
            List<TypeReference> parameters = GetParameters(context.Method);
            List<VariableDefinition> variables = parameters
                .Select(parameterType => new VariableDefinition(ResolveGenericParameters(parameterType, context.Method)))
                .ToList();

            context.AddVariables(variables);

            // Add items on stack to array. Note that we pop them backwards, so
            // we add them backwards as well.
            for (int i = parameters.Count - 1; i >= 0; --i)
            {
                TypeReference parameterType = ResolveGenericParameters(parameters[i], context.Method);

                if (parameterType.IsByReference)
                {
                }
                else if (parameterType.IsValueType)
                {
                    // If the declaring type of the method is a value type, it's *address* is pushed on the stack
                    // and we need to dereference it using ldobj to get the actual value.
                    if (context.Method.HasThis && i == 0)
                    {
                        context.Insert(Instruction.Create(OpCodes.Ldobj, parameterType));
                    }
                }

                context.Insert(Instruction.Create(OpCodes.Stloc, variables[i]));
            }

            return variables;
        }
Beispiel #6
0
        private VariableDefinition StoreVariablesInObjectArray(RewriteContext context, List<VariableDefinition> variables)
        {
            var arrayVariable = new VariableDefinition(context.Method.Module.Import(typeof(Object[])));
            context.Processor.Body.Variables.Add(arrayVariable);

            context.Insert(Instruction.Create(OpCodes.Ldc_I4, variables.Count));
            context.Insert(Instruction.Create(OpCodes.Newarr, context.Method.Module.Import(typeof(Object))));

            context.Insert(Instruction.Create(OpCodes.Stloc, arrayVariable));

            for (int i = 0; i < variables.Count; ++i)
            {
                VariableDefinition variable = variables[i];
                TypeReference variableType = variable.VariableType;

                context.Insert(Instruction.Create(OpCodes.Ldloc, arrayVariable));
                context.Insert(Instruction.Create(OpCodes.Ldc_I4, i));
                context.Insert(Instruction.Create(OpCodes.Ldloc, variable));

                if (variableType.IsByReference)
                {
                    variableType = StripByReference(context, variable.VariableType);
                    context.Insert(Instruction.Create(OpCodes.Ldobj, variableType));
                }

                if (variableType.IsValueType)
                {
                    context.Insert(Instruction.Create(OpCodes.Box, variableType));
                }

                context.Insert(Instruction.Create(OpCodes.Stelem_Ref));
            }

            return arrayVariable;
        }
Beispiel #7
0
        private void PushReturnValueOnStack(RewriteContext context, VariableDefinition interceptorResultVariable, bool isVoidMethod)
        {
            if (!isVoidMethod)
            {
                var type = context.Method.Module.Import(typeof(InterceptorResult<>));
                var genericType = new GenericInstanceType(type);
                genericType.GenericArguments.Add(GetReturnValue(context.Method));

                var returnValueProperty = type.Resolve().Properties.First(property => property.Name == "ReturnValue");
                var getMethod = context.Method.Module.Import(returnValueProperty.GetMethod);
                getMethod.DeclaringType = genericType;

                context.Insert(Instruction.Create(OpCodes.Ldloc, interceptorResultVariable));
                context.Insert(Instruction.Create(OpCodes.Callvirt, getMethod));
            }
        }
Beispiel #8
0
        private void RewriteInstruction(RewriteContext context)
        {
            bool isVoidMethod = context.Method.ReturnType.FullName == "System.Void" &&
                !IsConstructor(context.Method);

            // As per: https://groups.google.com/forum/#!topic/mono-cecil/v6LfFLj9eAE
            context.Processor.Body.SimplifyMacros();

            List<VariableDefinition> variables = StoreArgumentsInVariables(context);
            VariableDefinition arrayVariable = StoreVariablesInObjectArray(context, variables);
            VariableDefinition interceptorResultVariable = InvokeReplacementMethod(context, arrayVariable, isVoidMethod);

            Instruction currentPosition = context.CurrentPosition;

            // If the method was intercepted, we need to push the return value on the stack.
            PushReturnValueOnStack(context, interceptorResultVariable, isVoidMethod);

            // And copy any out/reference parameters back to their original address.
            CopyReferenceParametersToAddress(context, arrayVariable, variables);

            // Then skip over the part for when we didn't intercept.
            context.Insert(Instruction.Create(OpCodes.Br, context.OriginalInstruction.Next));

            // If it wasn't we need to rebuild the stack and invoke the original method.
            Instruction invokeOriginalStartInstruction = InvokeOriginalMethod(context, variables);

            // Inject an instruction to jump based on whether the instruction was intercepted.
            var interceptedPropertyGetter = context.Method.Module.Import(InterceptedProperty.GetGetMethod());
            context.InsertAfter(currentPosition, new[]
            {
                Instruction.Create(OpCodes.Ldloc, interceptorResultVariable),
                Instruction.Create(OpCodes.Callvirt, interceptedPropertyGetter),
                Instruction.Create(OpCodes.Brfalse, invokeOriginalStartInstruction)
            });

            context.Processor.Remove(context.OriginalInstruction);

            context.Processor.Body.OptimizeMacros();
        }
Beispiel #9
0
        private VariableDefinition InvokeReplacementMethod(RewriteContext context, VariableDefinition arrayVariable, bool isVoidMethod)
        {
            EventRewriteTarget eventTarget = context.Targets[0] as EventRewriteTarget;

            var importedReplacement = GetInterceptorMethod(context.Method, isVoidMethod, eventTarget);

            context.Insert(Instruction.Create(OpCodes.Ldloc, arrayVariable));

            PushMethod(context, context.Method);

            if (eventTarget != null)
            {
                PushMethod(context, context.Method.Module.Import(eventTarget.AddMethod));
                PushMethod(context, context.Method.Module.Import(eventTarget.RemoveMethod));
            }

            context.Insert(Instruction.Create(OpCodes.Call, importedReplacement));

            var interceptorResultVariable = new VariableDefinition(GetInterceptorResultType(context.Method, isVoidMethod));
            context.Processor.Body.Variables.Add(interceptorResultVariable);

            context.Insert(Instruction.Create(OpCodes.Stloc, interceptorResultVariable));

            return interceptorResultVariable;
        }
Beispiel #10
0
        private Instruction InvokeOriginalMethod(RewriteContext context, List<VariableDefinition> variables)
        {
            Instruction instruction;
            Instruction firstInstruction = null;

            for (int i = 0; i < variables.Count; ++i)
            {
                var variable = variables[i];

                // If we're calling an instance method of a value type, we need to put the
                // *address* of the instance on the stack.
                if (i == 0 && context.Method.HasThis && context.Method.DeclaringType.IsValueType)
                {
                    instruction = context.Insert(Instruction.Create(OpCodes.Ldloca, variable));
                }
                else
                {
                    instruction = context.Insert(Instruction.Create(OpCodes.Ldloc, variable));
                }

                firstInstruction = firstInstruction ?? instruction;
            }

            instruction = context.Insert(context.OriginalInstruction);
            firstInstruction = firstInstruction ?? instruction;

            return firstInstruction;
        }
Beispiel #11
0
        private void CopyReferenceParametersToAddress(RewriteContext context,
            VariableDefinition arrayVariable, List<VariableDefinition> variables)
        {
            for (int i = 0; i < variables.Count; ++i)
            {
                if (variables[i].VariableType.IsByReference)
                {
                    var variableType = StripByReference(context, variables[i].VariableType);

                    // Push address
                    context.Insert(Instruction.Create(OpCodes.Ldloc, variables[i]));

                    // Push value from arguments array
                    context.Insert(Instruction.Create(OpCodes.Ldloc, arrayVariable));
                    context.Insert(Instruction.Create(OpCodes.Ldc_I4, i));
                    context.Insert(Instruction.Create(OpCodes.Ldelem_Any, context.Method.Module.Import(typeof(object))));
                    context.Insert(Instruction.Create(OpCodes.Unbox_Any, variableType));

                    // Copy value to address
                    context.Insert(Instruction.Create(OpCodes.Stind_Ref));
                }
            }
        }
Beispiel #12
0
 private static TypeReference StripByReference(RewriteContext context, TypeReference type)
 {
     return context.Method.Module.Import(type.Resolve());
 }
Beispiel #13
0
 private static void PushMethod(RewriteContext context, MethodReference method)
 {
     context.Insert(Instruction.Create(OpCodes.Ldtoken, method));
     context.Insert(Instruction.Create(OpCodes.Call, context.Method.Module.Import(GetMethodFromHandleMethod)));
 }