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