1 // This program tests the basic features of the dyninst API.
2 // The mutatee that goes with this file is test1.mutatee.c
5 // All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
6 // XX is the test number
7 // YY is the instance withing the test
8 // func1_2 is the second function used in test case #1.
16 #ifdef i386_unknown_nt4_0
17 #define WIN32_LEAN_AND_MEAN
29 #include "BPatch_Vector.h"
30 #include "BPatch_thread.h"
31 #include "BPatch_snippet.h"
32 #include "test_util.h"
34 /* include spinlock function from RT lib as if in a header file */
35 /* note: testing assembly code this way is only really accurate on */
36 /* gnu-compiled systems */
38 #define EXPORT_SPINLOCKS_AS_HEADER 1
39 #if defined (os_solaris)
40 #include "dyninstAPI_RT/src/RTsolaris.c"
41 #elif defined (os_linux)
42 #include "dyninstAPI_RT/src/RTlinux.c"
43 #elif defined (os_windows)
44 #include "dyninstAPI_RT/src/RTwinnt.c"
45 #elif defined (os_irix)
47 #include "dyninstAPI_RT/src/RTirix.c"
48 #elif defined (os_osf)
49 #include "dyninstAPI_RT/src/RTosf.c"
50 #elif defined (os_aix)
51 #include "dyninstAPI_RT/src/RTaix.c"
54 int debugPrint = 0; // internal "mutator" tracing
55 int errorPrint = 1; // external "dyninst" tracing (via errorFunc)
57 bool forceRelocation = false; // force relocation of functions
59 int mutateeCplusplus = 0;
60 int mutateeFortran = 0;
63 bool runAllTests = true;
64 const unsigned int MAX_TEST = 4;
65 bool runTest[MAX_TEST+1];
66 bool passedTest[MAX_TEST+1];
70 static const char *mutateeNameRoot = "test12.mutatee";
71 static const char *libNameAroot = "libtestA";
72 static const char *libNameBroot = "libtestB";
73 char libNameA[64], libNameB[64];
75 // Globals for BPatch_thread and BPatch_image, just makes it easier
76 BPatch_thread *appThread;
77 BPatch_image *appImage;
80 // control debug printf statements
81 void dprintf(const char *fmt, ...) {
86 vfprintf(stderr, fmt, args);
95 //#if defined(os_solaris) && (os_solaris < 9)
102 usleep((ms % 1000) * 1000);
105 struct timespec ts,rem;
107 ts.tv_sec = (int) ms / 1000;
112 ts.tv_nsec = (ms % 1000) * 1000 * 1000;
113 //fprintf(stderr, "%s[%d]: sleep_ms (sec = %lu, nsec = %lu)\n",
114 // __FILE__, __LINE__, ts.tv_sec, ts.tv_nsec);
118 if (0 != nanosleep(&ts, &rem)) {
119 if (errno == EINTR) {
120 fprintf(stderr, "%s[%d]: sleep interrupted\n", __FILE__, __LINE__);
121 ts.tv_sec = rem.tv_sec;
122 ts.tv_nsec = rem.tv_nsec;
130 /**************************************************************************
132 **************************************************************************/
134 #define DYNINST_NO_ERROR -1
136 int expectError = DYNINST_NO_ERROR;
138 void errorFunc(BPatchErrorLevel level, int num, const char **params)
141 // conditional reporting of warnings and informational messages
143 if (level == BPatchInfo)
144 { if (errorPrint > 1) printf("%s\n", params[0]); }
146 printf("%s", params[0]);
150 // reporting of actual errors
152 const char *msg = bpatch->getEnglishErrorString(num);
153 bpatch->formatErrorString(line, sizeof(line), msg, params);
155 if (num != expectError) {
157 printf("Error #%d (level %d): %s\n", num, level, line);
159 // We consider some errors fatal.
167 BPatch_function *findFunction(const char *fname, int testno, const char *testname)
169 BPatch_Vector<BPatch_function *> bpfv;
170 if (NULL == appImage->findFunction(fname, bpfv) || (bpfv.size() != 1)) {
172 fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
173 fprintf(stderr, " Expected 1 functions matching %s, got %d\n",
180 void setVar(const char *vname, void *addr, int testno, const char *testname)
182 BPatch_variableExpr *v;
184 if (NULL == (v = appImage->findVariable(vname))) {
185 fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
186 fprintf(stderr, " cannot find variable %s\n", vname);
190 if (! v->writeValue(buf, sizeof(int),true)) {
191 fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
192 fprintf(stderr, " failed to write call site var to mutatee\n");
199 #define FAIL(x,y) fprintf(stdout, "**Failed test #%d (%s)\n", x,y);
200 #define PASS(x,y) fprintf(stdout, "Passed test #%d (%s)\n", x,y);
201 #define SKIP(x,y) fprintf(stdout, "Skipped test #%d (%s)\n", x,y);
202 /*******************************************************************************/
203 /*******************************************************************************/
204 /*******************************************************************************/
207 #define TESTNAME "dynamic call site callback"
208 static const char *expected_fnames[] = {"call1_1","call1_2","call1_3","call1_4"};
211 template class BPatch_Vector<void *>;
212 BPatch_Vector<void *> test1handles;
213 BPatch_Vector<BPatch_point *> dyncalls;
215 void dynSiteCB(BPatch_point *dyn_site, BPatch_function *called_function)
217 static int counter = 0;
218 static int counter2 = 0;
219 BPatch_point *pt = dyn_site;
220 BPatch_function *func = called_function;
223 void *callsite_addr = pt->getAddress();
225 func->getName(buf, 2048);
226 //fprintf(stderr, "%s[%d]: got func %s, expect func %s\n", __FILE__, __LINE__, buf,
227 // expected_fnames[counter]);
228 if (strcmp(expected_fnames[counter], buf)) {
229 FAIL(TESTNO, TESTNAME);
230 printf("\t%s[%d]: got func %s, expect func %s\n", __FILE__, __LINE__, buf,
231 expected_fnames[counter]);
232 appThread->stopExecution();
242 bool removal_error = false;
243 appThread->stopExecution();
244 // not passed yet, now remove dynamic call monitoring handles
245 assert (test1handles.size());
246 for (unsigned int i = 0; i < test1handles.size(); ++i) {
247 if (!dyncalls[i]->removeDynamicCallCallback(test1handles[i])) {
248 removal_error = true;
252 FAIL(TESTNO, TESTNAME);
255 PASS(TESTNO, TESTNAME);
265 BPatch_function *func1_1 = findFunction("call1_dispatch", TESTNO, TESTNAME);
266 BPatch_function *targetFunc = func1_1;
268 BPatch_Vector<BPatch_point *> *calls = targetFunc->findPoint(BPatch_subroutine);
270 FAIL(TESTNO, TESTNAME);
271 fprintf(stderr, " cannot find call points for func1_1\n");
275 for (unsigned int i = 0; i < calls->size(); ++i) {
276 BPatch_point *pt = (*calls)[i];
277 if (pt->isDynamic()){
279 handle = pt->registerDynamicCallCallback(dynSiteCB);
281 FAIL(TESTNO, TESTNAME);
282 fprintf(stderr, " registerDynamicCallCallback failed\n");
285 test1handles.push_back(handle);
286 dyncalls.push_back(pt);
290 if (dyncalls.size() != 3) {
291 FAIL(TESTNO, TESTNAME);
292 fprintf(stderr, " wrong number of dynamic points found (%d -- not 3)\n",
294 fprintf(stderr, " total number of calls found: %d\n", calls->size());
298 appThread->continueExecution();
300 while (!test1done) {};
302 return (test1err == 0);
308 #define TESTNAME "rtlib spinlocks"
311 #if !defined(os_windows)
313 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
314 extern void DYNINSTlock_spinlock(dyninst_spinlock *);
315 extern void DYNINSTunlock_spinlock(dyninst_spinlock *);
317 dyninst_spinlock mut;
318 int current_locks[THREADS];
319 pthread_t test2threads[THREADS];
320 pthread_mutex_t real_lock;
321 int test2counter = 0;
324 void register_my_lock(unsigned long id, int val)
328 for (i = 0; i < THREADS; ++i) {
329 if (pthread_equal(test2threads[i],(pthread_t)id)) {
331 current_locks[i] = val;
336 fprintf(stderr, "%s[%d]: FIXME\n", __FILE__, __LINE__);
341 for (i = 0; i < THREADS; ++i) {
342 if (0 != current_locks[i]) {
343 if (foundone) return 0; /*false*/
350 void *thread_main (void *arg)
352 DYNINSTlock_spinlock(&mut);
353 register_my_lock((unsigned long)pthread_self(),1);
354 pthread_mutex_lock(&real_lock);
355 /*printf("thread %lu got mutex %d\n", (unsigned long)pthread_self(), mut.lock); */
357 if (!is_only_one()) {
358 FAIL(TESTNO, TESTNAME);
361 pthread_mutex_unlock(&real_lock);
362 /*printf("thread %lu unlocking mutex\n", (unsigned long) pthread_self()); */
363 register_my_lock((unsigned long)pthread_self(),0);
365 DYNINSTunlock_spinlock(&mut);
369 void DYNINSTunlock_spinlock(dyninst_spinlock*s)
375 #define SLEEP_INTERVAL 100 /*ms*/
376 #define TIMEOUT 5000 /*ms*/
380 #if !defined (os_windows) && !defined(os_irix)
381 unsigned int timeout = 0; // in ms
385 /*pthread_mutex_attr_t mutattr; */
386 pthread_mutex_init(&real_lock, NULL);
388 pthread_attr_init(&attr);
389 pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED);
390 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
391 DYNINSTlock_spinlock(&mut);
393 for (i = 0; i < THREADS; ++i) {
394 current_locks[i] = 0;
396 err = pthread_create(&(test2threads[i]), &attr, thread_main, NULL);
399 fprintf(stderr, "Error creating thread %d: %s[%d]\n",
400 i, strerror(errno), errno);
402 fprintf(stderr, "Error creating thread %d: %s[%d]: max threads: %d\n",
403 i, strerror(errno), errno, PTHREAD_THREADS_MAX);
409 DYNINSTunlock_spinlock(&mut);
411 while((test2counter < THREADS) && !test2err && (timeout < TIMEOUT)) {
412 sleep_ms(SLEEP_INTERVAL/*ms*/);
413 timeout += SLEEP_INTERVAL;
416 if (timeout >= TIMEOUT) {
417 FAIL(TESTNO, TESTNAME);
418 fprintf(stderr, "%s[%d]: test timed out.\n",
425 for (i = 0; i < THREADS; ++i) {
426 pthread_kill(test2threads[i],9);
430 PASS(TESTNO, TESTNAME);
433 SKIP(TESTNO, TESTNAME);
434 fprintf(stderr, "%s[%d]: This test is not supported on this platform\n",
444 #define TESTNAME "thread create callback"
446 int test3_threadCreateCounter = 0;
447 void threadCreateCB(BPatch_thread *thr, int thread_id)
449 test3_threadCreateCounter++;
450 // fprintf(stderr, "%s[%d]: got a thread start event: %d\n", __FILE__, __LINE__,
451 // test3_threadCreateCounter);
456 unsigned int timeout = 0; // in ms
459 BPatchThreadEventCallback createcb = threadCreateCB;
460 if (!appThread->registerThreadEventCallback(BPatch_threadCreateEvent,
462 FAIL(TESTNO, TESTNAME);
463 fprintf(stderr, "%s[%d]: failed to register thread callback\n",
467 // unset mutateeIde to trigger thread (10) spawn.
469 setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
470 appThread->continueExecution();
472 // wait until we have received the desired number of events
473 // (or timeout happens)
475 while(test3_threadCreateCounter < 10 && (timeout < TIMEOUT)) {
476 sleep_ms(SLEEP_INTERVAL/*ms*/);
477 timeout += SLEEP_INTERVAL;
480 if (timeout >= TIMEOUT) {
481 FAIL(TESTNO, TESTNAME);
482 fprintf(stderr, "%s[%d]: test timed out.\n",
487 appThread->stopExecution();
489 if (!appThread->removeThreadEventCallback(BPatch_threadCreateEvent,
491 FAIL(TESTNO, TESTNAME);
492 fprintf(stderr, "%s[%d]: failed to remove thread callback\n",
497 PASS(TESTNO, TESTNAME);
506 #define TESTNAME "thread exit callback"
508 int test4_threadDestroyCounter = 0;
509 void threadDestroyCB(BPatch_thread *thr, int thread_id)
511 test4_threadDestroyCounter++;
512 // fprintf(stderr, "%s[%d]: got a thread destroy event: %d\n", __FILE__, __LINE__,
513 // test4_threadDestroyCounter);
518 unsigned int timeout = 0; // in ms
521 BPatchThreadEventCallback destroycb = threadDestroyCB;
522 if (!appThread->registerThreadEventCallback(BPatch_threadDestroyEvent,
524 FAIL(TESTNO, TESTNAME);
525 fprintf(stderr, "%s[%d]: failed to register thread callback\n",
530 // unset mutateeIdle to trigger thread (10) spawn.
533 setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
534 appThread->continueExecution();
536 // wait until we have received the desired number of events
537 // (or timeout happens)
538 while(test4_threadDestroyCounter < 10 && (timeout < TIMEOUT)) {
539 sleep_ms(SLEEP_INTERVAL/*ms*/);
540 timeout += SLEEP_INTERVAL;
543 if (timeout >= TIMEOUT) {
544 FAIL(TESTNO, TESTNAME);
545 fprintf(stderr, "%s[%d]: test timed out.\n",
550 appThread->stopExecution();
552 if (!appThread->removeThreadEventCallback(BPatch_threadDestroyEvent,
554 FAIL(TESTNO, TESTNAME);
555 fprintf(stderr, "%s[%d]: failed to remove thread callback\n",
561 PASS(TESTNO, TESTNAME);
571 #define TESTNAME "thread start callback"
582 #define TESTNAME "thread stop callback"
590 /*******************************************************************************/
591 /*******************************************************************************/
592 /*******************************************************************************/
594 int mutatorMAIN(char *pathname, bool useAttach)
598 // Create an instance of the BPatch library
601 // Force functions to be relocated
602 if (forceRelocation) {
603 bpatch->setForcedRelocation_NP(true);
606 // Register a callback function that prints any error messages
607 bpatch->registerErrorCallback(errorFunc);
610 printf("Starting \"%s\"\n", pathname);
612 const char *child_argv[MAX_TEST+5];
615 child_argv[n++] = pathname;
616 if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
619 child_argv[n++] = const_cast<char*>("-runall"); // signifies all tests
621 child_argv[n++] = const_cast<char*>("-run");
622 for (unsigned int j=1; j <= MAX_TEST; j++) {
625 sprintf(str, "%d", j);
626 child_argv[n++] = strdup(str);
631 child_argv[n] = NULL;
634 int pid = startNewProcessForAttach(pathname, child_argv);
636 printf("*ERROR*: unable to start tests due to error creating mutatee process\n");
639 dprintf("New mutatee process pid %d started; attaching...\n", pid);
641 P_sleep(1); // let the mutatee catch its breath for a moment
642 appThread = bpatch->attachProcess(pathname, pid);
644 appThread = bpatch->createProcess(pathname, child_argv,NULL);
647 if (appThread == NULL) {
648 fprintf(stderr, "Unable to run test program.\n");
652 // Read the program's image and get an associated image object
653 appImage = appThread->getImage();
655 // Signal the child that we've attached
657 signalAttached(appThread, appImage);
660 // determine whether mutatee is C or C++
661 BPatch_variableExpr *isCxx = appImage->findVariable("mutateeCplusplus");
663 fprintf(stderr, " Unable to locate variable \"mutateeCplusplus\""
664 " -- assuming 0!\n");
666 isCxx->readValue(&mutateeCplusplus);
667 dprintf("Mutatee is %s.\n", mutateeCplusplus ? "C++" : "C");
672 if (runTest[1]) passedTest[1] = mutatorTest1();
673 if (runTest[2]) passedTest[2] = mutatorTest2();
674 if (runTest[3]) passedTest[3] = mutatorTest3();
675 if (runTest[4]) passedTest[4] = mutatorTest4();
676 //if (runTest[5]) passedTest[5] = mutatorTest5();
677 //if (runTest[6]) passedTest[6] = mutatorTest6();
679 if (appThread && !appThread->isTerminated())
680 appThread->terminateExecution();
684 int failed_tests = 0;
685 for (unsigned int i = 1; i < (MAX_TEST+1); ++i) {
686 if ((runTest[i]) && (!passedTest[i])) {
691 printf("**Failed %d test%s\n", failed_tests,
692 failed_tests == 1 ? "." : "s.");
693 for (unsigned int i = 1; i < (MAX_TEST + 1); ++i) {
694 printf("%s ", passedTest[i] ? "P" : "F");
700 printf("All tests passed.\n");
702 printf("All requested tests passed.\n");
708 main(unsigned int argc, char *argv[])
710 char mutateeName[128];
714 bool useAttach = false;
716 strcpy(mutateeName,mutateeNameRoot);
717 strcpy(libNameA,libNameAroot);
718 strcpy(libNameB,libNameBroot);
721 if (!getenv("DYNINSTAPI_RT_LIB")) {
722 fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
723 #if defined(i386_unknown_nt4_0)
724 " using standard search strategy for libdyninstAPI_RT.dll\n");
726 " set it to the full pathname of libdyninstAPI_RT\n");
730 strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
733 // by default run all tests
734 for (i=1; i <= MAX_TEST; i++) {
736 passedTest[i] = false;
739 for (i=1; i < argc; i++) {
740 if (strncmp(argv[i], "-v+", 3) == 0) errorPrint++;
741 if (strncmp(argv[i], "-v++", 4) == 0) errorPrint++;
742 if (strncmp(argv[i], "-verbose", 2) == 0) {
744 } else if (!strcmp(argv[i], "-V")) {
745 fprintf (stdout, "%s\n", V_libdyninstAPI);
747 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
749 } else if (!strcmp(argv[i], "-attach")) {
751 } else if (!strcmp(argv[i], "-skip")) {
754 for (j=i+1; j < argc; j++) {
756 if ((testId = atoi(argv[j]))) {
757 if ((testId > 0) && (testId <= MAX_TEST)) {
758 runTest[testId] = false;
760 printf("invalid test %d requested\n", testId);
769 } else if (!strcmp(argv[i], "-run")) {
772 for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
773 for (j=i+1; j < argc; j++) {
775 if ((testId = atoi(argv[j]))) {
776 if ((testId > 0) && (testId <= MAX_TEST)) {
777 runTest[testId] = true;
779 printf("invalid test %d requested\n", testId);
788 } else if (!strcmp(argv[i], "-mutatee")) {
791 strcat(mutateeName,argv[i]);
793 strcpy(mutateeName,argv[i]);
794 #if defined(i386_unknown_nt4_0) || defined(i386_unknown_linux2_0) || defined(sparc_sun_solaris2_4)
795 } else if (!strcmp(argv[i], "-relocate")) {
796 forceRelocation = true;
798 #if defined(mips_sgi_irix6_4)
799 } else if (!strcmp(argv[i], "-n32")) {
803 fprintf(stderr, "Usage: test12 "
804 "[-V] [-verbose] [-attach] "
805 #if defined(mips_sgi_irix6_4)
808 #if defined(sparc_sun_solaris2_4) || defined(i386_unknown_linux2_0) || defined(rs6000_ibm_aix4_1)
811 "[-mutatee <test12.mutatee>] "
812 "[-run <test#> <test#> ...] "
813 "[-skip <test#> <test#> ...]\n");
814 fprintf(stderr, "%d subtests\n", MAX_TEST);
819 // detect IBM xlC compiler and set flag
820 if (strstr(mutateeName, "xlc") || strstr(mutateeName, "xlC"))
824 printf("Running Tests: ");
825 for (unsigned int j=1; j <= MAX_TEST; j++) {
826 if (runTest[j]) printf("%d ", j);
831 // patch up the default compiler in mutatee name (if necessary)
832 if (!strstr(mutateeName, "_"))
833 #if defined(i386_unknown_nt4_0)
834 strcat(mutateeName,"_VC");
836 strcat(mutateeName,"_gcc");
838 if (N32ABI || strstr(mutateeName,"_n32")) {
839 // patch up file names based on alternate ABI (as necessary)
840 if (!strstr(mutateeName, "_n32")) strcat(mutateeName,"_n32");
841 strcat(libNameA,"_n32");
842 strcat(libNameB,"_n32");
845 // patch up the platform-specific filename extensions
846 #if defined(i386_unknown_nt4_0)
847 if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
848 strcat(libNameA,".dll");
849 strcat(libNameB,".dll");
851 strcat(libNameA,".so");
852 strcat(libNameB,".so");
855 int retval = mutatorMAIN(mutateeName, useAttach);