void FlowGraph::computeDefUseDist(){ uint32_t fcnt = function->getNumberOfInstructions(); std::pebil_map_type<uint64_t, X86Instruction*> imap; std::pebil_map_type<uint64_t, BasicBlock*> bmap; std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*> alliuses; std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*> allidefs; for (uint32_t i = 0; i < basicBlocks.size(); i++){ BasicBlock* bb = basicBlocks[i]; for (uint32_t j = 0; j < bb->getNumberOfInstructions(); j++){ X86Instruction* x = bb->getInstruction(j); for (uint32_t k = 0; k < x->getSizeInBytes(); k++){ ASSERT(imap.count(x->getBaseAddress() + k) == 0); ASSERT(bmap.count(x->getBaseAddress() + k) == 0); imap[x->getBaseAddress() + k] = x; bmap[x->getBaseAddress() + k] = bb; } ASSERT(alliuses.count(x->getBaseAddress()) == 0); ASSERT(allidefs.count(x->getBaseAddress()) == 0); alliuses[x->getBaseAddress()] = x->getUses(); allidefs[x->getBaseAddress()] = x->getDefs(); } } // For each loop for (uint32_t i = 0; i < loops.size(); ++i) { BasicBlock** allLoopBlocks = new BasicBlock*[loops[i]->getNumberOfBlocks()]; loops[i]->getAllBlocks(allLoopBlocks); uint64_t loopLeader = loops[i]->getHead()->getBaseAddress(); // For each block for (uint32_t j = 0; j < loops[i]->getNumberOfBlocks(); ++j){ BasicBlock* bb = allLoopBlocks[j]; // For each instruction for (uint32_t k = 0; k < bb->getNumberOfInstructions(); ++k){ X86Instruction* ins = bb->getInstruction(k); // Skip the instruction if it can't define anything if (!ins->isIntegerOperation() && !ins->isFloatPOperation() && !ins->isMoveOperation()) { continue; } ASSERT(!ins->usesControlTarget()); singleDefUse(this, ins, bb, loops[i], imap, bmap, alliuses, allidefs, k, loopLeader, fcnt); } } delete[] allLoopBlocks; } // handle all non-loop blocks for (uint32_t i = 0; i < getNumberOfBasicBlocks(); i++){ BasicBlock* bb = basicBlocks[i]; if (!isBlockInLoop(bb->getIndex())){ for (uint32_t k = 0; k < bb->getNumberOfInstructions(); ++k){ X86Instruction* ins = bb->getInstruction(k); if (!ins->isIntegerOperation() && !ins->isFloatPOperation() && !ins->isMoveOperation()) { continue; } ASSERT(!ins->usesControlTarget()); singleDefUse(this, ins, bb, NULL, imap, bmap, alliuses, allidefs, k, 0, fcnt); } } } for (uint32_t i = 0; i < basicBlocks.size(); i++){ BasicBlock* bb = basicBlocks[i]; for (uint32_t j = 0; j < bb->getNumberOfInstructions(); j++){ X86Instruction* x = bb->getInstruction(j); uint64_t addr = x->getBaseAddress(); ASSERT(alliuses.count(addr) == 1); LinkedList<X86Instruction::ReachingDefinition*>* l = alliuses[addr]; alliuses.erase(addr); while (!l->empty()){ delete l->shift(); } delete l; ASSERT(allidefs.count(addr) == 1); l = allidefs[addr]; allidefs.erase(addr); while (!l->empty()){ delete l->shift(); } delete l; } } ASSERT(alliuses.size() == 0); ASSERT(allidefs.size() == 0); }
void CallReplace::instrument(){ uint32_t temp32; uint64_t temp64; LineInfoFinder* lineInfoFinder = NULL; if (hasLineInformation()){ lineInfoFinder = getLineInfoFinder(); } InstrumentationPoint* p = addInstrumentationPoint(getProgramEntryBlock(), programEntry, InstrumentationMode_tramp, FlagsProtectionMethod_full, InstLocation_prior); ASSERT(p); if (!p->getInstBaseAddress()){ PRINT_ERROR("Cannot find an instrumentation point at the exit function"); } p = addInstrumentationPoint(getProgramExitBlock(), programExit, InstrumentationMode_tramp, FlagsProtectionMethod_full, InstLocation_prior); ASSERT(p); if (!p->getInstBaseAddress()){ PRINT_ERROR("Cannot find an instrumentation point at the exit function"); } uint64_t siteIndex = reserveDataOffset(sizeof(uint32_t)); programEntry->addArgument(siteIndex); Vector<X86Instruction*> myInstPoints; Vector<uint32_t> myInstList; Vector<LineInfo*> myLineInfos; for (uint32_t i = 0; i < getNumberOfExposedInstructions(); i++){ X86Instruction* instruction = getExposedInstruction(i); ASSERT(instruction->getContainer()->isFunction()); Function* function = (Function*)instruction->getContainer(); if (instruction->isFunctionCall()){ Symbol* functionSymbol = getElfFile()->lookupFunctionSymbol(instruction->getTargetAddress()); if (functionSymbol){ //PRINT_INFOR("looking for function %s", functionSymbol->getSymbolName()); uint32_t funcIdx = searchFileList(functionList, functionSymbol->getSymbolName()); if (funcIdx < (*functionList).size()){ BasicBlock* bb = function->getBasicBlockAtAddress(instruction->getBaseAddress()); ASSERT(bb->containsCallToRange(0,-1)); ASSERT(instruction->getSizeInBytes() == Size__uncond_jump); myInstPoints.append(instruction); myInstList.append(funcIdx); LineInfo* li = NULL; if (lineInfoFinder){ li = lineInfoFinder->lookupLineInfo(bb); } myLineInfos.append(li); } } } } ASSERT(myInstPoints.size() == myInstList.size()); ASSERT(myLineInfos.size() == myInstList.size()); uint64_t fileNames = reserveDataOffset(sizeof(char*) * myInstList.size()); uint64_t lineNumbers = reserveDataOffset(sizeof(uint32_t) * myInstList.size()); for (uint32_t i = 0; i < myInstList.size(); i++){ uint32_t line = 0; char* fname = NOSTRING; if (myLineInfos[i]){ line = myLineInfos[i]->GET(lr_line); fname = myLineInfos[i]->getFileName(); } uint64_t filenameaddr = getInstDataAddress() + reserveDataOffset(strlen(fname) + 1); initializeReservedData(getInstDataAddress() + fileNames + i*sizeof(char*), sizeof(char*), &filenameaddr); initializeReservedData(filenameaddr, strlen(fname), fname); initializeReservedData(getInstDataAddress() + lineNumbers + i*sizeof(uint32_t), sizeof(uint32_t), &line); } programEntry->addArgument(fileNames); programEntry->addArgument(lineNumbers); for (uint32_t i = 0; i < myInstPoints.size(); i++){ PRINT_INFOR("(site %d) %#llx: replacing call %s -> %s in function %s", i, myInstPoints[i]->getBaseAddress(), getFunctionName(myInstList[i]), getWrapperName(myInstList[i]), myInstPoints[i]->getContainer()->getName()); InstrumentationPoint* pt = addInstrumentationPoint(myInstPoints[i], functionWrappers[myInstList[i]], InstrumentationMode_tramp, FlagsProtectionMethod_none, InstLocation_replace); if (getElfFile()->is64Bit()){ pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + getRegStorageOffset())); pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveImmToReg(i, X86_REG_CX)); pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + siteIndex)); pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveMemToReg(getInstDataAddress() + getRegStorageOffset(), X86_REG_CX, true)); } else { pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + getRegStorageOffset())); pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveImmToReg(i, X86_REG_CX)); pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + siteIndex)); pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveMemToReg(getInstDataAddress() + getRegStorageOffset(), X86_REG_CX)); } } }
inline void singleDefUse(FlowGraph* fg, X86Instruction* ins, BasicBlock* bb, Loop* loop, std::pebil_map_type<uint64_t, X86Instruction*>& ipebil_map_type, std::pebil_map_type<uint64_t, BasicBlock*>& bpebil_map_type, std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*>& alliuses, std::pebil_map_type<uint64_t, LinkedList<X86Instruction::ReachingDefinition*>*>& allidefs, int k, uint64_t loopLeader, uint32_t fcnt){ // Get defintions for this instruction: ins LinkedList<X86Instruction::ReachingDefinition*>* idefs = ins->getDefs(); LinkedList<X86Instruction::ReachingDefinition*>* allDefs = idefs; // Skip instruction if it doesn't define anything if (idefs == NULL) { return; } if (idefs->empty()) { delete idefs; return; } set<LinkedList<X86Instruction::ReachingDefinition*>*> allDefLists; allDefLists.insert(idefs); PriorityQueue<struct path*, uint32_t> paths = PriorityQueue<struct path*, uint32_t>(); bool blockTouched[fg->getFunction()->getNumberOfBasicBlocks()]; bzero(&blockTouched, sizeof(bool) * fg->getFunction()->getNumberOfBasicBlocks()); // Initialize worklist with the path from this instruction // Only take paths inside the loop. Since the definitions are in a loop, uses in the loop will be most relevant. if (k == bb->getNumberOfInstructions() - 1){ ASSERT(ins->controlFallsThrough()); if (bb->getNumberOfTargets() > 0){ ASSERT(bb->getNumberOfTargets() == 1); if (flowsInDefUseScope(bb->getTargetBlock(0), loop)){ // Path flows to the first instruction of the next block paths.insert(new path(bb->getTargetBlock(0)->getLeader(), idefs), 1); } } } else { // path flows to the next instruction in this block paths.insert(new path(bb->getInstruction(k+1), idefs), 1); } // while there are paths in worklist while (!paths.isEmpty()) { // take the shortest path in list uint32_t currDist; struct path* p = paths.deleteMin(&currDist); X86Instruction* cand = p->ins; idefs = p->defs; delete p; LinkedList<X86Instruction::ReachingDefinition*>* i2uses, *i2defs, *newdefs; i2uses = alliuses[cand->getBaseAddress()]; // Check if any of idefs is used if(i2uses != NULL && anyDefsAreUsed(idefs, i2uses)){ // Check if use is shortest uint32_t duDist; duDist = trueDefUseDist(currDist, fcnt); if (!ins->getDefUseDist() || ins->getDefUseDist() > duDist) { ins->setDefUseDist(duDist); } // If dist has increased beyond size of function, we must be looping? if (currDist > fcnt) { ins->setDefXIter(); break; } // Stop searching along this path continue; } // Check if any defines are overwritten i2defs = allidefs[cand->getBaseAddress()]; newdefs = removeInvalidated(idefs, i2defs); // If all definitions killed, stop searching along this path if (newdefs == NULL) continue; allDefLists.insert(newdefs); // end of block that is a branch if (cand->usesControlTarget() && !cand->isCall()){ BasicBlock* tgtBlock = bpebil_map_type[cand->getTargetAddress()]; if (tgtBlock && !blockTouched[tgtBlock->getIndex()] && flowsInDefUseScope(tgtBlock, loop)){ blockTouched[tgtBlock->getIndex()] = true; if (tgtBlock->getBaseAddress() == loopLeader){ paths.insert(new path(tgtBlock->getLeader(), newdefs), loopXDefUseDist(currDist + 1, fcnt)); } else { paths.insert(new path(tgtBlock->getLeader(), newdefs), currDist + 1); } } } // non-branching control if (cand->controlFallsThrough()){ BasicBlock* tgtBlock = bpebil_map_type[cand->getBaseAddress() + cand->getSizeInBytes()]; if (tgtBlock && flowsInDefUseScope(tgtBlock, loop)){ X86Instruction* ftTarget = ipebil_map_type[cand->getBaseAddress() + cand->getSizeInBytes()]; if (ftTarget){ if (ftTarget->isLeader()){ if (!blockTouched[tgtBlock->getIndex()]){ blockTouched[tgtBlock->getIndex()] = true; if (ftTarget->getBaseAddress() == loopLeader){ paths.insert(new path(ftTarget, newdefs), loopXDefUseDist(currDist + 1, fcnt)); } else { paths.insert(new path(ftTarget, newdefs), currDist + 1); } } } else { paths.insert(new path(ftTarget, newdefs), currDist + 1); } } } } } if (!paths.isEmpty()){ ins->setDefUseDist(0); } while (!paths.isEmpty()){ delete paths.deleteMin(NULL); } while (!allDefs->empty()){ delete allDefs->shift(); } for(set<LinkedList<X86Instruction::ReachingDefinition*>*>::iterator it = allDefLists.begin(); it != allDefLists.end(); ++it){ delete *it; } }