Example #1
0
        // creates a method for a given method CFG (IMPORTANT: it updates the operations
        // and exception handlers of the existing method, does not create a new method)
        public void createMethodFromCfg(MethodCfg methodCfg) {

            // list of basic blocks that belong together logically (i.e. BB2 lies directly behind BB1 because it reaches it without a branch)
            IList<BasicBlockUnion> basicBlockUnions = new List<BasicBlockUnion>();

            // first step: create basic block unions
            // create first basic block union starting from the start basic block
            BasicBlockUnion firstBasicBlockUnion = new BasicBlockUnion();
            this.createRecursivelyBasicBlockUnion(basicBlockUnions, firstBasicBlockUnion, methodCfg.startBasicBlock);
            basicBlockUnions.Add(firstBasicBlockUnion);

            // create basic block unions for the rest of the basic blocks
            foreach (BasicBlock tempBB in methodCfg.basicBlocks) {

                // create a basic block union (if basic block is not contained by another existing basic block union)
                BasicBlockUnion basicBlockUnion = new BasicBlockUnion();
                this.createRecursivelyBasicBlockUnion(basicBlockUnions, basicBlockUnion, tempBB);

                // if the newly created basic block union contains basic blocks
                // => add to list of basic block unions
                if (basicBlockUnion.basicBlocks.Count() != 0) {
                    basicBlockUnions.Add(basicBlockUnion);
                }
            }


            // step two: merge basic block unions with respect to the exception handler
            foreach (OperationExceptionInformation exceptionHandler in methodCfg.method.Body.OperationExceptionInformation) {

                // create a temporary object to reorder the basic block unions with respect to the exception handler
                BasicBlockUnionExceptionHandlerOrder tempNewOrder = new BasicBlockUnionExceptionHandlerOrder();
                tempNewOrder.exceptionHandler = exceptionHandler;

                // find all basic blocks that are connected to the current exception handler
                foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) {
                    foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) {

                        // ignore all basic blocks that do not have any try/catch/finally handler in it
                        if (basicBlock.tryBlocks.Count() == 0 && basicBlock.handlerBlocks.Count() == 0) {
                            continue;
                        }

                        // find the try block that is connected to the current exception handler
                        foreach (TryBlock tryBlock in basicBlock.tryBlocks) {

                            // ignore try blocks that do not belong to the current exception handler
                            if (tryBlock.exceptionHandler != exceptionHandler) {
                                continue;
                            }

                            // check if basic block union already resides in try body
                            // if not => add to try body
                            if (!tempNewOrder.tryBody.Contains(basicBlockUnion)) {
                                tempNewOrder.tryBody.Add(basicBlockUnion);
                            }

                            // check if the basic block starts the try block
                            if (tryBlock.firstBasicBlockOfTryBlock) {
                                tempNewOrder.tryStart = basicBlockUnion;
                            }

                            // check if the basic block ends the try block
                            if (tryBlock.lastBasicBlockOfTryBlock) {
                                tempNewOrder.tryEnd = basicBlockUnion;
                            }
                        }

                        // find the handler block that is connected to the current exception handler
                        foreach (HandlerBlock handlerBlock in basicBlock.handlerBlocks) {

                            // ignore handler blocks that do not belong to the current exception handler
                            if (handlerBlock.exceptionHandler != exceptionHandler) {
                                continue;
                            }

                            // check if basic block union already resides in handler body
                            // if not => add to handler body
                            if (!tempNewOrder.handlerBody.Contains(basicBlockUnion)) {
                                tempNewOrder.handlerBody.Add(basicBlockUnion);
                            }

                            // check if the basic block starts the handler block
                            if (handlerBlock.firstBasicBlockOfHandlerBlock) {
                                tempNewOrder.handlerStart = basicBlockUnion;
                            }

                            // check if the basic block ends the handler block
                            if (handlerBlock.lastBasicBlockOfHandlerBlock) {
                                tempNewOrder.handlerEnd = basicBlockUnion;
                            }
                        }
                    }
                }
                if (tempNewOrder.tryStart == null
                    || tempNewOrder.tryEnd == null
                    || tempNewOrder.handlerStart == null
                    || tempNewOrder.handlerEnd == null) {
                        throw new ArgumentException("Could not find all try/catch beginnings/ends.");
                }



                // merge basic block unions with respect to the current exception handler

                // check if the complete exception handling is done in only one basic block union
                // => ignore it
                if (tempNewOrder.tryStart == tempNewOrder.tryEnd
                    && tempNewOrder.handlerStart == tempNewOrder.handlerEnd
                    && tempNewOrder.tryStart == tempNewOrder.handlerStart) {
                    continue;
                }

                // if not everything lies in the same basic block union
                // extend the basic block union that starts the try block
                BasicBlockUnion extendedUnion = tempNewOrder.tryStart;

                // if try block start and end are the same => nothing to merge
                // else merge the basic block unions
                if (tempNewOrder.tryStart != tempNewOrder.tryEnd) {
                    foreach (BasicBlockUnion tryBodyBasicBlockUnion in tempNewOrder.tryBody) {

                        // ignore the basic block union that starts the try block (already in extended union)
                        // and ignore the basic block union that ends the try block (is added last)
                        if (tryBodyBasicBlockUnion == tempNewOrder.tryStart
                            || tryBodyBasicBlockUnion == tempNewOrder.tryEnd) {
                            continue;
                        }

                        // extend first basic block union with the basic block union of the
                        // try block body and remove the added one from the list of basic block unions
                        extendedUnion.basicBlocks.AddRange(tryBodyBasicBlockUnion.basicBlocks);
                        basicBlockUnions.Remove(tryBodyBasicBlockUnion);
                    }

                    // extend first basic block union with the basic block union of the
                    // try block end and remove the added one from the list of basic block unions
                    extendedUnion.basicBlocks.AddRange(tempNewOrder.tryEnd.basicBlocks);
                    basicBlockUnions.Remove(tempNewOrder.tryEnd);
                }

                // if the try block end and the handler block start are not the same basic block union
                // => merge the union of the handler block start to the current basic block union
                if (tempNewOrder.tryEnd != tempNewOrder.handlerStart) {
                    extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerStart.basicBlocks);
                    basicBlockUnions.Remove(tempNewOrder.handlerStart);
                }

                // if handler block start and end are the same => nothing to merge
                // else merge the basic block unions
                if (tempNewOrder.handlerStart != tempNewOrder.handlerEnd) {
                    foreach (BasicBlockUnion handlerBodyBasicBlockUnion in tempNewOrder.handlerBody) {

                        // ignore the basic block union that starts the handler block (already in extended union)
                        // and ignore the basic block union that ends the handler block (is added last)
                        if (handlerBodyBasicBlockUnion == tempNewOrder.handlerStart
                            || handlerBodyBasicBlockUnion == tempNewOrder.handlerEnd) {
                            continue;
                        }

                        // add basic block union of the handler block body to the extended basic block union 
                        // and remove the added one from the list of basic block unions
                        extendedUnion.basicBlocks.AddRange(handlerBodyBasicBlockUnion.basicBlocks);
                        basicBlockUnions.Remove(handlerBodyBasicBlockUnion);
                    }

                    // extend the extended basic block union with the basic block union of the
                    // handler block end and remove the added one from the list of basic block unions
                    extendedUnion.basicBlocks.AddRange(tempNewOrder.handlerEnd.basicBlocks);
                    basicBlockUnions.Remove(tempNewOrder.handlerEnd);
                }
            }


            // step three: create one list of operations and modify jump offsets
            // create a list of operations from the basic blocks,
            // update basic block start/end indices accordingly
            // and update the offsets of the operations (needed to update branch operations)
            IList<IOperation> methodOperations = new List<IOperation>();
            int operationIdx = 0;
            uint currentOffset = 0;
            foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) {
                foreach (BasicBlock basicBlock in basicBlockUnion.basicBlocks) {
                    basicBlock.startIdx = operationIdx;
                    //foreach (IOperation operation in basicBlock.operations) {
                    for (int opIdx = 0; opIdx < basicBlock.operations.Count(); opIdx++) {
                        IOperation operation = basicBlock.operations.ElementAt(opIdx);

                        // a new operation object is needed because the old operations
                        // are read only due to cci
                        InternalOperation newOperation = new InternalOperation();

                        // exchange every short instruction with its larger one
                        switch (operation.OperationCode) {
                            case OperationCode.Beq_S:
                                newOperation.OperationCode = OperationCode.Beq;
                                break;
                            case OperationCode.Bge_S:
                                newOperation.OperationCode = OperationCode.Bge;
                                break;
                            case OperationCode.Bge_Un_S:
                                newOperation.OperationCode = OperationCode.Bge_Un;
                                break;
                            case OperationCode.Bgt_S:
                                newOperation.OperationCode = OperationCode.Bgt;
                                break;
                            case OperationCode.Bgt_Un_S:
                                newOperation.OperationCode = OperationCode.Bgt_Un;
                                break;
                            case OperationCode.Ble_S:
                                newOperation.OperationCode = OperationCode.Ble;
                                break;
                            case OperationCode.Ble_Un_S:
                                newOperation.OperationCode = OperationCode.Ble_Un;
                                break;
                            case OperationCode.Blt_S:
                                newOperation.OperationCode = OperationCode.Blt;
                                break;
                            case OperationCode.Blt_Un_S:
                                newOperation.OperationCode = OperationCode.Blt_Un;
                                break;
                            case OperationCode.Bne_Un_S:
                                newOperation.OperationCode = OperationCode.Bne_Un;
                                break;
                            case OperationCode.Br_S:
                                newOperation.OperationCode = OperationCode.Br;
                                break;
                            case OperationCode.Brfalse_S:
                                newOperation.OperationCode = OperationCode.Brfalse;
                                break;
                            case OperationCode.Brtrue_S:
                                newOperation.OperationCode = OperationCode.Brtrue;
                                break;
                            case OperationCode.Ldarg_S:
                                newOperation.OperationCode = OperationCode.Ldarg;
                                break;
                            case OperationCode.Ldarga_S:
                                newOperation.OperationCode = OperationCode.Ldarga;
                                break;
                            case OperationCode.Ldc_I4_S:
                                newOperation.OperationCode = OperationCode.Ldc_I4;
                                break;
                            case OperationCode.Ldloc_S:
                                newOperation.OperationCode = OperationCode.Ldloc;
                                break;
                            case OperationCode.Ldloca_S:
                                newOperation.OperationCode = OperationCode.Ldloca;
                                break;
                            case OperationCode.Leave_S:
                                newOperation.OperationCode = OperationCode.Leave;
                                break;
                            case OperationCode.Starg_S:
                                newOperation.OperationCode = OperationCode.Starg;
                                break;
                            case OperationCode.Stloc_S:
                                newOperation.OperationCode = OperationCode.Stloc;
                                break;
                            default:
                                newOperation.OperationCode = operation.OperationCode;
                                break;
                        }
                        newOperation.Value = operation.Value;
                        newOperation.Location = operation.Location;
                        newOperation.Offset = currentOffset;
                        methodOperations.Add(newOperation);

                        // replace old operation in basic block with newly created one
                        basicBlock.operations[opIdx] = newOperation;

                        operationIdx++;
                        currentOffset += CfgBuilder.getSizeOfOperation(newOperation);
                    }
                    basicBlock.endIdx = operationIdx - 1;
                }
            }


            // step four: update branches with new target offsets
            foreach (BasicBlock tempBB in methodCfg.basicBlocks) {
                InternalOperation branchOperation = (InternalOperation)methodOperations.ElementAt(tempBB.endIdx);

                // check which kind of exit branch is used by this basic block and update its operation accordingly
                if (tempBB.exitBranch as NoBranchTarget != null) {
                    continue;
                }
                else if (tempBB.exitBranch as TryBlockTarget != null) {
                    continue;
                }
                else if (tempBB.exitBranch as ConditionalBranchTarget != null) {
                    ConditionalBranchTarget tempExitBranch = (tempBB.exitBranch as ConditionalBranchTarget);

                    // check if the branch is done by a branch operation
                    if (!CfgBuilder.isBranchOperation(branchOperation)) {
                        throw new ArgumentException("Branch is not done by a valid branch operation.");
                    }

                    // get index of the branch target
                    int targetBranchIdx = tempExitBranch.takenTarget.startIdx;

                    // update offset of the taken branch
                    branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset;
                }
                else if (tempBB.exitBranch as SwitchBranchTarget != null) {
                    SwitchBranchTarget tempExitBranch = (tempBB.exitBranch as SwitchBranchTarget);

                    // check if the branch is done by a branch operation
                    if (!CfgBuilder.isBranchOperation(branchOperation)) {
                        throw new ArgumentException("Branch is not done by a valid branch operation.");
                    }

                    // update all switch branches
                    for (int switchIdx = 0; switchIdx < tempExitBranch.takenTarget.Count(); switchIdx++) {

                        // get index of the branch target
                        int targetBranchIdx = tempExitBranch.takenTarget.ElementAt(switchIdx).startIdx;

                        // update offset of the taken branch
                        ((uint[])branchOperation.Value)[switchIdx] = methodOperations.ElementAt(targetBranchIdx).Offset;
                    }
                }
                else if (tempBB.exitBranch as UnconditionalBranchTarget != null) {
                    UnconditionalBranchTarget tempExitBranch = (tempBB.exitBranch as UnconditionalBranchTarget);

                    // check if the branch is done by a branch operation
                    if (!CfgBuilder.isBranchOperation(branchOperation)) {
                        throw new ArgumentException("Branch is not done by a valid branch operation.");
                    }

                    // get index of the branch target
                    int targetBranchIdx = tempExitBranch.takenTarget.startIdx;

                    // update offset of the taken branch
                    branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset;
                }
                else if (tempBB.exitBranch as ExitBranchTarget != null) {
                    continue;
                }
                else if (tempBB.exitBranch as ThrowBranchTarget != null) {
                    continue;
                }
                else if (tempBB.exitBranch as ExceptionBranchTarget != null) {
                    ExceptionBranchTarget tempExitBranch = (tempBB.exitBranch as ExceptionBranchTarget);

                    // check if the branch is done by a branch operation
                    if (!CfgBuilder.isBranchOperation(branchOperation)) {
                        throw new ArgumentException("Branch is not done by a valid branch operation.");
                    }

                    // get index of the branch target
                    int targetBranchIdx = tempExitBranch.exitTarget.startIdx;

                    // update offset of the taken branch
                    branchOperation.Value = methodOperations.ElementAt(targetBranchIdx).Offset;
                }
                else {
                    throw new ArgumentException("Do not know how to handle exit branch.");
                }
            }


            // step five: create new exception handler with updated offsets and
            // create new method body of the cci method
            MethodDefinition method = methodCfg.method;
            var ilGenerator = new ILGenerator(this.host, method);
            // emit all operations to the new body
            foreach (IOperation operation in methodOperations) {
                ilGenerator.Emit(operation.OperationCode, operation.Value);
            }

            // list that is used to replace the pointer to the old exception handler in the basic blocks to the new exception handler
            List<OldExceptionHandlerMapping> oldExceptionHandlerMappings = new List<OldExceptionHandlerMapping>();
            
            // create for each old exception handler a new one with updated data
            foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) {

                // create mapping object for old exception handler
                OldExceptionHandlerMapping oldExceptionHandlerMapping = new OldExceptionHandlerMapping();
                oldExceptionHandlerMapping.oldExceptionHandler = exceptionHandler;
                oldExceptionHandlerMappings.Add(oldExceptionHandlerMapping);

                ILGeneratorLabel tryStart = new ILGeneratorLabel();
                ILGeneratorLabel tryEnd = new ILGeneratorLabel();
                ILGeneratorLabel handlerStart = new ILGeneratorLabel();
                ILGeneratorLabel handlerEnd = new ILGeneratorLabel();
                ILGeneratorLabel filterStart = new ILGeneratorLabel();

                // search for the basic blocks that start/end the try block and handler block
                foreach (BasicBlock tempBB in methodCfg.basicBlocks) {

                    foreach (TryBlock tempTryBlock in tempBB.tryBlocks) {

                        // ignore try blocks that do not belong to the current exception handler
                        if (tempTryBlock.exceptionHandler != exceptionHandler) {
                            continue;
                        }

                        // get offset of the instruction that starts the try block
                        if (tempTryBlock.firstBasicBlockOfTryBlock) {
                            tryStart.Offset = tempBB.operations.ElementAt(0).Offset;
                            oldExceptionHandlerMapping.tryStartOffset = tryStart.Offset;
                        }

                        // get offset of the instruction that ends the try block (always the last instruction of the basic block)
                        if (tempTryBlock.lastBasicBlockOfTryBlock) {
                            tryEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset;
                            // exception handler object needs offset of the end of the instruction (not the beginning)
                            tryEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1));
                            oldExceptionHandlerMapping.tryEndOffset = tryEnd.Offset;
                        }
                    }

                    foreach (HandlerBlock tempHandlerBlock in tempBB.handlerBlocks) {

                        // ignore handler blocks that do not belong to the current exception handler
                        if (tempHandlerBlock.exceptionHandler != exceptionHandler) {
                            continue;
                        }

                        // get offset ot the instruction that starts the handler block
                        if (tempHandlerBlock.firstBasicBlockOfHandlerBlock) {
                            handlerStart.Offset = tempBB.operations.ElementAt(0).Offset;
                            oldExceptionHandlerMapping.handlerStartOffset = handlerStart.Offset;
                        }

                        // get offset of the instruction that ends the handler block
                        if (tempHandlerBlock.lastBasicBlockOfHandlerBlock) {
                            handlerEnd.Offset = tempBB.operations.ElementAt(tempBB.operations.Count() - 1).Offset;
                            // exception handler object needs offset of the end of the instruction (not the beginning)
                            handlerEnd.Offset += CfgBuilder.getSizeOfOperation(tempBB.operations.ElementAt(tempBB.operations.Count() - 1));
                            oldExceptionHandlerMapping.handlerEndOffset = handlerEnd.Offset;
                        }
                    }
                }

                // copy the exception handler filter
                filterStart.Offset = exceptionHandler.FilterDecisionStartOffset;
                oldExceptionHandlerMapping.filterStartOffset = filterStart.Offset;

                // add new exception handler
                oldExceptionHandlerMapping.exceptionType = exceptionHandler.ExceptionType;
                oldExceptionHandlerMapping.handlerKind = exceptionHandler.HandlerKind;
                ilGenerator.AddExceptionHandlerInformation(exceptionHandler.HandlerKind, exceptionHandler.ExceptionType, tryStart, tryEnd, handlerStart, handlerEnd, filterStart);
            }

            // create the body
            List<ILocalDefinition> variableListCopy = new List<ILocalDefinition>(method.Body.LocalVariables);
            List<ITypeDefinition> privateHelperTypesListCopy = new List<ITypeDefinition>(method.Body.PrivateHelperTypes);
            var newBody = new ILGeneratorMethodBody(ilGenerator, method.Body.LocalsAreZeroed, 8, method, variableListCopy, privateHelperTypesListCopy); // TODO dynamic max stack size?
            method.Body = newBody;


            // step six: replace pointer to the old exception handler with the new exception handler

            // map all old exception handler to the new objects
            foreach (IOperationExceptionInformation exceptionHandler in method.Body.OperationExceptionInformation) {

                // search for the new exception handler object to get the mapping to the old one
                bool found = false;
                foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) {
                    if (oldExceptionHandlerMapping.exceptionType == exceptionHandler.ExceptionType
                        && oldExceptionHandlerMapping.handlerKind == exceptionHandler.HandlerKind
                        && oldExceptionHandlerMapping.filterStartOffset == exceptionHandler.FilterDecisionStartOffset
                        && oldExceptionHandlerMapping.tryStartOffset == exceptionHandler.TryStartOffset
                        && oldExceptionHandlerMapping.tryEndOffset == exceptionHandler.TryEndOffset
                        && oldExceptionHandlerMapping.handlerStartOffset == exceptionHandler.HandlerStartOffset
                        && oldExceptionHandlerMapping.handlerEndOffset == exceptionHandler.HandlerEndOffset) {
                        oldExceptionHandlerMapping.newExceptionHandler = exceptionHandler;
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    throw new ArgumentException("Not able to map old exception handler to new one.");
                }
            }

            // replace all old exception handler in the basic blocks with the new exception handler
            foreach (BasicBlock tempBB in methodCfg.basicBlocks) {

                // replace all exception handler in the try blocks
                foreach (TryBlock tryBlock in tempBB.tryBlocks) {
                    foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) {
                        if (tryBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) {
                            tryBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler;
                            break;
                        }
                    }
                }

                // replace all exception handler in the handler blocks
                foreach (HandlerBlock handlerBlock in tempBB.handlerBlocks) {
                    foreach (OldExceptionHandlerMapping oldExceptionHandlerMapping in oldExceptionHandlerMappings) {
                        if (handlerBlock.exceptionHandler == oldExceptionHandlerMapping.oldExceptionHandler) {
                            handlerBlock.exceptionHandler = oldExceptionHandlerMapping.newExceptionHandler;
                            break;
                        }
                    }
                }
            }

            
            // TODO
            // DEBUG
            /*
            // sanitize method name to store it as a file
            String invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
            String invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);
            String fileName = System.Text.RegularExpressions.Regex.Replace(methodCfg.method.ToString(), invalidRegStr, "_");
            fileName = fileName.Length >= 230 ? fileName.Substring(0, 230) : fileName;

            // dump cfg created from the exit branches
            System.IO.StreamWriter dotFile = new System.IO.StreamWriter("e:\\" + "\\BBUnion_" + fileName + ".dot");

            // start .dot file graph
            dotFile.WriteLine("digraph G {");

            for (int bbuidx = 0; bbuidx < basicBlockUnions.Count(); bbuidx++) {
                BasicBlockUnion basicBlockUnion = basicBlockUnions.ElementAt(bbuidx);
                    // write all basic blocks to .dot file
                    for (int idx = 0; idx < basicBlockUnion.basicBlocks.Count(); idx++) {

                        BasicBlock currentBasicBlock = basicBlockUnion.basicBlocks.ElementAt(idx);

                        // write the current basic block to the file and all its instructions
                        dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [shape=record]");
                        bool first = true;
                        for (int opIdx = 0; opIdx < currentBasicBlock.operations.Count(); opIdx++) {
                            var operation = currentBasicBlock.operations.ElementAt(opIdx);
                            if (first) {
                                dotFile.Write("BB" + bbuidx.ToString() + "_" + idx.ToString() + " [label=\"{");
                                first = false;
                            }
                            else {
                                dotFile.Write("|");
                            }

                            // insert try block beginnings
                            foreach (var tryBlock in currentBasicBlock.tryBlocks) {
                                if (tryBlock.firstBasicBlockOfTryBlock && opIdx == 0) {
                                    dotFile.Write("TRY START (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")|");
                                }
                            }

                            // insert catch block beginnings
                            foreach (var handlerBlock in currentBasicBlock.handlerBlocks) {
                                if (handlerBlock.firstBasicBlockOfHandlerBlock && opIdx == 0) {
                                    if (handlerBlock.typeOfHandler == HandlerKind.Catch) {
                                        dotFile.Write("CATCH START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|");
                                    }
                                    else if (handlerBlock.typeOfHandler == HandlerKind.Finally) {
                                        dotFile.Write("FINALLY START (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")|");
                                    }
                                    else {
                                        throw new ArgumentException("Do not know how to handle handler.");
                                    }
                                }
                            }

                            // check if instruction has an argument
                            if (operation.Value != null) {
                                dotFile.Write(operation.OperationCode.ToString() + " " + operation.Value.ToString());
                            }
                            else {
                                dotFile.Write(operation.OperationCode.ToString());
                            }

                            // insert try block endings
                            foreach (var tryBlock in currentBasicBlock.tryBlocks) {
                                if (tryBlock.lastBasicBlockOfTryBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) {
                                    dotFile.Write("|TRY END (" + tryBlock.exceptionHandler.ExceptionType.ToString() + ")");
                                }
                            }

                            // insert catch block endings
                            foreach (var handlerBlock in currentBasicBlock.handlerBlocks) {
                                if (handlerBlock.lastBasicBlockOfHandlerBlock && (currentBasicBlock.operations.Count() - 1) == opIdx) {
                                    if (handlerBlock.typeOfHandler == HandlerKind.Catch) {
                                        dotFile.Write("|CATCH END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")");
                                    }
                                    else if (handlerBlock.typeOfHandler == HandlerKind.Finally) {
                                        dotFile.Write("|FINALLY END (" + handlerBlock.exceptionHandler.ExceptionType.ToString() + ")");
                                    }
                                    else {
                                        throw new ArgumentException("Do not know how to handle handler.");
                                    }
                                }
                            }
                        }
                        dotFile.WriteLine("}\"]");


                        if ((idx + 1) < basicBlockUnion.basicBlocks.Count()) {
                            dotFile.WriteLine("BB" + bbuidx.ToString() + "_" + idx.ToString() + " -> BB" + bbuidx.ToString() + "_" + (idx + 1).ToString() + "[ color=\"blue\" ]");
                        }

                    }
                }


            // finish graph
            dotFile.WriteLine("}");

            dotFile.Close();
            */
        }
Example #2
0
        // builds recursively a basic block union (a list of basic blocks that belong together in the control flow because
        // they are lying directly behind each other)
        private void createRecursivelyBasicBlockUnion(IList<BasicBlockUnion> basicBlockUnions, BasicBlockUnion currentUnion, BasicBlock currentBasicBlock) {

            // check if current basic block already belongs to a basic block union
            foreach (BasicBlockUnion basicBlockUnion in basicBlockUnions) {
                // ignore current basic block union
                if (basicBlockUnion == currentUnion) {
                    continue;
                }
                foreach (BasicBlock tempBB in basicBlockUnion.basicBlocks) {
                    if (tempBB == currentBasicBlock) {
                        return;
                    }
                }
            }

            // if there are no basic blocks inside the current basic block union
            // check if the entry to the current basic block could be a not taken branch
            // or no branch at all => start building the basic block union from the predecessor basic block
            if (currentUnion.basicBlocks.Count() == 0) {
                foreach (IBranchTarget entryBranch in currentBasicBlock.entryBranches) {
                    BasicBlock predecessorBasicBlock = entryBranch.sourceBasicBlock;

                    if (predecessorBasicBlock.exitBranch as NoBranchTarget != null) {
                        NoBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as NoBranchTarget);

                        // check if the basic block that comes directly after the predecessor basic block is the current one
                        // => start building basic block union from the predecessor
                        if (predecessorExitBranch.takenTarget == currentBasicBlock) {
                            this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock);
                            return;
                        }

                        continue;
                    }
                    else if (predecessorBasicBlock.exitBranch as TryBlockTarget != null) {
                        TryBlockTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as TryBlockTarget);

                        // check if the basic block that comes directly after the predecessor basic block is the current one
                        // => start building basic block union from the predecessor
                        if (predecessorExitBranch.takenTarget == currentBasicBlock) {
                            this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock);
                            return;
                        }

                        continue;                        
                    }
                    else if (predecessorBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                        ConditionalBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as ConditionalBranchTarget);

                        // check if the basic block that comes directly after the predecessor basic block is the current one
                        // => start building basic block union from the predecessor
                        if (predecessorExitBranch.notTakenTarget == currentBasicBlock) {
                            this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock);
                            return;
                        }

                        continue;
                    }
                    else if (predecessorBasicBlock.exitBranch as SwitchBranchTarget != null) {
                        SwitchBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as SwitchBranchTarget);

                        // check if the basic block that comes directly after the predecessor basic block is the current one
                        // => start building basic block union from the predecessor
                        if (predecessorExitBranch.notTakenTarget == currentBasicBlock) {
                            this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock);
                            return;
                        }

                        continue;
                    }
                    else if (predecessorBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                        ExceptionBranchTarget predecessorExitBranch = (predecessorBasicBlock.exitBranch as ExceptionBranchTarget);

                        // check if the basic block that comes directly after the predecessor basic block is the current one
                        // => start building basic block union from the predecessor
                        if (predecessorExitBranch.exceptionTarget == currentBasicBlock) {
                            this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, predecessorBasicBlock);
                            return;
                        }

                        continue;
                    }
                }
            }

            // add current basic block to the union
            currentUnion.basicBlocks.Add(currentBasicBlock);

            // follow all not taken branches and add them to the current basic block union
            // (this means all basic blocks that follow directly the current one directly
            // because they lie directly behind the current one are added to the basic block union)
            if (currentBasicBlock.exitBranch as NoBranchTarget != null) {
                NoBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as NoBranchTarget);
                this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.takenTarget);
                return;
            }
            else if (currentBasicBlock.exitBranch as TryBlockTarget != null) {
                TryBlockTarget tempExitBranch = (currentBasicBlock.exitBranch as TryBlockTarget);
                this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.takenTarget);
                return;
            }
            else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) {
                ConditionalBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as ConditionalBranchTarget);
                this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.notTakenTarget);
                return;
            }
            else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) {
                SwitchBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as SwitchBranchTarget);
                this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.notTakenTarget);
                return;
            }
            else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) {
                return;
            }
            else if (currentBasicBlock.exitBranch as ExitBranchTarget != null) {
                return;
            }
            else if (currentBasicBlock.exitBranch as ThrowBranchTarget != null) {
                return;
            }
            else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                ExceptionBranchTarget tempExitBranch = (currentBasicBlock.exitBranch as ExceptionBranchTarget);
                this.createRecursivelyBasicBlockUnion(basicBlockUnions, currentUnion, tempExitBranch.exceptionTarget);
                return;
            }
            else {
                throw new ArgumentException("Do not know how to handle exit branch.");
            }
        }