summaryrefslogtreecommitdiffstats
path: root/setupdwfl.cxx
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2009-09-28 15:36:33 +0200
committerMark Wielaard <mjw@redhat.com>2009-09-28 15:36:33 +0200
commit3db9c8433e58812c9ce47df384e23841aca27894 (patch)
tree5af4c562d8bd9775075dcb6bf6ff3b4feb07f355 /setupdwfl.cxx
parentd498530cec1fcf4b71b1b27a068206fda18f3188 (diff)
downloadsystemtap-steved-3db9c8433e58812c9ce47df384e23841aca27894.tar.gz
systemtap-steved-3db9c8433e58812c9ce47df384e23841aca27894.tar.xz
systemtap-steved-3db9c8433e58812c9ce47df384e23841aca27894.zip
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.
Diffstat (limited to 'setupdwfl.cxx')
-rw-r--r--setupdwfl.cxx167
1 files changed, 167 insertions, 0 deletions
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 <set>
+#include <string>
+
+extern "C" {
+#include <fnmatch.h>
+#include <stdlib.h>
+}
+
+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<string> 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<std::string> &names,
+ unsigned *found,
+ systemtap_session &s)
+{
+ offline_search_modname = NULL;
+ offline_search_names = names;
+ return setup_dwfl_kernel(found, s);
+}