diff options
-rw-r--r-- | dwflpp.cxx | 64 | ||||
-rw-r--r-- | dwflpp.h | 4 | ||||
-rw-r--r-- | tapsets.cxx | 49 | ||||
-rw-r--r-- | tapsets.h | 1 | ||||
-rw-r--r-- | translate.cxx | 59 |
5 files changed, 121 insertions, 56 deletions
@@ -63,16 +63,16 @@ using namespace __gnu_cxx; static string TOK_KERNEL("kernel"); -dwflpp::dwflpp(systemtap_session & session, const string& user_module): +dwflpp::dwflpp(systemtap_session & session, const string& name, bool kernel_p): sess(session), module(NULL), module_bias(0), mod_info(NULL), module_start(0), module_end(0), cu(NULL), dwfl(NULL), module_dwarf(NULL), function(NULL), blacklist_enabled(false), pc_cached_scopes(0), num_cached_scopes(0), cached_scopes(NULL) { - if (user_module.empty()) - setup_kernel(); + if (kernel_p) + setup_kernel(name); else - setup_user(user_module); + setup_user(name); } @@ -250,8 +250,32 @@ dwflpp::function_name_final_match(const string& pattern) } +static const char *offline_search_modname = NULL; +static int offline_search_match_p = 0; + +static int dwfl_report_offline_predicate (const char* modname, const char* filename) +{ + if (pending_interrupts) + return -1; + + if (offline_search_match_p) + return -1; + + assert (offline_search_modname); + + /* Reject mismatching module names */ + if (strcmp(modname, offline_search_modname)) + return 0; + else + { + offline_search_match_p ++; + return 1; + } +} + + void -dwflpp::setup_kernel(bool debuginfo_needed) +dwflpp::setup_kernel(const string& name, bool debuginfo_needed) { // XXX: See also translate.cxx:emit_symbol_data @@ -289,21 +313,31 @@ dwflpp::setup_kernel(bool debuginfo_needed) else elfutils_kernel_path = sess.kernel_build_tree; + offline_search_modname = name.c_str(); + offline_search_match_p = 0; int rc = dwfl_linux_kernel_report_offline (dwfl, elfutils_kernel_path.c_str(), &dwfl_report_offline_predicate); + offline_search_modname = NULL; + + (void) rc; /* Ignore since the predicate probably returned -1 at some point, + And libdwfl interprets that as "whole query failed" rather than + "found it already, stop looking". */ - if (debuginfo_needed) { - if (rc) { - // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); - find_debug_rpms(sess, dir.c_str()); + /* But we still need to check whether the module was itself found. One could + do an iterate_modules() search over the resulting dwfl and count hits. Or + one could rely on the match_p flag being set just before. */ + if (! offline_search_match_p) + { + if (debuginfo_needed) { + // Suggest a likely kernel dir to find debuginfo rpm for + string dir = string("/lib/modules/" + sess.kernel_release ); + find_debug_rpms(sess, dir.c_str()); + } + throw semantic_error (string("missing ") + sess.architecture + + string(" kernel/module debuginfo under '") + + sess.kernel_build_tree + string("'")); } - dwfl_assert (string("missing ") + sess.architecture + - string(" kernel/module debuginfo under '") + - sess.kernel_build_tree + string("'"), - rc); - } // XXX: it would be nice if we could do a single // ..._report_offline call for an entire systemtap script, so @@ -166,7 +166,7 @@ struct dwflpp std::string cu_name; std::string function_name; - dwflpp(systemtap_session & session, const std::string& user_module=""); + dwflpp(systemtap_session & session, const std::string& user_module, bool kernel_p); ~dwflpp(); void get_module_dwarf(bool required = false, bool report = true); @@ -280,7 +280,7 @@ private: Dwarf * module_dwarf; Dwarf_Die * function; - void setup_kernel(bool debuginfo_needed = true); + void setup_kernel(const std::string& module_name, bool debuginfo_needed = true); void setup_user(const std::string& module_name, bool debuginfo_needed = true); typedef std::map<Dwarf*, std::vector<Dwarf_Die>*> module_cu_cache_t; diff --git a/tapsets.cxx b/tapsets.cxx index 4f172506..4988b7e7 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -312,15 +312,6 @@ static bool null_die(Dwarf_Die *die) } -// PR 9941 introduces the need for a predicate - -int dwfl_report_offline_predicate (const char* modname, const char* filename) -{ - if (pending_interrupts) { return -1; } - return 1; -} - - enum function_spec_type { @@ -598,34 +589,36 @@ struct dwarf_query : public base_query struct dwarf_builder: public derived_probe_builder { - dwflpp *kern_dw; + map <string,dwflpp*> kern_dw; map <string,dwflpp*> user_dw; - dwarf_builder(): kern_dw(0) {} + dwarf_builder() {} - dwflpp *get_kern_dw(systemtap_session& sess) + dwflpp *get_kern_dw(systemtap_session& sess, const string& module) { - if (!kern_dw) - kern_dw = new dwflpp(sess); - return kern_dw; + if (kern_dw.find(module) == kern_dw.end()) + kern_dw[module] = new dwflpp(sess, module, true); + return kern_dw[module]; } dwflpp *get_user_dw(systemtap_session& sess, const string& module) { if (user_dw.find(module) == user_dw.end()) - user_dw[module] = new dwflpp(sess, module); + user_dw[module] = new dwflpp(sess, module, false); return user_dw[module]; } /* NB: not virtual, so can be called from dtor too: */ void dwarf_build_no_more (bool verbose) { - if (kern_dw) + for (map<string,dwflpp*>::iterator udi = kern_dw.begin(); + udi != kern_dw.end(); + udi ++) { if (verbose) - clog << "dwarf_builder releasing kernel dwflpp" << endl; - delete kern_dw; - kern_dw = 0; + clog << "dwarf_builder releasing kernel dwflpp " << udi->first << endl; + delete udi->second; } + kern_dw.erase (kern_dw.begin(), kern_dw.end()); for (map<string,dwflpp*>::iterator udi = user_dw.begin(); udi != user_dw.end(); @@ -2715,7 +2708,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) if (module.find('/') == string::npos) { // kernel or kernel module target - dw = db.get_kern_dw(s); + dw = db.get_kern_dw(s, module); } else { @@ -3445,11 +3438,13 @@ dwarf_builder::build(systemtap_session & sess, dwflpp* dw = 0; string module_name; - if (has_null_param (parameters, TOK_KERNEL) - || get_param (parameters, TOK_MODULE, module_name)) + if (has_null_param (parameters, TOK_KERNEL)) + { + dw = get_kern_dw(sess, "kernel"); + } + else if (get_param (parameters, TOK_MODULE, module_name)) { - // kernel or kernel module target - dw = get_kern_dw(sess); + dw = get_kern_dw(sess, module_name); } else if (get_param (parameters, TOK_PROCESS, module_name)) { @@ -5703,7 +5698,7 @@ tracepoint_builder::init_dw(systemtap_session& s) if (s.verbose > 2) clog << "Pass 2: using cached " << s.tracequery_path << endl; - dw = new dwflpp(s, s.tracequery_path); + dw = new dwflpp(s, s.tracequery_path, false); close(fd); return true; } @@ -5728,7 +5723,7 @@ tracepoint_builder::init_dw(systemtap_session& s) << s.tracequery_path << "\"): " << strerror(errno) << endl; } - dw = new dwflpp(s, tracequery_ko); + dw = new dwflpp(s, tracequery_ko, false); return true; } @@ -15,7 +15,6 @@ void register_standard_tapsets(systemtap_session& sess); std::vector<derived_probe_group*> all_session_groups(systemtap_session& s); -int dwfl_report_offline_predicate (const char* modname, const char* filename); void common_probe_entryfn_prologue (translator_output* o, std::string statestr, std::string new_pp, bool overload_processing = true); void common_probe_entryfn_epilogue (translator_output* o, bool overload_processing = true); diff --git a/translate.cxx b/translate.cxx index 378395b8..9c901065 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4907,6 +4907,27 @@ dump_unwindsyms (Dwfl_Module *m, // them with the runtime. void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&); + +static set<string> offline_search_modules; +static int dwfl_report_offline_predicate2 (const char* modname, const char* filename) +{ + if (pending_interrupts) + return -1; + + if (offline_search_modules.empty()) + return -1; + + /* Reject mismatching module names */ + if (offline_search_modules.find(modname) == offline_search_modules.end()) + return 0; + else + { + offline_search_modules.erase(modname); + return 1; + } +} + + void emit_symbol_data (systemtap_session& s) { @@ -4959,22 +4980,38 @@ emit_symbol_data (systemtap_session& s) else elfutils_kernel_path = s.kernel_build_tree; + + // Set up our offline search for kernel modules. As in dwflpp.cxx, + // we don't want the offline search iteration to do a complete search + // of the kernel build tree, since that's wasteful. + offline_search_modules.erase (offline_search_modules.begin(), + offline_search_modules.end()); + for (set<string>::iterator it = s.unwindsym_modules.begin(); + it != s.unwindsym_modules.end(); + it++) + { + string foo = *it; + if (foo[0] != '/') /* Omit user-space, since we're only using this for + kernel space offline searches. */ + offline_search_modules.insert (foo); + } + int rc = dwfl_linux_kernel_report_offline (dwfl, elfutils_kernel_path.c_str(), - &dwfl_report_offline_predicate); + & dwfl_report_offline_predicate2); + + (void) rc; // As in dwflpp.cxx, we ignore rc here. + dwfl_report_end (dwfl, NULL, NULL); - if (rc == 0) // tolerate missing data; will warn user about it anyway + ptrdiff_t off = 0; + do { - ptrdiff_t off = 0; - do - { - if (pending_interrupts) return; - if (ctx.undone_unwindsym_modules.empty()) break; - off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0); - } - while (off > 0); - dwfl_assert("dwfl_getmodules", off == 0); + if (pending_interrupts) return; + if (ctx.undone_unwindsym_modules.empty()) break; + off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0); } + while (off > 0); + dwfl_assert("dwfl_getmodules", off == 0); dwfl_end(dwfl); |