diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index a2a1e1f1a0a8..73e9e14db4d6 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt @@ -20,6 +20,7 @@ set(SANITIZER_SOURCES sanitizer_stacktrace.cc sanitizer_suppressions.cc sanitizer_symbolizer.cc + sanitizer_symbolizer_libbacktrace.cc sanitizer_symbolizer_win.cc sanitizer_thread_registry.cc sanitizer_win.cc) @@ -67,6 +68,7 @@ set(SANITIZER_HEADERS sanitizer_stoptheworld.h sanitizer_suppressions.h sanitizer_symbolizer.h + sanitizer_symbolizer_libbacktrace.h sanitizer_syscall_generic.inc sanitizer_syscall_linux_x86_64.inc sanitizer_thread_registry.h) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc new file mode 100644 index 000000000000..4ec6f0a19a65 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc @@ -0,0 +1,206 @@ +//===-- sanitizer_symbolizer_libbacktrace.cc ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Libbacktrace implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#include "sanitizer_internal_defs.h" +#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_libbacktrace.h" + +#if SANITIZER_LIBBACKTRACE +# include "backtrace-supported.h" +# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC +# include "backtrace.h" +# if SANITIZER_CP_DEMANGLE +# undef ARRAY_SIZE +# include "demangle.h" +# endif +# else +# define SANITIZER_LIBBACKTRACE 0 +# endif +#endif + +namespace __sanitizer { + +#if SANITIZER_LIBBACKTRACE + +namespace { + +# if SANITIZER_CP_DEMANGLE +struct CplusV3DemangleData { + char *buf; + uptr size, allocated; +}; + +extern "C" { +static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { + CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; + uptr needed = data->size + l + 1; + if (needed > data->allocated) { + data->allocated *= 2; + if (needed > data->allocated) + data->allocated = needed; + char *buf = (char *)InternalAlloc(data->allocated); + if (data->buf) { + internal_memcpy(buf, data->buf, data->size); + InternalFree(data->buf); + } + data->buf = buf; + } + internal_memcpy(data->buf + data->size, s, l); + data->buf[data->size + l] = '\0'; + data->size += l; +} +} // extern "C" + +char *CplusV3Demangle(const char *name) { + CplusV3DemangleData data; + data.buf = 0; + data.size = 0; + data.allocated = 0; + if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, + CplusV3DemangleCallback, &data)) { + if (data.size + 64 > data.allocated) + return data.buf; + char *buf = internal_strdup(data.buf); + InternalFree(data.buf); + return buf; + } + if (data.buf) + InternalFree(data.buf); + return 0; +} +# endif // SANITIZER_CP_DEMANGLE + +struct SymbolizeCodeData { + AddressInfo *frames; + uptr n_frames; + uptr max_frames; + const char *module_name; + uptr module_offset; +}; + +extern "C" { +static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, + const char *filename, int lineno, + const char *function) { + SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata; + if (function) { + AddressInfo *info = &cdata->frames[cdata->n_frames++]; + info->Clear(); + info->FillAddressAndModuleInfo(addr, cdata->module_name, + cdata->module_offset); + info->function = LibbacktraceSymbolizer::Demangle(function, true); + if (filename) + info->file = internal_strdup(filename); + info->line = lineno; + if (cdata->n_frames == cdata->max_frames) + return 1; + } + return 0; +} + +static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, + const char *symname, uintptr_t, uintptr_t) { + SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata; + if (symname) { + AddressInfo *info = &cdata->frames[0]; + info->Clear(); + info->FillAddressAndModuleInfo(addr, cdata->module_name, + cdata->module_offset); + info->function = LibbacktraceSymbolizer::Demangle(symname, true); + cdata->n_frames = 1; + } +} + +static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, + uintptr_t symval, uintptr_t symsize) { + DataInfo *info = (DataInfo *)vdata; + if (symname && symval) { + info->name = LibbacktraceSymbolizer::Demangle(symname, true); + info->start = symval; + info->size = symsize; + } +} + +static void ErrorCallback(void *, const char *, int) {} +} // extern "C" + +} // namespace + +LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { + // State created in backtrace_create_state is leaked. + void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, + ErrorCallback, NULL)); + if (!state) + return 0; + return new(*alloc) LibbacktraceSymbolizer(state); +} + +uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames, + uptr max_frames, + const char *module_name, + uptr module_offset) { + SymbolizeCodeData data; + data.frames = frames; + data.n_frames = 0; + data.max_frames = max_frames; + data.module_name = module_name; + data.module_offset = module_offset; + backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, + ErrorCallback, &data); + if (data.n_frames) + return data.n_frames; + backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, + ErrorCallback, &data); + return data.n_frames; +} + +bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) { + backtrace_syminfo((backtrace_state *)state_, info->address, + SymbolizeDataCallback, ErrorCallback, info); + return true; +} + +#else // SANITIZER_LIBBACKTRACE + +LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { + return 0; +} + +uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames, + uptr max_frames, + const char *module_name, + uptr module_offset) { + (void)state_; + return 0; +} + +bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) { + return false; +} + +#endif // SANITIZER_LIBBACKTRACE + +char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) { +#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE + if (char *demangled = CplusV3Demangle(name)) + return demangled; +#endif + if (always_alloc) + return internal_strdup(name); + return 0; +} + +} // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h new file mode 100644 index 000000000000..7a2f04d658c9 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h @@ -0,0 +1,47 @@ +//===-- sanitizer_symbolizer_libbacktrace.h ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Header for libbacktrace symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#include "sanitizer_common.h" +#include "sanitizer_symbolizer.h" + +#ifndef SANITIZER_LIBBACKTRACE +# define SANITIZER_LIBBACKTRACE 0 +#endif + +#ifndef SANITIZER_CP_DEMANGLE +# define SANITIZER_CP_DEMANGLE 0 +#endif + +namespace __sanitizer { + +class LibbacktraceSymbolizer { + public: + static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc); + + uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames, + const char *module_name, uptr module_offset); + + bool SymbolizeData(DataInfo *info); + + // May return NULL if demangling failed. + static char *Demangle(const char *name, bool always_alloc = false); + + private: + explicit LibbacktraceSymbolizer(void *state) : state_(state) {} + + void *state_; // Leaked. +}; + +} // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 1df924fb4414..2fb2acb8ff15 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -21,6 +21,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_libbacktrace.h" #include #include @@ -386,10 +387,12 @@ class InternalSymbolizer { class POSIXSymbolizer : public Symbolizer { public: POSIXSymbolizer(ExternalSymbolizer *external_symbolizer, - InternalSymbolizer *internal_symbolizer) + InternalSymbolizer *internal_symbolizer, + LibbacktraceSymbolizer *libbacktrace_symbolizer) : Symbolizer(), external_symbolizer_(external_symbolizer), - internal_symbolizer_(internal_symbolizer) {} + internal_symbolizer_(internal_symbolizer), + libbacktrace_symbolizer_(libbacktrace_symbolizer) {} uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) { BlockingMutexLock l(&mu_); @@ -399,9 +402,17 @@ class POSIXSymbolizer : public Symbolizer { uptr module_offset; if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) return 0; + // First, try to use libbacktrace symbolizer (if it's available). + if (libbacktrace_symbolizer_ != 0) { + mu_.CheckLocked(); + uptr res = libbacktrace_symbolizer_->SymbolizeCode( + addr, frames, max_frames, module_name, module_offset); + if (res > 0) + return res; + } const char *str = SendCommand(false, module_name, module_offset); if (str == 0) { - // External symbolizer was not initialized or failed. Fill only data + // Symbolizer was not initialized or failed. Fill only data // about module name and offset. AddressInfo *info = &frames[0]; info->Clear(); @@ -462,6 +473,12 @@ class POSIXSymbolizer : public Symbolizer { info->address = addr; info->module = internal_strdup(module_name); info->module_offset = module_offset; + // First, try to use libbacktrace symbolizer (if it's available). + if (libbacktrace_symbolizer_ != 0) { + mu_.CheckLocked(); + if (libbacktrace_symbolizer_->SymbolizeData(info)) + return true; + } const char *str = SendCommand(true, module_name, module_offset); if (str == 0) return true; @@ -479,7 +496,8 @@ class POSIXSymbolizer : public Symbolizer { } bool CanReturnFileLineInfo() { - return internal_symbolizer_ != 0 || external_symbolizer_ != 0; + return internal_symbolizer_ != 0 || external_symbolizer_ != 0 || + libbacktrace_symbolizer_ != 0; } void Flush() { @@ -497,6 +515,11 @@ class POSIXSymbolizer : public Symbolizer { // Run hooks even if we don't use internal symbolizer, as cxxabi // demangle may call system functions. SymbolizerScope sym_scope(this); + // Try to use libbacktrace demangler (if available). + if (libbacktrace_symbolizer_ != 0) { + if (const char *demangled = libbacktrace_symbolizer_->Demangle(name)) + return demangled; + } if (internal_symbolizer_ != 0) return internal_symbolizer_->Demangle(name); return DemangleCXXABI(name); @@ -578,24 +601,30 @@ class POSIXSymbolizer : public Symbolizer { ExternalSymbolizer *external_symbolizer_; // Leaked. InternalSymbolizer *const internal_symbolizer_; // Leaked. + LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked. }; Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { InternalSymbolizer* internal_symbolizer = InternalSymbolizer::get(&symbolizer_allocator_); ExternalSymbolizer *external_symbolizer = 0; + LibbacktraceSymbolizer *libbacktrace_symbolizer = 0; if (!internal_symbolizer) { - // Find path to llvm-symbolizer if it's not provided. - if (!path_to_external) - path_to_external = FindPathToBinary("llvm-symbolizer"); - if (path_to_external && path_to_external[0] != '\0') - external_symbolizer = new(symbolizer_allocator_) - ExternalSymbolizer(path_to_external); + libbacktrace_symbolizer = + LibbacktraceSymbolizer::get(&symbolizer_allocator_); + if (!libbacktrace_symbolizer) { + // Find path to llvm-symbolizer if it's not provided. + if (!path_to_external) + path_to_external = FindPathToBinary("llvm-symbolizer"); + if (path_to_external && path_to_external[0] != '\0') + external_symbolizer = new(symbolizer_allocator_) + ExternalSymbolizer(path_to_external); + } } - return new(symbolizer_allocator_) - POSIXSymbolizer(external_symbolizer, internal_symbolizer); + return new(symbolizer_allocator_) POSIXSymbolizer( + external_symbolizer, internal_symbolizer, libbacktrace_symbolizer); } } // namespace __sanitizer