Home | History | Annotate | Line # | Download | only in sanitizer_common
      1 //===-- sanitizer_common.cc -----------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is shared between sanitizers' run-time libraries.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_stacktrace_printer.h"
     15 #include "sanitizer_file.h"
     16 #include "sanitizer_fuchsia.h"
     17 
     18 namespace __sanitizer {
     19 
     20 // sanitizer_symbolizer_markup.cc implements these differently.
     21 #if !SANITIZER_SYMBOLIZER_MARKUP
     22 
     23 static const char *StripFunctionName(const char *function, const char *prefix) {
     24   if (!function) return nullptr;
     25   if (!prefix) return function;
     26   uptr prefix_len = internal_strlen(prefix);
     27   if (0 == internal_strncmp(function, prefix, prefix_len))
     28     return function + prefix_len;
     29   return function;
     30 }
     31 
     32 static const char *DemangleFunctionName(const char *function) {
     33   if (!function) return nullptr;
     34 
     35   // NetBSD uses indirection for old threading functions for historical reasons
     36   // The mangled names are internal implementation detail and should not be
     37   // exposed even in backtraces.
     38 #if SANITIZER_NETBSD
     39   if (!internal_strcmp(function, "__libc_mutex_init"))
     40     return "pthread_mutex_init";
     41   if (!internal_strcmp(function, "__libc_mutex_lock"))
     42     return "pthread_mutex_lock";
     43   if (!internal_strcmp(function, "__libc_mutex_trylock"))
     44     return "pthread_mutex_trylock";
     45   if (!internal_strcmp(function, "__libc_mutex_unlock"))
     46     return "pthread_mutex_unlock";
     47   if (!internal_strcmp(function, "__libc_mutex_destroy"))
     48     return "pthread_mutex_destroy";
     49   if (!internal_strcmp(function, "__libc_mutexattr_init"))
     50     return "pthread_mutexattr_init";
     51   if (!internal_strcmp(function, "__libc_mutexattr_settype"))
     52     return "pthread_mutexattr_settype";
     53   if (!internal_strcmp(function, "__libc_mutexattr_destroy"))
     54     return "pthread_mutexattr_destroy";
     55   if (!internal_strcmp(function, "__libc_cond_init"))
     56     return "pthread_cond_init";
     57   if (!internal_strcmp(function, "__libc_cond_signal"))
     58     return "pthread_cond_signal";
     59   if (!internal_strcmp(function, "__libc_cond_broadcast"))
     60     return "pthread_cond_broadcast";
     61   if (!internal_strcmp(function, "__libc_cond_wait"))
     62     return "pthread_cond_wait";
     63   if (!internal_strcmp(function, "__libc_cond_timedwait"))
     64     return "pthread_cond_timedwait";
     65   if (!internal_strcmp(function, "__libc_cond_destroy"))
     66     return "pthread_cond_destroy";
     67   if (!internal_strcmp(function, "__libc_rwlock_init"))
     68     return "pthread_rwlock_init";
     69   if (!internal_strcmp(function, "__libc_rwlock_rdlock"))
     70     return "pthread_rwlock_rdlock";
     71   if (!internal_strcmp(function, "__libc_rwlock_wrlock"))
     72     return "pthread_rwlock_wrlock";
     73   if (!internal_strcmp(function, "__libc_rwlock_tryrdlock"))
     74     return "pthread_rwlock_tryrdlock";
     75   if (!internal_strcmp(function, "__libc_rwlock_trywrlock"))
     76     return "pthread_rwlock_trywrlock";
     77   if (!internal_strcmp(function, "__libc_rwlock_unlock"))
     78     return "pthread_rwlock_unlock";
     79   if (!internal_strcmp(function, "__libc_rwlock_destroy"))
     80     return "pthread_rwlock_destroy";
     81   if (!internal_strcmp(function, "__libc_thr_keycreate"))
     82     return "pthread_key_create";
     83   if (!internal_strcmp(function, "__libc_thr_setspecific"))
     84     return "pthread_setspecific";
     85   if (!internal_strcmp(function, "__libc_thr_getspecific"))
     86     return "pthread_getspecific";
     87   if (!internal_strcmp(function, "__libc_thr_keydelete"))
     88     return "pthread_key_delete";
     89   if (!internal_strcmp(function, "__libc_thr_once"))
     90     return "pthread_once";
     91   if (!internal_strcmp(function, "__libc_thr_self"))
     92     return "pthread_self";
     93   if (!internal_strcmp(function, "__libc_thr_exit"))
     94     return "pthread_exit";
     95   if (!internal_strcmp(function, "__libc_thr_setcancelstate"))
     96     return "pthread_setcancelstate";
     97   if (!internal_strcmp(function, "__libc_thr_equal"))
     98     return "pthread_equal";
     99   if (!internal_strcmp(function, "__libc_thr_curcpu"))
    100     return "pthread_curcpu_np";
    101   if (!internal_strcmp(function, "__libc_thr_sigsetmask"))
    102     return "pthread_sigmask";
    103 #endif
    104 
    105   return function;
    106 }
    107 
    108 static const char kDefaultFormat[] = "    #%n %p %F %L";
    109 
    110 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
    111                  const AddressInfo &info, bool vs_style,
    112                  const char *strip_path_prefix, const char *strip_func_prefix) {
    113   if (0 == internal_strcmp(format, "DEFAULT"))
    114     format = kDefaultFormat;
    115   for (const char *p = format; *p != '\0'; p++) {
    116     if (*p != '%') {
    117       buffer->append("%c", *p);
    118       continue;
    119     }
    120     p++;
    121     switch (*p) {
    122     case '%':
    123       buffer->append("%%");
    124       break;
    125     // Frame number and all fields of AddressInfo structure.
    126     case 'n':
    127       buffer->append("%zu", frame_no);
    128       break;
    129     case 'p':
    130       buffer->append("0x%zx", info.address);
    131       break;
    132     case 'm':
    133       buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
    134       break;
    135     case 'o':
    136       buffer->append("0x%zx", info.module_offset);
    137       break;
    138     case 'f':
    139       buffer->append("%s",
    140         DemangleFunctionName(
    141           StripFunctionName(info.function, strip_func_prefix)));
    142       break;
    143     case 'q':
    144       buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
    145                                   ? info.function_offset
    146                                   : 0x0);
    147       break;
    148     case 's':
    149       buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
    150       break;
    151     case 'l':
    152       buffer->append("%d", info.line);
    153       break;
    154     case 'c':
    155       buffer->append("%d", info.column);
    156       break;
    157     // Smarter special cases.
    158     case 'F':
    159       // Function name and offset, if file is unknown.
    160       if (info.function) {
    161         buffer->append("in %s",
    162                        DemangleFunctionName(
    163                          StripFunctionName(info.function, strip_func_prefix)));
    164         if (!info.file && info.function_offset != AddressInfo::kUnknown)
    165           buffer->append("+0x%zx", info.function_offset);
    166       }
    167       break;
    168     case 'S':
    169       // File/line information.
    170       RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
    171                            strip_path_prefix);
    172       break;
    173     case 'L':
    174       // Source location, or module location.
    175       if (info.file) {
    176         RenderSourceLocation(buffer, info.file, info.line, info.column,
    177                              vs_style, strip_path_prefix);
    178       } else if (info.module) {
    179         RenderModuleLocation(buffer, info.module, info.module_offset,
    180                              info.module_arch, strip_path_prefix);
    181       } else {
    182         buffer->append("(<unknown module>)");
    183       }
    184       break;
    185     case 'M':
    186       // Module basename and offset, or PC.
    187       if (info.address & kExternalPCBit)
    188         {} // There PCs are not meaningful.
    189       else if (info.module)
    190         // Always strip the module name for %M.
    191         RenderModuleLocation(buffer, StripModuleName(info.module),
    192                              info.module_offset, info.module_arch, "");
    193       else
    194         buffer->append("(%p)", (void *)info.address);
    195       break;
    196     default:
    197       Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
    198              *p);
    199       Die();
    200     }
    201   }
    202 }
    203 
    204 void RenderData(InternalScopedString *buffer, const char *format,
    205                 const DataInfo *DI, const char *strip_path_prefix) {
    206   for (const char *p = format; *p != '\0'; p++) {
    207     if (*p != '%') {
    208       buffer->append("%c", *p);
    209       continue;
    210     }
    211     p++;
    212     switch (*p) {
    213       case '%':
    214         buffer->append("%%");
    215         break;
    216       case 's':
    217         buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
    218         break;
    219       case 'l':
    220         buffer->append("%d", DI->line);
    221         break;
    222       case 'g':
    223         buffer->append("%s", DI->name);
    224         break;
    225       default:
    226         Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
    227                *p);
    228         Die();
    229     }
    230   }
    231 }
    232 
    233 #endif  // !SANITIZER_SYMBOLIZER_MARKUP
    234 
    235 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
    236                           int line, int column, bool vs_style,
    237                           const char *strip_path_prefix) {
    238   if (vs_style && line > 0) {
    239     buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
    240     if (column > 0)
    241       buffer->append(",%d", column);
    242     buffer->append(")");
    243     return;
    244   }
    245 
    246   buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
    247   if (line > 0) {
    248     buffer->append(":%d", line);
    249     if (column > 0)
    250       buffer->append(":%d", column);
    251   }
    252 }
    253 
    254 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
    255                           uptr offset, ModuleArch arch,
    256                           const char *strip_path_prefix) {
    257   buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
    258   if (arch != kModuleArchUnknown) {
    259     buffer->append(":%s", ModuleArchToString(arch));
    260   }
    261   buffer->append("+0x%zx)", offset);
    262 }
    263 
    264 } // namespace __sanitizer
    265