summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/runtime.h21
-rw-r--r--runtime/stack-arm.c2
-rw-r--r--runtime/stack-i386.c13
-rw-r--r--runtime/stack-ppc.c2
-rw-r--r--runtime/stack-s390.c3
-rw-r--r--runtime/stack-x86_64.c14
-rw-r--r--runtime/stack.c27
-rw-r--r--runtime/sym.c24
-rw-r--r--runtime/uprobes2/uprobes.c38
-rw-r--r--runtime/uprobes2/uprobes.h8
-rw-r--r--tapset/context-unwind.stp4
-rw-r--r--tapset/ucontext-unwind.stp22
-rw-r--r--tapsets.cxx49
-rw-r--r--testsuite/systemtap.context/fib.c31
-rw-r--r--testsuite/systemtap.context/fib.exp37
-rw-r--r--testsuite/systemtap.context/fib.stp17
-rw-r--r--testsuite/systemtap.context/uprobe_backtrace.stp31
-rw-r--r--testsuite/systemtap.context/uprobe_uaddr.exp58
-rw-r--r--testsuite/systemtap.context/uprobe_uaddr.stp24
-rw-r--r--translate.cxx3
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)&REG_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 *)&REG_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 {";