// ################################################### BRANCH MANIPULATION LOGIC ################################################### // insert the given new target basic block (given by start and end block) between the given branch to manipulate private void insertBasicBlockBetweenBranch(BasicBlock introBasicBlock, BasicBlock outroBasicBlock, IBranchTarget branchToManipulate, ref BasicBlock branchToManipulateTargetBasicBlock, BasicBlock newTargetStart, BasicBlock newTargetEnd, IBranchTarget exitBranch, ref BasicBlock exitBranchTargetBasicBlock) { // check if there exists try/handler blocks if (introBasicBlock.tryBlocks.Count() != 0) { throw new ArgumentException("Try blocks not yet implemented."); } if (introBasicBlock.handlerBlocks.Count() != 0) { throw new ArgumentException("Handler blocks not yet implemented."); } // add the new target given by basic blocks to the method cfg basic blocks if (!methodCfg.basicBlocks.Contains(newTargetStart)) { this.methodCfg.basicBlocks.Add(newTargetStart); } // recursively add all other basic blocks of the new target code to the method cfg if (newTargetStart.exitBranch as NoBranchTarget != null) { if (newTargetStart != newTargetEnd) { BasicBlock tempBB = ((NoBranchTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } } else if (newTargetStart.exitBranch as TryBlockTarget != null) { if (newTargetStart != newTargetEnd) { BasicBlock tempBB = ((TryBlockTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } } else if (newTargetStart.exitBranch as UnconditionalBranchTarget != null) { if (newTargetStart != newTargetEnd) { BasicBlock tempBB = ((UnconditionalBranchTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); } } else if (newTargetStart.exitBranch as ConditionalBranchTarget != null) { BasicBlock tempBB = ((ConditionalBranchTarget)newTargetStart.exitBranch).takenTarget; this.addBasicBlockToCfgRecursively(tempBB); tempBB = ((ConditionalBranchTarget)newTargetStart.exitBranch).notTakenTarget; this.addBasicBlockToCfgRecursively(tempBB); } else if (newTargetStart.exitBranch as SwitchBranchTarget != null) { BasicBlock tempBB = ((SwitchBranchTarget)newTargetStart.exitBranch).notTakenTarget; this.addBasicBlockToCfgRecursively(tempBB); foreach (BasicBlock takenTempBB in ((SwitchBranchTarget)newTargetStart.exitBranch).takenTarget) { this.addBasicBlockToCfgRecursively(takenTempBB); } } else if (newTargetStart.exitBranch as ExceptionBranchTarget != null) { BasicBlock tempBB = ((ExceptionBranchTarget)newTargetStart.exitBranch).exceptionTarget; this.addBasicBlockToCfgRecursively(tempBB); tempBB = ((ExceptionBranchTarget)newTargetStart.exitBranch).exitTarget; this.addBasicBlockToCfgRecursively(tempBB); } else { throw new ArgumentException("Do not know how to handle branch target in order to add all basic blocks to the method CFG."); } // add the branch to manipulate as the entry branch of the new target basic block newTargetStart.entryBranches.Add(branchToManipulate); // remove branch entry from old target outroBasicBlock.entryBranches.Remove(branchToManipulate); // make the given target basic block the new branch target branchToManipulateTargetBasicBlock = newTargetStart; // set branch as exit branch of the new last basic block of the new target code newTargetEnd.exitBranch = exitBranch; // set the last basic block of the new target as source of the exit branch exitBranch.sourceBasicBlock = newTargetEnd; exitBranchTargetBasicBlock = outroBasicBlock; // add branch to the list of entry branches of the original outro basic block // (if the exit branch of the new code is a no branch target => check if it is the only one that entries the outro basic block) if ((exitBranch as NoBranchTarget) != null) { foreach (IBranchTarget temp in outroBasicBlock.entryBranches) { if ((temp as NoBranchTarget) != null) { throw new ArgumentException("Only one 'No Branch Target' can be entry of a basic block."); } } } outroBasicBlock.entryBranches.Add(exitBranch); }
// this function replaces a basic block inside the cfg (oldBasicBlock) with a construction of new basic blocks (newBasicBlockStart and newBasicBlockEnd) public void replaceBasicBlock(BasicBlock oldBasicBlock, BasicBlock newBasicBlockStart, BasicBlock newBasicBlockEnd) { // add new basic blocks to cfg this.addBasicBlockToCfgRecursively(newBasicBlockStart); // add entry branches that enter the old basic block to the new basic block newBasicBlockStart.entryBranches.AddRange(oldBasicBlock.entryBranches); // exchange the target of the entry branches from the old basic block to the new one foreach (IBranchTarget entryBranch in new List <IBranchTarget>(oldBasicBlock.entryBranches)) { if ((entryBranch as NoBranchTarget) != null) { NoBranchTarget tempEntryBranch = (entryBranch as NoBranchTarget); // check sanity of entry branch if (tempEntryBranch.takenTarget != oldBasicBlock) { throw new ArgumentException("Entry branch must have old basic block as target."); } // set new basic block as target tempEntryBranch.takenTarget = newBasicBlockStart; } else if ((entryBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempEntryBranch = (entryBranch as UnconditionalBranchTarget); // check sanity of entry branch if (tempEntryBranch.takenTarget != oldBasicBlock) { throw new ArgumentException("Entry branch must have old basic block as target."); } // set new basic block as target tempEntryBranch.takenTarget = newBasicBlockStart; } else if ((entryBranch as ConditionalBranchTarget) != null) { ConditionalBranchTarget tempEntryBranch = (entryBranch as ConditionalBranchTarget); bool sanity = false; // change all branches to the old basic block to the new basic block if (tempEntryBranch.takenTarget == oldBasicBlock) { tempEntryBranch.takenTarget = newBasicBlockStart; sanity = true; } if (tempEntryBranch.notTakenTarget == oldBasicBlock) { tempEntryBranch.notTakenTarget = newBasicBlockStart; sanity = true; } // check sanity of entry branch if (!sanity) { throw new ArgumentException("Entry branch must have old basic block as target."); } } else if ((entryBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempEntryBranch = (entryBranch as SwitchBranchTarget); bool sanity = false; // change all branches to the old basic block to the new basic block if (tempEntryBranch.notTakenTarget == oldBasicBlock) { tempEntryBranch.notTakenTarget = newBasicBlockStart; sanity = true; } for (int idx = 0; idx < tempEntryBranch.takenTarget.Count(); idx++) { if (tempEntryBranch.takenTarget.ElementAt(idx) == oldBasicBlock) { tempEntryBranch.takenTarget[idx] = newBasicBlockStart; sanity = true; } } // check sanity of entry branch if (!sanity) { throw new ArgumentException("Entry branch must have old basic block as target."); } } else { throw new ArgumentException("Not yet implemented."); } // remove entry branch from the old basic block entry branches list oldBasicBlock.entryBranches.Remove(entryBranch); } IBranchTarget exitBranch = oldBasicBlock.exitBranch; // change the exit branch of the old basic block to be the exit branch of the new one exitBranch.sourceBasicBlock = newBasicBlockEnd; newBasicBlockEnd.exitBranch = exitBranch; // check if the old basic block was the start basic block of the cfg // => change it to the new basic block if (this.methodCfg.startBasicBlock == oldBasicBlock) { this.methodCfg.startBasicBlock = newBasicBlockStart; } // remove old basic block if it still belongs to the cfg if (this.methodCfg.basicBlocks.Contains(oldBasicBlock)) { this.methodCfg.basicBlocks.Remove(oldBasicBlock); } }
// 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; } } }
// this function generates and injects code into the given entry branch that moves the pointer from the source node to the target node private void injectLinkMoveCode(CfgManipulator cfgManipulator, BasicBlockGraphNodeLink startGraphLink, BasicBlockGraphNodeLink targetGraphLink, IBranchTarget entryBranch, int currentValidPathId, LocalDefinition currentNodeLocal) { NodeObject targetNode = targetGraphLink.graphNode; NodeObject startNode = startGraphLink.graphNode; IBranchTarget branchToManipulate = entryBranch; // do nothing if the source node is already the same as the target node if (startNode == targetNode) { return; } // check if the pointer have to be moved to the start pointer before it can be moved to the target element bool goToStart = false; if (startNode.positionInGraph.Count() >= targetNode.positionInGraph.Count()) { goToStart = true; } else { for (int idx = 0; idx < startNode.positionInGraph.Count(); idx++) { if (startNode.positionInGraph.ElementAt(idx) != targetNode.positionInGraph.ElementAt(idx)) { goToStart = true; break; } } } // set current graph link (is used for the metadata of the pointer correcting basic blocks BasicBlockGraphNodeLink currentGraphLink = new BasicBlockGraphNodeLink(startGraphLink.graphNode, currentValidPathId); // check how to move the pointer to the target element // => first go to the start pointer if (goToStart) { // generate and inject code that moves the pointer on a random path forward until the start node of the graph is reached while (startNode != this.graph.startingNode) { // generate code to move the pointer to the next node in the graph and inject it int nextNodeIdx = this.prng.Next(this.graphDimension); UnconditionalBranchTarget injectedExitBranch = new UnconditionalBranchTarget(); BasicBlock injectedBasicBlock = this.createCodeNextNode(injectedExitBranch, currentGraphLink, currentNodeLocal, nextNodeIdx, true); if ((branchToManipulate as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempBranchToManipulate = (branchToManipulate as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, injectedBasicBlock, injectedExitBranch); } else if ((branchToManipulate as SwitchBranchTarget) != null) { SwitchBranchTarget tempBranchToManipulate = (branchToManipulate as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, currentValidPathId, injectedBasicBlock, injectedExitBranch); } else { throw new ArgumentException("Not yet implemented."); // TODO } // set the next branch to manipulate as the newly created exit branch branchToManipulate = injectedExitBranch; // move pointer to the next node in the graph or to the start node if it does not exist if (startNode.nodeObjects[nextNodeIdx] == null) { startNode = this.graph.startingNode; } else { startNode = startNode.nodeObjects[nextNodeIdx]; } // create new graph link for the current node currentGraphLink = new BasicBlockGraphNodeLink(startNode, currentValidPathId); } // generate and inject code that moves the pointer to the correct position of the given graph node foreach (int nextNodeIdx in targetNode.positionInGraph) { // generate code to move the pointer to the next node in the graph and inject it UnconditionalBranchTarget injectedExitBranch = new UnconditionalBranchTarget(); BasicBlock injectedBasicBlock = this.createCodeNextNode(injectedExitBranch, currentGraphLink, currentNodeLocal, nextNodeIdx, true); if ((branchToManipulate as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempBranchToManipulate = (branchToManipulate as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, injectedBasicBlock, injectedExitBranch); } else if ((branchToManipulate as SwitchBranchTarget) != null) { SwitchBranchTarget tempBranchToManipulate = (branchToManipulate as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, currentValidPathId, injectedBasicBlock, injectedExitBranch); } else { throw new ArgumentException("Not yet implemented."); // TODO } // set the next branch to manipulate as the newly created exit branch branchToManipulate = injectedExitBranch; // move pointer to the next node in the graph or to the start node if it does not exist if (startNode.nodeObjects[nextNodeIdx] == null) { startNode = this.graph.startingNode; } else { startNode = startNode.nodeObjects[nextNodeIdx]; } // create new graph link for the current node currentGraphLink = new BasicBlockGraphNodeLink(startNode, currentValidPathId); } } // => go on a direct path to the target element else { // generate and inject code that moves the pointer to the correct position of the given graph node for (int idx = startNode.positionInGraph.Count(); idx < targetNode.positionInGraph.Count(); idx++) { // generate code to move the pointer to the next node in the graph and inject it UnconditionalBranchTarget injectedExitBranch = new UnconditionalBranchTarget(); BasicBlock injectedBasicBlock = this.createCodeNextNode(injectedExitBranch, currentGraphLink, currentNodeLocal, targetNode.positionInGraph.ElementAt(idx), true); if ((branchToManipulate as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempBranchToManipulate = (branchToManipulate as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, injectedBasicBlock, injectedExitBranch); } else if ((branchToManipulate as SwitchBranchTarget) != null) { SwitchBranchTarget tempBranchToManipulate = (branchToManipulate as SwitchBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempBranchToManipulate, currentValidPathId, injectedBasicBlock, injectedExitBranch); } else { throw new ArgumentException("Not yet implemented."); // TODO } // set the next branch to manipulate as the newly created exit branch branchToManipulate = injectedExitBranch; // move pointer to the next node in the graph or to the start node if it does not exist if (startNode.nodeObjects[targetNode.positionInGraph.ElementAt(idx)] == null) { startNode = this.graph.startingNode; } else { startNode = startNode.nodeObjects[targetNode.positionInGraph.ElementAt(idx)]; } // create new graph link for the current node currentGraphLink = new BasicBlockGraphNodeLink(startNode, currentValidPathId); } } // check if the final reached node is the same as the target node if (startNode != targetNode) { throw new ArgumentException("Current node and target node are not the same."); } }
// this function injects an opaque predicate to the target branch private void injectOpaquePredicateCode(CfgManipulator cfgManipulator, MethodCfg methodCfg, BasicBlock targetBasicBlock, IBranchTarget targetBranch, BasicBlockGraphNodeLink link, int opaquePredicate, LocalDefinition currentNodeLocal) { int currentValidPathId = link.validPathId; ConditionalBranchTarget opaqueExitBranch = null; // 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 if ((targetBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempTargetBranch = (targetBranch as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, 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 = targetBasicBlock.semanticId; // create intermediate basic block and inject it between correct opaque predicate branch and target basic block BasicBlock intermediateBasicBlock = new BasicBlock(); intermediateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br, 0)); methodCfg.basicBlocks.Add(intermediateBasicBlock); // add metadata to intermediate basic block GraphTransformerIntermediateBasicBlock metadataIntermediate = new GraphTransformerIntermediateBasicBlock(); metadataIntermediate.correspondingGraphNodes.Add(link); intermediateBasicBlock.transformationMetadata.Add(metadataIntermediate); // create intermediate exit branch UnconditionalBranchTarget intermediateBasicBlockExitBranch = new UnconditionalBranchTarget(); intermediateBasicBlockExitBranch.sourceBasicBlock = intermediateBasicBlock; intermediateBasicBlock.exitBranch = intermediateBasicBlockExitBranch; cfgManipulator.insertBasicBlockBetweenBranch(opaqueExitBranch, true, intermediateBasicBlock, intermediateBasicBlockExitBranch); 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 if ((targetBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempTargetBranch = (targetBranch as UnconditionalBranchTarget); cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, 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 = targetBasicBlock.semanticId; // create intermediate basic block and inject it between correct opaque predicate branch and target basic block BasicBlock intermediateBasicBlock = new BasicBlock(); intermediateBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br, 0)); methodCfg.basicBlocks.Add(intermediateBasicBlock); // add metadata to intermediate basic block GraphTransformerIntermediateBasicBlock metadataIntermediate = new GraphTransformerIntermediateBasicBlock(); metadataIntermediate.correspondingGraphNodes.Add(link); intermediateBasicBlock.transformationMetadata.Add(metadataIntermediate); // create intermediate exit branch UnconditionalBranchTarget intermediateBasicBlockExitBranch = new UnconditionalBranchTarget(); intermediateBasicBlockExitBranch.sourceBasicBlock = intermediateBasicBlock; intermediateBasicBlock.exitBranch = intermediateBasicBlockExitBranch; cfgManipulator.insertBasicBlockBetweenBranch(opaqueExitBranch, false, intermediateBasicBlock, intermediateBasicBlockExitBranch); 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."); } }
// 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."); } }
// this function generates code to move the current pointer to the next child node (or start node if there is no next child node) private BasicBlock createCodeNextNode(IBranchTarget usedExitBranch, BasicBlockGraphNodeLink graphLink, LocalDefinition currentNodeLocal, int index, bool correctNextNode) { // create graph transformer metadata for the basic blocks GraphTransformerNextNodeBasicBlock metadata = new GraphTransformerNextNodeBasicBlock(); metadata.correctNextNode = correctNextNode; metadata.correspondingGraphNodes.Add(graphLink); // create new basic block BasicBlock nextNodeBasicBlock = new BasicBlock(); nextNodeBasicBlock.startIdx = 0; nextNodeBasicBlock.endIdx = 0; nextNodeBasicBlock.transformationMetadata.Add(metadata); nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal)); nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4, index)); // TODO perhaps a more dynamically calculated index? nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceChildNodesGet)); nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, currentNodeLocal)); // check which exit branch is used to inject the code to the cfg and generate code for it accordingly if ((usedExitBranch as NoBranchTarget) != null) { nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Nop)); } else if ((usedExitBranch as UnconditionalBranchTarget) != null) { nextNodeBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Br)); } else { throw new ArgumentException("Do not know how to generate code for given exit branch."); } // add exit branch to newly created basic block nextNodeBasicBlock.exitBranch = usedExitBranch; usedExitBranch.sourceBasicBlock = nextNodeBasicBlock; return nextNodeBasicBlock; }