210 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between AddressSanitizer and ThreadSanitizer10// 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_LIBBACKTRACE21# include "backtrace-supported.h"22# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC23# include "backtrace.h"24# if SANITIZER_CP_DEMANGLE25# undef ARRAY_SIZE26# include "demangle.h"27# endif28# else29# define SANITIZER_LIBBACKTRACE 030# endif31#endif32 33namespace __sanitizer {34 35static char *DemangleAlloc(const char *name, bool always_alloc);36 37#if SANITIZER_LIBBACKTRACE38 39namespace {40 41# if SANITIZER_CP_DEMANGLE42struct CplusV3DemangleData {43 char *buf;44 uptr size, allocated;45};46 47extern "C" {48static 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 68char *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_DEMANGLE86 87struct 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 108extern "C" {109static 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 124static 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 134static 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 144static void ErrorCallback(void *, const char *, int) {}145} // extern "C"146 147} // namespace148 149LibbacktraceSymbolizer *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 158bool 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 172bool 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_LIBBACKTRACE179 180LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {181 return 0;182}183 184bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {185 (void)state_;186 return false;187}188 189bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {190 return false;191}192 193#endif // SANITIZER_LIBBACKTRACE194 195static char *DemangleAlloc(const char *name, bool always_alloc) {196#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE197 if (char *demangled = CplusV3Demangle(name))198 return demangled;199#endif200 if (always_alloc)201 return internal_strdup(name);202 return nullptr;203}204 205const char *LibbacktraceSymbolizer::Demangle(const char *name) {206 return DemangleAlloc(name, /*always_alloc*/ false);207}208 209} // namespace __sanitizer210