1//===-- sanitizer_common.cc -----------------------------------------------===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is shared between sanitizers' run-time libraries. 9// 10//===----------------------------------------------------------------------===// 11#include "sanitizer_stacktrace_printer.h" 12 13namespace __sanitizer { 14 15static const char *StripFunctionName(const char *function, const char *prefix) { 16 if (function == 0) return 0; 17 if (prefix == 0) return function; 18 uptr prefix_len = internal_strlen(prefix); 19 if (0 == internal_strncmp(function, prefix, prefix_len)) 20 return function + prefix_len; 21 return function; 22} 23 24static const char kDefaultFormat[] = " #%n %p %F %L"; 25 26void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 27 const AddressInfo &info, const char *strip_path_prefix, 28 const char *strip_func_prefix) { 29 if (0 == internal_strcmp(format, "DEFAULT")) 30 format = kDefaultFormat; 31 for (const char *p = format; *p != '\0'; p++) { 32 if (*p != '%') { 33 buffer->append("%c", *p); 34 continue; 35 } 36 p++; 37 switch (*p) { 38 case '%': 39 buffer->append("%%"); 40 break; 41 // Frame number and all fields of AddressInfo structure. 42 case 'n': 43 buffer->append("%zu", frame_no); 44 break; 45 case 'p': 46 buffer->append("0x%zx", info.address); 47 break; 48 case 'm': 49 buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); 50 break; 51 case 'o': 52 buffer->append("0x%zx", info.module_offset); 53 break; 54 case 'f': 55 buffer->append("%s", StripFunctionName(info.function, strip_func_prefix)); 56 break; 57 case 'q': 58 buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown 59 ? info.function_offset 60 : 0x0); 61 break; 62 case 's': 63 buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); 64 break; 65 case 'l': 66 buffer->append("%d", info.line); 67 break; 68 case 'c': 69 buffer->append("%d", info.column); 70 break; 71 // Smarter special cases. 72 case 'F': 73 // Function name and offset, if file is unknown. 74 if (info.function) { 75 buffer->append("in %s", 76 StripFunctionName(info.function, strip_func_prefix)); 77 if (!info.file && info.function_offset != AddressInfo::kUnknown) 78 buffer->append("+0x%zx", info.function_offset); 79 } 80 break; 81 case 'S': 82 // File/line information. 83 RenderSourceLocation(buffer, info.file, info.line, info.column, 84 strip_path_prefix); 85 break; 86 case 'L': 87 // Source location, or module location. 88 if (info.file) { 89 RenderSourceLocation(buffer, info.file, info.line, info.column, 90 strip_path_prefix); 91 } else if (info.module) { 92 RenderModuleLocation(buffer, info.module, info.module_offset, 93 strip_path_prefix); 94 } else { 95 buffer->append("(<unknown module>)"); 96 } 97 break; 98 case 'M': 99 // Module basename and offset, or PC. 100 if (info.module) 101 buffer->append("(%s+%p)", StripModuleName(info.module), 102 (void *)info.module_offset); 103 else 104 buffer->append("(%p)", (void *)info.address); 105 break; 106 default: 107 Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", 108 *p, *p); 109 Die(); 110 } 111 } 112} 113 114void RenderSourceLocation(InternalScopedString *buffer, const char *file, 115 int line, int column, const char *strip_path_prefix) { 116 buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); 117 if (line > 0) { 118 buffer->append(":%d", line); 119 if (column > 0) 120 buffer->append(":%d", column); 121 } 122} 123 124void RenderModuleLocation(InternalScopedString *buffer, const char *module, 125 uptr offset, const char *strip_path_prefix) { 126 buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix), 127 offset); 128} 129 130} // namespace __sanitizer 131