From: David Smith Date: Wed, 15 Aug 2012 15:11:12 +0000 (-0500) Subject: Fix PR14026 by updating the IP before calling the inode-uprobe handler. X-Git-Tag: release-2.0~163 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=39e63baec1c22a96ea87fce594c9bb71370c4078;p=systemtap.git Fix PR14026 by updating the IP before calling the inode-uprobe handler. * 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'. --- diff --git a/buildrun.cxx b/buildrun.cxx index 0f5106385..6fd641d58 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -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"); diff --git a/runtime/linux/runtime.h b/runtime/linux/runtime.h index 92e948c51..317bb58b5 100644 --- a/runtime/linux/runtime.h +++ b/runtime/linux/runtime.h @@ -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) diff --git a/runtime/linux/uprobes-inode.c b/runtime/linux/uprobes-inode.c index 07f5ed7c0..49b7b5926 100644 --- a/runtime/linux/uprobes-inode.c +++ b/runtime/linux/uprobes-inode.c @@ -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 { diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 29e549cb7..712ea0f24 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -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 diff --git a/tapsets.cxx b/tapsets.cxx index f660bd87d..097cc99db 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -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) << "}";