예제 #1
0
        ILFunction TransformDelegateConstruction(
            ILInstruction value, IMethod targetMethod,
            ILInstruction target, IType delegateType)
        {
            if (!IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod))
            {
                return(null);
            }
            if (targetMethod.MetadataToken.IsNil)
            {
                return(null);
            }
            if (LocalFunctionDecompiler.IsLocalFunctionMethod(targetMethod, context))
            {
                return(null);
            }
            if (!ValidateDelegateTarget(target))
            {
                return(null);
            }
            var handle = (MethodDefinitionHandle)targetMethod.MetadataToken;

            if (activeMethods.Contains(handle))
            {
                this.context.Function.Warnings.Add(" Found self-referencing delegate construction. Abort transformation to avoid stack overflow.");
                return(null);
            }
            var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken);

            if (!methodDefinition.HasBody())
            {
                return(null);
            }
            var genericContext = GenericContextFromTypeArguments(targetMethod.Substitution);

            if (genericContext == null)
            {
                return(null);
            }
            var ilReader = context.CreateILReader();
            var body     = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
            var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, ILFunctionKind.Delegate, context.CancellationToken);

            function.DelegateType = delegateType;
            // Embed the lambda into the parent function's ILAst, so that "Show steps" can show
            // how the lambda body is being transformed.
            value.ReplaceWith(function);
            function.CheckInvariant(ILPhase.Normal);

            var contextPrefix = targetMethod.Name;

            foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter))
            {
                v.Name = contextPrefix + v.Name;
            }

            var nestedContext = new ILTransformContext(context, function);

            function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)).Concat(GetTransforms()), nestedContext);
            nestedContext.Step("DelegateConstruction (ReplaceDelegateTargetVisitor)", function);
            function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(VariableKindExtensions.IsThis)));
            // handle nested lambdas
            nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function);
            ((IILTransform)this).Run(function, nestedContext);
            nestedContext.StepEndGroup();
            function.AddILRange(target);
            function.AddILRange(value);
            if (value is Call call)
            {
                function.AddILRange(call.Arguments[1]);
            }
            return(function);
        }
예제 #2
0
        ILFunction TransformDelegateConstruction(NewObj value, out ILInstruction target)
        {
            target = null;
            if (!IsDelegateConstruction(value))
            {
                return(null);
            }
            var targetMethod = ((IInstructionWithMethodOperand)value.Arguments[1]).Method;

            if (!IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod))
            {
                return(null);
            }
            if (LocalFunctionDecompiler.IsLocalFunctionMethod(targetMethod.ParentModule.PEFile, (MethodDefinitionHandle)targetMethod.MetadataToken))
            {
                return(null);
            }
            target = value.Arguments[0];
            if (targetMethod.MetadataToken.IsNil)
            {
                return(null);
            }
            var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken);

            if (!methodDefinition.HasBody())
            {
                return(null);
            }
            var genericContext = GenericContextFromTypeArguments(targetMethod.Substitution);

            if (genericContext == null)
            {
                return(null);
            }
            var ilReader = context.CreateILReader();
            var body     = context.PEFile.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
            var function = ilReader.ReadIL((MethodDefinitionHandle)targetMethod.MetadataToken, body, genericContext.Value, context.CancellationToken);

            function.DelegateType = value.Method.DeclaringType;
            function.CheckInvariant(ILPhase.Normal);
            // Embed the lambda into the parent function's ILAst, so that "Show steps" can show
            // how the lambda body is being transformed.
            value.ReplaceWith(function);

            var contextPrefix = targetMethod.Name;

            foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter))
            {
                v.Name = contextPrefix + v.Name;
            }

            var nestedContext = new ILTransformContext(context, function);

            function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)).Concat(GetTransforms()), nestedContext);
            nestedContext.Step("DelegateConstruction (ReplaceDelegateTargetVisitor)", function);
            function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
            // handle nested lambdas
            nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function);
            ((IILTransform) new DelegateConstruction()).Run(function, nestedContext);
            nestedContext.StepEndGroup();
            function.AddILRange(target);
            function.AddILRange(value);
            function.AddILRange(value.Arguments[1]);
            return(function);
        }
예제 #3
0
        void PerformAssignment(ILFunction function)
        {
            // remove unused variables before assigning names
            function.Variables.RemoveDead();
            int numDisplayClassLocals = 0;

            foreach (var v in function.Variables)
            {
                switch (v.Kind)
                {
                case VariableKind.Parameter:                         // ignore
                    break;

                case VariableKind.InitializerTarget:                         // keep generated names
                    AddExistingName(reservedVariableNames, v.Name);
                    break;

                case VariableKind.DisplayClassLocal:
                    v.Name = "CS$<>8__locals" + (numDisplayClassLocals++);
                    break;

                default:
                    if (v.HasGeneratedName || !IsValidName(v.Name) || ConflictWithLocal(v))
                    {
                        // don't use the name from the debug symbols if it looks like a generated name
                        v.Name = null;
                    }
                    else
                    {
                        // use the name from the debug symbols
                        // (but ensure we don't use the same name for two variables)
                        v.Name = GetAlternativeName(v.Name);
                    }
                    break;
                }
            }
            foreach (var localFunction in function.LocalFunctions)
            {
                if (!LocalFunctionDecompiler.ParseLocalFunctionName(localFunction.Name, out _, out var newName) || !IsValidName(newName))
                {
                    newName = null;
                }
                localFunction.Name = newName;
            }
            // Now generate names:
            var mapping = new Dictionary <ILVariable, string>(ILVariableEqualityComparer.Instance);

            foreach (var inst in function.Descendants.OfType <IInstructionWithVariableOperand>())
            {
                var v = inst.Variable;
                if (!mapping.TryGetValue(v, out string name))
                {
                    if (string.IsNullOrEmpty(v.Name))
                    {
                        v.Name = GenerateNameForVariable(v);
                    }
                    mapping.Add(v, v.Name);
                }
                else
                {
                    v.Name = name;
                }
            }
            foreach (var localFunction in function.LocalFunctions)
            {
                var newName = localFunction.Name;
                if (newName == null)
                {
                    newName = GetAlternativeName("f");
                }
                localFunction.Name = newName;
            }
        }
예제 #4
0
 public void Run(ILFunction function, ILTransformContext context)
 {
     try {
         if (this.context != null)
         {
             throw new InvalidOperationException("Reentrancy in " + nameof(TransformDisplayClassUsage));
         }
         this.context = context;
         var decompilationContext = new SimpleTypeResolveContext(context.Function.Method);
         // Traverse nested functions in post-order:
         // Inner functions are transformed before outer functions
         foreach (var f in function.Descendants.OfType <ILFunction>())
         {
             foreach (var v in f.Variables.ToArray())
             {
                 if (HandleMonoStateMachine(function, v, decompilationContext, f))
                 {
                     continue;
                 }
                 if (IsClosure(v, out ITypeDefinition closureType, out var inst))
                 {
                     AddOrUpdateDisplayClass(f, v, closureType, inst, localFunctionClosureParameter: false);
                 }
                 if (context.Settings.LocalFunctions && f.Kind == ILFunctionKind.LocalFunction && v.Kind == VariableKind.Parameter && v.Index > -1 && f.Method.Parameters[v.Index.Value] is IParameter p && LocalFunctionDecompiler.IsClosureParameter(p, decompilationContext))
                 {
                     AddOrUpdateDisplayClass(f, v, ((ByReferenceType)p.Type).ElementType.GetDefinition(), f.Body, localFunctionClosureParameter: true);
                 }
             }
         }
         VisitILFunction(function);
         if (instructionsToRemove.Count > 0)
         {
             context.Step($"Remove instructions", function);
             foreach (var store in instructionsToRemove)
             {
                 if (store.Parent is Block containingBlock)
                 {
                     containingBlock.Instructions.Remove(store);
                 }
             }
         }
         RemoveDeadVariableInit.ResetHasInitialValueFlag(function, context);
     } finally {
         instructionsToRemove.Clear();
         displayClasses.Clear();
         this.context = null;
     }
 }
예제 #5
0
        void PerformAssignment(ILFunction function)
        {
            // remove unused variables before assigning names
            function.Variables.RemoveDead();
            int numDisplayClassLocals = 0;
            Dictionary <int, string> assignedLocalSignatureIndices = new Dictionary <int, string>();

            foreach (var v in function.Variables.OrderBy(v => v.Name))
            {
                switch (v.Kind)
                {
                case VariableKind.Parameter:                         // ignore
                    break;

                case VariableKind.InitializerTarget:                         // keep generated names
                    AddExistingName(reservedVariableNames, v.Name);
                    break;

                case VariableKind.DisplayClassLocal:
                    v.Name = "CS$<>8__locals" + (numDisplayClassLocals++);
                    break;

                case VariableKind.Local when v.Index != null:
                    if (assignedLocalSignatureIndices.TryGetValue(v.Index.Value, out string name))
                    {
                        // make sure all local ILVariables that refer to the same slot in the locals signature
                        // are assigned the same name.
                        v.Name = name;
                    }
                    else
                    {
                        AssignName();
                        // Remember the newly assigned name:
                        assignedLocalSignatureIndices.Add(v.Index.Value, v.Name);
                    }
                    break;

                default:
                    AssignName();
                    break;
                }

                void AssignName()
                {
                    if (v.HasGeneratedName || !IsValidName(v.Name) || ConflictWithLocal(v))
                    {
                        // don't use the name from the debug symbols if it looks like a generated name
                        v.Name = null;
                    }
                    else
                    {
                        // use the name from the debug symbols
                        // (but ensure we don't use the same name for two variables)
                        v.Name = GetAlternativeName(v.Name);
                    }
                }
            }
            foreach (var localFunction in function.LocalFunctions)
            {
                if (!LocalFunctionDecompiler.ParseLocalFunctionName(localFunction.Name, out _, out var newName) || !IsValidName(newName))
                {
                    newName = null;
                }
                localFunction.Name = newName;
                localFunction.ReducedMethod.Name = newName;
            }
            // Now generate names:
            var mapping = new Dictionary <ILVariable, string>(ILVariableEqualityComparer.Instance);

            foreach (var inst in function.Descendants.OfType <IInstructionWithVariableOperand>())
            {
                var v = inst.Variable;
                if (!mapping.TryGetValue(v, out string name))
                {
                    if (string.IsNullOrEmpty(v.Name))
                    {
                        v.Name = GenerateNameForVariable(v);
                    }
                    mapping.Add(v, v.Name);
                }
                else
                {
                    v.Name = name;
                }
            }
            foreach (var localFunction in function.LocalFunctions)
            {
                var newName = localFunction.Name;
                if (newName == null)
                {
                    newName = GetAlternativeName("f");
                }
                localFunction.Name = newName;
                localFunction.ReducedMethod.Name = newName;
                localFunctionMapping[(MethodDefinitionHandle)localFunction.ReducedMethod.MetadataToken] = newName;
            }
            foreach (var inst in function.Descendants)
            {
                LocalFunctionMethod localFunction;
                switch (inst)
                {
                case Call call:
                    localFunction = call.Method as LocalFunctionMethod;
                    break;

                case LdFtn ldftn:
                    localFunction = ldftn.Method as LocalFunctionMethod;
                    break;

                default:
                    localFunction = null;
                    break;
                }
                if (localFunction == null || !localFunctionMapping.TryGetValue((MethodDefinitionHandle)localFunction.MetadataToken, out var name))
                {
                    continue;
                }
                localFunction.Name = name;
            }
        }