From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16371 invoked by alias); 23 Mar 2011 15:12:30 -0000 Received: (qmail 15810 invoked by uid 22791); 23 Mar 2011 15:12:07 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_DW,TW_FL,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 23 Mar 2011 15:11:59 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p2NFBvgh006675 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 23 Mar 2011 11:11:57 -0400 Received: from [10.11.231.159] (dhcp231-159.rdu.redhat.com [10.11.231.159]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p2NFBufv024086 for ; Wed, 23 Mar 2011 11:11:57 -0400 Message-ID: <4D8A0D75.9080600@redhat.com> Date: Wed, 23 Mar 2011 15:12:00 -0000 From: Stan Cox User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101209 Fedora/3.1.7-0.35.b3pre.fc14 Lightning/1.0b3pre Thunderbird/3.1.7 MIME-Version: 1.0 To: systemtap@sourceware.org Subject: PATCH add more syntax for shared library probing Content-Type: multipart/mixed; boundary="------------060504060901030204030507" X-IsSubscribed: yes Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org X-SW-Source: 2011-q1/txt/msg00518.txt.bz2 This is a multi-part message in MIME format. --------------060504060901030204030507 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 2187 Comments on this patch to add more syntax for shared library probing? Example: 1. library wildcard for function in libc.so stap -c "/usr/bin/printf '%s\n' 'ABCD'" -e 'probe process("/usr/bin/printf").library("*").function("__snprintf_chk") {printf("at printf begin\n")} probe process("/usr/bin/printf").library("*").function("__snprintf_chk").return {printf("at printf end\n")} probe process("/usr/bin/printf").library("*").statement("__snprintf_chk@snprintf_chk.c+2") {printf("in printf body\n")}' ABCD at printf begin in printf body at printf end 2. Similar for -L. Perhaps filling in the wildcard with the matched library would be useful. stap -L 'process("/usr/bin/printf").library("*").function("__snprintf_chk")' process("/usr/bin/printf").library("*").function("__snprintf_chk")? $s:char* $maxlen:size_t $flags:int $slen:size_t $format:char const* $arg:va_list $done:int 3. Probe in a user SO stap -c ./sdt_misc_uprobe_shared.x -e 'probe process ("./sdt_misc_uprobe_shared.x").library("*").statement("bar@sdt_misc.c+9") ? {printf ("In bar i=%d\n",$i)}' In bar i=2 * dwflpp.cxx (iterate_over_libraries): New. Just calls iterate_over_libraries_dynamic with the Dwfl_Module. (iterate_over_libraries_dynamic): Iterate through SHT_DYNAMIC for the Dwfl_Module. Save DT_RPATH/DT_RUNPATH for library search. DT_NEEDED/DT_SONAME are potentially SOs to search. Insure we haven't already seen it, call the callback, then find the SOs that this so references via iterate_over_libraries_module. The system default library paths are explicitly appended to runpath. (iterate_over_libraries_module): Get the Dwfl_Module for this SO via dwfl_getmodules which just callbacks iterate_over_libraries_dynamic. * util.cxx (find_executable): Add rpath and runpath default parameters. Search: 1. LD_RPATH 2. LD_LIBRARY_PATH 3. LD_RUNPATH 4. system libraries * tapsets.cxx (base_query): If this is a library then save the executable path. (query_module): For a library, call query_library_callback via iterate_over_libraries. (query_library_callback): New. Calls query_library. (query_library): Substitute the library name into the chain then derive_probes. --------------060504060901030204030507 Content-Type: text/plain; name=",git.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=",git.diff" Content-length: 12575 diff --git a/dwflpp.cxx b/dwflpp.cxx index 70bf07c..f47df3f 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -1021,8 +1021,6 @@ dwflpp::iterate_over_notes (void *object, void (*callback)(void *object, int typ if (elf_getshdrstrndx (elf, &shstrndx)) return elf_errno(); - GElf_Addr base = (GElf_Addr) -1; - Elf_Scn *scn = NULL; vector notes; @@ -1037,9 +1035,6 @@ dwflpp::iterate_over_notes (void *object, void (*callback)(void *object, int typ case SHT_NOTE: if (!(shdr.sh_flags & SHF_ALLOC)) { - if (base == (GElf_Addr) -1) - base = 0; - Elf_Data *data = elf_getdata (scn, NULL); size_t next; GElf_Nhdr nhdr; @@ -1057,6 +1052,125 @@ dwflpp::iterate_over_notes (void *object, void (*callback)(void *object, int typ } +/* For each entry in the .dynamic section in the current module call 'callback', use + * 'data' for the dynamic entry buffer return the entry type and 'object' in case + * 'callback' is a method */ + +typedef struct {Dwfl *dwfl; base_query *q; void (*callback)(void *object, int type, const char *arg);} iol_data; +static void iterate_over_libraries_module (const string& fname, iol_data *iold); +set libs_found; + +static int +iterate_over_libraries_dynamic(Dwfl_Module *mod, void **, const char *name, Dwarf_Addr addr, void *arg) +{ + Dwarf_Addr bias; + Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias)) + ?: dwfl_module_getelf (mod, &bias)); + size_t shstrndx; + iol_data *iold = (iol_data*)arg; + if (elf_getshdrstrndx (elf, &shstrndx)) + return elf_errno(); + + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) == NULL) + continue; + if (shdr.sh_type == SHT_DYNAMIC) + { + string rpath; + string runpath; + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + return 0; + + for (unsigned cnt = 0; cnt < shdr.sh_size / shdr.sh_entsize; ++cnt) + { + GElf_Dyn dynmem; + GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem); + if (dyn == NULL) + break; + switch (dyn->d_tag) + { + case DT_RPATH: + rpath = (const char*)elf_strptr (elf, shdr.sh_link, dyn->d_un.d_val); + break; + case DT_RUNPATH: + runpath = (const char*)elf_strptr (elf, shdr.sh_link, dyn->d_un.d_val); + break; + } + } + for (unsigned cnt = 0; cnt < shdr.sh_size / shdr.sh_entsize; ++cnt) + { + GElf_Dyn dynmem; + GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem); + string fname; + if (dyn == NULL) + break; + switch (dyn->d_tag) + { + case DT_NEEDED: + case DT_SONAME: + fname = (const char*)elf_strptr (elf, shdr.sh_link, dyn->d_un.d_val); + if (libs_found.find(fname) != libs_found.end()) + continue; + libs_found.insert(fname); + runpath = runpath + "/lib64:/usr/lib64:/lib:/usr/lib"; + fname = find_executable(fname, "LD_LIBRARY_PATH", rpath, runpath); + (iold->callback) (iold->q, dyn->d_tag, fname.c_str()); + iterate_over_libraries_module (fname, iold); + } + } + } + } + return 0; +} + + +static void +iterate_over_libraries_module (const string& fname, iol_data *iold) +{ + int fd; + + if ((fd = open (fname.c_str(), O_RDONLY)) < 0) + { + return; + } + static const Dwfl_Callbacks callbacks = + { + dwfl_build_id_find_elf, + dwfl_standard_find_debuginfo, + dwfl_offline_section_address, + NULL + }; + Dwfl *dwfl = dwfl_begin (&callbacks); + if (dwfl == NULL) + return; + if (dwfl_report_offline (dwfl, fname.c_str(), fname.c_str(), fd) == NULL) + return; + else + { + dwfl_report_end (dwfl, NULL, NULL); + + /* Process the one or more modules gleaned from this file. */ + // struct process_dwflmod_args a = { .fd = fd, .only_one = only_one }; + dwfl_getmodules (dwfl, &iterate_over_libraries_dynamic, iold, 0); + } + dwfl_end (dwfl); +} + + +void +dwflpp::iterate_over_libraries(void (*callback)(void *object, int type, const char *arg), base_query *q) +{ + libs_found.erase(libs_found.begin(),libs_found.end()); + iol_data iol_data = {dwfl_ptr.get()->dwfl, q, callback}; + iterate_over_libraries_dynamic (module, NULL, this->module_name.c_str(), 0, &iol_data); +} + + // This little test routine represents an unfortunate breakdown in // abstraction between dwflpp (putatively, a layer right on top of // elfutils), and dwarf_query (interpreting a systemtap probe point). diff --git a/dwflpp.h b/dwflpp.h index 5735f4e..fbbf2a2 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -251,6 +251,10 @@ struct dwflpp void (*callback)(void *object, int type, const char *data, size_t len)); + void iterate_over_libraries (void (*callback)(void *object, + int type, const char *data), base_query *data); + + GElf_Shdr * get_section(std::string section_name, GElf_Shdr *shdr_mem, Elf **elf_ret=NULL); diff --git a/tapsets.cxx b/tapsets.cxx index ceb78b8..0405c86 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -504,6 +504,9 @@ struct base_query string const & k, long & v); static bool get_number_param(literal_map_t const & params, string const & k, Dwarf_Addr & v); + static void query_library_callback (void *object, int type, const char *data); + virtual void query_library (int type, const char *data) = 0; + // Extracted parameters. bool has_kernel; @@ -532,13 +535,18 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): string library_name; has_process = get_string_param(params, TOK_PROCESS, module_val); has_library = get_string_param (params, TOK_LIBRARY, library_name); - if (has_library) - { - path = find_executable (module_val); - module_val = find_executable (library_name, "LD_LIBRARY_PATH"); - } - else if (has_process) + if (has_process) module_val = find_executable (module_val); + if (has_library) + { + if (! contains_glob_chars (library_name)) + { + path = module_val; + module_val = find_executable (library_name, "LD_LIBRARY_PATH"); + } + else + path = library_name; + } } assert (has_kernel || has_process || has_module); @@ -619,6 +627,7 @@ struct dwarf_query : public base_query virtual void handle_query_module(); void query_module_dwarf(); void query_module_symtab(); + void query_library (int type, const char *data); void add_probe_point(string const & funcname, char const * filename, @@ -1919,8 +1928,12 @@ query_module (Dwfl_Module *mod, q->sess.sym_stext = lookup_symbol_address (mod, "_stext"); } - // Finally, search the module for matches of the probe point. - q->handle_query_module(); + if (q->has_library && contains_glob_chars (q->path)) + // handle .library(GLOB) + q->dw.iterate_over_libraries(&q->query_library_callback, q); + else + // search the module for matches of the probe point. + q->handle_query_module(); // If we know that there will be no more matches, abort early. @@ -1937,6 +1950,43 @@ query_module (Dwfl_Module *mod, } +void +base_query::query_library_callback (void *q, int type, const char *data) +{ + base_query *me = (base_query*)q; + me->query_library (type, data); +} + + +void +dwarf_query::query_library (int type, const char *library) +{ + if (type == DT_NEEDED + && dw.function_name_matches_pattern(library, user_lib)) + { + string library_path = find_executable (library, "LD_LIBRARY_PATH"); + probe_point* specific_loc = new probe_point(*base_loc); + specific_loc->optional = true; + vector derived_comps; + + vector::iterator it; + for (it = specific_loc->components.begin(); + it != specific_loc->components.end(); ++it) + if ((*it)->functor == TOK_LIBRARY) + derived_comps.push_back(new probe_point::component(TOK_LIBRARY, + new literal_string(library_path))); + else + derived_comps.push_back(*it); + probe_point* derived_loc = new probe_point(*specific_loc); + derived_loc->components = derived_comps; + probe *new_base = base_probe->create_alias(derived_loc, specific_loc); + derive_probes(sess, new_base, results); + if (sess.verbose > 2) + clog << _("module=") << library_path; + } +} + + // This would more naturally fit into elaborate.cxx:semantic_pass_symbols, // but the needed declaration for module_cache is not available there. // Nor for that matter in session.cxx. Only in this CU is that field ever @@ -3453,6 +3503,7 @@ struct dwarf_cast_query : public base_query userspace_p(userspace_p), result(result) {} void handle_query_module(); + void query_library (int type, const char *data) {}; }; @@ -5307,6 +5358,7 @@ struct sdt_query : public base_query dwflpp & dw, literal_map_t const & params, vector & results); + void query_library (int type, const char *data) {}; void handle_query_module(); private: @@ -5954,9 +6006,7 @@ dwarf_builder::build(systemtap_session & sess, dw = get_kern_dw(sess, module_name); } else if (get_param (parameters, TOK_PROCESS, module_name)) - { - string library_name; - + { // PR6456 process("/bin/*") glob handling if (contains_glob_chars (module_name)) { @@ -6113,11 +6163,9 @@ dwarf_builder::build(systemtap_session & sess, script_file.close(); } - if (get_param (parameters, TOK_LIBRARY, library_name)) - { - module_name = find_executable (library_name, "LD_LIBRARY_PATH"); - user_lib = module_name; - } + get_param (parameters, TOK_LIBRARY, user_lib); + if (user_lib.length() && ! contains_glob_chars (user_lib)) + module_name = find_executable (user_lib, "LD_LIBRARY_PATH"); else module_name = user_path; // canonicalize it @@ -8479,6 +8527,7 @@ struct tracepoint_query : public base_query void handle_query_module(); int handle_query_cu(Dwarf_Die * cudie); int handle_query_func(Dwarf_Die * func); + void query_library (int type, const char *data) {}; static int tracepoint_query_cu (Dwarf_Die * cudie, void * arg); static int tracepoint_query_func (Dwarf_Die * func, base_query * query); diff --git a/util.cxx b/util.cxx index a1dc8c0..24be913 100644 --- a/util.cxx +++ b/util.cxx @@ -321,7 +321,8 @@ tokenize(const string& str, vector& 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& env_path, + const string& rpath, const string& runpath) { string retpath; @@ -336,8 +337,12 @@ string find_executable(const string& name, const string& env_path) } else // Nope, search $PATH. { - char *path = getenv(env_path.c_str()); - if (path) + string path = getenv(env_path.c_str()); + if (rpath.length() != 0 && runpath.length() == 0) + path = rpath + ":" + path; + if (runpath.length() != 0) + path = path + ":" + runpath; + if (path.length()) { // Split PATH up. vector dirs; diff --git a/util.h b/util.h index bc79dd5..074ed34 100644 --- a/util.h +++ b/util.h @@ -23,7 +23,9 @@ std::string getmemusage (); void tokenize(const std::string& str, std::vector& tokens, const std::string& delimiters); std::string find_executable(const std::string& name, - const std::string& env_path = "PATH"); + const std::string& env_path = "PATH", + const std::string& rpath = "", + const std::string& runpath = ""); const std::string cmdstr_quoted(const std::string& cmd); const std::string cmdstr_join(const std::vector& cmds); std::string git_revision(const std::string& path); --------------060504060901030204030507--