(root)/
strace-6.5/
src/
unwind-libunwind.c
       1  /*
       2   * Copyright (c) 2013 Luca Clementi <luca.clementi@gmail.com>
       3   * Copyright (c) 2013-2021 The strace developers.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   */
       7  
       8  #include "defs.h"
       9  #include "unwind.h"
      10  
      11  #include "mmap_cache.h"
      12  #include <libunwind-ptrace.h>
      13  
      14  static unw_addr_space_t libunwind_as;
      15  
      16  static void
      17  init(void)
      18  {
      19  	mmap_cache_enable();
      20  
      21  	libunwind_as = unw_create_addr_space(&_UPT_accessors, 0);
      22  	if (!libunwind_as)
      23  		error_msg_and_die("failed to create address space"
      24  				  " for stack tracing");
      25  	unw_set_caching_policy(libunwind_as, UNW_CACHE_GLOBAL);
      26  }
      27  
      28  static void *
      29  tcb_init(struct tcb *tcp)
      30  {
      31  	void *r = _UPT_create(tcp->pid);
      32  
      33  	if (!r)
      34  		perror_msg_and_die("_UPT_create");
      35  	return r;
      36  }
      37  
      38  static void
      39  tcb_fin(struct tcb *tcp)
      40  {
      41  	_UPT_destroy(tcp->unwind_ctx);
      42  }
      43  
      44  static void
      45  get_symbol_name(unw_cursor_t *cursor, char **name,
      46  		size_t *size, unw_word_t *offset)
      47  {
      48  	for (;;) {
      49  		int rc = unw_get_proc_name(cursor, *name, *size, offset);
      50  
      51  		if (rc == 0)
      52  			break;
      53  		if (rc != -UNW_ENOMEM) {
      54  			**name = '\0';
      55  			*offset = 0;
      56  			break;
      57  		}
      58  		*name = xgrowarray(*name, size, 1);
      59  	}
      60  }
      61  
      62  static int
      63  print_stack_frame(struct tcb *tcp,
      64  		  unwind_call_action_fn call_action,
      65  		  unwind_error_action_fn error_action,
      66  		  void *data,
      67  		  unw_cursor_t *cursor,
      68  		  char **symbol_name,
      69  		  size_t *symbol_name_size)
      70  {
      71  	unw_word_t ip;
      72  
      73  	if (unw_get_reg(cursor, UNW_REG_IP, &ip) < 0) {
      74  		perror_msg("cannot walk the stack of process %d", tcp->pid);
      75  		return -1;
      76  	}
      77  
      78  	struct mmap_cache_entry_t *entry = mmap_cache_search(tcp, ip);
      79  
      80  	if (entry
      81  	    /* ignore mappings that have no PROT_EXEC bit set */
      82  	    && (entry->protections & MMAP_CACHE_PROT_EXECUTABLE)) {
      83  		unw_word_t function_offset;
      84  
      85  		get_symbol_name(cursor, symbol_name, symbol_name_size,
      86  				&function_offset);
      87  		unsigned long true_offset =
      88  			ip - entry->start_addr + entry->mmap_offset;
      89  		call_action(data,
      90  			    entry->binary_filename,
      91  			    *symbol_name,
      92  			    function_offset,
      93  			    true_offset);
      94  
      95  		return 0;
      96  	}
      97  
      98  	/*
      99  	 * there is a bug in libunwind >= 1.0
     100  	 * after a set_tid_address syscall
     101  	 * unw_get_reg returns IP == 0
     102  	 */
     103  	if (ip)
     104  		error_action(data, "unexpected_backtracing_error", ip);
     105  	return -1;
     106  }
     107  
     108  static void
     109  walk(struct tcb *tcp,
     110       unwind_call_action_fn call_action,
     111       unwind_error_action_fn error_action,
     112       void *data)
     113  {
     114  	char *symbol_name;
     115  	size_t symbol_name_size = 40;
     116  	unw_cursor_t cursor;
     117  	int stack_depth;
     118  
     119  	if (!tcp->mmap_cache)
     120  		error_func_msg_and_die("mmap_cache is NULL");
     121  
     122  	symbol_name = xmalloc(symbol_name_size);
     123  
     124  	if (unw_init_remote(&cursor, libunwind_as, tcp->unwind_ctx) < 0)
     125  		perror_func_msg_and_die("cannot initialize libunwind");
     126  
     127  	for (stack_depth = 0; stack_depth < 256; ++stack_depth) {
     128  		if (print_stack_frame(tcp, call_action, error_action, data,
     129  				&cursor, &symbol_name, &symbol_name_size) < 0)
     130  			break;
     131  		if (unw_step(&cursor) <= 0)
     132  			break;
     133  	}
     134  	if (stack_depth >= 256)
     135  		error_action(data, "too many stack frames", 0);
     136  
     137  	free(symbol_name);
     138  }
     139  
     140  static void
     141  tcb_walk(struct tcb *tcp,
     142  	 unwind_call_action_fn call_action,
     143  	 unwind_error_action_fn error_action,
     144  	 void *data)
     145  {
     146  	switch (mmap_cache_rebuild_if_invalid(tcp, __func__)) {
     147  		case MMAP_CACHE_REBUILD_RENEWED:
     148  			/*
     149  			 * Rebuild the unwinder internal cache.
     150  			 * Called when mmap cache subsystem detects a
     151  			 * change of tracee memory mapping.
     152  			 */
     153  			unw_flush_cache(libunwind_as, 0, 0);
     154  			ATTRIBUTE_FALLTHROUGH;
     155  		case MMAP_CACHE_REBUILD_READY:
     156  			walk(tcp, call_action, error_action, data);
     157  			break;
     158  		default:
     159  			/* Do nothing */
     160  			;
     161  	}
     162  }
     163  
     164  const struct unwind_unwinder_t unwinder = {
     165  	.name = "libunwind",
     166  	.init = init,
     167  	.tcb_init = tcb_init,
     168  	.tcb_fin = tcb_fin,
     169  	.tcb_walk = tcb_walk,
     170  };