brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.3 KiB · 5631d13 Raw
366 lines · cpp
1//===-- sanitizer_common.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 sanitizers' run-time libraries.10//11//===----------------------------------------------------------------------===//12 13#include "sanitizer_stacktrace_printer.h"14 15#include "sanitizer_common.h"16#include "sanitizer_file.h"17#include "sanitizer_flags.h"18#include "sanitizer_fuchsia.h"19#include "sanitizer_symbolizer_markup.h"20 21namespace __sanitizer {22 23StackTracePrinter *StackTracePrinter::GetOrInit() {24  static StackTracePrinter *stacktrace_printer;25  static StaticSpinMutex init_mu;26  SpinMutexLock l(&init_mu);27  if (stacktrace_printer)28    return stacktrace_printer;29 30  stacktrace_printer = StackTracePrinter::NewStackTracePrinter();31 32  CHECK(stacktrace_printer);33  return stacktrace_printer;34}35 36const char *StackTracePrinter::StripFunctionName(const char *function) {37  if (!common_flags()->demangle)38    return function;39  if (!function)40    return nullptr;41  auto try_strip = [function](const char *prefix) -> const char * {42    const uptr prefix_len = internal_strlen(prefix);43    if (!internal_strncmp(function, prefix, prefix_len))44      return function + prefix_len;45    return nullptr;46  };47  if (SANITIZER_APPLE) {48    if (const char *s = try_strip("wrap_"))49      return s;50  } else if (SANITIZER_WINDOWS) {51    if (const char *s = try_strip("__asan_wrap_"))52      return s;53  } else {54    if (const char *s = try_strip("___interceptor_"))55      return s;56    if (const char *s = try_strip("__interceptor_"))57      return s;58  }59  return function;60}61 62// sanitizer_symbolizer_markup.cpp implements these differently.63#if !SANITIZER_SYMBOLIZER_MARKUP64 65StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {66  if (common_flags()->enable_symbolizer_markup)67    return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();68 69  return new (GetGlobalLowLevelAllocator()) FormattedStackTracePrinter();70}71 72static const char *DemangleFunctionName(const char *function) {73  if (!common_flags()->demangle)74    return function;75  if (!function)76    return nullptr;77 78  // NetBSD uses indirection for old threading functions for historical reasons79  // The mangled names are internal implementation detail and should not be80  // exposed even in backtraces.81#if SANITIZER_NETBSD82  if (!internal_strcmp(function, "__libc_mutex_init"))83    return "pthread_mutex_init";84  if (!internal_strcmp(function, "__libc_mutex_lock"))85    return "pthread_mutex_lock";86  if (!internal_strcmp(function, "__libc_mutex_trylock"))87    return "pthread_mutex_trylock";88  if (!internal_strcmp(function, "__libc_mutex_unlock"))89    return "pthread_mutex_unlock";90  if (!internal_strcmp(function, "__libc_mutex_destroy"))91    return "pthread_mutex_destroy";92  if (!internal_strcmp(function, "__libc_mutexattr_init"))93    return "pthread_mutexattr_init";94  if (!internal_strcmp(function, "__libc_mutexattr_settype"))95    return "pthread_mutexattr_settype";96  if (!internal_strcmp(function, "__libc_mutexattr_destroy"))97    return "pthread_mutexattr_destroy";98  if (!internal_strcmp(function, "__libc_cond_init"))99    return "pthread_cond_init";100  if (!internal_strcmp(function, "__libc_cond_signal"))101    return "pthread_cond_signal";102  if (!internal_strcmp(function, "__libc_cond_broadcast"))103    return "pthread_cond_broadcast";104  if (!internal_strcmp(function, "__libc_cond_wait"))105    return "pthread_cond_wait";106  if (!internal_strcmp(function, "__libc_cond_timedwait"))107    return "pthread_cond_timedwait";108  if (!internal_strcmp(function, "__libc_cond_destroy"))109    return "pthread_cond_destroy";110  if (!internal_strcmp(function, "__libc_rwlock_init"))111    return "pthread_rwlock_init";112  if (!internal_strcmp(function, "__libc_rwlock_rdlock"))113    return "pthread_rwlock_rdlock";114  if (!internal_strcmp(function, "__libc_rwlock_wrlock"))115    return "pthread_rwlock_wrlock";116  if (!internal_strcmp(function, "__libc_rwlock_tryrdlock"))117    return "pthread_rwlock_tryrdlock";118  if (!internal_strcmp(function, "__libc_rwlock_trywrlock"))119    return "pthread_rwlock_trywrlock";120  if (!internal_strcmp(function, "__libc_rwlock_unlock"))121    return "pthread_rwlock_unlock";122  if (!internal_strcmp(function, "__libc_rwlock_destroy"))123    return "pthread_rwlock_destroy";124  if (!internal_strcmp(function, "__libc_thr_keycreate"))125    return "pthread_key_create";126  if (!internal_strcmp(function, "__libc_thr_setspecific"))127    return "pthread_setspecific";128  if (!internal_strcmp(function, "__libc_thr_getspecific"))129    return "pthread_getspecific";130  if (!internal_strcmp(function, "__libc_thr_keydelete"))131    return "pthread_key_delete";132  if (!internal_strcmp(function, "__libc_thr_once"))133    return "pthread_once";134  if (!internal_strcmp(function, "__libc_thr_self"))135    return "pthread_self";136  if (!internal_strcmp(function, "__libc_thr_exit"))137    return "pthread_exit";138  if (!internal_strcmp(function, "__libc_thr_setcancelstate"))139    return "pthread_setcancelstate";140  if (!internal_strcmp(function, "__libc_thr_equal"))141    return "pthread_equal";142  if (!internal_strcmp(function, "__libc_thr_curcpu"))143    return "pthread_curcpu_np";144  if (!internal_strcmp(function, "__libc_thr_sigsetmask"))145    return "pthread_sigmask";146#endif147 148  return function;149}150 151static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,152                                 InternalScopedString *buffer) {153  if (info.uuid_size) {154    if (PrefixSpace)155      buffer->Append(" ");156    buffer->Append("(BuildId: ");157    for (uptr i = 0; i < info.uuid_size; ++i) {158      buffer->AppendF("%02x", info.uuid[i]);159    }160    buffer->Append(")");161  }162}163 164static const char kDefaultFormat[] = "    #%n %p %F %L";165 166void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,167                                             const char *format, int frame_no,168                                             uptr address,169                                             const AddressInfo *info,170                                             bool vs_style,171                                             const char *strip_path_prefix) {172  // info will be null in the case where symbolization is not needed for the173  // given format. This ensures that the code below will get a hard failure174  // rather than print incorrect information in case RenderNeedsSymbolization175  // ever ends up out of sync with this function. If non-null, the addresses176  // should match.177  CHECK(!info || address == info->address);178  if (0 == internal_strcmp(format, "DEFAULT"))179    format = kDefaultFormat;180  for (const char *p = format; *p != '\0'; p++) {181    if (*p != '%') {182      buffer->AppendF("%c", *p);183      continue;184    }185    p++;186    switch (*p) {187    case '%':188      buffer->Append("%");189      break;190    // Frame number and all fields of AddressInfo structure.191    case 'n':192      buffer->AppendF("%u", frame_no);193      break;194    case 'p':195      buffer->AppendF("%p", (void *)address);196      break;197    case 'm':198      buffer->AppendF("%s", StripPathPrefix(info->module, strip_path_prefix));199      break;200    case 'o':201      buffer->AppendF("0x%zx", info->module_offset);202      break;203    case 'b':204      MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/false, buffer);205      break;206    case 'f':207      buffer->AppendF("%s",208                      DemangleFunctionName(StripFunctionName(info->function)));209      break;210    case 'q':211      buffer->AppendF("0x%zx", info->function_offset != AddressInfo::kUnknown212                                   ? info->function_offset213                                   : 0x0);214      break;215    case 's':216      buffer->AppendF("%s", StripPathPrefix(info->file, strip_path_prefix));217      break;218    case 'l':219      buffer->AppendF("%d", info->line);220      break;221    case 'c':222      buffer->AppendF("%d", info->column);223      break;224    // Smarter special cases.225    case 'F':226      // Function name and offset, if file is unknown.227      if (info->function) {228        buffer->AppendF(229            "in %s", DemangleFunctionName(StripFunctionName(info->function)));230        if (!info->file && info->function_offset != AddressInfo::kUnknown)231          buffer->AppendF("+0x%zx", info->function_offset);232      }233      break;234    case 'S':235      // File/line information.236      RenderSourceLocation(buffer, info->file, info->line, info->column,237                           vs_style, strip_path_prefix);238      break;239    case 'L':240      // Source location, or module location.241      if (info->file) {242        RenderSourceLocation(buffer, info->file, info->line, info->column,243                             vs_style, strip_path_prefix);244      } else if (info->module) {245        RenderModuleLocation(buffer, info->module, info->module_offset,246                             info->module_arch, strip_path_prefix);247 248#if !SANITIZER_APPLE249        MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);250#endif251      } else {252        buffer->Append("(<unknown module>)");253      }254      break;255    case 'M':256      // Module basename and offset, or PC.257      if (address & kExternalPCBit) {258        // There PCs are not meaningful.259      } else if (info->module) {260        // Always strip the module name for %M.261        RenderModuleLocation(buffer, StripModuleName(info->module),262                             info->module_offset, info->module_arch, "");263#if !SANITIZER_APPLE264        MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);265#endif266      } else {267        buffer->AppendF("(%p)", (void *)address);268      }269      break;270    default:271      Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,272             (const void *)p);273      Die();274    }275  }276}277 278bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format) {279  if (0 == internal_strcmp(format, "DEFAULT"))280    format = kDefaultFormat;281  for (const char *p = format; *p != '\0'; p++) {282    if (*p != '%')283      continue;284    p++;285    switch (*p) {286      case '%':287        break;288      case 'n':289        // frame_no290        break;291      case 'p':292        // address293        break;294      default:295        return true;296    }297  }298  return false;299}300 301void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,302                                            const char *format,303                                            const DataInfo *DI,304                                            const char *strip_path_prefix) {305  for (const char *p = format; *p != '\0'; p++) {306    if (*p != '%') {307      buffer->AppendF("%c", *p);308      continue;309    }310    p++;311    switch (*p) {312      case '%':313        buffer->Append("%");314        break;315      case 's':316        buffer->AppendF("%s", StripPathPrefix(DI->file, strip_path_prefix));317        break;318      case 'l':319        buffer->AppendF("%zu", DI->line);320        break;321      case 'g':322        buffer->AppendF("%s", DI->name);323        break;324      default:325        Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,326               (const void *)p);327        Die();328    }329  }330}331 332#endif  // !SANITIZER_SYMBOLIZER_MARKUP333 334void StackTracePrinter::RenderSourceLocation(InternalScopedString *buffer,335                                             const char *file, int line,336                                             int column, bool vs_style,337                                             const char *strip_path_prefix) {338  if (vs_style && line > 0) {339    buffer->AppendF("%s(%d", StripPathPrefix(file, strip_path_prefix), line);340    if (column > 0)341      buffer->AppendF(",%d", column);342    buffer->Append(")");343    return;344  }345 346  buffer->AppendF("%s", StripPathPrefix(file, strip_path_prefix));347  if (line > 0) {348    buffer->AppendF(":%d", line);349    if (column > 0)350      buffer->AppendF(":%d", column);351  }352}353 354void StackTracePrinter::RenderModuleLocation(InternalScopedString *buffer,355                                             const char *module, uptr offset,356                                             ModuleArch arch,357                                             const char *strip_path_prefix) {358  buffer->AppendF("(%s", StripPathPrefix(module, strip_path_prefix));359  if (arch != kModuleArchUnknown) {360    buffer->AppendF(":%s", ModuleArchToString(arch));361  }362  buffer->AppendF("+0x%zx)", offset);363}364 365} // namespace __sanitizer366