summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorTim Moore <timoore@redhat.com>2010-01-05 15:18:57 +0100
committerTim Moore <timoore@redhat.com>2010-01-05 15:18:57 +0100
commit21e8e579ef10942bf2db3e1514026a6d132b1502 (patch)
tree08214b1f9a8699ae9368ffb787f2513fcf54d4d7 /runtime
parentc799f7e71c710566175d57c25ad775ec29e18ad4 (diff)
downloadsystemtap-steved-21e8e579ef10942bf2db3e1514026a6d132b1502.tar.gz
systemtap-steved-21e8e579ef10942bf2db3e1514026a6d132b1502.tar.xz
systemtap-steved-21e8e579ef10942bf2db3e1514026a6d132b1502.zip
bz6436 backtraces from uprobes
This implements proper unwinding from uprobes in the presence of uretprobe trampolines. * runtime/stack.c (_stp_stack_print): Rework for uprobe context case and refactor a bit. * runtime/uprobes2/uprobes.h (GET_PC_URETPROBE_NONE): new constant * runtime/uprobes2/uprobes.c (uprobe_get_pc): Support translating the trampoline function from uprobe context in addition to uretprobe context. * runtime/uprobes/uprobes.h (GET_PC_URETPROBE_NONE): ditto * runtime/uprobes/uprobes.c (uprobe_get_pc): ditto * tapsets.cxx (uprobe_derived_probe_group::emit_module_decls): Initialize ri in context to GET_PC_URETPROBE_NONE in generated enter_uprobe_probe. * testsuite/systemtap.context/fib.stp: Add an option to do a backtrace on function entry. * testsuite/systemtap.context/fib.exp: Test backtrace in function entry (uprobe) probes.
Diffstat (limited to 'runtime')
-rw-r--r--runtime/stack.c18
-rw-r--r--runtime/uprobes/uprobes.c71
-rw-r--r--runtime/uprobes/uprobes.h4
-rw-r--r--runtime/uprobes2/uprobes.c71
-rw-r--r--runtime/uprobes2/uprobes.h4
5 files changed, 99 insertions, 69 deletions
diff --git a/runtime/stack.c b/runtime/stack.c
index 50dde6e1..612fa010 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -132,25 +132,29 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
_stp_print("\nReturning to : ");
}
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
- } else if (ri) {
-#ifdef CONFIG_UTRACE /* as a proxy for presence of uprobes */
+ _stp_print_char('\n');
+#ifdef CONFIG_UTRACE /* as a proxy for presence of uprobes... */
+ } else if (ri && ri != GET_PC_URETPROBE_NONE) {
if (verbose == SYM_VERBOSE_FULL) {
_stp_print("Returning from: ");
- _stp_usymbol_print(ri->rp->u.vaddr, tsk); /* otherwise this dereference fails */
+ /* ... otherwise this dereference fails */
+ _stp_usymbol_print(ri->rp->u.vaddr, tsk);
_stp_print("\nReturning to : ");
_stp_usymbol_print(ri->ret_addr, tsk);
+ _stp_print_char('\n');
} else
_stp_func_print(ri->ret_addr, verbose, 0, tsk);
#endif
+ } else if (verbose == SYM_VERBOSE_BRIEF) {
+ _stp_func_print(REG_IP(regs), verbose, 0, tsk);
} else {
_stp_print_char(' ');
if (tsk)
- _stp_usymbol_print(REG_IP(regs), tsk);
+ _stp_usymbol_print(REG_IP(regs), tsk);
else
- _stp_symbol_print(REG_IP(regs));
- }
- if (verbose != SYM_VERBOSE_BRIEF)
+ _stp_symbol_print(REG_IP(regs));
_stp_print_char('\n');
+ }
} else if (pi)
_stp_printf("%p %p ", (int64_t)(long)_stp_ret_addr_r(pi), (int64_t) REG_IP(regs));
else
diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c
index cdb98707..5ccc7102 100644
--- a/runtime/uprobes/uprobes.c
+++ b/runtime/uprobes/uprobes.c
@@ -2599,37 +2599,46 @@ static void uretprobe_set_trampoline(struct uprobe_process *uproc,
unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc,
unsigned long sp)
{
- struct uretprobe *rp;
- struct uprobe_kimg *uk;
- struct uprobe_process *uproc;
- unsigned long trampoline_addr;
- struct hlist_node *r;
- struct uretprobe_instance *ret_inst;
-
- if (!ri)
- return 0;
- rp = ri->rp;
- uk = (struct uprobe_kimg *)rp->u.kdata;
- if (!uk)
- return 0;
- uproc = uk->ppt->uproc;
- if (IS_ERR(uproc->uretprobe_trampoline_addr))
- return pc;
- trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr;
- if (pc != trampoline_addr)
- return pc;
- r = &ri->hlist;
- hlist_for_each_entry_from(ret_inst, r, hlist) {
- if (ret_inst->ret_addr == trampoline_addr)
- continue;
- /* First handler with a stack pointer lower than the
- address (or equal) must be the one. */
- if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp))
- return ret_inst->ret_addr;
- }
- printk(KERN_ERR "Original return address for trampoline not found at "
- "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid);
- return 0;
+ struct uretprobe *rp;
+ struct uprobe_kimg *uk;
+ struct uprobe_task *utask;
+ struct uprobe_process *uproc;
+ unsigned long trampoline_addr;
+ struct hlist_node *r;
+ struct uretprobe_instance *ret_inst;
+
+ if (!ri)
+ return 0;
+ if (ri == GET_PC_URETPROBE_NONE) {
+ utask = uprobe_find_utask(current);
+ if (!utask)
+ return 0;
+ uproc = utask->uproc;
+ r = utask->uretprobe_instances.first;
+ } else {
+ rp = ri->rp;
+ uk = (struct uprobe_kimg *)rp->u.kdata;
+ if (!uk)
+ return 0;
+ uproc = uk->ppt->uproc;
+ r = &ri->hlist;
+ }
+ if (IS_ERR(uproc->uretprobe_trampoline_addr))
+ return pc;
+ trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr;
+ if (pc != trampoline_addr)
+ return pc;
+ hlist_for_each_entry_from(ret_inst, r, hlist) {
+ if (ret_inst->ret_addr == trampoline_addr)
+ continue;
+ /* First handler with a stack pointer lower than the
+ address (or equal) must be the one. */
+ if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp))
+ return ret_inst->ret_addr;
+ }
+ printk(KERN_ERR "Original return address for trampoline not found at "
+ "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid);
+ return 0;
}
EXPORT_SYMBOL_GPL(uprobe_get_pc);
diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h
index e888f9e8..80725f23 100644
--- a/runtime/uprobes/uprobes.h
+++ b/runtime/uprobes/uprobes.h
@@ -99,7 +99,11 @@ extern void unmap_uretprobe(struct uretprobe *rp);
* Given a program counter, translate it back to the original address
* if it is the address of the trampoline. sp is the stack pointer for
* the frame that corresponds to the address.
+ *
+ * When not called from a uretprobe hander, pass GET_PC_URETPROBE_NONE
+ * instead of a uretprobe_instance.
*/
+#define GET_PC_URETPROBE_NONE ((struct uretprobe_instance *)-1L)
extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri,
unsigned long pc,
unsigned long sp);
diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c
index 02941e26..623855ff 100644
--- a/runtime/uprobes2/uprobes.c
+++ b/runtime/uprobes2/uprobes.c
@@ -2840,37 +2840,46 @@ static void uretprobe_set_trampoline(struct uprobe_process *uproc,
unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc,
unsigned long sp)
{
- struct uretprobe *rp;
- struct uprobe_kimg *uk;
- struct uprobe_process *uproc;
- unsigned long trampoline_addr;
- struct hlist_node *r;
- struct uretprobe_instance *ret_inst;
-
- if (!ri)
- return 0;
- rp = ri->rp;
- uk = (struct uprobe_kimg *)rp->u.kdata;
- if (!uk)
- return 0;
- uproc = uk->ppt->uproc;
- if (IS_ERR(uproc->uretprobe_trampoline_addr))
- return pc;
- trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr;
- if (pc != trampoline_addr)
- return pc;
- r = &ri->hlist;
- hlist_for_each_entry_from(ret_inst, r, hlist) {
- if (ret_inst->ret_addr == trampoline_addr)
- continue;
- /* First handler with a stack pointer lower than the
- address (or equal) must be the one. */
- if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp))
- return ret_inst->ret_addr;
- }
- printk(KERN_ERR "Original return address for trampoline not found at "
- "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid);
- return 0;
+ struct uretprobe *rp;
+ struct uprobe_kimg *uk;
+ struct uprobe_task *utask;
+ struct uprobe_process *uproc;
+ unsigned long trampoline_addr;
+ struct hlist_node *r;
+ struct uretprobe_instance *ret_inst;
+
+ if (!ri)
+ return 0;
+ if (ri == GET_PC_URETPROBE_NONE) {
+ utask = uprobe_find_utask(current);
+ if (!utask)
+ return 0;
+ uproc = utask->uproc;
+ r = utask->uretprobe_instances.first;
+ } else {
+ rp = ri->rp;
+ uk = (struct uprobe_kimg *)rp->u.kdata;
+ if (!uk)
+ return 0;
+ uproc = uk->ppt->uproc;
+ r = &ri->hlist;
+ }
+ if (IS_ERR(uproc->uretprobe_trampoline_addr))
+ return pc;
+ trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr;
+ if (pc != trampoline_addr)
+ return pc;
+ hlist_for_each_entry_from(ret_inst, r, hlist) {
+ if (ret_inst->ret_addr == trampoline_addr)
+ continue;
+ /* First handler with a stack pointer lower than the
+ address (or equal) must be the one. */
+ if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp))
+ return ret_inst->ret_addr;
+ }
+ printk(KERN_ERR "Original return address for trampoline not found at "
+ "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid);
+ return 0;
}
EXPORT_SYMBOL_GPL(uprobe_get_pc);
diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h
index 5d2a826e..c4e1f59c 100644
--- a/runtime/uprobes2/uprobes.h
+++ b/runtime/uprobes2/uprobes.h
@@ -92,7 +92,11 @@ extern void unmap_uretprobe(struct uretprobe *rp);
* Given a program counter, translate it back to the original address
* if it is the address of the trampoline. sp is the stack pointer for
* the frame that corresponds to the address.
+ *
+ * When not called from a uretprobe hander, pass GET_PC_URETPROBE_NONE
+ * instead of a uretprobe_instance.
*/
+#define GET_PC_URETPROBE_NONE ((struct uretprobe_instance *)-1L)
extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri,
unsigned long pc,
unsigned long sp);