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