Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test3_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: test3_6.C,v 1.1 2008/10/30 19:20:43 legendre Exp $
33 /*
34  * #Name: test3_6
35  * #Desc: Create processes (via standard OS methods, not BPatch::createProcess), process events, and kill them, no instrumentation
36  * #Dep: 
37  * #Arch:
38  * #Notes:useAttach does not apply
39  */
40
41 #if !defined(os_windows_test)
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #endif
45
46 #include "BPatch.h"
47 #include "BPatch_Vector.h"
48 #include "BPatch_thread.h"
49 #include "BPatch_snippet.h"
50
51 #include "test_lib.h"
52 //#include "test3.h"
53
54 #define MAX_MUTATEES    32
55
56 #include "dyninst_comp.h"
57 class test3_6_Mutator : public DyninstMutator {
58   BPatch_exitType expectedSignal;
59   unsigned int Mutatees;
60   int debugPrint;
61   BPatch *bpatch;
62   char *pathname;
63
64 public:
65   test3_6_Mutator();
66   virtual bool hasCustomExecutionPath() { return true; }
67   virtual test_results_t setup(ParameterDict &param);
68   virtual test_results_t executeTest();
69 };
70 extern "C" DLLEXPORT  TestMutator *test3_6_factory() {
71   return new test3_6_Mutator();
72 }
73
74 test3_6_Mutator::test3_6_Mutator()
75   : Mutatees(3), bpatch(NULL), pathname(NULL) {
76 #if defined(os_windows_test)
77   expectedSignal = ExitedNormally;
78 #else
79   expectedSignal = ExitedViaSignal;
80 #endif
81 }
82
83 //
84 // Start Test Case #1 - create processes and process events from each
85 //     Just let them run a while, then kill them, no instrumentation added.
86 //
87
88 #if !defined (os_windows_test)
89 static int forkNewMutatee(const char *filename, const char *child_argv[])
90 {
91   int pid;
92   static int pgid = 0;
93   pid = fork();
94   if (pid == 0) {
95     // child, do exec
96     dprintf("%s[%d]:  before exec in new mutatee %s, pgid = %d\n", __FILE__, __LINE__, filename, getpgid(0));
97
98     //  sanity check, make sure that all forked processes have the same process group id
99     if (!pgid) pgid = getpgid(0);
100     else if (pgid != getpgid(0)) {
101        logerror("%s[%d]:  Something is broken with the test -- all forked processes should belong to the same group\n",                __FILE__, __LINE__);
102        // FIXME Don't call abort here.  We juse want to return failure from
103        // this mutator
104        abort();
105     }
106
107     execv (filename, (char * const *)child_argv);
108     //  if we get here, error
109     logerror("%s[%d]:  exec failed: %s\n", __FILE__, __LINE__, strerror(errno));
110     // FIXME Don't call exit here.  We just want to return failure from this
111     // mutator..
112     exit (-1);
113   }
114   else if (pid < 0) {
115     //  fork error, fail test
116     logerror("%s[%d]:  fork failed: %s\n", __FILE__, __LINE__, strerror(errno));
117     return -1;
118   } else {
119     // Parent; register child for cleanup
120     registerPID(pid);
121   }
122
123   return pid;
124 }
125
126 static bool grandparentForkMutatees(int num, int *pids, const char *filename, const char *child_argv[])
127 {
128     //  this is like fork_mutatee in test_util.C, except it guarantees that mutatees are all
129     //  in the same process group.
130
131     //  need a pipe to get grandchild pids back to grandparent
132     int filedes[2];
133     int result;
134     pipe(filedes);
135
136     int childpid = fork();
137     if (childpid > 0) {
138       //parent -- read grandchild pids
139       registerPID(childpid); // Register for cleanup
140       for (unsigned int i = 0; i < num; ++i) {
141         result = 0;
142         do {
143            result = read(filedes[0], &pids[i], sizeof(int));
144         } while (result == -1 && errno == EINTR);
145         if (0 > result) {
146            logerror("%s[%d]:  read failed %s\n", __FILE__, __LINE__, strerror(errno));
147            // FIXME Don't abort here.  We just want to return failure from this
148            // mutator
149            abort();
150         }
151         dprintf("%s[%d]:  parent -- have new pid %d\n", __FILE__, __LINE__, pids[i]);
152       }
153
154       //  and wait for child exit
155       int status;
156       int waitpid_ret = waitpid(childpid, &status, 0);
157       if (waitpid_ret != childpid) {
158         logerror("%s[%d]:  waitpid failed: %s\n", __FILE__, __LINE__, strerror(errno));
159         // FIXME Don't exit here.  We just want to return failure from this
160         // mutator
161         exit (0);
162       }
163       if (!WIFEXITED(status)) {
164          logerror("%s[%d]:  not exited\n", __FILE__, __LINE__);
165          // FIXME Don't exit here.  We just want to return failure from this
166          // mutator
167          exit(-1);
168       }
169       close(filedes[0]);
170       close(filedes[1]);
171       return true;
172     }
173
174     else if (childpid == 0) {
175       int gchild_pid;
176       //  child -- run as its own session, fork children (mutatees), and exit.
177       setsid();
178       for (int n=0; n<num; n++) {
179         gchild_pid = forkNewMutatee(filename, child_argv);
180         if (gchild_pid < 0) {
181            logerror("%s[%d]:  failed to fork/exec\n", __FILE__, __LINE__);
182            return false;
183         }
184         dprintf("%s[%d]:  forked mutatee %d\n", __FILE__, __LINE__, gchild_pid);
185         //  let parent know the grandchild pid
186         if (0 > write(filedes[1], &gchild_pid, sizeof(int))) {
187             logerror("%s[%d]:  write failed\n", __FILE__, __LINE__);
188             // FIXME Don't abort here.  We just want to return failure from
189             // this mutator
190             abort();
191         }
192       }
193       close (filedes[0]);
194       close (filedes[1]);
195       // FIXME Don't exit here.  We just want to return failure from this
196       // mutator
197       exit(0);
198    }
199    else if (childpid < 0) {
200      //  fork error, fail test
201      close (filedes[0]);
202      close (filedes[1]);
203      logerror("%s[%d]:  fork failed: %s\n", __FILE__, __LINE__, strerror(errno));
204      return false;
205    }
206    return true;
207 }
208
209 #endif
210
211 // static int mutatorTest(char *pathname, BPatch *bpatch)
212 test_results_t test3_6_Mutator::executeTest() {
213 #if !defined (os_windows_test)
214     unsigned int n=0;
215     const char *child_argv[5];
216     child_argv[n++] = pathname;
217     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
218     child_argv[n++] = const_cast<char*>("-run");
219     child_argv[n++] = const_cast<char*>("test3_6"); // run test1 in mutatee
220     child_argv[n++] = NULL;
221
222     int pids[Mutatees];
223     BPatch_thread *appThread[MAX_MUTATEES];
224
225     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
226
227     // Start the mutatees
228     if (!grandparentForkMutatees(Mutatees, pids, pathname, child_argv)) {
229       logerror("%s[%d]:  failed to fork mutatees\n", __FILE__, __LINE__);
230       exit(1);
231     }
232
233     P_sleep(2);
234     //  Attach to them
235     for (n=0; n<Mutatees; n++) {
236         dprintf("Attaching \"%s\" %d/%d\n", pathname, n, Mutatees);
237         appThread[n] = bpatch->attachProcess(pathname, pids[n]);
238         if (!appThread[n]) {
239             logerror("*ERROR*: unable to create handle%d for executable\n", n);
240             logerror("**Failed** test3_6 (simultaneous multiple-process management - terminate (fork))\n");
241             MopUpMutatees(n-1,appThread);
242             return FAILED;
243         }
244         dprintf("Mutatee %d attached, pid=%d\n", n, appThread[n]->getPid());
245     }
246
247     dprintf("Letting mutatee processes run a short while (5s).\n");
248     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
249
250     P_sleep(5);
251     dprintf("Terminating mutatee processes.\n");
252
253     appThread[0]->getProcess(); // ???
254
255     // And kill them
256     unsigned int numTerminated=0;
257     for (n=0; n<Mutatees; n++) {
258         bool dead = appThread[n]->terminateExecution();
259         if (!dead || !(appThread[n]->isTerminated())) {
260             logerror("**Failed** test3_6 (simultaneous multiple-process management - terminate (fork))\n");
261             logerror("    mutatee process [%d] was not terminated\n", n);
262             continue;
263         }
264 #if !defined(os_aix_test) && !defined(os_solaris_test) && !defined(os_osf_test)
265         if(appThread[n]->terminationStatus() != expectedSignal) {
266             logerror("**Failed** test3_6 (simultaneous multiple-process management - terminate (fork))\n");
267             logerror("    mutatee process [%d] didn't get notice of termination\n", n);
268             continue;
269         }
270         int signalNum = appThread[n]->getExitSignal();
271         dprintf("Terminated mutatee [%d] from signal 0x%x\n", n, signalNum);
272 #endif
273         numTerminated++;
274     }
275
276     if (numTerminated == Mutatees) {
277         logerror("Passed test3_6 (simultaneous multiple-process management - terminate (fork))\n");
278         return PASSED;
279     }
280
281     return FAILED;
282 #else // os_windows
283     logerror("Skipped test3_6 (simultaneous multiple-process management - terminate (fork))\n");
284     return SKIPPED;
285 #endif
286 }
287
288 // extern "C" TEST_DLL_EXPORT int test3_6_mutatorMAIN(ParameterDict &param)
289 test_results_t test3_6_Mutator::setup(ParameterDict &param) {
290     pathname = param["pathname"]->getString();
291     bpatch = (BPatch *)(param["bpatch"]->getPtr());
292     debugPrint = param["debugPrint"]->getInt();
293
294 #if defined (sparc_sun_solaris2_4_test)
295     // we use some unsafe type operations in the test cases.
296     bpatch->setTypeChecking(false);
297 #endif
298     
299     return PASSED;
300 }