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_symbolizer_libbacktrace.h" 15 16 #include "sanitizer_internal_defs.h" 17 #include "sanitizer_platform.h" 18 #include "sanitizer_symbolizer.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 33 namespace __sanitizer { 34 35 static char *DemangleAlloc(const char *name, bool always_alloc); 36 37 #if SANITIZER_LIBBACKTRACE 38 39 namespace { 40 41 # if SANITIZER_CP_DEMANGLE 42 struct CplusV3DemangleData { 43 char *buf; 44 uptr size, allocated; 45 }; 46 47 extern "C" { 48 static 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 68 char *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 87 struct 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 108 extern "C" { 109 static 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 124 static 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 134 static 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 144 static void ErrorCallback(void *, const char *, int) {} 145 } // extern "C" 146 147 } // namespace 148 149 LibbacktraceSymbolizer *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 158 bool 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 172 bool 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 180 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 181 return 0; 182 } 183 184 bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 185 (void)state_; 186 return false; 187 } 188 189 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { 190 return false; 191 } 192 193 #endif // SANITIZER_LIBBACKTRACE 194 195 static 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 nullptr; 203 } 204 205 const char *LibbacktraceSymbolizer::Demangle(const char *name) { 206 return DemangleAlloc(name, /*always_alloc*/ false); 207 } 208 209 } // namespace __sanitizer 210