* process.plt.return probes
@ 2014-07-01 18:12 Stan Cox
0 siblings, 0 replies; only message in thread
From: Stan Cox @ 2014-07-01 18:12 UTC (permalink / raw)
To: systemtap
[-- Attachment #1: Type: text/plain, Size: 1318 bytes --]
This patch (not fully tested but complete enough to spur discussion)
adds plt.return. First, a brief discussion of what the plt (program
linkage table) and got (global offset table do:
.text
1. foo@plt jumps to .got.plt entry via .plt entry
callq 0x1,foo@plt
.plt
1a. first here
0x0 jmpq 0xN(%rip) # 0x10
3. which pushes foo's entry #
0x4 pushq 0x4c
4. then jumps to rtld which puts address of foo into .got.plt entry
0x8 jmpq <rtld>
.got.plt
1b. second here
2. then jumps to insn after plt entry jump
5. so going forward jumps will be here to target
0x10 jmpq 0x4
The current process.plt mechanism works by setting a probe at the
.got.plt address. To allow for process.plt.return probes this mechanism
has been enhanced as follows:
iterate_over_plt
->query_one_plt
->iterate_over_libraries
has been changed to iterate if there is no .interp; in which case
each interpreter is tried until success. (The ldd command uses
ld-linux --verify; but posix_spawn cannot check errno,
so it cannot do something similar, can it?)
->pltreturn_library_callback
looks for entry in the elf symbol table
if entry found in a library
then handle as process.function[.return]
else handle via existing process.plt.statement
[-- Attachment #2: stap-plt.patch --]
[-- Type: text/x-patch, Size: 10388 bytes --]
/work/scox/systemtap/src /work/scox/systemtap/bld /work/scox/systemtap/bld ~
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 09407b4..6ab8fd3 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -1248,6 +1248,23 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
assert (this->module_name.length() != 0);
Dwarf_Addr bias;
+
+ // Interpreters should follow startswith("/lib/ld") || startswith("/lib64/ld")
+ // Untrustworthy loaders should not be installed in those paths.
+ // See also http://sourceware.org/git/?p=glibc.git;a=blob;f=shlib-versions;hb=HEAD
+
+ string interpreters [] = {
+ "", // desired interpreter entry
+ "/lib64/ld-linux-x86-64.so.2", // x8664
+ "/lib/ld-linux.so.2", // x86
+ "/lib/ld64.so.1", // s390x, ppc64
+ "/lib64/ld64.so.1",
+ "/lib/ld-linux-ia64.so.2", // ia64
+ "/emul/ia32-linux/lib/ld-linux.so.2",
+ "/lib/ld-linux.so.3", // arm
+ "/lib/ld-linux-armhf.so.3" // arm
+ };
+
// We cannot use this: dwarf_getelf (dwfl_module_getdwarf (module, &bias))
Elf *elf = dwfl_module_getelf (module, &bias);
// elf_getphdrnum (elf, &phnum) is not available in all versions of elfutils
@@ -1270,27 +1287,7 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
}
}
- if (interpreter.length() == 0)
- return;
- // If it gets cumbersome to maintain this whitelist, we could just check for
- // startswith("/lib/ld") || startswith("/lib64/ld"), and trust that no admin
- // would install untrustworthy loaders in those paths.
- // See also http://sourceware.org/git/?p=glibc.git;a=blob;f=shlib-versions;hb=HEAD
- if (interpreter != "/lib/ld.so.1" // s390, ppc
- && interpreter != "/lib/ld64.so.1" // s390x, ppc64
- && interpreter != "/lib64/ld64.so.1"
- && interpreter != "/lib/ld-linux-ia64.so.2" // ia64
- && interpreter != "/emul/ia32-linux/lib/ld-linux.so.2"
- && interpreter != "/lib64/ld-linux-x86-64.so.2" // x8664
- && interpreter != "/lib/ld-linux.so.2" // x86
- && interpreter != "/lib/ld-linux.so.3" // arm
- && interpreter != "/lib/ld-linux-armhf.so.3" // arm
- )
- {
- sess.print_warning (_F("module %s --ldd skipped: unsupported interpreter: %s",
- module_name.c_str(), interpreter.c_str()));
- return;
- }
+ interpreters[0] = interpreter;
vector<string> ldd_command;
ldd_command.push_back("/usr/bin/env");
@@ -1300,6 +1297,15 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
ldd_command.push_back(interpreter);
ldd_command.push_back(module_name);
+ for (unsigned int i = 0; i < sizeof (interpreters) / sizeof (void*); i++)
+ {
+ // interpreter not setup yet
+ if (interpreters[0].length() == 0 && i == 0)
+ continue;
+ // found desired interpreter; skip remainder of interpreter list
+ else if (interpreters[0].length() > 0 && i > 0)
+ continue;
+ ldd_command[4] = interpreters[i];
FILE *fp;
int child_fd;
pid_t child = stap_spawn_piped(sess.verbose, ldd_command, NULL, &child_fd);
@@ -1351,9 +1357,13 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
free (soname);
free (shlib);
}
+ if (! added.empty())
+ interpreters[0] = interpreters[i];
+
if ((fclose(fp) || stap_waitpid(sess.verbose, child)))
sess.print_warning("failed to read libraries from " + module_name + ": " + strerror(errno));
}
+ }
for (std::set<std::string>::iterator it = added.begin();
it != added.end();
diff --git a/dwflpp.h b/dwflpp.h
index 2d4a656..548bd87 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -105,7 +105,8 @@ module_info
info_status symtab_status; // symbol table cached?
std::set<std::string> inlined_funcs;
- std::set<std::string> plt_funcs;
+// std::set<std::string> plt_funcs;
+ std::map<std::string,std::string> plt_funcs;
std::set<std::pair<std::string,std::string> > marks; /* <provider,name> */
void get_symtab();
diff --git a/tapsets.cxx b/tapsets.cxx
index edbcf92..8e14b80 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -587,6 +587,7 @@ struct base_query
static bool get_number_param(literal_map_t const & params,
string const & k, Dwarf_Addr & v);
static void query_library_callback (base_query *me, const char *data);
+ static void pltreturn_library_callback (dwarf_query *me, const char *data);
static void query_plt_callback (base_query *me, const char *link, size_t addr);
virtual void query_library (const char *data) = 0;
virtual void query_plt (const char *link, size_t addr) = 0;
@@ -2442,15 +2443,55 @@ void
base_query::query_plt_callback (base_query *me, const char *entry, size_t address)
{
if (me->dw.function_name_matches_pattern (entry, me->plt_val))
+ {
me->query_plt (entry, address);
- me->dw.mod_info->plt_funcs.insert(entry);
+ if (me->dw.mod_info->plt_funcs[entry].length() == 0)
+ me->dw.mod_info->plt_funcs[entry] = "";
+ }
+ // dw.mod_info->marks.insert(make_pair(provider_name, probe_name));
+ // for itmarks...marks.begin() itmarks->first.c_str()
+}
+
+
+void
+base_query::pltreturn_library_callback (dwarf_query *me, const char *entry)
+{
+ static Dwfl_Callbacks callbacks = {
+ &dwfl_linux_proc_find_elf,
+ &dwfl_standard_find_debuginfo,
+ NULL,
+ NULL,
+ };
+ Dwfl *dwfl = dwfl_begin (&callbacks);
+
+ Dwfl_Module *module = dwfl_report_offline (dwfl, entry, entry, -1);
+ int syms = dwfl_module_getsymtab (module);
+ DWFL_ASSERT (_("Getting symbols"), syms >= 0);
+
+ // Search elf symbol table of shared object for entry
+ for (int i = 0; i < syms; i++)
+ {
+ GElf_Sym sym;
+ GElf_Word shndxp;
+ const char *symname = dwfl_module_getsym(module, i, &sym, &shndxp);
+ if (symname && strcmp (me->plt_val.c_str(), symname) == 0)
+ {
+ if (GELF_ST_TYPE(sym.st_info) == STT_FUNC
+ && (GELF_ST_BIND(sym.st_info) == STB_GLOBAL
+ || GELF_ST_BIND(sym.st_info) == STB_WEAK
+ || GELF_ST_BIND(sym.st_info) == STB_GNU_UNIQUE))
+ {
+ me->dw.mod_info->plt_funcs[me->plt_val] = entry;
+ }
+ }
+ }
}
void
query_one_plt (const char *entry, long addr, dwflpp & dw,
probe * base_probe, probe_point *base_loc,
- vector<derived_probe *> & results, base_query *q)
+ vector<derived_probe *> & results, dwarf_query *q)
{
string module = dw.module_name;
if (q->has_process)
@@ -2458,7 +2499,7 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
probe_point* specific_loc = new probe_point(*base_loc);
specific_loc->well_formed = true;
-
+ string save_plt_val;
vector<probe_point::component*> derived_comps;
if (dw.sess.verbose > 2)
@@ -2477,6 +2518,14 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
else if ((*it)->functor == TOK_PLT)
{
// Replace possibly globby component
+ save_plt_val = q->plt_val;
+ q->plt_val = entry;
+ q->dw.iterate_over_libraries (&q->pltreturn_library_callback, q);
+ q->plt_val = save_plt_val;
+
+ if (q->dw.mod_info->plt_funcs[entry].length() == 0)
+ {
+ // Cannot find entry in a library: PROCESS.PLT.STATEMENT
*it = new probe_point::component(TOK_PLT,
new literal_string(entry));
derived_comps.push_back(*it);
@@ -2484,7 +2533,23 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
new literal_number(addr, true)));
}
else
+ {
+ // Found entry in a library: PROCESS.FUNCTION
+ // Change TOK_PROCESS argument to the found library path
+ // TODO not the ideal way to do this
+ derived_comps[0]->arg = new literal_string(q->dw.mod_info->plt_funcs[entry].c_str());
+ *it = new probe_point::component(TOK_FUNCTION,
+ new literal_string(entry));
derived_comps.push_back(*it);
+ }
+ }
+ else if ((*it)->functor == TOK_RETURN)
+ {
+ derived_comps.push_back(new probe_point::component(TOK_RETURN));
+ }
+ else
+ derived_comps.push_back(*it);
+
probe_point* derived_loc = new probe_point(*specific_loc);
derived_loc->components = derived_comps;
probe *new_base = new probe (new probe (base_probe, specific_loc),
@@ -2493,6 +2558,7 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
plt_expanding_visitor pltv (e);
pltv.replace (new_base->body);
derive_probes(dw.sess, new_base, results);
+ return;
}
@@ -5211,6 +5277,23 @@ dwarf_derived_probe::register_plt_variants(systemtap_session& s,
root->bind_str(TOK_PLT)->bind_num(TOK_STATEMENT)
->bind_privilege(pr_all)
->bind(dw);
+
+ root->bind(TOK_PLT)
+ ->bind(TOK_RETURN)
+ ->bind_privilege(pr_all)
+ ->bind(dw);
+ root->bind_str(TOK_PLT)
+ ->bind(TOK_RETURN)
+ ->bind_privilege(pr_all)
+ ->bind(dw);
+ root->bind(TOK_PLT)->bind_num(TOK_STATEMENT)
+ ->bind(TOK_RETURN)
+ ->bind_privilege(pr_all)
+ ->bind(dw);
+ root->bind_str(TOK_PLT)->bind_num(TOK_STATEMENT)
+ ->bind(TOK_RETURN)
+ ->bind_privilege(pr_all)
+ ->bind(dw);
}
void
@@ -7420,8 +7503,11 @@ suggest_plt_functions(systemtap_session& sess,
{
map<string, module_info*>::const_iterator itcache;
if ((itcache = cache.find(*itmod)) != cache.end())
- funcs.insert(itcache->second->plt_funcs.begin(),
- itcache->second->plt_funcs.end());
+ for (std::map<string,string>::iterator it=itcache->second->plt_funcs.begin();
+ it != itcache->second->plt_funcs.end(); ++it)
+ funcs.insert(it->first);
+// funcs.insert(itcache->second->plt_funcs.begin(),
+// itcache->second->plt_funcs.end());
}
if (sess.verbose > 2)
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2014-07-01 18:12 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-01 18:12 process.plt.return probes Stan Cox
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).