Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / tests / src / test10.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: test10.C,v 1.13 2008/04/11 23:30:30 legendre Exp $
33 //
34 // libdyninst validation suite test #10
35 //    Author: Jeff Hollingsworth Williams (14 aug 2003) 
36 //
37
38 //  This program tests the platform specific code modifications by
39 //      of DyninstAPI.
40 //      The mutatee that goes with this file is test10.mutatee.c
41 //      
42 //  Naming conventions:
43 //      All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
44 //          XX is the test number
45 //          YY is the instance withing the test
46 //          func1_2 is the second function used in test case #1.
47 //
48
49 #include <stdio.h>
50 #include <string.h>
51 #include <ctype.h>
52 #include <assert.h>
53 #include <unistd.h>
54 #include <stdarg.h>
55
56 #if defined(i386_unknown_linux2_0) \
57  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
58 #include <sys/types.h>
59 #include <sys/wait.h>
60 #endif
61
62 #include "BPatch.h"
63 #include "BPatch_Vector.h"
64 #include "BPatch_thread.h"
65 #include "BPatch_snippet.h"
66 #include "test_util.h"
67 #include "test1.h"
68
69 #define TEST1 "1"
70 #define TEST2 "2"
71 #define TEST3 "3"
72 #define TEST4 "4"
73   
74 int debugPrint = 0; // internal "mutator" tracing
75 int errorPrint = 0; // external "dyninst" tracing (via errorFunc)
76
77 bool forceRelocation = true; // force relocation of functions
78
79 int mutateeCplusplus = 0;
80 int mutateeFortran = 0;
81 int mutateeF77 = 0;
82 bool runAllTests = true;
83 const unsigned int MAX_TEST = 6;
84 bool runTest[MAX_TEST+1];
85 bool passedTest[MAX_TEST+1];
86
87 template class BPatch_Vector<BPatch_variableExpr*>;
88 template class BPatch_Set<int>;
89
90 BPatch *bpatch;
91
92 static const char *mutateeNameRoot = "test10.mutatee";
93
94 // control debug printf statements
95 void dprintf(const char *fmt, ...) {
96    va_list args;
97    va_start(args, fmt);
98
99    if(debugPrint)
100       vfprintf(stderr, fmt, args);
101
102    va_end(args);
103
104    fflush(stderr);
105 }
106
107 /**************************************************************************
108  * Error callback
109  **************************************************************************/
110
111 #define DYNINST_NO_ERROR -1
112
113 int expectError = DYNINST_NO_ERROR;
114
115 void errorFunc(BPatchErrorLevel level, int num, const char * const *params)
116 {
117     if (num == 0) {
118         // conditional reporting of warnings and informational messages
119         if (errorPrint) {
120             if (level == BPatchInfo)
121               { if (errorPrint > 1) printf("%s\n", params[0]); }
122             else
123                 printf("%s", params[0]);
124         }
125     } else {
126         // reporting of actual errors
127         char line[256];
128         const char *msg = bpatch->getEnglishErrorString(num);
129         bpatch->formatErrorString(line, sizeof(line), msg, params);
130         
131         if (num != expectError) {
132           if(num != 112)
133             printf("Error #%d (level %d): %s\n", num, level, line);
134         
135             // We consider some errors fatal.
136             if (num == 101) {
137                exit(-1);
138             }
139         }
140     }
141 }
142
143 void createInstPointError(BPatchErrorLevel level, int num, const char **params)
144 {
145     if (num != 117 && num != 118)
146         errorFunc(level, num, params);
147 }
148
149 /**************************************************************************
150  * Utility functions
151  **************************************************************************/
152 // Wrapper function to find variables
153 // For Fortran, will look for lowercase variable, if mixed case not found
154 BPatch_variableExpr *findVariable(BPatch_image *appImage, const char* var,
155                                   BPatch_Vector <BPatch_point *> *point = NULL)
156 {
157   //BPatch_variableExpr *FortVar = NULL;
158     BPatch_variableExpr *ret = NULL;
159     int i, numchars = strlen (var);
160     char *lowercase = new char [numchars];
161     int temp = expectError;
162
163     if (mutateeFortran && point) {
164             strcpy (lowercase, var);
165             expectError = 100;
166             for (i = 0; i < numchars; i++)
167                 lowercase [i] = tolower (lowercase [i]);
168             ret = appImage->findVariable (*(*point) [0], lowercase);
169         if (!ret) {
170             expectError = temp;
171             ret = appImage->findVariable (*(*point) [0], var);
172         }
173     } else {
174         ret = appImage->findVariable (var);
175     }
176
177     expectError = temp;
178     delete [] lowercase;
179     return ret;
180 }
181
182
183 void instrumentToCallZeroArg(BPatch_thread *appThread, BPatch_image *appImage, char *instrumentee, char*patch, int testNo, char *testName){
184
185   BPatch_Vector<BPatch_function *> found_funcs;
186   if ((NULL == appImage->findFunction(instrumentee, found_funcs)) || !found_funcs.size()) {
187     fprintf(stderr, "    Unable to find function %s\n","instrumentee");
188     exit(1);
189   }
190   
191   if (1 < found_funcs.size()) {
192     fprintf(stderr, "%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
193             __FILE__, __LINE__, found_funcs.size(), instrumentee);
194   }
195   
196   BPatch_Vector<BPatch_point *> *point1_1 = found_funcs[0]->findPoint(BPatch_entry);
197
198
199   if (!point1_1 || ((*point1_1).size() == 0)) {
200     fprintf(stderr, "**Failed** test #%d (%s)\n", testNo,testName);
201     fprintf(stderr, "    Unable to find entry point to \"%s.\"\n",instrumentee);
202     exit(1);
203   }
204
205   if (((*point1_1).size() > 1)) {
206     fprintf(stderr, "**Failed** test #%d (%s)\n", testNo,testName);
207     fprintf(stderr, "    Too many entry points for \"%s.\"\n",instrumentee);
208     exit(1);
209   }
210
211   //fprintf(stderr, "%s[%d]:  address of entry point = 0x%x\n", __FILE__, __LINE__, (*point1_1)[0]->getAddress());
212   BPatch_Vector<BPatch_function *> bpfv;
213   if (NULL == appImage->findFunction(patch, bpfv) || !bpfv.size()
214       || NULL == bpfv[0]){
215     fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
216     fprintf(stderr, "    Unable to find function %s\n", patch);
217     exit(1);
218   }
219   BPatch_function *call1_func = bpfv[0];
220   
221   BPatch_Vector<BPatch_snippet *> call1_args;
222   BPatch_funcCallExpr call1Expr(*call1_func, call1_args);
223   
224   dprintf("Inserted snippet2\n");
225   if (!appThread->insertSnippet(call1Expr, *point1_1)) {
226     fprintf(stderr, "**Failed** test #%d (%s)\n", testNo, testName);
227     fprintf(stderr, "    Unable to insert call to %s\n", patch);
228     exit(1);
229
230   }
231
232 }
233
234
235 //
236 // Start Test Case #1 - ()
237 //
238 void mutatorTest1(BPatch_thread *appThread, BPatch_image *appImage)
239 {
240     instrumentToCallZeroArg(appThread, appImage, "func1", "call1", 1, "test10.1");
241 }
242
243 //
244 // Start Test Case #2 
245 //
246 void mutatorTest2(BPatch_thread *appThread, BPatch_image *appImage)
247 {
248     instrumentToCallZeroArg(appThread, appImage, "func2", "call2", 2, "test10.2");
249 }
250
251
252 //
253 // Start Test Case #3 
254 //
255 void mutatorTest3(BPatch_thread *appThread, BPatch_image *appImage)
256 {
257     instrumentToCallZeroArg(appThread, appImage, "func3", "call3", 3, "test10.3");
258 }
259
260 //
261 // Start Test Case #4 
262 //
263 void mutatorTest4(BPatch_thread *appThread, BPatch_image *appImage)
264 {
265     instrumentToCallZeroArg(appThread, appImage, "func4", "call4", 4, "test10.4");
266 }
267
268 int mutatorMAIN(char *pathname)
269 {
270
271     BPatch_thread *appThread;
272     BPatch_image *appImage;
273
274     // Create an instance of the BPatch library
275     bpatch = new BPatch;
276
277     // Force functions to be relocated
278     bpatch->setForcedRelocation_NP(true);
279
280     // Register a callback function that prints any error messages
281     bpatch->registerErrorCallback(errorFunc);
282
283     // Start the mutatee
284     printf("Starting \"%s\"\n", pathname);
285
286     const char* child_argv[MAX_TEST+5];
287
288     int n = 0;
289     child_argv[n++] = pathname;
290     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
291
292     if (runAllTests) {
293         child_argv[n++] = const_cast<char*>("-runall"); // signifies all tests
294     } else {
295         child_argv[n++] = const_cast<char*>("-run");
296         for (unsigned int j=1; j <= MAX_TEST; j++) {
297             if (runTest[j]) {
298                 char str[5];
299                 sprintf(str, "%d", j);
300                 child_argv[n++] = strdup(str);
301             }
302         }
303     }
304
305     child_argv[n] = NULL;
306
307     appThread = bpatch->createProcess(pathname, child_argv,NULL);
308     appImage = appThread->getImage();
309
310     if (runTest[1]) mutatorTest1(appThread, appImage);
311     if (runTest[2]) mutatorTest2(appThread, appImage);
312     if (runTest[3]) mutatorTest3(appThread, appImage);
313     if (runTest[4]) mutatorTest4(appThread, appImage);
314
315     appThread->continueExecution();
316
317     while (!appThread->isTerminated())
318         bpatch->waitForStatusChange();
319
320     int retval;
321     if(appThread->terminationStatus() == ExitedNormally) {
322        int exitCode = appThread->getExitCode();
323        if (exitCode || debugPrint)
324           printf("Mutatee exited with exit code 0x%x\n", exitCode);
325        retval = exitCode;
326     } else if(appThread->terminationStatus() == ExitedViaSignal) {
327        int signalNum = appThread->getExitSignal();
328        if (signalNum || debugPrint)
329           printf("Mutatee exited from signal 0x%d\n", signalNum);
330        retval = signalNum;
331     }
332
333     dprintf("Done.\n");
334
335     return retval;
336 }
337
338 //
339 // main - decide our role and call the correct "main"
340 //
341 int main(int argc, char *argv[])
342 {
343     char mutateeName[128];
344     char libRTname[256];
345
346
347     strcpy(mutateeName,mutateeNameRoot);
348     libRTname[0]='\0';
349
350     if (!getenv("DYNINSTAPI_RT_LIB")) {
351          fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
352                  "    set it to the full pathname of libdyninstAPI_RT\n");
353          exit(-1);
354     } else
355          strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
356
357     updateSearchPaths(argv[0]);
358
359     unsigned int i;
360     // by default run all tests
361     for (i=1; i <= MAX_TEST; i++) {
362         runTest[i] = true;
363         passedTest[i] = false;
364     }
365
366     for (i=1; i < argc; i++) {
367         if (strncmp(argv[i], "-v+", 3) == 0)    errorPrint++;
368         if (strncmp(argv[i], "-v++", 4) == 0)   errorPrint++;
369         if (strncmp(argv[i], "-verbose", 2) == 0) {
370             debugPrint = 1;
371         } else if (!strcmp(argv[i], "-V")) {
372             fprintf (stdout, "%s\n", V_libdyninstAPI);
373             if (libRTname[0])
374                 fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
375             fflush(stdout);
376         } else if (!strcmp(argv[i], "-skip")) {
377             unsigned int j;
378             runAllTests = false;
379             for (j=i+1; j < argc; j++) {
380                 unsigned int testId;
381                 if ((testId = atoi(argv[j]))) {
382                     if ((testId > 0) && (testId <= MAX_TEST)) {
383                         runTest[testId] = false;
384                     } else {
385                         printf("invalid test %d requested\n", testId);
386                         exit(-1);
387                     }
388                 } else {
389                     // end of test list
390                     break;
391                 }
392             }
393             i=j-1;
394         } else if (!strcmp(argv[i], "-run")) {
395             unsigned int j;
396             runAllTests = false;
397             for (j=0; j <= MAX_TEST; j++) runTest[j] = false;
398             for (j=i+1; j < argc; j++) {
399                 unsigned int testId;
400                 if ((testId = atoi(argv[j]))) {
401                     if ((testId > 0) && (testId <= MAX_TEST)) {
402                         runTest[testId] = true;
403                     } else {
404                         printf("invalid test %d requested\n", testId);
405                         exit(-1);
406                     }
407                 } else {
408                     // end of test list
409                     break;
410                 }
411             }
412             i=j-1;
413         } else if (!strcmp(argv[i], "-mutatee")) {
414             i++;
415             if (*argv[i]=='_')
416                 strcat(mutateeName,argv[i]);
417             else
418                 strcpy(mutateeName,argv[i]);
419 #if defined(i386_unknown_nt4_0) \
420  || defined(i386_unknown_linux2_0) \
421  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
422  || defined(sparc_sun_solaris2_4)
423         } else if (!strcmp(argv[i], "-relocate")) {
424             forceRelocation = true;
425 #endif
426         } else {
427             fprintf(stderr, "Usage: test10 "
428                     "[-V] [-verbose]  "
429 #if defined(sparc_sun_solaris2_4) \
430  || defined(i386_unknown_linux2_0) \
431  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
432  || defined(rs6000_ibm_aix4_1)
433                     "[-saveworld] "
434 #endif 
435                     "[-mutatee <test1.mutatee>] "
436                     "[-run <test#> <test#> ...] "
437                     "[-skip <test#> <test#> ...]\n");
438             fprintf(stderr, "%d subtests\n", MAX_TEST);
439             exit(-1);
440         }
441     }
442
443     if (!runAllTests) {
444         printf("Running Tests: ");
445         for (unsigned int j=1; j <= MAX_TEST; j++) {
446             if (runTest[j]) printf("%d ", j);
447         }
448         printf("\n");
449     }
450
451     // patch up the default compiler in mutatee name (if necessary)
452     if (!strstr(mutateeName, "_"))
453 #if defined(i386_unknown_nt4_0)
454         strcat(mutateeName,"_VC");
455 #else
456         strcat(mutateeName,"_gcc");
457 #endif
458     int retVal = mutatorMAIN(mutateeName);
459
460     return retVal;
461 }