// insert the given new target basic block between the given switch branch to manipulate public void insertBasicBlockBetweenBranch(SwitchBranchTarget branchToManipulate, int manipulateTakenBranchIdx, BasicBlock newTarget, ConditionalBranchTarget exitBranch, bool useTakenBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // check wether to use the taken or not taken part of the exit branch if (useTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref tempTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); branchToManipulate.takenTarget[manipulateTakenBranchIdx] = tempTakenTarget; } else { outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref tempTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); branchToManipulate.takenTarget[manipulateTakenBranchIdx] = tempTakenTarget; } }
// insert the given new target basic block between the given switch branch to manipulate public void insertBasicBlockBetweenBranch(SwitchBranchTarget branchToManipulate, int manipulateTakenBranchIdx, BasicBlock newTarget, SwitchBranchTarget exitBranch, int switchTakenBranchIdx) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock branchToManipulateTakenTarget = null; BasicBlock exitBranchTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulateTakenTarget, newTarget, newTarget, exitBranch, ref exitBranchTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = exitBranchTakenTarget; branchToManipulate.takenTarget[manipulateTakenBranchIdx] = branchToManipulateTakenTarget; }
// insert the given new target basic block between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTarget, SwitchBranchTarget exitBranch, int switchTakenBranchIdx) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // check wether to manipulate the taken or not taken branch of the branch to manipulate if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref tempTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = tempTakenTarget; } else { BasicBlock tempTakenTarget = null; outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTarget, newTarget, exitBranch, ref tempTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = tempTakenTarget; } }
// ################################################### SWITCH BRANCHES TO MANIPULATE ################################################### // insert the given new target basic block between the given switch branch to manipulate public void insertBasicBlockBetweenBranch(SwitchBranchTarget branchToManipulate, int manipulateTakenBranchIdx, BasicBlock newTarget, UnconditionalBranchTarget exitBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; outroBasicBlock = branchToManipulate.takenTarget.ElementAt(manipulateTakenBranchIdx); BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref tempTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); branchToManipulate.takenTarget[manipulateTakenBranchIdx] = tempTakenTarget; }
// 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; } } }
// 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); } }
// this function generates code for the "state change" private void createCodeStateChange(ref BasicBlock outStateChangeBasicBlock, ref SwitchBranchTarget outStateChangeExitBranch, GraphRandomStateGenerator randomStateGenerator, BasicBlockGraphNodeLink link, LocalDefinition intStateLocal) { // create a basic block to change the current global state BasicBlock stateChangeBasicBlock = new BasicBlock(); stateChangeBasicBlock.startIdx = 0; stateChangeBasicBlock.endIdx = 0; // create graph transformer metadata for the basic block GraphTransformerStateChangeBasicBlock metadataChange = new GraphTransformerStateChangeBasicBlock(); metadataChange.correspondingGraphNodes.Add(link); stateChangeBasicBlock.transformationMetadata.Add(metadataChange); // generate code for setting the new global state List<IOperation> tempOperations = randomStateGenerator.generateCodeSetRandomState(intStateLocal); stateChangeBasicBlock.operations.AddRange(tempOperations); // create switch statement for the "state switch" stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, intStateLocal)); uint[] switchSize = new uint[this.graph.graphValidPathCount]; stateChangeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Switch, switchSize)); // create exit branch for the new state basic block SwitchBranchTarget stateChangeExitBranch = new SwitchBranchTarget(); stateChangeExitBranch.sourceBasicBlock = stateChangeBasicBlock; stateChangeBasicBlock.exitBranch = stateChangeExitBranch; // create the dead code for this "state switch" BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(stateChangeExitBranch); stateChangeExitBranch.notTakenTarget = deadCodeBasicBlock; // TODO at the moment always the not taken branch of the switch statement is the dead code basic block // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); outStateChangeBasicBlock = stateChangeBasicBlock; outStateChangeExitBranch = stateChangeExitBranch; }
// this function generates code for the "state switch" private void createCodeStateSwitch(ref BasicBlock outStateBasicBlock, ref SwitchBranchTarget outStateExitBranch, LocalDefinition intStateLocal, List<BasicBlockGraphNodeLink> links) { BasicBlock stateBasicBlock = new BasicBlock(); stateBasicBlock.startIdx = 0; stateBasicBlock.endIdx = 0; // create graph transformer metadata for the basic block GraphTransformerStateBasicBlock stateMetadata = new GraphTransformerStateBasicBlock(); foreach (BasicBlockGraphNodeLink link in links) { stateMetadata.correspondingGraphNodes.Add(link); } stateBasicBlock.transformationMetadata.Add(stateMetadata); // create switch statement for the "state switch" stateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, intStateLocal)); uint[] switchSize = new uint[this.graph.graphValidPathCount]; stateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Switch, switchSize)); // create exit branch for the new state basic block SwitchBranchTarget stateExitBranch = new SwitchBranchTarget(); stateExitBranch.sourceBasicBlock = stateBasicBlock; stateBasicBlock.exitBranch = stateExitBranch; // create the dead code for this "state switch" BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "not taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(stateExitBranch); stateExitBranch.notTakenTarget = deadCodeBasicBlock; // TODO at the moment always the not taken branch of the switch statement is the dead code basic block // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set new created basic blocks and exit branch as output outStateBasicBlock = stateBasicBlock; outStateExitBranch = stateExitBranch; }