cleanup
[dyninst.git] / dyninstAPI / tests / src / test2.C
1 // $Id: test2.C,v 1.16 1999/06/08 06:01:26 csserra Exp $
2 //
3 // libdyninst validation suite test #2
4 //    Author: Jeff Hollingsworth (7/10/97)
5 //
6
7 //  This program tests the error features of the dyninst API.  
8 //      The mutatee that goes with this file is test2.mutatee.c
9 //      
10 //  Naming conventions:
11 //      All functions, variables, etc are name funcXX_YY, exprXX_YY, etc.
12 //          XX is the test number
13 //          YY is the instance withing the test
14 //          func1_2 is the second function used in test case #1.
15 //
16
17 #include <stdio.h>
18 #include <signal.h>
19 #include <string.h>
20 #ifdef i386_unknown_nt4_0
21 #include <io.h>
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #else
25 #include <unistd.h>
26 #endif
27
28 #include "BPatch.h"
29 #include "BPatch_Vector.h"
30 #include "BPatch_thread.h"
31 #include "BPatch_snippet.h"
32 #include "test_util.h"
33 #include "test2.h"
34
35 #ifdef i386_unknown_nt4_0
36 #define access _access
37 #define unlink _unlink
38 #define F_OK 0
39 #endif
40
41 #ifdef i386_unknown_nt4_0
42 #define MUTATEE_NAME    "test2.mutatee.exe"
43 #else
44 #define MUTATEE_NAME    "./test2.mutatee"
45 #endif
46
47 extern "C" const char V_libdyninstAPI[];
48
49 int debugPrint = 0;
50 bool expectErrors = false;
51 bool gotError = false;
52
53 BPatch *bpatch;
54
55 // control debug printf statements
56 #define dprintf if (debugPrint) printf
57
58 void test10a(BPatch_thread *appThread, BPatch_image *appImage)
59 {
60     /*
61      * Instrument a function with a BPatch_breakPointExpr.
62      */
63     BPatch_Vector<BPatch_point*> *points =
64         appImage->findProcedurePoint("func10_1", BPatch_entry);
65     if (points == NULL) {
66         printf("**Failed** test #10 (BPatch_breakPointExpr)\n");
67         printf("    unable to locate function \"func10_1\".\n");
68         exit(1);
69     }
70
71     BPatch_breakPointExpr bp;
72
73     if (appThread->insertSnippet(bp, *points) == NULL) {
74         printf("**Failed** test #10 (BPatch_breakPointExpr)\n");
75         printf("    unable to insert breakpoint snippet\n");
76         exit(1);
77     }
78 }
79
80 void test11(BPatch_thread * /*appThread*/, BPatch_image *appImage)
81 {
82 #if !defined(rs6000_ibm_aix4_1)
83     // Test getDisplacedInstructions
84     printf("Skipping test #11 (getDisplacedInstructions)\n");
85     printf("         - not implemented on this platform\n");
86 #else
87     BPatch_Vector<BPatch_point*> *points =
88         appImage->findProcedurePoint("func11_1", BPatch_entry);
89     if (points == NULL) {
90         printf("**Failed** test #11 (getDisplacedInstructions)\n");
91         printf("    unable to locate function \"func11_1\".\n");
92         exit(1);
93     }
94
95     char buf[128];
96     memset(buf, 128, 0);
97     int nbytes = (*points)[0]->getDisplacedInstructions(128, buf);
98     if (nbytes < 0 || nbytes > 128) {
99         printf("**Failed** test #11 (getDisplacedInstructions)\n");
100         printf("    getDisplacedInstructions returned a strange number of bytes (%d)\n", nbytes);
101     }
102     int i;
103     for (i = 0; i < nbytes; i++) {
104         if (buf[i] != 0) break;
105     }
106     if (i == nbytes) {
107         printf("**Failed** test #11 (getDisplacedInstructions)\n");
108         printf("    getDisplacedInstructions doesn't seem to have returned any instructions\n");
109     }
110     printf("Passed test #11 (getDisplacedInstructions)\n");
111 #endif
112 }
113
114 void test12(BPatch_thread *appThread, BPatch_image *appImage)
115 {
116
117     BPatch_Vector<BPatch_point*> *points =
118         appImage->findProcedurePoint("func12_1", BPatch_entry);
119     
120     if (!points) {
121         printf("**Failed** test #12 (BPatch_point query funcs)\n");
122         printf("    unable to locate function \"func12_1\".\n");
123         exit(1);
124     }
125
126     void *addr = (*points)[0]->getAddress();
127
128     bool trapFlag = (*points)[0]->usesTrap_NP();
129
130     printf("Passed test #12 (BPatch_point query funcs)\n");
131 }
132
133 BPatch_thread *mutatorMAIN(char *pathname, bool useAttach)
134 {
135     BPatch_thread *appThread;
136
137     // Start the mutatee
138     dprintf("Starting \"%s\"\n", pathname);
139
140     char *child_argv[4];
141    
142     int n = 0;
143     child_argv[n++] = pathname;
144     if (debugPrint) child_argv[n++] = "-verbose";
145     child_argv[n] = NULL;
146
147     if (useAttach) {
148         int pid = startNewProcessForAttach(pathname, child_argv);
149         if (pid < 0 && !expectErrors) {
150             printf("*ERROR*: unable to start tests due to error starting mutatee process\n");
151             exit(-1);
152         }
153         appThread = bpatch->attachProcess(pathname, pid);
154     } else {
155         appThread = bpatch->createProcess(pathname, child_argv);
156     }
157
158     return appThread;
159 }
160
161 void errorFunc(BPatchErrorLevel level, int num, const char **params)
162 {
163     char line[256];
164
165     const char *msg = bpatch->getEnglishErrorString(num);
166     bpatch->formatErrorString(line, sizeof(line), msg, params);
167
168     gotError = true;
169
170     if (expectErrors) {
171         if (debugPrint)
172             printf("Error (expected) #%d (level %d): %s\n", num, level, line);
173     } else {
174         printf("Error #%d (level %d): %s\n", num, level, line);
175     }
176 }
177
178 bool processMgmntTests()
179 {
180     BPatch_thread *ret;
181
182     // Now test forking.
183     char *child_argv[4];
184
185     child_argv[0] = MUTATEE_NAME;
186     child_argv[1] = "-fork";
187     child_argv[2] = NULL;
188     ret = bpatch->createProcess(MUTATEE_NAME, child_argv);
189
190     if (!ret) {
191         printf("**Failed** test #14 (process mgmnt. tests)\n"); // LAST TEST
192         printf("    unable to create the new process\n");
193         return(true);
194     }
195
196     if (ret->isStopped()) ret->continueExecution();
197
198     bool dead = ret->terminateExecution();
199     if (!dead) {
200         printf("**Failed** test #14 (process mgmnt. tests)\n"); // LAST TEST
201         printf("    unable to terminate the new process\n");
202         return(true);
203     }
204
205     printf("Passed test #14 (process mgmnt. tests)\n");
206     return false;
207 }
208
209 //
210 // main - decide our role and call the correct "main"
211 //
212 main(int argc, char *argv[])
213 {
214     BPatch_thread *ret;
215     bool useAttach = false;
216     bool failed = false;
217
218     char libname[256];
219     libname[0]='\0';
220
221 #if !defined(USES_LIBDYNINSTRT_SO)
222     fprintf(stderr,"(Expecting application to be statically linked"
223                         " with libdyninstAPI_RT.)\n");
224 #else
225 #if !defined(i386_unknown_nt4_0)
226     if (getenv("DYNINSTAPI_RT_LIB") != NULL) {
227         strcpy((char*) libname, (char*) getenv("DYNINSTAPI_RT_LIB"));
228     } else {
229         fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
230                 "    set it to the full pathname of libdyninstAPI_RT\n");   
231         exit(-1);
232     }
233 #endif
234 #endif
235
236     // Create an instance of the bpatch library
237     bpatch = new BPatch;
238
239     bpatch->registerErrorCallback(errorFunc);
240
241     int i;
242     for (i=1; i < argc; i++) {
243         if (!strcmp(argv[i], "-verbose")) {
244             debugPrint = 1;
245         } else if (!strcmp(argv[i], "-V")) {
246             fprintf (stdout, "%s\n", V_libdyninstAPI);
247             if (libname[0]) fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libname);
248         } else if (!strcmp(argv[i], "-attach")) {
249             useAttach = true;
250         } else {
251             fprintf(stderr, "Usage: test2 [-V] [-attach] [-verbose]\n");
252             exit(-1);
253         }
254     }
255
256 #if defined(sparc_sun_sunos4_1_3) || defined(alpha_dec_osf4_0)
257     if (useAttach) {
258         printf("Attach is not supported on this platform.\n");
259         exit(1);
260     }
261 #endif
262
263     // Try failure cases
264     expectErrors = true;
265
266     if (useAttach) {
267         printf("Skipping test #1 (run an executable that does not exist)\n");
268         printf("    not relevant with -attach option\n");
269     } else {
270         // try to run a program that does not exist
271         gotError = false;
272         ret = mutatorMAIN("./noSuchFile", useAttach);
273         if (ret || !gotError) {
274             failed = true;
275             printf("**Failed** test #1 (run an executable that does not exist)\n");
276             if (ret)
277                 printf("    created a thread handle for a non-existant file\n");
278             if (!gotError)
279                 printf("    the error callback should have been called but wasn't\n");
280         } else {
281             printf("Passed test #1 (run an executable that does not exist)\n");
282         }
283     }
284
285     // try to run a files that is not a valid program
286     gotError = false;
287 #ifdef i386_unknown_nt4_0
288     ret = mutatorMAIN("nul:", false);
289 #else
290     ret = mutatorMAIN("/dev/null", false);
291 #endif
292     if (ret || !gotError) {
293         printf("**Failed** test #2 (try to execute a file that is not a valid program)\n");
294         failed = true;
295         if (ret)
296             printf("    created a thread handle for invalid executable\n");
297         if (!gotError)
298             printf("    the error callback should have been called but wasn't\n");
299     } else {
300         printf("Passed test #2 (try to execute a file that is not a valid program)\n");
301     }
302
303 #if defined(sparc_sun_sunos4_1_3)
304     printf("Skipping test #3 (attach to an invalid pid)\n");
305     printf("Skipping test #4 (attach to a protected pid)\n");
306     printf("    attach is not supported on this platform\n");
307 #else
308     // attach to an an invalid pid
309     gotError = false;
310     ret = bpatch->attachProcess(MUTATEE_NAME, 65539);
311     if (ret || !gotError) {
312         printf("**Failed** test #3 (attach to an invalid pid)\n");
313         failed = true;
314         if (ret)
315             printf("    created a thread handle for invalid executable\n");
316         if (!gotError)
317             printf("    the error callback should have been called but wasn't\n");
318     } else {
319         printf("Passed test #3 (attach to an invalid pid)\n");
320     }
321
322     // attach to an a protected pid
323     gotError = false;
324     ret = bpatch->attachProcess(MUTATEE_NAME, 1);
325     if (ret || !gotError) {
326         printf("**Failed** test #4 (attach to a protected pid)\n");
327         failed = true;
328         if (ret)
329             printf("    created a thread handle for invalid executable\n");
330         if (!gotError)
331             printf("    the error callback should have been called but wasn't\n");
332     } else {
333         printf("Passed test #4 (attach to a protected pid)\n");
334     }
335 #endif
336
337     // Finished trying failure cases
338     expectErrors = false;
339
340     // now start a real program
341     gotError = false;
342     ret = mutatorMAIN(MUTATEE_NAME, useAttach);
343     if (!ret || gotError) {
344         printf("*ERROR*: unable to create handle for executable\n");
345         failed = true;
346     }
347
348     BPatch_image *img = ret->getImage();
349
350     // Signal the child that we've attached
351     if ( useAttach )
352                 signalAttached( ret, img );
353
354     gotError = false;
355     expectErrors = true; // test #5 causes error #100 (Unable to find function)
356     BPatch_function *func = img->findFunction("NoSuchFunction");
357     expectErrors = false;
358     if (func || !gotError) {
359         printf("**Failed** test #5 (look up nonexistent function)\n");
360         failed = true;
361         if (func)
362             printf("    non-null for findFunction on non-existant func\n");
363         if (!gotError)
364             printf("    the error callback should have been called but wasn't\n");
365     } else {
366         printf("Passed test #5 (look up nonexistent function)\n");
367     }
368
369     test10a(ret, img);
370
371     ret->continueExecution();
372
373 #if !defined(sparc_sun_solaris2_4)  && !defined(i386_unknown_solaris2_5) && \
374     !defined(i386_unknown_linux2_0) && !defined(mips_sgi_irix6_4) && \
375     !defined(alpha_dec_osf4_0)
376     printf("Skipping test #6 (load a dynamically linked library from the mutatee)\n");
377     printf("    feature not implemented on this platform\n");
378
379     printf("Skipping test #7 (load a dynamically linked library from the mutator)\n");
380     printf("    feature not implemented on this platform\n");
381 #else
382
383     bool found = false;
384
385     waitUntilStopped(bpatch, ret, 6, "load a dynamically linked library");
386
387     // see if the dlopen happended.
388     char match2[256];
389     sprintf(match2, "%s_module", TEST_DYNAMIC_LIB);
390     BPatch_Vector<BPatch_module *> *m = img->getModules();
391     for (i=0; i < m->size(); i++) {
392             char name[80];
393             (*m)[i]->getName(name, sizeof(name));
394             if (strcmp(name, TEST_DYNAMIC_LIB) == 0 ||
395                 strcmp(name, match2) == 0) {
396                 found = true;
397                 break;
398             }
399     }
400     if (found) {
401         printf("Passed test #6 (load a dynamically linked library from the mutatee)\n");
402     } else {
403         printf("**Failed** test #6 (load a dynamically linked library from the mutatee)\n");
404         printf("    image::getModules() did not indicate that the library had been loaded\n");
405         failed = true;
406     }
407
408 #if defined(alpha_dec_osf4_0)
409     printf("Skipping test #7 (load a dynamically linked library from the mutator)\n");
410 #else
411     if (!ret->loadLibrary(TEST_DYNAMIC_LIB2)) {
412         printf("**Failed** test #7 (load a dynamically linked library from the mutator)\n");
413         printf("    BPatch_thread::loadLibrary returned an error\n");
414         failed = true;
415     } else {
416         // see if it worked
417         found = false;
418         char match2[256];
419         sprintf(match2, "%s_module", TEST_DYNAMIC_LIB2);
420         BPatch_Vector<BPatch_module *> *m = img->getModules();
421         for (i=0; i < m->size(); i++) {
422                 char name[80];
423                 (*m)[i]->getName(name, sizeof(name));
424                 if (strcmp(name, TEST_DYNAMIC_LIB2) == 0 ||
425                     strcmp(name, match2) == 0) {
426                     found = true;
427                     break;
428                 }
429         }
430         if (found) {
431             printf("Passed test #7 (load a dynamically linked library from the mutator)\n");
432         } else {
433             printf("**Failed** test #7 (load a dynamically linked library from the mutator)\n");
434             printf("    image::getModules() did not indicate that the library had been loaded\n");
435             failed = true;
436         }
437     }
438 #endif
439
440     ret->continueExecution();
441
442 #endif
443
444     // Wait for process to finish
445     waitUntilStopped(bpatch, ret, 8, "BPatch_breakPointExpr");
446
447     // waitUntilStopped would not return is we didn't stop
448     printf("Passed test #8 (BPatch_breakPointExpr)\n");
449
450 #if !defined(sparc_sun_sunos4_1_3) && !defined(sparc_sun_solaris2_4) && !defined(mips_sgi_irix6_4)
451     printf("Skipping test #9 (dump core but do not terminate)\n");
452     printf("    BPatch_thread::dumpCore not implemented on this platform\n");
453 #else
454     // dump core, but do not terminate.
455     // this doesn't seem to do anything - jkh 7/12/97
456     if (access("mycore", F_OK) == 0) {
457         dprintf("File \"mycore\" exists.  Deleting it.\n");
458         if (unlink("mycore") != 0) {
459             printf("Couldn't delete the file \"mycore\".  Exiting.\n");
460             exit(-1);
461         }
462     }
463
464     gotError = false;
465     ret->dumpCore("mycore", true);
466     bool coreExists = (access("mycore", F_OK) == 0);
467     if (gotError || !coreExists) {
468         printf("**Failed** test #9 (dump core but do not terminate)\n");
469         failed = true;
470         if (gotError)
471             printf("    error reported by dumpCore\n");
472         if (!coreExists)
473             printf("    the core file wasn't written\n");
474     } else {
475         printf("Passed test #9 (dump core but do not terminate)\n");
476     }
477 #endif
478
479 #if !defined(rs6000_ibm_aix4_1)    && !defined(sparc_sun_sunos4_1_3)  && \
480     !defined(sparc_sun_solaris2_4) && !defined(i386_unknown_linux2_0) && \
481     !defined(mips_sgi_irix6_4) && !defined(alpha_dec_osf4_0)
482     printf("Skipping test #10 (dump image)\n");
483     printf("    BPatch_thread::dumpImage not implemented on this platform\n");
484 #else
485     // dump image
486     if (access("myimage", F_OK) == 0) {
487         dprintf("File \"myimage\" exists.  Deleting it.\n");
488         if (unlink("myimage") != 0) {
489             printf("Couldn't delete the file \"myimage\".  Exiting.\n");
490             exit(-1);
491         }
492     }
493
494     gotError = false;
495     ret->dumpImage("myimage");
496     bool imageExists = (access("myimage", F_OK) == 0);
497     if (gotError || !imageExists) {
498         printf("**Failed** test #10 (dump image)\n");
499         failed = true;
500         if (gotError)
501             printf("    error reported by dumpImage\n");
502         if (!imageExists)
503             printf("    the image file wasn't written\n");
504     } else {
505         printf("Passed test #10 (dump image)\n");
506     }
507 #endif
508
509     // Test getDisplacedInstructions
510     test11(ret, img);
511
512     // BPatch_point information functions
513     test12(ret, img);
514
515     /**********************************************************************
516      * Kill process and make sure it goes away
517      **********************************************************************/
518     
519     int pid = ret->getPid();
520
521 #ifndef i386_unknown_nt4_0 /* Not yet implemented on NT. */
522     // detach from the process.
523     ret->detach(true);
524 #endif
525
526     // now kill the process.
527 #ifdef i386_unknown_nt4_0
528     HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
529     if (h != NULL) {
530         TerminateProcess(h, 0);
531         CloseHandle(h);
532     }
533 #else
534     kill(pid, SIGKILL);
535 #endif
536
537     delete (ret);
538     bool failed_this = false;
539     BPatch_Vector<BPatch_thread *> *threads = bpatch->getThreads();
540     for (i=0; i < threads->size(); i++) {
541         if ((*threads)[i] == ret) {
542             printf("**Failed** test #13 (delete thread)\n"); 
543             printf("    thread %d was deleted, but getThreads found it\n",
544                 ret->getPid());
545             failed = true;
546             failed_this = true;
547         }
548     }
549
550     if (!failed_this) {
551         printf("Passed test #13 (delete thread)\n");
552     }
553
554     failed |= processMgmntTests();
555
556     delete (bpatch);
557
558     if (failed) {
559         printf("**Failed** tests\n");
560     } else {
561         printf("Passed all tests\n");
562     }
563
564     return 0;
565 }