trace.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Backtrace debugging
  3. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "includes.h"
  9. #include "common.h"
  10. #include "trace.h"
  11. #ifdef WPA_TRACE
  12. static struct dl_list active_references =
  13. { &active_references, &active_references };
  14. #ifdef WPA_TRACE_BFD
  15. #include <bfd.h>
  16. #define DMGL_PARAMS (1 << 0)
  17. #define DMGL_ANSI (1 << 1)
  18. static char *prg_fname = NULL;
  19. static bfd *cached_abfd = NULL;
  20. static asymbol **syms = NULL;
  21. static void get_prg_fname(void)
  22. {
  23. char exe[50], fname[512];
  24. int len;
  25. os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
  26. len = readlink(exe, fname, sizeof(fname) - 1);
  27. if (len < 0 || len >= (int) sizeof(fname)) {
  28. wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
  29. return;
  30. }
  31. fname[len] = '\0';
  32. prg_fname = strdup(fname);
  33. }
  34. static bfd * open_bfd(const char *fname)
  35. {
  36. bfd *abfd;
  37. char **matching;
  38. abfd = bfd_openr(prg_fname, NULL);
  39. if (abfd == NULL) {
  40. wpa_printf(MSG_INFO, "bfd_openr failed");
  41. return NULL;
  42. }
  43. if (bfd_check_format(abfd, bfd_archive)) {
  44. wpa_printf(MSG_INFO, "bfd_check_format failed");
  45. bfd_close(abfd);
  46. return NULL;
  47. }
  48. if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
  49. wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
  50. free(matching);
  51. bfd_close(abfd);
  52. return NULL;
  53. }
  54. return abfd;
  55. }
  56. static void read_syms(bfd *abfd)
  57. {
  58. long storage, symcount;
  59. bfd_boolean dynamic = FALSE;
  60. if (syms)
  61. return;
  62. if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
  63. wpa_printf(MSG_INFO, "No symbols");
  64. return;
  65. }
  66. storage = bfd_get_symtab_upper_bound(abfd);
  67. if (storage == 0) {
  68. storage = bfd_get_dynamic_symtab_upper_bound(abfd);
  69. dynamic = TRUE;
  70. }
  71. if (storage < 0) {
  72. wpa_printf(MSG_INFO, "Unknown symtab upper bound");
  73. return;
  74. }
  75. syms = malloc(storage);
  76. if (syms == NULL) {
  77. wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
  78. "(%ld bytes)", storage);
  79. return;
  80. }
  81. if (dynamic)
  82. symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
  83. else
  84. symcount = bfd_canonicalize_symtab(abfd, syms);
  85. if (symcount < 0) {
  86. wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
  87. dynamic ? "dynamic " : "");
  88. free(syms);
  89. syms = NULL;
  90. return;
  91. }
  92. }
  93. struct bfd_data {
  94. bfd_vma pc;
  95. bfd_boolean found;
  96. const char *filename;
  97. const char *function;
  98. unsigned int line;
  99. };
  100. static void find_addr_sect(bfd *abfd, asection *section, void *obj)
  101. {
  102. struct bfd_data *data = obj;
  103. bfd_vma vma;
  104. bfd_size_type size;
  105. if (data->found)
  106. return;
  107. if (!(bfd_get_section_vma(abfd, section)))
  108. return;
  109. vma = bfd_get_section_vma(abfd, section);
  110. if (data->pc < vma)
  111. return;
  112. size = bfd_get_section_size(section);
  113. if (data->pc >= vma + size)
  114. return;
  115. data->found = bfd_find_nearest_line(abfd, section, syms,
  116. data->pc - vma,
  117. &data->filename,
  118. &data->function,
  119. &data->line);
  120. }
  121. static void wpa_trace_bfd_addr(void *pc)
  122. {
  123. bfd *abfd = cached_abfd;
  124. struct bfd_data data;
  125. const char *name;
  126. char *aname = NULL;
  127. const char *filename;
  128. if (abfd == NULL)
  129. return;
  130. data.pc = (bfd_hostptr_t) pc;
  131. data.found = FALSE;
  132. bfd_map_over_sections(abfd, find_addr_sect, &data);
  133. if (!data.found)
  134. return;
  135. do {
  136. if (data.function)
  137. aname = bfd_demangle(abfd, data.function,
  138. DMGL_ANSI | DMGL_PARAMS);
  139. name = aname ? aname : data.function;
  140. filename = data.filename;
  141. if (filename) {
  142. char *end = os_strrchr(filename, '/');
  143. int i = 0;
  144. while (*filename && *filename == prg_fname[i] &&
  145. filename <= end) {
  146. filename++;
  147. i++;
  148. }
  149. }
  150. wpa_printf(MSG_INFO, " %s() %s:%u",
  151. name, filename, data.line);
  152. free(aname);
  153. aname = NULL;
  154. data.found = bfd_find_inliner_info(abfd, &data.filename,
  155. &data.function, &data.line);
  156. } while (data.found);
  157. }
  158. static const char * wpa_trace_bfd_addr2func(void *pc)
  159. {
  160. bfd *abfd = cached_abfd;
  161. struct bfd_data data;
  162. if (abfd == NULL)
  163. return NULL;
  164. data.pc = (bfd_hostptr_t) pc;
  165. data.found = FALSE;
  166. bfd_map_over_sections(abfd, find_addr_sect, &data);
  167. if (!data.found)
  168. return NULL;
  169. return data.function;
  170. }
  171. static void wpa_trace_bfd_init(void)
  172. {
  173. if (!prg_fname) {
  174. get_prg_fname();
  175. if (!prg_fname)
  176. return;
  177. }
  178. if (!cached_abfd) {
  179. cached_abfd = open_bfd(prg_fname);
  180. if (!cached_abfd) {
  181. wpa_printf(MSG_INFO, "Failed to open bfd");
  182. return;
  183. }
  184. }
  185. read_syms(cached_abfd);
  186. if (!syms) {
  187. wpa_printf(MSG_INFO, "Failed to read symbols");
  188. return;
  189. }
  190. }
  191. void wpa_trace_dump_funcname(const char *title, void *pc)
  192. {
  193. wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
  194. wpa_trace_bfd_init();
  195. wpa_trace_bfd_addr(pc);
  196. }
  197. #else /* WPA_TRACE_BFD */
  198. #define wpa_trace_bfd_init() do { } while (0)
  199. #define wpa_trace_bfd_addr(pc) do { } while (0)
  200. #define wpa_trace_bfd_addr2func(pc) NULL
  201. #endif /* WPA_TRACE_BFD */
  202. void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
  203. {
  204. char **sym;
  205. int i;
  206. enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
  207. wpa_trace_bfd_init();
  208. wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
  209. sym = backtrace_symbols(btrace, btrace_num);
  210. state = TRACE_HEAD;
  211. for (i = 0; i < btrace_num; i++) {
  212. const char *func = wpa_trace_bfd_addr2func(btrace[i]);
  213. if (state == TRACE_HEAD && func &&
  214. (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
  215. os_strcmp(func, "wpa_trace_check_ref") == 0 ||
  216. os_strcmp(func, "wpa_trace_show") == 0))
  217. continue;
  218. if (state == TRACE_TAIL && sym && sym[i] &&
  219. os_strstr(sym[i], "__libc_start_main"))
  220. break;
  221. if (state == TRACE_HEAD)
  222. state = TRACE_RELEVANT;
  223. if (sym)
  224. wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
  225. else
  226. wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
  227. wpa_trace_bfd_addr(btrace[i]);
  228. if (state == TRACE_RELEVANT && func &&
  229. os_strcmp(func, "main") == 0)
  230. state = TRACE_TAIL;
  231. }
  232. free(sym);
  233. wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
  234. }
  235. void wpa_trace_show(const char *title)
  236. {
  237. struct info {
  238. WPA_TRACE_INFO
  239. } info;
  240. wpa_trace_record(&info);
  241. wpa_trace_dump(title, &info);
  242. }
  243. void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
  244. {
  245. if (addr == NULL)
  246. return;
  247. ref->addr = addr;
  248. wpa_trace_record(ref);
  249. dl_list_add(&active_references, &ref->list);
  250. }
  251. void wpa_trace_check_ref(const void *addr)
  252. {
  253. struct wpa_trace_ref *ref;
  254. dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
  255. if (addr != ref->addr)
  256. continue;
  257. wpa_trace_show("Freeing referenced memory");
  258. wpa_trace_dump("Reference registration", ref);
  259. abort();
  260. }
  261. }
  262. #endif /* WPA_TRACE */