1//===-- sanitizer_symbolizer_libbacktrace.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 AddressSanitizer and ThreadSanitizer 10// run-time libraries. 11// Libbacktrace implementation of symbolizer parts. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_platform.h" 15 16#include "sanitizer_internal_defs.h" 17#include "sanitizer_symbolizer.h" 18#include "sanitizer_symbolizer_libbacktrace.h" 19 20#if SANITIZER_LIBBACKTRACE 21# include "backtrace-supported.h" 22# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC 23# include "backtrace.h" 24# if SANITIZER_CP_DEMANGLE 25# undef ARRAY_SIZE 26# include "demangle.h" 27# endif 28# else 29# define SANITIZER_LIBBACKTRACE 0 30# endif 31#endif 32 33namespace __sanitizer { 34 35static char *DemangleAlloc(const char *name, bool always_alloc); 36 37#if SANITIZER_LIBBACKTRACE 38 39namespace { 40 41# if SANITIZER_CP_DEMANGLE 42struct CplusV3DemangleData { 43 char *buf; 44 uptr size, allocated; 45}; 46 47extern "C" { 48static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { 49 CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; 50 uptr needed = data->size + l + 1; 51 if (needed > data->allocated) { 52 data->allocated *= 2; 53 if (needed > data->allocated) 54 data->allocated = needed; 55 char *buf = (char *)InternalAlloc(data->allocated); 56 if (data->buf) { 57 internal_memcpy(buf, data->buf, data->size); 58 InternalFree(data->buf); 59 } 60 data->buf = buf; 61 } 62 internal_memcpy(data->buf + data->size, s, l); 63 data->buf[data->size + l] = '\0'; 64 data->size += l; 65} 66} // extern "C" 67 68char *CplusV3Demangle(const char *name) { 69 CplusV3DemangleData data; 70 data.buf = 0; 71 data.size = 0; 72 data.allocated = 0; 73 if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, 74 CplusV3DemangleCallback, &data)) { 75 if (data.size + 64 > data.allocated) 76 return data.buf; 77 char *buf = internal_strdup(data.buf); 78 InternalFree(data.buf); 79 return buf; 80 } 81 if (data.buf) 82 InternalFree(data.buf); 83 return 0; 84} 85# endif // SANITIZER_CP_DEMANGLE 86 87struct SymbolizeCodeCallbackArg { 88 SymbolizedStack *first; 89 SymbolizedStack *last; 90 uptr frames_symbolized; 91 92 AddressInfo *get_new_frame(uintptr_t addr) { 93 CHECK(last); 94 if (frames_symbolized > 0) { 95 SymbolizedStack *cur = SymbolizedStack::New(addr); 96 AddressInfo *info = &cur->info; 97 info->FillModuleInfo(first->info.module, first->info.module_offset, 98 first->info.module_arch); 99 last->next = cur; 100 last = cur; 101 } 102 CHECK_EQ(addr, first->info.address); 103 CHECK_EQ(addr, last->info.address); 104 return &last->info; 105 } 106}; 107 108extern "C" { 109static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, 110 const char *filename, int lineno, 111 const char *function) { 112 SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; 113 if (function) { 114 AddressInfo *info = cdata->get_new_frame(addr); 115 info->function = DemangleAlloc(function, /*always_alloc*/ true); 116 if (filename) 117 info->file = internal_strdup(filename); 118 info->line = lineno; 119 cdata->frames_symbolized++; 120 } 121 return 0; 122} 123 124static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, 125 const char *symname, uintptr_t, uintptr_t) { 126 SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; 127 if (symname) { 128 AddressInfo *info = cdata->get_new_frame(addr); 129 info->function = DemangleAlloc(symname, /*always_alloc*/ true); 130 cdata->frames_symbolized++; 131 } 132} 133 134static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, 135 uintptr_t symval, uintptr_t symsize) { 136 DataInfo *info = (DataInfo *)vdata; 137 if (symname && symval) { 138 info->name = DemangleAlloc(symname, /*always_alloc*/ true); 139 info->start = symval; 140 info->size = symsize; 141 } 142} 143 144static void ErrorCallback(void *, const char *, int) {} 145} // extern "C" 146 147} // namespace 148 149LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 150 // State created in backtrace_create_state is leaked. 151 void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, 152 ErrorCallback, NULL)); 153 if (!state) 154 return 0; 155 return new(*alloc) LibbacktraceSymbolizer(state); 156} 157 158bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 159 SymbolizeCodeCallbackArg data; 160 data.first = stack; 161 data.last = stack; 162 data.frames_symbolized = 0; 163 backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, 164 ErrorCallback, &data); 165 if (data.frames_symbolized > 0) 166 return true; 167 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, 168 ErrorCallback, &data); 169 return (data.frames_symbolized > 0); 170} 171 172bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { 173 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback, 174 ErrorCallback, info); 175 return true; 176} 177 178#else // SANITIZER_LIBBACKTRACE 179 180LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 181 return 0; 182} 183 184bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 185 (void)state_; 186 return false; 187} 188 189bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { 190 return false; 191} 192 193#endif // SANITIZER_LIBBACKTRACE 194 195static char *DemangleAlloc(const char *name, bool always_alloc) { 196#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE 197 if (char *demangled = CplusV3Demangle(name)) 198 return demangled; 199#endif 200 if (always_alloc) 201 return internal_strdup(name); 202 return 0; 203} 204 205const char *LibbacktraceSymbolizer::Demangle(const char *name) { 206 return DemangleAlloc(name, /*always_alloc*/ false); 207} 208 209} // namespace __sanitizer 210