/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 (*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 (*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 ldd_command; ldd_command.push_back("/usr/bin/env"); @@ -1300,6 +1297,15 @@ dwflpp::iterate_over_libraries(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 (*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::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 inlined_funcs; - std::set plt_funcs; +// std::set plt_funcs; + std::map plt_funcs; std::set > marks; /* */ 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 & results, base_query *q) + vector & 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 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::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::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)