Fixes for bug 1081, bug 1104 (fork test bugs)
[dyninst.git] / testsuite / src / dyninst / test_fork_8.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_8.C,v 1.1 2008/10/30 19:21:42 legendre Exp $
33 /*
34  * #Name: test7_4
35  * #Desc: Insert snippet in child - wo inherited snippets
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_8_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_8_factory() {
59   return new test_fork_8_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 /* Insert a snippet into a child process, which hasn't inherited
71    any snippets from the parent process. 
72 */
73
74 /*
75    var7_5 initial value = 789
76    --- fork ---
77    child:  insert snippet A, var7_5 += 211
78    --- run  ---
79    child:  verify snippet A ran, (ie. var7_5 == 1000)
80 */
81
82 static void prepareTestCase4(procType proc_type, BPatch_thread *thread, forkWhen when)
83 {
84    static BPatchSnippetHandle *parSnippetHandle4;
85
86    if(proc_type == Child_p  &&  when == PostFork) {
87        BPatch_image *childImage = thread->getProcess()->getImage();
88
89       BPatch_Vector<BPatch_function *> found_funcs;
90       const char *inFunction = "test_fork_8_func1";
91       if ((NULL == childImage->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_4c = found_funcs[0]->findPoint(BPatch_entry);
103       if(doError(&passedTest, !points7_4c || ((*points7_4c).size() == 0),
104                  "  Unable to find entry point to \"test_fork_8_func1\".\n")) return;
105       BPatch_point *point7_4c = (*points7_4c)[0];
106
107       BPatch_variableExpr *var7_4c = 
108          childImage->findVariable("test_fork_8_global1");
109       if(doError(&passedTest, (var7_4c==NULL),
110                  "  Unable to locate variable test_fork_8_global1\n")) return;
111
112       BPatch_arithExpr a_expr7_4c(BPatch_plus, *var7_4c,BPatch_constExpr(211));
113       BPatch_arithExpr b_expr7_4c(BPatch_assign, *var7_4c, a_expr7_4c);
114       parSnippetHandle4 =
115               thread->getProcess()->insertSnippet(b_expr7_4c, *point7_4c, BPatch_callBefore);
116    }
117 }
118
119 static void checkTestCase4(procType proc_type, BPatch_thread *thread) {
120    if(proc_type == Parent_p) {
121        if(! verifyProcMemory(thread->getProcess(), "test_fork_8_global1", 789, proc_type)) {
122          passedTest = false;
123       }
124    } else if(proc_type == Child_p) {
125        if(! verifyProcMemory(thread->getProcess(), "test_fork_8_global1", 1000, proc_type)) {
126          passedTest = false;
127       }
128    }
129 }
130
131
132 /* We make changes at post-fork */
133 static void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
134 {
135     //dprintf("in postForkFunc\n");
136     /* For later identification */
137     childThread = child;
138     dprintf("Preparing tests on parent\n");
139     prepareTestCase4(Parent_p, parent, PostFork);
140     dprintf("Preparing tests on child\n");
141     prepareTestCase4(Child_p,  child,  PostFork);
142     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
143 }
144
145 /* And verify them when they exit */
146 static void exitFunc(BPatch_thread *thread, BPatch_exitType exit_type) {
147     dprintf("Exit func called\n");
148     if (thread == parentThread) {
149         dprintf("Parent exit reached, checking...\n");
150         checkTestCase4(Parent_p, thread);
151         parentDone = true;
152         dprintf("Parent done\n");
153     }
154     else if (thread == childThread) {
155         dprintf("Child exit reached, checking...\n");
156         checkTestCase4(Child_p, thread);
157         dprintf("Child done\n");
158         childDone = true;
159     }
160     else {
161         dprintf("Thread ptr 0x%x, parent 0x%x, child 0x%x\n",
162                 thread, parentThread, childThread);
163         assert(0 && "Unexpected BPatch_thread in exitFunc");
164     }
165     return;
166 }
167
168 static void initialPreparation(BPatch_thread *parent)
169 {
170    //cerr << "in initialPreparation\n";
171     assert(parent->getProcess()->isStopped());
172
173    //cerr << "ok, inserting instr\n";
174    prepareTestCase4(Parent_p, parent, PreFork);
175 }
176
177 static int mutatorTest(BPatch *bpatch, BPatch_thread *appThread)
178 {
179     if ( !setupMessaging(&msgid) )
180     {
181        passedTest = false;
182        return passedTest;
183     }
184
185     parentThread = appThread;
186
187     initialPreparation(parentThread);
188     /* ok, do the fork */;
189                          parentThread->getProcess()->continueExecution();
190
191     /* the rest of the execution occurs in postForkFunc() */
192     /* Secondary test: we should not have to manually continue
193        either parent or child at any point */
194
195     while ( !parentThread->getProcess()->isTerminated() )
196     {
197        bpatch->waitForStatusChange();
198     }
199
200     // At this point if childThread == NULL the postfork handler failed
201     // to run.  Fail gracefully instead of segfaulting on 
202     // childThread->isTerminated()
203     if (doError(&passedTest, childThread == NULL,
204              "childThread == NULL: postForkFunc must not have run\n") )
205     {
206        return passedTest;
207     }
208     
209     while ( !childThread->getProcess()->isTerminated() )
210     {
211        bpatch->waitForStatusChange();
212     }
213
214     return passedTest;
215 }
216
217 test_results_t test_fork_8_Mutator::executeTest() {
218   // Initialize global variables
219   parentDone = false;
220   childDone = false;
221   passedTest = true;
222   parentThread = NULL;
223   childThread = NULL;
224   msgid = -1;
225
226   // Register callbacks
227   bpatch->registerPostForkCallback(postForkFunc);
228   bpatch->registerExitCallback(exitFunc);
229
230   bool passed = mutatorTest(bpatch, appThread);
231
232   // Remove callbacks upon test completion
233   bpatch->registerPostForkCallback(NULL);
234   bpatch->registerExitCallback(NULL);
235
236   showFinalResults(passed, 4);
237   if ( passed )
238     return PASSED;
239   else
240     return FAILED;
241 }
242
243 // extern "C" int test7_4_mutatorMAIN(ParameterDict &param)
244 test_results_t test_fork_8_Mutator::setup(ParameterDict &param) {
245 #ifdef os_windows_test
246   return SKIPPED;
247 #else
248   bpatch = (BPatch *)(param["bpatch"]->getPtr());
249   appThread = (BPatch_thread *)(param["appThread"]->getPtr());
250
251   return PASSED;
252 #endif
253 }