// static bool mutatorTest3and4(int testno, const char *testname) test_results_t test_thread_3_Mutator::executeTest() { test3_threadCreateCounter = 0; callback_tids.clear(); unsigned int timeout = 0; // in ms int err = 0; BPatchAsyncThreadEventCallback createcb = threadCreateCB; if (!bpatch->registerThreadEventCallback(BPatch_threadCreateEvent, createcb)) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: failed to register thread callback\n", __FILE__, __LINE__); appThread->getProcess()->terminateExecution(); return FAILED; } #if 0 // unset mutateeIde to trigger thread (10) spawn. int zero = 0; // FIXME Check the return value of setVar() setVar("mutateeIdle", (void *) &zero, TESTNO, TESTDESC); dprintf("%s[%d]: continue execution for test %d\n", __FILE__, __LINE__, TESTNO); appThread->continueExecution(); #endif // wait until we have received the desired number of events // (or timeout happens) BPatch_Vector<BPatch_thread *> threads; BPatch_process *appProc = appThread->getProcess(); assert(appProc); appProc->getThreads(threads); int active_threads = 11; // FIXME Magic number threads.clear(); while (((test3_threadCreateCounter < TEST3_THREADS) || (active_threads > 1)) && (timeout < TIMEOUT)) { dprintf("%s[%d]: waiting for completion for test %d, num active threads = %d\n", __FILE__, __LINE__, TESTNO, active_threads); sleep_ms(SLEEP_INTERVAL/*ms*/); timeout += SLEEP_INTERVAL; if (appProc->isTerminated()) { dprintf("%s[%d]: BAD NEWS: somehow the process died\n", __FILE__, __LINE__); err = 1; break; } bpatch->pollForStatusChange(); if (appProc->isStopped()) { appProc->continueExecution(); } appProc->getThreads(threads); active_threads = threads.size(); threads.clear(); } if (timeout >= TIMEOUT) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: test timed out. got %d/10 events\n", __FILE__, __LINE__, test3_threadCreateCounter); logerror("test3_createCounter is %d, expected %d; active threads %d, expected %d\n", test3_threadCreateCounter, TEST3_THREADS, active_threads, 1); err = 1; } dprintf("%s[%d]: ending test %d, num active threads = %d\n", __FILE__, __LINE__, TESTNO, active_threads); dprintf("%s[%d]: stop execution for test %d\n", __FILE__, __LINE__, TESTNO); appProc->stopExecution(); // read all tids from the mutatee and verify that we got them all unsigned long mutatee_tids[TEST3_THREADS]; const char *threads_varname = "test4_threads"; getVar(threads_varname, (void *) mutatee_tids, (sizeof(unsigned long) * TEST3_THREADS), TESTNO, TESTDESC); if (debugPrint()) { dprintf("%s[%d]: read following tids for test%d from mutatee\n", __FILE__, __LINE__, TESTNO); for (unsigned int i = 0; i < TEST3_THREADS; ++i) { dprintf("\t%lu\n", mutatee_tids[i]); } } for (unsigned int i = 0; i < TEST3_THREADS; ++i) { bool found = false; for (unsigned int j = 0; j < callback_tids.size(); ++j) { if (callback_tids[j] == mutatee_tids[i]) { found = true; break; } } if (!found) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: could not find record for tid %lu: have these:\n", __FILE__, __LINE__, mutatee_tids[i]); for (unsigned int j = 0; j < callback_tids.size(); ++j) { logerror("%lu\n", callback_tids[j]); } err = true; break; } } dprintf("%s[%d]: removing thread callback\n", __FILE__, __LINE__); if (!bpatch->removeThreadEventCallback(BPatch_threadCreateEvent, createcb)) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: failed to remove thread callback\n", __FILE__, __LINE__); err = true; } if (!err) { PASS_MES(TESTNAME, TESTDESC); appProc->terminateExecution(); return PASSED; } appProc->terminateExecution(); return FAILED; }
// static int mutatorTest(BPatch_thread *appThread, BPatch_image *appImage) test_results_t test_callback_2_Mutator::executeTest() { // a simple single threaded user messagin scenario where we want to send // async messages at function entry/exit and call points. // load libtest12.so -- currently only used by subtest 5, but make it generally // available const char *libname = "./libTest12.so"; test7err = false; test7done = false; callback_counter = 0; elog.resize(0); #if defined(arch_x86_64_test) if (appProc->getAddressWidth() == 4) libname = "./libTest12_m32.so"; #endif dprintf("%s[%d]: loading test library: %s\n", __FILE__, __LINE__, libname); if (!appProc->loadLibrary(libname)) { logerror("%s[%d]: failed to load library %s, cannot proceed\n", __FILE__, __LINE__, libname); appProc->terminateExecution(); return FAILED; } dprintf("%s[%d]: loaded test library: %s\n", __FILE__, __LINE__, libname); BPatchUserEventCallback cb = test7cb; if (!bpatch->registerUserEventCallback(cb)) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: could not register callback\n", __FILE__, __LINE__); appProc->terminateExecution(); return FAILED; } // instrument entry and exit of call7_1, as well as call points inside call7_1 const char *call1name = "test_callback_2_call1"; BPatch_function *call7_1 = findFunction(call1name, appImage,TESTNO, TESTNAME); BPatch_point *entry = findPoint(call7_1, BPatch_entry,TESTNO, TESTNAME); if (NULL == entry) { logerror("%s[%d]: Unable to find entry point to function %s\n", __FILE__, __LINE__, call1name); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } BPatch_point *exit = findPoint(call7_1, BPatch_exit,TESTNO, TESTNAME); if (NULL == entry) { logerror("%s[%d]: Unable to find exit point to function %s\n", __FILE__, __LINE__, call1name); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } BPatch_point *callsite = findPoint(call7_1, BPatch_subroutine,TESTNO, TESTNAME); if (NULL == callsite) { logerror("%s[%d]: Unable to find subroutine call point in function %s\n", __FILE__, __LINE__, call1name); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } // These are our asynchronous message functions (in libTest12) that we // attach to the "interesting" points BPatch_function *reportEntry = findFunction("reportEntry", appImage,TESTNO, TESTNAME); BPatch_function *reportExit = findFunction("reportExit", appImage,TESTNO, TESTNAME); BPatch_function *reportCallsite = findFunction("reportCallsite", appImage,TESTNO, TESTNAME); if (!reportEntry) { logerror("%s[%d]: reportEntry = NULL\n", FILE__, __LINE__); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } if (!reportExit) { logerror("%s[%d]: reportExit = NULL\n", FILE__, __LINE__); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } if (!reportCallsite) { logerror("%s[%d]: reportCallsite = NULL\n", FILE__, __LINE__); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } // Do the instrumentation BPatchSnippetHandle *entryHandle = at(entry, reportEntry, TESTNO, TESTNAME); BPatchSnippetHandle *exitHandle = at(exit, reportExit, TESTNO, TESTNAME); BPatchSnippetHandle *callsiteHandle = at(callsite, reportCallsite, TESTNO, TESTNAME); // "at" may set test7err if ((test7err) || (NULL == entryHandle) || (NULL == exitHandle) || (NULL == callsiteHandle) ) { logerror("%s[%d]: instrumentation failed, test7err = %d\n", FILE__, __LINE__, test7err); logerror("%s[%d]: entryHandle = %p\n", FILE__, __LINE__, entryHandle); logerror("%s[%d]: exitHandle = %p\n", FILE__, __LINE__, exitHandle); logerror("%s[%d]: callsiteHandle = %p\n", FILE__, __LINE__, callsiteHandle); bpatch->removeUserEventCallback(test7cb); return FAILED; } if (debugPrint()) { int one = 1; const char *varName = "libraryDebug"; if (setVar(varName, (void *) &one, TESTNO, TESTNAME)) { logerror("%s[%d]: Error setting variable '%s' in mutatee\n", FILE__, __LINE__, varName); bpatch->removeUserEventCallback(test7cb); appProc->terminateExecution(); return FAILED; } } dprintf("%s[%d]: did instrumentation, continuing process...: %s\n", __FILE__, __LINE__, libname); // unset mutateeIdle to trigger mutatee to issue messages. int timeout = 0; appProc->continueExecution(); dprintf("%s[%d]: continued process...: %s\n", __FILE__, __LINE__, libname); // wait until we have received the desired number of events // (or timeout happens) while(!test7err && !test7done && (timeout < TIMEOUT)) { sleep_ms(SLEEP_INTERVAL/*ms*/); timeout += SLEEP_INTERVAL; bpatch->pollForStatusChange(); if (appProc->isTerminated()) { BPatch_exitType et = appProc->terminationStatus(); if (et == ExitedNormally) { int ecode = appProc->getExitCode(); logerror("%s[%d]: normal exit with code %d\n", __FILE__, __LINE__, ecode); } if (et == ExitedViaSignal) { int ecode = appProc->getExitSignal(); logerror("%s[%d]: caught signal %d\n", __FILE__, __LINE__, ecode); } log_res(); bpatch->removeUserEventCallback(test7cb); return FAILED; } } dprintf("%s[%d]: after wait loop: test7err = %s, test7done = %s, timeout = %d\n", __FILE__, __LINE__, test7err ? "true" : "false", test7done ? "true" : "false", timeout); if (timeout >= TIMEOUT) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: test timed out: %d ms\n", __FILE__, __LINE__, TIMEOUT); test7err = true; } if (!appProc->stopExecution()) { logerror("%s[%d]: stopExecution failed\n", __FILE__, __LINE__); } dprintf("%s[%d]: stopped process...\n", __FILE__, __LINE__ ); if (!bpatch->removeUserEventCallback(test7cb)) { FAIL_MES(TESTNAME, TESTDESC); logerror("%s[%d]: failed to remove callback\n", __FILE__, __LINE__); appProc->terminateExecution(); log_res(); return FAILED; } dprintf("%s[%d]: removed callback...\n", __FILE__, __LINE__ ); if (!appProc->terminateExecution()) { // don't care //fprintf(stderr, "%s[%d]: terminateExecution failed\n", FILE__, __LINE__); //return FAILED; } #if 0 int one = 1; if (setVar("test_callback_2_idle", (void *) &one, TESTNO, TESTNAME)) { logerror("Error setting variable 'test_callback_2_idle' in mutatee\n"); test7err = true; appProc->terminateExecution(); } #endif #if 0 // And let it run out if (!appThread->isTerminated()) { appProc->continueExecution(); } while (!appThread->isTerminated()) { // Workaround for pgCC_high mutatee issue bpatch->waitForStatusChange(); } #endif if (!test7err) { PASS_MES(TESTNAME, TESTDESC); return PASSED; } log_res(); FAIL_MES(TESTNAME, TESTDESC); return FAILED; }