Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test3_3.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_3.C,v 1.1 2008/10/30 19:20:37 legendre Exp $
33 /*
34  * #Name: test3_3
35  * #Desc: instrument multiple processes
36  * #Dep: 
37  * #Arch: all
38  * #Notes: useAttach does not apply
39  */
40
41 #include "BPatch.h"
42 #include "BPatch_Vector.h"
43 #include "BPatch_thread.h"
44 #include "BPatch_snippet.h"
45
46 #include "test_lib.h"
47 //#include "test3.h"
48
49 #define MAX_MUTATEES    32
50
51 #include "dyninst_comp.h"
52 class test3_3_Mutator : public DyninstMutator {
53   unsigned int Mutatees;
54   int debugPrint;
55   char *pathname;
56   BPatch *bpatch;
57
58 public:
59   test3_3_Mutator();
60   virtual bool hasCustomExecutionPath() { return true; }
61   virtual test_results_t setup(ParameterDict &param);
62   virtual test_results_t executeTest();
63 };
64 extern "C" DLLEXPORT  TestMutator *test3_3_factory() {
65   return new test3_3_Mutator();
66 }
67
68 test3_3_Mutator::test3_3_Mutator() 
69   : Mutatees(3), pathname(NULL), bpatch(NULL) {
70 }
71
72 //
73 // read the result code written to the file test3.out.<pid> and return it
74 //
75 static int readResult(int pid)
76 {
77     int ret;
78     FILE *fp;
79     char filename[80];
80
81     sprintf(filename, "test3.out.%d", pid);
82     fp = fopen(filename, "r");
83     if (!fp) {
84         logerror("ERROR: unable to open output file %s\n", filename);
85         return FAILED;
86     }
87     fscanf(fp, "%d\n", &ret);
88     fclose(fp);
89     // don't need the file any longer so delete it now
90     unlink(filename);
91
92     return ret;
93 }
94
95 //
96 // Start Test Case #3 - create processes and insert different code into
97 //     each one.  The code sets a global variable which the mutatee then
98 //     writes to a file.  After all mutatees exit, the mutator reads the
99 //     files to verify that the correct code ran in each mutatee.
100 //     The first mutator should write a 1 to the file, the second a 2, etc.
101 //     If no code is patched into the mutatees, the value is 0xdeadbeef.
102 //
103 // static int mutatorTest(char *pathname, BPatch *bpatch)
104 test_results_t test3_3_Mutator::executeTest() {
105     unsigned int n=0;
106     const char *child_argv[5];
107     child_argv[n++] = pathname;
108     if (debugPrint) child_argv[n++] = const_cast<char*>("-verbose");
109     child_argv[n++] = const_cast<char*>("-run");
110     child_argv[n++] = const_cast<char*>("test3_3"); // run test3 in mutatee
111     child_argv[n++] = NULL;
112
113     int pid[MAX_MUTATEES];
114     BPatch_thread *appThread[MAX_MUTATEES];
115
116     for (n=0; n<MAX_MUTATEES; n++) appThread[n]=NULL;
117
118     // Start the mutatees
119     for (n=0; n<Mutatees; n++) {
120         dprintf("Starting \"%s\" %d/%d\n", pathname, n, Mutatees);
121         appThread[n] = bpatch->createProcess(pathname, child_argv, NULL);
122         if (!appThread[n]) {
123             logerror("*ERROR*: unable to create handle%d for executable\n", n);
124             logerror("**Failed** test #3 (instrument multiple processes)\n");
125                         if(n > 0) {
126                     MopUpMutatees(n-1,appThread);
127                         }
128             return FAILED;
129         }
130         pid[n] = appThread[n]->getPid();
131         dprintf("Mutatee %d started, pid=%d\n", n, pid[n]);
132         registerPID(pid[n]); // Register for cleanup
133     }
134
135     // Instrument mutatees
136     for (n=0; n<Mutatees; n++) {
137         dprintf("Instrumenting %d/%d\n", n, Mutatees);
138
139         const char *Func="test3_3_mutatee";
140         const char *Var = "test3_3_ret";
141         const char *Call="test3_3_call1";
142         BPatch_image *img = appThread[n]->getImage();
143
144   BPatch_Vector<BPatch_function *> found_funcs;
145     if ((NULL == img->findFunction(Func, found_funcs, 1)) || !found_funcs.size()) {
146       logerror("    Unable to find function %s\n",
147               Func);
148       return FAILED;
149     }
150
151     if (1 < found_funcs.size()) {
152       logerror("%s[%d]:  WARNING  : found %d functions named %s.  Using the first.\n", 
153               __FILE__, __LINE__, found_funcs.size(), Func);
154     }
155
156     BPatch_Vector<BPatch_point *> *point = found_funcs[0]->findPoint(BPatch_entry);
157
158         if (!point || (*point).size() == 0) {
159             logerror("  Unable to find entry point to \"%s\".\n", Func);
160             logerror("**Failed** test #3 (instrument multiple processes)\n");
161             MopUpMutatees(Mutatees,appThread);
162             return FAILED;
163         }
164         BPatch_variableExpr *var = img->findVariable(Var);
165         if (var == NULL) {
166             logerror("  Unable to find variable \"%s\".\n", Var);
167             logerror("**Failed** test #3 (instrument multiple processes)\n");
168             MopUpMutatees(Mutatees,appThread);
169             return FAILED;
170         }
171
172         BPatch_Vector<BPatch_function *> bpfv;
173         if (NULL == img->findFunction(Call, bpfv) || !bpfv.size()
174             || NULL == bpfv[0]){
175           logerror("  Unable to find target function \"%s\".\n", Call);
176           logerror("**Failed** test #3 (instrument multiple processes)\n");
177           return FAILED;
178         }
179
180         BPatch_function *callFunc = bpfv[0];
181
182         // start with a simple snippet
183         BPatch_arithExpr snip(BPatch_assign, *var, BPatch_constExpr((int)n));
184         BPatchSnippetHandle *inst = appThread[n]->insertSnippet(snip, *point);
185         if (inst == NULL) {
186             logerror("  Failed to insert simple snippet.\n");
187             logerror("**Failed** test #3 (instrument multiple processes)\n");
188             MopUpMutatees(Mutatees,appThread);
189             return FAILED;
190         }
191
192         // now add a call snippet
193         BPatch_Vector<BPatch_snippet *> callArgs;
194         BPatch_constExpr arg1(2); callArgs.push_back(&arg1);
195         BPatch_constExpr arg2((int)n); callArgs.push_back(&arg2);
196         BPatch_funcCallExpr callExpr(*callFunc, callArgs);
197         BPatchSnippetHandle *call = 
198                 appThread[n]->insertSnippet(callExpr, *point);
199         if (call == NULL) {
200             logerror("  Failed to insert call snippet.\n");
201             logerror("**Failed** test #3 (instrument multiple processes)\n");
202             MopUpMutatees(Mutatees,appThread);
203             return FAILED;
204         }
205     }
206
207     dprintf("Letting %d mutatee processes run.\n", Mutatees);
208     for (n=0; n<Mutatees; n++) appThread[n]->continueExecution();
209
210     unsigned int numTerminated=0;
211     bool terminated[MAX_MUTATEES];
212     for (n=0; n<Mutatees; n++) terminated[n]=false;
213
214     // monitor the mutatee termination reports
215     while (numTerminated < Mutatees) {
216         bpatch->waitForStatusChange();
217         for (n=0; n<Mutatees; n++)
218             if (!terminated[n] && (appThread[n]->isTerminated())) {
219                 if(appThread[n]->terminationStatus() == ExitedNormally) {
220                     int exitCode = appThread[n]->getExitCode();
221                     if (exitCode || debugPrint)
222                         dprintf("Mutatee %d exited with exit code 0x%x\n", n,
223                                 exitCode);
224                 }
225                 else if(appThread[n]->terminationStatus() == ExitedViaSignal) {
226                     int signalNum = appThread[n]->getExitSignal();
227                     if (signalNum || debugPrint)
228                         dprintf("Mutatee %d exited from signal 0x%d\n", n,
229                                 signalNum);
230                 }
231                 terminated[n]=true;
232                 numTerminated++;
233             }
234     }
235
236     // now read the files to see if the value is what is expected
237     bool allCorrect=true;
238     int ret[MAX_MUTATEES];
239     for (n=0; n<Mutatees; n++) {
240         ret[n]=readResult(pid[n]);
241         if (ret[n] != (int)n) {
242             dprintf("    mutatee process %d produced %d, not %d\n",
243                 pid[n], ret[n], n);
244             allCorrect=false;
245         } else {
246             dprintf("    mutatee process %d produced expected value %d\n", 
247                 pid[n], ret[n]);
248         }
249     }
250
251     if (allCorrect) {
252         logerror("Passed Test #3 (instrument multiple processes)\n");
253         return PASSED;
254     } else {
255         logerror("**Failed** test #3 (instrument multiple processes)\n");
256         return FAILED;
257     }
258 }
259
260 // extern "C" TEST_DLL_EXPORT int test3_3_mutatorMAIN(ParameterDict &param)
261 test_results_t test3_3_Mutator::setup(ParameterDict &param) {
262     pathname = param["pathname"]->getString();
263     bpatch = (BPatch *)(param["bpatch"]->getPtr());
264     debugPrint = param["debugPrint"]->getInt();
265     
266 #if defined (sparc_sun_solaris2_4_test)
267     // we use some unsafe type operations in the test cases.
268     bpatch->setTypeChecking(false);
269 #endif
270     
271     return PASSED;
272 }