Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / tests / src / test3.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: test3.C,v 1.57 2008/04/11 23:30:33 legendre Exp $
33 //
34 // libdyninst validation suite test #3
35 //    Author: Jeff Hollingsworth (6/18/99)
36 //
37
38 //  This program tests having multiple active mutatee processes.
39 //   
40 //  To run a subset of the tests, enter -run <test nums> on the command
41 //      line.
42 //
43 //  Naming conventions:
44 //      All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
45 //          XX is the test number
46 //          YY is the instance withing the test
47 //          func1_2 is the second function used in test case #1.
48 //
49
50 #include <stdio.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <sys/types.h>
54 #ifdef i386_unknown_nt4_0
55 #define WIN32_LEAN_AND_MEAN
56 #include <windows.h>
57 #include <winbase.h>
58 #define unlink _unlink
59 #else
60 #include <sys/wait.h>
61 #include <unistd.h>
62 #endif
63
64 #include "BPatch.h"
65 #include "BPatch_Vector.h"
66 #include "BPatch_thread.h"
67 #include "BPatch_snippet.h"
68 #include "test_util.h"
69
70
71 int debugPrint = 0; // internal "mutator" tracing
72 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
73
74 bool forceRelocation = false;  // Force relocation upon instrumentation
75
76 const unsigned int MAX_MUTATEES = 32;
77 unsigned int Mutatees=3;
78
79 bool runAllTests = true;
80 const unsigned int MAX_TEST = 7;
81 bool passedTest[MAX_TEST+1];
82
83 template class BPatch_Vector<BPatch_variableExpr*>;
84
85 BPatch *bpatch;
86
87 static const char *mutateeNameRoot = "test3.mutatee";
88
89 // control debug printf statements
90 void dprintf(const char *fmt, ...) {
91    va_list args;
92    va_start(args, fmt);
93
94    if(debugPrint)
95       vfprintf(stderr, fmt, args);
96
97    va_end(args);
98
99    fflush(stderr);
100 }
101
102 /**************************************************************************
103  * Error callback
104  **************************************************************************/
105
106 #define DYNINST_NO_ERROR -1
107
108 int expectError = DYNINST_NO_ERROR;
109
110 void errorFunc(BPatchErrorLevel level, int num, const char * const *params)
111 {
112     if (num == 0) {
113         // conditional reporting of warnings and informational messages
114         if (errorPrint) {
115             if (level == BPatchInfo)
116               { if (errorPrint > 1) printf("%s\n", params[0]); }
117             else
118                 printf("%s", params[0]);
119         }
120     } else {
121         // reporting of actual errors
122         char line[256];
123         const char *msg = bpatch->getEnglishErrorString(num);
124         bpatch->formatErrorString(line, sizeof(line), msg, params);
125         
126         if (num != expectError) {
127             printf("Error #%d (level %d): %s\n", num, level, line);
128         
129             // We consider some errors fatal.
130             if (num == 101) {
131                exit(-1);
132             }
133         }
134     }
135 }
136
137 /**************************************************************************
138  * Utility functions
139  **************************************************************************/
140
141 //
142 // Return a pointer to a pdstring identifying a BPatch_procedureLocation
143 //
144 const char *locationName(BPatch_procedureLocation l)
145 {
146     switch(l) {
147       case BPatch_entry:
148         return "entry";
149       case BPatch_exit:
150         return "exit";
151       case BPatch_subroutine:
152         return "call points";
153       case BPatch_longJump:
154         return "long jump";
155       case BPatch_allLocations:
156         return "all";
157       default:
158         return "<invalid BPatch_procedureLocation>";
159     };
160 }
161
162
163 //
164 // Insert "snippet" at the location "loc" in the function "inFunction."
165 // Returns the value returned by BPatch_thread::insertSnippet.
166 //
167 BPatchSnippetHandle *insertSnippetAt(BPatch_thread *appThread,
168         BPatch_image *appImage, char *inFunction, BPatch_procedureLocation loc,
169         BPatch_snippet &snippet, int testNo, char *testName)
170 {
171     // Find the point(s) we'll be instrumenting
172
173   BPatch_Vector<BPatch_function *> found_funcs;
174     if ((NULL == appImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
175       fprintf(stderr, "    Unable to find function %s\n",
176               inFunction);
177       exit(1);
178     }
179
180     if (1 < found_funcs.size()) {
181       fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
182               __FILE__, __LINE__, found_funcs.size(), inFunction);
183     }
184
185     BPatch_Vector<BPatch_point *> *points = found_funcs[0]->findPoint(loc);
186
187     if (!points) {
188         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
189         fprintf(stderr, "    Unable to find point %s - %s\n",
190                 inFunction, locationName(loc));
191         exit(-1);
192     }
193
194     return appThread->insertSnippet(snippet, *points);
195 }
196
197 //
198 // Create a snippet that calls the function "funcName" with no arguments
199 //
200 BPatch_snippet *makeCallSnippet(BPatch_image *appImage, char *funcName,
201                                 int testNo, char *testName)
202 {
203   BPatch_Vector<BPatch_function *> bpfv;
204   if (NULL == appImage->findFunction(funcName, bpfv) || !bpfv.size()
205       || NULL == bpfv[0]){
206     fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
207     fprintf(stderr, "    Unable to find function %s\n", funcName);
208     exit(1);
209   }
210
211   BPatch_function *call_func = bpfv[0];
212
213     BPatch_Vector<BPatch_snippet *> nullArgs;
214     BPatch_snippet *ret = new BPatch_funcCallExpr(*call_func, nullArgs);
215
216     if (ret == NULL) {
217         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
218         fprintf(stderr, "    Unable to create snippet to call %s\n", funcName);
219         exit(1);
220     }
221
222     return ret;
223 }
224
225 //
226 // Insert a snippet to call function "funcName" with no arguments into the
227 // procedure "inFunction" at the points given by "loc."
228 //
229 BPatchSnippetHandle *insertCallSnippetAt(BPatch_thread *appThread,
230         BPatch_image *appImage, char *inFunction, BPatch_procedureLocation loc,
231         char *funcName, int testNo, char *testName)
232 {
233     BPatch_snippet *call_expr =
234         makeCallSnippet(appImage, funcName, testNo, testName);
235
236     BPatchSnippetHandle *ret = insertSnippetAt(appThread, appImage,
237                                                inFunction, loc, *call_expr,
238                                                testNo, testName);
239     if (ret == NULL) {
240         fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
241         fprintf(stderr, "    Unable to insert snippet to call function %s\n",
242                 funcName);
243         exit(-1);
244     }
245
246     delete call_expr;
247     
248     return ret;
249 }
250
251 void MopUpMutatees(const unsigned int mutatees, BPatch_thread *appThread[])
252 {
253     unsigned int n=0;
254     dprintf("MopUpMutatees(%d)\n", mutatees);
255     for (n=0; n<mutatees; n++) {
256         if (appThread[n]) {
257             if (appThread[n]->terminateExecution()) {
258                 assert(appThread[n]->terminationStatus() == ExitedViaSignal);
259                 int signalNum = appThread[n]->getExitSignal();
260                 dprintf("Mutatee terminated from signal 0x%x\n", signalNum);
261             } else {
262                 printf("Failed to mop up mutatee %d (pid=%d)!\n",
263                         n, appThread[n]->getPid());
264             }
265         } else {
266             printf("Mutatee %d already terminated?\n", n);
267         }
268     }
269     dprintf("MopUpMutatees(%d) done\n", mutatees);
270 }
271
272 /**************************************************************************
273  * Tests
274  **************************************************************************/
275
276 //
277 // Start Test Case #1 - create processes and process events from each
278 //     Just let them run a while, then kill them, no instrumentation added.
279 //
280 void mutatorTest1(char *pathname, BPatch *bpatch)
281 {
282     unsigned int n=0;
283     const char *child_argv[5];
284     child_argv[n++] = pathname;
285     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
286     child_argv[n++] = const_cast<char*>("-run");
287     child_argv[n++] = const_cast<char*>("1");       // run test1 in mutatee
288     child_argv[n++] = NULL;
289
290     BPatch_thread *appThread[MAX_MUTATEES];
291
292     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
293
294     // Start the mutatees
295     for (n=0; n<Mutatees; n++) {
296         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
297         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
298         if (!appThread[n]) {
299             printf("*ERROR*: unable to create handle%d for executable\n", n);
300             printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
301             MopUpMutatees(n-1,appThread);
302             return;
303         }
304         dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
305     }
306
307     dprintf("Letting mutatee processes run a short while (5s).\n");
308     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
309
310     P_sleep(5);
311     dprintf("Terminating mutatee processes.\n");
312
313     unsigned int numTerminated=0;
314     for (n=0; n<Mutatees; n++) {
315         bool dead = appThread[n]->terminateExecution();
316         if (!dead || !(appThread[n]->isTerminated())) {
317             printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
318             printf("    mutatee process [%d] was not terminated\n", n);
319             continue;
320         }
321         if(appThread[n]->terminationStatus() != ExitedViaSignal) {
322             printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
323             printf("    mutatee process [%d] didn't get notice of termination\n", n);
324             continue;
325         }
326         int signalNum = appThread[n]->getExitSignal();
327         dprintf("Terminated mutatee [%d] from signal 0x%x\n", n, signalNum);
328         numTerminated++;
329         delete appThread[n];
330     }
331
332     if (numTerminated == Mutatees) {
333         printf("Passed Test #1 (simultaneous multiple-process management - terminate)\n");
334         passedTest[1] = true;
335     }
336 }
337
338 //
339 // Start Test Case #2 - create processes and process events from each
340 //     Just let them run to finish, no instrumentation added.
341 //
342 void mutatorTest2(char *pathname, BPatch *bpatch)
343 {
344     unsigned int n=0;
345     const char *child_argv[5];
346     child_argv[n++] = pathname;
347     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
348     child_argv[n++] = const_cast<char*>("-run");
349     child_argv[n++] = const_cast<char*>("2");       // run test2 in mutatee
350     child_argv[n++] = NULL;
351
352     BPatch_thread *appThread[MAX_MUTATEES];
353
354     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
355
356     // Start the mutatees
357     for (n=0; n<Mutatees; n++) {
358         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
359         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
360         if (!appThread[n]) {
361             printf("*ERROR*: unable to create handle%d for executable\n", n);
362             printf("**Failed** test #2 (simultaneous multiple-process management - exit)\n");
363             MopUpMutatees(n-1,appThread);
364             return;
365         }
366         dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
367     }
368     dprintf("Letting %d mutatee processes run.\n", Mutatees);
369     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
370
371     unsigned int numTerminated=0;
372     bool terminated[MAX_MUTATEES];
373     for (n=0; n<Mutatees; n++) terminated[n]=false;
374
375     // monitor the mutatee termination reports
376     while (numTerminated < Mutatees) {
377         bpatch->waitForStatusChange();
378         for (n=0; n<Mutatees; n++)
379             if (!terminated[n] && (appThread[n]->isTerminated())) {
380                 if(appThread[n]->terminationStatus() == ExitedNormally) {
381                     int exitCode = appThread[n]->getExitCode();
382                     if (exitCode || debugPrint)
383                         dprintf("Mutatee %d exited with exit code 0x%x\n", n,
384                                 exitCode);
385                 }
386                 else if(appThread[n]->terminationStatus() == ExitedViaSignal) {
387                     int signalNum = appThread[n]->getExitSignal();
388                     if (signalNum || debugPrint)
389                         dprintf("Mutatee %d exited from signal 0x%d\n", n,
390                                 signalNum);
391                 }
392                 terminated[n]=true;
393                 delete appThread[n];
394                 numTerminated++;
395             }
396             else if (!terminated[n] && (appThread[n]->isStopped())) {
397                 appThread[n]->continueExecution();
398             }
399     }
400
401     if (numTerminated == Mutatees) {
402         printf("Passed Test #2 (simultaneous multiple-process management - exit)\n");
403         passedTest[2] = true;
404     }
405 }
406
407 //
408 // read the result code written to the file test3.out.<pid> and return it
409 //
410 int readResult(int pid)
411 {
412     int ret;
413     FILE *fp;
414     char filename[80];
415
416     sprintf(filename, "test3.out.%d", pid);
417     fp = fopen(filename, "r");
418     if (!fp) {
419         fprintf(stderr, "%s[%d]: ERROR: unable to open output file %s: %s\n", FILE__, __LINE__, filename,strerror(errno));
420         return -1;
421     }
422     fscanf(fp, "%d\n", &ret);
423     fclose(fp);
424     // don't need the file any longer so delete it now
425     unlink(filename);
426
427     return ret;
428 }
429
430 //
431 // Start Test Case #3 - create processes and insert different code into
432 //     each one.  The code sets a global variable which the mutatee then
433 //     writes to a file.  After all mutatees exit, the mutator reads the
434 //     files to verify that the correct code ran in each mutatee.
435 //     The first mutator should write a 1 to the file, the second a 2, etc.
436 //     If no code is patched into the mutatees, the value is 0xdeadbeef.
437 //
438 void mutatorTest3(char *pathname, BPatch *bpatch)
439 {
440     unsigned int n=0;
441     const char *child_argv[5];
442     child_argv[n++] = pathname;
443     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
444     child_argv[n++] = const_cast<char*>("-run");
445     child_argv[n++] = const_cast<char*>("3");       // run test3 in mutatee
446     child_argv[n++] = NULL;
447
448     int pid[MAX_MUTATEES];
449     BPatch_thread *appThread[MAX_MUTATEES];
450
451     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
452
453     // Start the mutatees
454     for (n=0; n<Mutatees; n++) {
455         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
456         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
457         if (!appThread[n]) {
458             printf("*ERROR*: unable to create handle%d for executable\n", n);
459             printf("**Failed** test #3 (instrument multiple processes)\n");
460             MopUpMutatees(n-1,appThread);
461             return;
462         }
463         pid[n] = appThread[n]->getPid();
464         dprintf("Mutatee %d started, pid=%d\n", n, pid[n]);
465     }
466
467     // Instrument mutatees
468     for (n=0; n<Mutatees; n++) {
469         dprintf("Instrumenting %d/%d\n", n, Mutatees);
470
471         const char *Func="func3_1";
472         const char *Var="test3ret";
473         const char *Call="call3_1";
474         BPatch_image *img = appThread[n]->getImage();
475
476   BPatch_Vector<BPatch_function *> found_funcs;
477     if ((NULL == img->findFunction(Func, found_funcs, 1)) || !found_funcs.size()) {
478       fprintf(stderr, "    Unable to find function %s\n",
479               Func);
480       exit(1);
481     }
482
483     if (1 < found_funcs.size()) {
484       fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
485               __FILE__, __LINE__, found_funcs.size(), Func);
486     }
487
488     BPatch_Vector<BPatch_point *> *point = found_funcs[0]->findPoint(BPatch_entry);
489
490         if (!point || (*point).size() == 0) {
491             printf("  Unable to find entry point to \"%s\".\n", Func);
492             printf("**Failed** test #3 (instrument multiple processes)\n");
493             MopUpMutatees(Mutatees,appThread);
494             return;
495         }
496         BPatch_variableExpr *var = img->findVariable(Var);
497         if (var == NULL) {
498             printf("  Unable to find variable \"%s\".\n", Var);
499             printf("**Failed** test #3 (instrument multiple processes)\n");
500             MopUpMutatees(Mutatees,appThread);
501             return;
502         }
503
504         BPatch_Vector<BPatch_function *> bpfv;
505         if (NULL == img->findFunction(Call, bpfv) || !bpfv.size()
506             || NULL == bpfv[0]){
507           printf("  Unable to find target function \"%s\".\n", Call);
508           printf("**Failed** test #3 (instrument multiple processes)\n");
509           exit(1);
510         }
511
512         BPatch_function *callFunc = bpfv[0];
513
514         // start with a simple snippet
515         BPatch_arithExpr snip(BPatch_assign, *var, BPatch_constExpr((int)n));
516         BPatchSnippetHandle *inst = appThread[n]->insertSnippet(snip, *point);
517         if (inst == NULL) {
518             printf("  Failed to insert simple snippet.\n");
519             printf("**Failed** test #3 (instrument multiple processes)\n");
520             MopUpMutatees(Mutatees,appThread);
521             return;
522         }
523
524         // now add a call snippet
525         BPatch_Vector<BPatch_snippet *> callArgs;
526         BPatch_constExpr arg1(2); callArgs.push_back(&arg1);
527         BPatch_constExpr arg2((int)n); callArgs.push_back(&arg2);
528         BPatch_funcCallExpr callExpr(*callFunc, callArgs);
529         BPatchSnippetHandle *call = 
530                 appThread[n]->insertSnippet(callExpr, *point);
531         if (call == NULL) {
532             printf("  Failed to insert call snippet.\n");
533             printf("**Failed** test #3 (instrument multiple processes)\n");
534             MopUpMutatees(Mutatees,appThread);
535             return;
536         }
537     }
538
539     dprintf("Letting %d mutatee processes run.\n", Mutatees);
540     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
541
542     unsigned int numTerminated=0;
543     bool terminated[MAX_MUTATEES];
544     for (n=0; n<Mutatees; n++) terminated[n]=false;
545
546     // monitor the mutatee termination reports
547     while (numTerminated < Mutatees) {
548         bpatch->waitForStatusChange();
549         for (n=0; n<Mutatees; n++)
550             if (!terminated[n] && (appThread[n]->isTerminated())) {
551                 if(appThread[n]->terminationStatus() == ExitedNormally) {
552                     int exitCode = appThread[n]->getExitCode();
553                     if (exitCode || debugPrint)
554                         dprintf("Mutatee %d exited with exit code 0x%x\n", n,
555                                 exitCode);
556                 }
557                 else if(appThread[n]->terminationStatus() == ExitedViaSignal) {
558                     int signalNum = appThread[n]->getExitSignal();
559                     if (signalNum || debugPrint)
560                         dprintf("Mutatee %d exited from signal 0x%d\n", n,
561                                 signalNum);
562                 }
563                 delete appThread[n];
564                 terminated[n]=true;
565                 numTerminated++;
566             }
567             else if (!terminated[n] && (appThread[n]->isStopped())) {
568                fprintf(stderr, "%s[%d]:  continuing stopped thread\n", __FILE__, __LINE__); 
569                appThread[n]->continueExecution();
570             }
571     }
572
573     // now read the files to see if the value is what is expected
574     bool allCorrect=true;
575     int ret[MAX_MUTATEES];
576     for (n=0; n<Mutatees; n++) {
577         ret[n]=readResult(pid[n]);
578         if (ret[n] != (int)n) {
579             printf("    mutatee process %d produced %d, not %d\n",
580                 pid[n], ret[n], n);
581             allCorrect=false;
582         } else {
583             dprintf("    mutatee process %d produced expected value %d\n", 
584                 pid[n], ret[n]);
585         }
586     }
587
588     if (allCorrect) {
589         printf("Passed Test #3 (instrument multiple processes)\n");
590         passedTest[3] = true;
591     } else {
592         printf("**Failed** test #3 (instrument multiple processes)\n");
593     }
594 }
595
596 //
597 // Start Test Case #4 - create one process, wait for it to exit.  Then 
598 //     create a second one and wait for it to exit.  Repeat as required.
599 //
600 void mutatorTest4(char *pathname, BPatch *bpatch)
601 {
602     unsigned int n=0;
603     const char *child_argv[5];
604     child_argv[n++] = pathname;
605     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
606     child_argv[n++] = const_cast<char*>("-run");
607     child_argv[n++] = const_cast<char*>("2");           // run test2 in mutatee
608     child_argv[n++] = NULL;
609
610     BPatch_thread *appThread;
611
612     for (n=0; n<Mutatees; n++) {
613         // Start the mutatee
614         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
615         appThread = bpatch->createProcess(pathname, child_argv, NULL);
616         if (!appThread) {
617             printf("*ERROR*: unable to create handle%d for executable\n", n);
618             printf("**Failed** Test #4 (sequential multiple-process management - exit)\n");
619             return;
620         }
621         dprintf("Mutatee %d started, pid=%d\n", n, appThread->getPid());
622
623         appThread->continueExecution();
624
625         while (!appThread->isTerminated()) {
626             if (appThread->isStopped())
627                appThread->continueExecution();
628             bpatch->waitForStatusChange();
629         }
630
631         if(appThread->terminationStatus() == ExitedNormally) {
632            int exitCode = appThread->getExitCode();
633            if (exitCode || debugPrint)
634                dprintf("Mutatee %d exited with exit code 0x%x\n", n, exitCode);
635         } else if(appThread->terminationStatus() == ExitedViaSignal) {
636            int signalNum = appThread->getExitSignal();
637            if (signalNum || debugPrint)
638                dprintf("Mutatee %d exited from signal 0x%d\n", n, signalNum);
639         }
640         delete appThread;
641     }
642
643     printf("Passed Test #4 (sequential multiple-process management - exit)\n");
644     passedTest[4] = true;
645 }
646
647
648 //
649 // Start Test Case #5 - create one process, wait for it to exit.  Then 
650 //     create a second one and wait for it to exit.  Repeat as required.
651 //     Differs from test 3 in that the mutatee processes terminate with
652 //     abort rather than exit.
653 //
654 void mutatorTest5(char *pathname, BPatch *bpatch)
655 {
656     unsigned int n=0;
657     const char *child_argv[5];
658     child_argv[n++] = pathname;
659     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
660     child_argv[n++] = const_cast<char*>("-run");
661     child_argv[n++] = const_cast<char*>("5");     // run test5 in mutatee
662     child_argv[n++] = NULL;
663
664     BPatch_thread *appThread;
665
666     for (n=0; n<Mutatees; n++) {
667         // Start the mutatee
668         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
669         appThread = bpatch->createProcess(pathname, child_argv, NULL);
670         if (!appThread) {
671             printf("*ERROR*: unable to create handle%d for executable\n", n);
672             printf("**Failed** Test #5 (sequential multiple-process management - abort)\n");
673             return;
674         }
675         dprintf("Mutatee %d started, pid=%d\n", n, appThread->getPid());
676         appThread->continueExecution();
677
678         while (!appThread->isTerminated()) {
679                fprintf(stderr, "%s[%d]:  !terminated\n", FILE__, __LINE__);
680             if (appThread->isStopped()) {
681                fprintf(stderr, "%s[%d]:  hitting continue...\n", FILE__, __LINE__);
682               appThread->continueExecution();
683             }
684             bpatch->waitForStatusChange();
685         }
686
687         if(appThread->terminationStatus() == ExitedNormally) {
688            int exitCode = appThread->getExitCode();
689            if (exitCode || debugPrint)
690                dprintf("Mutatee %d exited with exit code 0x%x\n", n, exitCode);
691         } else if(appThread->terminationStatus() == ExitedViaSignal) {
692            int signalNum = appThread->getExitSignal();
693            if (signalNum || debugPrint)
694                dprintf("Mutatee %d exited from signal 0x%d\n", n, signalNum);
695         }
696         delete appThread;
697     }
698
699     printf("Passed Test #5 (sequential multiple-process management - abort)\n");
700     passedTest[5] = true;
701 }
702
703 //
704 // Start Test Case #6 - attach processes and process events from each
705 //     Just let them run a while, then kill them, no instrumentation added.
706 //
707 #if !defined(os_windows)
708 int forkNewMutatee(const char *filename, const char *child_argv[])
709 {
710   int pid;
711   static int pgid = 0;
712   pid = fork();
713   if (pid == 0) {
714     // child, do exec
715     dprintf("%s[%d]:  before exec in new mutatee %s, pgid = %d\n", __FILE__, __LINE__, filename, getpgid(0));
716
717     //  sanity check, make sure that all forked processes have the same process group id
718     if (!pgid) pgid = getpgid(0);
719     else if (pgid != getpgid(0)) {
720        fprintf(stderr, "%s[%d]:  Something is broken with the test -- all forked processes should belong to the same group\n", __FILE__, __LINE__);
721        abort();
722     }
723
724     execv (filename, (char * const *)child_argv);
725     //  if we get here, error
726     fprintf(stderr, "%s[%d]:  exec failed: %s\n", __FILE__, __LINE__, strerror(errno));
727     exit (-1);
728   }
729   else if (pid < 0) {
730     //  fork error, fail test
731     fprintf(stderr, "%s[%d]:  fork failed: %s\n", __FILE__, __LINE__, strerror(errno));
732     return -1;
733   }
734   
735   return pid;
736 }
737  
738 bool grandparentForkMutatees(int num, int *pids, const char *filename, const char *child_argv[])
739 {
740     //  this is like fork_mutatee in test_util.C, except it guarantees that mutatees are all
741     //  in the same process group.
742
743     //  need a pipe to get grandchild pids back to grandparent
744     int filedes[2];
745     pipe(filedes);
746
747     int childpid = fork();
748     if (childpid > 0) {
749       //parent -- read grandchild pids
750       for (unsigned int i = 0; i < num; ++i) {
751         if (0 > read(filedes[0], &pids[i], sizeof(int))) {
752            fprintf(stderr, "%s[%d]:  read failed %s\n", __FILE__, __LINE__, strerror(errno));
753            abort();
754         }
755         dprintf("%s[%d]:  parent -- have new pid %d\n", __FILE__, __LINE__, pids[i]);
756       }
757
758       //  and wait for child exit
759       int status;
760       int waitpid_ret = waitpid(childpid, &status, 0);
761       if (waitpid_ret != childpid) {
762         fprintf(stderr, "%s[%d]:  waitpid failed: %s\n", __FILE__, __LINE__, strerror(errno));
763         exit (0);
764       }
765       if (!WIFEXITED(status)) {
766          fprintf(stderr, "%s[%d]:  not exited\n", __FILE__, __LINE__);
767          exit(-1);
768       }
769       close(filedes[0]);
770       close(filedes[1]);
771       return true;
772     }
773
774     else if (childpid == 0) {
775       int gchild_pid;
776       //  child -- run as its own session, fork children (mutatees), and exit.
777       setsid();
778
779       for (int n=0; n<num; n++) {
780         gchild_pid = forkNewMutatee(filename, child_argv);
781         if (gchild_pid < 0) {
782            fprintf(stderr, "%s[%d]:  failed to fork/exec\n", __FILE__, __LINE__);
783            return false;
784         }
785         dprintf("%s[%d]:  forked mutatee %d\n", __FILE__, __LINE__, gchild_pid);
786         //  let parent know the grandchild pid
787         if (0 > write(filedes[1], &gchild_pid, sizeof(int))) {
788             fprintf(stderr, "%s[%d]:  write failed\n", __FILE__, __LINE__);
789             abort();
790         }
791       }
792       close (filedes[0]);
793       close (filedes[1]);
794       exit(0);
795    }
796    else if (childpid < 0) {
797      //  fork error, fail test
798      close (filedes[0]);
799      close (filedes[1]);
800      fprintf(stderr, "%s[%d]:  fork failed: %s\n", __FILE__, __LINE__, strerror(errno));
801      return false;
802    }
803    return true;
804 }
805 #endif
806
807 void mutatorTest6(char *pathname, BPatch *bpatch)
808 {
809 #if !defined(os_windows) 
810     unsigned int n=0;
811     int pids[Mutatees];
812     const char *child_argv[5];
813     child_argv[n++] = pathname;
814     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
815     child_argv[n++] = const_cast<char*>("-run");
816     child_argv[n++] = const_cast<char*>("1");       // use -run 1, it just spins, ok for our purpose
817     child_argv[n++] = NULL;
818
819     BPatch_thread *appThread[MAX_MUTATEES];
820
821     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
822
823     // Start the mutatees
824     if (!grandparentForkMutatees(Mutatees, pids, pathname, child_argv)) {
825       fprintf(stderr, "%s[%d]:  failed to fork mutatees\n", __FILE__, __LINE__);
826       exit(1);
827     }
828
829     P_sleep(2);
830     //  Attach to them
831     for (n=0; n<Mutatees; n++) {
832         dprintf("Attaching \"%s\" %d/%d\n", pathname, n, Mutatees);
833         appThread[n] = bpatch->attachProcess(pathname, pids[n]);
834         if (!appThread[n]) {
835             printf("%s[%d]: *ERROR*: unable to create handle %d for executable, pid = %d\n", 
836                    __FILE__, __LINE__, n, pids[n]);
837             printf("**Failed** test #6 (simultaneous multiple-process management - terminate)\n");
838             MopUpMutatees(n-1,appThread);
839             return;
840         }
841         dprintf("Mutatee %d attached, pid=%d\n", n, appThread[n]->getPid());
842     }
843
844     dprintf("Letting mutatee processes run a short while (5s).\n");
845     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
846
847     P_sleep(5);
848     dprintf("Terminating mutatee processes.\n");
849
850     //  And kill them
851     unsigned int numTerminated=0;
852     for (n=0; n<Mutatees; n++) {
853         bool dead = appThread[n]->terminateExecution();
854         if (!dead || !(appThread[n]->isTerminated())) {
855             printf("**Failed** test #6 (simultaneous multiple-process management - attach terminate)\n");
856             printf("    mutatee process [%d] was not terminated\n", n);
857             continue;
858         }
859 #if !defined(os_aix) && !defined(os_solaris) && !defined(os_osf)
860         // This will work on Linux (and others?), but not AIX/Solaris due to waitpid not working
861         // on non-children.
862         if(appThread[n]->terminationStatus() != ExitedViaSignal) {
863             printf("**Failed** test #6 (simultaneous multiple-process management - attach terminate)\n");
864             printf("    mutatee process [%d] didn't get notice of termination\n", n);
865             if (appThread[n]->terminationStatus() == ExitedNormally)
866                fprintf(stderr, "%s[%d]:  exited normally\n", __FILE__, __LINE__);
867             if (appThread[n]->terminationStatus() == NoExit)
868                fprintf(stderr, "%s[%d]:  no exit type reported\n", __FILE__, __LINE__);
869             continue;
870         }
871         int signalNum = appThread[n]->getExitSignal();
872         dprintf("Terminated mutatee [%d] from signal 0x%x\n", n, signalNum);
873 #endif
874         numTerminated++;
875         delete appThread[n];
876     }
877
878     if (numTerminated == Mutatees) {
879         printf("Passed Test #6 (simultaneous multiple-process management - attach terminate)\n");
880         passedTest[6] = true;
881     }
882 #else
883     passedTest[6] = true;
884     fprintf(stderr,"Skipped Test #6: not implemented on this platform\n");
885 #endif
886 }
887 //
888 // Start Test Case #7 - create processes and process events from each
889 //     Run a whole ton of asynchronous OneTimeCodes to test signal handling
890 //
891 unsigned int num_callbacks_issued = 0;
892 bool test7done = false;
893 #if defined (os_osf)
894 #define TEST7_NUM_ONETIMECODE 100
895 #else
896 #define TEST7_NUM_ONETIMECODE 400
897 #endif
898 #define TIMEOUT 120 /*seconds */
899
900 void test7_oneTimeCodeCallback(BPatch_thread * /*thread*/,
901                                 void *userData,
902                                 void * /*returnValue*/) {
903     num_callbacks_issued++;
904     if (num_callbacks_issued == TEST7_NUM_ONETIMECODE) {
905         *((bool *)userData) = true; // we are done
906     }
907 }
908
909 void mutatorTest7(char *pathname, BPatch *bpatch)
910 {
911     unsigned int n=0;
912     const char *child_argv[5];
913     child_argv[n++] = pathname;
914     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
915     child_argv[n++] = const_cast<char*>("-run");
916     child_argv[n++] = const_cast<char*>("1");       // run test1 in mutatee
917     child_argv[n++] = NULL;
918
919     BPatch_thread *appThread[MAX_MUTATEES];
920
921     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
922
923     // Start the mutatees
924     for (n=0; n<Mutatees; n++) {
925         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
926         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
927         if (!appThread[n]) {
928             printf("*ERROR*: unable to create handle%d for executable\n", n);
929             printf("**Failed** test #7 (simultaneous multiple-process management - terminate)\n");
930             MopUpMutatees(n-1,appThread);
931             return;
932         }
933         dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
934     }
935
936     // Register a callback that we will use to check for done-ness
937     BPatchOneTimeCodeCallback oldCallback =
938         bpatch->registerOneTimeCodeCallback(test7_oneTimeCodeCallback);
939
940     dprintf("Letting mutatee processes run a short while (5s).\n");
941     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
942
943    ////////////////////////////
944    ////////////////////////////
945
946     BPatch_snippet **irpcSnippets = new BPatch_snippet*[Mutatees];
947
948     // Build snippets for each mutatee
949     for (unsigned i = 0; i < Mutatees; i++) {
950         //  our oneTimeCode will just be a simple call to a function that increments a global variable
951         BPatch_image *appImage = appThread[i]->getImage();
952         BPatch_Vector<BPatch_function *> bpfv;
953         if (NULL == appImage->findFunction("call7_1", bpfv) || !bpfv.size()
954             || NULL == bpfv[0]){
955             fprintf(stderr, "    Unable to find function call7_1\n" );
956             exit(1);
957         }
958         
959         BPatch_function *call7_1 = bpfv[0];
960         
961         BPatch_Vector<BPatch_snippet *> nullArgs;
962         BPatch_funcCallExpr *call7_1_snip = new BPatch_funcCallExpr(*call7_1, nullArgs);
963         irpcSnippets[i] = call7_1_snip;
964     }
965
966     dprintf("Pausing apps pre-iRPC...\n");
967     for (n=0; n<Mutatees; n++) appThread[n]->stopExecution();
968
969     //  Submit inferior RPCs to all of our mutatees equally...
970     unsigned doneFlag = 0;
971     for (unsigned int i = 0; i < TEST7_NUM_ONETIMECODE; ++i) {
972       int index = i % (Mutatees);
973       //fprintf(stderr, "%s[%d]:  issuing oneTimeCode to thread %d\n", __FILE__, __LINE__, index);
974       appThread[index]->oneTimeCodeAsync(*(irpcSnippets[index]), (void *)&doneFlag);
975     }
976
977     dprintf("Running mutatees post-iRPC..., num_callbacks_isued = %d\n", num_callbacks_issued);
978     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
979
980    ////////////////////////////
981    ////////////////////////////
982
983    // and wait for completion/timeout
984    int timeout = 0;
985    while (!doneFlag && (timeout < TIMEOUT)) {
986      P_sleep(1);
987      bpatch->pollForStatusChange();
988      timeout++;
989    }
990    int test7err = false;
991    if (!doneFlag) {
992             printf("**Failed** test #7 (simultaneous multiple-process management - oneTimeCode)\n");
993             printf("   did not receive the right # of events: got %d, expected %d ", num_callbacks_issued, TEST7_NUM_ONETIMECODE);
994             test7err = true;
995    }
996
997     dprintf("Terminating mutatee processes.\n");
998
999
1000     unsigned int numTerminated=0;
1001     for (n=0; n<Mutatees; n++) {
1002         bool dead = appThread[n]->terminateExecution();
1003         if (!dead || !(appThread[n]->isTerminated())) {
1004             printf("**Failed** test #7 (simultaneous multiple-process management - oneTimeCode)\n");
1005             printf("    mutatee process [%d] was not terminated\n", n);
1006             continue;
1007         }
1008         if(appThread[n]->terminationStatus() != ExitedViaSignal) {
1009             printf("**Failed** test #7 (simultaneous multiple-process management - oneTimeCode)\n");
1010             printf("    mutatee process [%d] didn't get notice of termination\n", n);
1011             continue;
1012         }
1013         int signalNum = appThread[n]->getExitSignal();
1014         dprintf("Terminated mutatee [%d] from signal 0x%x\n", n, signalNum);
1015         numTerminated++;
1016         delete appThread[n];
1017     }
1018
1019     if  (numTerminated == Mutatees && !test7err) {
1020         printf("Passed Test #7 (simultaneous multiple-process management - oneTimeCode)\n");
1021         passedTest[7] = true;
1022     }
1023
1024         delete irpcSnippets;
1025 }
1026
1027 int main(int argc, char *argv[])
1028 {
1029     bool ABI_32=false;
1030     char mutateeName[128];
1031     char libRTname[256];
1032     bool runTest[MAX_TEST+1];           // should we run a particular test
1033
1034     strcpy(mutateeName,mutateeNameRoot);
1035     libRTname[0]='\0';
1036
1037     if (!getenv("DYNINSTAPI_RT_LIB")) {
1038          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
1039 #if defined(i386_unknown_nt4_0)
1040                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
1041 #else
1042                  "    set it to the full pathname of libdyninstAPI_RT\n");   
1043          exit(-1);
1044 #endif
1045     } else
1046          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
1047
1048     updateSearchPaths(argv[0]);
1049
1050     unsigned int i;
1051     // by default run all tests
1052     for (i=1; i <= MAX_TEST; i++) {
1053         runTest[i] = true;
1054         passedTest[i] = false;
1055     }
1056
1057     for (i=1; i < argc; i++) {
1058         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
1059         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
1060         if (strncmp(argv[i], "-verbose", 2) == 0) {
1061             debugPrint = 1;
1062         } else if (!strcmp(argv[i], "-V")) {
1063             if (libRTname[0]) 
1064                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
1065             fflush(stdout);
1066         } else if (strncmp(argv[i], "-plurality", 2) == 0) {
1067             Mutatees = atoi(argv[++i]);
1068             if (Mutatees > MAX_MUTATEES) {
1069                 printf("Limiting plurality to maximum of %d!\n", MAX_MUTATEES);
1070                 Mutatees = MAX_MUTATEES;
1071             } else if (Mutatees <= 1) {
1072                 printf("Plurality of at least 2 required for these tests!\n");
1073                 exit(-1);
1074             }
1075             dprintf ("%d mutatees to be used for each test.\n", Mutatees);
1076         } else if (!strcmp(argv[i], "-skip")) {
1077             unsigned int j;
1078             runAllTests = false;
1079             for (j=i+1; j < argc; j++) {
1080                 unsigned int testId;
1081                 if ((testId = atoi(argv[j]))) {
1082                     if ((testId > 0) && (testId <= MAX_TEST)) {
1083                         runTest[testId] = false;
1084                     } else {
1085                         printf("invalid test %d requested\n", testId);
1086                         exit(-1);
1087                     }
1088                 } else {
1089                     // end of test list
1090                     break;
1091                 }
1092             }
1093             i=j-1;
1094         } else if (!strcmp(argv[i], "-run")) {
1095             unsigned int j;
1096             runAllTests = false;
1097             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
1098             for (j=i+1; j < argc; j++) { 
1099                 unsigned int testId;
1100                 if ((testId = atoi(argv[j]))) {
1101                     if ((testId > 0) && (testId <= MAX_TEST)) {
1102                         dprintf("test %d requested\n", testId);
1103                         runTest[testId] = true;
1104                     } else {
1105                         printf("invalid test %d requested\n", testId);
1106                         exit(-1);
1107                     }
1108                 } else {
1109                     // end of test list
1110                     break;
1111                 }
1112             }
1113             i=j-1;
1114         } else if (!strcmp(argv[i], "-mutatee")) {
1115             i++;
1116             if (*argv[i]=='_')
1117                 strcat(mutateeName,argv[i]);
1118             else
1119                 strcpy(mutateeName,argv[i]);
1120 #if defined(i386_unknown_nt4_0) \
1121  || defined(i386_unknown_linux2_0) \
1122  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
1123  || defined(sparc_sun_solaris2_4) \
1124  || defined(ia64_unknown_linux2_4)
1125         } else if (!strcmp(argv[i], "-relocate")) {
1126             forceRelocation = true;
1127 #endif
1128 #if defined(x86_64_unknown_linux2_4)
1129         } else if (!strcmp(argv[i], "-m32")) {
1130             ABI_32=true;
1131 #endif
1132         } else {
1133             fprintf(stderr, "Usage: test3 "
1134                     "[-V] [-verbose] "
1135 #if defined(x86_64_unknown_linux2_4)
1136                     "[-m32] "
1137 #endif
1138                     "[-mutatee <test3.mutatee>] "
1139                     "[-plurality #] "
1140                     "[-run <test#> <test#> ...] "
1141                     "[-skip <test#> <test#> ...]\n");
1142             fprintf(stderr, "%d subtests\n", MAX_TEST);
1143             exit(-1);
1144         }
1145     }
1146
1147     if (!runAllTests) {
1148         printf("Running Tests: ");
1149         for (unsigned int j=1; j <= MAX_TEST; j++) {
1150             if (runTest[j]) printf("%d ", j);
1151         }
1152         printf("\n");
1153     }
1154
1155     // patch up the default compiler in mutatee name (if necessary)
1156     if (!strstr(mutateeName, "_"))
1157 #if defined(i386_unknown_nt4_0)
1158         strcat(mutateeName,"_VC");
1159 #else
1160         strcat(mutateeName,"_gcc");
1161 #endif
1162     if (ABI_32 || strstr(mutateeName,"_m32")) {
1163         // patch up file names based on alternate ABI (as necessary)
1164         if (!strstr(mutateeName, "_m32")) strcat(mutateeName,"_m32");
1165     }
1166     // patch up the platform-specific filename extensions
1167 #if defined(i386_unknown_nt4_0)
1168     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
1169 #endif
1170
1171     // Create an instance of the BPatch library
1172     bpatch = new BPatch;
1173
1174     // Force functions to be relocated
1175     if (forceRelocation) {
1176       bpatch->setForcedRelocation_NP(true);
1177     }
1178
1179 #if defined (sparc_sun_solaris2_4)
1180     // we use some unsafe type operations in the test cases.
1181     bpatch->setTypeChecking(false);
1182 #endif
1183
1184     // Register a callback function that prints any error messages
1185     bpatch->registerErrorCallback(errorFunc);
1186
1187     if (runTest[1]) mutatorTest1(mutateeName, bpatch);
1188     if (runTest[2]) mutatorTest2(mutateeName, bpatch);
1189     if (runTest[3]) mutatorTest3(mutateeName, bpatch);
1190     if (runTest[4]) mutatorTest4(mutateeName, bpatch);
1191     if (runTest[5]) mutatorTest5(mutateeName, bpatch);
1192     if (runTest[6]) mutatorTest6(mutateeName, bpatch);
1193     if (runTest[7]) mutatorTest7(mutateeName, bpatch);
1194
1195     unsigned int testsFailed = 0;
1196     for (i=1; i <= MAX_TEST; i++) {
1197         if (runTest[i] && !passedTest[i]) testsFailed++;
1198     }
1199
1200     if (!testsFailed) {
1201         if (runAllTests) {
1202             printf("All tests passed\n");
1203         } else {
1204             printf("All requested tests passed\n");
1205         }
1206     } else {
1207         printf("**Failed** %d test%c\n",testsFailed,(testsFailed>1)?'s':' ');
1208     }
1209
1210     return (testsFailed ? 127 : 0);
1211 }