backtrace.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2013, Digium, Inc.
  5. *
  6. * Matt Jordan <mjordan@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. * \brief Asterisk backtrace generation
  20. *
  21. * This file provides backtrace generation utilities
  22. */
  23. /*** MODULEINFO
  24. <support_level>core</support_level>
  25. ***/
  26. /*
  27. * Block automatic include of asterisk/lock.h to allow use of pthread_mutex
  28. * functions directly. We don't need or want the lock.h overhead.
  29. */
  30. #define _ASTERISK_LOCK_H
  31. #include "asterisk.h"
  32. #include "asterisk/backtrace.h"
  33. /*
  34. * The astmm ast_ memory management functions can cause ast_bt_get_symbols
  35. * to be invoked so we must not use them. To use the libc functions, we
  36. * could call the ast_std_ functions but the vector macros call ast_calloc,
  37. * ast_free and ast_malloc so it just makes sense to undef the standard
  38. * function overrides and use them directly.
  39. */
  40. #undef malloc
  41. #undef calloc
  42. #undef strdup
  43. #undef free
  44. /*
  45. * As stated above, the vector macros call the ast_ functions so
  46. * we need to remap those back to the libc ones.
  47. */
  48. #undef ast_free
  49. #undef ast_calloc
  50. #undef ast_malloc
  51. #define ast_free(x) free(x)
  52. #define ast_calloc(n, x) calloc(n, x)
  53. #define ast_malloc(x) malloc(x)
  54. #include "asterisk/vector.h"
  55. #ifdef HAVE_BKTR
  56. #include <execinfo.h>
  57. #if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
  58. #include <dlfcn.h>
  59. #include <bfd.h>
  60. #endif
  61. #include <pthread.h>
  62. /* simple definition of S_OR so we don't have include strings.h */
  63. #define S_OR(a, b) (a && a[0] != '\0') ? a : b
  64. struct ast_bt *__ast_bt_create(void)
  65. {
  66. struct ast_bt *bt = calloc(1, sizeof(*bt));
  67. if (!bt) {
  68. return NULL;
  69. }
  70. bt->alloced = 1;
  71. ast_bt_get_addresses(bt);
  72. return bt;
  73. }
  74. int __ast_bt_get_addresses(struct ast_bt *bt)
  75. {
  76. bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
  77. return 0;
  78. }
  79. void *__ast_bt_destroy(struct ast_bt *bt)
  80. {
  81. if (bt && bt->alloced) {
  82. free(bt);
  83. }
  84. return NULL;
  85. }
  86. #ifdef BETTER_BACKTRACES
  87. struct bfd_data {
  88. struct ast_vector_string *return_strings;
  89. bfd_vma pc; /* bfd.h */
  90. asymbol **syms; /* bfd.h */
  91. Dl_info dli; /* dlfcn.h */
  92. const char *libname;
  93. int dynamic;
  94. int has_syms;
  95. char *msg;
  96. int found;
  97. };
  98. #define MSG_BUFF_LEN 1024
  99. static void process_section(bfd *bfdobj, asection *section, void *obj)
  100. {
  101. struct bfd_data *data = obj;
  102. const char *file, *func;
  103. unsigned int line;
  104. bfd_vma offset;
  105. bfd_vma vma;
  106. bfd_size_type size;
  107. bfd_boolean line_found = 0;
  108. char *fn;
  109. int inlined = 0;
  110. offset = data->pc - (data->dynamic ? (bfd_vma)(uintptr_t) data->dli.dli_fbase : 0);
  111. if (!(bfd_get_section_flags(bfdobj, section) & SEC_ALLOC)) {
  112. return;
  113. }
  114. vma = bfd_get_section_vma(bfdobj, section);
  115. size = bfd_get_section_size(section);
  116. if (offset < vma || offset >= vma + size) {
  117. /* Not in this section */
  118. return;
  119. }
  120. line_found = bfd_find_nearest_line(bfdobj, section, data->syms, offset - vma, &file,
  121. &func, &line);
  122. if (!line_found) {
  123. return;
  124. }
  125. /*
  126. * If we find a line, we will want to continue calling bfd_find_inliner_info
  127. * to capture any inlined functions that don't have their own stack frames.
  128. */
  129. do {
  130. data->found++;
  131. /* file can possibly be null even with a success result from bfd_find_nearest_line */
  132. file = file ? file : "";
  133. fn = strrchr(file, '/');
  134. #define FMT_INLINED "[%s] %s %s:%u %s()"
  135. #define FMT_NOT_INLINED "[%p] %s %s:%u %s()"
  136. snprintf(data->msg, MSG_BUFF_LEN, inlined ? FMT_INLINED : FMT_NOT_INLINED,
  137. inlined ? "inlined" : (char *)(uintptr_t) data->pc,
  138. data->libname,
  139. fn ? fn + 1 : file,
  140. line, S_OR(func, "???"));
  141. if (AST_VECTOR_APPEND(data->return_strings, strdup(data->msg))) {
  142. return;
  143. }
  144. inlined++;
  145. /* Let's see if there are any inlined functions */
  146. } while (bfd_find_inliner_info(bfdobj, &file, &func, &line));
  147. }
  148. struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
  149. {
  150. struct ast_vector_string *return_strings;
  151. int stackfr;
  152. bfd *bfdobj;
  153. long allocsize;
  154. char msg[MSG_BUFF_LEN];
  155. static pthread_mutex_t bfd_mutex = PTHREAD_MUTEX_INITIALIZER;
  156. return_strings = malloc(sizeof(struct ast_vector_string));
  157. if (!return_strings) {
  158. return NULL;
  159. }
  160. if (AST_VECTOR_INIT(return_strings, num_frames)) {
  161. free(return_strings);
  162. return NULL;
  163. }
  164. for (stackfr = 0; stackfr < num_frames; stackfr++) {
  165. int symbolcount;
  166. struct bfd_data data = {
  167. .return_strings = return_strings,
  168. .msg = msg,
  169. .pc = (bfd_vma)(uintptr_t) addresses[stackfr],
  170. .found = 0,
  171. .dynamic = 0,
  172. };
  173. msg[0] = '\0';
  174. if (!dladdr((void *)(uintptr_t) data.pc, &data.dli)) {
  175. continue;
  176. }
  177. data.libname = strrchr(data.dli.dli_fname, '/');
  178. if (!data.libname) {
  179. data.libname = data.dli.dli_fname;
  180. } else {
  181. data.libname++;
  182. }
  183. pthread_mutex_lock(&bfd_mutex);
  184. /* Using do while(0) here makes it easier to escape and clean up */
  185. do {
  186. bfdobj = bfd_openr(data.dli.dli_fname, NULL);
  187. if (!bfdobj) {
  188. break;
  189. }
  190. /* bfd_check_format does more than check. It HAS to be called */
  191. if (!bfd_check_format(bfdobj, bfd_object)) {
  192. break;
  193. }
  194. data.has_syms = !!(bfd_get_file_flags(bfdobj) & HAS_SYMS);
  195. data.dynamic = !!(bfd_get_file_flags(bfdobj) & DYNAMIC);
  196. if (!data.has_syms) {
  197. break;
  198. }
  199. allocsize = data.dynamic ?
  200. bfd_get_dynamic_symtab_upper_bound(bfdobj) : bfd_get_symtab_upper_bound(bfdobj);
  201. if (allocsize < 0) {
  202. break;
  203. }
  204. data.syms = malloc(allocsize);
  205. if (!data.syms) {
  206. break;
  207. }
  208. symbolcount = data.dynamic ?
  209. bfd_canonicalize_dynamic_symtab(bfdobj, data.syms) : bfd_canonicalize_symtab(bfdobj, data.syms);
  210. if (symbolcount < 0) {
  211. break;
  212. }
  213. bfd_map_over_sections(bfdobj, process_section, &data);
  214. } while(0);
  215. if (bfdobj) {
  216. bfd_close(bfdobj);
  217. free(data.syms);
  218. data.syms = NULL;
  219. }
  220. pthread_mutex_unlock(&bfd_mutex);
  221. /* Default output, if we cannot find the information within BFD */
  222. if (!data.found) {
  223. snprintf(msg, sizeof(msg), "%s %s()",
  224. data.libname,
  225. S_OR(data.dli.dli_sname, "<unknown>"));
  226. AST_VECTOR_APPEND(return_strings, strdup(msg));
  227. }
  228. }
  229. return return_strings;
  230. }
  231. #else
  232. struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
  233. {
  234. char **strings;
  235. struct ast_vector_string *return_strings;
  236. int i;
  237. return_strings = malloc(sizeof(struct ast_vector_string));
  238. if (!return_strings) {
  239. return NULL;
  240. }
  241. if (AST_VECTOR_INIT(return_strings, num_frames)) {
  242. free(return_strings);
  243. return NULL;
  244. }
  245. strings = backtrace_symbols(addresses, num_frames);
  246. if (strings) {
  247. for (i = 0; i < num_frames; i++) {
  248. AST_VECTOR_APPEND(return_strings, strdup(strings[i]));
  249. }
  250. free(strings);
  251. }
  252. return return_strings;
  253. }
  254. #endif /* BETTER_BACKTRACES */
  255. void __ast_bt_free_symbols(struct ast_vector_string *symbols)
  256. {
  257. AST_VECTOR_CALLBACK_VOID(symbols, free);
  258. AST_VECTOR_PTR_FREE(symbols);
  259. }
  260. #endif /* HAVE_BKTR */