Home | History | Annotate | Download | only in sanitizer_common
      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