backtrace.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /* Return backtrace of current program state.
  2. Copyright (C) 2003-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, see
  15. <http://www.gnu.org/licenses/>. */
  16. #include <libc-lock.h>
  17. #include <dlfcn.h>
  18. #include <execinfo.h>
  19. #include <gnu/lib-names.h>
  20. #include <stdlib.h>
  21. #include <unwind.h>
  22. struct trace_arg
  23. {
  24. void **array;
  25. _Unwind_Word cfa;
  26. int cnt;
  27. int size;
  28. };
  29. #ifdef SHARED
  30. static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
  31. static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
  32. static _Unwind_Word (*unwind_getcfa) (struct _Unwind_Context *);
  33. static void *libgcc_handle;
  34. /* Dummy version in case libgcc_s does not contain the real code. */
  35. static _Unwind_Word
  36. dummy_getcfa (struct _Unwind_Context *ctx __attribute__ ((unused)))
  37. {
  38. return 0;
  39. }
  40. static void
  41. init (void)
  42. {
  43. libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
  44. if (libgcc_handle == NULL)
  45. return;
  46. unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
  47. unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
  48. if (unwind_getip == NULL)
  49. unwind_backtrace = NULL;
  50. unwind_getcfa = (__libc_dlsym (libgcc_handle, "_Unwind_GetCFA")
  51. ?: dummy_getcfa);
  52. }
  53. #else
  54. # define unwind_backtrace _Unwind_Backtrace
  55. # define unwind_getip _Unwind_GetIP
  56. # define unwind_getcfa _Unwind_GetCFA
  57. #endif
  58. static _Unwind_Reason_Code
  59. backtrace_helper (struct _Unwind_Context *ctx, void *a)
  60. {
  61. struct trace_arg *arg = a;
  62. /* We are first called with address in the __backtrace function.
  63. Skip it. */
  64. if (arg->cnt != -1)
  65. {
  66. arg->array[arg->cnt] = (void *) unwind_getip (ctx);
  67. /* Check whether we make any progress. */
  68. _Unwind_Word cfa = unwind_getcfa (ctx);
  69. if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
  70. && cfa == arg->cfa)
  71. return _URC_END_OF_STACK;
  72. arg->cfa = cfa;
  73. }
  74. if (++arg->cnt == arg->size)
  75. return _URC_END_OF_STACK;
  76. return _URC_NO_REASON;
  77. }
  78. int
  79. __backtrace (void **array, int size)
  80. {
  81. struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
  82. if (size <= 0)
  83. return 0;
  84. #ifdef SHARED
  85. __libc_once_define (static, once);
  86. __libc_once (once, init);
  87. if (unwind_backtrace == NULL)
  88. return 0;
  89. #endif
  90. unwind_backtrace (backtrace_helper, &arg);
  91. /* _Unwind_Backtrace seems to put NULL address above
  92. _start. Fix it up here. */
  93. if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
  94. --arg.cnt;
  95. return arg.cnt != -1 ? arg.cnt : 0;
  96. }
  97. weak_alias (__backtrace, backtrace)
  98. libc_hidden_def (__backtrace)
  99. #ifdef SHARED
  100. /* Free all resources if necessary. */
  101. libc_freeres_fn (free_mem)
  102. {
  103. unwind_backtrace = NULL;
  104. if (libgcc_handle != NULL)
  105. {
  106. __libc_dlclose (libgcc_handle);
  107. libgcc_handle = NULL;
  108. }
  109. }
  110. #endif