diff options
-rw-r--r-- | runtime/runtime.h | 21 | ||||
-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 | 27 | ||||
-rw-r--r-- | runtime/sym.c | 24 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 38 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 8 | ||||
-rw-r--r-- | tapset/context-unwind.stp | 4 | ||||
-rw-r--r-- | tapset/ucontext-unwind.stp | 22 | ||||
-rw-r--r-- | tapsets.cxx | 49 | ||||
-rw-r--r-- | testsuite/systemtap.context/fib.c | 31 | ||||
-rw-r--r-- | testsuite/systemtap.context/fib.exp | 37 | ||||
-rw-r--r-- | testsuite/systemtap.context/fib.stp | 17 | ||||
-rw-r--r-- | testsuite/systemtap.context/uprobe_backtrace.stp | 31 | ||||
-rw-r--r-- | testsuite/systemtap.context/uprobe_uaddr.exp | 58 | ||||
-rw-r--r-- | testsuite/systemtap.context/uprobe_uaddr.stp | 24 | ||||
-rw-r--r-- | translate.cxx | 3 |
20 files changed, 384 insertions, 44 deletions
diff --git a/runtime/runtime.h b/runtime/runtime.h index ba583aeb..0fd2a380 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -31,6 +31,17 @@ #include <linux/sched.h> #include <linux/mm.h> +/* If uprobes isn't in the kernel, pull it in from the runtime. */ +#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE) +#include <linux/uprobes.h> +#else +#include "uprobes/uprobes.h" +#endif +#ifndef UPROBES_API_VERSION +#define UPROBES_API_VERSION 1 +#endif + + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) #if !defined (CONFIG_DEBUG_FS) && !defined (CONFIG_DEBUG_FS_MODULE) #error "DebugFS is required and was not found in the kernel." @@ -115,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 25dbdbbd..3d907a7f 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -107,15 +107,25 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve * @param regs A pointer to the struct pt_regs. */ -static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk) +static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk, struct uretprobe_instance *ri) { 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) { + 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) @@ -123,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 @@ -138,14 +149,14 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe * @param regs A pointer to the struct pt_regs. * @returns void */ -static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk) +static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk, struct uretprobe_instance *ri) { /* To get a string, we use a simple trick. First flush the print buffer, */ /* then call _stp_stack_print, then copy the result into the output string */ /* and clear the print buffer. */ _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id()); _stp_print_flush(); - _stp_stack_print(regs, verbose, pi, levels, tsk); + _stp_stack_print(regs, verbose, pi, levels, tsk, ri); strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len); pb->len = 0; } 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 diff --git a/tapset/context-unwind.stp b/tapset/context-unwind.stp index 741031c0..8f35a783 100644 --- a/tapset/context-unwind.stp +++ b/tapset/context-unwind.stp @@ -28,7 +28,7 @@ */ function print_backtrace () %{ if (CONTEXT->regs) { - _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE, NULL); + _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE, NULL, NULL); } else { _stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point); } @@ -42,7 +42,7 @@ function print_backtrace () %{ */ function backtrace:string () %{ /* pure */ if (CONTEXT->regs) - _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE, NULL); + _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE, NULL, NULL); else strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); %} diff --git a/tapset/ucontext-unwind.stp b/tapset/ucontext-unwind.stp index d699e588..399ce0c5 100644 --- a/tapset/ucontext-unwind.stp +++ b/tapset/ucontext-unwind.stp @@ -28,7 +28,25 @@ function print_ubacktrace () %{ /* unprivileged */ assert_is_myproc(); if (CONTEXT->regs) { _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE, - current); + current, CONTEXT->ri); + } else { + _stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point); + } +%} + +/** + * sfunction print_ubacktrace_brief- Print stack back trace for current task. EXPERIMENTAL! + * + * Equivalent to print_ubacktrace(), but output for each symbol is + * shorter (just name and offset), and the function address is + * printed if it can't be mapped to a name. + */ + +function print_ubacktrace_brief () %{ /* unprivileged */ + assert_is_myproc(); + if (CONTEXT->regs) { + _stp_stack_print(CONTEXT->regs, SYM_VERBOSE_BRIEF, CONTEXT->pi, + MAXTRACE, current, CONTEXT->ri); } else { _stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point); } @@ -47,7 +65,7 @@ function ubacktrace:string () %{ /* pure */ /* unprivileged */ if (CONTEXT->regs) _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE, - current); + current, CONTEXT->ri); else strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); %} diff --git a/tapsets.cxx b/tapsets.cxx index 555a6587..5729757b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -142,6 +142,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "#ifdef STP_TIMING"; o->newline() << "c->statp = 0;"; o->newline() << "#endif"; + o->newline() << "c->ri = 0;"; // NB: The following would actually be incorrect. // That's because cycles_sum/cycles_base values are supposed to survive // between consecutive probes. Periodically (STP_OVERLOAD_INTERVAL @@ -3373,8 +3374,15 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "{"; s.op->indent(1); s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "if (entry) {"; + s.op->indent(1); s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->rp->kp.addr);"; - s.op->newline() << "(entry ? sdp->entry_ph : sdp->ph) (c);"; + s.op->newline() << "(sdp->entry_ph) (c);"; + s.op->newline(-1) << "} else {"; + s.op->indent(1); + s.op->newline() << "SET_REG_IP(regs, (unsigned long)inst->ret_addr);"; + s.op->newline() << "(sdp->ph) (c);"; + s.op->newline(-1) << "}"; s.op->newline() << "SET_REG_IP(regs, kprobes_ip);"; s.op->newline(-1) << "}"; @@ -3711,6 +3719,22 @@ sdt_query::handle_query_module() && !probes_handled.insert(probe_name).second) continue; + if (sess.verbose > 3) + { + clog << "matched probe_name " << probe_name << " probe_type "; + switch (probe_type) + { + case uprobe_type: + clog << "uprobe at 0x" << hex << probe_arg << dec << endl; + break; + case kprobe_type: + clog << "kprobe" << endl; + break; + case utrace_type: + clog << "utrace" << endl; + break; + } + } probe *new_base = new probe(*base_probe); probe_point *new_location = new probe_point(*base_loc); convert_location(new_base, new_location); @@ -3873,12 +3897,7 @@ sdt_query::get_next_probe() if ((mark_name == probe_name) || (dw.name_has_wildcard (mark_name) && dw.function_name_matches_pattern (probe_name, mark_name))) - { - if (sess.verbose > 3) - clog << "found probe_name" << probe_name << " at 0x" - << hex << probe_arg << dec << endl; - return true; - } + return true; else continue; } @@ -4016,8 +4035,7 @@ sdt_query::convert_location (probe *base, probe_point *location) clog << "probe_type == uprobe_type, use statement addr: 0x" << hex << probe_arg << dec << endl; // process("executable").statement(probe_arg) - location->components[i]->functor = TOK_STATEMENT; - location->components[i]->arg = new literal_number(probe_arg); + location->components[i] = new probe_point::component(TOK_STATEMENT, new literal_number(probe_arg)); break; case kprobe_type: @@ -4559,16 +4577,6 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) if (probes.empty()) return; s.op->newline() << "/* ---- user probes ---- */"; - // If uprobes isn't in the kernel, pull it in from the runtime. - s.op->newline() << "#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE)"; - s.op->newline() << "#include <linux/uprobes.h>"; - s.op->newline() << "#else"; - s.op->newline() << "#include \"uprobes/uprobes.h\""; - s.op->newline() << "#endif"; - s.op->newline() << "#ifndef UPROBES_API_VERSION"; - s.op->newline() << "#define UPROBES_API_VERSION 1"; - s.op->newline() << "#endif"; - // We'll probably need at least this many: unsigned minuprobes = probes.size(); // .. but we don't want so many that .bss is inflated (PR10507): @@ -4713,6 +4721,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst->rp, struct stap_uprobe, urp);"; s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sups->pp"); + s.op->newline() << "c->ri = inst;"; s.op->newline() << "if (sup->spec_index < 0 ||" << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen // XXX: kretprobes saves "c->pi = inst;" too @@ -4724,7 +4733,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "{"; s.op->indent(1); s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->regs);"; - s.op->newline() << "SET_REG_IP(regs, inst->rp->u.vaddr);"; + s.op->newline() << "SET_REG_IP(regs, inst->ret_addr);"; s.op->newline() << "(*sups->ph) (c);"; s.op->newline() << "SET_REG_IP(regs, uprobes_ip);"; s.op->newline(-1) << "}"; diff --git a/testsuite/systemtap.context/fib.c b/testsuite/systemtap.context/fib.c new file mode 100644 index 00000000..61fee0a7 --- /dev/null +++ b/testsuite/systemtap.context/fib.c @@ -0,0 +1,31 @@ +#include <stdlib.h> +#include <stdio.h> + +long fib(int x) +{ + if (x == 0 || x == 1) + return 1; + else + return fib(x - 1) + fib(x - 2); +} + +int main(int argc, char **argv) +{ + int x = 0; + long result = 0; + + if (argc != 2) + { + printf("0\n"); + return 1; + } + x = atoi(argv[1]); + if (x < 0) + { + printf("0\n"); + return 1; + } + result = fib(x); + printf("%ld\n", result); + return 0; +} diff --git a/testsuite/systemtap.context/fib.exp b/testsuite/systemtap.context/fib.exp new file mode 100644 index 00000000..cc4d75a1 --- /dev/null +++ b/testsuite/systemtap.context/fib.exp @@ -0,0 +1,37 @@ +# Tests backtrace in the classic Fibonacci program + + +set test "fib" + +# Only run on make installcheck and utrace present. +if {! [installtest_p]} { untested "$test"; return } +if {! [utrace_p]} { untested "$test"; return } + +set testpath "$srcdir/$subdir" +set testsrc "$testpath/fib.c" +set testexe "[pwd]/$test" + +# We want debug info and no optimization (is that totally necessary?) +set testflags "additional_flags=-g additional_flags=-O0" +set teststp "$testpath/$test.stp" + +set res [target_compile $testsrc $testexe executable $testflags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "unable to compile $testsrc" + return +} + +spawn stap -c "$testexe 10" $teststp +set fibcalls 0 +set maincalls 0 +expect { + -timeout 120 + -re {^fib[^\r\n]*[\r\n]} { incr fibcalls; exp_continue } + -re {^main[^\r\n]*[\r\n]} { incr maincalls; exp_continue } + -re {^[^\r\n]*[\r\n]} {exp_continue} + timeout { fail "$test (timeout)" } + eof { } +} +wait +if {$fibcalls == 18 && $maincalls == 2} { pass "$test ($fibcalls $maincalls)" } { fail "$test ($fibcalls $maincalls)" } diff --git a/testsuite/systemtap.context/fib.stp b/testsuite/systemtap.context/fib.stp new file mode 100644 index 00000000..85c2fc1d --- /dev/null +++ b/testsuite/systemtap.context/fib.stp @@ -0,0 +1,17 @@ +global depth = 0 +global max_depth = 0 + +probe process("fib").function("fib").call { + depth++ + if (depth > max_depth) { + max_depth = depth + } +} + +probe process("fib").function("fib").return { + if (depth == max_depth) { + print_ubacktrace_brief() + printf("\n") + } + depth-- +} diff --git a/testsuite/systemtap.context/uprobe_backtrace.stp b/testsuite/systemtap.context/uprobe_backtrace.stp new file mode 100644 index 00000000..6d6fe3f7 --- /dev/null +++ b/testsuite/systemtap.context/uprobe_backtrace.stp @@ -0,0 +1,31 @@ +probe process("uprobe_uaddr").function("main").call { + print_ubacktrace() + printf("\n") +} + +probe process("uprobe_uaddr").function("main").return { + print_ubacktrace() + printf("\n") +} + +probe process("uprobe_uaddr").function("func").call { + print_ubacktrace() + printf("\n") +} + +probe process("uprobe_uaddr").function("func").return { + print_ubacktrace() + printf("\n") +} + + +probe process("uprobe_uaddr").function("func2").call { + print_ubacktrace() + printf("\n") +} + + +probe process("uprobe_uaddr").function("func2").return { + print_ubacktrace() + printf("\n") +} diff --git a/testsuite/systemtap.context/uprobe_uaddr.exp b/testsuite/systemtap.context/uprobe_uaddr.exp new file mode 100644 index 00000000..521dfa57 --- /dev/null +++ b/testsuite/systemtap.context/uprobe_uaddr.exp @@ -0,0 +1,58 @@ +# Tests uaddr in function call and return probes. For a call probe we +# expect the address to be in the function; for a return probe it +# should be in the function's caller. + +set test "uprobe_uaddr" + +# Only run on make installcheck and utrace present. +if {! [installtest_p]} { untested "$test"; return } +if {! [utrace_p]} { untested "$test"; return } + +set testpath "$srcdir/$subdir" +set testsrc "$testpath/uprobe_stmt_num.c" +set testexe "[pwd]/$test" + +# We want debug info and no optimization (every line counts). +set testflags "additional_flags=-g additional_flags=-O0" +set teststp "$testpath/$test.stp" + +set res [target_compile $testsrc $testexe executable $testflags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "unable to compile $testsrc" + return +} + +set cmd [concat stap -c $testexe $teststp] +send_log "cmd: $cmd\n" +catch {eval exec $cmd} output +send_log "cmd output:\n $output\n" + +set output_lines [split $output "\n"] + +set lines [llength $output_lines] +if { $lines == 6 } { + pass "$test" +} else { + fail "$test ($lines)" +} + +set result_funcs [list "main *" "func *" "func2 *" "func *" "main *"] + +foreach expected $result_funcs output $output_lines { + if {$expected != ""} { + if [string match $expected $output] { + pass "$test" + } else { + fail "$test $output" + } + } else { + break; + } +} + +if [string match "main *" [lindex $output_lines 5]] { + fail "$test return from main" +} else { + pass "$test" +} diff --git a/testsuite/systemtap.context/uprobe_uaddr.stp b/testsuite/systemtap.context/uprobe_uaddr.stp new file mode 100644 index 00000000..1528e559 --- /dev/null +++ b/testsuite/systemtap.context/uprobe_uaddr.stp @@ -0,0 +1,24 @@ +probe process("uprobe_uaddr").function("main").call { + println(usymdata(uaddr())) +} + +probe process("uprobe_uaddr").function("main").return { + println(usymdata(uaddr())) +} + +probe process("uprobe_uaddr").function("func").call { + println(usymdata(uaddr())) +} + +probe process("uprobe_uaddr").function("func").return { + println(usymdata(uaddr())) +} + +probe process("uprobe_uaddr").function("func2").call { + println(usymdata(uaddr())) +} + +probe process("uprobe_uaddr").function("func2").return { + println(usymdata(uaddr())) +} + diff --git a/translate.cxx b/translate.cxx index aca0d868..8c624a2f 100644 --- a/translate.cxx +++ b/translate.cxx @@ -905,6 +905,7 @@ c_unparser::emit_common_header () o->newline() << "cycles_t cycles_base;"; o->newline() << "cycles_t cycles_sum;"; o->newline() << "#endif"; + o->newline() << "struct uretprobe_instance *ri;"; // PR10516: probe locals @@ -1500,7 +1501,7 @@ c_unparser::emit_function (functiondecl* v) // or 0...N (if we're called from another function). Incoming parameters are already // stored in c->locals[c->nesting+1]. See also ::emit_common_header() for more. - o->newline() << "if (unlikely (c->nesting+1 > MAXNESTING)) {"; + o->newline() << "if (unlikely (c->nesting+1 >= MAXNESTING)) {"; o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";"; o->newline() << "return;"; o->newline(-1) << "} else {"; |