Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / tests / src / test7.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: test7.C,v 1.25 2008/04/11 23:30:37 legendre Exp $
33 //
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <sys/msg.h>
39 #include <iostream>
40 #include <errno.h>
41 #include <stdarg.h>
42 #ifdef i386_unknown_nt4_0
43 #define WIN32_LEAN_AND_MEAN
44 #include <windows.h>
45 #include <winbase.h>
46 #else
47 #include <unistd.h>
48 #endif
49
50 #include "BPatch.h"
51 #include "BPatch_Vector.h"
52 #include "BPatch_thread.h"
53 #include "BPatch_snippet.h"
54 #include "test_util.h"
55
56
57 const char *mutateeNameRoot = "test7.mutatee";
58
59 int inTest;             // current test #
60 int expectError;
61 int debugPrint = 0; // internal "mutator" tracing
62 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
63
64 bool forceRelocation = false;  // Force relocation upon instrumentation
65
66 // control debug printf statements
67 void dprintf(const char *fmt, ...) {
68    va_list args;
69    va_start(args, fmt);
70
71    if(debugPrint)
72       vfprintf(stderr, fmt, args);
73
74    va_end(args);
75
76    fflush(stderr);
77 }
78
79
80 bool runAllTests = true;
81 const unsigned int MAX_TEST = 9;
82 bool runTest[MAX_TEST+1];
83 bool passedTest[MAX_TEST+1];
84
85 char *subTestNames[MAX_TEST+1] = {
86     "<no test # 0>",
87     "Delete snippet in parent",
88     "Delete snippet in child",
89     "Delete snippet in both parent and child",
90     "Insert snippet in child - wo inherited snippets",
91     "Add snippets to parent & child",
92     "OneTimeCode in parent & child",
93     "Memory allocation in parent & child",
94     "Memory deallocate in child",
95     "Memory deallocate in parent",
96 };
97
98 BPatch *bpatch;
99
100 typedef enum { Parent_p, Child_p } procType;
101 typedef enum { PreFork, PostFork } forkWhen;
102
103 bool parentDone = false;
104 bool childDone = false;
105
106 BPatch_thread *parentThread = NULL;
107 BPatch_thread *childThread = NULL;
108
109 const char *procName[2] = { "parent", "child" };
110
111 /*
112  * Given a string variable name and an expected value, lookup the varaible
113  *    in the process, and verify that the value matches.
114  *
115  */
116 bool verifyProcMemory(BPatch_thread *appThread, const char *name,
117                       int expectedVal, procType proc_type)
118 {
119    BPatch_image *appImage = appThread->getImage();
120
121    if (!appImage) {
122       dprintf("unable to locate image for %d\n", appThread->getPid());
123       return false;
124    }
125    
126    BPatch_variableExpr *var = appImage->findVariable(name);
127    if (!var) {
128       dprintf("unable to located variable %s in child\n", name);
129       return false;
130    }
131
132    int actualVal;
133    var->readValue(&actualVal);
134    
135    if (expectedVal != actualVal) {
136       fprintf(stderr,"*** for %s (%s), expected val = %d, but actual was %d\n",
137               name, procName[proc_type], expectedVal, actualVal);
138       return false;
139    } else {
140       dprintf("verified %s (%s) was = %d\n", name, procName[proc_type], 
141               actualVal);
142       return true;
143    }
144 }
145
146 /*
147  * Given a string variable name and an expected value, lookup the varaible
148  *    in the process, and verify that the value matches.
149  *
150  */
151 bool verifyProcMemory(const char *name, BPatch_variableExpr *var,
152                       int expectedVal, procType proc_type)
153 {
154    int actualVal;
155    var->readValue(&actualVal);
156    
157    if (expectedVal != actualVal) {
158       fprintf(stderr,"*** for %s (%s), expected val = %d, but actual was %d\n",
159               name, procName[proc_type], expectedVal, actualVal);
160       return false;
161    } else {
162       dprintf("verified %s (%s) was = %d\n", name, procName[proc_type], 
163               actualVal);
164       return true;
165    }
166 }
167
168
169 bool doError(int testNum, bool cond, const char *str) {
170    if(cond == true) {
171       fprintf(stderr, str);
172       passedTest[testNum] = false;
173       return true;
174    }
175    return false;
176 }
177
178 struct  msgSt {
179   long  mtype;     /* message type */
180   char  mtext[1];  /* message text */
181 };
182 typedef struct msgSt ipcMsg;
183
184 int msgid = -1;
185
186 int checkForDoneMsg() {
187   ipcMsg A;
188   int bytesRead = 0, ret = 0;
189   const long int DONEMSG = 4321;
190
191   A.mtype = 0;
192   if((bytesRead = msgrcv(msgid, &A, sizeof(char), DONEMSG,IPC_NOWAIT)) == -1) {
193     if(errno == ENOMSG)
194       return 0;
195     else {
196         return 1;
197         perror("msgRecv: msgrcv failed");
198     }
199     
200   }
201   if(A.mtype == DONEMSG)
202     ret = 1;
203   else
204     printf("Invalid message sent to mutator (%ld)\n",A.mtype);
205   return ret;
206 }
207
208 void waitForDoneMsg() {
209    while(! checkForDoneMsg());
210 }
211
212 void closeMessaging() {
213   msgctl(msgid, IPC_RMID, NULL);   
214 }
215
216 void setupMessaging() {
217   key_t msgkey = 1234;
218
219   if((msgid = msgget(msgkey, 0666|IPC_CREAT)) == -1) {
220     perror("Couldn't create messaging");
221     exit(1);
222   }
223 }
224
225 /* Make sure deleting a snippet in a parent process doesn't delete the
226    snippet in the child process.
227
228    parent: snippetHandleA  = insert snippetA at pointA
229    child:  snippetHandleA' = pointA.getCurrentSnippets()
230    --- fork ---
231    parent: deleteSnippet( snippetHandleA )
232    --- run  ---
233    child:  verify snippetHandleA' still ran
234 */
235
236 void prepareTestCase1(procType proc_type, BPatch_thread *thread, forkWhen when)
237 {
238    static BPatchSnippetHandle *parSnippetHandle1;
239    
240    if(proc_type == Parent_p  &&  when == PreFork) {
241        BPatch_image *parImage = thread->getImage();
242        
243        BPatch_Vector<BPatch_function *> found_funcs;
244        const char *inFunction = "func7_1";
245        if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
246            fprintf(stderr, "    Unable to find function %s\n",
247                    inFunction);
248            exit(1);
249        }
250        
251        if (1 < found_funcs.size()) {
252            fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
253                    __FILE__, __LINE__, found_funcs.size(), inFunction);
254        }
255        
256        BPatch_Vector<BPatch_point *> *point7_1p = found_funcs[0]->findPoint(BPatch_entry);
257        
258        if(doError(1, !point7_1p || ((*point7_1p).size() == 0),
259                   "  Unable to find entry point to \"func7_1\".\n")) return;
260        
261        BPatch_variableExpr *var7_1p = 
262        parImage->findVariable("globalVariable7_1");
263        if(doError(1, (var7_1p==NULL),
264                   "  Unable to locate variable globalVariable7_1\n")) return;
265        
266        BPatch_arithExpr expr7_1p(BPatch_assign, *var7_1p,BPatch_constExpr(321));
267        
268        parSnippetHandle1 =
269        thread->insertSnippet(expr7_1p, *point7_1p, BPatch_callBefore);
270        if(doError(1, (parSnippetHandle1 == NULL),
271                   "  Unable to insert snippet into parent for test 1\n")) return;
272    } else if(proc_type == Parent_p  &&  when == PostFork) {
273        thread->deleteSnippet(parSnippetHandle1);
274    }
275 }
276
277 void checkTestCase1(procType proc_type, BPatch_thread *thread) {
278    if(proc_type == Parent_p) {
279       if(! verifyProcMemory(thread, "globalVariable7_1", 123, proc_type)) {
280          passedTest[1] = false;
281       }
282    } else if(proc_type == Child_p) {
283       if(! verifyProcMemory(thread, "globalVariable7_1", 321, proc_type)) {
284          passedTest[1] = false;
285       }
286    }
287 }
288
289 /* Make sure deleting a snippet in a child process doesn't delete the
290    snippet in the parent process.
291
292    parent: snippetHandleA  = insert snippetA at pointA
293    child:  snippetHandleA' = pointA.getCurrentSnippets()
294    --- fork ---
295    child:  deleteSnippet( snippetHandleA' )
296    --- run  ---
297    parent: verify snippetHandleA still ran
298 */
299
300 void prepareTestCase2(procType proc_type, BPatch_thread *thread, forkWhen when)
301 {
302    static BPatchSnippetHandle *parSnippetHandle2;
303
304    if(proc_type == Parent_p  &&  when == PreFork) {
305       BPatch_image *parImage = thread->getImage();
306       
307       BPatch_Vector<BPatch_function *> found_funcs;
308       const char *inFunction = "func7_2";
309       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
310         fprintf(stderr, "    Unable to find function %s\n",
311                 inFunction);
312         exit(1);
313       }
314       
315       if (1 < found_funcs.size()) {
316         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
317                 __FILE__, __LINE__, found_funcs.size(), inFunction);
318       }
319       
320       BPatch_Vector<BPatch_point *> *points7_2p = found_funcs[0]->findPoint(BPatch_entry);
321
322       if(doError(2, !points7_2p || ((*points7_2p).size() == 0),
323                  "  Unable to find entry point to \"func7_2\".\n")) return;
324       BPatch_point *point7_2p = (*points7_2p)[0];
325
326       BPatch_variableExpr *var7_2p = 
327          parImage->findVariable("globalVariable7_2");
328       if(doError(2, (var7_2p==NULL),
329                  "  Unable to locate variable globalVariable7_2\n")) return;
330
331       BPatch_arithExpr expr7_2p(BPatch_assign, *var7_2p,BPatch_constExpr(951));
332
333       parSnippetHandle2 =
334          thread->insertSnippet(expr7_2p, *point7_2p, BPatch_callBefore);
335    } else if(proc_type == Child_p  &&  when == PostFork) {
336       BPatch_image *childImage = thread->getImage();      
337
338       BPatch_Vector<BPatch_function *> found_funcs;
339       const char *inFunction = "func7_2";
340       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
341         fprintf(stderr, "    Unable to find function %s\n",
342                 inFunction);
343         exit(1);
344       }
345       
346       if (1 < found_funcs.size()) {
347         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
348                 __FILE__, __LINE__, found_funcs.size(), inFunction);
349       }
350       
351       BPatch_Vector<BPatch_point *> *points7_2c = found_funcs[0]->findPoint(BPatch_entry);
352
353       if(doError(2, !points7_2c || ((*points7_2c).size() == 0),
354                  "  Unable to find entry point to \"func7_2\".\n")) return;
355       BPatch_point *point7_2c = (*points7_2c)[0];
356
357       BPatch_Vector<BPatchSnippetHandle *> childSnippets =
358          point7_2c->getCurrentSnippets();
359       if(doError(2, (childSnippets.size()==0),
360                  " No snippets were found at func7_2\n")) return;
361
362       for(unsigned i=0; i<childSnippets.size(); i++) {
363          bool result = thread->deleteSnippet(childSnippets[i]);
364          if(result == false) {
365             fprintf(stderr, "  error, couldn't delete snippet\n");
366             passedTest[2] = false;
367             return;
368          }
369       }
370    }
371 }
372
373 void checkTestCase2(procType proc_type, BPatch_thread *thread) {
374    if(proc_type == Parent_p) {
375       if(! verifyProcMemory(thread, "globalVariable7_2", 951, proc_type)) {
376          passedTest[2] = false;
377       }
378    } else if(proc_type == Child_p) {
379       if(! verifyProcMemory(thread, "globalVariable7_2", 159, proc_type)) {
380          passedTest[2] = false;
381       }
382    }
383 }
384
385 /* Delete both a parent and a child snippet, and make sure both are getting
386    deleted.
387
388    parent: snippetHandleA  = insert snippetA at pointA
389    --- fork ---
390    parent: deleteSnippet( snippetHandleA )
391    child:  snippetHandleA' = pointA.getCurrentSnippets()
392    child:  deleteSnippet( snippetHandleA' )
393    --- run  ---
394    parent: verify snippetHandleA didn't run
395    child:  verify snippetHandleA didn't run
396 */
397
398 void prepareTestCase3(procType proc_type, BPatch_thread *thread, forkWhen when)
399 {
400    static BPatchSnippetHandle *parSnippetHandle3;
401
402    if(proc_type == Parent_p  &&  when == PreFork) {
403       BPatch_image *parImage = thread->getImage();
404
405       BPatch_Vector<BPatch_function *> found_funcs;
406       const char *inFunction = "func7_3";
407       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
408         fprintf(stderr, "    Unable to find function %s\n",
409                 inFunction);
410         exit(1);
411       }
412       
413       if (1 < found_funcs.size()) {
414         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
415                 __FILE__, __LINE__, found_funcs.size(), inFunction);
416       }
417       
418       BPatch_Vector<BPatch_point *> *points7_3p = found_funcs[0]->findPoint(BPatch_entry);
419
420       if(doError(3, !points7_3p || ((*points7_3p).size() == 0),
421                  "  Unable to find entry point to \"func7_3\".\n")) return;
422       BPatch_point *point7_3p = (*points7_3p)[0];
423
424       BPatch_variableExpr *var7_3p = 
425          parImage->findVariable("globalVariable7_3");
426       if(doError(3, (var7_3p==NULL),
427                  "  Unable to locate variable globalVariable7_3\n")) return;
428
429       BPatch_arithExpr expr7_3p(BPatch_assign, *var7_3p,BPatch_constExpr(642));
430
431       parSnippetHandle3 =
432          thread->insertSnippet(expr7_3p, *point7_3p, BPatch_callBefore);
433    } else if(proc_type == Parent_p  &&  when == PostFork) {
434       bool result = thread->deleteSnippet(parSnippetHandle3);
435       if(result == false) {
436          fprintf(stderr, "  error, couldn't delete snippet\n");
437          passedTest[3] = false;
438          return;
439       }
440    } else if(proc_type == Child_p  &&  when == PostFork) {
441       BPatch_image *childImage = thread->getImage();
442
443       BPatch_Vector<BPatch_function *> found_funcs;
444       const char *inFunction = "func7_3";
445       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
446         fprintf(stderr, "    Unable to find function %s\n",
447                 inFunction);
448         exit(1);
449       }
450       
451       if (1 < found_funcs.size()) {
452         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
453                 __FILE__, __LINE__, found_funcs.size(), inFunction);
454       }
455       
456       BPatch_Vector<BPatch_point *> *points7_3c = found_funcs[0]->findPoint(BPatch_entry);
457       
458       if(doError(3, !points7_3c || ((*points7_3c).size() == 0),
459                  "  Unable to find entry point to \"func7_3\".\n")) return;
460       BPatch_point *point7_3c = (*points7_3c)[0];
461
462       BPatch_Vector<BPatchSnippetHandle *> childSnippets =
463          point7_3c->getCurrentSnippets();
464       if(doError(3, (childSnippets.size()==0),
465                  " No snippets were found at func7_3\n")) return;
466
467       for(unsigned i=0; i<childSnippets.size(); i++) {
468          bool result = thread->deleteSnippet(childSnippets[i]);
469          if(result == false) {
470             fprintf(stderr, "  error, couldn't delete snippet\n");
471             passedTest[3] = false;
472             return;
473          }
474       }
475    }
476 }
477
478 void checkTestCase3(procType proc_type, BPatch_thread *thread) {
479    if(proc_type == Parent_p) {
480       if(! verifyProcMemory(thread, "globalVariable7_3", 246, proc_type)) {
481          passedTest[3] = false;
482       }
483    } else if(proc_type == Child_p) {
484       if(! verifyProcMemory(thread, "globalVariable7_3", 246, proc_type)) {
485          passedTest[3] = false;
486       }
487    }
488 }
489
490 /* Insert a snippet into a child process, which hasn't inherited
491    any snippets from the parent process. 
492 */
493
494 /*
495    var7_5 initial value = 789
496    --- fork ---
497    child:  insert snippet A, var7_5 += 211
498    --- run  ---
499    child:  verify snippet A ran, (ie. var7_5 == 1000)
500 */
501
502 void prepareTestCase4(procType proc_type, BPatch_thread *thread, forkWhen when)
503 {
504    const int TN = 4;
505    static BPatchSnippetHandle *parSnippetHandle4;
506
507    if(proc_type == Child_p  &&  when == PostFork) {
508       BPatch_image *childImage = thread->getImage();
509
510       BPatch_Vector<BPatch_function *> found_funcs;
511       const char *inFunction = "func7_4";
512       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
513         fprintf(stderr, "    Unable to find function %s\n",
514                 inFunction);
515         exit(1);
516       }
517       
518       if (1 < found_funcs.size()) {
519         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
520                 __FILE__, __LINE__, found_funcs.size(), inFunction);
521       }
522       
523       BPatch_Vector<BPatch_point *> *points7_4c = found_funcs[0]->findPoint(BPatch_entry);
524       if(doError(TN, !points7_4c || ((*points7_4c).size() == 0),
525                  "  Unable to find entry point to \"func7_4\".\n")) return;
526       BPatch_point *point7_4c = (*points7_4c)[0];
527
528       BPatch_variableExpr *var7_4c = 
529          childImage->findVariable("globalVariable7_4");
530       if(doError(TN, (var7_4c==NULL),
531                  "  Unable to locate variable globalVariable7_4\n")) return;
532
533       BPatch_arithExpr a_expr7_4c(BPatch_plus, *var7_4c,BPatch_constExpr(211));
534       BPatch_arithExpr b_expr7_4c(BPatch_assign, *var7_4c, a_expr7_4c);
535       parSnippetHandle4 =
536         thread->insertSnippet(b_expr7_4c, *point7_4c, BPatch_callBefore);
537    }
538 }
539
540 void checkTestCase4(procType proc_type, BPatch_thread *thread) {
541    if(proc_type == Parent_p) {
542       if(! verifyProcMemory(thread, "globalVariable7_4", 789, proc_type)) {
543          passedTest[4] = false;
544       }
545    } else if(proc_type == Child_p) {
546       if(! verifyProcMemory(thread, "globalVariable7_4", 1000, proc_type)) {
547          passedTest[4] = false;
548       }
549    }
550 }
551
552
553 /* Add two snippets to an already existing snippet in the parent and child
554    and see if all of the snippets get run.
555
556    parent/child: globalVariable7_5 initial value = 7
557    parent: snippetHandleA  = insert snippetA at pointA   += 9
558    --- fork ---
559    child:  snippetHandleA' = pointA.getCurrentSnippets()
560    parent: add snippetB (+= 11);  add snippetC (+= 13);
561    child:  add snippetB' (+= 5);  add snippetC' (+= 3);
562    --- run  ---
563    parent: verify snippetA, snippetB, and snippetC ran     7+9+11+13 == 40
564    child:  verify snippetA', snippetB', and snippetC' ran  7+9+5+3   == 24
565 */
566
567 void prepareTestCase5(procType proc_type, BPatch_thread *thread, forkWhen when)
568 {
569    const int TN = 5;
570    static BPatchSnippetHandle *parSnippetHandle5;
571
572    if(proc_type == Parent_p  &&  when == PreFork) {
573       BPatch_image *parImage = thread->getImage();
574
575       BPatch_Vector<BPatch_function *> found_funcs;
576       const char *inFunction = "func7_5";
577       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
578         fprintf(stderr, "    Unable to find function %s\n",
579                 inFunction);
580         exit(1);
581       }
582       
583       if (1 < found_funcs.size()) {
584         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
585                 __FILE__, __LINE__, found_funcs.size(), inFunction);
586       }
587       
588       BPatch_Vector<BPatch_point *> *points7_5p = found_funcs[0]->findPoint(BPatch_entry);
589
590       if(doError(TN, !points7_5p || ((*points7_5p).size() == 0),
591                  "  Unable to find entry point to \"func7_5\".\n")) return;
592       BPatch_point *point7_5p = (*points7_5p)[0];
593
594       BPatch_variableExpr *var7_5p = 
595          parImage->findVariable("globalVariable7_5");
596       if(doError(TN, (var7_5p==NULL),
597                  "  Unable to locate variable globalVariable7_5\n")) return;
598
599       BPatch_arithExpr expr7_5p(BPatch_plus, *var7_5p, BPatch_constExpr(9));
600       BPatch_arithExpr b_expr7_5p(BPatch_assign, *var7_5p, expr7_5p);
601       parSnippetHandle5 =
602          thread->insertSnippet(b_expr7_5p, *point7_5p, BPatch_callBefore);
603    } else if(proc_type == Parent_p  &&  when == PostFork) {
604       BPatch_image *parImage = thread->getImage();
605
606       BPatch_Vector<BPatch_function *> found_funcs;
607       const char *inFunction = "func7_5";
608       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
609         fprintf(stderr, "    Unable to find function %s\n",
610                 inFunction);
611         exit(1);
612       }
613       
614       if (1 < found_funcs.size()) {
615         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
616                 __FILE__, __LINE__, found_funcs.size(), inFunction);
617       }
618       
619       BPatch_Vector<BPatch_point *> *points7_5p = found_funcs[0]->findPoint(BPatch_entry);
620
621       if(doError(TN, !points7_5p || ((*points7_5p).size() == 0),
622                  "  Unable to find entry point to \"func7_5\".\n")) return;
623       BPatch_point *point7_5p = (*points7_5p)[0];
624
625       BPatch_variableExpr *var7_5p = 
626          parImage->findVariable("globalVariable7_5");
627       if(doError(TN, (var7_5p==NULL),
628                  "  Unable to locate variable globalVariable7_5\n")) return;
629
630       BPatch_arithExpr a_expr7_5p(BPatch_plus, *var7_5p, BPatch_constExpr(11));
631       BPatch_arithExpr b_expr7_5p(BPatch_assign, *var7_5p, a_expr7_5p);
632       parSnippetHandle5 =
633          thread->insertSnippet(b_expr7_5p, *point7_5p, BPatch_callBefore,
634                                BPatch_lastSnippet);
635
636       BPatch_arithExpr c_expr7_5p(BPatch_plus, *var7_5p, BPatch_constExpr(13));
637       BPatch_arithExpr d_expr7_5p(BPatch_assign, *var7_5p, c_expr7_5p);
638       parSnippetHandle5 =
639          thread->insertSnippet(d_expr7_5p, *point7_5p, BPatch_callBefore);
640    } else if(proc_type == Child_p  &&  when == PostFork) {
641       BPatch_image *childImage = thread->getImage();
642
643       BPatch_Vector<BPatch_function *> found_funcs;
644       const char *inFunction = "func7_5";
645       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
646         fprintf(stderr, "    Unable to find function %s\n",
647                 inFunction);
648         exit(1);
649       }
650       
651       if (1 < found_funcs.size()) {
652         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
653                 __FILE__, __LINE__, found_funcs.size(), inFunction);
654       }
655       
656       BPatch_Vector<BPatch_point *> *points7_5c = found_funcs[0]->findPoint(BPatch_entry);
657
658       if(doError(TN, !points7_5c || ((*points7_5c).size() == 0),
659                  "  Unable to find entry point to \"func7_5\".\n")) return;
660       BPatch_point *point7_5c = (*points7_5c)[0];
661
662       BPatch_variableExpr *var7_5c = 
663          childImage->findVariable("globalVariable7_5");
664       if(doError(TN, (var7_5c==NULL),
665                  "  Unable to locate variable globalVariable7_5\n")) return;
666
667       BPatch_arithExpr a_expr7_5c(BPatch_plus, *var7_5c, BPatch_constExpr(5));
668       BPatch_arithExpr b_expr7_5c(BPatch_assign, *var7_5c, a_expr7_5c);
669       parSnippetHandle5 =
670         thread->insertSnippet(b_expr7_5c, *point7_5c, BPatch_callBefore,
671                               BPatch_lastSnippet);
672       BPatch_arithExpr c_expr7_5c(BPatch_plus, *var7_5c, BPatch_constExpr(3));
673       BPatch_arithExpr d_expr7_5c(BPatch_assign, *var7_5c, c_expr7_5c);
674       parSnippetHandle5 =
675         thread->insertSnippet(d_expr7_5c, *point7_5c, BPatch_callBefore);
676    }
677 }
678
679 void checkTestCase5(procType proc_type, BPatch_thread *thread) {
680    const int TN = 5;
681    if(proc_type == Parent_p) {
682       if(! verifyProcMemory(thread, "globalVariable7_5", 40, proc_type)) {
683          passedTest[TN] = false;
684       }
685    } else if(proc_type == Child_p) {
686       if(! verifyProcMemory(thread, "globalVariable7_5", 24, proc_type)) {
687          passedTest[TN] = false;
688       }
689    }
690 }
691
692 /* Run a oneTimeCode in both the parent and child and see if they both
693    happen.
694
695    parent/child: globalVariable7_6 initial value = 21
696
697    parent: run one time code, value += 5
698    child:  run one time code, value += 9
699    parent: value == 26
700    child:  value == 30
701 */
702
703 void prepareTestCase6(procType proc_type, BPatch_thread *thread, forkWhen when)
704 {
705    const int TN = 6;
706
707    if(proc_type == Parent_p  &&  when == PostFork) {
708       BPatch_image *parImage = thread->getImage();
709
710       BPatch_variableExpr *var7_6p = 
711          parImage->findVariable("globalVariable7_6");
712       if(doError(TN, (var7_6p==NULL),
713                  "  Unable to locate variable globalVariable7_6\n")) return;
714
715       BPatch_arithExpr a_expr7_6p(BPatch_plus, *var7_6p, BPatch_constExpr(5));
716       BPatch_arithExpr b_expr7_6p(BPatch_assign, *var7_6p, a_expr7_6p);
717       thread->oneTimeCode(b_expr7_6p);
718    } else if(proc_type == Child_p  &&  when == PostFork) {
719       BPatch_image *childImage = thread->getImage();
720
721       BPatch_variableExpr *var7_6c = 
722          childImage->findVariable("globalVariable7_6");
723       if(doError(TN, (var7_6c==NULL),
724                  "  Unable to locate variable globalVariable7_6\n")) return;
725
726       BPatch_arithExpr a_expr7_6c(BPatch_plus, *var7_6c, BPatch_constExpr(9));
727       BPatch_arithExpr b_expr7_6c(BPatch_assign, *var7_6c, a_expr7_6c);
728       thread->oneTimeCode(b_expr7_6c);
729    }
730 }
731
732 void checkTestCase6(procType proc_type, BPatch_thread *thread) {
733    const int TN = 6;
734    if(proc_type == Parent_p) {
735       if(! verifyProcMemory(thread, "globalVariable7_6", 26, proc_type)) {
736          passedTest[TN] = false;
737       }
738    } else if(proc_type == Child_p) {
739       if(! verifyProcMemory(thread, "globalVariable7_6", 30, proc_type)) {
740          passedTest[TN] = false;
741       }
742    }
743 }
744
745 /* Verify that the memory created with malloc is per process and isn't
746    being shared between a parent and child process.
747
748    parent/child: malloc a variable
749    parent/child: oneTimeCode(snippetA)  (malloced variable = 10)
750    --- fork ---
751    parent: insert snippet B  (malloced_var += 3);
752    child:  insert snippet B' (malloced_var += 7);
753    --- run  ---
754    parent: verify malloced_var = 13
755    child:  verify malloced_var = 17
756 */
757
758 BPatch_variableExpr *var7_7p;
759 BPatch_variableExpr *var7_7c;
760
761 void prepareTestCase7(procType proc_type, BPatch_thread *thread, forkWhen when)
762 {
763    const int TN = 7;
764
765    if(proc_type == Parent_p  &&  when == PreFork) {
766       BPatch_image *parImage = thread->getImage();
767       var7_7p = thread->malloc(*(parImage->findType("int")));
768       if(doError(TN, (var7_7p==NULL),
769                  "  Unable to malloc variable in parent\n")) return;
770
771       BPatch_arithExpr a_expr7_7p(BPatch_assign, *var7_7p,
772                                   BPatch_constExpr(10));
773       thread->oneTimeCode(a_expr7_7p);
774    } else if(proc_type == Parent_p  &&  when == PostFork) {
775       BPatch_image *parImage = thread->getImage();
776
777       BPatch_Vector<BPatch_function *> found_funcs;
778       const char *inFunction = "func7_7";
779       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
780         fprintf(stderr, "    Unable to find function %s\n",
781                 inFunction);
782         exit(1);
783       }
784       
785       if (1 < found_funcs.size()) {
786         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
787                 __FILE__, __LINE__, found_funcs.size(), inFunction);
788       }
789       
790       BPatch_Vector<BPatch_point *> *points7_7p = found_funcs[0]->findPoint(BPatch_entry);
791
792       if(doError(TN, !points7_7p || ((*points7_7p).size() == 0),
793                  "  Unable to find entry point to \"func7_7\".\n")) return;
794       BPatch_point *point7_7p = (*points7_7p)[0];
795
796       BPatch_arithExpr a_expr7_7p(BPatch_plus, *var7_7p, BPatch_constExpr(3));
797       BPatch_arithExpr b_expr7_7p(BPatch_assign, *var7_7p, a_expr7_7p);
798       thread->insertSnippet(b_expr7_7p, *point7_7p, BPatch_callBefore);
799    } else if(proc_type == Child_p  &&  when == PostFork) {
800       var7_7c = thread->getInheritedVariable(*var7_7p);
801
802       BPatch_image *childImage = thread->getImage();
803
804       BPatch_Vector<BPatch_function *> found_funcs;
805       const char *inFunction = "func7_7";
806       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
807         fprintf(stderr, "    Unable to find function %s\n",
808                 inFunction);
809         exit(1);
810       }
811       
812       if (1 < found_funcs.size()) {
813         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
814                 __FILE__, __LINE__, found_funcs.size(), inFunction);
815       }
816       
817       BPatch_Vector<BPatch_point *> *points7_7c = found_funcs[0]->findPoint(BPatch_entry);
818
819       if(doError(TN, !points7_7c || ((*points7_7c).size() == 0),
820                  "  Unable to find entry point to \"func7_7\".\n")) return;
821       BPatch_point *point7_7c = (*points7_7c)[0];
822
823       BPatch_arithExpr a_expr7_7c(BPatch_plus, *var7_7c, BPatch_constExpr(7));
824       BPatch_arithExpr b_expr7_7c(BPatch_assign, *var7_7c, a_expr7_7c);
825
826       thread->insertSnippet(b_expr7_7c, *point7_7c, BPatch_callBefore);
827    }
828 }
829
830 void checkTestCase7(procType proc_type, BPatch_thread */*thread*/) {
831    const int TN = 7;
832    char varname[50];
833    sprintf(varname,"test%d malloced var",TN);
834    if(proc_type == Parent_p) {
835       if(! verifyProcMemory(varname, var7_7p, 13, proc_type)) {
836          passedTest[TN] = false;
837       }
838    } else if(proc_type == Child_p) {
839       if(! verifyProcMemory(varname, var7_7c, 17, proc_type)) {
840          passedTest[TN] = false;
841       }
842    }
843 }
844
845 /* Verify that if a variable in the child process is freed with 
846    BPatch_thread::free, the corresponding variable in the parent process
847    isn't also deleted.
848
849    parent/child: malloc a variable
850    parent/child: oneTimeCode(snippetA)  (malloced variable = 10)
851    --- fork ---
852    parent: insert snippet B  (malloced_var += 3);
853    child:  free(getInheritedVariable(malloced_var))
854    --- run  ---
855    parent: verify malloced_var = 13
856    (no way to verify the child variable has indeed been freed)
857 */
858
859 BPatch_variableExpr *var7_8p;
860
861 void prepareTestCase8(procType proc_type, BPatch_thread *thread, forkWhen when)
862 {
863    const int TN = 8;
864
865    if(proc_type == Parent_p  &&  when == PreFork) {
866       BPatch_image *parImage = thread->getImage();
867       var7_8p = thread->malloc(*(parImage->findType("int")));
868       if(doError(TN, (var7_8p==NULL),
869                  "  Unable to malloc variable in parent\n")) return;
870
871       BPatch_arithExpr a_expr7_8p(BPatch_assign, *var7_8p,
872                                   BPatch_constExpr(10));
873       thread->oneTimeCode(a_expr7_8p);
874    } else if(proc_type == Parent_p  &&  when == PostFork) {
875       BPatch_image *parImage = thread->getImage();
876
877       BPatch_Vector<BPatch_function *> found_funcs;
878       const char *inFunction = "func7_8";
879       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
880         fprintf(stderr, "    Unable to find function %s\n",
881                 inFunction);
882         exit(1);
883       }
884       
885       if (1 < found_funcs.size()) {
886         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
887                 __FILE__, __LINE__, found_funcs.size(), inFunction);
888       }
889       
890       BPatch_Vector<BPatch_point *> *points7_8p = found_funcs[0]->findPoint(BPatch_entry);
891
892       if(doError(TN, !points7_8p || ((*points7_8p).size() == 0),
893                  "  Unable to find entry point to \"func7_8\".\n")) return;
894       BPatch_point *point7_8p = (*points7_8p)[0];
895
896       BPatch_arithExpr a_expr7_8p(BPatch_plus, *var7_8p, BPatch_constExpr(3));
897       BPatch_arithExpr b_expr7_8p(BPatch_assign, *var7_8p, a_expr7_8p);
898
899       thread->insertSnippet(b_expr7_8p, *point7_8p, BPatch_callBefore);
900    } else if(proc_type == Child_p  &&  when == PostFork) {
901       BPatch_variableExpr *var7_8c = thread->getInheritedVariable(*var7_8p);
902       thread->free(*var7_8c);
903    }
904 }
905
906 void checkTestCase8(procType proc_type, BPatch_thread */*thread*/) {
907    const int TN = 8;
908    char varname[50];
909    sprintf(varname,"test%d malloced var",TN);
910    if(proc_type == Parent_p) {
911       if(! verifyProcMemory(varname, var7_8p, 13, proc_type)) {
912          passedTest[TN] = false;
913       }
914    }
915 }
916
917 /* Verify that if a variable in the parent process is freed with 
918    BPatch_thread::free, the corresponding variable in the child process
919    isn't also deleted.
920
921    parent/child: malloc a variable
922    parent/child: oneTimeCode(snippetA)  (malloced variable = 10)
923    --- fork ---
924    child:  insert snippet B  (malloced_var += 5);
925    parent: free(getInheritedVariable(malloced_var))
926
927    --- run  ---
928    parent: verify malloced_var = 15
929    (no way to verify the child variable has indeed been freed)
930 */
931
932 BPatch_variableExpr *var7_9p;
933 BPatch_variableExpr *var7_9c;
934
935 void prepareTestCase9(procType proc_type, BPatch_thread *thread, forkWhen when)
936 {
937    const int TN = 9;
938
939    if(proc_type == Parent_p  &&  when == PreFork) {
940       BPatch_image *parImage = thread->getImage();
941       var7_9p = thread->malloc(*(parImage->findType("int")));
942       if(doError(TN, (var7_9p==NULL),
943                  "  Unable to malloc variable in parent\n")) return;
944
945       BPatch_arithExpr a_expr7_9p(BPatch_assign, *var7_9p,
946                                   BPatch_constExpr(10));
947       thread->oneTimeCode(a_expr7_9p);
948    } else if(proc_type == Parent_p  &&  when == PostFork) {
949       // can't delete var7_9p here, since then the getInheritedVariable
950       // would be operating on a freed variable
951    } else if(proc_type == Child_p  &&  when == PostFork) {
952       var7_9c = thread->getInheritedVariable(*var7_9p);
953       parentThread->free(*var7_9p);
954
955       BPatch_image *childImage = thread->getImage();
956
957       BPatch_Vector<BPatch_function *> found_funcs;
958       const char *inFunction = "func7_9";
959       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
960         fprintf(stderr, "    Unable to find function %s\n",
961                 inFunction);
962         exit(1);
963       }
964       
965       if (1 < found_funcs.size()) {
966         fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
967                 __FILE__, __LINE__, found_funcs.size(), inFunction);
968       }
969       
970       BPatch_Vector<BPatch_point *> *points7_9c = found_funcs[0]->findPoint(BPatch_entry);
971
972       if(doError(TN, !points7_9c || ((*points7_9c).size() == 0),
973                  "  Unable to find entry point to \"func7_9\".\n")) return;
974       BPatch_point *point7_9c = (*points7_9c)[0];
975
976       BPatch_arithExpr a_expr7_9c(BPatch_plus, *var7_9c, BPatch_constExpr(5));
977       BPatch_arithExpr b_expr7_9c(BPatch_assign, *var7_9c, a_expr7_9c);
978
979       thread->insertSnippet(b_expr7_9c, *point7_9c, BPatch_callBefore);
980    }
981 }
982
983 void checkTestCase9(procType proc_type, BPatch_thread */*thread*/) {
984    const int TN = 9;
985    char varname[50];
986    sprintf(varname,"test%d malloced var",TN);
987
988    if(proc_type == Child_p) {
989       if(! verifyProcMemory(varname, var7_9c, 15, proc_type)) {
990          passedTest[TN] = false;
991       }
992    }
993 }
994
995
996 void prepareTests(procType proc_type, BPatch_thread *thread, forkWhen when)
997 {
998   //cerr << "prepareTests, proc_type: " << proc_type << "\n";
999   for(unsigned testNum=1; testNum<=MAX_TEST; testNum++) {
1000     //cerr << "testNum: " << testNum << "\n";
1001       if(! runTest[testNum] || passedTest[testNum]==false) continue;
1002       switch(testNum) {
1003         case 1:  prepareTestCase1(proc_type, thread, when);  break;
1004         case 2:  prepareTestCase2(proc_type, thread, when);  break;
1005         case 3:  prepareTestCase3(proc_type, thread, when);  break;
1006         case 4:  prepareTestCase4(proc_type, thread, when);  break;
1007         case 5:  prepareTestCase5(proc_type, thread, when);  break;
1008         case 6:  prepareTestCase6(proc_type, thread, when);  break;
1009         case 7:  prepareTestCase7(proc_type, thread, when);  break;
1010         case 8:  prepareTestCase8(proc_type, thread, when);  break;
1011         case 9:  prepareTestCase9(proc_type, thread, when);  break;
1012         default: 
1013            fprintf(stderr, "prepareTest: Invalid test num type\n");
1014            exit(0);
1015            break;
1016       }
1017    }
1018 }
1019
1020 void checkTests(procType proc_type, BPatch_thread *thread)
1021 {
1022   //cerr << "checkTests, proc_type: " << proc_type << "\n";
1023    for(unsigned testNum=1; testNum<=MAX_TEST; testNum++) {
1024      //cerr << "testNum: " << testNum << "\n";
1025       if(! runTest[testNum] || passedTest[testNum]==false) continue;
1026       switch(testNum) {
1027         case 1:  checkTestCase1(proc_type, thread);  break;
1028         case 2:  checkTestCase2(proc_type, thread);  break;
1029         case 3:  checkTestCase3(proc_type, thread);  break;
1030         case 4:  checkTestCase4(proc_type, thread);  break;
1031         case 5:  checkTestCase5(proc_type, thread);  break;
1032         case 6:  checkTestCase6(proc_type, thread);  break;
1033         case 7:  checkTestCase7(proc_type, thread);  break;
1034         case 8:  checkTestCase8(proc_type, thread);  break;
1035         case 9:  checkTestCase9(proc_type, thread);  break;
1036         default: 
1037            fprintf(stderr, "checkTest: Invalid test num type\n");
1038            exit(0);
1039            break;
1040       }
1041    }
1042 }
1043
1044 void errorFunc(BPatchErrorLevel level, int num, const char * const *params)
1045 {
1046     if (num == 0) {
1047         // conditional reporting of warnings and informational messages
1048         if (errorPrint) {
1049             if (level == BPatchInfo)
1050               { if (errorPrint > 1) printf("%s\n", params[0]); }
1051             else
1052                 printf("%s", params[0]);
1053         }
1054     } else {
1055         // reporting of actual errors
1056         char line[256];
1057         const char *msg = bpatch->getEnglishErrorString(num);
1058         bpatch->formatErrorString(line, sizeof(line), msg, params);
1059         
1060         if (num != expectError) {
1061             printf("Error #%d (level %d): %s\n", num, level, line);
1062         
1063             // We consider some errors fatal.
1064             if (num == 101) {
1065                exit(-1);
1066             }
1067         }
1068     }
1069 }
1070
1071 void showFinalResults() {
1072    unsigned int testsFailed = 0;
1073    for (unsigned int i=1; i <= MAX_TEST; i++) {
1074       if (runTest[i]==false) {
1075          printf("Skipped test #%d (%s)\n", i, subTestNames[i]);
1076       } else if(passedTest[i]==false) {
1077          testsFailed++;
1078          printf("Failed test #%d (%s)\n", i, subTestNames[i]);
1079       } else {
1080          printf("Passed test #%d (%s)\n", i, subTestNames[i]);
1081       }
1082    }
1083    
1084    if (!testsFailed) {
1085       if (runAllTests) {
1086          printf("All tests passed\n");
1087       } else {
1088          printf("All requested tests passed\n");
1089       }
1090    }
1091 }
1092
1093 /* Here's the sequence:
1094    MUTATOR                      ParentProc        ChildProc
1095    insert initial 
1096        instrumentation
1097    parent->continue
1098
1099    registerPostFork
1100    parent->continue                    
1101                                 fork()
1102    postFork-callback()
1103    insert instrumentation
1104    (parent & child)->continue   
1105                                 instr is run      instr is run
1106                                 kill(STOP)        kill(STOP)
1107    if( isStopped())
1108       checkInstrResults()
1109    terminate parent, child
1110                                 exit              exit
1111 */
1112
1113 void initialPreparation(BPatch_thread *parent)
1114 {
1115    //cerr << "in initialPreparation\n";
1116    assert(parent->isStopped());
1117
1118    //cerr << "ok, inserting instr\n";
1119    prepareTests(Parent_p, parent, PreFork);
1120 }
1121
1122 /* We make changes at post-fork */
1123
1124 void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
1125 {
1126    //fprintf(stderr, "in postForkFunc\n");
1127     /* For later identification */
1128     childThread = child;
1129     dprintf("Preparing tests on parent\n");
1130     prepareTests(Parent_p, parent, PostFork);
1131     dprintf("Preparing tests on child\n");
1132     prepareTests(Child_p,  child,  PostFork);
1133     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
1134
1135     // DO NOT continue here. The fork function should NOT continue.
1136     //childThread->continueExecution();
1137     //parentThread->continueExecution();
1138 }
1139
1140 /* And verify them when they exit */
1141
1142 void exitFunc(BPatch_thread *thread, BPatch_exitType /* exit_type */) {
1143     dprintf("Exit func called\n");
1144     if (thread == parentThread) {
1145         dprintf("Parent exit reached, checking...\n");
1146         checkTests(Parent_p, thread);
1147         parentDone = true;
1148         dprintf("Parent done\n");
1149     }
1150     else if (thread == childThread) {
1151         dprintf("Child exit reached, checking...\n");
1152         checkTests(Child_p, thread);
1153         dprintf("Child done\n");
1154         childDone = true;
1155     }
1156     else {
1157         fprintf(stderr, "Thread ptr 0x%p, parent 0x%p, child 0x%p\n",
1158                 thread, parentThread, childThread);
1159         assert(0 && "Unexpected BPatch_thread in exitFunc");
1160     }
1161     return;
1162 }
1163
1164 void mutatorMAIN(char *pathname)
1165 {
1166     // Create an instance of the BPatch library
1167     bpatch = new BPatch;
1168
1169     // Force functions to be relocated
1170     if (forceRelocation) {
1171       bpatch->setForcedRelocation_NP(true);
1172     }
1173
1174     // Register a callback function that prints any error messages
1175     bpatch->registerErrorCallback(errorFunc);
1176     //bpatch->registerPreForkCallback(preForkFunc);    
1177     bpatch->registerPostForkCallback(postForkFunc);
1178     bpatch->registerExitCallback(exitFunc);
1179     for(unsigned i=1; i<=MAX_TEST; i++)  passedTest[i] = true;
1180
1181     int n = 0;
1182     const char *child_argv[MAX_TEST+5];
1183         
1184     dprintf("in mutatorTest1\n");
1185
1186     inTest = 1;
1187     child_argv[n++] = pathname;
1188     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
1189
1190     child_argv[n] = NULL;
1191
1192     // Start the mutatee
1193     printf("Starting \"%s\"\n", pathname);
1194     setupMessaging();
1195
1196     parentThread = bpatch->createProcess(pathname, child_argv, 
1197                                          NULL);
1198     if(parentThread == NULL) {
1199         fprintf(stderr, "Unable to run test program.\n");
1200         exit(1);
1201     }
1202     initialPreparation(parentThread);
1203     /* ok, do the fork */;
1204     parentThread->continueExecution();
1205
1206     /* the rest of the execution occurs in postForkFunc() */
1207     /* Secondary test: we should not have to manually continue
1208        either parent or child at any point */
1209     while (!parentThread->isTerminated() ||
1210            !childThread->isTerminated()) {
1211         bpatch->waitForStatusChange();
1212     }
1213     delete parentThread;
1214     delete childThread;
1215     showFinalResults();
1216     exit(0);
1217 }
1218
1219 //
1220 // main - decide our role and call the correct "main"
1221 //
1222 int
1223 main(int argc, char *argv[])
1224 {
1225     unsigned int i;
1226     bool ABI_32=false;
1227     char mutateeName[128];
1228     char libRTname[256];
1229
1230     strcpy(mutateeName,mutateeNameRoot);
1231     libRTname[0]='\0';
1232
1233     if (!getenv("DYNINSTAPI_RT_LIB")) {
1234          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
1235 #if defined(i386_unknown_nt4_0)
1236                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
1237 #else
1238                  "    set it to the full pathname of libdyninstAPI_RT\n");   
1239          exit(-1);
1240 #endif
1241     } else
1242          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
1243
1244     updateSearchPaths(argv[0]);
1245
1246     // by default run all tests
1247     for (i=1; i <= MAX_TEST; i++) {
1248         runTest[i] = true;
1249         passedTest[i] = false;
1250     }
1251
1252     for (i=1; i < argc; i++) {
1253         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
1254         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
1255         if (strncmp(argv[i], "-verbose", 2) == 0) {
1256             debugPrint = 1;
1257         } else if (!strcmp(argv[i], "-V")) {
1258             if (libRTname[0]) 
1259                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
1260             fflush(stdout);
1261         } else if (!strcmp(argv[i], "-skip")) {
1262             unsigned int j;
1263             runAllTests = false;
1264             for (j=i+1; j < argc; j++) {
1265                 unsigned int testId;
1266                 if ((testId = atoi(argv[j]))) {
1267                     if ((testId > 0) && (testId <= MAX_TEST)) {
1268                         runTest[testId] = false;
1269                     } else {
1270                         printf("invalid test %d requested\n", testId);
1271                         exit(-1);
1272                     }
1273                 } else {
1274                     // end of test list
1275                     break;
1276                 }
1277             }
1278             i=j-1;
1279         } else if (!strcmp(argv[i], "-run")) {
1280             unsigned int j;
1281             runAllTests = false;
1282             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
1283             for (j=i+1; j < argc; j++) {
1284                 unsigned int testId;
1285                 if ((testId = atoi(argv[j]))) {
1286                     if ((testId > 0) && (testId <= MAX_TEST)) {
1287                         runTest[testId] = true;
1288                     } else {
1289                         printf("invalid test %d requested\n", testId);
1290                         exit(-1);
1291                     }
1292                 } else {
1293                     // end of test list
1294                     break;
1295                 }
1296             }
1297             i=j-1;
1298         } else if (!strcmp(argv[i], "-mutatee")) {
1299             i++;
1300             if (*argv[i]=='_')
1301                 strcat(mutateeName,argv[i]);
1302             else
1303                 strcpy(mutateeName,argv[i]);
1304 #if defined(i386_unknown_nt4_0) \
1305  || defined(i386_unknown_linux2_0) \
1306  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
1307  || defined(sparc_sun_solaris2_4) \
1308  || defined(ia64_unknown_linux2_4)
1309         } else if (!strcmp(argv[i], "-relocate")) {
1310             forceRelocation = true;
1311 #endif
1312 #if defined(x86_64_unknown_linux2_4)
1313         } else if (!strcmp(argv[i], "-m32")) {
1314             ABI_32=true;
1315 #endif
1316         } else {
1317             fprintf(stderr, "Usage: test7 "
1318                     "[-V] [-verbose] "
1319 #if defined(mips_sgi_irix6_4)
1320                     "[-n32] "
1321 #endif
1322                     "[-mutatee <test7.mutatee>] "
1323                     "[-run <test#> <test#> ...] "
1324                     "[-skip <test#> <test#> ...]\n");
1325             fprintf(stderr, "%d subtests\n", MAX_TEST);
1326             exit(-1);
1327         }
1328     }
1329
1330     if (!runAllTests) {
1331         printf("Running Tests: ");
1332         for (unsigned int j=1; j <= MAX_TEST; j++) {
1333             if (runTest[j]) printf("%d ", j);
1334         }
1335         printf("\n");
1336     }
1337
1338     // patch up the default compiler in mutatee name (if necessary)
1339     if (!strstr(mutateeName, "_"))
1340 #if defined(i386_unknown_nt4_0)
1341         strcat(mutateeName,"_VC");
1342 #else
1343         strcat(mutateeName,"_gcc");
1344 #endif
1345     if (ABI_32 || strstr(mutateeName,"_m32")) {
1346         // patch up file names based on alternate ABI (as necessary)
1347         if (!strstr(mutateeName, "_m32")) strcat(mutateeName,"_m32");
1348     }
1349     // patch up the platform-specific filename extensions
1350 #if defined(i386_unknown_nt4_0)
1351     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
1352 #endif
1353
1354     mutatorMAIN(mutateeName);
1355
1356     return 0;
1357 }