Home | History | Annotate | Download | only in strace
      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