]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // systemtap translator/driver |
44edbcd6 | 2 | // Copyright (C) 2005-2011 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" | |
85007c04 DB |
12 | #include "staptree.h" |
13 | #include "parse.h" | |
14 | #include "elaborate.h" | |
15 | #include "translate.h" | |
16 | #include "buildrun.h" | |
dc38c0ae | 17 | #include "session.h" |
85007c04 DB |
18 | #include "hash.h" |
19 | #include "cache.h" | |
20 | #include "util.h" | |
21 | #include "coveragedb.h" | |
22 | #include "rpm_finder.h" | |
23 | #include "task_finder.h" | |
24 | #include "csclient.h" | |
daa75206 | 25 | #include "remote.h" |
b82d77b4 | 26 | #include "tapsets.h" |
05fb3e0c | 27 | #include "setupdwfl.h" |
85007c04 | 28 | |
79bc39ab LB |
29 | #include <libintl.h> |
30 | #include <locale.h> | |
79bc39ab | 31 | |
0f5d597d | 32 | #include "stap-probe.h" |
aa4d21c0 | 33 | |
24cb178f | 34 | #include <cstdlib> |
73267b89 | 35 | |
85007c04 DB |
36 | extern "C" { |
37 | #include <glob.h> | |
38 | #include <unistd.h> | |
39 | #include <signal.h> | |
40 | #include <sys/utsname.h> | |
41 | #include <sys/times.h> | |
42 | #include <sys/time.h> | |
43 | #include <sys/stat.h> | |
44 | #include <time.h> | |
45 | #include <unistd.h> | |
222e16ed | 46 | #include <wordexp.h> |
85007c04 DB |
47 | } |
48 | ||
49 | using namespace std; | |
50 | ||
40a50254 JS |
51 | static void |
52 | uniq_list(list<string>& l) | |
e2012a7a | 53 | { |
40a50254 JS |
54 | set<string> s; |
55 | list<string>::iterator i = l.begin(); | |
56 | while (i != l.end()) | |
57 | if (s.insert(*i).second) | |
58 | ++i; | |
59 | else | |
60 | i = l.erase(i); | |
85007c04 | 61 | } |
2dce8c42 | 62 | |
85007c04 DB |
63 | static void |
64 | printscript(systemtap_session& s, ostream& o) | |
65 | { | |
66 | if (s.listing_mode) | |
67 | { | |
68 | // We go through some heroic measures to produce clean output. | |
69 | // Record the alias and probe pointer as <name, set<derived_probe *> > | |
70 | map<string,set<derived_probe *> > probe_list; | |
6e683641 | 71 | |
85007c04 DB |
72 | // Pre-process the probe alias |
73 | for (unsigned i=0; i<s.probes.size(); i++) | |
74 | { | |
e19ebcf7 | 75 | assert_no_interrupts(); |
85007c04 DB |
76 | |
77 | derived_probe* p = s.probes[i]; | |
78 | // NB: p->basest() is not so interesting; | |
79 | // p->almost_basest() doesn't quite work, so ... | |
80 | vector<probe*> chain; | |
81 | p->collect_derivation_chain (chain); | |
82 | probe* second = (chain.size()>1) ? chain[chain.size()-2] : chain[0]; | |
83 | ||
7977a734 | 84 | if (s.verbose > 5) { |
85007c04 DB |
85 | p->printsig(cerr); cerr << endl; |
86 | cerr << "chain[" << chain.size() << "]:" << endl; | |
87 | for (unsigned j=0; j<chain.size(); j++) | |
88 | { | |
89 | cerr << " [" << j << "]: " << endl; | |
90 | cerr << "\tlocations[" << chain[j]->locations.size() << "]:" << endl; | |
91 | for (unsigned k=0; k<chain[j]->locations.size(); k++) | |
92 | { | |
93 | cerr << "\t [" << k << "]: "; | |
94 | chain[j]->locations[k]->print(cerr); | |
95 | cerr << endl; | |
96 | } | |
97 | const probe_alias *a = chain[j]->get_alias(); | |
98 | if (a) | |
99 | { | |
100 | cerr << "\taliases[" << a->alias_names.size() << "]:" << endl; | |
101 | for (unsigned k=0; k<a->alias_names.size(); k++) | |
102 | { | |
103 | cerr << "\t [" << k << "]: "; | |
104 | a->alias_names[k]->print(cerr); | |
105 | cerr << endl; | |
106 | } | |
107 | } | |
108 | } | |
7977a734 | 109 | } |
85007c04 DB |
110 | |
111 | stringstream tmps; | |
8eb6206c SM |
112 | // XXX PR14297 make this more accurate wrt complex wildcard expansions |
113 | const probe_point *a = second->get_alias_loc(); | |
85007c04 DB |
114 | if (a) |
115 | { | |
8eb6206c | 116 | a->print(tmps); |
85007c04 DB |
117 | } |
118 | else | |
119 | { | |
120 | assert (second->locations.size() >= 1); | |
8eb6206c | 121 | second->locations[0]->print(tmps); // XXX: choosing only one location is less arbitrary here than in get_alias_loc(), but still ... |
85007c04 DB |
122 | } |
123 | string pp = tmps.str(); | |
124 | ||
125 | // Now duplicate-eliminate. An alias may have expanded to | |
126 | // several actual derived probe points, but we only want to | |
127 | // print the alias head name once. | |
128 | probe_list[pp].insert(p); | |
129 | } | |
130 | ||
131 | // print probe name and variables if there | |
132 | for (map<string, set<derived_probe *> >::iterator it=probe_list.begin(); it!=probe_list.end(); ++it) | |
133 | { | |
134 | o << it->first; // probe name or alias | |
135 | ||
136 | // Print the locals and arguments for -L mode only | |
137 | if (s.listing_mode_vars) | |
138 | { | |
139 | map<string,unsigned> var_count; // format <"name:type",count> | |
140 | map<string,unsigned> arg_count; | |
141 | list<string> var_list; | |
142 | list<string> arg_list; | |
143 | // traverse set<derived_probe *> to collect all locals and arguments | |
144 | for (set<derived_probe *>::iterator ix=it->second.begin(); ix!=it->second.end(); ++ix) | |
145 | { | |
146 | derived_probe* p = *ix; | |
147 | // collect available locals of the probe | |
148 | for (unsigned j=0; j<p->locals.size(); j++) | |
149 | { | |
150 | stringstream tmps; | |
151 | vardecl* v = p->locals[j]; | |
152 | v->printsig (tmps); | |
153 | var_count[tmps.str()]++; | |
154 | var_list.push_back(tmps.str()); | |
155 | } | |
156 | // collect arguments of the probe if there | |
157 | list<string> arg_set; | |
158 | p->getargs(arg_set); | |
159 | for (list<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) { | |
160 | arg_count[*ia]++; | |
161 | arg_list.push_back(*ia); | |
162 | } | |
163 | } | |
164 | ||
165 | uniq_list(arg_list); | |
166 | uniq_list(var_list); | |
167 | ||
168 | // print the set-intersection only | |
169 | for (list<string>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir) | |
170 | if (var_count.find(*ir)->second == it->second.size()) // print locals | |
171 | o << " " << *ir; | |
172 | for (list<string>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir) | |
173 | if (arg_count.find(*ir)->second == it->second.size()) // print arguments | |
174 | o << " " << *ir; | |
175 | } | |
176 | o << endl; | |
177 | } | |
178 | } | |
179 | else | |
2dce8c42 | 180 | { |
85007c04 | 181 | if (s.embeds.size() > 0) |
79bc39ab | 182 | o << _("# global embedded code") << endl; |
85007c04 DB |
183 | for (unsigned i=0; i<s.embeds.size(); i++) |
184 | { | |
e19ebcf7 | 185 | assert_no_interrupts(); |
85007c04 DB |
186 | embeddedcode* ec = s.embeds[i]; |
187 | ec->print (o); | |
188 | o << endl; | |
189 | } | |
2dce8c42 | 190 | |
85007c04 | 191 | if (s.globals.size() > 0) |
79bc39ab | 192 | o << _("# globals") << endl; |
85007c04 DB |
193 | for (unsigned i=0; i<s.globals.size(); i++) |
194 | { | |
e19ebcf7 | 195 | assert_no_interrupts(); |
85007c04 DB |
196 | vardecl* v = s.globals[i]; |
197 | v->printsig (o); | |
198 | if (s.verbose && v->init) | |
199 | { | |
200 | o << " = "; | |
201 | v->init->print(o); | |
202 | } | |
203 | o << endl; | |
204 | } | |
205 | ||
206 | if (s.functions.size() > 0) | |
79bc39ab | 207 | o << _("# functions") << endl; |
85007c04 DB |
208 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
209 | { | |
e19ebcf7 | 210 | assert_no_interrupts(); |
85007c04 DB |
211 | functiondecl* f = it->second; |
212 | f->printsig (o); | |
213 | o << endl; | |
214 | if (f->locals.size() > 0) | |
79bc39ab | 215 | o << _(" # locals") << endl; |
85007c04 DB |
216 | for (unsigned j=0; j<f->locals.size(); j++) |
217 | { | |
218 | vardecl* v = f->locals[j]; | |
219 | o << " "; | |
220 | v->printsig (o); | |
221 | o << endl; | |
222 | } | |
223 | if (s.verbose) | |
224 | { | |
225 | f->body->print (o); | |
226 | o << endl; | |
227 | } | |
228 | } | |
229 | ||
230 | if (s.probes.size() > 0) | |
79bc39ab | 231 | o << _("# probes") << endl; |
85007c04 DB |
232 | for (unsigned i=0; i<s.probes.size(); i++) |
233 | { | |
e19ebcf7 | 234 | assert_no_interrupts(); |
85007c04 DB |
235 | derived_probe* p = s.probes[i]; |
236 | p->printsig (o); | |
237 | o << endl; | |
238 | if (p->locals.size() > 0) | |
79bc39ab | 239 | o << _(" # locals") << endl; |
85007c04 DB |
240 | for (unsigned j=0; j<p->locals.size(); j++) |
241 | { | |
242 | vardecl* v = p->locals[j]; | |
243 | o << " "; | |
244 | v->printsig (o); | |
245 | o << endl; | |
246 | } | |
247 | if (s.verbose) | |
248 | { | |
249 | p->body->print (o); | |
250 | o << endl; | |
251 | } | |
252 | } | |
2dce8c42 | 253 | } |
85007c04 | 254 | } |
e2012a7a | 255 | |
e2012a7a | 256 | |
85007c04 DB |
257 | int pending_interrupts; |
258 | ||
259 | extern "C" | |
260 | void handle_interrupt (int sig) | |
261 | { | |
c9c8c406 JS |
262 | // This might be nice, but we don't know our current verbosity... |
263 | // clog << _F("Received signal %d", sig) << endl << flush; | |
878b2f3f CM |
264 | kill_stap_spawn(SIGTERM); |
265 | ||
85007c04 | 266 | pending_interrupts ++; |
536a1b69 FCE |
267 | // Absorb the first two signals. This used to be one, but when |
268 | // stap is run under sudo, and then interrupted, sudo relays a | |
269 | // redundant copy of the signal to stap, leading to an unclean shutdown. | |
270 | if (pending_interrupts > 2) // XXX: should be configurable? time-based? | |
85007c04 DB |
271 | { |
272 | char msg[] = "Too many interrupts received, exiting.\n"; | |
273 | int rc = write (2, msg, sizeof(msg)-1); | |
274 | if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;} | |
275 | _exit (1); | |
276 | } | |
277 | } | |
278 | ||
279 | ||
280 | void | |
281 | setup_signals (sighandler_t handler) | |
282 | { | |
283 | struct sigaction sa; | |
284 | ||
11c6c509 | 285 | memset(&sa, 0, sizeof(sa)); |
85007c04 DB |
286 | sa.sa_handler = handler; |
287 | sigemptyset (&sa.sa_mask); | |
288 | if (handler != SIG_IGN) | |
289 | { | |
290 | sigaddset (&sa.sa_mask, SIGHUP); | |
291 | sigaddset (&sa.sa_mask, SIGPIPE); | |
292 | sigaddset (&sa.sa_mask, SIGINT); | |
293 | sigaddset (&sa.sa_mask, SIGTERM); | |
5ed19be2 DB |
294 | sigaddset (&sa.sa_mask, SIGXFSZ); |
295 | sigaddset (&sa.sa_mask, SIGXCPU); | |
85007c04 DB |
296 | } |
297 | sa.sa_flags = SA_RESTART; | |
298 | ||
299 | sigaction (SIGHUP, &sa, NULL); | |
300 | sigaction (SIGPIPE, &sa, NULL); | |
301 | sigaction (SIGINT, &sa, NULL); | |
302 | sigaction (SIGTERM, &sa, NULL); | |
5ed19be2 DB |
303 | sigaction (SIGXFSZ, &sa, NULL); |
304 | sigaction (SIGXCPU, &sa, NULL); | |
e2012a7a | 305 | } |
6e683641 | 306 | |
85007c04 DB |
307 | int parse_kernel_config (systemtap_session &s) |
308 | { | |
309 | // PR10702: pull config options | |
310 | string kernel_config_file = s.kernel_build_tree + "/.config"; | |
311 | struct stat st; | |
312 | int rc = stat(kernel_config_file.c_str(), &st); | |
313 | if (rc != 0) | |
46a1a151 JS |
314 | { |
315 | clog << _F("Checking \"%s\" failed with error: %s", | |
316 | kernel_config_file.c_str(), strerror(errno)) << endl; | |
76c87907 LB |
317 | find_devel_rpms(s, s.kernel_build_tree.c_str()); |
318 | missing_rpm_list_print(s,"-devel"); | |
85007c04 DB |
319 | return rc; |
320 | } | |
6861e056 | 321 | |
85007c04 DB |
322 | ifstream kcf (kernel_config_file.c_str()); |
323 | string line; | |
324 | while (getline (kcf, line)) | |
325 | { | |
326 | if (!startswith(line, "CONFIG_")) continue; | |
327 | size_t off = line.find('='); | |
328 | if (off == string::npos) continue; | |
329 | string key = line.substr(0, off); | |
330 | string value = line.substr(off+1, string::npos); | |
331 | s.kernel_config[key] = value; | |
332 | } | |
333 | if (s.verbose > 2) | |
46a1a151 | 334 | clog << _F("Parsed kernel \"%s\", ", kernel_config_file.c_str()) |
19211404 LB |
335 | << _F(ngettext("containing %zu tuple", "containing %zu tuples", |
336 | s.kernel_config.size()), s.kernel_config.size()) << endl; | |
46a1a151 | 337 | |
85007c04 DB |
338 | kcf.close(); |
339 | return 0; | |
340 | } | |
341 | ||
342 | ||
343 | int parse_kernel_exports (systemtap_session &s) | |
344 | { | |
345 | string kernel_exports_file = s.kernel_build_tree + "/Module.symvers"; | |
346 | struct stat st; | |
347 | int rc = stat(kernel_exports_file.c_str(), &st); | |
348 | if (rc != 0) | |
349 | { | |
19211404 LB |
350 | clog << _F("Checking \"%s\" failed with error: %s\nEnsure kernel development headers & makefiles are installed", |
351 | kernel_exports_file.c_str(), strerror(errno)) << endl; | |
85007c04 DB |
352 | return rc; |
353 | } | |
354 | ||
355 | ifstream kef (kernel_exports_file.c_str()); | |
356 | string line; | |
357 | while (getline (kef, line)) | |
358 | { | |
359 | vector<string> tokens; | |
360 | tokenize (line, tokens, "\t"); | |
361 | if (tokens.size() == 4 && | |
362 | tokens[2] == "vmlinux" && | |
363 | tokens[3].substr(0,13) == string("EXPORT_SYMBOL")) | |
364 | s.kernel_exports.insert (tokens[1]); | |
6c090ccb DS |
365 | // RHEL4 Module.symvers file only has 3 tokens. No |
366 | // 'EXPORT_SYMBOL' token at the end of the line. | |
367 | else if (tokens.size() == 3 && tokens[2] == "vmlinux") | |
368 | s.kernel_exports.insert (tokens[1]); | |
85007c04 DB |
369 | } |
370 | if (s.verbose > 2) | |
ce0f6648 LB |
371 | clog << _F(ngettext("Parsed kernel %s, which contained one vmlinux export", |
372 | "Parsed kernel %s, which contained %zu vmlinux exports", | |
373 | s.kernel_exports.size()), kernel_exports_file.c_str(), | |
374 | s.kernel_exports.size()) << endl; | |
46a1a151 | 375 | |
85007c04 DB |
376 | kef.close(); |
377 | return 0; | |
378 | } | |
379 | ||
44edbcd6 | 380 | // Compilation passes 0 through 4 |
85007c04 DB |
381 | static int |
382 | passes_0_4 (systemtap_session &s) | |
383 | { | |
384 | int rc = 0; | |
daa75206 | 385 | |
504d2b61 JS |
386 | // If we don't know the release, there's no hope either locally or on a server. |
387 | if (s.kernel_release.empty()) | |
388 | { | |
389 | if (s.kernel_build_tree.empty()) | |
390 | cerr << _("ERROR: kernel release isn't specified") << endl; | |
391 | else | |
46a1a151 JS |
392 | cerr << _F("ERROR: kernel release isn't found in \"%s\"", |
393 | s.kernel_build_tree.c_str()) << endl; | |
504d2b61 JS |
394 | return 1; |
395 | } | |
396 | ||
85007c04 DB |
397 | // Perform passes 0 through 4 using a compile server? |
398 | if (! s.specified_servers.empty ()) | |
399 | { | |
0d1534e8 | 400 | #if HAVE_NSS |
85007c04 | 401 | compile_server_client client (s); |
a46f9abe FCE |
402 | int rc = client.passes_0_4 (); |
403 | // Need to give a user a better diagnostic, if she didn't | |
404 | // even ask for a server | |
405 | if (rc && s.automatic_server_mode) { | |
406 | cerr << _("Note: --use-server --unprivileged was selected because of stapusr membership.") << endl; | |
407 | } | |
408 | return rc; | |
0d1534e8 | 409 | #else |
2713ea24 | 410 | s.print_warning("Without NSS, using a compile-server is not supported by this version of systemtap"); |
3e1ec884 DB |
411 | // This cannot be an attempt to use a server after a local compile failed |
412 | // since --use-server-on-error is locked to 'no' if we don't have | |
413 | // NSS. | |
414 | assert (! s.try_server ()); | |
0d1534e8 | 415 | #endif |
85007c04 DB |
416 | } |
417 | ||
418 | // PASS 0: setting up | |
419 | s.verbose = s.perpass_verbose[0]; | |
0f5d597d | 420 | PROBE1(stap, pass0__start, &s); |
85007c04 | 421 | |
85007c04 DB |
422 | // For PR1477, we used to override $PATH and $LC_ALL and other stuff |
423 | // here. We seem to use complete pathnames in | |
424 | // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further, | |
425 | // it interferes with util.cxx:find_executable(), used for $PATH | |
426 | // resolution. | |
427 | ||
428 | s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-')); | |
429 | ||
05fb3e0c WF |
430 | // Update various paths to include the sysroot, if provided. |
431 | if (!s.sysroot.empty()) | |
432 | { | |
433 | if (s.update_release_sysroot && !s.sysroot.empty()) | |
434 | s.kernel_build_tree = s.sysroot + s.kernel_build_tree; | |
435 | debuginfo_path_insert_sysroot(s.sysroot); | |
436 | } | |
437 | ||
85007c04 | 438 | // Now that no further changes to s.kernel_build_tree can occur, let's use it. |
44edbcd6 JS |
439 | if ((rc = parse_kernel_config (s)) != 0) |
440 | { | |
441 | // Try again with a server | |
442 | s.set_try_server (); | |
443 | return rc; | |
444 | } | |
85007c04 | 445 | |
44edbcd6 JS |
446 | if ((rc = parse_kernel_exports (s)) != 0) |
447 | { | |
448 | // Try again with a server | |
449 | s.set_try_server (); | |
450 | return rc; | |
451 | } | |
85007c04 DB |
452 | |
453 | // Create the name of the C source file within the temporary | |
a4b9c3b3 FCE |
454 | // directory. Note the _src prefix, explained in |
455 | // buildrun.cxx:compile_pass() | |
456 | s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c"; | |
85007c04 | 457 | |
0f5d597d | 458 | PROBE1(stap, pass0__end, &s); |
85007c04 DB |
459 | |
460 | struct tms tms_before; | |
461 | times (& tms_before); | |
462 | struct timeval tv_before; | |
463 | gettimeofday (&tv_before, NULL); | |
464 | ||
e7c60c35 | 465 | // PASS 1a: PARSING LIBRARY SCRIPTS |
0f5d597d | 466 | PROBE1(stap, pass1a__start, &s); |
85007c04 | 467 | |
e7c60c35 SM |
468 | // We need to handle the library scripts first because this pass |
469 | // gathers information on .stpm files that might be needed to | |
470 | // parse the user script. | |
471 | ||
472 | // We need to first ascertain the status of the user script, though. | |
85007c04 DB |
473 | struct stat user_file_stat; |
474 | int user_file_stat_rc = -1; | |
475 | ||
476 | if (s.script_file == "-") | |
477 | { | |
85007c04 DB |
478 | user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat); |
479 | } | |
480 | else if (s.script_file != "") | |
481 | { | |
85007c04 DB |
482 | user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat); |
483 | } | |
e7c60c35 | 484 | // otherwise, rc is 0 for a command line script |
f705da87 | 485 | |
85007c04 | 486 | vector<string> version_suffixes; |
f705da87 JS |
487 | if (s.runtime_mode == systemtap_session::kernel_runtime) |
488 | { | |
489 | // Construct kernel-versioning search path | |
490 | string kvr = s.kernel_release; | |
491 | ||
492 | // add full kernel-version-release (2.6.NN-FOOBAR) | |
493 | version_suffixes.push_back ("/" + kvr); | |
494 | ||
495 | // add kernel version (2.6.NN) | |
496 | if (kvr != s.kernel_base_release) | |
497 | { | |
498 | kvr = s.kernel_base_release; | |
499 | version_suffixes.push_back ("/" + kvr); | |
500 | } | |
501 | ||
502 | // add kernel family (2.6) | |
503 | string::size_type dot1_index = kvr.find ('.'); | |
504 | string::size_type dot2_index = kvr.rfind ('.'); | |
505 | while (dot2_index > dot1_index && dot2_index != string::npos) | |
506 | { | |
507 | kvr.erase(dot2_index); | |
508 | version_suffixes.push_back ("/" + kvr); | |
509 | dot2_index = kvr.rfind ('.'); | |
510 | } | |
511 | } | |
512 | ||
85007c04 DB |
513 | // add empty string as last element |
514 | version_suffixes.push_back (""); | |
515 | ||
f705da87 JS |
516 | // Add arch variants of every path, just before each |
517 | const string& arch = s.architecture; | |
518 | for (unsigned i=0; i<version_suffixes.size(); i+=2) | |
519 | version_suffixes.insert(version_suffixes.begin() + i, | |
520 | version_suffixes[i] + "/" + arch); | |
521 | ||
522 | // Add runtime variants of every path, before everything else | |
523 | string runtime_prefix; | |
524 | if (s.runtime_mode == systemtap_session::kernel_runtime) | |
525 | runtime_prefix = "/linux"; | |
526 | else if (s.runtime_mode == systemtap_session::dyninst_runtime) | |
527 | runtime_prefix = "/dyninst"; | |
528 | if (!runtime_prefix.empty()) | |
529 | for (unsigned i=0; i<version_suffixes.size(); i+=2) | |
530 | version_suffixes.insert(version_suffixes.begin() + i/2, | |
531 | runtime_prefix + version_suffixes[i]); | |
85007c04 | 532 | |
ad7c8e43 FCE |
533 | set<pair<dev_t, ino_t> > seen_library_files; |
534 | ||
e7c60c35 | 535 | // TODOXXX gather a list of .stpm file paths using a similar method |
85007c04 DB |
536 | for (unsigned i=0; i<s.include_path.size(); i++) |
537 | { | |
538 | // now iterate upon it | |
539 | for (unsigned k=0; k<version_suffixes.size(); k++) | |
540 | { | |
541 | glob_t globbuf; | |
542 | string dir = s.include_path[i] + version_suffixes[k] + "/*.stp"; | |
543 | int r = glob(dir.c_str (), 0, NULL, & globbuf); | |
544 | if (r == GLOB_NOSPACE || r == GLOB_ABORTED) | |
3e1ec884 | 545 | rc ++; |
44edbcd6 | 546 | // GLOB_NOMATCH is acceptable |
85007c04 | 547 | |
ad7c8e43 | 548 | unsigned prev_s_library_files = s.library_files.size(); |
85007c04 DB |
549 | |
550 | for (unsigned j=0; j<globbuf.gl_pathc; j++) | |
551 | { | |
e19ebcf7 | 552 | assert_no_interrupts(); |
85007c04 | 553 | |
85007c04 DB |
554 | struct stat tapset_file_stat; |
555 | int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat); | |
556 | if (stat_rc == 0 && user_file_stat_rc == 0 && | |
557 | user_file_stat.st_dev == tapset_file_stat.st_dev && | |
558 | user_file_stat.st_ino == tapset_file_stat.st_ino) | |
559 | { | |
79bc39ab | 560 | cerr |
46a1a151 JS |
561 | << _F("usage error: tapset file '%s' cannot be run directly as a session script.", |
562 | globbuf.gl_pathv[j]) << endl; | |
85007c04 DB |
563 | rc ++; |
564 | } | |
565 | ||
ad7c8e43 FCE |
566 | // PR11949: duplicate-eliminate tapset files |
567 | if (stat_rc == 0) | |
568 | { | |
569 | pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev, | |
570 | tapset_file_stat.st_ino); | |
571 | if (seen_library_files.find(here) != seen_library_files.end()) | |
572 | continue; | |
573 | seen_library_files.insert (here); | |
574 | } | |
575 | ||
576 | // XXX: privilege only for /usr/share/systemtap? | |
577 | stapfile* f = parse (s, globbuf.gl_pathv[j], true); | |
2713ea24 | 578 | if (f == 0) |
ad7c8e43 FCE |
579 | s.print_warning("tapset '" + string(globbuf.gl_pathv[j]) |
580 | + "' has errors, and will be skipped."); | |
581 | else | |
582 | s.library_files.push_back (f); | |
85007c04 DB |
583 | } |
584 | ||
ad7c8e43 FCE |
585 | unsigned next_s_library_files = s.library_files.size(); |
586 | if (s.verbose>1 && globbuf.gl_pathc > 0) | |
ce0f6648 | 587 | //TRANSLATORS: Searching through directories, 'processed' means 'examined so far' |
46a1a151 JS |
588 | clog << _F("Searched: \" %s \", found: %zu, processed: %u", |
589 | dir.c_str(), globbuf.gl_pathc, | |
590 | (next_s_library_files-prev_s_library_files)) << endl; | |
ad7c8e43 | 591 | |
85007c04 DB |
592 | globfree (& globbuf); |
593 | } | |
594 | } | |
595 | if (s.num_errors()) | |
3e1ec884 | 596 | rc ++; |
85007c04 DB |
597 | |
598 | if (rc == 0 && s.last_pass == 1) | |
599 | { | |
79bc39ab | 600 | cout << _("# parse tree dump") << endl; |
85007c04 DB |
601 | s.user_file->print (cout); |
602 | cout << endl; | |
603 | if (s.verbose) | |
604 | for (unsigned i=0; i<s.library_files.size(); i++) | |
605 | { | |
606 | s.library_files[i]->print (cout); | |
607 | cout << endl; | |
608 | } | |
609 | } | |
610 | ||
e7c60c35 SM |
611 | // PASS 1b: PARSING USER SCRIPT |
612 | PROBE1(stap, pass1b__start, &s); | |
613 | ||
614 | if (s.script_file == "-") | |
615 | { | |
616 | s.user_file = parse (s, cin, s.guru_mode); | |
617 | } | |
618 | else if (s.script_file != "") | |
619 | { | |
620 | s.user_file = parse (s, s.script_file, s.guru_mode); | |
621 | } | |
622 | else | |
623 | { | |
624 | istringstream ii (s.cmdline_script); | |
625 | s.user_file = parse (s, ii, s.guru_mode); | |
626 | } | |
627 | if (s.user_file == 0) | |
628 | { | |
629 | // Syntax errors already printed. | |
630 | rc ++; | |
631 | } | |
632 | ||
85007c04 DB |
633 | struct tms tms_after; |
634 | times (& tms_after); | |
635 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
636 | struct timeval tv_after; | |
637 | gettimeofday (&tv_after, NULL); | |
638 | ||
639 | #define TIMESPRINT "in " << \ | |
640 | (tms_after.tms_cutime + tms_after.tms_utime \ | |
641 | - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \ | |
642 | << (tms_after.tms_cstime + tms_after.tms_stime \ | |
643 | - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \ | |
644 | << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \ | |
645 | ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms." | |
646 | ||
647 | // syntax errors, if any, are already printed | |
648 | if (s.verbose) | |
649 | { | |
e7c60c35 | 650 | // XXX also include a count of helper macro files loaded (.stpm)? |
85007c04 DB |
651 | clog << "Pass 1: parsed user script and " |
652 | << s.library_files.size() | |
653 | << " library script(s) " | |
654 | << getmemusage() | |
655 | << TIMESPRINT | |
656 | << endl; | |
657 | } | |
658 | ||
659 | if (rc && !s.listing_mode) | |
79bc39ab LB |
660 | cerr << _("Pass 1: parse failed. Try again with another '--vp 1' option.") << endl; |
661 | //cerr << "Pass 1: parse failed. " | |
662 | // << "Try again with another '--vp 1' option." | |
663 | // << endl; | |
85007c04 | 664 | |
0f5d597d | 665 | PROBE1(stap, pass1__end, &s); |
85007c04 | 666 | |
e19ebcf7 | 667 | assert_no_interrupts(); |
985892de | 668 | if (rc || s.last_pass == 1) return rc; |
85007c04 DB |
669 | |
670 | times (& tms_before); | |
671 | gettimeofday (&tv_before, NULL); | |
672 | ||
673 | // PASS 2: ELABORATION | |
674 | s.verbose = s.perpass_verbose[1]; | |
0f5d597d | 675 | PROBE1(stap, pass2__start, &s); |
85007c04 DB |
676 | rc = semantic_pass (s); |
677 | ||
b82d77b4 DB |
678 | // Dump a list of known probe point types, if requested. |
679 | if (s.dump_probe_types) | |
680 | s.pattern_root->dump (s); | |
681 | ||
85007c04 DB |
682 | if (s.listing_mode || (rc == 0 && s.last_pass == 2)) |
683 | printscript(s, cout); | |
684 | ||
685 | times (& tms_after); | |
686 | gettimeofday (&tv_after, NULL); | |
687 | ||
688 | if (s.verbose) clog << "Pass 2: analyzed script: " | |
689 | << s.probes.size() << " probe(s), " | |
690 | << s.functions.size() << " function(s), " | |
691 | << s.embeds.size() << " embed(s), " | |
692 | << s.globals.size() << " global(s) " | |
693 | << getmemusage() | |
694 | << TIMESPRINT | |
695 | << endl; | |
696 | ||
44edbcd6 | 697 | if (rc && !s.listing_mode && !s.try_server ()) |
3e1ec884 | 698 | cerr << _("Pass 2: analysis failed. Try again with another '--vp 01' option.") << endl; |
79bc39ab LB |
699 | //cerr << "Pass 2: analysis failed. " |
700 | // << "Try again with another '--vp 01' option." | |
701 | // << endl; | |
85007c04 DB |
702 | |
703 | /* Print out list of missing files. XXX should be "if (rc)" ? */ | |
76c87907 | 704 | missing_rpm_list_print(s,"-debuginfo"); |
85007c04 | 705 | |
0f5d597d | 706 | PROBE1(stap, pass2__end, &s); |
85007c04 | 707 | |
e19ebcf7 | 708 | assert_no_interrupts(); |
985892de | 709 | if (rc || s.listing_mode || s.last_pass == 2) return rc; |
85007c04 | 710 | |
d13bcfd8 | 711 | rc = prepare_translate_pass (s); |
e19ebcf7 | 712 | assert_no_interrupts(); |
985892de | 713 | if (rc) return rc; |
d13bcfd8 | 714 | |
85007c04 DB |
715 | // Generate hash. There isn't any point in generating the hash |
716 | // if last_pass is 2, since we'll quit before using it. | |
717 | if (s.use_script_cache) | |
718 | { | |
719 | ostringstream o; | |
720 | unsigned saved_verbose; | |
721 | ||
722 | { | |
723 | // Make sure we're in verbose mode, so that printscript() | |
724 | // will output function/probe bodies. | |
725 | saved_verbose = s.verbose; | |
726 | s.verbose = 3; | |
727 | printscript(s, o); // Print script to 'o' | |
728 | s.verbose = saved_verbose; | |
729 | } | |
730 | ||
731 | // Generate hash | |
732 | find_script_hash (s, o.str()); | |
733 | ||
734 | // See if we can use cached source/module. | |
735 | if (get_script_from_cache(s)) | |
736 | { | |
7d26ee02 JS |
737 | // We may still need to build uprobes, if it's not also cached. |
738 | if (s.need_uprobes) | |
739 | rc = uprobes_pass(s); | |
740 | ||
85007c04 DB |
741 | // If our last pass isn't 5, we're done (since passes 3 and |
742 | // 4 just generate what we just pulled out of the cache). | |
e19ebcf7 | 743 | assert_no_interrupts(); |
985892de | 744 | if (rc || s.last_pass < 5) return rc; |
85007c04 DB |
745 | |
746 | // Short-circuit to pass 5. | |
747 | return 0; | |
748 | } | |
749 | } | |
750 | ||
751 | // PASS 3: TRANSLATION | |
752 | s.verbose = s.perpass_verbose[2]; | |
753 | times (& tms_before); | |
754 | gettimeofday (&tv_before, NULL); | |
0f5d597d | 755 | PROBE1(stap, pass3__start, &s); |
85007c04 DB |
756 | |
757 | rc = translate_pass (s); | |
3e1ec884 | 758 | if (! rc && s.last_pass == 3) |
85007c04 DB |
759 | { |
760 | ifstream i (s.translated_source.c_str()); | |
761 | cout << i.rdbuf(); | |
762 | } | |
763 | ||
764 | times (& tms_after); | |
765 | gettimeofday (&tv_after, NULL); | |
766 | ||
79bc39ab LB |
767 | if (s.verbose) |
768 | clog << "Pass 3: translated to C into \"" | |
769 | << s.translated_source | |
770 | << "\" " | |
771 | << getmemusage() | |
772 | << TIMESPRINT | |
85007c04 DB |
773 | << endl; |
774 | ||
44edbcd6 | 775 | if (rc && ! s.try_server ()) |
79bc39ab LB |
776 | cerr << _("Pass 3: translation failed. Try again with another '--vp 001' option.") << endl; |
777 | //cerr << "Pass 3: translation failed. " | |
778 | // << "Try again with another '--vp 001' option." | |
779 | // << endl; | |
780 | ||
0f5d597d | 781 | PROBE1(stap, pass3__end, &s); |
85007c04 | 782 | |
e19ebcf7 | 783 | assert_no_interrupts(); |
985892de | 784 | if (rc || s.last_pass == 3) return rc; |
85007c04 DB |
785 | |
786 | // PASS 4: COMPILATION | |
787 | s.verbose = s.perpass_verbose[3]; | |
788 | times (& tms_before); | |
789 | gettimeofday (&tv_before, NULL); | |
0f5d597d | 790 | PROBE1(stap, pass4__start, &s); |
85007c04 DB |
791 | |
792 | if (s.use_cache) | |
793 | { | |
794 | find_stapconf_hash(s); | |
795 | get_stapconf_from_cache(s); | |
796 | } | |
797 | rc = compile_pass (s); | |
3e1ec884 | 798 | if (! rc && s.last_pass == 4) |
85007c04 | 799 | { |
4441e344 | 800 | cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path); |
85007c04 DB |
801 | cout << endl; |
802 | } | |
803 | ||
804 | times (& tms_after); | |
805 | gettimeofday (&tv_after, NULL); | |
806 | ||
807 | if (s.verbose) clog << "Pass 4: compiled C into \"" | |
4441e344 | 808 | << s.module_filename() |
85007c04 DB |
809 | << "\" " |
810 | << TIMESPRINT | |
811 | << endl; | |
812 | ||
44edbcd6 | 813 | if (rc && ! s.try_server ()) |
79bc39ab LB |
814 | cerr << _("Pass 4: compilation failed. Try again with another '--vp 0001' option.") << endl; |
815 | //cerr << "Pass 4: compilation failed. " | |
816 | // << "Try again with another '--vp 0001' option." | |
817 | // << endl; | |
85007c04 DB |
818 | else |
819 | { | |
820 | // Update cache. Cache cleaning is kicked off at the beginning of this function. | |
821 | if (s.use_script_cache) | |
822 | add_script_to_cache(s); | |
4441e344 | 823 | if (s.use_cache && !s.is_usermode()) |
85007c04 DB |
824 | add_stapconf_to_cache(s); |
825 | ||
826 | // We may need to save the module in $CWD if the cache was | |
827 | // inaccessible for some reason. | |
828 | if (! s.use_script_cache && s.last_pass == 4) | |
829 | s.save_module = true; | |
830 | ||
831 | // Copy module to the current directory. | |
832 | if (s.save_module && !pending_interrupts) | |
833 | { | |
4441e344 JS |
834 | string module_src_path = s.tmpdir + "/" + s.module_filename(); |
835 | string module_dest_path = s.module_filename(); | |
85007c04 DB |
836 | copy_file(module_src_path, module_dest_path, s.verbose > 1); |
837 | } | |
838 | } | |
839 | ||
0f5d597d | 840 | PROBE1(stap, pass4__end, &s); |
85007c04 DB |
841 | |
842 | return rc; | |
843 | } | |
844 | ||
845 | static int | |
ebff2ed0 | 846 | pass_5 (systemtap_session &s, vector<remote*> targets) |
85007c04 DB |
847 | { |
848 | // PASS 5: RUN | |
849 | s.verbose = s.perpass_verbose[4]; | |
850 | struct tms tms_before; | |
851 | times (& tms_before); | |
852 | struct timeval tv_before; | |
853 | gettimeofday (&tv_before, NULL); | |
854 | // NB: this message is a judgement call. The other passes don't emit | |
855 | // a "hello, I'm starting" message, but then the others aren't interactive | |
856 | // and don't take an indefinite amount of time. | |
0f5d597d | 857 | PROBE1(stap, pass5__start, &s); |
79bc39ab | 858 | if (s.verbose) clog << _("Pass 5: starting run.") << endl; |
4f244435 | 859 | int rc = remote::run(targets); |
85007c04 DB |
860 | struct tms tms_after; |
861 | times (& tms_after); | |
862 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
863 | struct timeval tv_after; | |
864 | gettimeofday (&tv_after, NULL); | |
865 | if (s.verbose) clog << "Pass 5: run completed " | |
866 | << TIMESPRINT | |
867 | << endl; | |
868 | ||
869 | if (rc) | |
79bc39ab LB |
870 | cerr << _("Pass 5: run failed. Try again with another '--vp 00001' option.") << endl; |
871 | //cerr << "Pass 5: run failed. " | |
872 | // << "Try again with another '--vp 00001' option." | |
873 | // << endl; | |
85007c04 DB |
874 | else |
875 | // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below. | |
876 | pending_interrupts = 0; | |
877 | ||
0f5d597d | 878 | PROBE1(stap, pass5__end, &s); |
85007c04 DB |
879 | |
880 | return rc; | |
881 | } | |
882 | ||
883 | static void | |
884 | cleanup (systemtap_session &s, int rc) | |
885 | { | |
886 | // PASS 6: cleaning up | |
0f5d597d | 887 | PROBE1(stap, pass6__start, &s); |
85007c04 | 888 | |
ebff2ed0 JS |
889 | for (systemtap_session::session_map_t::iterator it = s.subsessions.begin(); |
890 | it != s.subsessions.end(); ++it) | |
891 | cleanup (*it->second, rc); | |
892 | ||
85007c04 DB |
893 | // update the database information |
894 | if (!rc && s.tapset_compile_coverage && !pending_interrupts) { | |
895 | #ifdef HAVE_LIBSQLITE3 | |
896 | update_coverage_db(s); | |
897 | #else | |
79bc39ab | 898 | cerr << _("Coverage database not available without libsqlite3") << endl; |
85007c04 DB |
899 | #endif |
900 | } | |
901 | ||
0f5d597d | 902 | PROBE1(stap, pass6__end, &s); |
85007c04 DB |
903 | } |
904 | ||
44edbcd6 JS |
905 | static int |
906 | passes_0_4_again_with_server (systemtap_session &s) | |
907 | { | |
908 | // Not a server and not already using a server. | |
909 | assert (! s.client_options); | |
910 | assert (s.specified_servers.empty ()); | |
911 | ||
912 | // Specify default server(s). | |
913 | s.specified_servers.push_back (""); | |
914 | ||
b96901b7 CM |
915 | // Reset the previous temporary directory and start fresh |
916 | s.reset_tmp_dir(); | |
44edbcd6 JS |
917 | |
918 | // Try to compile again, using the server | |
b5f561be | 919 | clog << _("Attempting compilation using a compile server") |
44edbcd6 | 920 | << endl; |
b96901b7 | 921 | |
44edbcd6 JS |
922 | int rc = passes_0_4 (s); |
923 | return rc; | |
924 | } | |
925 | ||
85007c04 DB |
926 | int |
927 | main (int argc, char * const argv []) | |
928 | { | |
929 | // Initialize defaults. | |
b96901b7 | 930 | try { |
891043f0 CM |
931 | systemtap_session s; |
932 | ||
933 | setlocale (LC_ALL, ""); | |
934 | bindtextdomain (PACKAGE, LOCALEDIR); | |
935 | textdomain (PACKAGE); | |
936 | ||
937 | // Set up our handler to catch routine signals, to allow clean | |
938 | // and reasonably timely exit. | |
939 | setup_signals(&handle_interrupt); | |
940 | ||
941 | // PR13520: Parse $SYSTEMTAP_DIR/rc for extra options | |
942 | string rc_file = s.data_path + "/rc"; | |
943 | ifstream rcf (rc_file.c_str()); | |
944 | string rcline; | |
945 | wordexp_t words; | |
946 | memset (& words, 0, sizeof(words)); | |
947 | int rc = 0; | |
948 | int linecount = 0; | |
949 | while (getline (rcf, rcline)) | |
950 | { | |
951 | rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF| | |
952 | (linecount > 0 ? WRDE_APPEND : 0)); | |
953 | // NB: WRDE_APPEND automagically reallocates words.* as more options are added. | |
954 | linecount ++; | |
955 | if (rc) break; | |
956 | } | |
957 | int extended_argc = words.we_wordc + argc; | |
958 | char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*)); | |
959 | if (rc || !extended_argv) | |
960 | { | |
961 | clog << _F("Error processing extra options in %s", rc_file.c_str()); | |
962 | exit (1); | |
963 | } | |
964 | // Copy over the arguments *by reference*, first the ones from the rc file. | |
965 | char **p = & extended_argv[0]; | |
966 | *p++ = argv[0]; | |
967 | for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i]; | |
968 | for (int j=1; j<argc; j++) *p++ = argv[j]; | |
969 | *p++ = NULL; | |
970 | ||
971 | // Process the command line. | |
972 | rc = s.parse_cmdline (extended_argc, extended_argv); | |
973 | if (rc != 0) | |
974 | exit (rc); | |
975 | ||
976 | if (words.we_wordc > 0 && s.verbose > 1) | |
977 | clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc); | |
978 | ||
979 | // Check for options conflicts. Exits if errors are detected. | |
980 | s.check_options (extended_argc, extended_argv); | |
981 | ||
982 | // We don't need these strings any more. | |
983 | wordfree (& words); | |
984 | free (extended_argv); | |
985 | ||
986 | // arguments parsed; get down to business | |
987 | if (s.verbose > 1) | |
988 | s.version (); | |
989 | ||
990 | // Need to send the verbose message here, rather than in the session ctor, since | |
991 | // we didn't know if verbose was set. | |
992 | if (rc == 0 && s.verbose>1) | |
993 | clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl; | |
994 | ||
995 | // Prepare connections for each specified remote target. | |
996 | vector<remote*> targets; | |
997 | bool fake_remote=false; | |
998 | if (s.remote_uris.empty()) | |
999 | { | |
1000 | fake_remote=true; | |
1001 | s.remote_uris.push_back("direct:"); | |
1002 | } | |
1003 | for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i) | |
1004 | { | |
1005 | // PR13354: pass remote id#/url only in non --remote=HOST cases | |
1006 | remote *target = remote::create(s, s.remote_uris[i], | |
1007 | fake_remote ? -1 : (int)i); | |
1008 | if (target) | |
1009 | targets.push_back(target); | |
1010 | else | |
1011 | rc = 1; | |
1012 | } | |
3a97e514 | 1013 | |
891043f0 CM |
1014 | // Discover and loop over each unique session created by the remote targets. |
1015 | set<systemtap_session*> sessions; | |
1016 | for (unsigned i = 0; i < targets.size(); ++i) | |
1017 | sessions.insert(targets[i]->get_session()); | |
1018 | for (set<systemtap_session*>::iterator it = sessions.begin(); | |
1019 | rc == 0 && !pending_interrupts && it != sessions.end(); ++it) | |
1020 | { | |
1021 | systemtap_session& ss = **it; | |
1022 | if (ss.verbose > 1) | |
1023 | clog << _F("Session arch: %s release: %s", | |
1024 | ss.architecture.c_str(), ss.kernel_release.c_str()) << endl; | |
85007c04 | 1025 | |
c4fd15b4 | 1026 | #if HAVE_NSS |
891043f0 CM |
1027 | // If requested, query server status. This is independent of other tasks. |
1028 | query_server_status (ss); | |
85007c04 | 1029 | |
891043f0 CM |
1030 | // If requested, manage trust of servers. This is independent of other tasks. |
1031 | manage_server_trust (ss); | |
c4fd15b4 | 1032 | #endif |
ebff2ed0 | 1033 | |
891043f0 CM |
1034 | // Run the passes only if a script has been specified. The requirement for |
1035 | // a script has already been checked in systemtap_session::check_options. | |
1036 | // Run the passes also if a dump of supported probe types has been requested via a server. | |
1037 | if (ss.have_script || (ss.dump_probe_types && ! s.specified_servers.empty ())) | |
1038 | { | |
1039 | // Run passes 0-4 for each unique session, | |
1040 | // either locally or using a compile-server. | |
1041 | ss.init_try_server (); | |
1042 | if ((rc = passes_0_4 (ss))) | |
1043 | { | |
1044 | // Compilation failed. | |
1045 | // Try again using a server if appropriate. | |
1046 | if (ss.try_server ()) | |
1047 | rc = passes_0_4_again_with_server (ss); | |
1048 | } | |
1049 | } | |
1050 | else if (ss.dump_probe_types) | |
1051 | { | |
1052 | // Dump a list of known probe point types, if requested. | |
1053 | register_standard_tapsets(ss); | |
1054 | ss.pattern_root->dump (ss); | |
1055 | } | |
1056 | } | |
3a97e514 | 1057 | |
891043f0 CM |
1058 | // Run pass 5, if requested |
1059 | if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts) | |
1060 | rc = pass_5 (s, targets); | |
85007c04 | 1061 | |
891043f0 CM |
1062 | // Pass 6. Cleanup |
1063 | for (unsigned i = 0; i < targets.size(); ++i) | |
1064 | delete targets[i]; | |
1065 | cleanup (s, rc); | |
b96901b7 | 1066 | |
e19ebcf7 | 1067 | assert_no_interrupts(); |
985892de | 1068 | return (rc) ? EXIT_FAILURE : EXIT_SUCCESS; |
b96901b7 | 1069 | } |
8d4072eb | 1070 | catch (const interrupt_exception& e) { |
985892de CM |
1071 | // User entered ctrl-c, exit quietly. |
1072 | exit(EXIT_FAILURE); | |
1073 | } | |
8d4072eb | 1074 | catch (const runtime_error &e) { |
985892de CM |
1075 | // Some other uncaught runtime_error exception. |
1076 | cerr << e.what() << endl; | |
1077 | exit(EXIT_FAILURE); | |
1078 | } | |
1079 | catch (...) { | |
1080 | // Catch all other unknown exceptions. | |
1081 | cerr << _("ERROR: caught unknown exception!") << endl; | |
1082 | exit(EXIT_FAILURE); | |
b96901b7 | 1083 | } |
85007c04 DB |
1084 | } |
1085 | ||
1086 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |