Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / tests / src / test12.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 //  This program tests the basic features of the dyninst API.
32 //      The mutatee that goes with this file is test1.mutatee.c
33 //
34 //  Naming conventions:
35 //      All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
36 //          XX is the test number
37 //          YY is the instance withing the test
38 //          func1_2 is the second function used in test case #1.
39 //
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <assert.h>
45 #include <stdarg.h>
46 #ifdef i386_unknown_nt4_0
47 #define WIN32_LEAN_AND_MEAN
48 #include <windows.h>
49 #include <winsock2.h>
50 #include <winbase.h>
51 #else
52 #include <unistd.h>
53 #endif
54
55 #include <iostream>
56 #include <vector>
57 using namespace std;
58
59 #include "BPatch.h"
60 #include "BPatch_Vector.h"
61 #include "BPatch_thread.h"
62 #include "BPatch_snippet.h"
63 #include "test_util.h"
64 #include "test12.h"
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <sys/wait.h>
68
69
70 #define FAIL(x,y) fprintf(stdout, "**Failed test #%d (%s)\n", x,y);
71 #define PASS(x,y) fprintf(stdout, "Passed test #%d (%s)\n", x,y);
72 #define SKIP(x,y) fprintf(stdout, "Skipped test #%d (%s)\n", x,y);
73 #define SLEEP_INTERVAL 100 /*ms*/
74
75 /* include spinlock function from RT lib as if in a header file */
76 /* note:  testing assembly code this way is only really accurate on */
77 /* gnu-compiled systems */
78
79 int debugPrint = 0; // internal "mutator" tracing
80 int errorPrint = 1; // external "dyninst" tracing (via errorFunc)
81
82 bool forceRelocation = false; // force relocation of functions
83
84 int mutateeCplusplus = 0;
85 int mutateeFortran = 0;
86 int mutateeXLC = 0;
87 int mutateeF77 = 0;
88 bool runAllTests = true;
89 bool runTest[MAX_TEST+1];
90 bool passedTest[MAX_TEST+1];
91 char mutateeName[128];
92 const char *child_argv[MAX_TEST+5];
93
94 BPatch *bpatch;
95
96 static const char *mutateeNameRoot = "test12.mutatee";
97 static const char *libNameAroot = "libtestA";
98 static const char *libNameBroot = "libtestB";
99 char libNameA[64], libNameB[64];
100
101 //  Globals for BPatch_thread and BPatch_image, just makes it easier
102 BPatch_thread *appThread;
103 BPatch_image *appImage;
104 char err_str[1024];
105
106 // control debug printf statements
107 void dprintf(const char *fmt, ...) {
108    va_list args;
109    va_start(args, fmt);
110
111    if(debugPrint)
112       vfprintf(stderr, fmt, args);
113
114    va_end(args);
115
116    fflush(stderr);
117 }
118
119 void sleep_ms(int ms) 
120 {
121   struct timespec ts,rem;
122   if (ms >= 1000) {
123     ts.tv_sec = (int) ms / 1000;
124   }
125   else
126     ts.tv_sec = 0;
127
128   ts.tv_nsec = (ms - (ts.tv_sec * 1000)) * 1000 * 1000;
129   //fprintf(stderr, "%s[%d]:  sleep_ms (sec = %lu, nsec = %lu)\n",
130   //        __FILE__, __LINE__, ts.tv_sec, ts.tv_nsec);
131
132   sleep:
133
134   if (0 != nanosleep(&ts, &rem)) {
135     if (errno == EINTR) {
136       fprintf(stderr, "%s[%d]:  sleep interrupted\n", __FILE__, __LINE__);
137       ts.tv_sec = rem.tv_sec;
138       ts.tv_nsec = rem.tv_nsec;
139       goto sleep;
140     }
141     assert(0);
142   }
143 }
144
145 /**************************************************************************
146  * Error callback
147  **************************************************************************/
148
149 #define DYNINST_NO_ERROR -1
150
151 int expectError = DYNINST_NO_ERROR;
152
153 void errorFunc(BPatchErrorLevel level, int num, const char * const *params)
154 {
155     if (num == 0) {
156         // conditional reporting of warnings and informational messages
157         if (errorPrint) {
158             if ((level == BPatchInfo) || (level == BPatchWarning))
159               { if (errorPrint > 1) printf("%s\n", params[0]); }
160             else {
161                 printf("%s", params[0]);
162             }
163         }
164     } else {
165         // reporting of actual errors
166         char line[256];
167         const char *msg = bpatch->getEnglishErrorString(num);
168         bpatch->formatErrorString(line, sizeof(line), msg, params);
169
170         if (num != expectError) {
171           if(num != 112)
172             printf("Error #%d (level %d): %s\n", num, level, line);
173
174             // We consider some errors fatal.
175             if (num == 101) {
176                exit(-1);
177             }
178         }
179     }
180 }
181
182 BPatch_function *findFunction(const char *fname, int testno, const char *testname)
183 {
184   BPatch_Vector<BPatch_function *> bpfv;
185   if (NULL == appImage->findFunction(fname, bpfv) || (bpfv.size() != 1)) {
186
187       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
188       fprintf(stderr, "  Expected 1 functions matching %s, got %d\n",
189               fname, bpfv.size());
190          exit(1);
191   }
192   return bpfv[0];
193 }
194
195 BPatch_function *findFunction(const char *fname, BPatch_module *inmod, int testno, const char *testname)
196 {
197   BPatch_Vector<BPatch_function *> bpfv;
198   if (NULL == inmod->findFunction(fname, bpfv) || (bpfv.size() != 1)) {
199
200       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
201       fprintf(stderr, "  Expected 1 functions matching %s, got %d\n",
202               fname, bpfv.size());
203          exit(1);
204   }
205   return bpfv[0];
206 }
207
208 BPatch_point *findPoint(BPatch_function *f, BPatch_procedureLocation loc, 
209                         int testno, const char *testname)
210 {
211   assert(f);
212   BPatch_Vector<BPatch_point *> *pts = f->findPoint(loc);
213
214   if (!pts) {
215     FAIL(testno, testname);
216     fprintf(stderr, "%s[%d]:  no points matching requested location\n", __FILE__, __LINE__);
217     exit(1);
218   }
219
220   if (pts->size() != 1) {
221     FAIL(testno, testname);
222     fprintf(stderr, "%s[%d]:  %d points matching requested location, not 1\n", __FILE__, __LINE__, 
223            pts->size());
224     exit(1);
225   }
226
227   return (*pts)[0];
228 }
229
230 //  at -- simple instrumentation.  As written, only can insert funcs without args -- 
231 //     -- modify to take snippet vector args if necessary.
232 BPatchSnippetHandle *at(BPatch_point * pt, BPatch_function *call, 
233                         int testno, const char *testname)
234 {
235   BPatch_Vector<BPatch_snippet *> args;
236   BPatch_funcCallExpr snip(*call, args);
237   BPatch_procedureLocation pttype = pt->getPointType();
238   BPatch_callWhen when;
239   if (pttype == BPatch_entry) when = BPatch_callBefore;
240   else if (pttype == BPatch_exit) when = BPatch_callAfter;
241   else if (pttype == BPatch_subroutine) when = BPatch_callBefore;
242   else assert(0);
243
244   BPatchSnippetHandle *ret;
245   ret = appThread->insertSnippet(snip, *pt,when);
246
247   if (!ret) {
248     FAIL(testno, testname);
249     fprintf(stderr, "%s[%d]:  could not insert instrumentation\n", __FILE__, __LINE__);
250     exit(1);
251   }
252
253   return ret;
254 }
255
256 void dumpVars(void)
257 {
258   BPatch_Vector<BPatch_variableExpr *> vars;
259   appImage->getVariables(vars);
260   for (unsigned int i = 0; i < vars.size(); ++i) {
261     fprintf(stderr, "\t%s\n", vars[i]->getName());
262   }
263 }
264
265 void setVar(const char *vname, void *addr, int testno, const char *testname)
266 {
267    BPatch_variableExpr *v;
268    void *buf = addr;
269    if (NULL == (v = appImage->findVariable(vname))) {
270       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
271       fprintf(stderr, "  cannot find variable %s, avail vars:\n", vname);
272       dumpVars();
273          exit(1);
274    }
275
276    if (! v->writeValue(buf, sizeof(int),true)) {
277       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
278       fprintf(stderr, "  failed to write call site var to mutatee\n");
279       exit(1);
280    }
281 }
282
283 void getVar(const char *vname, void *addr, int len, int testno, const char *testname)
284 {
285    BPatch_variableExpr *v;
286    if (NULL == (v = appImage->findVariable(vname))) {
287       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
288       fprintf(stderr, "  cannot find variable %s: avail vars:\n", vname);
289       dumpVars();
290          exit(1);
291    }
292
293    if (! v->readValue(addr, len)) {
294       fprintf(stderr, "**Failed test #%d (%s)\n", testno, testname);
295       fprintf(stderr, "  failed to read var in mutatee\n");
296       exit(1);
297    }
298 }
299
300
301
302 /*******************************************************************************/
303 /*******************************************************************************/
304 /*******************************************************************************/
305 #undef  TESTNO
306 #define TESTNO 1
307 #undef  TESTNAME
308 #define TESTNAME "rtlib spinlocks"
309 #define THREADS 10
310
311 bool mutatorTest1()
312 {
313   
314   const char *local_child_argv[MAX_TEST+5];
315
316   //  not really going to attach, just start and let run to completion,
317   //  checking exit code.  
318
319   dprintf("%s[%d]: starting mutatee for attach: %s ", __FILE__, __LINE__, mutateeName);
320   int j = 0;
321   int i = 0;
322   local_child_argv[i++] = child_argv[j++];
323   for ( j = 0; j < MAX_TEST +5; ++j) {
324     if (child_argv[j]) {
325        if (!strcmp(child_argv[j], "-verbose"))
326           local_child_argv[i++] = child_argv[j];
327     }
328     else {
329       local_child_argv[i++] = "-run";
330       local_child_argv[i++] = "1";
331       local_child_argv[i++] = NULL;
332       break;
333     }
334   } 
335   for (j = 0; i < MAX_TEST +5; ++j) {
336     if (local_child_argv[j]) dprintf(" %s", local_child_argv[j]);
337     else break;
338   }
339   dprintf("\n");
340
341   BPatch_process *proc = bpatch->processCreate(mutateeName, local_child_argv);
342   if (!proc)  {
343      FAIL(TESTNO, TESTNAME);
344      fprintf(stderr, "could not create process %s\n", mutateeName);
345   }
346
347   int childpid = proc->getPid();
348   dprintf("%s[%d]:  mutatee process: %d\n", __FILE__, __LINE__, childpid);
349
350   proc->continueExecution();
351
352    //sleep (3);
353    int timeout = 0;
354    while (timeout < TIMEOUT) {
355      sleep_ms(SLEEP_INTERVAL/*ms*/);
356      timeout += SLEEP_INTERVAL;
357      if (proc->isTerminated()) 
358         break;
359      if (proc->isStopped()) {
360         //  This really shouldn't happen
361         fprintf(stderr, "%s[%d]:  BAD NEWS:  process is stopped, something is broken\n", 
362                 __FILE__, __LINE__);
363         proc->continueExecution();
364      }
365      if (proc->isDetached()) {
366         fprintf(stderr, "%s[%d]:  BAD NEWS:  process is detached, something is broken\n", 
367                 __FILE__, __LINE__);
368         abort();
369      }
370    }
371
372    if (proc->isTerminated()) {
373      switch(proc->terminationStatus()) {
374        case ExitedNormally:
375          {
376           int code = proc->getExitCode();
377           dprintf("%s[%d]:  exited normally with code %d\n", 
378                   __FILE__, __LINE__, code);
379           if (code != 0) return false;
380           break;
381          }
382        case ExitedViaSignal:
383          {
384           int code = proc->getExitSignal();
385           fprintf(stderr, "%s[%d]:  exited with signal %d\n", 
386                   __FILE__, __LINE__, code);
387           return false;
388           break;
389          }
390        case NoExit:
391        default:
392           assert(0);
393      };
394    }
395
396    if (timeout >= TIMEOUT) {
397      FAIL(TESTNO, TESTNAME);
398      fprintf(stderr, "%s[%d]:  test timed out.\n",
399             __FILE__, __LINE__);
400      //test1err = 1;
401      return false;
402    }
403
404   //sleep_ms(1000/*ms*/);
405   PASS(TESTNO,TESTNAME);
406   delete(proc);
407   return true;
408 }
409
410
411
412 #undef TESTNO
413 #undef TESTNAME
414 #define TESTNO 2 
415 #define TESTNAME "dynamic call site callback"
416 static const char *expected_fnames[] = {"call2_1","call2_2","call2_3","call2_4"};
417 int test2done = 0;
418 int test2err = 0;
419 template class BPatch_Vector<void *>;
420 BPatch_Vector<BPatch_point *> test2handles;
421 BPatch_Vector<BPatch_point *> dyncalls;
422
423 void dynSiteCB(BPatch_point *dyn_site, BPatch_function *called_function)
424 {
425   //fprintf(stderr, "%s[%d]:  dynSiteCB: pt = %p. func = %p.\n",
426   //                 __FILE__, __LINE__, dyn_site, called_function);
427   static int counter = 0;
428   static int counter2 = 0;
429   BPatch_point *pt = dyn_site;
430   BPatch_function *func = called_function;
431   assert(pt);
432   assert(func);
433   void *callsite_addr = pt->getAddress();
434   if (debugPrint) 
435     fprintf(stderr, "%s[%d]:  callsite addr = %p\n", __FILE__, __LINE__, callsite_addr);
436   char buf[2048];
437   func->getName(buf, 2048);
438   //fprintf(stderr, "%s[%d]:  got func %s, expect func %s\n", __FILE__, __LINE__, buf,
439   //        expected_fnames[counter]);
440   if (strcmp(expected_fnames[counter], buf)) {
441     FAIL(TESTNO, TESTNAME);
442     printf("\t%s[%d]:  got func %s, expect func %s\n", __FILE__, __LINE__, buf,
443           expected_fnames[counter]);
444     appThread->stopExecution();      
445     test2done = 1;
446   }
447   counter++;
448   if (counter > 3) {
449     counter = 0;
450     counter2++;
451   }
452
453   if (counter2 >= 2) {
454     bool removal_error = false;
455     appThread->stopExecution();      
456     //  not passed yet, now remove dynamic call monitoring handles
457     assert (test2handles.size());
458     for (unsigned int i = 0; i < test2handles.size(); ++i) {
459       if (!test2handles[i]->stopMonitoring()) {
460         removal_error = true;
461       }
462     }
463     if (removal_error) {
464       FAIL(TESTNO, TESTNAME);
465       test2err = 1;
466     }else {
467       PASS(TESTNO, TESTNAME);
468     }
469     test2done = 1;
470   }
471 }
472
473
474 bool mutatorTest2()
475 {
476 #if !defined(arch_ia64)
477   int timeout = 0;
478
479   if (mutateeXLC) {
480      appThread->continueExecution();
481      SKIP(TESTNO, TESTNAME);
482      fprintf(stderr, "\txlc optimizes out dynamic call sites for this test\n");
483      sleep_ms(100);
484      return true;
485   }
486
487   if (!bpatch->registerDynamicCallCallback(dynSiteCB)) {
488      FAIL(TESTNO, TESTNAME);
489      fprintf(stderr, "  failed to register callsite callback\n");
490      exit(1);
491   }
492
493   BPatch_function *func2_1 = findFunction("call2_dispatch", TESTNO, TESTNAME);
494   BPatch_function *targetFunc = func2_1;
495
496   BPatch_Vector<BPatch_point *> *calls = targetFunc->findPoint(BPatch_subroutine);
497   if (!calls) {
498      FAIL(TESTNO, TESTNAME);
499      fprintf(stderr, "  cannot find call points for func1_1\n");
500      exit(1);
501   }
502
503   for (unsigned int i = 0; i < calls->size(); ++i) {
504     BPatch_point *pt = (*calls)[i];
505     if (pt->isDynamic()){
506       bool ret;
507       ret = pt->monitorCalls();
508       if (!ret) {
509         FAIL(TESTNO, TESTNAME);
510         fprintf(stderr, "  failed monitorCalls\n");
511         exit(1);
512       } 
513       test2handles.push_back(pt);
514       dyncalls.push_back(pt);
515     }
516   }
517
518   if (dyncalls.size() != 3) {
519      FAIL(TESTNO, TESTNAME);
520      fprintf(stderr, "  wrong number of dynamic points found (%d -- not 3)\n",
521              dyncalls.size());
522      fprintf(stderr, "  total number of calls found: %d\n", calls->size());
523         exit(1);
524   }
525
526   appThread->continueExecution();
527
528   //  wait until we have received the desired number of events
529   //  (or timeout happens)
530
531   while(!test2done && (timeout < TIMEOUT)) {
532     bpatch->pollForStatusChange();
533     sleep_ms(SLEEP_INTERVAL/*ms*/);
534     timeout += SLEEP_INTERVAL;
535   }
536
537   if (timeout >= TIMEOUT) {
538     FAIL(TESTNO, TESTNAME);
539     fprintf(stderr, "%s[%d]:  test timed out.\n",
540            __FILE__, __LINE__);
541     test2err = 1;
542   }
543
544   return (test2err == 0);
545 #else
546   SKIP(TESTNO, TESTNAME);
547   return true;
548 #endif
549 }
550
551 #undef  TESTNO
552 #define TESTNO 3
553 #undef  TESTNAME
554 #define TESTNAME "thread create callback"
555
556
557 vector<unsigned long> callback_tids;
558
559 int test3_threadCreateCounter = 0;
560 void threadCreateCB(BPatch_process * proc, BPatch_thread *thr)
561 {
562   assert(thr);
563   if (debugPrint)
564      fprintf(stderr, "%s[%d]:  thread %lu start event for pid %d\n", __FILE__, __LINE__,
565                thr->getTid(), thr->getPid());
566   test3_threadCreateCounter++;
567   callback_tids.push_back(thr->getTid());
568   if (thr->isDeadOnArrival()) {
569      dprintf("%s[%d]:  thread %lu is doa \n", __FILE__, __LINE__, thr->getTid());
570   }
571 }
572
573 bool mutatorTest3and4(int testno, const char *testname)
574 {
575   test3_threadCreateCounter = 0;
576   callback_tids.clear();
577
578   unsigned int timeout = 0; // in ms
579   int err = 0;
580
581   BPatchAsyncThreadEventCallback createcb = threadCreateCB;
582   if (!bpatch->registerThreadEventCallback(BPatch_threadCreateEvent, createcb)) 
583   {
584     FAIL(testno, testname);
585     fprintf(stderr, "%s[%d]:  failed to register thread callback\n",
586            __FILE__, __LINE__);
587     return false;
588   }
589
590   //  unset mutateeIde to trigger thread (10) spawn.
591   int zero = 0;
592   setVar("mutateeIdle", (void *) &zero, testno, testname);
593   dprintf("%s[%d]:  continue execution for test %d\n", __FILE__, __LINE__, testno);
594   appThread->continueExecution();
595
596   //  wait until we have received the desired number of events
597   //  (or timeout happens)
598
599   BPatch_Vector<BPatch_thread *> threads;
600   BPatch_process *appProc = appThread->getProcess();
601   assert(appProc);
602   appProc->getThreads(threads);
603   int active_threads = 11;
604   threads.clear();
605   while (((test3_threadCreateCounter < TEST3_THREADS)
606          || (active_threads > 1)) 
607          && (timeout < TIMEOUT)) {
608     dprintf("%s[%d]: waiting for completion for test %d, num active threads = %d\n", 
609             __FILE__, __LINE__, testno, active_threads);
610     sleep_ms(SLEEP_INTERVAL/*ms*/);
611     timeout += SLEEP_INTERVAL;
612     if (appThread->isTerminated()) {
613        fprintf(stderr, "%s[%d]:  BAD NEWS:  somehow the process died\n", __FILE__, __LINE__);
614        err = 1;
615        break;
616     }
617     bpatch->pollForStatusChange();
618     if (appThread->isStopped()) {
619        //  this should cause the test to fail, but for the moment we're
620        //  just gonna continue it and complain
621        fprintf(stderr, "%s[%d]:  BAD NEWS:  somehow the process stopped\n", __FILE__, __LINE__);
622        appThread->continueExecution();
623     }
624     appProc->getThreads(threads);
625     active_threads = threads.size();
626     threads.clear();
627   }
628
629   if (timeout >= TIMEOUT) {
630     FAIL(testno, testname);
631     fprintf(stderr, "%s[%d]:  test timed out. got %d/10 events\n",
632            __FILE__, __LINE__, test3_threadCreateCounter);
633     err = 1;
634   }
635
636   dprintf("%s[%d]: ending test %d, num active threads = %d\n", 
637             __FILE__, __LINE__, testno, active_threads);
638   //sleep_ms(500);
639   dprintf("%s[%d]:  stop execution for test %d\n", __FILE__, __LINE__, testno);
640   appThread->stopExecution();
641
642   //   read all tids from the mutatee and verify that we got them all
643   unsigned long mutatee_tids[TEST3_THREADS];
644   const char *threads_varname = NULL;
645   if (testno == 3)
646      threads_varname = "test3_threads";
647   if (testno == 4)
648      threads_varname = "test4_threads";
649   assert(threads_varname);
650   getVar(threads_varname, (void *) mutatee_tids, 
651          (sizeof(unsigned long) * TEST3_THREADS),
652          testno, testname);
653
654   if (debugPrint) {
655     fprintf(stderr, "%s[%d]:  read following tids for test%d from mutatee\n", __FILE__, __LINE__, testno);
656     
657     for (unsigned int i = 0; i < TEST3_THREADS; ++i) {
658        fprintf(stderr, "\t%lu\n", mutatee_tids[i]);
659     }
660   }
661
662   for (unsigned int i = 0; i < TEST3_THREADS; ++i) {
663      bool found = false;
664      for (unsigned int j = 0; j < callback_tids.size(); ++j) {
665        if (callback_tids[j] == mutatee_tids[i]) {
666          found = true;
667          break;
668        }
669      }
670
671     if (!found) {
672       FAIL(testno, testname);
673       fprintf(stderr, "%s[%d]:  could not find record for tid %lu: have these:\n",
674              __FILE__, __LINE__, mutatee_tids[i]);
675        for (unsigned int j = 0; j < callback_tids.size(); ++j) {
676           fprintf(stderr, "%lu\n", callback_tids[j]);
677        }
678       err = true;
679       break;
680     }
681   }
682
683   dprintf("%s[%d]: removing thread callback\n", __FILE__, __LINE__);
684   if (!bpatch->removeThreadEventCallback(BPatch_threadCreateEvent, createcb)) {
685     FAIL(testno, testname);
686     fprintf(stderr, "%s[%d]:  failed to remove thread callback\n",
687            __FILE__, __LINE__);
688     err = true;
689   }
690
691   if (!err)  {
692     PASS(testno, testname);
693     //sleep(5);
694     //sleep_ms(200);
695     return true;
696   }
697   return false;
698 }
699
700 bool mutatorTest3()
701 {
702   return  mutatorTest3and4(TESTNO, TESTNAME);
703 }
704
705 #undef  TESTNO
706 #define TESTNO 4
707 #undef  TESTNAME
708 #define TESTNAME "thread create callback -- doa"
709
710 bool mutatorTest4()
711 {
712 #if 0
713 #if defined(os_linux) && defined(arch_x86)
714   SKIP(TESTNO, TESTNAME);
715 #else
716   return  mutatorTest3and4(TESTNO, TESTNAME);
717 #endif
718 #endif
719   return  mutatorTest3and4(TESTNO, TESTNAME);
720 }
721
722 #undef  TESTNO
723 #define TESTNO 5 
724 #undef  TESTNAME
725 #define TESTNAME "thread exit callback"
726
727 int test5_threadDestroyCounter = 0;
728 void threadDestroyCB(BPatch_process * /*proc*/, BPatch_thread *thr)
729 {
730   if (debugPrint)
731     fprintf(stderr, "%s[%d]:  thread %lu destroy event for pid %d\n", 
732             __FILE__, __LINE__, thr->getTid(), thr->getPid());
733   test5_threadDestroyCounter++;
734 }
735
736 bool mutatorTest5and6(int testno, const char *testname)
737 {
738   unsigned int timeout = 0; // in ms
739   int err = 0;
740
741   BPatchAsyncThreadEventCallback destroycb = threadDestroyCB;
742   if (!bpatch->registerThreadEventCallback(BPatch_threadDestroyEvent, destroycb)) 
743   {
744     FAIL(testno, testname);
745     fprintf(stderr, "%s[%d]:  failed to register thread callback\n",
746            __FILE__, __LINE__);
747     return false;
748   }
749
750   if (debugPrint)
751     fprintf(stderr, "%s[%d]:  registered threadDestroy callback\n", 
752             __FILE__, __LINE__);
753
754   //  unset mutateeIdle to trigger thread (10) spawn.
755
756   int zero = 0;
757   setVar("mutateeIdle", (void *) &zero, testno, testname);
758   appThread->continueExecution();
759
760   //  wait until we have received the desired number of events
761   //  (or timeout happens)
762   while(test5_threadDestroyCounter < TEST5_THREADS && (timeout < TIMEOUT)) {
763     sleep_ms(SLEEP_INTERVAL/*ms*/);
764     timeout += SLEEP_INTERVAL; 
765     fprintf(stderr, "%s[%d]:  polliing\n", __FILE__, __LINE__);
766     bpatch->pollForStatusChange();
767   }
768
769   if (timeout >= TIMEOUT) {
770     FAIL(testno, testname);
771     fprintf(stderr, "%s[%d]:  test timed out.\n",
772            __FILE__, __LINE__);
773     err = 1;
774   }
775
776   appThread->stopExecution();
777
778   if (!bpatch->removeThreadEventCallback(BPatch_threadDestroyEvent, destroycb)) {
779     FAIL(testno, testname);
780     fprintf(stderr, "%s[%d]:  failed to remove thread callback\n",
781            __FILE__, __LINE__);
782     return false;
783   }
784
785   if (!err) {
786     PASS(testno, testname);
787     return true;
788   }
789   return false;
790 }
791
792 bool mutatorTest5()
793 {
794 #if defined (os_none)
795   return mutatorTest5and6(TESTNO, TESTNAME);
796 #else
797   SKIP(TESTNO, TESTNAME);
798   return true;
799 #endif
800 }
801
802 #undef  TESTNO
803 #define TESTNO 6 
804 #undef  TESTNAME
805 #define TESTNAME "thread exit callback -- doa"
806
807 bool mutatorTest6()
808 {
809 #if defined (os_none)
810   return mutatorTest5and6(TESTNO, TESTNAME);
811 #else
812   SKIP(TESTNO, TESTNAME);
813   return true;
814 #endif
815 }
816
817 #undef  TESTNO
818 #define TESTNO 7 
819 #undef  TESTNAME
820 #define TESTNAME "user defined message callback -- st"
821
822 bool test7done = false;
823 bool test7err = false;
824 unsigned long test7_tids[TEST8_THREADS];
825
826 void test7cb(BPatch_process * /* proc*/, void *buf, unsigned int bufsize)
827 {
828   static int callback_counter = 0;
829   if (debugPrint)
830     fprintf(stderr, "%s[%d]:  inside test7cb\n", __FILE__, __LINE__);
831
832   if (bufsize != sizeof(user_msg_t)) {
833     //  something is incredibly wrong
834     fprintf(stderr, "%s[%d]:  unexpected message size %d not %d\n", 
835             __FILE__, __LINE__, bufsize, sizeof(user_msg_t));
836     test7err = true;
837     return;
838   }
839
840   user_msg_t *msg = (user_msg_t *) buf;
841   user_event_t what = msg->what;
842   unsigned long tid = msg->tid;
843
844   if (debugPrint)
845     fprintf(stderr, "%s[%d]:  thread = %lu, what = %d\n", __FILE__, __LINE__, tid, what);
846
847   if (callback_counter == 0) {
848     //  we expect the entry point to be reported first
849     if (what != func_entry) {
850       fprintf(stderr, "%s[%d]:  unexpected message %d not %d\n", 
851             __FILE__, __LINE__, (int) what, (int) func_entry);
852       FAIL(TESTNO, TESTNAME);
853       test7err = 1;
854       return; 
855     }
856   } else if (callback_counter <= TEST7_NUMCALLS) {
857     // we expect to get a bunch of function calls next
858     if (what != func_callsite) {
859       fprintf(stderr, "%s[%d]:  unexpected message %d not %d\n", 
860             __FILE__, __LINE__, (int) what, (int) func_callsite);
861       FAIL(TESTNO, TESTNAME);
862       test7err = 1;
863       return; 
864     }
865   }
866   else if (callback_counter == (TEST7_NUMCALLS +1)) {
867     // lastly comes the function exit
868     if (what != func_exit) {
869       fprintf(stderr, "%s[%d]:  unexpected message %d not %d\n", 
870             __FILE__, __LINE__, (int) what, (int) func_exit);
871       FAIL(TESTNO, TESTNAME);
872       test7err = 1;
873       return; 
874     }
875     // set test7done to end the test
876     test7done = true;
877   }
878   callback_counter++;
879 }
880
881 bool mutatorTest7()
882 {
883   //  a simple single threaded user messagin scenario where we want to send
884   //  async messages at function entry/exit and call points.
885
886   BPatchUserEventCallback cb = test7cb;
887   if (!bpatch->registerUserEventCallback(cb)) {
888     FAIL(TESTNO, TESTNAME);
889     fprintf(stderr, "%s[%d]: could not register callback\n", __FILE__, __LINE__);
890     return false;
891   }
892
893   //  instrument entry and exit of call7_1, as well as call points inside call7_1
894   BPatch_function *call7_1 = findFunction("call7_1", TESTNO, TESTNAME);
895   BPatch_point *entry = findPoint(call7_1, BPatch_entry,TESTNO, TESTNAME);
896   BPatch_point *exit = findPoint(call7_1, BPatch_exit,TESTNO, TESTNAME);
897   BPatch_point *callsite = findPoint(call7_1, BPatch_subroutine,TESTNO, TESTNAME);
898
899   //  These are our asynchronous message functions (in libTest12) that we
900   //  attach to the "interesting" points
901   BPatch_function *reportEntry = findFunction("reportEntry", TESTNO, TESTNAME);
902   BPatch_function *reportExit = findFunction("reportExit", TESTNO, TESTNAME);
903   BPatch_function *reportCallsite = findFunction("reportCallsite", TESTNO, TESTNAME);
904
905   //  Do the instrumentation
906   BPatchSnippetHandle *entryHandle = at(entry, reportEntry, TESTNO, TESTNAME); 
907   BPatchSnippetHandle *exitHandle = at(exit, reportExit, TESTNO, TESTNAME); 
908   BPatchSnippetHandle *callsiteHandle = at(callsite, reportCallsite, TESTNO, TESTNAME); 
909
910
911   if (debugPrint) {
912      int one = 1;
913      setVar("libraryDebug", (void *) &one, TESTNO, TESTNAME);
914   }
915  //  unset mutateeIdle to trigger mutatee to issue messages.
916
917   int zero = 0;
918   int timeout = 0;
919   setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
920   appThread->getProcess()->continueExecution();
921
922   //  wait until we have received the desired number of events
923   //  (or timeout happens)
924   while(!test7err && !test7done && (timeout < TIMEOUT)) {
925     sleep_ms(SLEEP_INTERVAL/*ms*/);
926     timeout += SLEEP_INTERVAL;
927     bpatch->pollForStatusChange();
928   }
929
930   if (timeout >= TIMEOUT) {
931     FAIL(TESTNO, TESTNAME);
932     fprintf(stderr, "%s[%d]:  test timed out.\n",
933            __FILE__, __LINE__);
934     test7err = true;
935   }
936
937   appThread->getProcess()->stopExecution();
938
939   if (!bpatch->removeUserEventCallback(test7cb)) {
940     FAIL(TESTNO, TESTNAME);
941     fprintf(stderr, "%s[%d]:  failed to remove callback\n",
942            __FILE__, __LINE__);
943     return false;
944   }
945
946   if (!test7err) {
947     PASS(TESTNO, TESTNAME);
948     return true;
949   } 
950
951   FAIL(TESTNO, TESTNAME);
952   return false;
953 }
954
955 #undef  TESTNO
956 #define TESTNO 8 
957 #undef  TESTNAME
958 #define TESTNAME "user defined message callback -- mt"
959
960 bool test8done = false;
961 bool test8err = false;
962 unsigned long tids[TEST8_THREADS];
963 user_event_t last_event[TEST8_THREADS];
964
965 bool findThreadIndex(unsigned long tid, unsigned int &index)
966 {
967  //  find the index with tid <tid>, if it exists, otherwise, the index of
968  //  an empty slot.  If no empty slot, return false (fail);
969   for (index = 0; index < TEST8_THREADS; ++index) {
970     if (0 == tids[index]) {
971       tids[index] = tid;
972       if (debugPrint)
973         fprintf(stderr, "%s[%d]:  giving new slot to thread id %lu\n",
974                 __FILE__, __LINE__, tid);
975       return true;
976     }
977     if (tid == tids[index]) 
978       return true;
979   }
980   return false;
981 }
982
983 void test8cb(BPatch_process * /*proc*/, void *buf, unsigned int bufsize)
984 {
985   static int destroy_counter = 0;
986   if (debugPrint)
987     fprintf(stderr, "%s[%d]:  inside test8cb\n", __FILE__, __LINE__);
988
989   if (bufsize != sizeof(user_msg_t)) {
990     //  something is incredibly wrong
991     fprintf(stderr, "%s[%d]:  unexpected message size %d not %d\n", 
992             __FILE__, __LINE__, bufsize, sizeof(user_msg_t));
993     test8err = true;
994     return;
995   }
996
997   user_msg_t *msg = (user_msg_t *) buf;
998   user_event_t what = msg->what;
999   unsigned long tid = msg->tid;
1000
1001   if (debugPrint)
1002     fprintf(stderr, "%s[%d]:  thread = %lu, what = %d\n", __FILE__, __LINE__, tid, what);
1003   unsigned int index;
1004   if (!findThreadIndex(tid, index)) {
1005     test8err = true;
1006     fprintf(stderr, "%s[%d]:  failed to find record for tid %lu (or empty slot)\n",
1007             __FILE__, __LINE__,tid);
1008     return;
1009   }
1010
1011   if (debugPrint)
1012     fprintf(stderr, "%s[%d]:  thread id %lu: index %d\n", __FILE__, __LINE__, tid, index);
1013   if (last_event[index] != (what - 1)) {
1014     test8err = true;
1015     fprintf(stderr, "%s[%d]:  out of order messsage received for thread %lu, last = %d, now = %d\n",
1016            __FILE__, __LINE__, tid, last_event[index], what);
1017     return;
1018   }
1019
1020   last_event[index] = what;
1021   
1022   if (what == mutex_destroy) 
1023      destroy_counter++;
1024   if (destroy_counter == TEST8_THREADS)
1025     test8done = true;
1026   //sleep_ms(10);
1027 }
1028
1029 bool mutatorTest8()
1030 {
1031   for (unsigned int i = 0; i < TEST8_THREADS; ++i) {
1032     tids[i] = 0;
1033     last_event[i] = null_event;
1034   }  
1035   //  instrument events having to do with mutex init, lock, unlock, destroy
1036   //  with messaging functions in libtest12.so
1037   BPatch_module *libpthread = appImage->findModule("libpthread",true);
1038   assert(libpthread);
1039
1040   BPatch_function *mutInit = findFunction("createLock", TESTNO, TESTNAME);
1041   BPatch_point *mutInitPt = findPoint(mutInit, BPatch_entry,TESTNO, TESTNAME);
1042   BPatch_function *reportInit = findFunction("reportMutexInit", TESTNO, TESTNAME);
1043   BPatchSnippetHandle *initHandle = at(mutInitPt, reportInit, TESTNO, TESTNAME); 
1044   BPatch_function *mutDestroy = findFunction("destroyLock", TESTNO, TESTNAME);
1045   BPatch_point *mutDestroyPt = findPoint(mutDestroy, BPatch_entry,TESTNO, TESTNAME);
1046   BPatch_function *reportDestroy = findFunction("reportMutexDestroy", TESTNO, TESTNAME);
1047   BPatchSnippetHandle *destroyHandle = at(mutDestroyPt, reportDestroy, TESTNO, TESTNAME); 
1048
1049   BPatch_function *mutLock = findFunction("lockLock", TESTNO, TESTNAME);
1050   BPatch_point *mutLockPt = findPoint(mutLock, BPatch_entry,TESTNO,TESTNAME);
1051   BPatch_function *reportLock = findFunction("reportMutexLock", TESTNO, TESTNAME);
1052   BPatchSnippetHandle *lockHandle = at(mutLockPt, reportLock, TESTNO, TESTNAME); 
1053   BPatch_function *mutUnlock = findFunction("unlockLock", TESTNO, TESTNAME);
1054   BPatch_point *mutUnlockPt = findPoint(mutUnlock, BPatch_entry,TESTNO,TESTNAME);
1055   BPatch_function *reportUnlock = findFunction("reportMutexUnlock", TESTNO, TESTNAME);
1056   BPatchSnippetHandle *unlockHandle = at(mutUnlockPt, reportUnlock, TESTNO, TESTNAME); 
1057
1058   BPatchUserEventCallback cb = test8cb;
1059   if (!bpatch->registerUserEventCallback(cb)) {
1060     FAIL(TESTNO, TESTNAME);
1061     fprintf(stderr, "%s[%d]: could not register callback\n", __FILE__, __LINE__);
1062     return false;
1063   }
1064
1065  //  unset mutateeIdle to trigger mutatee to issue messages.
1066
1067   int zero = 0;
1068   int timeout = 0;
1069   setVar("mutateeIdle", (void *) &zero, TESTNO, TESTNAME);
1070   appThread->getProcess()->continueExecution();
1071
1072   //  wait until we have received the desired number of events
1073   //  (or timeout happens)
1074   while(!test8err && !test8done && (timeout < TIMEOUT)) {
1075     sleep_ms(SLEEP_INTERVAL/*ms*/);
1076     timeout += SLEEP_INTERVAL;
1077     bpatch->pollForStatusChange();
1078   }
1079
1080   if (timeout >= TIMEOUT) {
1081     FAIL(TESTNO, TESTNAME);
1082     fprintf(stderr, "%s[%d]:  test timed out. Took longer than %d ms\n",
1083            __FILE__, __LINE__, TIMEOUT);
1084     test8err = true;
1085   }
1086
1087   appThread->getProcess()->stopExecution();
1088
1089   if (!bpatch->removeUserEventCallback(test8cb)) {
1090     FAIL(TESTNO, TESTNAME);
1091     fprintf(stderr, "%s[%d]:  failed to remove callback\n",
1092            __FILE__, __LINE__);
1093     return false;
1094   }
1095
1096   //  what happens here if we still have messages coming in, but no handler -- should
1097   //  check this?
1098
1099   appThread->getProcess()->deleteSnippet(initHandle);
1100   appThread->getProcess()->deleteSnippet(destroyHandle);
1101   appThread->getProcess()->deleteSnippet(lockHandle);
1102   appThread->getProcess()->deleteSnippet(unlockHandle);
1103   if (!test8err) {
1104     PASS(TESTNO, TESTNAME);
1105     return true;
1106   }
1107   return false;
1108
1109 }
1110
1111
1112 /*******************************************************************************/
1113 /*******************************************************************************/
1114 /*******************************************************************************/
1115
1116 int mutatorMAIN(char *pathname, bool useAttach)
1117 {
1118         //char *dirName;
1119
1120    // Create an instance of the BPatch library
1121     bpatch = new BPatch;
1122
1123     // Force functions to be relocated
1124     if (forceRelocation) {
1125       bpatch->setForcedRelocation_NP(true);
1126     }
1127
1128     // Register a callback function that prints any error messages
1129     bpatch->registerErrorCallback(errorFunc);
1130
1131     //  set up argument vector for mutatee
1132     int n = 0;
1133     child_argv[n++] = pathname;
1134     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
1135
1136     if (runAllTests) {
1137         child_argv[n++] = const_cast<char*>("-runall"); // signifies all tests
1138     } else {
1139         child_argv[n++] = const_cast<char*>("-run");
1140         for (unsigned int j=1; j <= MAX_TEST; j++) {
1141             if (runTest[j]) {
1142                 char str[5];
1143                 sprintf(str, "%d", j);
1144                 child_argv[n++] = strdup(str);
1145             }
1146         }
1147     }
1148
1149
1150     //  subtest1 does not have a mutatee, exactly, so deal with it here
1151     //  before we start the mutatee
1152     child_argv[n] = NULL;
1153     if (runTest[1]) passedTest[1] = mutatorTest1();
1154
1155     if ( ! ( runTest[2] ||
1156              runTest[3] ||
1157              runTest[4] ||
1158              runTest[5] ||
1159              runTest[6] ||
1160              runTest[7] ||
1161              runTest[8] )) {
1162       if (passedTest[1])
1163          printf("All requested tests passed\n");
1164       else
1165          printf("** Failed test1 (rtlib spinlocks)\n");
1166      return 0;
1167     }
1168
1169     // Start the mutatee
1170     printf("Starting \"%s\"\n", pathname);
1171
1172     if (useAttach) {
1173         int pid = startNewProcessForAttach(pathname, child_argv);
1174         if (pid < 0) {
1175             printf("*ERROR*: unable to start tests due to error creating mutatee process\n");
1176             exit(-1);
1177         } else {
1178             dprintf("New mutatee process pid %d started; attaching...\n", pid);
1179         }
1180         sleep_ms(100); // let the mutatee catch its breath for a moment
1181         //P_sleep(1); // let the mutatee catch its breath for a moment
1182         appThread = bpatch->attachProcess(pathname, pid);
1183     } else {
1184         child_argv[n++] = const_cast<char *>("-attachrun");
1185         child_argv[n] = NULL;
1186         dprintf("%s[%d]:  starting mutatee %s for tests2 and higher\n", __FILE__, __LINE__, pathname);
1187         appThread = bpatch->createProcess(pathname, child_argv,NULL);
1188     }
1189
1190     if (appThread == NULL) {
1191         fprintf(stderr, "Unable to run test program.\n");
1192         exit(1);
1193     }
1194
1195     // Read the program's image and get an associated image object
1196     appImage = appThread->getImage();
1197
1198     // Signal the child that we've attached
1199     if (useAttach) {
1200         signalAttached(appThread, appImage);
1201     }
1202
1203     // determine whether mutatee is C or C++
1204     BPatch_variableExpr *isCxx = appImage->findVariable("mutateeCplusplus");
1205     if (isCxx == NULL) {
1206         fprintf(stderr, "  Unable to locate variable \"mutateeCplusplus\""
1207                  " -- assuming 0!\n");
1208     } else {
1209         isCxx->readValue(&mutateeCplusplus);
1210         dprintf("Mutatee is %s.\n", mutateeCplusplus ? "C++" : "C");
1211     }
1212
1213     // load libtest12.so -- currently only used by subtest 5, but make it generally
1214     // available
1215     dprintf("%s[%d]:  loading test library: %s\n", __FILE__, __LINE__, TEST12_LIBNAME);
1216     if (!appThread->loadLibrary(TEST12_LIBNAME)) {
1217       fprintf(stderr, "%s[%d]:  failed to load library %s, cannot proceed\n", __FILE__, __LINE__,
1218               TEST12_LIBNAME);
1219       goto cleanup;
1220     }
1221     printf("\n");
1222
1223     if (runTest[2]) passedTest[2] = mutatorTest2();
1224     if (runTest[3]) passedTest[3] = mutatorTest3();
1225     if (runTest[4]) passedTest[4] = mutatorTest4();
1226     if (runTest[5]) passedTest[5] = mutatorTest5();
1227     if (runTest[6]) passedTest[6] = mutatorTest6();
1228     if (runTest[7]) passedTest[7] = mutatorTest7();
1229     if (runTest[8]) passedTest[8] = mutatorTest8();
1230
1231     cleanup:
1232
1233      //  unset mutateeIdle -- should exit gracefully
1234      int zero = 0;
1235       setVar("mutateeIdle", (void *) &zero, -1, "general test12 infrastructure");
1236
1237      if (appThread->isStopped())  {
1238          appThread->continueExecution();
1239       }
1240         
1241
1242      while (!appThread->isTerminated()) {
1243         bpatch->waitForStatusChange();
1244      }
1245
1246     printf("\n");
1247
1248     int failed_tests  = 0;
1249     for (unsigned int i = 1; i < (MAX_TEST+1); ++i) {
1250       if ((runTest[i]) && (!passedTest[i])) {
1251          failed_tests++;
1252       }
1253     }
1254     if (failed_tests) {
1255       printf("**Failed %d test%s\n", failed_tests, 
1256                                      failed_tests == 1 ? "." : "s.");
1257       for (unsigned int i = 1; i < (MAX_TEST + 1); ++i) {
1258         printf("%s ", passedTest[i] ? "P" : "F");
1259       }
1260       printf("\n");
1261     }
1262     else {
1263       if (runAllTests)
1264         printf("All tests passed.\n");
1265       else
1266         printf("All requested tests passed.\n");
1267     }
1268     return 0;
1269 }
1270
1271 int
1272 main(int argc, char *argv[])
1273 {
1274     char libRTname[256];
1275
1276     bool ABI_32 = false;
1277     bool useAttach = false;
1278
1279     strcpy(mutateeName,mutateeNameRoot);
1280     strcpy(libNameA,libNameAroot);
1281     strcpy(libNameB,libNameBroot);
1282     libRTname[0]='\0';
1283
1284     if (!getenv("DYNINSTAPI_RT_LIB")) {
1285          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
1286 #if defined(i386_unknown_nt4_0)
1287                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
1288 #else
1289                  "    set it to the full pathname of libdyninstAPI_RT\n");
1290          exit(-1);
1291 #endif
1292     } else
1293          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
1294
1295     updateSearchPaths(argv[0]);
1296
1297     unsigned int i;
1298     // by default run all tests
1299     for (i=1; i <= MAX_TEST; i++) {
1300         runTest[i] = true;
1301         passedTest[i] = false;
1302     }
1303
1304     for (i=1; i < argc; i++) {
1305         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
1306         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
1307         if (strncmp(argv[i], "-verbose", 2) == 0) {
1308             debugPrint = 1;
1309         } else if (!strcmp(argv[i], "-V")) {
1310             fprintf (stdout, "%s\n", V_libdyninstAPI);
1311             if (libRTname[0])
1312                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
1313             fflush(stdout);
1314         } else if (!strcmp(argv[i], "-attach")) {
1315             useAttach = true;
1316         } else if (!strcmp(argv[i], "-skip")) {
1317             unsigned int j;
1318             runAllTests = false;
1319             for (j=i+1; j < argc; j++) {
1320                 unsigned int testId;
1321                 if ((testId = atoi(argv[j]))) {
1322                     if ((testId > 0) && (testId <= MAX_TEST)) {
1323                         runTest[testId] = false;
1324                     } else {
1325                         printf("invalid test %d requested\n", testId);
1326                         exit(-1);
1327                     }
1328                 } else {
1329                     // end of test list
1330                     break;
1331                 }
1332             }
1333             i=j-1;
1334         } else if (!strcmp(argv[i], "-run")) {
1335             unsigned int j;
1336             runAllTests = false;
1337             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
1338             for (j=i+1; j < argc; j++) {
1339                 unsigned int testId;
1340                 if ((testId = atoi(argv[j]))) {
1341                     if ((testId > 0) && (testId <= MAX_TEST)) {
1342                         runTest[testId] = true;
1343                     } else {
1344                         printf("invalid test %d requested\n", testId);
1345                         exit(-1);
1346                     }
1347                 } else {
1348                     // end of test list
1349                     break;
1350                 }
1351             }
1352             i=j-1;
1353         } else if (!strcmp(argv[i], "-mutatee")) {
1354             i++;
1355             if (*argv[i]=='_')
1356                 strcat(mutateeName,argv[i]);
1357             else
1358                 strcpy(mutateeName,argv[i]);
1359 #if defined(i386_unknown_nt4_0) || defined(i386_unknown_linux2_0) || defined(sparc_sun_solaris2_4)
1360         } else if (!strcmp(argv[i], "-relocate")) {
1361             forceRelocation = true;
1362 #endif
1363 #if defined(x86_64_unknown_linux2_4)
1364         } else if (!strcmp(argv[i], "-m32")) {
1365             ABI_32 = true;
1366 #endif
1367         } else {
1368             fprintf(stderr, "Usage: test12 "
1369                     "[-V] [-verbose] [-attach] "
1370 #if defined(mips_sgi_irix6_4)
1371                     "[-n32] "
1372 #endif
1373 #if defined(sparc_sun_solaris2_4) || defined(i386_unknown_linux2_0) || defined(rs6000_ibm_aix4_1)
1374                     "[-saveworld] "
1375 #endif
1376                     "[-mutatee <test12.mutatee>] "
1377                     "[-run <test#> <test#> ...] "
1378                     "[-skip <test#> <test#> ...]\n");
1379             fprintf(stderr, "%d subtests\n", MAX_TEST);
1380             exit(-1);
1381         }
1382     }
1383
1384     //  detect IBM xlC compiler and set flag
1385     if (strstr(mutateeName, "xlc") || strstr(mutateeName, "xlC"))
1386       mutateeXLC = true;
1387
1388     if (!runAllTests) {
1389         printf("Running Tests: ");
1390         for (unsigned int j=1; j <= MAX_TEST; j++) {
1391             if (runTest[j]) printf("%d ", j);
1392         }
1393         printf("\n");
1394     }
1395
1396     // patch up the default compiler in mutatee name (if necessary)
1397     if (!strstr(mutateeName, "_"))
1398 #if defined(i386_unknown_nt4_0)
1399         strcat(mutateeName,"_VC");
1400 #else
1401         strcat(mutateeName,"_gcc");
1402 #endif
1403     if (ABI_32 || strstr(mutateeName,"_m32")) {
1404         // patch up file names based on alternate ABI (as necessary)
1405         if (!strstr(mutateeName, "_m32")) strcat(mutateeName,"_m32");
1406         strcat(libNameA,"_n32");
1407         strcat(libNameB,"_n32");
1408     }
1409
1410     // patch up the platform-specific filename extensions
1411 #if defined(i386_unknown_nt4_0)
1412     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
1413     strcat(libNameA,".dll");
1414     strcat(libNameB,".dll");
1415 #else
1416     strcat(libNameA,".so");
1417     strcat(libNameB,".so");
1418 #endif
1419
1420     int retval = mutatorMAIN(mutateeName, useAttach);
1421
1422     return retval;
1423 }
1424