Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

unwind-libunwind.c 3.6KB

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