sanitizer_stacktrace_libcdep.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. //===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file is shared between AddressSanitizer and ThreadSanitizer
  10. // run-time libraries.
  11. //===----------------------------------------------------------------------===//
  12. #include "sanitizer_common.h"
  13. #include "sanitizer_placement_new.h"
  14. #include "sanitizer_stacktrace.h"
  15. #include "sanitizer_stacktrace_printer.h"
  16. #include "sanitizer_symbolizer.h"
  17. namespace __sanitizer {
  18. namespace {
  19. class StackTraceTextPrinter {
  20. public:
  21. StackTraceTextPrinter(const char *stack_trace_fmt, char frame_delimiter,
  22. InternalScopedString *output,
  23. InternalScopedString *dedup_token)
  24. : stack_trace_fmt_(stack_trace_fmt),
  25. frame_delimiter_(frame_delimiter),
  26. output_(output),
  27. dedup_token_(dedup_token),
  28. symbolize_(RenderNeedsSymbolization(stack_trace_fmt)) {}
  29. bool ProcessAddressFrames(uptr pc) {
  30. SymbolizedStack *frames = symbolize_
  31. ? Symbolizer::GetOrInit()->SymbolizePC(pc)
  32. : SymbolizedStack::New(pc);
  33. if (!frames)
  34. return false;
  35. for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
  36. uptr prev_len = output_->length();
  37. RenderFrame(output_, stack_trace_fmt_, frame_num_++, cur->info.address,
  38. symbolize_ ? &cur->info : nullptr,
  39. common_flags()->symbolize_vs_style,
  40. common_flags()->strip_path_prefix);
  41. if (prev_len != output_->length())
  42. output_->append("%c", frame_delimiter_);
  43. ExtendDedupToken(cur);
  44. }
  45. frames->ClearAll();
  46. return true;
  47. }
  48. private:
  49. // Extend the dedup token by appending a new frame.
  50. void ExtendDedupToken(SymbolizedStack *stack) {
  51. if (!dedup_token_)
  52. return;
  53. if (dedup_frames_-- > 0) {
  54. if (dedup_token_->length())
  55. dedup_token_->append("--");
  56. if (stack->info.function != nullptr)
  57. dedup_token_->append("%s", stack->info.function);
  58. }
  59. }
  60. const char *stack_trace_fmt_;
  61. const char frame_delimiter_;
  62. int dedup_frames_ = common_flags()->dedup_token_length;
  63. uptr frame_num_ = 0;
  64. InternalScopedString *output_;
  65. InternalScopedString *dedup_token_;
  66. const bool symbolize_ = false;
  67. };
  68. static void CopyStringToBuffer(const InternalScopedString &str, char *out_buf,
  69. uptr out_buf_size) {
  70. if (!out_buf_size)
  71. return;
  72. CHECK_GT(out_buf_size, 0);
  73. uptr copy_size = Min(str.length(), out_buf_size - 1);
  74. internal_memcpy(out_buf, str.data(), copy_size);
  75. out_buf[copy_size] = '\0';
  76. }
  77. } // namespace
  78. void StackTrace::PrintTo(InternalScopedString *output) const {
  79. CHECK(output);
  80. InternalScopedString dedup_token;
  81. StackTraceTextPrinter printer(common_flags()->stack_trace_format, '\n',
  82. output, &dedup_token);
  83. if (trace == nullptr || size == 0) {
  84. output->append(" <empty stack>\n\n");
  85. return;
  86. }
  87. for (uptr i = 0; i < size && trace[i]; i++) {
  88. // PCs in stack traces are actually the return addresses, that is,
  89. // addresses of the next instructions after the call.
  90. uptr pc = GetPreviousInstructionPc(trace[i]);
  91. CHECK(printer.ProcessAddressFrames(pc));
  92. }
  93. // Always add a trailing empty line after stack trace.
  94. output->append("\n");
  95. // Append deduplication token, if non-empty.
  96. if (dedup_token.length())
  97. output->append("DEDUP_TOKEN: %s\n", dedup_token.data());
  98. }
  99. uptr StackTrace::PrintTo(char *out_buf, uptr out_buf_size) const {
  100. CHECK(out_buf);
  101. InternalScopedString output;
  102. PrintTo(&output);
  103. CopyStringToBuffer(output, out_buf, out_buf_size);
  104. return output.length();
  105. }
  106. void StackTrace::Print() const {
  107. InternalScopedString output;
  108. PrintTo(&output);
  109. Printf("%s", output.data());
  110. }
  111. void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
  112. uptr stack_top, uptr stack_bottom,
  113. bool request_fast_unwind) {
  114. // Ensures all call sites get what they requested.
  115. CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind));
  116. top_frame_bp = (max_depth > 0) ? bp : 0;
  117. // Avoid doing any work for small max_depth.
  118. if (max_depth == 0) {
  119. size = 0;
  120. return;
  121. }
  122. if (max_depth == 1) {
  123. size = 1;
  124. trace_buffer[0] = pc;
  125. return;
  126. }
  127. if (!WillUseFastUnwind(request_fast_unwind)) {
  128. #if SANITIZER_CAN_SLOW_UNWIND
  129. if (context)
  130. UnwindSlow(pc, context, max_depth);
  131. else
  132. UnwindSlow(pc, max_depth);
  133. // If there are too few frames, the program may be built with
  134. // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below.
  135. if (size > 2 || size >= max_depth)
  136. return;
  137. #else
  138. UNREACHABLE("slow unwind requested but not available");
  139. #endif
  140. }
  141. UnwindFast(pc, bp, stack_top, stack_bottom, max_depth);
  142. }
  143. static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
  144. uptr module_name_len, uptr *pc_offset) {
  145. const char *found_module_name = nullptr;
  146. bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
  147. pc, &found_module_name, pc_offset);
  148. if (!ok) return false;
  149. if (module_name && module_name_len) {
  150. internal_strncpy(module_name, found_module_name, module_name_len);
  151. module_name[module_name_len - 1] = '\x00';
  152. }
  153. return true;
  154. }
  155. } // namespace __sanitizer
  156. using namespace __sanitizer;
  157. extern "C" {
  158. SANITIZER_INTERFACE_ATTRIBUTE
  159. void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
  160. uptr out_buf_size) {
  161. if (!out_buf_size)
  162. return;
  163. pc = StackTrace::GetPreviousInstructionPc(pc);
  164. InternalScopedString output;
  165. StackTraceTextPrinter printer(fmt, '\0', &output, nullptr);
  166. if (!printer.ProcessAddressFrames(pc)) {
  167. output.clear();
  168. output.append("<can't symbolize>");
  169. }
  170. CopyStringToBuffer(output, out_buf, out_buf_size);
  171. }
  172. SANITIZER_INTERFACE_ATTRIBUTE
  173. void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
  174. char *out_buf, uptr out_buf_size) {
  175. if (!out_buf_size) return;
  176. out_buf[0] = 0;
  177. DataInfo DI;
  178. if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
  179. InternalScopedString data_desc;
  180. RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
  181. internal_strncpy(out_buf, data_desc.data(), out_buf_size);
  182. out_buf[out_buf_size - 1] = 0;
  183. }
  184. SANITIZER_INTERFACE_ATTRIBUTE
  185. int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name,
  186. uptr module_name_len,
  187. uptr *pc_offset) {
  188. return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
  189. pc_offset);
  190. }
  191. } // extern "C"