1 /* 2 * Copyright (c) 2013 Luca Clementi <luca.clementi (at) gmail.com> 3 * Copyright (c) 2013-2017 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 <limits.h> 30 #include <libunwind-ptrace.h> 31 32 #ifdef _LARGEFILE64_SOURCE 33 # ifdef HAVE_FOPEN64 34 # define fopen_for_input fopen64 35 # else 36 # define fopen_for_input fopen 37 # endif 38 #else 39 # define fopen_for_input fopen 40 #endif 41 42 #define DPRINTF(F, A, ...) \ 43 do { \ 44 if (debug_flag) \ 45 error_msg("[unwind(" A ")] " F, __VA_ARGS__); \ 46 } while (0) 47 48 /* 49 * Keep a sorted array of cache entries, 50 * so that we can binary search through it. 51 */ 52 struct mmap_cache_t { 53 /** 54 * example entry: 55 * 7fabbb09b000-7fabbb09f000 r-xp 00179000 fc:00 1180246 /lib/libc-2.11.1.so 56 * 57 * start_addr is 0x7fabbb09b000 58 * end_addr is 0x7fabbb09f000 59 * mmap_offset is 0x179000 60 * binary_filename is "/lib/libc-2.11.1.so" 61 */ 62 unsigned long start_addr; 63 unsigned long end_addr; 64 unsigned long mmap_offset; 65 char *binary_filename; 66 }; 67 68 /* 69 * Type used in stacktrace walker 70 */ 71 typedef void (*call_action_fn)(void *data, 72 const char *binary_filename, 73 const char *symbol_name, 74 unw_word_t function_offset, 75 unsigned long true_offset); 76 typedef void (*error_action_fn)(void *data, 77 const char *error, 78 unsigned long true_offset); 79 80 /* 81 * Type used in stacktrace capturing 82 */ 83 struct call_t { 84 struct call_t *next; 85 char *output_line; 86 }; 87 88 struct queue_t { 89 struct call_t *tail; 90 struct call_t *head; 91 }; 92 93 static void queue_print(struct queue_t *queue); 94 static void delete_mmap_cache(struct tcb *tcp, const char *caller); 95 96 static unw_addr_space_t libunwind_as; 97 static unsigned int mmap_cache_generation; 98 99 void 100 unwind_init(void) 101 { 102 libunwind_as = unw_create_addr_space(&_UPT_accessors, 0); 103 if (!libunwind_as) 104 error_msg_and_die("failed to create address space for stack tracing"); 105 unw_set_caching_policy(libunwind_as, UNW_CACHE_GLOBAL); 106 } 107 108 void 109 unwind_tcb_init(struct tcb *tcp) 110 { 111 if (tcp->libunwind_ui) 112 return; 113 114 tcp->libunwind_ui = _UPT_create(tcp->pid); 115 if (!tcp->libunwind_ui) 116 perror_msg_and_die("_UPT_create"); 117 118 tcp->queue = xmalloc(sizeof(*tcp->queue)); 119 tcp->queue->head = NULL; 120 tcp->queue->tail = NULL; 121 } 122 123 void 124 unwind_tcb_fin(struct tcb *tcp) 125 { 126 queue_print(tcp->queue); 127 free(tcp->queue); 128 tcp->queue = NULL; 129 130 delete_mmap_cache(tcp, __func__); 131 132 _UPT_destroy(tcp->libunwind_ui); 133 tcp->libunwind_ui = NULL; 134 } 135 136 /* 137 * caching of /proc/ID/maps for each process to speed up stack tracing 138 * 139 * The cache must be refreshed after syscalls that affect memory mappings, 140 * e.g. mmap, mprotect, munmap, execve. 141 */ 142 static void 143 build_mmap_cache(struct tcb *tcp) 144 { 145 FILE *fp; 146 struct mmap_cache_t *cache_head; 147 /* start with a small dynamically-allocated array and then expand it */ 148 size_t cur_array_size = 10; 149 char filename[sizeof("/proc/4294967296/maps")]; 150 char buffer[PATH_MAX + 80]; 151 152 unw_flush_cache(libunwind_as, 0, 0); 153 154 sprintf(filename, "/proc/%u/maps", tcp->pid); 155 fp = fopen_for_input(filename, "r"); 156 if (!fp) { 157 perror_msg("fopen: %s", filename); 158 return; 159 } 160 161 cache_head = xcalloc(cur_array_size, sizeof(*cache_head)); 162 163 while (fgets(buffer, sizeof(buffer), fp) != NULL) { 164 struct mmap_cache_t *entry; 165 unsigned long start_addr, end_addr, mmap_offset; 166 char exec_bit; 167 char binary_path[sizeof(buffer)]; 168 169 if (sscanf(buffer, "%lx-%lx %*c%*c%c%*c %lx %*x:%*x %*d %[^\n]", 170 &start_addr, &end_addr, &exec_bit, 171 &mmap_offset, binary_path) != 5) 172 continue; 173 174 /* ignore mappings that have no PROT_EXEC bit set */ 175 if (exec_bit != 'x') 176 continue; 177 178 if (end_addr < start_addr) { 179 error_msg("%s: unrecognized file format", filename); 180 break; 181 } 182 183 /* 184 * sanity check to make sure that we're storing 185 * non-overlapping regions in ascending order 186 */ 187 if (tcp->mmap_cache_size > 0) { 188 entry = &cache_head[tcp->mmap_cache_size - 1]; 189 if (entry->start_addr == start_addr && 190 entry->end_addr == end_addr) { 191 /* duplicate entry, e.g. [vsyscall] */ 192 continue; 193 } 194 if (start_addr <= entry->start_addr || 195 start_addr < entry->end_addr) { 196 error_msg("%s: overlapping memory region", 197 filename); 198 continue; 199 } 200 } 201 202 if (tcp->mmap_cache_size >= cur_array_size) { 203 cur_array_size *= 2; 204 cache_head = xreallocarray(cache_head, cur_array_size, 205 sizeof(*cache_head)); 206 } 207 208 entry = &cache_head[tcp->mmap_cache_size]; 209 entry->start_addr = start_addr; 210 entry->end_addr = end_addr; 211 entry->mmap_offset = mmap_offset; 212 entry->binary_filename = xstrdup(binary_path); 213 tcp->mmap_cache_size++; 214 } 215 fclose(fp); 216 tcp->mmap_cache = cache_head; 217 tcp->mmap_cache_generation = mmap_cache_generation; 218 219 DPRINTF("tgen=%u, ggen=%u, tcp=%p, cache=%p", 220 "cache-build", 221 tcp->mmap_cache_generation, 222 mmap_cache_generation, 223 tcp, tcp->mmap_cache); 224 } 225 226 /* deleting the cache */ 227 static void 228 delete_mmap_cache(struct tcb *tcp, const char *caller) 229 { 230 unsigned int i; 231 232 DPRINTF("tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s", 233 "cache-delete", 234 tcp->mmap_cache_generation, 235 mmap_cache_generation, 236 tcp, tcp->mmap_cache, caller); 237 238 for (i = 0; i < tcp->mmap_cache_size; i++) { 239 free(tcp->mmap_cache[i].binary_filename); 240 tcp->mmap_cache[i].binary_filename = NULL; 241 } 242 free(tcp->mmap_cache); 243 tcp->mmap_cache = NULL; 244 tcp->mmap_cache_size = 0; 245 } 246 247 static bool 248 rebuild_cache_if_invalid(struct tcb *tcp, const char *caller) 249 { 250 if ((tcp->mmap_cache_generation != mmap_cache_generation) 251 && tcp->mmap_cache) 252 delete_mmap_cache(tcp, caller); 253 254 if (!tcp->mmap_cache) 255 build_mmap_cache(tcp); 256 257 if (!tcp->mmap_cache || !tcp->mmap_cache_size) 258 return false; 259 else 260 return true; 261 } 262 263 void 264 unwind_cache_invalidate(struct tcb *tcp) 265 { 266 #if SUPPORTED_PERSONALITIES > 1 267 if (tcp->currpers != DEFAULT_PERSONALITY) { 268 /* disable strack trace */ 269 return; 270 } 271 #endif 272 mmap_cache_generation++; 273 DPRINTF("tgen=%u, ggen=%u, tcp=%p, cache=%p", "increment", 274 tcp->mmap_cache_generation, 275 mmap_cache_generation, 276 tcp, 277 tcp->mmap_cache); 278 } 279 280 static void 281 get_symbol_name(unw_cursor_t *cursor, char **name, 282 size_t *size, unw_word_t *offset) 283 { 284 for (;;) { 285 int rc = unw_get_proc_name(cursor, *name, *size, offset); 286 if (rc == 0) 287 break; 288 if (rc != -UNW_ENOMEM) { 289 **name = '\0'; 290 *offset = 0; 291 break; 292 } 293 *name = xreallocarray(*name, 2, *size); 294 *size *= 2; 295 } 296 } 297 298 static int 299 print_stack_frame(struct tcb *tcp, 300 call_action_fn call_action, 301 error_action_fn error_action, 302 void *data, 303 unw_cursor_t *cursor, 304 char **symbol_name, 305 size_t *symbol_name_size) 306 { 307 unw_word_t ip; 308 int lower = 0; 309 int upper = (int) tcp->mmap_cache_size - 1; 310 311 if (unw_get_reg(cursor, UNW_REG_IP, &ip) < 0) { 312 perror_msg("Can't walk the stack of process %d", tcp->pid); 313 return -1; 314 } 315 316 while (lower <= upper) { 317 struct mmap_cache_t *cur_mmap_cache; 318 int mid = (upper + lower) / 2; 319 320 cur_mmap_cache = &tcp->mmap_cache[mid]; 321 322 if (ip >= cur_mmap_cache->start_addr && 323 ip < cur_mmap_cache->end_addr) { 324 unsigned long true_offset; 325 unw_word_t function_offset; 326 327 get_symbol_name(cursor, symbol_name, symbol_name_size, 328 &function_offset); 329 true_offset = ip - cur_mmap_cache->start_addr + 330 cur_mmap_cache->mmap_offset; 331 call_action(data, 332 cur_mmap_cache->binary_filename, 333 *symbol_name, 334 function_offset, 335 true_offset); 336 return 0; 337 } else if (ip < cur_mmap_cache->start_addr) 338 upper = mid - 1; 339 else 340 lower = mid + 1; 341 } 342 343 /* 344 * there is a bug in libunwind >= 1.0 345 * after a set_tid_address syscall 346 * unw_get_reg returns IP == 0 347 */ 348 if (ip) 349 error_action(data, "unexpected_backtracing_error", ip); 350 return -1; 351 } 352 353 /* 354 * walking the stack 355 */ 356 static void 357 stacktrace_walk(struct tcb *tcp, 358 call_action_fn call_action, 359 error_action_fn error_action, 360 void *data) 361 { 362 char *symbol_name; 363 size_t symbol_name_size = 40; 364 unw_cursor_t cursor; 365 int stack_depth; 366 367 if (!tcp->mmap_cache) 368 error_msg_and_die("bug: mmap_cache is NULL"); 369 if (tcp->mmap_cache_size == 0) 370 error_msg_and_die("bug: mmap_cache is empty"); 371 372 symbol_name = xmalloc(symbol_name_size); 373 374 if (unw_init_remote(&cursor, libunwind_as, tcp->libunwind_ui) < 0) 375 perror_msg_and_die("Can't initiate libunwind"); 376 377 for (stack_depth = 0; stack_depth < 256; ++stack_depth) { 378 if (print_stack_frame(tcp, call_action, error_action, data, 379 &cursor, &symbol_name, &symbol_name_size) < 0) 380 break; 381 if (unw_step(&cursor) <= 0) 382 break; 383 } 384 if (stack_depth >= 256) 385 error_action(data, "too many stack frames", 0); 386 387 free(symbol_name); 388 } 389 390 /* 391 * printing an entry in stack to stream or buffer 392 */ 393 /* 394 * we want to keep the format used by backtrace_symbols from the glibc 395 * 396 * ./a.out() [0x40063d] 397 * ./a.out() [0x4006bb] 398 * ./a.out() [0x4006c6] 399 * /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d] 400 * ./a.out() [0x400569] 401 */ 402 #define STACK_ENTRY_SYMBOL_FMT \ 403 " > %s(%s+0x%lx) [0x%lx]\n", \ 404 binary_filename, \ 405 symbol_name, \ 406 (unsigned long) function_offset, \ 407 true_offset 408 #define STACK_ENTRY_NOSYMBOL_FMT \ 409 " > %s() [0x%lx]\n", \ 410 binary_filename, true_offset 411 #define STACK_ENTRY_BUG_FMT \ 412 " > BUG IN %s\n" 413 #define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \ 414 " > %s [0x%lx]\n", error, true_offset 415 #define STACK_ENTRY_ERROR_FMT \ 416 " > %s\n", error 417 418 static void 419 print_call_cb(void *dummy, 420 const char *binary_filename, 421 const char *symbol_name, 422 unw_word_t function_offset, 423 unsigned long true_offset) 424 { 425 if (symbol_name && (symbol_name[0] != '\0')) 426 tprintf(STACK_ENTRY_SYMBOL_FMT); 427 else if (binary_filename) 428 tprintf(STACK_ENTRY_NOSYMBOL_FMT); 429 else 430 tprintf(STACK_ENTRY_BUG_FMT, __func__); 431 432 line_ended(); 433 } 434 435 static void 436 print_error_cb(void *dummy, 437 const char *error, 438 unsigned long true_offset) 439 { 440 if (true_offset) 441 tprintf(STACK_ENTRY_ERROR_WITH_OFFSET_FMT); 442 else 443 tprintf(STACK_ENTRY_ERROR_FMT); 444 445 line_ended(); 446 } 447 448 static char * 449 sprint_call_or_error(const char *binary_filename, 450 const char *symbol_name, 451 unw_word_t function_offset, 452 unsigned long true_offset, 453 const char *error) 454 { 455 char *output_line = NULL; 456 int n; 457 458 if (symbol_name) 459 n = asprintf(&output_line, STACK_ENTRY_SYMBOL_FMT); 460 else if (binary_filename) 461 n = asprintf(&output_line, STACK_ENTRY_NOSYMBOL_FMT); 462 else if (error) 463 n = true_offset 464 ? asprintf(&output_line, STACK_ENTRY_ERROR_WITH_OFFSET_FMT) 465 : asprintf(&output_line, STACK_ENTRY_ERROR_FMT); 466 else 467 n = asprintf(&output_line, STACK_ENTRY_BUG_FMT, __func__); 468 469 if (n < 0) 470 error_msg_and_die("error in asprintf"); 471 472 return output_line; 473 } 474 475 /* 476 * queue manipulators 477 */ 478 static void 479 queue_put(struct queue_t *queue, 480 const char *binary_filename, 481 const char *symbol_name, 482 unw_word_t function_offset, 483 unsigned long true_offset, 484 const char *error) 485 { 486 struct call_t *call; 487 488 call = xmalloc(sizeof(*call)); 489 call->output_line = sprint_call_or_error(binary_filename, 490 symbol_name, 491 function_offset, 492 true_offset, 493 error); 494 call->next = NULL; 495 496 if (!queue->head) { 497 queue->head = call; 498 queue->tail = call; 499 } else { 500 queue->tail->next = call; 501 queue->tail = call; 502 } 503 } 504 505 static void 506 queue_put_call(void *queue, 507 const char *binary_filename, 508 const char *symbol_name, 509 unw_word_t function_offset, 510 unsigned long true_offset) 511 { 512 queue_put(queue, 513 binary_filename, 514 symbol_name, 515 function_offset, 516 true_offset, 517 NULL); 518 } 519 520 static void 521 queue_put_error(void *queue, 522 const char *error, 523 unsigned long ip) 524 { 525 queue_put(queue, NULL, NULL, 0, ip, error); 526 } 527 528 static void 529 queue_print(struct queue_t *queue) 530 { 531 struct call_t *call, *tmp; 532 533 queue->tail = NULL; 534 call = queue->head; 535 queue->head = NULL; 536 while (call) { 537 tmp = call; 538 call = call->next; 539 540 tprints(tmp->output_line); 541 line_ended(); 542 543 free(tmp->output_line); 544 tmp->output_line = NULL; 545 tmp->next = NULL; 546 free(tmp); 547 } 548 } 549 550 /* 551 * printing stack 552 */ 553 void 554 unwind_print_stacktrace(struct tcb *tcp) 555 { 556 #if SUPPORTED_PERSONALITIES > 1 557 if (tcp->currpers != DEFAULT_PERSONALITY) { 558 /* disable strack trace */ 559 return; 560 } 561 #endif 562 if (tcp->queue->head) { 563 DPRINTF("tcp=%p, queue=%p", "queueprint", tcp, tcp->queue->head); 564 queue_print(tcp->queue); 565 } else if (rebuild_cache_if_invalid(tcp, __func__)) { 566 DPRINTF("tcp=%p, queue=%p", "stackprint", tcp, tcp->queue->head); 567 stacktrace_walk(tcp, print_call_cb, print_error_cb, NULL); 568 } 569 } 570 571 /* 572 * capturing stack 573 */ 574 void 575 unwind_capture_stacktrace(struct tcb *tcp) 576 { 577 #if SUPPORTED_PERSONALITIES > 1 578 if (tcp->currpers != DEFAULT_PERSONALITY) { 579 /* disable strack trace */ 580 return; 581 } 582 #endif 583 if (tcp->queue->head) 584 error_msg_and_die("bug: unprinted entries in queue"); 585 586 if (rebuild_cache_if_invalid(tcp, __func__)) { 587 stacktrace_walk(tcp, queue_put_call, queue_put_error, 588 tcp->queue); 589 DPRINTF("tcp=%p, queue=%p", "captured", tcp, tcp->queue->head); 590 } 591 } 592