backtrace.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* Return backtrace of current program state.
  2. Copyright (C) 2013-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-link.h>
  18. struct trace_arg
  19. {
  20. void **array;
  21. struct unwind_link *unwind_link;
  22. int cnt, size;
  23. void *lastfp, *lastsp;
  24. };
  25. static _Unwind_Reason_Code
  26. backtrace_helper (struct _Unwind_Context *ctx, void *a)
  27. {
  28. struct trace_arg *arg = a;
  29. /* We are first called with address in the __backtrace function.
  30. Skip it. */
  31. if (arg->cnt != -1)
  32. arg->array[arg->cnt]
  33. = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
  34. if (++arg->cnt == arg->size)
  35. return _URC_END_OF_STACK;
  36. /* %fp is DWARF2 register 14 on M68K. */
  37. arg->lastfp
  38. = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetGR) (ctx, 14);
  39. arg->lastsp
  40. = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
  41. return _URC_NO_REASON;
  42. }
  43. /* This is a global variable set at program start time. It marks the
  44. highest used stack address. */
  45. extern void *__libc_stack_end;
  46. /* This is the stack layout we see with every stack frame
  47. if not compiled without frame pointer.
  48. +-----------------+ +-----------------+
  49. %fp -> | %fp last frame--------> | %fp last frame--->...
  50. | | | |
  51. | return address | | return address |
  52. +-----------------+ +-----------------+
  53. First try as far to get as far as possible using
  54. _Unwind_Backtrace which handles -fomit-frame-pointer
  55. as well, but requires .eh_frame info. Then fall back to
  56. walking the stack manually. */
  57. struct layout
  58. {
  59. struct layout *fp;
  60. void *ret;
  61. };
  62. int
  63. __backtrace (void **array, int size)
  64. {
  65. struct trace_arg arg =
  66. {
  67. .array = array,
  68. .unwind_link = __libc_unwind_link_get (),
  69. .size = size,
  70. .cnt = -1,
  71. };
  72. if (size <= 0 || arg.unwind_link == NULL)
  73. return 0;
  74. UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
  75. (backtrace_helper, &arg);
  76. if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
  77. --arg.cnt;
  78. else if (arg.cnt < size)
  79. {
  80. struct layout *fp = (struct layout *) arg.lastfp;
  81. while (arg.cnt < size)
  82. {
  83. /* Check for out of range. */
  84. if ((void *) fp < arg.lastsp || (void *) fp > __libc_stack_end
  85. || ((long) fp & 1))
  86. break;
  87. array[arg.cnt++] = fp->ret;
  88. fp = fp->fp;
  89. }
  90. }
  91. return arg.cnt != -1 ? arg.cnt : 0;
  92. }
  93. weak_alias (__backtrace, backtrace)
  94. libc_hidden_def (__backtrace)