Dispatcher::~Dispatcher() { auto locked = _mutex.try_lock(); if (!locked) { LOGe("Dispatcher deleted while in use."); assert(locked); _mutex.lock(); } if (_state != State::STOPPED) { LOGe("Dispatcher deleted but not yet stopped. Forgot to call waitUntilStopped()?"); assert(_state == State::STOPPED); if (std::this_thread::get_id() != _thread.get_id()) { if (_state == State::STARTED) { stop(); } waitUntilStopped(); } else { LOGe("Cannot delete the dispatcher from within the dispatcher thread."); } } _mutex.unlock(); }
// static int mutatorTest(BPatch_thread *appThread, BPatch_image *appImage) test_results_t test_stack_1_Mutator::executeTest() { 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(rs6000_ibm_aix4_1_test) { false, false, BPatch_frameNormal, NULL }, #endif #if !defined(i386_unknown_nt4_0_test) { true, false, BPatch_frameNormal, "stop_process_" }, #endif { true, false, BPatch_frameNormal, "test_stack_1_func3" }, { true, false, BPatch_frameNormal, "test_stack_1_func2" }, { true, false, BPatch_frameNormal, "test_stack_1_func1" }, { true, false, BPatch_frameNormal, "test_stack_1_mutateeTest" }, { true, false, BPatch_frameNormal, "main" }, }; if (waitUntilStopped(bpatch, appProc, 1, "getCallStack") < 0) { appProc->terminateExecution(); return FAILED; } if (checkStack(appThread, correct_frame_info, sizeof(correct_frame_info)/sizeof(frameInfo_t), 1, "getCallStack")) { logerror("Passed test #1 (getCallStack)\n"); } else { appProc->terminateExecution(); return FAILED; } appProc->continueExecution(); while (!appProc->isTerminated()) { bpatch->waitForStatusChange(); } return PASSED; }
// 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() */
test_results_t test1_19_Mutator::executeTest() { // Avoid a race condition in fast & loose mode while (!appProc->isStopped()) { BPatch::bpatch->waitForStatusChange(); } appProc->continueExecution(); if (waitUntilStopped(BPatch::bpatch, appProc, 19, "oneTimeCode") < 0) { return FAILED; } BPatch_Vector<BPatch_function *> bpfv; const char *fn = "test1_19_call1"; if (NULL == appImage->findFunction(fn, bpfv) || !bpfv.size() || NULL == bpfv[0]) { logerror(" Unable to find function %s\n", fn); return FAILED; } BPatch_function *call19_1_func = bpfv[0]; BPatch_Vector<BPatch_snippet *> nullArgs; BPatch_funcCallExpr call19_1Expr(*call19_1_func, nullArgs); checkCost(call19_1Expr); appProc->oneTimeCode(call19_1Expr); // Let the mutatee run to check the result appProc->continueExecution(); // Wait for the next test if (waitUntilStopped(BPatch::bpatch, appProc, 19, "oneTimeCode") < 0) { return FAILED; } bpfv.clear(); const char *fn2 = "test1_19_call2"; if (NULL == appImage->findFunction(fn2, bpfv) || !bpfv.size() || NULL == bpfv[0]) { logerror(" Unable to find function %s\n", fn2); return FAILED; } BPatch_function *call19_2_func = bpfv[0]; BPatch_funcCallExpr call19_2Expr(*call19_2_func, nullArgs); checkCost(call19_2Expr); int callbackFlag = 0; // Register a callback that will set the flag callbackFlag BPatchOneTimeCodeCallback oldCallback = BPatch::bpatch->registerOneTimeCodeCallback(test19_oneTimeCodeCallback); appProc->oneTimeCodeAsync(call19_2Expr, (void *)&callbackFlag); while (!appProc->isTerminated() && !appProc->isStopped() ) { BPatch::bpatch->waitForStatusChange(); } // Continue mutatee after one-time code runs appProc->continueExecution(); // Wait for the callback to be called while (!appProc->isTerminated() && !callbackFlag) { if( !BPatch::bpatch->waitForStatusChange() ) { logerror(" FAILED: could not wait for callback to be called\n"); return FAILED; } } if( !callbackFlag ) { logerror(" FAILED: process %d terminated while waiting for async oneTimeCode\n", appProc->getPid()); return FAILED; } // After the oneTimeCode is completed, there could be a crash due to bugs in // the RPC code, wait for termination while( !appProc->isTerminated() ) { if( !BPatch::bpatch->waitForStatusChange() ) { logerror(" FAILED: could not wait for process to terminate\n"); return FAILED; } } // Restore old callback (if there was one) BPatch::bpatch->registerOneTimeCodeCallback(oldCallback); return PASSED; } // test1_19_Mutator::executeTest()