From 4766b1e6c87368fc33c63163217d15b2a86ac94f Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Wed, 9 Jul 2014 10:44:43 -0400 Subject: [PATCH] PR17073: module probes: support out-of-tree modules This patch adds support for out-of-tree modules by specifying the fullpath. This did not work before because both the _stp_module struct and the stap_dwarf_probe struct were using the full path as the module name. This caused issues during relocation of module sections/kprobe addresses. In this patch, we use the already existing modname_from_path() function to modify the module member of the dwarf_derived_probe (which later affects the stap_dwarf_probe struct) and to emit the proper name in dump_unwindsym_cxt() for the _stp_module struct. --- setupdwfl.cxx | 10 +++++++--- setupdwfl.h | 2 ++ tapsets.cxx | 9 ++++++++- translate.cxx | 13 +++++++++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/setupdwfl.cxx b/setupdwfl.cxx index c92d31c42..fe44828f8 100644 --- a/setupdwfl.cxx +++ b/setupdwfl.cxx @@ -105,9 +105,13 @@ static const string abrt_path = ? "/usr/libexec/abrt-action-install-debuginfo-to-abrt-cache" : "")); -// The module name is the basename (without the extension) of the -// module path, with ',' and '-' replaced by '_'. -static string +// The module name is the basename (without the extension) of the module path, +// with ',' and '-' replaced by '_'. This is a (more or less safe) heuristic: +// the actual name by which the module is known once inside the kernel is not +// derived from the path, but from the .gnu.linkonce.this_module section of the +// KO. In practice, modules in /lib/modules/ respect this convention, and we +// require it as well for out-of-tree kernel modules. +string modname_from_path(const string &path) { size_t dot = path.rfind('.'); diff --git a/setupdwfl.h b/setupdwfl.h index 2aaf5f07c..ab4418188 100644 --- a/setupdwfl.h +++ b/setupdwfl.h @@ -24,6 +24,8 @@ extern "C" { #include } +std::string modname_from_path(const std::string &path); + Dwfl *setup_dwfl_kernel(const std::string &name, unsigned *found, systemtap_session &s); diff --git a/tapsets.cxx b/tapsets.cxx index 005205447..44e44e12e 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4671,6 +4671,9 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, // module & section specify a relocation // base for , unless section=="" // (equivalently module=="kernel") + // for userspace, it's a full path, for + // modules, it's either a full path, or + // the basename (e.g. 'btrfs') const string& module, const string& section, // NB: dwfl_addr is the virtualized @@ -4695,6 +4698,10 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, saved_longs(0), saved_strings(0), entry_handler(0) { + // If we were given a fullpath to a kernel module, then get the simple name + if (q.has_module && is_fully_resolved(module, q.dw.sess.sysroot, q.dw.sess.sysenv)) + this->module = modname_from_path(module); + if (user_lib.size() != 0) has_library = true; @@ -4940,7 +4947,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, check->args[0]->tok = this->tok; check->args.push_back(new literal_number(level)); check->args[1]->tok = this->tok; - check->args.push_back(new literal_string(module)); + check->args.push_back(new literal_string(this->module)); check->args[2]->tok = this->tok; check->args.push_back(new literal_string(caller_section)); check->args[3]->tok = this->tok; diff --git a/translate.cxx b/translate.cxx index b9101a305..4410cbe8e 100644 --- a/translate.cxx +++ b/translate.cxx @@ -6289,10 +6289,19 @@ dump_unwindsym_cxt (Dwfl_Module *m, // For kernel modules just the name itself. string mainpath = resolve_path(mainfile); string mainname; - if (modname[0] == '/') // userspace + if (is_user_module(modname)) // userspace mainname = lex_cast_qstring (path_remove_sysroot(c->session,mainpath)); else - mainname = lex_cast_qstring (modname); + { // kernel module + + // If the module name is the full path to the ko, then we have to retrieve + // the actual name by which the module will be known inside the kernel. + // Otherwise, section relocations would be mismatched. + if (is_fully_resolved(modname, c->session.sysroot, c->session.sysenv)) + mainname = lex_cast_qstring (modname_from_path(modname)); + else + mainname = lex_cast_qstring (modname); + } c->output << "static struct _stp_module _stp_module_" << stpmod_idx << " = {\n"; c->output << ".name = " << mainname.c_str() << ",\n"; -- 2.43.5