diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2009-12-20 13:34:16 -0500 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2009-12-20 13:34:16 -0500 |
commit | 028e1bde11b9644d1ac62f0a1a2188cf8def234a (patch) | |
tree | 8f1eb8ecb8e904d84bd91627c87b8fd5bdb0d4f2 /runtime | |
parent | be00414012df13c2eddf98909b3cdfe21c2a94d8 (diff) | |
download | systemtap-steved-028e1bde11b9644d1ac62f0a1a2188cf8def234a.tar.gz systemtap-steved-028e1bde11b9644d1ac62f0a1a2188cf8def234a.tar.xz systemtap-steved-028e1bde11b9644d1ac62f0a1a2188cf8def234a.zip |
runtime backtracing: port commit #2e7f8442 to uprobes1
* runtime/uprobes/uprobes.c (uprobe_get_pc): new function
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/stack-x86_64.c | 2 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.c | 38 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.h | 8 |
3 files changed, 46 insertions, 2 deletions
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index d6c63412..3fc203f7 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -38,7 +38,6 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels, while (levels && (tsk || !arch_unw_user_mode(&info))) { int ret = unwind(&info, tsk); -#if defined(UPROBES_API_VERSION) && UPROBES_API_VERSION > 1 unsigned long maybe_pc = 0; if (ri) { maybe_pc = uprobe_get_pc(ri, UNW_PC(&info), @@ -48,7 +47,6 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels, else UNW_PC(&info) = maybe_pc; } -#endif dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); if (ret == 0) { _stp_func_print(UNW_PC(&info), verbose, 1, tsk); diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 60c84509..cdb98707 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -2596,6 +2596,44 @@ 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; +} + +EXPORT_SYMBOL_GPL(uprobe_get_pc); + #else /* ! CONFIG_URETPROBES */ static void uretprobe_handle_entry(struct uprobe *u, struct pt_regs *regs, diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h index d542420d..e888f9e8 100644 --- a/runtime/uprobes/uprobes.h +++ b/runtime/uprobes/uprobes.h @@ -95,6 +95,14 @@ extern void unregister_uretprobe(struct uretprobe *rp); /* For PRs 9940, 6852... */ extern void unmap_uprobe(struct uprobe *u); 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. + */ +extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri, + unsigned long pc, + unsigned long sp); #ifdef UPROBES_IMPLEMENTATION |