From 3db9c8433e58812c9ce47df384e23841aca27894 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 28 Sep 2009 15:36:33 +0200 Subject: Factor out duplicated code to setup kernel/module Dwfl from dwflpp/translate. * setupdwfl.h: New header file. * setupdwfl.cxx: New source file containing shared setup_dwfl_kernel() code. * dwflpp.cxx (dwfl_report_offline_predicate): Removed. (setup_kernel): Call setup_dwfl_kernel(). * translate.cxx (dwfl_report_offline_predicate2): Remove. (emit_symbol_data): Call setup_dwfl_kernel(). * Makefile.am (stap_SOURCES): Add setupdwfl.cxx. * Makefile.in: Regenerated. --- Makefile.am | 3 +- Makefile.in | 21 +++++++- dwflpp.cxx | 97 ++-------------------------------- setupdwfl.cxx | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ setupdwfl.h | 28 ++++++++++ translate.cxx | 78 +++++---------------------- 6 files changed, 232 insertions(+), 162 deletions(-) create mode 100644 setupdwfl.cxx create mode 100644 setupdwfl.h diff --git a/Makefile.am b/Makefile.am index a838e01a..aa45bf0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,7 +45,8 @@ stap_SOURCES = main.cxx \ cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \ tapset-perfmon.cxx tapset-mark.cxx tapset-itrace.cxx \ - tapset-utrace.cxx task_finder.cxx dwflpp.cxx rpm_finder.cxx + tapset-utrace.cxx task_finder.cxx dwflpp.cxx rpm_finder.cxx \ + setupdwfl.cxx stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ @rpm_LIBS@ stap_DEPENDENCIES = endif diff --git a/Makefile.in b/Makefile.in index 17188edb..09b4700d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -143,7 +143,8 @@ loc2c_test_LINK = $(CCLD) $(loc2c_test_CFLAGS) $(CFLAGS) \ @BUILD_TRANSLATOR_TRUE@ stap-tapset-utrace.$(OBJEXT) \ @BUILD_TRANSLATOR_TRUE@ stap-task_finder.$(OBJEXT) \ @BUILD_TRANSLATOR_TRUE@ stap-dwflpp.$(OBJEXT) \ -@BUILD_TRANSLATOR_TRUE@ stap-rpm_finder.$(OBJEXT) +@BUILD_TRANSLATOR_TRUE@ stap-rpm_finder.$(OBJEXT) \ +@BUILD_TRANSLATOR_TRUE@ stap-setupdwfl.$(OBJEXT) stap_OBJECTS = $(am_stap_OBJECTS) stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \ $(LDFLAGS) -o $@ @@ -379,7 +380,8 @@ oldinclude_HEADERS = includes/sys/sdt.h @BUILD_TRANSLATOR_TRUE@ cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \ @BUILD_TRANSLATOR_TRUE@ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \ @BUILD_TRANSLATOR_TRUE@ tapset-perfmon.cxx tapset-mark.cxx tapset-itrace.cxx \ -@BUILD_TRANSLATOR_TRUE@ tapset-utrace.cxx task_finder.cxx dwflpp.cxx rpm_finder.cxx +@BUILD_TRANSLATOR_TRUE@ tapset-utrace.cxx task_finder.cxx dwflpp.cxx rpm_finder.cxx \ +@BUILD_TRANSLATOR_TRUE@ setupdwfl.cxx @BUILD_TRANSLATOR_TRUE@stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ @rpm_LIBS@ @BUILD_TRANSLATOR_TRUE@stap_DEPENDENCIES = $(am__append_11) @@ -708,6 +710,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-mdfour.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-parse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-rpm_finder.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-setupdwfl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-staptree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-been.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-itrace.Po@am__quote@ @@ -1339,6 +1342,20 @@ stap-rpm_finder.obj: rpm_finder.cxx @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-rpm_finder.obj `if test -f 'rpm_finder.cxx'; then $(CYGPATH_W) 'rpm_finder.cxx'; else $(CYGPATH_W) '$(srcdir)/rpm_finder.cxx'; fi` +stap-setupdwfl.o: setupdwfl.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-setupdwfl.o -MD -MP -MF $(DEPDIR)/stap-setupdwfl.Tpo -c -o stap-setupdwfl.o `test -f 'setupdwfl.cxx' || echo '$(srcdir)/'`setupdwfl.cxx +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stap-setupdwfl.Tpo $(DEPDIR)/stap-setupdwfl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='setupdwfl.cxx' object='stap-setupdwfl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-setupdwfl.o `test -f 'setupdwfl.cxx' || echo '$(srcdir)/'`setupdwfl.cxx + +stap-setupdwfl.obj: setupdwfl.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-setupdwfl.obj -MD -MP -MF $(DEPDIR)/stap-setupdwfl.Tpo -c -o stap-setupdwfl.obj `if test -f 'setupdwfl.cxx'; then $(CYGPATH_W) 'setupdwfl.cxx'; else $(CYGPATH_W) '$(srcdir)/setupdwfl.cxx'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stap-setupdwfl.Tpo $(DEPDIR)/stap-setupdwfl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='setupdwfl.cxx' object='stap-setupdwfl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-setupdwfl.obj `if test -f 'setupdwfl.cxx'; then $(CYGPATH_W) 'setupdwfl.cxx'; else $(CYGPATH_W) '$(srcdir)/setupdwfl.cxx'; fi` + stap_sign_module-modsign.o: modsign.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_sign_module_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stap_sign_module-modsign.o -MD -MP -MF $(DEPDIR)/stap_sign_module-modsign.Tpo -c -o stap_sign_module-modsign.o `test -f 'modsign.cxx' || echo '$(srcdir)/'`modsign.cxx @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stap_sign_module-modsign.Tpo $(DEPDIR)/stap_sign_module-modsign.Po diff --git a/dwflpp.cxx b/dwflpp.cxx index 636cd38d..4ef9f76b 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -22,6 +22,7 @@ #include "auto_free.h" #include "hash.h" #include "rpm_finder.h" +#include "setupdwfl.h" #include #include @@ -293,99 +294,16 @@ dwflpp::function_scope_matches(const vector scopes) } -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; - - assert (offline_search_modname); - - // elfutils sends us NULL filenames sometimes if it can't find dwarf - if (filename == NULL) - return 0; - - if (dwflpp::name_has_wildcard (offline_search_modname)) { - int match_p = !fnmatch(offline_search_modname, modname, 0); - // In the wildcard case, we don't short-circuit (return -1) upon - // offline_search_match_p, analogously to dwflpp::module_name_final_match(). - - if (match_p) - offline_search_match_p ++; - - return match_p; - } else { /* non-wildcard mode */ - if (offline_search_match_p) - return -1; - - /* Reject mismatching module names */ - if (strcmp(modname, offline_search_modname)) - return 0; - else - { - offline_search_match_p ++; - return 1; - } - } -} - - void dwflpp::setup_kernel(const string& name, bool debuginfo_needed) { - // XXX: See also translate.cxx:emit_symbol_data - if (! sess.module_cache) sess.module_cache = new module_cache (); - static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; - static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); - static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr ); + unsigned offline_search_matches = 0; + dwfl = setup_dwfl_kernel(name, &offline_search_matches, sess); - static const Dwfl_Callbacks kernel_callbacks = - { - dwfl_linux_kernel_find_elf, - dwfl_standard_find_debuginfo, - dwfl_offline_section_address, - (char **) & debuginfo_path - }; - - dwfl = dwfl_begin (&kernel_callbacks); - if (!dwfl) - throw semantic_error ("cannot open dwfl"); - dwfl_report_begin (dwfl); - - // We have a problem with -r REVISION vs -r BUILDDIR here. If - // we're running against a fedora/rhel style kernel-debuginfo - // tree, s.kernel_build_tree is not the place where the unstripped - // vmlinux will be installed. Rather, it's over yonder at - // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is - // no way to set the dwfl_callback.debuginfo_path and always - // passs the plain kernel_release here. So instead we have to - // hard-code this magic here. - string elfutils_kernel_path; - if (sess.kernel_build_tree == string("/lib/modules/" + sess.kernel_release + "/build")) - elfutils_kernel_path = sess.kernel_release; - 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". */ - - /* 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 (offline_search_matches < 1) { if (debuginfo_needed) { // Suggest a likely kernel dir to find debuginfo rpm for @@ -397,13 +315,6 @@ dwflpp::setup_kernel(const string& name, bool debuginfo_needed) sess.kernel_build_tree + string("'")); } - // NB: the result of an _offline call is the assignment of - // virtualized addresses to relocatable objects such as - // modules. These have to be converted to real addresses at - // run time. See the dwarf_derived_probe ctor and its caller. - - dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); - build_blacklist(); } diff --git a/setupdwfl.cxx b/setupdwfl.cxx new file mode 100644 index 00000000..1cec0828 --- /dev/null +++ b/setupdwfl.cxx @@ -0,0 +1,167 @@ +// Setup routines for creating fully populated DWFLs. Used in pass 2 and 3. +// Copyright (C) 2009 Red Hat, Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + +#include "config.h" +#include "setupdwfl.h" + +#include "dwarf_wrappers.h" +#include "dwflpp.h" +#include "session.h" + +#include +#include + +extern "C" { +#include +#include +} + +static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; +static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); +static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); + +static const Dwfl_Callbacks kernel_callbacks = + { + dwfl_linux_kernel_find_elf, + dwfl_standard_find_debuginfo, + dwfl_offline_section_address, + (char **) & debuginfo_path + }; + +using namespace std; + +// Setup in setup_dwfl_kernel(), for use in setup_dwfl_report_kernel_p(). +// Either offline_search_modname or offline_search_names is +// used. When offline_search_modname is not NULL then +// offline_search_names is ignored. +static const char *offline_search_modname; +static set offline_search_names; +static unsigned *offline_modules_found; + +// Set up our offline search for kernel modules. We don't want the +// offline search iteration to do a complete search of the kernel +// build tree, since that's wasteful, so create a predicate that +// filters and stops reporting as soon as we got everything. +static int +setup_dwfl_report_kernel_p(const char* modname, const char* filename) +{ + if (pending_interrupts) + return -1; + + // elfutils sends us NULL filenames sometimes if it can't find dwarf + if (filename == NULL) + return 0; + + // If offline_search_modname is setup use it (either as regexp or + // explicit module/kernel name) and ignore offline_search_names. + // Otherwise use offline_search_names exclusively. + if (offline_search_modname != NULL) + { + if (dwflpp::name_has_wildcard (offline_search_modname)) + { + int match_p = !fnmatch(offline_search_modname, modname, 0); + // In the wildcard case, we don't short-circuit (return -1) + // analogously to dwflpp::module_name_final_match(). + if (match_p) + (*offline_modules_found)++; + return match_p; + } + else + { /* non-wildcard mode */ + if (*offline_modules_found) + return -1; // Done, only one name needed and found it. + + /* Reject mismatching module names */ + if (strcmp(modname, offline_search_modname)) + return 0; + else + { + (*offline_modules_found)++; + return 1; + } + } + } + else + { /* find all in set mode */ + if (offline_search_names.empty()) + return -1; + + /* Reject mismatching module names */ + if (offline_search_names.find(modname) == offline_search_names.end()) + return 0; + else + { + offline_search_names.erase(modname); + (*offline_modules_found)++; + return 1; + } + } +} + +static Dwfl * +setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) +{ + Dwfl *dwfl = dwfl_begin (&kernel_callbacks); + dwfl_assert ("dwfl_begin", dwfl); + dwfl_report_begin (dwfl); + + // We have a problem with -r REVISION vs -r BUILDDIR here. If + // we're running against a fedora/rhel style kernel-debuginfo + // tree, s.kernel_build_tree is not the place where the unstripped + // vmlinux will be installed. Rather, it's over yonder at + // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is + // no way to set the dwfl_callback.debuginfo_path and always + // passs the plain kernel_release here. So instead we have to + // hard-code this magic here. + string elfutils_kernel_path; + if (s.kernel_build_tree == string("/lib/modules/" + + s.kernel_release + + "/build")) + elfutils_kernel_path = s.kernel_release; + else + elfutils_kernel_path = s.kernel_build_tree; + + offline_modules_found = modules_found; + *offline_modules_found = 0; + + int rc = dwfl_linux_kernel_report_offline (dwfl, + elfutils_kernel_path.c_str(), + &setup_dwfl_report_kernel_p); + + (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". */ + + // NB: the result of an _offline call is the assignment of + // virtualized addresses to relocatable objects such as + // modules. These have to be converted to real addresses at + // run time. See the dwarf_derived_probe ctor and its caller. + + dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); + return dwfl; +} + +Dwfl* +setup_dwfl_kernel(const std::string &name, + unsigned *found, + systemtap_session &s) +{ + offline_search_modname = name.c_str(); + offline_search_names.clear(); + return setup_dwfl_kernel(found, s); +} + +Dwfl* +setup_dwfl_kernel(const std::set &names, + unsigned *found, + systemtap_session &s) +{ + offline_search_modname = NULL; + offline_search_names = names; + return setup_dwfl_kernel(found, s); +} diff --git a/setupdwfl.h b/setupdwfl.h new file mode 100644 index 00000000..7884e4da --- /dev/null +++ b/setupdwfl.h @@ -0,0 +1,28 @@ +// Setup routines for creating fully populated DWFLs. Used in pass 2 and 3. +// Copyright (C) 2009 Red Hat, Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. +// +#ifndef SETUP_DWFLPP_H +#define SETUP_DWFLPP_H + +#include "config.h" +#include "session.h" + +#include +#include + +extern "C" { +#include +} + +Dwfl *setup_dwfl_kernel(const std::string &name, + unsigned *found, + systemtap_session &s); +Dwfl *setup_dwfl_kernel(const std::set &names, + unsigned *found, + systemtap_session &s); +#endif diff --git a/translate.cxx b/translate.cxx index 04a92476..1bb6252f 100644 --- a/translate.cxx +++ b/translate.cxx @@ -15,6 +15,7 @@ #include "tapsets.h" #include "util.h" #include "dwarf_wrappers.h" +#include "setupdwfl.h" #include #include @@ -4929,27 +4930,6 @@ dump_unwindsyms (Dwfl_Module *m, // them with the runtime. void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&); - -static set 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) { @@ -4969,45 +4949,9 @@ emit_symbol_data (systemtap_session& s) return; } - // XXX: copied from tapsets.cxx dwflpp::, sadly - static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; - static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); - static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); - // ---- step 1: process any kernel modules listed - static const Dwfl_Callbacks kernel_callbacks = - { - dwfl_linux_kernel_find_elf, - dwfl_standard_find_debuginfo, - dwfl_offline_section_address, - (char **) & debuginfo_path - }; - - Dwfl *dwfl = dwfl_begin (&kernel_callbacks); - if (!dwfl) - throw semantic_error ("cannot open dwfl"); - dwfl_report_begin (dwfl); - - // We have a problem with -r REVISION vs -r BUILDDIR here. If - // we're running against a fedora/rhel style kernel-debuginfo - // tree, s.kernel_build_tree is not the place where the unstripped - // vmlinux will be installed. Rather, it's over yonder at - // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is - // no way to set the dwfl_callback.debuginfo_path and always - // passs the plain kernel_release here. So instead we have to - // hard-code this magic here. - string elfutils_kernel_path; - if (s.kernel_build_tree == string("/lib/modules/" + s.kernel_release + "/build")) - elfutils_kernel_path = s.kernel_release; - 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()); + set offline_search_modules; + unsigned count; for (set::iterator it = s.unwindsym_modules.begin(); it != s.unwindsym_modules.end(); it++) @@ -5017,14 +4961,10 @@ emit_symbol_data (systemtap_session& s) kernel space offline searches. */ offline_search_modules.insert (foo); } + Dwfl *dwfl = setup_dwfl_kernel (offline_search_modules, &count, s); + dwfl_assert("all kernel modules found", + count >= offline_search_modules.size()); - int rc = dwfl_linux_kernel_report_offline (dwfl, - elfutils_kernel_path.c_str(), - & dwfl_report_offline_predicate2); - - (void) rc; // As in dwflpp.cxx, we ignore rc here. - - dwfl_report_end (dwfl, NULL, NULL); ptrdiff_t off = 0; do { @@ -5039,6 +4979,12 @@ emit_symbol_data (systemtap_session& s) // ---- step 2: process any user modules (files) listed // XXX: see dwflpp::setup_user. + + // XXX: copied from tapsets.cxx dwflpp::, sadly + static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; + static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); + static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); + static const Dwfl_Callbacks user_callbacks = { NULL, /* dwfl_linux_kernel_find_elf, */ -- cgit