1 /* 2 * Copyright (c) 2013 Luca Clementi <luca.clementi (at) gmail.com> 3 * Copyright (c) 2013-2018 The strace developers. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "defs.h" 29 #include "unwind.h" 30 31 #ifdef USE_DEMANGLE 32 # if defined HAVE_DEMANGLE_H 33 # include <demangle.h> 34 # elif defined HAVE_LIBIBERTY_DEMANGLE_H 35 # include <libiberty/demangle.h> 36 # endif 37 #endif 38 39 /* 40 * Type used in stacktrace capturing 41 */ 42 struct call_t { 43 struct call_t *next; 44 char *output_line; 45 }; 46 47 struct unwind_queue_t { 48 struct call_t *tail; 49 struct call_t *head; 50 }; 51 52 static void queue_print(struct unwind_queue_t *queue); 53 54 static const char asprintf_error_str[] = "???"; 55 56 void 57 unwind_init(void) 58 { 59 if (unwinder.init) 60 unwinder.init(); 61 } 62 63 void 64 unwind_tcb_init(struct tcb *tcp) 65 { 66 if (tcp->unwind_queue) 67 return; 68 69 tcp->unwind_queue = xmalloc(sizeof(*tcp->unwind_queue)); 70 tcp->unwind_queue->head = NULL; 71 tcp->unwind_queue->tail = NULL; 72 73 tcp->unwind_ctx = unwinder.tcb_init(tcp); 74 } 75 76 void 77 unwind_tcb_fin(struct tcb *tcp) 78 { 79 if (!tcp->unwind_queue) 80 return; 81 82 queue_print(tcp->unwind_queue); 83 free(tcp->unwind_queue); 84 tcp->unwind_queue = NULL; 85 86 unwinder.tcb_fin(tcp); 87 tcp->unwind_ctx = NULL; 88 } 89 90 /* 91 * printing an entry in stack to stream or buffer 92 */ 93 /* 94 * we want to keep the format used by backtrace_symbols from the glibc 95 * 96 * ./a.out() [0x40063d] 97 * ./a.out() [0x4006bb] 98 * ./a.out() [0x4006c6] 99 * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d] 100 * ./a.out() [0x400569] 101 */ 102 #define STACK_ENTRY_SYMBOL_FMT(SYM) \ 103 " > %s(%s+0x%lx) [0x%lx]\n", \ 104 binary_filename, \ 105 (SYM), \ 106 (unsigned long) function_offset, \ 107 true_offset 108 #define STACK_ENTRY_NOSYMBOL_FMT \ 109 " > %s() [0x%lx]\n", \ 110 binary_filename, true_offset 111 #define STACK_ENTRY_BUG_FMT \ 112 " > BUG IN %s\n" 113 #define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \ 114 " > %s [0x%lx]\n", error, true_offset 115 #define STACK_ENTRY_ERROR_FMT \ 116 " > %s\n", error 117 118 static void 119 print_call_cb(void *dummy, 120 const char *binary_filename, 121 const char *symbol_name, 122 unwind_function_offset_t function_offset, 123 unsigned long true_offset) 124 { 125 if (symbol_name && (symbol_name[0] != '\0')) { 126 #ifdef USE_DEMANGLE 127 char *demangled_name = 128 cplus_demangle(symbol_name, 129 DMGL_AUTO | DMGL_PARAMS); 130 #endif 131 tprintf(STACK_ENTRY_SYMBOL_FMT( 132 #ifdef USE_DEMANGLE 133 demangled_name ? demangled_name : 134 #endif 135 symbol_name)); 136 #ifdef USE_DEMANGLE 137 free(demangled_name); 138 #endif 139 } 140 else if (binary_filename) 141 tprintf(STACK_ENTRY_NOSYMBOL_FMT); 142 else 143 tprintf(STACK_ENTRY_BUG_FMT, __func__); 144 145 line_ended(); 146 } 147 148 static void 149 print_error_cb(void *dummy, 150 const char *error, 151 unsigned long true_offset) 152 { 153 if (true_offset) 154 tprintf(STACK_ENTRY_ERROR_WITH_OFFSET_FMT); 155 else 156 tprintf(STACK_ENTRY_ERROR_FMT); 157 158 line_ended(); 159 } 160 161 static char * 162 sprint_call_or_error(const char *binary_filename, 163 const char *symbol_name, 164 unwind_function_offset_t function_offset, 165 unsigned long true_offset, 166 const char *error) 167 { 168 char *output_line = NULL; 169 int n; 170 171 if (symbol_name) { 172 #ifdef USE_DEMANGLE 173 char *demangled_name = 174 cplus_demangle(symbol_name, 175 DMGL_AUTO | DMGL_PARAMS); 176 #endif 177 n = asprintf(&output_line, 178 STACK_ENTRY_SYMBOL_FMT( 179 #ifdef USE_DEMANGLE 180 demangled_name ? demangled_name : 181 #endif 182 symbol_name)); 183 #ifdef USE_DEMANGLE 184 free(demangled_name); 185 #endif 186 } 187 else if (binary_filename) 188 n = asprintf(&output_line, STACK_ENTRY_NOSYMBOL_FMT); 189 else if (error) 190 n = true_offset 191 ? asprintf(&output_line, STACK_ENTRY_ERROR_WITH_OFFSET_FMT) 192 : asprintf(&output_line, STACK_ENTRY_ERROR_FMT); 193 else 194 n = asprintf(&output_line, STACK_ENTRY_BUG_FMT, __func__); 195 196 if (n < 0) { 197 perror_func_msg("asprintf"); 198 output_line = (char *) asprintf_error_str; 199 } 200 201 return output_line; 202 } 203 204 /* 205 * queue manipulators 206 */ 207 static void 208 queue_put(struct unwind_queue_t *queue, 209 const char *binary_filename, 210 const char *symbol_name, 211 unwind_function_offset_t function_offset, 212 unsigned long true_offset, 213 const char *error) 214 { 215 struct call_t *call; 216 217 call = xmalloc(sizeof(*call)); 218 call->output_line = sprint_call_or_error(binary_filename, 219 symbol_name, 220 function_offset, 221 true_offset, 222 error); 223 call->next = NULL; 224 225 if (!queue->head) { 226 queue->head = call; 227 queue->tail = call; 228 } else { 229 queue->tail->next = call; 230 queue->tail = call; 231 } 232 } 233 234 static void 235 queue_put_call(void *queue, 236 const char *binary_filename, 237 const char *symbol_name, 238 unwind_function_offset_t function_offset, 239 unsigned long true_offset) 240 { 241 queue_put(queue, 242 binary_filename, 243 symbol_name, 244 function_offset, 245 true_offset, 246 NULL); 247 } 248 249 static void 250 queue_put_error(void *queue, 251 const char *error, 252 unsigned long ip) 253 { 254 queue_put(queue, NULL, NULL, 0, ip, error); 255 } 256 257 static void 258 queue_print(struct unwind_queue_t *queue) 259 { 260 struct call_t *call, *tmp; 261 262 queue->tail = NULL; 263 call = queue->head; 264 queue->head = NULL; 265 while (call) { 266 tmp = call; 267 call = call->next; 268 269 tprints(tmp->output_line); 270 line_ended(); 271 272 if (tmp->output_line != asprintf_error_str) 273 free(tmp->output_line); 274 275 tmp->output_line = NULL; 276 tmp->next = NULL; 277 free(tmp); 278 } 279 } 280 281 /* 282 * printing stack 283 */ 284 void 285 unwind_tcb_print(struct tcb *tcp) 286 { 287 #if SUPPORTED_PERSONALITIES > 1 288 if (tcp->currpers != DEFAULT_PERSONALITY) { 289 /* disable stack trace */ 290 return; 291 } 292 #endif 293 if (tcp->unwind_queue->head) { 294 debug_func_msg("head: tcp=%p, queue=%p", 295 tcp, tcp->unwind_queue->head); 296 queue_print(tcp->unwind_queue); 297 } else 298 unwinder.tcb_walk(tcp, print_call_cb, print_error_cb, NULL); 299 } 300 301 /* 302 * capturing stack 303 */ 304 void 305 unwind_tcb_capture(struct tcb *tcp) 306 { 307 #if SUPPORTED_PERSONALITIES > 1 308 if (tcp->currpers != DEFAULT_PERSONALITY) { 309 /* disable stack trace */ 310 return; 311 } 312 #endif 313 if (tcp->unwind_queue->head) 314 error_msg_and_die("bug: unprinted entries in queue"); 315 else { 316 debug_func_msg("walk: tcp=%p, queue=%p", 317 tcp, tcp->unwind_queue->head); 318 unwinder.tcb_walk(tcp, queue_put_call, queue_put_error, 319 tcp->unwind_queue); 320 } 321 } 322