// copies recursively the next basic block of the method CFG (with a switch branch as entry branch)
        private void copyMethodCfgRecursively(List<BasicBlock> processedBasicBlocks, BasicBlock sourceBasicBlock, ref BasicBlock targetBasicBlock, SwitchBranchTarget copiedEntryBranch, int takenEntryBranchIdx) {

            // check if source basic block was already processed
            if (processedBasicBlocks.Contains(sourceBasicBlock)) {

                bool found = false;
                foreach (BasicBlock searchBasicBlock in this.basicBlocks) {
                    if (searchBasicBlock.id == sourceBasicBlock.id) {

                        // set entry branch target
                        if (takenEntryBranchIdx == -1) {
                            copiedEntryBranch.notTakenTarget = searchBasicBlock;

                        }
                        else {

                            // fill switch taken branch list with empty elements when index is out of range
                            while (copiedEntryBranch.takenTarget.Count() <= takenEntryBranchIdx) {
                                copiedEntryBranch.takenTarget.Add(null);
                            }

                            copiedEntryBranch.takenTarget[takenEntryBranchIdx] = searchBasicBlock;
                        }

                        searchBasicBlock.entryBranches.Add(copiedEntryBranch);
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    throw new ArgumentException("Copied basic block was not found.");
                }

                return;
            }

            // add source basic block to the list of already processed basic blocks
            processedBasicBlocks.Add(sourceBasicBlock);

            // create copy of the source basic block
            targetBasicBlock = new BasicBlock();
            this.basicBlocks.Add(targetBasicBlock);

            // set entry branch target
            if (takenEntryBranchIdx == -1) {
                copiedEntryBranch.notTakenTarget = targetBasicBlock;

            }
            else {

                // fill switch taken branch list with empty elements when index is out of range
                while (copiedEntryBranch.takenTarget.Count() <= takenEntryBranchIdx) {
                    copiedEntryBranch.takenTarget.Add(null);
                }

                copiedEntryBranch.takenTarget[takenEntryBranchIdx] = targetBasicBlock;
            }
            targetBasicBlock.entryBranches.Add(copiedEntryBranch);

            // copy simple values
            targetBasicBlock.id = sourceBasicBlock.id;
            targetBasicBlock.semanticId = sourceBasicBlock.semanticId;
            targetBasicBlock.startIdx = sourceBasicBlock.startIdx;
            targetBasicBlock.endIdx = sourceBasicBlock.endIdx;

            // copy all operations of the basic block
            foreach (IOperation operation in sourceBasicBlock.operations) {
                InternalOperation copiedOperation = new InternalOperation();
                copiedOperation.OperationCode = operation.OperationCode;
                copiedOperation.Value = operation.Value;
                copiedOperation.Offset = operation.Offset;
                copiedOperation.Location = operation.Location;
                targetBasicBlock.operations.Add(copiedOperation);
            }


            // process rest of the cfg and copy the exit branch
            if ((sourceBasicBlock.exitBranch as NoBranchTarget) != null) {
                NoBranchTarget exitBranch = (sourceBasicBlock.exitBranch as NoBranchTarget);

                // create a copied exit branch
                NoBranchTarget copiedExitBranch = new NoBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceBasicBlock.exitBranch as UnconditionalBranchTarget != null) {
                UnconditionalBranchTarget exitBranch = (sourceBasicBlock.exitBranch as UnconditionalBranchTarget);

                // create a copied exit branch
                UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                ConditionalBranchTarget exitBranch = (sourceBasicBlock.exitBranch as ConditionalBranchTarget);

                // create a copied exit branch
                ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else if (sourceBasicBlock.exitBranch as SwitchBranchTarget != null) {
                SwitchBranchTarget exitBranch = (sourceBasicBlock.exitBranch as SwitchBranchTarget);

                // create a copied exit branch
                SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // first process not taken branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1);

                // process all taken branches and next basic blocks
                for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) {
                    nextCopiedBasicBlock = null;
                    this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx);
                }

            }

            else if (sourceBasicBlock.exitBranch as ExitBranchTarget != null) {

                // create a copied exit branch
                ExitBranchTarget copiedExitBranch = new ExitBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceBasicBlock.exitBranch as ThrowBranchTarget != null) {

                // create a copied exit branch
                ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceBasicBlock.exitBranch as TryBlockTarget != null) {
                TryBlockTarget exitBranch = (sourceBasicBlock.exitBranch as TryBlockTarget);

                // create a copied exit branch
                TryBlockTarget copiedExitBranch = new TryBlockTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                ExceptionBranchTarget exitBranch = (sourceBasicBlock.exitBranch as ExceptionBranchTarget);

                // create a copied exit branch
                ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget();
                copiedExitBranch.sourceBasicBlock = targetBasicBlock;
                targetBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else {
                throw new ArgumentException("Do not know how to handle exit branch.");
            }


            // copy all try blocks
            foreach (TryBlock sourceTryBlock in sourceBasicBlock.tryBlocks) {

                TryBlock copiedTryBlock = new TryBlock();
                copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler;
                copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock;
                copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock;

                targetBasicBlock.tryBlocks.Add(copiedTryBlock);
            }


            // copy all handler blocks
            foreach (HandlerBlock sourceHandlerBlock in sourceBasicBlock.handlerBlocks) {

                HandlerBlock copiedHandlerBlock = new HandlerBlock();
                copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler;
                copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler;
                copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock;
                copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock;

                targetBasicBlock.handlerBlocks.Add(copiedHandlerBlock);
            }

        }
Exemple #2
0
        // builds a CFG for the given method and returns it
        public MethodCfg buildCfgForMethod(MethodDefinition method) {

            MethodCfg methodCfg = new MethodCfg();
            methodCfg.method = method;

            // start building the cfg
            BasicBlock firstBasicBlock = new BasicBlock(this.semanticId);
            this.semanticId++;
            methodCfg.startBasicBlock = firstBasicBlock;
            this.buildRecursivelyCfg(methodCfg, method.Body.Operations, 0, null, ref firstBasicBlock);

            // add exception handler to the cfg
            foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) {

                // debugging variables to throw an exception if start/end of try/handler block was not found
                bool tryStartFound = false;
                bool tryEndFound = false;
                bool handlerStartFound = false;
                bool handlerEndFound = false;

                // search each basic block if they reside in an exception handler
                List<BasicBlock> localCopy = new List<BasicBlock>();
                localCopy.AddRange(methodCfg.basicBlocks);
                for (int bbIdx = 0; bbIdx < localCopy.Count(); bbIdx++) {
                    BasicBlock basicBlock = localCopy.ElementAt(bbIdx);
                    int lastOperationIdx = basicBlock.operations.Count() - 1;

                    // ignore basic block if the start of the try block lies behind the current basic block
                    // (catch or finally blocks can never lie before a try block)
                    if (basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.TryStartOffset) {
                        continue;
                    }

                    // check if the current basic block resides in the try block of the exception handler
                    else if ((exceptionHandler.TryStartOffset >= basicBlock.operations.ElementAt(0).Offset && exceptionHandler.TryStartOffset <= basicBlock.operations.ElementAt(lastOperationIdx).Offset)
                        || (exceptionHandler.TryStartOffset <= basicBlock.operations.ElementAt(0).Offset && basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.TryEndOffset)) {

                        TryBlock tempTryBlock = new TryBlock();
                        tempTryBlock.exceptionHandler = exceptionHandler;

                        // check if the try block starts inside this basic block
                        if (exceptionHandler.TryStartOffset >= basicBlock.operations.ElementAt(0).Offset) {

                            // find the index of the operation that starts the try block
                            bool foundIdx = false;
                            for (int idx = 0; idx < basicBlock.operations.Count(); idx++) {
                                if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.TryStartOffset) {
                                    
                                    // if the try block does not start at the beginning of the current basic block
                                    // => split basic block and let the try block begin at the second half of the basic block
                                    if (idx != 0) {

                                        // create new basic block which will be the second half of the found one
                                        BasicBlock newBasicBlock = new BasicBlock(this.semanticId);
                                        this.semanticId++;
                                        newBasicBlock.startIdx = basicBlock.startIdx + idx;
                                        newBasicBlock.endIdx = basicBlock.endIdx;
                                        basicBlock.endIdx = basicBlock.startIdx + idx - 1;

                                        // move the exit basic blocks to the new created basic block
                                        // and make the new created basic block the exit of the splitted one   
                                        newBasicBlock.exitBranch = basicBlock.exitBranch;
                                        newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock;
                                        TryBlockTarget tempExitBranch = new TryBlockTarget();
                                        tempExitBranch.takenTarget = newBasicBlock;
                                        tempExitBranch.sourceBasicBlock = basicBlock;
                                        basicBlock.exitBranch = tempExitBranch;

                                        // add splitted basic block branch to the entry of the new one
                                        newBasicBlock.entryBranches.Add(tempExitBranch);

                                        // distribute the instructions to the basic blocks 
                                        List<IOperation> previousOperations = new List<IOperation>();
                                        List<IOperation> nextOperations = new List<IOperation>();
                                        for (int operationIdx = 0; (operationIdx + basicBlock.startIdx) <= newBasicBlock.endIdx; operationIdx++) {

                                            if ((operationIdx + basicBlock.startIdx) < newBasicBlock.startIdx) {
                                                previousOperations.Add(basicBlock.operations.ElementAt(operationIdx));
                                            }
                                            else {
                                                nextOperations.Add(basicBlock.operations.ElementAt(operationIdx));
                                            }
                                        }
                                        basicBlock.operations = previousOperations;
                                        newBasicBlock.operations = nextOperations;

                                        // add new basic block to the cfg
                                        methodCfg.basicBlocks.Add(newBasicBlock);

                                        // add try block to the new created basic block (it is the start of the try block)
                                        newBasicBlock.tryBlocks.Add(tempTryBlock);

                                        // try block can not end at the first part of the splitted basic block
                                        // (because it starts at the second one), but it can end at the
                                        // second part of the splitted basic block
                                        basicBlock = newBasicBlock;
                                        lastOperationIdx = newBasicBlock.operations.Count() - 1;
                                    }

                                    // the try block starts at the beginning of the current basic block => add the try block
                                    else {
                                        basicBlock.tryBlocks.Add(tempTryBlock);
                                    }
                                    
                                    // mark try block as the beginning of the try block
                                    tempTryBlock.firstBasicBlockOfTryBlock = true;
                                    foundIdx = true;
                                    tryStartFound = true;
                                    break;
                                }
                            }
                            if (!foundIdx) {
                                throw new ArgumentException("Did not find index of operation that starts Try block.");
                            }
                        }
                        else {
                            basicBlock.tryBlocks.Add(tempTryBlock);
                            tempTryBlock.firstBasicBlockOfTryBlock = false;
                        }

                        // check if the try block ends at the end of this basic block (try blocks always end at the end of a basic block)
                        if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.TryEndOffset) {
                            tempTryBlock.lastBasicBlockOfTryBlock = true;
                            tryEndFound = true;
                        }
                        else {
                            tempTryBlock.lastBasicBlockOfTryBlock = false;
                        }

                        continue;
                    }

                    // check if the current basic block resides in the handler block of the exception handler
                    else if ((exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset && exceptionHandler.HandlerStartOffset <= basicBlock.operations.ElementAt(lastOperationIdx).Offset)
                        || (exceptionHandler.HandlerStartOffset <= basicBlock.operations.ElementAt(0).Offset && basicBlock.operations.ElementAt(lastOperationIdx).Offset < exceptionHandler.HandlerEndOffset)) {

                        // check if the handler block is a catch block
                        if (exceptionHandler.HandlerKind == HandlerKind.Catch) {
                            HandlerBlock tempCatchBock = new HandlerBlock();
                            tempCatchBock.typeOfHandler = HandlerKind.Catch;
                            tempCatchBock.exceptionHandler = exceptionHandler;
                            basicBlock.handlerBlocks.Add(tempCatchBock);

                            // check if the catch block starts inside this basic block
                            if (exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset) {

                                // find the index of the operation that starts the catch block
                                bool foundIdx = false;
                                for (int idx = 0; idx < basicBlock.operations.Count(); idx++) {
                                    if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.HandlerStartOffset) {
                                        tempCatchBock.firstBasicBlockOfHandlerBlock = true;
                                        foundIdx = true;
                                        handlerStartFound = true;
                                        break;
                                    }
                                }
                                if (!foundIdx) {
                                    throw new ArgumentException("Did not find index of operation that starts Catch block.");
                                }
                            }
                            else {
                                tempCatchBock.firstBasicBlockOfHandlerBlock = false;
                            }

                            // check if the catch block ends inside this basic block
                            if (basicBlock.operations[0].Offset < exceptionHandler.HandlerEndOffset
                                && exceptionHandler.HandlerEndOffset <= (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)))) {

                                // check if the catch block ends at the last instruction of this basic block (this happens usually => optimization)
                                if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.HandlerEndOffset) {
                                    tempCatchBock.lastBasicBlockOfHandlerBlock = true;
                                    handlerEndFound = true;
                                    continue;
                                }
                                else {
                                    throw new ArgumentException("Did not find the operation that ends Catch block.");
                                }
                            }
                            else {
                                tempCatchBock.lastBasicBlockOfHandlerBlock = false;
                            }

                            continue;
                        }

                            // check if the handler block is a finally block
                        else if (exceptionHandler.HandlerKind == HandlerKind.Finally) {
                            HandlerBlock tempFinallyBock = new HandlerBlock();
                            tempFinallyBock.typeOfHandler = HandlerKind.Finally;
                            tempFinallyBock.exceptionHandler = exceptionHandler;
                            basicBlock.handlerBlocks.Add(tempFinallyBock);

                            // check if the finally block starts inside this basic block
                            if (exceptionHandler.HandlerStartOffset >= basicBlock.operations.ElementAt(0).Offset) {

                                // find the index of the operation that starts the finally block
                                bool foundIdx = false;
                                for (int idx = 0; idx < basicBlock.operations.Count(); idx++) {
                                    if (basicBlock.operations.ElementAt(idx).Offset == exceptionHandler.HandlerStartOffset) {
                                        tempFinallyBock.firstBasicBlockOfHandlerBlock = true;
                                        foundIdx = true;
                                        handlerStartFound = true;
                                        break;
                                    }
                                }
                                if (!foundIdx) {
                                    throw new ArgumentException("Did not find index of operation that starts Finally block.");
                                }
                            }
                            else {
                                tempFinallyBock.firstBasicBlockOfHandlerBlock = false;
                            }

                            // check if the finally block ends inside this basic block
                            if (basicBlock.operations[0].Offset < exceptionHandler.HandlerEndOffset
                                && exceptionHandler.HandlerEndOffset <= (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)))) {

                                // check if the finally block ends at the last instruction of this basic block
                                if (basicBlock.operations.ElementAt(lastOperationIdx).Offset + CfgBuilder.getSizeOfOperation(basicBlock.operations.ElementAt(lastOperationIdx)) == exceptionHandler.HandlerEndOffset) {
                                    tempFinallyBock.lastBasicBlockOfHandlerBlock = true;
                                    handlerEndFound = true;
                                    continue;
                                }
                                else {
                                    throw new ArgumentException("Did not find the operation that ends Finally block.");
                                }
                            }

                            continue;
                        }

                        else {
                            throw new ArgumentException("Do not know how to handle exception handler.");
                        }
                    }
                }

                // check if start/end of try/handler block was found
                if(!tryStartFound
                    || !tryEndFound
                    || !handlerStartFound
                    || !handlerEndFound) {
                    throw new ArgumentException("Was not able to find start/end of try/handler block.");
                }

            }



            // TODO
            // DEBUG
            //this.logger.dumpMethodCfg(methodCfg, this.logger.sanitizeString(methodCfg.method.ToString()));

            return methodCfg;
        }
        // this constructor copies the given source method cfg and all its elements
        // NOTE: it ignores the transformation metadata
        public MethodCfg(MethodCfg sourceMethodCfg) {

            // copy link to the method
            this.method = sourceMethodCfg.method;

            // generate a list of already processed basic blocks
            List<BasicBlock> processedBasicBlocks = new List<BasicBlock>();

            // set start basic block of the CFG as already processed
            processedBasicBlocks.Add(sourceMethodCfg.startBasicBlock);

            // create copy of start basic block
            BasicBlock copiedStartBasicBlock = new BasicBlock();
            this.startBasicBlock = copiedStartBasicBlock;
            this.basicBlocks.Add(copiedStartBasicBlock);

            // copy simple values
            copiedStartBasicBlock.id = sourceMethodCfg.startBasicBlock.id;
            copiedStartBasicBlock.semanticId = sourceMethodCfg.startBasicBlock.semanticId;
            copiedStartBasicBlock.startIdx = sourceMethodCfg.startBasicBlock.startIdx;
            copiedStartBasicBlock.endIdx = sourceMethodCfg.startBasicBlock.endIdx;

            // copy all operations of the basic block
            foreach (IOperation operation in sourceMethodCfg.startBasicBlock.operations) {
                InternalOperation copiedOperation = new InternalOperation();
                copiedOperation.OperationCode = operation.OperationCode;
                copiedOperation.Value = operation.Value;
                copiedOperation.Offset = operation.Offset;
                copiedOperation.Location = operation.Location;
                copiedStartBasicBlock.operations.Add(copiedOperation);
            }


            // process rest of the cfg and copy the exit branch
            if ((sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget) != null) {
                NoBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as NoBranchTarget);

                // create a copied exit branch
                NoBranchTarget copiedExitBranch = new NoBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget != null) {
                UnconditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as UnconditionalBranchTarget);

                // create a copied exit branch
                UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                ConditionalBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ConditionalBranchTarget);

                // create a copied exit branch
                ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget != null) {
                SwitchBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as SwitchBranchTarget);

                // create a copied exit branch
                SwitchBranchTarget copiedExitBranch = new SwitchBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // first process not taken branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.notTakenTarget, ref nextCopiedBasicBlock, copiedExitBranch, -1);

                // process all taken branches and next basic blocks
                for (int idx = 0; idx < exitBranch.takenTarget.Count(); idx++) {
                    nextCopiedBasicBlock = null;
                    this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget.ElementAt(idx), ref nextCopiedBasicBlock, copiedExitBranch, idx);
                }

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ExitBranchTarget != null) {

                // create a copied exit branch
                ExitBranchTarget copiedExitBranch = new ExitBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ThrowBranchTarget != null) {

                // create a copied exit branch
                ThrowBranchTarget copiedExitBranch = new ThrowBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget != null) {
                TryBlockTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as TryBlockTarget);

                // create a copied exit branch
                TryBlockTarget copiedExitBranch = new TryBlockTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.takenTarget, ref nextCopiedBasicBlock, copiedExitBranch);

            }

            else if (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                ExceptionBranchTarget exitBranch = (sourceMethodCfg.startBasicBlock.exitBranch as ExceptionBranchTarget);

                // create a copied exit branch
                ExceptionBranchTarget copiedExitBranch = new ExceptionBranchTarget();
                copiedExitBranch.sourceBasicBlock = copiedStartBasicBlock;
                copiedStartBasicBlock.exitBranch = copiedExitBranch;

                // process branch and next basic block
                BasicBlock nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exceptionTarget, ref nextCopiedBasicBlock, copiedExitBranch, true);

                // process branch and next basic block
                nextCopiedBasicBlock = null;
                this.copyMethodCfgRecursively(processedBasicBlocks, exitBranch.exitTarget, ref nextCopiedBasicBlock, copiedExitBranch, false);

            }

            else {
                throw new ArgumentException("Do not know how to handle exit branch.");
            }


            // copy all try blocks
            foreach (TryBlock sourceTryBlock in sourceMethodCfg.startBasicBlock.tryBlocks) {

                TryBlock copiedTryBlock = new TryBlock();
                copiedTryBlock.exceptionHandler = sourceTryBlock.exceptionHandler;
                copiedTryBlock.firstBasicBlockOfTryBlock = sourceTryBlock.firstBasicBlockOfTryBlock;
                copiedTryBlock.lastBasicBlockOfTryBlock = sourceTryBlock.lastBasicBlockOfTryBlock;

                copiedStartBasicBlock.tryBlocks.Add(copiedTryBlock);
            }


            // copy all handler blocks
            foreach (HandlerBlock sourceHandlerBlock in sourceMethodCfg.startBasicBlock.handlerBlocks) {

                HandlerBlock copiedHandlerBlock = new HandlerBlock();
                copiedHandlerBlock.exceptionHandler = sourceHandlerBlock.exceptionHandler;
                copiedHandlerBlock.typeOfHandler = sourceHandlerBlock.typeOfHandler;
                copiedHandlerBlock.firstBasicBlockOfHandlerBlock = sourceHandlerBlock.firstBasicBlockOfHandlerBlock;
                copiedHandlerBlock.lastBasicBlockOfHandlerBlock = sourceHandlerBlock.lastBasicBlockOfHandlerBlock;

                copiedStartBasicBlock.handlerBlocks.Add(copiedHandlerBlock);
            }

        }