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 34 namespace __sanitizer { 35 36 static char *DemangleAlloc(const char *name, bool always_alloc); 37 38 #if SANITIZER_LIBBACKTRACE 39 40 namespace { 41 42 # if SANITIZER_CP_DEMANGLE 43 struct CplusV3DemangleData { 44 char *buf; 45 uptr size, allocated; 46 }; 47 48 extern "C" { 49 static 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 69 char *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 88 struct 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 first->info.module_arch); 100 last->next = cur; 101 last = cur; 102 } 103 CHECK_EQ(addr, first->info.address); 104 CHECK_EQ(addr, last->info.address); 105 return &last->info; 106 } 107 }; 108 109 extern "C" { 110 static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, 111 const char *filename, int lineno, 112 const char *function) { 113 SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; 114 if (function) { 115 AddressInfo *info = cdata->get_new_frame(addr); 116 info->function = DemangleAlloc(function, /*always_alloc*/ true); 117 if (filename) 118 info->file = internal_strdup(filename); 119 info->line = lineno; 120 cdata->frames_symbolized++; 121 } 122 return 0; 123 } 124 125 static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, 126 const char *symname, uintptr_t, uintptr_t) { 127 SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; 128 if (symname) { 129 AddressInfo *info = cdata->get_new_frame(addr); 130 info->function = DemangleAlloc(symname, /*always_alloc*/ true); 131 cdata->frames_symbolized++; 132 } 133 } 134 135 static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, 136 uintptr_t symval, uintptr_t symsize) { 137 DataInfo *info = (DataInfo *)vdata; 138 if (symname && symval) { 139 info->name = DemangleAlloc(symname, /*always_alloc*/ true); 140 info->start = symval; 141 info->size = symsize; 142 } 143 } 144 145 static void ErrorCallback(void *, const char *, int) {} 146 } // extern "C" 147 148 } // namespace 149 150 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 151 // State created in backtrace_create_state is leaked. 152 void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, 153 ErrorCallback, NULL)); 154 if (!state) 155 return 0; 156 return new(*alloc) LibbacktraceSymbolizer(state); 157 } 158 159 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 160 SymbolizeCodeCallbackArg data; 161 data.first = stack; 162 data.last = stack; 163 data.frames_symbolized = 0; 164 backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, 165 ErrorCallback, &data); 166 if (data.frames_symbolized > 0) 167 return true; 168 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, 169 ErrorCallback, &data); 170 return (data.frames_symbolized > 0); 171 } 172 173 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { 174 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback, 175 ErrorCallback, info); 176 return true; 177 } 178 179 #else // SANITIZER_LIBBACKTRACE 180 181 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 182 return 0; 183 } 184 185 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 186 (void)state_; 187 return false; 188 } 189 190 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { 191 return false; 192 } 193 194 #endif // SANITIZER_LIBBACKTRACE 195 196 static char *DemangleAlloc(const char *name, bool always_alloc) { 197 #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE 198 if (char *demangled = CplusV3Demangle(name)) 199 return demangled; 200 #endif 201 if (always_alloc) 202 return internal_strdup(name); 203 return 0; 204 } 205 206 const char *LibbacktraceSymbolizer::Demangle(const char *name) { 207 return DemangleAlloc(name, /*always_alloc*/ false); 208 } 209 210 } // namespace __sanitizer 211