Rename newtestsuite to testsuite
[dyninst.git] / testsuite / src / dyninst / test_thread_5.C
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 // $Id: 
43 /*
44  * #Name: test12_8
45  * #Desc: user defined message callback -- mt
46  * #Dep: 
47  * #Arch: all
48  * #Notes:
49  */
50
51 #include <vector>
52 using std::vector;
53 #include "BPatch.h"
54 #include "BPatch_Vector.h"
55 #include "BPatch_thread.h"
56 #include "BPatch_snippet.h"
57
58 #include "test_lib.h"
59 #include "test12.h"
60
61 #include "dyninst_comp.h"
62 class test_thread_5_Mutator : public DyninstMutator {
63 protected:
64   BPatch *bpatch;
65
66   BPatchSnippetHandle *at(BPatch_point * pt, BPatch_function *call,
67                           int testno, const char *testname);
68   void dumpVars();
69   bool setVar(const char *vname, void *addr, int testno,
70               const char *testname);
71
72
73
74 public:
75   virtual bool hasCustomExecutionPath() { return true; }
76   virtual test_results_t setup(ParameterDict &param);
77   virtual test_results_t executeTest();
78 };
79 extern "C" DLLEXPORT TestMutator *test_thread_5_factory() {
80   return new test_thread_5_Mutator();
81 }
82
83 #define TESTNO 8
84 #define TESTNAME "test_thread_5"
85 #define TESTDESC "user defined message callback -- mt"
86
87 static int debugPrint;
88
89 static BPatch_point *findPoint(BPatch_function *f, BPatch_procedureLocation loc,
90                         int testno, const char *testname)
91 {
92   assert(f);
93   BPatch_Vector<BPatch_point *> *pts = f->findPoint(loc);
94
95   if (!pts) {
96     FAIL_MES(testno, testname);
97     logerror("%s[%d]:  no points matching requested location\n", __FILE__, __LINE__);
98     return NULL;
99   }
100
101   if (pts->size() != 1) {
102     FAIL_MES(testno, testname);
103     logerror("%s[%d]:  %d points matching requested location, not 1\n", __FILE__, __LINE__,
104            pts->size());
105     return NULL;
106   }
107
108   return (*pts)[0];
109 }
110
111 //  at -- simple instrumentation.  As written, only can insert funcs without args -- 
112 //     -- modify to take snippet vector args if necessary.
113 BPatchSnippetHandle *
114 test_thread_5_Mutator::at(BPatch_point * pt, BPatch_function *call,
115                           int testno, const char *testname)
116 {
117   BPatch_Vector<BPatch_snippet *> args;
118   BPatch_funcCallExpr snip(*call, args);
119   BPatch_procedureLocation pttype = pt->getPointType();
120   BPatch_callWhen when;
121   if (pttype == BPatch_entry) when = BPatch_callBefore;
122   else if (pttype == BPatch_exit) when = BPatch_callAfter;
123   else if (pttype == BPatch_subroutine) when = BPatch_callBefore;
124   else assert(0);
125
126   BPatchSnippetHandle *ret;
127   ret = appThread->insertSnippet(snip, *pt,when);
128
129   if (!ret) {
130     FAIL_MES(testno, testname);
131     logerror("%s[%d]:  could not insert instrumentation\n", __FILE__, __LINE__);
132     return NULL;
133   }
134
135   return ret;
136 }
137
138 void test_thread_5_Mutator::dumpVars() {
139   BPatch_Vector<BPatch_variableExpr *> vars;
140   appImage->getVariables(vars);
141   for (unsigned int i = 0; i < vars.size(); ++i) {
142     logerror("\t%s\n", vars[i]->getName());
143   }
144 }
145
146 // Returns false on success and true on error
147 bool test_thread_5_Mutator::setVar(const char *vname, void *addr, int testno,
148                                    const char *testname) {
149    BPatch_variableExpr *v;
150    void *buf = addr;
151    if (NULL == (v = appImage->findVariable(vname))) {
152       logerror("**Failed test #%d (%s)\n", testno, testname);
153       logerror("  cannot find variable %s, avail vars:\n", vname);
154       dumpVars();
155       return true;
156    }
157
158    if (! v->writeValue(buf, sizeof(int),true)) {
159       logerror("**Failed test #%d (%s)\n", testno, testname);
160       logerror("  failed to write call site var to mutatee\n");
161       return true;
162    }
163    return false;
164 }
165
166 static bool test8done = false;
167 static bool test8err = false;
168 static unsigned long tids[TEST8_THREADS];
169 static user_event_t last_event[TEST8_THREADS];
170
171 static bool findThreadIndex(unsigned long tid, unsigned int &index)
172 {
173  //  find the index with tid <tid>, if it exists, otherwise, the index of
174  //  an empty slot.  If no empty slot, return false (fail);
175   for (index = 0; index < TEST8_THREADS; ++index) {
176     if (0 == tids[index]) {
177       tids[index] = tid;
178       if (debugPrint)
179         dprintf("%s[%d]:  giving new slot to thread id %lu\n",
180                 __FILE__, __LINE__, tid);
181       return true;
182     }
183     if (tid == tids[index])
184       return true;
185   }
186   return false;
187 }
188
189 static void test8cb(BPatch_process * /*proc*/, void *buf, unsigned int bufsize)
190 {
191   // FIXME This being static is probably killing the test
192   static int destroy_counter = 0;
193   if (debugPrint)
194     dprintf("%s[%d]:  inside test8cb\n", __FILE__, __LINE__);
195
196   if (bufsize != sizeof(user_msg_t)) {
197     //  something is incredibly wrong
198     logerror("%s[%d]:  unexpected message size %d not %d\n",
199             __FILE__, __LINE__, bufsize, sizeof(user_msg_t));
200     test8err = true;
201     return;
202   }
203
204   user_msg_t *msg = (user_msg_t *) buf;
205   user_event_t what = msg->what;
206   unsigned long tid = msg->tid;
207
208   if (debugPrint)
209     dprintf("%s[%d]:  thread = %lu, what = %d\n", __FILE__, __LINE__, tid, what);
210   unsigned int index;
211   if (!findThreadIndex(tid, index)) {
212     test8err = true;
213     logerror("%s[%d]:  failed to find record for tid %lu (or empty slot)\n",
214             __FILE__, __LINE__,tid);
215     return;
216   }
217
218   if (debugPrint)
219     dprintf("%s[%d]:  thread id %lu: index %d\n", __FILE__, __LINE__, tid, index);
220   if (last_event[index] != (what - 1)) {
221     test8err = true;
222     logerror("%s[%d]:  out of order messsage received for thread %lu, last = %d, now = %d\n",
223            __FILE__, __LINE__, tid, last_event[index], what);
224     return;
225   }
226   last_event[index] = what;
227
228   if (what == mutex_destroy) {
229      destroy_counter++;
230   }
231   if (destroy_counter == TEST8_THREADS) {
232     destroy_counter = 0;
233     test8done = true;
234   }
235   //sleep_ms(10);
236 }
237
238 // Macro to do some return code checking after calls to findPoint()
239 #define CHECK_POINT(pt, ptname, fnname) \
240 do { \
241   if (NULL == (pt)) { \
242     logerror("**Failed test_thread_5\n"); \
243     logerror("    Unable to find %s point to %s\n", (ptname), (fnname)); \
244     appThread->getProcess()->terminateExecution(); \
245     return FAILED; \
246   } \
247 } while (0)
248
249 #define CHECK_AT(snippet) \
250 do { \
251   if (NULL == snippet) { \
252     logerror("**Failed test_thread_5\n"); \
253     logerror("    Failed to insert snippet\n"); \
254     appThread->getProcess()->terminateExecution(); \
255     return FAILED; \
256   } \
257 } while (0)
258
259 // static int mutatorTest(BPatch_thread *appThread, BPatch_image *appImage)
260 test_results_t test_thread_5_Mutator::executeTest() {
261   test8done = false;
262   test8err = false;
263
264     // load libtest12.so -- currently only used by subtest 5, but make it generally
265     // available
266     char *libname = "./libTest12.so";    
267 #if defined(arch_x86_64_test)
268     if (appThread->getProcess()->getAddressWidth() == 4)
269       libname = "./libTest12_m32.so";
270 #endif
271     dprintf("%s[%d]:  loading test library: %s\n", __FILE__, __LINE__, libname);
272     if (!appThread->loadLibrary(libname)) {
273       logerror("%s[%d]:  failed to load library %s, cannot proceed\n", 
274               __FILE__, __LINE__, libname);
275       appThread->getProcess()->terminateExecution();
276       return FAILED;
277     }
278
279   for (unsigned int i = 0; i < TEST8_THREADS; ++i) {
280     tids[i] = 0;
281     last_event[i] = null_event;
282   }
283
284   //  instrument events having to do with mutex init, lock, unlock, destroy
285   //  with messaging functions in libtest12.so
286   BPatch_module *libpthread = appImage->findModule("libpthread",true);
287   assert(libpthread);
288
289   BPatch_function *mutInit = findFunction("createLock", appImage,TESTNO, TESTDESC);
290   BPatch_point *mutInitPt = findPoint(mutInit, BPatch_entry,TESTNO, TESTDESC);
291   CHECK_POINT(mutInitPt, "entry", "createLock");
292   BPatch_function *reportInit = findFunction("reportMutexInit", appImage,TESTNO, TESTDESC);
293   BPatchSnippetHandle *initHandle = at(mutInitPt, reportInit, TESTNO, TESTDESC);
294   CHECK_AT(initHandle);
295   BPatch_function *mutDestroy = findFunction("destroyLock", appImage,TESTNO, TESTDESC);
296   BPatch_point *mutDestroyPt = findPoint(mutDestroy, BPatch_entry,TESTNO, TESTDESC);
297   CHECK_POINT(mutDestroyPt, "entry", "destroyLock");
298   BPatch_function *reportDestroy = findFunction("reportMutexDestroy", appImage,TESTNO, TESTDESC);
299   BPatchSnippetHandle *destroyHandle = at(mutDestroyPt, reportDestroy, TESTNO, TESTDESC);
300   CHECK_AT(destroyHandle);
301
302   BPatch_function *mutLock = findFunction("lockLock", appImage,TESTNO, TESTDESC);
303   BPatch_point *mutLockPt = findPoint(mutLock, BPatch_entry,TESTNO,TESTDESC);
304   CHECK_POINT(mutLockPt, "entry", "lockLock");
305   BPatch_function *reportLock = findFunction("reportMutexLock", appImage,TESTNO, TESTDESC);
306   BPatchSnippetHandle *lockHandle = at(mutLockPt, reportLock, TESTNO, TESTDESC);
307   CHECK_AT(lockHandle);
308   BPatch_function *mutUnlock = findFunction("unlockLock", appImage,TESTNO, TESTDESC);
309   BPatch_point *mutUnlockPt = findPoint(mutUnlock, BPatch_entry,TESTNO,TESTDESC);
310   CHECK_POINT(mutUnlockPt, "entry", "unlockLock");
311   BPatch_function *reportUnlock = findFunction("reportMutexUnlock", appImage,TESTNO, TESTDESC);
312   BPatchSnippetHandle *unlockHandle = at(mutUnlockPt, reportUnlock, TESTNO, TESTDESC);
313   CHECK_AT(unlockHandle);
314
315   BPatchUserEventCallback cb = test8cb;
316   if (!bpatch->registerUserEventCallback(cb)) {
317     FAIL_MES(TESTNAME, TESTDESC);
318     logerror("%s[%d]: could not register callback\n", __FILE__, __LINE__);
319     appThread->getProcess()->terminateExecution();
320     return FAILED;
321   }
322
323
324   int timeout = 0;
325   appThread->getProcess()->continueExecution();
326
327   //  wait until we have received the desired number of events
328   //  (or timeout happens)
329   while(!test8err && !test8done && (timeout < TIMEOUT)) {
330     sleep_ms(SLEEP_INTERVAL/*ms*/);
331     timeout += SLEEP_INTERVAL;
332     bpatch->pollForStatusChange();
333   }
334
335   if (timeout >= TIMEOUT) {
336     FAIL_MES(TESTNAME, TESTDESC);
337     logerror("%s[%d]:  test timed out. Took longer than %d ms\n",
338            __FILE__, __LINE__, TIMEOUT);
339     test8err = true;
340   }
341
342   appThread->getProcess()->stopExecution();
343
344   int one = 1;
345   // I need to check the return value for this function call
346   if (setVar("test_thread_5_idle", (void *) &one, TESTNO, TESTDESC)) {
347     logerror("Unable to set variable test_thread_5_idle\n");
348     appThread->getProcess()->terminateExecution();
349     return FAILED;
350   }
351
352   if (!bpatch->removeUserEventCallback(test8cb)) {
353     FAIL_MES(TESTNAME, TESTDESC);
354     logerror("%s[%d]:  failed to remove callback\n",
355            __FILE__, __LINE__);
356     appThread->getProcess()->terminateExecution();
357     return FAILED;
358   }
359
360   //  what happens here if we still have messages coming in, but no handler -- should
361   //  check this?
362
363
364   appThread->getProcess()->deleteSnippet(initHandle);
365   appThread->getProcess()->deleteSnippet(destroyHandle);
366   appThread->getProcess()->deleteSnippet(lockHandle);
367   appThread->getProcess()->deleteSnippet(unlockHandle);
368
369   appThread->getProcess()->continueExecution();
370
371   while (!appThread->getProcess()->isTerminated()) {
372     bpatch->waitForStatusChange();
373   }
374
375   if (!test8err) {
376     PASS_MES(TESTNAME, TESTDESC);
377     return PASSED;
378   }
379   return FAILED;
380 }
381
382 #undef CHECK_POINT // Clean up after myself
383 #undef CHECK_AT
384
385 // extern "C" int test12_8_mutatorMAIN(ParameterDict &param)
386 test_results_t test_thread_5_Mutator::setup(ParameterDict &param) {
387   DyninstMutator::setup(param);
388   debugPrint = param["debugPrint"]->getInt();
389   bpatch = (BPatch *)(param["bpatch"]->getPtr());
390   return PASSED;
391 }