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 36#if SANITIZER_LIBBACKTRACE 37 38namespace { 39 40# if SANITIZER_CP_DEMANGLE 41struct CplusV3DemangleData { 42 char *buf; 43 uptr size, allocated; 44}; 45 46extern "C" { 47static 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 67char *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 86struct SymbolizeCodeData { 87 AddressInfo *frames; 88 uptr n_frames; 89 uptr max_frames; 90 const char *module_name; 91 uptr module_offset; 92}; 93 94extern "C" { 95static 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 114static 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 127static 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 137static void ErrorCallback(void *, const char *, int) {} 138} // extern "C" 139 140} // namespace 141 142LibbacktraceSymbolizer *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 151uptr 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 170bool 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 178LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { 179 return 0; 180} 181 182uptr 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 190bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) { 191 return false; 192} 193 194#endif // SANITIZER_LIBBACKTRACE 195 196char *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