diff options
author | Mark Wielaard <mjw@redhat.com> | 2009-10-02 00:28:46 +0200 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2009-10-02 00:37:13 +0200 |
commit | ae06d951b9775c39b92913417c902eae0775e4b6 (patch) | |
tree | e94fa50a0f8d3f8600f7612779367545508383e2 /setupdwfl.cxx | |
parent | df61ffd1451723231b70401dbf7d895baa2f1081 (diff) | |
download | systemtap-steved-ae06d951b9775c39b92913417c902eae0775e4b6.tar.gz systemtap-steved-ae06d951b9775c39b92913417c902eae0775e4b6.tar.xz systemtap-steved-ae06d951b9775c39b92913417c902eae0775e4b6.zip |
PR10678 vta-gcc: module debuginfo: relocation refers to undefined symbol
libdwfl tries to resolve all relocations in a module debuginfo file and
if it cannot find a symbol used in a relocation it will fail when
dwfl_module_getdwarf() is called. So we must make sure all possible
dependencies of the module are also in the dwfl. We do this by trying
to find and parse the modules.dep file and insert all dependencies
into the dwfl.
* setupdwfl.cxx (elfutils_kernel_path): Lift from setup_dwfl_kernel and
make static.
(is_comma_dash): New function.
(modname_from_path): Likewise.
(setup_mod_deps): Likewise.
(setup_dwfl_report_kernel_p): Call setup_mod_deps().
* testsuite/buildok/pr10678.stp: New test.
Diffstat (limited to 'setupdwfl.cxx')
-rw-r--r-- | setupdwfl.cxx | 108 |
1 files changed, 107 insertions, 1 deletions
diff --git a/setupdwfl.cxx b/setupdwfl.cxx index 554f4e54..32274615 100644 --- a/setupdwfl.cxx +++ b/setupdwfl.cxx @@ -13,6 +13,10 @@ #include "dwflpp.h" #include "session.h" +#include <algorithm> +#include <iostream> +#include <fstream> +#include <sstream> #include <set> #include <string> @@ -77,6 +81,107 @@ static set<string> user_modset; // symbols in vmlinux and/or other modules they depend on. See PR10678. static const bool setup_all_deps = true; +// Where to find the kernel (and the Modules.dep file). Setup in +// setup_dwfl_kernel(), used by dwfl_linux_kernel_report_offline() and +// setup_mod_deps(). +static string elfutils_kernel_path; + +static bool is_comma_dash(const char c) { return (c == ',' || c == '-'); } + +// The module name is the basename (without the extension) of the +// module path, with ',' and '-' replaced by '_'. +static string +modname_from_path(const string &path) +{ + size_t dot = path.rfind('.'); + size_t slash = path.rfind('/'); + if (dot == string::npos || slash == string::npos || dot < slash) + return ""; + string name = path.substr(slash + 1, dot - slash - 1); + replace_if(name.begin(), name.end(), is_comma_dash, '_'); + return name; +} + +// Try to parse modules.dep file, +// Simple format: module path (either full or relative), colon, +// (possibly empty) space delimited list of module (path) +// dependencies. +static void +setup_mod_deps() +{ + string modulesdep; + ifstream in; + string l; + + if (elfutils_kernel_path[0] == '/') + { + modulesdep = elfutils_kernel_path; + modulesdep += "/modules.dep"; + } + else + { + modulesdep = "/lib/modules/"; + modulesdep += elfutils_kernel_path; + modulesdep += "/modules.dep"; + } + in.open(modulesdep.c_str()); + if (in.fail ()) + return; + + while (getline (in, l)) + { + size_t off = l.find (':'); + if (off != string::npos) + { + string modpath, modname; + modpath = l.substr (0, off); + modname = modname_from_path (modpath); + if (modname == "") + continue; + + bool dep_needed; + if (offline_search_modname != NULL) + { + if (dwflpp::name_has_wildcard (offline_search_modname)) + { + dep_needed = !fnmatch (offline_search_modname, + modname.c_str (), 0); + if (dep_needed) + offline_search_names.insert (modname); + } + else + { + dep_needed = ! strcmp(modname.c_str (), + offline_search_modname); + if (dep_needed) + offline_search_names.insert (modname); + } + } + else + dep_needed = (offline_search_names.find (modname) + != offline_search_names.end ()); + + if (! dep_needed) + continue; + + string depstring = l.substr (off + 1); + if (depstring.size () > 0) + { + stringstream ss (depstring); + string deppath; + while (ss >> deppath) + offline_search_names.insert (modname_from_path(deppath)); + + } + } + } + + // We always want kernel (needed in list so size checks match). + // Everything needed now stored in offline_search_names. + offline_search_names.insert ("kernel"); + offline_search_modname = NULL; +} + // 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 @@ -101,6 +206,8 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename) || (offline_search_names.size() == 1 && *offline_search_names.begin() == "kernel")) setup_dwfl_done = true; + else + setup_mod_deps(); offline_modules_found++; return 1; @@ -162,7 +269,6 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s) // 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")) |