// creates a new CCI operation private static IOperation createNewOperation(OperationCode operationCode, object value = null, ILocation location = null, uint offset = 0) { InternalOperation newOperation = new InternalOperation(); newOperation.OperationCode = operationCode; newOperation.Value = value; newOperation.Location = location; newOperation.Offset = offset; return(newOperation); }
// adds a nop instruction after every instruction in the given method cfg public void addNopsToCfg(MethodCfg methodCfg) { foreach (BasicBlock tempBB in methodCfg.basicBlocks) { List<IOperation> newOperations = new List<IOperation>(); for (int idx = 0; idx < tempBB.operations.Count(); idx++) { IOperation currentOperation = tempBB.operations.ElementAt(idx); // copy current operation to new operations list newOperations.Add(currentOperation); if (idx == tempBB.operations.Count() - 1) { break; } // ignore all prefixes (because nop after prefix will crash the program) if (currentOperation.OperationCode == OperationCode.No_ || currentOperation.OperationCode == OperationCode.Constrained_ || currentOperation.OperationCode == OperationCode.Readonly_ || currentOperation.OperationCode == OperationCode.Tail_ || currentOperation.OperationCode == OperationCode.Unaligned_ || currentOperation.OperationCode == OperationCode.Volatile_) { continue; } InternalOperation newNopOperation = new InternalOperation(); newNopOperation.OperationCode = OperationCode.Nop; // add nop operation after current one newOperations.Add(newNopOperation); } // replace old operations with new ones tempBB.operations = newOperations; } }
// adds a nop instruction after every instruction in the given method cfg public void addNopsToCfg(MethodCfg methodCfg) { foreach (BasicBlock tempBB in methodCfg.basicBlocks) { List <IOperation> newOperations = new List <IOperation>(); for (int idx = 0; idx < tempBB.operations.Count(); idx++) { IOperation currentOperation = tempBB.operations.ElementAt(idx); // copy current operation to new operations list newOperations.Add(currentOperation); if (idx == tempBB.operations.Count() - 1) { break; } // ignore all prefixes (because nop after prefix will crash the program) if (currentOperation.OperationCode == OperationCode.No_ || currentOperation.OperationCode == OperationCode.Constrained_ || currentOperation.OperationCode == OperationCode.Readonly_ || currentOperation.OperationCode == OperationCode.Tail_ || currentOperation.OperationCode == OperationCode.Unaligned_ || currentOperation.OperationCode == OperationCode.Volatile_) { continue; } InternalOperation newNopOperation = new InternalOperation(); newNopOperation.OperationCode = OperationCode.Nop; // add nop operation after current one newOperations.Add(newNopOperation); } // replace old operations with new ones tempBB.operations = newOperations; } }
// 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(); */ }
// 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); } }
// 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); } }
// creates a new CCI operation private static IOperation createNewOperation(OperationCode operationCode, object value=null, ILocation location=null, uint offset=0) { InternalOperation newOperation = new InternalOperation(); newOperation.OperationCode = operationCode; newOperation.Value = value; newOperation.Location = location; newOperation.Offset = offset; return newOperation; }