Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test_thread_5.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: 
33 /*
34  * #Name: test12_8
35  * #Desc: user defined message callback -- mt
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_thread_5_Mutator : public DyninstMutator {
53 protected:
54   BPatch *bpatch;
55
56   BPatchSnippetHandle *at(BPatch_point * pt, BPatch_function *call,
57                           int testno, const char *testname);
58   void dumpVars();
59   bool setVar(const char *vname, void *addr, int testno,
60               const char *testname);
61
62
63
64 public:
65   virtual bool hasCustomExecutionPath() { return true; }
66   virtual test_results_t setup(ParameterDict &param);
67   virtual test_results_t executeTest();
68 };
69 extern "C" DLLEXPORT TestMutator *test_thread_5_factory() {
70   return new test_thread_5_Mutator();
71 }
72
73 #define TESTNO 8
74 #define TESTNAME "test_thread_5"
75 #define TESTDESC "user defined message callback -- mt"
76
77 static int debugPrint;
78
79 static BPatch_point *findPoint(BPatch_function *f, BPatch_procedureLocation loc,
80                         int testno, const char *testname)
81 {
82   assert(f);
83   BPatch_Vector<BPatch_point *> *pts = f->findPoint(loc);
84
85   if (!pts) {
86     FAIL_MES(testno, testname);
87     logerror("%s[%d]:  no points matching requested location\n", __FILE__, __LINE__);
88     return NULL;
89   }
90
91   if (pts->size() != 1) {
92     FAIL_MES(testno, testname);
93     logerror("%s[%d]:  %d points matching requested location, not 1\n", __FILE__, __LINE__,
94            pts->size());
95     return NULL;
96   }
97
98   return (*pts)[0];
99 }
100
101 //  at -- simple instrumentation.  As written, only can insert funcs without args -- 
102 //     -- modify to take snippet vector args if necessary.
103 BPatchSnippetHandle *
104 test_thread_5_Mutator::at(BPatch_point * pt, BPatch_function *call,
105                           int testno, const char *testname)
106 {
107   BPatch_Vector<BPatch_snippet *> args;
108   BPatch_funcCallExpr snip(*call, args);
109   BPatch_procedureLocation pttype = pt->getPointType();
110   BPatch_callWhen when;
111   if (pttype == BPatch_entry) when = BPatch_callBefore;
112   else if (pttype == BPatch_exit) when = BPatch_callAfter;
113   else if (pttype == BPatch_subroutine) when = BPatch_callBefore;
114   else assert(0);
115
116   BPatchSnippetHandle *ret;
117   ret = appThread->insertSnippet(snip, *pt,when);
118
119   if (!ret) {
120     FAIL_MES(testno, testname);
121     logerror("%s[%d]:  could not insert instrumentation\n", __FILE__, __LINE__);
122     return NULL;
123   }
124
125   return ret;
126 }
127
128 void test_thread_5_Mutator::dumpVars() {
129   BPatch_Vector<BPatch_variableExpr *> vars;
130   appImage->getVariables(vars);
131   for (unsigned int i = 0; i < vars.size(); ++i) {
132     logerror("\t%s\n", vars[i]->getName());
133   }
134 }
135
136 // Returns false on success and true on error
137 bool test_thread_5_Mutator::setVar(const char *vname, void *addr, int testno,
138                                    const char *testname) {
139    BPatch_variableExpr *v;
140    void *buf = addr;
141    if (NULL == (v = appImage->findVariable(vname))) {
142       logerror("**Failed test #%d (%s)\n", testno, testname);
143       logerror("  cannot find variable %s, avail vars:\n", vname);
144       dumpVars();
145       return true;
146    }
147
148    if (! v->writeValue(buf, sizeof(int),true)) {
149       logerror("**Failed test #%d (%s)\n", testno, testname);
150       logerror("  failed to write call site var to mutatee\n");
151       return true;
152    }
153    return false;
154 }
155
156 static bool test8done = false;
157 static bool test8err = false;
158 static unsigned long tids[TEST8_THREADS];
159 static user_event_t last_event[TEST8_THREADS];
160
161 static bool findThreadIndex(unsigned long tid, unsigned int &index)
162 {
163  //  find the index with tid <tid>, if it exists, otherwise, the index of
164  //  an empty slot.  If no empty slot, return false (fail);
165   for (index = 0; index < TEST8_THREADS; ++index) {
166     if (0 == tids[index]) {
167       tids[index] = tid;
168       if (debugPrint)
169         dprintf("%s[%d]:  giving new slot to thread id %lu\n",
170                 __FILE__, __LINE__, tid);
171       return true;
172     }
173     if (tid == tids[index])
174       return true;
175   }
176   return false;
177 }
178
179 static void test8cb(BPatch_process * /*proc*/, void *buf, unsigned int bufsize)
180 {
181   // FIXME This being static is probably killing the test
182   static int destroy_counter = 0;
183   if (debugPrint)
184     dprintf("%s[%d]:  inside test8cb\n", __FILE__, __LINE__);
185
186   if (bufsize != sizeof(user_msg_t)) {
187     //  something is incredibly wrong
188     logerror("%s[%d]:  unexpected message size %d not %d\n",
189             __FILE__, __LINE__, bufsize, sizeof(user_msg_t));
190     test8err = true;
191     return;
192   }
193
194   user_msg_t *msg = (user_msg_t *) buf;
195   user_event_t what = msg->what;
196   unsigned long tid = msg->tid;
197
198   if (debugPrint)
199     dprintf("%s[%d]:  thread = %lu, what = %d\n", __FILE__, __LINE__, tid, what);
200   unsigned int index;
201   if (!findThreadIndex(tid, index)) {
202     test8err = true;
203     logerror("%s[%d]:  failed to find record for tid %lu (or empty slot)\n",
204             __FILE__, __LINE__,tid);
205     return;
206   }
207
208   if (debugPrint)
209     dprintf("%s[%d]:  thread id %lu: index %d\n", __FILE__, __LINE__, tid, index);
210   if (last_event[index] != (what - 1)) {
211     test8err = true;
212     logerror("%s[%d]:  out of order messsage received for thread %lu, last = %d, now = %d\n",
213            __FILE__, __LINE__, tid, last_event[index], what);
214     return;
215   }
216   last_event[index] = what;
217
218   if (what == mutex_destroy) {
219      destroy_counter++;
220   }
221   if (destroy_counter == TEST8_THREADS) {
222     destroy_counter = 0;
223     test8done = true;
224   }
225   //sleep_ms(10);
226 }
227
228 // Macro to do some return code checking after calls to findPoint()
229 #define CHECK_POINT(pt, ptname, fnname) \
230 do { \
231   if (NULL == (pt)) { \
232     logerror("**Failed test_thread_5\n"); \
233     logerror("    Unable to find %s point to %s\n", (ptname), (fnname)); \
234     appThread->getProcess()->terminateExecution(); \
235     return FAILED; \
236   } \
237 } while (0)
238
239 #define CHECK_AT(snippet) \
240 do { \
241   if (NULL == snippet) { \
242     logerror("**Failed test_thread_5\n"); \
243     logerror("    Failed to insert snippet\n"); \
244     appThread->getProcess()->terminateExecution(); \
245     return FAILED; \
246   } \
247 } while (0)
248
249 // static int mutatorTest(BPatch_thread *appThread, BPatch_image *appImage)
250 test_results_t test_thread_5_Mutator::executeTest() {
251   test8done = false;
252   test8err = false;
253
254     // load libtest12.so -- currently only used by subtest 5, but make it generally
255     // available
256     char *libname = "./libTest12.so";    
257 #if defined(arch_x86_64_test)
258     if (appThread->getProcess()->getAddressWidth() == 4)
259       libname = "./libTest12_m32.so";
260 #endif
261     dprintf("%s[%d]:  loading test library: %s\n", __FILE__, __LINE__, libname);
262     if (!appThread->loadLibrary(libname)) {
263       logerror("%s[%d]:  failed to load library %s, cannot proceed\n", 
264               __FILE__, __LINE__, libname);
265       appThread->getProcess()->terminateExecution();
266       return FAILED;
267     }
268
269   for (unsigned int i = 0; i < TEST8_THREADS; ++i) {
270     tids[i] = 0;
271     last_event[i] = null_event;
272   }
273
274   //  instrument events having to do with mutex init, lock, unlock, destroy
275   //  with messaging functions in libtest12.so
276   BPatch_module *libpthread = appImage->findModule("libpthread",true);
277   assert(libpthread);
278
279   BPatch_function *mutInit = findFunction("createLock", appImage,TESTNO, TESTDESC);
280   BPatch_point *mutInitPt = findPoint(mutInit, BPatch_entry,TESTNO, TESTDESC);
281   CHECK_POINT(mutInitPt, "entry", "createLock");
282   BPatch_function *reportInit = findFunction("reportMutexInit", appImage,TESTNO, TESTDESC);
283   BPatchSnippetHandle *initHandle = at(mutInitPt, reportInit, TESTNO, TESTDESC);
284   CHECK_AT(initHandle);
285   BPatch_function *mutDestroy = findFunction("destroyLock", appImage,TESTNO, TESTDESC);
286   BPatch_point *mutDestroyPt = findPoint(mutDestroy, BPatch_entry,TESTNO, TESTDESC);
287   CHECK_POINT(mutDestroyPt, "entry", "destroyLock");
288   BPatch_function *reportDestroy = findFunction("reportMutexDestroy", appImage,TESTNO, TESTDESC);
289   BPatchSnippetHandle *destroyHandle = at(mutDestroyPt, reportDestroy, TESTNO, TESTDESC);
290   CHECK_AT(destroyHandle);
291
292   BPatch_function *mutLock = findFunction("lockLock", appImage,TESTNO, TESTDESC);
293   BPatch_point *mutLockPt = findPoint(mutLock, BPatch_entry,TESTNO,TESTDESC);
294   CHECK_POINT(mutLockPt, "entry", "lockLock");
295   BPatch_function *reportLock = findFunction("reportMutexLock", appImage,TESTNO, TESTDESC);
296   BPatchSnippetHandle *lockHandle = at(mutLockPt, reportLock, TESTNO, TESTDESC);
297   CHECK_AT(lockHandle);
298   BPatch_function *mutUnlock = findFunction("unlockLock", appImage,TESTNO, TESTDESC);
299   BPatch_point *mutUnlockPt = findPoint(mutUnlock, BPatch_entry,TESTNO,TESTDESC);
300   CHECK_POINT(mutUnlockPt, "entry", "unlockLock");
301   BPatch_function *reportUnlock = findFunction("reportMutexUnlock", appImage,TESTNO, TESTDESC);
302   BPatchSnippetHandle *unlockHandle = at(mutUnlockPt, reportUnlock, TESTNO, TESTDESC);
303   CHECK_AT(unlockHandle);
304
305   BPatchUserEventCallback cb = test8cb;
306   if (!bpatch->registerUserEventCallback(cb)) {
307     FAIL_MES(TESTNAME, TESTDESC);
308     logerror("%s[%d]: could not register callback\n", __FILE__, __LINE__);
309     appThread->getProcess()->terminateExecution();
310     return FAILED;
311   }
312
313
314   int timeout = 0;
315   appThread->getProcess()->continueExecution();
316
317   //  wait until we have received the desired number of events
318   //  (or timeout happens)
319   while(!test8err && !test8done && (timeout < TIMEOUT)) {
320     sleep_ms(SLEEP_INTERVAL/*ms*/);
321     timeout += SLEEP_INTERVAL;
322     bpatch->pollForStatusChange();
323   }
324
325   if (timeout >= TIMEOUT) {
326     FAIL_MES(TESTNAME, TESTDESC);
327     logerror("%s[%d]:  test timed out. Took longer than %d ms\n",
328            __FILE__, __LINE__, TIMEOUT);
329     test8err = true;
330   }
331
332   appThread->getProcess()->stopExecution();
333
334   int one = 1;
335   // I need to check the return value for this function call
336   if (setVar("test_thread_5_idle", (void *) &one, TESTNO, TESTDESC)) {
337     logerror("Unable to set variable test_thread_5_idle\n");
338     appThread->getProcess()->terminateExecution();
339     return FAILED;
340   }
341
342   if (!bpatch->removeUserEventCallback(test8cb)) {
343     FAIL_MES(TESTNAME, TESTDESC);
344     logerror("%s[%d]:  failed to remove callback\n",
345            __FILE__, __LINE__);
346     appThread->getProcess()->terminateExecution();
347     return FAILED;
348   }
349
350   //  what happens here if we still have messages coming in, but no handler -- should
351   //  check this?
352
353
354   appThread->getProcess()->deleteSnippet(initHandle);
355   appThread->getProcess()->deleteSnippet(destroyHandle);
356   appThread->getProcess()->deleteSnippet(lockHandle);
357   appThread->getProcess()->deleteSnippet(unlockHandle);
358
359   appThread->getProcess()->continueExecution();
360
361   while (!appThread->getProcess()->isTerminated()) {
362     bpatch->waitForStatusChange();
363   }
364
365   if (!test8err) {
366     PASS_MES(TESTNAME, TESTDESC);
367     return PASSED;
368   }
369   return FAILED;
370 }
371
372 #undef CHECK_POINT // Clean up after myself
373 #undef CHECK_AT
374
375 // extern "C" int test12_8_mutatorMAIN(ParameterDict &param)
376 test_results_t test_thread_5_Mutator::setup(ParameterDict &param) {
377   DyninstMutator::setup(param);
378   debugPrint = param["debugPrint"]->getInt();
379   bpatch = (BPatch *)(param["bpatch"]->getPtr());
380   return PASSED;
381 }