summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/stack-i386.c22
-rw-r--r--runtime/stack-x86_64.c17
-rw-r--r--runtime/stack.c22
-rw-r--r--runtime/sym.h1
-rw-r--r--runtime/transport/symbols.c2
-rw-r--r--runtime/unwind.c86
-rw-r--r--testsuite/systemtap.context/backtrace.stp27
-rw-r--r--testsuite/systemtap.context/backtrace.tcl123
8 files changed, 194 insertions, 106 deletions
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c
index a86f94be..d7c2c201 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -43,7 +43,10 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
#endif /* STAPCONF_X86_UNIREGS */
while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) {
- addr = *(unsigned long *)(ebp + 4);
+ if (unlikely(__stp_get_user(addr, (unsigned long *)(ebp + 4)))) {
+ /* cannot access stack. give up. */
+ return;
+ }
if (verbose) {
_stp_print_char(' ');
_stp_symbol_print (addr);
@@ -55,18 +58,19 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
#else
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
+
while (!arch_unw_user_mode(&info)) {
int ret = unwind(&info);
dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info));
- if (ret < 0) {
- _stp_stack_print_fallback(context, UNW_SP(&info), verbose);
- break;
+ if (ret == 0) {
+ _stp_func_print(UNW_PC(&info), verbose, 1);
+ continue;
}
- if (ret)
- break;
- _stp_func_print(UNW_PC(&info), verbose, 1);
+ /* 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))
+ _stp_stack_print_fallback(UNW_SP(&info), verbose);
+ break;
}
-// _stp_printf("***********************\n");
-// _stp_stack_print_fallback(context, (unsigned long)stack, verbose);
#endif /* CONFIG_FRAME_POINTER */
}
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c
index e2eb4aa2..846653be 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -8,13 +8,12 @@
* later version.
*/
-// todo: don't use unwinder for kernel if CONFIG_FRAME
+// todo: don't use unwinder for kernel if CONFIG_FRAME
/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */
static void _stp_stack_print_fallback(unsigned long stack, int verbose)
{
unsigned long addr;
-
while (stack & (THREAD_SIZE - 1)) {
if (unlikely(__stp_get_user(addr, (unsigned long *)stack))) {
/* cannot access stack. give up. */
@@ -33,12 +32,14 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels)
while (!arch_unw_user_mode(&info)) {
int ret = unwind(&info);
dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info));
- if (ret < 0) {
- _stp_stack_print_fallback(UNW_SP(&info), verbose);
- break;
+ if (ret == 0) {
+ _stp_func_print(UNW_PC(&info), verbose, 1);
+ continue;
}
- if (ret)
- break;
- _stp_func_print(UNW_PC(&info), verbose, 1);
+ /* 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))
+ _stp_stack_print_fallback(UNW_SP(&info), verbose);
+ break;
}
}
diff --git a/runtime/stack.c b/runtime/stack.c
index e338f587..eefdf715 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -58,12 +58,15 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
} else {
_stp_print_char(' ');
- _stp_symbol_print (REG_IP(regs));
+ _stp_symbol_print(REG_IP(regs));
}
_stp_print_char('\n');
- } else
- _stp_printf ("%p ", (int64_t)REG_IP(regs));
- __stp_stack_print (regs, verbose, 0);
+ } else if (pi)
+ _stp_printf("%p %p ", (int64_t) _stp_ret_addr_r(pi), (int64_t) REG_IP(regs));
+ else
+ _stp_printf("%p ", (int64_t) REG_IP(regs));
+
+ __stp_stack_print(regs, verbose, 0);
}
/** Writes stack backtrace to a string
@@ -72,7 +75,7 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan
* @param regs A pointer to the struct pt_regs.
* @returns void
*/
-void _stp_stack_snprint (char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi)
+void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi)
{
/* 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 */
@@ -84,19 +87,18 @@ void _stp_stack_snprint (char *str, int size, struct pt_regs *regs, int verbose,
pb->len = 0;
}
-
/** 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
-void _stp_ustack_print (char *str)
+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));
+ 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)));
+ _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
}
#endif /* 0 */
diff --git a/runtime/sym.h b/runtime/sym.h
index 631a5bbf..0bb64c13 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -84,6 +84,7 @@ struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES];
/* the number of modules in the arrays */
int _stp_num_modules = 0;
+static unsigned long _stp_kretprobe_trampoline = 0;
unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset);
static struct _stp_module *_stp_get_unwind_info (unsigned long addr);
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index a81e594f..83a3a635 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -200,6 +200,8 @@ static int _stp_init_kernel_symbols(void)
_stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext");
_stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text;
_stp_modules_by_addr[0] = _stp_modules[0];
+
+ _stp_kretprobe_trampoline = _stp_kallsyms_lookup_name("kretprobe_trampoline");
return 0;
}
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 483c9345..e8cba72e 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -321,7 +321,7 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy
return 0;
}
if ((ptrType & DW_EH_PE_indirect)
- && __stp_get_user(value, (unsigned long *)value))
+ && __stp_get_user(value, (unsigned long *)value))
return 0;
*pLoc = ptr.p8;
@@ -621,15 +621,62 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m)
return fde;
}
+#ifdef DEBUG_UNWIND
+static const char *_stp_enc_hi_name[] = {
+ "",
+ "DW_EH_PE_pcrel",
+ "DW_EH_PE_textrel",
+ "DW_EH_PE_datarel",
+ "DW_EH_PE_funcrel",
+ "DW_EH_PE_aligned"
+};
+static const char *_stp_enc_lo_name[] = {
+ "DW_EH_PE_absptr",
+ "DW_EH_PE_uleb128",
+ "DW_EH_PE_udata2",
+ "DW_EH_PE_udata4",
+ "DW_EH_PE_udata8",
+ "DW_EH_PE_sleb128",
+ "DW_EH_PE_sdata2",
+ "DW_EH_PE_sdata4",
+ "DW_EH_PE_sdata8"
+};
+char *_stp_eh_enc_name(signed type)
+{
+ static char buf[64];
+ int hi, low;
+ if (type == DW_EH_PE_omit)
+ return "DW_EH_PE_omit";
+
+ hi = (type & DW_EH_PE_ADJUST) >> 4;
+ low = type & DW_EH_PE_FORM;
+ if (hi > 5 || low > 4 || (low == 0 && (type & DW_EH_PE_signed))) {
+ sprintf(buf, "ERROR:encoding=0x%x", type);
+ return buf;
+ }
+
+ buf[0] = 0;
+ if (type & DW_EH_PE_indirect)
+ strlcpy(buf, "DW_EH_PE_indirect|", sizeof(buf));
+ if (hi)
+ strlcat(buf, _stp_enc_hi_name[hi], sizeof(buf));
+
+ if (type & DW_EH_PE_signed)
+ low += 4;
+ strlcat(buf, _stp_enc_lo_name[low], sizeof(buf));
+ return buf;
+}
+#endif /* DEBUG_UNWIND */
+
/* 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. */
+ * number in case of an error. A positive return means unwinding is finished;
+ * don't try to fallback to dumping addresses on the stack. */
int unwind(struct unwind_frame_info *frame)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
const u32 *fde, *cie = NULL;
const u8 *ptr = NULL, *end = NULL;
- unsigned long pc = UNW_PC(frame) - frame->call_frame;
+ unsigned long pc = UNW_PC(frame);
unsigned long tableSize, startLoc = 0, endLoc = 0, cfa;
unsigned i;
signed ptrType = -1;
@@ -637,6 +684,15 @@ int unwind(struct unwind_frame_info *frame)
struct _stp_module *m;
struct unwind_state state;
+ if (pc != _stp_kretprobe_trampoline)
+ pc -= frame->call_frame;
+ else {
+ unsigned long a1, a2, *addr = (unsigned long *)UNW_SP(frame);
+ __stp_get_user(a1, addr);
+ __stp_get_user(a2, addr+1);
+ dbug_unwind(1, "TRAMPOLINE: SP=%lx *SP=%lx *(SP+1)=%lx\n", UNW_SP(frame), a1, a2);
+ return -EINVAL;
+ }
dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame));
if (UNW_PC(frame) == 0)
@@ -659,16 +715,16 @@ int unwind(struct unwind_frame_info *frame)
/* found the fde, now set startLoc and endLoc */
if (fde != NULL) {
cie = cie_for_fde(fde, m);
- ptr = (const u8 *)(fde + 2);
if (likely(cie != NULL && cie != &bad_cie && cie != &not_fde)) {
+ ptr = (const u8 *)(fde + 2);
ptrType = fde_pointer_type(cie);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType));
if (!(ptrType & DW_EH_PE_indirect))
ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
if (pc > endLoc) {
- dbug_unwind(1, "pc (%lx) > endLoc(%x)\n", pc, endLoc);
- /* finished? */
+ dbug_unwind(1, "pc (%lx) > endLoc(%lx)\n", pc, endLoc);
goto done;
}
} else {
@@ -676,6 +732,8 @@ int unwind(struct unwind_frame_info *frame)
fde = NULL;
}
}
+
+ /* did not a good fde find with binary search, so do slow linear search */
if (fde == NULL) {
for (fde = m->unwind_data, tableSize = m->unwind_data_len; cie = NULL, tableSize > sizeof(*fde)
&& tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
@@ -690,13 +748,13 @@ int unwind(struct unwind_frame_info *frame)
ptr = (const u8 *)(fde + 2);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- dbug_unwind(3, "startLoc=%p\n", (u64)startLoc);
+ dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType));
if (!startLoc)
continue;
if (!(ptrType & DW_EH_PE_indirect))
ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- dbug_unwind(3, "endLoc=%p\n", (u64)endLoc);
+ dbug_unwind(3, "endLoc=%lx\n", endLoc);
if (pc >= startLoc && pc < endLoc)
break;
}
@@ -729,6 +787,7 @@ int unwind(struct unwind_frame_info *frame)
case 'R':
continue;
case 'S':
+ dbug_unwind(1, "This is a signal frame\n");
frame->call_frame = 0;
continue;
default:
@@ -785,7 +844,6 @@ int unwind(struct unwind_frame_info *frame)
goto err;
/* update frame */
- dbug_unwind(1, "cie=%lx fde=%lx\n", cie, fde);
#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
if (frame->call_frame && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
frame->call_frame = 0;
@@ -793,11 +851,11 @@ int unwind(struct unwind_frame_info *frame)
cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
startLoc = min((unsigned long)UNW_SP(frame), cfa);
endLoc = max((unsigned long)UNW_SP(frame), cfa);
- dbug_unwind(1, "cfa=%lx SP startLoc=%lx, endLoc=%lx\n", cfa, startLoc, endLoc);
+ dbug_unwind(1, "cfa=%lx startLoc=%lx, endLoc=%lx\n", cfa, startLoc, endLoc);
if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
startLoc = min(STACK_LIMIT(cfa), cfa);
endLoc = max(STACK_LIMIT(cfa), cfa);
- dbug_unwind(1, "SP startLoc=%p, endLoc=%p\n", (u64)startLoc, (u64)endLoc);
+ dbug_unwind(1, "cfa startLoc=%p, endLoc=%p\n", (u64)startLoc, (u64)endLoc);
}
#ifndef CONFIG_64BIT
# define CASES CASE(8); CASE(16); CASE(32)
@@ -898,7 +956,11 @@ copy_failed:
err:
read_unlock(&m->lock);
return -EIO;
+
done:
+ /* PC was in a range convered by a module but no unwind info */
+ /* found for the specific PC. This seems to happen only for kretprobe */
+ /* trampolines and at the end of interrupt backtraces. */
read_unlock(&m->lock);
return 1;
#undef CASES
diff --git a/testsuite/systemtap.context/backtrace.stp b/testsuite/systemtap.context/backtrace.stp
index c14d071c..ddd7d00a 100644
--- a/testsuite/systemtap.context/backtrace.stp
+++ b/testsuite/systemtap.context/backtrace.stp
@@ -1,10 +1,9 @@
-function print_all_trace_info(point:string) {
+function print_all_trace_info(point) {
printf("backtrace from %s:\n", pp())
print_backtrace()
- print("--------\n")
+ printf("--- %s ---\n", point)
bt = backtrace()
- printf("the %s stack is %s\n", point, bt)
- printf("--<%s>--\n", point)
+ printf("the stack is %s\n", bt)
print_stack(bt);
print("--------\n")
}
@@ -18,18 +17,20 @@ probe end {
}
global flag = 0
-probe module("systemtap_test_module2").function("yyy_func3").call {
- print_all_trace_info("call")
+
+probe module("systemtap_test_module2").function("yyy_func2") {
+ print_all_trace_info("yyy_func2")
flag ++
}
-probe module("systemtap_test_module2").function("yyy_func4").return {
- print_all_trace_info("return")
+
+probe module("systemtap_test_module2").function("yyy_func3") {
+ print_all_trace_info("yyy_func3")
flag ++
}
-probe timer.profile {
- if (cpu() == 0 && flag == 2 && probemod() != "systemtap_test_module2") {
- print_all_trace_info("profile")
- flag ++
- }
+
+probe module("systemtap_test_module2").function("yyy_func4") {
+ print_all_trace_info("yyy_func4")
+ flag ++
}
+
diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl
index f359cd41..6c8aee40 100644
--- a/testsuite/systemtap.context/backtrace.tcl
+++ b/testsuite/systemtap.context/backtrace.tcl
@@ -5,13 +5,7 @@ set m4 0
set m5 0
set m6 0
-if {[istarget ia64-*-*]} {
- set retexp {.*return\>--\r\n 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n}
-} else {
- set retexp {.*return\>--\r\n 0x[a-f0-9]+ : kretprobe_trampoline_holder[^\r\n]+\r\n}
-}
-
-spawn stap $srcdir/$subdir/backtrace.stp
+spawn stap -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp
#exp_internal 1
expect {
-timeout 240
@@ -20,69 +14,61 @@ expect {
exec echo 0 > /proc/stap_test_cmd
exp_continue
}
- -re {^backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func3@[^\r\n]+\r\n} {
+
+ #backtrace from yyy_func2
+ -re {^backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func2@[^\r\n]+\r\n} {
incr m1
expect {
-timeout 5
- -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m1 == 1} {incr m1}
- exp_continue
- }
-re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m1 == 2} {incr m1}
+ if {$m1 == 1} {incr m1}
exp_continue
}
-re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m1 == 3} {incr m1}
+ if {$m1 == 2} {incr m1}
}
}
exp_continue
}
- -re {.*---\r\nthe call stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
+ -re {.*--- yyy_func2 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
incr m2
expect {
-timeout 5
- -re {.*call\>--\r\n 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m2 == 1} {incr m2}
- exp_continue
- }
-re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m2 == 2} {incr m2}
+ if {$m2 == 1} {incr m2}
exp_continue
}
-re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m2 == 3} {incr m2}
+ if {$m2 == 2} {incr m2}
}
}
exp_continue
}
- -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func4@[^\r\n]+\r\n} {
+
+ #backtrace from yyy_func3
+ -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func3@[^\r\n]+\r\n} {
incr m3
expect {
-timeout 5
- -re {^Returning from: 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} {
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m3 == 1} {incr m3}
exp_continue
- }
- -re {^Returning to : 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m3 == 2} {incr m3}
- exp_continue
- }
+ }
-re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m3 == 3} {incr m3}
+ if {$m3 == 2} {incr m3}
exp_continue
}
-re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m3 == 4} {incr m3}
+ if {$m3 == 3} {incr m3}
}
}
exp_continue
}
- -re {.*---\r\nthe return stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
+ -re {.*--- yyy_func3 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
incr m4
expect {
-timeout 5
- -re $retexp {
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m4 == 1} {incr m4}
exp_continue
}
@@ -96,58 +82,87 @@ expect {
}
exp_continue
}
- -re {.*backtrace from timer.profile:\r\n} {
+
+ #backtrace from yyy_func4
+ -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func4@[^\r\n]+\r\n} {
incr m5
expect {
-timeout 5
- -re {^ 0x[a-f0-9]+[^\r\n]+\r\n} {
+ -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m5 == 1} {incr m5}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m5 == 2} {incr m5}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m5 == 3} {incr m5}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m5 == 4} {incr m5}
}
}
exp_continue
}
- -re {.*---\r\nthe profile stack is 0x[a-f0-9]+[^\r\n]+\r\n} {
+ -re {.*--- yyy_func4 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
incr m6
expect {
-timeout 5
- -re {.*profile>--\r\n 0x[a-f0-9]+[^\r\n]+\r\n} {
+ -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m6 == 1} {incr m6}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m6 == 2} {incr m6}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m6 == 3} {incr m6}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m6 == 4} {incr m6}
}
}
+ exp_continue
}
- eof {fail "backtrace of yyy_func3, yyy_func4.return and timer.profile. unexpected EOF" }
+ eof {fail "backtrace of yyy_func[2-4]: unexpected EOF" }
}
exec kill -INT -[exp_pid]
-if {$m1 == 4} {
- pass "backtrace of yyy_func3"
+if {$m1 == 3} {
+ pass "backtrace of yyy_func2"
} else {
- fail "backtrace of yyy_func3 ($m1)"
+ fail "backtrace of yyy_func2 ($m1)"
}
-if {$m2 == 4} {
- pass "print_stack of yyy_func3"
+if {$m2 == 3} {
+ pass "print_stack of yyy_func2"
} else {
- fail "print_stack of yyy_func3 ($m2)"
+ fail "print_stack of yyy_func2 ($m2)"
}
-if {$m3 == 5} {
- pass "backtrace of yyy_func4.return"
+if {$m3 == 4} {
+ pass "backtrace of yyy_func3"
} else {
- fail "backtrace of yyy_func4.return ($m3)"
+ fail "backtrace of yyy_func3 ($m3)"
}
if {$m4 == 4} {
- pass "print_stack of yyy_func4.return"
+ pass "print_stack of yyy_func3"
} else {
- fail "print_stack of yyy_func4.return ($m4)"
+ fail "print_stack of yyy_func3 ($m4)"
}
-if {$m5 == 2} {
- pass "backtrace of timer.profile"
+if {$m5 == 5} {
+ pass "backtrace of yyy_func4"
} else {
- fail "backtrace of timer.profile ($m5)"
+ fail "backtrace of yyy_func4 ($m5)"
}
-if {$m6 == 2} {
- pass "print_stack of timer.profile"
+if {$m6 == 5} {
+ pass "print_stack of yyy_func4"
} else {
- fail "print_stack of timer.profile ($m6)"
+ fail "print_stack of yyy_func4 ($m6)"
}
+
+
close
wait