trace.c 6.5 KB

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