C/C++ determination/reporting.
[dyninst.git] / dyninstAPI / tests / src / test2.C
1 // $Id: test2.C,v 1.38 2000/06/20 21:45:57 wylie Exp $
2 //
3 // libdyninst validation suite test #2
4 //    Author: Jeff Hollingsworth (7/10/97)
5 //
6
7 //  This program tests the error features of the dyninst API.  
8 //      The mutatee that goes with this file is test2.mutatee.c
9 //      
10 //  Naming conventions:
11 //      All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
12 //          XX is the test number
13 //          YY is the instance withing the test
14 //          func1_2 is the second function used in test case #1.
15 //
16
17 #include <stdio.h>
18 #include <signal.h>
19 #include <string.h>
20 #ifdef i386_unknown_nt4_0
21 #include <io.h>
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #else
25 #include <unistd.h>
26 #include <errno.h>
27 #include <sys/wait.h>
28 #endif
29
30 #include "BPatch.h"
31 #include "BPatch_Vector.h"
32 #include "BPatch_thread.h"
33 #include "BPatch_snippet.h"
34 #include "test_util.h"
35 #include "test2.h"
36
37 #ifdef i386_unknown_nt4_0
38 #define access _access
39 #define unlink _unlink
40 #define F_OK 0
41 #endif
42
43 BPatch_thread *mutatorMAIN(char *path);
44 extern "C" const char V_libdyninstAPI[];
45
46 bool useAttach = false;
47 int debugPrint = 0; // internal "mutator" tracing
48 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
49 bool expectErrors = false;
50 bool gotError = false;
51
52 int mutateeCplusplus = 0;
53 bool runAllTests = true;
54 const unsigned int MAX_TEST = 14;
55 bool runTest[MAX_TEST+1];
56 bool passedTest[MAX_TEST+1];
57
58 BPatch *bpatch;
59
60 static char *mutateeNameRoot = "test2.mutatee";
61 char mutateeName[128];
62
63 // control debug printf statements
64 #define dprintf if (debugPrint) printf
65
66 //
67 // Test #1 - run an executable that does not exist
68 //      Attempt to run a program file that does not exist.  Should return a
69 //      null values from createProcess (called via mutatorMAIN)
70 //
71
72 void test1()
73 {
74     if (useAttach) {
75         printf("Skipping test #1 (run an executable that does not exist)\n");
76         printf("    not relevant with -attach option\n");
77         passedTest[1] = true;
78     } else {
79         // try to run a program that does not exist
80         gotError = false;
81         BPatch_thread *ret = mutatorMAIN("./noSuchFile");
82         if (ret || !gotError) {
83             printf("**Failed** test #1 (run an executable that does not exist)\n");
84             if (ret)
85                 printf("    created a thread handle for a non-existant file\n");
86             if (!gotError)
87                 printf("    the error callback should have been called but wasn't\n");
88         } else {
89             printf("Passed test #1 (run an executable that does not exist)\n");
90             passedTest[1] = true;
91         }
92     }
93 }
94
95 //
96 // Test #2 - try to execute a file that is not a valid program
97 //      Try to run a createProcess on a file that is not an executable file 
98 //      (via mutatorMAIN).
99 //
100 void test2()
101 {
102     if (useAttach) {
103         printf("Skipping test #2 (try to execute a file that is not a valid program)\n");
104         printf("    not relevant with -attach option\n");
105         passedTest[2] = true;
106         return;
107     }
108
109     // try to run a files that is not a valid program
110     gotError = false;
111 #ifdef i386_unknown_nt4_0
112     BPatch_thread *ret = mutatorMAIN("nul:");
113 #else
114     BPatch_thread *ret = mutatorMAIN("/dev/null");
115 #endif
116     if (ret || !gotError) {
117         printf("**Failed** test #2 (try to execute a file that is not a valid program)\n");
118         if (ret)
119             printf("    created a thread handle for invalid executable\n");
120         if (!gotError)
121             printf("    the error callback should have been called but wasn't\n");
122     } else {
123         printf("Passed test #2 (try to execute a file that is not a valid program)\n");
124         passedTest[2] = true;
125     }
126 }
127
128 //
129 // Test #3 - attach to an invalid pid
130 //      Try to attach to an invalid pid number (65539).
131 //
132 void test3()
133 {
134 #if defined(sparc_sun_sunos4_1_3)
135     printf("Skipping test #3 (attach to an invalid pid)\n");
136     printf("    attach is not supported on this platform\n");
137     passedTest[3] = true;
138 #else
139     // attach to an an invalid pid
140     gotError = false;
141     BPatch_thread *ret = bpatch->attachProcess(mutateeName, 65539);
142     if (ret || !gotError) {
143         printf("**Failed** test #3 (attach to an invalid pid)\n");
144         if (ret)
145             printf("    created a thread handle for invalid executable\n");
146         if (!gotError)
147             printf("    the error callback should have been called but wasn't\n");
148     } else {
149         printf("Passed test #3 (attach to an invalid pid)\n");
150         passedTest[3] = true;
151     }
152 #endif
153 }
154
155 //
156 // Test #4 - attach to a protected pid
157 //      Try to attach to a "protected pid" number.  This should test the
158 //      procfs attach to a pid that we don't have "rw" access to. The pid
159 //      selected is pid #1 which is a OS kernel process that user processes
160 //      can't read or write.
161 //
162
163 void test4()
164 {
165 #if defined(sparc_sun_sunos4_1_3)
166     printf("Skipping test #4 (attach to a protected pid)\n");
167     printf("    attach is not supported on this platform\n");
168     passedTest[4] = true;
169 #else
170     // attach to an a protected pid
171     gotError = false;
172     BPatch_thread *ret = bpatch->attachProcess(mutateeName, 1);
173     if (ret || !gotError) {
174         printf("**Failed** test #4 (attach to a protected pid)\n");
175         if (ret)
176             printf("    created a thread handle for invalid executable\n");
177         if (!gotError)
178             printf("    the error callback should have been called but wasn't\n");
179     } else {
180         printf("Passed test #4 (attach to a protected pid)\n");
181         passedTest[4] = true;
182     }
183 #endif
184 }
185
186 //
187 // Test #5 - look up nonexistent function)
188 //      Try to call findFunction on a function that is not defined for the
189 //      process.
190 //
191 void test5(BPatch_image *img)
192 {
193     gotError = false;
194     expectErrors = true; // test #5 causes error #100 (Unable to find function)
195     BPatch_function *func = img->findFunction("NoSuchFunction");
196     expectErrors = false;
197     if (func || !gotError) {
198         printf("**Failed** test #5 (look up nonexistent function)\n");
199         if (func)
200             printf("    non-null for findFunction on non-existant func\n");
201         if (!gotError)
202             printf("    the error callback should have been called but wasn't\n");
203     } else {
204         printf("Passed test #5 (look up nonexistent function)\n");
205         passedTest[5] = true;
206     }
207 }
208
209 //
210 // Test #6 - load a dynamically linked library from the mutatee
211 //      Have the mutatee use dlopen (or NT loadLibrary) to load a shared library
212 //      into itself.  We should then be able to see the new functions from the
213 //      library via getModules.
214 //
215
216 void test6(BPatch_thread *thread, BPatch_image *img)
217 {
218 #if !defined(sparc_sun_solaris2_4) \
219  && !defined(i386_unknown_solaris2_5) \
220  && !defined(i386_unknown_linux2_0) \
221  && !defined(mips_sgi_irix6_4) \
222  && !defined(alpha_dec_osf4_0)
223     printf("Skipping test #6 (load a dynamically linked library from the mutatee)\n");
224     printf("    feature not implemented on this platform\n");
225     passedTest[6] = true;
226 #else
227
228     bool found = false;
229
230     // see if the dlopen happended.
231     char match2[256];
232     sprintf(match2, "%s_module", TEST_DYNAMIC_LIB);
233     BPatch_Vector<BPatch_module *> *m = img->getModules();
234     for (unsigned i=0; i < m->size(); i++) {
235             char name[80];
236             (*m)[i]->getName(name, sizeof(name));
237             if (strcmp(name, TEST_DYNAMIC_LIB) == 0 ||
238                 strcmp(name, match2) == 0) {
239                 found = true;
240                 break;
241             }
242     }
243     if (found) {
244         printf("Passed test #6 (load a dynamically linked library from the mutatee)\n");
245         passedTest[6] = true;
246     } else {
247         printf("**Failed** test #6 (load a dynamically linked library from the mutatee)\n");
248         printf("    image::getModules() did not indicate that the library had been loaded\n");
249     }
250 #endif
251 }
252
253 //
254 // Test #7 - load a dynamically linked library from the mutator
255 //      Have the mutator "force" a load of a library into the mutatee.
256 //      We then check that the new symbols are found in the thread via the
257 //      getModules method.
258 //
259 void test7(BPatch_thread *thread, BPatch_image *img)
260 {
261 #if !defined(sparc_sun_solaris2_4) \
262  && !defined(i386_unknown_solaris2_5) \
263  && !defined(i386_unknown_linux2_0) \
264  && !defined(mips_sgi_irix6_4)
265     printf("Skipping test #7 (load a dynamically linked library from the mutator)\n");
266     printf("    feature not implemented on this platform\n");
267     passedTest[7] = true;
268 #else
269
270     if (!thread->loadLibrary(TEST_DYNAMIC_LIB2)) {
271         printf("**Failed** test #7 (load a dynamically linked library from the mutator)\n");
272         printf("    BPatch_thread::loadLibrary returned an error\n");
273     } else {
274         // see if it worked
275         bool found = false;
276         char match2[256];
277         sprintf(match2, "%s_module", TEST_DYNAMIC_LIB2);
278         BPatch_Vector<BPatch_module *> *m = img->getModules();
279         for (int i=0; i < m->size(); i++) {
280                 char name[80];
281                 (*m)[i]->getName(name, sizeof(name));
282                 if (strcmp(name, TEST_DYNAMIC_LIB2) == 0 ||
283                     strcmp(name, match2) == 0) {
284                     found = true;
285                     break;
286                 }
287         }
288         if (found) {
289             printf("Passed test #7 (load a dynamically linked library from the mutator)\n");
290             passedTest[7] = true;
291         } else {
292             printf("**Failed** test #7 (load a dynamically linked library from the mutator)\n");
293             printf("    image::getModules() did not indicate that the library had been loaded\n");
294         }
295     }
296 #endif
297 }
298
299 //
300 // Start of test #8 - BPatch_breakPointExpr
301 //
302 //   There are two parts to the mutator side of this test.  The first part
303 //     (test8a) inserts a BPatch_breakPointExpr into the entry point of
304 //     the function test8_1.  The secon pat (test8b) waits for this breakpoint
305 //     to be reached.  The first part is run before the processes is continued
306 //     (i.e. just after process creation or attach).
307 //
308 void test8a(BPatch_thread *appThread, BPatch_image *appImage)
309 {
310     /*
311      * Instrument a function with a BPatch_breakPointExpr.
312      */
313     BPatch_Vector<BPatch_point*> *points =
314         appImage->findProcedurePoint("func8_1", BPatch_entry);
315     if (points == NULL) {
316         printf("**Failed** test #8 (BPatch_breakPointExpr)\n");
317         printf("    unable to locate function \"func8_1\".\n");
318         exit(1);
319     }
320
321     BPatch_breakPointExpr bp;
322
323     if (appThread->insertSnippet(bp, *points) == NULL) {
324         printf("**Failed** test #8 (BPatch_breakPointExpr)\n");
325         printf("    unable to insert breakpoint snippet\n");
326         exit(1);
327     }
328 }
329
330 void test8b(BPatch_thread *thread)
331 {
332     // Wait for process to finish
333     waitUntilStopped(bpatch, thread, 8, "BPatch_breakPointExpr");
334
335     // waitUntilStopped would not return is we didn't stop
336     printf("Passed test #8 (BPatch_breakPointExpr)\n");
337     passedTest[8] = true;
338 }
339
340 //
341 // Test #9 - dump core but do not terminate
342 //      This test dumps the core file from the mutatee process, without having
343 //      the process terminate exuection.  It looks for the creation of the file
344 //      "mycore" in the current directory.
345 //      
346 void test9(BPatch_thread *thread)
347 {
348 #if !defined(sparc_sun_sunos4_1_3) \
349  && !defined(sparc_sun_solaris2_4) \
350  && !defined(mips_sgi_irix6_4)
351     printf("Skipping test #9 (dump core but do not terminate)\n");
352     printf("    BPatch_thread::dumpCore not implemented on this platform\n");
353     passedTest[9] = true;
354 #else
355     // dump core, but do not terminate.
356     // this doesn't seem to do anything - jkh 7/12/97
357     if (access("mycore", F_OK) == 0) {
358         dprintf("File \"mycore\" exists.  Deleting it.\n");
359         if (unlink("mycore") != 0) {
360             printf("Couldn't delete the file \"mycore\".  Exiting.\n");
361             exit(-1);
362         }
363     }
364
365     gotError = false;
366     thread->dumpCore("mycore", true);
367     bool coreExists = (access("mycore", F_OK) == 0);
368     if (gotError || !coreExists) {
369         printf("**Failed** test #9 (dump core but do not terminate)\n");
370         if (gotError)
371             printf("    error reported by dumpCore\n");
372         if (!coreExists)
373             printf("    the core file wasn't written\n");
374     } else {
375         unlink("mycore");
376         printf("Passed test #9 (dump core but do not terminate)\n");
377         passedTest[9] = true;
378     }
379 #endif
380 }
381
382 //
383 // Test #10 - dump image
384 //      This test dumps out the modified program file.  Note: only the 
385 //      modified executable is written, any shared libraries that have been
386 //      instrumented are not written.  In addition, the current dyninst
387 //      shared library is *NOT* written either.  Thus the results image is
388 //      really only useful for checking the state of instrumentation code
389 //      via gdb. It will crash if you try to run it.
390 //
391 void test10(BPatch_thread *thread)
392 {
393 #if !defined(rs6000_ibm_aix4_1) \
394  && !defined(sparc_sun_sunos4_1_3) \
395  && !defined(sparc_sun_solaris2_4) \
396  && !defined(i386_unknown_linux2_0) \
397  && !defined(mips_sgi_irix6_4) \
398  && !defined(alpha_dec_osf4_0)
399     printf("Skipping test #10 (dump image)\n");
400     printf("    BPatch_thread::dumpImage not implemented on this platform\n");
401     passedTest[10] = true;
402 #else
403     // dump image
404     if (access("myimage", F_OK) == 0) {
405         dprintf("File \"myimage\" exists.  Deleting it.\n");
406         if (unlink("myimage") != 0) {
407             printf("Couldn't delete the file \"myimage\".  Exiting.\n");
408             exit(-1);
409         }
410     }
411
412     gotError = false;
413     thread->dumpImage("myimage");
414     bool imageExists = (access("myimage", F_OK) == 0);
415     if (gotError || !imageExists) {
416         printf("**Failed** test #10 (dump image)\n");
417         if (gotError)
418             printf("    error reported by dumpImage\n");
419         if (!imageExists)
420             printf("    the image file wasn't written\n");
421     } else {
422         printf("Passed test #10 (dump image)\n");
423         unlink("myimage");
424         passedTest[10] = true;
425     }
426 #endif
427 }
428
429 //
430 // Test 11 - getDisplacedInstructions
431 //      This function tests the getDisplacedInstructions instructions methods.
432 //      Currently this tests is only enabled on AIX platforms.
433 //
434 void test11(BPatch_thread * /*appThread*/, BPatch_image *appImage)
435 {
436 #if !defined(rs6000_ibm_aix4_1)
437     // Test getDisplacedInstructions
438     printf("Skipping test #11 (getDisplacedInstructions)\n");
439     printf("         - not implemented on this platform\n");
440 #else
441     BPatch_Vector<BPatch_point*> *points =
442         appImage->findProcedurePoint("func11_1", BPatch_entry);
443     if (points == NULL) {
444         printf("**Failed** test #11 (getDisplacedInstructions)\n");
445         printf("    unable to locate function \"func11_1\".\n");
446         return;
447     }
448
449     char buf[128];
450     memset(buf, 128, 0);
451     int nbytes = (*points)[0]->getDisplacedInstructions(128, buf);
452     if (nbytes < 0 || nbytes > 128) {
453         printf("**Failed** test #11 (getDisplacedInstructions)\n");
454         printf("    getDisplacedInstructions returned a strange number of bytes (%d)\n", nbytes);
455         return;
456     }
457     int i;
458     for (i = 0; i < nbytes; i++) {
459         if (buf[i] != 0) break;
460     }
461     if (i == nbytes) {
462         printf("**Failed** test #11 (getDisplacedInstructions)\n");
463         printf("    getDisplacedInstructions doesn't seem to have returned any instructions\n");
464         return;
465     }
466     printf("Passed test #11 (getDisplacedInstructions)\n");
467 #endif
468     passedTest[11] = true;
469 }
470
471 //
472 // Test #12 - BPatch_point query funcs
473 //      This tests the BPatch_point functions that supply information about
474 //      an inst. point:
475 //              getAddress - should return the address of the point
476 //              usesTrap_NP - returns true of the point requires a trap
477 //                      instruction.
478
479 void test12(BPatch_thread *appThread, BPatch_image *appImage)
480 {
481
482     BPatch_Vector<BPatch_point*> *points =
483         appImage->findProcedurePoint("func12_1", BPatch_entry);
484     
485     if (!points) {
486         printf("**Failed** test #12 (BPatch_point query funcs)\n");
487         printf("    unable to locate function \"func12_1\".\n");
488         exit(1);
489     }
490
491     void *addr = (*points)[0]->getAddress();
492
493     bool trapFlag = (*points)[0]->usesTrap_NP();
494
495     printf("Passed test #12 (BPatch_point query funcs)\n");
496     passedTest[12] = true;
497 }
498
499 //
500 // Test 13 - Look through the thread list and make sure the thread has
501 //    been deleted as required.
502 //
503 void test13(BPatch_thread *thread)
504 {
505     bool failed_this = false;
506     BPatch_Vector<BPatch_thread *> *threads = bpatch->getThreads();
507     for (int i=0; i < threads->size(); i++) {
508         if ((*threads)[i] == thread) {
509             printf("**Failed** test #13 (delete thread)\n"); 
510             printf("    thread %d was deleted, but getThreads found it\n",
511                 thread->getPid());
512             failed_this = true;
513         }
514     }
515
516     if (!failed_this) {
517         printf("Passed test #13 (delete thread)\n");
518         passedTest[13] = true;
519     }
520 }
521
522 //
523 // Test 14 - Test process management
524 //      createThread
525 //      continueThread
526 //      terminateThread
527 //
528 void test14()
529 {
530     BPatch_thread *ret;
531
532     // Now test forking.
533     char *child_argv[4];
534
535     child_argv[0] = mutateeName;
536     child_argv[1] = "-fork";
537     child_argv[2] = NULL;
538     ret = bpatch->createProcess(mutateeName, child_argv);
539
540     if (!ret) {
541         printf("**Failed** test #14 (process mgmnt. tests)\n"); // LAST TEST
542         printf("    unable to create the new process\n");
543         return;
544     }
545
546     if (ret->isStopped()) ret->continueExecution();
547
548     bool dead = ret->terminateExecution();
549     if (!dead) {
550         printf("**Failed** test #14 (process mgmnt. tests)\n"); // LAST TEST
551         printf("    unable to terminate the new process\n");
552         return;
553     }
554
555     int statusCode = ret->terminationStatus();
556     dprintf("Terminated mutatee returned status code 0x%x\n", statusCode);
557
558     printf("Passed test #14 (process mgmnt. tests)\n");
559     passedTest[14] = true;
560     return;
561 }
562
563 BPatch_thread *mutatorMAIN(char *pathname)
564 {
565     BPatch_thread *appThread;
566
567     // Start the mutatee
568     dprintf("Starting \"%s\"\n", pathname);
569
570     char *child_argv[MAX_TEST+4];
571    
572     int n = 0;
573     child_argv[n++] = pathname;
574     if (debugPrint) child_argv[n++] = "-verbose";
575
576     if (!runAllTests) {
577         child_argv[n++] = "-run";
578         for (unsigned int j=0; j <= MAX_TEST; j++) {
579             if (runTest[j]) {
580                 char str[5];
581                 sprintf(str, "%d", j);
582                 child_argv[n++] = strdup(str);
583             }
584         }
585     }
586
587     child_argv[n] = NULL;
588
589     if (useAttach) {
590         int pid = startNewProcessForAttach(pathname, child_argv);
591         if (pid < 0 && !expectErrors) {
592             printf("*ERROR*: unable to start tests due to error starting mutatee process\n");
593             exit(-1);
594         } else {
595             dprintf("New mutatee process pid %d started; attaching...\n", pid);
596         }
597         P_sleep(1); // let the mutatee catch its breath for a moment
598         appThread = bpatch->attachProcess(pathname, pid);
599     } else {
600         appThread = bpatch->createProcess(pathname, child_argv);
601     }
602
603     return appThread;
604 }
605
606 void errorFunc(BPatchErrorLevel level, int num, const char **params)
607 {
608     if (num == 0) {
609         // conditional reporting of warnings and informational messages
610         if (errorPrint) {
611             if (level == BPatchInfo)
612               { if (errorPrint > 1) printf("%s\n", params[0]); }
613             else
614                 printf("%s", params[0]);
615         }
616     } else {
617         // reporting of actual errors
618         char line[256];
619         const char *msg = bpatch->getEnglishErrorString(num);
620         bpatch->formatErrorString(line, sizeof(line), msg, params);
621         
622         gotError = true;
623
624         if (expectErrors) {
625             dprintf("Error (expected) #%d (level %d): %s\n", num, level, line);
626         } else {
627             printf("Error #%d (level %d): %s\n", num, level, line);
628         }
629     }
630 }
631
632 //
633 // main - decide our role and call the correct "main"
634 //
635 int
636 main(unsigned int argc, char *argv[])
637 {
638     BPatch_thread *ret;
639
640     bool N32ABI=false;
641     char libRTname[256];
642
643     strcpy(mutateeName,mutateeNameRoot);
644     libRTname[0]='\0';
645
646     unsigned int i;
647
648 #if !defined(USES_LIBDYNINSTRT_SO)
649     fprintf(stderr,"(Expecting subject application to be statically linked"
650                         " with libdyninstAPI_RT.)\n");
651 #else
652     if (!getenv("DYNINSTAPI_RT_LIB")) {
653          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
654 #if defined(i386_unknown_nt4_0)
655                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
656 #else
657                  "    set it to the full pathname of libdyninstAPI_RT\n");   
658          exit(-1);
659 #endif
660     } else
661          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
662 #endif
663
664     // by default run all tests
665     for (i=1; i <= MAX_TEST; i++) {
666         runTest[i] = true;
667         passedTest[i] = false;
668     }
669
670     for (i=1; i < argc; i++) {
671         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
672         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
673         if (strncmp(argv[i], "-verbose", 2) == 0) {
674             debugPrint = 1;
675         } else if (!strcmp(argv[i], "-V")) {
676             fprintf (stdout, "%s\n", V_libdyninstAPI);
677             if (libRTname[0]) 
678                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
679             fflush(stdout);
680         } else if (!strcmp(argv[i], "-attach")) {
681             useAttach = true;
682         } else if (!strcmp(argv[i], "-skip")) {
683             unsigned int j;
684             runAllTests = false;
685             for (j=i+1; j < argc; j++) {
686                 unsigned int testId;
687                 if ((testId = atoi(argv[j]))) {
688                     if ((testId > 0) && (testId <= MAX_TEST)) {
689                         runTest[testId] = false;
690                     } else {
691                         printf("invalid test %d requested\n", testId);
692                         exit(-1);
693                     }
694                 } else {
695                     // end of test list
696                     break;
697                 }
698             }
699             i=j-1;
700         } else if (!strcmp(argv[i], "-run")) {
701             unsigned int j;
702             runAllTests = false;
703             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
704             for (j=i+1; j < argc; j++) {
705                 unsigned int testId;
706                 if ((testId = atoi(argv[j]))) {
707                     if ((testId > 0) && (testId <= MAX_TEST)) {
708                         runTest[testId] = true;
709                     } else {
710                         printf("invalid test %d requested\n", testId);
711                         exit(-1);
712                     }
713                 } else {
714                     // end of test list
715                     break;
716                 }
717             }
718             i = j-1;
719         } else if (!strcmp(argv[i], "-mutatee")) {
720             i++;
721             if (*argv[i]=='_')
722                 strcat(mutateeName,argv[i]);
723             else
724                 strcpy(mutateeName,argv[i]);
725 #if defined(mips_sgi_irix6_4)
726         } else if (!strcmp(argv[i], "-n32")) {
727             N32ABI=true;
728 #endif
729         } else {
730             fprintf(stderr, "Usage: test2 "
731                     "[-V] [-verbose] [-attach] "
732 #if defined(mips_sgi_irix6_4)
733                     "[-n32] "
734 #endif
735                     "[-mutatee <test2.mutatee>] "
736                     "[-run <test#> <test#> ...] "
737                     "[-skip <test#> <test#> ...]\n");
738             exit(-1);
739         }
740     }
741
742     // patch up the default compiler in mutatee name (if necessary)
743     if (!strstr(mutateeName, "_"))
744 #if defined(i386_unknown_nt4_0)
745         strcat(mutateeName,"_VC");
746 #else
747         strcat(mutateeName,"_gcc");
748 #endif
749     if (N32ABI || strstr(mutateeName,"_n32")) {
750         // patch up file names based on alternate ABI (as necessary)
751         if (!strstr(mutateeName, "_n32")) strcat(mutateeName,"_n32");
752     }
753     // patch up the platform-specific filename extensions
754 #if defined(i386_unknown_nt4_0)
755     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
756 #endif
757
758     // Create an instance of the BPatch library
759     bpatch = new BPatch;
760
761     bpatch->registerErrorCallback(errorFunc);
762
763     // Try failure cases
764     expectErrors = true;
765
766     if (runTest[1]) test1();
767     if (runTest[2]) test2();
768     if (runTest[3]) test3();
769     if (runTest[4]) test4();
770
771     // Finished trying failure cases
772     expectErrors = false;
773
774     // now start a real program
775     gotError = false;
776     ret = mutatorMAIN(mutateeName);
777     if (!ret || gotError) {
778         printf("*ERROR*: unable to create handle for executable\n");
779         exit(-1);
780     }
781
782     BPatch_image *img = ret->getImage();
783
784     // Signal the child that we've attached
785     if ( useAttach )
786                 signalAttached( ret, img );
787
788     // determine whether mutatee is C or C++
789     BPatch_variableExpr *isCxx = img->findVariable("mutateeCplusplus");
790     if (isCxx == NULL) {
791         fprintf(stderr, "  Unable to locate variable \"mutateeCplusplus\""
792                  " -- assuming 0!\n");
793     } else {
794         isCxx->readValue(&mutateeCplusplus);
795         dprintf("Mutatee is %s.\n", mutateeCplusplus ? "C++" : "C");
796     }
797
798     if (runTest[5]) test5(img);
799
800     if (runTest[8]) test8a(ret, img);
801
802     ret->continueExecution();
803
804     // Tests 6 and 7 need to be run with the thread stopped
805     if (runTest[6] || runTest[7]) {
806         waitUntilStopped(bpatch, ret, 6, "load a dynamically linked library");
807
808         if (runTest[6]) test6(ret, img);
809         if (runTest[7]) test7(ret, img);
810
811         ret->continueExecution();
812     }
813
814     if (runTest[8]) test8b(ret);
815     if (runTest[9]) test9(ret);
816     if (runTest[10]) test10(ret);
817     if (runTest[11]) test11(ret, img);
818     if (runTest[12]) test12(ret, img);
819
820     /**********************************************************************
821      * Kill process and make sure it goes away
822      **********************************************************************/
823     
824     int pid = ret->getPid();
825
826 #ifndef i386_unknown_nt4_0 /* Not yet implemented on NT. */
827     // detach from the process.
828     ret->detach(true);
829 #else
830     printf("[Process detach not yet implemented.]\n");
831 #endif
832
833     // now kill the process.
834 #ifdef i386_unknown_nt4_0
835     HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
836     if (h != NULL) {
837         TerminateProcess(h, 0);
838         CloseHandle(h);
839     }
840 #else
841     int kret;
842
843     // Alpha seems to take to kills to work - jkh 3/13/00
844     while (1) {
845         kret = kill(pid, SIGKILL);
846         if (kret) {
847             if (errno == ESRCH) {
848                break;
849             } else {
850                perror("kill");
851                break;
852             }
853         }
854         kret = waitpid(pid, NULL, WNOHANG);
855         if (kret == pid) break;
856     }
857
858 #endif
859
860     delete (ret);
861
862     if (runTest[13]) test13(ret);
863     if (runTest[14]) test14();
864
865     delete (bpatch);
866
867     unsigned int testsFailed = 0;
868     for (i=1; i <= MAX_TEST; i++) {
869         if (runTest[i] && !passedTest[i]) testsFailed++;
870     }
871
872     if (!testsFailed) {
873         if (runAllTests) {
874             printf("All tests passed\n");
875         } else {
876             printf("All requested tests passed\n");
877         }
878     } else {
879         printf("**Failed** %d test%c\n",testsFailed,(testsFailed>1)?'s':' ');
880     }
881
882     return (testsFailed ? 127 : 0);
883 }