1353944Sdim//===-- sanitizer_common.cpp ----------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is shared between sanitizers' run-time libraries. 10353944Sdim// 11353944Sdim//===----------------------------------------------------------------------===// 12353944Sdim 13353944Sdim#include "sanitizer_stacktrace_printer.h" 14353944Sdim#include "sanitizer_file.h" 15353944Sdim#include "sanitizer_fuchsia.h" 16353944Sdim 17353944Sdimnamespace __sanitizer { 18353944Sdim 19353944Sdim// sanitizer_symbolizer_markup.cpp implements these differently. 20353944Sdim#if !SANITIZER_SYMBOLIZER_MARKUP 21353944Sdim 22353944Sdimstatic const char *StripFunctionName(const char *function, const char *prefix) { 23353944Sdim if (!function) return nullptr; 24353944Sdim if (!prefix) return function; 25353944Sdim uptr prefix_len = internal_strlen(prefix); 26353944Sdim if (0 == internal_strncmp(function, prefix, prefix_len)) 27353944Sdim return function + prefix_len; 28353944Sdim return function; 29353944Sdim} 30353944Sdim 31353944Sdimstatic const char *DemangleFunctionName(const char *function) { 32353944Sdim if (!function) return nullptr; 33353944Sdim 34353944Sdim // NetBSD uses indirection for old threading functions for historical reasons 35353944Sdim // The mangled names are internal implementation detail and should not be 36353944Sdim // exposed even in backtraces. 37353944Sdim#if SANITIZER_NETBSD 38353944Sdim if (!internal_strcmp(function, "__libc_mutex_init")) 39353944Sdim return "pthread_mutex_init"; 40353944Sdim if (!internal_strcmp(function, "__libc_mutex_lock")) 41353944Sdim return "pthread_mutex_lock"; 42353944Sdim if (!internal_strcmp(function, "__libc_mutex_trylock")) 43353944Sdim return "pthread_mutex_trylock"; 44353944Sdim if (!internal_strcmp(function, "__libc_mutex_unlock")) 45353944Sdim return "pthread_mutex_unlock"; 46353944Sdim if (!internal_strcmp(function, "__libc_mutex_destroy")) 47353944Sdim return "pthread_mutex_destroy"; 48353944Sdim if (!internal_strcmp(function, "__libc_mutexattr_init")) 49353944Sdim return "pthread_mutexattr_init"; 50353944Sdim if (!internal_strcmp(function, "__libc_mutexattr_settype")) 51353944Sdim return "pthread_mutexattr_settype"; 52353944Sdim if (!internal_strcmp(function, "__libc_mutexattr_destroy")) 53353944Sdim return "pthread_mutexattr_destroy"; 54353944Sdim if (!internal_strcmp(function, "__libc_cond_init")) 55353944Sdim return "pthread_cond_init"; 56353944Sdim if (!internal_strcmp(function, "__libc_cond_signal")) 57353944Sdim return "pthread_cond_signal"; 58353944Sdim if (!internal_strcmp(function, "__libc_cond_broadcast")) 59353944Sdim return "pthread_cond_broadcast"; 60353944Sdim if (!internal_strcmp(function, "__libc_cond_wait")) 61353944Sdim return "pthread_cond_wait"; 62353944Sdim if (!internal_strcmp(function, "__libc_cond_timedwait")) 63353944Sdim return "pthread_cond_timedwait"; 64353944Sdim if (!internal_strcmp(function, "__libc_cond_destroy")) 65353944Sdim return "pthread_cond_destroy"; 66353944Sdim if (!internal_strcmp(function, "__libc_rwlock_init")) 67353944Sdim return "pthread_rwlock_init"; 68353944Sdim if (!internal_strcmp(function, "__libc_rwlock_rdlock")) 69353944Sdim return "pthread_rwlock_rdlock"; 70353944Sdim if (!internal_strcmp(function, "__libc_rwlock_wrlock")) 71353944Sdim return "pthread_rwlock_wrlock"; 72353944Sdim if (!internal_strcmp(function, "__libc_rwlock_tryrdlock")) 73353944Sdim return "pthread_rwlock_tryrdlock"; 74353944Sdim if (!internal_strcmp(function, "__libc_rwlock_trywrlock")) 75353944Sdim return "pthread_rwlock_trywrlock"; 76353944Sdim if (!internal_strcmp(function, "__libc_rwlock_unlock")) 77353944Sdim return "pthread_rwlock_unlock"; 78353944Sdim if (!internal_strcmp(function, "__libc_rwlock_destroy")) 79353944Sdim return "pthread_rwlock_destroy"; 80353944Sdim if (!internal_strcmp(function, "__libc_thr_keycreate")) 81353944Sdim return "pthread_key_create"; 82353944Sdim if (!internal_strcmp(function, "__libc_thr_setspecific")) 83353944Sdim return "pthread_setspecific"; 84353944Sdim if (!internal_strcmp(function, "__libc_thr_getspecific")) 85353944Sdim return "pthread_getspecific"; 86353944Sdim if (!internal_strcmp(function, "__libc_thr_keydelete")) 87353944Sdim return "pthread_key_delete"; 88353944Sdim if (!internal_strcmp(function, "__libc_thr_once")) 89353944Sdim return "pthread_once"; 90353944Sdim if (!internal_strcmp(function, "__libc_thr_self")) 91353944Sdim return "pthread_self"; 92353944Sdim if (!internal_strcmp(function, "__libc_thr_exit")) 93353944Sdim return "pthread_exit"; 94353944Sdim if (!internal_strcmp(function, "__libc_thr_setcancelstate")) 95353944Sdim return "pthread_setcancelstate"; 96353944Sdim if (!internal_strcmp(function, "__libc_thr_equal")) 97353944Sdim return "pthread_equal"; 98353944Sdim if (!internal_strcmp(function, "__libc_thr_curcpu")) 99353944Sdim return "pthread_curcpu_np"; 100353944Sdim if (!internal_strcmp(function, "__libc_thr_sigsetmask")) 101353944Sdim return "pthread_sigmask"; 102353944Sdim#endif 103353944Sdim 104353944Sdim return function; 105353944Sdim} 106353944Sdim 107353944Sdimstatic const char kDefaultFormat[] = " #%n %p %F %L"; 108353944Sdim 109353944Sdimvoid RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, 110353944Sdim const AddressInfo &info, bool vs_style, 111353944Sdim const char *strip_path_prefix, const char *strip_func_prefix) { 112353944Sdim if (0 == internal_strcmp(format, "DEFAULT")) 113353944Sdim format = kDefaultFormat; 114353944Sdim for (const char *p = format; *p != '\0'; p++) { 115353944Sdim if (*p != '%') { 116353944Sdim buffer->append("%c", *p); 117353944Sdim continue; 118353944Sdim } 119353944Sdim p++; 120353944Sdim switch (*p) { 121353944Sdim case '%': 122353944Sdim buffer->append("%%"); 123353944Sdim break; 124353944Sdim // Frame number and all fields of AddressInfo structure. 125353944Sdim case 'n': 126353944Sdim buffer->append("%zu", frame_no); 127353944Sdim break; 128353944Sdim case 'p': 129353944Sdim buffer->append("0x%zx", info.address); 130353944Sdim break; 131353944Sdim case 'm': 132353944Sdim buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); 133353944Sdim break; 134353944Sdim case 'o': 135353944Sdim buffer->append("0x%zx", info.module_offset); 136353944Sdim break; 137353944Sdim case 'f': 138353944Sdim buffer->append("%s", 139353944Sdim DemangleFunctionName( 140353944Sdim StripFunctionName(info.function, strip_func_prefix))); 141353944Sdim break; 142353944Sdim case 'q': 143353944Sdim buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown 144353944Sdim ? info.function_offset 145353944Sdim : 0x0); 146353944Sdim break; 147353944Sdim case 's': 148353944Sdim buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); 149353944Sdim break; 150353944Sdim case 'l': 151353944Sdim buffer->append("%d", info.line); 152353944Sdim break; 153353944Sdim case 'c': 154353944Sdim buffer->append("%d", info.column); 155353944Sdim break; 156353944Sdim // Smarter special cases. 157353944Sdim case 'F': 158353944Sdim // Function name and offset, if file is unknown. 159353944Sdim if (info.function) { 160353944Sdim buffer->append("in %s", 161353944Sdim DemangleFunctionName( 162353944Sdim StripFunctionName(info.function, strip_func_prefix))); 163353944Sdim if (!info.file && info.function_offset != AddressInfo::kUnknown) 164353944Sdim buffer->append("+0x%zx", info.function_offset); 165353944Sdim } 166353944Sdim break; 167353944Sdim case 'S': 168353944Sdim // File/line information. 169353944Sdim RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, 170353944Sdim strip_path_prefix); 171353944Sdim break; 172353944Sdim case 'L': 173353944Sdim // Source location, or module location. 174353944Sdim if (info.file) { 175353944Sdim RenderSourceLocation(buffer, info.file, info.line, info.column, 176353944Sdim vs_style, strip_path_prefix); 177353944Sdim } else if (info.module) { 178353944Sdim RenderModuleLocation(buffer, info.module, info.module_offset, 179353944Sdim info.module_arch, strip_path_prefix); 180353944Sdim } else { 181353944Sdim buffer->append("(<unknown module>)"); 182353944Sdim } 183353944Sdim break; 184353944Sdim case 'M': 185353944Sdim // Module basename and offset, or PC. 186353944Sdim if (info.address & kExternalPCBit) 187353944Sdim {} // There PCs are not meaningful. 188353944Sdim else if (info.module) 189353944Sdim // Always strip the module name for %M. 190353944Sdim RenderModuleLocation(buffer, StripModuleName(info.module), 191353944Sdim info.module_offset, info.module_arch, ""); 192353944Sdim else 193353944Sdim buffer->append("(%p)", (void *)info.address); 194353944Sdim break; 195353944Sdim default: 196353944Sdim Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, 197353944Sdim *p); 198353944Sdim Die(); 199353944Sdim } 200353944Sdim } 201353944Sdim} 202353944Sdim 203353944Sdimvoid RenderData(InternalScopedString *buffer, const char *format, 204353944Sdim const DataInfo *DI, const char *strip_path_prefix) { 205353944Sdim for (const char *p = format; *p != '\0'; p++) { 206353944Sdim if (*p != '%') { 207353944Sdim buffer->append("%c", *p); 208353944Sdim continue; 209353944Sdim } 210353944Sdim p++; 211353944Sdim switch (*p) { 212353944Sdim case '%': 213353944Sdim buffer->append("%%"); 214353944Sdim break; 215353944Sdim case 's': 216353944Sdim buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); 217353944Sdim break; 218353944Sdim case 'l': 219353944Sdim buffer->append("%d", DI->line); 220353944Sdim break; 221353944Sdim case 'g': 222353944Sdim buffer->append("%s", DI->name); 223353944Sdim break; 224353944Sdim default: 225353944Sdim Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, 226353944Sdim *p); 227353944Sdim Die(); 228353944Sdim } 229353944Sdim } 230353944Sdim} 231353944Sdim 232353944Sdim#endif // !SANITIZER_SYMBOLIZER_MARKUP 233353944Sdim 234353944Sdimvoid RenderSourceLocation(InternalScopedString *buffer, const char *file, 235353944Sdim int line, int column, bool vs_style, 236353944Sdim const char *strip_path_prefix) { 237353944Sdim if (vs_style && line > 0) { 238353944Sdim buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); 239353944Sdim if (column > 0) 240353944Sdim buffer->append(",%d", column); 241353944Sdim buffer->append(")"); 242353944Sdim return; 243353944Sdim } 244353944Sdim 245353944Sdim buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); 246353944Sdim if (line > 0) { 247353944Sdim buffer->append(":%d", line); 248353944Sdim if (column > 0) 249353944Sdim buffer->append(":%d", column); 250353944Sdim } 251353944Sdim} 252353944Sdim 253353944Sdimvoid RenderModuleLocation(InternalScopedString *buffer, const char *module, 254353944Sdim uptr offset, ModuleArch arch, 255353944Sdim const char *strip_path_prefix) { 256353944Sdim buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); 257353944Sdim if (arch != kModuleArchUnknown) { 258353944Sdim buffer->append(":%s", ModuleArchToString(arch)); 259353944Sdim } 260353944Sdim buffer->append("+0x%zx)", offset); 261353944Sdim} 262353944Sdim 263353944Sdim} // namespace __sanitizer 264