backtrace.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* Return backtrace of current program state.
  2. Copyright (C) 2003-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <execinfo.h>
  16. #include <stdlib.h>
  17. #include <unwind.h>
  18. #include <unwind-link.h>
  19. #if ENABLE_SFRAME
  20. #include <sframe.h>
  21. #endif
  22. struct trace_arg
  23. {
  24. void **array;
  25. struct unwind_link *unwind_link;
  26. _Unwind_Word cfa;
  27. int cnt;
  28. int size;
  29. };
  30. #if ENABLE_SFRAME
  31. /* Initialize the SFrame backtrace routine and attempt to backtrace
  32. the current stack using SFrame information. For the SFrame
  33. backtrace to be considered valid, the tracer must return more than
  34. one frame. If it doesn't, this could indicate a mixed
  35. environment for example, glibc may have been compiled with SFrame
  36. support, while the application was not. An even more complex
  37. scenario arises when the application uses shared objects compiled
  38. with differing configurations.
  39. Additionally, glibc includes certain callback paths that must be
  40. considered. For example: an application calls shared object A,
  41. which calls shared object B, which in turn calls qsort() in
  42. glibc. qsort() then invokes a helper in shared object C, which
  43. raises a SIGFPE signal, handled by object D, which requests a
  44. backtrace. Any of these components may or may not include SFrame
  45. encoding.
  46. In cases where a stack frame lacks SFrame information, the SFrame
  47. backtracer can fall back to using the DWARF unwinder.
  48. This function must be always inline. Otherwise the
  49. __builtin_frame_address and the __getXX helper functions will not
  50. return the right addresses. */
  51. static inline int __attribute__ ((always_inline))
  52. do_sframe_backtrace (void **array, int size)
  53. {
  54. frame frame;
  55. frame.pc = __getPC ();
  56. frame.sp = __getSP ();
  57. frame.fp = (_Unwind_Ptr) __builtin_frame_address (0);
  58. return __stacktrace_sframe (array, size, &frame);
  59. }
  60. #endif
  61. static _Unwind_Reason_Code
  62. backtrace_helper (struct _Unwind_Context *ctx, void *a)
  63. {
  64. struct trace_arg *arg = a;
  65. /* We are first called with address in the __backtrace function.
  66. Skip it. */
  67. if (arg->cnt != -1)
  68. {
  69. arg->array[arg->cnt]
  70. = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
  71. if (arg->cnt > 0)
  72. arg->array[arg->cnt]
  73. = unwind_arch_adjustment (arg->array[arg->cnt - 1],
  74. arg->array[arg->cnt]);
  75. /* Check whether we make any progress. */
  76. _Unwind_Word cfa
  77. = UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
  78. if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
  79. && cfa == arg->cfa)
  80. return _URC_END_OF_STACK;
  81. arg->cfa = cfa;
  82. }
  83. if (++arg->cnt == arg->size)
  84. return _URC_END_OF_STACK;
  85. return _URC_NO_REASON;
  86. }
  87. int
  88. __backtrace (void **array, int size)
  89. {
  90. struct trace_arg arg =
  91. {
  92. .array = array,
  93. .unwind_link = __libc_unwind_link_get (),
  94. .cfa = 0,
  95. .size = size,
  96. .cnt = -1
  97. };
  98. if (size <= 0)
  99. return 0;
  100. #if ENABLE_SFRAME
  101. /* Try first the SFrame backtracer. */
  102. int cnt = do_sframe_backtrace (array, size);
  103. if (cnt > 1)
  104. return cnt;
  105. #endif
  106. /* Try the dwarf unwinder. */
  107. if (arg.unwind_link == NULL)
  108. return 0;
  109. UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
  110. (backtrace_helper, &arg);
  111. /* _Unwind_Backtrace seems to put NULL address above
  112. _start. Fix it up here. */
  113. if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
  114. --arg.cnt;
  115. return arg.cnt != -1 ? arg.cnt : 0;
  116. }
  117. weak_alias (__backtrace, backtrace)
  118. libc_hidden_def (__backtrace)