[PATCH] ldv/unwind: Improve stacktrace feature
Masatake YAMATO
yamato at redhat.com
Thu Oct 10 13:54:08 UTC 2013
Based on the discussion on strace-devel, I improved following points:
* using unwind_ as prefix for functions exported from unwind.c
* stacktrace for execve
About the most of system calls, stacktrace is captured and printed at
the same time, the system call exiting. However, about execve, which
is marked with STACKTRACE_CAPTURE_IN_ENTERING(CE), stacktrace is
captured at the system call entering, and is printed at the exiting.
By capturing in the system call entering, user can know the process
context of execve is called.
struct queue_t and some manipulators are introduced for
capturing-at-entering and printing-at-exiting.
* controlling the maps cache with STACKTRACE_MAKE_CACHE_INVALID(CI) marker
Currently stacktrace feature of strace needs the information of the
memory mapping. Some of system calls like mmap change the memory
mapping of the target process. Therefore unwind.c must track the
modification of memory mapping.
In older version the modification is tracked in print functions of
each system call. In this patch STACKTRACE_MAKE_CACHE_INVALID(CI)
marker is introduced. In stead of handling in print functions, the
modification is tracked in system call entering only if current
system call is marked with CI.
If new system call modifying the memory mapping is added, just
mark it with CI.
* marking CI on brk, mremap, shmat, shmdt, and remap_file_pages.
TODO:
* Move the memory mapping cache to libuwind and use API for it.
See http://lists.nongnu.org/archive/html/libunwind-devel/2013-10/msg00001.html
* Handle multi threads
If target threads are share the same address space, cache invalidation
on a thread must be propagated to the other threads.
* Static link target
Target compiled with gcc -static, stacktrace is not
shown well through gdb can show it. Maybe libunwind
side issue.
* Platform other than linux/x86_64
* Test cases
Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
defs.h | 15 ++-
linux/x86_64/syscallent.h | 18 +--
mem.c | 17 ---
process.c | 10 --
strace.c | 10 +-
syscall.c | 27 +++-
unwind.c | 334 +++++++++++++++++++++++++++++++++++++++++-----
7 files changed, 351 insertions(+), 80 deletions(-)
diff --git a/defs.h b/defs.h
index 7f76008..af3bcdf 100644
--- a/defs.h
+++ b/defs.h
@@ -445,6 +445,7 @@ struct tcb {
struct UPT_info* libunwind_ui;
struct mmap_cache_t* mmap_cache;
unsigned int mmap_cache_size;
+ struct queue_t* queue;
#endif
};
@@ -557,6 +558,8 @@ extern const struct xlat whence_codes[];
#define TRACE_DESC 040 /* Trace file descriptor-related syscalls. */
#define TRACE_MEMORY 0100 /* Trace memory mapping-related syscalls. */
#define SYSCALL_NEVER_FAILS 0200 /* Syscall is always successful. */
+#define STACKTRACE_MAKE_CACHE_INVALID 0400 /* Trigger proc/maps cache updating */
+#define STACKTRACE_CAPTURE_IN_ENTERING 01000 /* Capture stacktrace in "entering" stage */
typedef enum {
CFLAG_NONE = 0,
@@ -737,12 +740,12 @@ extern void tv_mul(struct timeval *, struct timeval *, int);
extern void tv_div(struct timeval *, struct timeval *, int);
#ifdef USE_LIBUNWIND
-extern void init_unwind_addr_space(void);
-extern void init_libunwind_ui(struct tcb *tcp);
-extern void free_libunwind_ui(struct tcb *tcp);
-extern void alloc_mmap_cache(struct tcb* tcp);
-extern void delete_mmap_cache(struct tcb* tcp);
-extern void print_stacktrace(struct tcb* tcp);
+extern void unwind_init(void);
+extern void unwind_tcb_init(struct tcb *);
+extern void unwind_tcb_fin(struct tcb *);
+extern void unwind_cache_invalidate(struct tcb * );
+extern void unwind_stacktrace_capture(struct tcb *);
+extern void unwind_stacktrace_print(struct tcb *);
#endif
/* Strace log generation machinery.
diff --git a/linux/x86_64/syscallent.h b/linux/x86_64/syscallent.h
index 8e3a200..13dd6fe 100644
--- a/linux/x86_64/syscallent.h
+++ b/linux/x86_64/syscallent.h
@@ -7,10 +7,10 @@
{ 2, TF, sys_lstat, "lstat" }, /* 6 */
{ 3, TD, sys_poll, "poll" }, /* 7 */
{ 3, TD, sys_lseek, "lseek" }, /* 8 */
- { 6, TD|TM, sys_mmap, "mmap" }, /* 9 */
- { 3, TM, sys_mprotect, "mprotect" }, /* 10 */
- { 2, TM, sys_munmap, "munmap" }, /* 11 */
- { 1, TM, sys_brk, "brk" }, /* 12 */
+ { 6, TD|TM|CI,sys_mmap, "mmap" }, /* 9 */
+ { 3, TM|CI, sys_mprotect, "mprotect" }, /* 10 */
+ { 2, TM|CI, sys_munmap, "munmap" }, /* 11 */
+ { 1, TM|CI, sys_brk, "brk" }, /* 12 */
{ 4, TS, sys_rt_sigaction, "rt_sigaction" }, /* 13 */
{ 4, TS, sys_rt_sigprocmask, "rt_sigprocmask"}, /* 14 */
{ 0, TS, sys_rt_sigreturn, "rt_sigreturn" }, /* 15 */
@@ -23,12 +23,12 @@
{ 1, TD, sys_pipe, "pipe" }, /* 22 */
{ 5, TD, sys_select, "select" }, /* 23 */
{ 0, 0, sys_sched_yield, "sched_yield" }, /* 24 */
- { 5, TM, sys_mremap, "mremap" }, /* 25 */
+ { 5, TM|CI, sys_mremap, "mremap" }, /* 25 */
{ 3, TM, sys_msync, "msync" }, /* 26 */
{ 3, TM, sys_mincore, "mincore" }, /* 27 */
{ 3, TM, sys_madvise, "madvise" }, /* 28 */
{ 4, TI, sys_shmget, "shmget" }, /* 29 */
- { 4, TI, sys_shmat, "shmat" }, /* 30 */
+ { 4, TI|CI, sys_shmat, "shmat" }, /* 30 */
{ 4, TI, sys_shmctl, "shmctl" }, /* 31 */
{ 1, TD, sys_dup, "dup" }, /* 32 */
{ 2, TD, sys_dup2, "dup2" }, /* 33 */
@@ -57,7 +57,7 @@
{ 5, TP, sys_clone, "clone" }, /* 56 */
{ 0, TP, sys_fork, "fork" }, /* 57 */
{ 0, TP, sys_vfork, "vfork" }, /* 58 */
- { 3, TF|TP, sys_execve, "execve" }, /* 59 */
+ { 3, TF|TP|CI|CE,sys_execve, "execve" }, /* 59 */
{ 1, TP, sys_exit, "_exit" }, /* 60 */
{ 4, TP, sys_wait4, "wait4" }, /* 61 */
{ 2, TS, sys_kill, "kill" }, /* 62 */
@@ -65,7 +65,7 @@
{ 4, TI, sys_semget, "semget" }, /* 64 */
{ 4, TI, sys_semop, "semop" }, /* 65 */
{ 4, TI, sys_semctl, "semctl" }, /* 66 */
- { 4, TI, sys_shmdt, "shmdt" }, /* 67 */
+ { 4, TI|CI, sys_shmdt, "shmdt" }, /* 67 */
{ 4, TI, sys_msgget, "msgget" }, /* 68 */
{ 4, TI, sys_msgsnd, "msgsnd" }, /* 69 */
{ 5, TI, sys_msgrcv, "msgrcv" }, /* 70 */
@@ -214,7 +214,7 @@
{ 1, TD, sys_epoll_create, "epoll_create" }, /* 213 */
{ 4, 0, printargs, "epoll_ctl_old" }, /* 214 */
{ 4, 0, printargs, "epoll_wait_old"}, /* 215 */
- { 5, TM, sys_remap_file_pages, "remap_file_pages"}, /* 216 */
+ { 5, TM|CI, sys_remap_file_pages, "remap_file_pages"}, /* 216 */
{ 3, TD, sys_getdents64, "getdents64" }, /* 217 */
{ 1, 0, sys_set_tid_address, "set_tid_address"}, /* 218 */
{ 0, 0, sys_restart_syscall, "restart_syscall"}, /* 219 */
diff --git a/mem.c b/mem.c
index ca6caa1..ef273c7 100644
--- a/mem.c
+++ b/mem.c
@@ -175,11 +175,6 @@ static int
print_mmap(struct tcb *tcp, long *u_arg, unsigned long long offset)
{
if (entering(tcp)) {
-#ifdef USE_LIBUNWIND
- if (stack_trace_enabled)
- delete_mmap_cache(tcp);
-#endif
-
/* addr */
if (!u_arg[0])
tprints("NULL, ");
@@ -309,12 +304,6 @@ sys_munmap(struct tcb *tcp)
tprintf("%#lx, %lu",
tcp->u_arg[0], tcp->u_arg[1]);
}
-#ifdef USE_LIBUNWIND
- else {
- if (stack_trace_enabled)
- delete_mmap_cache(tcp);
- }
-#endif
return 0;
}
@@ -326,12 +315,6 @@ sys_mprotect(struct tcb *tcp)
tcp->u_arg[0], tcp->u_arg[1]);
printflags(mmap_prot, tcp->u_arg[2], "PROT_???");
}
-#ifdef USE_LIBUNWIND
- else {
- if (stack_trace_enabled)
- delete_mmap_cache(tcp);
- }
-#endif
return 0;
}
diff --git a/process.c b/process.c
index 22bb5b6..ab3511c 100644
--- a/process.c
+++ b/process.c
@@ -992,12 +992,6 @@ sys_execve(struct tcb *tcp)
tprints("]");
}
}
-#ifdef USE_LIBUNWIND
- else {
- if (stack_trace_enabled)
- delete_mmap_cache(tcp);
- }
-#endif
return 0;
}
@@ -1200,10 +1194,6 @@ sys_waitid(struct tcb *tcp)
tprintf(", %ld, ", tcp->u_arg[1]);
}
else {
-#ifdef USE_LIBUNWIND
- if (stack_trace_enabled)
- delete_mmap_cache(tcp);
-#endif
/* siginfo */
printsiginfo_at(tcp, tcp->u_arg[2]);
/* options */
diff --git a/strace.c b/strace.c
index 7775b42..5875cf5 100644
--- a/strace.c
+++ b/strace.c
@@ -696,7 +696,7 @@ alloctcb(int pid)
#ifdef USE_LIBUNWIND
if (stack_trace_enabled)
- init_libunwind_ui(tcp);
+ unwind_tcb_init(tcp);
#endif
nprocs++;
@@ -736,10 +736,8 @@ droptcb(struct tcb *tcp)
printing_tcp = NULL;
#ifdef USE_LIBUNWIND
- if (stack_trace_enabled) {
- delete_mmap_cache(tcp);
- free_libunwind_ui(tcp);
- }
+ if (stack_trace_enabled)
+ unwind_tcb_fin(tcp);
#endif
memset(tcp, 0, sizeof(*tcp));
}
@@ -1805,7 +1803,7 @@ init(int argc, char *argv[])
#ifdef USE_LIBUNWIND
if (stack_trace_enabled)
- init_unwind_addr_space();
+ unwind_init();
#endif
if (!followfork)
diff --git a/syscall.c b/syscall.c
index b01c023..8c4c738 100644
--- a/syscall.c
+++ b/syscall.c
@@ -97,6 +97,8 @@
#define TM TRACE_MEMORY
#define NF SYSCALL_NEVER_FAILS
#define MA MAX_ARGS
+#define CI STACKTRACE_MAKE_CACHE_INVALID
+#define CE STACKTRACE_CAPTURE_IN_ENTERING
const struct_sysent sysent0[] = {
#include "syscallent.h"
@@ -124,6 +126,8 @@ static const struct_sysent sysent2[] = {
#undef TM
#undef NF
#undef MA
+#undef CI
+#undef CE
/*
* `ioctlent.h' may be generated from `ioctlent.raw' by the auxiliary
@@ -2025,12 +2029,31 @@ trace_syscall_entering(struct tcb *tcp)
|| (tracing_paths && !pathtrace_match(tcp))
) {
tcp->flags |= TCB_INSYSCALL | TCB_FILTERED;
+#ifdef USE_LIBUNWIND
+ if (stack_trace_enabled)
+ if (tcp->s_ent->sys_flags & STACKTRACE_MAKE_CACHE_INVALID)
+ unwind_cache_invalidate(tcp);
+#endif
return 0;
}
tcp->flags &= ~TCB_FILTERED;
- if (cflag == CFLAG_ONLY_STATS || hide_log_until_execve) {
+ if (cflag == CFLAG_ONLY_STATS) {
+ res = 0;
+ goto ret;
+ }
+
+#ifdef USE_LIBUNWIND
+ if (stack_trace_enabled) {
+ if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_IN_ENTERING)
+ unwind_stacktrace_capture(tcp);
+ if (tcp->s_ent->sys_flags & STACKTRACE_MAKE_CACHE_INVALID)
+ unwind_cache_invalidate(tcp);
+ }
+#endif
+
+ if (hide_log_until_execve) {
res = 0;
goto ret;
}
@@ -2708,7 +2731,7 @@ trace_syscall_exiting(struct tcb *tcp)
#ifdef USE_LIBUNWIND
if (stack_trace_enabled)
- print_stacktrace(tcp);
+ unwind_stacktrace_print(tcp);
#endif
ret:
diff --git a/unwind.c b/unwind.c
index 0b8f0b0..5adf7ec 100644
--- a/unwind.c
+++ b/unwind.c
@@ -28,6 +28,15 @@
#include <limits.h>
#include <libunwind-ptrace.h>
+/* #define UNWINDE_DEBUG */
+
+#ifdef UNWINDE_DEBUG
+#include <stdio.h>
+#define DPRINTF(F, ...) fprintf(stderr, "--- <unwind> " F " ---\n", __VA_ARGS__);
+#else
+#define DPRINTF(...)
+#endif
+
/*
* Кeep a sorted array of cache entries,
* so that we can binary search through it.
@@ -48,9 +57,54 @@ struct mmap_cache_t {
char* binary_filename;
};
+/*
+ * Keep a captured stracktrace.
+ */
+struct call_t {
+ struct call_t* next;
+ char* binary_filename;
+ char* symbol_name;
+ unw_word_t function_off_set;
+ unsigned long true_offset;
+ const char* error;
+};
+
+struct queue_t {
+ struct call_t *tail;
+ struct call_t *head;
+};
+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 void queue_free(struct queue_t *queue);
+static void queue_print(struct queue_t *queue);
+static void queue_walk(struct queue_t *queue,
+ call_action_fn call_action,
+ error_action_fn error_action,
+ void* data);
+static void queue_put_call(void *queue,
+ char* binary_filename,
+ char* symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset);
+static void queue_put_error(void *queue, const char* error,
+ unw_word_t ip);
+static void queue_put(struct queue_t *queue,
+ char* binary_filename,
+ char* symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset,
+ const char* error);
+
static unw_addr_space_t libunwind_as;
-void
+static void
init_unwind_addr_space(void)
{
libunwind_as = unw_create_addr_space(&_UPT_accessors, 0);
@@ -58,7 +112,7 @@ init_unwind_addr_space(void)
error_msg_and_die("failed to create address space for stack tracing");
}
-void
+static void
init_libunwind_ui(struct tcb *tcp)
{
tcp->libunwind_ui = _UPT_create(tcp->pid);
@@ -66,7 +120,7 @@ init_libunwind_ui(struct tcb *tcp)
die_out_of_memory();
}
-void
+static void
free_libunwind_ui(struct tcb *tcp)
{
_UPT_destroy(tcp->libunwind_ui);
@@ -78,8 +132,8 @@ free_libunwind_ui(struct tcb *tcp)
*
* The cache must be refreshed after some syscall: mmap, mprotect, munmap, execve
*/
-void
-alloc_mmap_cache(struct tcb* tcp)
+static void
+build_cache(struct tcb* tcp)
{
unsigned long start_addr, end_addr, mmap_offset;
char filename[sizeof ("/proc/0123456789/maps")];
@@ -91,6 +145,8 @@ alloc_mmap_cache(struct tcb* tcp)
struct mmap_cache_t *cache_head;
FILE *fp;
+ DPRINTF("BUILDCACHE: %p", tcp->queue->head);
+
sprintf(filename, "/proc/%d/maps", tcp->pid);
fp = fopen(filename, "r");
if (!fp) {
@@ -155,7 +211,7 @@ alloc_mmap_cache(struct tcb* tcp)
}
/* deleting the cache */
-void
+static void
delete_mmap_cache(struct tcb* tcp)
{
unsigned int i;
@@ -168,9 +224,158 @@ delete_mmap_cache(struct tcb* tcp)
tcp->mmap_cache_size = 0;
}
-/* use libunwind to unwind the stack and print a backtrace */
-void
-print_stacktrace(struct tcb* tcp)
+static void
+queue_put(struct queue_t *queue,
+ char* binary_filename,
+ char* symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset,
+ const char* error)
+{
+ struct call_t *call;
+
+ call = malloc(sizeof(*call));
+ if (!call)
+ die_out_of_memory();
+
+ call->binary_filename = binary_filename;
+ call->symbol_name = symbol_name;
+ call->function_off_set = function_off_set;
+ call->true_offset = true_offset;
+ call->error = error;
+ call->next = NULL;
+
+ if (!queue->head) {
+ queue->head = call;
+ queue->tail = call;
+ } else {
+ queue->tail->next = call;
+ queue->tail = call;
+ }
+}
+
+static void
+queue_put_call(void *queue,
+ char* binary_filename,
+ char* symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset)
+{
+
+ char* binary_filename0 = strdup(binary_filename);
+ char* symbol_name0 = strdup(symbol_name);
+ if (!binary_filename0)
+ die_out_of_memory();
+ if (!symbol_name0)
+ die_out_of_memory();
+
+ queue_put(queue,
+ binary_filename0,
+ symbol_name0,
+ function_off_set,
+ true_offset,
+ NULL);
+}
+
+static void
+queue_put_error(void *queue,
+ const char* error,
+ unw_word_t ip)
+{
+ queue_put(queue, NULL, NULL, 0, ip, error);
+}
+
+static void
+queue_walk(struct queue_t *queue,
+ call_action_fn call_action,
+ error_action_fn error_action,
+ void* data)
+{
+ struct call_t* call;
+
+
+ call = queue->head;
+ while(call) {
+ if (call->error)
+ error_action(data,
+ call->error,
+ call->true_offset);
+ else
+ call_action(data,
+ call->binary_filename,
+ call->symbol_name,
+ call->function_off_set,
+ call->true_offset);
+ call = call->next;
+ }
+}
+
+static void
+queue_free(struct queue_t *queue)
+{
+ struct call_t *call, *tmp;
+
+ queue->tail = NULL;
+ call = queue->head;
+ queue->head = NULL;
+ while (call) {
+ tmp = call;
+ call = call->next;
+ free(tmp->binary_filename);
+ tmp->binary_filename = NULL;
+ free(tmp->symbol_name);
+ tmp->symbol_name = NULL;
+ tmp->error = NULL;
+ tmp->next = NULL;
+ free(tmp);
+ }
+}
+
+static void
+print_call(void* dummy,
+ char* binary_filename,
+ char* symbol_name,
+ unw_word_t function_off_set,
+ unsigned long true_offset)
+{
+ if (symbol_name) {
+ tprintf(" > %s(%s+0x%lx) [0x%lx]\n",
+ binary_filename,
+ symbol_name, function_off_set, true_offset);
+ }
+ else if (binary_filename)
+ tprintf(" > %s() [0x%lx]\n",
+ binary_filename, true_offset);
+ else
+ tprintf(" > BUG IN print_call\n");
+
+ line_ended();
+}
+
+static void
+print_error(void* dummy,
+ const char* error,
+ unsigned long true_offset)
+{
+ if (true_offset)
+ tprintf(" > %s [0x%lx]\n", error, true_offset);
+ else
+ tprintf(" > %s\n", error);
+ line_ended();
+}
+
+static void
+queue_print(struct queue_t *queue)
+{
+ DPRINTF("QUEUEPRINT: %p", queue->head);
+ queue_walk(queue, print_call, print_error, NULL);
+}
+
+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;
@@ -183,10 +388,6 @@ print_stacktrace(struct tcb* tcp)
struct mmap_cache_t* cur_mmap_cache;
unsigned long true_offset;
- if (!tcp->mmap_cache)
- alloc_mmap_cache(tcp);
- if (!tcp->mmap_cache || !tcp->mmap_cache_size)
- return;
symbol_name = malloc(symbol_name_size);
if (!symbol_name)
@@ -236,25 +437,24 @@ print_stacktrace(struct tcb* tcp)
* /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) {
- /*
- * there is a bug in libunwind >= 1.0
- * after a set_tid_address syscall
- * 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)
@@ -264,19 +464,93 @@ 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);
}
+
+static void
+stacktrace_print(struct tcb* tcp)
+{
+ DPRINTF("STACKPRINT: %p", tcp->queue->head);
+ stacktrace_walk(tcp, print_call, print_error, NULL);
+}
+
+/* use libunwind to unwind the stack and print a backtrace */
+void
+unwind_init(void)
+{
+ init_unwind_addr_space();
+}
+
+void
+unwind_tcb_init(struct tcb *tcp)
+{
+ init_libunwind_ui(tcp);
+ tcp->queue = malloc(sizeof(*tcp->queue));
+ if (!tcp->queue)
+ die_out_of_memory();
+ tcp->queue->head = NULL;
+ tcp->queue->tail = NULL;
+}
+
+void
+unwind_tcb_fin(struct tcb *tcp)
+{
+ delete_mmap_cache(tcp);
+ free_libunwind_ui(tcp);
+ queue_free(tcp->queue);
+ free(tcp->queue);
+ tcp->queue = NULL;
+}
+
+void
+unwind_cache_invalidate(struct tcb* tcp)
+{
+ delete_mmap_cache(tcp);
+ DPRINTF("INVALIDATED: %p", tcp->queue->head);
+}
+
+
+void
+unwind_stacktrace_capture(struct tcb* tcp)
+{
+ queue_free(tcp->queue);
+
+ if (!tcp->mmap_cache)
+ build_cache(tcp);
+ if (!tcp->mmap_cache || !tcp->mmap_cache_size)
+ return;
+
+ stacktrace_walk(tcp, queue_put_call, queue_put_error,
+ tcp->queue);
+ DPRINTF("CAPTURED: %p", tcp->queue->head);
+}
+
+void
+unwind_stacktrace_print(struct tcb* tcp)
+{
+ if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_IN_ENTERING) {
+ queue_print(tcp->queue);
+ queue_free(tcp->queue);
+ }
+ else {
+ if (!tcp->mmap_cache)
+ build_cache(tcp);
+ if (!tcp->mmap_cache || !tcp->mmap_cache_size)
+ return;
+ stacktrace_print(tcp);
+ }
+}
--
1.8.3.1
More information about the Strace-devel
mailing list