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