sanitizer_stacktrace_libcdep.cpp 7.1 KB

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