Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test_fork_5.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_5.C,v 1.1 2008/10/30 19:21:36 legendre Exp $
33 /*
34  * #Name: test7_1
35  * #Desc: Delete snippet in parent
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_5_Mutator : public DyninstMutator {
50   BPatch *bpatch;
51
52 public:
53   virtual bool hasCustomExecutionPath() { return true; }
54   virtual test_results_t setup(ParameterDict &param);
55   virtual test_results_t executeTest();
56 };
57 extern "C" DLLEXPORT TestMutator *test_fork_5_factory() {
58   return new test_fork_5_Mutator();
59 }
60
61 static bool parentDone;
62 static bool childDone;
63 static bool passedTest;
64 static BPatch_thread *parentThread;
65 static BPatch_thread *childThread;
66 static int msgid;
67
68
69 /* Make sure deleting a snippet in a parent process doesn't delete the
70    snippet in the child process.
71
72    parent: snippetHandleA  = insert snippetA at pointA
73    child:  snippetHandleA' = pointA.getCurrentSnippets()
74    --- fork ---
75    parent: deleteSnippet( snippetHandleA )
76    --- run  ---
77    child:  verify snippetHandleA' still ran
78 */
79
80 static void prepareTestCase1(procType proc_type, BPatch_thread *thread, forkWhen when)
81 {
82   static BPatchSnippetHandle *parSnippetHandle1;
83    
84   if(proc_type == Parent_p  &&  when == PreFork) {
85     BPatch_image *parImage = thread->getImage();
86        
87     BPatch_Vector<BPatch_function *> found_funcs;
88     const char *inFunction = "test_fork_5_func1";
89     if ((NULL == parImage->findFunction(inFunction, found_funcs, 1))
90         || !found_funcs.size()) {
91       logerror("    Unable to find function %s\n",
92                inFunction);
93       // FIXME Don't just exit() here!
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 *> *point7_1p =
103         found_funcs[0]->findPoint(BPatch_entry);
104
105     // FIXME This call will not compile.  Need to fix it to work and print
106     // out the correct error message
107     if(doError(&passedTest, !point7_1p || ((*point7_1p).size() == 0),
108                "  Unable to find entry point to \"test_fork_5_func1\".\n")) return;
109        
110     BPatch_variableExpr *var7_1p = 
111       parImage->findVariable("test_fork_5_global1");
112     if(doError(&passedTest, (var7_1p==NULL),
113                "  Unable to locate variable test_fork_5_global1\n")) return;
114        
115     BPatch_arithExpr expr7_1p(BPatch_assign, *var7_1p,BPatch_constExpr(321));
116        
117     parSnippetHandle1 =
118       thread->insertSnippet(expr7_1p, *point7_1p, BPatch_callBefore);
119     if(doError(&passedTest, (parSnippetHandle1 == NULL),
120                "  Unable to insert snippet into parent for test 1\n")) return;
121   } else if(proc_type == Parent_p  &&  when == PostFork) {
122     thread->deleteSnippet(parSnippetHandle1);
123   }
124 }
125
126 static void checkTestCase1(procType proc_type, BPatch_thread *thread) {
127    if(proc_type == Parent_p) {
128       if(! verifyProcMemory(thread, "test_fork_5_global1", 123, proc_type)) {
129          passedTest = false;
130       }
131    } else if(proc_type == Child_p) {
132       if(! verifyProcMemory(thread, "test_fork_5_global1", 321, proc_type)) {
133          passedTest = false;
134       }
135    }
136 }
137
138 /* We make changes at post-fork */
139 static void postForkFunc(BPatch_thread *parent, BPatch_thread *child)
140 {
141     //dprintf("in postForkFunc\n");
142     /* For later identification */
143     childThread = child;
144     dprintf("Preparing tests on parent\n");
145     prepareTestCase1(Parent_p, parent, PostFork);
146     dprintf("Preparing tests on child\n");
147     prepareTestCase1(Child_p,  child,  PostFork);
148     dprintf("Fork handler finished (parent %p, child %p)\n", parent, child);
149 }
150
151 /* And verify them when they exit */
152 static void exitFunc(BPatch_thread *thread, BPatch_exitType exit_type) {
153     dprintf("Exit func called\n");
154     if (thread == parentThread) {
155         dprintf("Parent exit reached, checking...\n");
156         checkTestCase1(Parent_p, thread);
157         parentDone = true;
158         dprintf("Parent done\n");
159     }
160     else if (thread == childThread) {
161         dprintf("Child exit reached, checking...\n");
162         checkTestCase1(Child_p, thread);
163         dprintf("Child done\n");
164         childDone = true;
165     }
166     else {
167         dprintf("Thread ptr 0x%x, parent 0x%x, child 0x%x\n",
168                 thread, parentThread, childThread);
169         assert(0 && "Unexpected BPatch_thread in exitFunc");
170     }
171     return;
172 }
173
174 static void initialPreparation(BPatch_thread *parent)
175 {
176    //cerr << "in initialPreparation\n";
177    assert(parent->isStopped());
178
179    //cerr << "ok, inserting instr\n";
180    prepareTestCase1(Parent_p, parent, PreFork);
181 }
182
183 static test_results_t mutatorTest(BPatch *bpatch, BPatch_thread *appThread)
184 {
185     if ( !setupMessaging(&msgid) )
186     {
187        passedTest = false;
188        return FAILED;
189     }
190
191     parentThread = appThread;
192
193     initialPreparation(parentThread);
194     /* ok, do the fork */;
195     parentThread->continueExecution();
196
197     /* the rest of the execution occurs in postForkFunc() */
198     /* Secondary test: we should not have to manually continue
199        either parent or child at any point */
200
201     while ( !parentThread->isTerminated() ) 
202     {
203        bpatch->waitForStatusChange();
204     }
205
206     // At this point if childThread == NULL the postfork handler failed
207     // to run.  Fail gracefully instead of segfaulting on 
208     // childThread->isTerminated()
209     if (doError(&passedTest, childThread == NULL,
210              "childThread == NULL: postForkFunc must not have run\n") )
211     {
212        return FAILED;
213     }
214     
215     while ( !childThread->isTerminated() )
216     {
217        bpatch->waitForStatusChange();
218     }
219
220     if (passedTest) {
221       return PASSED;
222     } else {
223       return FAILED;
224     }
225 }
226
227 test_results_t test_fork_5_Mutator::executeTest() {
228   // initialize global variables
229   parentDone = false;
230   childDone = false;
231   passedTest = true;
232   parentThread = NULL;
233   childThread = NULL;
234   msgid = -1;
235
236   // Register callbacks
237   bpatch->registerPostForkCallback(postForkFunc);
238   bpatch->registerExitCallback(exitFunc);
239
240   test_results_t result = mutatorTest(bpatch, appThread);
241
242   // Remove callbacks upon test completion
243   bpatch->registerPostForkCallback(NULL);
244   bpatch->registerExitCallback(NULL);
245
246   if (FAILED == result) {
247     logerror("Failed test_fork_5 (Delete snippet in parent)\n");
248   } else { // Assuming PASSED rather than SKIPPED
249     logerror("Passed test_fork_5 (Delete snippet in parent)\n");
250   }
251   return result;
252 }
253
254 // extern "C" int test7_1_mutatorMAIN(ParameterDict &param)
255 test_results_t test_fork_5_Mutator::setup(ParameterDict &param) {
256 #ifdef os_windows_test
257   return SKIPPED;
258 #else
259   bpatch = (BPatch *)(param["bpatch"]->getPtr());
260   appThread = (BPatch_thread *)(param["appThread"]->getPtr());
261
262   return PASSED;
263 #endif
264 }