This commit allows us to force the relocation of functions being
[dyninst.git] / dyninstAPI / tests / src / test4.C
1 // $Id: test4.C,v 1.11 2001/07/11 21:21:09 gurari Exp $
2 //
3
4 #include <stdio.h>
5 #include <string.h>
6 #include <assert.h>
7 #ifdef i386_unknown_nt4_0
8 #include <windows.h>
9 #include <winbase.h>
10 #else
11 #include <unistd.h>
12 #endif
13
14 #include "BPatch.h"
15 #include "BPatch_Vector.h"
16 #include "BPatch_thread.h"
17 #include "BPatch_snippet.h"
18 #include "test_util.h"
19
20
21 char *mutateeNameRoot = "test4a.mutatee";
22
23 int inTest;             // current test #
24 int expectError;
25 int debugPrint = 0; // internal "mutator" tracing
26 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
27
28 bool forceRelocation = false;  // Force relocation upon instrumentation
29
30 #define dprintf if (debugPrint) printf
31
32 bool runAllTests = true;
33 const unsigned int MAX_TEST = 4;
34 bool runTest[MAX_TEST+1];
35 bool passedTest[MAX_TEST+1];
36 bool failedTest[MAX_TEST+1];
37 int threadCount = 0;
38 BPatch_thread *mythreads[25];
39
40 BPatch *bpatch;
41
42 /*
43  * Given a string variable name and an expected value, lookup the varaible
44  *    in the child process, and verify that the value matches.
45  *
46  */
47 bool verifyChildMemory(BPatch_thread *appThread, 
48                               char *name, int expectedVal)
49 {
50      BPatch_image *appImage = appThread->getImage();
51
52      if (!appImage) {
53          dprintf("unable to locate image for %d\n", appThread->getPid());
54          return false;
55      }
56
57      BPatch_variableExpr *var = appImage->findVariable(name);
58      if (!var) {
59          dprintf("unable to located variable %s in child\n", name);
60          return false;
61      }
62
63      int actualVal;
64      var->readValue(&actualVal);
65
66      if (expectedVal != actualVal) {
67          printf("*** for %s, expected val = %d, but actual was %d\n",
68                 name, expectedVal, actualVal);
69          return false;
70      } else {
71          dprintf("verified %s was = %d\n", name, actualVal);
72          return true;
73      }
74 }
75
76 BPatch_thread *test2Child;
77 BPatch_thread *test2Parent;
78 BPatch_thread *test4Child;
79 BPatch_thread *test4Parent;
80
81
82 void forkFunc(BPatch_thread *parent, BPatch_thread *child)
83 {
84     BPatch_image *appImage;
85     BPatch_Vector<BPatch_snippet *> nullArgs;
86
87     if (child) mythreads[threadCount++] = child;
88
89     if (!child) {
90         dprintf("in prefork for %d\n", parent->getPid());
91     } else {
92         dprintf("in fork of %d to %d\n", parent->getPid(), child->getPid());
93     }
94
95     if (inTest == 1) {
96        // nothing to do for this case
97     } else if (inTest == 2) {
98        if (!child) return;      // skip prefork case
99
100        // insert code into parent
101        appImage = parent->getImage();
102        assert(appImage);
103        BPatch_function *func2_3 = appImage->findFunction("func2_3");
104        assert(func2_3);
105        BPatch_funcCallExpr callExpr2(*func2_3, nullArgs);
106        BPatch_Vector<BPatch_point *> *point2;
107        point2 = appImage->findProcedurePoint("func2_2", BPatch_exit);
108        assert(point2);
109        parent->insertSnippet(callExpr2, *point2);
110
111        // insert different code into child
112        appImage = child->getImage();
113        assert(appImage);
114        BPatch_function *func2_4 = appImage->findFunction("func2_4");
115        BPatch_funcCallExpr callExpr1(*func2_4, nullArgs);
116        BPatch_Vector<BPatch_point *> *point1;
117        point1 = appImage->findProcedurePoint("func2_2", BPatch_exit);
118        child->insertSnippet(callExpr1, *point1);
119
120        test2Child = child;
121        test2Parent = parent;
122     } else if (inTest == 4) {
123        if (!child) return;      // skip prefork case
124
125        // insert code into parent
126        appImage = parent->getImage();
127        assert(appImage);
128        BPatch_function *func4_3 = appImage->findFunction("func4_3");
129        assert(func4_3);
130        BPatch_funcCallExpr callExpr2(*func4_3, nullArgs);
131        BPatch_Vector<BPatch_point *> *point2;
132        point2 = appImage->findProcedurePoint("func4_2", BPatch_exit);
133        assert(point2);
134        parent->insertSnippet(callExpr2, *point2);
135
136        // code goes into child after in-exec in this test.
137
138        test4Child = child;
139     }
140 }
141
142 void exitFunc(BPatch_thread *thread, int code)
143 {
144     // Read out the values of the variables.
145     if (inTest == 1) {
146         if (thread->getPid() == code) {
147             if (verifyChildMemory(thread, "globalVariable1_1", 1000001)) {
148                 printf("Passed test #1 (exit callback)\n");
149                 passedTest[1] = true;
150             } else {
151                 passedTest[1] = false;
152             }
153         } else {
154             printf("**Failed** test #1 (exit callback)\n");
155             printf("    exit code = %d, was not equal to pid\n", code);
156         }
157     } else if (inTest == 2) {
158         static int exited = 0;
159         exited++;
160         if (thread->getPid() != code) {
161             printf("Failed test #2 (fork callback)\n");
162             printf("    exit code was not equal to pid\n");
163             exited = 0;
164         } else {
165             dprintf("test #2, pid %d exited\n", code);
166             if ((test2Parent == thread) &&
167                 !verifyChildMemory(test2Parent, "globalVariable2_1", 2000002)) {
168                 failedTest[2] = true;
169             }
170             if ((test2Child == thread) &&
171                 !verifyChildMemory(test2Child, "globalVariable2_1", 2000003)) {
172                 failedTest[2] = true;
173             }
174
175             // See if all the processes are done
176             if (exited == 2) {
177                 if (!failedTest[2]) {
178                     printf("Passed test #2 (fork callback)\n");
179                     passedTest[2] = true;
180                 } else {
181                     printf("Failed test #2 (fork callback)\n");
182                 }
183             }
184         }
185     } else if (inTest == 3) {
186         // simple exec 
187         if (!verifyChildMemory(thread, "globalVariable3_1", 3000002)) {
188             printf("Failed test #3 (exec callback)\n");
189         } else {
190             printf("Passed test #3 (exec callback)\n");
191             passedTest[3] = true;
192         }
193     } else if (inTest == 4) {
194         static int exited = 0;
195         exited++;
196         if (thread->getPid() != code) {
197             printf("Failed test #4 (fork callback)\n");
198             printf("    exit code was not equal to pid\n");
199             failedTest[4] = true;
200         } else if (test4Parent == thread) {
201             dprintf("test #4, pid %d exited\n", code);
202             if (!verifyChildMemory(test4Parent,"globalVariable4_1",4000002)){
203                 failedTest[4] = true;
204             }
205         } else if (test4Child == thread) {
206             dprintf("test #4, pid %d exited\n", code);
207             if (!verifyChildMemory(test4Child, "globalVariable4_1", 4000003)) {
208                 failedTest[4] = true;
209             }
210         } else {
211             // exit from unknown thread
212             printf("Failed test #4 (fork callback)\n");
213             printf("    exit from unknown pid = %d\n", code);
214             failedTest[4] = true;
215         }
216         // See if all the processes are done
217         if (exited == 2) {
218             if (!failedTest[4]) {
219                 printf("Passed test #4 (fork & exec)\n");
220                 passedTest[4] = true;
221             } else {
222                 printf("Failed test #4 (fork & exec)\n");
223             }
224         }
225     } else {
226         printf("**Exit from unknown test case**\n");
227     }
228 }
229
230 void execFunc(BPatch_thread *thread)
231 {
232     if (inTest == 1 || inTest == 2) {
233         printf("**Failed Test #%d\n", inTest);
234         printf("    execCallback invoked, but exec was not called!\n");
235     } else if (inTest == 3) {
236         dprintf("in exec callback for %d\n", thread->getPid());
237
238         // insert code into parent
239         BPatch_Vector<BPatch_snippet *> nullArgs;
240         BPatch_image *appImage = thread->getImage();
241         assert(appImage);
242         BPatch_function *func3_2 = appImage->findFunction("func3_2");
243         assert(func3_2);
244         BPatch_funcCallExpr callExpr(*func3_2, nullArgs);
245         BPatch_Vector<BPatch_point *> *point;
246         point = appImage->findProcedurePoint("func3_1", BPatch_exit);
247         assert(point);
248         thread->insertSnippet(callExpr, *point);
249     } else if (inTest == 4) {
250         dprintf("in exec callback for %d\n", thread->getPid());
251
252         // insert code into child
253         BPatch_Vector<BPatch_snippet *> nullArgs;
254         BPatch_image *appImage = thread->getImage();
255         assert(appImage);
256         BPatch_function *func4_4 = appImage->findFunction("func4_4");
257         assert(func4_4);
258         BPatch_funcCallExpr callExpr1(*func4_4, nullArgs);
259         BPatch_Vector<BPatch_point *> *point1;
260         point1 = appImage->findProcedurePoint("func4_2", BPatch_exit);
261         assert(point1);
262         thread->insertSnippet(callExpr1, *point1);
263     } else {
264         printf("in exec callback for %d\n", thread->getPid());
265     }
266 }
267
268 void errorFunc(BPatchErrorLevel level, int num, const char **params)
269 {
270     if (num == 0) {
271         // conditional reporting of warnings and informational messages
272         if (errorPrint) {
273             if (level == BPatchInfo)
274               { if (errorPrint > 1) printf("%s\n", params[0]); }
275             else
276                 printf("%s", params[0]);
277         }
278     } else {
279         // reporting of actual errors
280         char line[256];
281         const char *msg = bpatch->getEnglishErrorString(num);
282         bpatch->formatErrorString(line, sizeof(line), msg, params);
283         
284         if (num != expectError) {
285             printf("Error #%d (level %d): %s\n", num, level, line);
286         
287             // We consider some errors fatal.
288             if (num == 101) {
289                exit(-1);
290             }
291         }
292     }
293 }
294
295 void contAndWaitForAllThreads(BPatch_thread *appThread)
296 {
297     mythreads[threadCount++] = appThread;
298
299     appThread->continueExecution();
300     while (1) {
301         int i;
302         for (i=0; i < threadCount; i++) {
303             if (!mythreads[i]->isTerminated()) {
304                 break;
305             }
306         }
307
308         // see if all exited
309         if (i== threadCount) break;
310
311         bpatch->waitForStatusChange();
312         for (i=0; i < threadCount; i++) {
313             if (mythreads[i]->isStopped()) {
314                 mythreads[i]->continueExecution();
315             }
316         }
317     }
318
319     for (int i=0; i < threadCount; i++) {
320         delete mythreads[i];
321     }
322     threadCount = 0;
323 }
324
325 void mutatorTest1(char *pathname)
326 {
327 #if !defined(sparc_sun_solaris2_4) && !defined(i386_unknown_solaris2_5) && !defined(alpha_dec_osf4_0) && !defined(mips_sgi_irix6_4)
328     printf("Skipping test #1 (exit callback)\n");
329     printf("    not implemented on this platform\n");
330     passedTest[1] = true;
331 #else
332     int n = 0;
333     char *child_argv[MAX_TEST+5];
334         
335     dprintf("in mutatorTest1\n");
336
337     inTest = 1;
338     child_argv[n++] = pathname;
339     if (debugPrint) child_argv[n++] = "-verbose";
340
341     child_argv[n++] = "-run";
342     child_argv[n++] = "1";
343     child_argv[n] = NULL;
344
345     // Start the mutatee
346     printf("Starting \"%s\"\n", pathname);
347
348     BPatch_thread *appThread = bpatch->createProcess(pathname, child_argv,NULL);
349     if (appThread == NULL) {
350         fprintf(stderr, "Unable to run test program.\n");
351         exit(1);
352     }
353
354     contAndWaitForAllThreads(appThread);
355
356     inTest = 0;
357 #endif
358 }
359
360
361 void mutatorTest2(char *pathname)
362 {
363 #if !defined(sparc_sun_solaris2_4) && !defined(i386_unknown_solaris2_5) && !defined(alpha_dec_osf4_0) && !defined(mips_sgi_irix6_4)
364
365     printf("Skipping test #2 (fork callback)\n");
366     printf("    not implemented on this platform\n");
367     passedTest[2] = true;
368 #else
369     int n = 0;
370     char *child_argv[MAX_TEST+5];
371         
372     dprintf("in mutatorTest2\n");
373
374     inTest = 2;
375     child_argv[n++] = pathname;
376     if (debugPrint) child_argv[n++] = "-verbose";
377
378     child_argv[n++] = "-run";
379     child_argv[n++] = "2";
380     child_argv[n] = NULL;
381
382     // Start the mutatee
383     printf("Starting \"%s\"\n", pathname);
384
385     BPatch_thread *appThread = bpatch->createProcess(pathname, child_argv,NULL);
386     if (appThread == NULL) {
387         fprintf(stderr, "Unable to run test program.\n");
388         exit(1);
389     }
390
391     contAndWaitForAllThreads(appThread);
392
393     inTest = 0;
394 #endif
395 }
396
397 void mutatorTest3(char *pathname)
398 {
399 #if !defined(sparc_sun_solaris2_4) && !defined(i386_unknown_solaris2_5) && !defined(alpha_dec_osf4_0) && !defined(mips_sgi_irix6_4)
400     printf("Skipping test #3 (exec callback)\n");
401     printf("    not implemented on this platform\n");
402     passedTest[3] = true;
403 #else
404     int n = 0;
405     char *child_argv[MAX_TEST+5];
406         
407     dprintf("in mutatorTest3\n");
408
409     inTest = 3;
410     child_argv[n++] = pathname;
411     if (debugPrint) child_argv[n++] = "-verbose";
412
413     child_argv[n++] = "-run";
414     child_argv[n++] = "3";
415     child_argv[n] = NULL;
416
417     // Start the mutatee
418     printf("Starting \"%s\"\n", pathname);
419
420     BPatch_thread *appThread = bpatch->createProcess(pathname, child_argv,NULL);
421     if (appThread == NULL) {
422         fprintf(stderr, "Unable to run test program.\n");
423         exit(1);
424     }
425
426     contAndWaitForAllThreads(appThread);
427
428     inTest = 0;
429 #endif
430 }
431
432 void mutatorTest4(char *pathname)
433 {
434 #if !defined(sparc_sun_solaris2_4) && !defined(i386_unknown_solaris2_5) \
435  && !defined(alpha_dec_osf4_0) && !defined(mips_sgi_irix6_4)
436     printf("Skipping test #4 (fork & exec)\n");
437     printf("    not implemented on this platform\n");
438     passedTest[4] = true;
439 #else
440     int n = 0;
441     char *child_argv[MAX_TEST+5];
442         
443     dprintf("in mutatorTest4\n");
444
445     inTest = 4;
446     child_argv[n++] = pathname;
447     if (debugPrint) child_argv[n++] = "-verbose";
448
449     child_argv[n++] = "-run";
450     child_argv[n++] = "4";
451     child_argv[n] = NULL;
452
453     // Start the mutatee
454     printf("Starting \"%s\"\n", pathname);
455
456     test4Parent = bpatch->createProcess(pathname, child_argv,NULL);
457     if (test4Parent == NULL) {
458         fprintf(stderr, "Unable to run test program.\n");
459         exit(1);
460     }
461
462     contAndWaitForAllThreads(test4Parent);
463
464     inTest = 0;
465 #endif
466 }
467
468 void mutatorMAIN(char *pathname)
469 {
470     // Create an instance of the BPatch library
471     bpatch = new BPatch;
472
473     // Force functions to be relocated
474     if (forceRelocation) {
475       bpatch->setForcedRelocation_NP(true);
476     }
477
478     bpatch->setTrampRecursive(true);
479     // Register a callback function that prints any error messages
480     bpatch->registerErrorCallback(errorFunc);
481     bpatch->registerPreForkCallback(forkFunc);
482     bpatch->registerPostForkCallback(forkFunc);
483     bpatch->registerExecCallback(execFunc);
484     bpatch->registerExitCallback(exitFunc);
485
486     if (runTest[1]) mutatorTest1(pathname);
487     if (runTest[2]) mutatorTest2(pathname);
488     if (runTest[3]) mutatorTest3(pathname);
489     if (runTest[4]) mutatorTest4(pathname);
490
491     unsigned int testsFailed = 0;
492     for (unsigned int i=1; i <= MAX_TEST; i++) {
493         if (runTest[i] && !passedTest[i]) testsFailed++;
494     }
495
496     if (!testsFailed) {
497         if (runAllTests) {
498             printf("All tests passed\n");
499         } else {
500             printf("All requested tests passed\n");
501         }
502     }
503 }
504
505 //
506 // main - decide our role and call the correct "main"
507 //
508 int
509 main(unsigned int argc, char *argv[])
510 {
511     unsigned int i;
512     bool N32ABI=false;
513     char mutateeName[128];
514     char libRTname[256];
515
516     strcpy(mutateeName,mutateeNameRoot);
517     libRTname[0]='\0';
518
519     if (!getenv("DYNINSTAPI_RT_LIB")) {
520          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
521 #if defined(i386_unknown_nt4_0)
522                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
523 #else
524                  "    set it to the full pathname of libdyninstAPI_RT\n");   
525          exit(-1);
526 #endif
527     } else
528          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
529
530     // by default run all tests
531     for (i=1; i <= MAX_TEST; i++) {
532         runTest[i] = true;
533         passedTest[i] = false;
534     }
535
536     for (i=1; i < argc; i++) {
537         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
538         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
539         if (strncmp(argv[i], "-verbose", 2) == 0) {
540             debugPrint = 1;
541         } else if (!strcmp(argv[i], "-V")) {
542             fprintf (stdout, "%s\n", V_libdyninstAPI);
543             if (libRTname[0]) 
544                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
545             fflush(stdout);
546         } else if (!strcmp(argv[i], "-skip")) {
547             unsigned int j;
548             runAllTests = false;
549             for (j=i+1; j < argc; j++) {
550                 unsigned int testId;
551                 if ((testId = atoi(argv[j]))) {
552                     if ((testId > 0) && (testId <= MAX_TEST)) {
553                         runTest[testId] = false;
554                     } else {
555                         printf("invalid test %d requested\n", testId);
556                         exit(-1);
557                     }
558                 } else {
559                     // end of test list
560                     break;
561                 }
562             }
563             i=j-1;
564         } else if (!strcmp(argv[i], "-run")) {
565             unsigned int j;
566             runAllTests = false;
567             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
568             for (j=i+1; j < argc; j++) {
569                 unsigned int testId;
570                 if ((testId = atoi(argv[j]))) {
571                     if ((testId > 0) && (testId <= MAX_TEST)) {
572                         runTest[testId] = true;
573                     } else {
574                         printf("invalid test %d requested\n", testId);
575                         exit(-1);
576                     }
577                 } else {
578                     // end of test list
579                     break;
580                 }
581             }
582             i=j-1;
583         } else if (!strcmp(argv[i], "-mutatee")) {
584             i++;
585             if (*argv[i]=='_')
586                 strcat(mutateeName,argv[i]);
587             else
588                 strcpy(mutateeName,argv[i]);
589 #if defined(i386_unknown_nt4_0) || defined(i386_unknown_linux2_0) || defined(sparc_sun_solaris2_4)
590         } else if (!strcmp(argv[i], "-relocate")) {
591             forceRelocation = true;
592 #endif
593 #if defined(mips_sgi_irix6_4)
594         } else if (!strcmp(argv[i], "-n32")) {
595             N32ABI=true;
596 #endif
597         } else {
598             fprintf(stderr, "Usage: test4 "
599                     "[-V] [-verbose] "
600 #if defined(mips_sgi_irix6_4)
601                     "[-n32] "
602 #endif
603                     "[-mutatee <test4a.mutatee>] "
604                     "[-run <test#> <test#> ...] "
605                     "[-skip <test#> <test#> ...]\n");
606             fprintf(stderr, "%d subtests\n", MAX_TEST);
607             exit(-1);
608         }
609     }
610
611     if (!runAllTests) {
612         printf("Running Tests: ");
613         for (unsigned int j=1; j <= MAX_TEST; j++) {
614             if (runTest[j]) printf("%d ", j);
615         }
616         printf("\n");
617     }
618
619     // patch up the default compiler in mutatee name (if necessary)
620     if (!strstr(mutateeName, "_"))
621 #if defined(i386_unknown_nt4_0)
622         strcat(mutateeName,"_VC");
623 #else
624         strcat(mutateeName,"_gcc");
625 #endif
626     if (N32ABI || strstr(mutateeName,"_n32")) {
627         // patch up file names based on alternate ABI (as necessary)
628         if (!strstr(mutateeName, "_n32")) strcat(mutateeName,"_n32");
629     }
630     // patch up the platform-specific filename extensions
631 #if defined(i386_unknown_nt4_0)
632     if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
633 #endif
634
635     mutatorMAIN(mutateeName);
636
637     return 0;
638 }