session.cxx - systemtap
Functions defined
Macros defined
Source code
#include "config.h"
#include "session.h"
#include "cache.h"
#include "stapregex.h"
#include "elaborate.h"
#include "translate.h"
#include "buildrun.h"
#include "coveragedb.h"
#include "hash.h"
#include "task_finder.h"
#include "csclient.h"
#include "rpm_finder.h"
#include "util.h"
#include "cmdline.h"
#include "git_version.h"
#include "version.h"
#include <cerrno>
#include <cstdlib>
extern "C" {
#include <getopt.h>
#include <limits.h>
#include <grp.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <sys/resource.h>
#include <elfutils/libdwfl.h>
#include <elfutils/version.h>
#include <unistd.h>
#include <sys/wait.h>
#include <wordexp.h>
}
#if HAVE_NSS
extern "C" {
#include <nspr.h>
}
#endif
#include <string>
using namespace std;
extern int optind;
#define PATH_TBD string("__TBD__")
#if HAVE_NSS
bool systemtap_session::NSPR_Initialized = false;
#endif
systemtap_session::systemtap_session ():
runtime_mode(kernel_runtime),
base_hash(0),
pattern_root(new match_node),
dfa_counter (0),
dfa_maxstate (0),
dfa_maxtag (0),
need_tagged_dfa (false),
be_derived_probes(0),
dwarf_derived_probes(0),
kprobe_derived_probes(0),
hwbkpt_derived_probes(0),
perf_derived_probes(0),
uprobe_derived_probes(0),
utrace_derived_probes(0),
itrace_derived_probes(0),
task_finder_derived_probes(0),
timer_derived_probes(0),
netfilter_derived_probes(0),
profile_derived_probes(0),
mark_derived_probes(0),
tracepoint_derived_probes(0),
hrtimer_derived_probes(0),
procfs_derived_probes(0),
dynprobe_derived_probes(0),
op (0), up (0),
sym_kprobes_text_start (0),
sym_kprobes_text_end (0),
sym_stext (0),
module_cache (0),
benchmark_sdt_loops(0),
benchmark_sdt_threads(0),
suppressed_warnings(0),
suppressed_errors(0),
warningerr_count(0),
last_token (0)
{
struct utsname buf;
(void) uname (& buf);
kernel_release = string (buf.release);
release = kernel_release;
kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
architecture = machine = normalize_machine(buf.machine);
for (unsigned i=0; i<5; i++) perpass_verbose[i]=0;
verbose = 0;
have_script = false;
runtime_specified = false;
include_arg_start = -1;
timing = false;
guru_mode = false;
bulk_mode = false;
unoptimized = false;
suppress_warnings = false;
panic_warnings = false;
dump_mode = systemtap_session::dump_none;
dump_matched_pattern = "";
#ifdef ENABLE_PROLOGUES
prologue_searching = true;
#else
prologue_searching = false;
#endif
buffer_size = 0;
last_pass = 5;
module_name = "stap_" + lex_cast(getpid());
stapconf_name = "stapconf_" + lex_cast(getpid()) + ".h";
output_file = ""; tmpdir_opt_set = false;
save_module = false;
save_uprobes = false;
modname_given = false;
keep_tmpdir = false;
cmd = "";
target_pid = 0;
use_cache = true;
use_script_cache = true;
poison_cache = false;
tapset_compile_coverage = false;
need_uprobes = false;
need_unwind = false;
need_symbols = false;
uprobes_path = "";
load_only = false;
skip_badvars = false;
privilege = pr_stapdev;
privilege_set = false;
omit_werror = false;
compatible = VERSION; XXX unwindsym_ldd = false;
client_options = false;
server_cache = NULL;
auto_privilege_level_msg = "";
auto_server_msgs.clear ();
use_server_on_error = false;
try_server_status = try_server_unset;
use_remote_prefix = false;
systemtap_v_check = false;
download_dbinfo = 0;
suppress_handler_errors = false;
native_build = true; sysroot = "";
update_release_sysroot = false;
suppress_time_limits = false;
color_mode = color_auto;
color_errors = isatty(STDERR_FILENO) && strcmp(getenv("TERM") ?: "notdumb", "dumb");
const char* s_p = getenv ("SYSTEMTAP_TAPSET");
if (s_p != NULL)
{
include_path.push_back (s_p);
}
else
{
include_path.push_back (string(PKGDATADIR) + "/tapset");
}
const char* s_p1 = getenv ("XDG_DATA_DIRS");
if ( s_p1 != NULL )
{
vector<string> dirs;
tokenize(s_p1, dirs, ":");
for(vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i)
{
include_path.push_back(*i + "/systemtap/tapset");
}
}
const char* s_r = getenv ("SYSTEMTAP_RUNTIME");
if (s_r != NULL)
runtime_path = s_r;
else
runtime_path = string(PKGDATADIR) + "/runtime";
const char* s_d = getenv ("SYSTEMTAP_DIR");
if (s_d != NULL)
data_path = s_d;
else
data_path = get_home_directory() + string("/.systemtap");
if (create_dir(data_path.c_str()) == 1)
{
const char* e = strerror (errno);
print_warning("failed to create systemtap data directory \"" + data_path + "\" " + e + ", disabling cache support.");
use_cache = use_script_cache = false;
}
if (use_cache)
{
cache_path = data_path + "/cache";
if (create_dir(cache_path.c_str()) == 1)
{
const char* e = strerror (errno);
print_warning("failed to create cache directory (\" " + cache_path + " \") " + e + ", disabling cache support.");
use_cache = use_script_cache = false;
}
}
const char* s_tc = getenv ("SYSTEMTAP_COVERAGE");
if (s_tc != NULL)
tapset_compile_coverage = true;
const char* s_kr = getenv ("SYSTEMTAP_RELEASE");
if (s_kr != NULL) {
setup_kernel_release(s_kr);
}
create_tmp_dir();
}
systemtap_session::systemtap_session (const systemtap_session& other,
const string& arch,
const string& kern):
runtime_mode(other.runtime_mode),
base_hash(0),
pattern_root(new match_node),
user_files (other.user_files),
dfa_counter(0),
dfa_maxtag (0),
need_tagged_dfa(other.need_tagged_dfa),
be_derived_probes(0),
dwarf_derived_probes(0),
kprobe_derived_probes(0),
hwbkpt_derived_probes(0),
perf_derived_probes(0),
uprobe_derived_probes(0),
utrace_derived_probes(0),
itrace_derived_probes(0),
task_finder_derived_probes(0),
timer_derived_probes(0),
netfilter_derived_probes(0),
profile_derived_probes(0),
mark_derived_probes(0),
tracepoint_derived_probes(0),
hrtimer_derived_probes(0),
procfs_derived_probes(0),
dynprobe_derived_probes(0),
op (0), up (0),
sym_kprobes_text_start (0),
sym_kprobes_text_end (0),
sym_stext (0),
module_cache (0),
benchmark_sdt_loops(other.benchmark_sdt_loops),
benchmark_sdt_threads(other.benchmark_sdt_threads),
suppressed_warnings(0),
suppressed_errors(0),
warningerr_count(0),
last_token (0)
{
release = kernel_release = kern;
kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
architecture = machine = normalize_machine(arch);
setup_kernel_release(kern.c_str());
native_build = false; XXX
copy(other.perpass_verbose, other.perpass_verbose + 5, perpass_verbose);
verbose = other.verbose;
have_script = other.have_script;
runtime_specified = other.runtime_specified;
include_arg_start = other.include_arg_start;
timing = other.timing;
guru_mode = other.guru_mode;
bulk_mode = other.bulk_mode;
unoptimized = other.unoptimized;
suppress_warnings = other.suppress_warnings;
panic_warnings = other.panic_warnings;
dump_mode = other.dump_mode;
dump_matched_pattern = other.dump_matched_pattern;
prologue_searching = other.prologue_searching;
buffer_size = other.buffer_size;
last_pass = other.last_pass;
module_name = other.module_name;
stapconf_name = other.stapconf_name;
output_file = other.output_file; XXX tmpdir_opt_set = false;
save_module = other.save_module;
save_uprobes = other.save_uprobes;
modname_given = other.modname_given;
keep_tmpdir = other.keep_tmpdir;
cmd = other.cmd;
target_pid = other.target_pid; XXX use_cache = other.use_cache;
use_script_cache = other.use_script_cache;
poison_cache = other.poison_cache;
tapset_compile_coverage = other.tapset_compile_coverage;
need_uprobes = false;
need_unwind = false;
need_symbols = false;
uprobes_path = "";
load_only = other.load_only;
skip_badvars = other.skip_badvars;
privilege = other.privilege;
privilege_set = other.privilege_set;
omit_werror = other.omit_werror;
compatible = other.compatible;
unwindsym_ldd = other.unwindsym_ldd;
client_options = other.client_options;
server_cache = NULL;
use_server_on_error = other.use_server_on_error;
try_server_status = other.try_server_status;
use_remote_prefix = other.use_remote_prefix;
systemtap_v_check = other.systemtap_v_check;
download_dbinfo = other.download_dbinfo;
suppress_handler_errors = other.suppress_handler_errors;
sysroot = other.sysroot;
update_release_sysroot = other.update_release_sysroot;
sysenv = other.sysenv;
suppress_time_limits = other.suppress_time_limits;
color_errors = other.color_errors;
color_mode = other.color_mode;
include_path = other.include_path;
runtime_path = other.runtime_path;
data_path = other.data_path;
cache_path = other.cache_path;
tapset_compile_coverage = other.tapset_compile_coverage;
script_file = other.script_file;
cmdline_script = other.cmdline_script;
additional_scripts = other.additional_scripts;
c_macros = other.c_macros;
args = other.args;
kbuildflags = other.kbuildflags;
globalopts = other.globalopts;
modinfos = other.modinfos;
client_options_disallowed_for_unprivileged = other.client_options_disallowed_for_unprivileged;
server_status_strings = other.server_status_strings;
specified_servers = other.specified_servers;
server_trust_spec = other.server_trust_spec;
server_args = other.server_args;
mok_fingerprints = other.mok_fingerprints;
unwindsym_modules = other.unwindsym_modules;
auto_privilege_level_msg = other.auto_privilege_level_msg;
auto_server_msgs = other.auto_server_msgs;
create_tmp_dir();
}
systemtap_session::~systemtap_session ()
{
remove_tmp_dir();
delete_map(subsessions);
delete pattern_root;
}
const string
systemtap_session::module_filename() const
{
if (runtime_usermode_p())
return module_name + ".so";
return module_name + ".ko";
}
#if HAVE_NSS
void
systemtap_session::NSPR_init ()
{
if (! NSPR_Initialized)
{
PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
NSPR_Initialized = true;
}
}
#endif
systemtap_session*
systemtap_session::clone(const string& arch, const string& release)
{
const string norm_arch = normalize_machine(arch);
if (this->architecture == norm_arch && this->kernel_release == release)
return this;
systemtap_session*& s = subsessions[make_pair(norm_arch, release)];
if (!s)
s = new systemtap_session(*this, norm_arch, release);
return s;
}
string
systemtap_session::version_string ()
{
string elfutils_version1;
#ifdef _ELFUTILS_VERSION
elfutils_version1 = "0." + lex_cast(_ELFUTILS_VERSION);
#endif
string elfutils_version2 = dwfl_version(NULL);
if (elfutils_version1 != elfutils_version2)
elfutils_version2 += string("/") + elfutils_version1;
return string (VERSION) + "/" + elfutils_version2 + ", " + STAP_EXTENDED_VERSION;
}
void
systemtap_session::version ()
{
cout << _F("Systemtap translator/driver (version %s)\n"
"Copyright (C) 2005-2014 Red Hat, Inc. and others\n"
"This is free software; see the source for copying conditions.\n",
version_string().c_str());
cout << _("enabled features:")
#ifdef HAVE_AVAHI
<< " AVAHI"
#endif
#ifdef HAVE_LIBRPM
<< " LIBRPM"
#endif
#ifdef HAVE_LIBSQLITE3
<< " LIBSQLITE3"
#endif
#ifdef HAVE_NSS
<< " NSS"
#endif
#ifdef HAVE_BOOST_SHARED_PTR_HPP
<< " BOOST_SHARED_PTR"
#endif
#ifdef HAVE_TR1_UNORDERED_MAP
<< " TR1_UNORDERED_MAP"
#endif
#ifdef ENABLE_PROLOGUES
<< " PROLOGUES"
#endif
#ifdef ENABLE_NLS
<< " NLS"
#endif
#ifdef HAVE_DYNINST
<< " DYNINST"
#endif
#ifdef HAVE_JAVA
<< " JAVA"
#endif
#ifdef HAVE_LIBVIRT
<< " LIBVIRT"
#endif
#ifdef HAVE_LIBXML2
<< " LIBXML2"
#endif
<< endl;
}
void
systemtap_session::usage (int exitcode)
{
if (exitcode != EXIT_SUCCESS)
{
clog << _("Try '--help' for more information.") << endl;
throw exit_exception(exitcode);
}
version ();
cout
<< endl
<< _F(
"Usage: stap [options] FILE Run script in file.\n"
" or: stap [options] - Run script on stdin.\n"
" or: stap [options] -e SCRIPT Run given script.\n"
" or: stap [options] -l PROBE List matching probes.\n"
" or: stap [options] -L PROBE List matching probes and local variables.\n"
" or: stap [options] --dump-probe-types List available probe types.\n"
" or: stap [options] --dump-probe-aliases List available probe aliases.\n"
" or: stap [options] --dump-functions List available functions.\n\n"
"Options (in %s/rc and on command line):\n"
" -- end of translator options, script options follow\n"
" -h --help show help\n"
" -V --version show version\n"
" -p NUM stop after pass NUM 1-5, instead of %d\n"
" (parse, elaborate, translate, compile, run)\n"
" -v add verbosity to all passes\n"
" --vp {N}+ add per-pass verbosity [", data_path.c_str(), last_pass);
for (unsigned i=0; i<5; i++)
cout << (perpass_verbose[i] <= 9 ? perpass_verbose[i] : 9);
cout
<< "]" << endl;
cout << _F(" -k keep temporary directory\n"
" -u unoptimized translation %s\n"
" -w suppress warnings %s\n"
" -W turn warnings into errors %s\n"
" -g guru mode %s\n"
" -P prologue-searching for function probes %s\n"
" -b bulk (percpu file) mode %s\n"
" -s NUM buffer size in megabytes, instead of %d\n"
" -I DIR look in DIR for additional .stp script files", (unoptimized ? _(" [set]") : ""),
(suppress_warnings ? _(" [set]") : ""), (panic_warnings ? _(" [set]") : ""),
(guru_mode ? _(" [set]") : ""), (prologue_searching ? _(" [set]") : ""),
(bulk_mode ? _(" [set]") : ""), buffer_size);
if (include_path.size() == 0)
cout << endl;
else
cout << _(", in addition to") << endl;
for (unsigned i=0; i<include_path.size(); i++)
cout << " " << include_path[i].c_str() << endl;
cout
<< _F(" -D NM=VAL emit macro definition into generated C code\n"
" -B NM=VAL pass option to kbuild make\n"
" --modinfo NM=VAL\n"
" include a MODULE_INFO(NM,VAL) in the generated C code\n"
" -G VAR=VAL set global variable to value\n"
" -R DIR look in DIR for runtime, instead of\n"
" %s\n"
" -r DIR cross-compile to kernel with given build tree; or else\n"
" -r RELEASE cross-compile to kernel /lib/modules/RELEASE/build, instead of\n"
" %s\n"
" -a ARCH cross-compile to given architecture, instead of %s\n"
" -m MODULE set probe module name, instead of \n"
" %s\n"
" -o FILE send script output to file, instead of stdout. This supports\n"
" strftime(3) formats for FILE\n"
" -E SCRIPT run the SCRIPT in addition to the main script specified\n"
" through -e or a script file\n"
" -c CMD start the probes, run CMD, and exit when it finishes\n"
" -x PID sets target() to PID\n"
" -F run as on-file flight recorder with -o.\n"
" run as on-memory flight recorder without -o.\n"
" -S size[,n] set maximum of the size and the number of files.\n"
" -d OBJECT add unwind/symbol data for OBJECT file", runtime_path.c_str(), kernel_build_tree.c_str(), architecture.c_str(), module_name.c_str());
if (unwindsym_modules.size() == 0)
cout << endl;
else
cout << _(", in addition to") << endl;
{
vector<string> syms (unwindsym_modules.begin(), unwindsym_modules.end());
for (unsigned i=0; i<syms.size(); i++)
cout << " " << syms[i].c_str() << endl;
}
cout
<< _F(" --ldd add unwind/symbol data for all referenced object files.\n"
" --all-modules\n"
" add unwind/symbol data for all loaded kernel objects.\n"
" -t collect probe timing information\n"
#ifdef HAVE_LIBSQLITE3
" -q generate information on tapset coverage\n"
#endif " --runtime=MODE\n"
" set the pass-5 runtime mode, instead of kernel\n"
#ifdef HAVE_DYNINST
" --dyninst\n"
" shorthand for --runtime=dyninst\n"
#endif " --privilege=PRIVILEGE_LEVEL\n"
" check the script for constructs not allowed at the given privilege level\n"
" --unprivileged\n"
" equivalent to --privilege=stapusr\n"
" --compatible=VERSION\n"
" suppress incompatible language/tapset changes beyond VERSION,\n"
" instead of %s\n"
" --check-version\n"
" displays warnings where a syntax element may be \n"
" version dependent\n"
" --skip-badvars\n"
" substitute zero for bad context $variables\n"
" --suppress-handler-errors\n"
" catch all runtime errors, quietly skip probe handlers\n"
" --use-server[=SERVER-SPEC]\n"
" specify systemtap compile-servers\n"
" --list-servers[=PROPERTIES]\n"
" report on the status of the specified compile-servers:\n"
" all,specified,online,trusted,signer,compatible\n"
#if HAVE_NSS
" --trust-servers[=TRUST-SPEC]\n"
" add/revoke trust of specified compile-servers:\n"
" ssl,signer,all-users,revoke,no-prompt\n"
" --use-server-on-error[=yes/no]\n"
" retry compilation using a compile server upon compilation error\n"
#endif
" --remote=HOSTNAME\n"
" run pass 5 on the specified ssh host.\n"
" may be repeated for targeting multiple hosts.\n"
" --remote-prefix\n"
" prefix each line of remote output with a host index.\n"
" --tmpdir=NAME\n"
" specify name of temporary directory to be used.\n"
" --download-debuginfo[=OPTION]\n"
" automatically download debuginfo using ABRT.\n"
" yes,no,ask,<timeout value>\n"
" --dump-probe-types\n"
" show a list of available probe types.\n"
" --sysroot=DIR\n"
" specify sysroot directory where target files (executables,\n" " libraries, etc.) are located.\n"
" --sysenv=VAR=VALUE\n"
" provide an alternate value for an environment variable\n"
" where the value on a remote system differs. Path\n"
" variables (e.g. PATH, LD_LIBRARY_PATH) are assumed to be\n"
" relative to the sysroot.\n"
" --suppress-time-limits\n"
" disable -DSTP_OVERLOAD, -DMAXACTION, and -DMAXTRYACTION limits\n"
" --save-uprobes\n"
" save uprobes.ko to current directory if it is built from source\n"
, compatible.c_str()) << endl
;
time_t now;
time (& now);
struct tm* t = localtime (& now);
if (t && t->tm_mon*3 + t->tm_mday*173 == 0xb6)
cout << morehelp << endl;
throw exit_exception (exitcode);
}
int
systemtap_session::parse_cmdline (int argc, char * const argv [])
{
client_options_disallowed_for_unprivileged = "";
struct rlimit our_rlimit;
while (true)
{
char * num_endptr;
int grc = getopt_long (argc, argv, STAP_SHORT_OPTIONS, stap_long_options, NULL);
if (grc < 0)
break;
switch (grc)
{
case 'V':
version ();
throw exit_exception (EXIT_SUCCESS);
case 'v':
server_args.push_back (string ("-") + (char)grc);
for (unsigned i=0; i<5; i++)
perpass_verbose[i] ++;
verbose ++;
break;
case 'G':
assert_regexp_match("-G parameter", optarg, "^[a-z_][a-z0-9_]*=[a-z0-9_-]+$");
globalopts.push_back (string(optarg));
break;
case 't':
server_args.push_back (string ("-") + (char)grc);
timing = true;
break;
case 'w':
server_args.push_back (string ("-") + (char)grc);
suppress_warnings = true;
break;
case 'W':
server_args.push_back (string ("-") + (char)grc);
panic_warnings = true;
break;
case 'p':
last_pass = (int)strtoul(optarg, &num_endptr, 10);
if (*num_endptr != '\0' || last_pass < 1 || last_pass > 5)
{
cerr << _("Invalid pass number (should be 1-5).") << endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
break;
case 'I':
if (client_options)
client_options_disallowed_for_unprivileged += client_options_disallowed_for_unprivileged.empty () ? "-I" : ", -I";
if (include_arg_start == -1)
include_arg_start = include_path.size ();
include_path.push_back (string (optarg));
break;
case 'd':
server_args.push_back (string ("-") + (char)grc + optarg);
{
if (strlen (optarg) == 0)
{
cerr << _("Data object (-d) cannot be empty.") << endl;
return 1;
}
unwindsym_modules.insert (resolve_path (optarg));
break;
}
case 'e':
if (have_script)
{
cerr << _("Only one script can be given on the command line.")
<< endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
cmdline_script = string (optarg);
have_script = true;
break;
case 'E':
server_args.push_back (string("-") + (char)grc + optarg);
additional_scripts.push_back(string (optarg));
break;
case 'o':
server_args.push_back (string ("-") + (char)grc + optarg);
output_file = string (optarg);
break;
case 'R':
if (client_options) { cerr << _F("ERROR: %s invalid with %s", "-R", "--client-options") << endl; return 1; }
runtime_specified = true;
runtime_path = string (optarg);
break;
case 'm':
if (client_options)
client_options_disallowed_for_unprivileged += client_options_disallowed_for_unprivileged.empty () ? "-m" : ", -m";
module_name = string (optarg);
save_module = true;
modname_given = true;
{
if (endswith(module_name, ".ko") || endswith(module_name, ".so"))
{
module_name.erase(module_name.size() - 3);
cerr << _F("Truncating module name to '%s'", module_name.c_str()) << endl;
}
if (module_name.empty())
{
cerr << _("Module name cannot be empty.") << endl;
return 1;
}
assert_regexp_match("-m parameter", module_name, "^[a-z0-9_]+$");
if (module_name.size() >= (MODULE_NAME_LEN - 1))
{
module_name.resize(MODULE_NAME_LEN - 1);
cerr << _F("Truncating module name to '%s'", module_name.c_str()) << endl;
}
}
server_args.push_back (string ("-") + (char)grc + optarg);
use_script_cache = false;
break;
case 'r':
if (client_options) assert_regexp_match("-r parameter from client", optarg, "^[a-z0-9_.-]+$");
server_args.push_back (string ("-") + (char)grc + optarg);
setup_kernel_release(optarg);
break;
case 'a':
assert_regexp_match("-a parameter", optarg, "^[a-z0-9_-]+$");
server_args.push_back (string ("-") + (char)grc + optarg);
architecture = string(optarg);
break;
case 'k':
if (client_options) { cerr << _F("ERROR: %s invalid with %s", "-k", "--client-options") << endl; return 1; }
keep_tmpdir = true;
use_script_cache = false; break;
case 'g':
server_args.push_back (string ("-") + (char)grc);
guru_mode = true;
break;
case 'P':
server_args.push_back (string ("-") + (char)grc);
prologue_searching = true;
break;
case 'b':
server_args.push_back (string ("-") + (char)grc);
bulk_mode = true;
break;
case 'u':
server_args.push_back (string ("-") + (char)grc);
unoptimized = true;
break;
case 's':
buffer_size = (int) strtoul (optarg, &num_endptr, 10);
if (*num_endptr != '\0' || buffer_size < 1 || buffer_size > 4095)
{
cerr << _("Invalid buffer size (should be 1-4095).") << endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
break;
case 'c':
cmd = string (optarg);
if (cmd == "")
{
cerr << _("Empty CMD string invalid.") << endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
break;
case 'x':
target_pid = (int) strtoul(optarg, &num_endptr, 10);
if (*num_endptr != '\0')
{
cerr << _("Invalid target process ID number.") << endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
break;
case 'D':
assert_regexp_match ("-D parameter", optarg, "^[a-z_][a-z_0-9]*(=-?[a-z_0-9]+)?$");
if (client_options)
client_options_disallowed_for_unprivileged += client_options_disallowed_for_unprivileged.empty () ? "-D" : ", -D";
server_args.push_back (string ("-") + (char)grc + optarg);
c_macros.push_back (string (optarg));
break;
case 'S':
assert_regexp_match ("-S parameter", optarg, "^[0-9]+(,[0-9]+)?$");
server_args.push_back (string ("-") + (char)grc + optarg);
size_option = string (optarg);
break;
case 'q':
if (client_options) { cerr << _F("ERROR: %s invalid with %s", "-q", "--client-options") << endl; return 1; }
server_args.push_back (string ("-") + (char)grc);
tapset_compile_coverage = true;
break;
case 'h':
usage (0);
break;
case 'L':
if (dump_mode)
{
cerr << _("ERROR: only one of the -l/-L/--dump-* "
"switches may be specified") << endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
dump_mode = systemtap_session::dump_matched_probes_vars;
dump_matched_pattern = optarg;
unoptimized = true; suppress_warnings = true;
break;
case 'l':
if (dump_mode)
{
cerr << _("ERROR: only one of the -l/-L/--dump-* "
"switches may be specified") << endl;
return 1;
}
server_args.push_back (string ("-") + (char)grc + optarg);
dump_mode = systemtap_session::dump_matched_probes;
dump_matched_pattern = optarg;
suppress_warnings = true;
break;
case 'F':
server_args.push_back (string ("-") + (char)grc);
load_only = true;
break;
case 'B':
if (client_options) { cerr << _F("ERROR: %s invalid with %s", "-B", "--client-options") << endl; return 1; }
server_args.push_back (string ("-") + (char)grc + optarg);
kbuildflags.push_back (string (optarg));
break;
case LONG_OPT_VERSION:
version ();
throw exit_exception (EXIT_SUCCESS);
case LONG_OPT_VERBOSE_PASS:
{
bool ok = true;
if (strlen(optarg) < 1 || strlen(optarg) > 5)
ok = false;
if (ok)
{
for (unsigned i=0; i<strlen(optarg); i++)
if (isdigit (optarg[i]))
perpass_verbose[i] += optarg[i]-'0';
else
ok = false;
}
if (! ok)
{
cerr << _("Invalid --vp argument: it takes 1 to 5 digits.") << endl;
return 1;
}
server_args.push_back ("--vp=" + string(optarg));
break;
}
case LONG_OPT_SKIP_BADVARS:
server_args.push_back ("--skip-badvars");
skip_badvars = true;
break;
case LONG_OPT_PRIVILEGE:
{
privilege_t newPrivilege;
if (strcmp (optarg, "stapdev") == 0)
newPrivilege = pr_stapdev;
else if (strcmp (optarg, "stapsys") == 0)
newPrivilege = pr_stapsys;
else if (strcmp (optarg, "stapusr") == 0)
newPrivilege = pr_stapusr;
else
{
cerr << _F("Invalid argument '%s' for --privilege.", optarg) << endl;
return 1;
}
if (privilege_set && newPrivilege != privilege)
{
cerr << _("Privilege level may be set only once.") << endl;
return 1;
}
privilege = newPrivilege;
privilege_set = true;
server_args.push_back ("--privilege=" + string(optarg));
}
break;
case LONG_OPT_UNPRIVILEGED:
if (privilege_set && pr_unprivileged != privilege)
{
cerr << _("Privilege level may be set only once.") << endl;
return 1;
}
privilege = pr_unprivileged;
privilege_set = true;
server_args.push_back ("--unprivileged");
break;
case LONG_OPT_OMIT_WERROR:
server_args.push_back (OMIT_WERROR_NAME);
omit_werror = true;
break;
case LONG_OPT_CLIENT_OPTIONS:
client_options = true;
break;
case LONG_OPT_TMPDIR:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--tmpdir", "--client-options") << endl;
return 1;
}
tmpdir_opt_set = true;
tmpdir = optarg;
break;
case LONG_OPT_DOWNLOAD_DEBUGINFO:
if(optarg)
{
if(strcmp(optarg, "no") == 0)
download_dbinfo = 0; else if (strcmp(optarg, "yes") == 0)
download_dbinfo = INT_MAX; else if(atoi(optarg) > 0)
download_dbinfo = atoi(optarg); else if (strcmp(optarg, "ask") == 0)
download_dbinfo = -1; else
{
cerr << _F("ERROR: %s is not a valid value. Use 'yes', 'no', 'ask' or a timeout value.", optarg) << endl;
return 1;
}
}
else
download_dbinfo = INT_MAX; break;
case LONG_OPT_USE_SERVER:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--use-server", "--client-options") << endl;
return 1;
}
if (optarg)
specified_servers.push_back (optarg);
else
specified_servers.push_back ("");
break;
case LONG_OPT_USE_SERVER_ON_ERROR:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--use-server-on-error", "--client-options") << endl;
return 1;
}
if (optarg)
{
string arg = optarg;
for (unsigned i = 0; i < arg.size (); ++i)
arg[i] = tolower (arg[i]);
if (arg == "yes" || arg == "ye" || arg == "y")
use_server_on_error = true;
else if (arg == "no" || arg == "n")
use_server_on_error = false;
else
cerr << _F("Invalid argument '%s' for --use-server-on-error.", optarg) << endl;
}
else
use_server_on_error = true;
break;
case LONG_OPT_LIST_SERVERS:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--list-servers", "--client-options") << endl;
return 1;
}
if (optarg)
server_status_strings.push_back (optarg);
else
server_status_strings.push_back ("");
break;
case LONG_OPT_TRUST_SERVERS:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--trust-servers", "--client-options") << endl;
return 1;
}
if (optarg)
server_trust_spec = optarg;
else
server_trust_spec = "ssl";
break;
case LONG_OPT_HELP:
usage (0);
break;
case LONG_OPT_DISABLE_CACHE:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--disable-cache", "--client-options") << endl;
return 1;
}
use_cache = use_script_cache = false;
break;
case LONG_OPT_POISON_CACHE:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--poison-cache", "--client-options") << endl;
return 1;
}
poison_cache = true;
break;
case LONG_OPT_CLEAN_CACHE:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--clean-cache", "--client-options") << endl;
return 1;
}
clean_cache(*this);
throw exit_exception(EXIT_SUCCESS);
case LONG_OPT_COMPATIBLE:
server_args.push_back ("--compatible=" + string(optarg));
if (strverscmp(optarg, VERSION) > 0) {
cerr << _F("ERROR: systemtap version %s cannot be compatible with future version %s", VERSION, optarg)
<< endl;
return 1;
}
compatible = optarg;
break;
case LONG_OPT_LDD:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--ldd", "--client-options") << endl;
return 1;
}
unwindsym_ldd = true;
break;
case LONG_OPT_ALL_MODULES:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--all-modules", "--client-options") << endl;
return 1;
}
insert_loaded_modules();
break;
case LONG_OPT_REMOTE:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--remote", "--client-options") << endl;
return 1;
}
remote_uris.push_back(optarg);
break;
case LONG_OPT_REMOTE_PREFIX:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--remote-prefix", "--client-options") << endl;
return 1;
}
use_remote_prefix = true;
break;
case LONG_OPT_CHECK_VERSION:
server_args.push_back ("--check-version");
systemtap_v_check = true;
break;
case LONG_OPT_DUMP_PROBE_TYPES:
if (dump_mode)
{
cerr << _("ERROR: only one of the -l/-L/--dump-* "
"switches may be specified") << endl;
return 1;
}
server_args.push_back ("--dump-probe-types");
dump_mode = systemtap_session::dump_probe_types;
break;
case LONG_OPT_DUMP_PROBE_ALIASES:
if (dump_mode)
{
cerr << _("ERROR: only one of the -l/-L/--dump-* "
"switches may be specified") << endl;
return 1;
}
server_args.push_back ("--dump-probe-aliases");
suppress_warnings = true;
dump_mode = systemtap_session::dump_probe_aliases;
break;
case LONG_OPT_DUMP_FUNCTIONS:
if (dump_mode)
{
cerr << _("ERROR: only one of the -l/-L/--dump-* "
"switches may be specified") << endl;
return 1;
}
server_args.push_back ("--dump-functions");
suppress_warnings = true;
dump_mode = systemtap_session::dump_functions;
unoptimized = true; break;
case LONG_OPT_SUPPRESS_HANDLER_ERRORS:
suppress_handler_errors = true;
c_macros.push_back (string ("STAP_SUPPRESS_HANDLER_ERRORS"));
break;
case LONG_OPT_MODINFO:
if (client_options) {
cerr << _F("ERROR: %s is invalid with %s", "--modinfo", "--client-options") << endl;
return 1;
}
assert_regexp_match("--modinfo parameter", optarg, "^[a-z_][a-z0-9_]*=.+$");
modinfos.push_back (string(optarg));
break;
case LONG_OPT_RLIMIT_AS:
if(getrlimit(RLIMIT_AS, & our_rlimit))
cerr << _F("Unable to obtain resource limits for rlimit_as : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = strtoul (optarg, &num_endptr, 0);
if(*num_endptr || setrlimit (RLIMIT_AS, & our_rlimit))
cerr << _F("Unable to set resource limits for rlimit_as : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = 0;
(void) setrlimit (RLIMIT_CORE, & our_rlimit);
break;
case LONG_OPT_RLIMIT_CPU:
if(getrlimit(RLIMIT_CPU, & our_rlimit))
cerr << _F("Unable to obtain resource limits for rlimit_cpu : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = strtoul (optarg, &num_endptr, 0);
if(*num_endptr || setrlimit (RLIMIT_CPU, & our_rlimit))
cerr << _F("Unable to set resource limits for rlimit_cpu : %s", strerror (errno)) << endl;
break;
case LONG_OPT_RLIMIT_NPROC:
if(getrlimit(RLIMIT_NPROC, & our_rlimit))
cerr << _F("Unable to obtain resource limits for rlimit_nproc : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = strtoul (optarg, &num_endptr, 0);
if(*num_endptr || setrlimit (RLIMIT_NPROC, & our_rlimit))
cerr << _F("Unable to set resource limits for rlimit_nproc : %s", strerror (errno)) << endl;
break;
case LONG_OPT_RLIMIT_STACK:
if(getrlimit(RLIMIT_STACK, & our_rlimit))
cerr << _F("Unable to obtain resource limits for rlimit_stack : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = strtoul (optarg, &num_endptr, 0);
if(*num_endptr || setrlimit (RLIMIT_STACK, & our_rlimit))
cerr << _F("Unable to set resource limits for rlimit_stack : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = 0;
(void) setrlimit (RLIMIT_CORE, & our_rlimit);
break;
case LONG_OPT_RLIMIT_FSIZE:
if(getrlimit(RLIMIT_FSIZE, & our_rlimit))
cerr << _F("Unable to obtain resource limits for rlimit_fsize : %s", strerror (errno)) << endl;
our_rlimit.rlim_max = our_rlimit.rlim_cur = strtoul (optarg, &num_endptr, 0);
if(*num_endptr || setrlimit (RLIMIT_FSIZE, & our_rlimit))
cerr << _F("Unable to set resource limits for rlimit_fsize : %s", strerror (errno)) << endl;
break;
case LONG_OPT_SYSROOT:
if (client_options) {
cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl;
return 1;
} else if (!sysroot.empty()) {
cerr << "ERROR: multiple --sysroot options not supported" << endl;
return 1;
} else {
char *spath = canonicalize_file_name (optarg);
if (spath == NULL) {
cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
return 1;
}
sysroot = string(spath);
free (spath);
if (sysroot[sysroot.size() - 1] != '/')
sysroot.append("/");
break;
}
case LONG_OPT_SYSENV:
if (client_options) {
cerr << _F("ERROR: %s invalid with %s", "--sysenv", "--client-options") << endl;
return 1;
} else {
string sysenv_str = optarg;
string value;
size_t pos;
if (sysroot.empty()) {
cerr << "ERROR: --sysenv must follow --sysroot" << endl;
return 1;
}
pos = sysenv_str.find("=");
if (pos == string::npos) {
cerr << _F("ERROR: %s is an invalid argument for --sysenv", optarg) << endl;
return 1;
}
value = sysenv_str.substr(pos + 1);
sysenv[sysenv_str.substr(0, pos)] = value;
break;
}
case LONG_OPT_SUPPRESS_TIME_LIMITS: if (guru_mode == false)
{
cerr << _F("ERROR %s requires guru mode (-g)", "--suppress-time-limits") << endl;
return 1;
}
else
{
suppress_time_limits = true;
server_args.push_back (string ("--suppress-time-limits"));
c_macros.push_back (string ("STAP_SUPPRESS_TIME_LIMITS_ENABLE"));
break;
}
case LONG_OPT_RUNTIME:
if (!parse_cmdline_runtime (optarg))
return 1;
break;
case LONG_OPT_RUNTIME_DYNINST:
if (!parse_cmdline_runtime ("dyninst"))
return 1;
break;
case LONG_OPT_BENCHMARK_SDT:
XXX benchmark_sdt_threads = sysconf(_SC_NPROCESSORS_ONLN);
break;
case LONG_OPT_BENCHMARK_SDT_LOOPS:
assert(optarg != 0); XXX benchmark_sdt_loops = strtoul(optarg, NULL, 10);
break;
case LONG_OPT_BENCHMARK_SDT_THREADS:
assert(optarg != 0); XXX benchmark_sdt_threads = strtoul(optarg, NULL, 10);
break;
case LONG_OPT_COLOR_ERRS:
if (!optarg || !strcmp(optarg, "always"))
color_mode = color_always;
else if (!strcmp(optarg, "auto"))
color_mode = color_auto;
else if (!strcmp(optarg, "never"))
color_mode = color_never;
else {
cerr << _F("Invalid argument '%s' for --color.", optarg) << endl;
return 1;
}
color_errors = color_mode == color_always
|| (color_mode == color_auto && isatty(STDERR_FILENO) &&
strcmp(getenv("TERM") ?: "notdumb", "dumb"));
break;
case LONG_OPT_SAVE_UPROBES:
save_uprobes = true;
break;
case '?':
usage(1);
break;
default:
cerr << _F("Unhandled argument code %d", (char)grc) << endl;
return 1;
break;
}
}
return 0;
}
bool
systemtap_session::parse_cmdline_runtime (const string& opt_runtime)
{
if (opt_runtime == string("kernel"))
runtime_mode = kernel_runtime;
else if (opt_runtime == string("dyninst"))
{
#ifndef HAVE_DYNINST
cerr << _("ERROR: --runtime=dyninst unavailable; this build lacks DYNINST feature") << endl;
version();
return false;
#endif
if (privilege_set && pr_unprivileged != privilege)
{
cerr << _("ERROR: --runtime=dyninst implies unprivileged mode only") << endl;
return false;
}
privilege = pr_unprivileged;
privilege_set = true;
runtime_mode = dyninst_runtime;
}
else
{
cerr << _F("ERROR: %s is an invalid argument for --runtime", opt_runtime.c_str()) << endl;
return false;
}
return true;
}
void
systemtap_session::check_options (int argc, char * const argv [])
{
for (int i = optind; i < argc; i++)
{
if (! have_script && ! dump_mode)
{
script_file = string (argv[i]);
have_script = true;
}
else
args.push_back (string (argv[i]));
}
bool need_script = server_status_strings.empty () &&
server_trust_spec.empty () &&
!dump_mode;
if (benchmark_sdt_loops > 0 || benchmark_sdt_threads > 0)
{
if (client_options || !remote_uris.empty())
{
cerr << _("Benchmark options are only for local use.") << endl;
usage(1);
}
if (benchmark_sdt_loops == 0)
benchmark_sdt_loops = 10000000;
if (benchmark_sdt_threads == 0)
benchmark_sdt_threads = 1;
need_script = false;
}
if (need_script && ! have_script)
{
cerr << _("A script must be specified.") << endl;
usage(1);
}
if (dump_mode && have_script)
{
cerr << _("Cannot specify a script with -l/-L/--dump-* switches.") << endl;
usage(1);
}
if (dump_mode && last_pass != 5)
{
cerr << _("Cannot specify -p with -l/-L/--dump-* switches.") << endl;
usage(1);
}
#if ! HAVE_NSS
if (client_options)
print_warning("--client-options is not supported by this version of systemtap");
if (! server_status_strings.empty ())
{
print_warning("--list-servers is not supported by this version of systemtap");
server_status_strings.clear ();
}
if (! server_trust_spec.empty ())
{
print_warning("--trust-servers is not supported by this version of systemtap");
server_trust_spec.clear ();
}
#endif
if (runtime_specified && ! specified_servers.empty ())
{
print_warning("Ignoring --use-server due to the use of -R");
specified_servers.clear ();
}
if (client_options && last_pass > 4)
{
last_pass = 4; }
XXX if (last_pass > 4 && have_script && ! client_options &&
runtime_mode == kernel_runtime && remote_uris.empty())
{
privilege_t credentials = get_privilege_credentials ();
if (! privilege_set && ! pr_contains (credentials, privilege))
{
if (pr_contains (credentials, pr_stapsys))
{
privilege = pr_stapsys;
server_args.push_back ("--privilege=stapsys");
auto_privilege_level_msg =
_("--privilege=stapsys was automatically selected because you are a member "
"of the groups stapusr and stapsys. [man stap]");
}
else if (pr_contains (credentials, pr_stapusr))
{
privilege = pr_stapusr;
server_args.push_back ("--privilege=stapusr");
auto_privilege_level_msg =
_("--privilege=stapusr was automatically selected because you are a member "
"of the group stapusr. [man stap]");
}
else
{
cerr << _("You are trying to run systemtap as a normal user.\n"
"You should either be root, or be part of "
"the group \"stapusr\" and possibly one of the groups "
"\"stapsys\" or \"stapdev\". [man stap]\n");
#if HAVE_DYNINST
cerr << _("Alternatively, you may specify --runtime=dyninst for userspace probing.\n");
#endif
usage (1); }
}
if (! pr_contains (credentials, pr_stapdev))
{
enable_auto_server (
_F("For users with the privilege level %s, the module created by compiling your "
"script must be signed by a trusted systemtap compile-server. [man stap-server]",
pr_name (credentials)));
}
}
if (client_options && ! pr_contains (privilege, pr_stapdev) && ! client_options_disallowed_for_unprivileged.empty ())
{
cerr << _F("You can't specify %s when --privilege=%s is specified.",
client_options_disallowed_for_unprivileged.c_str(),
pr_name (privilege))
<< endl;
usage (1);
}
if ((cmd != "") && (target_pid))
{
cerr << _F("You can't specify %s and %s together.", "-c", "-x") << endl;
usage (1);
}
if (! runtime_usermode_p () && ! pr_contains (privilege, pr_stapdev) && guru_mode)
{
cerr << _F("You can't specify %s and --privilege=%s together.", "-g", pr_name (privilege))
<< endl;
usage (1);
}
if (!remote_uris.empty() && tmpdir_opt_set)
{
cerr << _F("You can't specify %s and %s together.", "--remote", "--tmpdir") << endl;
usage(1);
}
native_build = (release == kernel_release &&
machine == architecture);
if (last_pass > 4 && !native_build && remote_uris.empty())
{
print_warning("kernel release/architecture mismatch with host forces last-pass 4.");
last_pass = 4;
}
if(download_dbinfo != 0 && access ("/usr/bin/abrt-action-install-debuginfo-to-abrt-cache", X_OK) < 0
&& access ("/usr/libexec/abrt-action-install-debuginfo-to-abrt-cache", X_OK) < 0)
{
print_warning("abrt-action-install-debuginfo-to-abrt-cache is not installed. Continuing without downloading debuginfo.");
download_dbinfo = 0;
}
if (runtime_path[0] != '/')
{
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)))
{
runtime_path = string(cwd) + "/" + runtime_path;
}
}
const char *tmpdir = getenv("TMPDIR");
if (tmpdir != NULL)
assert_regexp_match("TMPDIR", tmpdir, "^[-/._0-9a-z]+$");
if (!client_options && modules_must_be_signed())
{
enable_auto_server (
_("The kernel on your system requires modules to be signed for loading.\n"
"The module created by compiling your script must be signed by a systemtap "
"compile-server. [man stap-server]"));
get_mok_info();
}
}
int
systemtap_session::parse_kernel_config ()
{
string kernel_config_file = kernel_build_tree + "/.config";
struct stat st;
int rc = stat(kernel_config_file.c_str(), &st);
if (rc != 0)
{
clog << _F("Checking \"%s\" failed with error: %s",
kernel_config_file.c_str(), strerror(errno)) << endl;
find_devel_rpms(*this, kernel_build_tree.c_str());
missing_rpm_list_print(*this, "-devel");
return rc;
}
ifstream kcf (kernel_config_file.c_str());
string line;
while (getline (kcf, line))
{
if (!startswith(line, "CONFIG_")) continue;
size_t off = line.find('=');
if (off == string::npos) continue;
string key = line.substr(0, off);
string value = line.substr(off+1, string::npos);
kernel_config[key] = value;
}
if (verbose > 2)
clog << _F("Parsed kernel \"%s\", ", kernel_config_file.c_str())
<< _NF("containing %zu tuple", "containing %zu tuples",
kernel_config.size(), kernel_config.size()) << endl;
kcf.close();
return 0;
}
int
systemtap_session::parse_kernel_exports ()
{
string kernel_exports_file = kernel_build_tree + "/Module.symvers";
struct stat st;
int rc = stat(kernel_exports_file.c_str(), &st);
if (rc != 0)
{
clog << _F("Checking \"%s\" failed with error: %s\nEnsure kernel development headers & makefiles are installed",
kernel_exports_file.c_str(), strerror(errno)) << endl;
return rc;
}
ifstream kef (kernel_exports_file.c_str());
string line;
while (getline (kef, line))
{
vector<string> tokens;
tokenize (line, tokens, "\t");
if (tokens.size() == 4 &&
tokens[2] == "vmlinux" &&
tokens[3].substr(0,13) == string("EXPORT_SYMBOL"))
kernel_exports.insert (tokens[1]);
else if (tokens.size() == 3 && tokens[2] == "vmlinux")
kernel_exports.insert (tokens[1]);
}
if (verbose > 2)
clog << _NF("Parsed kernel \"%s\", containing one vmlinux export",
"Parsed kernel \"%s\", containing %zu vmlinux exports",
kernel_exports.size(), kernel_exports_file.c_str(),
kernel_exports.size()) << endl;
kef.close();
return 0;
}
int
systemtap_session::parse_kernel_functions ()
{
string system_map_path = kernel_build_tree + "/System.map";
ifstream system_map;
system_map.open(system_map_path.c_str(), ifstream::in);
if (! system_map.is_open())
{
if (verbose > 1)
clog << _F("Kernel symbol table %s unavailable, (%s)",
system_map_path.c_str(), strerror(errno)) << endl;
system_map_path = "/boot/System.map-" + kernel_release;
system_map.clear();
system_map.open(system_map_path.c_str(), ifstream::in);
if (! system_map.is_open())
{
if (verbose > 1)
clog << _F("Kernel symbol table %s unavailable, (%s)",
system_map_path.c_str(), strerror(errno)) << endl;
}
}
string address, type, name;
while (system_map.good())
{
assert_no_interrupts();
system_map >> address >> type >> name;
if (verbose > 3)
clog << "'" << address << "' '" << type << "' '" << name
<< "'" << endl;
if (type != "t" && type != "T")
continue;
#ifdef __powerpc__ XXX if (name[0] == '.')
name.erase(0, 1);
#endif
FIXME kernel_functions.insert(name);
}
system_map.close();
if (kernel_functions.size() == 0)
print_warning ("Kernel function symbol table missing [man warning::symbols]", 0);
if (verbose > 2)
clog << _F("Parsed kernel \"%s\", ", system_map_path.c_str())
<< _NF("containing %zu symbol", "containing %zu symbols",
kernel_functions.size(), kernel_functions.size()) << endl;
return 0;
}
string
systemtap_session::cmd_file ()
{
wordexp_t words;
string file;
if (target_pid && cmd == "")
{
string err_msg;
if(!is_valid_pid (target_pid, err_msg))
throw SEMANTIC_ERROR(err_msg);
file = string("/proc/") + lex_cast(target_pid) + "/exe";
}
else {
int rc = wordexp (cmd.c_str (), &words, WRDE_NOCMD|WRDE_UNDEF);
if(rc == 0)
{
if (words.we_wordc > 0)
file = words.we_wordv[0];
wordfree (& words);
}
else
{
switch (rc)
{
case WRDE_BADCHAR:
throw SEMANTIC_ERROR(_("command contains illegal characters"));
case WRDE_BADVAL:
throw SEMANTIC_ERROR(_("command contains undefined shell variables"));
case WRDE_CMDSUB:
throw SEMANTIC_ERROR(_("command contains command substitutions"));
case WRDE_NOSPACE:
throw SEMANTIC_ERROR(_("out of memory"));
case WRDE_SYNTAX:
throw SEMANTIC_ERROR(_("command contains shell syntax errors"));
default:
throw SEMANTIC_ERROR(_("unspecified wordexp failure"));
}
}
}
return file;
}
void
systemtap_session::init_try_server ()
{
#if HAVE_NSS
if (! use_server_on_error || client_options || ! specified_servers.empty ())
try_server_status = dont_try_server;
else
try_server_status = try_server_unset;
#else
try_server_status = dont_try_server;
#endif
}
void
systemtap_session::set_try_server (int t)
{
if (try_server_status != dont_try_server)
try_server_status = t;
}
void systemtap_session::insert_loaded_modules()
{
char line[1024];
ifstream procmods ("/proc/modules");
while (procmods.good()) {
procmods.getline (line, sizeof(line));
strtok(line, " \t");
if (line[0] == '\0')
break; unwindsym_modules.insert (string (line));
}
procmods.close();
unwindsym_modules.insert ("kernel");
}
void
systemtap_session::setup_kernel_release (const char* kstr)
{
if (kernel_release == kstr)
return;
kernel_release = kernel_build_tree = kernel_source_tree = "";
if (kstr[0] == '/') {
kernel_build_tree = kstr;
kernel_release = kernel_release_from_build_tree (kernel_build_tree, verbose);
string some_random_source_only_file = kernel_build_tree + "/COPYING";
ifstream epic (some_random_source_only_file.c_str());
if (! epic.fail())
{
kernel_source_tree = kernel_build_tree;
if (verbose > 2)
clog << _F("Located kernel source tree (COPYING) at '%s'", kernel_source_tree.c_str()) << endl;
}
}
else
{
update_release_sysroot = true;
kernel_release = string (kstr);
if (!kernel_release.empty())
kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
}
}
void
systemtap_session::register_library_aliases()
{
vector<stapfile*> files(library_files);
files.insert(files.end(), user_files.begin(), user_files.end());
for (unsigned f = 0; f < files.size(); ++f)
{
stapfile * file = files[f];
for (unsigned a = 0; a < file->aliases.size(); ++a)
{
probe_alias * alias = file->aliases[a];
try
{
for (unsigned n = 0; n < alias->alias_names.size(); ++n)
{
probe_point * name = alias->alias_names[n];
match_node * mn = pattern_root;
for (unsigned c = 0; c < name->components.size(); ++c)
{
probe_point::component * comp = name->components[c];
XXX if (comp->arg)
throw SEMANTIC_ERROR(_F("alias component %s contains illegal parameter",
comp->functor.c_str()));
mn = mn->bind(comp->functor);
}
mn->bind_privilege (pr_all);
mn->bind(new alias_expansion_builder(alias));
}
}
catch (const semantic_error& e)
{
semantic_error er(ERR_SRC, _("while registering probe alias"),
alias->tok, NULL, &e);
print_error (er);
}
}
}
}
void
systemtap_session::print_token (ostream& o, const token* tok)
{
assert (tok);
if (last_token && last_token->location.file == tok->location.file)
{
stringstream tmpo;
tmpo << *tok;
string ts = tmpo.str();
size_t idx = ts.find (tok->location.file->name);
if (idx != string::npos) {
ts.erase(idx, tok->location.file->name.size()); if (color_errors) {
string src = ts.substr(idx); ts.erase(idx); ts += colorize(src, "source"); }
}
o << ts;
}
else
o << colorize(tok);
last_token = tok;
}
void
systemtap_session::print_error (const semantic_error& se)
{
if (this->dump_mode && this->verbose <= 1)
{
seen_errors[se.errsrc_chain()]++; return;
}
if (verbose > 0 || seen_errors[se.errsrc_chain()] < 1)
{
seen_errors[se.errsrc_chain()]++;
for (const semantic_error *e = &se; e != NULL; e = e->get_chain())
cerr << build_error_msg(*e);
}
else suppressed_errors++;
}
string
systemtap_session::build_error_msg (const semantic_error& e)
{
stringstream message;
string align_semantic_error (" ");
message << colorize(_("semantic error:"), "error") << ' ' << e.what ();
if (e.tok1 || e.tok2)
message << ": ";
else
{
print_error_details (message, align_semantic_error, e);
message << endl;
if (verbose > 1) message << _(" thrown from: ") << e.errsrc;
}
if (e.tok1)
{
print_token (message, e.tok1);
print_error_details (message, align_semantic_error, e);
message << endl;
if (verbose > 1)
message << _(" thrown from: ") << e.errsrc << endl;
print_error_source (message, align_semantic_error, e.tok1);
}
if (e.tok2)
{
print_token (message, e.tok2);
message << endl;
print_error_source (message, align_semantic_error, e.tok2);
}
message << endl;
return message.str();
}
void
systemtap_session::print_error_source (std::ostream& message,
std::string& align, const token* tok)
{
unsigned i = 0;
assert (tok);
if (!tok->location.file)
return;
unsigned line = tok->location.line;
unsigned col = tok->location.column;
const string &file_contents = tok->location.file->file_contents;
size_t start_pos = 0, end_pos = 0;
while (i != line && end_pos != std::string::npos)
{
start_pos = end_pos;
end_pos = file_contents.find ('\n', start_pos) + 1;
i++;
}
message << align << _("source: ");
string srcline = file_contents.substr(start_pos, end_pos-start_pos-1);
if (color_errors &&
(tok->type == tok_number ||
tok->type == tok_identifier ||
tok->type == tok_operator)) {
string tok_content = tok->content;
message << srcline.substr(0, col-1);
message << colorize(tok_content, "token");
message << srcline.substr(col+tok_content.size()-1) << endl;
} else
message << srcline << endl;
message << align << " ";
for (i=start_pos; i<start_pos+col-1; i++)
{
if(isspace(file_contents[i]))
message << file_contents[i];
else
message << ' ';
}
message << colorize("^", "caret") << endl;
if (tok->chain)
{
if (tok->location.file->synthetic)
message << _("\tin synthesized code from: ");
else
message << _("\tin expansion of macro: ");
message << colorize(tok->chain) << endl;
print_error_source (message, align, tok->chain);
}
}
void
systemtap_session::print_error_details (std::ostream& message,
std::string& align,
const semantic_error& e)
{
for (size_t i = 0; i < e.details.size(); ++i)
message << endl << align << e.details[i];
}
void
systemtap_session::print_warning (const string& message_str, const token* tok)
{
if (suppress_warnings && (!dump_mode || verbose <= 1))
return;
string align_warning (" ");
if (verbose > 0 || seen_warnings.find (message_str) == seen_warnings.end())
{
seen_warnings.insert (message_str);
clog << colorize(_("WARNING:"), "warning") << ' ' << message_str;
if (tok) { clog << ": "; print_token (clog, tok); }
clog << endl;
if (tok) { print_error_source (clog, align_warning, tok); }
}
else suppressed_warnings++;
}
void
systemtap_session::print_error (const parse_error &pe,
const token* tok,
const std::string &input_name,
bool is_warningerr)
{
if (verbose > 0 || seen_errors[pe.errsrc_chain()] < 1)
{
seen_errors[pe.errsrc_chain()]++; if (seen_errors[pe.errsrc_chain()] == 1 && is_warningerr) warningerr_count++; cerr << build_error_msg(pe, tok, input_name);
for (const parse_error *e = pe.chain; e != NULL; e = e->chain)
cerr << build_error_msg(*e, e->tok, input_name);
}
else suppressed_errors++;
}
string
systemtap_session::build_error_msg (const parse_error& pe,
const token* tok,
const std::string &input_name)
{
stringstream message;
string align_parse_error (" ");
bool found_junk = false;
if (tok && tok->type == tok_junk && tok->msg != "")
{
found_junk = true;
message << colorize(_("parse error:"), "error") << ' ' << tok->msg << endl;
}
else
{
message << colorize(_("parse error:"), "error") << ' ' << pe.what() << endl;
}
if (pe.tok || found_junk)
{
message << _("\tat: ") << colorize(tok) << endl;
print_error_source (message, align_parse_error, tok);
}
else if (tok) {
message << _("\tsaw: ") << colorize(tok) << endl;
print_error_source (message, align_parse_error, tok);
}
else
{
message << _("\tsaw: ") << input_name << " EOF" << endl;
}
message << endl;
return message.str();
}
void
systemtap_session::report_suppression()
{
if (this->suppressed_errors > 0)
cerr << colorize(_F("Number of similar error messages suppressed: %d.",
this->suppressed_errors),
"error") << endl;
if (this->suppressed_warnings > 0)
cerr << colorize(_F("Number of similar warning messages suppressed: %d.",
this->suppressed_warnings),
"warning") << endl;
if (this->suppressed_errors > 0 || this->suppressed_warnings > 0)
cerr << "Rerun with -v to see them." << endl;
}
void
systemtap_session::create_tmp_dir()
{
if (!tmpdir.empty())
return;
const char * tmpdir_env = getenv("TMPDIR");
if (!tmpdir_env)
tmpdir_env = "/tmp";
string stapdir = "/stapXXXXXX";
string tmpdirt = tmpdir_env + stapdir;
const char *tmpdir_name = mkdtemp((char *)tmpdirt.c_str());
if (! tmpdir_name)
{
const char* e = strerror(errno);
throw runtime_error(_F("cannot create temporary directory (\" %s \"): %s", tmpdirt.c_str(), e));
}
else
tmpdir = tmpdir_name;
}
void
systemtap_session::remove_tmp_dir()
{
if(tmpdir.empty())
return;
if (keep_tmpdir && !tmpdir_opt_set)
clog << _F("Keeping temporary directory \"%s\"", tmpdir.c_str()) << endl;
else if (!tmpdir_opt_set)
{
stap_sigmasker masked;
vector<string> cleanupcmd;
cleanupcmd.push_back("rm");
cleanupcmd.push_back("-rf");
cleanupcmd.push_back(tmpdir);
(void) stap_system(verbose, cleanupcmd);
if (verbose>1)
clog << _F("Removed temporary directory \"%s\"", tmpdir.c_str()) << endl;
tmpdir.clear();
}
}
void
systemtap_session::reset_tmp_dir()
{
remove_tmp_dir();
create_tmp_dir();
}
translator_output* systemtap_session::op_create_auxiliary(bool trailer_p)
{
static int counter = 0;
string tmpname = this->tmpdir + "/" + this->module_name + "_aux_" + lex_cast(counter++) + ".c";
translator_output* n = new translator_output (tmpname);
n->trailer_p = trailer_p;
auxiliary_outputs.push_back (n);
return n;
}
void
assert_no_interrupts()
{
if (pending_interrupts)
throw interrupt_exception();
}
std::string
systemtap_session::colorize(const std::string& str, const std::string& type)
{
if (str.empty() || !color_errors)
return str;
else {
std::string color = parse_stap_color(type);
if (!color.empty()) return "\033[" + color + "m\033[K" + str + "\033[m\033[K";
else
return str;
}
}
std::string
systemtap_session::colorize(const token* tok)
{
if (tok == NULL)
return "";
stringstream tmp;
tmp << *tok;
if (!color_errors)
return tmp.str(); else {
string ts = tmp.str();
stringstream loc;
loc << tok->location;
ts.erase(ts.size()-loc.str().size());
return ts + colorize(loc.str(), "source");
}
}
std::string
systemtap_session::parse_stap_color(const std::string& type)
{
const char *key, *col, *eq;
int n = type.size();
int done = 0;
key = getenv("SYSTEMTAP_COLORS");
if (key == NULL)
key = "error=01;31:warning=00;33:source=00;34:caret=01:token=01";
else if (*key == '\0')
return "";
while (!done) {
if (!(col = strchr(key, ':'))) {
col = strchr(key, '\0');
done = 1;
}
if (!((eq = strchr(key, '=')) && eq < col))
return ""; if (!(key < eq && eq < col-1))
return ""; if (strspn(eq+1, "0123456789;") < (size_t)(col-eq-1))
return ""; if (eq-key == n && type.compare(0, n, key, n) == 0)
return string(eq+1, col-eq-1);
if (!done) key = col+1; }
return "";
}
bool
systemtap_session::modules_must_be_signed()
{
ifstream statm("/sys/module/module/parameters/sig_enforce");
char status = 'N';
statm >> status;
if (status == 'Y')
return true;
return false;
}
void
systemtap_session::get_mok_info()
{
vector<string> cmd;
int rc;
stringstream out;
FIXME
cmd.push_back("mokutil");
cmd.push_back("--list-enrolled");
rc = stap_system_read(verbose, cmd, out);
if (rc != 0)
throw runtime_error(_F("failed to get list of machine owner keys (MOK) fingerprints: rc %d", rc));
string line, fingerprint;
while (! out.eof())
{
vector<string> matches;
getline(out, line);
if (! regexp_match(line, "^SHA1 Fingerprint: ([0-9a-f:]+)$", matches))
{
if (verbose > 2)
clog << "MOK fingerprint found: " << matches[1] << endl;
if (! matches[1].empty())
mok_fingerprints.push_back(matches[1]);
}
}
}
void
systemtap_session::enable_auto_server (const string &message)
{
auto_server_msgs.push_back (message);
#if HAVE_NSS
if (specified_servers.empty())
specified_servers.push_back ("");
#else
explain_auto_options ();
clog << _("Unable to request compilation by a compile-server\n."
"Without NSS, --use-server is not supported by this version systemtap.") << endl;
exit(1);
#endif
}
void
systemtap_session::explain_auto_options()
{
if (! auto_privilege_level_msg.empty())
clog << auto_privilege_level_msg << endl;
if (! auto_server_msgs.empty())
{
for (vector<string>::iterator i = auto_server_msgs.begin(); i != auto_server_msgs.end(); ++i)
{
clog << *i << endl;
clog << _("--use-server was automatically selected in order to request compilation by "
"a compile-server.") << endl;
}
}
}
bool
systemtap_session::is_user_file (const string &name)
{
for (vector<stapfile*>::iterator it = user_files.begin(); it != user_files.end(); it++)
if (name == (*it)->name)
return true;
return false; }
bool
systemtap_session::is_primary_probe (derived_probe *dp)
{
if (user_files.empty())
return false;
vector<probe*> chain;
dp->collect_derivation_chain (chain);
const source_loc& origin = chain.back()->tok->location;
return origin.file == user_files[0];
}
const char*
systemtap_session::morehelp =
"\x1b\x5b\x30\x6d\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x60\x20\x20\x2e\x60\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x1b\x5b"
"\x33\x33\x6d\x20\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x1b\x5b\x33\x33\x6d\x20\x60"
"\x2e\x60\x1b\x5b\x33\x37\x6d\x20\x3a\x2c\x3a\x2e\x60\x20\x60\x20\x60\x20\x60"
"\x2c\x3b\x2c\x3a\x20\x1b\x5b\x33\x33\x6d\x60\x2e\x60\x20\x1b\x5b\x33\x37\x6d"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x1b\x5b\x33"
"\x33\x6d\x20\x60\x20\x60\x20\x3a\x27\x60\x1b\x5b\x33\x37\x6d\x20\x60\x60\x60"
"\x20\x20\x20\x60\x20\x60\x60\x60\x20\x1b\x5b\x33\x33\x6d\x60\x3a\x60\x20\x60"
"\x20\x60\x20\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x2e\x1b\x5b\x33\x33\x6d\x60\x2e\x60\x20\x60\x20\x60\x20\x20\x1b\x5b\x33"
"\x37\x6d\x20\x3a\x20\x20\x20\x60\x20\x20\x20\x60\x20\x20\x2e\x1b\x5b\x33\x33"
"\x6d\x60\x20\x60\x2e\x60\x20\x60\x2e\x60\x20\x1b\x5b\x33\x37\x6d\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x2e\x3a\x20\x20"
"\x20\x20\x20\x20\x20\x20\x2e\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x2e\x76\x53\x1b\x5b\x33\x34\x6d\x53\x1b\x5b\x33\x37\x6d\x53\x1b\x5b"
"\x33\x31\x6d\x2b\x1b\x5b\x33\x33\x6d\x60\x20\x60\x20\x60\x20\x20\x20\x20\x1b"
"\x5b\x33\x31\x6d\x3f\x1b\x5b\x33\x30\x6d\x53\x1b\x5b\x33\x33\x6d\x2b\x1b\x5b"
"\x33\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x2e\x1b\x5b\x33\x30\x6d\x24\x1b\x5b"
"\x33\x37\x6d\x3b\x1b\x5b\x33\x31\x6d\x7c\x1b\x5b\x33\x33\x6d\x20\x60\x20\x60"
"\x20\x60\x20\x60\x1b\x5b\x33\x31\x6d\x2c\x1b\x5b\x33\x32\x6d\x53\x1b\x5b\x33"
"\x37\x6d\x53\x53\x3e\x2c\x2e\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x2e"
"\x3b\x27\x20\x20\x20\x20\x20\x20\x20\x20\x20\x60\x3c\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x2e\x2e\x3a\x1b\x5b\x33\x30\x6d\x26\x46\x46\x46\x48\x46\x1b\x5b"
"\x33\x33\x6d\x60\x2e\x60\x20\x60\x20\x60\x20\x60\x1b\x5b\x33\x30\x6d\x4d\x4d"
"\x46\x1b\x5b\x33\x33\x6d\x20\x20\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x1b\x5b"
"\x33\x33\x6d\x20\x3a\x1b\x5b\x33\x30\x6d\x4d\x4d\x46\x1b\x5b\x33\x33\x6d\x20"
"\x20\x20\x60\x20\x60\x2e\x60\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x30\x6d\x46"
"\x46\x46\x24\x53\x46\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x20\x0a\x20\x20\x20"
"\x20\x2e\x3c\x3a\x60\x20\x20\x20\x20\x2e\x3a\x2e\x3a\x2e\x2e\x3b\x27\x20\x20"
"\x20\x20\x20\x20\x2e\x60\x2e\x3a\x60\x60\x3c\x27\x1b\x5b\x33\x31\x6d\x3c\x27"
"\x1b\x5b\x33\x33\x6d\x20\x60\x20\x60\x20\x60\x20\x20\x20\x60\x3c\x1b\x5b\x33"
"\x30\x6d\x26\x1b\x5b\x33\x31\x6d\x3f\x1b\x5b\x33\x33\x6d\x20\x1b\x5b\x33\x37"
"\x6d\x20\x1b\x5b\x33\x33\x6d\x20\x20\x20\x20\x20\x1b\x5b\x33\x37\x6d\x60\x1b"
"\x5b\x33\x30\x6d\x2a\x46\x1b\x5b\x33\x37\x6d\x27\x1b\x5b\x33\x33\x6d\x20\x60"
"\x20\x60\x20\x60\x20\x60\x20\x1b\x5b\x33\x31\x6d\x60\x3a\x1b\x5b\x33\x37\x6d"
"\x27\x3c\x1b\x5b\x33\x30\x6d\x23\x1b\x5b\x33\x37\x6d\x3c\x60\x3a\x20\x20\x20"
"\x0a\x20\x20\x20\x20\x3a\x60\x3a\x60\x20\x20\x20\x60\x3a\x2e\x2e\x2e\x2e\x3c"
"\x3c\x20\x20\x20\x20\x20\x20\x3a\x2e\x60\x3a\x60\x20\x20\x20\x60\x1b\x5b\x33"
"\x33\x6d\x3a\x1b\x5b\x33\x31\x6d\x60\x1b\x5b\x33\x33\x6d\x20\x60\x2e\x60\x20"
"\x60\x20\x60\x20\x60\x20\x60\x1b\x5b\x33\x37\x6d\x20\x20\x1b\x5b\x33\x33\x6d"
"\x20\x60\x20\x20\x20\x60\x1b\x5b\x33\x37\x6d\x20\x60\x20\x60\x1b\x5b\x33\x33"
"\x6d\x20\x60\x2e\x60\x20\x60\x2e\x60\x20\x60\x3a\x1b\x5b\x33\x37\x6d\x20\x20"
"\x20\x60\x3a\x2e\x60\x2e\x20\x0a\x20\x20\x20\x60\x3a\x60\x3a\x60\x20\x20\x20"
"\x20\x20\x60\x60\x60\x60\x20\x3a\x2d\x20\x20\x20\x20\x20\x60\x20\x60\x20\x20"
"\x20\x20\x20\x60\x1b\x5b\x33\x33\x6d\x3a\x60\x2e\x60\x20\x60\x20\x60\x20\x60"
"\x20\x60\x20\x20\x2e\x3b\x1b\x5b\x33\x31\x6d\x76\x1b\x5b\x33\x30\x6d\x24\x24"
"\x24\x1b\x5b\x33\x31\x6d\x2b\x53\x1b\x5b\x33\x33\x6d\x2c\x60\x20\x60\x20\x60"
"\x20\x60\x20\x60\x20\x60\x2e\x1b\x5b\x33\x31\x6d\x60\x1b\x5b\x33\x33\x6d\x3a"
"\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x60\x2e\x60\x20\x20\x0a\x20\x20\x20\x60"
"\x3a\x3a\x3a\x3a\x20\x20\x20\x20\x3a\x60\x60\x60\x60\x3a\x53\x20\x20\x20\x20"
"\x20\x20\x3a\x2e\x60\x2e\x20\x20\x20\x20\x20\x1b\x5b\x33\x33\x6d\x3a\x1b\x5b"
"\x33\x31\x6d\x3a\x1b\x5b\x33\x33\x6d\x2e\x60\x2e\x60\x20\x60\x2e\x60\x20\x60"
"\x20\x3a\x1b\x5b\x33\x30\x6d\x24\x46\x46\x48\x46\x46\x46\x46\x46\x1b\x5b\x33"
"\x31\x6d\x53\x1b\x5b\x33\x33\x6d\x2e\x60\x20\x60\x2e\x60\x20\x60\x2e\x60\x2e"
"\x1b\x5b\x33\x31\x6d\x3a\x1b\x5b\x33\x33\x6d\x3a\x1b\x5b\x33\x37\x6d\x20\x20"
"\x20\x2e\x60\x2e\x3a\x20\x20\x0a\x20\x20\x20\x60\x3a\x3a\x3a\x60\x20\x20\x20"
"\x60\x3a\x20\x2e\x20\x3b\x27\x3a\x20\x20\x20\x20\x20\x20\x3a\x2e\x60\x3a\x20"
"\x20\x20\x20\x20\x3a\x1b\x5b\x33\x33\x6d\x3c\x3a\x1b\x5b\x33\x31\x6d\x60\x1b"
"\x5b\x33\x33\x6d\x2e\x60\x20\x60\x20\x60\x20\x60\x2e\x1b\x5b\x33\x30\x6d\x53"
"\x46\x46\x46\x53\x46\x46\x46\x53\x46\x46\x1b\x5b\x33\x33\x6d\x20\x60\x20\x60"
"\x20\x60\x2e\x60\x2e\x60\x3a\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x37\x6d\x20"
"\x20\x20\x20\x3a\x60\x3a\x60\x20\x20\x0a\x20\x20\x20\x20\x60\x3c\x3b\x3c\x20"
"\x20\x20\x20\x20\x60\x60\x60\x20\x3a\x3a\x20\x20\x20\x20\x20\x20\x20\x3a\x3a"
"\x2e\x60\x20\x20\x20\x20\x20\x3a\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31\x6d"
"\x3c\x3a\x60\x1b\x5b\x33\x33\x6d\x2e\x60\x2e\x60\x20\x60\x3a\x1b\x5b\x33\x30"
"\x6d\x53\x46\x53\x46\x46\x46\x53\x46\x46\x46\x53\x1b\x5b\x33\x33\x6d\x2e\x60"
"\x20\x60\x2e\x60\x2e\x60\x3a\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x33\x6d\x3b"
"\x1b\x5b\x33\x37\x6d\x27\x20\x20\x20\x60\x3a\x3a\x60\x20\x20\x20\x0a\x20\x20"
"\x20\x20\x20\x60\x3b\x3c\x20\x20\x20\x20\x20\x20\x20\x3a\x3b\x60\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x60\x3a\x60\x2e\x20\x20\x20\x20\x20\x3a\x1b\x5b\x33"
"\x33\x6d\x3c\x3b\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x33\x6d\x3a\x1b\x5b\x33"
"\x31\x6d\x3a\x1b\x5b\x33\x33\x6d\x2e\x60\x2e\x60\x20\x1b\x5b\x33\x31\x6d\x3a"
"\x1b\x5b\x33\x30\x6d\x46\x53\x46\x53\x46\x53\x46\x53\x46\x1b\x5b\x33\x31\x6d"
"\x3f\x1b\x5b\x33\x33\x6d\x20\x60\x2e\x60\x2e\x3a\x3a\x1b\x5b\x33\x31\x6d\x3c"
"\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x37\x6d\x60\x20"
"\x20\x20\x3a\x3a\x3a\x60\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x53\x3c"
"\x20\x20\x20\x20\x20\x20\x3a\x53\x3a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x60\x3a\x3a\x60\x2e\x20\x20\x20\x20\x60\x3a\x1b\x5b\x33\x31\x6d\x3c\x1b"
"\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31\x6d\x3c\x3b\x3c\x1b\x5b\x33\x33\x6d\x3a"
"\x60\x2e\x60\x3c\x1b\x5b\x33\x30\x6d\x53\x46\x53\x24\x53\x46\x53\x24\x1b\x5b"
"\x33\x33\x6d\x60\x3a\x1b\x5b\x33\x31\x6d\x3a\x1b\x5b\x33\x33\x6d\x3a\x1b\x5b"
"\x33\x31\x6d\x3a\x3b\x3c\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31\x6d\x3c\x1b"
"\x5b\x33\x33\x6d\x3a\x1b\x5b\x33\x37\x6d\x60\x20\x20\x2e\x60\x3a\x3a\x60\x20"
"\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x3b\x3c\x2e\x2e\x2c\x2e\x2e\x20"
"\x3a\x3c\x3b\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x60\x3a\x3a\x3a"
"\x60\x20\x20\x20\x20\x20\x60\x3a\x1b\x5b\x33\x33\x6d\x3c\x3b\x1b\x5b\x33\x31"
"\x6d\x3c\x3b\x3c\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33"
"\x33\x6d\x3b\x1b\x5b\x33\x31\x6d\x3c\x3c\x1b\x5b\x33\x30\x6d\x53\x24\x53\x1b"
"\x5b\x33\x31\x6d\x53\x1b\x5b\x33\x37\x6d\x27\x1b\x5b\x33\x33\x6d\x2e\x3a\x3b"
"\x1b\x5b\x33\x31\x6d\x3c\x3b\x3c\x1b\x5b\x33\x33\x6d\x3a\x1b\x5b\x33\x31\x6d"
"\x3c\x1b\x5b\x33\x33\x6d\x3a\x1b\x5b\x33\x37\x6d\x60\x20\x20\x20\x60\x2e\x3a"
"\x3a\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x2e\x3a\x3a\x3c\x53\x3c\x3a\x60"
"\x3a\x3a\x3a\x3a\x53\x1b\x5b\x33\x32\x6d\x53\x1b\x5b\x33\x37\x6d\x3b\x27\x3a"
"\x3c\x2c\x2e\x20\x20\x20\x20\x20\x20\x20\x20\x20\x60\x3a\x3a\x3a\x3a\x2e\x60"
"\x2e\x60\x2e\x60\x3a\x1b\x5b\x33\x33\x6d\x3c\x3a\x1b\x5b\x33\x31\x6d\x3c\x1b"
"\x5b\x33\x33\x6d\x53\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b"
"\x33\x31\x6d\x3c\x2c\x1b\x5b\x33\x33\x6d\x3c\x3b\x3a\x1b\x5b\x33\x31\x6d\x2c"
"\x1b\x5b\x33\x33\x6d\x3c\x3b\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x33\x6d\x53"
"\x1b\x5b\x33\x31\x6d\x3c\x1b\x5b\x33\x33\x6d\x3b\x3c\x1b\x5b\x33\x37\x6d\x3a"
"\x60\x2e\x60\x2e\x3b\x1b\x5b\x33\x34\x6d\x53\x1b\x5b\x33\x37\x6d\x53\x3f\x27"
"\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x2e\x60\x3a\x60\x3a\x3c\x53\x53\x3b\x3c"
"\x3a\x60\x3a\x3a\x53\x53\x53\x3c\x3a\x60\x3a\x1b\x5b\x33\x30\x6d\x53\x1b\x5b"
"\x33\x37\x6d\x2b\x20\x20\x20\x20\x20\x20\x60\x20\x20\x20\x3a\x1b\x5b\x33\x34"
"\x6d\x53\x1b\x5b\x33\x30\x6d\x53\x46\x24\x1b\x5b\x33\x37\x6d\x2c\x60\x3a\x3a"
"\x3a\x3c\x3a\x3c\x1b\x5b\x33\x33\x6d\x53\x1b\x5b\x33\x37\x6d\x3c\x1b\x5b\x33"
"\x33\x6d\x53\x1b\x5b\x33\x31\x6d\x53\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31"
"\x6d\x53\x3b\x53\x1b\x5b\x33\x33\x6d\x3b\x1b\x5b\x33\x31\x6d\x53\x1b\x5b\x33"
"\x33\x6d\x53\x1b\x5b\x33\x37\x6d\x3c\x1b\x5b\x33\x33\x6d\x53\x1b\x5b\x33\x37"
"\x6d\x3c\x53\x3c\x3a\x3a\x3a\x3a\x3f\x1b\x5b\x33\x30\x6d\x53\x24\x48\x1b\x5b"
"\x33\x37\x6d\x27\x60\x20\x60\x20\x20\x20\x20\x20\x20\x0a\x2e\x60\x3a\x60\x2e"
"\x60\x3a\x60\x2e\x60\x3a\x60\x2e\x60\x3a\x60\x2e\x60\x3a\x60\x2e\x1b\x5b\x33"
"\x30\x6d\x53\x46\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x60\x20\x20\x20\x60\x20"
"\x60\x3a\x1b\x5b\x33\x30\x6d\x3c\x46\x46\x46\x1b\x5b\x33\x37\x6d\x3f\x2e\x60"
"\x3a\x60\x3a\x60\x3a\x60\x3a\x60\x3a\x3c\x3a\x60\x3a\x27\x3a\x60\x3a\x60\x3a"
"\x60\x3a\x60\x3b\x1b\x5b\x33\x30\x6d\x53\x46\x48\x46\x1b\x5b\x33\x37\x6d\x27"
"\x20\x60\x20\x60\x20\x60\x20\x20\x20\x20\x0a\x20\x3c\x3b\x3a\x2e\x60\x20\x60"
"\x2e\x60\x20\x60\x2e\x60\x20\x60\x2e\x60\x2c\x53\x1b\x5b\x33\x32\x6d\x53\x1b"
"\x5b\x33\x30\x6d\x53\x1b\x5b\x33\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x60\x20\x60\x3c\x1b\x5b\x33\x30\x6d\x46\x46\x46\x1b\x5b\x33\x34\x6d"
"\x2b\x1b\x5b\x33\x37\x6d\x3a\x20\x60\x20\x60\x20\x60\x2e\x60\x20\x60\x2e\x60"
"\x20\x60\x2e\x60\x20\x60\x20\x60\x2c\x1b\x5b\x33\x30\x6d\x24\x46\x48\x46\x1b"
"\x5b\x33\x37\x6d\x27\x20\x60\x20\x20\x20\x60\x20\x20\x20\x20\x20\x20\x0a\x20"
"\x60\x3a\x1b\x5b\x33\x30\x6d\x53\x24\x1b\x5b\x33\x37\x6d\x53\x53\x53\x3b\x3c"
"\x2c\x60\x2c\x3b\x3b\x53\x3f\x53\x1b\x5b\x33\x30\x6d\x24\x46\x3c\x1b\x5b\x33"
"\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x60\x20\x60"
"\x3c\x1b\x5b\x33\x30\x6d\x48\x46\x46\x46\x1b\x5b\x33\x37\x6d\x3f\x2e\x60\x20"
"\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x3b\x76\x1b\x5b\x33\x30\x6d"
"\x48\x46\x48\x46\x1b\x5b\x33\x37\x6d\x27\x20\x60\x20\x20\x20\x60\x20\x20\x20"
"\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x60\x3c\x1b\x5b\x33\x30\x6d\x46\x24\x1b"
"\x5b\x33\x37\x6d\x53\x53\x53\x53\x53\x53\x1b\x5b\x33\x30\x6d\x53\x24\x53\x46"
"\x46\x46\x1b\x5b\x33\x37\x6d\x27\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x60\x3c\x1b\x5b\x33\x30\x6d\x23\x46\x46\x46"
"\x24\x1b\x5b\x33\x37\x6d\x76\x2c\x2c\x20\x2e\x20\x2e\x20\x2c\x2c\x76\x1b\x5b"
"\x33\x30\x6d\x26\x24\x46\x46\x48\x3c\x1b\x5b\x33\x37\x6d\x27\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x60"
"\x3c\x1b\x5b\x33\x30\x6d\x53\x46\x46\x24\x46\x24\x46\x46\x48\x46\x53\x1b\x5b"
"\x33\x37\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x2e\x60\x20\x60\x2e\x60\x2e\x60"
"\x2e\x60\x2e\x60\x3a\x3a\x3a\x3a\x3a\x1b\x5b\x33\x30\x6d\x2a\x46\x46\x46\x48"
"\x46\x48\x46\x48\x46\x46\x46\x48\x46\x48\x46\x48\x1b\x5b\x33\x37\x6d\x3c\x22"
"\x2e\x60\x2e\x60\x2e\x60\x2e\x60\x2e\x60\x20\x20\x20\x20\x20\x20\x20\x20\x0a"
"\x20\x20\x20\x20\x20\x20\x20\x60\x3a\x1b\x5b\x33\x30\x6d\x48\x46\x46\x46\x48"
"\x46\x46\x46\x1b\x5b\x33\x37\x6d\x27\x20\x20\x20\x60\x20\x60\x2e\x60\x20\x60"
"\x2e\x60\x2e\x60\x3a\x60\x3a\x60\x3a\x60\x3a\x60\x3a\x3a\x3a\x60\x3a\x3c\x3c"
"\x1b\x5b\x33\x30\x6d\x3c\x46\x48\x46\x46\x46\x48\x46\x46\x46\x1b\x5b\x33\x37"
"\x6d\x27\x3a\x60\x3a\x60\x3a\x60\x3a\x60\x2e\x60\x2e\x60\x20\x60\x2e\x60\x20"
"\x60\x20\x60\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x60\x22\x1b\x5b"
"\x33\x30\x6d\x2a\x46\x48\x46\x1b\x5b\x33\x37\x6d\x3f\x20\x20\x20\x60\x20\x60"
"\x2e\x60\x20\x60\x2e\x60\x2e\x60\x3a\x60\x2e\x60\x3a\x60\x3a\x60\x3a\x60\x3a"
"\x60\x3a\x60\x3a\x60\x3a\x60\x3a\x1b\x5b\x33\x30\x6d\x46\x46\x48\x46\x48\x46"
"\x1b\x5b\x33\x37\x6d\x27\x3a\x60\x3a\x60\x3a\x60\x3a\x60\x2e\x60\x3a\x60\x2e"
"\x60\x2e\x60\x20\x60\x2e\x60\x20\x60\x20\x60\x0a\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x60\x3c\x1b\x5b\x33\x30\x6d\x48\x46\x46\x1b\x5b\x33\x37\x6d"
"\x2b\x60\x20\x20\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x2e\x60\x20"
"\x60\x2e\x60\x20\x60\x2e\x60\x20\x60\x3a\x60\x2e\x60\x3b\x1b\x5b\x33\x30\x6d"
"\x48\x46\x46\x46\x1b\x5b\x33\x37\x6d\x27\x2e\x60\x2e\x60\x20\x60\x2e\x60\x20"
"\x60\x2e\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x20\x20\x60\x20\x20\x0a\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x1b\x5b\x33\x30\x6d\x3c"
"\x48\x46\x53\x1b\x5b\x33\x37\x6d\x2b\x3a\x20\x20\x20\x60\x20\x60\x20\x60\x20"
"\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x2c\x1b"
"\x5b\x33\x30\x6d\x24\x46\x48\x46\x1b\x5b\x33\x37\x6d\x3f\x20\x60\x20\x60\x20"
"\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x60\x20\x20\x20\x60"
"\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x60\x22\x3c\x1b\x5b\x33\x30\x6d\x48\x24\x46\x46\x1b\x5b\x33\x37\x6d\x3e\x2c"
"\x2e\x2e\x20\x20\x20\x20\x20\x20\x20\x20\x60\x20\x20\x20\x60\x20\x20\x20\x3b"
"\x2c\x2c\x1b\x5b\x33\x30\x6d\x24\x53\x46\x46\x46\x1b\x5b\x33\x37\x6d\x27\x22"
"\x20\x20\x60\x20\x20\x20\x60\x20\x20\x20\x60\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x60\x22\x1b\x5b\x33\x30\x6d\x2a\x3c\x48"
"\x46\x46\x24\x53\x24\x1b\x5b\x33\x37\x6d\x53\x53\x53\x3e\x3e\x3e\x3e\x3e\x53"
"\x3e\x53\x1b\x5b\x33\x30\x6d\x24\x53\x24\x46\x24\x48\x46\x23\x1b\x5b\x33\x37"
"\x6d\x27\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x60\x60\x22\x3c\x1b\x5b\x33\x30\x6d\x2a\x3c\x3c\x3c\x48\x46\x46\x46\x48\x46"
"\x46\x46\x23\x3c\x1b\x5b\x33\x36\x6d\x3c\x1b\x5b\x33\x37\x6d\x3c\x27\x22\x22"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x1b"
"\x5b\x30\x6d";