sanitizer_unwind_posix_libcdep.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //===-- sanitizer_unwind_posix.cc ----------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // This file contains the unwind.h-based (aka "slow") stack unwinding routines
  9. // available to the tools on Linux, Android, FreeBSD and OS X.
  10. //===----------------------------------------------------------------------===//
  11. #include "sanitizer_platform.h"
  12. #if SANITIZER_POSIX
  13. #include "sanitizer_common.h"
  14. #include "sanitizer_stacktrace.h"
  15. #if SANITIZER_ANDROID
  16. #include <dlfcn.h> // for dlopen()
  17. #endif
  18. #if SANITIZER_FREEBSD
  19. #define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h>
  20. #endif
  21. #include <unwind.h>
  22. namespace __sanitizer {
  23. //------------------------- SlowUnwindStack -----------------------------------
  24. typedef struct {
  25. uptr absolute_pc;
  26. uptr stack_top;
  27. uptr stack_size;
  28. } backtrace_frame_t;
  29. extern "C" {
  30. typedef void *(*acquire_my_map_info_list_func)();
  31. typedef void (*release_my_map_info_list_func)(void *map);
  32. typedef sptr (*unwind_backtrace_signal_arch_func)(
  33. void *siginfo, void *sigcontext, void *map_info_list,
  34. backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
  35. acquire_my_map_info_list_func acquire_my_map_info_list;
  36. release_my_map_info_list_func release_my_map_info_list;
  37. unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
  38. } // extern "C"
  39. #if SANITIZER_ANDROID
  40. void SanitizerInitializeUnwinder() {
  41. void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
  42. if (!p) {
  43. VReport(1,
  44. "Failed to open libcorkscrew.so. You may see broken stack traces "
  45. "in SEGV reports.");
  46. return;
  47. }
  48. acquire_my_map_info_list =
  49. (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
  50. release_my_map_info_list =
  51. (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
  52. unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
  53. p, "unwind_backtrace_signal_arch");
  54. if (!acquire_my_map_info_list || !release_my_map_info_list ||
  55. !unwind_backtrace_signal_arch) {
  56. VReport(1,
  57. "Failed to find one of the required symbols in libcorkscrew.so. "
  58. "You may see broken stack traces in SEGV reports.");
  59. acquire_my_map_info_list = 0;
  60. unwind_backtrace_signal_arch = 0;
  61. release_my_map_info_list = 0;
  62. }
  63. }
  64. #endif
  65. #ifdef __arm__
  66. #define UNWIND_STOP _URC_END_OF_STACK
  67. #define UNWIND_CONTINUE _URC_NO_REASON
  68. #else
  69. #define UNWIND_STOP _URC_NORMAL_STOP
  70. #define UNWIND_CONTINUE _URC_NO_REASON
  71. #endif
  72. uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
  73. #ifdef __arm__
  74. uptr val;
  75. _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
  76. 15 /* r15 = PC */, _UVRSD_UINT32, &val);
  77. CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
  78. // Clear the Thumb bit.
  79. return val & ~(uptr)1;
  80. #else
  81. return _Unwind_GetIP(ctx);
  82. #endif
  83. }
  84. struct UnwindTraceArg {
  85. BufferedStackTrace *stack;
  86. uptr max_depth;
  87. };
  88. _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
  89. UnwindTraceArg *arg = (UnwindTraceArg*)param;
  90. CHECK_LT(arg->stack->size, arg->max_depth);
  91. uptr pc = Unwind_GetIP(ctx);
  92. arg->stack->trace_buffer[arg->stack->size++] = pc;
  93. if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
  94. return UNWIND_CONTINUE;
  95. }
  96. void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
  97. CHECK_GE(max_depth, 2);
  98. size = 0;
  99. UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
  100. _Unwind_Backtrace(Unwind_Trace, &arg);
  101. // We need to pop a few frames so that pc is on top.
  102. uptr to_pop = LocatePcInTrace(pc);
  103. // trace_buffer[0] belongs to the current function so we always pop it.
  104. if (to_pop == 0 && size > 1)
  105. to_pop = 1;
  106. PopStackFrames(to_pop);
  107. trace_buffer[0] = pc;
  108. }
  109. void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
  110. uptr max_depth) {
  111. CHECK_GE(max_depth, 2);
  112. if (!unwind_backtrace_signal_arch) {
  113. SlowUnwindStack(pc, max_depth);
  114. return;
  115. }
  116. void *map = acquire_my_map_info_list();
  117. CHECK(map);
  118. InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax);
  119. // siginfo argument appears to be unused.
  120. sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,
  121. frames.data(),
  122. /* ignore_depth */ 0, max_depth);
  123. release_my_map_info_list(map);
  124. if (res < 0) return;
  125. CHECK_LE((uptr)res, kStackTraceMax);
  126. size = 0;
  127. // +2 compensate for libcorkscrew unwinder returning addresses of call
  128. // instructions instead of raw return addresses.
  129. for (sptr i = 0; i < res; ++i)
  130. trace_buffer[size++] = frames[i].absolute_pc + 2;
  131. }
  132. } // namespace __sanitizer
  133. #endif // SANITIZER_POSIX