1 // $Id: test3.C,v 1.23 2001/07/11 21:21:09 gurari Exp $
3 // libdyninst validation suite test #3
4 // Author: Jeff Hollingsworth (6/18/99)
7 // This program tests having multiple active mutatee processes.
9 // To run a subset of the tests, enter -run <test nums> on the command
12 // Naming conventions:
13 // All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
14 // XX is the test number
15 // YY is the instance withing the test
16 // func1_2 is the second function used in test case #1.
21 #ifdef i386_unknown_nt4_0
24 #define unlink _unlink
30 #include "BPatch_Vector.h"
31 #include "BPatch_thread.h"
32 #include "BPatch_snippet.h"
33 #include "test_util.h"
36 int debugPrint = 0; // internal "mutator" tracing
37 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
39 bool forceRelocation = false; // Force relocation upon instrumentation
41 const unsigned int MAX_MUTATEES = 32;
42 unsigned int Mutatees=3;
44 bool runAllTests = true;
45 const unsigned int MAX_TEST = 5;
46 bool passedTest[MAX_TEST+1];
48 template class BPatch_Vector<BPatch_variableExpr*>;
52 static char *mutateeNameRoot = "test3.mutatee";
54 // control debug printf statements
55 #define dprintf if (debugPrint) printf
57 /**************************************************************************
59 **************************************************************************/
61 #define DYNINST_NO_ERROR -1
63 int expectError = DYNINST_NO_ERROR;
65 void errorFunc(BPatchErrorLevel level, int num, const char **params)
68 // conditional reporting of warnings and informational messages
70 if (level == BPatchInfo)
71 { if (errorPrint > 1) printf("%s\n", params[0]); }
73 printf("%s", params[0]);
76 // reporting of actual errors
78 const char *msg = bpatch->getEnglishErrorString(num);
79 bpatch->formatErrorString(line, sizeof(line), msg, params);
81 if (num != expectError) {
82 printf("Error #%d (level %d): %s\n", num, level, line);
84 // We consider some errors fatal.
92 /**************************************************************************
94 **************************************************************************/
97 // Return a pointer to a string identifying a BPatch_procedureLocation
99 char *locationName(BPatch_procedureLocation l)
106 case BPatch_subroutine:
107 return "call points";
108 case BPatch_longJump:
110 case BPatch_allLocations:
113 return "<invalid BPatch_procedureLocation>";
119 // Insert "snippet" at the location "loc" in the function "inFunction."
120 // Returns the value returned by BPatch_thread::insertSnippet.
122 BPatchSnippetHandle *insertSnippetAt(BPatch_thread *appThread,
123 BPatch_image *appImage, char *inFunction, BPatch_procedureLocation loc,
124 BPatch_snippet &snippet, int testNo, char *testName)
126 // Find the point(s) we'll be instrumenting
127 BPatch_Vector<BPatch_point *> *points =
128 appImage->findProcedurePoint(inFunction, loc);
131 fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
132 fprintf(stderr, " Unable to find point %s - %s\n",
133 inFunction, locationName(loc));
137 return appThread->insertSnippet(snippet, *points);
141 // Create a snippet that calls the function "funcName" with no arguments
143 BPatch_snippet *makeCallSnippet(BPatch_image *appImage, char *funcName,
144 int testNo, char *testName)
146 BPatch_function *call_func = appImage->findFunction(funcName);
147 if (call_func == NULL) {
148 fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
149 fprintf(stderr, " Unable to find function %s\n", funcName);
153 BPatch_Vector<BPatch_snippet *> nullArgs;
154 BPatch_snippet *ret = new BPatch_funcCallExpr(*call_func, nullArgs);
157 fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
158 fprintf(stderr, " Unable to create snippet to call %s\n", funcName);
166 // Insert a snippet to call function "funcName" with no arguments into the
167 // procedure "inFunction" at the points given by "loc."
169 BPatchSnippetHandle *insertCallSnippetAt(BPatch_thread *appThread,
170 BPatch_image *appImage, char *inFunction, BPatch_procedureLocation loc,
171 char *funcName, int testNo, char *testName)
173 BPatch_snippet *call_expr =
174 makeCallSnippet(appImage, funcName, testNo, testName);
176 BPatchSnippetHandle *ret = insertSnippetAt(appThread, appImage,
177 inFunction, loc, *call_expr,
180 fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
181 fprintf(stderr, " Unable to insert snippet to call function %s\n",
191 void MopUpMutatees(const unsigned int mutatees, BPatch_thread *appThread[])
194 dprintf("MopUpMutatees(%d)\n", mutatees);
195 for (n=0; n<mutatees; n++) {
197 if (appThread[n]->terminateExecution()) {
198 dprintf("Mutatee %d terminated (code=0x%x).\n",
199 n, appThread[n]->terminationStatus());
201 printf("Failed to mop up mutatee %d (pid=%d)!\n",
202 n, appThread[n]->getPid());
205 printf("Mutatee %d already terminated?\n", n);
208 dprintf("MopUpMutatees(%d) done\n", mutatees);
211 /**************************************************************************
213 **************************************************************************/
216 // Start Test Case #1 - create processes and process events from each
217 // Just let them run a while, then kill them, no instrumentation added.
219 void mutatorTest1(char *pathname, BPatch *bpatch)
223 child_argv[n++] = pathname;
224 if (debugPrint) child_argv[n++] = "-verbose";
225 child_argv[n++] = "-run";
226 child_argv[n++] = "1"; // run test1 in mutatee
227 child_argv[n++] = NULL;
229 BPatch_thread *appThread[MAX_MUTATEES];
231 for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
233 // Start the mutatees
234 for (n=0; n<Mutatees; n++) {
235 dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
236 appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
238 printf("*ERROR*: unable to create handle%d for executable\n", n);
239 printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
240 MopUpMutatees(n-1,appThread);
243 dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
246 dprintf("Letting mutatee processes run a short while (10s).\n");
247 for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
250 dprintf("Terminating mutatee processes.\n");
252 unsigned int numTerminated=0;
253 for (n=0; n<Mutatees; n++) {
254 bool dead = appThread[n]->terminateExecution();
255 if (!dead || !(appThread[n]->isTerminated())) {
256 printf("**Failed** test #1 (simultaneous multiple-process management - terminate)\n");
257 printf(" mutatee process [%d] was not terminated\n", n);
261 int statusCode = appThread[n]->terminationStatus();
262 dprintf("Terminated mutatee [%d] returned status code 0x%x\n", n, statusCode);
265 if (numTerminated == Mutatees) {
266 printf("Passed Test #1 (simultaneous multiple-process management - terminate)\n");
267 passedTest[1] = true;
272 // Start Test Case #2 - create processes and process events from each
273 // Just let them run to finish, no instrumentation added.
275 void mutatorTest2(char *pathname, BPatch *bpatch)
279 child_argv[n++] = pathname;
280 if (debugPrint) child_argv[n++] = "-verbose";
281 child_argv[n++] = "-run";
282 child_argv[n++] = "2"; // run test2 in mutatee
283 child_argv[n++] = NULL;
285 BPatch_thread *appThread[MAX_MUTATEES];
287 for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
289 // Start the mutatees
290 for (n=0; n<Mutatees; n++) {
291 dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
292 appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
294 printf("*ERROR*: unable to create handle%d for executable\n", n);
295 printf("**Failed** test #2 (simultaneous multiple-process management - exit)\n");
296 MopUpMutatees(n-1,appThread);
299 dprintf("Mutatee %d started, pid=%d\n", n, appThread[n]->getPid());
301 dprintf("Letting %d mutatee processes run.\n", Mutatees);
302 for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
304 unsigned int numTerminated=0;
305 bool terminated[MAX_MUTATEES];
306 for (n=0; n<Mutatees; n++) terminated[n]=false;
308 // monitor the mutatee termination reports
309 while (numTerminated < Mutatees) {
310 bpatch->waitForStatusChange();
311 for (n=0; n<Mutatees; n++)
312 if (!terminated[n] && (appThread[n]->isTerminated())) {
313 dprintf("Mutatee %d termination received (code=0x%x).\n",
314 n, appThread[n]->terminationStatus());
320 if (numTerminated == Mutatees) {
321 printf("Passed Test #2 (simultaneous multiple-process management - exit)\n");
322 passedTest[2] = true;
327 // read the result code written to the file test3.out.<pid> and return it
329 int readResult(int pid)
335 sprintf(filename, "test3.out.%d", pid);
336 fp = fopen(filename, "r");
338 printf("ERROR: unable to open output file %s\n", filename);
341 fscanf(fp, "%d\n", &ret);
343 // don't need the file any longer so delete it now
350 // Start Test Case #3 - create processes and insert different code into
351 // each one. The code sets a global variable which the mutatee then
352 // writes to a file. After all mutatees exit, the mutator reads the
353 // files to verify that the correct code ran in each mutatee.
354 // The first mutator should write a 1 to the file, the second a 2, etc.
355 // If no code is patched into the mutatees, the value is 0xdeadbeef.
357 void mutatorTest3(char *pathname, BPatch *bpatch)
361 child_argv[n++] = pathname;
362 if (debugPrint) child_argv[n++] = "-verbose";
363 child_argv[n++] = "-run";
364 child_argv[n++] = "3"; // run test3 in mutatee
365 child_argv[n++] = NULL;
367 int pid[MAX_MUTATEES];
368 BPatch_thread *appThread[MAX_MUTATEES];
370 for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
372 // Start the mutatees
373 for (n=0; n<Mutatees; n++) {
374 dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
375 appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
377 printf("*ERROR*: unable to create handle%d for executable\n", n);
378 printf("**Failed** test #3 (instrument multiple processes)\n");
379 MopUpMutatees(n-1,appThread);
382 pid[n] = appThread[n]->getPid();
383 dprintf("Mutatee %d started, pid=%d\n", n, pid[n]);
386 // Instrument mutatees
387 for (n=0; n<Mutatees; n++) {
388 dprintf("Instrumenting %d/%d\n", n, Mutatees);
390 const char *Func="func3_1";
391 const char *Var="test3ret";
392 const char *Call="call3_1";
393 BPatch_image *img = appThread[n]->getImage();
394 BPatch_Vector<BPatch_point *> *point =
395 img->findProcedurePoint(Func, BPatch_entry);
396 if (!point || (*point).size() == 0) {
397 printf(" Unable to find entry point to \"%s\".\n", Func);
398 printf("**Failed** test #3 (instrument multiple processes)\n");
399 MopUpMutatees(Mutatees,appThread);
402 BPatch_variableExpr *var = img->findVariable(Var);
404 printf(" Unable to find variable \"%s\".\n", Var);
405 printf("**Failed** test #3 (instrument multiple processes)\n");
406 MopUpMutatees(Mutatees,appThread);
409 BPatch_function *callFunc = img->findFunction(Call);
410 if (callFunc == NULL) {
411 printf(" Unable to find target function \"%s\".\n", Call);
412 printf("**Failed** test #3 (instrument multiple processes)\n");
413 MopUpMutatees(Mutatees,appThread);
416 // start with a simple snippet
417 BPatch_arithExpr snip(BPatch_assign, *var, BPatch_constExpr(n));
418 BPatchSnippetHandle *inst = appThread[n]->insertSnippet(snip, *point);
420 printf(" Failed to insert simple snippet.\n");
421 printf("**Failed** test #3 (instrument multiple processes)\n");
422 MopUpMutatees(Mutatees,appThread);
426 // now add a call snippet
427 BPatch_Vector<BPatch_snippet *> callArgs;
428 BPatch_constExpr arg1(2); callArgs.push_back(&arg1);
429 BPatch_constExpr arg2(n); callArgs.push_back(&arg2);
430 BPatch_funcCallExpr callExpr(*callFunc, callArgs);
431 BPatchSnippetHandle *call =
432 appThread[n]->insertSnippet(callExpr, *point);
434 printf(" Failed to insert call snippet.\n");
435 printf("**Failed** test #3 (instrument multiple processes)\n");
436 MopUpMutatees(Mutatees,appThread);
441 dprintf("Letting %d mutatee processes run.\n", Mutatees);
442 for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
444 unsigned int numTerminated=0;
445 bool terminated[MAX_MUTATEES];
446 for (n=0; n<Mutatees; n++) terminated[n]=false;
448 // monitor the mutatee termination reports
449 while (numTerminated < Mutatees) {
450 bpatch->waitForStatusChange();
451 for (n=0; n<Mutatees; n++)
452 if (!terminated[n] && (appThread[n]->isTerminated())) {
453 dprintf("Mutatee %d termination received (code=0x%x).\n",
454 n, appThread[n]->terminationStatus());
460 // now read the files to see if the value is what is expected
461 bool allCorrect=true;
462 int ret[MAX_MUTATEES];
463 for (n=0; n<Mutatees; n++) {
464 ret[n]=readResult(pid[n]);
465 if (ret[n] != (int)n) {
466 printf(" mutatee process %d produced %d, not %d\n",
470 dprintf(" mutatee process %d produced expected value %d\n",
476 printf("Passed Test #3 (instrument multiple processes)\n");
477 passedTest[3] = true;
479 printf("**Failed** test #3 (instrument multiple processes)\n");
484 // Start Test Case #4 - create one process, wait for it to exit. Then
485 // create a second one and wait for it to exit. Repeat as required.
487 void mutatorTest4(char *pathname, BPatch *bpatch)
491 child_argv[n++] = pathname;
492 if (debugPrint) child_argv[n++] = "-verbose";
493 child_argv[n++] = "-run";
494 child_argv[n++] = "2"; // run test2 in mutatee
495 child_argv[n++] = NULL;
497 BPatch_thread *appThread;
499 for (n=0; n<Mutatees; n++) {
501 dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
502 appThread = bpatch->createProcess(pathname, child_argv, NULL);
504 printf("*ERROR*: unable to create handle%d for executable\n", n);
505 printf("**Failed** Test #4 (sequential multiple-process management - exit)\n");
508 dprintf("Mutatee %d started, pid=%d\n", n, appThread->getPid());
510 appThread->continueExecution();
512 while (!appThread->isTerminated())
513 bpatch->waitForStatusChange();
515 dprintf("Mutatee %d termination received (code=0x%x).\n",
516 n, appThread->terminationStatus());
519 printf("Passed Test #4 (sequential multiple-process management - exit)\n");
520 passedTest[4] = true;
525 // Start Test Case #5 - create one process, wait for it to exit. Then
526 // create a second one and wait for it to exit. Repeat as required.
527 // Differs from test 3 in that the mutatee processes terminate with
528 // abort rather than exit.
530 void mutatorTest5(char *pathname, BPatch *bpatch)
534 child_argv[n++] = pathname;
535 if (debugPrint) child_argv[n++] = "-verbose";
536 child_argv[n++] = "-run";
537 child_argv[n++] = "5"; // run test5 in mutatee
538 child_argv[n++] = NULL;
540 BPatch_thread *appThread;
542 for (n=0; n<Mutatees; n++) {
544 dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
545 appThread = bpatch->createProcess(pathname, child_argv, NULL);
547 printf("*ERROR*: unable to create handle%d for executable\n", n);
548 printf("**Failed** Test #5 (sequential multiple-process management - abort)\n");
551 dprintf("Mutatee %d started, pid=%d\n", n, appThread->getPid());
553 appThread->continueExecution();
555 while (!appThread->isTerminated())
556 bpatch->waitForStatusChange();
558 dprintf("Mutatee %d termination received (code=0x%x).\n",
559 n, appThread->terminationStatus());
562 printf("Passed Test #5 (sequential multiple-process management - abort)\n");
563 passedTest[5] = true;
566 int main(unsigned int argc, char *argv[])
569 char mutateeName[128];
571 bool runTest[MAX_TEST+1]; // should we run a particular test
573 strcpy(mutateeName,mutateeNameRoot);
576 if (!getenv("DYNINSTAPI_RT_LIB")) {
577 fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
578 #if defined(i386_unknown_nt4_0)
579 " using standard search strategy for libdyninstAPI_RT.dll\n");
581 " set it to the full pathname of libdyninstAPI_RT\n");
585 strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
588 // by default run all tests
589 for (i=1; i <= MAX_TEST; i++) {
591 passedTest[i] = false;
594 for (i=1; i < argc; i++) {
595 if (strncmp(argv[i], "-v+", 3) == 0) errorPrint++;
596 if (strncmp(argv[i], "-v++", 4) == 0) errorPrint++;
597 if (strncmp(argv[i], "-verbose", 2) == 0) {
599 } else if (!strcmp(argv[i], "-V")) {
600 fprintf (stdout, "%s\n", V_libdyninstAPI);
602 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
604 } else if (strncmp(argv[i], "-plurality", 2) == 0) {
605 Mutatees = atoi(argv[++i]);
606 if (Mutatees > MAX_MUTATEES) {
607 printf("Limiting plurality to maximum of %d!\n", MAX_MUTATEES);
608 Mutatees = MAX_MUTATEES;
609 } else if (Mutatees <= 1) {
610 printf("Plurality of at least 2 required for these tests!\n");
613 dprintf ("%d mutatees to be used for each test.\n", Mutatees);
614 } else if (!strcmp(argv[i], "-skip")) {
617 for (j=i+1; j < argc; j++) {
619 if ((testId = atoi(argv[j]))) {
620 if ((testId > 0) && (testId <= MAX_TEST)) {
621 runTest[testId] = false;
623 printf("invalid test %d requested\n", testId);
632 } else if (!strcmp(argv[i], "-run")) {
635 for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
636 for (j=i+1; j < argc; j++) {
638 if ((testId = atoi(argv[j]))) {
639 if ((testId > 0) && (testId <= MAX_TEST)) {
640 dprintf("test %d requested\n", testId);
641 runTest[testId] = true;
643 printf("invalid test %d requested\n", testId);
652 } else if (!strcmp(argv[i], "-mutatee")) {
655 strcat(mutateeName,argv[i]);
657 strcpy(mutateeName,argv[i]);
658 #if defined(i386_unknown_nt4_0) || defined(i386_unknown_linux2_0) || defined(sparc_sun_solaris2_4)
659 } else if (!strcmp(argv[i], "-relocate")) {
660 forceRelocation = true;
662 #if defined(mips_sgi_irix6_4)
663 } else if (!strcmp(argv[i], "-n32")) {
667 fprintf(stderr, "Usage: test3 "
669 #if defined(mips_sgi_irix6_4)
672 "[-mutatee <test3.mutatee>] "
674 "[-run <test#> <test#> ...] "
675 "[-skip <test#> <test#> ...]\n");
676 fprintf(stderr, "%d subtests\n", MAX_TEST);
682 printf("Running Tests: ");
683 for (unsigned int j=1; j <= MAX_TEST; j++) {
684 if (runTest[j]) printf("%d ", j);
689 // patch up the default compiler in mutatee name (if necessary)
690 if (!strstr(mutateeName, "_"))
691 #if defined(i386_unknown_nt4_0)
692 strcat(mutateeName,"_VC");
694 strcat(mutateeName,"_gcc");
696 if (N32ABI || strstr(mutateeName,"_n32")) {
697 // patch up file names based on alternate ABI (as necessary)
698 if (!strstr(mutateeName, "_n32")) strcat(mutateeName,"_n32");
700 // patch up the platform-specific filename extensions
701 #if defined(i386_unknown_nt4_0)
702 if (!strstr(mutateeName, ".exe")) strcat(mutateeName,".exe");
705 // Create an instance of the BPatch library
708 // Force functions to be relocated
709 if (forceRelocation) {
710 bpatch->setForcedRelocation_NP(true);
713 #if defined (sparc_sun_solaris2_4)
714 // we use some unsafe type operations in the test cases.
715 bpatch->setTypeChecking(false);
718 // Register a callback function that prints any error messages
719 bpatch->registerErrorCallback(errorFunc);
721 if (runTest[1]) mutatorTest1(mutateeName, bpatch);
722 if (runTest[2]) mutatorTest2(mutateeName, bpatch);
723 if (runTest[3]) mutatorTest3(mutateeName, bpatch);
724 if (runTest[4]) mutatorTest4(mutateeName, bpatch);
725 if (runTest[5]) mutatorTest5(mutateeName, bpatch);
727 unsigned int testsFailed = 0;
728 for (i=1; i <= MAX_TEST; i++) {
729 if (runTest[i] && !passedTest[i]) testsFailed++;
734 printf("All tests passed\n");
736 printf("All requested tests passed\n");
739 printf("**Failed** %d test%c\n",testsFailed,(testsFailed>1)?'s':' ');
742 return (testsFailed ? 127 : 0);