[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