Fixes for bug 1081, bug 1104 (fork test bugs)
[dyninst.git] / testsuite / src / dyninst / test_fork_9.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_9.C,v 1.1 2008/10/30 19:21:44 legendre Exp $
33 /*
34  * #Name: test7_5
35  * #Desc: Add snippets to 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_9_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_9_factory() {
59   return new test_fork_9_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 /* Add two snippets to an already existing snippet in the parent and child
70    and see if all of the snippets get run.
71
72    parent/child: test_fork_9_global1 initial value = 7
73    parent: snippetHandleA  = insert snippetA at pointA   += 9
74    --- fork ---
75    child:  snippetHandleA' = pointA.getCurrentSnippets()
76    parent: add snippetB (+= 11);  add snippetC (+= 13);
77    child:  add snippetB' (+= 5);  add snippetC' (+= 3);
78    --- run  ---
79    parent: verify snippetA, snippetB, and snippetC ran     7+9+11+13 == 40
80    child:  verify snippetA', snippetB', and snippetC' ran  7+9+5+3   == 24
81 */
82
83 static void prepareTestCase5(procType proc_type, BPatch_thread *thread, forkWhen when)
84 {
85    static BPatchSnippetHandle *parSnippetHandle5;
86    logerror("prepareTestCase5, %d, %p, %d\n",
87             proc_type, thread, when);
88    
89
90    if(proc_type == Parent_p  &&  when == PreFork) {
91        BPatch_image *parImage = thread->getProcess()->getImage();
92
93       BPatch_Vector<BPatch_function *> found_funcs;
94       const char *inFunction = "test_fork_9_func1";
95       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
96         logerror("    Unable to find function %s\n",
97                 inFunction);
98         exit(1);
99       }
100       
101       if (1 < found_funcs.size()) {
102         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
103                 __FILE__, __LINE__, found_funcs.size(), inFunction);
104       }
105       
106       BPatch_Vector<BPatch_point *> *points7_5p = found_funcs[0]->findPoint(BPatch_entry);
107
108       if(doError(&passedTest, !points7_5p || ((*points7_5p).size() == 0),
109                  "  Unable to find entry point to \"test_fork_9_func1\".\n")) return;
110       BPatch_point *point7_5p = (*points7_5p)[0];
111
112       BPatch_variableExpr *var7_5p = 
113          parImage->findVariable("test_fork_9_global1");
114       if(doError(&passedTest, (var7_5p==NULL),
115                  "  Unable to locate variable test_fork_9_global1\n")) return;
116
117       BPatch_arithExpr expr7_5p(BPatch_plus, *var7_5p, BPatch_constExpr(9));
118       BPatch_arithExpr b_expr7_5p(BPatch_assign, *var7_5p, expr7_5p);
119       parSnippetHandle5 =
120               thread->getProcess()->insertSnippet(b_expr7_5p, *point7_5p, BPatch_callBefore);
121    } else if(proc_type == Parent_p  &&  when == PostFork) {
122        BPatch_image *parImage = thread->getProcess()->getImage();
123
124       BPatch_Vector<BPatch_function *> found_funcs;
125       const char *inFunction = "test_fork_9_func1";
126       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
127         logerror("    Unable to find function %s\n",
128                 inFunction);
129         exit(1);
130       }
131       
132       if (1 < found_funcs.size()) {
133         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
134                 __FILE__, __LINE__, found_funcs.size(), inFunction);
135       }
136       
137       BPatch_Vector<BPatch_point *> *points7_5p = found_funcs[0]->findPoint(BPatch_entry);
138
139       if(doError(&passedTest, !points7_5p || ((*points7_5p).size() == 0),
140                  "  Unable to find entry point to \"test_fork_9_func1\".\n")) return;
141       BPatch_point *point7_5p = (*points7_5p)[0];
142
143       BPatch_variableExpr *var7_5p = 
144          parImage->findVariable("test_fork_9_global1");
145       if(doError(&passedTest, (var7_5p==NULL),
146                  "  Unable to locate variable test_fork_9_global1\n")) return;
147
148       BPatch_arithExpr a_expr7_5p(BPatch_plus, *var7_5p, BPatch_constExpr(11));
149       BPatch_arithExpr b_expr7_5p(BPatch_assign, *var7_5p, a_expr7_5p);
150       parSnippetHandle5 =
151               thread->getProcess()->insertSnippet(b_expr7_5p, *point7_5p, BPatch_callBefore,
152                                BPatch_lastSnippet);
153
154       BPatch_arithExpr c_expr7_5p(BPatch_plus, *var7_5p, BPatch_constExpr(13));
155       BPatch_arithExpr d_expr7_5p(BPatch_assign, *var7_5p, c_expr7_5p);
156       parSnippetHandle5 =
157               thread->getProcess()->insertSnippet(d_expr7_5p, *point7_5p, BPatch_callBefore);
158    } else if(proc_type == Child_p  &&  when == PostFork) {
159        BPatch_image *childImage = thread->getProcess()->getImage();
160
161       BPatch_Vector<BPatch_function *> found_funcs;
162       const char *inFunction = "test_fork_9_func1";
163       if ((NULL == childImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
164         logerror("    Unable to find function %s\n",
165                 inFunction);
166         exit(1);
167       }
168       
169       if (1 < found_funcs.size()) {
170         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
171                 __FILE__, __LINE__, found_funcs.size(), inFunction);
172       }
173       
174       BPatch_Vector<BPatch_point *> *points7_5c = found_funcs[0]->findPoint(BPatch_entry);
175
176       if(doError(&passedTest, !points7_5c || ((*points7_5c).size() == 0),
177                  "  Unable to find entry point to \"test_fork_9_func1\".\n")) return;
178       BPatch_point *point7_5c = (*points7_5c)[0];
179
180       BPatch_variableExpr *var7_5c = 
181          childImage->findVariable("test_fork_9_global1");
182       if(doError(&passedTest, (var7_5c==NULL),
183                  "  Unable to locate variable test_fork_9_global1\n")) return;
184
185       BPatch_arithExpr a_expr7_5c(BPatch_plus, *var7_5c, BPatch_constExpr(5));
186       BPatch_arithExpr b_expr7_5c(BPatch_assign, *var7_5c, a_expr7_5c);
187       parSnippetHandle5 =
188               thread->getProcess()->insertSnippet(b_expr7_5c, *point7_5c, BPatch_callBefore,
189                               BPatch_lastSnippet);
190       BPatch_arithExpr c_expr7_5c(BPatch_plus, *var7_5c, BPatch_constExpr(3));
191       BPatch_arithExpr d_expr7_5c(BPatch_assign, *var7_5c, c_expr7_5c);
192       parSnippetHandle5 =
193               thread->getProcess()->insertSnippet(d_expr7_5c, *point7_5c, BPatch_callBefore);
194    }
195 }
196
197 static void checkTestCase5(procType proc_type, BPatch_thread *thread) {
198    if(proc_type == Parent_p) {
199        if(! verifyProcMemory(thread->getProcess(), "test_fork_9_global1", 40, proc_type)) {
200          passedTest = false;
201       }
202    } else if(proc_type == Child_p) {
203        if(! verifyProcMemory(thread->getProcess(), "test_fork_9_global1", 24, proc_type)) {
204          passedTest = false;
205       }
206    }
207 }
208
209
210
211 /* We make changes at post-fork */
212 static void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
213 {
214     //dprintf("in postForkFunc\n");
215     /* For later identification */
216     childThread = child;
217     dprintf("Preparing tests on parent\n");
218     prepareTestCase5(Parent_p, parent, PostFork);
219     dprintf("Preparing tests on child\n");
220     prepareTestCase5(Child_p,  child,  PostFork);
221     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
222 }
223
224 /* And verify them when they exit */
225 static void exitFunc(BPatch_thread *thread, BPatch_exitType exit_type) {
226     dprintf("Exit func called\n");
227     if (thread == parentThread) {
228         dprintf("Parent exit reached, checking...\n");
229         checkTestCase5(Parent_p, thread);
230         parentDone = true;
231         dprintf("Parent done\n");
232     }
233     else if (thread == childThread) {
234         dprintf("Child exit reached, checking...\n");
235         checkTestCase5(Child_p, thread);
236         dprintf("Child done\n");
237         childDone = true;
238     }
239     else {
240         dprintf("Thread ptr 0x%x, parent 0x%x, child 0x%x\n",
241                 thread, parentThread, childThread);
242         assert(0 && "Unexpected BPatch_thread in exitFunc");
243     }
244     return;
245 }
246
247 static void initialPreparation(BPatch_thread *parent)
248 {
249    //cerr << "in initialPreparation\n";
250     assert(parent->getProcess()->isStopped());
251
252    //cerr << "ok, inserting instr\n";
253    prepareTestCase5(Parent_p, parent, PreFork);
254 }
255
256 static int mutatorTest(BPatch *bpatch, BPatch_thread *appThread)
257 {
258     if ( !setupMessaging(&msgid) )
259     {
260        passedTest = false;
261        return passedTest;
262     }
263
264     parentThread = appThread;
265
266     initialPreparation(parentThread);
267     /* ok, do the fork */;
268                          parentThread->getProcess()->continueExecution();
269
270     /* the rest of the execution occurs in postForkFunc() */
271     /* Secondary test: we should not have to manually continue
272        either parent or child at any point */
273
274    while ( !parentThread->getProcess()->isTerminated() )
275     {
276        bpatch->waitForStatusChange();
277     }
278
279     // At this point if childThread == NULL the postfork handler failed
280     // to run.  Fail gracefully instead of segfaulting on 
281     // childThread->isTerminated()
282     if (doError(&passedTest, childThread == NULL,
283              "childThread == NULL: postForkFunc must not have run\n") )
284     {
285        return passedTest;
286     }
287     
288     while ( !childThread->getProcess()->isTerminated() )
289     {
290        bpatch->waitForStatusChange();
291     }
292
293     return passedTest;
294 }
295
296 test_results_t test_fork_9_Mutator::executeTest() {
297   // Initialize global variables
298   parentDone = false;
299   childDone = false;
300   passedTest = true;
301   parentThread = NULL;
302   childThread = NULL;
303   msgid = -1;
304
305   // Register callbacks
306   bpatch->registerPostForkCallback(postForkFunc);
307   bpatch->registerExitCallback(exitFunc);
308
309   bool passed = mutatorTest(bpatch, appThread);
310
311   // Remove callbacks upon test completion
312   bpatch->registerPostForkCallback(NULL);
313   bpatch->registerExitCallback(NULL);
314
315   showFinalResults(passed, 5);
316   if ( passed )
317     return PASSED;
318   else
319     return FAILED;
320 }
321
322 // extern "C" int test7_5_mutatorMAIN(ParameterDict &param)
323 test_results_t test_fork_9_Mutator::setup(ParameterDict &param) {
324 #ifdef os_windows_test
325   return SKIPPED;
326 #else
327   bpatch = (BPatch *)(param["bpatch"]->getPtr());
328   appThread = (BPatch_thread *)(param["appThread"]->getPtr());
329
330   return PASSED;
331 #endif
332 }