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