* [PATCH] Add --sysroot option @ 2012-01-09 14:51 Wade Farnsworth 2012-01-20 15:49 ` Wade Farnsworth ` (2 more replies) 0 siblings, 3 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-01-09 14:51 UTC (permalink / raw) To: systemtap This adds a --sysroot option to facilitate different file locations for user-space processes and libraries at compile-time versus run-time when generating stap kernel modules for a remote system. For example if we compile the probe: process("/bin/foo").begin {} while passing "--sysroot=/bar/baz" to stap, symbols will be taken from /bar/baz/bin/foo, but the resulting .ko will still refer to /bin/foo. This allows the probe to be used on a different machine than the one it is compiled on, so long as the compiling machine replicates the necessary files in the sysroot directory. This is a fairly typical use case for embedded Linux. Known limitations: 1. Probes must contain the absolute file path to the process or library. If a relative path is used, it will be assumed to be located in the top level of the sysroot. 2. Similarly probes on scripts containing "#!/usr/bin/env bash" or similar will also assume that the interpreter is located in the sysroot top level. The reason for these limitations is that we do not have access to the target machine's environment compile-time, so some assumptions must necessarily be made. Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com> --- session.cxx | 16 ++++++++++++++++ session.h | 1 + tapset-itrace.cxx | 5 ++++- tapset-utrace.cxx | 5 ++++- tapsets.cxx | 53 +++++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/session.cxx b/session.cxx index f4ce8a6..1c1adbf 100644 --- a/session.cxx +++ b/session.cxx @@ -84,6 +84,7 @@ systemtap_session::systemtap_session (): kernel_release = string (buf.release); release = kernel_release; kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; + sysroot = string(); architecture = machine = normalize_machine(buf.machine); for (unsigned i=0; i<5; i++) perpass_verbose[i]=0; @@ -534,6 +535,8 @@ systemtap_session::usage (int exitcode) " 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 executables are located" , compatible.c_str()) << endl ; @@ -587,6 +590,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) #define LONG_OPT_PRIVILEGE 28 #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29 #define LONG_OPT_MODINFO 30 +#define LONG_OPT_SYSROOT 31 // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page static struct option long_options[] = { { "kelf", 0, &long_opt, LONG_OPT_KELF }, @@ -625,6 +629,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) { "privilege", 1, &long_opt, LONG_OPT_PRIVILEGE }, { "suppress-handler-errors", 0, &long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS }, { "modinfo", 1, &long_opt, LONG_OPT_MODINFO }, + { "sysroot", 1, &long_opt, LONG_OPT_SYSROOT }, { NULL, 0, NULL, 0 } }; int grc = getopt_long (argc, argv, "hVvtp:I:e:o:R:r:a:m:kgPc:x:D:bs:uqwl:d:L:FS:B:WG:", @@ -1151,6 +1156,17 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) modinfos.push_back (string(optarg)); break; + case LONG_OPT_SYSROOT: + { + const 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) + "/"; + break; + } + default: // NOTREACHED unless one added a getopt option but not a corresponding switch/case: cerr << _F("Unhandled long argument id %d", long_opt) << endl; diff --git a/session.h b/session.h index 64a22a5..f1a301b 100644 --- a/session.h +++ b/session.h @@ -140,6 +140,7 @@ public: std::string kernel_base_release; std::string kernel_build_tree; std::string kernel_source_tree; + std::string sysroot; std::map<std::string,std::string> kernel_config; std::set<std::string> kernel_exports; std::string machine; diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx index 1a9bf67..77811d5 100644 --- a/tapset-itrace.cxx +++ b/tapset-itrace.cxx @@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder // If we have a path, we need to validate it. if (has_path) { - path = find_executable (path); + size_t pos; + path = find_executable (sess.sysroot + path); sess.unwindsym_modules.insert (path); + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + path.replace(pos, sess.sysroot.length(), "/"); } finished_results.push_back(new itrace_derived_probe(sess, base, location, diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index 64ba900..11cf292 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder } else if (has_path) { - path = find_executable (path); + size_t pos; + path = find_executable (sess.sysroot + path); sess.unwindsym_modules.insert (path); + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + path.replace(pos, sess.sysroot.length(), "/"); } else if (has_pid) { diff --git a/tapsets.cxx b/tapsets.cxx index 177f565..50464dc 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -584,13 +584,13 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); if (has_process) - module_val = find_executable (module_val); + module_val = find_executable (sess.sysroot + module_val); if (has_library) { if (! contains_glob_chars (library_name)) { path = module_val; - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); + module_val = find_executable (sess.sysroot + library_name, "LD_LIBRARY_PATH"); } else path = library_name; @@ -1139,7 +1139,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, { string reloc_section; // base section for relocation purposes Dwarf_Addr reloc_addr; // relocated - const string& module = dw.module_name; // "kernel" or other + string& module = dw.module_name; // "kernel" or other string funcname = dw_funcname; assert (! has_absolute); // already handled in dwarf_builder::build() @@ -1190,6 +1190,14 @@ dwarf_query::add_probe_point(const string& dw_funcname, if (has_process) { + if (!sess.sysroot.empty()) + { + size_t pos; + if ((pos = module.find(sess.sysroot)) != string::npos) + module.replace(pos, sess.sysroot.length(), "/"); + if ((pos = path.find(sess.sysroot)) != string::npos) + path.replace(pos, sess.sysroot.length(), "/"); + } results.push_back (new uprobe_derived_probe(funcname, filename, line, module, reloc_section, addr, reloc_addr, *this, scope_die)); @@ -6548,13 +6556,14 @@ dwarf_builder::build(systemtap_session & sess, } else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS)) { + module_name = sess.sysroot + module_name; if(has_null_param(filled_parameters, TOK_PROCESS)) { wordexp_t words; int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF); if(rc || words.we_wordc <= 0) throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND")); - module_name = words.we_wordv[0]; + module_name = sess.sysroot + words.we_wordv[0]; filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map // in the case of TOK_MARK we need to modify locations as well if(location->components[0]->functor==TOK_PROCESS && @@ -6607,9 +6616,15 @@ dwarf_builder::build(systemtap_session & sess, if (sess.verbose > 1) clog << _F("Expanded process(\"%s\") to process(\"%s\")", module_name.c_str(), eglobbed.c_str()) << endl; + if (!sess.sysroot.empty()) + { + size_t pos; + if ((pos = eglobbed.find(sess.sysroot)) != string::npos) + eglobbed.replace(pos, sess.sysroot.length(), "/"); + } probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (eglobbed)); + new literal_string (eglobbed)); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6681,12 +6696,12 @@ dwarf_builder::build(systemtap_session & sess, if (p3 != string::npos) { string env_path = path.substr(p3); - user_path = find_executable (env_path); + user_path = find_executable (sess.sysroot + env_path); } } else { - user_path = find_executable (path); + user_path = find_executable (sess.sysroot + path); } struct stat st; @@ -6707,8 +6722,12 @@ dwarf_builder::build(systemtap_session & sess, // synthesize a new probe_point, with the expanded string probe_point *pp = new probe_point (*location); + string user_path_tgt = user_path; + size_t pos; + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + user_path_tgt.replace(pos, sess.sysroot.length(), "/"); probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (user_path.c_str())); + new literal_string (user_path_tgt.c_str())); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6727,7 +6746,7 @@ dwarf_builder::build(systemtap_session & sess, if(get_param (parameters, TOK_LIBRARY, user_lib) && user_lib.length() && ! contains_glob_chars (user_lib)) - module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); + module_name = find_executable (sess.sysroot + user_lib, "LD_LIBRARY_PATH"); else module_name = user_path; // canonicalize it @@ -8195,7 +8214,7 @@ struct kprobe_builder: public derived_probe_builder void -kprobe_builder::build(systemtap_session &, +kprobe_builder::build(systemtap_session & sess, probe * base, probe_point * location, literal_map_t const & parameters, @@ -8218,9 +8237,19 @@ kprobe_builder::build(systemtap_session &, has_library = get_param (parameters, TOK_LIBRARY, library); if (has_path) - path = find_executable (path); + { + size_t pos; + path = find_executable (sess.sysroot + path); + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + path.replace(pos, sess.sysroot.length(), "/"); + } if (has_library) - library = find_executable (library, "LD_LIBRARY_PATH"); + { + size_t pos; + library = find_executable (sess.sysroot + library, "LD_LIBRARY_PATH"); + if (!sess.sysroot.empty() && ((pos = library.find(sess.sysroot)) != string::npos)) + library.replace(pos, sess.sysroot.length(), "/"); + } if (has_function_str) { -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Add --sysroot option 2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth @ 2012-01-20 15:49 ` Wade Farnsworth 2012-01-20 18:11 ` Josh Stone 2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth 2 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-01-20 15:49 UTC (permalink / raw) To: systemtap Wade Farnsworth wrote: > This adds a --sysroot option to facilitate different file locations for > user-space processes and libraries at compile-time versus run-time when > generating stap kernel modules for a remote system. > > For example if we compile the probe: > > process("/bin/foo").begin {} > > while passing "--sysroot=/bar/baz" to stap, symbols will be taken from > /bar/baz/bin/foo, but the resulting .ko will still refer to /bin/foo. > This allows the probe to be used on a different machine than the one it > is compiled on, so long as the compiling machine replicates the > necessary files in the sysroot directory. This is a fairly typical use case > for embedded Linux. > > Known limitations: > 1. Probes must contain the absolute file path to the process or library. > If a relative path is used, it will be assumed to be located in the > top level of the sysroot. > 2. Similarly probes on scripts containing "#!/usr/bin/env bash" or similar > will also assume that the interpreter is located in the sysroot > top level. > The reason for these limitations is that we do not have access to the > target machine's environment compile-time, so some assumptions must > necessarily be made. > > Signed-off-by: Wade Farnsworth<wade_farnsworth@mentor.com> Any comments on this patch? In particular, I'm wondering if I'm on the right track here. Any advice would be appreciated. Thanks! -Wade > --- > session.cxx | 16 ++++++++++++++++ > session.h | 1 + > tapset-itrace.cxx | 5 ++++- > tapset-utrace.cxx | 5 ++++- > tapsets.cxx | 53 +++++++++++++++++++++++++++++++++++++++++------------ > 5 files changed, 66 insertions(+), 14 deletions(-) > > diff --git a/session.cxx b/session.cxx > index f4ce8a6..1c1adbf 100644 > --- a/session.cxx > +++ b/session.cxx > @@ -84,6 +84,7 @@ systemtap_session::systemtap_session (): > kernel_release = string (buf.release); > release = kernel_release; > kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; > + sysroot = string(); > architecture = machine = normalize_machine(buf.machine); > > for (unsigned i=0; i<5; i++) perpass_verbose[i]=0; > @@ -534,6 +535,8 @@ systemtap_session::usage (int exitcode) > " 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 executables are located" > , compatible.c_str())<< endl > ; > > @@ -587,6 +590,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) > #define LONG_OPT_PRIVILEGE 28 > #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29 > #define LONG_OPT_MODINFO 30 > +#define LONG_OPT_SYSROOT 31 > // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page > static struct option long_options[] = { > { "kelf", 0,&long_opt, LONG_OPT_KELF }, > @@ -625,6 +629,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) > { "privilege", 1,&long_opt, LONG_OPT_PRIVILEGE }, > { "suppress-handler-errors", 0,&long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS }, > { "modinfo", 1,&long_opt, LONG_OPT_MODINFO }, > + { "sysroot", 1,&long_opt, LONG_OPT_SYSROOT }, > { NULL, 0, NULL, 0 } > }; > int grc = getopt_long (argc, argv, "hVvtp:I:e:o:R:r:a:m:kgPc:x:D:bs:uqwl:d:L:FS:B:WG:", > @@ -1151,6 +1156,17 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) > modinfos.push_back (string(optarg)); > break; > > + case LONG_OPT_SYSROOT: > + { > + const 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) + "/"; > + break; > + } > + > default: > // NOTREACHED unless one added a getopt option but not a corresponding switch/case: > cerr<< _F("Unhandled long argument id %d", long_opt)<< endl; > diff --git a/session.h b/session.h > index 64a22a5..f1a301b 100644 > --- a/session.h > +++ b/session.h > @@ -140,6 +140,7 @@ public: > std::string kernel_base_release; > std::string kernel_build_tree; > std::string kernel_source_tree; > + std::string sysroot; > std::map<std::string,std::string> kernel_config; > std::set<std::string> kernel_exports; > std::string machine; > diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx > index 1a9bf67..77811d5 100644 > --- a/tapset-itrace.cxx > +++ b/tapset-itrace.cxx > @@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder > // If we have a path, we need to validate it. > if (has_path) > { > - path = find_executable (path); > + size_t pos; > + path = find_executable (sess.sysroot + path); > sess.unwindsym_modules.insert (path); > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); > } > > finished_results.push_back(new itrace_derived_probe(sess, base, location, > diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx > index 64ba900..11cf292 100644 > --- a/tapset-utrace.cxx > +++ b/tapset-utrace.cxx > @@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder > } > else if (has_path) > { > - path = find_executable (path); > + size_t pos; > + path = find_executable (sess.sysroot + path); > sess.unwindsym_modules.insert (path); > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); > } > else if (has_pid) > { > diff --git a/tapsets.cxx b/tapsets.cxx > index 177f565..50464dc 100644 > --- a/tapsets.cxx > +++ b/tapsets.cxx > @@ -584,13 +584,13 @@ base_query::base_query(dwflpp& dw, literal_map_t const& params): > has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); > > if (has_process) > - module_val = find_executable (module_val); > + module_val = find_executable (sess.sysroot + module_val); > if (has_library) > { > if (! contains_glob_chars (library_name)) > { > path = module_val; > - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); > + module_val = find_executable (sess.sysroot + library_name, "LD_LIBRARY_PATH"); > } > else > path = library_name; > @@ -1139,7 +1139,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, > { > string reloc_section; // base section for relocation purposes > Dwarf_Addr reloc_addr; // relocated > - const string& module = dw.module_name; // "kernel" or other > + string& module = dw.module_name; // "kernel" or other > string funcname = dw_funcname; > > assert (! has_absolute); // already handled in dwarf_builder::build() > @@ -1190,6 +1190,14 @@ dwarf_query::add_probe_point(const string& dw_funcname, > > if (has_process) > { > + if (!sess.sysroot.empty()) > + { > + size_t pos; > + if ((pos = module.find(sess.sysroot)) != string::npos) > + module.replace(pos, sess.sysroot.length(), "/"); > + if ((pos = path.find(sess.sysroot)) != string::npos) > + path.replace(pos, sess.sysroot.length(), "/"); > + } > results.push_back (new uprobe_derived_probe(funcname, filename, line, > module, reloc_section, addr, reloc_addr, > *this, scope_die)); > @@ -6548,13 +6556,14 @@ dwarf_builder::build(systemtap_session& sess, > } > else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS)) > { > + module_name = sess.sysroot + module_name; > if(has_null_param(filled_parameters, TOK_PROCESS)) > { > wordexp_t words; > int rc = wordexp(sess.cmd.c_str(),&words, WRDE_NOCMD|WRDE_UNDEF); > if(rc || words.we_wordc<= 0) > throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND")); > - module_name = words.we_wordv[0]; > + module_name = sess.sysroot + words.we_wordv[0]; > filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map > // in the case of TOK_MARK we need to modify locations as well > if(location->components[0]->functor==TOK_PROCESS&& > @@ -6607,9 +6616,15 @@ dwarf_builder::build(systemtap_session& sess, > if (sess.verbose> 1) > clog<< _F("Expanded process(\"%s\") to process(\"%s\")", > module_name.c_str(), eglobbed.c_str())<< endl; > + if (!sess.sysroot.empty()) > + { > + size_t pos; > + if ((pos = eglobbed.find(sess.sysroot)) != string::npos) > + eglobbed.replace(pos, sess.sysroot.length(), "/"); > + } > > probe_point::component* ppc = new probe_point::component (TOK_PROCESS, > - new literal_string (eglobbed)); > + new literal_string (eglobbed)); > ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above > pp->components[0] = ppc; > > @@ -6681,12 +6696,12 @@ dwarf_builder::build(systemtap_session& sess, > if (p3 != string::npos) > { > string env_path = path.substr(p3); > - user_path = find_executable (env_path); > + user_path = find_executable (sess.sysroot + env_path); > } > } > else > { > - user_path = find_executable (path); > + user_path = find_executable (sess.sysroot + path); > } > > struct stat st; > @@ -6707,8 +6722,12 @@ dwarf_builder::build(systemtap_session& sess, > > // synthesize a new probe_point, with the expanded string > probe_point *pp = new probe_point (*location); > + string user_path_tgt = user_path; > + size_t pos; > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + user_path_tgt.replace(pos, sess.sysroot.length(), "/"); > probe_point::component* ppc = new probe_point::component (TOK_PROCESS, > - new literal_string (user_path.c_str())); > + new literal_string (user_path_tgt.c_str())); > ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above > pp->components[0] = ppc; > > @@ -6727,7 +6746,7 @@ dwarf_builder::build(systemtap_session& sess, > > if(get_param (parameters, TOK_LIBRARY, user_lib) > && user_lib.length()&& ! contains_glob_chars (user_lib)) > - module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); > + module_name = find_executable (sess.sysroot + user_lib, "LD_LIBRARY_PATH"); > else > module_name = user_path; // canonicalize it > > @@ -8195,7 +8214,7 @@ struct kprobe_builder: public derived_probe_builder > > > void > -kprobe_builder::build(systemtap_session&, > +kprobe_builder::build(systemtap_session& sess, > probe * base, > probe_point * location, > literal_map_t const& parameters, > @@ -8218,9 +8237,19 @@ kprobe_builder::build(systemtap_session&, > has_library = get_param (parameters, TOK_LIBRARY, library); > > if (has_path) > - path = find_executable (path); > + { > + size_t pos; > + path = find_executable (sess.sysroot + path); > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); > + } > if (has_library) > - library = find_executable (library, "LD_LIBRARY_PATH"); > + { > + size_t pos; > + library = find_executable (sess.sysroot + library, "LD_LIBRARY_PATH"); > + if (!sess.sysroot.empty()&& ((pos = library.find(sess.sysroot)) != string::npos)) > + library.replace(pos, sess.sysroot.length(), "/"); > + } > > if (has_function_str) > { ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Add --sysroot option 2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth 2012-01-20 15:49 ` Wade Farnsworth @ 2012-01-20 18:11 ` Josh Stone 2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth 2 siblings, 0 replies; 15+ messages in thread From: Josh Stone @ 2012-01-20 18:11 UTC (permalink / raw) To: Wade Farnsworth; +Cc: systemtap On 01/09/2012 06:51 AM, Wade Farnsworth wrote: > This adds a --sysroot option to facilitate different file locations for > user-space processes and libraries at compile-time versus run-time when > generating stap kernel modules for a remote system. This enhancement is PR12331, so please prefix as such in your patch's subject. If you like, you may also claim assignment on the bug itself. http://sourceware.org/bugzilla/show_bug.cgi?id=12331 > > For example if we compile the probe: > > process("/bin/foo").begin {} > > while passing "--sysroot=/bar/baz" to stap, symbols will be taken from > /bar/baz/bin/foo, but the resulting .ko will still refer to /bin/foo. > This allows the probe to be used on a different machine than the one it > is compiled on, so long as the compiling machine replicates the > necessary files in the sysroot directory. This is a fairly typical use case > for embedded Linux. > > Known limitations: > 1. Probes must contain the absolute file path to the process or library. > If a relative path is used, it will be assumed to be located in the > top level of the sysroot. > 2. Similarly probes on scripts containing "#!/usr/bin/env bash" or similar > will also assume that the interpreter is located in the sysroot > top level. > The reason for these limitations is that we do not have access to the > target machine's environment compile-time, so some assumptions must > necessarily be made. It is a bit sticky that we don't know the target environment PATH or LD_LIBRARY_PATH. However, I think even assuming the same as this host is better than nothing, so one can at least benefit from the usual /bin:/usr/bin:... sort of paths. If need be, we can add another option for this, something like --sysenv=PATH=/bin:/system/bin:etc. So at least the basic part of this can be achieved by making find_executable() smarter about sysroot. In calls like this: > diff --git a/tapsets.cxx b/tapsets.cxx > index 177f565..50464dc 100644 > --- a/tapsets.cxx > +++ b/tapsets.cxx > @@ -584,13 +584,13 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): > has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); > > if (has_process) > - module_val = find_executable (module_val); > + module_val = find_executable (sess.sysroot + module_val); > if (has_library) > { > if (! contains_glob_chars (library_name)) > { > path = module_val; > - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); > + module_val = find_executable (sess.sysroot + library_name, "LD_LIBRARY_PATH"); > } > else > path = library_name; Notice that find_executable() takes an environment variable to to use for path searching (and defaults to "PATH"). I think the sysroot needs to be taken as a separate parameter in these calls, so it can be searched appropriately. The current behavior of find_executable() is if the name already has a '/', return as-is, else search the path. The new behavior needs to also prefix everything, so for names with '/' return sysroot/name, else search sysroot/PATH1/name, sysroot/PATH2/name, etc. and return whatever matches. This can still be escaped by relative paths that traverse upwards, e.g. "../../../usr/bin/foo". User shoots self in foot, news at 11. But this may matter for the client-server mode if a server has chosen to build from some sysroot. Perhaps ".." paths should be disallowed when sysroot is in use? I'm not really sure how well we can really protect this, but better to at least try. Also, I think clients should not be allowed to pass sysroot at all, given that they don't really know how the server is laid out in the first place. See how the client_options flag is used in restricting other options, and please do the same for --sysroot. Your patch focuses on process/library paths, but I think there are a few other cases that will need sysroot treatment too. For one, I would expect that some of the dwarf processing will need munging, especially for the case with split debuginfo from the main binary. Another is for locating the kernel binaries and build tree -- if -r is given as a path, that's probably fine, but for plain versions we should probably look in sysroot/lib/modules/RELEASE/... Thanks for tackling this feature, and sorry for the delayed review. Josh ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv 2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth 2012-01-20 15:49 ` Wade Farnsworth 2012-01-20 18:11 ` Josh Stone @ 2012-02-09 18:26 ` Wade Farnsworth 2012-02-17 14:39 ` Wade Farnsworth ` (2 more replies) 2 siblings, 3 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-02-09 18:26 UTC (permalink / raw) To: systemtap, jistone This adds new command-line options to facilitate different file locations at compile-time versus run-time when generating stap kernel modules for a remote system: 1. --sysroot=DIR Specifies a separate filesystem for the remote system on the local system. The following stap functionalities will make use of this: a. When compiling process and library probes with a remote filesystem path (e.g. process("/bin/foo") with --sysroot=/bar/baz). In this case symbols will be taken from the local filesystem (/bar/baz/bin/foo), but the resulting .ko will still contain paths on the remote filesystem (/bin/foo). b. When passing a kernel release with -r (not a full path), the kernel build directory will be expected in the sysroot. c. When DWARF debug info is contained in a separate file from the executable, the sysroot is used to find the debug info files. d. All calls to find_executable() search the path passed in the argument env_path relative to the sysroot. For example if PATH=/bin/foo, and --sysroot=/bar/baz is provided, then find_executable() called with env_path == "PATH" will search /bar/baz/bin/foo. e. stap attempts to detect if a path in a probe would be outside of the sysroot and errors appropriately. This situation may occur, for example, if the path contains several ".." directories. 2. --sysenv=VAR=VALUE Specifies a different environment variable for the remote system as opposed to the local one, and that the value on the remote system should be used. Currently only valid env_path arguments to find_executable() are handled (i.e. PATH, LD_LIBRARY_PATH). If --sysroot is provided and --sysenv is omitted, then the local environment relative to the sysroot will be used. These options are disabled for systemtap clients. Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com> --- Josh, I believe I have implemented all of your comments on the previous version of this patch. Any further suggestions are welcome! -v2: Implemented several improvements per Josh Stone's comment. cmdline.cxx | 2 + cmdline.h | 2 + dwflpp.cxx | 4 +- hash.cxx | 3 +- session.cxx | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- session.h | 3 ++ setupdwfl.cxx | 39 ++++++++++++++++++++++++++---- setupdwfl.h | 3 +- tapset-itrace.cxx | 5 +++- tapset-utrace.cxx | 5 +++- tapsets.cxx | 64 ++++++++++++++++++++++++++++++++++++++------------ translate.cxx | 6 ++-- util.cxx | 28 +++++++++++++++++---- util.h | 3 ++ 14 files changed, 197 insertions(+), 37 deletions(-) diff --git a/cmdline.cxx b/cmdline.cxx index 88e02f9..881a5c3 100644 --- a/cmdline.cxx +++ b/cmdline.cxx @@ -50,5 +50,7 @@ struct option stap_long_options[] = { { "privilege", 1, &stap_long_opt, LONG_OPT_PRIVILEGE }, { "suppress-handler-errors", 0, &stap_long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS }, { "modinfo", 1, &stap_long_opt, LONG_OPT_MODINFO }, + { "sysroot", 1, &stap_long_opt, LONG_OPT_SYSROOT }, + { "sysenv", 1, &stap_long_opt, LONG_OPT_SYSENV }, { NULL, 0, NULL, 0 } }; diff --git a/cmdline.h b/cmdline.h index 3229a7b..680f290 100644 --- a/cmdline.h +++ b/cmdline.h @@ -44,6 +44,8 @@ extern "C" { #define LONG_OPT_PRIVILEGE 28 #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29 #define LONG_OPT_MODINFO 30 +#define LONG_OPT_SYSROOT 31 +#define LONG_OPT_SYSENV 32 // NB: when adding new options, consider very carefully whether they // should be restricted from stap clients (after --client-options)! diff --git a/dwflpp.cxx b/dwflpp.cxx index 4d78187..17fd5c6 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session & s, bool debuginfo_n { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); find_debug_rpms(sess, dir.c_str()); } throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", @@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed) { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); find_debug_rpms(sess, dir.c_str()); } throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", diff --git a/hash.cxx b/hash.cxx index c435a03..69334f5 100644 --- a/hash.cxx +++ b/hash.cxx @@ -133,6 +133,7 @@ void create_hash_log(const string &type_str, const string &parms, const string & static const hash& get_base_hash (systemtap_session& s) { + map<string, char*> dummy; if (s.base_hash) return *s.base_hash; @@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s) // Hash compiler path, size, and mtime. We're just going to assume // we'll be using gcc. XXX: getting kbuild to spit out out would be // better, especially since this is fooled by ccache. - h.add_path("Compiler ", find_executable("gcc")); + h.add_path("Compiler ", find_executable("gcc", "", dummy)); // Hash the systemtap size and mtime. We could use VERSION/DATE, // but when developing systemtap that doesn't work well (since you diff --git a/session.cxx b/session.cxx index 24c329a..2c5be33 100644 --- a/session.cxx +++ b/session.cxx @@ -20,6 +20,7 @@ #include "util.h" #include "cmdline.h" #include "git_version.h" +#include "setupdwfl.h" #include <cerrno> #include <cstdlib> @@ -86,6 +87,8 @@ systemtap_session::systemtap_session (): kernel_release = string (buf.release); release = kernel_release; kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; + sysroot = ""; + update_release_sysroot = false; architecture = machine = normalize_machine(buf.machine); for (unsigned i=0; i<5; i++) perpass_verbose[i]=0; @@ -533,6 +536,13 @@ systemtap_session::usage (int exitcode) " 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 executables 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" + " relatve to the sysroot.\n" , compatible.c_str()) << endl ; @@ -1097,6 +1107,56 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) modinfos.push_back (string(optarg)); break; + case LONG_OPT_SYSROOT: + if (client_options) { + cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl; + return 1; + } else { + const 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); + if (sysroot[sysroot.size() - 1] != '/') + sysroot.append("/"); + + if (update_release_sysroot) + kernel_build_tree = sysroot + kernel_build_tree; + + debuginfo_path_insert_sysroot(sysroot); + + 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_str; + char * 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_str = sysenv_str.substr(pos + 1); + value = new char[value_str.size()+1]; + strcpy(value, value_str.c_str()); + sysenv[sysenv_str.substr(0, pos)] = value; + + break; + } + default: // NOTREACHED unless one added a getopt option but not a corresponding switch/case: cerr << _F("Unhandled long argument id %d", stap_long_opt) << endl; @@ -1387,8 +1447,13 @@ systemtap_session::setup_kernel_release (const char* kstr) else { kernel_release = string (kstr); - if (!kernel_release.empty()) + if (!kernel_release.empty()) { kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; + if (sysroot.empty()) + update_release_sysroot = true; + else + kernel_build_tree = sysroot + kernel_build_tree; + } // PR10745 // Let's not look for the kernel_source_tree; it's definitely diff --git a/session.h b/session.h index e128b2f..b5b8d82 100644 --- a/session.h +++ b/session.h @@ -140,6 +140,9 @@ public: std::string kernel_base_release; std::string kernel_build_tree; std::string kernel_source_tree; + std::string sysroot; + std::map<std::string,char *> sysenv; + bool update_release_sysroot; std::map<std::string,std::string> kernel_config; std::set<std::string> kernel_exports; std::string machine; diff --git a/setupdwfl.cxx b/setupdwfl.cxx index 82bc42a..fbffaf0 100644 --- a/setupdwfl.cxx +++ b/setupdwfl.cxx @@ -39,14 +39,14 @@ extern "C" { // XXX: also consider adding $HOME/.debug/ for perf build-id-cache static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build"; static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); -static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); +static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr); // NB: kernel_build_tree doesn't enter into this, as it's for // kernel-side modules only. // XXX: also consider adding $HOME/.debug/ for perf build-id-cache static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug"; -static const char *debuginfo_usr_path = (debuginfo_env_arr - ?: debuginfo_usr_path_arr); +static char *debuginfo_usr_path = (char *)(debuginfo_env_arr + ?: debuginfo_usr_path_arr); // A pointer to the current systemtap session for use only by a few // dwfl calls. DO NOT rely on this, as it is cleared after use. @@ -146,7 +146,10 @@ setup_mod_deps() } else { - modulesdep = "/lib/modules/"; + string sysroot = ""; + if (current_session_for_find_debuginfo) + sysroot = current_session_for_find_debuginfo->sysroot; + modulesdep = sysroot + "/lib/modules/"; modulesdep += elfutils_kernel_path; modulesdep += "/modules.dep"; } @@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename) } } +static char * path_insert_sysroot(string sysroot, string path) +{ + char * path_new; + size_t pos = 1; + if (path[0] == '/') + path.replace(0, 1, sysroot); + while (true) { + pos = path.find(":/", pos); + if (pos == string::npos) + break; + path.replace(pos, 2, ":" + sysroot); + ++pos; + } + path_new = new char[path.size()+1]; + strcpy (path_new, path.c_str()); + return path_new; +} + +void debuginfo_path_insert_sysroot(string sysroot) +{ + debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path); + debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path); +} + static DwflPtr setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) { @@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) // no way to set the dwfl_callback.debuginfo_path and always // passs the plain kernel_release here. So instead we have to // hard-code this magic here. - if (s.kernel_build_tree == string("/lib/modules/" + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" + s.kernel_release + "/build")) elfutils_kernel_path = s.kernel_release; @@ -413,7 +440,7 @@ setup_dwfl_kernel(const std::set<std::string> &names, } DwflPtr -setup_dwfl_user(const std::string &name) +setup_dwfl_user(const std::string &name, systemtap_session &s) { if (user_dwfl != NULL && user_modset.size() == 1 diff --git a/setupdwfl.h b/setupdwfl.h index 48f9105..4686574 100644 --- a/setupdwfl.h +++ b/setupdwfl.h @@ -50,7 +50,7 @@ DwflPtr setup_dwfl_kernel(const std::set<std::string> &names, unsigned *found, systemtap_session &s); -DwflPtr setup_dwfl_user(const std::string &name); +DwflPtr setup_dwfl_user(const std::string &name, systemtap_session &s); DwflPtr setup_dwfl_user(std::vector<std::string>::const_iterator &begin, const std::vector<std::string>::const_iterator &end, bool all_needed, systemtap_session &s); @@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod, int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex); std::string get_kernel_build_id (systemtap_session &s); int download_kernel_debuginfo (systemtap_session &s, std::string hex); +void debuginfo_path_insert_sysroot(std::string sysroot); #endif diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx index 1a9bf67..0e623fe 100644 --- a/tapset-itrace.cxx +++ b/tapset-itrace.cxx @@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder // If we have a path, we need to validate it. if (has_path) { - path = find_executable (path); + size_t pos; + path = find_executable (path, sess.sysroot, sess.sysenv); sess.unwindsym_modules.insert (path); + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + path.replace(pos, sess.sysroot.length(), "/"); } finished_results.push_back(new itrace_derived_probe(sess, base, location, diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index 64ba900..133d42a 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder } else if (has_path) { - path = find_executable (path); + size_t pos; + path = find_executable (path, sess.sysroot, sess.sysenv); sess.unwindsym_modules.insert (path); + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + path.replace(pos, sess.sysroot.length(), "/"); } else if (has_pid) { diff --git a/tapsets.cxx b/tapsets.cxx index cb56170..6cdb8e1 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -584,13 +584,14 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); if (has_process) - module_val = find_executable (module_val); + module_val = find_executable (module_val, sess.sysroot, sess.sysenv); if (has_library) { if (! contains_glob_chars (library_name)) { path = module_val; - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); + module_val = find_executable (library_name, sess.sysroot, + sess.sysenv, "LD_LIBRARY_PATH"); } else path = library_name; @@ -1137,7 +1138,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, { string reloc_section; // base section for relocation purposes Dwarf_Addr reloc_addr; // relocated - const string& module = dw.module_name; // "kernel" or other + string& module = dw.module_name; // "kernel" or other string funcname = dw_funcname; assert (! has_absolute); // already handled in dwarf_builder::build() @@ -1188,6 +1189,14 @@ dwarf_query::add_probe_point(const string& dw_funcname, if (has_process) { + if (!sess.sysroot.empty()) + { + size_t pos; + if ((pos = module.find(sess.sysroot)) != string::npos) + module.replace(pos, sess.sysroot.length(), "/"); + if ((pos = path.find(sess.sysroot)) != string::npos) + path.replace(pos, sess.sysroot.length(), "/"); + } results.push_back (new uprobe_derived_probe(funcname, filename, line, module, reloc_section, addr, reloc_addr, *this, scope_die)); @@ -2051,7 +2060,8 @@ query_one_library (const char *library, dwflpp & dw, { if (dw.function_name_matches_pattern(library, user_lib)) { - string library_path = find_executable (library, "LD_LIBRARY_PATH"); + string library_path = find_executable (library, "", dw.sess.sysenv, + "LD_LIBRARY_PATH"); probe_point* specific_loc = new probe_point(*base_loc); specific_loc->optional = true; vector<probe_point::component*> derived_comps; @@ -3906,7 +3916,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) } else { - module = find_executable (module); // canonicalize it + module = find_executable (module, "", s.sysenv); // canonicalize it dw = db.get_user_dw(s, module); } } @@ -6546,13 +6556,14 @@ dwarf_builder::build(systemtap_session & sess, } else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS)) { + module_name = sess.sysroot + module_name; if(has_null_param(filled_parameters, TOK_PROCESS)) { wordexp_t words; int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF); if(rc || words.we_wordc <= 0) throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND")); - module_name = words.we_wordv[0]; + module_name = sess.sysroot + words.we_wordv[0]; filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map // in the case of TOK_MARK we need to modify locations as well if(location->components[0]->functor==TOK_PROCESS && @@ -6605,9 +6616,15 @@ dwarf_builder::build(systemtap_session & sess, if (sess.verbose > 1) clog << _F("Expanded process(\"%s\") to process(\"%s\")", module_name.c_str(), eglobbed.c_str()) << endl; + if (!sess.sysroot.empty()) + { + size_t pos; + if ((pos = eglobbed.find(sess.sysroot)) != string::npos) + eglobbed.replace(pos, sess.sysroot.length(), "/"); + } probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (eglobbed)); + new literal_string (eglobbed)); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6633,7 +6650,7 @@ dwarf_builder::build(systemtap_session & sess, // PR13338: unquote glob results module_name = unescape_glob_chars (module_name); - user_path = find_executable (module_name); // canonicalize it + user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it // if the executable starts with "#!", we look for the interpreter of the script { @@ -6679,12 +6696,13 @@ dwarf_builder::build(systemtap_session & sess, if (p3 != string::npos) { string env_path = path.substr(p3); - user_path = find_executable (env_path); + user_path = find_executable (env_path, sess.sysroot, + sess.sysenv); } } else { - user_path = find_executable (path); + user_path = find_executable (path, sess.sysroot, sess.sysenv); } struct stat st; @@ -6705,8 +6723,12 @@ dwarf_builder::build(systemtap_session & sess, // synthesize a new probe_point, with the expanded string probe_point *pp = new probe_point (*location); + string user_path_tgt = user_path; + size_t pos; + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + user_path_tgt.replace(pos, sess.sysroot.length(), "/"); probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (user_path.c_str())); + new literal_string (user_path_tgt.c_str())); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6725,7 +6747,8 @@ dwarf_builder::build(systemtap_session & sess, if(get_param (parameters, TOK_LIBRARY, user_lib) && user_lib.length() && ! contains_glob_chars (user_lib)) - module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); + module_name = find_executable (user_lib, sess.sysroot, sess.sysenv, + "LD_LIBRARY_PATH"); else module_name = user_path; // canonicalize it @@ -8189,7 +8212,7 @@ struct kprobe_builder: public derived_probe_builder void -kprobe_builder::build(systemtap_session &, +kprobe_builder::build(systemtap_session & sess, probe * base, probe_point * location, literal_map_t const & parameters, @@ -8212,9 +8235,20 @@ kprobe_builder::build(systemtap_session &, has_library = get_param (parameters, TOK_LIBRARY, library); if (has_path) - path = find_executable (path); + { + size_t pos; + path = find_executable (path, sess.sysroot, sess.sysenv); + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) + path.replace(pos, sess.sysroot.length(), "/"); + } if (has_library) - library = find_executable (library, "LD_LIBRARY_PATH"); + { + size_t pos; + library = find_executable (library, sess.sysroot, sess.sysenv, + "LD_LIBRARY_PATH"); + if (!sess.sysroot.empty() && ((pos = library.find(sess.sysroot)) != string::npos)) + library.replace(pos, sess.sysroot.length(), "/"); + } if (has_function_str) { diff --git a/translate.cxx b/translate.cxx index 97847a8..70c4751 100644 --- a/translate.cxx +++ b/translate.cxx @@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session &s) // having the BUILDDIR we need to do a deep search (the specific // arch name dir in the kernel build tree is unknown). string vdso_dir; - if (s.kernel_build_tree == string("/lib/modules/" + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" + s.kernel_release + "/build")) - vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso"; + vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso"; else vdso_dir = s.kernel_build_tree + "/arch/"; @@ -6353,7 +6353,7 @@ emit_symbol_data (systemtap_session& s) string modname = *it; assert (modname.length() != 0); if (! is_user_module (modname)) continue; - DwflPtr dwfl_ptr = setup_dwfl_user (modname); + DwflPtr dwfl_ptr = setup_dwfl_user (modname, s); Dwfl *dwfl = dwfl_ptr.get()->dwfl; if (dwfl != NULL) // tolerate missing data; will warn below { diff --git a/util.cxx b/util.cxx index 93cf12a..4158f0d 100644 --- a/util.cxx +++ b/util.cxx @@ -345,7 +345,8 @@ tokenize_cxx(const string& str, vector<string>& tokens) // same policy as execvp(). A program name not containing a slash // will be searched along the $PATH. -string find_executable(const string& name, const string& env_path) +string find_executable(const string& name, const string& sysroot, + map<string, char*>& sysenv, const string& env_path) { string retpath; @@ -356,11 +357,15 @@ string find_executable(const string& name, const string& env_path) if (name.find('/') != string::npos) // slash in the path already? { - retpath = name; + retpath = sysroot + name; } else // Nope, search $PATH. { - char *path = getenv(env_path.c_str()); + char *path; + if (sysenv.count(env_path) != 0) + path = sysenv[env_path]; + else + path = getenv(env_path.c_str()); if (path) { // Split PATH up. @@ -370,7 +375,7 @@ string find_executable(const string& name, const string& env_path) // Search the path looking for the first executable of the right name. for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++) { - string fname = *i + "/" + name; + string fname = sysroot + *i + "/" + name; const char *f = fname.c_str(); // Look for a normal executable file. @@ -389,13 +394,24 @@ string find_executable(const string& name, const string& env_path) // Could not find the program on the $PATH. We'll just fall back to // the unqualified name, which our caller will probably fail with. if (retpath == "") - retpath = name; + retpath = sysroot + name; // Canonicalize the path name. char *cf = canonicalize_file_name (retpath.c_str()); if (cf) { - retpath = string(cf); + string scf = string(cf); + if (sysroot.empty()) + retpath = scf; + else { + int pos = scf.find(sysroot); + if (pos == 0) + retpath = scf; + else { + cerr << _F("ERROR: file %s not in sysroot %s", cf, sysroot.c_str()) << endl; + exit(1); + } + } free (cf); } diff --git a/util.h b/util.h index e576036..44e41e4 100644 --- a/util.h +++ b/util.h @@ -12,6 +12,7 @@ #include <cctype> #include <set> #include <iomanip> +#include <map> extern "C" { #include <libintl.h> #include <locale.h> @@ -51,6 +52,8 @@ void tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters); void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens); std::string find_executable(const std::string& name, + const std::string& sysroot, + std::map<std::string,char *>& sysenv, const std::string& env_path = "PATH"); const std::string cmdstr_quoted(const std::string& cmd); const std::string cmdstr_join(const std::vector<std::string>& cmds); -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv 2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth @ 2012-02-17 14:39 ` Wade Farnsworth 2012-02-24 22:56 ` Josh Stone 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth 2 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-02-17 14:39 UTC (permalink / raw) To: systemtap, jistone Hi all, Anyone have a chance to review this yet? Thanks in advance! -Wade Wade Farnsworth wrote: > This adds new command-line options to facilitate different file locations at > compile-time versus run-time when generating stap kernel modules for a remote > system: > > 1. --sysroot=DIR > Specifies a separate filesystem for the remote system on the local > system. The following stap functionalities will make use of this: > > a. When compiling process and library probes with a remote filesystem path > (e.g. process("/bin/foo") with --sysroot=/bar/baz). In this case symbols > will be taken from the local filesystem (/bar/baz/bin/foo), but the > resulting .ko will still contain paths on the remote filesystem > (/bin/foo). > > b. When passing a kernel release with -r (not a full path), the kernel > build directory will be expected in the sysroot. > > c. When DWARF debug info is contained in a separate file from the > executable, the sysroot is used to find the debug info files. > > d. All calls to find_executable() search the path passed in the > argument env_path relative to the sysroot. For example if > PATH=/bin/foo, and --sysroot=/bar/baz is provided, then > find_executable() called with env_path == "PATH" will search > /bar/baz/bin/foo. > > e. stap attempts to detect if a path in a probe would be outside of the > sysroot and errors appropriately. This situation may occur, for > example, if the path contains several ".." directories. > > 2. --sysenv=VAR=VALUE > Specifies a different environment variable for the remote system as opposed > to the local one, and that the value on the remote system should be used. > Currently only valid env_path arguments to find_executable() are handled > (i.e. PATH, LD_LIBRARY_PATH). If --sysroot is provided and --sysenv > is omitted, then the local environment relative to the sysroot will > be used. > > These options are disabled for systemtap clients. > > Signed-off-by: Wade Farnsworth<wade_farnsworth@mentor.com> > --- > > Josh, I believe I have implemented all of your comments on the previous version > of this patch. Any further suggestions are welcome! > > -v2: Implemented several improvements per Josh Stone's comment. > > cmdline.cxx | 2 + > cmdline.h | 2 + > dwflpp.cxx | 4 +- > hash.cxx | 3 +- > session.cxx | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- > session.h | 3 ++ > setupdwfl.cxx | 39 ++++++++++++++++++++++++++---- > setupdwfl.h | 3 +- > tapset-itrace.cxx | 5 +++- > tapset-utrace.cxx | 5 +++- > tapsets.cxx | 64 ++++++++++++++++++++++++++++++++++++++------------ > translate.cxx | 6 ++-- > util.cxx | 28 +++++++++++++++++---- > util.h | 3 ++ > 14 files changed, 197 insertions(+), 37 deletions(-) > > diff --git a/cmdline.cxx b/cmdline.cxx > index 88e02f9..881a5c3 100644 > --- a/cmdline.cxx > +++ b/cmdline.cxx > @@ -50,5 +50,7 @@ struct option stap_long_options[] = { > { "privilege", 1,&stap_long_opt, LONG_OPT_PRIVILEGE }, > { "suppress-handler-errors", 0,&stap_long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS }, > { "modinfo", 1,&stap_long_opt, LONG_OPT_MODINFO }, > + { "sysroot", 1,&stap_long_opt, LONG_OPT_SYSROOT }, > + { "sysenv", 1,&stap_long_opt, LONG_OPT_SYSENV }, > { NULL, 0, NULL, 0 } > }; > diff --git a/cmdline.h b/cmdline.h > index 3229a7b..680f290 100644 > --- a/cmdline.h > +++ b/cmdline.h > @@ -44,6 +44,8 @@ extern "C" { > #define LONG_OPT_PRIVILEGE 28 > #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29 > #define LONG_OPT_MODINFO 30 > +#define LONG_OPT_SYSROOT 31 > +#define LONG_OPT_SYSENV 32 > > // NB: when adding new options, consider very carefully whether they > // should be restricted from stap clients (after --client-options)! > diff --git a/dwflpp.cxx b/dwflpp.cxx > index 4d78187..17fd5c6 100644 > --- a/dwflpp.cxx > +++ b/dwflpp.cxx > @@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session& s, bool debuginfo_n > { > if (debuginfo_needed) { > // Suggest a likely kernel dir to find debuginfo rpm for > - string dir = string("/lib/modules/" + sess.kernel_release ); > + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); > find_debug_rpms(sess, dir.c_str()); > } > throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", > @@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed) > { > if (debuginfo_needed) { > // Suggest a likely kernel dir to find debuginfo rpm for > - string dir = string("/lib/modules/" + sess.kernel_release ); > + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); > find_debug_rpms(sess, dir.c_str()); > } > throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", > diff --git a/hash.cxx b/hash.cxx > index c435a03..69334f5 100644 > --- a/hash.cxx > +++ b/hash.cxx > @@ -133,6 +133,7 @@ void create_hash_log(const string&type_str, const string&parms, const string& > static const hash& > get_base_hash (systemtap_session& s) > { > + map<string, char*> dummy; > if (s.base_hash) > return *s.base_hash; > > @@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s) > // Hash compiler path, size, and mtime. We're just going to assume > // we'll be using gcc. XXX: getting kbuild to spit out out would be > // better, especially since this is fooled by ccache. > - h.add_path("Compiler ", find_executable("gcc")); > + h.add_path("Compiler ", find_executable("gcc", "", dummy)); > > // Hash the systemtap size and mtime. We could use VERSION/DATE, > // but when developing systemtap that doesn't work well (since you > diff --git a/session.cxx b/session.cxx > index 24c329a..2c5be33 100644 > --- a/session.cxx > +++ b/session.cxx > @@ -20,6 +20,7 @@ > #include "util.h" > #include "cmdline.h" > #include "git_version.h" > +#include "setupdwfl.h" > > #include<cerrno> > #include<cstdlib> > @@ -86,6 +87,8 @@ systemtap_session::systemtap_session (): > kernel_release = string (buf.release); > release = kernel_release; > kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; > + sysroot = ""; > + update_release_sysroot = false; > architecture = machine = normalize_machine(buf.machine); > > for (unsigned i=0; i<5; i++) perpass_verbose[i]=0; > @@ -533,6 +536,13 @@ systemtap_session::usage (int exitcode) > " 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 executables 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" > + " relatve to the sysroot.\n" > , compatible.c_str())<< endl > ; > > @@ -1097,6 +1107,56 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) > modinfos.push_back (string(optarg)); > break; > > + case LONG_OPT_SYSROOT: > + if (client_options) { > + cerr<< _F("ERROR: %s invalid with %s", "--sysroot", "--client-options")<< endl; > + return 1; > + } else { > + const 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); > + if (sysroot[sysroot.size() - 1] != '/') > + sysroot.append("/"); > + > + if (update_release_sysroot) > + kernel_build_tree = sysroot + kernel_build_tree; > + > + debuginfo_path_insert_sysroot(sysroot); > + > + 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_str; > + char * 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_str = sysenv_str.substr(pos + 1); > + value = new char[value_str.size()+1]; > + strcpy(value, value_str.c_str()); > + sysenv[sysenv_str.substr(0, pos)] = value; > + > + break; > + } > + > default: > // NOTREACHED unless one added a getopt option but not a corresponding switch/case: > cerr<< _F("Unhandled long argument id %d", stap_long_opt)<< endl; > @@ -1387,8 +1447,13 @@ systemtap_session::setup_kernel_release (const char* kstr) > else > { > kernel_release = string (kstr); > - if (!kernel_release.empty()) > + if (!kernel_release.empty()) { > kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; > + if (sysroot.empty()) > + update_release_sysroot = true; > + else > + kernel_build_tree = sysroot + kernel_build_tree; > + } > > // PR10745 > // Let's not look for the kernel_source_tree; it's definitely > diff --git a/session.h b/session.h > index e128b2f..b5b8d82 100644 > --- a/session.h > +++ b/session.h > @@ -140,6 +140,9 @@ public: > std::string kernel_base_release; > std::string kernel_build_tree; > std::string kernel_source_tree; > + std::string sysroot; > + std::map<std::string,char *> sysenv; > + bool update_release_sysroot; > std::map<std::string,std::string> kernel_config; > std::set<std::string> kernel_exports; > std::string machine; > diff --git a/setupdwfl.cxx b/setupdwfl.cxx > index 82bc42a..fbffaf0 100644 > --- a/setupdwfl.cxx > +++ b/setupdwfl.cxx > @@ -39,14 +39,14 @@ extern "C" { > // XXX: also consider adding $HOME/.debug/ for perf build-id-cache > static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build"; > static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); > -static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); > +static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr); > > // NB: kernel_build_tree doesn't enter into this, as it's for > // kernel-side modules only. > // XXX: also consider adding $HOME/.debug/ for perf build-id-cache > static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug"; > -static const char *debuginfo_usr_path = (debuginfo_env_arr > - ?: debuginfo_usr_path_arr); > +static char *debuginfo_usr_path = (char *)(debuginfo_env_arr > + ?: debuginfo_usr_path_arr); > > // A pointer to the current systemtap session for use only by a few > // dwfl calls. DO NOT rely on this, as it is cleared after use. > @@ -146,7 +146,10 @@ setup_mod_deps() > } > else > { > - modulesdep = "/lib/modules/"; > + string sysroot = ""; > + if (current_session_for_find_debuginfo) > + sysroot = current_session_for_find_debuginfo->sysroot; > + modulesdep = sysroot + "/lib/modules/"; > modulesdep += elfutils_kernel_path; > modulesdep += "/modules.dep"; > } > @@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename) > } > } > > +static char * path_insert_sysroot(string sysroot, string path) > +{ > + char * path_new; > + size_t pos = 1; > + if (path[0] == '/') > + path.replace(0, 1, sysroot); > + while (true) { > + pos = path.find(":/", pos); > + if (pos == string::npos) > + break; > + path.replace(pos, 2, ":" + sysroot); > + ++pos; > + } > + path_new = new char[path.size()+1]; > + strcpy (path_new, path.c_str()); > + return path_new; > +} > + > +void debuginfo_path_insert_sysroot(string sysroot) > +{ > + debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path); > + debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path); > +} > + > static DwflPtr > setup_dwfl_kernel (unsigned *modules_found, systemtap_session&s) > { > @@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session&s) > // no way to set the dwfl_callback.debuginfo_path and always > // passs the plain kernel_release here. So instead we have to > // hard-code this magic here. > - if (s.kernel_build_tree == string("/lib/modules/" > + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" > + s.kernel_release > + "/build")) > elfutils_kernel_path = s.kernel_release; > @@ -413,7 +440,7 @@ setup_dwfl_kernel(const std::set<std::string> &names, > } > > DwflPtr > -setup_dwfl_user(const std::string&name) > +setup_dwfl_user(const std::string&name, systemtap_session&s) > { > if (user_dwfl != NULL > && user_modset.size() == 1 > diff --git a/setupdwfl.h b/setupdwfl.h > index 48f9105..4686574 100644 > --- a/setupdwfl.h > +++ b/setupdwfl.h > @@ -50,7 +50,7 @@ DwflPtr setup_dwfl_kernel(const std::set<std::string> &names, > unsigned *found, > systemtap_session&s); > > -DwflPtr setup_dwfl_user(const std::string&name); > +DwflPtr setup_dwfl_user(const std::string&name, systemtap_session&s); > DwflPtr setup_dwfl_user(std::vector<std::string>::const_iterator&begin, > const std::vector<std::string>::const_iterator&end, > bool all_needed, systemtap_session&s); > @@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod, > int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex); > std::string get_kernel_build_id (systemtap_session&s); > int download_kernel_debuginfo (systemtap_session&s, std::string hex); > +void debuginfo_path_insert_sysroot(std::string sysroot); > > #endif > diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx > index 1a9bf67..0e623fe 100644 > --- a/tapset-itrace.cxx > +++ b/tapset-itrace.cxx > @@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder > // If we have a path, we need to validate it. > if (has_path) > { > - path = find_executable (path); > + size_t pos; > + path = find_executable (path, sess.sysroot, sess.sysenv); > sess.unwindsym_modules.insert (path); > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); > } > > finished_results.push_back(new itrace_derived_probe(sess, base, location, > diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx > index 64ba900..133d42a 100644 > --- a/tapset-utrace.cxx > +++ b/tapset-utrace.cxx > @@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder > } > else if (has_path) > { > - path = find_executable (path); > + size_t pos; > + path = find_executable (path, sess.sysroot, sess.sysenv); > sess.unwindsym_modules.insert (path); > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); > } > else if (has_pid) > { > diff --git a/tapsets.cxx b/tapsets.cxx > index cb56170..6cdb8e1 100644 > --- a/tapsets.cxx > +++ b/tapsets.cxx > @@ -584,13 +584,14 @@ base_query::base_query(dwflpp& dw, literal_map_t const& params): > has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); > > if (has_process) > - module_val = find_executable (module_val); > + module_val = find_executable (module_val, sess.sysroot, sess.sysenv); > if (has_library) > { > if (! contains_glob_chars (library_name)) > { > path = module_val; > - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); > + module_val = find_executable (library_name, sess.sysroot, > + sess.sysenv, "LD_LIBRARY_PATH"); > } > else > path = library_name; > @@ -1137,7 +1138,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, > { > string reloc_section; // base section for relocation purposes > Dwarf_Addr reloc_addr; // relocated > - const string& module = dw.module_name; // "kernel" or other > + string& module = dw.module_name; // "kernel" or other > string funcname = dw_funcname; > > assert (! has_absolute); // already handled in dwarf_builder::build() > @@ -1188,6 +1189,14 @@ dwarf_query::add_probe_point(const string& dw_funcname, > > if (has_process) > { > + if (!sess.sysroot.empty()) > + { > + size_t pos; > + if ((pos = module.find(sess.sysroot)) != string::npos) > + module.replace(pos, sess.sysroot.length(), "/"); > + if ((pos = path.find(sess.sysroot)) != string::npos) > + path.replace(pos, sess.sysroot.length(), "/"); > + } > results.push_back (new uprobe_derived_probe(funcname, filename, line, > module, reloc_section, addr, reloc_addr, > *this, scope_die)); > @@ -2051,7 +2060,8 @@ query_one_library (const char *library, dwflpp& dw, > { > if (dw.function_name_matches_pattern(library, user_lib)) > { > - string library_path = find_executable (library, "LD_LIBRARY_PATH"); > + string library_path = find_executable (library, "", dw.sess.sysenv, > + "LD_LIBRARY_PATH"); > probe_point* specific_loc = new probe_point(*base_loc); > specific_loc->optional = true; > vector<probe_point::component*> derived_comps; > @@ -3906,7 +3916,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) > } > else > { > - module = find_executable (module); // canonicalize it > + module = find_executable (module, "", s.sysenv); // canonicalize it > dw = db.get_user_dw(s, module); > } > } > @@ -6546,13 +6556,14 @@ dwarf_builder::build(systemtap_session& sess, > } > else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS)) > { > + module_name = sess.sysroot + module_name; > if(has_null_param(filled_parameters, TOK_PROCESS)) > { > wordexp_t words; > int rc = wordexp(sess.cmd.c_str(),&words, WRDE_NOCMD|WRDE_UNDEF); > if(rc || words.we_wordc<= 0) > throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND")); > - module_name = words.we_wordv[0]; > + module_name = sess.sysroot + words.we_wordv[0]; > filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map > // in the case of TOK_MARK we need to modify locations as well > if(location->components[0]->functor==TOK_PROCESS&& > @@ -6605,9 +6616,15 @@ dwarf_builder::build(systemtap_session& sess, > if (sess.verbose> 1) > clog<< _F("Expanded process(\"%s\") to process(\"%s\")", > module_name.c_str(), eglobbed.c_str())<< endl; > + if (!sess.sysroot.empty()) > + { > + size_t pos; > + if ((pos = eglobbed.find(sess.sysroot)) != string::npos) > + eglobbed.replace(pos, sess.sysroot.length(), "/"); > + } > > probe_point::component* ppc = new probe_point::component (TOK_PROCESS, > - new literal_string (eglobbed)); > + new literal_string (eglobbed)); > ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above > pp->components[0] = ppc; > > @@ -6633,7 +6650,7 @@ dwarf_builder::build(systemtap_session& sess, > > // PR13338: unquote glob results > module_name = unescape_glob_chars (module_name); > - user_path = find_executable (module_name); // canonicalize it > + user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it > > // if the executable starts with "#!", we look for the interpreter of the script > { > @@ -6679,12 +6696,13 @@ dwarf_builder::build(systemtap_session& sess, > if (p3 != string::npos) > { > string env_path = path.substr(p3); > - user_path = find_executable (env_path); > + user_path = find_executable (env_path, sess.sysroot, > + sess.sysenv); > } > } > else > { > - user_path = find_executable (path); > + user_path = find_executable (path, sess.sysroot, sess.sysenv); > } > > struct stat st; > @@ -6705,8 +6723,12 @@ dwarf_builder::build(systemtap_session& sess, > > // synthesize a new probe_point, with the expanded string > probe_point *pp = new probe_point (*location); > + string user_path_tgt = user_path; > + size_t pos; > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + user_path_tgt.replace(pos, sess.sysroot.length(), "/"); > probe_point::component* ppc = new probe_point::component (TOK_PROCESS, > - new literal_string (user_path.c_str())); > + new literal_string (user_path_tgt.c_str())); > ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above > pp->components[0] = ppc; > > @@ -6725,7 +6747,8 @@ dwarf_builder::build(systemtap_session& sess, > > if(get_param (parameters, TOK_LIBRARY, user_lib) > && user_lib.length()&& ! contains_glob_chars (user_lib)) > - module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); > + module_name = find_executable (user_lib, sess.sysroot, sess.sysenv, > + "LD_LIBRARY_PATH"); > else > module_name = user_path; // canonicalize it > > @@ -8189,7 +8212,7 @@ struct kprobe_builder: public derived_probe_builder > > > void > -kprobe_builder::build(systemtap_session&, > +kprobe_builder::build(systemtap_session& sess, > probe * base, > probe_point * location, > literal_map_t const& parameters, > @@ -8212,9 +8235,20 @@ kprobe_builder::build(systemtap_session&, > has_library = get_param (parameters, TOK_LIBRARY, library); > > if (has_path) > - path = find_executable (path); > + { > + size_t pos; > + path = find_executable (path, sess.sysroot, sess.sysenv); > + if (!sess.sysroot.empty()&& ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); > + } > if (has_library) > - library = find_executable (library, "LD_LIBRARY_PATH"); > + { > + size_t pos; > + library = find_executable (library, sess.sysroot, sess.sysenv, > + "LD_LIBRARY_PATH"); > + if (!sess.sysroot.empty()&& ((pos = library.find(sess.sysroot)) != string::npos)) > + library.replace(pos, sess.sysroot.length(), "/"); > + } > > if (has_function_str) > { > diff --git a/translate.cxx b/translate.cxx > index 97847a8..70c4751 100644 > --- a/translate.cxx > +++ b/translate.cxx > @@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session&s) > // having the BUILDDIR we need to do a deep search (the specific > // arch name dir in the kernel build tree is unknown). > string vdso_dir; > - if (s.kernel_build_tree == string("/lib/modules/" > + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" > + s.kernel_release > + "/build")) > - vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso"; > + vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso"; > else > vdso_dir = s.kernel_build_tree + "/arch/"; > > @@ -6353,7 +6353,7 @@ emit_symbol_data (systemtap_session& s) > string modname = *it; > assert (modname.length() != 0); > if (! is_user_module (modname)) continue; > - DwflPtr dwfl_ptr = setup_dwfl_user (modname); > + DwflPtr dwfl_ptr = setup_dwfl_user (modname, s); > Dwfl *dwfl = dwfl_ptr.get()->dwfl; > if (dwfl != NULL) // tolerate missing data; will warn below > { > diff --git a/util.cxx b/util.cxx > index 93cf12a..4158f0d 100644 > --- a/util.cxx > +++ b/util.cxx > @@ -345,7 +345,8 @@ tokenize_cxx(const string& str, vector<string>& tokens) > // same policy as execvp(). A program name not containing a slash > // will be searched along the $PATH. > > -string find_executable(const string& name, const string& env_path) > +string find_executable(const string& name, const string& sysroot, > + map<string, char*>& sysenv, const string& env_path) > { > string retpath; > > @@ -356,11 +357,15 @@ string find_executable(const string& name, const string& env_path) > > if (name.find('/') != string::npos) // slash in the path already? > { > - retpath = name; > + retpath = sysroot + name; > } > else // Nope, search $PATH. > { > - char *path = getenv(env_path.c_str()); > + char *path; > + if (sysenv.count(env_path) != 0) > + path = sysenv[env_path]; > + else > + path = getenv(env_path.c_str()); > if (path) > { > // Split PATH up. > @@ -370,7 +375,7 @@ string find_executable(const string& name, const string& env_path) > // Search the path looking for the first executable of the right name. > for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++) > { > - string fname = *i + "/" + name; > + string fname = sysroot + *i + "/" + name; > const char *f = fname.c_str(); > > // Look for a normal executable file. > @@ -389,13 +394,24 @@ string find_executable(const string& name, const string& env_path) > // Could not find the program on the $PATH. We'll just fall back to > // the unqualified name, which our caller will probably fail with. > if (retpath == "") > - retpath = name; > + retpath = sysroot + name; > > // Canonicalize the path name. > char *cf = canonicalize_file_name (retpath.c_str()); > if (cf) > { > - retpath = string(cf); > + string scf = string(cf); > + if (sysroot.empty()) > + retpath = scf; > + else { > + int pos = scf.find(sysroot); > + if (pos == 0) > + retpath = scf; > + else { > + cerr<< _F("ERROR: file %s not in sysroot %s", cf, sysroot.c_str())<< endl; > + exit(1); > + } > + } > free (cf); > } > > diff --git a/util.h b/util.h > index e576036..44e41e4 100644 > --- a/util.h > +++ b/util.h > @@ -12,6 +12,7 @@ > #include<cctype> > #include<set> > #include<iomanip> > +#include<map> > extern "C" { > #include<libintl.h> > #include<locale.h> > @@ -51,6 +52,8 @@ void tokenize(const std::string& str, std::vector<std::string>& tokens, > const std::string& delimiters); > void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens); > std::string find_executable(const std::string& name, > + const std::string& sysroot, > + std::map<std::string,char *>& sysenv, > const std::string& env_path = "PATH"); > const std::string cmdstr_quoted(const std::string& cmd); > const std::string cmdstr_join(const std::vector<std::string>& cmds); ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv 2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth 2012-02-17 14:39 ` Wade Farnsworth @ 2012-02-24 22:56 ` Josh Stone 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth 2 siblings, 0 replies; 15+ messages in thread From: Josh Stone @ 2012-02-24 22:56 UTC (permalink / raw) To: Wade Farnsworth; +Cc: systemtap Looks pretty good. I found a few things in review, noted below, but otherwise I think we can go ahead and push this into the repo, and patch any other issues as they arise. We should have at least some minimal testing for these options. It's hard since the testsuite can't assume any location of a real sysroot, but at least it should be sanity checked that something like this doesn't break: stap --sysroot=/ --sysenv=PATH=$PATH ... Docs are needed too -- please update stap.1 and NEWS. Thanks, Josh (review is heavily snipped, but hopefully it makes sense...) On 02/09/2012 10:26 AM, Wade Farnsworth wrote: > // Hash compiler path, size, and mtime. We're just going to assume > // we'll be using gcc. XXX: getting kbuild to spit out out would be > // better, especially since this is fooled by ccache. > - h.add_path("Compiler ", find_executable("gcc")); > + h.add_path("Compiler ", find_executable("gcc", "", dummy)); Not your fault, but that comment is getting more urgent. (or rather, this way of hashing gcc is getting more irrelevent.) Tracking the file info of a ccache wrapper is not helpful, and this is also missing the boat if CROSS_COMPILE is used. May have to look at kbuild again, or manually emulate kbuild's logic in choosing a compiler... > @@ -86,6 +87,8 @@ systemtap_session::systemtap_session (): > kernel_release = string (buf.release); > release = kernel_release; > kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; > + sysroot = ""; > + update_release_sysroot = false; These two and sysenv should be addressed in the session copy-ctor too. > + case LONG_OPT_SYSROOT: > + if (client_options) { > + cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl; > + return 1; > + } else { > + const 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); > + if (sysroot[sysroot.size() - 1] != '/') > + sysroot.append("/"); > + > + if (update_release_sysroot) > + kernel_build_tree = sysroot + kernel_build_tree; This method of "update_release_sysroot" feels convoluted to me. For one, if --sysroot occurs multiple times, it will get prepended every time. (If there are other reasons to prohibit multiple sysroot, then please check that.) How about instead, just delay sysroot prepending until after all arg processing? I think in passes_0_4() right at the start of pass 0 is better, just before the comment that says: // Now that no further changes to s.kernel_build_tree can occur [...] > + > + debuginfo_path_insert_sysroot(sysroot); This too should probably wait until options are all settled. > DwflPtr > -setup_dwfl_user(const std::string &name) > +setup_dwfl_user(const std::string &name, systemtap_session &s) > { > if (user_dwfl != NULL > && user_modset.size() == 1 Missing code to make use of the new "s" here? > + if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos)) > + path.replace(pos, sess.sysroot.length(), "/"); IMHO, this replacement is common enough to deserve a function. > // Canonicalize the path name. > char *cf = canonicalize_file_name (retpath.c_str()); > if (cf) > { > - retpath = string(cf); > + string scf = string(cf); > + if (sysroot.empty()) > + retpath = scf; > + else { > + int pos = scf.find(sysroot); > + if (pos == 0) > + retpath = scf; > + else { > + cerr << _F("ERROR: file %s not in sysroot %s", cf, sysroot.c_str()) << endl; > + exit(1); We need to do better than an exit(1) here, because there will be temporary files and possibly --remote connections that need to be cleaned up. Probably "throw runtime_error" will suffice instead. ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 0/3] PR12331: Introduce stap options --sysroot and --sysenv 2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth 2012-02-17 14:39 ` Wade Farnsworth 2012-02-24 22:56 ` Josh Stone @ 2012-03-02 14:47 ` Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 1/3] " Wade Farnsworth ` (3 more replies) 2 siblings, 4 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-02 14:47 UTC (permalink / raw) To: systemtap, jistone This patchset introduces --sysroot and --sysenv options for stap, which improve functionality in environments where the compiling system differs from the one running the probes. See Patch 1/3's description for more details on what has been implemented. v2: Implemented several improvements per Josh Stone's comments. v3: Further improvements per Josh Stone. Include documentation and test cases for the new options. Wade Farnsworth (3): PR12331: Introduce stap options --sysroot and --sysenv PR12331: Document --sysroot and --sysenv PR12331: Add testcase for --sysroot and --sysenv NEWS | 3 + cmdline.cxx | 2 + cmdline.h | 2 + dwflpp.cxx | 4 +- hash.cxx | 3 +- main.cxx | 9 ++++ session.cxx | 62 +++++++++++++++++++++++++++ session.h | 3 + setupdwfl.cxx | 37 ++++++++++++++-- setupdwfl.h | 1 + stap.1 | 11 +++++ tapset-itrace.cxx | 3 +- tapset-utrace.cxx | 3 +- tapsets.cxx | 54 +++++++++++++++++------ tapsets.h | 1 + testsuite/systemtap.base/sysroot_sysenv.exp | 15 ++++++ testsuite/systemtap.base/sysroot_sysenv.stp | 3 + translate.cxx | 4 +- util.cxx | 26 +++++++++--- util.h | 3 + 20 files changed, 216 insertions(+), 33 deletions(-) create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 1/3] PR12331: Introduce stap options --sysroot and --sysenv 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth @ 2012-03-02 14:48 ` Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 2/3] PR12331: Document " Wade Farnsworth ` (2 subsequent siblings) 3 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-02 14:48 UTC (permalink / raw) To: systemtap, jistone This adds new command-line options to facilitate different file locations at compile-time versus run-time when generating stap kernel modules for a remote system: 1. --sysroot=DIR Specifies a separate filesystem for the remote system on the local system. The following stap functionalities will make use of this: a. When compiling process and library probes with a remote filesystem path (e.g. process("/bin/foo") with --sysroot=/bar/baz). In this case symbols will be taken from the local filesystem (/bar/baz/bin/foo), but the resulting .ko will still contain paths on the remote filesystem (/bin/foo). b. When passing a kernel release with -r (not a full path), the kernel build directory will be expected in the sysroot. c. When DWARF debug info is contained in a separate file from the executable, the sysroot is used to find the debug info files. d. All calls to find_executable() search the path passed in the argument env_path relative to the sysroot. For example if PATH=/bin/foo, and --sysroot=/bar/baz is provided, then find_executable() called with env_path == "PATH" will search /bar/baz/bin/foo. e. stap attempts to detect if a path in a probe would be outside of the sysroot and errors appropriately. This situation may occur, for example, if the path contains several ".." directories. 2. --sysenv=VAR=VALUE Specifies a different environment variable for the remote system as opposed to the local one, and that the value on the remote system should be used. Currently only valid env_path arguments to find_executable() are handled (i.e. PATH, LD_LIBRARY_PATH). If --sysroot is provided and --sysenv is omitted, then the local environment relative to the sysroot will be used. These options are disabled for systemtap clients. Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com> --- cmdline.cxx | 2 + cmdline.h | 2 + dwflpp.cxx | 4 +- hash.cxx | 3 +- main.cxx | 9 +++++++ session.cxx | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ session.h | 3 ++ setupdwfl.cxx | 37 +++++++++++++++++++++++++++---- setupdwfl.h | 1 + tapset-itrace.cxx | 3 +- tapset-utrace.cxx | 3 +- tapsets.cxx | 54 +++++++++++++++++++++++++++++++++------------ tapsets.h | 1 + translate.cxx | 4 +- util.cxx | 26 +++++++++++++++++----- util.h | 3 ++ 16 files changed, 184 insertions(+), 33 deletions(-) diff --git a/cmdline.cxx b/cmdline.cxx index 88e02f9..881a5c3 100644 --- a/cmdline.cxx +++ b/cmdline.cxx @@ -50,5 +50,7 @@ struct option stap_long_options[] = { { "privilege", 1, &stap_long_opt, LONG_OPT_PRIVILEGE }, { "suppress-handler-errors", 0, &stap_long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS }, { "modinfo", 1, &stap_long_opt, LONG_OPT_MODINFO }, + { "sysroot", 1, &stap_long_opt, LONG_OPT_SYSROOT }, + { "sysenv", 1, &stap_long_opt, LONG_OPT_SYSENV }, { NULL, 0, NULL, 0 } }; diff --git a/cmdline.h b/cmdline.h index 3229a7b..680f290 100644 --- a/cmdline.h +++ b/cmdline.h @@ -44,6 +44,8 @@ extern "C" { #define LONG_OPT_PRIVILEGE 28 #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29 #define LONG_OPT_MODINFO 30 +#define LONG_OPT_SYSROOT 31 +#define LONG_OPT_SYSENV 32 // NB: when adding new options, consider very carefully whether they // should be restricted from stap clients (after --client-options)! diff --git a/dwflpp.cxx b/dwflpp.cxx index dd42962..6cb2fdb 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session & s, bool debuginfo_n { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); find_debug_rpms(sess, dir.c_str()); } throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", @@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed) { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); find_debug_rpms(sess, dir.c_str()); } throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", diff --git a/hash.cxx b/hash.cxx index c435a03..69334f5 100644 --- a/hash.cxx +++ b/hash.cxx @@ -133,6 +133,7 @@ void create_hash_log(const string &type_str, const string &parms, const string & static const hash& get_base_hash (systemtap_session& s) { + map<string, char*> dummy; if (s.base_hash) return *s.base_hash; @@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s) // Hash compiler path, size, and mtime. We're just going to assume // we'll be using gcc. XXX: getting kbuild to spit out out would be // better, especially since this is fooled by ccache. - h.add_path("Compiler ", find_executable("gcc")); + h.add_path("Compiler ", find_executable("gcc", "", dummy)); // Hash the systemtap size and mtime. We could use VERSION/DATE, // but when developing systemtap that doesn't work well (since you diff --git a/main.cxx b/main.cxx index 9e55f8e..4707989 100644 --- a/main.cxx +++ b/main.cxx @@ -24,6 +24,7 @@ #include "csclient.h" #include "remote.h" #include "tapsets.h" +#include "setupdwfl.h" #include <libintl.h> #include <locale.h> @@ -486,6 +487,14 @@ passes_0_4 (systemtap_session &s) s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-')); + // Update various paths to include the sysroot, if provided. + if (!s.sysroot.empty()) + { + if (s.update_release_sysroot && !s.sysroot.empty()) + s.kernel_build_tree = s.sysroot + s.kernel_build_tree; + debuginfo_path_insert_sysroot(s.sysroot); + } + // Now that no further changes to s.kernel_build_tree can occur, let's use it. if ((rc = parse_kernel_config (s)) != 0) { diff --git a/session.cxx b/session.cxx index 24c329a..73b2a19 100644 --- a/session.cxx +++ b/session.cxx @@ -149,6 +149,8 @@ systemtap_session::systemtap_session (): download_dbinfo = 0; suppress_handler_errors = false; native_build = true; // presumed + sysroot = ""; + update_release_sysroot = false; /* adding in the XDG_DATA_DIRS variable path, * this searches in conjunction with SYSTEMTAP_TAPSET @@ -310,6 +312,9 @@ systemtap_session::systemtap_session (const systemtap_session& other, 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; include_path = other.include_path; runtime_path = other.runtime_path; @@ -533,6 +538,13 @@ systemtap_session::usage (int exitcode) " 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" , compatible.c_str()) << endl ; @@ -1097,6 +1109,55 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) modinfos.push_back (string(optarg)); break; + case LONG_OPT_SYSROOT: + if (client_options) { + cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl; + return 1; + } + if (!sysroot.empty()) { + cerr << "ERROR: multiple --sysroot options not supported" << endl; + return 1; + } else { + const 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); + 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_str; + char * 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_str = sysenv_str.substr(pos + 1); + value = new char[value_str.size()+1]; + strcpy(value, value_str.c_str()); + sysenv[sysenv_str.substr(0, pos)] = value; + + break; + } + default: // NOTREACHED unless one added a getopt option but not a corresponding switch/case: cerr << _F("Unhandled long argument id %d", stap_long_opt) << endl; @@ -1386,6 +1447,7 @@ systemtap_session::setup_kernel_release (const char* kstr) } else { + update_release_sysroot = true; kernel_release = string (kstr); if (!kernel_release.empty()) kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; diff --git a/session.h b/session.h index e128b2f..b5b8d82 100644 --- a/session.h +++ b/session.h @@ -140,6 +140,9 @@ public: std::string kernel_base_release; std::string kernel_build_tree; std::string kernel_source_tree; + std::string sysroot; + std::map<std::string,char *> sysenv; + bool update_release_sysroot; std::map<std::string,std::string> kernel_config; std::set<std::string> kernel_exports; std::string machine; diff --git a/setupdwfl.cxx b/setupdwfl.cxx index 82bc42a..91bfd39 100644 --- a/setupdwfl.cxx +++ b/setupdwfl.cxx @@ -39,14 +39,14 @@ extern "C" { // XXX: also consider adding $HOME/.debug/ for perf build-id-cache static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build"; static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); -static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); +static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr); // NB: kernel_build_tree doesn't enter into this, as it's for // kernel-side modules only. // XXX: also consider adding $HOME/.debug/ for perf build-id-cache static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug"; -static const char *debuginfo_usr_path = (debuginfo_env_arr - ?: debuginfo_usr_path_arr); +static char *debuginfo_usr_path = (char *)(debuginfo_env_arr + ?: debuginfo_usr_path_arr); // A pointer to the current systemtap session for use only by a few // dwfl calls. DO NOT rely on this, as it is cleared after use. @@ -146,7 +146,10 @@ setup_mod_deps() } else { - modulesdep = "/lib/modules/"; + string sysroot = ""; + if (current_session_for_find_debuginfo) + sysroot = current_session_for_find_debuginfo->sysroot; + modulesdep = sysroot + "/lib/modules/"; modulesdep += elfutils_kernel_path; modulesdep += "/modules.dep"; } @@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename) } } +static char * path_insert_sysroot(string sysroot, string path) +{ + char * path_new; + size_t pos = 1; + if (path[0] == '/') + path.replace(0, 1, sysroot); + while (true) { + pos = path.find(":/", pos); + if (pos == string::npos) + break; + path.replace(pos, 2, ":" + sysroot); + ++pos; + } + path_new = new char[path.size()+1]; + strcpy (path_new, path.c_str()); + return path_new; +} + +void debuginfo_path_insert_sysroot(string sysroot) +{ + debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path); + debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path); +} + static DwflPtr setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) { @@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) // no way to set the dwfl_callback.debuginfo_path and always // passs the plain kernel_release here. So instead we have to // hard-code this magic here. - if (s.kernel_build_tree == string("/lib/modules/" + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" + s.kernel_release + "/build")) elfutils_kernel_path = s.kernel_release; diff --git a/setupdwfl.h b/setupdwfl.h index 48f9105..aa1c800 100644 --- a/setupdwfl.h +++ b/setupdwfl.h @@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod, int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex); std::string get_kernel_build_id (systemtap_session &s); int download_kernel_debuginfo (systemtap_session &s, std::string hex); +void debuginfo_path_insert_sysroot(std::string sysroot); #endif diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx index 1a9bf67..94a47da 100644 --- a/tapset-itrace.cxx +++ b/tapset-itrace.cxx @@ -114,8 +114,9 @@ struct itrace_builder: public derived_probe_builder // If we have a path, we need to validate it. if (has_path) { - path = find_executable (path); + path = find_executable (path, sess.sysroot, sess.sysenv); sess.unwindsym_modules.insert (path); + path_remove_sysroot(sess, path); } finished_results.push_back(new itrace_derived_probe(sess, base, location, diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index 64ba900..8c98435 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -679,8 +679,9 @@ struct utrace_builder: public derived_probe_builder } else if (has_path) { - path = find_executable (path); + path = find_executable (path, sess.sysroot, sess.sysenv); sess.unwindsym_modules.insert (path); + path_remove_sysroot(sess, path); } else if (has_pid) { diff --git a/tapsets.cxx b/tapsets.cxx index 716e23c..c2d00bb 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -584,13 +584,14 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); if (has_process) - module_val = find_executable (module_val); + module_val = find_executable (module_val, sess.sysroot, sess.sysenv); if (has_library) { if (! contains_glob_chars (library_name)) { path = module_val; - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); + module_val = find_executable (library_name, sess.sysroot, + sess.sysenv, "LD_LIBRARY_PATH"); } else path = library_name; @@ -1127,6 +1128,13 @@ bad: base_probe->tok); } +void path_remove_sysroot(const systemtap_session& sess, string& path) +{ + size_t pos; + if (!sess.sysroot.empty() && + (pos = path.find(sess.sysroot)) != string::npos) + path.replace(pos, sess.sysroot.length(), "/"); +} void dwarf_query::add_probe_point(const string& dw_funcname, @@ -1137,7 +1145,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, { string reloc_section; // base section for relocation purposes Dwarf_Addr reloc_addr; // relocated - const string& module = dw.module_name; // "kernel" or other + string& module = dw.module_name; // "kernel" or other string funcname = dw_funcname; assert (! has_absolute); // already handled in dwarf_builder::build() @@ -1188,6 +1196,8 @@ dwarf_query::add_probe_point(const string& dw_funcname, if (has_process) { + path_remove_sysroot(sess, module); + path_remove_sysroot(sess, path); results.push_back (new uprobe_derived_probe(funcname, filename, line, module, reloc_section, addr, reloc_addr, *this, scope_die)); @@ -2051,7 +2061,8 @@ query_one_library (const char *library, dwflpp & dw, { if (dw.function_name_matches_pattern(library, user_lib)) { - string library_path = find_executable (library, "LD_LIBRARY_PATH"); + string library_path = find_executable (library, "", dw.sess.sysenv, + "LD_LIBRARY_PATH"); probe_point* specific_loc = new probe_point(*base_loc); specific_loc->optional = true; vector<probe_point::component*> derived_comps; @@ -3906,7 +3917,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) } else { - module = find_executable (module); // canonicalize it + module = find_executable (module, "", s.sysenv); // canonicalize it dw = db.get_user_dw(s, module); } } @@ -6546,13 +6557,14 @@ dwarf_builder::build(systemtap_session & sess, } else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS)) { + module_name = sess.sysroot + module_name; if(has_null_param(filled_parameters, TOK_PROCESS)) { wordexp_t words; int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF); if(rc || words.we_wordc <= 0) throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND")); - module_name = words.we_wordv[0]; + module_name = sess.sysroot + words.we_wordv[0]; filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map // in the case of TOK_MARK we need to modify locations as well if(location->components[0]->functor==TOK_PROCESS && @@ -6605,9 +6617,10 @@ dwarf_builder::build(systemtap_session & sess, if (sess.verbose > 1) clog << _F("Expanded process(\"%s\") to process(\"%s\")", module_name.c_str(), eglobbed.c_str()) << endl; + path_remove_sysroot(sess, eglobbed); probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (eglobbed)); + new literal_string (eglobbed)); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6633,7 +6646,7 @@ dwarf_builder::build(systemtap_session & sess, // PR13338: unquote glob results module_name = unescape_glob_chars (module_name); - user_path = find_executable (module_name); // canonicalize it + user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it // if the executable starts with "#!", we look for the interpreter of the script { @@ -6679,12 +6692,13 @@ dwarf_builder::build(systemtap_session & sess, if (p3 != string::npos) { string env_path = path.substr(p3); - user_path = find_executable (env_path); + user_path = find_executable (env_path, sess.sysroot, + sess.sysenv); } } else { - user_path = find_executable (path); + user_path = find_executable (path, sess.sysroot, sess.sysenv); } struct stat st; @@ -6705,8 +6719,10 @@ dwarf_builder::build(systemtap_session & sess, // synthesize a new probe_point, with the expanded string probe_point *pp = new probe_point (*location); + string user_path_tgt = user_path; + path_remove_sysroot(sess, user_path_tgt); probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (user_path.c_str())); + new literal_string (user_path_tgt.c_str())); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6725,7 +6741,8 @@ dwarf_builder::build(systemtap_session & sess, if(get_param (parameters, TOK_LIBRARY, user_lib) && user_lib.length() && ! contains_glob_chars (user_lib)) - module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); + module_name = find_executable (user_lib, sess.sysroot, sess.sysenv, + "LD_LIBRARY_PATH"); else module_name = user_path; // canonicalize it @@ -8189,7 +8206,7 @@ struct kprobe_builder: public derived_probe_builder void -kprobe_builder::build(systemtap_session &, +kprobe_builder::build(systemtap_session & sess, probe * base, probe_point * location, literal_map_t const & parameters, @@ -8212,9 +8229,16 @@ kprobe_builder::build(systemtap_session &, has_library = get_param (parameters, TOK_LIBRARY, library); if (has_path) - path = find_executable (path); + { + path = find_executable (path, sess.sysroot, sess.sysenv); + path_remove_sysroot(sess, path); + } if (has_library) - library = find_executable (library, "LD_LIBRARY_PATH"); + { + library = find_executable (library, sess.sysroot, sess.sysenv, + "LD_LIBRARY_PATH"); + path_remove_sysroot(sess, library); + } if (has_function_str) { diff --git a/tapsets.h b/tapsets.h index c5fb30c..530bf51 100644 --- a/tapsets.h +++ b/tapsets.h @@ -31,6 +31,7 @@ void register_tapset_timers(systemtap_session& sess); void register_tapset_perf(systemtap_session& sess); void register_tapset_utrace(systemtap_session& sess); +void path_remove_sysroot(const systemtap_session& sess, std::string& path); // ------------------------------------------------------------------------ // Generic derived_probe_group: contains an ordinary vector of the diff --git a/translate.cxx b/translate.cxx index 97847a8..2b8d012 100644 --- a/translate.cxx +++ b/translate.cxx @@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session &s) // having the BUILDDIR we need to do a deep search (the specific // arch name dir in the kernel build tree is unknown). string vdso_dir; - if (s.kernel_build_tree == string("/lib/modules/" + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" + s.kernel_release + "/build")) - vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso"; + vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso"; else vdso_dir = s.kernel_build_tree + "/arch/"; diff --git a/util.cxx b/util.cxx index c14695b..7ece67f 100644 --- a/util.cxx +++ b/util.cxx @@ -346,7 +346,8 @@ tokenize_cxx(const string& str, vector<string>& tokens) // same policy as execvp(). A program name not containing a slash // will be searched along the $PATH. -string find_executable(const string& name, const string& env_path) +string find_executable(const string& name, const string& sysroot, + map<string, char*>& sysenv, const string& env_path) { string retpath; @@ -357,11 +358,15 @@ string find_executable(const string& name, const string& env_path) if (name.find('/') != string::npos) // slash in the path already? { - retpath = name; + retpath = sysroot + name; } else // Nope, search $PATH. { - char *path = getenv(env_path.c_str()); + char *path; + if (sysenv.count(env_path) != 0) + path = sysenv[env_path]; + else + path = getenv(env_path.c_str()); if (path) { // Split PATH up. @@ -371,7 +376,7 @@ string find_executable(const string& name, const string& env_path) // Search the path looking for the first executable of the right name. for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++) { - string fname = *i + "/" + name; + string fname = sysroot + *i + "/" + name; const char *f = fname.c_str(); // Look for a normal executable file. @@ -390,13 +395,22 @@ string find_executable(const string& name, const string& env_path) // Could not find the program on the $PATH. We'll just fall back to // the unqualified name, which our caller will probably fail with. if (retpath == "") - retpath = name; + retpath = sysroot + name; // Canonicalize the path name. char *cf = canonicalize_file_name (retpath.c_str()); if (cf) { - retpath = string(cf); + string scf = string(cf); + if (sysroot.empty()) + retpath = scf; + else { + int pos = scf.find(sysroot); + if (pos == 0) + retpath = scf; + else + throw runtime_error(_F("find_executable(): file %s not in sysroot %s", cf, sysroot.c_str())); + } free (cf); } diff --git a/util.h b/util.h index e576036..44e41e4 100644 --- a/util.h +++ b/util.h @@ -12,6 +12,7 @@ #include <cctype> #include <set> #include <iomanip> +#include <map> extern "C" { #include <libintl.h> #include <locale.h> @@ -51,6 +52,8 @@ void tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters); void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens); std::string find_executable(const std::string& name, + const std::string& sysroot, + std::map<std::string,char *>& sysenv, const std::string& env_path = "PATH"); const std::string cmdstr_quoted(const std::string& cmd); const std::string cmdstr_join(const std::vector<std::string>& cmds); -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 2/3] PR12331: Document --sysroot and --sysenv 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 1/3] " Wade Farnsworth @ 2012-03-02 14:48 ` Wade Farnsworth 2012-03-02 14:49 ` [PATCH v3 3/3] PR12331: Add testcase for " Wade Farnsworth 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth 3 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-02 14:48 UTC (permalink / raw) To: systemtap, jistone Update stap.1 and NEWS to document the new options. --- NEWS | 3 +++ stap.1 | 11 +++++++++++ 2 files changed, 14 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 6b52cf9..e5142c8 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,9 @@ removed in release 1.9: daddr_to_string() +- Addition of stap --sysroot and --sysenv options to facilitate different + paths and environment variables at run-time. + * What's new in version 1.7, 2012-02-01 - Map inserting and deleting is now significantly faster due to diff --git a/stap.1 b/stap.1 index 731ed21..cc7ebad 100644 --- a/stap.1 +++ b/stap.1 @@ -527,7 +527,18 @@ show abrt output, and ask before continuing download. No timeout will be set. .BI <timeout> specify a timeout as a positive number to stop the download if it is taking too long. +.RE + +.TP +.BI \-\-sysroot "=DIR" +Specify sysroot directory where target files (executables, libraries, etc.) +are located. +.TP +.BI \-\-sysenv "=VAR=VALUE" +Provide an alternate value for an environment variable where the value on a +remote system differs. Path variables (e.g. PATH, LD_LIBRARY_PATH) are assumed +to be relative to the sysroot. .SH ARGUMENTS -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 3/3] PR12331: Add testcase for --sysroot and --sysenv 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 1/3] " Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 2/3] PR12331: Document " Wade Farnsworth @ 2012-03-02 14:49 ` Wade Farnsworth 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth 3 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-02 14:49 UTC (permalink / raw) To: systemtap, jistone Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com> --- testsuite/systemtap.base/sysroot_sysenv.exp | 15 +++++++++++++++ testsuite/systemtap.base/sysroot_sysenv.stp | 3 +++ 2 files changed, 18 insertions(+), 0 deletions(-) create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp diff --git a/testsuite/systemtap.base/sysroot_sysenv.exp b/testsuite/systemtap.base/sysroot_sysenv.exp new file mode 100644 index 0000000..72b6822 --- /dev/null +++ b/testsuite/systemtap.base/sysroot_sysenv.exp @@ -0,0 +1,15 @@ +set test "sysroot_sysenv" + +if {[installtest_p] && [utrace_p] && [uprobes_p]} { + spawn stap --sysroot=/ --sysenv=PATH=$env(PATH) $srcdir/$subdir/$test.stp ls -c "ls > /dev/null" + expect { + -timeout 180 + -re {^process begin\r\n} { pass "$test" } + timeout { fail "$test (timeout)" } + eof { fail "$test" } + } +} else { + untested "$test" +} +catch {close} +wait diff --git a/testsuite/systemtap.base/sysroot_sysenv.stp b/testsuite/systemtap.base/sysroot_sysenv.stp new file mode 100644 index 0000000..950936f --- /dev/null +++ b/testsuite/systemtap.base/sysroot_sysenv.stp @@ -0,0 +1,3 @@ +probe process(@1).begin { + println("process begin") +} -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 0/3] Introduce stap options --sysroot and --sysenv 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth ` (2 preceding siblings ...) 2012-03-02 14:49 ` [PATCH v3 3/3] PR12331: Add testcase for " Wade Farnsworth @ 2012-03-08 14:48 ` Wade Farnsworth 2012-03-08 14:49 ` [PATCH v4 1/3] PR12331: " Wade Farnsworth ` (3 more replies) 3 siblings, 4 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-08 14:48 UTC (permalink / raw) To: systemtap, jistone, fche This patchset introduces --sysroot and --sysenv options for stap, which improve functionality in environments where the compiling system differs from the one running the probes. See Patch 1/3's description for more details on what has been implemented. v2 - Implemented several improvements per Josh Stone's comments. v3 - Further improvements per Josh Stone. Include documentation and test cases for the new options. v4 - Add more detail to the man page for --sysroot to clarify which paths are affected. - Changed handling of paths where both sysroot and non- sysroot versions are needed so that it's clear which version we're tracking. - Store the sysenv variable as map<string, string> instead of <string, char*>. Wade Farnsworth (3): PR12331: Introduce stap options --sysroot and --sysenv PR12331: Document --sysroot and --sysenv PR12331: Add testcase for --sysroot and --sysenv cmdline.cxx | 2 + cmdline.h | 2 + dwflpp.cxx | 4 +- hash.cxx | 3 +- main.cxx | 9 ++++ session.cxx | 59 ++++++++++++++++++++++++ session.h | 3 + setupdwfl.cxx | 37 +++++++++++++-- setupdwfl.h | 1 + stap.1 | 13 +++++ tapset-itrace.cxx | 7 ++- tapset-utrace.cxx | 7 ++- tapsets.cxx | 66 ++++++++++++++++++--------- tapsets.h | 2 + testsuite/systemtap.base/sysroot_sysenv.exp | 15 ++++++ testsuite/systemtap.base/sysroot_sysenv.stp | 3 + translate.cxx | 4 +- util.cxx | 27 +++++++++--- util.h | 3 + 19 files changed, 224 insertions(+), 43 deletions(-) create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 1/3] PR12331: Introduce stap options --sysroot and --sysenv 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth @ 2012-03-08 14:49 ` Wade Farnsworth 2012-03-08 14:50 ` [PATCH v4 2/3] PR12331: Document " Wade Farnsworth ` (2 subsequent siblings) 3 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-08 14:49 UTC (permalink / raw) To: systemtap, jistone, fche This adds new command-line options to facilitate different file locations at compile-time versus run-time when generating stap kernel modules for a remote system: 1. --sysroot=DIR Specifies a separate filesystem for the remote system on the local system. The following stap functionalities will make use of this: a. When compiling process and library probes with a remote filesystem path (e.g. process("/bin/foo") with --sysroot=/bar/baz). In this case symbols will be taken from the local filesystem (/bar/baz/bin/foo), but the resulting .ko will still contain paths on the remote filesystem (/bin/foo). b. When passing a kernel release with -r (not a full path), the kernel build directory will be expected in the sysroot. c. When DWARF debug info is contained in a separate file from the executable, the sysroot is used to find the debug info files. d. All calls to find_executable() search the path passed in the argument env_path relative to the sysroot. For example if PATH=/bin/foo, and --sysroot=/bar/baz is provided, then find_executable() called with env_path == "PATH" will search /bar/baz/bin/foo. e. stap attempts to detect if a path in a probe would be outside of the sysroot and errors appropriately. This situation may occur, for example, if the path contains several ".." directories. 2. --sysenv=VAR=VALUE Specifies a different environment variable for the remote system as opposed to the local one, and that the value on the remote system should be used. Currently only valid env_path arguments to find_executable() are handled (i.e. PATH, LD_LIBRARY_PATH). If --sysroot is provided and --sysenv is omitted, then the local environment relative to the sysroot will be used. These options are disabled for systemtap clients. Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com> --- cmdline.cxx | 2 + cmdline.h | 2 + dwflpp.cxx | 4 +- hash.cxx | 3 +- main.cxx | 9 +++++++ session.cxx | 59 +++++++++++++++++++++++++++++++++++++++++++++++ session.h | 3 ++ setupdwfl.cxx | 37 +++++++++++++++++++++++++---- setupdwfl.h | 1 + tapset-itrace.cxx | 7 +++-- tapset-utrace.cxx | 7 +++-- tapsets.cxx | 66 ++++++++++++++++++++++++++++++++++++----------------- tapsets.h | 2 + translate.cxx | 4 +- util.cxx | 27 +++++++++++++++++----- util.h | 3 ++ 16 files changed, 193 insertions(+), 43 deletions(-) diff --git a/cmdline.cxx b/cmdline.cxx index 04d741e..720d34a 100644 --- a/cmdline.cxx +++ b/cmdline.cxx @@ -55,5 +55,7 @@ struct option stap_long_options[] = { { "rlimit-nproc", 1, &stap_long_opt, LONG_OPT_RLIMIT_NPROC }, { "rlimit-stack", 1, &stap_long_opt, LONG_OPT_RLIMIT_STACK }, { "rlimit-fsize", 1, &stap_long_opt, LONG_OPT_RLIMIT_FSIZE }, + { "sysroot", 1, &stap_long_opt, LONG_OPT_SYSROOT }, + { "sysenv", 1, &stap_long_opt, LONG_OPT_SYSENV }, { NULL, 0, NULL, 0 } }; diff --git a/cmdline.h b/cmdline.h index 4a09bd0..b41c734 100644 --- a/cmdline.h +++ b/cmdline.h @@ -49,6 +49,8 @@ extern "C" { #define LONG_OPT_RLIMIT_NPROC 33 #define LONG_OPT_RLIMIT_STACK 34 #define LONG_OPT_RLIMIT_FSIZE 35 +#define LONG_OPT_SYSROOT 36 +#define LONG_OPT_SYSENV 37 // NB: when adding new options, consider very carefully whether they // should be restricted from stap clients (after --client-options)! diff --git a/dwflpp.cxx b/dwflpp.cxx index dd42962..6cb2fdb 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session & s, bool debuginfo_n { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); find_debug_rpms(sess, dir.c_str()); } throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", @@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed) { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); + string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release ); find_debug_rpms(sess, dir.c_str()); } throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'", diff --git a/hash.cxx b/hash.cxx index c435a03..f665ac3 100644 --- a/hash.cxx +++ b/hash.cxx @@ -133,6 +133,7 @@ void create_hash_log(const string &type_str, const string &parms, const string & static const hash& get_base_hash (systemtap_session& s) { + map<string, string> dummy; if (s.base_hash) return *s.base_hash; @@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s) // Hash compiler path, size, and mtime. We're just going to assume // we'll be using gcc. XXX: getting kbuild to spit out out would be // better, especially since this is fooled by ccache. - h.add_path("Compiler ", find_executable("gcc")); + h.add_path("Compiler ", find_executable("gcc", "", dummy)); // Hash the systemtap size and mtime. We could use VERSION/DATE, // but when developing systemtap that doesn't work well (since you diff --git a/main.cxx b/main.cxx index c08cf18..84f6e7c 100644 --- a/main.cxx +++ b/main.cxx @@ -24,6 +24,7 @@ #include "csclient.h" #include "remote.h" #include "tapsets.h" +#include "setupdwfl.h" #include <libintl.h> #include <locale.h> @@ -487,6 +488,14 @@ passes_0_4 (systemtap_session &s) s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-')); + // Update various paths to include the sysroot, if provided. + if (!s.sysroot.empty()) + { + if (s.update_release_sysroot && !s.sysroot.empty()) + s.kernel_build_tree = s.sysroot + s.kernel_build_tree; + debuginfo_path_insert_sysroot(s.sysroot); + } + // Now that no further changes to s.kernel_build_tree can occur, let's use it. if ((rc = parse_kernel_config (s)) != 0) { diff --git a/session.cxx b/session.cxx index b8fc17f..95ddda3 100644 --- a/session.cxx +++ b/session.cxx @@ -150,6 +150,8 @@ systemtap_session::systemtap_session (): download_dbinfo = 0; suppress_handler_errors = false; native_build = true; // presumed + sysroot = ""; + update_release_sysroot = false; /* adding in the XDG_DATA_DIRS variable path, * this searches in conjunction with SYSTEMTAP_TAPSET @@ -311,6 +313,9 @@ systemtap_session::systemtap_session (const systemtap_session& other, 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; include_path = other.include_path; runtime_path = other.runtime_path; @@ -534,6 +539,13 @@ systemtap_session::usage (int exitcode) " 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" , compatible.c_str()) << endl ; @@ -1139,6 +1151,52 @@ systemtap_session::parse_cmdline (int argc, char * const argv []) 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 { + const 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); + 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; + } + default: // NOTREACHED unless one added a getopt option but not a corresponding switch/case: cerr << _F("Unhandled long argument id %d", stap_long_opt) << endl; @@ -1428,6 +1486,7 @@ systemtap_session::setup_kernel_release (const char* kstr) } else { + update_release_sysroot = true; kernel_release = string (kstr); if (!kernel_release.empty()) kernel_build_tree = "/lib/modules/" + kernel_release + "/build"; diff --git a/session.h b/session.h index e128b2f..a82f1d1 100644 --- a/session.h +++ b/session.h @@ -140,6 +140,9 @@ public: std::string kernel_base_release; std::string kernel_build_tree; std::string kernel_source_tree; + std::string sysroot; + std::map<std::string,std::string> sysenv; + bool update_release_sysroot; std::map<std::string,std::string> kernel_config; std::set<std::string> kernel_exports; std::string machine; diff --git a/setupdwfl.cxx b/setupdwfl.cxx index 82bc42a..91bfd39 100644 --- a/setupdwfl.cxx +++ b/setupdwfl.cxx @@ -39,14 +39,14 @@ extern "C" { // XXX: also consider adding $HOME/.debug/ for perf build-id-cache static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build"; static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); -static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); +static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr); // NB: kernel_build_tree doesn't enter into this, as it's for // kernel-side modules only. // XXX: also consider adding $HOME/.debug/ for perf build-id-cache static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug"; -static const char *debuginfo_usr_path = (debuginfo_env_arr - ?: debuginfo_usr_path_arr); +static char *debuginfo_usr_path = (char *)(debuginfo_env_arr + ?: debuginfo_usr_path_arr); // A pointer to the current systemtap session for use only by a few // dwfl calls. DO NOT rely on this, as it is cleared after use. @@ -146,7 +146,10 @@ setup_mod_deps() } else { - modulesdep = "/lib/modules/"; + string sysroot = ""; + if (current_session_for_find_debuginfo) + sysroot = current_session_for_find_debuginfo->sysroot; + modulesdep = sysroot + "/lib/modules/"; modulesdep += elfutils_kernel_path; modulesdep += "/modules.dep"; } @@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename) } } +static char * path_insert_sysroot(string sysroot, string path) +{ + char * path_new; + size_t pos = 1; + if (path[0] == '/') + path.replace(0, 1, sysroot); + while (true) { + pos = path.find(":/", pos); + if (pos == string::npos) + break; + path.replace(pos, 2, ":" + sysroot); + ++pos; + } + path_new = new char[path.size()+1]; + strcpy (path_new, path.c_str()); + return path_new; +} + +void debuginfo_path_insert_sysroot(string sysroot) +{ + debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path); + debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path); +} + static DwflPtr setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) { @@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) // no way to set the dwfl_callback.debuginfo_path and always // passs the plain kernel_release here. So instead we have to // hard-code this magic here. - if (s.kernel_build_tree == string("/lib/modules/" + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" + s.kernel_release + "/build")) elfutils_kernel_path = s.kernel_release; diff --git a/setupdwfl.h b/setupdwfl.h index 48f9105..aa1c800 100644 --- a/setupdwfl.h +++ b/setupdwfl.h @@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod, int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex); std::string get_kernel_build_id (systemtap_session &s); int download_kernel_debuginfo (systemtap_session &s, std::string hex); +void debuginfo_path_insert_sysroot(std::string sysroot); #endif diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx index 1a9bf67..982ad46 100644 --- a/tapset-itrace.cxx +++ b/tapset-itrace.cxx @@ -100,7 +100,7 @@ struct itrace_builder: public derived_probe_builder std::map<std::string, literal *> const & parameters, vector<derived_probe *> & finished_results) { - string path; + string path, path_tgt; int64_t pid = 0; int single_step; @@ -114,12 +114,13 @@ struct itrace_builder: public derived_probe_builder // If we have a path, we need to validate it. if (has_path) { - path = find_executable (path); + path = find_executable (path, sess.sysroot, sess.sysenv); sess.unwindsym_modules.insert (path); + path_tgt = path_remove_sysroot(sess, path); } finished_results.push_back(new itrace_derived_probe(sess, base, location, - has_path, path, pid, + has_path, path_tgt, pid, single_step )); } diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index 64ba900..1ad99cf 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -642,7 +642,7 @@ struct utrace_builder: public derived_probe_builder literal_map_t const & parameters, vector<derived_probe *> & finished_results) { - string path; + string path, path_tgt; int64_t pid; bool has_path = get_param (parameters, TOK_PROCESS, path); @@ -679,8 +679,9 @@ struct utrace_builder: public derived_probe_builder } else if (has_path) { - path = find_executable (path); + path = find_executable (path, sess.sysroot, sess.sysenv); sess.unwindsym_modules.insert (path); + path_tgt = path_remove_sysroot(sess, path); } else if (has_pid) { @@ -693,7 +694,7 @@ struct utrace_builder: public derived_probe_builder } finished_results.push_back(new utrace_derived_probe(sess, base, location, - has_path, path, pid, + has_path, path_tgt, pid, flags)); } }; diff --git a/tapsets.cxx b/tapsets.cxx index 716e23c..7dee698 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -584,13 +584,14 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); if (has_process) - module_val = find_executable (module_val); + module_val = find_executable (module_val, sess.sysroot, sess.sysenv); if (has_library) { if (! contains_glob_chars (library_name)) { - path = module_val; - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); + path = path_remove_sysroot(sess, module_val); + module_val = find_executable (library_name, sess.sysroot, + sess.sysenv, "LD_LIBRARY_PATH"); } else path = library_name; @@ -1127,6 +1128,15 @@ bad: base_probe->tok); } +string path_remove_sysroot(const systemtap_session& sess, const string& path) +{ + size_t pos; + string retval = path; + if (!sess.sysroot.empty() && + (pos = retval.find(sess.sysroot)) != string::npos) + retval.replace(pos, sess.sysroot.length(), "/"); + return retval; +} void dwarf_query::add_probe_point(const string& dw_funcname, @@ -1188,8 +1198,9 @@ dwarf_query::add_probe_point(const string& dw_funcname, if (has_process) { + string module_tgt = path_remove_sysroot(sess, module); results.push_back (new uprobe_derived_probe(funcname, filename, line, - module, reloc_section, addr, reloc_addr, + module_tgt, reloc_section, addr, reloc_addr, *this, scope_die)); } else @@ -2051,7 +2062,8 @@ query_one_library (const char *library, dwflpp & dw, { if (dw.function_name_matches_pattern(library, user_lib)) { - string library_path = find_executable (library, "LD_LIBRARY_PATH"); + string library_path = find_executable (library, "", dw.sess.sysenv, + "LD_LIBRARY_PATH"); probe_point* specific_loc = new probe_point(*base_loc); specific_loc->optional = true; vector<probe_point::component*> derived_comps; @@ -3906,7 +3918,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) } else { - module = find_executable (module); // canonicalize it + module = find_executable (module, "", s.sysenv); // canonicalize it dw = db.get_user_dw(s, module); } } @@ -6546,13 +6558,14 @@ dwarf_builder::build(systemtap_session & sess, } else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS)) { + module_name = sess.sysroot + module_name; if(has_null_param(filled_parameters, TOK_PROCESS)) { wordexp_t words; int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF); if(rc || words.we_wordc <= 0) throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND")); - module_name = words.we_wordv[0]; + module_name = sess.sysroot + words.we_wordv[0]; filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map // in the case of TOK_MARK we need to modify locations as well if(location->components[0]->functor==TOK_PROCESS && @@ -6605,9 +6618,10 @@ dwarf_builder::build(systemtap_session & sess, if (sess.verbose > 1) clog << _F("Expanded process(\"%s\") to process(\"%s\")", module_name.c_str(), eglobbed.c_str()) << endl; + string eglobbed_tgt = path_remove_sysroot(sess, eglobbed); probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (eglobbed)); + new literal_string (eglobbed_tgt)); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6633,7 +6647,7 @@ dwarf_builder::build(systemtap_session & sess, // PR13338: unquote glob results module_name = unescape_glob_chars (module_name); - user_path = find_executable (module_name); // canonicalize it + user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it // if the executable starts with "#!", we look for the interpreter of the script { @@ -6679,12 +6693,13 @@ dwarf_builder::build(systemtap_session & sess, if (p3 != string::npos) { string env_path = path.substr(p3); - user_path = find_executable (env_path); + user_path = find_executable (env_path, sess.sysroot, + sess.sysenv); } } else { - user_path = find_executable (path); + user_path = find_executable (path, sess.sysroot, sess.sysenv); } struct stat st; @@ -6705,8 +6720,9 @@ dwarf_builder::build(systemtap_session & sess, // synthesize a new probe_point, with the expanded string probe_point *pp = new probe_point (*location); + string user_path_tgt = path_remove_sysroot(sess, user_path); probe_point::component* ppc = new probe_point::component (TOK_PROCESS, - new literal_string (user_path.c_str())); + new literal_string (user_path_tgt.c_str())); ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above pp->components[0] = ppc; @@ -6725,7 +6741,8 @@ dwarf_builder::build(systemtap_session & sess, if(get_param (parameters, TOK_LIBRARY, user_lib) && user_lib.length() && ! contains_glob_chars (user_lib)) - module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); + module_name = find_executable (user_lib, sess.sysroot, sess.sysenv, + "LD_LIBRARY_PATH"); else module_name = user_path; // canonicalize it @@ -8189,14 +8206,14 @@ struct kprobe_builder: public derived_probe_builder void -kprobe_builder::build(systemtap_session &, +kprobe_builder::build(systemtap_session & sess, probe * base, probe_point * location, literal_map_t const & parameters, vector<derived_probe *> & finished_results) { string function_string_val, module_string_val; - string path, library; + string path, library, path_tgt, library_tgt; int64_t statement_num_val = 0, maxactive_val = 0; bool has_function_str, has_module_str, has_statement_num; bool has_absolute, has_return, has_maxactive; @@ -8212,9 +8229,16 @@ kprobe_builder::build(systemtap_session &, has_library = get_param (parameters, TOK_LIBRARY, library); if (has_path) - path = find_executable (path); + { + path = find_executable (path, sess.sysroot, sess.sysenv); + path_tgt = path_remove_sysroot(sess, path); + } if (has_library) - library = find_executable (library, "LD_LIBRARY_PATH"); + { + library = find_executable (library, sess.sysroot, sess.sysenv, + "LD_LIBRARY_PATH"); + library_tgt = path_remove_sysroot(sess, library); + } if (has_function_str) { @@ -8229,8 +8253,8 @@ kprobe_builder::build(systemtap_session &, has_path, has_library, maxactive_val, - path, - library)); + path_tgt, + library_tgt)); } else { @@ -8247,8 +8271,8 @@ kprobe_builder::build(systemtap_session &, has_path, has_library, maxactive_val, - path, - library)); + path_tgt, + library_tgt)); } } diff --git a/tapsets.h b/tapsets.h index c5fb30c..ad0ed70 100644 --- a/tapsets.h +++ b/tapsets.h @@ -31,6 +31,8 @@ void register_tapset_timers(systemtap_session& sess); void register_tapset_perf(systemtap_session& sess); void register_tapset_utrace(systemtap_session& sess); +std::string path_remove_sysroot(const systemtap_session& sess, + const std::string& path); // ------------------------------------------------------------------------ // Generic derived_probe_group: contains an ordinary vector of the diff --git a/translate.cxx b/translate.cxx index 97847a8..2b8d012 100644 --- a/translate.cxx +++ b/translate.cxx @@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session &s) // having the BUILDDIR we need to do a deep search (the specific // arch name dir in the kernel build tree is unknown). string vdso_dir; - if (s.kernel_build_tree == string("/lib/modules/" + if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/" + s.kernel_release + "/build")) - vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso"; + vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso"; else vdso_dir = s.kernel_build_tree + "/arch/"; diff --git a/util.cxx b/util.cxx index ea90732..a7d8c3b 100644 --- a/util.cxx +++ b/util.cxx @@ -387,7 +387,9 @@ tokenize_cxx(const string& str, vector<string>& tokens) // same policy as execvp(). A program name not containing a slash // will be searched along the $PATH. -string find_executable(const string& name, const string& env_path) +string find_executable(const string& name, const string& sysroot, + map<string, string>& sysenv, + const string& env_path) { string retpath; @@ -398,11 +400,15 @@ string find_executable(const string& name, const string& env_path) if (name.find('/') != string::npos) // slash in the path already? { - retpath = name; + retpath = sysroot + name; } else // Nope, search $PATH. { - char *path = getenv(env_path.c_str()); + char *path; + if (sysenv.count(env_path) != 0) + path = (char *)sysenv[env_path].c_str(); + else + path = getenv(env_path.c_str()); if (path) { // Split PATH up. @@ -412,7 +418,7 @@ string find_executable(const string& name, const string& env_path) // Search the path looking for the first executable of the right name. for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++) { - string fname = *i + "/" + name; + string fname = sysroot + *i + "/" + name; const char *f = fname.c_str(); // Look for a normal executable file. @@ -431,13 +437,22 @@ string find_executable(const string& name, const string& env_path) // Could not find the program on the $PATH. We'll just fall back to // the unqualified name, which our caller will probably fail with. if (retpath == "") - retpath = name; + retpath = sysroot + name; // Canonicalize the path name. char *cf = canonicalize_file_name (retpath.c_str()); if (cf) { - retpath = string(cf); + string scf = string(cf); + if (sysroot.empty()) + retpath = scf; + else { + int pos = scf.find(sysroot); + if (pos == 0) + retpath = scf; + else + throw runtime_error(_F("find_executable(): file %s not in sysroot %s", cf, sysroot.c_str())); + } free (cf); } diff --git a/util.h b/util.h index 64a9746..b4d9ebf 100644 --- a/util.h +++ b/util.h @@ -12,6 +12,7 @@ #include <cctype> #include <set> #include <iomanip> +#include <map> extern "C" { #include <libintl.h> #include <locale.h> @@ -53,6 +54,8 @@ void tokenize_full(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters); void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens); std::string find_executable(const std::string& name, + const std::string& sysroot, + std::map<std::string,std::string>& sysenv, const std::string& env_path = "PATH"); const std::string cmdstr_quoted(const std::string& cmd); const std::string cmdstr_join(const std::vector<std::string>& cmds); -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 2/3] PR12331: Document --sysroot and --sysenv 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth 2012-03-08 14:49 ` [PATCH v4 1/3] PR12331: " Wade Farnsworth @ 2012-03-08 14:50 ` Wade Farnsworth 2012-03-08 14:51 ` [PATCH v4 3/3] PR12331: Add testcase for " Wade Farnsworth 2012-03-09 6:56 ` [PATCH v4 0/3] Introduce stap options " Josh Stone 3 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-08 14:50 UTC (permalink / raw) To: systemtap, jistone, fche Update stap.1 and NEWS to document the new options. --- stap.1 | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/stap.1 b/stap.1 index 43658de..52afb0d 100644 --- a/stap.1 +++ b/stap.1 @@ -555,6 +555,19 @@ no limits are imposed. Specify the maximum size of files that the process may create, in bytes. If nothing is specified, no limits are imposed. +.TP +.BI \-\-sysroot "=DIR" +Specify sysroot directory where target files (executables, libraries, etc.) +are located. With \fI\-r RELEASE\fR, the sysroot will be searched for the +appropriate kernel build directory. With \fI\-r /DIR\fR, however, the sysroot +will not be used to find the kernel build. + +.TP +.BI \-\-sysenv "=VAR=VALUE" +Provide an alternate value for an environment variable where the value on a +remote system differs. Path variables (e.g. PATH, LD_LIBRARY_PATH) are assumed +to be relative to the directory provided by \fI\-\-sysroot\fR, if provided. + .SH ARGUMENTS Any additional arguments on the command line are passed to the script -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 3/3] PR12331: Add testcase for --sysroot and --sysenv 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth 2012-03-08 14:49 ` [PATCH v4 1/3] PR12331: " Wade Farnsworth 2012-03-08 14:50 ` [PATCH v4 2/3] PR12331: Document " Wade Farnsworth @ 2012-03-08 14:51 ` Wade Farnsworth 2012-03-09 6:56 ` [PATCH v4 0/3] Introduce stap options " Josh Stone 3 siblings, 0 replies; 15+ messages in thread From: Wade Farnsworth @ 2012-03-08 14:51 UTC (permalink / raw) To: systemtap, jistone, fche Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com> --- testsuite/systemtap.base/sysroot_sysenv.exp | 15 +++++++++++++++ testsuite/systemtap.base/sysroot_sysenv.stp | 3 +++ 2 files changed, 18 insertions(+), 0 deletions(-) create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp diff --git a/testsuite/systemtap.base/sysroot_sysenv.exp b/testsuite/systemtap.base/sysroot_sysenv.exp new file mode 100644 index 0000000..72b6822 --- /dev/null +++ b/testsuite/systemtap.base/sysroot_sysenv.exp @@ -0,0 +1,15 @@ +set test "sysroot_sysenv" + +if {[installtest_p] && [utrace_p] && [uprobes_p]} { + spawn stap --sysroot=/ --sysenv=PATH=$env(PATH) $srcdir/$subdir/$test.stp ls -c "ls > /dev/null" + expect { + -timeout 180 + -re {^process begin\r\n} { pass "$test" } + timeout { fail "$test (timeout)" } + eof { fail "$test" } + } +} else { + untested "$test" +} +catch {close} +wait diff --git a/testsuite/systemtap.base/sysroot_sysenv.stp b/testsuite/systemtap.base/sysroot_sysenv.stp new file mode 100644 index 0000000..950936f --- /dev/null +++ b/testsuite/systemtap.base/sysroot_sysenv.stp @@ -0,0 +1,3 @@ +probe process(@1).begin { + println("process begin") +} -- 1.7.0.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 0/3] Introduce stap options --sysroot and --sysenv 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth ` (2 preceding siblings ...) 2012-03-08 14:51 ` [PATCH v4 3/3] PR12331: Add testcase for " Wade Farnsworth @ 2012-03-09 6:56 ` Josh Stone 3 siblings, 0 replies; 15+ messages in thread From: Josh Stone @ 2012-03-09 6:56 UTC (permalink / raw) To: Wade Farnsworth; +Cc: systemtap, fche On 03/08/2012 06:48 AM, Wade Farnsworth wrote: > This patchset introduces --sysroot and --sysenv options for stap, which > improve functionality in environments where the compiling system differs > from the one running the probes. > > See Patch 1/3's description for more details on what has been implemented. > > v2 - Implemented several improvements per Josh Stone's comments. > v3 - Further improvements per Josh Stone. Include documentation and test cases > for the new options. > v4 - Add more detail to the man page for --sysroot to clarify which paths > are affected. > - Changed handling of paths where both sysroot and non- > sysroot versions are needed so that it's clear which version we're tracking. > - Store the sysenv variable as map<string, string> instead of > <string, char*>. > > > Wade Farnsworth (3): > PR12331: Introduce stap options --sysroot and --sysenv > PR12331: Document --sysroot and --sysenv > PR12331: Add testcase for --sysroot and --sysenv Thanks, these are now merged and pushed. I did have to fix some conflicts with commit 372c6458, but I think I did that right. :) Josh ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2012-03-09 6:56 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth 2012-01-20 15:49 ` Wade Farnsworth 2012-01-20 18:11 ` Josh Stone 2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth 2012-02-17 14:39 ` Wade Farnsworth 2012-02-24 22:56 ` Josh Stone 2012-03-02 14:47 ` [PATCH v3 0/3] " Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 1/3] " Wade Farnsworth 2012-03-02 14:48 ` [PATCH v3 2/3] PR12331: Document " Wade Farnsworth 2012-03-02 14:49 ` [PATCH v3 3/3] PR12331: Add testcase for " Wade Farnsworth 2012-03-08 14:48 ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth 2012-03-08 14:49 ` [PATCH v4 1/3] PR12331: " Wade Farnsworth 2012-03-08 14:50 ` [PATCH v4 2/3] PR12331: Document " Wade Farnsworth 2012-03-08 14:51 ` [PATCH v4 3/3] PR12331: Add testcase for " Wade Farnsworth 2012-03-09 6:56 ` [PATCH v4 0/3] Introduce stap options " Josh Stone
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).