]> sourceware.org Git - systemtap.git/commitdiff
Fix PR14026 by updating the IP before calling the inode-uprobe handler.
authorDavid Smith <dsmith@redhat.com>
Wed, 15 Aug 2012 15:11:12 +0000 (10:11 -0500)
committerDavid Smith <dsmith@redhat.com>
Wed, 15 Aug 2012 15:11:12 +0000 (10:11 -0500)
* tapsets.cxx (uprobe_derived_probe_group::emit_module_inode_decls): Fix
  the IP before calling the real probe handler using
  uprobe_get_swbp_addr().
* buildrun.cxx (compile_pass): Added
  STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED autoconf.
* runtime/linux/runtime.h: Add kallsyms_uprobe_get_swbp_addr declaration.
* runtime/linux/uprobes-inode.c: Ditto.
* runtime/transport/transport.c (_stp_transport_init): If
  STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED isn't defined, use
  kallsyms_lookup_name() to find the address of 'uprbe_get_swbp_addr'.

buildrun.cxx
runtime/linux/runtime.h
runtime/linux/uprobes-inode.c
runtime/transport/transport.c
tapsets.cxx

index 0f51063852f915362a53b449ccf0d50197053c9a..6fd641d589bf4ae9b033666f14a524ce4c4b4988 100644 (file)
@@ -359,6 +359,10 @@ compile_pass (systemtap_session& s)
   output_either_exportconf(s, o, "uprobe_unregister", "unregister_uprobe",
                           "STAPCONF_UPROBE_UNREGISTER_EXPORTED");
   output_autoconf(s, o, "autoconf-old-inode-uprobes.c", "STAPCONF_OLD_INODE_UPROBES", NULL);
+
+  // used by tapsets.cxx inode uprobe generated code
+  output_exportconf(s, o, "uprobe_get_swbp_addr", "STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED");
+
   // used by runtime/loc2c-runtime.h
   output_exportconf(s, o, "task_user_regset_view", "STAPCONF_TASK_USER_REGSET_VIEW_EXPORTED");
 
index 92e948c51b42a8ac2988b4966dd5b840d49fa9d8..317bb58b5d0751b968b7b77cf69f3df301cae676 100644 (file)
@@ -143,6 +143,9 @@ void *kallsyms_uprobe_register;
 #if !defined(STAPCONF_UPROBE_UNREGISTER_EXPORTED)
 void *kallsyms_uprobe_unregister;
 #endif
+#if !defined(STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED)
+void *kallsyms_uprobe_get_swbp_addr;
+#endif
 
 /* task_work functions lack the necessary SYMBOL_EXPORT's */
 #if !defined(STAPCONF_TASK_WORK_ADD_EXPORTED)
index 07f5ed7c0e6d7964edd5f4c9ced35658991af416..49b7b59265d7490009aba0b6d818ece1c19e2ae4 100644 (file)
@@ -40,6 +40,10 @@ typedef void (*uprobe_unregister_fn)(struct inode *inode, loff_t offset,
 #define uprobe_unregister unregister_uprobe
 #endif
 
+#if !defined(STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED)
+typedef unsigned long (*uprobe_get_swbp_addr_fn)(struct pt_regs *regs);
+#define uprobe_get_swbp_addr (* (uprobe_get_swbp_addr_fn)kallsyms_uprobe_get_swbp_addr)
+#endif
 
 /* A target is a specific file/inode that we want to probe.  */
 struct stapiu_target {
index 29e549cb7308c0eba0138b02cce1237ef8357f38..712ea0f241ab38cf24ae6327d38909efa11f7820 100644 (file)
@@ -348,6 +348,13 @@ static int _stp_transport_init(void)
                 goto err0;
         }
 #endif
+#if !defined(STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED)
+        kallsyms_uprobe_get_swbp_addr = (void*) kallsyms_lookup_name ("uprobe_get_swbp_addr");
+        if (kallsyms_uprobe_get_swbp_addr == NULL) {
+                printk(KERN_ERR "%s can't resolve uprobe_get_swbp_addr!", THIS_MODULE->name);
+                goto err0;
+        }
+#endif
 #endif
 
 
index f660bd87d3faa6a4a6b7b6bfc5b9df043f24e1b9..097cc99db35e901a4eef6c2d62fc53e0d44ccd36 100644 (file)
@@ -7569,9 +7569,17 @@ uprobe_derived_probe_group::emit_module_inode_decls (systemtap_session& s)
                                  "_STP_PROBE_HANDLER_UPROBE");
   s.op->newline() << "c->uregs = regs;";
   s.op->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;";
-  // XXX: Can't set SET_REG_IP; we don't actually know the relocated address.
-  // ...  In some error cases, uprobes itself calls uprobes_get_bkpt_addr().
+  // Make it look like the IP is set as it would in the actual user
+  // task when calling real probe handler. Reset IP regs on return, so
+  // we don't confuse uprobes.
+  s.op->newline() << "{";
+  s.op->indent(1);
+  s.op->newline() << "unsigned long uprobes_ip = REG_IP(regs);";
+  s.op->newline() << "SET_REG_IP(regs, uprobe_get_swbp_addr(regs));";
   s.op->newline() << "(*sup->probe->ph) (c);";
+  s.op->newline() << "SET_REG_IP(regs, uprobes_ip);";
+  s.op->newline(-1) << "}";
+
   common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
   s.op->newline() << "return 0;";
   s.op->newline(-1) << "}";
This page took 0.044575 seconds and 5 git commands to generate.