summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2009-04-21 20:01:00 +0200
committerMark Wielaard <mjw@redhat.com>2009-04-21 20:01:00 +0200
commit192d5136bbfcd1e61c2f17cc52df875a954d24ec (patch)
tree27dd76c7386e5b8d177756ad8175e5b700f8541a
parent41d9243cc9d107d1980e18537090ed358dc7920a (diff)
parent7d7f074398802c84f544e263995ce15874b9f408 (diff)
downloadsystemtap-steved-192d5136bbfcd1e61c2f17cc52df875a954d24ec.tar.gz
systemtap-steved-192d5136bbfcd1e61c2f17cc52df875a954d24ec.tar.xz
systemtap-steved-192d5136bbfcd1e61c2f17cc52df875a954d24ec.zip
Merge branch 'user_unwind'
-rw-r--r--runtime/stack-arm.c3
-rw-r--r--runtime/stack-i386.c25
-rw-r--r--runtime/stack-ia64.c3
-rw-r--r--runtime/stack-ppc64.c3
-rw-r--r--runtime/stack-s390.c3
-rw-r--r--runtime/stack-x86_64.c23
-rw-r--r--runtime/stack.c34
-rw-r--r--runtime/sym.c31
-rw-r--r--runtime/unwind.c22
-rw-r--r--tapset/context-symbols.stp4
-rw-r--r--tapset/context-unwind.stp4
-rw-r--r--tapset/ucontext-symbols.stp27
-rw-r--r--tapset/ucontext-unwind.stp52
-rwxr-xr-xtestsuite/buildok/ustack.stp10
-rw-r--r--testsuite/systemtap.base/uprobes_ustack.exp94
-rw-r--r--testsuite/systemtap.base/uprobes_ustack.stp35
-rw-r--r--testsuite/systemtap.context/backtrace.tcl1
17 files changed, 311 insertions, 63 deletions
diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c
index 9b0b772d..fcff0a3b 100644
--- a/runtime/stack-arm.c
+++ b/runtime/stack-arm.c
@@ -31,7 +31,8 @@ static int __init find_str_pc_offset(void)
}
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
#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 5a18c9d8..69623765 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -23,14 +23,15 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
/* cannot access stack. give up. */
return;
}
- if (_stp_func_print(addr, verbose, 0))
+ if (_stp_func_print(addr, verbose, 0, NULL))
levels--;
stack++;
}
}
#endif
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long context = (unsigned long)&REG_SP(regs) & ~(THREAD_SIZE - 1);
@@ -43,7 +44,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
/* cannot access stack. give up. */
return;
}
- _stp_func_print(addr, verbose, 1);
+ _stp_func_print(addr, verbose, 1, NULL);
if (unlikely(_stp_read_address(next_fp, (unsigned long *)fp, KERNEL_DS))) {
/* cannot access stack. give up. */
return;
@@ -60,19 +61,23 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
- while (levels && !arch_unw_user_mode(&info)) {
- int ret = unwind(&info);
+ while (levels && (tsk || !arch_unw_user_mode(&info))) {
+ int ret = unwind(&info, tsk);
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);
+ _stp_func_print(UNW_PC(&info), verbose, 1, tsk);
levels--;
continue;
}
- /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */
- /* FIXME: is there a way to unwind across kretprobe trampolines? */
- if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ /* If an error happened or we hit a kretprobe trampoline,
+ * use fallback backtrace, unless user task backtrace.
+ * FIXME: is there a way to unwind across kretprobe
+ * trampolines? */
+ if ((ret < 0
+ || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ && ! (tsk || arch_unw_user_mode(&info)))
_stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
- break;
+ return;
}
#else /* ! STP_USE_DWARF_UNWINDER */
_stp_stack_print_fallback((unsigned long)&REG_SP(regs), verbose, levels);
diff --git a/runtime/stack-ia64.c b/runtime/stack-ia64.c
index ca9d25a6..a04355fa 100644
--- a/runtime/stack-ia64.c
+++ b/runtime/stack-ia64.c
@@ -48,7 +48,8 @@ static void __stp_show_stack_addr(struct unw_frame_info *info, void *arg)
} while (unw_unwind(info) >= 0);
}
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long *stack = (unsigned long *)&REG_SP(regs);
struct dump_para para;
diff --git a/runtime/stack-ppc64.c b/runtime/stack-ppc64.c
index 3dc38526..3267194e 100644
--- a/runtime/stack-ppc64.c
+++ b/runtime/stack-ppc64.c
@@ -7,7 +7,8 @@
* later version.
*/
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long ip, newsp, lr = 0;
int count = 0;
diff --git a/runtime/stack-s390.c b/runtime/stack-s390.c
index c9654102..14e9b7d8 100644
--- a/runtime/stack-s390.c
+++ b/runtime/stack-s390.c
@@ -66,7 +66,8 @@ __stp_show_stack (unsigned long sp, unsigned long low,
}
static void __stp_stack_print (struct pt_regs *regs,
- int verbose, int levels)
+ int verbose, int levels,
+ struct task_struct *tsk)
{
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 03d88ef0..9afdf38a 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -19,7 +19,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
/* cannot access stack. give up. */
return;
}
- if (_stp_func_print(addr, verbose, 0))
+ if (_stp_func_print(addr, verbose, 0, NULL))
levels--;
stack++;
}
@@ -27,26 +27,31 @@ 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)
+static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
#ifdef STP_USE_DWARF_UNWINDER
// FIXME: large stack allocation
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
- while (levels && !arch_unw_user_mode(&info)) {
- int ret = unwind(&info);
+ while (levels && (tsk || !arch_unw_user_mode(&info))) {
+ int ret = unwind(&info, tsk);
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);
+ _stp_func_print(UNW_PC(&info), verbose, 1, tsk);
levels--;
continue;
}
- /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */
- /* FIXME: is there a way to unwind across kretprobe trampolines? */
- if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ /* If an error happened or we hit a kretprobe trampoline,
+ * use fallback backtrace, unless user task backtrace.
+ * FIXME: is there a way to unwind across kretprobe
+ * trampolines? */
+ if ((ret < 0
+ || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ && ! (tsk || arch_unw_user_mode(&info)))
_stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
- break;
+ return;
}
#else /* ! STP_USE_DWARF_UNWINDER */
_stp_stack_print_fallback(REG_SP(regs), verbose, levels);
diff --git a/runtime/stack.c b/runtime/stack.c
index 68fb9b1f..042f44c7 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* Stack tracing functions
- * Copyright (C) 2005-2008 Red Hat Inc.
+ * Copyright (C) 2005-2009 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
*
* This file is part of systemtap, and is free software. You can
@@ -77,7 +77,7 @@ static void print_stack_address(void *data, unsigned long addr, int reliable)
{
struct print_stack_data *sdata = data;
if (sdata->level++ < sdata->max_level)
- _stp_func_print(addr,sdata->verbose, 0);
+ _stp_func_print(addr, sdata->verbose, 0, NULL);
}
static const struct stacktrace_ops print_stack_ops = {
@@ -107,7 +107,7 @@ 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)
+static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
{
if (verbose) {
/* print the current address */
@@ -118,7 +118,10 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
} else {
_stp_print_char(' ');
- _stp_symbol_print(REG_IP(regs));
+ if (tsk)
+ _stp_usymbol_print(REG_IP(regs), tsk);
+ else
+ _stp_symbol_print(REG_IP(regs));
}
_stp_print_char('\n');
} else if (pi)
@@ -126,7 +129,7 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
else
_stp_printf("%p ", (int64_t) REG_IP(regs));
- __stp_stack_print(regs, verbose, levels);
+ __stp_stack_print(regs, verbose, levels, tsk);
}
/** Writes stack backtrace to a string
@@ -135,37 +138,20 @@ 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)
+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)
{
/* 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);
+ _stp_stack_print(regs, verbose, pi, levels, tsk);
strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
pb->len = 0;
}
#endif /* CONFIG_KPROBES */
-/** Prints the user stack backtrace
- * @param str string
- * @returns Same string as was input with trace info appended,
- * @note Currently limited to a depth of two. Works from jprobes and kprobes.
- */
-#if 0
-static void _stp_ustack_print(char *str)
-{
- struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1;
- _stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs));
- if (REG_SP(nregs))
- _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
-}
-#endif /* 0 */
-
-/** @} */
-
void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
{
#if defined(STAPCONF_KERNEL_STACKTRACE)
diff --git a/runtime/sym.c b/runtime/sym.c
index f6f97ac2..013edd0c 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -329,8 +329,35 @@ static void _stp_symbol_print(unsigned long address)
}
}
+/** Print an user space address from a specific task symbolically.
+ * @param address The address to lookup.
+ * @param task The address to lookup.
+ * @note Symbolic lookups should not normally be done within
+ * a probe because it is too time-consuming. Use at module exit time.
+ */
+
+static void _stp_usymbol_print(unsigned long address, struct task_struct *task)
+{
+ const char *modname;
+ const char *name;
+ unsigned long offset, size;
+
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL,
+ task);
+
+ _stp_printf("%p", (int64_t) address);
+
+ if (name) {
+ if (modname && *modname)
+ _stp_printf(" : %s+%#lx/%#lx [%s]", name, offset, size, modname);
+ else
+ _stp_printf(" : %s+%#lx/%#lx", name, offset, size);
+ }
+}
+
/* Like _stp_symbol_print, except only print if the address is a valid function address */
-static int _stp_func_print(unsigned long address, int verbose, int exact)
+static int _stp_func_print(unsigned long address, int verbose, int exact,
+ struct task_struct *task)
{
const char *modname;
const char *name;
@@ -342,7 +369,7 @@ static int _stp_func_print(unsigned long address, int verbose, int exact)
else
exstr = " (inexact)";
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, task);
if (name) {
if (verbose) {
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 41af72a7..aacd56f1 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -435,12 +435,18 @@ adjustStartLoc (unsigned long startLoc,
struct _stp_module *m,
struct _stp_section *s)
{
- if (startLoc && (strcmp (m->name, "kernel") != 0))
- {
- startLoc = _stp_module_relocate (m->name, s->name,
- startLoc);
- startLoc -= m->dwarf_module_base;
- }
+ /* XXX - some, or all, of this should really be done by
+ _stp_module_relocate. */
+ if (startLoc == 0
+ || strcmp (m->name, "kernel") == 0
+ || strcmp (s->name, ".absolute") == 0)
+ return startLoc;
+
+ if (strcmp (s->name, ".dynamic") == 0)
+ return startLoc + s->addr;
+
+ startLoc = _stp_module_relocate (m->name, s->name, startLoc);
+ startLoc -= m->dwarf_module_base;
return startLoc;
}
@@ -562,7 +568,7 @@ static char *_stp_eh_enc_name(signed type)
/* Unwind to previous to frame. Returns 0 if successful, negative
* number in case of an error. A positive return means unwinding is finished;
* don't try to fallback to dumping addresses on the stack. */
-static int unwind(struct unwind_frame_info *frame)
+static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
const u32 *fde, *cie = NULL;
@@ -581,7 +587,7 @@ static int unwind(struct unwind_frame_info *frame)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = _stp_mod_sec_lookup (pc, current, &s);
+ m = _stp_mod_sec_lookup (pc, tsk, &s);
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
diff --git a/tapset/context-symbols.stp b/tapset/context-symbols.stp
index 783f1b7b..e4406d9b 100644
--- a/tapset/context-symbols.stp
+++ b/tapset/context-symbols.stp
@@ -16,10 +16,10 @@
#define STP_NEED_SYMBOL_DATA 1
#endif
%}
-// weirdness with print_stack, argument appears in build as undescribed
+
/**
* sfunction print_stack - Print out stack from string.
- * @stk: String with list of hexidecimal addresses. (FIXME)
+ * @stk: String with list of hexidecimal addresses.
*
* Perform a symbolic lookup of the addresses in the given string,
* which is assumed to be the result of a prior call to
diff --git a/tapset/context-unwind.stp b/tapset/context-unwind.stp
index b3d19e29..f1e99dc8 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);
+ _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE, 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);
+ _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE, NULL);
else
strlcpy (THIS->__retvalue, "", MAXSTRINGLEN);
%}
diff --git a/tapset/ucontext-symbols.stp b/tapset/ucontext-symbols.stp
index 3813a8bf..5502f5cd 100644
--- a/tapset/ucontext-symbols.stp
+++ b/tapset/ucontext-symbols.stp
@@ -23,7 +23,7 @@
%}
/**
- * sfunction usymname - Return the symbol of an address in the current task.
+ * sfunction usymname - Return the symbol of an address in the current task. EXPERIMENTAL!
* @addr: The address to translate.
*
* Description: Returns the (function) symbol name associated with the
@@ -36,7 +36,7 @@ function usymname:string (addr: long) %{ /* pure */
%}
/**
- * sfunction usymdata - Return the symbol and module offset of an address.
+ * sfunction usymdata - Return the symbol and module offset of an address. EXPERIMENTAL!
* @addr: The address to translate.
*
* Description: Returns the (function) symbol name associated with the
@@ -50,3 +50,26 @@ function usymdata:string (addr: long) %{ /* pure */
_stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, THIS->addr,
current, 1);
%}
+
+/**
+ * sfunction print_ustack - Print out stack for the current task from string. EXPERIMENTAL!
+ * @stk: String with list of hexidecimal addresses for the current task.
+ *
+ * Perform a symbolic lookup of the addresses in the given string,
+ * which is assumed to be the result of a prior call to
+ * <command>ubacktrace()</command> for the current task.
+ *
+ * Print one line per address, including the address, the
+ * name of the function containing the address, and an estimate of
+ * its position within that function. Return nothing.
+ */
+function print_ustack(stk:string) %{
+ char *ptr = THIS->stk;
+ char *tok = strsep(&ptr, " ");
+ while (tok && *tok) {
+ _stp_print_char(' ');
+ _stp_usymbol_print (simple_strtol(tok, NULL, 16), current);
+ _stp_print_char('\n');
+ tok = strsep(&ptr, " ");
+ }
+%}
diff --git a/tapset/ucontext-unwind.stp b/tapset/ucontext-unwind.stp
new file mode 100644
index 00000000..0801f1c9
--- /dev/null
+++ b/tapset/ucontext-unwind.stp
@@ -0,0 +1,52 @@
+// User context unwind tapset
+// Copyright (C) 2009 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+%{
+#ifndef STP_NEED_UNWIND_DATA
+#define STP_NEED_UNWIND_DATA 1
+#endif
+#ifndef STP_NEED_SYMBOL_DATA
+#define STP_NEED_SYMBOL_DATA 1
+#endif
+#ifndef STP_NEED_VMA_TRACKER
+#define STP_NEED_VMA_TRACKER 1
+#endif
+%}
+
+/**
+ * sfunction print_ubacktrace - Print stack back trace for current task. EXPERIMENTAL!
+ *
+ * Equivalent to <command>print_ustack(ubacktrace())</command>,
+ * except that deeper stack nesting may be supported. Return nothing.
+ */
+function print_ubacktrace () %{
+ if (CONTEXT->regs) {
+ _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE,
+ current);
+ } else {
+ _stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point);
+ }
+%}
+
+/**
+ * sfunction ubacktrace - Hex backtrace of current task stack. EXPERIMENTAL!
+ *
+ * Return a string of hex addresses that are a backtrace of the
+ * stack of the current task. Output may be truncated as per maximum
+ * string length. Returns empty string when current probe point cannot
+ * determine user backtrace.
+ */
+
+function ubacktrace:string () %{ /* pure */
+ if (CONTEXT->regs)
+ _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN,
+ CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE,
+ current);
+ else
+ strlcpy (THIS->__retvalue, "", MAXSTRINGLEN);
+%}
diff --git a/testsuite/buildok/ustack.stp b/testsuite/buildok/ustack.stp
new file mode 100755
index 00000000..23af0bff
--- /dev/null
+++ b/testsuite/buildok/ustack.stp
@@ -0,0 +1,10 @@
+#! stap -p4
+#
+# Test the translatability for ubacktrace(), print_ustack()
+# and print_ubacktrace()
+#
+probe begin
+{
+ print_ustack(ubacktrace());
+ print_ubacktrace();
+}
diff --git a/testsuite/systemtap.base/uprobes_ustack.exp b/testsuite/systemtap.base/uprobes_ustack.exp
new file mode 100644
index 00000000..f085fc16
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_ustack.exp
@@ -0,0 +1,94 @@
+set test "uprobes_ustack"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/uprobes_exe.c"
+set testsrclib "$testpath/uprobes_lib.c"
+set testexe "./uprobes_exe"
+set testlibname "uprobes_lib"
+set testlibdir "."
+set testso "$testlibdir/lib${testlibname}.so"
+set testflags "additional_flags=-g additional_flags=-O"
+set testlibflags "$testflags additional_flags=-fPIC additional_flags=-shared"
+set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
+
+# Compile our test program and library.
+set res [target_compile $testsrclib $testso executable $testlibflags]
+if { $res != "" } {
+ verbose "target_compile for $testso failed: $res" 2
+ fail "$test compile $testsrclib"
+ return
+} else {
+ pass "$test compile $testsrclib"
+}
+
+set res [target_compile $testsrc $testexe executable $maintestflags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "$test compile $testsrc"
+ return
+} else {
+ pass "$test compile $testsrc"
+}
+
+set ::result_string {exe: main=main
+exe: main_func=main_func
+exe: main_func=main_func
+exe: main_func=main_func
+lib: lib_main=lib_main
+lib: lib_func=lib_func
+lib: lib_func=lib_func
+lib: lib_func=lib_func}
+
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test"; return }
+if {! [utrace_p]} { untested $test; return }
+
+# Output is:
+#print_ubacktrace exe 0
+# 0x080484ba : main_func+0xa/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+#print_ustack exe 1
+# 0x080484ba : main_func+0xa/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+#print_ubacktrace lib 2
+# 0x00db2422 : lib_func+0x16/0x2b [.../libuprobes_lib.so]
+# 0x00db2455 : lib_main+0x1e/0x29 [.../libuprobes_lib.so]
+# 0x080484d0 : main_func+0x20/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+#print_ustack lib 3
+# 0x00db2422 : lib_func+0x16/0x2b [.../libuprobes_lib.so]
+# 0x00db2431 : lib_func+0x25/0x2b [.../libuprobes_lib.so]
+# 0x00db2455 : lib_main+0x1e/0x29 [.../libuprobes_lib.so]
+# 0x080484d0 : main_func+0x20/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+
+set print 0
+set main 0
+set main_func 0
+set lib_main 0
+set lib_func 0
+spawn stap $srcdir/$subdir/$test.stp -c $testexe
+
+wait
+expect {
+ -timeout 60
+ -re {^print_[^\r\n]+\r\n} {incr print; exp_continue}
+ -re {^ 0x[a-f0-9]+ : main\+0x[^\r\n]+\r\n} {incr main; exp_continue}
+ -re {^ 0x[a-f0-9]+ : main_func\+0x[^\r\n]+\r\n} {incr main_func; exp_continue}
+ -re {^ 0x[a-f0-9]+ : lib_main\+0x[^\r\n]+\r\n} {incr lib_main; exp_continue}
+ -re {^ 0x[a-f0-9]+ : lib_func\+0x[^\r\n]+\r\n} {incr lib_func; exp_continue}
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+
+if {$print == 4} {pass "$test print"} {fail "$test print ($print)"}
+if {$main == 4} {pass "$test main"} {fail "$test main ($main)"}
+if {$main_func == 9} {pass "$test main_func"} {fail "$test main_func ($main_func)"}
+if {$lib_main == 2} {pass "$test lib_main"} {fail "$test lib_main ($lib_main)"}
+if {$lib_func == 3} {pass "$test lib_func"} {fail "$test lib_func ($lib_func)"}
+
+#exec rm -f $testexe $testso
diff --git a/testsuite/systemtap.base/uprobes_ustack.stp b/testsuite/systemtap.base/uprobes_ustack.stp
new file mode 100644
index 00000000..6de03b42
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_ustack.stp
@@ -0,0 +1,35 @@
+// Prints backtrace from lib through exe twice using diffent ustack functions.
+
+global hits = 0;
+
+probe process("uprobes_exe").function("main_func")
+{
+ if (hits == 0)
+ {
+ log("print_ubacktrace exe 0");
+ print_ubacktrace();
+ hits++;
+ }
+ else if (hits == 1)
+ {
+ log("print_ustack exe 1");
+ print_ustack(ubacktrace());
+ hits++;
+ }
+}
+
+probe process("libuprobes_lib.so").function("lib_func")
+{
+ if (hits == 2)
+ {
+ log("print_ubacktrace lib 2");
+ print_ubacktrace();
+ hits++;
+ }
+ else if (hits == 3)
+ {
+ log("print_ustack lib 3");
+ print_ustack(ubacktrace());
+ hits++;
+ }
+}
diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl
index 6edda812..975e6c4d 100644
--- a/testsuite/systemtap.context/backtrace.tcl
+++ b/testsuite/systemtap.context/backtrace.tcl
@@ -5,6 +5,7 @@ set m4 0
set m5 0
set m6 0
+#spawn stap -d kernel -d systemtap_test_module1 -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp
spawn stap -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp
#exp_internal 1
expect {