Example #1
0
        // 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);
            }

        }
Example #2
0
        // build recursively the cfg of the given operations
        private void buildRecursivelyCfg(MethodCfg methodCfg, IEnumerable<IOperation> operations, int currentIdx, IBranchTarget entryBranch, ref BasicBlock currentBasicBlock) {

            // check if a new basic block has to be created
            for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) {

                // check if the current index points into an existing basic block
                // => split basic block
                BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx);
                if (tempBB.startIdx < currentIdx && tempBB.endIdx >= currentIdx) {

                    // create new basic block which will be the second half of the found one
                    BasicBlock newBasicBlock = new BasicBlock(this.semanticId);
                    this.semanticId++;
                    newBasicBlock.startIdx = currentIdx;
                    newBasicBlock.endIdx = tempBB.endIdx;
                    tempBB.endIdx = currentIdx - 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 = tempBB.exitBranch;
                    newBasicBlock.exitBranch.sourceBasicBlock = newBasicBlock;
                    NoBranchTarget tempExitBranch = new NoBranchTarget();
                    tempExitBranch.takenTarget = newBasicBlock;
                    tempExitBranch.sourceBasicBlock = tempBB;
                    tempBB.exitBranch = tempExitBranch;

                    // set the current basic block to the new created basic block
                    currentBasicBlock = newBasicBlock;

                    // add splitted basic block branch and basic block branch that leads to this split
                    // to the entries of the new one
                    newBasicBlock.entryBranches.Add(entryBranch);
                    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 + tempBB.startIdx) <= newBasicBlock.endIdx; operationIdx++) {

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

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

                    return;
                }

                // if the current index of the operation points to the start index of an existing basic block
                // => update entry branches
                else if (tempBB.startIdx == currentIdx && entryBranch != null && currentBasicBlock != null) {
                    tempBB.entryBranches.Add(entryBranch);

                    // set the found basic block as the current basic block
                    currentBasicBlock = tempBB;
                    return;
                }

                // if the current index of the operation points to the start index of an existing basic block, has no entry branch
                // and is not the first instruction
                // set the current basic block to the found one
                else if (currentIdx != 0 && tempBB.startIdx == currentIdx && currentBasicBlock != null) {

                    // set the found basic block as the current basic block
                    currentBasicBlock = tempBB;
                    return;

                }

            }

            // set index of current basic block and add it to the cfg
            currentBasicBlock.startIdx = currentIdx;
            methodCfg.basicBlocks.Add(currentBasicBlock);

            // check if the basic block was jumped to from another basic block
            // => update entry branches
            if (entryBranch != null) {
                currentBasicBlock.entryBranches.Add(entryBranch);
            }

            // parse every instruction to find branches etc
            for (int idx = currentIdx; idx < operations.Count(); idx++) {

                // check if the current instruction is the start instruction of an already existing basic block (except the current basic block)
                // => add the current basic block to the list of entry basic blocks, the found basic block to the list of exit basic blocks and set the index
                for (int bbIdx = 0; bbIdx < methodCfg.basicBlocks.Count(); bbIdx++) {
                    BasicBlock tempBB = methodCfg.basicBlocks.ElementAt(bbIdx);
                    if (tempBB.startIdx == idx && tempBB != currentBasicBlock) {
                        currentBasicBlock.endIdx = idx - 1;

                        // create new exit branch and add it
                        NoBranchTarget currentExitBranch = new NoBranchTarget();
                        currentExitBranch.sourceBasicBlock = currentBasicBlock;
                        currentExitBranch.takenTarget = tempBB;
                        currentBasicBlock.exitBranch = currentExitBranch;

                        // add current exit branch as entry for the found one
                        tempBB.entryBranches.Add(currentExitBranch);
                        return;
                    }
                }

                // add current instruction to the basic block
                var operation = operations.ElementAt(idx);
                currentBasicBlock.operations.Add(operation);

                // check for special instructions like branches
                switch (operation.OperationCode) {

                    // conditional branch instructions
                    case OperationCode.Beq:
                    case OperationCode.Bge:
                    case OperationCode.Bge_Un:
                    case OperationCode.Bgt:
                    case OperationCode.Bgt_Un:
                    case OperationCode.Ble:
                    case OperationCode.Ble_Un:
                    case OperationCode.Blt:
                    case OperationCode.Blt_Un:
                    case OperationCode.Bne_Un:
                    case OperationCode.Brfalse:
                    case OperationCode.Brtrue:
                    case OperationCode.Beq_S:
                    case OperationCode.Bge_S:
                    case OperationCode.Bge_Un_S:
                    case OperationCode.Bgt_S:
                    case OperationCode.Bgt_Un_S:
                    case OperationCode.Ble_S:
                    case OperationCode.Ble_Un_S:
                    case OperationCode.Blt_S:
                    case OperationCode.Blt_Un_S:
                    case OperationCode.Bne_Un_S:
                    case OperationCode.Brfalse_S:
                    case OperationCode.Brtrue_S: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // calculate the target index of the branch
                            int branchTargetIdx = 0;
                            uint branchTargetOffset;

                            // do operation value can be of type long which can not be casted in this way
                            if (operation.Value is long) {
                                branchTargetOffset = Convert.ToUInt32(operation.Value);
                            }
                            else {
                                branchTargetOffset = (uint)operation.Value;
                            }

                            while (true) {
                                if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                    break;
                                }
                                else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                    throw new ArgumentException("Could not find target off branch.");
                                }
                                branchTargetIdx++;
                            }

                            // create new exit branch object
                            ConditionalBranchTarget currentExitBranch = new ConditionalBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentExitBranch.takenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start two new basic blocks from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget);
                            this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget);
                            return;
                        }

                    // unconditional branch instructions
                    case OperationCode.Br:
                    case OperationCode.Br_S: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // calculate the target index of the branch
                            int branchTargetIdx = 0;
                            uint branchTargetOffset = (uint)operation.Value;
                            while (true) {
                                if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                    break;
                                }
                                else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                    throw new ArgumentException("Could not find target off branch.");
                                }
                                branchTargetIdx++;
                            }

                            // create new exit branch object
                            UnconditionalBranchTarget currentExitBranch = new UnconditionalBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.takenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start one new basic block from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.takenTarget);
                            return;
                        }

                    // exit operation
                    case OperationCode.Ret: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            ExitBranchTarget currentExitBranch = new ExitBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // end current execution
                            return;
                        }

                    // operations that exit the current function/control flow
                    case OperationCode.Throw: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            ThrowBranchTarget currentExitBranch = new ThrowBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start a new basic block if this was not the last instruction of the method
                            // (needed because some control flows that are reached via throw are not found without it) 
                            if ((idx + 1) < operations.Count()) {
                                BasicBlock newStartBasicBlock = new BasicBlock(this.semanticId);
                                this.semanticId++;
                                this.buildRecursivelyCfg(methodCfg, operations, idx + 1, null, ref newStartBasicBlock);
                            }

                            // end current execution
                            return;
                        }

                    // switch instruction (has a variable set of jump targets)
                    case OperationCode.Switch: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            SwitchBranchTarget currentExitBranch = new SwitchBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.notTakenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // calculate the target index of all switch branches
                            int counter = 0;
                            foreach (uint branchTargetOffset in (uint[])operation.Value) {
                                int branchTargetIdx = 0;
                                while (true) {
                                    if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                        break;
                                    }
                                    else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                        throw new ArgumentException("Could not find target off branch.");
                                    }
                                    branchTargetIdx++;
                                }

                                // start a new basic block from this branch on
                                BasicBlock tempNextBasicBlock = new BasicBlock(this.semanticId);
                                this.semanticId++;
                                this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref tempNextBasicBlock);

                                // add new basic block to branch targets
                                currentExitBranch.takenTarget.Add(tempNextBasicBlock);

                                counter++;
                            }

                            // start a new basic block directly after the switch instruction and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.notTakenTarget);

                            return;
                        }

                    // exception handler beginning or end (end of try block or catch block)
                    case OperationCode.Leave:
                    case OperationCode.Leave_S: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // calculate the target index of the branch
                            int branchTargetIdx = 0;
                            uint branchTargetOffset = (uint)operation.Value;
                            while (true) {
                                if (operations.ElementAt(branchTargetIdx).Offset == branchTargetOffset) {
                                    break;
                                }
                                else if (operations.ElementAt(branchTargetIdx).Offset > branchTargetOffset) {
                                    throw new ArgumentException("Could not find target off branch.");
                                }
                                branchTargetIdx++;
                            }

                            // create new exit branch object
                            ExceptionBranchTarget currentExitBranch = new ExceptionBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.exceptionTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentExitBranch.exitTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start two new basic blocks from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.exceptionTarget);
                            this.buildRecursivelyCfg(methodCfg, operations, branchTargetIdx, currentExitBranch, ref currentExitBranch.exitTarget);
                            return;
                        }

                    // create a virtual basic block at the end of a catch/finally handler
                    case OperationCode.Rethrow:
                    case OperationCode.Endfinally: {

                            // the current basic block ends here
                            currentBasicBlock.endIdx = idx;

                            // create new exit branch object
                            NoBranchTarget currentExitBranch = new NoBranchTarget();
                            currentExitBranch.sourceBasicBlock = currentBasicBlock;
                            currentExitBranch.takenTarget = new BasicBlock(this.semanticId);
                            this.semanticId++;
                            currentBasicBlock.exitBranch = currentExitBranch;

                            // start a new basic block from this branch on and end current execution
                            this.buildRecursivelyCfg(methodCfg, operations, idx + 1, currentExitBranch, ref currentExitBranch.takenTarget);

                            return;
                        }


                    default:
                        break;
                }
            }
        }
Example #3
0
        // 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);
            }

        }