Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / ParseThat.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 #include "ParseThat.h"
32 #include "util.h"
33 #include "dyninst_comp.h"
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 using namespace Dyninst;
37
38 std::string ParseThat::emptyString("");
39
40 ParseThat::ParseThat() :
41         pt_path("parseThat"),
42         trans(T_None),
43         suppress_ipc(false),
44         nofork(false),
45         verbosity(7),
46         timeout_secs(300),
47         do_trace(true),
48         tracelength(0),
49         print_summary_(true),
50         parse_level(PL_Func),
51         do_recursive(false),
52         merge_tramps(false),
53         inst_level_(IL_FuncEntry),
54         include_libs_(false)
55 {
56 #if defined (os_windows_test)
57         char slashc = '\\';
58 #else
59         char slashc = '/';
60 #endif
61         char slashbuf[3];
62         sprintf(slashbuf, "%c", slashc);
63         std::string slash(slashbuf);
64
65         //  try to resolve the full path of the parseThat command
66         //  first look in the user's PATH
67         //  If not found, try looking in $DYNINST_ROOT/$PLATFORM/bin
68
69         const char *path_var = getenv("PATH");
70         if (path_var)
71         {
72                 char *fullpath = searchPath(path_var, "parseThat");
73                 if (fullpath)
74                 {
75                         pt_path = std::string(fullpath);
76                         ::free(fullpath);
77                         logerror("%s[%d]:  resolved parseThat to %s\n", FILE__, __LINE__, pt_path.c_str());
78                         return;
79                 }
80         }
81
82         //  If we get here, we didn't find it
83         const char *dyn_root_env = getenv("DYNINST_ROOT");
84         if (!dyn_root_env) {
85                 dyn_root_env = "../../";
86         }       
87         const char *plat_env = getenv("PLATFORM");
88
89         if (!plat_env)
90         {
91 #if defined (os_windows_test)
92                 plat_env = "i386-unknown-nt4.0";
93 #elif defined (os_linux_test)
94 #if defined (arch_x86_test)
95                 plat_env = "i386-unknown-linux2.4";
96 #elif defined (arch_ia64_test)
97                 plat_env = "ia64-unknown-linux2.4";
98 #elif defined (arch_x86_64_test)
99                 plat_env = "x86_64-unknown-linux2.4";
100 #elif defined (arch_power_test)
101 #if defined (arch_64bit_test)
102                 plat_env = "ppc64_linux";
103 #else
104                 plat_env = "ppc32_linux";
105 #endif
106 #endif
107 #elif defined (os_aix_test)
108                 plat_env = "rs6000-ibm-aix5.1";
109 #elif defined (os_solaris_test)
110                 //  annoyingly we don't seem to maintain an arch def that specifies
111                 //  solaris version through the build defines
112                 plat_env = "sparc-sun-solaris2.9";
113 #endif
114         }
115
116         if (plat_env)
117         {
118                 std::string expect_pt_loc = std::string(dyn_root_env) + slash 
119                         + std::string(plat_env) + slash + std::string("bin") 
120                         + slash +std::string("parseThat");
121
122                 struct stat statbuf;
123                 if (!stat(expect_pt_loc.c_str(), &statbuf))
124                 {
125                         pt_path = expect_pt_loc;
126                         logerror("%s[%d]:  resolved parseThat to %s\n", FILE__, __LINE__, pt_path.c_str());
127                         return;
128                 }
129                 else
130                 {
131                         logerror("%s[%d]:  cannot resolve pt path '%s'\n", FILE__, __LINE__, 
132                                         expect_pt_loc.c_str());
133                 }
134         }
135         else
136         {
137                 logerror("%s[%d]:  PLATFORM %s, can't resolve canonical parseThat loc\n",
138                                 FILE__, __LINE__, plat_env ? "set" : "not set");
139         }
140
141         //  try looking at relative paths
142         //  (1) assume we are in $DYNINST_ROOT/dyninst/newtestsuite/$PLATFORM
143         //  so look in ../../../$PLATFORM/bin
144
145         if (plat_env)
146         {
147                 char cwdbuf[1024];
148                 char *last_slash = NULL;
149                 char * cwd = getcwd(cwdbuf, 1024);
150
151                 if (cwd)
152                   last_slash = strrchr(cwd, slashc);
153
154                 if (last_slash) 
155                 {
156                         *last_slash = '\0';
157                         last_slash = strrchr(cwd, slashc);
158                         if (last_slash) 
159                         {
160                                 *last_slash = '\0';
161                                 last_slash = strrchr(cwd, slashc);
162                                 if (last_slash) 
163                                 {
164                                         *last_slash = '\0';
165                                         std::string expected_pt_path = std::string(cwd) + slash 
166                                                 + std::string(plat_env) + slash + std::string("bin") 
167                                                 + slash + std::string("parseThat");
168
169                                         struct stat statbuf;
170                                         if (!stat(expected_pt_path.c_str(), &statbuf))
171                                         {
172                                                 pt_path = expected_pt_path;
173                                                 logerror("%s[%d]:  resolved parseThat to %s\n", FILE__, __LINE__, pt_path.c_str());
174                                                 return;
175                                         }
176
177                                         logerror("%s[%d]: could not find parseThat at loc: '%s'\n", 
178                                                         FILE__, __LINE__, expected_pt_path.c_str());
179                                 }
180                         }
181                 }
182
183         }
184 }
185
186 ParseThat::~ParseThat()
187 {
188 }
189
190 bool ParseThat::setup_args(std::vector<std::string> &pt_args)
191 {
192         pt_args.push_back(std::string("-i"));
193         pt_args.push_back(utos((unsigned) inst_level_));
194         pt_args.push_back(std::string("-p"));
195         pt_args.push_back(utos((unsigned) parse_level));
196         pt_args.push_back(std::string("-v ") + utos(verbosity));
197
198         if (include_libs_) 
199                 pt_args.push_back(std::string("--include-libs"));
200         
201         if (merge_tramps) 
202                 pt_args.push_back(std::string("--merge-tramps"));
203
204         if (rewrite_filename.length()) 
205                 pt_args.push_back(std::string("--binary-edit=") + rewrite_filename);
206
207         if (do_recursive) 
208                 pt_args.push_back(std::string("-r"));
209
210         if (nofork) 
211                 pt_args.push_back(std::string("-S"));
212
213         if (print_summary_) 
214                 pt_args.push_back(std::string("--summary"));
215
216         if (timeout_secs) 
217                 pt_args.push_back(std::string("-t ") + utos(timeout_secs));
218
219         if (do_trace) 
220                 pt_args.push_back(std::string("-T ") + utos(tracelength));
221
222         if (suppress_ipc) 
223                 pt_args.push_back(std::string("--suppress-ipc"));
224
225         if (skip_mods.length()) 
226                 pt_args.push_back(std::string("--skip-mod=") + skip_mods);
227
228         if (skip_funcs.length()) 
229                 pt_args.push_back(std::string("--skip-func=") + skip_funcs);
230
231         if (limit_mod.length()) 
232                 pt_args.push_back(std::string("--only-mod=") + limit_mod);
233
234         if (limit_func.length()) 
235                 pt_args.push_back(std::string("--only-func=") + limit_func);
236
237         if (pt_out_name.length()) 
238                 pt_args.push_back(std::string("-o ") + pt_out_name);
239
240         if (trans != T_None)
241         {
242                 std::string tstr = std::string("--use-transactions=");
243
244                 switch(trans) 
245                 {
246                         case T_Func: tstr += std::string("func"); break;
247                         case T_Mod: tstr += std::string("mod"); break;
248                         case T_Proc: tstr += std::string("proc"); break;
249                         default: tstr += std::string("invalid"); break;
250                 };
251
252                 pt_args.push_back(tstr);
253         }
254
255         return true;
256 }
257
258 test_results_t ParseThat::pt_execute(std::vector<std::string> &pt_args)
259
260 {
261
262 #if defined (os_windows_test)
263         
264         logerror("%s[%d]:  skipping parseThat test for this platform for now\n", 
265                         FILE__, __LINE__);
266         return SKIPPED;
267         
268 #else
269
270         if (!pt_path.length()) pt_path = std::string("parseThat");
271
272         logerror("%s[%d]:  parseThat: %s\n", FILE__, __LINE__, pt_path.c_str());
273
274         return sys_execute(pt_path, pt_args, cmd_stdout_name, cmd_stderr_name);
275 #endif
276 }
277
278 test_results_t ParseThat::sys_execute(std::string cmd, std::vector<std::string> &args,
279                 std::string stdout_redirect, std::string stderr_redirect)
280
281 {
282 #if defined (os_windows_test)
283         fprintf(stderr, "%s[%d]:  FIXME:  should not be called\n", FILE__, __LINE__);
284 #else
285         if (stdout_redirect.length() && stdout_redirect == stderr_redirect)
286         {
287                 //  both to same file
288                 args.push_back(std::string("&>") + stdout_redirect);
289         }
290         else
291         {
292                 if (stdout_redirect.length())
293                 {
294                         args.push_back(std::string("1>") + stdout_redirect);
295                 }
296                 if (stderr_redirect.length())
297                 {
298                         args.push_back(std::string("2>") + stderr_redirect);
299                 }
300         }
301
302         char cmdbuf[2048];
303         sprintf(cmdbuf, "%s", cmd.c_str());
304
305         for (unsigned int i = 0; i < args.size(); ++i)
306         {
307                 sprintf(cmdbuf, "%s %s", cmdbuf, args[i].c_str());
308         }
309
310         logerror("%s[%d]:  about to issue command: \n\t\t'%s'\n", 
311                         FILE__, __LINE__, cmdbuf);
312
313         int res = system(cmdbuf);
314
315         if (WIFEXITED(res))
316         {
317                 short status = WEXITSTATUS(res);
318                 if (0 != status)
319                 {
320                         logerror("%s[%d]:  parseThat cmd failed with code %d\n", 
321                                         FILE__, __LINE__, status);
322                         return FAILED;
323                 }
324         }
325         else
326         {
327                 logerror("%s[%d]:  parseThat cmd failed\n", FILE__, __LINE__);
328                 if (WIFSIGNALED(res))
329                 {
330                         logerror("%s[%d]:  received signal %d\n", FILE__, __LINE__, WTERMSIG(res));
331                 }
332                 return FAILED;
333         }
334
335         return PASSED;
336 #endif
337 }
338
339 test_results_t ParseThat::operator()(std::string exec_path, std::vector<std::string> &mutatee_args)
340 {
341         
342         struct stat statbuf;
343         int result = stat(BINEDIT_DIR, &statbuf);
344         if (-1 == result)
345         {
346                 result = mkdir(BINEDIT_DIR, 0700);
347                 if (result == -1) {
348                         logerror("%s[%d]: Could not mkdir %s: %s\n ", FILE__, __LINE__, 
349                                         BINEDIT_DIR,strerror(errno) );
350                         return FAILED;
351                 }
352         }
353
354         std::vector<std::string> pt_args;
355         if (!setup_args(pt_args))
356         {
357                 logerror("%s[%d]:  failed to setup parseThat args\n", FILE__, __LINE__);
358                 return FAILED;
359         }
360
361         //  Use provided mutatee args to setup arglist for rewritten binary too...
362         std::string newbinary_args = 
363                 std::string("--args=") 
364                 + utos(mutatee_args.size()) 
365                 + std::string(":");
366
367         unsigned nargs = mutatee_args.size();
368         for (unsigned int i = 0; i < nargs; ++i)
369         {
370                 newbinary_args += mutatee_args[i];
371                 if (i < (nargs - 1) )
372                         newbinary_args += std::string(",");
373         }
374
375         pt_args.push_back(newbinary_args);
376
377         //  maybe want to check existence of mutatee executable here?
378
379         pt_args.push_back(exec_path);
380         for (unsigned int i = 0; i < mutatee_args.size(); ++i)
381         {
382                 pt_args.push_back(mutatee_args[i]);
383         }
384
385         return pt_execute(pt_args);
386 }
387
388 test_results_t ParseThat::operator()(int pid)
389 {
390         std::vector<std::string> pt_args;
391         if (!setup_args(pt_args))
392         {
393                 logerror("%s[%d]:  failed to setup parseThat args\n", FILE__, __LINE__);
394                 return FAILED;
395         }
396
397         pt_args.push_back(std::string("--pid=") + itos(pid));
398
399         return pt_execute(pt_args);
400 }