diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/runtime.h | 10 | ||||
-rw-r--r-- | runtime/stack-arm.c | 2 | ||||
-rw-r--r-- | runtime/stack-i386.c | 13 | ||||
-rw-r--r-- | runtime/stack-ppc.c | 2 | ||||
-rw-r--r-- | runtime/stack-s390.c | 3 | ||||
-rw-r--r-- | runtime/stack-x86_64.c | 14 | ||||
-rw-r--r-- | runtime/stack.c | 24 | ||||
-rw-r--r-- | runtime/sym.c | 24 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 38 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 8 |
10 files changed, 118 insertions, 20 deletions
diff --git a/runtime/runtime.h b/runtime/runtime.h index a7ee962c..0fd2a380 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -126,6 +126,16 @@ static struct #endif #endif +#ifndef SYM_VERBOSE_NO +#define SYM_VERBOSE_NO 0 +#endif +#ifndef SYM_VERBOSE_FULL +#define SYM_VERBOSE_FULL 1 +#endif +#ifndef SYM_VERBOSE_BRIEF +#define SYM_VERBOSE_BRIEF 2 +#endif + #include "alloc.c" #include "print.c" #include "string.c" diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c index fcff0a3b..2760eadd 100644 --- a/runtime/stack-arm.c +++ b/runtime/stack-arm.c @@ -32,7 +32,7 @@ static int __init find_str_pc_offset(void) static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, - struct task_struct *tsk) + struct task_struct *tsk, struct uretprobe_instance *ri) { #ifdef STP_USE_FRAME_POINTER int pc_offset = find_str_pc_offset(); diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index b447e495..4bd3cc53 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -31,7 +31,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve #endif static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, - struct task_struct *tsk) + struct task_struct *tsk, struct uretprobe_instance *ri) { unsigned long context = (unsigned long)®_SP(regs) & ~(THREAD_SIZE - 1); @@ -63,6 +63,17 @@ 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 UPROBES_API_VERSION > 1 + unsigned long maybe_pc = 0; + if (ri) { + maybe_pc = uprobe_get_pc(ri, UNW_PC(&info), + UNW_SP(&info)); + if (!maybe_pc) + printk("SYSTEMTAP ERROR: uprobe_get_return returned 0\n"); + 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/stack-ppc.c b/runtime/stack-ppc.c index df2db15d..9670d06f 100644 --- a/runtime/stack-ppc.c +++ b/runtime/stack-ppc.c @@ -8,7 +8,7 @@ */ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, - struct task_struct *tsk) + struct task_struct *tsk, struct uretprobe_instance *ri) { unsigned long ip, newsp, lr = 0; int count = 0; diff --git a/runtime/stack-s390.c b/runtime/stack-s390.c index 14e9b7d8..7a53f794 100644 --- a/runtime/stack-s390.c +++ b/runtime/stack-s390.c @@ -67,7 +67,8 @@ __stp_show_stack (unsigned long sp, unsigned long low, static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, - struct task_struct *tsk) + struct task_struct *tsk, + struct uretprobe_instance *ri) { unsigned long *_sp = (unsigned long *)®_SP(regs); unsigned long sp = (unsigned long)_sp; diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 914242e0..80ebd3e7 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -28,15 +28,27 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels, - struct task_struct *tsk) + struct task_struct *tsk, struct uretprobe_instance *ri) { #ifdef STP_USE_DWARF_UNWINDER + int start_levels = levels; // FIXME: large stack allocation struct unwind_frame_info info; arch_unw_init_frame_info(&info, regs); while (levels && (tsk || !arch_unw_user_mode(&info))) { int ret = unwind(&info, tsk); +#if UPROBES_API_VERSION > 1 + unsigned long maybe_pc = 0; + if (ri) { + maybe_pc = uprobe_get_pc(ri, UNW_PC(&info), + UNW_SP(&info)); + if (!maybe_pc) + printk("SYSTEMTAP ERROR: uprobe_get_return returned 0\n"); + 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/stack.c b/runtime/stack.c index 9c23d530..3d907a7f 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -112,15 +112,20 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe if (verbose) { /* print the current address */ if (pi) { - _stp_print("Returning from: "); - _stp_symbol_print((unsigned long)_stp_probe_addr_r(pi)); - _stp_print("\nReturning to : "); + if (verbose == SYM_VERBOSE_FULL) { + _stp_print("Returning from: "); + _stp_symbol_print((unsigned long)_stp_probe_addr_r(pi)); + _stp_print("\nReturning to : "); + } _stp_symbol_print((unsigned long)_stp_ret_addr_r(pi)); } else if (ri) { - _stp_print("Returning from: "); - _stp_usymbol_print(ri->rp->u.vaddr, tsk); - _stp_print("\nReturning to : "); - _stp_usymbol_print(ri->ret_addr, tsk); + if (verbose == SYM_VERBOSE_FULL) { + _stp_print("Returning from: "); + _stp_usymbol_print(ri->rp->u.vaddr, tsk); + _stp_print("\nReturning to : "); + _stp_usymbol_print(ri->ret_addr, tsk); + } else + _stp_func_print(ri->ret_addr, verbose, 0, tsk); } else { _stp_print_char(' '); if (tsk) @@ -128,13 +133,14 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe else _stp_symbol_print(REG_IP(regs)); } - _stp_print_char('\n'); + if (verbose != SYM_VERBOSE_BRIEF) + _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 _stp_printf("%p ", (int64_t) REG_IP(regs)); - __stp_stack_print(regs, verbose, levels, tsk); + __stp_stack_print(regs, verbose, levels, tsk, ri); } /** Writes stack backtrace to a string diff --git a/runtime/sym.c b/runtime/sym.c index 953161bc..cd0c8a71 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -374,19 +374,31 @@ static int _stp_func_print(unsigned long address, int verbose, int exact, else exstr = " (inexact)"; - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, task); + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, + task); if (name) { - if (verbose) { + switch (verbose) { + case SYM_VERBOSE_FULL: if (modname && *modname) _stp_printf(" %p : %s+%#lx/%#lx [%s]%s\n", - (int64_t) address, name, offset, size, modname, exstr); + (int64_t) address, name, offset, + size, modname, exstr); else - _stp_printf(" %p : %s+%#lx/%#lx%s\n", (int64_t) address, name, offset, size, exstr); - } else + _stp_printf(" %p : %s+%#lx/%#lx%s\n", + (int64_t) address, name, offset, size, + exstr); + break; + case SYM_VERBOSE_BRIEF: + _stp_printf("%s+%#lx\n", name, offset); + break; + case SYM_VERBOSE_NO: + default: _stp_printf("%p ", (int64_t) address); + } return 1; - } + } else if (verbose == SYM_VERBOSE_BRIEF) + _stp_printf("%p\n", (int64_t) address); return 0; } diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index bf454752..4c3a9c9c 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -2810,6 +2810,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/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index ae0692f0..5d2a826e 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -88,6 +88,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 |