* PATCH add more syntax for shared library probing
@ 2011-03-23 15:12 Stan Cox
2011-03-24 16:50 ` Frank Ch. Eigler
0 siblings, 1 reply; 2+ messages in thread
From: Stan Cox @ 2011-03-23 15:12 UTC (permalink / raw)
To: systemtap
[-- Attachment #1: Type: text/plain, Size: 2187 bytes --]
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.
[-- Attachment #2: ,git.diff --]
[-- Type: text/plain, Size: 12575 bytes --]
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<Dwarf_Die> 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<string> 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<probe_point::component*> derived_comps;
+
+ vector<probe_point::component*>::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<derived_probe *> & 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<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& 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<string> 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<std::string>& 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<std::string>& cmds);
std::string git_revision(const std::string& path);
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: PATCH add more syntax for shared library probing
2011-03-23 15:12 PATCH add more syntax for shared library probing Stan Cox
@ 2011-03-24 16:50 ` Frank Ch. Eigler
0 siblings, 0 replies; 2+ messages in thread
From: Frank Ch. Eigler @ 2011-03-24 16:50 UTC (permalink / raw)
To: Stan Cox; +Cc: systemtap
scox wrote:
> [...]
Looks good!
> 2. Similar for -L. Perhaps filling in the wildcard with the matched
> library would be useful.
Yup. pp() etc. should get the fully resolved name.
> [...]
> +/* 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 */
> [...]
This ld.so-emulation code looks promising, but the risk of giving
results inconsistent with actual ld.so would have to be guarded
against. Have you considered PR12560's alternate approach?
- FChE
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-03-24 16:50 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-23 15:12 PATCH add more syntax for shared library probing Stan Cox
2011-03-24 16:50 ` Frank Ch. Eigler
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).