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 #if SANITIZER_LIBBACKTRACE 37 38 namespace { 39 40 # if SANITIZER_CP_DEMANGLE 41 struct CplusV3DemangleData { 42 char *buf; 43 uptr size, allocated; 44 }; 45 46 extern "C" { 47 static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { 48 CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; 49 uptr needed = data->size + l + 1; 50 if (needed > data->allocated) { 51 data->allocated *= 2; 52 if (needed > data->allocated) 53 data->allocated = needed; 54 char *buf = (char *)InternalAlloc(data->allocated); 55 if (data->buf) { 56 internal_memcpy(buf, data->buf, data->size); 57 InternalFree(data->buf); 58 } 59 data->buf = buf; 60 } 61 internal_memcpy(data->buf + data->size, s, l); 62 data->buf[data->size + l] = '\0'; 63 data->size += l; 64 } 65 } // extern "C" 66 67 char *CplusV3Demangle(const char *name) { 68 CplusV3DemangleData data; 69 data.buf = 0; 70 data.size = 0; 71 data.allocated = 0; 72 if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, 73 CplusV3DemangleCallback, &data)) { 74 if (data.size + 64 > data.allocated) 75 return data.buf; 76 char *buf = internal_strdup(data.buf); 77 InternalFree(data.buf); 78 return buf; 79 } 80 if (data.buf) 81 InternalFree(data.buf); 82 return 0; 83 } 84 # endif // SANITIZER_CP_DEMANGLE 85 86 struct SymbolizeCodeData { 87 AddressInfo *frames; 88 uptr n_frames; 89 uptr max_frames; 90 const char *module_name; 91 uptr module_offset; 92 }; 93 94 extern "C" { 95 static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, 96 const char *filename, int lineno, 97 const char *function) { 98 SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata; 99 if (function) { 100 AddressInfo *info = &cdata->frames[cdata->n_frames++]; 101 info->Clear(); 102 info->FillAddressAndModuleInfo(addr, cdata->module_name, 103 cdata->module_offset); 104 info->function = LibbacktraceSymbolizer::Demangle(function, true); 105 if (filename) 106 info->file = internal_strdup(filename); 107 info->line = lineno; 108 if (cdata->n_frames == cdata->max_frames) 109 return 1; 110 } 111 return 0; 112 } 113 114 static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, 115 const char *symname, uintptr_t, uintptr_t) { 116 SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata; 117 if (symname) { 118 AddressInfo *info = &cdata->frames[0]; 119 info->Clear(); 120 info->FillAddressAndModuleInfo(addr, cdata->module_name, 121 cdata->module_offset); 122 info->function = LibbacktraceSymbolizer::Demangle(symname, true); 123 cdata->n_frames = 1; 124 } 125 } 126 127 static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, 128 uintptr_t symval, uintptr_t symsize) { 129 DataInfo *info = (DataInfo *)vdata; 130 if (symname && symval) { 131 info->name = LibbacktraceSymbolizer::Demangle(symname, true); 132 info->start = symval; 133 info->size = symsize; 134 } 135 } 136 137 static void ErrorCallback(void *, const char *, int) {} 138 } // extern "C" 139 140 } // namespace 141 142 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 143 // State created in backtrace_create_state is leaked. 144 void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, 145 ErrorCallback, NULL)); 146 if (!state) 147 return 0; 148 return new(*alloc) LibbacktraceSymbolizer(state); 149 } 150 151 uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames, 152 uptr max_frames, 153 const char *module_name, 154 uptr module_offset) { 155 SymbolizeCodeData data; 156 data.frames = frames; 157 data.n_frames = 0; 158 data.max_frames = max_frames; 159 data.module_name = module_name; 160 data.module_offset = module_offset; 161 backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, 162 ErrorCallback, &data); 163 if (data.n_frames) 164 return data.n_frames; 165 backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, 166 ErrorCallback, &data); 167 return data.n_frames; 168 } 169 170 bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) { 171 backtrace_syminfo((backtrace_state *)state_, info->address, 172 SymbolizeDataCallback, ErrorCallback, info); 173 return true; 174 } 175 176 #else // SANITIZER_LIBBACKTRACE 177 178 LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 179 return 0; 180 } 181 182 uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames, 183 uptr max_frames, 184 const char *module_name, 185 uptr module_offset) { 186 (void)state_; 187 return 0; 188 } 189 190 bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) { 191 return false; 192 } 193 194 #endif // SANITIZER_LIBBACKTRACE 195 196 char *LibbacktraceSymbolizer::Demangle(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 } // namespace __sanitizer 207