Home | History | Annotate | 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 
     16 namespace __sanitizer {
     17 
     18 static const char *StripFunctionName(const char *function, const char *prefix) {
     19   if (!function) return nullptr;
     20   if (!prefix) return function;
     21   uptr prefix_len = internal_strlen(prefix);
     22   if (0 == internal_strncmp(function, prefix, prefix_len))
     23     return function + prefix_len;
     24   return function;
     25 }
     26 
     27 static const char kDefaultFormat[] = "    #%n %p %F %L";
     28 
     29 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
     30                  const AddressInfo &info, bool vs_style,
     31                  const char *strip_path_prefix, const char *strip_func_prefix) {
     32   if (0 == internal_strcmp(format, "DEFAULT"))
     33     format = kDefaultFormat;
     34   for (const char *p = format; *p != '\0'; p++) {
     35     if (*p != '%') {
     36       buffer->append("%c", *p);
     37       continue;
     38     }
     39     p++;
     40     switch (*p) {
     41     case '%':
     42       buffer->append("%%");
     43       break;
     44     // Frame number and all fields of AddressInfo structure.
     45     case 'n':
     46       buffer->append("%zu", frame_no);
     47       break;
     48     case 'p':
     49       buffer->append("0x%zx", info.address);
     50       break;
     51     case 'm':
     52       buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
     53       break;
     54     case 'o':
     55       buffer->append("0x%zx", info.module_offset);
     56       break;
     57     case 'f':
     58       buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
     59       break;
     60     case 'q':
     61       buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
     62                                   ? info.function_offset
     63                                   : 0x0);
     64       break;
     65     case 's':
     66       buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
     67       break;
     68     case 'l':
     69       buffer->append("%d", info.line);
     70       break;
     71     case 'c':
     72       buffer->append("%d", info.column);
     73       break;
     74     // Smarter special cases.
     75     case 'F':
     76       // Function name and offset, if file is unknown.
     77       if (info.function) {
     78         buffer->append("in %s",
     79                        StripFunctionName(info.function, strip_func_prefix));
     80         if (!info.file && info.function_offset != AddressInfo::kUnknown)
     81           buffer->append("+0x%zx", info.function_offset);
     82       }
     83       break;
     84     case 'S':
     85       // File/line information.
     86       RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
     87                            strip_path_prefix);
     88       break;
     89     case 'L':
     90       // Source location, or module location.
     91       if (info.file) {
     92         RenderSourceLocation(buffer, info.file, info.line, info.column,
     93                              vs_style, strip_path_prefix);
     94       } else if (info.module) {
     95         RenderModuleLocation(buffer, info.module, info.module_offset,
     96                              strip_path_prefix);
     97       } else {
     98         buffer->append("(<unknown module>)");
     99       }
    100       break;
    101     case 'M':
    102       // Module basename and offset, or PC.
    103       if (info.address & kExternalPCBit)
    104         {} // There PCs are not meaningful.
    105       else if (info.module)
    106         buffer->append("(%s+%p)", StripModuleName(info.module),
    107                        (void *)info.module_offset);
    108       else
    109         buffer->append("(%p)", (void *)info.address);
    110       break;
    111     default:
    112       Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
    113              *p);
    114       Die();
    115     }
    116   }
    117 }
    118 
    119 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
    120                           int line, int column, bool vs_style,
    121                           const char *strip_path_prefix) {
    122   if (vs_style && line > 0) {
    123     buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
    124     if (column > 0)
    125       buffer->append(",%d", column);
    126     buffer->append(")");
    127     return;
    128   }
    129 
    130   buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
    131   if (line > 0) {
    132     buffer->append(":%d", line);
    133     if (column > 0)
    134       buffer->append(":%d", column);
    135   }
    136 }
    137 
    138 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
    139                           uptr offset, const char *strip_path_prefix) {
    140   buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
    141                  offset);
    142 }
    143 
    144 } // namespace __sanitizer
    145