A delimited collection of statements to execute in a new (nested) scope.
상속: Microsoft.Cci.MutableCodeModel.BlockStatement
예제 #1
0
        /// <summary>
        /// Decompile the IL operations of this method body into a block of statements.
        /// </summary>
        protected override IBlockStatement GetBlock()
        {
            var block = new DecompiledBlock(0, this.ilMethodBody.Size, new Sublist <BasicBlock <Instruction> >(this.cdfg.AllBlocks, 0, this.cdfg.AllBlocks.Count), isLexicalScope: true);

            this.CreateExceptionBlocks(block);
            bool addDeclarations = true;

            if (this.localScopeProvider != null)
            {
                var scopes = new List <ILocalScope>(this.localScopeProvider.GetLocalScopes(this.ilMethodBody));
                if (scopes.Count > 0)
                {
                    this.CreateLexicalScopes(block, new Sublist <ILocalScope>(scopes, 0, scopes.Count));
                    addDeclarations = false;
                }
            }
            if (addDeclarations)
            {
                int counter = 0;
                foreach (var local in this.ilMethodBody.LocalVariables)
                {
                    Contract.Assume(local != null);
                    Contract.Assume(counter <= block.Statements.Count);
                    block.Statements.Insert(counter++, new LocalDeclarationStatement()
                    {
                        LocalVariable = this.GetLocalWithSourceName(local)
                    });
                }
            }
            new InstructionParser(this).Traverse(block);
            new SwitchReplacer(this).Traverse(block);
            DeleteNops(block);
            DeleteLocalAssignedLocal(block);
            new PatternReplacer(this, block).Traverse(block);
            new TryCatchReplacer(this, block).Traverse(block);
            new RemoveNonLexicalBlocks().Traverse(block);
            new DeclarationUnifier(this).Traverse(block);
            new IfThenElseReplacer(this).Traverse(block);
            if ((this.options & DecompilerOptions.Loops) != 0)
            {
                new WhileLoopReplacer(this).Traverse(block);
                new ForLoopReplacer(this).Traverse(block);
            }
            new UnreferencedLabelRemover(this).Traverse(block);
            new LockReplacer(this).Traverse(block);
            new BlockFlattener().Traverse(block);
            this.RemoveRedundantFinalReturn(block);
            var result = new CompilationArtifactRemover(this).Rewrite(block);

            if ((this.options & DecompilerOptions.AnonymousDelegates) != 0)
            {
                bool didNothing;
                result = new AnonymousDelegateInserter(this).InsertAnonymousDelegates(result, out didNothing);
                if (!didNothing)
                {
                    new DeclarationUnifier(this).Traverse(result);
                }
            }
            return(result);
        }
예제 #2
0
        private bool RemoveEndFinallyFrom(DecompiledBlock block, LabeledStatement labelToGoto)
        {
            Contract.Requires(block != null);
            Contract.Requires(labelToGoto != null);

            for (int i = 0; i < block.Statements.Count; i++)
            {
                if (block.Statements[i] is EndFinally)
                {
                    var gotoFinally = new GotoStatement()
                    {
                        TargetStatement = labelToGoto
                    };
                    block.Statements[i] = gotoFinally;
                    var gotos = new List <IGotoStatement>(1);
                    gotos.Add(gotoFinally);
                    this.gotosThatTarget[(uint)labelToGoto.Label.UniqueKey] = gotos;
                    return(true);
                }
                var nestedBlock = block.Statements[i] as DecompiledBlock;
                if (nestedBlock != null && this.RemoveEndFinallyFrom(nestedBlock, labelToGoto))
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #3
0
        private void CreateExceptionBlocks(DecompiledBlock block)
        {
            Contract.Requires(block != null);

            if (IteratorHelper.EnumerableIsEmpty(this.ilMethodBody.OperationExceptionInformation))
            {
                return;
            }
            List <IOperationExceptionInformation> handlers = new List <IOperationExceptionInformation>(this.ilMethodBody.OperationExceptionInformation);

            handlers.Sort(CompareHandlers);
            foreach (var exInfo in handlers)
            {
                Contract.Assume(exInfo != null);
                this.CreateNestedBlock(block, exInfo.TryStartOffset, exInfo.TryEndOffset);
                if (exInfo.HandlerKind == HandlerKind.Filter)
                {
                    this.CreateNestedBlock(block, exInfo.FilterDecisionStartOffset, exInfo.HandlerEndOffset);
                }
                else
                {
                    this.CreateNestedBlock(block, exInfo.HandlerStartOffset, exInfo.HandlerEndOffset);
                }
            }
        }
예제 #4
0
        private void AddLocalsAndConstants(DecompiledBlock block, ILocalScope scope)
        {
            Contract.Requires(block != null);
            Contract.Requires(scope != null);
            Contract.Requires(this.localScopeProvider != null);

            bool isLexicalScope = false;
            int  counter        = 0;

            foreach (var local in this.localScopeProvider.GetConstantsInScope(scope))
            {
                Contract.Assume(local != null);
                var localVariable = this.GetLocalWithSourceName(local);
                Contract.Assume(counter <= block.Statements.Count);
                block.Statements.Insert(counter++, new LocalDeclarationStatement()
                {
                    LocalVariable = localVariable
                });
            }
            foreach (var local in this.localScopeProvider.GetVariablesInScope(scope))
            {
                Contract.Assume(local != null);
                var localVariable = this.GetLocalWithSourceName(local);
                Contract.Assume(counter <= block.Statements.Count);
                block.Statements.Insert(counter++, new LocalDeclarationStatement()
                {
                    LocalVariable = localVariable
                });
            }
            if (isLexicalScope)
            {
                block.IsLexicalScope = true;
            }
        }
예제 #5
0
        internal TryCatchReplacer(SourceMethodBody sourceMethodBody, DecompiledBlock block)
        {
            Contract.Requires(sourceMethodBody != null);
            Contract.Requires(block != null);
            this.host            = sourceMethodBody.host; Contract.Assume(sourceMethodBody.host != null);
            this.gotosThatTarget = sourceMethodBody.gotosThatTarget; Contract.Assume(this.gotosThatTarget != null);
            this.unconditionalBranchRemover.gotosThatTarget = sourceMethodBody.gotosThatTarget;

            Contract.Assume(sourceMethodBody.ilMethodBody != null);
            foreach (var exInfo in sourceMethodBody.ilMethodBody.OperationExceptionInformation)
            {
                var tryCatchF = this.tryCatchFinallyMap.Find(exInfo.TryStartOffset, exInfo.TryEndOffset);
                if (tryCatchF == null)
                {
                    tryCatchF = new TryCatchFinallyStatement();
                    this.tryCatchFinallyMap.Add(exInfo.TryStartOffset, exInfo.TryEndOffset, tryCatchF);
                }
                if (exInfo.HandlerKind == HandlerKind.Filter)
                {
                    this.tryCatchFinallyMap.Add(exInfo.FilterDecisionStartOffset, exInfo.HandlerEndOffset, tryCatchF);
                    this.handlerMap.Add(exInfo.FilterDecisionStartOffset, exInfo.HandlerEndOffset, exInfo);
                }
                this.tryCatchFinallyMap.Add(exInfo.HandlerStartOffset, exInfo.HandlerEndOffset, tryCatchF);
                this.handlerMap.Add(exInfo.HandlerStartOffset, exInfo.HandlerEndOffset, exInfo);
            }
        }
예제 #6
0
 private void RemoveLocalDeclarationOf(ILocalDefinition exceptionContainer, DecompiledBlock block)
 {
     Contract.Requires(exceptionContainer != null);
     Contract.Requires(block != null);
     this.localDeclarationRemover.localVariableToRemove = exceptionContainer;
     this.localDeclarationRemover.StopTraversal         = false;
     this.localDeclarationRemover.Traverse(block);
 }
예제 #7
0
        private IExpression /*?*/ GetFilterCondition(DecompiledBlock block)
        {
            Contract.Requires(block != null);
            BlockExpression   result     = null;
            List <IStatement> statements = null;

            foreach (var statement in block.Statements)
            {
                var nestedBlock = statement as DecompiledBlock;
                if (nestedBlock != null)
                {
                    var nestedResult = this.GetFilterCondition(nestedBlock);
                    if (nestedResult != null)
                    {
                        if (result == null)
                        {
                            return(nestedResult);
                        }
                        result.Expression = nestedResult;
                        return(result);
                    }
                }
                else
                {
                    var endFilter = statement as EndFilter;
                    if (endFilter != null)
                    {
                        if (result == null)
                        {
                            return(endFilter.FilterResult);
                        }
                        result.Expression = endFilter.FilterResult;
                        return(result);
                    }
                }
                if (statements == null)
                {
                    statements = new List <IStatement>();
                    result     = new BlockExpression()
                    {
                        BlockStatement = new BlockStatement()
                        {
                            Statements = statements
                        }
                    };
                }
                statements.Add(statement);
            }
            if (result != null && result.Expression == CodeDummy.Expression)
            {
                return(null);
            }
            return(result);
        }
예제 #8
0
        private void SplitBlock(DecompiledBlock blockToSplit, uint splitOffset, List <IStatement> leftList, List <IStatement> rightList)
        {
            Contract.Requires(blockToSplit != null);
            Contract.Requires(leftList != null);
            Contract.Requires(rightList != null);
            Contract.Requires(splitOffset >= blockToSplit.StartOffset);
            Contract.Requires(splitOffset <= blockToSplit.EndOffset);

            var leftBasicBlocks = blockToSplit.GetBasicBlocksForRange(blockToSplit.StartOffset, splitOffset);

            Contract.Assume(splitOffset >= blockToSplit.StartOffset);
            var leftBlock = new DecompiledBlock(blockToSplit.StartOffset, splitOffset, leftBasicBlocks, isLexicalScope: false);

            leftList.Add(leftBlock);
            var rightBasicBlocks = blockToSplit.GetBasicBlocksForRange(splitOffset, blockToSplit.EndOffset);

            Contract.Assume(splitOffset <= blockToSplit.EndOffset);
            var rightBlock = new DecompiledBlock(splitOffset, blockToSplit.EndOffset, rightBasicBlocks, isLexicalScope: false);

            rightList.Add(rightBlock);

            var n = blockToSplit.Statements.Count;

            if (n == 0)
            {
                return;
            }
            var leftStatements  = leftBlock.Statements = new List <IStatement>();
            var rightStatements = rightBlock.Statements = new List <IStatement>();

            for (int i = 0; i < n; i++)
            {
                var nb = blockToSplit.Statements[i] as DecompiledBlock;
                Contract.Assume(nb != null);
                if (nb.EndOffset <= splitOffset)
                {
                    leftStatements.Add(nb);
                }
                else if (nb.StartOffset < splitOffset)
                {
                    Contract.Assume(!nb.IsLexicalScope); //lexical scopes are assumed to nest cleanly.
                    this.SplitBlock(nb, splitOffset, leftStatements, rightStatements);
                }
                else
                {
                    rightStatements.Add(nb);
                }
            }
            Consolidate(leftBlock);
            Consolidate(rightBlock);
        }
예제 #9
0
        private void CreateLexicalScopes(DecompiledBlock block, Sublist <ILocalScope> scopes)
        {
            Contract.Requires(block != null);
            Contract.Requires(this.localScopeProvider != null);

            for (int i = 0, n = scopes.Count; i < n;)
            {
                var scope = scopes[i++];
                if (scope.Length == 0)
                {
                    continue;
                }
                var nestedBlock = this.CreateNestedBlock(block, scope.Offset, scope.Offset + scope.Length);
                this.AddLocalsAndConstants(nestedBlock, scope);
            }
        }
예제 #10
0
        private void RemoveRedundantFinalReturn(DecompiledBlock block)
        {
            Contract.Requires(block != null);
            var n = block.Statements.Count;

            if (n > 0)
            {
                var returnStatement = block.Statements[n - 1] as ReturnStatement;
                if (returnStatement == null)
                {
                    return;
                }
                if (this.ilMethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void)
                {
                    var boundExpression = returnStatement.Expression as IBoundExpression;
                    if (boundExpression == null)
                    {
                        return;
                    }
                    var local = boundExpression.Definition as ILocalDefinition;
                    if (local == null)
                    {
                        return;
                    }
                    if (this.numberOfAssignmentsToLocal[local] > 0)
                    {
                        return;
                    }
                    this.numberOfReferencesToLocal[local]--;
                    if (this.numberOfReferencesToLocal[local] == 0 && this.numberOfAssignmentsToLocal[local] == 0)
                    {
                        for (int j = 0; j < n - 1; j++)
                        {
                            var locDecl = block.Statements[j] as ILocalDeclarationStatement;
                            if (locDecl != null && locDecl.LocalVariable == local)
                            {
                                block.Statements.RemoveAt(j);
                                n--;
                                break;
                            }
                        }
                    }
                }
                block.Statements.RemoveAt(n - 1);
            }
        }
예제 #11
0
        private void Consolidate(DecompiledBlock block)
        {
            if (block == null)
            {
                return;
            }
            if (block.Statements.Count != 1)
            {
                return;
            }
            var nestedBlock = block.Statements[0] as DecompiledBlock;

            if (nestedBlock == null)
            {
                return;
            }
            Consolidate(nestedBlock);
            block.Statements = nestedBlock.Statements;
        }
예제 #12
0
 private bool RemovedFilterCondition(DecompiledBlock block)
 {
     Contract.Requires(block != null);
     for (int i = 0; i < block.Statements.Count; i++)
     {
         var statement   = block.Statements[i];
         var nestedBlock = statement as DecompiledBlock;
         if (nestedBlock != null)
         {
             if (this.RemovedFilterCondition(nestedBlock))
             {
                 return(true);
             }
         }
         block.Statements.RemoveAt(i);
         if (statement is EndFilter)
         {
             return(true);
         }
     }
     return(false);
 }
예제 #13
0
    internal TryCatchReplacer(SourceMethodBody sourceMethodBody, DecompiledBlock block) {
      Contract.Requires(sourceMethodBody != null);
      Contract.Requires(block != null);
      this.host = sourceMethodBody.host; Contract.Assume(sourceMethodBody.host != null);
      this.gotosThatTarget = sourceMethodBody.gotosThatTarget; Contract.Assume(this.gotosThatTarget != null);
      this.unconditionalBranchRemover.gotosThatTarget = sourceMethodBody.gotosThatTarget;

      Contract.Assume(sourceMethodBody.ilMethodBody != null);
      foreach (var exInfo in sourceMethodBody.ilMethodBody.OperationExceptionInformation) {
        var tryCatchF = this.tryCatchFinallyMap.Find(exInfo.TryStartOffset, exInfo.TryEndOffset);
        if (tryCatchF == null) {
          tryCatchF = new TryCatchFinallyStatement();
          this.tryCatchFinallyMap.Add(exInfo.TryStartOffset, exInfo.TryEndOffset, tryCatchF);
        }        
        if (exInfo.HandlerKind == HandlerKind.Filter) {
          this.tryCatchFinallyMap.Add(exInfo.FilterDecisionStartOffset, exInfo.HandlerEndOffset, tryCatchF); 
          this.handlerMap.Add(exInfo.FilterDecisionStartOffset, exInfo.HandlerEndOffset, exInfo); 
        }
        this.tryCatchFinallyMap.Add(exInfo.HandlerStartOffset, exInfo.HandlerEndOffset, tryCatchF);
        this.handlerMap.Add(exInfo.HandlerStartOffset, exInfo.HandlerEndOffset, exInfo); 
      }
    }
예제 #14
0
        private bool RemoveEndFinallyFrom(DecompiledBlock block)
        {
            Contract.Requires(block != null);
            Contract.Assume(block.Statements.Count > 0); //There must be an endfinally
            if (block.Statements[block.Statements.Count - 1] is EndFinally)
            {
                block.Statements.RemoveAt(block.Statements.Count - 1);
                return(true);
            }
            var lastBlock = block.Statements[block.Statements.Count - 1] as DecompiledBlock;

            if (lastBlock != null && this.RemoveEndFinallyFrom(lastBlock))
            {
                return(true);
            }
            LabeledStatement endFinally = new LabeledStatement()
            {
                Label = this.host.NameTable.GetNameFor("__endfinally#" + this.endFinallyCounter++), Statement = new EmptyStatement()
            };

            block.Statements.Add(endFinally);
            return(this.RemoveEndFinallyFrom(block, endFinally));
        }
예제 #15
0
 private static void ConsolidateScopes(DecompiledBlock cb)
 {
     Contract.Requires(cb != null);
     for (int i = 0; i < cb.Statements.Count; i++)
     {
         var nb = cb.Statements[i] as DecompiledBlock;
         if (nb == null)
         {
             break;
         }
         if (nb.Statements.Count == 0)
         {
             cb.Statements.RemoveAt(i--);
         }
     }
     if (cb.Statements.Count == 1)
     {
         var nb = cb.Statements[0] as DecompiledBlock;
         if (nb != null)
         {
             cb.Statements = nb.Statements;
         }
     }
 }
예제 #16
0
        private DecompiledBlock CreateNestedBlock(DecompiledBlock block, uint startOffset, uint endOffset)
        {
            Contract.Requires(block != null);
            Contract.Requires(startOffset <= endOffset);
            Contract.Ensures(Contract.Result <DecompiledBlock>() != null);

            {
nextBlock:
                foreach (var statement in block.Statements)
                {
                    var nestedBlock = statement as DecompiledBlock;
                    if (nestedBlock == null)
                    {
                        continue;
                    }
                    if (nestedBlock.StartOffset <= startOffset && nestedBlock.EndOffset >= endOffset)
                    {
                        block = nestedBlock;
                        goto nextBlock;
                    }
                }
            }
            if (block.StartOffset == startOffset && block.EndOffset == endOffset)
            {
                return(block);
            }
            //replace block.Statements with three nested blocks, the middle one corresponding to one we have to create
            //but keep any declarations.
            int n             = block.Statements.Count;
            var oldStatements = block.Statements;
            var newStatements = block.Statements;
            int m             = 0;

            if (n >= 0)
            {
                while (m < n && oldStatements[m] is LocalDeclarationStatement)
                {
                    m++;
                }
                if (m < n)
                {
                    newStatements = new List <IStatement>(m + 3);
                    for (int i = 0; i < m; i++)
                    {
                        newStatements.Add(oldStatements[i]);
                    }
                }
            }
            block.Statements = newStatements;
            var             basicBlocks    = block.GetBasicBlocksForRange(startOffset, endOffset);
            var             newNestedBlock = new DecompiledBlock(startOffset, endOffset, basicBlocks, isLexicalScope: true);
            DecompiledBlock beforeBlock    = null;

            if (block.StartOffset < startOffset)
            {
                var basicBlocksBefore = block.GetBasicBlocksForRange(block.StartOffset, startOffset);
                Contract.Assume(block.StartOffset < startOffset);
                beforeBlock = new DecompiledBlock(block.StartOffset, startOffset, basicBlocksBefore, isLexicalScope: false);
                newStatements.Add(beforeBlock);
            }
            newStatements.Add(newNestedBlock);
            DecompiledBlock afterBlock = null;

            if (block.EndOffset > endOffset)
            {
                var basicBlocksAfter = block.GetBasicBlocksForRange(endOffset, block.EndOffset);
                Contract.Assume(block.EndOffset > endOffset);
                afterBlock = new DecompiledBlock(endOffset, block.EndOffset, basicBlocksAfter, isLexicalScope: false);
                newStatements.Add(afterBlock);
            }
            if (newStatements != oldStatements)
            {
                //In this case there were already some nested blocks, which happens when there are nested exception blocks
                //and we are creating an enclosing lexical block that does not quite coincide with block.
                //We now have to populate the newly created blocks with these nested blocks, splitting them if necessary.
                for (int i = m; i < n; i++)
                {
                    var nb = oldStatements[i] as DecompiledBlock;
                    Contract.Assume(nb != null);
                    if (nb.EndOffset <= startOffset)
                    {
                        Contract.Assume(beforeBlock != null);
                        beforeBlock.Statements.Add(nb);
                    }
                    else if (nb.StartOffset < startOffset)
                    {
                        Contract.Assume(nb.EndOffset <= endOffset); //nb starts before newNestedBlock but ends inside it.
                        Contract.Assume(beforeBlock != null);
                        if (nb.IsLexicalScope)
                        {
                            //Lexical scopes are assumed to nest cleanly. But the C# is not playing along when one using statement immediately follows another
                            //Well fix matters by making nb.EndOffset == startOffset
                            nb.EndOffset = startOffset;
                            beforeBlock.Statements.Add(nb);
                        }
                        else
                        {
                            this.SplitBlock(nb, startOffset, beforeBlock.Statements, newNestedBlock.Statements);
                        }
                    }
                    else if (nb.EndOffset <= endOffset)
                    {
                        newNestedBlock.Statements.Add(nb);
                    }
                    else if (nb.StartOffset < endOffset)
                    {
                        Contract.Assert(nb.EndOffset > endOffset); //nb starts inside newNestedBlock but ends after it.
                        Contract.Assume(!nb.IsLexicalScope);       //lexical scopes are assumed to nest cleanly.
                        Contract.Assume(afterBlock != null);
                        this.SplitBlock(nb, endOffset, newNestedBlock.Statements, afterBlock.Statements);
                    }
                    else
                    {
                        Contract.Assume(afterBlock != null);
                        afterBlock.Statements.Add(nb);
                    }
                }
                //consolidate blocks consisting of a single block
                Consolidate(beforeBlock);
                Consolidate(newNestedBlock);
                Consolidate(afterBlock);
            }
            return(newNestedBlock);
        }
예제 #17
0
    private ILocalDefinition ExtractExceptionContainer(DecompiledBlock nestedBlock, ITypeReference exceptionType) {
      Contract.Requires(nestedBlock != null);
      Contract.Requires(exceptionType != null);
      Contract.Ensures(Contract.Result<ILocalDefinition>() != null);

      Contract.Assume(nestedBlock.Statements.Count > 0);
      int i = 0;
      while (nestedBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < nestedBlock.Statements.Count); };
      var firstStatement = nestedBlock.Statements[i++];
      var firstBlock = firstStatement as DecompiledBlock;
      while (firstBlock != null) {
        Contract.Assume(firstBlock.Statements.Count > 0);
        i = 0;
        while (firstBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < firstBlock.Statements.Count); };
        firstStatement = firstBlock.Statements[i++];
        nestedBlock = firstBlock;
        firstBlock = firstStatement as DecompiledBlock;
      }
      //Ignoring any local declarations inserted for lexical scopes, any decompiled block that does not start with a nested block, starts with a label.
      Contract.Assume(firstStatement is LabeledStatement);
      if (nestedBlock.Statements.Count > i) {
        var exprStatement = nestedBlock.Statements[i] as ExpressionStatement;
        if (exprStatement != null) {
          nestedBlock.Statements.RemoveRange(i-1, 2);
          if (exprStatement.Expression is PopValue) return Dummy.LocalVariable;
          var assignment = exprStatement.Expression as Assignment;
          if (assignment != null && assignment.Source is PopValue) {
            var local = assignment.Target.Definition as ILocalDefinition;
            if (local != null) return local; //if not, this is not a recognized code pattern.
          }
        }
        // can't find the local, so just introduce one and leave its value on the stack
        var ld = new LocalDefinition() {
          Type = exceptionType,
        };
        var pushStatement = new PushStatement() {
          ValueToPush = new BoundExpression() {
            Definition = ld,
            Type = exceptionType,
          },
        };
        nestedBlock.Statements.Insert(0, pushStatement);
        return ld;
      } else {
        //Valid IL should always have at least one instruction to consume the exception value as well as a branch out of the handler block.
        Contract.Assume(false);
        return Dummy.LocalVariable;
      }
    }
예제 #18
0
 private bool RemovedFilterCondition(DecompiledBlock block) {
   Contract.Requires(block != null);
   for (int i = 0; i < block.Statements.Count; i++) {
     var statement = block.Statements[i];
     var nestedBlock = statement as DecompiledBlock;
     if (nestedBlock != null) {
       if (this.RemovedFilterCondition(nestedBlock)) return true;
     }
     block.Statements.RemoveAt(i);
     if (statement is EndFilter) return true;
   }
   return false;
 }
예제 #19
0
 private IExpression/*?*/ GetFilterCondition(DecompiledBlock block) {
   Contract.Requires(block != null);
   BlockExpression result = null;
   List<IStatement> statements = null;
   foreach (var statement in block.Statements) {
     var nestedBlock = statement as DecompiledBlock;
     if (nestedBlock != null) {
       var nestedResult = this.GetFilterCondition(nestedBlock);
       if (nestedResult != null) {
         if (result == null) return nestedResult;
         result.Expression = nestedResult;
         return result;
       }
     } else {
       var endFilter = statement as EndFilter;
       if (endFilter != null) {
         if (result == null) return endFilter.FilterResult;
         result.Expression = endFilter.FilterResult;
         return result;
       }
     }
     if (statements == null) {
       statements = new List<IStatement>();
       result = new BlockExpression() { BlockStatement = new BlockStatement() { Statements = statements } };
     }
     statements.Add(statement);
   }
   if (result != null && result.Expression == CodeDummy.Expression) return null;
   return result;
 }
예제 #20
0
 /// <summary>
 /// Decompile the IL operations of this method body into a block of statements.
 /// </summary>
 protected override IBlockStatement GetBlock() {
   var block = new DecompiledBlock(0, this.ilMethodBody.Size, new Sublist<BasicBlock<Instruction>>(this.cdfg.AllBlocks, 0, this.cdfg.AllBlocks.Count), isLexicalScope: true);
   this.CreateExceptionBlocks(block);
   bool addDeclarations = true;
   if (this.localScopeProvider != null) {
     var scopes = new List<ILocalScope>(this.localScopeProvider.GetLocalScopes(this.ilMethodBody));
     if (scopes.Count > 0) {
       this.CreateLexicalScopes(block, new Sublist<ILocalScope>(scopes, 0, scopes.Count));
       addDeclarations = false;
     }
   }
   if (addDeclarations) {
     int counter = 0;
     foreach (var local in this.ilMethodBody.LocalVariables) {
       Contract.Assume(local != null);
       Contract.Assume(counter <= block.Statements.Count);
       block.Statements.Insert(counter++, new LocalDeclarationStatement() { LocalVariable = this.GetLocalWithSourceName(local) });
     }
   }
   new InstructionParser(this).Traverse(block);
   new SwitchReplacer(this).Traverse(block);
   DeleteNops(block);
   DeleteLocalAssignedLocal(block);
   new PatternReplacer(this, block).Traverse(block);
   new TryCatchReplacer(this, block).Traverse(block);
   new RemoveNonLexicalBlocks().Traverse(block);
   new DeclarationUnifier(this).Traverse(block);
   new IfThenElseReplacer(this).Traverse(block);
   if ((this.options & DecompilerOptions.Loops) != 0) {
     new WhileLoopReplacer(this).Traverse(block);
     new ForLoopReplacer(this).Traverse(block);
   }
   new UnreferencedLabelRemover(this).Traverse(block);
   new LockReplacer(this).Traverse(block);
   new BlockFlattener().Traverse(block);
   this.RemoveRedundantFinalReturn(block);
   var result = new CompilationArtifactRemover(this).Rewrite(block);
   if ((this.options & DecompilerOptions.AnonymousDelegates) != 0) {
     bool didNothing;
     result = new AnonymousDelegateInserter(this).InsertAnonymousDelegates(result, out didNothing);
     if (!didNothing) new DeclarationUnifier(this).Traverse(result);
   }
   return result;
 }
예제 #21
0
    private void CreateExceptionBlocks(DecompiledBlock block) {
      Contract.Requires(block != null);

      if (IteratorHelper.EnumerableIsEmpty(this.ilMethodBody.OperationExceptionInformation)) return;
      List<IOperationExceptionInformation> handlers = new List<IOperationExceptionInformation>(this.ilMethodBody.OperationExceptionInformation);
      handlers.Sort(CompareHandlers);
      foreach (var exInfo in handlers) {
        Contract.Assume(exInfo != null);
        this.CreateNestedBlock(block, exInfo.TryStartOffset, exInfo.TryEndOffset);
        if (exInfo.HandlerKind == HandlerKind.Filter)
          this.CreateNestedBlock(block, exInfo.FilterDecisionStartOffset, exInfo.HandlerEndOffset);
        this.CreateNestedBlock(block, exInfo.HandlerStartOffset, exInfo.HandlerEndOffset);
      }
    }
예제 #22
0
 private void Consolidate(DecompiledBlock block) {
   if (block == null) return;
   if (block.Statements.Count != 1) return;
   var nestedBlock = block.Statements[0] as DecompiledBlock;
   if (nestedBlock == null) return;
   Consolidate(nestedBlock);
   block.Statements = nestedBlock.Statements;
 }
예제 #23
0
    private bool RemoveEndFinallyFrom(DecompiledBlock block, LabeledStatement labelToGoto) {
      Contract.Requires(block != null);
      Contract.Requires(labelToGoto != null);

      for (int i = 0; i < block.Statements.Count; i++) {
        if (block.Statements[i] is EndFinally) {
          var gotoFinally = new GotoStatement() { TargetStatement = labelToGoto };
          block.Statements[i] = gotoFinally;
          var gotos = new List<IGotoStatement>(1);
          gotos.Add(gotoFinally);
          this.gotosThatTarget[(uint)labelToGoto.Label.UniqueKey] = gotos;
          return true;
        }
        var nestedBlock = block.Statements[i] as DecompiledBlock;
        if (nestedBlock != null && this.RemoveEndFinallyFrom(nestedBlock, labelToGoto)) return true;
      }
      return false;
    }
예제 #24
0
    private void SplitBlock(DecompiledBlock blockToSplit, uint splitOffset, List<IStatement> leftList, List<IStatement> rightList) {
      Contract.Requires(blockToSplit != null);
      Contract.Requires(leftList != null);
      Contract.Requires(rightList != null);
      Contract.Requires(splitOffset >= blockToSplit.StartOffset);
      Contract.Requires(splitOffset <= blockToSplit.EndOffset);

      var leftBasicBlocks = blockToSplit.GetBasicBlocksForRange(blockToSplit.StartOffset, splitOffset);
      Contract.Assume(splitOffset >= blockToSplit.StartOffset);
      var leftBlock = new DecompiledBlock(blockToSplit.StartOffset, splitOffset, leftBasicBlocks, isLexicalScope: false);
      leftList.Add(leftBlock);
      var rightBasicBlocks = blockToSplit.GetBasicBlocksForRange(splitOffset, blockToSplit.EndOffset);
      Contract.Assume(splitOffset <= blockToSplit.EndOffset);
      var rightBlock = new DecompiledBlock(splitOffset, blockToSplit.EndOffset, rightBasicBlocks, isLexicalScope: false);
      rightList.Add(rightBlock);

      var n = blockToSplit.Statements.Count;
      if (n == 0) return;
      var leftStatements = leftBlock.Statements = new List<IStatement>();
      var rightStatements = rightBlock.Statements = new List<IStatement>();
      for (int i = 0; i < n; i++) {
        var nb = blockToSplit.Statements[i] as DecompiledBlock;
        Contract.Assume(nb != null);
        if (nb.EndOffset <= splitOffset) {
          leftStatements.Add(nb);
        } else if (nb.StartOffset < splitOffset) {
          Contract.Assume(!nb.IsLexicalScope); //lexical scopes are assumed to nest cleanly.
          this.SplitBlock(nb, splitOffset, leftStatements, rightStatements);
        } else {
          rightStatements.Add(nb);
        }
      }
      Consolidate(leftBlock);
      Consolidate(rightBlock);
    }
예제 #25
0
 private void RemoveUnconditionalBranchesToLabelImmediatelyFollowing(TryCatchFinallyStatement trycf, DecompiledBlock followingBlock)
 {
     Contract.Requires(trycf != null);
     while (followingBlock != null)
     {
         if (followingBlock.Statements.Count == 0)
         {
             return;
         }
         var label = followingBlock.Statements[0] as LabeledStatement;
         if (label != null)
         {
             this.unconditionalBranchRemover.StopTraversal = false;
             this.unconditionalBranchRemover.targetLabel   = label;
             this.unconditionalBranchRemover.Traverse(trycf);
             var gotos = this.gotosThatTarget.Find((uint)label.Label.UniqueKey);
             if (gotos == null || gotos.Count == 0)
             {
                 followingBlock.Statements.RemoveAt(0);
             }
             return;
         }
         followingBlock = followingBlock.Statements[0] as DecompiledBlock;
     }
 }
예제 #26
0
    private void CreateLexicalScopes(DecompiledBlock block, Sublist<ILocalScope> scopes) {
      Contract.Requires(block != null);
      Contract.Requires(this.localScopeProvider != null);

      for (int i = 0, n = scopes.Count; i < n; ) {
        var scope = scopes[i++];
        if (scope.Length == 0) continue;
        var nestedBlock = this.CreateNestedBlock(block, scope.Offset, scope.Offset+scope.Length);
        this.AddLocalsAndConstants(nestedBlock, scope);
      }
    }
예제 #27
0
    private void AddLocalsAndConstants(DecompiledBlock block, ILocalScope scope) {
      Contract.Requires(block != null);
      Contract.Requires(scope != null);
      Contract.Requires(this.localScopeProvider != null);

      bool isLexicalScope = false;
      int counter = 0;
      foreach (var local in this.localScopeProvider.GetConstantsInScope(scope)) {
        Contract.Assume(local != null);
        var localVariable = this.GetLocalWithSourceName(local);
        Contract.Assume(counter <= block.Statements.Count);
        block.Statements.Insert(counter++, new LocalDeclarationStatement() { LocalVariable = localVariable });
      }
      foreach (var local in this.localScopeProvider.GetVariablesInScope(scope)) {
        Contract.Assume(local != null);
        var localVariable = this.GetLocalWithSourceName(local);
        Contract.Assume(counter <= block.Statements.Count);
        block.Statements.Insert(counter++, new LocalDeclarationStatement() { LocalVariable = localVariable });
      }
      if (isLexicalScope) block.IsLexicalScope = true;
    }
예제 #28
0
 private bool RemoveEndFinallyFrom(DecompiledBlock block) {
   Contract.Requires(block != null);
   Contract.Assume(block.Statements.Count > 0); //There must be an endfinally
   if (block.Statements[block.Statements.Count-1] is EndFinally) {
     block.Statements.RemoveAt(block.Statements.Count-1);
     return true;
   }
   var lastBlock = block.Statements[block.Statements.Count-1] as DecompiledBlock;
   if (lastBlock != null && this.RemoveEndFinallyFrom(lastBlock)) return true;
   LabeledStatement endFinally = new LabeledStatement() { Label = this.host.NameTable.GetNameFor("__endfinally#"+this.endFinallyCounter++), Statement = new EmptyStatement() };
   block.Statements.Add(endFinally);
   return this.RemoveEndFinallyFrom(block, endFinally);
 }
예제 #29
0
 private void RemoveLocalDeclarationOf(ILocalDefinition exceptionContainer, DecompiledBlock block) {
   Contract.Requires(exceptionContainer != null);
   Contract.Requires(block != null);
   this.localDeclarationRemover.localVariableToRemove = exceptionContainer;
   this.localDeclarationRemover.StopTraversal = false;
   this.localDeclarationRemover.Traverse(block);
 }
예제 #30
0
        private ILocalDefinition ExtractExceptionContainer(DecompiledBlock nestedBlock, ITypeReference exceptionType)
        {
            Contract.Requires(nestedBlock != null);
            Contract.Requires(exceptionType != null);
            Contract.Ensures(Contract.Result <ILocalDefinition>() != null);

            Contract.Assume(nestedBlock.Statements.Count > 0);
            int i = 0;

            while (nestedBlock.Statements[i] is LocalDeclarationStatement)
            {
                i++; Contract.Assume(i < nestedBlock.Statements.Count);
            }
            ;
            var firstStatement = nestedBlock.Statements[i++];
            var firstBlock     = firstStatement as DecompiledBlock;

            while (firstBlock != null)
            {
                Contract.Assume(firstBlock.Statements.Count > 0);
                i = 0;
                while (firstBlock.Statements[i] is LocalDeclarationStatement)
                {
                    i++; Contract.Assume(i < firstBlock.Statements.Count);
                }
                ;
                firstStatement = firstBlock.Statements[i++];
                nestedBlock    = firstBlock;
                firstBlock     = firstStatement as DecompiledBlock;
            }
            //Ignoring any local declarations inserted for lexical scopes, any decompiled block that does not start with a nested block, starts with a label.
            Contract.Assume(firstStatement is LabeledStatement);
            if (nestedBlock.Statements.Count > i)
            {
                var exprStatement = nestedBlock.Statements[i] as ExpressionStatement;
                if (exprStatement != null)
                {
                    nestedBlock.Statements.RemoveRange(i - 1, 2);
                    if (exprStatement.Expression is PopValue)
                    {
                        return(Dummy.LocalVariable);
                    }
                    var assignment = exprStatement.Expression as Assignment;
                    if (assignment != null && assignment.Source is PopValue)
                    {
                        var local = assignment.Target.Definition as ILocalDefinition;
                        if (local != null)
                        {
                            return(local);   //if not, this is not a recognized code pattern.
                        }
                    }
                }
                // can't find the local, so just introduce one and leave its value on the stack
                var ld = new LocalDefinition()
                {
                    Type = exceptionType,
                };
                var pushStatement = new PushStatement()
                {
                    ValueToPush = new BoundExpression()
                    {
                        Definition = ld,
                        Type       = exceptionType,
                    },
                };
                nestedBlock.Statements.Insert(0, pushStatement);
                return(ld);
            }
            else
            {
                //Valid IL should always have at least one instruction to consume the exception value as well as a branch out of the handler block.
                Contract.Assume(false);
                return(Dummy.LocalVariable);
            }
        }
예제 #31
0
 private void RemoveUnconditionalBranchesToLabelImmediatelyFollowing(TryCatchFinallyStatement trycf, DecompiledBlock followingBlock) {
   Contract.Requires(trycf != null);
   while (followingBlock != null) {
     if (followingBlock.Statements.Count == 0) return;
     var label = followingBlock.Statements[0] as LabeledStatement;
     if (label != null) {
       this.unconditionalBranchRemover.StopTraversal = false;
       this.unconditionalBranchRemover.targetLabel = label;
       this.unconditionalBranchRemover.Traverse(trycf);
       var gotos = this.gotosThatTarget.Find((uint)label.Label.UniqueKey);
       if (gotos == null || gotos.Count == 0) {
         followingBlock.Statements.RemoveAt(0);
       }
       return;
     }
     followingBlock = followingBlock.Statements[0] as DecompiledBlock;
   }
 }
예제 #32
0
    private DecompiledBlock CreateNestedBlock(DecompiledBlock block, uint startOffset, uint endOffset) {
      Contract.Requires(block != null);
      Contract.Requires(startOffset <= endOffset);
      Contract.Ensures(Contract.Result<DecompiledBlock>() != null);

      {
      nextBlock:
        foreach (var statement in block.Statements) {
          var nestedBlock = statement as DecompiledBlock;
          if (nestedBlock == null) continue;
          if (nestedBlock.StartOffset <= startOffset && nestedBlock.EndOffset >= endOffset) {
            block = nestedBlock;
            goto nextBlock;
          }
        }
      }
      if (block.StartOffset == startOffset && block.EndOffset == endOffset) return block;
      //replace block.Statements with three nested blocks, the middle one corresponding to one we have to create
      //but keep any declarations.
      int n = block.Statements.Count;
      var oldStatements = block.Statements;
      var newStatements = block.Statements;
      int m = 0;
      if (n >= 0) {
        while (m < n && oldStatements[m] is LocalDeclarationStatement) m++;
        if (m < n) {
          newStatements = new List<IStatement>(m+3);
          for (int i = 0; i < m; i++) newStatements.Add(oldStatements[i]);
        }
      }
      block.Statements = newStatements;
      var basicBlocks = block.GetBasicBlocksForRange(startOffset, endOffset);
      var newNestedBlock = new DecompiledBlock(startOffset, endOffset, basicBlocks, isLexicalScope: true);
      DecompiledBlock beforeBlock = null;
      if (block.StartOffset < startOffset) {
        var basicBlocksBefore = block.GetBasicBlocksForRange(block.StartOffset, startOffset);
        Contract.Assume(block.StartOffset < startOffset);
        beforeBlock = new DecompiledBlock(block.StartOffset, startOffset, basicBlocksBefore, isLexicalScope: false);
        newStatements.Add(beforeBlock);
      }
      newStatements.Add(newNestedBlock);
      DecompiledBlock afterBlock = null;
      if (block.EndOffset > endOffset) {
        var basicBlocksAfter = block.GetBasicBlocksForRange(endOffset, block.EndOffset);
        Contract.Assume(block.EndOffset > endOffset);
        afterBlock = new DecompiledBlock(endOffset, block.EndOffset, basicBlocksAfter, isLexicalScope: false);
        newStatements.Add(afterBlock);
      }
      if (newStatements != oldStatements) {
        //In this case there were already some nested blocks, which happens when there are nested exception blocks
        //and we are creating an enclosing lexical block that does not quite coincide with block.
        //We now have to populate the newly created blocks with these nested blocks, splitting them if necessary.
        for (int i = m; i < n; i++) {
          var nb = oldStatements[i] as DecompiledBlock;
          Contract.Assume(nb != null);
          if (nb.EndOffset <= startOffset) {
            Contract.Assume(beforeBlock != null);
            beforeBlock.Statements.Add(nb);
          } else if (nb.StartOffset < startOffset) {
            Contract.Assume(nb.EndOffset <= endOffset);  //nb starts before newNestedBlock but ends inside it.
            Contract.Assume(beforeBlock != null);
            if (nb.IsLexicalScope) {
              //Lexical scopes are assumed to nest cleanly. But the C# is not playing along when one using statement immediately follows another
              //Well fix matters by making nb.EndOffset == startOffset
              nb.EndOffset = startOffset;
              beforeBlock.Statements.Add(nb);
            } else 
              this.SplitBlock(nb, startOffset, beforeBlock.Statements, newNestedBlock.Statements);
          } else if (nb.EndOffset <= endOffset) {
            newNestedBlock.Statements.Add(nb);
          } else if (nb.StartOffset < endOffset) {
            Contract.Assert(nb.EndOffset > endOffset); //nb starts inside newNestedBlock but ends after it.
            Contract.Assume(!nb.IsLexicalScope); //lexical scopes are assumed to nest cleanly.
            Contract.Assume(afterBlock != null);
            this.SplitBlock(nb, endOffset, newNestedBlock.Statements, afterBlock.Statements);
          } else {
            Contract.Assume(afterBlock != null);
            afterBlock.Statements.Add(nb);
          }
        }
        //consolidate blocks consisting of a single block
        Consolidate(beforeBlock);
        Consolidate(newNestedBlock);
        Consolidate(afterBlock);
      }
      return newNestedBlock;
    }
예제 #33
0
 private static void ConsolidateScopes(DecompiledBlock cb) {
   Contract.Requires(cb != null);
   for (int i = 0; i < cb.Statements.Count; i++) {
     var nb = cb.Statements[i] as DecompiledBlock;
     if (nb == null) break;
     if (nb.Statements.Count == 0) cb.Statements.RemoveAt(i--);
   }
   if (cb.Statements.Count == 1) {
     var nb = cb.Statements[0] as DecompiledBlock;
     if (nb != null) cb.Statements = nb.Statements;
   }
 }
예제 #34
0
 private void RemoveRedundantFinalReturn(DecompiledBlock block) {
   Contract.Requires(block != null);
   var n = block.Statements.Count;
   if (n > 0) {
     var returnStatement = block.Statements[n-1] as ReturnStatement;
     if (returnStatement == null) return;
     if (this.ilMethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void) {
       var boundExpression = returnStatement.Expression as IBoundExpression;
       if (boundExpression == null) return;
       var local = boundExpression.Definition as ILocalDefinition;
       if (local == null) return;
       if (this.numberOfAssignmentsToLocal[local] > 0) return;
       this.numberOfReferencesToLocal[local]--;
       if (this.numberOfReferencesToLocal[local] == 0 && this.numberOfAssignmentsToLocal[local] == 0) {
         for (int j = 0; j < n-1; j++) {
           var locDecl = block.Statements[j] as ILocalDeclarationStatement;
           if (locDecl != null && locDecl.LocalVariable == local) {
             block.Statements.RemoveAt(j);
             n--;
             break;
           }
         }
       }
     }
     block.Statements.RemoveAt(n-1);
   }
 }