From f08d541bb2de3a09a5f1b0f647d62aed6821bcc8 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Wed, 27 Nov 2013 11:46:58 +0000 Subject: [PATCH] [Sanitizer] Add rudimentary support for using libbacktrace in symbolizer. More steps are needed to actually make it usable: * sanitizer runtimes should be compiled with -DSANITIZER_LIBBACKTRACE. * libbacktrace headers should be installed. * user has to manually link in libbacktrace.a into the executable. We can easily solve the first two problems in the build system, but detecting/linking libbacktrace to all the tests we have and end-user programs is more challenging (and will unlikely work w/o Driver support). Based on the patch by Jakub Jelinek! git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@195837 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 2 + .../sanitizer_symbolizer_libbacktrace.cc | 146 +++++++++++++++++++++ .../sanitizer_symbolizer_libbacktrace.h | 40 ++++++ .../sanitizer_symbolizer_posix_libcdep.cc | 47 +++++-- 4 files changed, 223 insertions(+), 12 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index d31822c9e..cd518477b 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -28,6 +28,7 @@ set(SANITIZER_LIBCDEP_SOURCES sanitizer_posix_libcdep.cc sanitizer_stacktrace_libcdep.cc sanitizer_stoptheworld_linux_libcdep.cc + sanitizer_symbolizer_libbacktrace.cc sanitizer_symbolizer_libcdep.cc sanitizer_symbolizer_posix_libcdep.cc) @@ -65,6 +66,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/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc new file mode 100644 index 000000000..839aa4cb7 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc @@ -0,0 +1,146 @@ +//===-- 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" +# else +# define SANITIZER_LIBBACKTRACE 0 +# endif +#endif + +namespace __sanitizer { + +#if SANITIZER_LIBBACKTRACE + +namespace { + +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 = internal_strdup(function); + 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 = internal_strdup(symname); + 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 = internal_strdup(symname); + 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 + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h new file mode 100644 index 000000000..b9f60a9d1 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h @@ -0,0 +1,40 @@ +//===-- sanitizer_symbolizer_libbacktrace.h -------------------------------===// +// +// 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 + +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); + + private: + explicit LibbacktraceSymbolizer(void *state) : state_(state) {} + + void *state_; // Leaked. +}; + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 69c62a644..be6849542 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/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 SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) { BlockingMutexLock l(&mu_); @@ -400,9 +403,17 @@ class POSIXSymbolizer : public Symbolizer { return 0; const char *module_name = module->full_name(); uptr module_offset = addr - module->base_address(); + // 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(); @@ -463,6 +474,11 @@ class POSIXSymbolizer : public Symbolizer { info->address = addr; info->module = internal_strdup(module_name); info->module_offset = module_offset; + 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; @@ -474,7 +490,8 @@ class POSIXSymbolizer : public Symbolizer { } bool IsAvailable() { - return internal_symbolizer_ != 0 || external_symbolizer_ != 0; + return internal_symbolizer_ != 0 || external_symbolizer_ != 0 || + libbacktrace_symbolizer_ != 0; } bool IsExternalAvailable() { @@ -567,24 +584,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 -- 2.11.4.GIT