1 //===-- sanitizer_common.cpp ----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is shared between sanitizers' run-time libraries. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_stacktrace_printer.h" 14 15 #include "sanitizer_file.h" 16 #include "sanitizer_flags.h" 17 #include "sanitizer_fuchsia.h" 18 19 namespace __sanitizer { 20 21 const char *StripFunctionName(const char *function) { 22 if (!common_flags()->demangle) 23 return function; 24 if (!function) 25 return nullptr; 26 auto try_strip = [function](const char *prefix) -> const char * { 27 const uptr prefix_len = internal_strlen(prefix); 28 if (!internal_strncmp(function, prefix, prefix_len)) 29 return function + prefix_len; 30 return nullptr; 31 }; 32 if (SANITIZER_APPLE) { 33 if (const char *s = try_strip("wrap_")) 34 return s; 35 } else { 36 if (const char *s = try_strip("__interceptor_")) 37 return s; 38 } 39 return function; 40 } 41 42 // sanitizer_symbolizer_markup.cpp implements these differently. 43 #if !SANITIZER_SYMBOLIZER_MARKUP 44 45 static const char *DemangleFunctionName(const char *function) { 46 if (!common_flags()->demangle) 47 return function; 48 if (!function) 49 return nullptr; 50 51 // NetBSD uses indirection for old threading functions for historical reasons 52 // The mangled names are internal implementation detail and should not be 53 // exposed even in backtraces. 54 #if SANITIZER_NETBSD 55 if (!internal_strcmp(function, "__libc_mutex_init")) 56 return "pthread_mutex_init"; 57 if (!internal_strcmp(function, "__libc_mutex_lock")) 58 return "pthread_mutex_lock"; 59 if (!internal_strcmp(function, "__libc_mutex_trylock")) 60 return "pthread_mutex_trylock"; 61 if (!internal_strcmp(function, "__libc_mutex_unlock")) 62 return "pthread_mutex_unlock"; 63 if (!internal_strcmp(function, "__libc_mutex_destroy")) 64 return "pthread_mutex_destroy"; 65 if (!internal_strcmp(function, "__libc_mutexattr_init")) 66 return "pthread_mutexattr_init"; 67 if (!internal_strcmp(function, "__libc_mutexattr_settype")) 68 return "pthread_mutexattr_settype"; 69 if (!internal_strcmp(function, "__libc_mutexattr_destroy")) 70 return "pthread_mutexattr_destroy"; 71 if (!internal_strcmp(function, "__libc_cond_init")) 72 return "pthread_cond_init"; 73 if (!internal_strcmp(function, "__libc_cond_signal")) 74 return "pthread_cond_signal"; 75 if (!internal_strcmp(function, "__libc_cond_broadcast")) 76 return "pthread_cond_broadcast"; 77 if (!internal_strcmp(function, "__libc_cond_wait")) 78 return "pthread_cond_wait"; 79 if (!internal_strcmp(function, "__libc_cond_timedwait")) 80 return "pthread_cond_timedwait"; 81 if (!internal_strcmp(function, "__libc_cond_destroy")) 82 return "pthread_cond_destroy"; 83 if (!internal_strcmp(function, "__libc_rwlock_init")) 84 return "pthread_rwlock_init"; 85 if (!internal_strcmp(function, "__libc_rwlock_rdlock")) 86 return "pthread_rwlock_rdlock"; 87 if (!internal_strcmp(function, "__libc_rwlock_wrlock")) 88 return "pthread_rwlock_wrlock"; 89 if (!internal_strcmp(function, "__libc_rwlock_tryrdlock")) 90 return "pthread_rwlock_tryrdlock"; 91 if (!internal_strcmp(function, "__libc_rwlock_trywrlock")) 92 return "pthread_rwlock_trywrlock"; 93 if (!internal_strcmp(function, "__libc_rwlock_unlock")) 94 return "pthread_rwlock_unlock"; 95 if (!internal_strcmp(function, "__libc_rwlock_destroy")) 96 return "pthread_rwlock_destroy"; 97 if (!internal_strcmp(function, "__libc_thr_keycreate")) 98 return "pthread_key_create"; 99 if (!internal_strcmp(function, "__libc_thr_setspecific")) 100 return "pthread_setspecific"; 101 if (!internal_strcmp(function, "__libc_thr_getspecific")) 102 return "pthread_getspecific"; 103 if (!internal_strcmp(function, "__libc_thr_keydelete")) 104 return "pthread_key_delete"; 105 if (!internal_strcmp(function, "__libc_thr_once")) 106 return "pthread_once"; 107 if (!internal_strcmp(function, "__libc_thr_self")) 108 return "pthread_self"; 109 if (!internal_strcmp(function, "__libc_thr_exit")) 110 return "pthread_exit"; 111 if (!internal_strcmp(function, "__libc_thr_setcancelstate")) 112 return "pthread_setcancelstate"; 113 if (!internal_strcmp(function, "__libc_thr_equal")) 114 return "pthread_equal"; 115 if (!internal_strcmp(function, "__libc_thr_curcpu")) 116 return "pthread_curcpu_np"; 117 if (!internal_strcmp(function, "__libc_thr_sigsetmask")) 118 return "pthread_sigmask"; 119 #endif 120 121 return function; 122 } 123 124 static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace, 125 InternalScopedString *buffer) { 126 if (info.uuid_size) { 127 if (PrefixSpace) 128 buffer->append(" "); 129 buffer->append("(BuildId: "); 130 for (uptr i = 0; i < info.uuid_size; ++i) { 131 buffer->append("%02x", info.uuid[i]); 132 } 133 buffer->append(")"); 134 } 135 } 136 137 static const char kDefaultFormat[] = " #%n %p %F %L"; 138 139 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 140 uptr address, const AddressInfo *info, bool vs_style, 141 const char *strip_path_prefix) { 142 // info will be null in the case where symbolization is not needed for the 143 // given format. This ensures that the code below will get a hard failure 144 // rather than print incorrect information in case RenderNeedsSymbolization 145 // ever ends up out of sync with this function. If non-null, the addresses 146 // should match. 147 CHECK(!info || address == info->address); 148 if (0 == internal_strcmp(format, "DEFAULT")) 149 format = kDefaultFormat; 150 for (const char *p = format; *p != '\0'; p++) { 151 if (*p != '%') { 152 buffer->append("%c", *p); 153 continue; 154 } 155 p++; 156 switch (*p) { 157 case '%': 158 buffer->append("%%"); 159 break; 160 // Frame number and all fields of AddressInfo structure. 161 case 'n': 162 buffer->append("%u", frame_no); 163 break; 164 case 'p': 165 buffer->append("0x%zx", address); 166 break; 167 case 'm': 168 buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix)); 169 break; 170 case 'o': 171 buffer->append("0x%zx", info->module_offset); 172 break; 173 case 'b': 174 MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/false, buffer); 175 break; 176 case 'f': 177 buffer->append("%s", 178 DemangleFunctionName(StripFunctionName(info->function))); 179 break; 180 case 'q': 181 buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown 182 ? info->function_offset 183 : 0x0); 184 break; 185 case 's': 186 buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix)); 187 break; 188 case 'l': 189 buffer->append("%d", info->line); 190 break; 191 case 'c': 192 buffer->append("%d", info->column); 193 break; 194 // Smarter special cases. 195 case 'F': 196 // Function name and offset, if file is unknown. 197 if (info->function) { 198 buffer->append("in %s", 199 DemangleFunctionName(StripFunctionName(info->function))); 200 if (!info->file && info->function_offset != AddressInfo::kUnknown) 201 buffer->append("+0x%zx", info->function_offset); 202 } 203 break; 204 case 'S': 205 // File/line information. 206 RenderSourceLocation(buffer, info->file, info->line, info->column, 207 vs_style, strip_path_prefix); 208 break; 209 case 'L': 210 // Source location, or module location. 211 if (info->file) { 212 RenderSourceLocation(buffer, info->file, info->line, info->column, 213 vs_style, strip_path_prefix); 214 } else if (info->module) { 215 RenderModuleLocation(buffer, info->module, info->module_offset, 216 info->module_arch, strip_path_prefix); 217 218 MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer); 219 } else { 220 buffer->append("(<unknown module>)"); 221 } 222 break; 223 case 'M': 224 // Module basename and offset, or PC. 225 if (address & kExternalPCBit) { 226 // There PCs are not meaningful. 227 } else if (info->module) { 228 // Always strip the module name for %M. 229 RenderModuleLocation(buffer, StripModuleName(info->module), 230 info->module_offset, info->module_arch, ""); 231 MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer); 232 } else { 233 buffer->append("(%p)", (void *)address); 234 } 235 break; 236 default: 237 Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p, 238 (void *)p); 239 Die(); 240 } 241 } 242 } 243 244 bool RenderNeedsSymbolization(const char *format) { 245 if (0 == internal_strcmp(format, "DEFAULT")) 246 format = kDefaultFormat; 247 for (const char *p = format; *p != '\0'; p++) { 248 if (*p != '%') 249 continue; 250 p++; 251 switch (*p) { 252 case '%': 253 break; 254 case 'n': 255 // frame_no 256 break; 257 case 'p': 258 // address 259 break; 260 default: 261 return true; 262 } 263 } 264 return false; 265 } 266 267 void RenderData(InternalScopedString *buffer, const char *format, 268 const DataInfo *DI, const char *strip_path_prefix) { 269 for (const char *p = format; *p != '\0'; p++) { 270 if (*p != '%') { 271 buffer->append("%c", *p); 272 continue; 273 } 274 p++; 275 switch (*p) { 276 case '%': 277 buffer->append("%%"); 278 break; 279 case 's': 280 buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); 281 break; 282 case 'l': 283 buffer->append("%zu", DI->line); 284 break; 285 case 'g': 286 buffer->append("%s", DI->name); 287 break; 288 default: 289 Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p, 290 (void *)p); 291 Die(); 292 } 293 } 294 } 295 296 #endif // !SANITIZER_SYMBOLIZER_MARKUP 297 298 void RenderSourceLocation(InternalScopedString *buffer, const char *file, 299 int line, int column, bool vs_style, 300 const char *strip_path_prefix) { 301 if (vs_style && line > 0) { 302 buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); 303 if (column > 0) 304 buffer->append(",%d", column); 305 buffer->append(")"); 306 return; 307 } 308 309 buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); 310 if (line > 0) { 311 buffer->append(":%d", line); 312 if (column > 0) 313 buffer->append(":%d", column); 314 } 315 } 316 317 void RenderModuleLocation(InternalScopedString *buffer, const char *module, 318 uptr offset, ModuleArch arch, 319 const char *strip_path_prefix) { 320 buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); 321 if (arch != kModuleArchUnknown) { 322 buffer->append(":%s", ModuleArchToString(arch)); 323 } 324 buffer->append("+0x%zx)", offset); 325 } 326 327 } // namespace __sanitizer 328