Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test_fork_11.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_fork_11.C,v 1.1 2008/10/30 19:21:30 legendre Exp $
33 /*
34  * #Name: test7_7
35  * #Desc: Memory allocation in parent & child
36  * #Arch: all
37  * #Dep: 
38  */
39
40 #include "BPatch.h"
41 #include "BPatch_Vector.h"
42 #include "BPatch_thread.h"
43 #include "BPatch_snippet.h"
44
45 #include "test_lib.h"
46 #include "test_lib_test7.h"
47
48 #include "dyninst_comp.h"
49 class test_fork_11_Mutator : public DyninstMutator {
50 private:
51   BPatch *bpatch;
52
53 public:
54   virtual bool hasCustomExecutionPath() { return true; }
55   virtual test_results_t setup(ParameterDict &param);
56   virtual test_results_t executeTest();
57 };
58 extern "C" DLLEXPORT TestMutator *test_fork_11_factory() {
59   return new test_fork_11_Mutator();
60 }
61
62 static bool parentDone;
63 static bool childDone;
64 static bool passedTest;
65 static BPatch_thread *parentThread;
66 static BPatch_thread *childThread;
67 static int msgid;
68
69
70 /* Verify that the memory created with malloc is per process and isn't
71    being shared between a parent and child process.
72
73    parent/child: malloc a variable
74    parent/child: oneTimeCode(snippetA)  (malloced variable = 10)
75    --- fork ---
76    parent: insert snippet B  (malloced_var += 3);
77    child:  insert snippet B' (malloced_var += 7);
78    --- run  ---
79    parent: verify malloced_var = 13
80    child:  verify malloced_var = 17
81 */
82
83 static BPatch_variableExpr *var7_7p;
84 static BPatch_variableExpr *var7_7c;
85
86 static void prepareTestCase7(procType proc_type, BPatch_thread *thread, forkWhen when)
87 {
88    if(proc_type == Parent_p  &&  when == PreFork) {
89       BPatch_image *parImage = thread->getImage();
90       var7_7p = thread->malloc(*(parImage->findType("int")));
91       if(doError(&passedTest, (var7_7p==NULL),
92                  "  Unable to malloc variable in parent\n")) return;
93
94       BPatch_arithExpr a_expr7_7p(BPatch_assign, *var7_7p,
95                                   BPatch_constExpr(10));
96       thread->oneTimeCode(a_expr7_7p);
97    } else if(proc_type == Parent_p  &&  when == PostFork) {
98       BPatch_image *parImage = thread->getImage();
99
100       BPatch_Vector<BPatch_function *> found_funcs;
101       const char *inFunction = "test_fork_11_func1";
102       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
103         logerror("    Unable to find function %s\n",
104                 inFunction);
105         exit(1);
106       }
107       
108       if (1 < found_funcs.size()) {
109         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
110                 __FILE__, __LINE__, found_funcs.size(), inFunction);
111       }
112       
113       BPatch_Vector<BPatch_point *> *points7_7p = found_funcs[0]->findPoint(BPatch_entry);
114
115       if(doError(&passedTest, !points7_7p || ((*points7_7p).size() == 0),
116                  "  Unable to find entry point to \"test_fork_11_func1\".\n")) return;
117       BPatch_point *point7_7p = (*points7_7p)[0];
118
119       BPatch_arithExpr a_expr7_7p(BPatch_plus, *var7_7p, BPatch_constExpr(3));
120       BPatch_arithExpr b_expr7_7p(BPatch_assign, *var7_7p, a_expr7_7p);
121       thread->insertSnippet(b_expr7_7p, *point7_7p, BPatch_callBefore);
122    } else if(proc_type == Child_p  &&  when == PostFork) {
123       var7_7c = thread->getInheritedVariable(*var7_7p);
124
125       BPatch_image *childImage = thread->getImage();
126
127       BPatch_Vector<BPatch_function *> found_funcs;
128       const char *inFunction = "test_fork_11_func1";
129       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
130         logerror("    Unable to find function %s\n",
131                 inFunction);
132         exit(1);
133       }
134       
135       if (1 < found_funcs.size()) {
136         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
137                 __FILE__, __LINE__, found_funcs.size(), inFunction);
138       }
139       
140       BPatch_Vector<BPatch_point *> *points7_7c = found_funcs[0]->findPoint(BPatch_entry);
141
142       if(doError(&passedTest, !points7_7c || ((*points7_7c).size() == 0),
143                  "  Unable to find entry point to \"test_fork_11_func1\".\n")) return;
144       BPatch_point *point7_7c = (*points7_7c)[0];
145
146       BPatch_arithExpr a_expr7_7c(BPatch_plus, *var7_7c, BPatch_constExpr(7));
147       BPatch_arithExpr b_expr7_7c(BPatch_assign, *var7_7c, a_expr7_7c);
148
149       thread->insertSnippet(b_expr7_7c, *point7_7c, BPatch_callBefore);
150    }
151 }
152
153 static void checkTestCase7(procType proc_type, BPatch_thread */*thread*/) {
154    const int TN = 7;
155    char varname[50];
156    sprintf(varname,"test%d malloced var",TN);
157    if(proc_type == Parent_p) {
158       if(! verifyProcMemory(varname, var7_7p, 13, proc_type)) {
159          passedTest = false;
160       }
161    } else if(proc_type == Child_p) {
162       if(! verifyProcMemory(varname, var7_7c, 17, proc_type)) {
163          passedTest = false;
164       }
165    }
166 }
167
168
169 /* We make changes at post-fork */
170 static void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
171 {
172     //dprintf("in postForkFunc\n");
173     /* For later identification */
174     childThread = child;
175     dprintf("Preparing tests on parent\n");
176     prepareTestCase7(Parent_p, parent, PostFork);
177     dprintf("Preparing tests on child\n");
178     prepareTestCase7(Child_p,  child,  PostFork);
179     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
180 }
181
182 /* And verify them when they exit */
183 static void exitFunc(BPatch_thread *thread, BPatch_exitType exit_type) {
184     dprintf("Exit func called\n");
185     if (thread == parentThread) {
186         dprintf("Parent exit reached, checking...\n");
187         checkTestCase7(Parent_p, thread);
188         parentDone = true;
189         dprintf("Parent done\n");
190     }
191     else if (thread == childThread) {
192         dprintf("Child exit reached, checking...\n");
193         checkTestCase7(Child_p, thread);
194         dprintf("Child done\n");
195         childDone = true;
196     }
197     else {
198         dprintf("Thread ptr 0x%x, parent 0x%x, child 0x%x\n",
199                 thread, parentThread, childThread);
200         assert(0 && "Unexpected BPatch_thread in exitFunc");
201     }
202     return;
203 }
204
205 static void initialPreparation(BPatch_thread *parent)
206 {
207    //cerr << "in initialPreparation\n";
208    assert(parent->isStopped());
209
210    //cerr << "ok, inserting instr\n";
211    prepareTestCase7(Parent_p, parent, PreFork);
212 }
213
214 static int mutatorTest(BPatch *bpatch, BPatch_thread *appThread)
215 {
216     if ( !setupMessaging(&msgid) )
217     {
218        passedTest = false;
219        return passedTest;
220     }
221
222     parentThread = appThread;
223
224     initialPreparation(parentThread);
225     /* ok, do the fork */;
226     parentThread->continueExecution();
227
228     /* the rest of the execution occurs in postForkFunc() */
229     /* Secondary test: we should not have to manually continue
230        either parent or child at any point */
231
232     while ( !parentThread->isTerminated() ) 
233     {
234        bpatch->waitForStatusChange();
235     }
236
237     // At this point if childThread == NULL the postfork handler failed
238     // to run.  Fail gracefully instead of segfaulting on 
239     // childThread->isTerminated()
240     if (doError(&passedTest, childThread == NULL,
241              "childThread == NULL: postForkFunc must not have run\n") )
242     {
243        return passedTest;
244     }
245     
246     if ( !childThread->isTerminated() )
247     {
248        bpatch->waitForStatusChange();
249     }
250
251     return passedTest;
252 }
253
254 test_results_t test_fork_11_Mutator::executeTest() {
255   // Initialize global variables
256   parentDone = false;
257   childDone = false;
258   passedTest = true;
259   parentThread = NULL;
260   childThread = NULL;
261   msgid = -1;
262
263   // Register callbacks
264   bpatch->registerPostForkCallback(postForkFunc);
265   bpatch->registerExitCallback(exitFunc);
266
267   bool passed = mutatorTest(bpatch, appThread);
268
269   // Remove callbacks upon test completion
270   bpatch->registerPostForkCallback(NULL);
271   bpatch->registerExitCallback(NULL);
272
273   showFinalResults(passed, 7);
274   if ( passed )
275     return PASSED;
276   else
277     return FAILED;
278 }
279
280 test_results_t test_fork_11_Mutator::setup(ParameterDict &param) {
281 #ifdef os_windows_test
282   return SKIPPED;
283 #else
284   bpatch = (BPatch *)(param["bpatch"]->getPtr());
285   appThread = (BPatch_thread *)(param["appThread"]->getPtr());
286
287   return PASSED;
288 #endif
289 }