brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.5 KiB · 351e00d Raw
345 lines · cpp
1//===-- sanitizer_symbolizer_report.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 other sanitizer run-time10/// libraries and implements symbolized reports related functions.11///12//===----------------------------------------------------------------------===//13 14#include "sanitizer_common.h"15#include "sanitizer_file.h"16#include "sanitizer_flags.h"17#include "sanitizer_procmaps.h"18#include "sanitizer_report_decorator.h"19#include "sanitizer_stacktrace.h"20#include "sanitizer_stacktrace_printer.h"21#include "sanitizer_symbolizer.h"22 23#if SANITIZER_POSIX24# include "sanitizer_posix.h"25# include <sys/mman.h>26#endif27 28namespace __sanitizer {29 30#if !SANITIZER_GO31 32static bool FrameIsInternal(const SymbolizedStack *frame) {33  if (!frame)34    return true;35  const char *file = frame->info.file;36  const char *module = frame->info.module;37  // On Gentoo, the path is g++-*, so there's *not* a missing /.38  if (file && (internal_strstr(file, "/compiler-rt/lib/") ||39               internal_strstr(file, "/include/c++/") ||40               internal_strstr(file, "/include/g++")))41    return true;42  if (file && internal_strstr(file, "\\compiler-rt\\lib\\"))43    return true;44  if (module && (internal_strstr(module, "libclang_rt.")))45    return true;46  if (module && (internal_strstr(module, "clang_rt.")))47    return true;48  return false;49}50 51const SymbolizedStack *SkipInternalFrames(const SymbolizedStack *frames) {52  for (const SymbolizedStack *f = frames; f; f = f->next)53    if (!FrameIsInternal(f))54      return f;55  return nullptr;56}57 58void ReportErrorSummary(const char *error_type, const AddressInfo &info,59                        const char *alt_tool_name) {60  if (!common_flags()->print_summary) return;61  InternalScopedString buff;62  buff.AppendF("%s ", error_type);63  StackTracePrinter::GetOrInit()->RenderFrame(64      &buff, "%L %F", 0, info.address, &info,65      common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix);66  ReportErrorSummary(buff.data(), alt_tool_name);67}68#endif69 70#if !SANITIZER_FUCHSIA71 72bool ReportFile::SupportsColors() {73  SpinMutexLock l(mu);74  ReopenIfNecessary();75  return SupportsColoredOutput(fd);76}77 78static inline bool ReportSupportsColors() {79  return report_file.SupportsColors();80}81 82#else  // SANITIZER_FUCHSIA83 84// Fuchsia's logs always go through post-processing that handles colorization.85static inline bool ReportSupportsColors() { return true; }86 87#endif  // !SANITIZER_FUCHSIA88 89bool ColorizeReports() {90  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color91  // printing on Windows.92  if (SANITIZER_WINDOWS)93    return false;94 95  const char *flag = common_flags()->color;96  return internal_strcmp(flag, "always") == 0 ||97         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());98}99 100void ReportErrorSummary(const char *error_type, const StackTrace *stack,101                        const char *alt_tool_name) {102#if !SANITIZER_GO103  if (!common_flags()->print_summary)104    return;105 106  // Find first non-internal stack frame.107  for (uptr i = 0; i < stack->size; ++i) {108    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[i]);109    SymbolizedStackHolder symbolized_stack(110        Symbolizer::GetOrInit()->SymbolizePC(pc));111    if (const SymbolizedStack *frame = symbolized_stack.get()) {112      if (const SymbolizedStack *summary_frame = SkipInternalFrames(frame)) {113        ReportErrorSummary(error_type, summary_frame->info, alt_tool_name);114        return;115      }116    }117  }118 119  // Fallback to the top one.120  if (stack->size) {121    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);122    SymbolizedStackHolder symbolized_stack(123        Symbolizer::GetOrInit()->SymbolizePC(pc));124    if (const SymbolizedStack *frame = symbolized_stack.get()) {125      ReportErrorSummary(error_type, frame->info, alt_tool_name);126      return;127    }128  }129 130  // Fallback to a summary without location.131  ReportErrorSummary(error_type);132#endif133}134 135void ReportMmapWriteExec(int prot, int flags) {136#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID)137  int pflags = (PROT_WRITE | PROT_EXEC);138  if ((prot & pflags) != pflags)139    return;140 141#  if SANITIZER_APPLE && defined(MAP_JIT)142  if ((flags & MAP_JIT) == MAP_JIT)143    return;144#  endif145 146  ScopedErrorReportLock l;147  SanitizerCommonDecorator d;148 149  InternalMmapVector<BufferedStackTrace> stack_buffer(1);150  BufferedStackTrace *stack = stack_buffer.data();151  stack->Reset();152  uptr top = 0;153  uptr bottom = 0;154  GET_CALLER_PC_BP;155  bool fast = common_flags()->fast_unwind_on_fatal;156  if (StackTrace::WillUseFastUnwind(fast)) {157    GetThreadStackTopAndBottom(false, &top, &bottom);158    stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true);159  } else {160    stack->Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false);161  }162 163  Printf("%s", d.Warning());164  Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName);165  Printf("%s", d.Default());166 167  stack->Print();168  ReportErrorSummary("w-and-x-usage", stack);169#endif170}171 172#if !SANITIZER_FUCHSIA && !SANITIZER_GO173void StartReportDeadlySignal() {174  // Write the first message using fd=2, just in case.175  // It may actually fail to write in case stderr is closed.176  CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));177  static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";178  CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);179}180 181static void MaybeReportNonExecRegion(uptr pc) {182#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD183  MemoryMappingLayout proc_maps(/*cache_enabled*/ true);184  MemoryMappedSegment segment;185  while (proc_maps.Next(&segment)) {186    if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())187      Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");188  }189#endif190}191 192static void PrintMemoryByte(InternalScopedString *str, const char *before,193                            u8 byte) {194  SanitizerCommonDecorator d;195  str->AppendF("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,196               d.Default());197}198 199static void MaybeDumpInstructionBytes(uptr pc) {200  if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))201    return;202  InternalScopedString str;203  str.AppendF("First 16 instruction bytes at pc: ");204  if (IsAccessibleMemoryRange(pc, 16)) {205    for (int i = 0; i < 16; ++i) {206      PrintMemoryByte(&str, "", ((u8 *)pc)[i]);207    }208    str.AppendF("\n");209  } else {210    str.AppendF("unaccessible\n");211  }212  Report("%s", str.data());213}214 215static void MaybeDumpRegisters(void *context) {216  if (!common_flags()->dump_registers) return;217  SignalContext::DumpAllRegisters(context);218}219 220static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,221                                    UnwindSignalStackCallbackType unwind,222                                    const void *unwind_context) {223  SanitizerCommonDecorator d;224  Printf("%s", d.Warning());225  static const char kDescription[] = "stack-overflow";226  Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",227         SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,228         (void *)sig.bp, (void *)sig.sp, tid);229  Printf("%s", d.Default());230  // Avoid SEGVs in the unwinder when bp couldn't be determined.231  if (sig.bp) {232    InternalMmapVector<BufferedStackTrace> stack_buffer(1);233    BufferedStackTrace *stack = stack_buffer.data();234    stack->Reset();235    unwind(sig, unwind_context, stack);236    stack->Print();237    ReportErrorSummary(kDescription, stack);238  }239}240 241static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,242                                   UnwindSignalStackCallbackType unwind,243                                   const void *unwind_context) {244  SanitizerCommonDecorator d;245  Printf("%s", d.Warning());246  const char *description = sig.Describe();247  if (sig.is_memory_access && !sig.is_true_faulting_addr)248    Report("ERROR: %s: %s on unknown address (pc %p bp %p sp %p T%d)\n",249           SanitizerToolName, description, (void *)sig.pc, (void *)sig.bp,250           (void *)sig.sp, tid);251  else252    Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",253           SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,254           (void *)sig.bp, (void *)sig.sp, tid);255  Printf("%s", d.Default());256  if (sig.pc < GetPageSizeCached())257    Report("Hint: pc points to the zero page.\n");258  if (sig.is_memory_access) {259    const char *access_type =260        sig.write_flag == SignalContext::Write261            ? "WRITE"262            : (sig.write_flag == SignalContext::Read ? "READ" : "UNKNOWN");263    Report("The signal is caused by a %s memory access.\n", access_type);264    if (!sig.is_true_faulting_addr)265      Report("Hint: this fault was caused by a dereference of a high value "266             "address (see register values below).  Disassemble the provided "267             "pc to learn which register was used.\n");268    else if (sig.addr < GetPageSizeCached())269      Report("Hint: address points to the zero page.\n");270  }271  MaybeReportNonExecRegion(sig.pc);272  InternalMmapVector<BufferedStackTrace> stack_buffer(1);273  BufferedStackTrace *stack = stack_buffer.data();274  stack->Reset();275  unwind(sig, unwind_context, stack);276  stack->Print();277  MaybeDumpInstructionBytes(sig.pc);278  MaybeDumpRegisters(sig.context);279  Printf("%s can not provide additional info.\n", SanitizerToolName);280  ReportErrorSummary(description, stack);281}282 283void ReportDeadlySignal(const SignalContext &sig, u32 tid,284                        UnwindSignalStackCallbackType unwind,285                        const void *unwind_context) {286  if (sig.IsStackOverflow())287    ReportStackOverflowImpl(sig, tid, unwind, unwind_context);288  else289    ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);290}291 292void HandleDeadlySignal(void *siginfo, void *context, u32 tid,293                        UnwindSignalStackCallbackType unwind,294                        const void *unwind_context) {295  StartReportDeadlySignal();296  ScopedErrorReportLock rl;297  SignalContext sig(siginfo, context);298  ReportDeadlySignal(sig, tid, unwind, unwind_context);299  Report("ABORTING\n");300  Die();301}302 303#endif  // !SANITIZER_FUCHSIA && !SANITIZER_GO304 305atomic_uintptr_t ScopedErrorReportLock::reporting_thread_ = {0};306StaticSpinMutex ScopedErrorReportLock::mutex_;307 308void ScopedErrorReportLock::Lock() {309  uptr current = GetThreadSelf();310  for (;;) {311    uptr expected = 0;312    if (atomic_compare_exchange_strong(&reporting_thread_, &expected, current,313                                       memory_order_relaxed)) {314      // We've claimed reporting_thread so proceed.315      mutex_.Lock();316      return;317    }318 319    if (expected == current) {320      // This is either asynch signal or nested error during error reporting.321      // Fail simple to avoid deadlocks in Report().322 323      // Can't use Report() here because of potential deadlocks in nested324      // signal handlers.325      CatastrophicErrorWrite(SanitizerToolName,326                             internal_strlen(SanitizerToolName));327      static const char msg[] = ": nested bug in the same thread, aborting.\n";328      CatastrophicErrorWrite(msg, sizeof(msg) - 1);329 330      internal__exit(common_flags()->exitcode);331    }332 333    internal_sched_yield();334  }335}336 337void ScopedErrorReportLock::Unlock() {338  mutex_.Unlock();339  atomic_store_relaxed(&reporting_thread_, 0);340}341 342void ScopedErrorReportLock::CheckLocked() { mutex_.CheckLocked(); }343 344}  // namespace __sanitizer345