backtrace.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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 Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. 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. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with the GNU C Library; see the file COPYING.LIB. If
  14. not, see <https://www.gnu.org/licenses/>. */
  15. #include <execinfo.h>
  16. #include <stddef.h>
  17. #include <sysdep.h>
  18. #include <sys/trap.h>
  19. #include <backtrace.h>
  20. #include <unwind-link.h>
  21. struct layout
  22. {
  23. unsigned long locals[8];
  24. unsigned long ins[6];
  25. unsigned long next;
  26. void *return_address;
  27. };
  28. struct trace_arg
  29. {
  30. void **array;
  31. struct unwind_link *unwind_link;
  32. _Unwind_Word cfa;
  33. int cnt;
  34. int size;
  35. };
  36. static _Unwind_Reason_Code
  37. backtrace_helper (struct _Unwind_Context *ctx, void *a)
  38. {
  39. struct trace_arg *arg = a;
  40. _Unwind_Ptr ip;
  41. /* We are first called with address in the __backtrace function.
  42. Skip it. */
  43. if (arg->cnt != -1)
  44. {
  45. ip = UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
  46. arg->array[arg->cnt] = (void *) ip;
  47. /* Check whether we make any progress. */
  48. _Unwind_Word cfa
  49. = UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
  50. if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
  51. && cfa == arg->cfa)
  52. return _URC_END_OF_STACK;
  53. arg->cfa = cfa;
  54. }
  55. if (++arg->cnt == arg->size)
  56. return _URC_END_OF_STACK;
  57. return _URC_NO_REASON;
  58. }
  59. int
  60. __backtrace (void **array, int size)
  61. {
  62. int count;
  63. struct trace_arg arg =
  64. {
  65. .array = array,
  66. .unwind_link = __libc_unwind_link_get (),
  67. .size = size,
  68. .cnt = -1,
  69. };
  70. if (size <= 0)
  71. return 0;
  72. if (arg.unwind_link == NULL)
  73. {
  74. struct layout *current;
  75. unsigned long fp, i7;
  76. asm volatile ("mov %%fp, %0" : "=r"(fp));
  77. asm volatile ("mov %%i7, %0" : "=r"(i7));
  78. current = (struct layout *) (fp + BACKTRACE_STACK_BIAS);
  79. array[0] = (void *) i7;
  80. if (size == 1)
  81. return 1;
  82. backtrace_flush_register_windows();
  83. for (count = 1; count < size; count++)
  84. {
  85. array[count] = current->return_address;
  86. if (!current->next)
  87. break;
  88. current = (struct layout *) (current->next + BACKTRACE_STACK_BIAS);
  89. }
  90. }
  91. else
  92. {
  93. UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
  94. (backtrace_helper, &arg);
  95. /* _Unwind_Backtrace seems to put NULL address above
  96. _start. Fix it up here. */
  97. if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
  98. --arg.cnt;
  99. count = arg.cnt != -1 ? arg.cnt : 0;
  100. }
  101. return count;
  102. }
  103. weak_alias (__backtrace, backtrace)
  104. libc_hidden_def (__backtrace)