/* * BPatch_addressSpace::replaceFunctionCall * * Replace a function call with a call to a different function. Returns true * upon success, false upon failure. * * point The call site that is to be changed. * newFunc The function that the call site will now call. */ bool BPatch_addressSpace::replaceFunctionCall(BPatch_point &point, BPatch_function &newFunc) { char name[1024]; newFunc.getName(name, 1024); // Can't make changes to code when mutations are not active. if (!getMutationsActive()) return false; assert(point.point && newFunc.lowlevel_func()); /* PatchAPI stuffs */ AddressSpace* addr_space = point.getAS(); DynModifyCallCommand* rep_call = DynModifyCallCommand::create(addr_space, point.point->block(), newFunc.lowlevel_func(), point.point->func()); addr_space->patcher()->add(rep_call); /* End of PatchAPI */ if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; }
static void printCallingSites (int id, int total, char *name, string sharedlibname, BPatch_Vector<BPatch_point *> *vpoints) { if (vpoints->size() > 0) { unsigned j = 0; cout << id << " of " << total << " - Calling sites for " << name << " within " << sharedlibname << " (num = " << vpoints->size() << "):" << endl; while (j < vpoints->size()) { BPatch_function *called = ((*vpoints)[j])->getCalledFunction(); if (NULL != called) { char calledname[1024]; called->getName (calledname, 1024); cout << j+1 << " Calling " << calledname; BPatch_procedureLocation loc = ((*vpoints)[j])->getPointType(); if (loc == BPatch_entry) cout << " (entry)" << endl; else if (loc == BPatch_exit) cout << " (exit)" << endl; else if (loc == BPatch_subroutine) cout << " (subroutine)" << endl; else cout << " (unknown point type)" << endl; } else { cout << j+1 << " Undetermined " << endl; } j++; } cout << endl; } }
int main (int argc, const char* argv[]) { BPatch bpatch; // argv[2] is muttee's file name, will be muttee's argv[0] BPatch_process *proc = bpatch.processCreate(argv[2], argv + 2); // Options to tune performance char *s; if ((s = getenv("SET_TRAMP_RECURSIVE")) && (strcmp(s, "true") == 0)) bpatch.setTrampRecursive(true); if ((s = getenv("SET_SAVE_FPR")) && (strcmp(s, "false") == 0)) bpatch.setSaveFPR(false); BPatch_object *ipa = proc->loadLibrary(argv[1]); BPatch_image *image = proc->getImage(); std::vector<BPatch_function *> tracepoints, probes; image->findFunction("do_stuff", tracepoints); BPatch_function *tracepoint = tracepoints[0]; image->findFunction("tpbench_no_arg", probes); BPatch_function *probe = probes[0]; std::vector<BPatch_snippet*> args; BPatch_funcCallExpr call_probe(*probe, args); proc->insertSnippet(call_probe, (tracepoint->findPoint(BPatch_exit))[0]); proc->detach(true); return 0; }
void instrCodeNode::prepareCatchupInstr(pdvector<instReqNode *> &nodes_for_catchup) { if (instrCatchuped()) return; for (unsigned instIter = 0; instIter < V.instRequests.size(); instIter++) { instReqNode *curInstReq = V.instRequests[instIter]; //prepareCatchupInstr_debug(V.instRequests[instIter]); if (pd_debug_catchup) { char buf[2048]; BPatch_function *bpf = const_cast<BPatch_function *>(curInstReq->Point()->getFunction()); if (! bpf) { sprintf(buf, "<bad function> in instReq"); } else bpf->getName(buf, 2048); cerr << " looking at instReq [" << instIter << "], in func: " << buf <<endl; } BPatchSnippetHandle *sh = curInstReq->snippetHandle(); } // don't mark catchup as having completed because we don't want to mark // this until the processMetFocusNode has completed initiating catchup for // all of the threads }
// // findVariable // scp - a BPatch_point that defines the scope of the current search // name - name of the variable to find. // BPatch_variableExpr *BPatch_image::findVariableInScope(BPatch_point &scp, const char *name) { // Get the function to search for it's local variables. // XXX - should really use more detailed scoping info here - jkh 6/30/99 BPatch_function *func = const_cast<BPatch_function *> (scp.getFunction()); if (!func) { pdstring msg = pdstring("point passed to findVariable lacks a function\n address point type passed?"); showErrorCallback(100, msg); return NULL; } BPatch_localVar *lv = func->findLocalVar(name); if (!lv) { // look for it in the parameter scope now lv = func->findLocalParam(name); } if (lv) { // create a local expr with the correct frame offset or absolute // address if that is what is needed return new BPatch_variableExpr(proc, (void *) lv->getFrameOffset(), lv->getRegister(), lv->getType(), lv->getStorageClass(), &scp); } // finally check the global scope. // return findVariable(name); /* If we have something else to try, don't report errors on this failure. */ bool reportErrors = true; char mangledName[100]; func->getName( mangledName, 100 ); char * lastScoping = NULL; if( strrchr( mangledName, ':' ) != NULL ) { reportErrors = false; } BPatch_variableExpr * gsVar = findVariable( name, reportErrors ); if( gsVar == NULL ) { /* Try finding it with the function's scope prefixed. */ if( (lastScoping = strrchr( mangledName, ':' )) != NULL ) { * (lastScoping + sizeof(char)) = '\0'; char scopedName[200]; memmove( scopedName, mangledName, strlen( mangledName ) ); memmove( scopedName + strlen( mangledName ), name, strlen( name ) ); scopedName[ strlen( mangledName ) + strlen( name ) ] = '\0'; bperr( "Searching for scoped name '%s'\n", scopedName ); gsVar = findVariable( scopedName ); } } return gsVar; }
void instrumentModule(BPatch_module *module) { char funcname[BUFFER_STRING_LEN]; instrumentPLTSection(module); std::vector<BPatch_function *>* functions; functions = module->getProcedures(); for (unsigned i = 0; i < functions->size(); i++) { BPatch_function *function = functions->at(i); function->getName(funcname, BUFFER_STRING_LEN); instrumentFunction(function); } }
static void ShowFunctions (BPatch_image *appImage) { BPatch_Vector<BPatch_function *> *vfunctions = appImage->getProcedures (false); cout << PACKAGE_NAME << ": " << vfunctions->size() << " functions found in binary " << endl; unsigned i = 0; while (i < vfunctions->size()) { char name[1024]; BPatch_function *f = (*vfunctions)[i]; f->getName (name, 1024); if (VerboseLevel) { char mname[1024], tname[1024], modname[1024]; f->getMangledName (mname, 1024); f->getTypedName (tname, 1024); f->getModuleName (modname, 1024); cout << " * " << i+1 << " of " << vfunctions->size() << ", Name: " << name << endl << " Mangled Name: " << mname << endl << " Typed Name : " << tname << endl << " Module name : " << modname << endl << " Base address: " << f->getBaseAddr() << endl << " Instrumentable? " << (f->isInstrumentable()?"yes":"no") << endl << " In shared library? " << (f->isSharedLib()?"yes":"no") << endl << " Number of BB: " << getBasicBlocksSize(f) << endl; if (f->isSharedLib()) { char sharedlibname[1024]; BPatch_module *mod = f->getModule(); mod->getFullName (sharedlibname, 1024); cout << " Full library name: " << sharedlibname << endl; } cout << endl; } else { cout << name << endl; } i++; } }
/* Invoked for every signal handler function, adjusts the value of the saved * fault address to its unrelocated counterpart in the CONTEXT structure, * which contains the PC that is used when execution resumes */ void HybridAnalysis::signalHandlerEntryCB2(BPatch_point *point, Address excCtxtAddr) { mal_printf("\nAt signalHandlerEntry2(%lx , %lx)\n", point->getAddress(), (Address)excCtxtAddr); // calculate the offset of the fault address in the EXCEPTION_RECORD CONTEXT *cont= (CONTEXT*)excCtxtAddr; //bogus pointer, but I won't write to it Address pcAddr = excCtxtAddr + (Address)(&(cont->Eip)) - (Address)cont; // set fault address to the unrelocated address of that instruction // and save the PC address in the CONTEXT structure so the exit handler // can read it BPatch_function *func = point->getFunction(); func->setHandlerFaultAddrAddr((Address)pcAddr,true); handlerFunctions[(Address)func->getBaseAddr()].faultPCaddr = pcAddr; }
/* * BPatch_addressSpace::revertReplaceFunction * * Undoes a replaceFunction operation */ bool BPatch_addressSpace::revertReplaceFunction(BPatch_function &oldFunc) { assert(oldFunc.lowlevel_func()); if (!getMutationsActive()) return false; func_instance *func = oldFunc.lowlevel_func(); func->proc()->revertReplacedFunction(func); if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; }
/* * BPatch_addressSpace::replaceFunction * * Replace all calls to function OLDFUNC with calls to NEWFUNC. * Returns true upon success, false upon failure. * * oldFunc The function to replace * newFunc The replacement function */ bool BPatch_addressSpace::replaceFunction(BPatch_function &oldFunc, BPatch_function &newFunc) { assert(oldFunc.lowlevel_func() && newFunc.lowlevel_func()); if (!getMutationsActive()) return false; // Self replacement is a nop // We should just test direct equivalence here... if (oldFunc.lowlevel_func() == newFunc.lowlevel_func()) { return true; } /* PatchAPI stuffs */ AddressSpace* addr_space = oldFunc.lowlevel_func()->proc(); DynReplaceFuncCommand* rep_func = DynReplaceFuncCommand::create(addr_space, oldFunc.lowlevel_func(), newFunc.lowlevel_func()); addr_space->patcher()->add(rep_func); /* End of PatchAPI */ if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; }
void handleModule(BPatch_module *mod, const char *name) { char funcname[BUFFER_STRING_LEN]; // get list of all functions std::vector<BPatch_function *>* functions; functions = mod->getProcedures(); // for each function ... for (unsigned i = 0; i < functions->size(); i++) { BPatch_function *function = functions->at(i); function->getName(funcname, BUFFER_STRING_LEN); printf(" FUNC: %s (%lx)\n", funcname, (unsigned long)function->getBaseAddr()); } }
/* Invoked for every signal handler function, adjusts the value of the saved * fault address to its unrelocated counterpart in the EXCEPTION_RECORD */ void HybridAnalysis::signalHandlerEntryCB(BPatch_point *point, Address excRecAddr) { mal_printf("\nAt signalHandlerEntry(%lx , %lx)\n", point->getAddress(), (Address)excRecAddr); stats_.exceptions++; // calculate the offset of the fault address in the EXCEPTION_RECORD EXCEPTION_RECORD record; proc()->lowlevel_process()->readDataSpace( (void*)excRecAddr, sizeof(EXCEPTION_RECORD), &record, true); Address pcAddr = excRecAddr + (Address) &(record.ExceptionAddress) - (Address) &record; // set fault address to the unrelocated address of that instruction BPatch_function *func = point->getFunction(); func->setHandlerFaultAddrAddr((Address)pcAddr,false); handlerFunctions[(Address)func->getBaseAddr()].isInterrupt = (record.ExceptionCode == EXCEPTION_BREAKPOINT); }
static void ShowFunctions (BPatch_image *appImage) { BPatch_Vector<BPatch_function *> *vfunctions = appImage->getProcedures (false); cout << PACKAGE_NAME << ": " << vfunctions->size() << " functions found in binary " << endl; unsigned i = 0; while (i < vfunctions->size()) { char name[1024]; BPatch_function *f = (*vfunctions)[i]; f->getName (name, 1024); char mname[1024], tname[1024], modname[1024]; f->getMangledName (mname, 1024); f->getTypedName (tname, 1024); f->getModuleName (modname, 1024); cout << " * " << i+1 << " of " << vfunctions->size() << ", Name: " << name << endl << " Mangled Name: " << mname << endl << " Typed Name : " << tname << endl << " Module name : " << modname << endl << " Base address: " << f->getBaseAddr() << endl << " Instrumentable? " << (f->isInstrumentable()?"yes":"no") << endl << " In shared library? " << (f->isSharedLib()?"yes":"no") << endl; if (f->isSharedLib()) { //Old Dyninst API < 9.x //char sharedlibname[1024]; //mod->getFullName (sharedlibname, 1024); BPatch_module *mod = f->getModule(); string sharedlibname; sharedlibname = mod->getObject()->name(); cout << " Full library name: " << sharedlibname << endl; } cout << endl; i++; } }
/* If the context of the exception has been changed so that execution * will resume at a new address, parse and instrument the code at that * address; then add a springboard at that address if it is not the * entry point of a function */ void HybridAnalysis::signalHandlerExitCB(BPatch_point *point, void *) { BPatch_function *func = point->getFunction(); std::map<Dyninst::Address, ExceptionDetails>::iterator diter = handlerFunctions.find((Address)func->getBaseAddr()); assert(handlerFunctions.end() != diter && 0 != diter->second.faultPCaddr); Address pcLoc = diter->second.faultPCaddr; mal_printf("\nAt signalHandlerExit(%lx)\n", point->getAddress()); // figure out the address the program will resume at by reading // in the stored CONTEXT structure Address resumePC; assert(sizeof(Address) == proc()->getAddressWidth()); proc()->lowlevel_process()->readDataSpace( (void*)pcLoc, sizeof(resumePC), &resumePC, true); if (diter->second.isInterrupt) { resumePC += 1; } // parse at the resumePC address, if necessary vector<BPatch_function *> funcs; proc()->findFunctionsByAddr((Address)resumePC,funcs); if (funcs.empty()) { mal_printf("Program will resume in new function at %lx\n", resumePC); } else { mal_printf("Program will resume at %lx in %d existing functions, " "will add shared function starting at %lx\n", resumePC, funcs.size(), resumePC); } analyzeNewFunction(point, (Address)resumePC, true, true); mal_printf("Exception handler exiting at %lx will resume execution at " "%lx %s[%d]\n", point->getAddress(), resumePC, FILE__,__LINE__); }
void Instrumentcall (BPatch_image *appImage, BPatch_process *appProcess) { unsigned insertion = 0; unsigned i = 0; BPatch_Vector<BPatch_function *> *vfunctions = appImage->getProcedures (true); cout << vfunctions->size() << " functions found in binary " << endl; cout << "Parsing functions " << flush; while (i < vfunctions->size()) { char name[1024], sharedlibname[1024]; BPatch_function *f = (*vfunctions)[i]; (f->getModule())->getFullName (sharedlibname, 1024); f->getName (name, 1024); BPatch_Vector<BPatch_point *> *vpoints = f->findPoint (BPatch_subroutine); unsigned j = 0; while (j < vpoints->size()) { BPatch_function *called = ((*vpoints)[j])->getCalledFunction(); if (NULL != called) { char calledname[1024]; called->getName (calledname, 1024); if (strcmp (calledname, "functionB") == 0) { string s = "functionA"; BPatch_function *patch = getRoutine (s, appImage); if (patch != NULL) { bool replaced = appProcess->replaceFunctionCall (*((*vpoints)[j]), *patch); if (replaced) cout << "call to functionA has been successfully replaced by a call to functionB" << endl; else cout << "call to functionA failed to replace a call to functionB" << endl; insertion++; } } } j++; } i++; } cout << endl; cout << "insertion = " << insertion << endl; }
static void GenerateSymFile (set<string> &ParFunc, set<string> &UserFunc, BPatch_image *appImage, BPatch_addressSpace *appProces) { ofstream symfile; string symname = string(::XML_GetFinalDirectory())+string("/")+string(::XML_GetTracePrefix())+".sym"; symfile.open (symname.c_str()); if (!symfile.good()) { cerr << "Cannot create the symbolic file" << symname << endl; return; } for (set<string>::iterator iter = ParFunc.begin(); iter != ParFunc.end(); iter++) { BPatch_function *f = getRoutine ((*iter).c_str(), appImage); if (f != NULL) { BPatch_Vector< BPatch_statement > lines; appProces->getSourceLines ((unsigned long) f->getBaseAddr(), lines); if (lines.size() > 0) { symfile << "P " << hex << f->getBaseAddr() << dec << " \"" << *iter << "\" \"" << lines[0].fileName() << "\" " << lines[0].lineNumber() << endl; } else { /* this happens if the application was not compiled with -g */ char modname[1024]; f->getModuleName (modname, 1024); symfile << "P " << hex << f->getBaseAddr() << dec << " \"" << *iter << "\" \"" << modname << "\" 0" << endl; } } } for (set<string>::iterator iter = UserFunc.begin(); iter != UserFunc.end(); iter++) { BPatch_function *f = getRoutine ((*iter).c_str(), appImage); if (f != NULL) { BPatch_Vector< BPatch_statement > lines; appProces->getSourceLines ((unsigned long) f->getBaseAddr(), lines); if (lines.size() > 0) { symfile << "U " << hex << f->getBaseAddr() << dec << " \"" << *iter << "\" \"" << lines[0].fileName() << "\" " << lines[0].lineNumber() << endl; } else { /* this happens if the application was not compiled with -g */ char modname[1024]; f->getModuleName (modname, 1024); symfile << "U " << hex << f->getBaseAddr() << dec << " \"" << *iter << "\" \"" << modname << "\" 0" << endl; } } } map<string, unsigned>::iterator BB_symbols_iter = BB_symbols->begin(); map<string, unsigned>::iterator BB_symbols_end = BB_symbols->end(); while(BB_symbols_iter != BB_symbols_end){ symfile << "b " << BB_symbols_iter->second << " \"" << BB_symbols_iter->first << "\"\n"; BB_symbols_iter++; } symfile.close(); }
int main (int argc, char **argv) { if(!parseOptions(argc,argv)) { return EXIT_FAILURE; } BPatch bpatch; BPatch_binaryEdit *appBin = bpatch.openBinary (originalBinary, !instrumentLibraries.empty()); if (appBin == NULL) { cerr << "Failed to open binary" << endl; return EXIT_FAILURE; } if (!appBin->loadLibrary (instLibrary)) { cerr << "Failed to open instrumentation library." << endl; cerr << "It needs to be located in the current working directory." << endl; return EXIT_FAILURE; } BPatch_image *appImage = appBin->getImage (); /* Find code coverage functions in the instrumentation library */ BPatch_function *initAflForkServer = findFuncByName (appImage, (char *) "initAflForkServer"); BPatch_function *bbCallback = findFuncByName (appImage, (char *) "bbCallback"); if (!initAflForkServer || !bbCallback ) { cerr << "Instrumentation library lacks callbacks!" << endl; return EXIT_FAILURE; } //get and iterate over all modules, instrumenting only the default and manualy specified ones vector < BPatch_module * >*modules = appImage->getModules (); vector < BPatch_module * >::iterator moduleIter; BPatch_module *defaultModule = NULL; string defaultModuleName; for (moduleIter = modules->begin (); moduleIter != modules->end (); ++moduleIter) { //find default module name char moduleName[1024]; (*moduleIter)->getName (moduleName, 1024); if (string (moduleName).find ("DEFAULT_MODULE") != string::npos) { defaultModuleName = "DEFAULT_MODULE"; } } if(defaultModuleName.empty()) defaultModuleName = string(originalBinary).substr(string(originalBinary).find_last_of("\\/")+1); int bbIndex = 0; for (moduleIter = modules->begin (); moduleIter != modules->end (); ++moduleIter) { char moduleName[1024]; (*moduleIter)->getName (moduleName, 1024); if ((*moduleIter)->isSharedLib ()) { if (instrumentLibraries.find (moduleName) == instrumentLibraries.end ()) { cout << "Skipping library: " << moduleName << endl; continue; } } if (string (moduleName).find (defaultModuleName) != string::npos) { defaultModule = (*moduleIter); if(skipMainModule) continue; } cout << "Instrumenting module: " << moduleName << endl; vector < BPatch_function * >*allFunctions = (*moduleIter)->getProcedures (); vector < BPatch_function * >::iterator funcIter; // iterate over all functions in the module for (funcIter = allFunctions->begin (); funcIter != allFunctions->end (); ++funcIter) { BPatch_function *curFunc = *funcIter; char funcName[1024]; curFunc->getName (funcName, 1024); if(string (funcName) == string("_start")) continue; // here's a bug on hlt insertBBCallback (appBin, curFunc, funcName, bbCallback, &bbIndex); } } //if entrypoint set ,find function , else find _init BPatch_function *funcToPatch = NULL; if(!entryPoint) { BPatch_Vector<BPatch_function*> funcs; defaultModule->findFunction("_init", funcs); if(!funcs.size()) { cerr << "Couldn't locate _init, specify entry point manualy. "<< endl; return EXIT_FAILURE; } // there should really be only one funcToPatch = funcs[0]; } else { funcToPatch = defaultModule->findFunctionByEntry(entryPoint); } if(!funcToPatch) { cerr << "Couldn't locate function at given entry point. "<< endl; return EXIT_FAILURE; } if(!insertCallToInit (appBin, initAflForkServer,defaultModule,funcToPatch)){ cerr << "Could not insert init callback at given entry point." << endl; return EXIT_FAILURE; } cout << "Saving the instrumented binary to " << instrumentedBinary << "..." << endl; // Output the instrumented binary if (!appBin->writeFile (instrumentedBinary)) { cerr << "Failed to write output file: " << instrumentedBinary << endl; return EXIT_FAILURE; } if(!runtimeLibraries.empty()) { cout << "Instrumenting runtime libraries." << endl; set<string>::iterator rtLibIter ; for(rtLibIter = runtimeLibraries.begin(); rtLibIter != runtimeLibraries.end(); rtLibIter++) { BPatch_binaryEdit *libBin = bpatch.openBinary ((*rtLibIter).c_str(), false); if (libBin == NULL) { cerr << "Failed to open binary "<< *rtLibIter << endl; return EXIT_FAILURE; } libBin->loadLibrary (instLibrary); BPatch_image *libImg = libBin->getImage (); vector < BPatch_module * >*modules = libImg->getModules (); moduleIter = modules->begin (); ++moduleIter; for ( ; moduleIter != modules->end (); ++moduleIter) { char moduleName[1024]; (*moduleIter)->getName (moduleName, 1024); cout << "Instrumenting module: " << moduleName << endl; vector < BPatch_function * >*allFunctions = (*moduleIter)->getProcedures (); vector < BPatch_function * >::iterator funcIter; // iterate over all functions in the module for (funcIter = allFunctions->begin (); funcIter != allFunctions->end (); ++funcIter) { BPatch_function *curFunc = *funcIter; char funcName[1024]; curFunc->getName (funcName, 1024); if(string (funcName) == string("_start")) continue; insertBBCallback (libBin, curFunc, funcName, bbCallback, &bbIndex); } } if (!libBin->writeFile ((*rtLibIter + ".ins").c_str())) { cerr << "Failed to write output file: " <<(*rtLibIter + ".ins").c_str() << endl; return EXIT_FAILURE; } else { cout << "Saved the instrumented library to " << (*rtLibIter + ".ins").c_str() << "." << endl; } } } cout << "All done! Happy fuzzing!" << endl; return EXIT_SUCCESS; }
void HybridAnalysis::badTransferCB(BPatch_point *point, void *returnValue) { Address pointAddr = (Address) point->getAddress(); Address target = (Address) returnValue; time_t tstruct; struct tm * tmstruct; char timeStr[64]; time( &tstruct ); tmstruct = localtime( &tstruct ); strftime(timeStr, 64, "%X", tmstruct); mal_printf("badTransferCB %lx=>%lx %s\n\n", pointAddr, target, timeStr); BPatch_module * targMod = proc()->findModuleByAddr(target); if (!targMod) { mal_printf( "ERROR, NO MODULE for target addr %lx %s[%d]\n", target,FILE__,__LINE__); assert(0); } if (targMod == point->getFunction()->getModule() && targMod->isSystemLib()) { return; } // 1. the target address is in a shared library if ( targMod != point->getFunction()->getModule()) { // process the edge, decide if we should instrument target function bool doMoreProcessing = processInterModuleEdge(point, target, targMod); if (!doMoreProcessing) { return; } } // 2. the point is a call: if (point->getPointType() == BPatch_subroutine) { proc()->beginInsertionSet(); // if the target is in the body of an existing function we'll split // the function and wind up with two or more functions that share // the target address, so make sure we're not in the middle of an // overwrite loop; if we are, check for overwrites immediately BPatch_function *targFunc = proc()->findFunctionByEntry(target); vector<BPatch_function*> targFuncs; proc()->findFunctionsByAddr(target, targFuncs); if (!targFunc && targFuncs.size()) { mal_printf("discovery instr. got new entry point for func\n"); std::set<HybridAnalysisOW::owLoop*> loops; for (unsigned tidx=0; tidx < targFuncs.size(); tidx++) { BPatch_function *curFunc = targFuncs[tidx]; if ( hybridOW()->hasLoopInstrumentation(false, *curFunc, &loops) ) { /* Code sharing will change the loops, the appropriate response is to trigger early exit analysis and remove the loops if the underlying code hasn't changed */ mal_printf("[%d] Removing loop instrumentation for func %lx\n", __LINE__,curFunc->getBaseAddr()); std::set<HybridAnalysisOW::owLoop*>::iterator lIter = loops.begin(); while (lIter != loops.end()) { hybridOW()->deleteLoop(*lIter,false); lIter++; } } } } // 2.1 if the target is new, parse at the target if ( ! targFunc ) { mal_printf("stopThread instrumentation found call %lx=>%lx, " "parsing at call target %s[%d]\n", (long)point->getAddress(), target,FILE__,__LINE__); if (!analyzeNewFunction( point,target,false,false )) { //this happens for some single-instruction functions mal_printf("ERROR: parse of call target %lx=>%lx failed %s[%d]\n", (long)point->getAddress(), target, FILE__,__LINE__); assert(0); instrumentModules(false); proc()->finalizeInsertionSet(false); return; } targFunc = proc()->findFunctionByEntry(target); } // 2.2 if the target is a returning function, parse at the fallthrough bool instrument = true; if ( ParseAPI::RETURN == targFunc->lowlevel_func()->ifunc()->retstatus() ) { //mal_printf("stopThread instrumentation found returning call %lx=>%lx, " // "parsing after call site\n", // (long)point->getAddress(), target); if (parseAfterCallAndInstrument(point, targFunc, false)) { instrument = false; } } if (instrument) { instrumentModules(false); } proc()->finalizeInsertionSet(false); // 2. return return; } // 3. the point is a return instruction: if ( point->getPointType() == BPatch_locExit ) { // 3.2 find the call point so we can parse after it // ( In this case "point" is the return statement and // "target" is the fallthrough address of the call insn ) // in order to find the callPoint in the caller function that // corresponds to the non-returning call, we traverse list of // the caller's points to find the callpoint that is nearest // to the return address Address returnAddr = target; using namespace ParseAPI; // Find the call blocks preceding the address that we're returning // past, but only set set returningCallB if we can be sure that // that we've found a call block that actually called the function // we're returning from pair<Block*, Address> returningCallB((Block*)NULL,0); set<Block*> callBlocks; getCallBlocks(returnAddr, point->llpoint()->func(), point->llpoint()->block(), returningCallB, callBlocks); // 3.2.1 parse at returnAddr as the fallthrough of the preceding // call block, if there is one if (!callBlocks.empty()) { // we don't know if the function we called returns, so // invoke parseAfterCallAndInstrument with NULL as the // called func, so we won't try to parse after other // callers to the called func, as it may not actually // return in a normal fashion if (NULL == returningCallB.first) { vector<BPatch_point*> callPts; for (set<Block*>::iterator bit = callBlocks.begin(); bit != callBlocks.end(); bit++) { getPreCallPoints(*bit, proc(), callPts); } for (vector<BPatch_point*>::iterator pit = callPts.begin(); pit != callPts.end(); pit++) { parseAfterCallAndInstrument( *pit, NULL, true ); } } // if the return address has been parsed as the entry point // of a block, patch post-call areas and return else if ( returningCallB.first->obj()->findBlockByEntry( returningCallB.first->region(), target)) { vector<BPatch_point*> callPts; getPreCallPoints(returningCallB.first, proc(), callPts); for (unsigned j=0; j < callPts.size(); j++) { callPts[j]->patchPostCallArea(); } } else { // parse at the call fallthrough // find one callPoint, any other ones will // be found by parseAfterCallAndInstrument vector<BPatch_point*> callPoints; getPreCallPoints(returningCallB.first, proc(), callPoints); assert(!callPoints.empty()); mal_printf("stopThread instrumentation found return at %lx, " "parsing return addr %lx as fallthrough of call " "instruction at %lx %s[%d]\n", (long)point->getAddress(), target,callPoints[0]->getAddress(),FILE__,__LINE__); if (point->llpoint()->block()->llb()->isShared()) { // because of pc emulation, if the return point is shared, // we may have flipped between functions that share the // return point, so use the call target function BPatch_function *calledFunc = proc()-> findFunctionByEntry(returningCallB.second); parseAfterCallAndInstrument( callPoints[0], calledFunc, true ); } else { parseAfterCallAndInstrument( callPoints[0], point->getFunction(), true); } } } // 3.2.2 no call blocks, parse the return addr as a new function else { if ( point->getFunction()->getModule()->isExploratoryModeOn() ) { // otherwise we've instrumented a function in trusted library // because we want to catch its callbacks into our code, but in // the process are catching calls into other modules mal_printf("hybridCallbacks.C[%d] Observed abuse of normal return " "instruction semantics for insn at %lx target %lx\n", __LINE__, point->getAddress(), returnAddr); } analyzeNewFunction( point, returnAddr, true , true ); // there are no call blocks, so we don't have any post-call pads to patch } // 3. return return; } // 4. else case: the point is a jump/branch proc()->beginInsertionSet(); // 4.1 if the point is a direct branch, remove any instrumentation if (!point->isDynamic()) { BPatch_function *func = point->getFunction(); if (instrumentedFuncs->end() != instrumentedFuncs->find(func) && (*instrumentedFuncs)[func]->end() != (*instrumentedFuncs)[func]->find(point)) { proc()->deleteSnippet( (*(*instrumentedFuncs)[func])[point] ); (*instrumentedFuncs)[func]->erase(point); } //point is set to resolved in handleStopThread } bool newParsing; vector<BPatch_function*> targFuncs; proc()->findFunctionsByAddr(target, targFuncs); if ( 0 == targFuncs.size() ) { newParsing = true; mal_printf("stopThread instrumentation found jump " "at 0x%lx leading to an unparsed target at 0x%lx\n", (long)point->getAddress(), target); } else { newParsing = false; mal_printf("stopThread instrumentation added an edge for jump " " at 0x%lx leading to a previously parsed target at 0x%lx\n", (long)point->getAddress(), target); } // add the new edge to the program, parseNewEdgeInFunction will figure // out whether to extend the current function or parse as a new one. if (targMod != point->getFunction()->getModule()) { // Don't put in inter-module branches if (newParsing) analyzeNewFunction(point, target, true, false); } else { parseNewEdgeInFunction(point, target, false); } if (0 == targFuncs.size()) { proc()->findFunctionsByAddr( target, targFuncs ); } // manipulate init_retstatus so that we will instrument the function's // return addresses, since this jump might be a tail call for (unsigned tidx=0; tidx < targFuncs.size(); tidx++) { parse_func *imgfunc = targFuncs[tidx]->lowlevel_func()->ifunc(); FuncReturnStatus initStatus = imgfunc->init_retstatus(); if (ParseAPI::RETURN == initStatus) { imgfunc->setinit_retstatus(ParseAPI::UNKNOWN); removeInstrumentation(targFuncs[tidx],false,false); instrumentFunction(targFuncs[tidx],false,true); } } // re-instrument the function or the whole module, as needed if (newParsing) { instrumentModules(false); } proc()->finalizeInsertionSet(false); } // end badTransferCB
// static int mutatorTest( BPatch_thread * appThread, BPatch_image * appImage ) { test_results_t test_stack_3_Mutator::executeTest() { bool passedTest; BPatch::bpatch->setInstrStackFrames(true); appProc->continueExecution(); static const frameInfo_t correct_frame_info[] = { #if defined( os_linux_test ) && (defined( arch_x86_test ) || defined( arch_x86_64_test )) { true, true, BPatch_frameNormal, "_dl_sysinfo_int80" }, #endif #if defined( os_aix_test ) && defined( arch_power_test ) /* AIX uses kill(), but the PC of a process in a syscall can not be correctly determined, and appears to be the address to which the syscall function will return. */ #elif defined( os_windows_test ) && (defined( arch_x86 ) || defined( arch_x86_64_test )) /* Windows/x86 does not use kill(), so its lowermost frame will be something unidentifiable in a system DLL. */ { false, false, BPatch_frameNormal, NULL }, #else { true, false, BPatch_frameNormal, "kill" }, #endif #if ! defined( os_windows_test ) /* Windows/x86's stop_process_() calls DebugBreak(); it's apparently normal to lose this frame. */ { true, false, BPatch_frameNormal, "stop_process_" }, #endif { true, false, BPatch_frameNormal, "test_stack_3_func3" }, { true, false, BPatch_frameTrampoline, NULL }, /* On AIX and x86 (and others), if our instrumentation fires before frame construction or after frame destruction, it's acceptable to not report the function (since, after all, it doesn't have a frame on the stack. */ { true, true, BPatch_frameNormal, "test_stack_3_func2" }, { true, false, BPatch_frameNormal, "test_stack_3_func1" }, { true, false, BPatch_frameNormal, "test_stack_3_mutateeTest" }, { true, false, BPatch_frameNormal, "main" } }; /* Wait for the mutatee to stop in test_stack_3_func1(). */ if (waitUntilStopped( bpatch, appProc, 1, "getCallStack through instrumentation") < 0) { appProc->terminateExecution(); return FAILED; } /* Instrument test_stack_3_func2() to call test_stack_3_func3(), which will trip another breakpoint. */ BPatch_Vector<BPatch_function *> instrumentedFunctions; const char *fName = "test_stack_3_func2"; appImage->findFunction(fName, instrumentedFunctions ); if (instrumentedFunctions.size() != 1) { // FIXME Print out a useful error message logerror("**Failed** test_stack_3\n"); logerror(" Unable to find function '%s'\n", fName); appProc->terminateExecution(); return FAILED; } BPatch_Vector<BPatch_point *> * functionEntryPoints = instrumentedFunctions[0]->findPoint( BPatch_entry ); if (functionEntryPoints->size() != 1) { // FIXME Print out a useful error message logerror("**Failed** test_stack_3\n"); logerror(" Unable to find entry point to function '%s'\n", fName); appProc->terminateExecution(); return FAILED; } BPatch_Vector<BPatch_function *> calledFunctions; const char *fName2 = "test_stack_3_func3"; appImage->findFunction(fName2, calledFunctions ); if (calledFunctions.size() != 1) { //FIXME Print out a useful error message logerror("**Failed** test_stack_3\n"); logerror(" Unable to find function '%s'\n", fName2); appProc->terminateExecution(); return FAILED; } BPatch_Vector<BPatch_snippet *> functionArguments; BPatch_funcCallExpr functionCall( * calledFunctions[0], functionArguments ); appProc->insertSnippet( functionCall, functionEntryPoints[0] ); /* Repeat for all three types of instpoints. */ BPatch_Vector<BPatch_point *> * functionCallPoints = instrumentedFunctions[0]->findPoint( BPatch_subroutine ); if (functionCallPoints->size() != 1) { logerror("**Failed** test_stack_3\n"); logerror(" Unable to find subroutine call points in '%s'\n", fName); appProc->terminateExecution(); return FAILED; } appProc->insertSnippet( functionCall, functionCallPoints[0] ); BPatch_Vector<BPatch_point *> * functionExitPoints = instrumentedFunctions[0]->findPoint( BPatch_exit ); if (functionExitPoints->size() != 1) { logerror("**Failed** test_stack_3\n"); logerror(" Unable to find exit points in '%s'\n", fName); appProc->terminateExecution(); return FAILED; } appProc->insertSnippet( functionCall, functionExitPoints[0] ); #if defined( DEBUG ) for( int i = 0; i < 80; i++ ) { ptrace( PTRACE_SINGLESTEP, appThread->getPid(), NULL, NULL ); } for( int i = 80; i < 120; i++ ) { ptrace( PTRACE_SINGLESTEP, appThread->getPid(), NULL, NULL ); BPatch_Vector<BPatch_frame> stack; appThread->getCallStack( stack ); dprintf("single-step stack walk, %d instructions after stop for instrumentation.\n", i ); for( unsigned i = 0; i < stack.size(); i++ ) { char name[ 40 ]; BPatch_function * func = stack[i].findFunction(); if( func == NULL ) { strcpy( name, "[UNKNOWN]" ); } else { func->getName( name, 40 ); } dprintf(" %10p: %s, fp = %p\n", stack[i].getPC(), name, stack[i].getFP() ); } /* end stack walk dumper */ dprintf("end of stack walk.\n" ); } /* end single-step iterator */ #endif /* defined( DEBUG ) */ /* After inserting the instrumentation, let it be called. */ appProc->continueExecution(); /* Wait for the mutatee to stop because of the instrumentation we just inserted. */ if (waitUntilStopped( bpatch, appProc, 1, "getCallStack through instrumentation (entry)") < 0) { appProc->terminateExecution(); return FAILED; } passedTest = true; if( !checkStack( appThread, correct_frame_info, sizeof(correct_frame_info)/sizeof(frameInfo_t), 3, "getCallStack through instrumentation (entry)" ) ) { passedTest = false; } /* Repeat for other two types of instpoints. */ appProc->continueExecution(); /* Wait for the mutatee to stop because of the instrumentation we just inserted. */ if (waitUntilStopped( bpatch, appProc, 1, "getCallStack through instrumentation (call)") < 0) { appProc->terminateExecution(); return FAILED; } if( !checkStack( appThread, correct_frame_info, sizeof(correct_frame_info)/sizeof(frameInfo_t), 3, "getCallStack through instrumentation (call)" ) ) { passedTest = false; } appProc->continueExecution(); /* Wait for the mutatee to stop because of the instrumentation we just inserted. */ if (waitUntilStopped( bpatch, appProc, 1, "getCallStack through instrumentation (exit)") < 0) { appProc->terminateExecution(); return FAILED; } if( !checkStack( appThread, correct_frame_info, sizeof(correct_frame_info)/sizeof(frameInfo_t), 3, "getCallStack through instrumentation (exit)" ) ) { passedTest = false; } if (passedTest) logerror("Passed test #3 (unwind through base and mini tramps)\n"); /* Return the mutatee to its normal state. */ appProc->continueExecution(); while (!appProc->isTerminated()) { // Workaround for issue with pgCC_high mutatee bpatch->waitForStatusChange(); } if (passedTest) return PASSED; return FAILED; } /* end mutatorTest3() */
void HybridAnalysis::virtualFreeCB(BPatch_point *, void *t) { assert(virtualFreeAddr_ != 0); unsigned type = (unsigned) t; cerr << "virtualFree [" << hex << virtualFreeAddr_ << "," << virtualFreeAddr_ + (unsigned) virtualFreeSize_ << "], " << (unsigned) type << dec << endl; Address pageSize = proc()->lowlevel_process()->getMemoryPageSize(); // Windows page-aligns everything. unsigned addrShift = virtualFreeAddr_ % pageSize; unsigned sizeShift = pageSize - (virtualFreeSize_ % pageSize); virtualFreeAddr_ -= addrShift; if (type != MEM_RELEASE) { virtualFreeSize_ += addrShift + sizeShift; } // We need to: // 1) Remove any function with a block in the deleted range // 2) Remove memory translation for that range // 3) Skip trying to set permissions for any page in the range. // DEBUG! if (1 || type == MEM_RELEASE) { mapped_object *obj = proc()->lowlevel_process()->findObject(virtualFreeAddr_); if (!obj) return; virtualFreeAddr_ = obj->codeBase(); virtualFreeSize_ = obj->imageSize(); // DEBUG! cerr << "Removing VirtualAlloc'ed shared object " << obj->fileName() << endl; image *img = obj->parse_img(); proc()->lowlevel_process()->removeASharedObject(obj); virtualFreeAddr_ = 0; // Since removeASharedObject doesn't actually delete the object, // or its image (even if its refCount==0), make sure the image // goes away from global datastructure allImages for (unsigned int i=0; i < allImages.size(); i++) { if (img == allImages[i]) { allImages[i] = allImages.back(); allImages.pop_back(); } } return; } std::set<func_instance *> deletedFuncs; for (Address i = virtualFreeAddr_; i < (virtualFreeAddr_ + virtualFreeSize_); ++i) { proc()->lowlevel_process()->findFuncsByAddr(i, deletedFuncs); } for (std::set<func_instance *>::iterator iter = deletedFuncs.begin(); iter != deletedFuncs.end(); ++iter) { BPatch_function * bpfunc = proc()->findOrCreateBPFunc(*iter, NULL); if (!bpfunc) continue; PatchAPI::PatchModifier::remove(bpfunc->lowlevel_func()); } proc()->lowlevel_process()->getMemEm()->removeRegion(virtualFreeAddr_, virtualFreeSize_); // And nuke the RT cache proc()->lowlevel_process()->proc()->flushAddressCache_RT(virtualFreeAddr_, virtualFreeSize_); virtualFreeAddr_ = 0; return; }
static void InstrumentCalls (BPatch_image *appImage, BPatch_addressSpace *appProcess, ApplicationType *appType, set<string> &OMPset, set<string> &USERset, map<string, vector<string> > & LoopLevels, bool instrumentMPI, bool instrumentOMP, bool instrumentUF) { unsigned i = 0; unsigned OMPinsertion = 0; unsigned OMPreplacement_intel_v11 = 0; unsigned MPIinsertion = 0; unsigned APIinsertion = 0; unsigned UFinsertion = 0; const char *PMPI_C_prefix = "PMPI_"; const char *PMPI_F_prefix = "pmpi_"; const char *MPI_C_prefix = "MPI_"; const char *MPI_F_prefix= "mpi_"; cout << PACKAGE_NAME << ": Obtaining functions from application image (this may take a while)..." << flush; BPatch_Vector<BPatch_function *> *vfunctions = appImage->getProcedures (false); cout << "Done" << endl; set<string> CUDAkernels; /* Look for CUDA kernels if the application is CUDA */ if (appType->get_isCUDA()) { cout << PACKAGE_NAME << ": Looking for CUDA kernels inside binary (this may take a while)..." << endl; i = 0; while (i < vfunctions->size()) { char name[1024]; BPatch_function *f = (*vfunctions)[i]; f->getName (name, sizeof(name)); BPatch_Vector<BPatch_point *> *vpoints = f->findPoint (BPatch_subroutine); if (vpoints != NULL) { unsigned j = 0; while (j < vpoints->size()) { BPatch_function *called = ((*vpoints)[j])->getCalledFunction(); if (NULL != called) { char calledname[1024]; called->getName (calledname, 1024); if (strncmp (calledname, "__device_stub__", strlen("__device_stub__")) == 0) { CUDAkernels.insert (name); if (VerboseLevel) cout << PACKAGE_NAME << ": Found kernel " << name << endl; } } j++; } } i++; } cout << PACKAGE_NAME << ": Finished looking for CUDA kernels" << endl; } cout << PACKAGE_NAME << ": Parsing executable looking for instrumentation points (" << vfunctions->size() << ") "; if (VerboseLevel) cout << endl; else cout << flush; /* The 1st step includes: a) gather information of openmp outlined routines (original is added to USERset), b) instrument openmp outlined routines c) instrument mpi calls d) instrument api calls */ i = 0; while (i < vfunctions->size()) { char name[1024], sharedlibname_c[1024]; BPatch_function *f = (*vfunctions)[i]; (f->getModule())->getFullName (sharedlibname_c, sizeof(sharedlibname_c)); f->getName (name, sizeof(name)); string sharedlibname = sharedlibname_c; string sharedlibname_ext; if (sharedlibname.rfind('.') != string::npos) sharedlibname_ext = sharedlibname.substr (sharedlibname.rfind('.')); else sharedlibname_ext = ""; /* For OpenMP apps, if the application has been linked with Extrae, just need to instrument the function calls that have #pragma omp in them. The outlined routines will be instrumented by the library attached to the binary */ if (!BinaryLinkedWithInstrumentation && instrumentOMP && appType->get_isOpenMP() && loadedModule != sharedlibname) { /* OpenMP instrumentation (just for OpenMP apps) */ if (appType->isMangledOpenMProutine (name)) { if (VerboseLevel) if (!BinaryLinkedWithInstrumentation) cout << PACKAGE_NAME << ": Instrumenting OpenMP outlined routine " << name << endl; if (!BinaryLinkedWithInstrumentation) { /* Instrument routine */ wrapTypeRoutine (f, name, OMPFUNC_EV, appImage); /* Add to list if not already there */ OMPset.insert (name); } /* Demangle name and add into the UF list if it didn't exist there */ string demangled = appType->demangleOpenMProutine (name); if (!XML_excludeAutomaticFunctions()) USERset.insert (demangled); if (VerboseLevel) { if (!XML_excludeAutomaticFunctions()) cout << PACKAGE_NAME << ": Adding demangled OpenMP routine " << demangled << " to the user function list" << endl; else cout << PACKAGE_NAME << ": Will not add demangled OpenMP routine " << demangled << " due to user request in the XML configuration file" << endl; } OMPinsertion++; } } if (sharedlibname_ext == ".f" || sharedlibname_ext == ".F" || /* fortran */ sharedlibname_ext == ".for" || sharedlibname_ext == ".FOR" || /* fortran */ sharedlibname_ext == ".f90" || sharedlibname_ext == ".F90" || /* fortran 90 */ sharedlibname_ext == ".i90" || /* fortran 90 through ifort */ sharedlibname_ext == ".f77" || sharedlibname_ext == ".F77" || /* fortran 77 */ sharedlibname_ext == ".c" || sharedlibname_ext == ".C" || /* C */ sharedlibname_ext == ".cxx" || sharedlibname_ext == ".cpp" || /* c++ */ sharedlibname_ext == ".c++" || /* c++ */ sharedlibname_ext == ".i" || /* some compilers generate this extension in intermediate files */ sharedlibname == "DEFAULT_MODULE" /* Dyninst specific container that represents the executable */ ) { /* API instrumentation (for any kind of apps) Skip calls from my own module */ BPatch_Vector<BPatch_point *> *vpoints = f->findPoint (BPatch_subroutine); if (vpoints == NULL) break; if (VerboseLevel >= 2) printCallingSites (i, vfunctions->size(), name, sharedlibname, vpoints); unsigned j = 0; while (j < vpoints->size()) { BPatch_function *called = ((*vpoints)[j])->getCalledFunction(); if (NULL != called) { char calledname[1024]; called->getName (calledname, 1024); /* Check API calls */ BPatch_function *patch_api = getAPIPatch (calledname); if (patch_api != NULL) { if (appProcess->replaceFunctionCall (*((*vpoints)[j]), *patch_api)) { APIinsertion++; if (VerboseLevel) cout << PACKAGE_NAME << ": Replaced call " << calledname << " in routine " << name << " (" << sharedlibname << ")" << endl; } else cerr << PACKAGE_NAME << ": Cannot replace " << calledname << " routine" << endl; } /* Check MPI calls */ if (!BinaryLinkedWithInstrumentation && instrumentMPI && appType->get_isMPI() && ( strncmp (calledname, PMPI_C_prefix, 5) == 0 || strncmp (calledname, MPI_C_prefix, 4) == 0 || strncmp (calledname, PMPI_F_prefix, 5) == 0 || strncmp (calledname, MPI_F_prefix, 4) == 0)) { BPatch_function *patch_mpi = getMPIPatch (calledname); if (patch_mpi != NULL) { if (appProcess->replaceFunctionCall (*((*vpoints)[j]), *patch_mpi)) { MPIinsertion++; if (VerboseLevel) cout << PACKAGE_NAME << ": Replaced call " << calledname << " in routine " << name << " (" << sharedlibname << ")" << endl; } else cerr << PACKAGE_NAME << ": Cannot replace " << calledname << " routine" << endl; } } /* Special instrumentation for calls in Intel OpenMP runtime v11/v12 currently only for __kmpc_fork_call */ if (!BinaryLinkedWithInstrumentation && appType->get_OpenMP_rte() == ApplicationType::Intel_v11 && strncmp (calledname, "__kmpc_fork_call", strlen("__kmpc_fork_call")) == 0) { BPatch_function *patch_openmp = getRoutine ( "__kmpc_fork_call_extrae_dyninst", appImage, false); if (patch_openmp != NULL) { if (appProcess->replaceFunctionCall (*((*vpoints)[j]), *patch_openmp)) { OMPreplacement_intel_v11++; if (VerboseLevel) cout << PACKAGE_NAME << ": Replaced call " << calledname << " in routine " << name << " (" << sharedlibname << ")" << endl; } else cerr << PACKAGE_NAME << ": Cannot replace " << calledname << " routine" << endl; } /* Instrument the routine that invokes the runtime */ if (!XML_excludeAutomaticFunctions()) USERset.insert (name); if (VerboseLevel) { if (!XML_excludeAutomaticFunctions()) cout << PACKAGE_NAME << ": Adding call to OpenMP routine " << name << " to the user function list" << endl; else cout << PACKAGE_NAME << ": Will not add call to OpenMP routine " << name << " due to user request in the XML configuration file" << endl; } } /* Special instrumentation for fork() / wait() / exec* calls */ if (!BinaryLinkedWithInstrumentation && ( strncmp (calledname, "fork", strlen("fork")) == 0 || strncmp (calledname, "wait", strlen("wait")) == 0 || strncmp (calledname, "waitpid", strlen("waitpid")) == 0 || strncmp (calledname, "system", strlen("system")) == 0 || strncmp (calledname, "execl", strlen("execl")) == 0 || strncmp (calledname, "execle", strlen("execle")) == 0 || strncmp (calledname, "execlp", strlen("execlp")) == 0 || strncmp (calledname, "execv", strlen("execv")) == 0 || strncmp (calledname, "execve", strlen("execve")) == 0 || strncmp (calledname, "execvp", strlen("execvp")) == 0 ) ) { /* Instrument the routine that invokes the runtime */ if (!XML_excludeAutomaticFunctions()) USERset.insert (name); if (VerboseLevel) { if (!XML_excludeAutomaticFunctions()) cout << PACKAGE_NAME << ": Adding routine " << name << " to the user function list because it calls to " << calledname << endl; else cout << PACKAGE_NAME << ": Will not add routine to the user function list " << name << " due to user request in the XML configuration file" << endl; } } /* Instrument routines that call CUDA */ if (appType->get_isCUDA()) { string scalledname (calledname); if (find (CUDAkernels.begin(), CUDAkernels.end(), scalledname) != CUDAkernels.end()) { if (!XML_excludeAutomaticFunctions()) USERset.insert (name); if (VerboseLevel) { if (!XML_excludeAutomaticFunctions()) cout << PACKAGE_NAME << ": Adding routine " << name << " to the user function list because it calls the CUDA kernel '" << calledname<< "'" << endl; else cout << PACKAGE_NAME << ": Will not instrument CUDA routine " << name << " due to user request in the XML configuration file" << endl; } } } } j++; } } i++; if (!VerboseLevel) { if (i == 1) cout << "1" << flush; else if (i%1000 == 0) cout << i << flush; else if (i%100 == 0) cout << "." << flush; } } if (!VerboseLevel) cout << ".Done" << endl; if (USERset.size() > 0 && instrumentUF) { /* Instrument user functions! */ cout << PACKAGE_NAME << ": Instrumenting user functions..."; if (VerboseLevel) cout << endl; else cout << flush; set<string>::iterator iter = USERset.begin(); while (iter != USERset.end()) { if (*iter != "main") { BPatch_function *f = getRoutine ((*iter).c_str(), appImage); if (f != NULL) { wrapTypeRoutine (f, *iter, USRFUNC_EV, appImage); vector<string> points = LoopLevels[*iter]; // LoopLevels['foo'] = [bb_1,loop_1.2.3,bb_5] instrumentLoops(f, *iter, appImage, points); instrumentBasicBlocks(f, appImage, points); UFinsertion++; if (VerboseLevel) cout << PACKAGE_NAME << ": Instrumenting user function : " << *iter << endl; } else { if (VerboseLevel) cout << PACKAGE_NAME << ": Unable to instrument user function : " << *iter << endl; } } else { if (VerboseLevel) cout << PACKAGE_NAME << ": Although 'main' symbol was in the instrumented functions list, it will not be instrumented" << endl; } iter++; } if (VerboseLevel) cout << PACKAGE_NAME << ": End of instrumenting functions" << endl; else cout << "Done" << endl; } cout << PACKAGE_NAME << ": " << APIinsertion << " API patches applied" << endl; if (appType->get_isMPI()) cout << PACKAGE_NAME << ": " << MPIinsertion << " MPI patches applied" << endl; if (appType->get_isOpenMP()) { cout << PACKAGE_NAME << ": " << OMPinsertion << " OpenMP patches applied to outlined routines" << endl; if (appType->get_OpenMP_rte() == ApplicationType::Intel_v11) cout << PACKAGE_NAME << ": " << OMPreplacement_intel_v11 << " OpenMP patches applied to specific locations for Intel runtime" << endl; } if (USERset.size() > 0) cout << PACKAGE_NAME << ": " << UFinsertion << " user function" << ((UFinsertion!=1)?"s":"") << " instrumented" << endl; }
void readTracePipe() { int read_len; char buf[ STRING_MAX ] = { '\0' }; if (config.pipefd < 0) return; do { errno = 0; sendMsg(config.outfd, ID_TRACE_READ, DEBUG); read_len = read(config.pipefd, buf, trace_msglen); buf[trace_msglen] = '\0'; if (read_len < trace_msglen) { if (read_len == -1 && errno == EAGAIN) { // No data on pipe. Break out of read loop // and re-poll for status change. sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_PASS); break; } else if (read_len == 0 && errno == 0) { // Read EOF from pipefd. Close pipe and break. sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_PASS); close(config.pipefd); config.pipefd = -1; break; } else if (read_len > 0) { // Partial data written to trace pipe. Report to monitor. sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_FAIL, sprintf_static("Read partial message from trace pipe. Discarding message '%s'.", buf)); break; } else if (errno) { // Send error message to monitor. sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_FAIL, sprintf_static("Mutator encountered error on trace pipe read(): %s", strerror(errno))); close(config.pipefd); config.pipefd = -1; break; } } void *traceMsg = (void *)strtol(buf, NULL, 16); map< void *, BPatch_function * >::iterator iter = trace_points.find(traceMsg); if (iter == trace_points.end()) { sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_FAIL, sprintf_static("Read invalid message from trace pipe. 0x%s does not refer to a valid BPatch_point.", buf)); break; } sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_PASS); BPatch_point *point = (BPatch_point *)traceMsg; const char *pType = "Unknown "; if (point->getPointType() == BPatch_entry) pType = "Entering "; if (point->getPointType() == BPatch_exit) pType = "Exiting "; const char *pName = "anonymous function"; BPatch_function *pFunc = (*iter).second; if (pFunc) { if (pFunc->getName(buf, sizeof(buf))) pName = sprintf_static("function %s", buf); else pName = sprintf_static("anonymous function at 0x%0*lx", sizeof(void *), pFunc->getBaseAddr()); } if (config.pipefd > 0) { // Could have been interrupted by mutatee exit. sendMsg(config.outfd, ID_TRACE_POINT, INFO, ID_INFO, strcat_static(pType, pName)); } } while (errno == 0); }
test_results_t test1_23_Mutator::executeTest() { const char *funcName = "test1_23_call1"; BPatch_Vector<BPatch_function *> found_funcs; if ((NULL == appImage->findFunction(funcName, found_funcs, 1)) || !found_funcs.size()) { logerror(" Unable to find function %s\n", funcName); return FAILED; } if (1 < found_funcs.size()) { logerror("%s[%d]: WARNING : found %d functions named %s. Using the first.\n", __FILE__, __LINE__, found_funcs.size(), funcName); } BPatch_Vector<BPatch_point *> *point23_calls = found_funcs[0]->findPoint(BPatch_subroutine); if (!point23_calls || (point23_calls->size() < 1)) { logerror("**Failed** test #23 (local variables)\n"); logerror(" Unable to find point %s - subroutine calls\n", funcName); return FAILED; } /* We only want the first one... */ BPatch_Vector<BPatch_point *> point23_1; point23_1.push_back((*point23_calls)[0]); BPatch_variableExpr *var1 = appImage->findVariable(*(point23_1[0]), "localVariable23_1"); BPatch_variableExpr *var2 = appImage->findVariable(*(point23_1[0]), "test1_23_shadowVariable1"); BPatch_variableExpr *var3 = appImage->findVariable("test1_23_shadowVariable2"); BPatch_variableExpr *var4 = appImage->findVariable("test1_23_globalVariable1"); if (!var1 || !var2 || !var3 || !var4) { logerror("**Failed** test #23 (local variables)\n"); if (!var1) { logerror(" can't find local variable localVariable23_1\n"); BPatch_function *f = point23_1[0]->getCalledFunction(); assert(f); BPatch_Vector<BPatch_localVar *> *lvars = f->getVars(); assert(lvars); logerror("%s[%d]: have vars\n", FILE__, __LINE__); for (unsigned int i = 0; i < lvars->size(); ++i) { logerror("\t%s\n", (*lvars)[i]->getName()); } } if (!var2) logerror(" can't find local variable test1_23_shadowVariable1\n"); if (!var3) logerror(" can't find global variable test1_23_shadowVariable2\n"); return FAILED; } BPatch_arithExpr expr23_1(BPatch_assign, *var1, BPatch_constExpr(2300001)); BPatch_arithExpr expr23_2(BPatch_assign, *var2, BPatch_constExpr(2300012)); BPatch_arithExpr expr23_3(BPatch_assign, *var3, BPatch_constExpr(2300023)); BPatch_arithExpr expr23_4(BPatch_assign, *var4, *var1); BPatch_Vector<BPatch_snippet *> exprs; exprs.push_back(&expr23_1); exprs.push_back(&expr23_2); exprs.push_back(&expr23_3); exprs.push_back(&expr23_4); BPatch_sequence allParts(exprs); appAddrSpace->insertSnippet(allParts, point23_1); return PASSED; }
/* Parse and instrument any signal handlers that have yet to be * analyzed (and instrumented), and that are not in system libraries */ void HybridAnalysis::signalHandlerCB(BPatch_point *point, long signum, std::vector<Address> &handlers) { mal_printf("signalHandlerCB(%lx , %lx, %d handlers)\n", point->getAddress(), signum, handlers.size()); bool onlySysHandlers = true; std::vector<Address> handlerAddrs; proc()->beginInsertionSet(); // eliminate any handlers in system libraries, and handlers that have // already been parsed, add new handlers to handler function list std::vector<Address>::iterator it=handlers.begin(); while (it < handlers.end()) { BPatch_module *mod = proc()->findModuleByAddr(*it); if (!mod || mod->isSystemLib()) { it = handlers.erase(it); continue; } BPatch_function *handlerFunc = proc()->findFunctionByEntry(*it); handlerFunctions[*it] = ExceptionDetails(); if (handlerFunc) { it = handlers.erase(it); continue; } // parse and instrument handler mal_printf("found handler at %x %s[%d]\n", *it,FILE__,__LINE__); onlySysHandlers = false; analyzeNewFunction(point,*it,true,false); handlerFunc = proc()->findFunctionByEntry(*it); assert(handlerFunc); handlerAddrs.push_back(*it); BPatch_point *entryPt = (*handlerFunc->findPoint(BPatch_entry))[0]; // instrument the handler at its entry and exit points proc()->beginInsertionSet(); // instrument handler entry with callbacks that will deliver the stack // addresses at which the fault addr is stored BPatch_paramExpr excRecAddr(0,BPatch_ploc_entry); BPatch_paramExpr excCtxtAddr(2,BPatch_ploc_entry); BPatch_stopThreadExpr sThread1 (signalHandlerEntryCB_wrapper,excRecAddr,false,BPatch_noInterp); BPatch_stopThreadExpr sThread2 (signalHandlerEntryCB2_wrapper,excCtxtAddr,false,BPatch_noInterp); proc()->insertSnippet(sThread2, *entryPt); proc()->insertSnippet(sThread1, *entryPt); // remove any exit-point instrumentation and add new instrumentation // at exit points std::map<BPatch_point*,BPatchSnippetHandle*> *funcPoints = (*instrumentedFuncs)[handlerFunc]; if ( funcPoints ) { std::map<BPatch_point*, BPatchSnippetHandle*>::iterator pit; pit = funcPoints->begin(); while (pit != funcPoints->end()) { if ( BPatch_exit == (*pit).first->getPointType() ) { proc()->deleteSnippet((*pit).second); funcPoints->erase( (*pit).first ); pit = funcPoints->begin(); } else { pit++; } } } instrumentFunction(handlerFunc, false, true); it++; } proc()->finalizeInsertionSet(false); // trigger the signal-handler callback if (bpatchSignalHandlerCB) { bpatchSignalHandlerCB(point,signum,&handlerAddrs); } }
test_results_t test1_36_Mutator::executeTest() { const char *funcName = "test1_36_func1"; BPatch_Vector<BPatch_function *> found_funcs; if ((NULL == appImage->findFunction(funcName, found_funcs)) || !found_funcs.size()) { logerror(" Unable to find function %s\n", funcName); return FAILED; } if (1 < found_funcs.size()) { logerror("%s[%d]: WARNING : found %d functions named %s. Using the first.\n", __FILE__, __LINE__, found_funcs.size(), funcName); } BPatch_Vector<BPatch_point *> *all_points36_1 = found_funcs[0]->findPoint(BPatch_subroutine); if (!all_points36_1 || (all_points36_1->size() < 1)) { logerror("Unable to find point %s - subroutines.\n", funcName); return FAILED; } const char *funcName2 = "test1_36_call1"; BPatch_point *point36_1 = NULL; for (unsigned i=0; i<(*all_points36_1).size(); i++) { BPatch_point *cur_point = (*all_points36_1)[i]; if (cur_point == NULL) continue; BPatch_function *func = cur_point->getCalledFunction(); char funcname[100]; if (!func) continue; if (func->getName(funcname, 99)) { if (strstr(funcname, funcName2)) point36_1 = cur_point; } } if (point36_1 == NULL) { logerror("Unable to find callsite %s\n", funcName2); return FAILED; } BPatch_variableExpr *expr36_1 = findVariable(appImage, "test1_36_globalVariable1", all_points36_1); BPatch_variableExpr *expr36_2 = findVariable(appImage, "test1_36_globalVariable2", all_points36_1); BPatch_variableExpr *expr36_3 = findVariable(appImage, "test1_36_globalVariable3", all_points36_1); BPatch_variableExpr *expr36_4 = findVariable(appImage, "test1_36_globalVariable4", all_points36_1); BPatch_variableExpr *expr36_5 = findVariable(appImage, "test1_36_globalVariable5", all_points36_1); BPatch_variableExpr *expr36_6 = findVariable(appImage, "test1_36_globalVariable6", all_points36_1); BPatch_variableExpr *expr36_7 = findVariable(appImage, "test1_36_globalVariable7", all_points36_1); BPatch_variableExpr *expr36_8 = findVariable(appImage, "test1_36_globalVariable8", all_points36_1); BPatch_variableExpr *expr36_9 = findVariable(appImage, "test1_36_globalVariable9", all_points36_1); BPatch_variableExpr *expr36_10 = findVariable(appImage, "test1_36_globalVariable10", all_points36_1); if (expr36_1 == NULL || expr36_2 == NULL || expr36_3 == NULL || expr36_4 == NULL || expr36_5 == NULL || expr36_6 == NULL || expr36_7 == NULL || expr36_8 == NULL || expr36_9 == NULL || expr36_10 == NULL) { logerror("**Failed** test #36 (callsite parameter referencing)\n"); logerror(" Unable to locate at least one of " "test1_36_globalVariable{1...10}\n"); return FAILED; } BPatch_Vector<BPatch_snippet *> snippet_seq; snippet_seq.push_back(makeTest36paramExpr(expr36_1, 0)); snippet_seq.push_back(makeTest36paramExpr(expr36_2, 1)); snippet_seq.push_back(makeTest36paramExpr(expr36_3, 2)); snippet_seq.push_back(makeTest36paramExpr(expr36_4, 3)); snippet_seq.push_back(makeTest36paramExpr(expr36_5, 4)); snippet_seq.push_back(makeTest36paramExpr(expr36_6, 5)); snippet_seq.push_back(makeTest36paramExpr(expr36_7, 6)); snippet_seq.push_back(makeTest36paramExpr(expr36_8, 7)); snippet_seq.push_back(makeTest36paramExpr(expr36_9, 8)); snippet_seq.push_back(makeTest36paramExpr(expr36_10, 9)); BPatch_sequence seqExpr(snippet_seq); checkCost(seqExpr); appAddrSpace->insertSnippet(seqExpr, *point36_1); return PASSED; }
test_results_t test1_40_Mutator::executeTest() { const char *monitorFuncName = "test1_40_monitorFunc"; const char *callSiteAddrVarName = "test1_40_callsite5_addr"; BPatch_function *monitorFunc = NULL; BPatch_Vector<BPatch_function *> bpfv; BPatch_function *call40_1 = findFunction40("test1_40_call1", appImage); RETURNONNULL(call40_1); RETURNONFAIL(setVar40("test1_40_addr_of_call1", call40_1->getBaseAddr(),appImage)); BPatch_function *call40_2 = findFunction40("test1_40_call2", appImage); RETURNONNULL(call40_2); RETURNONFAIL(setVar40("test1_40_addr_of_call2", call40_2->getBaseAddr(),appImage)); BPatch_function *call40_3 = findFunction40("test1_40_call3", appImage); RETURNONNULL(call40_3); RETURNONFAIL(setVar40("test1_40_addr_of_call3", call40_3->getBaseAddr(),appImage)); // call40_5 is the "dispatcher" of function pointers BPatch_function *targetFunc = findFunction40("test1_40_call5", appImage); RETURNONNULL(targetFunc); //RETURNONFAIL(setVar40("test1_40_addr_of_call5", call40_5->getBaseAddr(),appImage)); monitorFunc = findFunction40(monitorFuncName, appImage); RETURNONNULL(monitorFunc); BPatch_Vector<BPatch_point *> *calls = targetFunc->findPoint(BPatch_subroutine); if (!calls) { logerror("**Failed test #40 (monitor call sites)\n"); logerror(" cannot find call points for test1_40_call5\n"); return FAILED; } BPatch_Vector<BPatch_point *> dyncalls; for (unsigned int i = 0; i < calls->size(); ++i) { BPatch_point *pt = (*calls)[i]; if (pt->isDynamic()) dyncalls.push_back(pt); } if (dyncalls.size() != 1) { logerror("**Failed test #40 (monitor call sites)\n"); logerror(" wrong number of dynamic points found (%d -- not 1)\n", dyncalls.size()); logerror(" total number of calls found: %d\n", calls->size()); return FAILED; } // write address of anticipated call site into mutatee var. void *callsite_address = dyncalls[0]->getAddress(); RETURNONFAIL(setVar40(callSiteAddrVarName, callsite_address, appImage)); // issue command to monitor calls at this site, and we're done. if (! dyncalls[0]->monitorCalls(monitorFunc)) { logerror("**Failed test #40 (monitor call sites)\n"); logerror(" cannot monitor calls\n"); return FAILED; } return PASSED; }
// // Start Test Case #3 - (overload operator) // // static int mutatorTest(BPatch_thread *appThread, BPatch_image *appImage) test_results_t test5_3_Mutator::executeTest() { BPatch_Vector<BPatch_function *> bpfv; const char *fn = "overload_op_test::func_cpp"; if (NULL == appImage->findFunction(fn, bpfv) || !bpfv.size() || NULL == bpfv[0]){ logerror("**Failed** test #3 (overloaded operation)\n"); logerror(" Unable to find function %s\n", fn); return FAILED; } BPatch_function *f1 = bpfv[0]; BPatch_Vector<BPatch_point *> *point3_1 = f1->findPoint(BPatch_subroutine); assert(point3_1); if (point3_1->size() == 0) { logerror("**Failed test5_3 (overload operation)\n"); logerror(" Can't find overloaded operator call points\n"); return FAILED; } unsigned int index = 0; char fn3[256]; BPatch_function *func; while (index < point3_1->size()) { if ((func = (*point3_1)[index]->getCalledFunction()) != NULL && !strcmp("overload_op_test::operator++", func->getName(fn3, 256))) { break; } index ++; } if(!func) { logerror("**Failed** test #3 (overload operation)\n"); logerror(" Can't find the overload operator\n"); return FAILED; } if (0 != strcmp("overload_op_test::operator++", func->getName(fn3, 256))) { logerror("**Failed** test #3 (overload operation)\n"); logerror(" Can't find the overloaded operator\n"); return FAILED; } // FIXME It caught fprintf... BPatch_Vector<BPatch_point *> *point3_2 = func->findPoint(BPatch_exit); assert(point3_2); bpfv.clear(); const char *fn2 = "overload_op_test::call_cpp"; if (NULL == appImage->findFunction(fn2, bpfv) || !bpfv.size() || NULL == bpfv[0]){ logerror("**Failed** test #3 (overloaded operation)\n"); logerror(" Unable to find function %s\n", fn2); return FAILED; } BPatch_function *call3_1 = bpfv[0]; BPatch_variableExpr *this2 = appImage->findVariable("test5_3_test3"); if (this2 == NULL) { logerror( "**Failed** test #3 (overloaded operation)\n"); logerror( "Unable to find variable \"test5_3_test3\"\n"); return FAILED; } BPatch_Vector<BPatch_snippet *> opArgs; BPatch_arithExpr expr2_0(BPatch_addr, *this2); opArgs.push_back(&expr2_0); opArgs.push_back(new BPatch_retExpr()); BPatch_funcCallExpr call3_1Expr(*call3_1, opArgs); checkCost(call3_1Expr); appAddrSpace->insertSnippet(call3_1Expr, *point3_2); // int tag = 1; // while (tag != 0) {} return PASSED; }
int main(int argc, char **argv) { if (argc < 3 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--h", 3) == 0) { cout << "Usage: " << argv[0] << USAGE; return false; } if (!parseOptions(argc, argv)) { return EXIT_FAILURE; } if (do_bb == true) { if (DYNINST_MAJOR_VERSION < 9 || (DYNINST_MAJOR_VERSION == 9 && DYNINST_MINOR_VERSION < 3) || (DYNINST_MAJOR_VERSION == 9 && DYNINST_MINOR_VERSION == 3 && DYNINST_PATCH_VERSION <= 2)) { if (dynfix == false) fprintf(stderr, "Warning: your dyninst version does not include a critical fix, you should use the -f option!\n"); } else { if (dynfix == true) fprintf(stderr, "Notice: your dyninst version is fixed, the -f option should not be necessary.\n"); } } BPatch bpatch; BPatch_binaryEdit *appBin = bpatch.openBinary(originalBinary, instrumentLibraries.size() != 1); if (appBin == NULL) { cerr << "Failed to open binary" << endl; return EXIT_FAILURE; } BPatch_image *appImage = appBin->getImage(); //get and iterate over all modules, instrumenting only the default and manually specified ones vector < BPatch_module * >*modules = appImage->getModules(); vector < BPatch_module * >::iterator moduleIter; vector < BPatch_function * >*funcsInModule; BPatch_module *defaultModule = NULL; string defaultModuleName; // look for _init if (defaultModuleName.empty()) { for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) { funcsInModule = (*moduleIter)->getProcedures(); vector < BPatch_function * >::iterator funcsIterator; for (funcsIterator = funcsInModule->begin(); funcsIterator != funcsInModule->end(); ++funcsIterator) { char funcName[1024]; (*funcsIterator)->getName(funcName, 1024); if (string(funcName) == string("_init")) { char moduleName[1024]; (*moduleIter)->getName(moduleName, 1024); defaultModuleName = string(moduleName); if (verbose) { cout << "Found _init in " << moduleName << endl; } break; } } if (!defaultModuleName.empty()) break; } } // last resort, by name of the binary if (defaultModuleName.empty()) defaultModuleName = string(originalBinary).substr(string(originalBinary).find_last_of("\\/") + 1); if (!appBin->loadLibrary(instLibrary)) { cerr << "Failed to open instrumentation library " << instLibrary << endl; cerr << "It needs to be located in the current working directory." << endl; return EXIT_FAILURE; } appImage = appBin->getImage(); /* Find code coverage functions in the instrumentation library */ BPatch_function *initAflForkServer; save_rdi = findFuncByName(appImage, (char *) "save_rdi"); restore_rdi = findFuncByName(appImage, (char *) "restore_rdi"); BPatch_function *bbCallback = findFuncByName(appImage, (char *) "bbCallback"); BPatch_function *forceCleanExit = findFuncByName(appImage, (char *) "forceCleanExit"); if (do_bb == true) initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServer"); else initAflForkServer = findFuncByName(appImage, (char *) "initOnlyAflForkServer"); if (!initAflForkServer || !bbCallback || !save_rdi || !restore_rdi || !forceCleanExit) { cerr << "Instrumentation library lacks callbacks!" << endl; return EXIT_FAILURE; } int bbIndex = 0; // instrument all shared libraries: for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) { char moduleName[1024]; (*moduleIter)->getName(moduleName, 1024); if ((*moduleIter)->isSharedLib()) { if (instrumentLibraries.find(moduleName) == instrumentLibraries.end()) { cout << "Skipping library: " << moduleName << endl; continue; } } if (string(moduleName).find(defaultModuleName) != string::npos) { defaultModule = (*moduleIter); if (skipMainModule) continue; } if (do_bb == true) { cout << "Instrumenting module: " << moduleName << endl; vector < BPatch_function * >*allFunctions = (*moduleIter)->getProcedures(); vector < BPatch_function * >::iterator funcIter; // iterate over all functions in the module for (funcIter = allFunctions->begin(); funcIter != allFunctions->end(); ++funcIter) { BPatch_function *curFunc = *funcIter; char funcName[1024]; int do_patch = 1; curFunc->getName(funcName, 1024); if (string(funcName) == string("_start")) continue; // here's a bug on hlt // XXX: check what happens if removed if (!skipAddresses.empty()) { set < string >::iterator saiter; for (saiter = skipAddresses.begin(); saiter != skipAddresses.end() && do_patch == 1; saiter++) if (*saiter == string(funcName)) do_patch = 0; if (do_patch == 0) { cout << "Skipping instrumenting function " << funcName << endl; continue; } } insertBBCallback(appBin, curFunc, funcName, bbCallback, &bbIndex); } } } // if an entrypoint was set then find function, else find _init BPatch_function *funcToPatch = NULL; if (!entryPoint) { BPatch_Vector < BPatch_function * >funcs; defaultModule->findFunction("_init", funcs); if (!funcs.size()) { cerr << "Couldn't locate _init, specify entry point manually with -e 0xaddr" << endl; return EXIT_FAILURE; } // there should really be only one funcToPatch = funcs[0]; } else { funcToPatch = defaultModule->findFunctionByEntry(entryPoint); } if (!funcToPatch) { cerr << "Couldn't locate function at given entry point. " << endl; return EXIT_FAILURE; } if (!insertCallToInit(appBin, initAflForkServer, defaultModule, funcToPatch)) { cerr << "Could not insert init callback at given entry point." << endl; return EXIT_FAILURE; } if (!exitAddresses.empty()) { cout << "Instrumenting forced exit addresses." << endl; set < unsigned long >::iterator uliter; for (uliter = exitAddresses.begin(); uliter != exitAddresses.end(); uliter++) { if (*uliter > 0 && (signed long)*uliter != -1) { funcToPatch = defaultModule->findFunctionByEntry(*uliter); if (!funcToPatch) { cerr << "Could not find enty point 0x" << hex << *uliter << " (continuing)" << endl; } else { if (!insertCallToInit(appBin, forceCleanExit, defaultModule, funcToPatch)) cerr << "Could not insert force clean exit callback at 0x" << hex << *uliter << " (continuing)" << endl; } } } } cout << "Saving the instrumented binary to " << instrumentedBinary << " ..." << endl; // Output the instrumented binary if (!appBin->writeFile(instrumentedBinary)) { cerr << "Failed to write output file: " << instrumentedBinary << endl; return EXIT_FAILURE; } if (!runtimeLibraries.empty()) { cout << "Instrumenting runtime libraries." << endl; set < string >::iterator rtLibIter; for (rtLibIter = runtimeLibraries.begin(); rtLibIter != runtimeLibraries.end(); rtLibIter++) { BPatch_binaryEdit *libBin = bpatch.openBinary((*rtLibIter).c_str(), false); if (libBin == NULL) { cerr << "Failed to open binary " << *rtLibIter << endl; return EXIT_FAILURE; } BPatch_image *libImg = libBin->getImage(); vector < BPatch_module * >*modules = libImg->getModules(); moduleIter = modules->begin(); for (; moduleIter != modules->end(); ++moduleIter) { char moduleName[1024]; (*moduleIter)->getName(moduleName, 1024); cout << "Instrumenting module: " << moduleName << endl; vector < BPatch_function * >*allFunctions = (*moduleIter)->getProcedures(); vector < BPatch_function * >::iterator funcIter; // iterate over all functions in the module for (funcIter = allFunctions->begin(); funcIter != allFunctions->end(); ++funcIter) { BPatch_function *curFunc = *funcIter; char funcName[1024]; curFunc->getName(funcName, 1024); if (string(funcName) == string("_start")) continue; insertBBCallback(libBin, curFunc, funcName, bbCallback, &bbIndex); } } if (!libBin->writeFile((*rtLibIter + ".ins").c_str())) { cerr << "Failed to write output file: " << (*rtLibIter + ".ins").c_str() << endl; return EXIT_FAILURE; } else { cout << "Saved the instrumented library to " << (*rtLibIter + ".ins").c_str() << "." << endl; } } } cout << "All done! Happy fuzzing!" << endl; return EXIT_SUCCESS; }