[PATCH v4 06/37] unwind: introduce stacktrace_walker
Masatake YAMATO
yamato at redhat.com
Wed Apr 16 06:33:04 UTC 2014
In current implementation, the stack trace is captured and printed at
the same time, in `trace_syscall_exiting'. This implementation cannot
provide user expected information when a system call changes the
memory mapping. Typical case is execve. The user may want to know
where execve is invoked; the stack trace should be captured in
`trace_syscall_entering' and print it in `trace_syscall_exiting'.
As the initial step for splitting capturing from printing, this patch
introduces stacktrace_walker utility function. It can be used both
capturing in `trace_syscall_entering' and printing in
`trace_syscall_exiting'.
As suggested by Dmitry V. Levin <ldv at altlinux.org>, in this patch I remove unnecessary
indirections of calls (wrapper functions).
Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
unwind.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 104 insertions(+), 24 deletions(-)
diff --git a/unwind.c b/unwind.c
index 4ebc048..ecb7aa0 100644
--- a/unwind.c
+++ b/unwind.c
@@ -48,6 +48,19 @@ struct mmap_cache_t {
char* binary_filename;
};
+/*
+ * Type used in stacktrace walker
+ */
+typedef void (*call_action_fn)(void *data,
+ char *binary_filename,
+ char *symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset);
+typedef void (*error_action_fn)(void *data,
+ const char *error,
+ unsigned long true_offset);
+
+
static unw_addr_space_t libunwind_as;
void
@@ -169,9 +182,14 @@ unwind_cache_invalidate(struct tcb* tcp)
tcp->mmap_cache_size = 0;
}
-/* use libunwind to unwind the stack and print a backtrace */
-void
-unwind_print_stacktrace(struct tcb* tcp)
+/*
+ * walking the stack
+ */
+static void
+stacktrace_walk(struct tcb *tcp,
+ call_action_fn call_action,
+ error_action_fn error_action,
+ void *data)
{
unw_word_t ip;
unw_cursor_t cursor;
@@ -228,23 +246,18 @@ unwind_print_stacktrace(struct tcb* tcp)
true_offset = ip - cur_mmap_cache->start_addr +
cur_mmap_cache->mmap_offset;
if (symbol_name[0]) {
- /*
- * we want to keep the format used by backtrace_symbols from the glibc
- *
- * ./a.out() [0x40063d]
- * ./a.out() [0x4006bb]
- * ./a.out() [0x4006c6]
- * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d]
- * ./a.out() [0x400569]
- */
- tprintf(" > %s(%s+0x%lx) [0x%lx]\n",
- cur_mmap_cache->binary_filename,
- symbol_name, function_off_set, true_offset);
+ call_action(data,
+ cur_mmap_cache->binary_filename,
+ symbol_name,
+ function_off_set,
+ true_offset);
} else {
- tprintf(" > %s() [0x%lx]\n",
- cur_mmap_cache->binary_filename, true_offset);
+ call_action(data,
+ cur_mmap_cache->binary_filename,
+ symbol_name,
+ 0,
+ true_offset);
}
- line_ended();
break; /* stack frame printed */
}
else if (mid == 0) {
@@ -254,8 +267,8 @@ unwind_print_stacktrace(struct tcb* tcp)
* unw_get_reg returns IP == 0
*/
if(ip)
- tprintf(" > backtracing_error\n");
- line_ended();
+ error_action(data,
+ "backtracing_error", 0);
goto ret;
}
else if (ip < cur_mmap_cache->start_addr)
@@ -265,19 +278,86 @@ unwind_print_stacktrace(struct tcb* tcp)
}
if (lower > upper) {
- tprintf(" > backtracing_error [0x%lx]\n", ip);
- line_ended();
+ error_action(data,
+ "backtracing_error", ip);
goto ret;
}
ret_val = unw_step(&cursor);
if (++stack_depth > 255) {
- tprintf("> too many stack frames\n");
- line_ended();
+ error_action(data,
+ "too many stack frames", 0);
break;
}
} while (ret_val > 0);
ret:
free(symbol_name);
}
+
+/*
+ * printing an entry in stack
+ */
+/*
+ * we want to keep the format used by backtrace_symbols from the glibc
+ *
+ * ./a.out() [0x40063d]
+ * ./a.out() [0x4006bb]
+ * ./a.out() [0x4006c6]
+ * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d]
+ * ./a.out() [0x400569]
+ */
+#define STACK_ENTRY_SYMBOL_FMT \
+ " > %s(%s+0x%lx) [0x%lx]\n", \
+ binary_filename, \
+ symbol_name, \
+ function_off_set, \
+ true_offset
+#define STACK_ENTRY_NOSYMBOL_FMT \
+ " > %s() [0x%lx]\n", \
+ binary_filename, true_offset
+#define STACK_ENTRY_BUG_FMT \
+ " > BUG IN %s\n"
+#define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \
+ " > %s [0x%lx]\n", error, true_offset
+#define STACK_ENTRY_ERROR_FMT \
+ " > %s [0x%lx]\n", error, true_offset
+
+static void
+print_call_cb(void *dummy,
+ char *binary_filename,
+ char *symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset)
+{
+ if (symbol_name)
+ tprintf(STACK_ENTRY_SYMBOL_FMT);
+ else if (binary_filename)
+ tprintf(STACK_ENTRY_NOSYMBOL_FMT);
+ else
+ tprintf(STACK_ENTRY_BUG_FMT, __FUNCTION__);
+
+ line_ended();
+}
+
+static void
+print_error_cb(void *dummy,
+ const char *error,
+ unsigned long true_offset)
+{
+ if (true_offset)
+ tprintf(STACK_ENTRY_ERROR_WITH_OFFSET_FMT);
+ else
+ tprintf(STACK_ENTRY_ERROR_FMT);
+
+ line_ended();
+}
+
+/*
+ * printing stack
+ */
+void
+unwind_print_stacktrace(struct tcb* tcp)
+{
+ stacktrace_walk(tcp, print_call_cb, print_error_cb, NULL);
+}
--
1.9.0
More information about the Strace-devel
mailing list