brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 1a0e00d Raw
229 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between AddressSanitizer and ThreadSanitizer10// run-time libraries.11//===----------------------------------------------------------------------===//12 13#include "sanitizer_common.h"14#include "sanitizer_placement_new.h"15#include "sanitizer_stacktrace.h"16#include "sanitizer_stacktrace_printer.h"17#include "sanitizer_symbolizer.h"18 19namespace __sanitizer {20 21namespace {22 23class StackTraceTextPrinter {24 public:25  StackTraceTextPrinter(const char *stack_trace_fmt, char frame_delimiter,26                        InternalScopedString *output,27                        InternalScopedString *dedup_token)28      : stack_trace_fmt_(stack_trace_fmt),29        frame_delimiter_(frame_delimiter),30        output_(output),31        dedup_token_(dedup_token),32        symbolize_(StackTracePrinter::GetOrInit()->RenderNeedsSymbolization(33            stack_trace_fmt)) {}34 35  bool ProcessAddressFrames(uptr pc) {36    SymbolizedStackHolder symbolized_stack(37        symbolize_ ? Symbolizer::GetOrInit()->SymbolizePC(pc)38                   : SymbolizedStack::New(pc));39    const SymbolizedStack *frames = symbolized_stack.get();40    if (!frames)41      return false;42 43    for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {44      uptr prev_len = output_->length();45      StackTracePrinter::GetOrInit()->RenderFrame(46          output_, stack_trace_fmt_, frame_num_++, cur->info.address,47          symbolize_ ? &cur->info : nullptr, common_flags()->symbolize_vs_style,48          common_flags()->strip_path_prefix);49 50      if (prev_len != output_->length())51        output_->AppendF("%c", frame_delimiter_);52 53      ExtendDedupToken(cur);54    }55    return true;56  }57 58 private:59  // Extend the dedup token by appending a new frame.60  void ExtendDedupToken(const SymbolizedStack *stack) {61    if (!dedup_token_)62      return;63 64    if (dedup_frames_-- > 0) {65      if (dedup_token_->length())66        dedup_token_->Append("--");67      if (stack->info.function)68        dedup_token_->Append(stack->info.function);69    }70  }71 72  const char *stack_trace_fmt_;73  const char frame_delimiter_;74  int dedup_frames_ = common_flags()->dedup_token_length;75  uptr frame_num_ = 0;76  InternalScopedString *output_;77  InternalScopedString *dedup_token_;78  const bool symbolize_ = false;79};80 81static void CopyStringToBuffer(const InternalScopedString &str, char *out_buf,82                               uptr out_buf_size) {83  if (!out_buf_size)84    return;85 86  CHECK_GT(out_buf_size, 0);87  uptr copy_size = Min(str.length(), out_buf_size - 1);88  internal_memcpy(out_buf, str.data(), copy_size);89  out_buf[copy_size] = '\0';90}91 92}  // namespace93 94void StackTrace::PrintTo(InternalScopedString *output) const {95  CHECK(output);96 97  InternalScopedString dedup_token;98  StackTraceTextPrinter printer(common_flags()->stack_trace_format, '\n',99                                output, &dedup_token);100 101  if (trace == nullptr || size == 0) {102    output->Append("    <empty stack>\n\n");103    return;104  }105 106  for (uptr i = 0; i < size && trace[i]; i++) {107    // PCs in stack traces are actually the return addresses, that is,108    // addresses of the next instructions after the call.109    uptr pc = GetPreviousInstructionPc(trace[i]);110    CHECK(printer.ProcessAddressFrames(pc));111  }112 113  // Always add a trailing empty line after stack trace.114  output->Append("\n");115 116  // Append deduplication token, if non-empty.117  if (dedup_token.length())118    output->AppendF("DEDUP_TOKEN: %s\n", dedup_token.data());119}120 121uptr StackTrace::PrintTo(char *out_buf, uptr out_buf_size) const {122  CHECK(out_buf);123 124  InternalScopedString output;125  PrintTo(&output);126  CopyStringToBuffer(output, out_buf, out_buf_size);127 128  return output.length();129}130 131void StackTrace::Print() const {132  InternalScopedString output;133  PrintTo(&output);134  Printf("%s", output.data());135}136 137void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,138                                uptr stack_top, uptr stack_bottom,139                                bool request_fast_unwind) {140  // Ensures all call sites get what they requested.141  CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind));142  top_frame_bp = (max_depth > 0) ? bp : 0;143  // Avoid doing any work for small max_depth.144  if (max_depth == 0) {145    size = 0;146    return;147  }148  if (max_depth == 1) {149    size = 1;150    trace_buffer[0] = pc;151    return;152  }153  if (!WillUseFastUnwind(request_fast_unwind)) {154#if SANITIZER_CAN_SLOW_UNWIND155    if (context)156      UnwindSlow(pc, context, max_depth);157    else158      UnwindSlow(pc, max_depth);159    // If there are too few frames, the program may be built with160    // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below.161    if (size > 2 || size >= max_depth)162      return;163#else164    UNREACHABLE("slow unwind requested but not available");165#endif166  }167  UnwindFast(pc, bp, stack_top, stack_bottom, max_depth);168}169 170int GetModuleAndOffsetForPc(uptr pc, char *module_name, uptr module_name_len,171                            uptr *pc_offset) {172  const char *found_module_name = nullptr;173  bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(174      pc, &found_module_name, pc_offset);175 176  if (!ok) return false;177 178  if (module_name && module_name_len) {179    internal_strncpy(module_name, found_module_name, module_name_len);180    module_name[module_name_len - 1] = '\x00';181  }182  return true;183}184 185}  // namespace __sanitizer186using namespace __sanitizer;187 188extern "C" {189SANITIZER_INTERFACE_ATTRIBUTE190void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,191                              uptr out_buf_size) {192  if (!out_buf_size)193    return;194 195  pc = StackTrace::GetPreviousInstructionPc(pc);196 197  InternalScopedString output;198  StackTraceTextPrinter printer(fmt, '\0', &output, nullptr);199  if (!printer.ProcessAddressFrames(pc)) {200    output.clear();201    output.Append("<can't symbolize>");202  }203  CopyStringToBuffer(output, out_buf, out_buf_size);204}205 206SANITIZER_INTERFACE_ATTRIBUTE207void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,208                                  char *out_buf, uptr out_buf_size) {209  if (!out_buf_size) return;210  out_buf[0] = 0;211  DataInfo DI;212  if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;213  InternalScopedString data_desc;214  StackTracePrinter::GetOrInit()->RenderData(&data_desc, fmt, &DI,215                                             common_flags()->strip_path_prefix);216  internal_strncpy(out_buf, data_desc.data(), out_buf_size);217  out_buf[out_buf_size - 1] = 0;218}219 220SANITIZER_INTERFACE_ATTRIBUTE221int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_name,222                                             uptr module_name_len,223                                             void **pc_offset) {224  return __sanitizer::GetModuleAndOffsetForPc(225      reinterpret_cast<uptr>(pc), module_name, module_name_len,226      reinterpret_cast<uptr *>(pc_offset));227}228}  // extern "C"229