BPatch functions that block are now locked (on a finer grain than the rest of the...
[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 #define SLEEP_INTERVAL 100 /*ms*/
203 #define TIMEOUT 7000 /*ms*/
204
205 /*******************************************************************************/
206 /*******************************************************************************/
207 /*******************************************************************************/
208
209 #define TESTNO 1
210 #define TESTNAME "dynamic call site callback"
211 static const char *expected_fnames[] = {"call1_1","call1_2","call1_3","call1_4"};
212 int test1done = 0;
213 int test1err = 0;
214 template class BPatch_Vector<void *>;
215 BPatch_Vector<void *> test1handles;
216 BPatch_Vector<BPatch_point *> dyncalls;
217
218 void dynSiteCB(BPatch_point *dyn_site, BPatch_function *called_function)
219 {
220   //fprintf(stderr, "%s[%d]:  dynSiteCB: pt = %p. func = %p.\n",
221   //                 __FILE__, __LINE__, dyn_site, called_function);
222   static int counter = 0;
223   static int counter2 = 0;
224   BPatch_point *pt = dyn_site;
225   BPatch_function *func = called_function;
226   assert(pt);
227   assert(func);
228   void *callsite_addr = pt->getAddress();
229   char buf[2048];
230   func->getName(buf, 2048);
231   //fprintf(stderr, "%s[%d]:  got func %s, expect func %s\n", __FILE__, __LINE__, buf,
232   //        expected_fnames[counter]);
233   if (strcmp(expected_fnames[counter], buf)) {
234     FAIL(TESTNO, TESTNAME);
235     printf("\t%s[%d]:  got func %s, expect func %s\n", __FILE__, __LINE__, buf,
236           expected_fnames[counter]);
237     appThread->stopExecution();      
238     test1done = 1;
239   }
240   counter++;
241   if (counter > 3) {
242     counter = 0;
243     counter2++;
244   }
245
246   if (counter2 >= 2) {
247     bool removal_error = false;
248     appThread->stopExecution();      
249     //  not passed yet, now remove dynamic call monitoring handles
250     assert (test1handles.size());
251     for (unsigned int i = 0; i < test1handles.size(); ++i) {
252       if (!dyncalls[i]->removeDynamicCallCallback(test1handles[i])) {
253         removal_error = true;
254       }
255     }
256     if (removal_error) {
257       FAIL(TESTNO, TESTNAME);
258       test1err = 1;
259     }else {
260       PASS(TESTNO, TESTNAME);
261     }
262     test1done = 1;
263   }
264 }
265
266
267 bool mutatorTest1()
268 {
269   int timeout = 0;
270
271   if (mutateeXLC) {
272      appThread->continueExecution();
273      SKIP(TESTNO, TESTNAME);
274      fprintf(stderr, "\txlc optimizes out dynamic call sites for this test\n");
275      sleep_ms(100);
276      return true;
277   }
278
279   BPatch_function *func1_1 = findFunction("call1_dispatch", TESTNO, TESTNAME);
280   BPatch_function *targetFunc = func1_1;
281
282   BPatch_Vector<BPatch_point *> *calls = targetFunc->findPoint(BPatch_subroutine);
283   if (!calls) {
284      FAIL(TESTNO, TESTNAME);
285      fprintf(stderr, "  cannot find call points for func1_1\n");
286      exit(1);
287   }
288
289   for (unsigned int i = 0; i < calls->size(); ++i) {
290     BPatch_point *pt = (*calls)[i];
291     if (pt->isDynamic()){
292       void *handle = NULL;
293       handle = pt->registerDynamicCallCallback(dynSiteCB);
294       if (!handle) {
295         FAIL(TESTNO, TESTNAME);
296         fprintf(stderr, "  registerDynamicCallCallback failed\n");
297         exit(1);
298       } 
299       test1handles.push_back(handle);
300       dyncalls.push_back(pt);
301     }
302   }
303
304   if (dyncalls.size() != 3) {
305      FAIL(TESTNO, TESTNAME);
306      fprintf(stderr, "  wrong number of dynamic points found (%d -- not 3)\n",
307              dyncalls.size());
308      fprintf(stderr, "  total number of calls found: %d\n", calls->size());
309         exit(1);
310   }
311
312   appThread->continueExecution();
313
314   //  wait until we have received the desired number of events
315   //  (or timeout happens)
316
317   while(!test1done && (timeout < TIMEOUT)) {
318     bpatch->pollForStatusChange();
319     sleep_ms(SLEEP_INTERVAL/*ms*/);
320     timeout += SLEEP_INTERVAL;
321   }
322
323   if (timeout >= TIMEOUT) {
324     FAIL(TESTNO, TESTNAME);
325     fprintf(stderr, "%s[%d]:  test timed out.\n",
326            __FILE__, __LINE__);
327     test1err = 1;
328   }
329
330   return (test1err == 0);
331 }
332
333 #undef  TESTNO
334 #define TESTNO 2
335 #undef  TESTNAME
336 #define TESTNAME "rtlib spinlocks"
337 #define THREADS 20
338
339 #if !defined(os_windows) 
340 #include <pthread.h>
341 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
342 extern void DYNINSTlock_spinlock(dyninst_spinlock *);
343 extern void DYNINSTunlock_spinlock(dyninst_spinlock *);
344
345 dyninst_spinlock mut;
346 int current_locks[THREADS];
347 pthread_t test2threads[THREADS];
348 pthread_mutex_t real_lock;
349 int test2counter = 0;
350 int test2err = 0;
351
352 void register_my_lock(unsigned long id, int val) 
353 {
354   unsigned int i;
355   int found = 0;
356   for (i = 0; i < THREADS; ++i) {
357     if (pthread_equal(test2threads[i],(pthread_t)id)) {
358       found = 1;
359       current_locks[i] = val;
360       break;
361     }
362   }
363   if (!found)
364     fprintf(stderr, "%s[%d]: FIXME\n", __FILE__, __LINE__);
365 }
366 int is_only_one() {
367   unsigned int i;
368   int foundone = 0;
369   for (i = 0; i < THREADS; ++i) {
370     if (0 != current_locks[i]) {
371       if (foundone) return 0; /*false*/
372       foundone++;
373     } 
374   }
375   return 1; /*true */
376 }
377
378 void *thread_main (void *arg)
379 {
380    DYNINSTlock_spinlock(&mut);
381    register_my_lock((unsigned long)pthread_self(),1);
382    pthread_mutex_lock(&real_lock);
383    /*printf("thread %lu got mutex %d\n", (unsigned long)pthread_self(), mut.lock); */
384    sleep_ms (1);
385    if (!is_only_one()) {
386      FAIL(TESTNO, TESTNAME);
387      test2err = 1;
388    }
389    pthread_mutex_unlock(&real_lock);
390    /*printf("thread %lu unlocking mutex\n", (unsigned long) pthread_self()); */
391    register_my_lock((unsigned long)pthread_self(),0);
392    test2counter++;
393    DYNINSTunlock_spinlock(&mut);
394    return NULL;
395 }
396
397 void DYNINSTunlock_spinlock(dyninst_spinlock*s)
398 {
399   s->lock = 0;
400 }
401
402 #endif
403 bool mutatorTest2()
404 {
405
406 #if !defined (os_windows) && !defined(os_irix)
407   unsigned int timeout = 0; // in ms
408   pthread_attr_t attr;
409   unsigned int i;
410   mut.lock = 0;
411   /*pthread_mutex_attr_t mutattr; */
412   pthread_mutex_init(&real_lock, NULL);
413
414   pthread_attr_init(&attr);
415   pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED);
416   pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
417   DYNINSTlock_spinlock(&mut);
418
419   for (i = 0; i < THREADS; ++i) {
420     current_locks[i] = 0;
421     int err;
422     err = pthread_create(&(test2threads[i]), &attr, thread_main, NULL);
423     if (err) {
424       fprintf(stderr, "Error creating thread %d: %s[%d]\n",
425               i, strerror(errno), errno);
426     }
427   }
428
429   sleep_ms(1);
430   DYNINSTunlock_spinlock(&mut);
431
432   while((test2counter < THREADS) && !test2err && (timeout < TIMEOUT)) {
433     sleep_ms(SLEEP_INTERVAL/*ms*/);
434     timeout += SLEEP_INTERVAL;
435   }
436
437   if (timeout >= TIMEOUT) {
438     FAIL(TESTNO, TESTNAME);
439     fprintf(stderr, "%s[%d]:  test timed out.\n",
440            __FILE__, __LINE__);
441     test2err = 1;
442   }
443
444
445   if (test2err) {
446     for (i = 0; i < THREADS; ++i) {
447      pthread_kill(test2threads[i],9);
448     }
449   }
450   else {
451     PASS(TESTNO, TESTNAME);
452   }
453 #else
454     SKIP(TESTNO, TESTNAME);
455     fprintf(stderr, "%s[%d]:  This test is not supported on this platform\n",
456                     __FILE__, __LINE__);
457 #endif
458   return true;
459 }
460
461
462 #undef  TESTNO
463 #define TESTNO 3
464 #undef  TESTNAME
465 #define TESTNAME "thread create callback"
466
467 int test3_threadCreateCounter = 0;
468 void threadCreateCB(BPatch_thread *thr, unsigned long thread_id)
469 {
470   test3_threadCreateCounter++;
471 //  fprintf(stderr, "%s[%d]:  got a thread start event: %d\n", __FILE__, __LINE__,
472 //          test3_threadCreateCounter);
473 }
474
475 bool mutatorTest3()
476 {
477   unsigned int timeout = 0; // in ms
478   int err = 0;
479
480   BPatchThreadEventCallback createcb = threadCreateCB;
481   if (!appThread->registerThreadEventCallback(BPatch_threadCreateEvent,
482                                               createcb)) {
483     FAIL(TESTNO, TESTNAME);
484     fprintf(stderr, "%s[%d]:  failed to register thread callback\n",
485            __FILE__, __LINE__);
486     return false;
487   }
488   //  unset mutateeIde to trigger thread (10) spawn.
489   int zero = 0;
490   setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
491   appThread->continueExecution();
492
493   //  wait until we have received the desired number of events
494   //  (or timeout happens)
495
496   while(test3_threadCreateCounter < 10 && (timeout < TIMEOUT)) {
497     sleep_ms(SLEEP_INTERVAL/*ms*/);
498     timeout += SLEEP_INTERVAL;
499     bpatch->pollForStatusChange();
500   }
501
502   if (timeout >= TIMEOUT) {
503     FAIL(TESTNO, TESTNAME);
504     fprintf(stderr, "%s[%d]:  test timed out.\n",
505            __FILE__, __LINE__);
506     err = 1;
507   }
508
509   appThread->stopExecution();
510
511   if (!appThread->removeThreadEventCallback(BPatch_threadCreateEvent,
512                                             createcb)) {
513     FAIL(TESTNO, TESTNAME);
514     fprintf(stderr, "%s[%d]:  failed to remove thread callback\n",
515            __FILE__, __LINE__);
516     return false;
517   }
518   if (!err)  {
519     PASS(TESTNO, TESTNAME);
520     return true;
521   }
522   return false;
523 }
524
525 #undef  TESTNO
526 #define TESTNO 4 
527 #undef  TESTNAME
528 #define TESTNAME "thread exit callback"
529
530 int test4_threadDestroyCounter = 0;
531 void threadDestroyCB(BPatch_thread *thr, unsigned long thread_id)
532 {
533   test4_threadDestroyCounter++;
534  // fprintf(stderr, "%s[%d]:  got a thread destroy event: %d\n", __FILE__, __LINE__,
535   //        test4_threadDestroyCounter);
536 }
537
538 bool mutatorTest4()
539 {
540   unsigned int timeout = 0; // in ms
541   int err = 0;
542
543   BPatchThreadEventCallback destroycb = threadDestroyCB;
544   if (!appThread->registerThreadEventCallback(BPatch_threadDestroyEvent,
545                                               destroycb)) {
546     FAIL(TESTNO, TESTNAME);
547     fprintf(stderr, "%s[%d]:  failed to register thread callback\n",
548            __FILE__, __LINE__);
549     return false;
550   }
551
552   //  unset mutateeIdle to trigger thread (10) spawn.
553
554   int zero = 0;
555   setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
556   appThread->continueExecution();
557
558   //  wait until we have received the desired number of events
559   //  (or timeout happens)
560   while(test4_threadDestroyCounter < 10 && (timeout < TIMEOUT)) {
561     sleep_ms(SLEEP_INTERVAL/*ms*/);
562     timeout += SLEEP_INTERVAL; 
563     bpatch->pollForStatusChange();
564   }
565
566   if (timeout >= TIMEOUT) {
567     FAIL(TESTNO, TESTNAME);
568     fprintf(stderr, "%s[%d]:  test timed out.\n",
569            __FILE__, __LINE__);
570     err = 1;
571   }
572
573   appThread->stopExecution();
574
575   if (!appThread->removeThreadEventCallback(BPatch_threadDestroyEvent,
576                                             destroycb)) {
577     FAIL(TESTNO, TESTNAME);
578     fprintf(stderr, "%s[%d]:  failed to remove thread callback\n",
579            __FILE__, __LINE__);
580     return false;
581   }
582
583   if (!err) {
584     PASS(TESTNO, TESTNAME);
585     return true;
586   }
587   return false;
588 }
589
590
591 #undef  TESTNO
592 #define TESTNO 5 
593 #undef  TESTNAME
594 #define TESTNAME "thread start callback"
595
596 bool mutatorTest5()
597 {
598
599   return true;
600 }
601
602 #undef  TESTNO
603 #define TESTNO 6 
604 #undef  TESTNAME
605 #define TESTNAME "thread stop callback"
606
607 bool mutatorTest6()
608 {
609
610   return true;
611 }
612
613 /*******************************************************************************/
614 /*******************************************************************************/
615 /*******************************************************************************/
616
617 int mutatorMAIN(char *pathname, bool useAttach)
618 {
619         char *dirName;
620
621    // Create an instance of the BPatch library
622     bpatch = new BPatch;
623
624     // Force functions to be relocated
625     if (forceRelocation) {
626       bpatch->setForcedRelocation_NP(true);
627     }
628
629     // Register a callback function that prints any error messages
630     bpatch->registerErrorCallback(errorFunc);
631
632     // Start the mutatee
633     printf("Starting \"%s\"\n", pathname);
634
635     const char *child_argv[MAX_TEST+5];
636
637     int n = 0;
638     child_argv[n++] = pathname;
639     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
640
641     if (runAllTests) {
642         child_argv[n++] = const_cast<char*>("-runall"); // signifies all tests
643     } else {
644         child_argv[n++] = const_cast<char*>("-run");
645         for (unsigned int j=1; j <= MAX_TEST; j++) {
646             if (runTest[j]) {
647                 char str[5];
648                 sprintf(str, "%d", j);
649                 child_argv[n++] = strdup(str);
650             }
651         }
652     }
653
654     child_argv[n] = NULL;
655
656     if (useAttach) {
657         int pid = startNewProcessForAttach(pathname, child_argv);
658         if (pid < 0) {
659             printf("*ERROR*: unable to start tests due to error creating mutatee process\n");
660             exit(-1);
661         } else {
662             dprintf("New mutatee process pid %d started; attaching...\n", pid);
663         }
664         P_sleep(1); // let the mutatee catch its breath for a moment
665         appThread = bpatch->attachProcess(pathname, pid);
666     } else {
667         appThread = bpatch->createProcess(pathname, child_argv,NULL);
668     }
669
670     if (appThread == NULL) {
671         fprintf(stderr, "Unable to run test program.\n");
672         exit(1);
673     }
674
675     // Read the program's image and get an associated image object
676     appImage = appThread->getImage();
677
678     // Signal the child that we've attached
679     if (useAttach) {
680         signalAttached(appThread, appImage);
681     }
682
683     // determine whether mutatee is C or C++
684     BPatch_variableExpr *isCxx = appImage->findVariable("mutateeCplusplus");
685     if (isCxx == NULL) {
686         fprintf(stderr, "  Unable to locate variable \"mutateeCplusplus\""
687                  " -- assuming 0!\n");
688     } else {
689         isCxx->readValue(&mutateeCplusplus);
690         dprintf("Mutatee is %s.\n", mutateeCplusplus ? "C++" : "C");
691     }
692
693     printf("\n");
694
695     if (runTest[1]) passedTest[1] = mutatorTest1();
696     if (runTest[2]) passedTest[2] = mutatorTest2();
697     if (runTest[3]) passedTest[3] = mutatorTest3();
698     if (runTest[4]) passedTest[4] = mutatorTest4();
699     //if (runTest[5]) passedTest[5] = mutatorTest5();
700     //if (runTest[6]) passedTest[6] = mutatorTest6();
701
702     if (appThread && !appThread->isTerminated())
703       appThread->terminateExecution();
704
705     printf("\n");
706
707     int failed_tests  = 0;
708     for (unsigned int i = 1; i < (MAX_TEST+1); ++i) {
709       if ((runTest[i]) && (!passedTest[i])) {
710          failed_tests++;
711       }
712     }
713     if (failed_tests) {
714       printf("**Failed %d test%s\n", failed_tests, 
715                                      failed_tests == 1 ? "." : "s.");
716       for (unsigned int i = 1; i < (MAX_TEST + 1); ++i) {
717         printf("%s ", passedTest[i] ? "P" : "F");
718       }
719       printf("\n");
720     }
721     else {
722       if (runAllTests)
723         printf("All tests passed.\n");
724       else
725         printf("All requested tests passed.\n");
726     }
727     return 0;
728 }
729
730 int
731 main(unsigned int argc, char *argv[])
732 {
733     char mutateeName[128];
734     char libRTname[256];
735
736     bool N32ABI = false;
737     bool useAttach = false;
738
739     strcpy(mutateeName,mutateeNameRoot);
740     strcpy(libNameA,libNameAroot);
741     strcpy(libNameB,libNameBroot);
742     libRTname[0]='\0';
743
744     if (!getenv("DYNINSTAPI_RT_LIB")) {
745          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
746 #if defined(i386_unknown_nt4_0)
747                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
748 #else
749                  "    set it to the full pathname of libdyninstAPI_RT\n");
750          exit(-1);
751 #endif
752     } else
753          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
754
755     unsigned int i;
756     // by default run all tests
757     for (i=1; i <= MAX_TEST; i++) {
758         runTest[i] = true;
759         passedTest[i] = false;
760     }
761
762     for (i=1; i < argc; i++) {
763         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
764         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
765         if (strncmp(argv[i], "-verbose", 2) == 0) {
766             debugPrint = 1;
767         } else if (!strcmp(argv[i], "-V")) {
768             fprintf (stdout, "%s\n", V_libdyninstAPI);
769             if (libRTname[0])
770                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
771             fflush(stdout);
772         } else if (!strcmp(argv[i], "-attach")) {
773             useAttach = true;
774         } else if (!strcmp(argv[i], "-skip")) {
775             unsigned int j;
776             runAllTests = false;
777             for (j=i+1; j < argc; j++) {
778                 unsigned int testId;
779                 if ((testId = atoi(argv[j]))) {
780                     if ((testId > 0) && (testId <= MAX_TEST)) {
781                         runTest[testId] = false;
782                     } else {
783                         printf("invalid test %d requested\n", testId);
784                         exit(-1);
785                     }
786                 } else {
787                     // end of test list
788                     break;
789                 }
790             }
791             i=j-1;
792         } else if (!strcmp(argv[i], "-run")) {
793             unsigned int j;
794             runAllTests = false;
795             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
796             for (j=i+1; j < argc; j++) {
797                 unsigned int testId;
798                 if ((testId = atoi(argv[j]))) {
799                     if ((testId > 0) && (testId <= MAX_TEST)) {
800                         runTest[testId] = true;
801                     } else {
802                         printf("invalid test %d requested\n", testId);
803                         exit(-1);
804                     }
805                 } else {
806                     // end of test list
807                     break;
808                 }
809             }
810             i=j-1;
811         } else if (!strcmp(argv[i], "-mutatee")) {
812             i++;
813             if (*argv[i]=='_')
814                 strcat(mutateeName,argv[i]);
815             else
816                 strcpy(mutateeName,argv[i]);
817 #if defined(i386_unknown_nt4_0) || defined(i386_unknown_linux2_0) || defined(sparc_sun_solaris2_4)
818         } else if (!strcmp(argv[i], "-relocate")) {
819             forceRelocation = true;
820 #endif
821 #if defined(mips_sgi_irix6_4)
822         } else if (!strcmp(argv[i], "-n32")) {
823             N32ABI = true;
824 #endif
825         } else {
826             fprintf(stderr, "Usage: test12 "
827                     "[-V] [-verbose] [-attach] "
828 #if defined(mips_sgi_irix6_4)
829                     "[-n32] "
830 #endif
831 #if defined(sparc_sun_solaris2_4) || defined(i386_unknown_linux2_0) || defined(rs6000_ibm_aix4_1)
832                     "[-saveworld] "
833 #endif
834                     "[-mutatee <test12.mutatee>] "
835                     "[-run <test#> <test#> ...] "
836                     "[-skip <test#> <test#> ...]\n");
837             fprintf(stderr, "%d subtests\n", MAX_TEST);
838             exit(-1);
839         }
840     }
841
842     //  detect IBM xlC compiler and set flag
843     if (strstr(mutateeName, "xlc") || strstr(mutateeName, "xlC"))
844       mutateeXLC = true;
845
846     if (!runAllTests) {
847         printf("Running Tests: ");
848         for (unsigned int j=1; j <= MAX_TEST; j++) {
849             if (runTest[j]) printf("%d ", j);
850         }
851         printf("\n");
852     }
853
854     // patch up the default compiler in mutatee name (if necessary)
855     if (!strstr(mutateeName, "_"))
856 #if defined(i386_unknown_nt4_0)
857         strcat(mutateeName,"_VC");
858 #else
859         strcat(mutateeName,"_gcc");
860 #endif
861     if (N32ABI || strstr(mutateeName,"_n32")) {
862         // patch up file names based on alternate ABI (as necessary)
863         if (!strstr(mutateeName, "_n32")) strcat(mutateeName,"_n32");
864         strcat(libNameA,"_n32");
865         strcat(libNameB,"_n32");
866     }
867
868     // patch up the platform-specific filename extensions
869 #if defined(i386_unknown_nt4_0)
870     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
871     strcat(libNameA,".dll");
872     strcat(libNameB,".dll");
873 #else
874     strcat(libNameA,".so");
875     strcat(libNameB,".so");
876 #endif
877
878     int retval = mutatorMAIN(mutateeName, useAttach);
879
880     return retval;
881 }
882