]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // systemtap translator/driver |
213bee8f | 2 | // Copyright (C) 2005-2006 Red Hat Inc. |
f12b2552 | 3 | // Copyright (C) 2005 IBM Corp. |
77a5c1f9 | 4 | // Copyright (C) 2006 Intel Corporation. |
69c68955 FCE |
5 | // |
6 | // This file is part of systemtap, and is free software. You can | |
7 | // redistribute it and/or modify it under the terms of the GNU General | |
8 | // Public License (GPL); either version 2, or (at your option) any | |
9 | // later version. | |
2b066ec1 FCE |
10 | |
11 | #include "config.h" | |
12 | #include "staptree.h" | |
13 | #include "parse.h" | |
14 | #include "elaborate.h" | |
15 | #include "translate.h" | |
f4b28491 | 16 | #include "buildrun.h" |
dc38c0ae | 17 | #include "session.h" |
1b78aef5 DS |
18 | #include "hash.h" |
19 | #include "cache.h" | |
20 | #include "util.h" | |
2b066ec1 FCE |
21 | |
22 | #include <iostream> | |
23 | #include <fstream> | |
24 | #include <sstream> | |
f4b28491 | 25 | #include <cerrno> |
24cb178f | 26 | #include <cstdlib> |
2b066ec1 FCE |
27 | |
28 | extern "C" { | |
29 | #include <glob.h> | |
30 | #include <unistd.h> | |
f4b28491 | 31 | #include <sys/utsname.h> |
5ee1c56b | 32 | #include <sys/times.h> |
1d738eed | 33 | #include <sys/time.h> |
f4b28491 | 34 | #include <time.h> |
f8949662 | 35 | #include <elfutils/libdwfl.h> |
2b066ec1 FCE |
36 | } |
37 | ||
38 | using namespace std; | |
39 | ||
40 | ||
f4b28491 | 41 | void |
c0de7a8d | 42 | version () |
2b066ec1 | 43 | { |
d54d4661 | 44 | clog |
d04cf5ff | 45 | << "SystemTap translator/driver " |
f4b28491 | 46 | << "(version " << VERSION << " built " << DATE << ")" << endl |
f8949662 | 47 | << "(Using " << dwfl_version (NULL) << " libraries.)" << endl |
b9b91512 | 48 | << "Copyright (C) 2005-2006 Red Hat, Inc. and others" << endl |
f8949662 | 49 | << "This is free software; see the source for copying conditions." << endl; |
c0de7a8d FCE |
50 | } |
51 | ||
52 | void | |
277c1957 | 53 | usage (systemtap_session& s, int exitcode) |
c0de7a8d FCE |
54 | { |
55 | version (); | |
56 | clog | |
f4b28491 | 57 | << endl |
b2d5d95c | 58 | << "Usage: stap [options] FILE Run script in file." |
f4b28491 | 59 | << endl |
b2d5d95c | 60 | << " or: stap [options] - Run script on stdin." |
f4b28491 | 61 | << endl |
d54d4661 | 62 | << " or: stap [options] -e SCRIPT Run given script." |
f4b28491 FCE |
63 | << endl |
64 | << endl | |
c0de7a8d | 65 | << "Options:" << endl |
f4b28491 | 66 | << " -- no more options after this" << endl |
b0ee93c4 | 67 | << " -v increase verbosity [" << s.verbose << "]" << endl |
c0de7a8d FCE |
68 | << " -h show help" << endl |
69 | << " -V show version" << endl | |
d5d7c2cc | 70 | << " -k keep temporary directory" << endl |
cbfbbf69 | 71 | << " -u unoptimized translation" << (s.unoptimized ? " [set]" : "") << endl |
377b8831 | 72 | << " -g guru mode" << (s.guru_mode ? " [set]" : "") << endl |
f12b2552 | 73 | << " -b bulk (relayfs) mode" << (s.bulk_mode ? " [set]" : "") << endl |
f272aacc | 74 | << " -M Don't merge per-cpu files for bulk (relayfs) mode" << (s.merge ? "" : " [set]") << endl |
177a8ead FCE |
75 | << " -s NUM buffer size in megabytes, instead of " |
76 | << s.buffer_size << endl | |
f8949662 | 77 | << " -p NUM stop after pass NUM 1-5, instead of " |
177a8ead | 78 | << s.last_pass << endl |
f4b28491 FCE |
79 | << " (parse, elaborate, translate, compile, run)" << endl |
80 | << " -I DIR look in DIR for additional .stp script files"; | |
81 | if (s.include_path.size() == 0) | |
0d49d7bc | 82 | clog << endl; |
f4b28491 | 83 | else |
24cb178f | 84 | clog << ", in addition to" << endl; |
f4b28491 | 85 | for (unsigned i=0; i<s.include_path.size(); i++) |
0d49d7bc FCE |
86 | clog << " " << s.include_path[i] << endl; |
87 | clog | |
ed10c639 | 88 | << " -D NM=VAL emit macro definition into generated C code" << endl |
24cb178f FCE |
89 | << " -R DIR look in DIR for runtime, instead of" << endl |
90 | << " " << s.runtime_path << endl | |
177a8ead FCE |
91 | << " -r RELEASE use kernel RELEASE, instead of " |
92 | << s.kernel_release << endl | |
f12b2552 FCE |
93 | << " -m MODULE set probe module name, instead of " |
94 | << s.module_name << endl | |
177a8ead | 95 | << " -o FILE send output to file, instead of stdout" << endl |
f8949662 | 96 | << " -c CMD start the probes, run CMD, and exit when it finishes" |
f12b2552 | 97 | << endl |
4c5ff1bb | 98 | << " -x PID sets target() to PID" << endl |
4b17d6af | 99 | << " -t benchmarking timing information generated" << endl |
d5d7c2cc | 100 | ; |
d54d4661 | 101 | // -d: dump safety-related external references |
2b066ec1 | 102 | |
277c1957 | 103 | exit (exitcode); |
2b066ec1 FCE |
104 | } |
105 | ||
106 | ||
1b78aef5 DS |
107 | static void |
108 | printscript(systemtap_session& s, ostream& o) | |
109 | { | |
110 | if (s.globals.size() > 0) | |
111 | o << "# globals" << endl; | |
112 | for (unsigned i=0; i<s.globals.size(); i++) | |
113 | { | |
114 | vardecl* v = s.globals[i]; | |
115 | v->printsig (o); | |
116 | o << endl; | |
117 | } | |
118 | ||
119 | if (s.functions.size() > 0) | |
120 | o << "# functions" << endl; | |
121 | for (unsigned i=0; i<s.functions.size(); i++) | |
122 | { | |
123 | functiondecl* f = s.functions[i]; | |
124 | f->printsig (o); | |
125 | o << endl; | |
126 | if (f->locals.size() > 0) | |
127 | o << " # locals" << endl; | |
128 | for (unsigned j=0; j<f->locals.size(); j++) | |
129 | { | |
130 | vardecl* v = f->locals[j]; | |
131 | o << " "; | |
132 | v->printsig (o); | |
133 | o << endl; | |
134 | } | |
135 | if (s.verbose) | |
136 | { | |
137 | f->body->print (o); | |
138 | o << endl; | |
139 | } | |
140 | } | |
141 | ||
142 | if (s.probes.size() > 0) | |
143 | o << "# probes" << endl; | |
144 | for (unsigned i=0; i<s.probes.size(); i++) | |
145 | { | |
146 | derived_probe* p = s.probes[i]; | |
147 | p->printsig (o); | |
148 | o << endl; | |
149 | if (p->locals.size() > 0) | |
150 | o << " # locals" << endl; | |
151 | for (unsigned j=0; j<p->locals.size(); j++) | |
152 | { | |
153 | vardecl* v = p->locals[j]; | |
154 | o << " "; | |
155 | v->printsig (o); | |
156 | o << endl; | |
157 | } | |
158 | if (s.verbose) | |
159 | { | |
160 | p->body->print (o); | |
161 | o << endl; | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
2b066ec1 FCE |
166 | int |
167 | main (int argc, char * const argv []) | |
168 | { | |
2b066ec1 FCE |
169 | string cmdline_script; // -e PROGRAM |
170 | string script_file; // FILE | |
171 | bool have_script = false; | |
ea3f75ae | 172 | bool release_changed = false; |
f4b28491 FCE |
173 | |
174 | // Initialize defaults | |
175 | systemtap_session s; | |
176 | struct utsname buf; | |
177 | (void) uname (& buf); | |
178 | s.kernel_release = string (buf.release); | |
44ce8ed5 | 179 | s.architecture = string (buf.machine); |
b0ee93c4 | 180 | s.verbose = 0; |
4b17d6af | 181 | s.timing = 0; |
377b8831 | 182 | s.guru_mode = false; |
16d8de1b | 183 | s.bulk_mode = false; |
cbfbbf69 | 184 | s.unoptimized = false; |
16d8de1b | 185 | s.buffer_size = 0; |
f4b28491 | 186 | s.last_pass = 5; |
ae24723e | 187 | s.module_name = "stap_" + stringify(getpid()); |
08c68653 | 188 | s.output_file = ""; // -o FILE |
f4b28491 | 189 | s.keep_tmpdir = false; |
4c5ff1bb MH |
190 | s.cmd = ""; |
191 | s.target_pid = 0; | |
f272aacc | 192 | s.merge=true; |
47dd066d | 193 | s.perfmon=0; |
f1bad60c | 194 | s.symtab = false; |
1b78aef5 | 195 | s.use_cache = true; |
24cb178f FCE |
196 | |
197 | const char* s_p = getenv ("SYSTEMTAP_TAPSET"); | |
ec819dc3 LG |
198 | if (s_p != NULL) |
199 | { | |
24cb178f | 200 | s.include_path.push_back (s_p); |
ec819dc3 LG |
201 | s.include_path.push_back (string(s_p) + "/LKET"); |
202 | } | |
24cb178f | 203 | else |
ec819dc3 | 204 | { |
24cb178f | 205 | s.include_path.push_back (string(PKGDATADIR) + "/tapset"); |
ec819dc3 LG |
206 | s.include_path.push_back (string(PKGDATADIR) + "/tapset/LKET"); |
207 | } | |
24cb178f FCE |
208 | |
209 | const char* s_r = getenv ("SYSTEMTAP_RUNTIME"); | |
210 | if (s_r != NULL) | |
211 | s.runtime_path = s_r; | |
212 | else | |
213 | s.runtime_path = string(PKGDATADIR) + "/runtime"; | |
f4b28491 | 214 | |
1b78aef5 DS |
215 | const char* s_d = getenv ("SYSTEMTAP_DIR"); |
216 | if (s_d != NULL) | |
217 | s.data_path = s_d; | |
218 | else | |
219 | s.data_path = get_home_directory() + string("/.systemtap"); | |
220 | if (create_dir(s.data_path.c_str()) == 1) | |
221 | { | |
222 | const char* e = strerror (errno); | |
223 | cerr << "Warning: failed to create systemtap data directory (\"" | |
224 | << s.data_path << "\"): " << e << endl; | |
225 | cerr << "Disabling cache support." << endl; | |
226 | s.use_cache = false; | |
227 | } | |
228 | ||
229 | if (s.use_cache) | |
230 | { | |
231 | s.cache_path = s.data_path + "/cache"; | |
232 | if (create_dir(s.cache_path.c_str()) == 1) | |
233 | { | |
234 | const char* e = strerror (errno); | |
235 | cerr << "Warning: failed to create cache directory (\"" | |
236 | << s.cache_path << "\"): " << e << endl; | |
237 | cerr << "Disabling cache support." << endl; | |
238 | s.use_cache = false; | |
239 | } | |
240 | } | |
241 | ||
2b066ec1 FCE |
242 | while (true) |
243 | { | |
f272aacc | 244 | int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgc:x:D:bs:u"); |
2b066ec1 FCE |
245 | if (grc < 0) |
246 | break; | |
247 | switch (grc) | |
248 | { | |
c0de7a8d FCE |
249 | case 'V': |
250 | version (); | |
251 | exit (0); | |
252 | ||
f272aacc LG |
253 | case 'M': |
254 | s.merge = false; | |
255 | break; | |
256 | ||
bd2b1e68 | 257 | case 'v': |
b0ee93c4 | 258 | s.verbose ++; |
bd2b1e68 GH |
259 | break; |
260 | ||
4b17d6af WC |
261 | case 't': |
262 | s.timing ++; | |
263 | break; | |
264 | ||
2b066ec1 | 265 | case 'p': |
f4b28491 FCE |
266 | s.last_pass = atoi (optarg); |
267 | if (s.last_pass < 1 || s.last_pass > 5) | |
2b066ec1 | 268 | { |
277c1957 DS |
269 | cerr << "Invalid pass number (should be 1-5)." << endl; |
270 | usage (s, 1); | |
2b066ec1 FCE |
271 | } |
272 | break; | |
273 | ||
274 | case 'I': | |
f4b28491 | 275 | s.include_path.push_back (string (optarg)); |
2b066ec1 FCE |
276 | break; |
277 | ||
278 | case 'e': | |
279 | if (have_script) | |
277c1957 DS |
280 | { |
281 | cerr << "Only one script can be given on the command line." | |
282 | << endl; | |
283 | usage (s, 1); | |
284 | } | |
2b066ec1 FCE |
285 | cmdline_script = string (optarg); |
286 | have_script = true; | |
287 | break; | |
288 | ||
289 | case 'o': | |
08c68653 | 290 | s.output_file = string (optarg); |
2b066ec1 FCE |
291 | break; |
292 | ||
f4b28491 FCE |
293 | case 'R': |
294 | s.runtime_path = string (optarg); | |
295 | break; | |
296 | ||
297 | case 'm': | |
298 | s.module_name = string (optarg); | |
1b78aef5 DS |
299 | cerr << "Warning: using '-m' disables cache support." << endl; |
300 | s.use_cache = false; | |
f4b28491 FCE |
301 | break; |
302 | ||
303 | case 'r': | |
304 | s.kernel_release = string (optarg); | |
ea3f75ae | 305 | release_changed = true; |
f4b28491 FCE |
306 | break; |
307 | ||
308 | case 'k': | |
309 | s.keep_tmpdir = true; | |
310 | break; | |
311 | ||
377b8831 FCE |
312 | case 'g': |
313 | s.guru_mode = true; | |
314 | break; | |
315 | ||
16d8de1b TZ |
316 | case 'b': |
317 | s.bulk_mode = true; | |
16d8de1b TZ |
318 | break; |
319 | ||
cbfbbf69 FCE |
320 | case 'u': |
321 | s.unoptimized = true; | |
322 | break; | |
323 | ||
16d8de1b TZ |
324 | case 's': |
325 | s.buffer_size = atoi (optarg); | |
326 | if (s.buffer_size < 1 || s.buffer_size > 64) | |
327 | { | |
277c1957 DS |
328 | cerr << "Invalid buffer size (should be 1-64)." << endl; |
329 | usage (s, 1); | |
16d8de1b TZ |
330 | } |
331 | break; | |
332 | ||
4c5ff1bb MH |
333 | case 'c': |
334 | s.cmd = string (optarg); | |
335 | break; | |
336 | ||
337 | case 'x': | |
338 | s.target_pid = atoi(optarg); | |
339 | break; | |
340 | ||
ed10c639 FCE |
341 | case 'D': |
342 | s.macros.push_back (string (optarg)); | |
343 | break; | |
344 | ||
2b066ec1 | 345 | case 'h': |
277c1957 DS |
346 | usage (s, 0); |
347 | break; | |
348 | ||
2b066ec1 | 349 | default: |
277c1957 DS |
350 | usage (s, 1); |
351 | break; | |
2b066ec1 FCE |
352 | } |
353 | } | |
354 | ||
f272aacc LG |
355 | if(!s.bulk_mode && !s.merge) |
356 | { | |
357 | cerr << "-M option is valid only for bulk (relayfs) mode." <<endl; | |
277c1957 | 358 | usage (s, 1); |
f272aacc LG |
359 | } |
360 | ||
361 | if(!s.output_file.empty() && s.bulk_mode && !s.merge) | |
362 | { | |
363 | cerr << "You can't specify -M, -b and -o options together." <<endl; | |
277c1957 | 364 | usage (s, 1); |
f272aacc LG |
365 | } |
366 | ||
ea3f75ae DS |
367 | if (s.last_pass > 4 && release_changed) |
368 | { | |
369 | cerr << ("Warning: changing last pass to 4 since the kernel release" | |
370 | " has changed.") << endl; | |
371 | s.last_pass = 4; | |
372 | } | |
373 | ||
2b066ec1 FCE |
374 | for (int i = optind; i < argc; i++) |
375 | { | |
376 | if (! have_script) | |
377 | { | |
378 | script_file = string (argv[i]); | |
379 | have_script = true; | |
380 | } | |
381 | else | |
f4b28491 | 382 | s.args.push_back (string (argv[i])); |
2b066ec1 FCE |
383 | } |
384 | ||
385 | // need a user file | |
386 | if (! have_script) | |
277c1957 DS |
387 | { |
388 | cerr << "A script must be specified." << endl; | |
389 | usage(s, 1); | |
390 | } | |
f4b28491 FCE |
391 | |
392 | int rc = 0; | |
2b066ec1 | 393 | |
ce3187ac | 394 | // override PATH and LC_ALL |
c72dc86c JS |
395 | const char *path = "/bin:/sbin:/usr/bin:/usr/sbin"; |
396 | rc = setenv("PATH", path, 1) || setenv("LC_ALL", "C", 1); | |
ce3187ac FCE |
397 | if (rc) |
398 | { | |
399 | const char* e = strerror (errno); | |
c72dc86c | 400 | cerr << "setenv (\"PATH=" << path << "\" + \"LC_ALL=C\"): " |
ce3187ac FCE |
401 | << e << endl; |
402 | } | |
f8949662 | 403 | |
197a4d62 JS |
404 | s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-')); |
405 | ||
ce3187ac | 406 | |
2b066ec1 FCE |
407 | // arguments parsed; get down to business |
408 | ||
f4b28491 FCE |
409 | // Create a temporary directory to build within. |
410 | // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end. | |
411 | { | |
c72dc86c | 412 | const char* tmpdir_env = getenv("TMPDIR"); |
ea8ea02c FCE |
413 | if (! tmpdir_env) |
414 | tmpdir_env = "/tmp"; | |
415 | ||
416 | string stapdir = "/stapXXXXXX"; | |
417 | string tmpdirt = tmpdir_env + stapdir; | |
418 | const char* tmpdir = mkdtemp((char *)tmpdirt.c_str()); | |
f4b28491 FCE |
419 | if (! tmpdir) |
420 | { | |
421 | const char* e = strerror (errno); | |
ea8ea02c FCE |
422 | cerr << "ERROR: cannot create temporary directory (\"" << tmpdirt << "\"): " << e << endl; |
423 | exit (1); // die | |
f4b28491 FCE |
424 | } |
425 | else | |
426 | s.tmpdir = tmpdir; | |
0d49d7bc | 427 | |
b0ee93c4 | 428 | if (s.verbose>1) |
0d49d7bc | 429 | clog << "Created temporary directory \"" << s.tmpdir << "\"" << endl; |
f4b28491 | 430 | } |
2b066ec1 | 431 | |
1b78aef5 DS |
432 | // Create the name of the C source file within the temporary |
433 | // directory. | |
434 | s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c"; | |
435 | ||
5ee1c56b FCE |
436 | struct tms tms_before; |
437 | times (& tms_before); | |
1d738eed FCE |
438 | struct timeval tv_before; |
439 | gettimeofday (&tv_before, NULL); | |
2b066ec1 FCE |
440 | |
441 | // PASS 1a: PARSING USER SCRIPT | |
442 | // XXX: pass args vector, so parser (or lexer?) can substitute | |
443 | // $1..$NN with actual arguments | |
69c68955 | 444 | if (script_file == "-") |
177a8ead | 445 | s.user_file = parser::parse (s, cin, s.guru_mode); |
69c68955 | 446 | else if (script_file != "") |
177a8ead | 447 | s.user_file = parser::parse (s, script_file, s.guru_mode); |
2b066ec1 FCE |
448 | else |
449 | { | |
450 | istringstream ii (cmdline_script); | |
177a8ead | 451 | s.user_file = parser::parse (s, ii, s.guru_mode); |
2b066ec1 FCE |
452 | } |
453 | if (s.user_file == 0) | |
454 | // syntax errors already printed | |
455 | rc ++; | |
377b8831 | 456 | |
5519d363 | 457 | // Construct arch / kernel-versioning search path |
377b8831 | 458 | vector<string> version_suffixes; |
6f9f33e2 | 459 | string kvr = s.kernel_release; |
5519d363 KS |
460 | const string& arch = s.architecture; |
461 | // add full kernel-version-release (2.6.NN-FOOBAR) + arch | |
462 | version_suffixes.push_back ("/" + kvr + "/" + arch); | |
377b8831 | 463 | version_suffixes.push_back ("/" + kvr); |
5519d363 | 464 | // add kernel version (2.6.NN) + arch |
197a4d62 JS |
465 | if (kvr != s.kernel_base_release) { |
466 | kvr = s.kernel_base_release; | |
6f9f33e2 JS |
467 | version_suffixes.push_back ("/" + kvr + "/" + arch); |
468 | version_suffixes.push_back ("/" + kvr); | |
5519d363 KS |
469 | } |
470 | // add kernel family (2.6) + arch | |
6f9f33e2 JS |
471 | string::size_type dot1_index = kvr.find ('.'); |
472 | string::size_type dot2_index = kvr.rfind ('.'); | |
473 | while (dot2_index > dot1_index && dot2_index != string::npos) { | |
474 | kvr.erase(dot2_index); | |
475 | version_suffixes.push_back ("/" + kvr + "/" + arch); | |
476 | version_suffixes.push_back ("/" + kvr); | |
477 | dot2_index = kvr.rfind ('.'); | |
5519d363 KS |
478 | } |
479 | // add architecture search path | |
480 | version_suffixes.push_back("/" + arch); | |
377b8831 FCE |
481 | // add empty string as last element |
482 | version_suffixes.push_back (""); | |
2b066ec1 FCE |
483 | |
484 | // PASS 1b: PARSING LIBRARY SCRIPTS | |
f4b28491 | 485 | for (unsigned i=0; i<s.include_path.size(); i++) |
2b066ec1 | 486 | { |
377b8831 FCE |
487 | // now iterate upon it |
488 | for (unsigned k=0; k<version_suffixes.size(); k++) | |
2b066ec1 | 489 | { |
377b8831 FCE |
490 | glob_t globbuf; |
491 | string dir = s.include_path[i] + version_suffixes[k] + "/*.stp"; | |
492 | int r = glob(dir.c_str (), 0, NULL, & globbuf); | |
493 | if (r == GLOB_NOSPACE || r == GLOB_ABORTED) | |
2b066ec1 | 494 | rc ++; |
377b8831 FCE |
495 | // GLOB_NOMATCH is acceptable |
496 | ||
b0ee93c4 | 497 | if (s.verbose>1) |
377b8831 FCE |
498 | clog << "Searched '" << dir << "', " |
499 | << "match count " << globbuf.gl_pathc << endl; | |
2b066ec1 | 500 | |
377b8831 FCE |
501 | for (unsigned j=0; j<globbuf.gl_pathc; j++) |
502 | { | |
24cb178f | 503 | // privilege only for /usr/share/systemtap? |
177a8ead | 504 | stapfile* f = parser::parse (s, globbuf.gl_pathv[j], true); |
377b8831 FCE |
505 | if (f == 0) |
506 | rc ++; | |
507 | else | |
24cb178f | 508 | s.library_files.push_back (f); |
377b8831 | 509 | } |
d54d4661 | 510 | |
377b8831 FCE |
511 | globfree (& globbuf); |
512 | } | |
2b066ec1 FCE |
513 | } |
514 | ||
f4b28491 | 515 | if (rc == 0 && s.last_pass == 1) |
2b066ec1 | 516 | { |
f4b28491 FCE |
517 | cout << "# parse tree dump" << endl; |
518 | s.user_file->print (cout); | |
519 | cout << endl; | |
ae56fddd FCE |
520 | if (s.verbose) |
521 | for (unsigned i=0; i<s.library_files.size(); i++) | |
522 | { | |
523 | s.library_files[i]->print (cout); | |
524 | cout << endl; | |
525 | } | |
2b066ec1 FCE |
526 | } |
527 | ||
5ee1c56b FCE |
528 | struct tms tms_after; |
529 | times (& tms_after); | |
530 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
1d738eed FCE |
531 | struct timeval tv_after; |
532 | gettimeofday (&tv_after, NULL); | |
5ee1c56b FCE |
533 | |
534 | #define TIMESPRINT \ | |
535 | (tms_after.tms_cutime + tms_after.tms_utime \ | |
1d738eed | 536 | - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \ |
5ee1c56b | 537 | << (tms_after.tms_cstime + tms_after.tms_stime \ |
1d738eed FCE |
538 | - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \ |
539 | << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \ | |
540 | ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms." | |
5ee1c56b | 541 | |
eaf134e7 | 542 | // syntax errors, if any, are already printed |
5ee1c56b FCE |
543 | if (s.verbose) |
544 | { | |
545 | clog << "Pass 1: parsed user script and " | |
546 | << s.library_files.size() | |
547 | << " library script(s) in " | |
548 | << TIMESPRINT | |
549 | << endl; | |
550 | } | |
0d49d7bc | 551 | |
2cfb0e46 FCE |
552 | if (rc) |
553 | cerr << "Pass 1: parse failed. " | |
213bee8f | 554 | << "Try again with more '-v' (verbose) options." |
2cfb0e46 FCE |
555 | << endl; |
556 | ||
0d49d7bc | 557 | if (rc || s.last_pass == 1) goto cleanup; |
f4b28491 | 558 | |
5ee1c56b | 559 | times (& tms_before); |
1d738eed | 560 | gettimeofday (&tv_before, NULL); |
5ee1c56b | 561 | |
2b066ec1 | 562 | // PASS 2: ELABORATION |
0d49d7bc | 563 | rc = semantic_pass (s); |
f4b28491 FCE |
564 | |
565 | if (rc == 0 && s.last_pass == 2) | |
1b78aef5 | 566 | printscript(s, cout); |
2b066ec1 | 567 | |
5ee1c56b | 568 | times (& tms_after); |
1d738eed FCE |
569 | gettimeofday (&tv_after, NULL); |
570 | ||
b0ee93c4 | 571 | if (s.verbose) clog << "Pass 2: analyzed script: " |
0d49d7bc FCE |
572 | << s.probes.size() << " probe(s), " |
573 | << s.functions.size() << " function(s), " | |
b20febf3 | 574 | << s.embeds.size() << " embed(s), " |
5ee1c56b FCE |
575 | << s.globals.size() << " global(s) in " |
576 | << TIMESPRINT | |
577 | << endl; | |
0d49d7bc | 578 | |
377b8831 FCE |
579 | if (rc) |
580 | cerr << "Pass 2: analysis failed. " | |
213bee8f | 581 | << "Try again with more '-v' (verbose) options." |
2cfb0e46 | 582 | << endl; |
1b78aef5 DS |
583 | // Generate hash. There isn't any point in generating the hash |
584 | // if last_pass is 2, since we'll quit before using it. | |
585 | else if (s.last_pass != 2 && s.use_cache) | |
586 | { | |
587 | ostringstream o; | |
588 | unsigned saved_verbose; | |
589 | ||
590 | // Make sure we're in verbose mode, so that printscript() | |
591 | // will output function/probe bodies. | |
592 | saved_verbose = s.verbose; | |
593 | s.verbose = 3; | |
594 | ||
595 | // Print script to 'o' | |
596 | printscript(s, o); | |
597 | ||
598 | // Restore original verbose mode setting. | |
599 | s.verbose = saved_verbose; | |
600 | ||
601 | // Generate hash | |
602 | find_hash (s, o.str()); | |
603 | ||
604 | // See if we can use cached source/module. | |
605 | if (get_from_cache(s)) | |
606 | { | |
607 | // If our last pass isn't 5, we're done (since passes 3 and | |
608 | // 4 just generate what we just pulled out of the cache). | |
609 | if (s.last_pass < 5) goto cleanup; | |
610 | ||
611 | // Short-circuit to pass 5. | |
612 | goto pass_5; | |
613 | } | |
614 | } | |
377b8831 | 615 | |
0d49d7bc | 616 | if (rc || s.last_pass == 2) goto cleanup; |
f4b28491 | 617 | |
2b066ec1 | 618 | // PASS 3: TRANSLATION |
5ee1c56b FCE |
619 | |
620 | times (& tms_before); | |
1d738eed FCE |
621 | gettimeofday (&tv_before, NULL); |
622 | ||
0d49d7bc | 623 | rc = translate_pass (s); |
f4b28491 FCE |
624 | |
625 | if (rc == 0 && s.last_pass == 3) | |
626 | { | |
627 | ifstream i (s.translated_source.c_str()); | |
628 | cout << i.rdbuf(); | |
629 | } | |
0d49d7bc | 630 | |
5ee1c56b | 631 | times (& tms_after); |
1d738eed | 632 | gettimeofday (&tv_after, NULL); |
5ee1c56b | 633 | |
0d49d7bc FCE |
634 | if (s.verbose) clog << "Pass 3: translated to C into \"" |
635 | << s.translated_source | |
5ee1c56b FCE |
636 | << "\" in " |
637 | << TIMESPRINT | |
638 | << endl; | |
0d49d7bc | 639 | |
377b8831 | 640 | if (rc) |
2cfb0e46 | 641 | cerr << "Pass 3: translation failed. " |
213bee8f | 642 | << "Try again with more '-v' (verbose) options." |
2cfb0e46 | 643 | << endl; |
377b8831 | 644 | |
0d49d7bc | 645 | if (rc || s.last_pass == 3) goto cleanup; |
d54d4661 | 646 | |
f4b28491 | 647 | // PASS 4: COMPILATION |
5ee1c56b | 648 | times (& tms_before); |
1d738eed | 649 | gettimeofday (&tv_before, NULL); |
0d49d7bc | 650 | rc = compile_pass (s); |
5ee1c56b | 651 | times (& tms_after); |
1d738eed | 652 | gettimeofday (&tv_after, NULL); |
5ee1c56b FCE |
653 | |
654 | if (s.verbose) clog << "Pass 4: compiled C into \"" | |
655 | << s.module_name << ".ko" | |
656 | << "\" in " | |
657 | << TIMESPRINT | |
658 | << endl; | |
f4b28491 | 659 | |
eaf134e7 FCE |
660 | if (rc) |
661 | cerr << "Pass 4: compilation failed. " | |
213bee8f | 662 | << "Try again with more '-v' (verbose) options." |
2cfb0e46 | 663 | << endl; |
1b78aef5 DS |
664 | else if (s.use_cache) |
665 | { | |
666 | // Update cache. | |
667 | add_to_cache(s); | |
668 | } | |
eaf134e7 | 669 | |
f8949662 | 670 | // XXX: what to do if rc==0 && last_pass == 4? dump .ko file to stdout? |
0d49d7bc | 671 | if (rc || s.last_pass == 4) goto cleanup; |
f4b28491 | 672 | |
0d49d7bc | 673 | // PASS 5: RUN |
1b78aef5 | 674 | pass_5: |
5ee1c56b | 675 | times (& tms_before); |
1d738eed | 676 | gettimeofday (&tv_before, NULL); |
03d569d3 FCE |
677 | // NB: this message is a judgement call. The other passes don't emit |
678 | // a "hello, I'm starting" message, but then the others aren't interactive | |
679 | // and don't take an indefinite amount of time. | |
680 | if (s.verbose) clog << "Pass 5: starting run." << endl; | |
0d49d7bc | 681 | rc = run_pass (s); |
5ee1c56b | 682 | times (& tms_after); |
1d738eed | 683 | gettimeofday (&tv_after, NULL); |
5ee1c56b FCE |
684 | if (s.verbose) clog << "Pass 5: run completed in " |
685 | << TIMESPRINT | |
686 | << endl; | |
f4b28491 | 687 | |
eaf134e7 FCE |
688 | if (rc) |
689 | cerr << "Pass 5: run failed. " | |
213bee8f | 690 | << "Try again with more '-v' (verbose) options." |
2cfb0e46 | 691 | << endl; |
eaf134e7 | 692 | |
0d49d7bc | 693 | // if (rc) goto cleanup; |
2b066ec1 | 694 | |
0d49d7bc | 695 | cleanup: |
f4b28491 FCE |
696 | // Clean up temporary directory. Obviously, be careful with this. |
697 | if (s.tmpdir == "") | |
698 | ; // do nothing | |
699 | else | |
700 | { | |
701 | if (s.keep_tmpdir) | |
0d49d7bc | 702 | clog << "Keeping temporary directory \"" << s.tmpdir << "\"" << endl; |
f4b28491 FCE |
703 | else |
704 | { | |
ce3187ac | 705 | string cleanupcmd = "rm -rf "; |
f4b28491 | 706 | cleanupcmd += s.tmpdir; |
b0ee93c4 | 707 | if (s.verbose>1) clog << "Running " << cleanupcmd << endl; |
d54d4661 | 708 | int status = system (cleanupcmd.c_str()); |
b0ee93c4 | 709 | if (status != 0 && s.verbose>1) |
d54d4661 | 710 | clog << "Cleanup command failed, status: " << status << endl; |
f4b28491 FCE |
711 | } |
712 | } | |
2b066ec1 | 713 | |
54dfabe9 | 714 | return rc ? EXIT_FAILURE : EXIT_SUCCESS; |
2b066ec1 | 715 | } |