commit 0caa975190e4d2b19e7b65a0b23a7700522aa5d7
Author: Frank Ch. Eigler <fche@redhat.com>
Date: Mon Aug 31 11:17:33 2015 -0400
PR18889 part: improve module-notification related debug tracing
-DDEBUG_KPROBES -DDEBUG_SYMBOLS -DDEBUG_STP_ON_THE_FLY recommended.
diff --git a/runtime/linux/kprobes.c b/runtime/linux/kprobes.c
index 47eb29a..54c224e 100644
--- a/runtime/linux/kprobes.c
+++ b/runtime/linux/kprobes.c
@@ -567,6 +567,8 @@ stapkp_refresh(const char *modname,
{
size_t i;
+ dbug_stapkp("refresh %lu probes with module %s\n", nprobes, modname ?: "?");
+
for (i = 0; i < nprobes; i++) {
struct stap_dwarf_probe *sdp = &probes[i];
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index fe576c1..9ea2b5b 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -1,7 +1,7 @@
-/* -*- linux-c -*-
+/* -*- linux-c -*-
* symbols.c - stp symbol and module functions
*
- * Copyright (C) Red Hat Inc, 2006-2012
+ * Copyright (C) Red Hat Inc, 2006-2015
*
* 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
@@ -121,10 +121,26 @@ static unsigned _stp_module_nsections (struct module_sect_attrs *attrs)
static int _stp_module_notifier (struct notifier_block * nb,
unsigned long val, void *data)
{
+ struct module *mod = data;
+ struct module_sect_attrs *attrs;
+ unsigned i, nsections;
+
+ (void) attrs;
+ (void) i;
+ (void) nsections;
+
+ if (!mod) { // so as to avoid null pointer checks later
+ WARN_ON (!mod);
+ return NOTIFY_DONE;
+ }
+
+ dbug_sym(1, "module notify %lu %s attrs %p\n",
+ val, mod->name, mod->sect_attrs);
+
/* Prior to 2.6.11, struct module contained a module_sections
attribute vector rather than module_sect_attrs. Prior to
2.6.19, module_sect_attrs lacked a number-of-sections
- field. Past 3.8, MODULE_STATE_COMING is sent too early to
+ field. Past 3.8, MODULE_STATE_COMING is sent too early to
let us probe module init functions.
Without CONFIG_KALLSYMS, we don't get any of the
@@ -132,11 +148,6 @@ static int _stp_module_notifier (struct notifier_block * nb,
that directly? */
#if defined(CONFIG_KALLSYMS) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
- struct module *mod = data;
- struct module_sect_attrs *attrs;
- unsigned i, nsections;
- WARN_ON (!mod);
-
if (val == MODULE_STATE_COMING ||
val == MODULE_STATE_LIVE) {
/* A module is arriving or has arrived. Register all
@@ -145,6 +156,7 @@ static int _stp_module_notifier (struct notifier_block * nb,
did the fishie go? */
attrs = mod->sect_attrs;
+ dbug_sym(1, "module_sect_attrs: %p\n", attrs);
if (attrs == NULL) // until add_sect_attrs(), may be zero
return NOTIFY_DONE; // remain ignorant
@@ -153,7 +165,7 @@ static int _stp_module_notifier (struct notifier_block * nb,
int init_p = (strstr(attrs->attrs[i].name, "init.") != NULL);
int init_gone_p = (val == MODULE_STATE_LIVE); // likely already unloaded
- _stp_kmodule_update_address(mod->name,
+ _stp_kmodule_update_address(mod->name,
attrs->attrs[i].name,
((init_p && init_gone_p) ? 0 : attrs->attrs[i].address));
}
@@ -161,7 +173,7 @@ static int _stp_module_notifier (struct notifier_block * nb,
/* Verify build-id. */
if (_stp_kmodule_check (mod->name))
_stp_kmodule_update_address(mod->name, NULL, 0); /* Pretend it was never here. */
- }
+ }
else if (val == MODULE_STATE_GOING) {
/* Unregister all sections. */
_stp_kmodule_update_address(mod->name, NULL, 0);
commit 2278079efc01124dd509241f6c6eadbd6e19cb2a
Author: Frank Ch. Eigler <fche@redhat.com>
Date: Mon Aug 31 17:46:43 2015 -0400
PR18889 part: module-init notification via module_{load,free} tracepoints
Investigating RHBZ1257399 et al., we found that module_notifier is
being called too early after kernel commit #4982223e51. This
precludes normal module section-address computation and thus kprobe
emplacement. This patch adds hooking into the module_{load,free}
tracepoints in parallel, because on some kernels (RHEL7.1.Z+) they
occur at just the right time.
On the downside, on recent LKML kernels, attaching to those
tracepoints requires EXPORT_TRACEPOINT_SYMBOL_GPL's, so until that is
done (or another workaround made), LKML kernels will still miss out on
module-init probing.
diff --git a/buildrun.cxx b/buildrun.cxx
index d7a431d..6d66b5a 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -1,5 +1,5 @@
// build/run probes
-// Copyright (C) 2005-2014 Red Hat Inc.
+// Copyright (C) 2005-2015 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
@@ -377,8 +377,10 @@ compile_pass (systemtap_session& s)
output_exportconf(s, o, "proc_create_data", "STAPCONF_PROC_CREATE_DATA");
output_exportconf(s, o, "PDE_DATA", "STAPCONF_PDE_DATA");
output_autoconf(s, o, "autoconf-module-sect-attrs.c", "STAPCONF_MODULE_SECT_ATTRS", NULL);
-
output_autoconf(s, o, "autoconf-utrace-via-tracepoints.c", "STAPCONF_UTRACE_VIA_TRACEPOINTS", NULL);
+ output_autoconf(s, o, "autoconf-module-tracepoints.c", "STAPCONF_MODULE_TRACEPOINT", NULL);
+ output_exportconf(s, o, "__tracepoint_module_load", "STAPCONF_MODULE_TRACEPOINT_EXPORT_LOAD");
+ output_exportconf(s, o, "__tracepoint_module_free", "STAPCONF_MODULE_TRACEPOINT_EXPORT_FREE");
output_autoconf(s, o, "autoconf-task_work-struct.c", "STAPCONF_TASK_WORK_STRUCT", NULL);
output_autoconf(s, o, "autoconf-vm-area-pte.c", "STAPCONF_VM_AREA_PTE", NULL);
output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL);
diff --git a/runtime/linux/autoconf-module-tracepoints.c b/runtime/linux/autoconf-module-tracepoints.c
new file mode 100644
index 0000000..77b938e
--- /dev/null
+++ b/runtime/linux/autoconf-module-tracepoints.c
@@ -0,0 +1,31 @@
+#include <linux/module.h>
+#include <trace/events/module.h>
+
+// NB: in kernels which do have the requisite pieces, just unconfigured, then
+// everything below will compile just fine, only returning ENOSYS at runtime.
+// To get the compile-time error that autoconf needs, check it directly:
+#ifndef CONFIG_TRACEPOINTS
+#error "CONFIG_TRACEPOINTS is not enabled"
+#endif
+
+// presuming void *data-parametrized tracepoint callback api
+
+void __module_load(void *cb_data, struct module* mod)
+{
+ (void) cb_data;
+ (void) mod;
+ return;
+}
+
+void __module_free(void *cb_data, struct module* mod)
+{
+ (void) cb_data;
+ (void) mod;
+ return;
+}
+
+void __autoconf_func(void)
+{
+ (void) register_trace_module_load(__module_load, NULL);
+ (void) register_trace_module_free(__module_free, NULL);
+}
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index 9ea2b5b..4266e5d 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -125,6 +125,7 @@ static int _stp_module_notifier (struct notifier_block * nb,
struct module_sect_attrs *attrs;
unsigned i, nsections;
+ (void) nb;
(void) attrs;
(void) i;
(void) nsections;
@@ -191,6 +192,21 @@ static int _stp_module_notifier (struct notifier_block * nb,
return NOTIFY_DONE;
}
+
+#ifdef STAPCONF_MODULE_TRACEPOINT
+/* We just delegate to the canonical notifier function */
+static void _stp_module_load_tp(void *data, struct module* mod)
+{
+ (void) _stp_module_notifier (NULL, MODULE_STATE_COMING, mod);
+
+}
+static void _stp_module_free_tp(void *data, struct module* mod)
+{
+ (void) _stp_module_notifier (NULL, MODULE_STATE_GOING, mod);
+}
+#endif
+
+
static int _stp_module_update_self (void)
{
/* Only bother if we need unwinding and have module_sect_attrs. */
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index 54e9b41..e069a3d 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -21,6 +21,23 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include "../uidgid_compatibility.h"
+#ifdef STAPCONF_MODULE_TRACEPOINT
+#include <trace/events/module.h>
+#endif
+
+/* PR18889: After 3.17, commit #de7b2973903c6, tracepoints are
+ attached by symbol-address rather than by name string. That means
+ they must be EXPORT_TRACEPOINT_SYMBOL_GPL'd for a tracepoint
+ [un]register operation. On RHEL7 kernels with out that commit
+ backported, we can do a tracepoint attach even without the exports. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+#if defined(STAPCONF_MODULE_TRACEPOINT) && defined(STAPCONF_MODULE_TRACEPOINT_EXPORT_LOAD) && defined(STAPCONF_MODULE_TRACEPOINT_EXPORT_FREE)
+#define STAP_USE_MODULE_TRACEPOINTS
+#endif
+#elif defined(STAPCONF_MODULE_TRACEPOINT)
+#define STAP_USE_MODULE_TRACEPOINTS
+#endif
+
static int _stp_exit_flag = 0;
@@ -83,6 +100,11 @@ static void systemtap_module_exit(void);
static int systemtap_module_init(void);
static int _stp_module_notifier_active = 0;
+#ifdef STAPCONF_MODULE_TRACEPOINT
+/* callbacks in runtime/transport/symbols.c */
+static void _stp_module_load_tp(void *data, struct module* mod);
+static void _stp_module_free_tp(void *data, struct module* mod);
+#endif
static int _stp_module_notifier (struct notifier_block * nb,
unsigned long val, void *data);
static struct notifier_block _stp_module_notifier_nb = {
@@ -158,11 +180,30 @@ static void _stp_handle_start(struct _stp_msg_start *st)
failed: something nasty has happened, and
we want no further probing started. PR16766 */
if (!_stp_module_notifier_active) {
- int rc = register_module_notifier(& _stp_module_notifier_nb);
- if (rc == 0)
- _stp_module_notifier_active = 1;
- else
- _stp_warn ("Cannot register module notifier (%d)\n", rc);
+#ifdef STAP_USE_MODULE_TRACEPOINTS
+ int rc0 = register_trace_module_load (& _stp_module_load_tp, NULL);
+ if (rc0)
+ _stp_warn ("Cannot register module load tracepoint (%d)\n", rc0);
+ else {
+ int rc1 = register_trace_module_free (& _stp_module_free_tp, NULL);
+ if (rc1) {
+ _stp_warn ("Cannot register module free tracepoint (%d)\n", rc1);
+ unregister_trace_module_load(& _stp_module_load_tp, NULL);
+ } else {
+#endif
+ int rc = register_module_notifier(& _stp_module_notifier_nb);
+ if (rc == 0)
+ _stp_module_notifier_active = 1;
+ else {
+ _stp_warn ("Cannot register module notifier (%d)\n", rc);
+#ifdef STAP_USE_MODULE_TRACEPOINTS
+ unregister_trace_module_load(& _stp_module_load_tp, NULL);
+ unregister_trace_module_free(& _stp_module_free_tp, NULL);
+
+ }
+ }
+#endif
+ }
}
}
@@ -198,7 +239,12 @@ static void _stp_cleanup_and_exit(int send_exit)
/* Unregister the module notifier. */
if (_stp_module_notifier_active) {
- int rc = unregister_module_notifier(& _stp_module_notifier_nb);
+ int rc;
+#ifdef STAP_USE_MODULE_TRACEPOINTS
+ unregister_trace_module_load(& _stp_module_load_tp, NULL);
+ unregister_trace_module_free(& _stp_module_free_tp, NULL);
+#endif
+ rc = unregister_module_notifier(& _stp_module_notifier_nb);
if (rc)
_stp_warn("module_notifier unregister error %d", rc);
_stp_module_notifier_active = 0;
commit 2e67c14dad1c661d2ce0b0ed218b371c1af218ba
Author: Frank Ch. Eigler <fche@redhat.com>
Date: Wed Sep 2 11:16:46 2015 -0400
PR18889: switch to STP_TRACEPOINT* frontend for kernel tracepoint registration
jistone kindly reminded that the runtime/stp_tracepoint.[ch] machinery
allows us to attach to kernel tracepoints, whether on string- or
tp*-based kernel APIs, and whether or not the tp* objects are
EXPORT_TRACEPOINT_SYMBOL_GPL'd. Let's use those; presto we get
module-init probing back on kernels oldish and newish.
diff --git a/buildrun.cxx b/buildrun.cxx
index 6d66b5a..2ca5933 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -379,8 +379,6 @@ compile_pass (systemtap_session& s)
output_autoconf(s, o, "autoconf-module-sect-attrs.c", "STAPCONF_MODULE_SECT_ATTRS", NULL);
output_autoconf(s, o, "autoconf-utrace-via-tracepoints.c", "STAPCONF_UTRACE_VIA_TRACEPOINTS", NULL);
output_autoconf(s, o, "autoconf-module-tracepoints.c", "STAPCONF_MODULE_TRACEPOINT", NULL);
- output_exportconf(s, o, "__tracepoint_module_load", "STAPCONF_MODULE_TRACEPOINT_EXPORT_LOAD");
- output_exportconf(s, o, "__tracepoint_module_free", "STAPCONF_MODULE_TRACEPOINT_EXPORT_FREE");
output_autoconf(s, o, "autoconf-task_work-struct.c", "STAPCONF_TASK_WORK_STRUCT", NULL);
output_autoconf(s, o, "autoconf-vm-area-pte.c", "STAPCONF_VM_AREA_PTE", NULL);
output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL);
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index e069a3d..db7de46 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -1,8 +1,8 @@
-/* -*- linux-c -*-
+/* -*- linux-c -*-
* transport.c - stp transport functions
*
* Copyright (C) IBM Corporation, 2005
- * Copyright (C) Red Hat Inc, 2005-2014
+ * Copyright (C) Red Hat Inc, 2005-2015
* Copyright (C) Intel Corporation, 2006
*
* This file is part of systemtap, and is free software. You can
@@ -23,19 +23,7 @@
#include "../uidgid_compatibility.h"
#ifdef STAPCONF_MODULE_TRACEPOINT
#include <trace/events/module.h>
-#endif
-
-/* PR18889: After 3.17, commit #de7b2973903c6, tracepoints are
- attached by symbol-address rather than by name string. That means
- they must be EXPORT_TRACEPOINT_SYMBOL_GPL'd for a tracepoint
- [un]register operation. On RHEL7 kernels with out that commit
- backported, we can do a tracepoint attach even without the exports. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
-#if defined(STAPCONF_MODULE_TRACEPOINT) && defined(STAPCONF_MODULE_TRACEPOINT_EXPORT_LOAD) && defined(STAPCONF_MODULE_TRACEPOINT_EXPORT_FREE)
-#define STAP_USE_MODULE_TRACEPOINTS
-#endif
-#elif defined(STAPCONF_MODULE_TRACEPOINT)
-#define STAP_USE_MODULE_TRACEPOINTS
+#include "../linux/stp_tracepoint.h"
#endif
@@ -149,7 +137,7 @@ static void _stp_handle_start(struct _stp_msg_start *st)
// protect against excessive or premature startup
handle_startup = (! _stp_start_called && ! _stp_exit_called);
_stp_start_called = 1;
-
+
if (handle_startup) {
dbug_trans(1, "stp_handle_start\n");
@@ -180,15 +168,15 @@ static void _stp_handle_start(struct _stp_msg_start *st)
failed: something nasty has happened, and
we want no further probing started. PR16766 */
if (!_stp_module_notifier_active) {
-#ifdef STAP_USE_MODULE_TRACEPOINTS
- int rc0 = register_trace_module_load (& _stp_module_load_tp, NULL);
+#ifdef STAPCONF_MODULE_TRACEPOINT
+ int rc0 = STP_TRACE_REGISTER(module_load, & _stp_module_load_tp);
if (rc0)
_stp_warn ("Cannot register module load tracepoint (%d)\n", rc0);
else {
- int rc1 = register_trace_module_free (& _stp_module_free_tp, NULL);
+ int rc1 = STP_TRACE_REGISTER(module_free, & _stp_module_free_tp);
if (rc1) {
_stp_warn ("Cannot register module free tracepoint (%d)\n", rc1);
- unregister_trace_module_load(& _stp_module_load_tp, NULL);
+ STP_TRACE_UNREGISTER(module_load, & _stp_module_load_tp);
} else {
#endif
int rc = register_module_notifier(& _stp_module_notifier_nb);
@@ -196,10 +184,9 @@ static void _stp_handle_start(struct _stp_msg_start *st)
_stp_module_notifier_active = 1;
else {
_stp_warn ("Cannot register module notifier (%d)\n", rc);
-#ifdef STAP_USE_MODULE_TRACEPOINTS
- unregister_trace_module_load(& _stp_module_load_tp, NULL);
- unregister_trace_module_free(& _stp_module_free_tp, NULL);
-
+#ifdef STAPCONF_MODULE_TRACEPOINT
+ STP_TRACE_UNREGISTER(module_load, & _stp_module_load_tp);
+ STP_TRACE_UNREGISTER(module_free, & _stp_module_free_tp);
}
}
#endif
@@ -240,9 +227,9 @@ static void _stp_cleanup_and_exit(int send_exit)
/* Unregister the module notifier. */
if (_stp_module_notifier_active) {
int rc;
-#ifdef STAP_USE_MODULE_TRACEPOINTS
- unregister_trace_module_load(& _stp_module_load_tp, NULL);
- unregister_trace_module_free(& _stp_module_free_tp, NULL);
+#ifdef STAPCONF_MODULE_TRACEPOINT
+ STP_TRACE_UNREGISTER(module_load, & _stp_module_load_tp);
+ STP_TRACE_UNREGISTER(module_free, & _stp_module_free_tp);
#endif
rc = unregister_module_notifier(& _stp_module_notifier_nb);
if (rc)
@@ -380,7 +367,7 @@ static void _stp_ctl_work_callback(unsigned long val)
* _stp_transport_close - close ctl and relayfs channels
*
* This is called automatically when the module is unloaded.
- *
+ *
*/
static void _stp_transport_close(void)
{
@@ -397,7 +384,7 @@ static void _stp_transport_close(void)
/**
* _stp_transport_init() is called from the module initialization.
- * It does the bare minimum to exchange commands with staprun
+ * It does the bare minimum to exchange commands with staprun
*/
static int _stp_transport_init(void)
{
@@ -657,7 +644,7 @@ static struct dentry *_stp_get_module_dir(void)
static int _stp_transport_fs_init(const char *module_name)
{
struct dentry *root_dir;
-
+
dbug_trans(1, "entry\n");
if (module_name == NULL)
return -1;
commit 578f5f6f6792fc92d74539a927cd85de5bcbb4dd
Author: Frank Ch. Eigler <fche@redhat.com>
Date: Wed Sep 2 11:52:31 2015 -0400
PR18889 testing: already done by modules_out_of_tree.exp
Ditch bz6503, given that it wasn't reliable.
diff --git a/testsuite/systemtap.base/bz6503.exp b/testsuite/systemtap.base/bz6503.exp
deleted file mode 100644
index 5d4d2d0..0000000
--- a/testsuite/systemtap.base/bz6503.exp
+++ /dev/null
@@ -1,55 +0,0 @@
-# Note that this test is *really* testing the bug fix for pr6503:
-# permit probes on module .init and __exit functions
-# <http://sourceware.org/bugzilla/show_bug.cgi?id=6503>
-#
-# Not BZ6503:
-# ypserve does not work
-# <https://bugzilla.redhat.com/show_bug.cgi?id=6503>
-#
-# Unfortunately, PR17249 indicates that module-init probes
-# have subsequently broken (due to kernel notification timing
-# changes).
-#
-
-set test bz6503
-
-if {! [installtest_p]} {
- untested "$test"
- return
-}
-
-# If we aren't root, make sure the test still succeeds.
-set effective_pid [exec /usr/bin/id -u]
-if {$effective_pid != 0} {
- set root_cmd "sudo "
-} else {
- set root_cmd ""
-}
-
-
-# jffs2/ext2/fat/vfat should cover a span of kernels.
-#
-# Note that this test might fail if there is a filesystem of one of
-# these types already mounted. The filesystem mount will be
-# unaffected (since the module can't be removed).
-spawn stap -t $srcdir/$subdir/bz6503.stp -c "( ($root_cmd /sbin/modprobe jffs2; $root_cmd /sbin/modprobe ext2; $root_cmd /sbin/modprobe fat; $root_cmd /sbin/modprobe vfat); wait; ($root_cmd /sbin/rmmod jffs2; $root_cmd /sbin/rmmod ext2; $root_cmd /sbin/rmmod vfat; $root_cmd /sbin/rmmod fat); wait) 2>/dev/null"
-
-set ok 0
-set ko 0
-expect {
- -timeout 60
- timeout { fail "$test (timeout)" }
- -re {^-----[^\r\n]*\r\n} { exp_continue }
- -re {^module[^\r\n]*hits:[^\r\n]*\r\n} { incr ok; exp_continue }
- -re {^WARNING:[\r\n]*\r\n} { incr ko; exp_continue }
- -re {^ERROR:[\r\n]*\r\n} { incr ko; exp_continue }
- eof { }
-}
-catch { close} ; catch { wait }
-
-# Mark kernels without module refresh support as xfail
-if {![module_refresh_p]} { setup_xfail *-*-* }
-
-if {$ok > 0 && $ko == 0} then { pass "$test $ok" } else { fail "$test $ok $ko"}
-
-
diff --git a/testsuite/systemtap.base/bz6503.stp b/testsuite/systemtap.base/bz6503.stp
deleted file mode 100644
index 409149f..0000000
--- a/testsuite/systemtap.base/bz6503.stp
+++ /dev/null
@@ -1,5 +0,0 @@
-probe module("jffs2").function("*").call ?,
- module("ext2").function("*").call ?,
- module("fat").function("*").call ?,
- module("vfat").function("*").call ?,
- never { }