This commit allows us to force the relocation of functions being
[dyninst.git] / dyninstAPI / tests / src / test3.C
1 // $Id: test3.C,v 1.23 2001/07/11 21:21:09 gurari Exp $
2 //
3 // libdyninst validation suite test #3
4 //    Author: Jeff Hollingsworth (6/18/99)
5 //
6
7 //  This program tests having multiple active mutatee processes.
8 //   
9 //  To run a subset of the tests, enter -run <test nums> on the command
10 //      line.
11 //
12 //  Naming conventions:
13 //      All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
14 //          XX is the test number
15 //          YY is the instance withing the test
16 //          func1_2 is the second function used in test case #1.
17 //
18
19 #include <stdio.h>
20 #include <string.h>
21 #ifdef i386_unknown_nt4_0
22 #include <windows.h>
23 #include <winbase.h>
24 #define unlink _unlink
25 #else
26 #include <unistd.h>
27 #endif
28
29 #include "BPatch.h"
30 #include "BPatch_Vector.h"
31 #include "BPatch_thread.h"
32 #include "BPatch_snippet.h"
33 #include "test_util.h"
34
35
36 int debugPrint = 0; // internal "mutator" tracing
37 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
38
39 bool forceRelocation = false;  // Force relocation upon instrumentation
40
41 const unsigned int MAX_MUTATEES = 32;
42 unsigned int Mutatees=3;
43
44 bool runAllTests = true;
45 const unsigned int MAX_TEST = 5;
46 bool passedTest[MAX_TEST+1];
47
48 template class BPatch_Vector<BPatch_variableExpr*>;
49
50 BPatch *bpatch;
51
52 static char *mutateeNameRoot = "test3.mutatee";
53
54 // control debug printf statements
55 #define dprintf if (debugPrint) printf
56
57 /**************************************************************************
58  * Error callback
59  **************************************************************************/
60
61 #define DYNINST_NO_ERROR -1
62
63 int expectError = DYNINST_NO_ERROR;
64
65 void errorFunc(BPatchErrorLevel level, int num, const char **params)
66 {
67     if (num == 0) {
68         // conditional reporting of warnings and informational messages
69         if (errorPrint) {
70             if (level == BPatchInfo)
71               { if (errorPrint > 1) printf("%s\n", params[0]); }
72             else
73                 printf("%s", params[0]);
74         }
75     } else {
76         // reporting of actual errors
77         char line[256];
78         const char *msg = bpatch->getEnglishErrorString(num);
79         bpatch->formatErrorString(line, sizeof(line), msg, params);
80         
81         if (num != expectError) {
82             printf("Error #%d (level %d): %s\n", num, level, line);
83         
84             // We consider some errors fatal.
85             if (num == 101) {
86                exit(-1);
87             }
88         }
89     }
90 }
91
92 /**************************************************************************
93  * Utility functions
94  **************************************************************************/
95
96 //
97 // Return a pointer to a string identifying a BPatch_procedureLocation
98 //
99 char *locationName(BPatch_procedureLocation l)
100 {
101     switch(l) {
102       case BPatch_entry:
103         return "entry";
104       case BPatch_exit:
105         return "exit";
106       case BPatch_subroutine:
107         return "call points";
108       case BPatch_longJump:
109         return "long jump";
110       case BPatch_allLocations:
111         return "all";
112       default:
113         return "<invalid BPatch_procedureLocation>";
114     };
115 }
116
117
118 //
119 // Insert "snippet" at the location "loc" in the function "inFunction."
120 // Returns the value returned by BPatch_thread::insertSnippet.
121 //
122 BPatchSnippetHandle *insertSnippetAt(BPatch_thread *appThread,
123         BPatch_image *appImage, char *inFunction, BPatch_procedureLocation loc,
124         BPatch_snippet &snippet, int testNo, char *testName)
125 {
126     // Find the point(s) we'll be instrumenting
127     BPatch_Vector<BPatch_point *> *points =
128         appImage->findProcedurePoint(inFunction, loc);
129
130     if (!points) {
131         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
132         fprintf(stderr, "    Unable to find point %s - %s\n",
133                 inFunction, locationName(loc));
134         exit(-1);
135     }
136
137     return appThread->insertSnippet(snippet, *points);
138 }
139
140 //
141 // Create a snippet that calls the function "funcName" with no arguments
142 //
143 BPatch_snippet *makeCallSnippet(BPatch_image *appImage, char *funcName,
144                                 int testNo, char *testName)
145 {
146     BPatch_function *call_func = appImage->findFunction(funcName);
147     if (call_func == NULL) {
148         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
149         fprintf(stderr, "    Unable to find function %s\n", funcName);
150         exit(1);
151     }
152
153     BPatch_Vector<BPatch_snippet *> nullArgs;
154     BPatch_snippet *ret = new BPatch_funcCallExpr(*call_func, nullArgs);
155
156     if (ret == NULL) {
157         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
158         fprintf(stderr, "    Unable to create snippet to call %s\n", funcName);
159         exit(1);
160     }
161
162     return ret;
163 }
164
165 //
166 // Insert a snippet to call function "funcName" with no arguments into the
167 // procedure "inFunction" at the points given by "loc."
168 //
169 BPatchSnippetHandle *insertCallSnippetAt(BPatch_thread *appThread,
170         BPatch_image *appImage, char *inFunction, BPatch_procedureLocation loc,
171         char *funcName, int testNo, char *testName)
172 {
173     BPatch_snippet *call_expr =
174         makeCallSnippet(appImage, funcName, testNo, testName);
175
176     BPatchSnippetHandle *ret = insertSnippetAt(appThread, appImage,
177                                                inFunction, loc, *call_expr,
178                                                testNo, testName);
179     if (ret == NULL) {
180         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
181         fprintf(stderr, "    Unable to insert snippet to call function %s\n",
182                 funcName);
183         exit(-1);
184     }
185
186     delete call_expr;
187     
188     return ret;
189 }
190
191 void MopUpMutatees(const unsigned int mutatees, BPatch_thread *appThread[])
192 {
193     unsigned int n=0;
194     dprintf("MopUpMutatees(%d)\n", mutatees);
195     for (n=0; n<mutatees; n++) {
196         if (appThread[n]) {
197             if (appThread[n]->terminateExecution()) {
198                 dprintf("Mutatee %d terminated (code=0x%x).\n",
199                         n, appThread[n]->terminationStatus());
200             } else {
201                 printf("Failed to mop up mutatee %d (pid=%d)!\n",
202                         n, appThread[n]->getPid());
203             }
204         } else {
205             printf("Mutatee %d already terminated?\n", n);
206         }
207     }
208     dprintf("MopUpMutatees(%d) done\n", mutatees);
209 }
210
211 /**************************************************************************
212  * Tests
213  **************************************************************************/
214
215 //
216 // Start Test Case #1 - create processes and process events from each
217 //     Just let them run a while, then kill them, no instrumentation added.
218 //
219 void mutatorTest1(char *pathname, BPatch *bpatch)
220 {
221     unsigned int n=0;
222     char *child_argv[5];
223     child_argv[n++] = pathname;
224     if (debugPrint) child_argv[n++] = "-verbose";
225     child_argv[n++] = "-run";
226     child_argv[n++] = "1";              // run test1 in mutatee
227     child_argv[n++] = NULL;
228
229     BPatch_thread *appThread[MAX_MUTATEES];
230
231     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
232
233     // Start the mutatees
234     for (n=0; n<Mutatees; n++) {
235         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
236         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
237         if (!appThread[n]) {
238             printf("*ERROR*: unable to create handle%d for executable\n", n);
239             printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
240             MopUpMutatees(n-1,appThread);
241             return;
242         }
243         dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
244     }
245
246     dprintf("Letting mutatee processes run a short while (10s).\n");
247     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
248
249     P_sleep(10);
250     dprintf("Terminating mutatee processes.\n");
251
252     unsigned int numTerminated=0;
253     for (n=0; n<Mutatees; n++) {
254         bool dead = appThread[n]->terminateExecution();
255         if (!dead || !(appThread[n]->isTerminated())) {
256             printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
257             printf("    mutatee process [%d] was not terminated\n", n);
258             //return;
259         }
260         numTerminated++;
261         int statusCode = appThread[n]->terminationStatus();
262         dprintf("Terminated mutatee [%d] returned status code 0x%x\n", n, statusCode);
263     }
264
265     if (numTerminated == Mutatees) {
266         printf("Passed Test #1 (simultaneous multiple-process management - terminate)\n");
267         passedTest[1] = true;
268     }
269 }
270
271 //
272 // Start Test Case #2 - create processes and process events from each
273 //     Just let them run to finish, no instrumentation added.
274 //
275 void mutatorTest2(char *pathname, BPatch *bpatch)
276 {
277     unsigned int n=0;
278     char *child_argv[5];
279     child_argv[n++] = pathname;
280     if (debugPrint) child_argv[n++] = "-verbose";
281     child_argv[n++] = "-run";
282     child_argv[n++] = "2";              // run test2 in mutatee
283     child_argv[n++] = NULL;
284
285     BPatch_thread *appThread[MAX_MUTATEES];
286
287     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
288
289     // Start the mutatees
290     for (n=0; n<Mutatees; n++) {
291         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
292         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
293         if (!appThread[n]) {
294             printf("*ERROR*: unable to create handle%d for executable\n", n);
295             printf("**Failed** test #2 (simultaneous multiple-process management - exit)\n");
296             MopUpMutatees(n-1,appThread);
297             return;
298         }
299         dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
300     }
301     dprintf("Letting %d mutatee processes run.\n", Mutatees);
302     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
303
304     unsigned int numTerminated=0;
305     bool terminated[MAX_MUTATEES];
306     for (n=0; n<Mutatees; n++) terminated[n]=false;
307
308     // monitor the mutatee termination reports
309     while (numTerminated < Mutatees) {
310         bpatch->waitForStatusChange();
311         for (n=0; n<Mutatees; n++)
312             if (!terminated[n] && (appThread[n]->isTerminated())) {
313                 dprintf("Mutatee %d termination received (code=0x%x).\n",
314                         n, appThread[n]->terminationStatus());
315                 terminated[n]=true;
316                 numTerminated++;
317             }
318     }
319
320     if (numTerminated == Mutatees) {
321         printf("Passed Test #2 (simultaneous multiple-process management - exit)\n");
322         passedTest[2] = true;
323     }
324 }
325
326 //
327 // read the result code written to the file test3.out.<pid> and return it
328 //
329 int readResult(int pid)
330 {
331     int ret;
332     FILE *fp;
333     char filename[80];
334
335     sprintf(filename, "test3.out.%d", pid);
336     fp = fopen(filename, "r");
337     if (!fp) {
338         printf("ERROR: unable to open output file %s\n", filename);
339         return -1;
340     }
341     fscanf(fp, "%d\n", &ret);
342     fclose(fp);
343     // don't need the file any longer so delete it now
344     unlink(filename);
345
346     return ret;
347 }
348
349 //
350 // Start Test Case #3 - create processes and insert different code into
351 //     each one.  The code sets a global variable which the mutatee then
352 //     writes to a file.  After all mutatees exit, the mutator reads the
353 //     files to verify that the correct code ran in each mutatee.
354 //     The first mutator should write a 1 to the file, the second a 2, etc.
355 //     If no code is patched into the mutatees, the value is 0xdeadbeef.
356 //
357 void mutatorTest3(char *pathname, BPatch *bpatch)
358 {
359     unsigned int n=0;
360     char *child_argv[5];
361     child_argv[n++] = pathname;
362     if (debugPrint) child_argv[n++] = "-verbose";
363     child_argv[n++] = "-run";
364     child_argv[n++] = "3";              // run test3 in mutatee
365     child_argv[n++] = NULL;
366
367     int pid[MAX_MUTATEES];
368     BPatch_thread *appThread[MAX_MUTATEES];
369
370     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
371
372     // Start the mutatees
373     for (n=0; n<Mutatees; n++) {
374         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
375         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
376         if (!appThread[n]) {
377             printf("*ERROR*: unable to create handle%d for executable\n", n);
378             printf("**Failed** test #3 (instrument multiple processes)\n");
379             MopUpMutatees(n-1,appThread);
380             return;
381         }
382         pid[n] = appThread[n]->getPid();
383         dprintf("Mutatee %d started, pid=%d\n", n, pid[n]);
384     }
385
386     // Instrument mutatees
387     for (n=0; n<Mutatees; n++) {
388         dprintf("Instrumenting %d/%d\n", n, Mutatees);
389
390         const char *Func="func3_1";
391         const char *Var="test3ret";
392         const char *Call="call3_1";
393         BPatch_image *img = appThread[n]->getImage();
394         BPatch_Vector<BPatch_point *> *point =
395             img->findProcedurePoint(Func, BPatch_entry);
396         if (!point || (*point).size() == 0) {
397             printf("  Unable to find entry point to \"%s\".\n", Func);
398             printf("**Failed** test #3 (instrument multiple processes)\n");
399             MopUpMutatees(Mutatees,appThread);
400             return;
401         }
402         BPatch_variableExpr *var = img->findVariable(Var);
403         if (var == NULL) {
404             printf("  Unable to find variable \"%s\".\n", Var);
405             printf("**Failed** test #3 (instrument multiple processes)\n");
406             MopUpMutatees(Mutatees,appThread);
407             return;
408         }
409         BPatch_function *callFunc = img->findFunction(Call);
410         if (callFunc == NULL) {
411             printf("  Unable to find target function \"%s\".\n", Call);
412             printf("**Failed** test #3 (instrument multiple processes)\n");
413             MopUpMutatees(Mutatees,appThread);
414             return;
415         }
416         // start with a simple snippet
417         BPatch_arithExpr snip(BPatch_assign, *var, BPatch_constExpr(n));
418         BPatchSnippetHandle *inst = appThread[n]->insertSnippet(snip, *point);
419         if (inst == NULL) {
420             printf("  Failed to insert simple snippet.\n");
421             printf("**Failed** test #3 (instrument multiple processes)\n");
422             MopUpMutatees(Mutatees,appThread);
423             return;
424         }
425
426         // now add a call snippet
427         BPatch_Vector<BPatch_snippet *> callArgs;
428         BPatch_constExpr arg1(2); callArgs.push_back(&arg1);
429         BPatch_constExpr arg2(n); callArgs.push_back(&arg2);
430         BPatch_funcCallExpr callExpr(*callFunc, callArgs);
431         BPatchSnippetHandle *call = 
432                 appThread[n]->insertSnippet(callExpr, *point);
433         if (call == NULL) {
434             printf("  Failed to insert call snippet.\n");
435             printf("**Failed** test #3 (instrument multiple processes)\n");
436             MopUpMutatees(Mutatees,appThread);
437             return;
438         }
439     }
440
441     dprintf("Letting %d mutatee processes run.\n", Mutatees);
442     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
443
444     unsigned int numTerminated=0;
445     bool terminated[MAX_MUTATEES];
446     for (n=0; n<Mutatees; n++) terminated[n]=false;
447
448     // monitor the mutatee termination reports
449     while (numTerminated < Mutatees) {
450         bpatch->waitForStatusChange();
451         for (n=0; n<Mutatees; n++)
452             if (!terminated[n] && (appThread[n]->isTerminated())) {
453                 dprintf("Mutatee %d termination received (code=0x%x).\n",
454                         n, appThread[n]->terminationStatus());
455                 terminated[n]=true;
456                 numTerminated++;
457             }
458     }
459
460     // now read the files to see if the value is what is expected
461     bool allCorrect=true;
462     int ret[MAX_MUTATEES];
463     for (n=0; n<Mutatees; n++) {
464         ret[n]=readResult(pid[n]);
465         if (ret[n] != (int)n) {
466             printf("    mutatee process %d produced %d, not %d\n",
467                 pid[n], ret[n], n);
468             allCorrect=false;
469         } else {
470             dprintf("    mutatee process %d produced expected value %d\n", 
471                 pid[n], ret[n]);
472         }
473     }
474
475     if (allCorrect) {
476         printf("Passed Test #3 (instrument multiple processes)\n");
477         passedTest[3] = true;
478     } else {
479         printf("**Failed** test #3 (instrument multiple processes)\n");
480     }
481 }
482
483 //
484 // Start Test Case #4 - create one process, wait for it to exit.  Then 
485 //     create a second one and wait for it to exit.  Repeat as required.
486 //
487 void mutatorTest4(char *pathname, BPatch *bpatch)
488 {
489     unsigned int n=0;
490     char *child_argv[5];
491     child_argv[n++] = pathname;
492     if (debugPrint) child_argv[n++] = "-verbose";
493     child_argv[n++] = "-run";
494     child_argv[n++] = "2";              // run test2 in mutatee
495     child_argv[n++] = NULL;
496
497     BPatch_thread *appThread;
498
499     for (n=0; n<Mutatees; n++) {
500         // Start the mutatee
501         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
502         appThread = bpatch->createProcess(pathname, child_argv, NULL);
503         if (!appThread) {
504             printf("*ERROR*: unable to create handle%d for executable\n", n);
505             printf("**Failed** Test #4 (sequential multiple-process management - exit)\n");
506             return;
507         }
508         dprintf("Mutatee %d started, pid=%d\n", n, appThread->getPid());
509
510         appThread->continueExecution();
511
512         while (!appThread->isTerminated())
513             bpatch->waitForStatusChange();
514
515         dprintf("Mutatee %d termination received (code=0x%x).\n",
516             n, appThread->terminationStatus());
517     }
518
519     printf("Passed Test #4 (sequential multiple-process management - exit)\n");
520     passedTest[4] = true;
521 }
522
523
524 //
525 // Start Test Case #5 - create one process, wait for it to exit.  Then 
526 //     create a second one and wait for it to exit.  Repeat as required.
527 //     Differs from test 3 in that the mutatee processes terminate with
528 //     abort rather than exit.
529 //
530 void mutatorTest5(char *pathname, BPatch *bpatch)
531 {
532     unsigned int n=0;
533     char *child_argv[5];
534     child_argv[n++] = pathname;
535     if (debugPrint) child_argv[n++] = "-verbose";
536     child_argv[n++] = "-run";
537     child_argv[n++] = "5";              // run test5 in mutatee
538     child_argv[n++] = NULL;
539
540     BPatch_thread *appThread;
541
542     for (n=0; n<Mutatees; n++) {
543         // Start the mutatee
544         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
545         appThread = bpatch->createProcess(pathname, child_argv, NULL);
546         if (!appThread) {
547             printf("*ERROR*: unable to create handle%d for executable\n", n);
548             printf("**Failed** Test #5 (sequential multiple-process management - abort)\n");
549             return;
550         }
551         dprintf("Mutatee %d started, pid=%d\n", n, appThread->getPid());
552
553         appThread->continueExecution();
554
555         while (!appThread->isTerminated())
556             bpatch->waitForStatusChange();
557
558         dprintf("Mutatee %d termination received (code=0x%x).\n",
559             n, appThread->terminationStatus());
560     }
561
562     printf("Passed Test #5 (sequential multiple-process management - abort)\n");
563     passedTest[5] = true;
564 }
565
566 int main(unsigned int argc, char *argv[])
567 {
568     bool N32ABI=false;
569     char mutateeName[128];
570     char libRTname[256];
571     bool runTest[MAX_TEST+1];           // should we run a particular test
572
573     strcpy(mutateeName,mutateeNameRoot);
574     libRTname[0]='\0';
575
576     if (!getenv("DYNINSTAPI_RT_LIB")) {
577          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
578 #if defined(i386_unknown_nt4_0)
579                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
580 #else
581                  "    set it to the full pathname of libdyninstAPI_RT\n");   
582          exit(-1);
583 #endif
584     } else
585          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
586
587     unsigned int i;
588     // by default run all tests
589     for (i=1; i <= MAX_TEST; i++) {
590         runTest[i] = true;
591         passedTest[i] = false;
592     }
593
594     for (i=1; i < argc; i++) {
595         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
596         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
597         if (strncmp(argv[i], "-verbose", 2) == 0) {
598             debugPrint = 1;
599         } else if (!strcmp(argv[i], "-V")) {
600             fprintf (stdout, "%s\n", V_libdyninstAPI);
601             if (libRTname[0]) 
602                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
603             fflush(stdout);
604         } else if (strncmp(argv[i], "-plurality", 2) == 0) {
605             Mutatees = atoi(argv[++i]);
606             if (Mutatees > MAX_MUTATEES) {
607                 printf("Limiting plurality to maximum of %d!\n", MAX_MUTATEES);
608                 Mutatees = MAX_MUTATEES;
609             } else if (Mutatees <= 1) {
610                 printf("Plurality of at least 2 required for these tests!\n");
611                 exit(-1);
612             }
613             dprintf ("%d mutatees to be used for each test.\n", Mutatees);
614         } else if (!strcmp(argv[i], "-skip")) {
615             unsigned int j;
616             runAllTests = false;
617             for (j=i+1; j < argc; j++) {
618                 unsigned int testId;
619                 if ((testId = atoi(argv[j]))) {
620                     if ((testId > 0) && (testId <= MAX_TEST)) {
621                         runTest[testId] = false;
622                     } else {
623                         printf("invalid test %d requested\n", testId);
624                         exit(-1);
625                     }
626                 } else {
627                     // end of test list
628                     break;
629                 }
630             }
631             i=j-1;
632         } else if (!strcmp(argv[i], "-run")) {
633             unsigned int j;
634             runAllTests = false;
635             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
636             for (j=i+1; j < argc; j++) { 
637                 unsigned int testId;
638                 if ((testId = atoi(argv[j]))) {
639                     if ((testId > 0) && (testId <= MAX_TEST)) {
640                         dprintf("test %d requested\n", testId);
641                         runTest[testId] = true;
642                     } else {
643                         printf("invalid test %d requested\n", testId);
644                         exit(-1);
645                     }
646                 } else {
647                     // end of test list
648                     break;
649                 }
650             }
651             i=j-1;
652         } else if (!strcmp(argv[i], "-mutatee")) {
653             i++;
654             if (*argv[i]=='_')
655                 strcat(mutateeName,argv[i]);
656             else
657                 strcpy(mutateeName,argv[i]);
658 #if defined(i386_unknown_nt4_0) || defined(i386_unknown_linux2_0) || defined(sparc_sun_solaris2_4)
659         } else if (!strcmp(argv[i], "-relocate")) {
660             forceRelocation = true;
661 #endif
662 #if defined(mips_sgi_irix6_4)
663         } else if (!strcmp(argv[i], "-n32")) {
664             N32ABI=true;
665 #endif
666         } else {
667             fprintf(stderr, "Usage: test3 "
668                     "[-V] [-verbose] "
669 #if defined(mips_sgi_irix6_4)
670                     "[-n32] "
671 #endif
672                     "[-mutatee <test3.mutatee>] "
673                     "[-plurality #] "
674                     "[-run <test#> <test#> ...] "
675                     "[-skip <test#> <test#> ...]\n");
676             fprintf(stderr, "%d subtests\n", MAX_TEST);
677             exit(-1);
678         }
679     }
680
681     if (!runAllTests) {
682         printf("Running Tests: ");
683         for (unsigned int j=1; j <= MAX_TEST; j++) {
684             if (runTest[j]) printf("%d ", j);
685         }
686         printf("\n");
687     }
688
689     // patch up the default compiler in mutatee name (if necessary)
690     if (!strstr(mutateeName, "_"))
691 #if defined(i386_unknown_nt4_0)
692         strcat(mutateeName,"_VC");
693 #else
694         strcat(mutateeName,"_gcc");
695 #endif
696     if (N32ABI || strstr(mutateeName,"_n32")) {
697         // patch up file names based on alternate ABI (as necessary)
698         if (!strstr(mutateeName, "_n32")) strcat(mutateeName,"_n32");
699     }
700     // patch up the platform-specific filename extensions
701 #if defined(i386_unknown_nt4_0)
702     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
703 #endif
704
705     // Create an instance of the BPatch library
706     bpatch = new BPatch;
707
708     // Force functions to be relocated
709     if (forceRelocation) {
710       bpatch->setForcedRelocation_NP(true);
711     }
712
713 #if defined (sparc_sun_solaris2_4)
714     // we use some unsafe type operations in the test cases.
715     bpatch->setTypeChecking(false);
716 #endif
717
718     // Register a callback function that prints any error messages
719     bpatch->registerErrorCallback(errorFunc);
720
721     if (runTest[1]) mutatorTest1(mutateeName, bpatch);
722     if (runTest[2]) mutatorTest2(mutateeName, bpatch);
723     if (runTest[3]) mutatorTest3(mutateeName, bpatch);
724     if (runTest[4]) mutatorTest4(mutateeName, bpatch);
725     if (runTest[5]) mutatorTest5(mutateeName, bpatch);
726
727     unsigned int testsFailed = 0;
728     for (i=1; i <= MAX_TEST; i++) {
729         if (runTest[i] && !passedTest[i]) testsFailed++;
730     }
731
732     if (!testsFailed) {
733         if (runAllTests) {
734             printf("All tests passed\n");
735         } else {
736             printf("All requested tests passed\n");
737         }
738     } else {
739         printf("**Failed** %d test%c\n",testsFailed,(testsFailed>1)?'s':' ');
740     }
741
742     return (testsFailed ? 127 : 0);
743 }