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