small fixes for my last commit (async events)
[dyninst.git] / dyninstAPI / tests / src / test12.C
1 //  This program tests the basic features of the dyninst API.
2 //      The mutatee that goes with this file is test1.mutatee.c
3 //
4 //  Naming conventions:
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.
9 //
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <assert.h>
15 #include <stdarg.h>
16 #ifdef i386_unknown_nt4_0
17 #define WIN32_LEAN_AND_MEAN
18 #include <windows.h>
19 #include <winsock2.h>
20 #include <winbase.h>
21 #else
22 #include <unistd.h>
23 #endif
24
25 #include <iostream>
26 using namespace std;
27
28 #include "BPatch.h"
29 #include "BPatch_Vector.h"
30 #include "BPatch_thread.h"
31 #include "BPatch_snippet.h"
32 #include "test_util.h"
33
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 */
37
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)
46 #define GNU_TO_ASS 1
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"
52 #endif
53
54 int debugPrint = 0; // internal "mutator" tracing
55 int errorPrint = 1; // external "dyninst" tracing (via errorFunc)
56
57 bool forceRelocation = false; // force relocation of functions
58
59 int mutateeCplusplus = 0;
60 int mutateeFortran = 0;
61 int mutateeXLC = 0;
62 int mutateeF77 = 0;
63 bool runAllTests = true;
64 const unsigned int MAX_TEST = 4;
65 bool runTest[MAX_TEST+1];
66 bool passedTest[MAX_TEST+1];
67
68 BPatch *bpatch;
69
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];
74
75 //  Globals for BPatch_thread and BPatch_image, just makes it easier
76 BPatch_thread *appThread;
77 BPatch_image *appImage;
78 char err_str[1024];
79
80 // control debug printf statements
81 void dprintf(const char *fmt, ...) {
82    va_list args;
83    va_start(args, fmt);
84
85    if(debugPrint)
86       vfprintf(stderr, fmt, args);
87
88    va_end(args);
89
90    fflush(stderr);
91 }
92
93 void sleep_ms(int ms) 
94 {
95 //#if defined(os_solaris) && (os_solaris < 9)
96 #ifdef NOTDEF
97   if (ms < 1000) {
98     usleep(ms * 1000);
99   }
100   else {
101     sleep(ms / 1000);
102     usleep((ms % 1000) * 1000);
103   }
104 #else
105   struct timespec ts,rem;
106   if (ms >= 1000) {
107     ts.tv_sec = (int) ms / 1000;
108   }
109   else
110     ts.tv_sec = 0;
111
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);
115
116   sleep:
117
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;
123       goto sleep;
124     }
125     assert(0);
126   }
127 #endif
128 }
129
130 /**************************************************************************
131  * Error callback
132  **************************************************************************/
133
134 #define DYNINST_NO_ERROR -1
135
136 int expectError = DYNINST_NO_ERROR;
137
138 void errorFunc(BPatchErrorLevel level, int num, const char **params)
139 {
140     if (num == 0) {
141         // conditional reporting of warnings and informational messages
142         if (errorPrint) {
143             if (level == BPatchInfo)
144               { if (errorPrint > 1) printf("%s\n", params[0]); }
145             else {
146                 printf("%s", params[0]);
147             }
148         }
149     } else {
150         // reporting of actual errors
151         char line[256];
152         const char *msg = bpatch->getEnglishErrorString(num);
153         bpatch->formatErrorString(line, sizeof(line), msg, params);
154
155         if (num != expectError) {
156           if(num != 112)
157             printf("Error #%d (level %d): %s\n", num, level, line);
158
159             // We consider some errors fatal.
160             if (num == 101) {
161                exit(-1);
162             }
163         }
164     }
165 }
166
167 BPatch_function *findFunction(const char *fname, int testno, const char *testname)
168 {
169   BPatch_Vector<BPatch_function *> bpfv;
170   if (NULL == appImage->findFunction(fname, bpfv) || (bpfv.size() != 1)) {
171
172       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
173       fprintf(stderr, "  Expected 1 functions matching %s, got %d\n",
174               fname, bpfv.size());
175          exit(1);
176   }
177   return bpfv[0];
178 }
179
180 void setVar(const char *vname, void *addr, int testno, const char *testname)
181 {
182    BPatch_variableExpr *v;
183    void *buf = addr;
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);
187          exit(1);
188    }
189
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");
193       exit(1);
194    }
195 }
196
197
198
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 /*******************************************************************************/
205
206 #define TESTNO 1
207 #define TESTNAME "dynamic call site callback"
208 static const char *expected_fnames[] = {"call1_1","call1_2","call1_3","call1_4"};
209 int test1done = 0;
210 int test1err = 0;
211 template class BPatch_Vector<void *>;
212 BPatch_Vector<void *> test1handles;
213 BPatch_Vector<BPatch_point *> dyncalls;
214
215 void dynSiteCB(BPatch_point *dyn_site, BPatch_function *called_function)
216 {
217   static int counter = 0;
218   static int counter2 = 0;
219   BPatch_point *pt = dyn_site;
220   BPatch_function *func = called_function;
221   assert(pt);
222   assert(func);
223   void *callsite_addr = pt->getAddress();
224   char buf[2048];
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();      
233     test1done = 1;
234   }
235   counter++;
236   if (counter > 3) {
237     counter = 0;
238     counter2++;
239   }
240
241   if (counter2 >= 2) {
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;
249       }
250     }
251     if (removal_error) {
252       FAIL(TESTNO, TESTNAME);
253       test1err = 1;
254     }else {
255       PASS(TESTNO, TESTNAME);
256     }
257     test1done = 1;
258   }
259 }
260
261
262 bool mutatorTest1()
263 {
264
265   BPatch_function *func1_1 = findFunction("call1_dispatch", TESTNO, TESTNAME);
266   BPatch_function *targetFunc = func1_1;
267
268   BPatch_Vector<BPatch_point *> *calls = targetFunc->findPoint(BPatch_subroutine);
269   if (!calls) {
270      FAIL(TESTNO, TESTNAME);
271      fprintf(stderr, "  cannot find call points for func1_1\n");
272      exit(1);
273   }
274
275   for (unsigned int i = 0; i < calls->size(); ++i) {
276     BPatch_point *pt = (*calls)[i];
277     if (pt->isDynamic()){
278       void *handle = NULL;
279       handle = pt->registerDynamicCallCallback(dynSiteCB);
280       if (!handle) {
281         FAIL(TESTNO, TESTNAME);
282         fprintf(stderr, "  registerDynamicCallCallback failed\n");
283         exit(1);
284       } 
285       test1handles.push_back(handle);
286       dyncalls.push_back(pt);
287     }
288   }
289
290   if (dyncalls.size() != 3) {
291      FAIL(TESTNO, TESTNAME);
292      fprintf(stderr, "  wrong number of dynamic points found (%d -- not 3)\n",
293              dyncalls.size());
294      fprintf(stderr, "  total number of calls found: %d\n", calls->size());
295         exit(1);
296   }
297
298   appThread->continueExecution();
299
300   while (!test1done) {};
301
302   return (test1err == 0);
303 }
304
305 #undef  TESTNO
306 #define TESTNO 2
307 #undef  TESTNAME
308 #define TESTNAME "rtlib spinlocks"
309 #define THREADS 20
310
311 #if !defined(os_windows) 
312 #include <pthread.h>
313 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
314 extern void DYNINSTlock_spinlock(dyninst_spinlock *);
315 extern void DYNINSTunlock_spinlock(dyninst_spinlock *);
316
317 dyninst_spinlock mut;
318 int current_locks[THREADS];
319 pthread_t test2threads[THREADS];
320 pthread_mutex_t real_lock;
321 int test2counter = 0;
322 int test2err = 0;
323
324 void register_my_lock(unsigned long id, int val) 
325 {
326   unsigned int i;
327   int found = 0;
328   for (i = 0; i < THREADS; ++i) {
329     if (pthread_equal(test2threads[i],(pthread_t)id)) {
330       found = 1;
331       current_locks[i] = val;
332       break;
333     }
334   }
335   if (!found)
336     fprintf(stderr, "%s[%d]: FIXME\n", __FILE__, __LINE__);
337 }
338 int is_only_one() {
339   unsigned int i;
340   int foundone = 0;
341   for (i = 0; i < THREADS; ++i) {
342     if (0 != current_locks[i]) {
343       if (foundone) return 0; /*false*/
344       foundone++;
345     } 
346   }
347   return 1; /*true */
348 }
349
350 void *thread_main (void *arg)
351 {
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); */
356    sleep_ms (1);
357    if (!is_only_one()) {
358      FAIL(TESTNO, TESTNAME);
359      test2err = 1;
360    }
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);
364    test2counter++;
365    DYNINSTunlock_spinlock(&mut);
366    return NULL;
367 }
368
369 void DYNINSTunlock_spinlock(dyninst_spinlock*s)
370 {
371   s->lock = 0;
372 }
373
374 #endif
375 #define SLEEP_INTERVAL 100 /*ms*/
376 #define TIMEOUT 5000 /*ms*/
377 bool mutatorTest2()
378 {
379
380 #if !defined (os_windows) && !defined(os_irix)
381   unsigned int timeout = 0; // in ms
382   pthread_attr_t attr;
383   unsigned int i;
384   mut.lock = 0;
385   /*pthread_mutex_attr_t mutattr; */
386   pthread_mutex_init(&real_lock, NULL);
387
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);
392
393   for (i = 0; i < THREADS; ++i) {
394     current_locks[i] = 0;
395     int err;
396     err = pthread_create(&(test2threads[i]), &attr, thread_main, NULL);
397     if (err) {
398 #if defined (os_osf)
399       fprintf(stderr, "Error creating thread %d: %s[%d]\n",
400               i, strerror(errno), errno);
401 #else
402       fprintf(stderr, "Error creating thread %d: %s[%d]: max threads: %d\n",
403               i, strerror(errno), errno, PTHREAD_THREADS_MAX);
404 #endif
405     }
406   }
407
408   sleep_ms(1);
409   DYNINSTunlock_spinlock(&mut);
410
411   while((test2counter < THREADS) && !test2err && (timeout < TIMEOUT)) {
412     sleep_ms(SLEEP_INTERVAL/*ms*/);
413     timeout += SLEEP_INTERVAL;
414   }
415
416   if (timeout >= TIMEOUT) {
417     FAIL(TESTNO, TESTNAME);
418     fprintf(stderr, "%s[%d]:  test timed out.\n",
419            __FILE__, __LINE__);
420     test2err = 1;
421   }
422
423
424   if (test2err) {
425     for (i = 0; i < THREADS; ++i) {
426      pthread_kill(test2threads[i],9);
427     }
428   }
429   else {
430     PASS(TESTNO, TESTNAME);
431   }
432 #else
433     SKIP(TESTNO, TESTNAME);
434     fprintf(stderr, "%s[%d]:  This test is not supported on this platform\n",
435                     __FILE__, __LINE__);
436 #endif
437   return true;
438 }
439
440
441 #undef  TESTNO
442 #define TESTNO 3
443 #undef  TESTNAME
444 #define TESTNAME "thread create callback"
445
446 int test3_threadCreateCounter = 0;
447 void threadCreateCB(BPatch_thread *thr, int thread_id)
448 {
449   test3_threadCreateCounter++;
450 //  fprintf(stderr, "%s[%d]:  got a thread start event: %d\n", __FILE__, __LINE__,
451 //          test3_threadCreateCounter);
452 }
453
454 bool mutatorTest3()
455 {
456   unsigned int timeout = 0; // in ms
457   int err = 0;
458
459   BPatchThreadEventCallback createcb = threadCreateCB;
460   if (!appThread->registerThreadEventCallback(BPatch_threadCreateEvent,
461                                               createcb)) {
462     FAIL(TESTNO, TESTNAME);
463     fprintf(stderr, "%s[%d]:  failed to register thread callback\n",
464            __FILE__, __LINE__);
465     return false;
466   }
467   //  unset mutateeIde to trigger thread (10) spawn.
468   int zero = 0;
469   setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
470   appThread->continueExecution();
471
472   //  wait until we have received the desired number of events
473   //  (or timeout happens)
474
475   while(test3_threadCreateCounter < 10 && (timeout < TIMEOUT)) {
476     sleep_ms(SLEEP_INTERVAL/*ms*/);
477     timeout += SLEEP_INTERVAL;
478   }
479
480   if (timeout >= TIMEOUT) {
481     FAIL(TESTNO, TESTNAME);
482     fprintf(stderr, "%s[%d]:  test timed out.\n",
483            __FILE__, __LINE__);
484     err = 1;
485   }
486
487   appThread->stopExecution();
488
489   if (!appThread->removeThreadEventCallback(BPatch_threadCreateEvent,
490                                             createcb)) {
491     FAIL(TESTNO, TESTNAME);
492     fprintf(stderr, "%s[%d]:  failed to remove thread callback\n",
493            __FILE__, __LINE__);
494     return false;
495   }
496   if (!err)  {
497     PASS(TESTNO, TESTNAME);
498     return true;
499   }
500   return false;
501 }
502
503 #undef  TESTNO
504 #define TESTNO 4 
505 #undef  TESTNAME
506 #define TESTNAME "thread exit callback"
507
508 int test4_threadDestroyCounter = 0;
509 void threadDestroyCB(BPatch_thread *thr, int thread_id)
510 {
511   test4_threadDestroyCounter++;
512  // fprintf(stderr, "%s[%d]:  got a thread destroy event: %d\n", __FILE__, __LINE__,
513   //        test4_threadDestroyCounter);
514 }
515
516 bool mutatorTest4()
517 {
518   unsigned int timeout = 0; // in ms
519   int err = 0;
520
521   BPatchThreadEventCallback destroycb = threadDestroyCB;
522   if (!appThread->registerThreadEventCallback(BPatch_threadDestroyEvent,
523                                               destroycb)) {
524     FAIL(TESTNO, TESTNAME);
525     fprintf(stderr, "%s[%d]:  failed to register thread callback\n",
526            __FILE__, __LINE__);
527     return false;
528   }
529
530   //  unset mutateeIdle to trigger thread (10) spawn.
531
532   int zero = 0;
533   setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
534   appThread->continueExecution();
535
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; 
541   }
542
543   if (timeout >= TIMEOUT) {
544     FAIL(TESTNO, TESTNAME);
545     fprintf(stderr, "%s[%d]:  test timed out.\n",
546            __FILE__, __LINE__);
547     err = 1;
548   }
549
550   appThread->stopExecution();
551
552   if (!appThread->removeThreadEventCallback(BPatch_threadDestroyEvent,
553                                             destroycb)) {
554     FAIL(TESTNO, TESTNAME);
555     fprintf(stderr, "%s[%d]:  failed to remove thread callback\n",
556            __FILE__, __LINE__);
557     return false;
558   }
559
560   if (!err) {
561     PASS(TESTNO, TESTNAME);
562     return true;
563   }
564   return false;
565 }
566
567
568 #undef  TESTNO
569 #define TESTNO 5 
570 #undef  TESTNAME
571 #define TESTNAME "thread start callback"
572
573 bool mutatorTest5()
574 {
575
576   return true;
577 }
578
579 #undef  TESTNO
580 #define TESTNO 6 
581 #undef  TESTNAME
582 #define TESTNAME "thread stop callback"
583
584 bool mutatorTest6()
585 {
586
587   return true;
588 }
589
590 /*******************************************************************************/
591 /*******************************************************************************/
592 /*******************************************************************************/
593
594 int mutatorMAIN(char *pathname, bool useAttach)
595 {
596         char *dirName;
597
598    // Create an instance of the BPatch library
599     bpatch = new BPatch;
600
601     // Force functions to be relocated
602     if (forceRelocation) {
603       bpatch->setForcedRelocation_NP(true);
604     }
605
606     // Register a callback function that prints any error messages
607     bpatch->registerErrorCallback(errorFunc);
608
609     // Start the mutatee
610     printf("Starting \"%s\"\n", pathname);
611
612     const char *child_argv[MAX_TEST+5];
613
614     int n = 0;
615     child_argv[n++] = pathname;
616     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
617
618     if (runAllTests) {
619         child_argv[n++] = const_cast<char*>("-runall"); // signifies all tests
620     } else {
621         child_argv[n++] = const_cast<char*>("-run");
622         for (unsigned int j=1; j <= MAX_TEST; j++) {
623             if (runTest[j]) {
624                 char str[5];
625                 sprintf(str, "%d", j);
626                 child_argv[n++] = strdup(str);
627             }
628         }
629     }
630
631     child_argv[n] = NULL;
632
633     if (useAttach) {
634         int pid = startNewProcessForAttach(pathname, child_argv);
635         if (pid < 0) {
636             printf("*ERROR*: unable to start tests due to error creating mutatee process\n");
637             exit(-1);
638         } else {
639             dprintf("New mutatee process pid %d started; attaching...\n", pid);
640         }
641         P_sleep(1); // let the mutatee catch its breath for a moment
642         appThread = bpatch->attachProcess(pathname, pid);
643     } else {
644         appThread = bpatch->createProcess(pathname, child_argv,NULL);
645     }
646
647     if (appThread == NULL) {
648         fprintf(stderr, "Unable to run test program.\n");
649         exit(1);
650     }
651
652     // Read the program's image and get an associated image object
653     appImage = appThread->getImage();
654
655     // Signal the child that we've attached
656     if (useAttach) {
657         signalAttached(appThread, appImage);
658     }
659
660     // determine whether mutatee is C or C++
661     BPatch_variableExpr *isCxx = appImage->findVariable("mutateeCplusplus");
662     if (isCxx == NULL) {
663         fprintf(stderr, "  Unable to locate variable \"mutateeCplusplus\""
664                  " -- assuming 0!\n");
665     } else {
666         isCxx->readValue(&mutateeCplusplus);
667         dprintf("Mutatee is %s.\n", mutateeCplusplus ? "C++" : "C");
668     }
669
670     printf("\n");
671
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();
678
679     if (appThread && !appThread->isTerminated())
680       appThread->terminateExecution();
681
682     printf("\n");
683
684     int failed_tests  = 0;
685     for (unsigned int i = 1; i < (MAX_TEST+1); ++i) {
686       if ((runTest[i]) && (!passedTest[i])) {
687          failed_tests++;
688       }
689     }
690     if (failed_tests) {
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");
695       }
696       printf("\n");
697     }
698     else {
699       if (runAllTests)
700         printf("All tests passed.\n");
701       else
702         printf("All requested tests passed.\n");
703     }
704     return 0;
705 }
706
707 int
708 main(unsigned int argc, char *argv[])
709 {
710     char mutateeName[128];
711     char libRTname[256];
712
713     bool N32ABI = false;
714     bool useAttach = false;
715
716     strcpy(mutateeName,mutateeNameRoot);
717     strcpy(libNameA,libNameAroot);
718     strcpy(libNameB,libNameBroot);
719     libRTname[0]='\0';
720
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");
725 #else
726                  "    set it to the full pathname of libdyninstAPI_RT\n");
727          exit(-1);
728 #endif
729     } else
730          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
731
732     unsigned int i;
733     // by default run all tests
734     for (i=1; i <= MAX_TEST; i++) {
735         runTest[i] = true;
736         passedTest[i] = false;
737     }
738
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) {
743             debugPrint = 1;
744         } else if (!strcmp(argv[i], "-V")) {
745             fprintf (stdout, "%s\n", V_libdyninstAPI);
746             if (libRTname[0])
747                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
748             fflush(stdout);
749         } else if (!strcmp(argv[i], "-attach")) {
750             useAttach = true;
751         } else if (!strcmp(argv[i], "-skip")) {
752             unsigned int j;
753             runAllTests = false;
754             for (j=i+1; j < argc; j++) {
755                 unsigned int testId;
756                 if ((testId = atoi(argv[j]))) {
757                     if ((testId > 0) && (testId <= MAX_TEST)) {
758                         runTest[testId] = false;
759                     } else {
760                         printf("invalid test %d requested\n", testId);
761                         exit(-1);
762                     }
763                 } else {
764                     // end of test list
765                     break;
766                 }
767             }
768             i=j-1;
769         } else if (!strcmp(argv[i], "-run")) {
770             unsigned int j;
771             runAllTests = false;
772             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
773             for (j=i+1; j < argc; j++) {
774                 unsigned int testId;
775                 if ((testId = atoi(argv[j]))) {
776                     if ((testId > 0) && (testId <= MAX_TEST)) {
777                         runTest[testId] = true;
778                     } else {
779                         printf("invalid test %d requested\n", testId);
780                         exit(-1);
781                     }
782                 } else {
783                     // end of test list
784                     break;
785                 }
786             }
787             i=j-1;
788         } else if (!strcmp(argv[i], "-mutatee")) {
789             i++;
790             if (*argv[i]=='_')
791                 strcat(mutateeName,argv[i]);
792             else
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;
797 #endif
798 #if defined(mips_sgi_irix6_4)
799         } else if (!strcmp(argv[i], "-n32")) {
800             N32ABI = true;
801 #endif
802         } else {
803             fprintf(stderr, "Usage: test12 "
804                     "[-V] [-verbose] [-attach] "
805 #if defined(mips_sgi_irix6_4)
806                     "[-n32] "
807 #endif
808 #if defined(sparc_sun_solaris2_4) || defined(i386_unknown_linux2_0) || defined(rs6000_ibm_aix4_1)
809                     "[-saveworld] "
810 #endif
811                     "[-mutatee <test12.mutatee>] "
812                     "[-run <test#> <test#> ...] "
813                     "[-skip <test#> <test#> ...]\n");
814             fprintf(stderr, "%d subtests\n", MAX_TEST);
815             exit(-1);
816         }
817     }
818
819     //  detect IBM xlC compiler and set flag
820     if (strstr(mutateeName, "xlc") || strstr(mutateeName, "xlC"))
821       mutateeXLC = true;
822
823     if (!runAllTests) {
824         printf("Running Tests: ");
825         for (unsigned int j=1; j <= MAX_TEST; j++) {
826             if (runTest[j]) printf("%d ", j);
827         }
828         printf("\n");
829     }
830
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");
835 #else
836         strcat(mutateeName,"_gcc");
837 #endif
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");
843     }
844
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");
850 #else
851     strcat(libNameA,".so");
852     strcat(libNameB,".so");
853 #endif
854
855     int retval = mutatorMAIN(mutateeName, useAttach);
856
857     return retval;
858 }
859