1//===-- sanitizer_symbolizer_libbacktrace.cc ------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is shared between AddressSanitizer and ThreadSanitizer 11// run-time libraries. 12// Libbacktrace implementation of symbolizer parts. 13//===----------------------------------------------------------------------===// 14 15#include "sanitizer_platform.h" 16 17#include "sanitizer_internal_defs.h" 18#include "sanitizer_symbolizer.h" 19#include "sanitizer_symbolizer_libbacktrace.h" 20 21#if SANITIZER_LIBBACKTRACE 22# include "backtrace-supported.h" 23# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC 24# include "backtrace.h" 25# if SANITIZER_CP_DEMANGLE 26# undef ARRAY_SIZE 27# include "demangle.h" 28# endif 29# else 30# define SANITIZER_LIBBACKTRACE 0 31# endif 32#endif 33 34namespace __sanitizer { 35 36static char *DemangleAlloc(const char *name, bool always_alloc); 37 38#if SANITIZER_LIBBACKTRACE 39 40namespace { 41 42# if SANITIZER_CP_DEMANGLE 43struct CplusV3DemangleData { 44 char *buf; 45 uptr size, allocated; 46}; 47 48extern "C" { 49static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { 50 CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; 51 uptr needed = data->size + l + 1; 52 if (needed > data->allocated) { 53 data->allocated *= 2; 54 if (needed > data->allocated) 55 data->allocated = needed; 56 char *buf = (char *)InternalAlloc(data->allocated); 57 if (data->buf) { 58 internal_memcpy(buf, data->buf, data->size); 59 InternalFree(data->buf); 60 } 61 data->buf = buf; 62 } 63 internal_memcpy(data->buf + data->size, s, l); 64 data->buf[data->size + l] = '\0'; 65 data->size += l; 66} 67} // extern "C" 68 69char *CplusV3Demangle(const char *name) { 70 CplusV3DemangleData data; 71 data.buf = 0; 72 data.size = 0; 73 data.allocated = 0; 74 if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, 75 CplusV3DemangleCallback, &data)) { 76 if (data.size + 64 > data.allocated) 77 return data.buf; 78 char *buf = internal_strdup(data.buf); 79 InternalFree(data.buf); 80 return buf; 81 } 82 if (data.buf) 83 InternalFree(data.buf); 84 return 0; 85} 86# endif // SANITIZER_CP_DEMANGLE 87 88struct SymbolizeCodeCallbackArg { 89 SymbolizedStack *first; 90 SymbolizedStack *last; 91 uptr frames_symbolized; 92 93 AddressInfo *get_new_frame(uintptr_t addr) { 94 CHECK(last); 95 if (frames_symbolized > 0) { 96 SymbolizedStack *cur = SymbolizedStack::New(addr); 97 AddressInfo *info = &cur->info; 98 info->FillModuleInfo(first->info.module, first->info.module_offset); 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