void instrumentFunction(BPatch_function *function) { std::set<BPatch_basicBlock*> blocks; std::set<BPatch_basicBlock*>::reverse_iterator b; BPatch_flowGraph *cfg = function->getCFG(); cfg->getAllBasicBlocks(blocks); for (b = blocks.rbegin(); b != blocks.rend(); b++) { instrumentBasicBlock(function, *b); } }
// inserts a callback for each basic block assigning it an instrumentation // time 16bit random ID just as afl bool insertBBCallback(BPatch_binaryEdit * appBin, BPatch_function * curFunc, char *funcName, BPatch_function * instBBIncFunc,int *bbIndex) { BPatch_flowGraph *appCFG = curFunc->getCFG (); unsigned short randID; if (!appCFG) { cerr << "Failed to find CFG for function " << funcName << endl; return false; } BPatch_Set < BPatch_basicBlock * >allBlocks; if (!appCFG->getAllBasicBlocks (allBlocks)) { cerr << "Failed to find basic blocks for function " << funcName << endl; return false; } else if (allBlocks.size () == 0) { cerr << "No basic blocks for function " << funcName << endl; return false; } BPatch_Set < BPatch_basicBlock * >::iterator iter; for (iter = allBlocks.begin (); iter != allBlocks.end (); iter++) { if(*bbIndex < bbSkip) { // skip over first bbSkip bbs (*bbIndex)++; continue; } unsigned long address = (*iter)->getStartAddress (); randID = rand() % USHRT_MAX; if(verbose) { cout << "Instrumenting Basic Block 0x" << hex << address << " of " << funcName << " with random id " << randID << endl; } BPatch_Vector < BPatch_snippet * >instArgs; BPatch_constExpr bbId (randID); instArgs.push_back (&bbId); BPatch_point *bbEntry = (*iter)->findEntryPoint (); if (NULL == bbEntry) { // warn the user, but continue cerr << "Failed to find entry for basic block at 0x" << hex << address << endl; (*bbIndex)++; continue; } BPatch_funcCallExpr instIncExpr (*instBBIncFunc, instArgs); BPatchSnippetHandle *handle = appBin->insertSnippet (instIncExpr, *bbEntry, BPatch_callBefore, BPatch_lastSnippet); if (!handle) { // warn the user, but continue to next bb cerr << "Failed to insert instrumention in basic block at 0x" << hex << address << endl; (*bbIndex)++; continue; } (*bbIndex)++; } return true; }
bool instrumentMemoryWrites(dynHandle *dh, BPatch_function *func) { BPatch_Set<BPatch_basicBlock*> allBlocks; BPatch_snippet incSnippet; BPatch_Set<BPatch_opCode> ops; BPatch_Set<BPatch_basicBlock*>::iterator iter; int bb_warn_cnt = 0, bb_pass_cnt = 0; sendMsg(config.outfd, ID_INST_MEM_WRITE, VERB2); sendMsg(config.outfd, ID_GET_CFG, VERB3); BPatch_flowGraph *appCFG = func->getCFG(); if (!appCFG) { sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_FAIL, "Failure in BPatch_function::getCFG()"); goto fail; } else { sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_PASS); } sendMsg(config.outfd, ID_INST_GET_BB, VERB3); if (!appCFG->getAllBasicBlocks(allBlocks)) { sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_FAIL, "Failure in BPatch_flowGraph::getAllBasicBlocks()"); goto fail; } else if (allBlocks.size() == 0) { sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_WARN, "No basic blocks found in function"); goto fail; } else { sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_PASS); } if (! generateInstrumentation (dh, func, &incSnippet)) goto fail; ops.insert(BPatch_opStore); sendMsg(config.outfd, ID_INST_BB_LIST, VERB3); for (iter = allBlocks.begin(); iter != allBlocks.end(); iter++) { if (!shouldInsert()) continue; sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4); BPatch_Vector<BPatch_point*> *points = (*iter)->findPoint(ops); if (!points) { sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_WARN, "Failure in BPatch_basicBlock::findPoint()"); ++bb_warn_cnt; continue; } else if (points->size() == 0) { sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_WARN, "No instrumentation points found in basic block"); ++bb_warn_cnt; continue; } else { sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_PASS); } sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4); BPatchSnippetHandle *handle = dh->addSpace->insertSnippet(incSnippet, *points); if (!handle) { sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_FAIL, "Failure in BPatch_process::insertSnippet()"); ++bb_warn_cnt; continue; } else { sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_PASS); ++bb_pass_cnt; } } if (bb_warn_cnt) sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_WARN, sprintf_static("%d warning(s), %d passed.", bb_warn_cnt, bb_pass_cnt)); else sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_PASS); sendMsg(config.outfd, ID_INST_MEM_WRITE, VERB2, ID_PASS); return true; fail: sendMsg(config.outfd, ID_INST_MEM_WRITE, VERB2, ID_WARN, "Failure while instrumenting memory writes."); return false; }
test_results_t test1_33_Mutator::executeTest() { int pvalue; unsigned int i; if (isMutateeFortran(appImage)) { return SKIPPED; } BPatch_Vector<BPatch_function *> bpfv; const char *fn = "test1_33_func2"; if (NULL == appImage->findFunction(fn, bpfv) || !bpfv.size() || NULL == bpfv[0]) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Unable to find function %s\n", fn); return FAILED; } BPatch_function *func2 = bpfv[0]; BPatch_flowGraph *cfg = func2->getCFG(); if (cfg == NULL) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Unable to get control flow graph of %s\n", fn); return FAILED; } /* * Test for consistency of entry basic blocks. */ BPatch_Vector<BPatch_basicBlock*> entry_blocks; cfg->getEntryBasicBlock(entry_blocks); if (entry_blocks.size() != 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected %d entry basic blocks in %s, should have been one.\n", entry_blocks.size(), fn); return FAILED; } for (i = 0; i < entry_blocks.size(); i++) { BPatch_Vector<BPatch_basicBlock*> sources; entry_blocks[i]->getSources(sources); if (sources.size() > 0) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" An entry basic block has incoming edges in the control flow graph\n"); return FAILED; } BPatch_Vector<BPatch_basicBlock*> targets; entry_blocks[i]->getTargets(targets); if (targets.size() < 1) { logerror("**Failed** test #33 (control flow graphs\n"); logerror(" An entry basic block has no outgoing edges in the control flow graph\n"); return FAILED; } } /* * Test for consistency of exit basic blocks. */ BPatch_Vector<BPatch_basicBlock*> exit_blocks; cfg->getExitBasicBlock(exit_blocks); if (exit_blocks.size() != 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected %d exit basic blocks in %s, should have been one.\n", exit_blocks.size(), fn); return FAILED; } for (i = 0; i < exit_blocks.size(); i++) { BPatch_Vector<BPatch_basicBlock*> sources; exit_blocks[i]->getSources(sources); if (sources.size() < 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" An exit basic block has no incoming edges in the control flow graph\n"); return FAILED; } BPatch_Vector<BPatch_basicBlock*> targets; exit_blocks[i]->getTargets(targets); if (targets.size() > 0) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" An exit basic block has outgoing edges in the control flow graph\n"); return FAILED; } } /* * Check structure of control flow graph. */ std::set<BPatch_basicBlock*> blocks; cfg->getAllBasicBlocks(blocks); if (blocks.size() < 4) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected %d basic blocks in %s, should be at least four.\n", blocks.size(), fn); return FAILED; } bool foundOutDegreeTwo = false; bool foundInDegreeTwo = false; int blocksNoIn = 0, blocksNoOut = 0; for (std::set<BPatch_basicBlock *>::iterator iter = blocks.begin(); iter != blocks.end(); ++iter) { BPatch_Vector<BPatch_basicBlock*> in; BPatch_Vector<BPatch_basicBlock*> out; (*iter)->getSources(in); (*iter)->getTargets(out); if (in.size() == 0) blocksNoIn++; if (out.size() == 0) blocksNoOut++; if (in.size() > 2 || out.size() > 2) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected a basic block in %s with %d incoming edges and %d\n", fn, in.size(), out.size()); logerror(" outgoing edges - neither should be greater than two.\n"); return FAILED; } else if (in.size() > 1 && out.size() > 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected a basic block in %s with %d incoming edges and %d\n", fn, in.size(), out.size()); logerror(" outgoing edges - only one should be greater than one.\n"); return FAILED; } else if (in.size() == 0 && out.size() == 0) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected a basic block in %s with no incoming or outgoing edges.\n", fn); return FAILED; } else if (in.size() == 2) { assert(out.size() <= 1); if (foundInDegreeTwo) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected two basic blocks in %s with in degree two, there should only\n", fn); logerror(" be one.\n"); return FAILED; } foundInDegreeTwo = true; if (in[0]->getBlockNumber() == in[1]->getBlockNumber()) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Two edges go to the same block (number %d).\n", in[0]->getBlockNumber()); return FAILED; } } else if (out.size() == 2) { assert(in.size() <= 1); if (foundOutDegreeTwo) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected two basic blocks in %s with out degree two, there should only\n", fn); logerror(" be one.\n"); return FAILED; } foundOutDegreeTwo = true; if (out[0]->getBlockNumber() == out[1]->getBlockNumber()) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Two edges go to the same block (number %d).\n", out[0]->getBlockNumber()); return FAILED; } } else if (in.size() > 1 || out.size() > 1) { /* Shouldn't be able to get here. */ logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected a basic block in %s with %d incoming edges and %d\n", fn, in.size(), out.size()); logerror(" outgoing edges.\n"); return FAILED; } } if (blocksNoIn > 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected more than one block in %s with no incoming edges.\n", fn); return FAILED; } if (blocksNoOut > 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected more than block in %s with no outgoing edges.\n", fn); return FAILED; } if (!foundOutDegreeTwo) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Did not detect the \"if\" statement in %s.\n", fn); return FAILED; } /* * Check for loops (there aren't any in the function we're looking at). */ std::set<int> empty; if (hasBackEdge(entry_blocks[0], empty)) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected a loop in %s, there should not be one.\n", fn); return FAILED; } /* * Now check a function with a switch statement. */ bpfv.clear(); const char *fn2 = "test1_33_func3"; // Bernat, 8JUN05 -- include uninstrumentable here... if (NULL == appImage->findFunction(fn2, bpfv, false, false, true) || !bpfv.size() || NULL == bpfv[0]) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Unable to find function %s\n", fn2); return FAILED; } BPatch_function *func3 = bpfv[0]; BPatch_flowGraph *cfg3 = func3->getCFG(); if (cfg3 == NULL) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Unable to get control flow graph of %s\n", fn2); return FAILED; } std::set<BPatch_basicBlock*> blocks3; cfg3->getAllBasicBlocks(blocks3); if (blocks3.size() < 10) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected %d basic blocks in %s, should be at least ten.\n", blocks3.size(), fn2); return FAILED; } bool foundSwitchIn = false; bool foundSwitchOut = false; bool foundRangeCheck = false; for (std::set<BPatch_basicBlock *>::iterator iter = blocks3.begin(); iter != blocks3.end(); ++iter) { BPatch_basicBlock *block = *iter; BPatch_Vector<BPatch_basicBlock*> in; BPatch_Vector<BPatch_basicBlock*> out; block->getSources(in); block->getTargets(out); if (!foundSwitchOut && out.size() >= 10 && in.size() <= 1) { foundSwitchOut = true; } else if (!foundSwitchIn && in.size() >= 10 && out.size() <= 1) { foundSwitchIn = true; } else if (!foundRangeCheck && out.size() == 2 && in.size() <= 1) { foundRangeCheck = true; } else if (in.size() > 1 && out.size() > 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Found basic block in %s with unexpected number of edges.\n", fn2); logerror(" %d incoming edges, %d outgoing edges.\n", in.size(), out.size()); return FAILED; } } if (!foundSwitchIn || !foundSwitchOut) { logerror("**Failed** test #33 (control flow graphs)\n"); if (!foundSwitchIn) logerror(" Did not find \"switch\" statement in %s.\n", fn2); if (!foundSwitchOut) logerror(" Did not find block after \"switch\" statement.\n"); return FAILED; } /* Check dominator info. */ BPatch_Vector<BPatch_basicBlock*> entry3; cfg3->getEntryBasicBlock(entry3); if (entry3.size() != 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected %d entry basic blocks in %s, should have been one.\n", entry_blocks.size(), fn2); return FAILED; } for (std::set<BPatch_basicBlock *>::iterator iter2 = blocks3.begin(); iter2 != blocks3.end(); ++iter2) { if (!entry3[0]->dominates(*iter2)) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Entry block does not dominate all blocks in %s\n", fn2); return FAILED; } } BPatch_Vector<BPatch_basicBlock*> exit3; cfg3->getExitBasicBlock(exit3); if (exit3.size() != 1) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Detected %d exit basic blocks in %s, should have been one.\n", exit3.size(), fn2); for (unsigned i = 0; i < exit3.size(); ++i) { logerror("\t%d: 0x%lx\n", i, exit3[i]->getStartAddress()); } return FAILED; } for (i = 0; i < (unsigned int) exit3.size(); i++) { if (!exit3[i]->postdominates(entry3[0])) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Exit block %d does not postdominate all entry blocks in %s\n", i, fn2); return FAILED; } } #if !defined(os_windows_test) && defined(ENABLE_PARSE_API_GRAPHS) logerror("Testing parseAPI dominators\n"); ParseAPI::Function* parse_func = ParseAPI::convert(func3); assert(parse_func); Block* parse_entry = parse_func->entry(); bool parse_idoms_ok = true; for(Function::blocklist::const_iterator bl = parse_func->blocks().begin(); bl != parse_func->blocks().end(); ++bl) { if(*bl == parse_entry) continue; if(!dominates(*parse_func, parse_entry, *bl)) { parse_idoms_ok = false; } } if(!parse_idoms_ok) { logerror("**Failed** test #33 (CFG)\n"); logerror(" ParseAPI dominator algorithm does not have entry block dominating all blocks in function\n"); return FAILED; } #endif BPatch_variableExpr *expr33_1 = appImage->findVariable("test1_33_globalVariable1"); if (expr33_1 == NULL) { logerror("**Failed** test #33 (control flow graphs)\n"); logerror(" Unable to locate test1_33_globalVariable1\n"); return FAILED; } pvalue = 1; expr33_1->writeValue(&pvalue); return PASSED; }
int main(int argc, char *argv[], char* envp[]) { if (argc < 2) { fprintf(stderr, "Usage: %s prog_filename prog_aruments\n", argv[0]); return 3; } #if 0 if (strcmp(argv[1], "prog") != 0 && strcmp(argv[1], "all")) { fprintf(stderr, "Options for patch selection are 'progonly' or 'all'\n"); return 3; } #endif int patchall = 0; //strcmp(argv[1], "all") != 0; // Create process BPatch_process *appProc = bpatch.processCreate(argv[1], (const char**) &(argv[1])); // Load pthread into the process... appProc->loadLibrary("libpthread.so.0"); // Get the process image BPatch_image *appImage = appProc->getImage(); // Find all the instrumentable procedures BPatch_Vector<BPatch_function*> *functions = appImage->getProcedures(); /************************************************************************* * General function search * *************************************************************************/ // Find the printf function BPatch_Vector<BPatch_function*> printfFuncs; appImage->findFunction("printf", printfFuncs); if (printfFuncs.size() == 0) appImage->findFunction("_printf", printfFuncs); if (printfFuncs.size() == 0) appImage->findFunction("__printf", printfFuncs); if(printfFuncs.size() == 0) { fprintf(stderr, "Could not find printf() function"); return 2; } // Find the exit function BPatch_Vector<BPatch_function*> exitFuncs; appImage->findFunction("exit", exitFuncs); if (exitFuncs.size() == 0) appImage->findFunction("_exit", exitFuncs); if (exitFuncs.size() == 0) appImage->findFunction("__exit", exitFuncs); if(exitFuncs.size() == 0) { fprintf(stderr, "Could not find exit() function"); return 2; } // Find the perror function BPatch_Vector<BPatch_function*> perrorFuncs; appImage->findFunction("perror", perrorFuncs); if (perrorFuncs.size() == 0) appImage->findFunction("_perror", perrorFuncs); if (perrorFuncs.size() == 0) appImage->findFunction("__perror", perrorFuncs); if(perrorFuncs.size() == 0) { fprintf(stderr, "Could not find perror() function"); return 2; } BPatch_Vector<BPatch_snippet*> mainEntryBlock; /************************************************************************ * Error exit call * ************************************************************************/ BPatch_Vector<BPatch_snippet*> exitArgs; BPatch_constExpr exitCode(-2); exitArgs.push_back(&exitCode); // Open call BPatch_funcCallExpr exitOnErrorCall(*exitFuncs[0], exitArgs); /************************************************************************ * Open imitate device patch * * **********************************************************************/ // Find main() BPatch_Vector<BPatch_function*> mainFunctions; appImage->findFunction("main", mainFunctions); if (mainFunctions.size() == 0) appImage->findFunction("_main", mainFunctions); if (mainFunctions.size() == 0) appImage->findFunction("__main", mainFunctions); if(mainFunctions.size() == 0) { fprintf(stderr, "Could not find main() function"); return 2; } // find open() BPatch_Vector<BPatch_function*> openFunctions; appImage->findFunction("open64", openFunctions); if (openFunctions.size() == 0) appImage->findFunction("open", openFunctions); if (openFunctions.size() == 0) appImage->findFunction("_open", openFunctions); if (openFunctions.size() == 0) appImage->findFunction("__open", openFunctions); if(openFunctions.size() == 0) { fprintf(stderr, "Could not find open() function"); return 2; } // Get main() entry point BPatch_Vector<BPatch_point*> *mainPoints = mainFunctions[0]->findPoint(BPatch_entry); // Open call arguments BPatch_Vector<BPatch_snippet*> openArgs; BPatch_constExpr fileName("/dev/imitate0"); BPatch_constExpr fileFlags(O_RDWR); openArgs.push_back(&fileName); openArgs.push_back(&fileFlags); // Open call BPatch_funcCallExpr openDevCall(*openFunctions[0], openArgs); // Allocate file descriptor BPatch_variableExpr *devFd = appProc->malloc(*appImage->findType("int")); // Assign fd with result of open call BPatch_arithExpr openDevice(BPatch_assign, *devFd, openDevCall); // defFd check BPatch_boolExpr devFdCheck(BPatch_lt, *devFd, BPatch_constExpr(0)); // perror message BPatch_Vector<BPatch_snippet*> devFdErrorArgs; BPatch_constExpr devFdErrorMsg("Opening imitate kernel device"); devFdErrorArgs.push_back(&devFdErrorMsg); BPatch_funcCallExpr devFdError(*perrorFuncs[0], devFdErrorArgs); BPatch_Vector<BPatch_snippet*> openErrorBlock; openErrorBlock.push_back(&devFdError); openErrorBlock.push_back(&exitOnErrorCall); // if (devFd < 0) { perror(...) } BPatch_ifExpr devFdBlock(devFdCheck, BPatch_sequence(openErrorBlock)); mainEntryBlock.push_back(&openDevice); mainEntryBlock.push_back(&devFdBlock); /************************************************************************* * Send ioctl IMITATE_APP_RECORD to module * *************************************************************************/ // find ioctl() BPatch_Vector<BPatch_function*> ioctlFunctions; appImage->findFunction("ioctl", ioctlFunctions); if (ioctlFunctions.size() == 0) appImage->findFunction("_ioctl", ioctlFunctions); if (ioctlFunctions.size() == 0) appImage->findFunction("__ioctl", ioctlFunctions); if(ioctlFunctions.size() == 0) { fprintf(stderr, "Could not find ioctl() function"); return 2; } // ioctl() arguments BPatch_Vector<BPatch_snippet*> ioctlArgs; BPatch_constExpr operation(IMITATE_APP_RECORD); fprintf(stderr, "PPID: %d\n", getppid()); BPatch_constExpr monitorPid(getppid()); ioctlArgs.push_back(devFd); ioctlArgs.push_back(&operation); ioctlArgs.push_back(&monitorPid); // ioctl() call BPatch_funcCallExpr ioctlCall(*ioctlFunctions[0], ioctlArgs); // ioctl() result check BPatch_boolExpr ioctlCheck(BPatch_lt, ioctlCall, BPatch_constExpr(0)); // perror message BPatch_Vector<BPatch_snippet*> ioctlErrorArgs; BPatch_constExpr ioctlErrorMsg("Notifying imitate kernel driver of RECORD"); ioctlErrorArgs.push_back(&ioctlErrorMsg); BPatch_funcCallExpr ioctlError(*perrorFuncs[0], ioctlErrorArgs); BPatch_Vector<BPatch_snippet*> ioctlErrorBlock; ioctlErrorBlock.push_back(&ioctlError); ioctlErrorBlock.push_back(&exitOnErrorCall); // if (ioctl(...) < 0) { perror(...) } BPatch_ifExpr ioctlBlock(ioctlCheck, BPatch_sequence(ioctlErrorBlock)); // Add ioctl check to entry block mainEntryBlock.push_back(&ioctlBlock); /************************************************************************* * Counter mmap() * *************************************************************************/ // Find the mmap function BPatch_Vector<BPatch_function*> mmapFuncs; appImage->findFunction("mmap", mmapFuncs); if (mmapFuncs.size() == 0) appImage->findFunction("_mmap", mmapFuncs); if (mmapFuncs.size() == 0) appImage->findFunction("__mmap", mmapFuncs); if(mmapFuncs.size() == 0) { fprintf(stderr, "Could not find mmap() function"); return 2; } // Allocate counter BPatch_variableExpr *counterAddr = appProc->malloc(sizeof(sched_counter_t*)); sched_counter_t counterVal = 0; counterAddr->writeValue(&counterVal, sizeof(sched_counter_t*), false); // Notify kernel of address BPatch_Vector<BPatch_snippet*> mmapArgs; BPatch_constExpr mmapStart(0); BPatch_constExpr mmapLength(sizeof(sched_counter_t)); BPatch_constExpr mmapProt(PROT_READ | PROT_WRITE); BPatch_constExpr mmapFlags(MAP_SHARED); BPatch_constExpr mmapOffset(0); mmapArgs.push_back(&mmapStart); mmapArgs.push_back(&mmapLength); mmapArgs.push_back(&mmapProt); mmapArgs.push_back(&mmapFlags); mmapArgs.push_back(devFd); mmapArgs.push_back(&mmapOffset); // mmap() call BPatch_funcCallExpr mmapCall(*mmapFuncs[0], mmapArgs); // assign result to counterAddr BPatch_arithExpr mmapAssign(BPatch_assign, *counterAddr, mmapCall); // Add to entry block mainEntryBlock.push_back(&mmapAssign); // mmap() result check BPatch_boolExpr mmapCheck(BPatch_eq, *counterAddr, BPatch_constExpr(MAP_FAILED)); // perror message BPatch_Vector<BPatch_snippet*> mmapErrorArgs; BPatch_constExpr mmapErrorMsg("Memory mapping schedule (back edge) counter"); mmapErrorArgs.push_back(&mmapErrorMsg); BPatch_funcCallExpr mmapError(*perrorFuncs[0], mmapErrorArgs); BPatch_Vector<BPatch_snippet*> mmapErrorBlock; mmapErrorBlock.push_back(&mmapError); mmapErrorBlock.push_back(&exitOnErrorCall); // if (mmap(...) == MAP_FAILED) { perror(...) } BPatch_ifExpr mmapBlock(mmapCheck, BPatch_sequence(mmapErrorBlock)); mainEntryBlock.push_back(&mmapBlock); // Patch main entry BPatch_sequence mainEntrySeq(mainEntryBlock); appProc->insertSnippet(mainEntrySeq, *mainPoints); /************************************************************************* * Back-edge patching * *************************************************************************/ #if 0 printf("intCounter address: %x\n PID: %d\n", intCounter->getBaseAddr(), appProc->getPid()); fflush(stdout); #endif // Find the mutex lock/unlock functions BPatch_Vector<BPatch_function*> mutexLockFunctions; appImage->findFunction("pthread_mutex_lock", mutexLockFunctions); if (mutexLockFunctions.size() == 0) appImage->findFunction("_pthread_mutex_lock", mutexLockFunctions); if (mutexLockFunctions.size() == 0) appImage->findFunction("__pthread_mutex_lock", mutexLockFunctions); if(mutexLockFunctions.size() == 0) { fprintf(stderr, "Could not find pthread_mutex_lock() function"); return 2; } BPatch_Vector<BPatch_function*> mutexUnlockFunctions; appImage->findFunction("pthread_mutex_unlock", mutexUnlockFunctions); if (mutexUnlockFunctions.size() == 0) appImage->findFunction("_pthread_mutex_unlock", mutexUnlockFunctions); if (mutexUnlockFunctions.size() == 0) appImage->findFunction("__pthread_mutex_unlock", mutexUnlockFunctions); if(mutexUnlockFunctions.size() == 0) { fprintf(stderr, "Could not find pthread_mutex_unlock() function"); return 2; } // Allocate a mutex pthread_mutex_t mutexValue = PTHREAD_MUTEX_INITIALIZER; BPatch_variableExpr *mutex = appProc->malloc(sizeof(pthread_mutex_t)); mutex->writeValue(&mutexValue, sizeof(pthread_mutex_t), false); // Build mutex lock call BPatch_Vector<BPatch_snippet*> mutexArgs; BPatch_constExpr mutexAddress(mutex->getBaseAddr()); mutexArgs.push_back(&mutexAddress); BPatch_funcCallExpr mutexLockCall(*mutexLockFunctions[0], mutexArgs); BPatch_funcCallExpr mutexUnlockCall(*mutexUnlockFunctions[0], mutexArgs); BPatch_arithExpr derefCounter(BPatch_deref, *counterAddr); // Create 'increment counter' snippet BPatch_arithExpr addOneToCounter(BPatch_assign, derefCounter, BPatch_arithExpr(BPatch_plus, derefCounter, BPatch_constExpr(1))); BPatch_Vector<BPatch_snippet*> snippet; snippet.push_back(&mutexLockCall); snippet.push_back(&addOneToCounter); snippet.push_back(&mutexUnlockCall); BPatch_sequence addOneAtomic(snippet); char *name = (char*) malloc(sizeof(char)*200); char *modname = (char*) malloc(sizeof(char)*200); if (! (name && modname)) { fprintf(stderr, "%s %d: Out of memory!", __FILE__, __LINE__); return 1; } appProc->beginInsertionSet(); // Iterate through the procedures for (int i = 0; i < functions->size(); i++) { (*functions)[i]->getName(name, 199); (*functions)[i]->getModuleName(modname, 199); if ((patchall && strcmp(modname, "DEFAULT_MODULE") != 0) || strncmp(name, "pthread", 7) == 0 || strncmp(modname, "libpthread", 10) == 0 || strncmp(modname, "libdyninst", 10) == 0 || (name[0] == '_' && name[1] != '_' && strncmp(modname, "libc", 4) == 0)) continue; fprintf(stderr, "patcher: Patching function: '%s' (%s)", name, modname); // Patch back-edge for call if (strcmp(name, "main") != 0) appProc->insertSnippet(addOneAtomic, *((*functions)[i]->findPoint(BPatch_entry))); // Get the control flow graph for the procedure BPatch_flowGraph *graph = (*functions)[i]->getCFG(); // Find the loops BPatch_Vector<BPatch_basicBlockLoop*> *loops = new BPatch_Vector<BPatch_basicBlockLoop*>(); graph->getLoops(*loops); // Patch the loop back-edges for(int j = 0; j < loops->size(); j++) { appProc->insertSnippet(addOneAtomic, *((*loops)[j]->getBackEdge()->getPoint())); fprintf(stderr, ".", (int) (*loops)[j]->getBackEdge()->getPoint()->getAddress()); } fprintf(stderr, "\n"); // Free the loops found delete(loops); } fprintf(stderr, "Finalising patches..."); fflush(stderr); appProc->finalizeInsertionSet(false); fprintf(stderr, "Done.\n----------------------------------------\n"); // Clear up memory used to store the name free(name); free(modname); #if 0 /************************************************************************* * Exit point counter print patch * *************************************************************************/ // Patch exit() function to print out no of back branches at the end // Get exit() exit point BPatch_Vector<BPatch_point*> *exitPoints = exitFuncs[0]->findPoint(BPatch_entry); // Build printf() call: // printf("Total Total Back-branches: %d\n", counter); // Build arguments to printf() BPatch_Vector<BPatch_snippet*> printfArgs; BPatch_constExpr formatString("Total Back-branches: %d\n"); printfArgs.push_back(&formatString); printfArgs.push_back(&derefCounter); // Build call to printf() BPatch_funcCallExpr printfCall(*printfFuncs[0], printfArgs); // Patch into exit() appProc->insertSnippet(printfCall, *exitPoints); #endif // Continue mutatee... appProc->continueExecution(); // Wait for mutatee to finish while (!appProc->isTerminated()) { bpatch.waitForStatusChange(); } fprintf(stderr, "----------------------------------------\n"); fprintf(stderr, "Done.\n"); return 0; }
void dyninst_analyze_address_taken(BPatch_addressSpace *handle, DICFG *cfg) { /* XXX: this is the most naive address-taken analysis that can be used by the * lbr_analysis_pass. More sophisticated ones can be (and are) plugged in in the pass. * This naive solution is provided only for comparison with more sophisticated ones. * * This analysis looks for instruction operands that correspond to known function addresses, * and then marks these functions as having their address taken. In particular, we * do /not/ look for function pointers stored in (static) memory, or for function * pointers that are computed at runtime. */ SymtabCodeSource *sts; CodeObject *co; std::vector<BPatch_object*> objs; handle->getImage()->getObjects(objs); assert(objs.size() > 0); const char *bin = objs[0]->pathName().c_str(); // Create a new binary object sts = new SymtabCodeSource((char*)bin); co = new CodeObject(sts); // Parse the binary co->parse(); BPatch_image *image = handle->getImage(); std::vector<BPatch_module *> *mods = image->getModules(); std::vector<BPatch_module *>::iterator mods_iter; for (mods_iter = mods->begin(); mods_iter != mods->end(); mods_iter++) { std::vector<BPatch_function *> *funcs = (*mods_iter)->getProcedures(false); std::vector<BPatch_function *>::iterator funcs_iter = funcs->begin(); for(; funcs_iter != funcs->end(); funcs_iter++) { co->parse((Address)(*funcs_iter)->getBaseAddr(), true); BPatch_flowGraph *fg = (*funcs_iter)->getCFG(); std::set<BPatch_basicBlock*> blocks; fg->getAllBasicBlocks(blocks); std::set<BPatch_basicBlock*>::iterator block_iter; for (block_iter = blocks.begin(); block_iter != blocks.end(); ++block_iter) { BPatch_basicBlock *block = (*block_iter); std::vector<Instruction::Ptr> insns; block->getInstructions(insns); std::vector<Instruction::Ptr>::iterator insn_iter; for (insn_iter = insns.begin(); insn_iter != insns.end(); ++insn_iter) { Instruction::Ptr ins = *insn_iter; std::vector<Operand> ops; ins->getOperands(ops); std::vector<Operand>::iterator op_iter; for (op_iter = ops.begin(); op_iter != ops.end(); ++op_iter) { Expression::Ptr expr = (*op_iter).getValue(); struct OperandAnalyzer : public Dyninst::InstructionAPI::Visitor { virtual void visit(BinaryFunction* op) {}; virtual void visit(Dereference* op) {} virtual void visit(Immediate* op) { address_t addr; ArmsFunction *func; switch(op->eval().type) { case s32: addr = op->eval().val.s32val; break; case u32: addr = op->eval().val.u32val; break; case s64: addr = op->eval().val.s64val; break; case u64: addr = op->eval().val.u64val; break; default: return; } func = cfg_->find_function(addr); if(func) { printf("Instruction [%s] references function 0x%jx\n", ins_->format().c_str(), addr); func->set_addr_taken(); } } virtual void visit(RegisterAST* op) {} OperandAnalyzer(DICFG *cfg, Instruction::Ptr ins) { cfg_ = cfg; ins_ = ins; }; DICFG *cfg_; Instruction::Ptr ins_; }; OperandAnalyzer oa(cfg, ins); expr->apply(&oa); } } } } } }