// 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 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; } }
// insert the given new target basic block (given by start and end block) between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTargetStart, BasicBlock newTargetEnd, 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; // manipulate the correct branch if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); } }
// 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; } } }
// insert the given new target basic block between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, 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) { // check wether to manipulate the taken or not taken branch of the branch to manipulate if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); } } else { // check wether to manipulate the taken or not taken branch of the branch to manipulate if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); } } }
// 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); } }
// 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 function injects an opaque predicate to the target branch private void injectOpaquePredicateCode(CfgManipulator cfgManipulator, Target target, ref ConditionalBranchTarget opaqueExitBranch, IBranchTarget targetBranch, BasicBlockGraphNodeLink link, int currentValidPathId, int opaquePredicate, LocalDefinition currentNodeLocal) { // create "true" or "false" opaque predicate and add it to the code switch (opaquePredicate) { // "true" opaque predicate case 0: { BasicBlock opaqueStartBasicBlock = null; this.createCodeTruePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal); // inject target branch with opaque predicate if ((targetBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, true); } else { throw new ArgumentException("Not implemented yet."); } // set template semantic id of dead code basic block BasicBlock deadCodeBasicBlock = opaqueExitBranch.notTakenTarget; GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock); deadCodeMetadata.semanticId = target.basicBlock.semanticId; break; } // "false" opaque predicate case 1: { BasicBlock opaqueStartBasicBlock = null; this.createCodeFalsePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal); // inject target branch with opaque predicate if ((targetBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, false); } else { throw new ArgumentException("Not implemented yet."); } // set template semantic id of dead code basic block BasicBlock deadCodeBasicBlock = opaqueExitBranch.takenTarget; GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock); deadCodeMetadata.semanticId = target.basicBlock.semanticId; break; } // "Random" opaque predicate. case 2: { BasicBlock opaqueStartBasicBlock = null; if((targetBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget); var destinationBlock = tempTargetBranch.takenTarget[currentValidPathId]; this.createCodeRandomPredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal); bool chooseBranch = prng.Next(1) == 0; cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, chooseBranch); } else { throw new ArgumentException("Not implemented yet."); } break; } default: throw new ArgumentException("This case should never be reached."); } }
// creates a duplicate of the given source basic block with the branch targets to semantically equivalent basic blocks // (not necessary the target basic block of the given source basic block) private BasicBlock duplicateBasicBlock(MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock sourceBasicBlock) { // search for a semantically equal basic block in the unmodified method CFG int searchSementicId = sourceBasicBlock.semanticId; BasicBlock copiedOriginalTargetBasicBlock = null; if (searchSementicId == -1) { throw new ArgumentException("No distinct semantic id given to search for."); } foreach (BasicBlock searchBasicBlock in originalMethodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { copiedOriginalTargetBasicBlock = searchBasicBlock; break; } } if (copiedOriginalTargetBasicBlock == null) { throw new ArgumentException("Not able to find semantically equal basic block in copied CFG."); } // create a new basic block BasicBlock newBasicBlock = new BasicBlock(); // copy simple values newBasicBlock.semanticId = copiedOriginalTargetBasicBlock.semanticId; newBasicBlock.startIdx = copiedOriginalTargetBasicBlock.startIdx; newBasicBlock.endIdx = copiedOriginalTargetBasicBlock.endIdx; // copy all operations of the basic block foreach (IOperation operation in copiedOriginalTargetBasicBlock.operations) { newBasicBlock.operations.Add(this.helperClass.createNewOperation(operation.OperationCode, operation.Value, operation.Location, operation.Offset)); } if (copiedOriginalTargetBasicBlock.tryBlocks.Count() != 0 || copiedOriginalTargetBasicBlock.handlerBlocks.Count() != 0) { throw new ArgumentException("Not implemented yet."); } // create an exit branch for the new basic block if ((copiedOriginalTargetBasicBlock.exitBranch as NoBranchTarget) != null) { //throw new ArgumentException("Not implemented yet."); // TODO: problem here with having 2 no branches before a basic block (but not necessarily because all branches are processed and exchanged) NoBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as NoBranchTarget); // create a copied exit branch NoBranchTarget copiedExitBranch = new NoBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) searchSementicId = exitBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.takenTarget = targetBasicBlock; } else if (copiedOriginalTargetBasicBlock.exitBranch as UnconditionalBranchTarget != null) { UnconditionalBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as UnconditionalBranchTarget); // create a copied exit branch UnconditionalBranchTarget copiedExitBranch = new UnconditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) searchSementicId = exitBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.takenTarget = targetBasicBlock; } else if (copiedOriginalTargetBasicBlock.exitBranch as ConditionalBranchTarget != null) { ConditionalBranchTarget exitBranch = (copiedOriginalTargetBasicBlock.exitBranch as ConditionalBranchTarget); // create a copied exit branch ConditionalBranchTarget copiedExitBranch = new ConditionalBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) (for "taken" branch) searchSementicId = exitBranch.takenTarget.semanticId; List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>(); foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } // use a random possible basic block as target int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); BasicBlock targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.takenTarget = targetBasicBlock; // search for all semantically equal basic blocks in the modified method CFG (as possible targets) (for "not taken" branch) searchSementicId = exitBranch.notTakenTarget.semanticId; possibleTargetBasicBlocks = new List<BasicBlock>(); foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) { if (searchBasicBlock.semanticId == searchSementicId) { possibleTargetBasicBlocks.Add(searchBasicBlock); } } if (possibleTargetBasicBlocks.Count() == 0) { throw new ArgumentException("Not able to find any semantically equal basic block in CFG."); } // use a random possible basic block as target randPosition = this.prng.Next(possibleTargetBasicBlocks.Count()); targetBasicBlock = possibleTargetBasicBlocks.ElementAt(randPosition); // set basic block as target for the branch targetBasicBlock.entryBranches.Add(copiedExitBranch); copiedExitBranch.notTakenTarget = targetBasicBlock; } else if (copiedOriginalTargetBasicBlock.exitBranch as SwitchBranchTarget != null) { throw new ArgumentException("Not implemented yet."); } else if (copiedOriginalTargetBasicBlock.exitBranch as ExitBranchTarget != null) { // create a copied exit branch ExitBranchTarget copiedExitBranch = new ExitBranchTarget(); copiedExitBranch.sourceBasicBlock = newBasicBlock; newBasicBlock.exitBranch = copiedExitBranch; } else if (copiedOriginalTargetBasicBlock.exitBranch as ThrowBranchTarget != null) { throw new ArgumentException("Not implemented yet."); } else if (copiedOriginalTargetBasicBlock.exitBranch as TryBlockTarget != null) { throw new ArgumentException("Not implemented yet."); } else if (copiedOriginalTargetBasicBlock.exitBranch as ExceptionBranchTarget != null) { throw new ArgumentException("Not implemented yet."); } else { throw new ArgumentException("Do not know how to handle exit branch."); } return newBasicBlock; }
// this function generates code for an opaque predicate that evaluates to "true" // => the "taken" branch of the conditional branch have to be taken for the correct code path private void createCodeTruePredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { // create a basic block that checks the opaque predicate (this check evaluates to "true") BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // add graph transformer metadata to the basic block GraphTransformerPredicateBasicBlock metadata = new GraphTransformerPredicateBasicBlock(); metadata.predicateType = GraphOpaquePredicate.True; metadata.correspondingGraphNodes.Add(link); startBasicBlock.transformationMetadata.Add(metadata); // search for the valid and invalid interfaces list of the current valid path id List<ITypeReference> validInterfaces = null; List<ITypeReference> invalidInterfaces = null; foreach (PathElement pathElement in link.graphNode.pathElements) { if (pathElement.validPathId == link.validPathId) { validInterfaces = pathElement.validInterfaces; invalidInterfaces = pathElement.invalidInterfaces; } } if (validInterfaces == null || invalidInterfaces == null) { throw new ArgumentException("No valid/invalid interface list was found."); } emitPredicateCode(startBasicBlock, currentNodeLocal, validInterfaces, invalidInterfaces); // create the conditional branch for the checking basic block (taken => correct code; not taken => dead code) ConditionalBranchTarget startBasicBlockExitBranch = new ConditionalBranchTarget(); startBasicBlockExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startBasicBlockExitBranch; // create the dead code for this opaque predicate 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(startBasicBlockExitBranch); startBasicBlockExitBranch.notTakenTarget = deadCodeBasicBlock; // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set the created basic block and conditional jumps as output outStartBasicBlock = startBasicBlock; outConditionalBranch = startBasicBlockExitBranch; }
// Generates code for an opaque predicate evaluating to a random value. // => Both branches point to basic blocks with equal semantics. private void createCodeRandomPredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { throw new ArgumentException("Not implemented."); // TODO: will improve the probabilistic control flow }
// this function generates code for an opaque predicate that evaluates to "false" // => the "not taken" branch of the conditional branch have to be taken for the correct code path private void createCodeFalsePredicate(ref BasicBlock outStartBasicBlock, ref ConditionalBranchTarget outConditionalBranch, BasicBlockGraphNodeLink link, LocalDefinition currentNodeLocal) { // create a basic block that checks the opaque predicate (this check evaluates to "false") BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; // add graph transformer metadata to the basic block GraphTransformerPredicateBasicBlock metadata = new GraphTransformerPredicateBasicBlock(); metadata.predicateType = GraphOpaquePredicate.False; metadata.correspondingGraphNodes.Add(link); startBasicBlock.transformationMetadata.Add(metadata); // search for the valid and invalid interfaces list of the current valid path id List<ITypeReference> validInterfaces = null; List<ITypeReference> invalidInterfaces = null; foreach (PathElement pathElement in link.graphNode.pathElements) { if (pathElement.validPathId == link.validPathId) { validInterfaces = pathElement.validInterfaces; invalidInterfaces = pathElement.invalidInterfaces; } } if(validInterfaces == null || invalidInterfaces == null) { throw new ArgumentException("No valid/invalid interface list was found."); } // add a random check to the code // important: for this predicate the dead code is reached by the "taken" branch and the correct code is reached by the "not taken" branch int randPosition; ITypeReference interfaceToCheck = null; switch (this.prng.Next(8)) { case 0: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 1: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 2: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 3: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(validInterfaces.Count()); interfaceToCheck = validInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 4: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 5: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; case 6: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Cgt_Un)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4_1)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brtrue, 0)); break; case 7: startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); randPosition = this.prng.Next(invalidInterfaces.Count()); interfaceToCheck = invalidInterfaces.ElementAt(randPosition); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Isinst, interfaceToCheck)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldnull)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ceq)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Brfalse, 0)); break; default: throw new ArgumentException("This case should never be reached."); } // create the conditional branch for the checking basic block (not taken => correct code; taken => dead code) ConditionalBranchTarget startBasicBlockExitBranch = new ConditionalBranchTarget(); startBasicBlockExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startBasicBlockExitBranch; // create the dead code for this opaque predicate BasicBlock deadCodeBasicBlock = new BasicBlock(); deadCodeBasicBlock.startIdx = 0; deadCodeBasicBlock.endIdx = 0; // set the dead code basic block as "taken" target for the conditional branch of the checking basic block deadCodeBasicBlock.entryBranches.Add(startBasicBlockExitBranch); startBasicBlockExitBranch.takenTarget = deadCodeBasicBlock; // generate dead code for the dead code basic block GraphTransformerDeadCodeBasicBlock deadCodeMetadata = new GraphTransformerDeadCodeBasicBlock(); deadCodeBasicBlock.transformationMetadata.Add(deadCodeMetadata); // set the created basic block and conditional jumps as output outStartBasicBlock = startBasicBlock; outConditionalBranch = startBasicBlockExitBranch; }