Fixes for bug 1081, bug 1104 (fork test bugs)
[dyninst.git] / testsuite / src / dyninst / test_fork_7.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_7.C,v 1.1 2008/10/30 19:21:40 legendre Exp $
33 /*
34  * #Name: test7_3
35  * #Desc: Delete snippet in both parent and 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_7_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_7_factory() {
59   return new test_fork_7_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 /* Delete both a parent and a child snippet, and make sure both are getting
70    deleted.
71
72    parent: snippetHandleA  = insert snippetA at pointA
73    --- fork ---
74    parent: deleteSnippet( snippetHandleA )
75    child:  snippetHandleA' = pointA.getCurrentSnippets()
76    child:  deleteSnippet( snippetHandleA' )
77    --- run  ---
78    parent: verify snippetHandleA didn't run
79    child:  verify snippetHandleA didn't run
80 */
81
82 static void prepareTestCase3(procType proc_type, BPatch_thread *thread, forkWhen when)
83 {
84    static BPatchSnippetHandle *parSnippetHandle3;
85
86    if(proc_type == Parent_p  &&  when == PreFork) {
87        BPatch_image *parImage = thread->getProcess()->getImage();
88
89       BPatch_Vector<BPatch_function *> found_funcs;
90       const char *inFunction = "test_fork_7_func1";
91       if ((NULL == parImage->findFunction(inFunction, found_funcs, 1)) || !found_funcs.size()) {
92         logerror("    Unable to find function %s\n",
93                 inFunction);
94         exit(1);
95       }
96       
97       if (1 < found_funcs.size()) {
98         logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
99                 __FILE__, __LINE__, found_funcs.size(), inFunction);
100       }
101       
102       BPatch_Vector<BPatch_point *> *points7_3p = found_funcs[0]->findPoint(BPatch_entry);
103
104       if(doError(&passedTest, !points7_3p || ((*points7_3p).size() == 0),
105                  "  Unable to find entry point to \"test_fork_7_func1\".\n")) return;
106       BPatch_point *point7_3p = (*points7_3p)[0];
107
108       BPatch_variableExpr *var7_3p = 
109          parImage->findVariable("test_fork_7_global1");
110       if(doError(&passedTest, (var7_3p==NULL),
111                  "  Unable to locate variable test_fork_7_global1\n")) return;
112
113       BPatch_arithExpr expr7_3p(BPatch_assign, *var7_3p,BPatch_constExpr(642));
114
115       parSnippetHandle3 =
116               thread->getProcess()->insertSnippet(expr7_3p, *point7_3p, BPatch_callBefore);
117    } else if(proc_type == Parent_p  &&  when == PostFork) {
118        bool result = thread->getProcess()->deleteSnippet(parSnippetHandle3);
119       if(result == false) {
120          logerror("  error, couldn't delete snippet\n");
121          passedTest = false;
122          return;
123       }
124    } else if(proc_type == Child_p  &&  when == PostFork) {
125        BPatch_image *childImage = thread->getProcess()->getImage();
126
127       BPatch_Vector<BPatch_function *> found_funcs;
128       const char *inFunction = "test_fork_7_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_3c = found_funcs[0]->findPoint(BPatch_entry);
141       
142       if(doError(&passedTest, !points7_3c || ((*points7_3c).size() == 0),
143                  "  Unable to find entry point to \"test_fork_7_func1\".\n")) return;
144       BPatch_point *point7_3c = (*points7_3c)[0];
145
146       BPatch_Vector<BPatchSnippetHandle *> childSnippets =
147          point7_3c->getCurrentSnippets();
148       if(doError(&passedTest, (childSnippets.size()==0),
149                  " No snippets were found at test_fork_7_func1\n")) return;
150
151       for(unsigned i=0; i<childSnippets.size(); i++) {
152           bool result = thread->getProcess()->deleteSnippet(childSnippets[i]);
153          if(result == false) {
154             logerror("  error, couldn't delete snippet\n");
155             passedTest = false;
156             return;
157          }
158       }
159    }
160 }
161
162 static void checkTestCase3(procType proc_type, BPatch_thread *thread) {
163    if(proc_type == Parent_p) {
164        if(! verifyProcMemory(thread->getProcess(), "test_fork_7_global1", 246, proc_type)) {
165          passedTest = false;
166       }
167    } else if(proc_type == Child_p) {
168        if(! verifyProcMemory(thread->getProcess(), "test_fork_7_global1", 246, proc_type)) {
169          passedTest = false;
170       }
171    }
172 }
173
174 /* We make changes at post-fork */
175 static void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
176 {
177     //dprintf("in postForkFunc\n");
178     /* For later identification */
179     childThread = child;
180     dprintf("Preparing tests on parent\n");
181     prepareTestCase3(Parent_p, parent, PostFork);
182     dprintf("Preparing tests on child\n");
183     prepareTestCase3(Child_p,  child,  PostFork);
184     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
185 }
186
187 /* And verify them when they exit */
188 static void exitFunc(BPatch_thread *thread, BPatch_exitType exit_type) {
189     dprintf("Exit func called\n");
190     if (thread == parentThread) {
191         dprintf("Parent exit reached, checking...\n");
192         checkTestCase3(Parent_p, thread);
193         parentDone = true;
194         dprintf("Parent done\n");
195     }
196     else if (thread == childThread) {
197         dprintf("Child exit reached, checking...\n");
198         checkTestCase3(Child_p, thread);
199         dprintf("Child done\n");
200         childDone = true;
201     }
202     else {
203         dprintf("Thread ptr 0x%x, parent 0x%x, child 0x%x\n",
204                 thread, parentThread, childThread);
205         assert(0 && "Unexpected BPatch_thread in exitFunc");
206     }
207     return;
208 }
209
210 static void initialPreparation(BPatch_thread *parent)
211 {
212    //cerr << "in initialPreparation\n";
213     assert(parent->getProcess()->isStopped());
214
215    //cerr << "ok, inserting instr\n";
216    prepareTestCase3(Parent_p, parent, PreFork);
217 }
218
219 static bool mutatorTest(BPatch *bpatch, BPatch_thread *appThread)
220 {
221     if ( !setupMessaging(&msgid) )
222     {
223        passedTest = false;
224        return passedTest;
225     }
226
227     parentThread = appThread;
228
229     initialPreparation(parentThread);
230     /* ok, do the fork */;
231                          parentThread->getProcess()->continueExecution();
232
233     /* the rest of the execution occurs in postForkFunc() */
234     /* Secondary test: we should not have to manually continue
235        either parent or child at any point */
236
237     while ( !parentThread->getProcess()->isTerminated() )
238     {
239        bpatch->waitForStatusChange();
240     }
241
242     // At this point if childThread == NULL the postfork handler failed
243     // to run.  Fail gracefully instead of segfaulting on 
244     // childThread->isTerminated()
245     if (doError(&passedTest, childThread == NULL,
246              "childThread == NULL: postForkFunc must not have run\n") )
247     {
248        return passedTest;
249     }
250     
251     while ( !childThread->getProcess()->isTerminated() )
252     {
253        bpatch->waitForStatusChange();
254     }
255
256     return passedTest;
257 }
258
259 test_results_t test_fork_7_Mutator::executeTest() {
260   // Initialize global variables
261   parentDone = false;
262   childDone = false;
263   passedTest = true;
264   parentThread = NULL;
265   childThread = NULL;
266   msgid = -1;
267
268   // Register callbacks
269   bpatch->registerPostForkCallback(postForkFunc);
270   bpatch->registerExitCallback(exitFunc);
271
272   bool passed = mutatorTest(bpatch, appThread);
273
274   // Remove callbacks upon test completion
275   bpatch->registerPostForkCallback(NULL);
276   bpatch->registerExitCallback(NULL);
277
278   showFinalResults(passed, 3);
279   if ( passed )
280     return PASSED;
281   else
282     return FAILED;
283 }
284
285 // extern "C" int test7_3_mutatorMAIN(ParameterDict &param)
286 test_results_t test_fork_7_Mutator::setup(ParameterDict &param) {
287 #ifdef os_windows_test
288   return SKIPPED;
289 #else
290   bpatch = (BPatch *)(param["bpatch"]->getPtr());
291   appThread = (BPatch_thread *)(param["appThread"]->getPtr());
292
293   return PASSED;
294 #endif
295 }
296