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