]>
sourceware.org Git - systemtap.git/blob - main.cxx
1 // systemtap translator/driver
2 // Copyright (C) 2005-2009 Red Hat Inc.
3 // Copyright (C) 2005 IBM Corp.
4 // Copyright (C) 2006 Intel Corporation.
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
14 #include "elaborate.h"
15 #include "translate.h"
21 #include "coveragedb.h"
22 #include "git_version.h"
35 #include <sys/utsname.h>
36 #include <sys/times.h>
40 #include <elfutils/libdwfl.h>
51 << "SystemTap translator/driver "
52 << "(version " << VERSION
<< "/" << dwfl_version (NULL
)
53 << " " << GIT_MESSAGE
<< ")" << endl
54 << "Copyright (C) 2005-2009 Red Hat, Inc. and others" << endl
55 << "This is free software; see the source for copying conditions." << endl
;
59 usage (systemtap_session
& s
, int exitcode
)
64 << "Usage: stap [options] FILE Run script in file."
66 << " or: stap [options] - Run script on stdin."
68 << " or: stap [options] -e SCRIPT Run given script."
70 << " or: stap [options] -l PROBE List matching probes."
72 << " or: stap [options] -L PROBE List matching probes and local variables."
76 << " -- end of translator options, script options follow" << endl
77 << " -h show help" << endl
78 << " -V show version" << endl
79 << " -p NUM stop after pass NUM 1-5, instead of " << s
.last_pass
<< endl
80 << " (parse, elaborate, translate, compile, run)" << endl
81 << " -v add verbosity to all passes" << endl
82 << " --vp {N}+ add per-pass verbosity [";
83 for (unsigned i
=0; i
<5; i
++)
84 clog
<< (s
.perpass_verbose
[i
] <= 9 ? s
.perpass_verbose
[i
] : 9);
87 << " -k keep temporary directory" << endl
88 << " -u unoptimized translation" << (s
.unoptimized
? " [set]" : "") << endl
89 << " -w suppress warnings" << (s
.suppress_warnings
? " [set]" : "") << endl
90 << " -g guru mode" << (s
.guru_mode
? " [set]" : "") << endl
91 << " -P prologue-searching for function probes"
92 << (s
.prologue_searching
? " [set]" : "") << endl
93 << " -b bulk (percpu file) mode" << (s
.bulk_mode
? " [set]" : "") << endl
94 << " -s NUM buffer size in megabytes, instead of " << s
.buffer_size
<< endl
95 << " -I DIR look in DIR for additional .stp script files";
96 if (s
.include_path
.size() == 0)
99 clog
<< ", in addition to" << endl
;
100 for (unsigned i
=0; i
<s
.include_path
.size(); i
++)
101 clog
<< " " << s
.include_path
[i
] << endl
;
103 << " -D NM=VAL emit macro definition into generated C code" << endl
104 << " -R DIR look in DIR for runtime, instead of" << endl
105 << " " << s
.runtime_path
<< endl
106 << " -r DIR cross-compile to kernel with given build tree; or else" << endl
107 << " -r RELEASE cross-compile to kernel /lib/modules/RELEASE/build, instead of" << endl
108 << " " << s
.kernel_build_tree
<< endl
109 << " -m MODULE set probe module name, instead of " << endl
110 << " " << s
.module_name
<< endl
111 << " -o FILE send script output to file, instead of stdout. This supports" << endl
112 << " strftime(3) formats for FILE" << endl
113 << " -c CMD start the probes, run CMD, and exit when it finishes" << endl
114 << " -x PID sets target() to PID" << endl
115 << " -F run as on-file flight recorder with -o." << endl
116 << " run as on-memory flight recorder without -o." << endl
117 << " -S size[,n] set maximum of the size and the number of files." << endl
118 << " -d OBJECT add unwind/symbol data for OBJECT file";
119 if (s
.unwindsym_modules
.size() == 0)
122 clog
<< ", in addition to" << endl
;
124 vector
<string
> syms (s
.unwindsym_modules
.begin(), s
.unwindsym_modules
.end());
125 for (unsigned i
=0; i
<syms
.size(); i
++)
126 clog
<< " " << syms
[i
] << endl
;
129 << " -t collect probe timing information" << endl
130 #ifdef HAVE_LIBSQLITE3
131 << " -q generate information on tapset coverage" << endl
132 #endif /* HAVE_LIBSQLITE3 */
133 #if 0 /* PR6864: disable temporarily; should merge with -d somehow */
134 << " --kelf make do with symbol table from vmlinux" << endl
135 << " --kmap[=FILE]" << endl
136 << " make do with symbol table from nm listing" << endl
138 // Formerly present --ignore-{vmlinux,dwarf} options are for testsuite use
139 // only, and don't belong in the eyesight of a plain user.
140 << " --skip-badvars" << endl
141 << " overlook context of bad $ variables" << endl
150 printscript(systemtap_session
& s
, ostream
& o
)
154 // We go through some heroic measures to produce clean output.
157 for (unsigned i
=0; i
<s
.probes
.size(); i
++)
159 if (pending_interrupts
) return;
161 derived_probe
* p
= s
.probes
[i
];
162 // NB: p->basest() is not so interesting;
163 // p->almost_basest() doesn't quite work, so ...
164 vector
<probe
*> chain
;
165 p
->collect_derivation_chain (chain
);
166 probe
* second
= (chain
.size()>1) ? chain
[chain
.size()-2] : chain
[0];
169 cerr
<< "\tchain[" << chain
.size() << "]:" << endl
;
170 for (unsigned i
=0; i
<chain
.size(); i
++)
171 { cerr
<< "\t"; chain
[i
]->printsig(cerr
); cerr
<< endl
; }
175 const probe_alias
*a
= second
->get_alias();
178 assert (a
->alias_names
.size() >= 1);
179 a
->alias_names
[0]->print(tmps
); // XXX: [0] is arbitrary; perhaps print all
183 assert (second
->locations
.size() >= 1);
184 second
->locations
[0]->print(tmps
); // XXX: [0] is less arbitrary here, but still ...
186 string pp
= tmps
.str();
188 // Now duplicate-eliminate. An alias may have expanded to
189 // several actual derived probe points, but we only want to
190 // print the alias head name once.
191 if (seen
.find (pp
) == seen
.end())
194 // Print the locals for -L mode only
196 for (unsigned j
=0; j
<p
->locals
.size(); j
++)
199 vardecl
* v
= p
->locals
[j
];
202 // Print arguments of probe if there
212 if (s
.embeds
.size() > 0)
213 o
<< "# global embedded code" << endl
;
214 for (unsigned i
=0; i
<s
.embeds
.size(); i
++)
216 if (pending_interrupts
) return;
217 embeddedcode
* ec
= s
.embeds
[i
];
222 if (s
.globals
.size() > 0)
223 o
<< "# globals" << endl
;
224 for (unsigned i
=0; i
<s
.globals
.size(); i
++)
226 if (pending_interrupts
) return;
227 vardecl
* v
= s
.globals
[i
];
229 if (s
.verbose
&& v
->init
)
237 if (s
.functions
.size() > 0)
238 o
<< "# functions" << endl
;
239 for (map
<string
,functiondecl
*>::iterator it
= s
.functions
.begin(); it
!= s
.functions
.end(); it
++)
241 if (pending_interrupts
) return;
242 functiondecl
* f
= it
->second
;
245 if (f
->locals
.size() > 0)
246 o
<< " # locals" << endl
;
247 for (unsigned j
=0; j
<f
->locals
.size(); j
++)
249 vardecl
* v
= f
->locals
[j
];
261 if (s
.probes
.size() > 0)
262 o
<< "# probes" << endl
;
263 for (unsigned i
=0; i
<s
.probes
.size(); i
++)
265 if (pending_interrupts
) return;
266 derived_probe
* p
= s
.probes
[i
];
269 if (p
->locals
.size() > 0)
270 o
<< " # locals" << endl
;
271 for (unsigned j
=0; j
<p
->locals
.size(); j
++)
273 vardecl
* v
= p
->locals
[j
];
288 int pending_interrupts
;
291 void handle_interrupt (int sig
)
293 kill_stap_spawn(sig
);
294 pending_interrupts
++;
295 if (pending_interrupts
> 1) // XXX: should be configurable? time-based?
297 char msg
[] = "Too many interrupts received, exiting.\n";
298 int rc
= write (2, msg
, sizeof(msg
)-1);
299 if (rc
) {/* Do nothing; we don't care if our last gasp went out. */ ;}
306 setup_signals (sighandler_t handler
)
310 sa
.sa_handler
= handler
;
311 sigemptyset (&sa
.sa_mask
);
312 if (handler
!= SIG_IGN
)
314 sigaddset (&sa
.sa_mask
, SIGHUP
);
315 sigaddset (&sa
.sa_mask
, SIGPIPE
);
316 sigaddset (&sa
.sa_mask
, SIGINT
);
317 sigaddset (&sa
.sa_mask
, SIGTERM
);
319 sa
.sa_flags
= SA_RESTART
;
321 sigaction (SIGHUP
, &sa
, NULL
);
322 sigaction (SIGPIPE
, &sa
, NULL
);
323 sigaction (SIGINT
, &sa
, NULL
);
324 sigaction (SIGTERM
, &sa
, NULL
);
328 setup_kernel_release (systemtap_session
&s
, const char* kstr
) {
329 if (kstr
[0] == '/') // fully specified path
331 s
.kernel_build_tree
= kstr
;
332 string version_file_name
= s
.kernel_build_tree
+ "/include/config/kernel.release";
333 // The file include/config/kernel.release within the
334 // build tree is used to pull out the version information
335 ifstream
version_file (version_file_name
.c_str());
336 if (version_file
.fail ())
338 cerr
<< "Missing " << version_file_name
<< endl
;
344 s
.kernel_release
= "";
345 while (version_file
.get(c
) && c
!= '\n')
346 s
.kernel_release
.push_back(c
);
351 s
.kernel_release
= string (kstr
);
352 s
.kernel_build_tree
= "/lib/modules/" + s
.kernel_release
+ "/build";
357 main (int argc
, char * const argv
[])
359 string cmdline_script
; // -e PROGRAM
360 string script_file
; // FILE
361 bool have_script
= false;
362 bool save_module
= false;
364 // Initialize defaults
367 (void) uname (& buf
);
368 s
.kernel_release
= string (buf
.release
);
369 s
.kernel_build_tree
= "/lib/modules/" + s
.kernel_release
+ "/build";
371 s
.architecture
= string (buf
.machine
);
372 for (unsigned i
=0; i
<5; i
++) s
.perpass_verbose
[i
]=0;
376 s
.unoptimized
= false;
377 s
.suppress_warnings
= false;
378 s
.listing_mode
= false;
380 #ifdef ENABLE_PROLOGUES
381 s
.prologue_searching
= true;
383 s
.prologue_searching
= false;
388 s
.module_name
= "stap_" + stringify(getpid());
389 s
.stapconf_name
= "stapconf_" + stringify(getpid()) + ".h";
390 s
.output_file
= ""; // -o FILE
391 s
.keep_tmpdir
= false;
398 s
.tapset_compile_coverage
= false;
399 s
.need_uprobes
= false;
400 s
.consult_symtab
= false;
401 s
.ignore_vmlinux
= false;
402 s
.ignore_dwarf
= false;
404 s
.skip_badvars
= false;
406 // Location of our signing certificate.
407 // If we're root, use the database in SYSCONFDIR, otherwise
408 // use the one in our $HOME directory. */
410 s
.cert_db_path
= SYSCONFDIR
"/systemtap/ssl/server";
412 s
.cert_db_path
= getenv("HOME") + string ("/.systemtap/ssl/server");
414 const char* s_p
= getenv ("SYSTEMTAP_TAPSET");
417 s
.include_path
.push_back (s_p
);
421 s
.include_path
.push_back (string(PKGDATADIR
) + "/tapset");
424 const char* s_r
= getenv ("SYSTEMTAP_RUNTIME");
426 s
.runtime_path
= s_r
;
428 s
.runtime_path
= string(PKGDATADIR
) + "/runtime";
430 const char* s_d
= getenv ("SYSTEMTAP_DIR");
434 s
.data_path
= get_home_directory() + string("/.systemtap");
435 if (create_dir(s
.data_path
.c_str()) == 1)
437 const char* e
= strerror (errno
);
438 if (! s
.suppress_warnings
)
439 cerr
<< "Warning: failed to create systemtap data directory (\""
440 << s
.data_path
<< "\"): " << e
441 << ", disabling cache support." << endl
;
447 s
.cache_path
= s
.data_path
+ "/cache";
448 if (create_dir(s
.cache_path
.c_str()) == 1)
450 const char* e
= strerror (errno
);
451 if (! s
.suppress_warnings
)
452 cerr
<< "Warning: failed to create cache directory (\""
453 << s
.cache_path
<< "\"): " << e
454 << ", disabling cache support." << endl
;
459 const char* s_tc
= getenv ("SYSTEMTAP_COVERAGE");
461 s
.tapset_compile_coverage
= true;
463 const char* s_kr
= getenv ("SYSTEMTAP_RELEASE");
465 setup_kernel_release(s
, s_kr
);
472 #define LONG_OPT_KELF 1
473 #define LONG_OPT_KMAP 2
474 #define LONG_OPT_IGNORE_VMLINUX 3
475 #define LONG_OPT_IGNORE_DWARF 4
476 #define LONG_OPT_VERBOSE_PASS 5
477 #define LONG_OPT_SKIP_BADVARS 6
478 // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page
479 static struct option long_options
[] = {
480 { "kelf", 0, &long_opt
, LONG_OPT_KELF
},
481 { "kmap", 2, &long_opt
, LONG_OPT_KMAP
},
482 { "ignore-vmlinux", 0, &long_opt
, LONG_OPT_IGNORE_VMLINUX
},
483 { "ignore-dwarf", 0, &long_opt
, LONG_OPT_IGNORE_DWARF
},
484 { "skip-badvars", 0, &long_opt
, LONG_OPT_SKIP_BADVARS
},
485 { "vp", 1, &long_opt
, LONG_OPT_VERBOSE_PASS
},
488 int grc
= getopt_long (argc
, argv
, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:FS:",
503 for (unsigned i
=0; i
<5; i
++)
504 s
.perpass_verbose
[i
] ++;
512 s
.suppress_warnings
= true;
518 cerr
<< "Listing (-l) mode implies pass 2." << endl
;
521 s
.last_pass
= atoi (optarg
);
522 if (s
.last_pass
< 1 || s
.last_pass
> 5)
524 cerr
<< "Invalid pass number (should be 1-5)." << endl
;
530 s
.include_path
.push_back (string (optarg
));
534 s
.unwindsym_modules
.insert (string (optarg
));
540 cerr
<< "Only one script can be given on the command line."
544 cmdline_script
= string (optarg
);
549 s
.output_file
= string (optarg
);
553 s
.runtime_path
= string (optarg
);
557 s
.module_name
= string (optarg
);
560 string::size_type len
= s
.module_name
.length();
562 // If the module name ends with '.ko', chop it off since
563 // modutils doesn't like modules named 'foo.ko.ko'.
564 if (len
> 3 && s
.module_name
.substr(len
- 3, 3) == ".ko")
566 s
.module_name
.erase(len
- 3);
568 cerr
<< "Truncating module name to '" << s
.module_name
572 // Make sure an empty module name wasn't specified (-m "")
575 cerr
<< "Module name cannot be empty." << endl
;
579 // Make sure the module name is only composed of the
580 // following chars: [_a-zA-Z0-9]
581 const string
identchars("_" "abcdefghijklmnopqrstuvwxyz"
582 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789");
583 if (s
.module_name
.find_first_not_of(identchars
) != string::npos
)
585 cerr
<< "Invalid module name (must only be composed of"
586 " characters [_a-zA-Z0-9])." << endl
;
590 // Make sure module name isn't too long.
591 if (s
.module_name
.size() >= (MODULE_NAME_LEN
- 1))
593 s
.module_name
.resize(MODULE_NAME_LEN
- 1);
594 cerr
<< "Truncating module name to '" << s
.module_name
603 setup_kernel_release(s
, optarg
);
607 s
.keep_tmpdir
= true;
608 s
.use_cache
= false; /* User wants to keep a usable build tree. */
616 s
.prologue_searching
= true;
624 s
.unoptimized
= true;
628 s
.buffer_size
= atoi (optarg
);
629 if (s
.buffer_size
< 1 || s
.buffer_size
> 4095)
631 cerr
<< "Invalid buffer size (should be 1-4095)." << endl
;
637 s
.cmd
= string (optarg
);
641 s
.target_pid
= atoi(optarg
);
645 s
.macros
.push_back (string (optarg
));
649 s
.size_option
= string (optarg
);
653 s
.tapset_compile_coverage
= true;
661 s
.unoptimized
= true; // This causes retention of variables for listing_mode
664 s
.suppress_warnings
= true;
665 s
.listing_mode
= true;
669 cerr
<< "Only one script can be given on the command line."
673 cmdline_script
= string("probe ") + string(optarg
) + " {}";
685 s
.consult_symtab
= true;
688 // Leave s.consult_symtab unset for now, to ease error checking.
689 if (!s
.kernel_symtab_path
.empty())
691 cerr
<< "You can't specify multiple --kmap options." << endl
;
695 s
.kernel_symtab_path
= optarg
;
697 #define PATH_TBD string("__TBD__")
698 s
.kernel_symtab_path
= PATH_TBD
;
700 case LONG_OPT_IGNORE_VMLINUX
:
701 s
.ignore_vmlinux
= true;
703 case LONG_OPT_IGNORE_DWARF
:
704 s
.ignore_dwarf
= true;
706 case LONG_OPT_VERBOSE_PASS
:
709 if (strlen(optarg
) < 1 || strlen(optarg
) > 5)
712 for (unsigned i
=0; i
<strlen(optarg
); i
++)
713 if (isdigit (optarg
[i
]))
714 s
.perpass_verbose
[i
] += optarg
[i
]-'0';
720 cerr
<< "Invalid --vp argument: it takes 1 to 5 digits." << endl
;
723 // NB: we don't do this: s.last_pass = strlen(optarg);
726 case LONG_OPT_SKIP_BADVARS
:
727 s
.skip_badvars
= true;
730 cerr
<< "Internal error parsing command arguments." << endl
;
741 if(!s
.bulk_mode
&& !s
.merge
)
743 cerr
<< "-M option is valid only for bulk (relayfs) mode." <<endl
;
747 if(!s
.output_file
.empty() && s
.bulk_mode
&& !s
.merge
)
749 cerr
<< "You can't specify -M, -b and -o options together." <<endl
;
753 if((s
.cmd
!= "") && (s
.target_pid
))
755 cerr
<< "You can't specify -c and -x options together." <<endl
;
759 if (!s
.kernel_symtab_path
.empty())
761 if (s
.consult_symtab
)
763 cerr
<< "You can't specify --kelf and --kmap together." << endl
;
766 s
.consult_symtab
= true;
767 if (s
.kernel_symtab_path
== PATH_TBD
)
768 s
.kernel_symtab_path
= string("/boot/System.map-") + s
.kernel_release
;
771 // Warn in case the target kernel release doesn't match the running one.
772 if (s
.last_pass
> 4 &&
773 (string(buf
.release
) != s
.kernel_release
||
774 string(buf
.machine
) != s
.architecture
))
776 if(! s
.suppress_warnings
)
777 cerr
<< "WARNING: kernel release/architecture mismatch with host forces last-pass 4." << endl
;
781 for (int i
= optind
; i
< argc
; i
++)
785 script_file
= string (argv
[i
]);
789 s
.args
.push_back (string (argv
[i
]));
795 cerr
<< "A script must be specified." << endl
;
799 // translate path of runtime to absolute path
800 if (s
.runtime_path
[0] != '/')
803 if (getcwd(cwd
, sizeof(cwd
)))
805 s
.runtime_path
= string(cwd
) + "/" + s
.runtime_path
;
811 // PASS 0: setting up
812 s
.verbose
= s
.perpass_verbose
[0];
814 // For PR1477, we used to override $PATH and $LC_ALL and other stuff
815 // here. We seem to use complete pathnames in
816 // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
817 // it interferes with util.cxx:find_executable(), used for $PATH
820 s
.kernel_base_release
.assign(s
.kernel_release
, 0, s
.kernel_release
.find('-'));
822 // arguments parsed; get down to business
826 clog
<< "Session arch: " << s
.architecture
827 << " release: " << s
.kernel_release
831 // Create a temporary directory to build within.
832 // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end.
834 const char* tmpdir_env
= getenv("TMPDIR");
838 string stapdir
= "/stapXXXXXX";
839 string tmpdirt
= tmpdir_env
+ stapdir
;
840 mode_t mask
= umask(0);
841 const char* tmpdir
= mkdtemp((char *)tmpdirt
.c_str());
845 const char* e
= strerror (errno
);
846 cerr
<< "ERROR: cannot create temporary directory (\"" << tmpdirt
<< "\"): " << e
<< endl
;
853 clog
<< "Created temporary directory \"" << s
.tmpdir
<< "\"" << endl
;
856 // Create the name of the C source file within the temporary
858 s
.translated_source
= string(s
.tmpdir
) + "/" + s
.module_name
+ ".c";
860 // Set up our handler to catch routine signals, to allow clean
861 // and reasonably timely exit.
862 setup_signals(&handle_interrupt
);
864 struct tms tms_before
;
865 times (& tms_before
);
866 struct timeval tv_before
;
867 gettimeofday (&tv_before
, NULL
);
869 // PASS 1a: PARSING USER SCRIPT
871 struct stat user_file_stat
;
872 int user_file_stat_rc
= -1;
874 if (script_file
== "-")
876 s
.user_file
= parser::parse (s
, cin
, s
.guru_mode
);
877 user_file_stat_rc
= fstat (STDIN_FILENO
, & user_file_stat
);
879 else if (script_file
!= "")
881 s
.user_file
= parser::parse (s
, script_file
, s
.guru_mode
);
882 user_file_stat_rc
= stat (script_file
.c_str(), & user_file_stat
);
886 istringstream
ii (cmdline_script
);
887 s
.user_file
= parser::parse (s
, ii
, s
.guru_mode
);
889 if (s
.user_file
== 0)
890 // syntax errors already printed
893 // Construct arch / kernel-versioning search path
894 vector
<string
> version_suffixes
;
895 string kvr
= s
.kernel_release
;
896 const string
& arch
= s
.architecture
;
897 // add full kernel-version-release (2.6.NN-FOOBAR) + arch
898 version_suffixes
.push_back ("/" + kvr
+ "/" + arch
);
899 version_suffixes
.push_back ("/" + kvr
);
900 // add kernel version (2.6.NN) + arch
901 if (kvr
!= s
.kernel_base_release
) {
902 kvr
= s
.kernel_base_release
;
903 version_suffixes
.push_back ("/" + kvr
+ "/" + arch
);
904 version_suffixes
.push_back ("/" + kvr
);
906 // add kernel family (2.6) + arch
907 string::size_type dot1_index
= kvr
.find ('.');
908 string::size_type dot2_index
= kvr
.rfind ('.');
909 while (dot2_index
> dot1_index
&& dot2_index
!= string::npos
) {
910 kvr
.erase(dot2_index
);
911 version_suffixes
.push_back ("/" + kvr
+ "/" + arch
);
912 version_suffixes
.push_back ("/" + kvr
);
913 dot2_index
= kvr
.rfind ('.');
915 // add architecture search path
916 version_suffixes
.push_back("/" + arch
);
917 // add empty string as last element
918 version_suffixes
.push_back ("");
920 // PASS 1b: PARSING LIBRARY SCRIPTS
921 for (unsigned i
=0; i
<s
.include_path
.size(); i
++)
923 // now iterate upon it
924 for (unsigned k
=0; k
<version_suffixes
.size(); k
++)
927 string dir
= s
.include_path
[i
] + version_suffixes
[k
] + "/*.stp";
928 int r
= glob(dir
.c_str (), 0, NULL
, & globbuf
);
929 if (r
== GLOB_NOSPACE
|| r
== GLOB_ABORTED
)
931 // GLOB_NOMATCH is acceptable
933 if (s
.verbose
>1 && globbuf
.gl_pathc
> 0)
934 clog
<< "Searched '" << dir
<< "', "
935 << "found " << globbuf
.gl_pathc
<< endl
;
937 for (unsigned j
=0; j
<globbuf
.gl_pathc
; j
++)
939 if (pending_interrupts
)
942 // XXX: privilege only for /usr/share/systemtap?
943 stapfile
* f
= parser::parse (s
, globbuf
.gl_pathv
[j
], true);
947 s
.library_files
.push_back (f
);
949 struct stat tapset_file_stat
;
950 int stat_rc
= stat (globbuf
.gl_pathv
[j
], & tapset_file_stat
);
951 if (stat_rc
== 0 && user_file_stat_rc
== 0 &&
952 user_file_stat
.st_dev
== tapset_file_stat
.st_dev
&&
953 user_file_stat
.st_ino
== tapset_file_stat
.st_ino
)
955 clog
<< "usage error: tapset file '" << globbuf
.gl_pathv
[j
]
956 << "' cannot be run directly as a session script." << endl
;
962 globfree (& globbuf
);
966 if (rc
== 0 && s
.last_pass
== 1)
968 cout
<< "# parse tree dump" << endl
;
969 s
.user_file
->print (cout
);
972 for (unsigned i
=0; i
<s
.library_files
.size(); i
++)
974 s
.library_files
[i
]->print (cout
);
979 struct tms tms_after
;
981 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
982 struct timeval tv_after
;
983 gettimeofday (&tv_after
, NULL
);
986 (tms_after.tms_cutime + tms_after.tms_utime \
987 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
988 << (tms_after.tms_cstime + tms_after.tms_stime \
989 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
990 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
991 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
993 // syntax errors, if any, are already printed
996 clog
<< "Pass 1: parsed user script and "
997 << s
.library_files
.size()
998 << " library script(s) in "
1003 if (rc
&& !s
.listing_mode
)
1004 cerr
<< "Pass 1: parse failed. "
1005 << "Try again with another '--vp 1' option."
1008 if (rc
|| s
.last_pass
== 1 || pending_interrupts
) goto cleanup
;
1010 times (& tms_before
);
1011 gettimeofday (&tv_before
, NULL
);
1013 // PASS 2: ELABORATION
1014 s
.verbose
= s
.perpass_verbose
[1];
1015 rc
= semantic_pass (s
);
1017 if (s
.listing_mode
|| (rc
== 0 && s
.last_pass
== 2))
1018 printscript(s
, cout
);
1020 times (& tms_after
);
1021 gettimeofday (&tv_after
, NULL
);
1023 if (s
.verbose
) clog
<< "Pass 2: analyzed script: "
1024 << s
.probes
.size() << " probe(s), "
1025 << s
.functions
.size() << " function(s), "
1026 << s
.embeds
.size() << " embed(s), "
1027 << s
.globals
.size() << " global(s) in "
1031 if (rc
&& !s
.listing_mode
)
1032 cerr
<< "Pass 2: analysis failed. "
1033 << "Try again with another '--vp 01' option."
1035 // Generate hash. There isn't any point in generating the hash
1036 // if last_pass is 2, since we'll quit before using it.
1037 else if (s
.last_pass
!= 2 && s
.use_cache
)
1040 unsigned saved_verbose
;
1043 // Make sure we're in verbose mode, so that printscript()
1044 // will output function/probe bodies.
1045 saved_verbose
= s
.verbose
;
1047 printscript(s
, o
); // Print script to 'o'
1048 s
.verbose
= saved_verbose
;
1052 find_hash (s
, o
.str());
1054 // See if we can use cached source/module.
1055 if (get_from_cache(s
))
1057 // If our last pass isn't 5, we're done (since passes 3 and
1058 // 4 just generate what we just pulled out of the cache).
1059 if (s
.last_pass
< 5 || pending_interrupts
) goto cleanup
;
1061 // Short-circuit to pass 5.
1066 if (rc
|| s
.listing_mode
|| s
.last_pass
== 2 || pending_interrupts
) goto cleanup
;
1068 // PASS 3: TRANSLATION
1069 s
.verbose
= s
.perpass_verbose
[2];
1070 times (& tms_before
);
1071 gettimeofday (&tv_before
, NULL
);
1073 rc
= translate_pass (s
);
1075 if (rc
== 0 && s
.last_pass
== 3)
1077 ifstream
i (s
.translated_source
.c_str());
1081 times (& tms_after
);
1082 gettimeofday (&tv_after
, NULL
);
1084 if (s
.verbose
) clog
<< "Pass 3: translated to C into \""
1085 << s
.translated_source
1091 cerr
<< "Pass 3: translation failed. "
1092 << "Try again with another '--vp 001' option."
1095 if (rc
|| s
.last_pass
== 3 || pending_interrupts
) goto cleanup
;
1097 // PASS 4: COMPILATION
1098 s
.verbose
= s
.perpass_verbose
[3];
1099 times (& tms_before
);
1100 gettimeofday (&tv_before
, NULL
);
1101 rc
= compile_pass (s
);
1103 if (rc
== 0 && s
.last_pass
== 4)
1105 cout
<< ((s
.hash_path
== "") ? (s
.module_name
+ string(".ko")) : s
.hash_path
);
1109 times (& tms_after
);
1110 gettimeofday (&tv_after
, NULL
);
1112 if (s
.verbose
) clog
<< "Pass 4: compiled C into \""
1113 << s
.module_name
<< ".ko"
1119 cerr
<< "Pass 4: compilation failed. "
1120 << "Try again with another '--vp 0001' option."
1124 // Update cache. Cache cleaning is kicked off at the end of this function.
1128 // We may need to save the module in $CWD if the cache was
1129 // inaccessible for some reason.
1130 if (! s
.use_cache
&& s
.last_pass
== 4)
1133 // Copy module to the current directory.
1134 if (save_module
&& !pending_interrupts
)
1136 string module_src_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
1137 string module_dest_path
= s
.module_name
+ ".ko";
1140 clog
<< "Copying " << module_src_path
<< " to "
1141 << module_dest_path
<< endl
;
1142 if (copy_file(module_src_path
.c_str(), module_dest_path
.c_str()) != 0)
1143 cerr
<< "Copy failed (\"" << module_src_path
<< "\" to \""
1144 << module_dest_path
<< "\"): " << strerror(errno
) << endl
;
1147 // Save the signature as well.
1148 assert (! s
.cert_db_path
.empty());
1149 module_src_path
+= ".sgn";
1150 module_dest_path
+= ".sgn";
1153 clog
<< "Copying " << module_src_path
<< " to "
1154 << module_dest_path
<< endl
;
1155 if (copy_file(module_src_path
.c_str(), module_dest_path
.c_str()) != 0)
1156 cerr
<< "Copy failed (\"" << module_src_path
<< "\" to \""
1157 << module_dest_path
<< "\"): " << strerror(errno
) << endl
;
1162 if (rc
|| s
.last_pass
== 4 || pending_interrupts
) goto cleanup
;
1167 s
.verbose
= s
.perpass_verbose
[4];
1168 times (& tms_before
);
1169 gettimeofday (&tv_before
, NULL
);
1170 // NB: this message is a judgement call. The other passes don't emit
1171 // a "hello, I'm starting" message, but then the others aren't interactive
1172 // and don't take an indefinite amount of time.
1173 if (s
.verbose
) clog
<< "Pass 5: starting run." << endl
;
1175 times (& tms_after
);
1176 gettimeofday (&tv_after
, NULL
);
1177 if (s
.verbose
) clog
<< "Pass 5: run completed in "
1182 cerr
<< "Pass 5: run failed. "
1183 << "Try again with another '--vp 00001' option."
1186 // if (rc) goto cleanup;
1188 // PASS 6: cleaning up
1191 // update the database information
1192 if (!rc
&& s
.tapset_compile_coverage
&& !pending_interrupts
) {
1193 #ifdef HAVE_LIBSQLITE3
1194 update_coverage_db(s
);
1196 cerr
<< "Coverage database not available without libsqlite3" << endl
;
1200 // Clean up temporary directory. Obviously, be careful with this.
1206 clog
<< "Keeping temporary directory \"" << s
.tmpdir
<< "\"" << endl
;
1209 // Ignore signals while we're deleting the temporary directory.
1210 setup_signals (SIG_IGN
);
1212 // Remove the temporary directory.
1213 string cleanupcmd
= "rm -rf ";
1214 cleanupcmd
+= s
.tmpdir
;
1215 if (s
.verbose
>1) clog
<< "Running " << cleanupcmd
<< endl
;
1216 int status
= stap_system (cleanupcmd
.c_str());
1217 if (status
!= 0 && s
.verbose
>1)
1218 clog
<< "Cleanup command failed, status: " << status
<< endl
;
1222 return (rc
||pending_interrupts
) ? EXIT_FAILURE
: EXIT_SUCCESS
;
1225 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.14449 seconds and 5 git commands to generate.