summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@elastic.org>2009-12-20 13:34:16 -0500
committerFrank Ch. Eigler <fche@elastic.org>2009-12-20 13:34:16 -0500
commit028e1bde11b9644d1ac62f0a1a2188cf8def234a (patch)
tree8f1eb8ecb8e904d84bd91627c87b8fd5bdb0d4f2 /runtime
parentbe00414012df13c2eddf98909b3cdfe21c2a94d8 (diff)
downloadsystemtap-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.c2
-rw-r--r--runtime/uprobes/uprobes.c38
-rw-r--r--runtime/uprobes/uprobes.h8
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