diff options
author | Alexey Samsonov <samsonov@google.com> | 2013-11-27 11:46:58 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2013-11-27 11:46:58 +0000 |
commit | 1c256cbcc463c34abf55f39853bc7ae4874eda35 (patch) | |
tree | ca2ac57d780f3d640a25cb38a6c2ab82035438ac /compiler-rt | |
parent | 3238e1c913b17646294bf05579350ade8bc00a27 (diff) | |
download | bcm5719-llvm-1c256cbcc463c34abf55f39853bc7ae4874eda35.tar.gz bcm5719-llvm-1c256cbcc463c34abf55f39853bc7ae4874eda35.zip |
[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!
llvm-svn: 195837
Diffstat (limited to 'compiler-rt')
4 files changed, 223 insertions, 12 deletions
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index d31822c9ebd..cd518477be1 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc new file mode 100644 index 00000000000..839aa4cb716 --- /dev/null +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h new file mode 100644 index 00000000000..b9f60a9d1b7 --- /dev/null +++ b/compiler-rt/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/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 69c62a644d1..be68495428a 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 <errno.h> #include <stdlib.h> @@ -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 |