]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // systemtap translator/driver |
4eb12770 | 2 | // Copyright (C) 2005-2016 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" |
9ac12b89 | 28 | #ifdef HAVE_LIBREADLINE |
11a046b7 | 29 | #include "interactive.h" |
9ac12b89 | 30 | #endif |
85007c04 | 31 | |
52c2652f | 32 | #if ENABLE_NLS |
79bc39ab LB |
33 | #include <libintl.h> |
34 | #include <locale.h> | |
52c2652f | 35 | #endif |
79bc39ab | 36 | |
0f5d597d | 37 | #include "stap-probe.h" |
aa4d21c0 | 38 | |
24cb178f | 39 | #include <cstdlib> |
636e55b8 | 40 | #include <thread> |
73267b89 | 41 | |
85007c04 DB |
42 | extern "C" { |
43 | #include <glob.h> | |
44 | #include <unistd.h> | |
45 | #include <signal.h> | |
46 | #include <sys/utsname.h> | |
47 | #include <sys/times.h> | |
48 | #include <sys/time.h> | |
49 | #include <sys/stat.h> | |
50 | #include <time.h> | |
51 | #include <unistd.h> | |
222e16ed | 52 | #include <wordexp.h> |
85007c04 DB |
53 | } |
54 | ||
55 | using namespace std; | |
56 | ||
40a50254 JS |
57 | static void |
58 | uniq_list(list<string>& l) | |
e2012a7a | 59 | { |
40a50254 JS |
60 | set<string> s; |
61 | list<string>::iterator i = l.begin(); | |
62 | while (i != l.end()) | |
63 | if (s.insert(*i).second) | |
64 | ++i; | |
65 | else | |
66 | i = l.erase(i); | |
85007c04 | 67 | } |
2dce8c42 | 68 | |
85007c04 DB |
69 | static void |
70 | printscript(systemtap_session& s, ostream& o) | |
71 | { | |
bba368c5 JL |
72 | if (s.dump_mode == systemtap_session::dump_matched_probes || |
73 | s.dump_mode == systemtap_session::dump_matched_probes_vars) | |
85007c04 DB |
74 | { |
75 | // We go through some heroic measures to produce clean output. | |
76 | // Record the alias and probe pointer as <name, set<derived_probe *> > | |
77 | map<string,set<derived_probe *> > probe_list; | |
6e683641 | 78 | |
85007c04 DB |
79 | // Pre-process the probe alias |
80 | for (unsigned i=0; i<s.probes.size(); i++) | |
81 | { | |
e19ebcf7 | 82 | assert_no_interrupts(); |
85007c04 DB |
83 | |
84 | derived_probe* p = s.probes[i]; | |
ede0102c JS |
85 | vector<probe*> chain; |
86 | p->collect_derivation_chain (chain); | |
87 | ||
8159bf55 | 88 | if (s.verbose > 2) { |
8159bf55 FCE |
89 | p->printsig(cerr); cerr << endl; |
90 | cerr << "chain[" << chain.size() << "]:" << endl; | |
91 | for (unsigned j=0; j<chain.size(); j++) | |
92 | { | |
93 | cerr << " [" << j << "]: " << endl; | |
94 | cerr << "\tlocations[" << chain[j]->locations.size() << "]:" << endl; | |
95 | for (unsigned k=0; k<chain[j]->locations.size(); k++) | |
96 | { | |
97 | cerr << "\t [" << k << "]: "; | |
98 | chain[j]->locations[k]->print(cerr); | |
99 | cerr << endl; | |
100 | } | |
101 | const probe_alias *a = chain[j]->get_alias(); | |
102 | if (a) | |
103 | { | |
104 | cerr << "\taliases[" << a->alias_names.size() << "]:" << endl; | |
105 | for (unsigned k=0; k<a->alias_names.size(); k++) | |
106 | { | |
107 | cerr << "\t [" << k << "]: "; | |
108 | a->alias_names[k]->print(cerr); | |
109 | cerr << endl; | |
110 | } | |
111 | } | |
112 | } | |
7977a734 | 113 | } |
eb55dce6 JS |
114 | |
115 | const string& pp = lex_cast(*p->script_location()); | |
116 | ||
117 | // PR16730: We should only list probes that can be traced back to the | |
118 | // user's spec, not any auxiliary probes in the tapsets. | |
ba48c27a AJ |
119 | // Also, do not want to the probes that are from the additional |
120 | // scripts (-E SCRIPT) to be listed. | |
1ee0d3ba JL |
121 | if (!s.is_primary_probe(p)) |
122 | continue; | |
85007c04 DB |
123 | |
124 | // Now duplicate-eliminate. An alias may have expanded to | |
125 | // several actual derived probe points, but we only want to | |
126 | // print the alias head name once. | |
127 | probe_list[pp].insert(p); | |
128 | } | |
129 | ||
130 | // print probe name and variables if there | |
131 | for (map<string, set<derived_probe *> >::iterator it=probe_list.begin(); it!=probe_list.end(); ++it) | |
132 | { | |
133 | o << it->first; // probe name or alias | |
134 | ||
135 | // Print the locals and arguments for -L mode only | |
bba368c5 | 136 | if (s.dump_mode == systemtap_session::dump_matched_probes_vars) |
85007c04 DB |
137 | { |
138 | map<string,unsigned> var_count; // format <"name:type",count> | |
139 | map<string,unsigned> arg_count; | |
140 | list<string> var_list; | |
141 | list<string> arg_list; | |
142 | // traverse set<derived_probe *> to collect all locals and arguments | |
143 | for (set<derived_probe *>::iterator ix=it->second.begin(); ix!=it->second.end(); ++ix) | |
144 | { | |
145 | derived_probe* p = *ix; | |
146 | // collect available locals of the probe | |
147 | for (unsigned j=0; j<p->locals.size(); j++) | |
148 | { | |
149 | stringstream tmps; | |
150 | vardecl* v = p->locals[j]; | |
151 | v->printsig (tmps); | |
152 | var_count[tmps.str()]++; | |
153 | var_list.push_back(tmps.str()); | |
154 | } | |
155 | // collect arguments of the probe if there | |
156 | list<string> arg_set; | |
157 | p->getargs(arg_set); | |
158 | for (list<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) { | |
159 | arg_count[*ia]++; | |
160 | arg_list.push_back(*ia); | |
161 | } | |
162 | } | |
163 | ||
164 | uniq_list(arg_list); | |
165 | uniq_list(var_list); | |
166 | ||
167 | // print the set-intersection only | |
168 | for (list<string>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir) | |
169 | if (var_count.find(*ir)->second == it->second.size()) // print locals | |
170 | o << " " << *ir; | |
171 | for (list<string>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir) | |
172 | if (arg_count.find(*ir)->second == it->second.size()) // print arguments | |
173 | o << " " << *ir; | |
174 | } | |
175 | o << endl; | |
176 | } | |
177 | } | |
178 | else | |
2dce8c42 | 179 | { |
85007c04 | 180 | if (s.embeds.size() > 0) |
79bc39ab | 181 | o << _("# global embedded code") << endl; |
85007c04 DB |
182 | for (unsigned i=0; i<s.embeds.size(); i++) |
183 | { | |
e19ebcf7 | 184 | assert_no_interrupts(); |
85007c04 DB |
185 | embeddedcode* ec = s.embeds[i]; |
186 | ec->print (o); | |
187 | o << endl; | |
188 | } | |
2dce8c42 | 189 | |
85007c04 | 190 | if (s.globals.size() > 0) |
79bc39ab | 191 | o << _("# globals") << endl; |
85007c04 DB |
192 | for (unsigned i=0; i<s.globals.size(); i++) |
193 | { | |
e19ebcf7 | 194 | assert_no_interrupts(); |
85007c04 DB |
195 | vardecl* v = s.globals[i]; |
196 | v->printsig (o); | |
197 | if (s.verbose && v->init) | |
198 | { | |
199 | o << " = "; | |
200 | v->init->print(o); | |
201 | } | |
202 | o << endl; | |
203 | } | |
204 | ||
205 | if (s.functions.size() > 0) | |
79bc39ab | 206 | o << _("# functions") << endl; |
85007c04 DB |
207 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
208 | { | |
e19ebcf7 | 209 | assert_no_interrupts(); |
85007c04 DB |
210 | functiondecl* f = it->second; |
211 | f->printsig (o); | |
212 | o << endl; | |
213 | if (f->locals.size() > 0) | |
79bc39ab | 214 | o << _(" # locals") << endl; |
85007c04 DB |
215 | for (unsigned j=0; j<f->locals.size(); j++) |
216 | { | |
217 | vardecl* v = f->locals[j]; | |
218 | o << " "; | |
219 | v->printsig (o); | |
220 | o << endl; | |
221 | } | |
222 | if (s.verbose) | |
223 | { | |
224 | f->body->print (o); | |
225 | o << endl; | |
226 | } | |
227 | } | |
228 | ||
229 | if (s.probes.size() > 0) | |
79bc39ab | 230 | o << _("# probes") << endl; |
85007c04 DB |
231 | for (unsigned i=0; i<s.probes.size(); i++) |
232 | { | |
e19ebcf7 | 233 | assert_no_interrupts(); |
85007c04 DB |
234 | derived_probe* p = s.probes[i]; |
235 | p->printsig (o); | |
236 | o << endl; | |
237 | if (p->locals.size() > 0) | |
79bc39ab | 238 | o << _(" # locals") << endl; |
85007c04 DB |
239 | for (unsigned j=0; j<p->locals.size(); j++) |
240 | { | |
241 | vardecl* v = p->locals[j]; | |
242 | o << " "; | |
243 | v->printsig (o); | |
244 | o << endl; | |
245 | } | |
246 | if (s.verbose) | |
247 | { | |
248 | p->body->print (o); | |
249 | o << endl; | |
250 | } | |
251 | } | |
2dce8c42 | 252 | } |
85007c04 | 253 | } |
e2012a7a | 254 | |
e2012a7a | 255 | |
85007c04 DB |
256 | int pending_interrupts; |
257 | ||
258 | extern "C" | |
dabd71bb | 259 | void handle_interrupt (int) |
85007c04 | 260 | { |
c9c8c406 JS |
261 | // This might be nice, but we don't know our current verbosity... |
262 | // clog << _F("Received signal %d", sig) << endl << flush; | |
878b2f3f CM |
263 | kill_stap_spawn(SIGTERM); |
264 | ||
85007c04 | 265 | pending_interrupts ++; |
536a1b69 FCE |
266 | // Absorb the first two signals. This used to be one, but when |
267 | // stap is run under sudo, and then interrupted, sudo relays a | |
268 | // redundant copy of the signal to stap, leading to an unclean shutdown. | |
269 | if (pending_interrupts > 2) // XXX: should be configurable? time-based? | |
85007c04 DB |
270 | { |
271 | char msg[] = "Too many interrupts received, exiting.\n"; | |
272 | int rc = write (2, msg, sizeof(msg)-1); | |
273 | if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;} | |
274 | _exit (1); | |
275 | } | |
276 | } | |
277 | ||
278 | ||
279 | void | |
280 | setup_signals (sighandler_t handler) | |
281 | { | |
282 | struct sigaction sa; | |
283 | ||
11c6c509 | 284 | memset(&sa, 0, sizeof(sa)); |
85007c04 DB |
285 | sa.sa_handler = handler; |
286 | sigemptyset (&sa.sa_mask); | |
287 | if (handler != SIG_IGN) | |
288 | { | |
289 | sigaddset (&sa.sa_mask, SIGHUP); | |
290 | sigaddset (&sa.sa_mask, SIGPIPE); | |
291 | sigaddset (&sa.sa_mask, SIGINT); | |
292 | sigaddset (&sa.sa_mask, SIGTERM); | |
5ed19be2 DB |
293 | sigaddset (&sa.sa_mask, SIGXFSZ); |
294 | sigaddset (&sa.sa_mask, SIGXCPU); | |
85007c04 DB |
295 | } |
296 | sa.sa_flags = SA_RESTART; | |
297 | ||
298 | sigaction (SIGHUP, &sa, NULL); | |
299 | sigaction (SIGPIPE, &sa, NULL); | |
300 | sigaction (SIGINT, &sa, NULL); | |
301 | sigaction (SIGTERM, &sa, NULL); | |
5ed19be2 DB |
302 | sigaction (SIGXFSZ, &sa, NULL); |
303 | sigaction (SIGXCPU, &sa, NULL); | |
e2012a7a | 304 | } |
6e683641 | 305 | |
85007c04 | 306 | |
636e55b8 JS |
307 | static void |
308 | sdt_benchmark_thread(unsigned long i) | |
3d0a328d | 309 | { |
26d48584 | 310 | PROBE(stap, benchmark__thread__start); |
3d0a328d | 311 | while (i--) |
bc7f17fb | 312 | PROBE1(stap, benchmark, i); |
f8e839e8 | 313 | PROBE(stap, benchmark__thread__end); |
3d0a328d JS |
314 | } |
315 | ||
316 | ||
317 | static int | |
318 | run_sdt_benchmark(systemtap_session& s) | |
319 | { | |
320 | unsigned long loops = s.benchmark_sdt_loops ?: 10000000; | |
321 | unsigned long threads = s.benchmark_sdt_threads ?: 1; | |
322 | ||
a7160c2b JS |
323 | if (s.verbose > 0) |
324 | clog << _F("Beginning SDT benchmark with %lu loops in %lu threads.", | |
325 | loops, threads) << endl; | |
3d0a328d JS |
326 | |
327 | struct tms tms_before, tms_after; | |
328 | struct timeval tv_before, tv_after; | |
329 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
330 | times (& tms_before); | |
331 | gettimeofday (&tv_before, NULL); | |
332 | ||
26d48584 | 333 | PROBE(stap, benchmark__start); |
636e55b8 JS |
334 | { |
335 | vector<thread> handles; | |
336 | for (unsigned long i = 0; i < threads; ++i) | |
337 | handles.push_back(thread(sdt_benchmark_thread, loops)); | |
338 | for (unsigned long i = 0; i < threads; ++i) | |
339 | handles[i].join(); | |
340 | } | |
f8e839e8 | 341 | PROBE(stap, benchmark__end); |
bc7f17fb | 342 | |
3d0a328d JS |
343 | times (& tms_after); |
344 | gettimeofday (&tv_after, NULL); | |
a7160c2b JS |
345 | if (s.verbose > 0) |
346 | clog << _F("Completed SDT benchmark in %ldusr/%ldsys/%ldreal ms.", | |
561d4ebd FCE |
347 | (long)(tms_after.tms_utime - tms_before.tms_utime) * 1000 / _sc_clk_tck, |
348 | (long)(tms_after.tms_stime - tms_before.tms_stime) * 1000 / _sc_clk_tck, | |
349 | (long)((tv_after.tv_sec - tv_before.tv_sec) * 1000 + | |
a7160c2b JS |
350 | ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000)) |
351 | << endl; | |
3d0a328d JS |
352 | |
353 | return EXIT_SUCCESS; | |
354 | } | |
355 | ||
356 | ||
44edbcd6 | 357 | // Compilation passes 0 through 4 |
11a046b7 | 358 | int |
85007c04 DB |
359 | passes_0_4 (systemtap_session &s) |
360 | { | |
361 | int rc = 0; | |
daa75206 | 362 | |
504d2b61 JS |
363 | // If we don't know the release, there's no hope either locally or on a server. |
364 | if (s.kernel_release.empty()) | |
365 | { | |
366 | if (s.kernel_build_tree.empty()) | |
367 | cerr << _("ERROR: kernel release isn't specified") << endl; | |
368 | else | |
46a1a151 JS |
369 | cerr << _F("ERROR: kernel release isn't found in \"%s\"", |
370 | s.kernel_build_tree.c_str()) << endl; | |
504d2b61 JS |
371 | return 1; |
372 | } | |
373 | ||
85007c04 DB |
374 | // Perform passes 0 through 4 using a compile server? |
375 | if (! s.specified_servers.empty ()) | |
376 | { | |
0d1534e8 | 377 | #if HAVE_NSS |
85007c04 | 378 | compile_server_client client (s); |
4e78c716 | 379 | return client.passes_0_4 (); |
0d1534e8 | 380 | #else |
4e78c716 DB |
381 | s.print_warning(_("Without NSS, using a compile-server is not supported by this version of systemtap")); |
382 | ||
3e1ec884 DB |
383 | // This cannot be an attempt to use a server after a local compile failed |
384 | // since --use-server-on-error is locked to 'no' if we don't have | |
385 | // NSS. | |
386 | assert (! s.try_server ()); | |
4e78c716 | 387 | s.print_warning(_("Ignoring --use-server")); |
0d1534e8 | 388 | #endif |
85007c04 DB |
389 | } |
390 | ||
391 | // PASS 0: setting up | |
392 | s.verbose = s.perpass_verbose[0]; | |
0f5d597d | 393 | PROBE1(stap, pass0__start, &s); |
85007c04 | 394 | |
85007c04 DB |
395 | // For PR1477, we used to override $PATH and $LC_ALL and other stuff |
396 | // here. We seem to use complete pathnames in | |
397 | // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further, | |
398 | // it interferes with util.cxx:find_executable(), used for $PATH | |
399 | // resolution. | |
400 | ||
401 | s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-')); | |
402 | ||
05fb3e0c WF |
403 | // Update various paths to include the sysroot, if provided. |
404 | if (!s.sysroot.empty()) | |
405 | { | |
406 | if (s.update_release_sysroot && !s.sysroot.empty()) | |
407 | s.kernel_build_tree = s.sysroot + s.kernel_build_tree; | |
408 | debuginfo_path_insert_sysroot(s.sysroot); | |
409 | } | |
410 | ||
85007c04 | 411 | // Now that no further changes to s.kernel_build_tree can occur, let's use it. |
d0923e36 NMA |
412 | if (s.runtime_mode == systemtap_session::kernel_runtime) { |
413 | if ((rc = s.parse_kernel_config ()) != 0 | |
414 | || (rc = s.parse_kernel_exports ()) != 0 | |
415 | || (rc = s.parse_kernel_functions ()) != 0) | |
416 | { | |
417 | // Try again with a server | |
418 | s.set_try_server (); | |
419 | return rc; | |
420 | } | |
421 | } | |
85007c04 DB |
422 | |
423 | // Create the name of the C source file within the temporary | |
a4b9c3b3 FCE |
424 | // directory. Note the _src prefix, explained in |
425 | // buildrun.cxx:compile_pass() | |
426 | s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c"; | |
85007c04 | 427 | |
0f5d597d | 428 | PROBE1(stap, pass0__end, &s); |
85007c04 DB |
429 | |
430 | struct tms tms_before; | |
431 | times (& tms_before); | |
432 | struct timeval tv_before; | |
433 | gettimeofday (&tv_before, NULL); | |
434 | ||
e7c60c35 | 435 | // PASS 1a: PARSING LIBRARY SCRIPTS |
0f5d597d | 436 | PROBE1(stap, pass1a__start, &s); |
85007c04 | 437 | |
d53a4bd1 | 438 | if (! s.pass_1a_complete) |
f705da87 | 439 | { |
d53a4bd1 DS |
440 | // We need to handle the library scripts first because this pass |
441 | // gathers information on .stpm files that might be needed to | |
442 | // parse the user script. | |
f705da87 | 443 | |
d53a4bd1 DS |
444 | // We need to first ascertain the status of the user script, though. |
445 | struct stat user_file_stat; | |
446 | int user_file_stat_rc = -1; | |
f705da87 | 447 | |
d53a4bd1 | 448 | if (s.script_file == "-") |
f705da87 | 449 | { |
d53a4bd1 DS |
450 | user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat); |
451 | } | |
452 | else if (s.script_file != "") | |
f705da87 | 453 | { |
d53a4bd1 DS |
454 | user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat); |
455 | } | |
456 | // otherwise, rc is 0 for a command line script | |
f705da87 | 457 | |
d53a4bd1 DS |
458 | vector<string> version_suffixes; |
459 | if (s.runtime_mode == systemtap_session::kernel_runtime) | |
f7a557ae | 460 | { |
d53a4bd1 DS |
461 | // Construct kernel-versioning search path |
462 | string kvr = s.kernel_release; | |
463 | ||
464 | // add full kernel-version-release (2.6.NN-FOOBAR) | |
465 | version_suffixes.push_back ("/" + kvr); | |
466 | ||
467 | // add kernel version (2.6.NN) | |
468 | if (kvr != s.kernel_base_release) | |
469 | { | |
470 | kvr = s.kernel_base_release; | |
471 | version_suffixes.push_back ("/" + kvr); | |
472 | } | |
473 | ||
474 | // add kernel family (2.6) | |
475 | string::size_type dot1_index = kvr.find ('.'); | |
476 | string::size_type dot2_index = kvr.rfind ('.'); | |
477 | while (dot2_index > dot1_index && dot2_index != string::npos) | |
478 | { | |
479 | kvr.erase(dot2_index); | |
480 | version_suffixes.push_back ("/" + kvr); | |
481 | dot2_index = kvr.rfind ('.'); | |
482 | } | |
483 | } | |
484 | ||
485 | // add empty string as last element | |
486 | version_suffixes.push_back (""); | |
487 | ||
488 | // Add arch variants of every path, just before each | |
489 | const string& arch = s.architecture; | |
490 | for (unsigned i=0; i<version_suffixes.size(); i+=2) | |
491 | version_suffixes.insert(version_suffixes.begin() + i, | |
492 | version_suffixes[i] + "/" + arch); | |
493 | ||
494 | // Add runtime variants of every path, before everything else | |
495 | string runtime_prefix; | |
496 | if (s.runtime_mode == systemtap_session::kernel_runtime) | |
497 | runtime_prefix = "/linux"; | |
498 | else if (s.runtime_mode == systemtap_session::dyninst_runtime) | |
499 | runtime_prefix = "/dyninst"; | |
500 | if (!runtime_prefix.empty()) | |
501 | for (unsigned i=0; i<version_suffixes.size(); i+=2) | |
502 | version_suffixes.insert(version_suffixes.begin() + i/2, | |
503 | runtime_prefix + version_suffixes[i]); | |
504 | ||
505 | // First, parse .stpm files on the include path. We need to have the | |
506 | // resulting macro definitions available for parsing library files, | |
507 | // but since .stpm files can consist only of '@define' constructs, | |
508 | // we can parse each one without reference to the others. | |
509 | set<pair<dev_t, ino_t> > seen_library_macro_files; | |
510 | set<string> seen_library_macro_files_names; | |
511 | ||
512 | for (unsigned i=0; i<s.include_path.size(); i++) | |
85007c04 | 513 | { |
d53a4bd1 DS |
514 | // now iterate upon it |
515 | for (unsigned k=0; k<version_suffixes.size(); k++) | |
516 | { | |
517 | glob_t globbuf; | |
518 | string dir = s.include_path[i] + version_suffixes[k] + "/*.stpm"; | |
519 | int r = glob(dir.c_str (), 0, NULL, & globbuf); | |
520 | if (r == GLOB_NOSPACE || r == GLOB_ABORTED) | |
521 | rc ++; | |
522 | // GLOB_NOMATCH is acceptable | |
523 | ||
524 | unsigned prev_s_library_files = s.library_files.size(); | |
525 | ||
526 | for (unsigned j=0; j<globbuf.gl_pathc; j++) | |
527 | { | |
528 | assert_no_interrupts(); | |
529 | ||
530 | struct stat tapset_file_stat; | |
531 | int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat); | |
532 | if (stat_rc == 0 && user_file_stat_rc == 0 && | |
533 | user_file_stat.st_dev == tapset_file_stat.st_dev && | |
534 | user_file_stat.st_ino == tapset_file_stat.st_ino) | |
535 | { | |
536 | cerr | |
537 | << _F("usage error: macro tapset file '%s' cannot be run directly as a session script.", | |
538 | globbuf.gl_pathv[j]) << endl; | |
539 | rc ++; | |
540 | } | |
541 | ||
542 | // PR11949: duplicate-eliminate tapset files | |
543 | if (stat_rc == 0) | |
544 | { | |
545 | pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev, | |
546 | tapset_file_stat.st_ino); | |
547 | if (seen_library_macro_files.find(here) != seen_library_macro_files.end()) | |
548 | { | |
549 | if (s.verbose>2) | |
550 | clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl; | |
551 | continue; | |
552 | } | |
553 | seen_library_macro_files.insert (here); | |
554 | } | |
555 | ||
556 | // PR12443: duplicate-eliminate harder | |
557 | string full_path = globbuf.gl_pathv[j]; | |
558 | string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too | |
559 | if (full_path.size() > tapset_base.size()) | |
560 | { | |
561 | string tail_part = full_path.substr(tapset_base.size()); | |
562 | if (seen_library_macro_files_names.find (tail_part) != seen_library_macro_files_names.end()) | |
563 | { | |
564 | if (s.verbose>2) | |
565 | clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl; | |
566 | continue; | |
567 | } | |
568 | seen_library_macro_files_names.insert (tail_part); | |
569 | } | |
570 | ||
571 | if (s.verbose>2) | |
572 | clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl; | |
573 | ||
574 | stapfile* f = parse_library_macros (s, globbuf.gl_pathv[j]); | |
575 | if (f == 0) | |
576 | s.print_warning(_F("macro tapset \"%s\" has errors, and will be skipped.", string(globbuf.gl_pathv[j]).c_str())); | |
577 | else | |
578 | s.library_files.push_back (f); | |
579 | } | |
580 | ||
581 | unsigned next_s_library_files = s.library_files.size(); | |
582 | if (s.verbose>1 && globbuf.gl_pathc > 0) | |
583 | //TRANSLATORS: Searching through directories, 'processed' means 'examined so far' | |
584 | clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u", | |
585 | dir.c_str(), globbuf.gl_pathc, | |
586 | (next_s_library_files-prev_s_library_files)) << endl; | |
587 | ||
588 | globfree (&globbuf); | |
589 | } | |
590 | } | |
591 | ||
592 | // Next, gather and parse the library files. | |
593 | set<pair<dev_t, ino_t> > seen_library_files; | |
594 | set<string> seen_library_files_names; | |
595 | ||
596 | for (unsigned i=0; i<s.include_path.size(); i++) | |
597 | { | |
598 | unsigned tapset_flags = pf_guru | pf_squash_errors; | |
599 | ||
600 | // The first path is special, as it's the builtin tapset. | |
601 | // Allow all features no matter what s.compatible says. | |
602 | if (i == 0) | |
603 | tapset_flags |= pf_no_compatible; | |
604 | ||
605 | // now iterate upon it | |
606 | for (unsigned k=0; k<version_suffixes.size(); k++) | |
607 | { | |
608 | glob_t globbuf; | |
609 | string dir = s.include_path[i] + version_suffixes[k] + "/*.stp"; | |
610 | int r = glob(dir.c_str (), 0, NULL, & globbuf); | |
611 | if (r == GLOB_NOSPACE || r == GLOB_ABORTED) | |
612 | rc ++; | |
613 | // GLOB_NOMATCH is acceptable | |
614 | ||
615 | unsigned prev_s_library_files = s.library_files.size(); | |
616 | ||
617 | for (unsigned j=0; j<globbuf.gl_pathc; j++) | |
618 | { | |
619 | assert_no_interrupts(); | |
620 | ||
621 | struct stat tapset_file_stat; | |
622 | int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat); | |
623 | if (stat_rc == 0 && user_file_stat_rc == 0 && | |
624 | user_file_stat.st_dev == tapset_file_stat.st_dev && | |
625 | user_file_stat.st_ino == tapset_file_stat.st_ino) | |
626 | { | |
627 | cerr | |
628 | << _F("usage error: tapset file '%s' cannot be run directly as a session script.", | |
629 | globbuf.gl_pathv[j]) << endl; | |
630 | rc ++; | |
631 | } | |
632 | ||
633 | // PR11949: duplicate-eliminate tapset files | |
634 | if (stat_rc == 0) | |
635 | { | |
636 | pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev, | |
637 | tapset_file_stat.st_ino); | |
638 | if (seen_library_files.find(here) != seen_library_files.end()) | |
639 | { | |
640 | if (s.verbose>2) | |
641 | clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl; | |
642 | continue; | |
643 | } | |
644 | seen_library_files.insert (here); | |
645 | } | |
646 | ||
647 | // PR12443: duplicate-eliminate harder | |
648 | string full_path = globbuf.gl_pathv[j]; | |
649 | string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too | |
650 | if (full_path.size() > tapset_base.size()) | |
651 | { | |
652 | string tail_part = full_path.substr(tapset_base.size()); | |
653 | if (seen_library_files_names.find (tail_part) != seen_library_files_names.end()) | |
654 | { | |
655 | if (s.verbose>2) | |
656 | clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl; | |
657 | continue; | |
658 | } | |
659 | seen_library_files_names.insert (tail_part); | |
660 | } | |
661 | ||
662 | if (s.verbose>2) | |
663 | clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl; | |
664 | ||
665 | // NB: we don't need to restrict privilege only for | |
666 | // /usr/share/systemtap, i.e., excluding | |
667 | // user-specified $XDG_DATA_DIRS. That's because | |
668 | // stapdev gets root-equivalent privileges anyway; | |
669 | // stapsys and stapusr use a remote compilation with | |
670 | // a trusted environment, where client-side | |
671 | // $XDG_DATA_DIRS are not passed. | |
672 | ||
673 | stapfile* f = parse (s, globbuf.gl_pathv[j], tapset_flags); | |
674 | if (f == 0) | |
675 | s.print_warning(_F("tapset \"%s\" has errors, and will be skipped", string(globbuf.gl_pathv[j]).c_str())); | |
676 | else | |
677 | s.library_files.push_back (f); | |
678 | } | |
679 | ||
680 | unsigned next_s_library_files = s.library_files.size(); | |
681 | if (s.verbose>1 && globbuf.gl_pathc > 0) | |
682 | //TRANSLATORS: Searching through directories, 'processed' means 'examined so far' | |
683 | clog << _F("Searched: \"%s\", found: %zu, processed: %u", | |
684 | dir.c_str(), globbuf.gl_pathc, | |
685 | (next_s_library_files-prev_s_library_files)) << endl; | |
686 | ||
687 | globfree (& globbuf); | |
688 | } | |
689 | } | |
690 | if (s.num_errors()) | |
691 | rc ++; | |
692 | ||
693 | // Now that we've made it through pass 1a, remember this so we | |
694 | // don't have to do this again in interactive mode. This doesn't | |
695 | // effect non-interactive mode. | |
696 | s.pass_1a_complete = true; | |
d53a4bd1 | 697 | } |
11a046b7 | 698 | |
e7c60c35 SM |
699 | // PASS 1b: PARSING USER SCRIPT |
700 | PROBE1(stap, pass1b__start, &s); | |
701 | ||
bba368c5 JL |
702 | // Only try to parse a user script if the user provided one, or if we have to |
703 | // make one (as is the case for listing mode). Otherwise, s.user_script | |
704 | // remains NULL. | |
705 | if (!s.script_file.empty() || | |
706 | !s.cmdline_script.empty() || | |
707 | s.dump_mode == systemtap_session::dump_matched_probes || | |
708 | s.dump_mode == systemtap_session::dump_matched_probes_vars) | |
e7c60c35 | 709 | { |
f8405ea5 | 710 | unsigned user_flags = s.guru_mode ? pf_guru : 0; |
7b5b30a8 | 711 | user_flags |= pf_user_file; |
bba368c5 JL |
712 | if (s.script_file == "-") |
713 | { | |
ba48c27a | 714 | s.user_files.push_back (parse (s, "<input>", cin, user_flags)); |
bba368c5 JL |
715 | } |
716 | else if (s.script_file != "") | |
717 | { | |
ba48c27a | 718 | s.user_files.push_back (parse (s, s.script_file, user_flags)); |
bba368c5 JL |
719 | } |
720 | else if (s.cmdline_script != "") | |
721 | { | |
722 | istringstream ii (s.cmdline_script); | |
ba48c27a | 723 | s.user_files.push_back(parse (s, "<input>", ii, user_flags)); |
bba368c5 JL |
724 | } |
725 | else // listing mode | |
726 | { | |
727 | istringstream ii ("probe " + s.dump_matched_pattern + " {}"); | |
ba48c27a | 728 | s.user_files.push_back (parse (s, "<input>", ii, user_flags)); |
bba368c5 | 729 | } |
ba48c27a AJ |
730 | |
731 | // parses the additional script(s) (-E script). does so even if in listing | |
732 | // mode, incase there is something special in the additional script(s), | |
733 | // like a macro or alias. give them a unique name to differentiate the | |
734 | // scripts that were inputted. | |
735 | unsigned count = 1; | |
736 | for (vector<string>::iterator script = s.additional_scripts.begin(); script != s.additional_scripts.end(); script++) | |
737 | { | |
738 | string input_name = "<input" + lex_cast(count) + ">"; | |
739 | istringstream ii (*script); | |
740 | s.user_files.push_back(parse (s, input_name, ii, user_flags)); | |
741 | count ++; | |
742 | } | |
743 | ||
744 | for(vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++) | |
bba368c5 | 745 | { |
ba48c27a AJ |
746 | if (!(*it)) |
747 | { | |
748 | // Syntax errors already printed. | |
749 | rc ++; | |
750 | } | |
bba368c5 | 751 | } |
e7c60c35 | 752 | } |
30b1666e FL |
753 | else if (s.cmdline_script.empty() && |
754 | s.dump_mode == systemtap_session::dump_none) // -e '' | |
4bc2b5cd FL |
755 | { |
756 | cerr << _("Input file '<input>' is empty.") << endl; | |
757 | rc++; | |
758 | } | |
e7c60c35 | 759 | |
7d66cd75 | 760 | // Dump a list of probe aliases picked up, if requested |
bba368c5 | 761 | if (s.dump_mode == systemtap_session::dump_probe_aliases) |
7d66cd75 JL |
762 | { |
763 | set<string> aliases; | |
764 | vector<stapfile*>::const_iterator file; | |
765 | for (file = s.library_files.begin(); | |
766 | file != s.library_files.end(); ++file) | |
767 | { | |
768 | vector<probe_alias*>::const_iterator alias; | |
769 | for (alias = (*file)->aliases.begin(); | |
770 | alias != (*file)->aliases.end(); ++alias) | |
771 | { | |
772 | stringstream ss; | |
773 | (*alias)->printsig(ss); | |
774 | string str = ss.str(); | |
775 | if (!s.verbose && startswith(str, "_")) | |
776 | continue; | |
777 | aliases.insert(str); | |
778 | } | |
779 | } | |
780 | ||
781 | set<string>::iterator alias; | |
782 | for (alias = aliases.begin(); | |
783 | alias != aliases.end(); ++alias) | |
784 | { | |
785 | cout << *alias << endl; | |
786 | } | |
787 | } | |
788 | // Dump the parse tree if this is the last pass | |
789 | else if (rc == 0 && s.last_pass == 1) | |
4c263acb SM |
790 | { |
791 | cout << _("# parse tree dump") << endl; | |
ba48c27a AJ |
792 | for (vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++) |
793 | (*it)->print (cout); | |
4c263acb SM |
794 | cout << endl; |
795 | if (s.verbose) | |
796 | for (unsigned i=0; i<s.library_files.size(); i++) | |
797 | { | |
798 | s.library_files[i]->print (cout); | |
799 | cout << endl; | |
800 | } | |
801 | } | |
802 | ||
85007c04 DB |
803 | struct tms tms_after; |
804 | times (& tms_after); | |
805 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
806 | struct timeval tv_after; | |
807 | gettimeofday (&tv_after, NULL); | |
808 | ||
678efd81 | 809 | #define TIMESPRINT _("in ") << \ |
85007c04 DB |
810 | (tms_after.tms_cutime + tms_after.tms_utime \ |
811 | - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \ | |
812 | << (tms_after.tms_cstime + tms_after.tms_stime \ | |
813 | - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \ | |
814 | << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \ | |
815 | ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms." | |
816 | ||
817 | // syntax errors, if any, are already printed | |
818 | if (s.verbose) | |
819 | { | |
e7c60c35 | 820 | // XXX also include a count of helper macro files loaded (.stpm)? |
678efd81 | 821 | int n = int(s.library_files.size()); |
f275fa40 | 822 | clog << _("Pass 1: parsed user script and ") |
678efd81 | 823 | << _NF("%d library script ", "%d library scripts ", n, n) |
85007c04 DB |
824 | << getmemusage() |
825 | << TIMESPRINT | |
826 | << endl; | |
827 | } | |
828 | ||
bba368c5 | 829 | if (rc && !s.dump_mode) |
1f35f4db | 830 | cerr << _("Pass 1: parse failed. [man error::pass1]") << endl; |
85007c04 | 831 | |
0f5d597d | 832 | PROBE1(stap, pass1__end, &s); |
85007c04 | 833 | |
e19ebcf7 | 834 | assert_no_interrupts(); |
bba368c5 JL |
835 | if (rc || s.last_pass == 1 || |
836 | s.dump_mode == systemtap_session::dump_probe_aliases) | |
837 | return rc; | |
85007c04 DB |
838 | |
839 | times (& tms_before); | |
840 | gettimeofday (&tv_before, NULL); | |
841 | ||
842 | // PASS 2: ELABORATION | |
843 | s.verbose = s.perpass_verbose[1]; | |
0f5d597d | 844 | PROBE1(stap, pass2__start, &s); |
85007c04 DB |
845 | rc = semantic_pass (s); |
846 | ||
b82d77b4 | 847 | // Dump a list of known probe point types, if requested. |
bba368c5 | 848 | if (s.dump_mode == systemtap_session::dump_probe_types) |
b82d77b4 | 849 | s.pattern_root->dump (s); |
eb9ea966 | 850 | // Dump a list of functions we picked up, if requested. |
bba368c5 | 851 | else if (s.dump_mode == systemtap_session::dump_functions) |
eb9ea966 JL |
852 | { |
853 | map<string,functiondecl*>::const_iterator func; | |
854 | for (func = s.functions.begin(); | |
855 | func != s.functions.end(); ++func) | |
856 | { | |
857 | functiondecl& curfunc = *func->second; | |
858 | if (curfunc.synthetic) | |
859 | continue; | |
8f54215e MC |
860 | if (!startswith(curfunc.name, "__global_")) |
861 | continue; | |
862 | if (!s.verbose && startswith(curfunc.name, "__global__")) | |
eb9ea966 JL |
863 | continue; |
864 | curfunc.printsigtags(cout, s.verbose>0 /* all_tags */ ); | |
865 | cout << endl; | |
866 | } | |
867 | } | |
868 | // Dump the whole script if requested, or if we stop at 2 | |
bba368c5 JL |
869 | else if (s.dump_mode == systemtap_session::dump_matched_probes || |
870 | s.dump_mode == systemtap_session::dump_matched_probes_vars || | |
871 | (rc == 0 && s.last_pass == 2)) | |
85007c04 DB |
872 | printscript(s, cout); |
873 | ||
874 | times (& tms_after); | |
875 | gettimeofday (&tv_after, NULL); | |
876 | ||
678efd81 MC |
877 | if (s.verbose) { |
878 | int np = s.probes.size(); | |
879 | int nf = s.functions.size(); | |
880 | int ne = s.embeds.size(); | |
881 | int ng = s.globals.size(); | |
882 | clog << _("Pass 2: analyzed script: ") | |
883 | << _NF("%d probe, ", "%d probes, ", np, np) | |
884 | << _NF("%d function, ", "%d functions, ", nf, nf) | |
885 | << _NF("%d embed, ", "%d embeds, ", ne, ne) | |
886 | << _NF("%d global ", "%d globals ", ng, ng) | |
887 | << getmemusage() | |
888 | << TIMESPRINT | |
889 | << endl; | |
890 | } | |
85007c04 | 891 | |
dae1c685 FCE |
892 | missing_rpm_list_print(s, "-debuginfo"); |
893 | ||
bba368c5 | 894 | if (rc && !s.dump_mode && !s.try_server ()) |
1f35f4db | 895 | cerr << _("Pass 2: analysis failed. [man error::pass2]") << endl; |
85007c04 | 896 | |
0f5d597d | 897 | PROBE1(stap, pass2__end, &s); |
85007c04 | 898 | |
e19ebcf7 | 899 | assert_no_interrupts(); |
bba368c5 JL |
900 | // NB: none of the dump modes need to go beyond pass-2. If this changes, break |
901 | // into individual modes here. | |
902 | if (rc || s.last_pass == 2 || s.dump_mode) | |
903 | return rc; | |
85007c04 | 904 | |
d13bcfd8 | 905 | rc = prepare_translate_pass (s); |
e19ebcf7 | 906 | assert_no_interrupts(); |
985892de | 907 | if (rc) return rc; |
d13bcfd8 | 908 | |
85007c04 DB |
909 | // Generate hash. There isn't any point in generating the hash |
910 | // if last_pass is 2, since we'll quit before using it. | |
911 | if (s.use_script_cache) | |
912 | { | |
913 | ostringstream o; | |
914 | unsigned saved_verbose; | |
915 | ||
916 | { | |
917 | // Make sure we're in verbose mode, so that printscript() | |
918 | // will output function/probe bodies. | |
919 | saved_verbose = s.verbose; | |
920 | s.verbose = 3; | |
921 | printscript(s, o); // Print script to 'o' | |
922 | s.verbose = saved_verbose; | |
923 | } | |
924 | ||
925 | // Generate hash | |
926 | find_script_hash (s, o.str()); | |
927 | ||
928 | // See if we can use cached source/module. | |
929 | if (get_script_from_cache(s)) | |
930 | { | |
7d26ee02 JS |
931 | // We may still need to build uprobes, if it's not also cached. |
932 | if (s.need_uprobes) | |
933 | rc = uprobes_pass(s); | |
934 | ||
85007c04 DB |
935 | // If our last pass isn't 5, we're done (since passes 3 and |
936 | // 4 just generate what we just pulled out of the cache). | |
e19ebcf7 | 937 | assert_no_interrupts(); |
985892de | 938 | if (rc || s.last_pass < 5) return rc; |
85007c04 DB |
939 | |
940 | // Short-circuit to pass 5. | |
941 | return 0; | |
942 | } | |
943 | } | |
944 | ||
945 | // PASS 3: TRANSLATION | |
946 | s.verbose = s.perpass_verbose[2]; | |
947 | times (& tms_before); | |
948 | gettimeofday (&tv_before, NULL); | |
0f5d597d | 949 | PROBE1(stap, pass3__start, &s); |
85007c04 DB |
950 | |
951 | rc = translate_pass (s); | |
3e1ec884 | 952 | if (! rc && s.last_pass == 3) |
85007c04 DB |
953 | { |
954 | ifstream i (s.translated_source.c_str()); | |
955 | cout << i.rdbuf(); | |
956 | } | |
957 | ||
958 | times (& tms_after); | |
959 | gettimeofday (&tv_after, NULL); | |
960 | ||
79bc39ab | 961 | if (s.verbose) |
f275fa40 | 962 | clog << _("Pass 3: translated to C into \"") |
79bc39ab LB |
963 | << s.translated_source |
964 | << "\" " | |
965 | << getmemusage() | |
966 | << TIMESPRINT | |
85007c04 DB |
967 | << endl; |
968 | ||
44edbcd6 | 969 | if (rc && ! s.try_server ()) |
1f35f4db | 970 | cerr << _("Pass 3: translation failed. [man error::pass3]") << endl; |
79bc39ab | 971 | |
0f5d597d | 972 | PROBE1(stap, pass3__end, &s); |
85007c04 | 973 | |
e19ebcf7 | 974 | assert_no_interrupts(); |
985892de | 975 | if (rc || s.last_pass == 3) return rc; |
85007c04 DB |
976 | |
977 | // PASS 4: COMPILATION | |
978 | s.verbose = s.perpass_verbose[3]; | |
979 | times (& tms_before); | |
980 | gettimeofday (&tv_before, NULL); | |
0f5d597d | 981 | PROBE1(stap, pass4__start, &s); |
85007c04 DB |
982 | |
983 | if (s.use_cache) | |
984 | { | |
985 | find_stapconf_hash(s); | |
986 | get_stapconf_from_cache(s); | |
987 | } | |
988 | rc = compile_pass (s); | |
3e1ec884 | 989 | if (! rc && s.last_pass == 4) |
85007c04 | 990 | { |
4441e344 | 991 | cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path); |
85007c04 DB |
992 | cout << endl; |
993 | } | |
994 | ||
995 | times (& tms_after); | |
996 | gettimeofday (&tv_after, NULL); | |
997 | ||
f275fa40 | 998 | if (s.verbose) clog << _("Pass 4: compiled C into \"") |
4441e344 | 999 | << s.module_filename() |
85007c04 DB |
1000 | << "\" " |
1001 | << TIMESPRINT | |
1002 | << endl; | |
1003 | ||
44edbcd6 | 1004 | if (rc && ! s.try_server ()) |
1f35f4db | 1005 | cerr << _("Pass 4: compilation failed. [man error::pass4]") << endl; |
be4b2eed | 1006 | |
85007c04 DB |
1007 | else |
1008 | { | |
1009 | // Update cache. Cache cleaning is kicked off at the beginning of this function. | |
1010 | if (s.use_script_cache) | |
1011 | add_script_to_cache(s); | |
ac3af990 | 1012 | if (s.use_cache && !s.runtime_usermode_p()) |
85007c04 DB |
1013 | add_stapconf_to_cache(s); |
1014 | ||
1015 | // We may need to save the module in $CWD if the cache was | |
1016 | // inaccessible for some reason. | |
1017 | if (! s.use_script_cache && s.last_pass == 4) | |
1018 | s.save_module = true; | |
1019 | ||
1020 | // Copy module to the current directory. | |
1021 | if (s.save_module && !pending_interrupts) | |
1022 | { | |
4441e344 JS |
1023 | string module_src_path = s.tmpdir + "/" + s.module_filename(); |
1024 | string module_dest_path = s.module_filename(); | |
85007c04 DB |
1025 | copy_file(module_src_path, module_dest_path, s.verbose > 1); |
1026 | } | |
50f92d4e SH |
1027 | |
1028 | // Copy uprobes module to the current directory. | |
91ea0ce6 | 1029 | if (s.save_uprobes && !s.uprobes_path.empty() && !pending_interrupts) |
50f92d4e SH |
1030 | { |
1031 | rc = create_dir("uprobes"); | |
1032 | if (! rc) | |
1033 | copy_file(s.uprobes_path, "uprobes/uprobes.ko", s.verbose > 1); | |
1034 | } | |
85007c04 DB |
1035 | } |
1036 | ||
0f5d597d | 1037 | PROBE1(stap, pass4__end, &s); |
85007c04 DB |
1038 | |
1039 | return rc; | |
1040 | } | |
1041 | ||
11a046b7 | 1042 | int |
ebff2ed0 | 1043 | pass_5 (systemtap_session &s, vector<remote*> targets) |
85007c04 DB |
1044 | { |
1045 | // PASS 5: RUN | |
1046 | s.verbose = s.perpass_verbose[4]; | |
1047 | struct tms tms_before; | |
1048 | times (& tms_before); | |
1049 | struct timeval tv_before; | |
1050 | gettimeofday (&tv_before, NULL); | |
1051 | // NB: this message is a judgement call. The other passes don't emit | |
1052 | // a "hello, I'm starting" message, but then the others aren't interactive | |
1053 | // and don't take an indefinite amount of time. | |
0f5d597d | 1054 | PROBE1(stap, pass5__start, &s); |
79bc39ab | 1055 | if (s.verbose) clog << _("Pass 5: starting run.") << endl; |
4f244435 | 1056 | int rc = remote::run(targets); |
85007c04 DB |
1057 | struct tms tms_after; |
1058 | times (& tms_after); | |
1059 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
1060 | struct timeval tv_after; | |
1061 | gettimeofday (&tv_after, NULL); | |
f275fa40 | 1062 | if (s.verbose) clog << _("Pass 5: run completed ") |
85007c04 DB |
1063 | << TIMESPRINT |
1064 | << endl; | |
1065 | ||
1066 | if (rc) | |
1f35f4db | 1067 | cerr << _("Pass 5: run failed. [man error::pass5]") << endl; |
85007c04 DB |
1068 | else |
1069 | // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below. | |
1070 | pending_interrupts = 0; | |
1071 | ||
0f5d597d | 1072 | PROBE1(stap, pass5__end, &s); |
85007c04 DB |
1073 | |
1074 | return rc; | |
1075 | } | |
1076 | ||
1077 | static void | |
1078 | cleanup (systemtap_session &s, int rc) | |
1079 | { | |
1080 | // PASS 6: cleaning up | |
0f5d597d | 1081 | PROBE1(stap, pass6__start, &s); |
85007c04 | 1082 | |
ebff2ed0 JS |
1083 | for (systemtap_session::session_map_t::iterator it = s.subsessions.begin(); |
1084 | it != s.subsessions.end(); ++it) | |
1085 | cleanup (*it->second, rc); | |
1086 | ||
85007c04 DB |
1087 | // update the database information |
1088 | if (!rc && s.tapset_compile_coverage && !pending_interrupts) { | |
1089 | #ifdef HAVE_LIBSQLITE3 | |
1090 | update_coverage_db(s); | |
1091 | #else | |
79bc39ab | 1092 | cerr << _("Coverage database not available without libsqlite3") << endl; |
85007c04 DB |
1093 | #endif |
1094 | } | |
1095 | ||
678b7381 | 1096 | s.report_suppression(); |
9e1a2390 | 1097 | |
0f5d597d | 1098 | PROBE1(stap, pass6__end, &s); |
85007c04 DB |
1099 | } |
1100 | ||
44edbcd6 JS |
1101 | static int |
1102 | passes_0_4_again_with_server (systemtap_session &s) | |
1103 | { | |
1104 | // Not a server and not already using a server. | |
1105 | assert (! s.client_options); | |
1106 | assert (s.specified_servers.empty ()); | |
1107 | ||
1108 | // Specify default server(s). | |
1109 | s.specified_servers.push_back (""); | |
1110 | ||
b96901b7 CM |
1111 | // Reset the previous temporary directory and start fresh |
1112 | s.reset_tmp_dir(); | |
44edbcd6 JS |
1113 | |
1114 | // Try to compile again, using the server | |
b5f561be | 1115 | clog << _("Attempting compilation using a compile server") |
44edbcd6 | 1116 | << endl; |
b96901b7 | 1117 | |
44edbcd6 JS |
1118 | int rc = passes_0_4 (s); |
1119 | return rc; | |
1120 | } | |
1121 | ||
85007c04 DB |
1122 | int |
1123 | main (int argc, char * const argv []) | |
1124 | { | |
1125 | // Initialize defaults. | |
b96901b7 | 1126 | try { |
891043f0 | 1127 | systemtap_session s; |
52c2652f | 1128 | #if ENABLE_NLS |
891043f0 CM |
1129 | setlocale (LC_ALL, ""); |
1130 | bindtextdomain (PACKAGE, LOCALEDIR); | |
1131 | textdomain (PACKAGE); | |
52c2652f | 1132 | #endif |
891043f0 CM |
1133 | |
1134 | // Set up our handler to catch routine signals, to allow clean | |
1135 | // and reasonably timely exit. | |
1136 | setup_signals(&handle_interrupt); | |
1137 | ||
1138 | // PR13520: Parse $SYSTEMTAP_DIR/rc for extra options | |
1139 | string rc_file = s.data_path + "/rc"; | |
1140 | ifstream rcf (rc_file.c_str()); | |
1141 | string rcline; | |
1142 | wordexp_t words; | |
1143 | memset (& words, 0, sizeof(words)); | |
1144 | int rc = 0; | |
1145 | int linecount = 0; | |
1146 | while (getline (rcf, rcline)) | |
1147 | { | |
1148 | rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF| | |
1149 | (linecount > 0 ? WRDE_APPEND : 0)); | |
1150 | // NB: WRDE_APPEND automagically reallocates words.* as more options are added. | |
1151 | linecount ++; | |
1152 | if (rc) break; | |
1153 | } | |
4eb12770 FCE |
1154 | rcf.close(); |
1155 | ||
891043f0 CM |
1156 | int extended_argc = words.we_wordc + argc; |
1157 | char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*)); | |
1158 | if (rc || !extended_argv) | |
1159 | { | |
1160 | clog << _F("Error processing extra options in %s", rc_file.c_str()); | |
e2d0f787 | 1161 | return EXIT_FAILURE; |
891043f0 CM |
1162 | } |
1163 | // Copy over the arguments *by reference*, first the ones from the rc file. | |
1164 | char **p = & extended_argv[0]; | |
1165 | *p++ = argv[0]; | |
1166 | for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i]; | |
1167 | for (int j=1; j<argc; j++) *p++ = argv[j]; | |
1168 | *p++ = NULL; | |
1169 | ||
1170 | // Process the command line. | |
1171 | rc = s.parse_cmdline (extended_argc, extended_argv); | |
1172 | if (rc != 0) | |
e2d0f787 | 1173 | return rc; |
891043f0 | 1174 | |
9fb50451 MC |
1175 | // Create the temp dir. |
1176 | s.create_tmp_dir(); | |
1177 | ||
891043f0 CM |
1178 | if (words.we_wordc > 0 && s.verbose > 1) |
1179 | clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc); | |
1180 | ||
1181 | // Check for options conflicts. Exits if errors are detected. | |
1182 | s.check_options (extended_argc, extended_argv); | |
1183 | ||
1184 | // We don't need these strings any more. | |
1185 | wordfree (& words); | |
1186 | free (extended_argv); | |
1187 | ||
1188 | // arguments parsed; get down to business | |
1189 | if (s.verbose > 1) | |
1190 | s.version (); | |
1191 | ||
1192 | // Need to send the verbose message here, rather than in the session ctor, since | |
1193 | // we didn't know if verbose was set. | |
1194 | if (rc == 0 && s.verbose>1) | |
1195 | clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl; | |
1196 | ||
3d0a328d JS |
1197 | // Run the benchmark and quit right away. |
1198 | if (s.benchmark_sdt_loops || s.benchmark_sdt_threads) | |
1199 | return run_sdt_benchmark(s); | |
1200 | ||
891043f0 CM |
1201 | // Prepare connections for each specified remote target. |
1202 | vector<remote*> targets; | |
1203 | bool fake_remote=false; | |
1204 | if (s.remote_uris.empty()) | |
1205 | { | |
1206 | fake_remote=true; | |
1207 | s.remote_uris.push_back("direct:"); | |
1208 | } | |
1209 | for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i) | |
1210 | { | |
1211 | // PR13354: pass remote id#/url only in non --remote=HOST cases | |
1212 | remote *target = remote::create(s, s.remote_uris[i], | |
1213 | fake_remote ? -1 : (int)i); | |
1214 | if (target) | |
1215 | targets.push_back(target); | |
1216 | else | |
1217 | rc = 1; | |
1218 | } | |
3a97e514 | 1219 | |
891043f0 CM |
1220 | // Discover and loop over each unique session created by the remote targets. |
1221 | set<systemtap_session*> sessions; | |
1222 | for (unsigned i = 0; i < targets.size(); ++i) | |
1223 | sessions.insert(targets[i]->get_session()); | |
11a046b7 DS |
1224 | |
1225 | // FIXME: For now, only attempt local interactive use. | |
1226 | if (s.interactive_mode && fake_remote) | |
891043f0 | 1227 | { |
9ac12b89 | 1228 | #ifdef HAVE_LIBREADLINE |
11a046b7 | 1229 | rc = interactive_mode (s, targets); |
9ac12b89 | 1230 | #endif |
11a046b7 DS |
1231 | } |
1232 | else | |
1233 | { | |
1234 | for (set<systemtap_session*>::iterator it = sessions.begin(); | |
1235 | rc == 0 && !pending_interrupts && it != sessions.end(); ++it) | |
1236 | { | |
1237 | systemtap_session& ss = **it; | |
1238 | if (ss.verbose > 1) | |
1239 | clog << _F("Session arch: %s release: %s", | |
1240 | ss.architecture.c_str(), ss.kernel_release.c_str()) | |
1241 | << endl; | |
85007c04 | 1242 | |
c4fd15b4 | 1243 | #if HAVE_NSS |
11a046b7 DS |
1244 | // If requested, query server status. This is independent |
1245 | // of other tasks. | |
1246 | query_server_status (ss); | |
85007c04 | 1247 | |
11a046b7 DS |
1248 | // If requested, manage trust of servers. This is |
1249 | // independent of other tasks. | |
1250 | manage_server_trust (ss); | |
c4fd15b4 | 1251 | #endif |
ebff2ed0 | 1252 | |
11a046b7 DS |
1253 | // Run the passes only if a script has been specified or |
1254 | // if we're dumping something. The requirement for a | |
1255 | // script has already been checked in | |
1256 | // systemtap_session::check_options. | |
1257 | if (ss.have_script || ss.dump_mode) | |
1258 | { | |
1259 | // Run passes 0-4 for each unique session, either | |
1260 | // locally or using a compile-server. | |
1261 | ss.init_try_server (); | |
1262 | if ((rc = passes_0_4 (ss))) | |
1263 | { | |
1264 | // Compilation failed. | |
1265 | // Try again using a server if appropriate. | |
1266 | if (ss.try_server ()) | |
1267 | rc = passes_0_4_again_with_server (ss); | |
1268 | } | |
1269 | if (rc || s.perpass_verbose[0] >= 1) | |
1270 | s.explain_auto_options (); | |
1271 | } | |
1272 | } | |
1273 | ||
1274 | // Run pass 5, if requested | |
1275 | if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts) | |
1276 | rc = pass_5 (s, targets); | |
891043f0 | 1277 | } |
3a97e514 | 1278 | |
891043f0 CM |
1279 | // Pass 6. Cleanup |
1280 | for (unsigned i = 0; i < targets.size(); ++i) | |
1281 | delete targets[i]; | |
1282 | cleanup (s, rc); | |
b96901b7 | 1283 | |
e19ebcf7 | 1284 | assert_no_interrupts(); |
985892de | 1285 | return (rc) ? EXIT_FAILURE : EXIT_SUCCESS; |
b96901b7 | 1286 | } |
8d4072eb | 1287 | catch (const interrupt_exception& e) { |
985892de | 1288 | // User entered ctrl-c, exit quietly. |
e2d0f787 JS |
1289 | return EXIT_FAILURE; |
1290 | } | |
1291 | catch (const exit_exception& e) { | |
1292 | // Exiting for any quiet reason. | |
1293 | return e.rc; | |
985892de | 1294 | } |
29375627 JL |
1295 | catch (const exception &e) { |
1296 | // Some other uncaught exception. | |
985892de | 1297 | cerr << e.what() << endl; |
e2d0f787 | 1298 | return EXIT_FAILURE; |
985892de CM |
1299 | } |
1300 | catch (...) { | |
1301 | // Catch all other unknown exceptions. | |
1302 | cerr << _("ERROR: caught unknown exception!") << endl; | |
e2d0f787 | 1303 | return EXIT_FAILURE; |
b96901b7 | 1304 | } |
85007c04 DB |
1305 | } |
1306 | ||
1307 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |