Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test_callback_2.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: test_callback_2.C,v 1.1 2008/10/30 19:21:26 legendre Exp $
33 /*
34  * #Name: test12_7
35  * #Desc: user defined message callback -- st
36  * #Dep: 
37  * #Arch: all
38  * #Notes:
39  */
40
41 #include <vector>
42 using std::vector;
43 #include "BPatch.h"
44 #include "BPatch_Vector.h"
45 #include "BPatch_thread.h"
46 #include "BPatch_snippet.h"
47
48 #include "test_lib.h"
49 #include "test12.h"
50
51 #include "dyninst_comp.h"
52 class test_callback_2_Mutator : public DyninstMutator {
53 protected:
54   BPatch *bpatch;
55
56   void dumpVars();
57   bool setVar(const char *vname, void *addr, int testno, const char *testname);
58   BPatchSnippetHandle *at(BPatch_point * pt, BPatch_function *call,
59                           int testno, const char *testname);
60
61 public:
62   virtual bool hasCustomExecutionPath() { return true; }
63   virtual test_results_t setup(ParameterDict &param);
64   virtual test_results_t executeTest();
65 };
66 extern "C" DLLEXPORT TestMutator *test_callback_2_factory() {
67   return new test_callback_2_Mutator();
68 }
69
70 #define TESTNO 7
71 #define TESTNAME "test_callback_2"
72 #define TESTDESC "user defined message callback -- st"
73
74 extern int debugPrint;
75
76 bool test7done = false;
77 bool test7err = false;
78 unsigned long test7_tids[TEST8_THREADS];
79 int callback_counter = 0;
80
81 std::vector<user_msg_t> elog;
82
83 static BPatch_point *findPoint(BPatch_function *f, BPatch_procedureLocation loc,
84                         int testno, const char *testname)
85 {
86   assert(f);
87   BPatch_Vector<BPatch_point *> *pts = f->findPoint(loc);
88
89   if (!pts) {
90           logerror("%s[%d]:  failed to find point\n", FILE__, __LINE__);
91     FAIL_MES(TESTNAME, TESTDESC);
92     return NULL;
93   }
94
95   if (pts->size() != 1) {
96           logerror("%s[%d]:  failed to find point: found too many\n", FILE__, __LINE__);
97       FAIL_MES(TESTNAME, TESTDESC);
98       return NULL;
99   }
100
101   return (*pts)[0];
102 }
103
104 //  at -- simple instrumentation.  As written, only can insert funcs without args -- 
105 //     -- modify to take snippet vector args if necessary.
106 BPatchSnippetHandle *
107 test_callback_2_Mutator::at(BPatch_point * pt, BPatch_function *call,
108                             int testno, const char *testname)
109 {
110   BPatch_Vector<BPatch_snippet *> args;
111   BPatch_funcCallExpr snip(*call, args);
112   BPatch_procedureLocation pttype = pt->getPointType();
113   BPatch_callWhen when;
114   if (pttype == BPatch_entry) when = BPatch_callBefore;
115   else if (pttype == BPatch_exit) when = BPatch_callAfter;
116   else if (pttype == BPatch_subroutine) when = BPatch_callBefore;
117   else assert(0);
118
119   BPatchSnippetHandle *ret;
120   ret = appThread->insertSnippet(snip, *pt,when);
121
122   if (!ret) 
123   {
124     logerror("%s[%d]:  could not insert instrumentation\n", __FILE__, __LINE__);
125     FAIL_MES(TESTNAME, TESTDESC);
126     test7err = true;
127   }
128
129   return ret;
130 }
131
132 void test_callback_2_Mutator::dumpVars()
133 {
134   BPatch_Vector<BPatch_variableExpr *> vars;
135   appImage->getVariables(vars);
136   for (unsigned int i = 0; i < vars.size(); ++i) {
137     logerror("\t%s\n", vars[i]->getName());
138   }
139 }
140
141 bool test_callback_2_Mutator::setVar(const char *vname, void *addr, int testno,
142                                      const char *testname) {
143    BPatch_variableExpr *v;
144    void *buf = addr;
145    if (NULL == (v = appImage->findVariable(vname))) {
146       logerror("**Failed test #%d (%s)\n", testno, testname);
147       logerror("  cannot find variable %s, avail vars:\n", vname);
148       dumpVars();
149       return true;
150    }
151
152    if (! v->writeValue(buf, sizeof(int),true)) {
153       logerror("**Failed test #%d (%s)\n", testno, testname);
154       logerror("  failed to write call site var to mutatee\n");
155       return true;
156    }
157    return false;
158 }
159
160
161 static void test7cb(BPatch_process *  proc, void *buf, unsigned int bufsize)
162 {
163   if (debugPrint)
164     dprintf("%s[%d]:  inside test7cb\n", __FILE__, __LINE__);
165
166   if (bufsize != sizeof(user_msg_t)) {
167     //  something is incredibly wrong
168     logerror("%s[%d]:  unexpected message size %d not %d\n",
169             __FILE__, __LINE__, bufsize, sizeof(user_msg_t));
170     test7err = true;
171     return;
172   }
173
174   user_msg_t *msg = (user_msg_t *) buf;
175   user_event_t what = msg->what;
176   unsigned long tid = msg->tid;
177
178   if (debugPrint)
179     dprintf("%s[%d]:  thread = %lu, what = %d\n", __FILE__, __LINE__, tid, what);
180
181   elog.push_back(*msg);
182
183   if (proc->getPid() != tid)
184   {
185           fprintf(stderr, "%s[%d]:  ERROR:  got event for pid %lu, not %lu\n", FILE__, __LINE__, tid, proc->getPid());
186   }
187
188   if (callback_counter == 0) {
189     //  we expect the entry point to be reported first
190     if (what != func_entry) {
191       logerror("%s[%d]:  unexpected message %d not %d\n",
192             __FILE__, __LINE__, (int) what, (int) func_entry);
193       FAIL_MES(TESTNAME, TESTDESC);
194       test7err = true;
195       return;
196     }
197   } else if (callback_counter <= TEST7_NUMCALLS) {
198     // we expect to get a bunch of function calls next
199     if (what != func_callsite) {
200       logerror("%s[%d]:  unexpected message %d not %d\n",
201             __FILE__, __LINE__, (int) what, (int) func_callsite);
202       FAIL_MES(TESTNAME, TESTDESC);
203       test7err = true;
204       return;
205     }
206   }
207   else if (callback_counter == (TEST7_NUMCALLS +1)) {
208     // lastly comes the function exit
209     if (what != func_exit) {
210       logerror("%s[%d]:  unexpected message %d not %d\n",
211             __FILE__, __LINE__, (int) what, (int) func_exit);
212       FAIL_MES(TESTNAME, TESTDESC);
213       test7err = true;
214       return;
215     }
216     // set test7done to end the test
217     test7done = true;
218   }
219   callback_counter++;
220 }
221
222 void log_res()
223 {
224         logerror("%s[%d]:  Here's what happened: \n", FILE__, __LINE__);
225         for (unsigned int i = 0; i < elog.size(); ++i)
226         {
227                 std::string ewhat;
228                 switch (elog[i].what) {
229                         case func_entry: ewhat = std::string("func_entry"); break;
230                         case func_callsite: ewhat = std::string("func_callsite"); break;
231                         case func_exit: ewhat = std::string("func_exit"); break;
232                         default:
233                                                         ewhat = std::string("unknown_event"); break;
234                 }
235                 logerror("\t %s:  %d\n", ewhat.c_str(), elog[i].tid);
236   }
237 }
238
239 // static int mutatorTest(BPatch_thread *appThread, BPatch_image *appImage)
240 test_results_t test_callback_2_Mutator::executeTest() 
241 {
242         //  a simple single threaded user messagin scenario where we want to send
243         //  async messages at function entry/exit and call points.
244
245         // load libtest12.so -- currently only used by subtest 5, but make it generally
246         // available
247         char *libname = "./libTest12.so";    
248         test7err = false;
249         test7done = false;
250         callback_counter = 0;
251         elog.resize(0);
252
253 #if defined(arch_x86_64_test)
254         if (appThread->getProcess()->getAddressWidth() == 4)
255                 libname = "./libTest12_m32.so";
256 #endif
257
258         dprintf("%s[%d]:  loading test library: %s\n", __FILE__, __LINE__, libname);
259
260         if (!appThread->loadLibrary(libname)) 
261         {
262                 logerror("%s[%d]:  failed to load library %s, cannot proceed\n", 
263                                 __FILE__, __LINE__, libname);
264                 appThread->getProcess()->terminateExecution();
265                 return FAILED;
266         }
267
268         dprintf("%s[%d]:  loaded test library: %s\n", __FILE__, __LINE__, libname);
269         BPatchUserEventCallback cb = test7cb;
270
271         if (!bpatch->registerUserEventCallback(cb)) 
272         {
273                 FAIL_MES(TESTNAME, TESTDESC);
274                 logerror("%s[%d]: could not register callback\n", __FILE__, __LINE__);
275                 appThread->getProcess()->terminateExecution();
276                 return FAILED;
277         }
278
279         //  instrument entry and exit of call7_1, as well as call points inside call7_1
280
281         const char *call1name = "test_callback_2_call1";
282
283         BPatch_function *call7_1 = findFunction(call1name, appImage,TESTNO, TESTNAME);
284
285         BPatch_point *entry = findPoint(call7_1, BPatch_entry,TESTNO, TESTNAME);
286
287         if (NULL == entry) 
288         {
289                 logerror("%s[%d]: Unable to find entry point to function %s\n", 
290                                 __FILE__, __LINE__, call1name);
291                 bpatch->removeUserEventCallback(test7cb);
292                 appThread->getProcess()->terminateExecution();
293                 return FAILED;
294         }
295
296         BPatch_point *exit = findPoint(call7_1, BPatch_exit,TESTNO, TESTNAME);
297
298         if (NULL == entry) 
299         {
300                 logerror("%s[%d]:  Unable to find exit point to function %s\n", 
301                                 __FILE__, __LINE__, call1name);
302                 bpatch->removeUserEventCallback(test7cb);
303                 appThread->getProcess()->terminateExecution();
304                 return FAILED;
305         }
306
307         BPatch_point *callsite = findPoint(call7_1, BPatch_subroutine,TESTNO, TESTNAME);
308
309         if (NULL == callsite) 
310         {
311                 logerror("%s[%d]:  Unable to find subroutine call point in function %s\n",
312                                 __FILE__, __LINE__, call1name);
313                 bpatch->removeUserEventCallback(test7cb);
314                 appThread->getProcess()->terminateExecution();
315                 return FAILED;
316         }
317
318         //  These are our asynchronous message functions (in libTest12) that we
319         //  attach to the "interesting" points
320
321         BPatch_function *reportEntry = findFunction("reportEntry", appImage,TESTNO, TESTNAME);
322         BPatch_function *reportExit = findFunction("reportExit", appImage,TESTNO, TESTNAME);
323         BPatch_function *reportCallsite = findFunction("reportCallsite", appImage,TESTNO, TESTNAME);
324
325         if (!reportEntry)
326         {
327                 logerror("%s[%d]:  reportEntry = NULL\n", FILE__, __LINE__);
328                 bpatch->removeUserEventCallback(test7cb);
329                 appThread->getProcess()->terminateExecution();
330                 return FAILED;
331         }
332         if (!reportExit)
333         {
334                 logerror("%s[%d]:  reportExit = NULL\n", FILE__, __LINE__);
335                 bpatch->removeUserEventCallback(test7cb);
336                 appThread->getProcess()->terminateExecution();
337                 return FAILED;
338         }
339         if (!reportCallsite)
340         {
341                 logerror("%s[%d]:  reportCallsite = NULL\n", FILE__, __LINE__);
342                 bpatch->removeUserEventCallback(test7cb);
343                 appThread->getProcess()->terminateExecution();
344                 return FAILED;
345         }
346
347         //  Do the instrumentation
348         BPatchSnippetHandle *entryHandle = at(entry, reportEntry, TESTNO, TESTNAME);
349         BPatchSnippetHandle *exitHandle = at(exit, reportExit, TESTNO, TESTNAME);
350         BPatchSnippetHandle *callsiteHandle = at(callsite, reportCallsite, TESTNO, TESTNAME);
351
352         //  "at" may set test7err
353         if ((test7err)
354                         ||  (NULL == entryHandle) 
355                         || (NULL == exitHandle) 
356                         || (NULL == callsiteHandle) )
357         {
358                 logerror("%s[%d]:  instrumentation failed, test7err = %d\n", FILE__, __LINE__, test7err);
359                 logerror("%s[%d]:  entryHandle = %p\n", FILE__, __LINE__, entryHandle);
360                 logerror("%s[%d]:  exitHandle = %p\n", FILE__, __LINE__, exitHandle);
361                 logerror("%s[%d]:  callsiteHandle = %p\n", FILE__, __LINE__, callsiteHandle);
362                 bpatch->removeUserEventCallback(test7cb);
363                 return FAILED;
364         }
365         if (debugPrint) 
366         {
367                 int one = 1;
368                 char *varName = "libraryDebug";
369                 if (setVar(varName, (void *) &one, TESTNO, TESTNAME)) 
370                 {
371                         logerror("%s[%d]:  Error setting variable '%s' in mutatee\n", 
372                                         FILE__, __LINE__, varName);
373                         bpatch->removeUserEventCallback(test7cb);
374                         appThread->getProcess()->terminateExecution();
375                         return FAILED;
376                 }
377         }
378
379         dprintf("%s[%d]:  did instrumentation, continuing process...: %s\n", 
380                         __FILE__, __LINE__, libname);
381         //  unset mutateeIdle to trigger mutatee to issue messages.
382
383         int timeout = 0;
384
385         appThread->getProcess()->continueExecution();
386
387         dprintf("%s[%d]:  continued process...: %s\n", 
388                         __FILE__, __LINE__, libname);
389         //  wait until we have received the desired number of events
390         //  (or timeout happens)
391
392         while(!test7err && !test7done && (timeout < TIMEOUT)) 
393         {
394                 sleep_ms(SLEEP_INTERVAL/*ms*/);
395                 timeout += SLEEP_INTERVAL;
396                 bpatch->pollForStatusChange();
397
398                 if (appThread->getProcess()->isTerminated())
399                 {
400                         BPatch_exitType et = appThread->getProcess()->terminationStatus();
401                         if (et == ExitedNormally)
402                         {
403                                 int ecode = appThread->getProcess()->getExitCode();
404                                 logerror("%s[%d]:  normal exit with code %d\n",
405                                                 __FILE__, __LINE__, ecode);
406                         }
407                         if (et == ExitedViaSignal)
408                         {
409                                 int ecode = appThread->getProcess()->getExitSignal();
410                                 logerror("%s[%d]:  caught signal %d\n",
411                                                 __FILE__, __LINE__, ecode);
412                         }
413                         log_res();
414                         bpatch->removeUserEventCallback(test7cb);
415                         return FAILED;
416                 }
417         }
418
419         dprintf("%s[%d]:  after wait loop:  test7err = %s, test7done = %s, timeout = %d\n", 
420                         __FILE__, __LINE__, test7err ? "true" : "false", test7done ? "true" : "false", timeout);
421
422         if (timeout >= TIMEOUT) 
423         {
424                 FAIL_MES(TESTNAME, TESTDESC);
425                 logerror("%s[%d]:  test timed out: %d ms\n",
426                                 __FILE__, __LINE__, TIMEOUT);
427                 test7err = true;
428         }
429
430         if (!appThread->getProcess()->stopExecution())
431         {
432                 logerror("%s[%d]:  stopExecution failed\n",
433                                 __FILE__, __LINE__);
434
435         }
436
437         dprintf("%s[%d]:  stopped process...\n", 
438                         __FILE__, __LINE__ );
439
440         if (!bpatch->removeUserEventCallback(test7cb)) 
441         {
442                 FAIL_MES(TESTNAME, TESTDESC);
443                 logerror("%s[%d]:  failed to remove callback\n",
444                                 __FILE__, __LINE__);
445                 appThread->getProcess()->terminateExecution();
446                 log_res();
447                 return FAILED;
448         }
449
450         dprintf("%s[%d]:  removed callback...\n", 
451                         __FILE__, __LINE__ );
452         if (!appThread->getProcess()->terminateExecution())
453         {
454                 //  don't care
455                 //fprintf(stderr, "%s[%d]:  terminateExecution failed\n", FILE__, __LINE__);
456                 //return FAILED;
457         }
458
459 #if 0
460         int one = 1;
461
462         if (setVar("test_callback_2_idle", (void *) &one, TESTNO, TESTNAME)) 
463         {
464                 logerror("Error setting variable 'test_callback_2_idle' in mutatee\n");
465                 test7err = true;
466                 appThread->getProcess()->terminateExecution();
467         }
468 #endif
469
470 #if 0
471         // And let it run out
472         if (!appThread->isTerminated()) 
473         {
474                 appThread->getProcess()->continueExecution();
475         }
476
477         while (!appThread->isTerminated()) 
478         {
479                 // Workaround for pgCC_high mutatee issue
480                 bpatch->waitForStatusChange();
481         }
482 #endif
483
484         if (!test7err) 
485         {
486                 PASS_MES(TESTNAME, TESTDESC);
487                 return PASSED;
488         }
489
490         log_res();
491         FAIL_MES(TESTNAME, TESTDESC);
492         return FAILED;
493 }
494
495 // extern "C" int test12_7_mutatorMAIN(ParameterDict &param)
496 test_results_t test_callback_2_Mutator::setup(ParameterDict &param) {
497         DyninstMutator::setup(param);
498         debugPrint = param["debugPrint"]->getInt();
499         bpatch = (BPatch *)(param["bpatch"]->getPtr());
500         return PASSED;
501 }