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