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-libdw.c 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * This file is based on a patch submitted by Mark Wielaard <mjw@redhat.com>
  3. * to ltrace project:
  4. * https://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=dfefa9f057857735a073ea655f5cb34351032c8e
  5. *
  6. * It was re-licensed for strace by the original author:
  7. * https://lists.strace.io/pipermail/strace-devel/2018-March/008063.html
  8. *
  9. * Copyright (c) 2014-2018 Mark Wielaard <mjw@redhat.com>
  10. * Copyright (c) 2018 Masatake YAMATO <yamato@redhat.com>
  11. * Copyright (c) 2018 The strace developers.
  12. * All rights reserved.
  13. *
  14. * SPDX-License-Identifier: LGPL-2.1-or-later
  15. */
  16. #include "defs.h"
  17. #include "unwind.h"
  18. #include "mmap_notify.h"
  19. #include <elfutils/libdwfl.h>
  20. struct ctx {
  21. Dwfl *dwfl;
  22. unsigned int last_proc_updating;
  23. };
  24. static unsigned int mapping_generation;
  25. static void
  26. update_mapping_generation(struct tcb *tcp, void *unused)
  27. {
  28. mapping_generation++;
  29. }
  30. static void
  31. init(void)
  32. {
  33. mmap_notify_register_client(update_mapping_generation, NULL);
  34. }
  35. static void *
  36. tcb_init(struct tcb *tcp)
  37. {
  38. static const Dwfl_Callbacks proc_callbacks = {
  39. .find_elf = dwfl_linux_proc_find_elf,
  40. .find_debuginfo = dwfl_standard_find_debuginfo
  41. };
  42. Dwfl *dwfl = dwfl_begin(&proc_callbacks);
  43. if (dwfl == NULL) {
  44. error_msg("dwfl_begin: %s", dwfl_errmsg(-1));
  45. return NULL;
  46. }
  47. int r = dwfl_linux_proc_attach(dwfl, tcp->pid, true);
  48. if (r) {
  49. const char *msg = NULL;
  50. if (r < 0)
  51. msg = dwfl_errmsg(-1);
  52. else if (r > 0)
  53. msg = strerror(r);
  54. error_msg("dwfl_linux_proc_attach returned an error"
  55. " for process %d: %s", tcp->pid, msg);
  56. dwfl_end(dwfl);
  57. return NULL;
  58. }
  59. struct ctx *ctx = xmalloc(sizeof(*ctx));
  60. ctx->dwfl = dwfl;
  61. ctx->last_proc_updating = 0;
  62. return ctx;
  63. }
  64. static void
  65. tcb_fin(struct tcb *tcp)
  66. {
  67. struct ctx *ctx = tcp->unwind_ctx;
  68. if (ctx) {
  69. dwfl_end(ctx->dwfl);
  70. free(ctx);
  71. }
  72. }
  73. static void
  74. flush_cache_maybe(struct tcb *tcp)
  75. {
  76. struct ctx *ctx = tcp->unwind_ctx;
  77. if (!ctx)
  78. return;
  79. if (ctx->last_proc_updating == mapping_generation)
  80. return;
  81. int r = dwfl_linux_proc_report(ctx->dwfl, tcp->pid);
  82. if (r < 0)
  83. error_msg("dwfl_linux_proc_report returned an error"
  84. " for pid %d: %s", tcp->pid, dwfl_errmsg(-1));
  85. else if (r > 0)
  86. error_msg("dwfl_linux_proc_report returned an error"
  87. " for pid %d", tcp->pid);
  88. else if (dwfl_report_end(ctx->dwfl, NULL, NULL) != 0)
  89. error_msg("dwfl_report_end returned an error"
  90. " for pid %d: %s", tcp->pid, dwfl_errmsg(-1));
  91. ctx->last_proc_updating = mapping_generation;
  92. }
  93. struct frame_user_data {
  94. unwind_call_action_fn call_action;
  95. unwind_error_action_fn error_action;
  96. void *data;
  97. int stack_depth;
  98. };
  99. static int
  100. frame_callback(Dwfl_Frame *state, void *arg)
  101. {
  102. struct frame_user_data *user_data = arg;
  103. Dwarf_Addr pc;
  104. bool isactivation;
  105. if (!dwfl_frame_pc(state, &pc, &isactivation)) {
  106. /* Propagate the error to the caller. */
  107. return -1;
  108. }
  109. if (!isactivation)
  110. pc--;
  111. Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(state));
  112. Dwfl_Module *mod = dwfl_addrmodule(dwfl, pc);
  113. GElf_Off off = 0;
  114. if (mod != NULL) {
  115. const char *modname = NULL;
  116. const char *symname = NULL;
  117. GElf_Sym sym;
  118. Dwarf_Addr true_offset = pc;
  119. modname = dwfl_module_info(mod, NULL, NULL, NULL, NULL,
  120. NULL, NULL, NULL);
  121. symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
  122. NULL, NULL, NULL);
  123. dwfl_module_relocate_address(mod, &true_offset);
  124. user_data->call_action(user_data->data, modname, symname,
  125. off, true_offset);
  126. }
  127. /* Max number of frames to print reached? */
  128. if (user_data->stack_depth-- == 0)
  129. return DWARF_CB_ABORT;
  130. return DWARF_CB_OK;
  131. }
  132. static void
  133. tcb_walk(struct tcb *tcp,
  134. unwind_call_action_fn call_action,
  135. unwind_error_action_fn error_action,
  136. void *data)
  137. {
  138. struct ctx *ctx = tcp->unwind_ctx;
  139. if (!ctx)
  140. return;
  141. struct frame_user_data user_data = {
  142. .call_action = call_action,
  143. .error_action = error_action,
  144. .data = data,
  145. .stack_depth = 256,
  146. };
  147. flush_cache_maybe(tcp);
  148. int r = dwfl_getthread_frames(ctx->dwfl, tcp->pid, frame_callback,
  149. &user_data);
  150. if (r)
  151. error_action(data,
  152. r < 0 ? dwfl_errmsg(-1) : "too many stack frames",
  153. 0);
  154. }
  155. const struct unwind_unwinder_t unwinder = {
  156. .name = "libdw",
  157. .init = init,
  158. .tcb_init = tcb_init,
  159. .tcb_fin = tcb_fin,
  160. .tcb_walk = tcb_walk,
  161. };