| //===-- sanitizer_common.cc -----------------------------------------------===// | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file is shared between sanitizers' run-time libraries. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "sanitizer_stacktrace_printer.h" | 
 | #include "sanitizer_file.h" | 
 | #include "sanitizer_fuchsia.h" | 
 |  | 
 | namespace __sanitizer { | 
 |  | 
 | // sanitizer_symbolizer_fuchsia.cc implements these differently for Fuchsia. | 
 | #if !SANITIZER_FUCHSIA | 
 |  | 
 | static const char *StripFunctionName(const char *function, const char *prefix) { | 
 |   if (!function) return nullptr; | 
 |   if (!prefix) return function; | 
 |   uptr prefix_len = internal_strlen(prefix); | 
 |   if (0 == internal_strncmp(function, prefix, prefix_len)) | 
 |     return function + prefix_len; | 
 |   return function; | 
 | } | 
 |  | 
 | static const char kDefaultFormat[] = "    #%n %p %F %L"; | 
 |  | 
 | void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, | 
 |                  const AddressInfo &info, bool vs_style, | 
 |                  const char *strip_path_prefix, const char *strip_func_prefix) { | 
 |   if (0 == internal_strcmp(format, "DEFAULT")) | 
 |     format = kDefaultFormat; | 
 |   for (const char *p = format; *p != '\0'; p++) { | 
 |     if (*p != '%') { | 
 |       buffer->append("%c", *p); | 
 |       continue; | 
 |     } | 
 |     p++; | 
 |     switch (*p) { | 
 |     case '%': | 
 |       buffer->append("%%"); | 
 |       break; | 
 |     // Frame number and all fields of AddressInfo structure. | 
 |     case 'n': | 
 |       buffer->append("%zu", frame_no); | 
 |       break; | 
 |     case 'p': | 
 |       buffer->append("0x%zx", info.address); | 
 |       break; | 
 |     case 'm': | 
 |       buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); | 
 |       break; | 
 |     case 'o': | 
 |       buffer->append("0x%zx", info.module_offset); | 
 |       break; | 
 |     case 'f': | 
 |       buffer->append("%s", StripFunctionName(info.function, strip_func_prefix)); | 
 |       break; | 
 |     case 'q': | 
 |       buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown | 
 |                                   ? info.function_offset | 
 |                                   : 0x0); | 
 |       break; | 
 |     case 's': | 
 |       buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); | 
 |       break; | 
 |     case 'l': | 
 |       buffer->append("%d", info.line); | 
 |       break; | 
 |     case 'c': | 
 |       buffer->append("%d", info.column); | 
 |       break; | 
 |     // Smarter special cases. | 
 |     case 'F': | 
 |       // Function name and offset, if file is unknown. | 
 |       if (info.function) { | 
 |         buffer->append("in %s", | 
 |                        StripFunctionName(info.function, strip_func_prefix)); | 
 |         if (!info.file && info.function_offset != AddressInfo::kUnknown) | 
 |           buffer->append("+0x%zx", info.function_offset); | 
 |       } | 
 |       break; | 
 |     case 'S': | 
 |       // File/line information. | 
 |       RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, | 
 |                            strip_path_prefix); | 
 |       break; | 
 |     case 'L': | 
 |       // Source location, or module location. | 
 |       if (info.file) { | 
 |         RenderSourceLocation(buffer, info.file, info.line, info.column, | 
 |                              vs_style, strip_path_prefix); | 
 |       } else if (info.module) { | 
 |         RenderModuleLocation(buffer, info.module, info.module_offset, | 
 |                              info.module_arch, strip_path_prefix); | 
 |       } else { | 
 |         buffer->append("(<unknown module>)"); | 
 |       } | 
 |       break; | 
 |     case 'M': | 
 |       // Module basename and offset, or PC. | 
 |       if (info.address & kExternalPCBit) | 
 |         {} // There PCs are not meaningful. | 
 |       else if (info.module) | 
 |         // Always strip the module name for %M. | 
 |         RenderModuleLocation(buffer, StripModuleName(info.module), | 
 |                              info.module_offset, info.module_arch, ""); | 
 |       else | 
 |         buffer->append("(%p)", (void *)info.address); | 
 |       break; | 
 |     default: | 
 |       Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, | 
 |              *p); | 
 |       Die(); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void RenderData(InternalScopedString *buffer, const char *format, | 
 |                 const DataInfo *DI, const char *strip_path_prefix) { | 
 |   for (const char *p = format; *p != '\0'; p++) { | 
 |     if (*p != '%') { | 
 |       buffer->append("%c", *p); | 
 |       continue; | 
 |     } | 
 |     p++; | 
 |     switch (*p) { | 
 |       case '%': | 
 |         buffer->append("%%"); | 
 |         break; | 
 |       case 's': | 
 |         buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); | 
 |         break; | 
 |       case 'l': | 
 |         buffer->append("%d", DI->line); | 
 |         break; | 
 |       case 'g': | 
 |         buffer->append("%s", DI->name); | 
 |         break; | 
 |       default: | 
 |         Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, | 
 |                *p); | 
 |         Die(); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | #endif  // !SANITIZER_FUCHSIA | 
 |  | 
 | void RenderSourceLocation(InternalScopedString *buffer, const char *file, | 
 |                           int line, int column, bool vs_style, | 
 |                           const char *strip_path_prefix) { | 
 |   if (vs_style && line > 0) { | 
 |     buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); | 
 |     if (column > 0) | 
 |       buffer->append(",%d", column); | 
 |     buffer->append(")"); | 
 |     return; | 
 |   } | 
 |  | 
 |   buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); | 
 |   if (line > 0) { | 
 |     buffer->append(":%d", line); | 
 |     if (column > 0) | 
 |       buffer->append(":%d", column); | 
 |   } | 
 | } | 
 |  | 
 | void RenderModuleLocation(InternalScopedString *buffer, const char *module, | 
 |                           uptr offset, ModuleArch arch, | 
 |                           const char *strip_path_prefix) { | 
 |   buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); | 
 |   if (arch != kModuleArchUnknown) { | 
 |     buffer->append(":%s", ModuleArchToString(arch)); | 
 |   } | 
 |   buffer->append("+0x%zx)", offset); | 
 | } | 
 |  | 
 | } // namespace __sanitizer |