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