/// <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); }
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); }
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); } } }
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; } }
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); } }
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); }
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); }
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); }
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); } }
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); } }
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; }
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); }
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)); }
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; } } }
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); }
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; } }
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; }
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; }
/// <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; }
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); } }
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; }
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; }
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); }
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; } }
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); } }
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; }
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); }
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); } }
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; } }
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; }
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; } }
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); } }