2 * Copyright (c) 2013 Luca Clementi <luca.clementi@gmail.com>
3 * Copyright (c) 2013-2018 The strace developers.
5 * SPDX-License-Identifier: LGPL-2.1-or-later
12 # if defined HAVE_DEMANGLE_H
13 # include <demangle.h>
14 # elif defined HAVE_LIBIBERTY_DEMANGLE_H
15 # include <libiberty/demangle.h>
20 * Type used in stacktrace capturing
27 struct unwind_queue_t {
32 static void queue_print(struct unwind_queue_t *queue);
34 static const char asprintf_error_str[] = "???";
44 unwind_tcb_init(struct tcb *tcp)
46 if (tcp->unwind_queue)
49 tcp->unwind_queue = xmalloc(sizeof(*tcp->unwind_queue));
50 tcp->unwind_queue->head = NULL;
51 tcp->unwind_queue->tail = NULL;
53 tcp->unwind_ctx = unwinder.tcb_init(tcp);
57 unwind_tcb_fin(struct tcb *tcp)
59 if (!tcp->unwind_queue)
62 queue_print(tcp->unwind_queue);
63 free(tcp->unwind_queue);
64 tcp->unwind_queue = NULL;
66 unwinder.tcb_fin(tcp);
67 tcp->unwind_ctx = NULL;
71 * printing an entry in stack to stream or buffer
74 * we want to keep the format used by backtrace_symbols from the glibc
76 * ./a.out() [0x40063d]
77 * ./a.out() [0x4006bb]
78 * ./a.out() [0x4006c6]
79 * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d]
80 * ./a.out() [0x400569]
82 #define STACK_ENTRY_SYMBOL_FMT(SYM) \
83 " > %s(%s+0x%lx) [0x%lx]\n", \
86 (unsigned long) function_offset, \
88 #define STACK_ENTRY_NOSYMBOL_FMT \
89 " > %s() [0x%lx]\n", \
90 binary_filename, true_offset
91 #define STACK_ENTRY_BUG_FMT \
93 #define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \
94 " > %s [0x%lx]\n", error, true_offset
95 #define STACK_ENTRY_ERROR_FMT \
99 print_call_cb(void *dummy,
100 const char *binary_filename,
101 const char *symbol_name,
102 unwind_function_offset_t function_offset,
103 unsigned long true_offset)
105 if (symbol_name && (symbol_name[0] != '\0')) {
107 char *demangled_name =
108 cplus_demangle(symbol_name,
109 DMGL_AUTO | DMGL_PARAMS);
111 tprintf(STACK_ENTRY_SYMBOL_FMT(
113 demangled_name ? demangled_name :
117 free(demangled_name);
120 else if (binary_filename)
121 tprintf(STACK_ENTRY_NOSYMBOL_FMT);
123 tprintf(STACK_ENTRY_BUG_FMT, __func__);
129 print_error_cb(void *dummy,
131 unsigned long true_offset)
134 tprintf(STACK_ENTRY_ERROR_WITH_OFFSET_FMT);
136 tprintf(STACK_ENTRY_ERROR_FMT);
142 sprint_call_or_error(const char *binary_filename,
143 const char *symbol_name,
144 unwind_function_offset_t function_offset,
145 unsigned long true_offset,
148 char *output_line = NULL;
153 char *demangled_name =
154 cplus_demangle(symbol_name,
155 DMGL_AUTO | DMGL_PARAMS);
157 n = asprintf(&output_line,
158 STACK_ENTRY_SYMBOL_FMT(
160 demangled_name ? demangled_name :
164 free(demangled_name);
167 else if (binary_filename)
168 n = asprintf(&output_line, STACK_ENTRY_NOSYMBOL_FMT);
171 ? asprintf(&output_line, STACK_ENTRY_ERROR_WITH_OFFSET_FMT)
172 : asprintf(&output_line, STACK_ENTRY_ERROR_FMT);
174 n = asprintf(&output_line, STACK_ENTRY_BUG_FMT, __func__);
177 perror_func_msg("asprintf");
178 output_line = (char *) asprintf_error_str;
188 queue_put(struct unwind_queue_t *queue,
189 const char *binary_filename,
190 const char *symbol_name,
191 unwind_function_offset_t function_offset,
192 unsigned long true_offset,
197 call = xmalloc(sizeof(*call));
198 call->output_line = sprint_call_or_error(binary_filename,
209 queue->tail->next = call;
215 queue_put_call(void *queue,
216 const char *binary_filename,
217 const char *symbol_name,
218 unwind_function_offset_t function_offset,
219 unsigned long true_offset)
230 queue_put_error(void *queue,
234 queue_put(queue, NULL, NULL, 0, ip, error);
238 queue_print(struct unwind_queue_t *queue)
240 struct call_t *call, *tmp;
249 tprints(tmp->output_line);
252 if (tmp->output_line != asprintf_error_str)
253 free(tmp->output_line);
255 tmp->output_line = NULL;
265 unwind_tcb_print(struct tcb *tcp)
267 #if SUPPORTED_PERSONALITIES > 1
268 if (tcp->currpers != DEFAULT_PERSONALITY) {
269 /* disable stack trace */
273 if (tcp->unwind_queue->head) {
274 debug_func_msg("head: tcp=%p, queue=%p",
275 tcp, tcp->unwind_queue->head);
276 queue_print(tcp->unwind_queue);
278 unwinder.tcb_walk(tcp, print_call_cb, print_error_cb, NULL);
285 unwind_tcb_capture(struct tcb *tcp)
287 #if SUPPORTED_PERSONALITIES > 1
288 if (tcp->currpers != DEFAULT_PERSONALITY) {
289 /* disable stack trace */
293 if (tcp->unwind_queue->head)
294 error_msg_and_die("bug: unprinted entries in queue");
296 debug_func_msg("walk: tcp=%p, queue=%p",
297 tcp, tcp->unwind_queue->head);
298 unwinder.tcb_walk(tcp, queue_put_call, queue_put_error,