]> sourceware.org Git - systemtap.git/commitdiff
Add RHEL7.2 fixes for PR18889 so that we can probe module initializers.
authorDavid Smith <dsmith@redhat.com>
Fri, 4 Dec 2015 20:23:17 +0000 (14:23 -0600)
committerDavid Smith <dsmith@redhat.com>
Fri, 4 Dec 2015 20:23:17 +0000 (14:23 -0600)
* runtime/linux/kprobes.c (stapkp_prepare_kprobe): If we have
  kallsyms_on_each_symbol(), just return if we don't have an address.
  (stapkp_prepare_kretprobe): Ditto.
  (stapkp_symbol_callback): New callback function for
  kallsyms_on_each_symbol() to convert symbol_name+offset probes into
  address probes. This works around a kernel bug and should be faster as
  well.
  (stapkp_init): Call kallsyms_on_each_symbol() when needed.
  (stapkp_refresh): Ditto.
* runtime/transport/symbols.c (_stp_module_notifier): Change to the new
  module refresh logic if the kernel version is 3.10 or higher.
* tapsets.cxx (dwarf_derived_probe_group::emit_module_decls): Ditto.
* testsuite/systemtap.base/kmodule.exp: Only run the subtests that load
  the test kernel module after the systemtap module is loaded on systems
  that support module refreshes.

runtime/linux/kprobes.c
runtime/transport/symbols.c
tapsets.cxx
testsuite/systemtap.base/kmodule.exp

index ec7c46c6a32725cb3a995ac16483bfece5d1b4f2..a4f2b71951b2ebb4c1c0f8049291dddfbcd231cc 100644 (file)
@@ -17,6 +17,7 @@
 #endif
 
 #include <linux/kprobes.h>
+#include <linux/module.h>
 
 #ifdef DEBUG_KPROBES
 #define dbug_stapkp(args...) do {                                      \
@@ -79,9 +80,10 @@ struct stap_dwarf_probe {
    // switch to using symbol_name+offset (on kernels that support
    // symbol_name+offset probing).
    const unsigned long address;
+
    // Note we can't really check for STAPCONF_KPROBE_SYMBOL_NAME here,
    // since that complicates the init logic too much.
-   const char * const symbol_name;
+   const char *symbol_name;
    unsigned int offset;
 
    const struct stap_probe * const probe;
@@ -131,17 +133,46 @@ stapkp_prepare_kprobe(struct stap_dwarf_probe *sdp)
       addr = stapkp_relocate_addr(sdp);
       if (addr == 0)
         return 1;
+      kp->addr = (void *) addr;
    }
    else {
-      // If we're doing symbolic name + offset probing, it doesn't
-      // really matter if the symbol is in a module and the module
-      // isn't loaded right now. The registration will fail, but will
-      // get tried again when the module is loaded.
+#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL
+      // If we're doing symbolic name + offset probing (that gets
+      // converted to an address), it doesn't really matter if the
+      // symbol is in a module and the module isn't loaded right
+      // now. The registration will fail, but will get tried again
+      // when the module is loaded.
+      if (kp->addr == 0)
+        return 1;
+#else
+      // If we don't have kallsyms_on_each_symbol(), we'll use
+      // symbol_name+offset probing and let
+      // register_kprobe()/register_kretprobe() call
+      // kallsyms_lookup_name() for us. However, on kernels < 3.11,
+      // module_kallsyms_lookup_name() (called from
+      // kallsyms_lookup_name()) has a bug where it modifies its
+      // argument. So, for those kernels we'll workaround the bug by
+      // duplicating the string (so we go from read-only memory in the
+      // initialized struct data to read-write allocated memory). The
+      // memory gets freed when the probe is unregistered.
+      //
+      // This bug was fixed in kernel 3.11+ by the following commit:
+      //
+      //   commit 4f6de4d51f4a3ab06a85e91e708cc89a513ef30c
+      //      Author: Mathias Krause <minipli@googlemail.com>
+      //      Date:   Tue Jul 2 15:35:11 2013 +0930
+      //
+      //      module: don't modify argument of module_kallsyms_lookup_name()
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+      if (kp->symbol_name == NULL)
+        kp->symbol_name = kstrdup(sdp->symbol_name, STP_ALLOC_FLAGS);
+#else
       kp->symbol_name = (typeof(kp->symbol_name))sdp->symbol_name;
+#endif
       kp->offset = sdp->offset;
+#endif
    }
 
-   kp->addr = (void *) addr;
    kp->pre_handler = &enter_kprobe_probe;
 
 #ifdef __ia64__ // PR6028
@@ -173,7 +204,7 @@ stapkp_arch_register_kprobe(struct stap_dwarf_probe *sdp)
       if (sdp->symbol_name)
         dbug_stapkp("+kprobe %s+%u\n", kp->symbol_name, kp->offset);
       else
-        dbug_stapkp_cond("+kprobe %p\n", kp->addr);
+        dbug_stapkp("+kprobe %p\n", kp->addr);
    }
 #else // PR6028
    ret = register_kprobe(&sdp->kprobe->dummy);
@@ -212,14 +243,23 @@ stapkp_prepare_kretprobe(struct stap_dwarf_probe *sdp)
       addr = stapkp_relocate_addr(sdp);
       if (addr == 0)
         return 1;
+      krp->kp.addr = (void *) addr;
    }
    else {
+#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL
+      if (krp->kp.addr == 0)
+        return 1;
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+      if (krp->kp.symbol_name == NULL)
+        krp->kp.symbol_name = kstrdup(sdp->symbol_name, STP_ALLOC_FLAGS);
+#else
       krp->kp.symbol_name = (typeof(krp->kp.symbol_name))sdp->symbol_name;
+#endif
       krp->kp.offset = sdp->offset;
+#endif
    }
 
-   krp->kp.addr = (void *) addr;
-
    if (sdp->maxactive_p)
       krp->maxactive = sdp->maxactive_val;
    else
@@ -367,6 +407,19 @@ stapkp_unregister_probe(struct stap_dwarf_probe *sdp)
 
    stapkp_add_missed(sdp);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+   if (sdp->symbol_name != NULL) {
+      if (sdp->return_p) {
+        if (sdk->u.krp.kp.symbol_name != NULL)
+           kfree(sdk->u.krp.kp.symbol_name);
+      }
+      else {
+        if (sdk->u.kp.symbol_name != NULL)
+           kfree(sdk->u.kp.symbol_name);
+      }
+   }
+#endif
+
    // PR16861: kprobes may have left some things in the k[ret]probe struct.
    // Let's reset it to be sure it's safe for re-use.
    memset(sdk, 0, sizeof(struct stap_dwarf_kprobe));
@@ -451,6 +504,19 @@ stapkp_batch_unregister_probes(struct stap_dwarf_probe *probes,
 
       stapkp_add_missed(sdp);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+      if (sdp->symbol_name != NULL) {
+        if (sdp->return_p) {
+           if (sdp->kprobe->u.krp.kp.symbol_name != NULL)
+              kfree(sdp->kprobe->u.krp.kp.symbol_name);
+        }
+        else {
+           if (sdp->kprobe->u.kp.symbol_name != NULL)
+              kfree(sdp->kprobe->u.kp.symbol_name);
+        }
+      }
+#endif
+
       // PR16861: kprobes may have left some things in the k[ret]probe struct.
       // Let's reset it to be sure it's safe for re-use.
       memset(sdp->kprobe, 0, sizeof(struct stap_dwarf_kprobe));
@@ -573,13 +639,89 @@ stapkp_refresh_probe(struct stap_dwarf_probe *sdp)
 #endif /* LINUX_VERSION_CODE >= 2.6.30 */
 
 
+#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL
+struct stapkp_symbol_data {
+   struct stap_dwarf_probe *probes;
+   size_t nprobes;                     /* number of probes in "probes" */
+   size_t probe_max;                   /* number of probes to process */
+   const char *modname;
+};
+
+
+static int
+stapkp_symbol_callback(void *data, const char *name,
+                      struct module *mod, unsigned long addr)
+{
+   struct stapkp_symbol_data *sd = data;
+   size_t i;
+
+   // Right now, all the symbol_name+offset probes are in modules, so
+   // if we aren't looking at a module symbol we're done.
+   if (!mod)
+      return 0;
+
+   for (i = 0; i < sd->nprobes; i++) {
+      struct stap_dwarf_probe *sdp = &sd->probes[i];
+      char *colon;
+
+      if (! sdp->symbol_name)
+        continue;
+      if (sd->modname && strcmp(mod->name, sd->modname) != 0)
+        continue;
+      colon = strchr(sdp->symbol_name, ':');
+      if (colon != NULL && strcmp(mod->name, sdp->module) == 0
+         && strcmp(name, colon+1) == 0) {
+        if (sdp->return_p)
+           sdp->kprobe->u.krp.kp.addr = (void *)(addr + sdp->offset);
+        else
+           sdp->kprobe->u.kp.addr = (void *)(addr + sdp->offset);
+        // Note that we could have more than 1 probe at the same
+        // symbol (with the same or differing offsets), so we can't
+        // return here.
+        //
+        // But we can quit if we've processed all the needed probes.
+        --sd->probe_max;
+        if (sd->probe_max == 0)
+           return -1;
+      }
+   }
+   return 0;
+}
+#endif
+
+
 static int
 stapkp_init(struct stap_dwarf_probe *probes,
             size_t nprobes)
 {
    size_t i;
+
+#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL
+   // If we have any symbol_name+offset probes, we need to try to
+   // convert those into address-based probes.
+   size_t probe_max = 0;
    for (i = 0; i < nprobes; i++) {
+      struct stap_dwarf_probe *sdp = &probes[i];
 
+      if (! sdp->symbol_name)
+        continue;
+      ++probe_max;
+   }
+   if (probe_max > 0) {
+      // Here we're going to try to convert any symbol_name+offset
+      // probes into address probes.
+      struct stapkp_symbol_data sd;
+      sd.probes = probes;
+      sd.nprobes = nprobes;
+      sd.probe_max = probe_max;
+      sd.modname = NULL;
+      mutex_lock(&module_mutex);
+      kallsyms_on_each_symbol(stapkp_symbol_callback, &sd);
+      mutex_unlock(&module_mutex);
+   }
+#endif
+
+   for (i = 0; i < nprobes; i++) {
       struct stap_dwarf_probe *sdp = &probes[i];
       int rc = 0;
 
@@ -616,6 +758,34 @@ stapkp_refresh(const char *modname,
 
    dbug_stapkp("refresh %lu probes with module %s\n", nprobes, modname ?: "?");
 
+#ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL
+   if (modname) {
+      size_t probe_max = 0;
+      for (i = 0; i < nprobes; i++) {
+        struct stap_dwarf_probe *sdp = &probes[i];
+
+        // If this probe is in the same module that is being
+        // loaded/unloaded and the probe is symbol_name+offset based
+        // and it isn't registered (so the module must be loaded),
+        // try to convert all probes in the same module to
+        // address-based probes.
+        if (sdp->module && strcmp(modname, sdp->module) == 0
+            && sdp->symbol_name && sdp->registered_p == 0)
+           ++probe_max;
+      }
+      if (probe_max > 0) {
+        struct stapkp_symbol_data sd;
+        sd.probes = probes;
+        sd.nprobes = nprobes;
+        sd.probe_max = probe_max;
+        sd.modname = modname;
+        mutex_lock(&module_mutex);
+        kallsyms_on_each_symbol(stapkp_symbol_callback, &sd);
+        mutex_unlock(&module_mutex);
+      }
+   }
+#endif
+
    for (i = 0; i < nprobes; i++) {
 
       struct stap_dwarf_probe *sdp = &probes[i];
@@ -634,12 +804,13 @@ stapkp_refresh(const char *modname,
          else if (sdp->registered_p == 1 && addr == 0)
             stapkp_unregister_probe(sdp);
 
+      }
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
-      else if (stapkp_should_enable_probe(sdp)
+      else if (stapkp_should_enable_probe(sdp)
               || stapkp_should_disable_probe(sdp)) {
          stapkp_refresh_probe(sdp);
-#endif
       }
+#endif
    }
 }
 
index 2401466d1f1797ac39a1812da0813d416fcf3815..fb5da2d0bc49f383719b8c9576c79b0e06a9f079 100644 (file)
@@ -151,7 +151,7 @@ static int _stp_module_notifier (struct notifier_block * nb,
        // After kernel commit 4982223e51, module notifiers are being
        // called too early to get module section info. So, we have to
        // switch to using symbol+offset probing for modules.
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
        // The module refresh code (in systemtap_module_refresh)
        // assumes the 1st call is on module load and the 2nd is on
        // module unload. So, we can't call systemtap_module_refresh()
index eb355c5eb11e1646c1fff7960a138eaa2552292f..e03f28506dc16c2ff3fd1518a7030db8c11e6152 100644 (file)
@@ -5766,7 +5766,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
          // After kernel commit 4982223e51, module notifiers are
          // being called too early. So, we have to switch to using
          // symbol+offset probing for modules.
-         s.op->newline(-1) << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)";
+         s.op->newline(-1) << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)";
          s.op->newline() << " .symbol_name=\"" << p->symbol_name << "\",";
          s.op->line() << " .offset=(unsigned int)" << p->offset << ",";
          s.op->newline() << "#endif";
index 65a813f35c0609e0e2bc32b6d3274f99b47a2307..3fc2694af4cfedcb4db4d2e7c463aba4ceb62e78 100644 (file)
@@ -2,6 +2,7 @@
 # function, install it, and get some output.
 
 set test "kmodule"
+set test2 "kprobe_module"
 if {![installtest_p]} {
     untested $test
     return
@@ -110,20 +111,27 @@ if {[build_and_install_module] == 0} {
 stap_run $srcdir/$subdir/$test.stp kmodule_load $output_string
 
 # Test 'kprobe.module("foo").function("bar")
-stap_run $srcdir/$subdir/kprobe_module.stp kmodule_load $output_string
+stap_run $srcdir/$subdir/$test2.stp kmodule_load $output_string
 
 # Now let's test and see if the same scripts work when the test module
 # is loaded *after* the systemtap script starts.
+set test_suffix "(loaded after)"
+if {![module_refresh_p]} {
+    untested "$subdir/$test.stp $test_suffix"
+    untested "$subdir/$test2.stp $test_suffix"
+    cleanup_module
+    return
+}
 as_root [list /sbin/rmmod stap_kmodule]
 
 # Test 'module("foo").function("bar")
 set test_file "$subdir/$test.stp"
-stap_run "$test_file (loaded after)" kmodule_load2 \
+stap_run "$test_file $test_suffix" kmodule_load2 \
     $output_string $srcdir/$test_file
 
 # Test 'kprobe.module("foo").function("bar")
-set test_file "$subdir/kprobe_module.stp"
-stap_run "$test_file (loaded after)" kmodule_load2 \
+set test_file "$subdir/$test2.stp"
+stap_run "$test_file $test_suffix" kmodule_load2 \
     $output_string $srcdir/$test_file
 
 cleanup_module
This page took 0.046046 seconds and 5 git commands to generate.