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; }
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; }
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; }
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); } } } } } }