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