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