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 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; }
// // 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; }
/* 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_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; }
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; }