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");
#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)
#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 {
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
"_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) << "}";