diff options
author | Alexey Samsonov <samsonov@google.com> | 2014-02-12 08:29:42 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2014-02-12 08:29:42 +0000 |
commit | 7304b4201f7f5b64cb44c540d98182cea1f630da (patch) | |
tree | aebab3e230b7ceb6e7bc88db4a435ef782e8dca3 /compiler-rt | |
parent | c34a997669646c0f87f6eb63a57173f4e2e2ac71 (diff) | |
download | bcm5719-llvm-7304b4201f7f5b64cb44c540d98182cea1f630da.tar.gz bcm5719-llvm-7304b4201f7f5b64cb44c540d98182cea1f630da.zip |
[Sanitizer] Teach external symbolizer to work with addr2line if llvm-symbolizer is unavailable. Allow this mode in TSan.
llvm-svn: 201218
Diffstat (limited to 'compiler-rt')
5 files changed, 120 insertions, 16 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc index cbff0a541a1..2982a0bb472 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc @@ -23,6 +23,7 @@ CommonFlags common_flags_dont_use; void SetCommonFlagsDefaults(CommonFlags *f) { f->symbolize = true; f->external_symbolizer_path = 0; + f->allow_addr2line = false; f->strip_path_prefix = ""; f->fast_unwind_on_fatal = false; f->fast_unwind_on_malloc = true; @@ -44,6 +45,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) { void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { ParseFlag(str, &f->symbolize, "symbolize"); ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path"); + ParseFlag(str, &f->allow_addr2line, "allow_addr2line"); ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix"); ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal"); ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc"); @@ -63,8 +65,6 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { // Do a sanity check for certain flags. if (f->malloc_context_size < 1) f->malloc_context_size = 1; - if (!f->symbolize) - f->external_symbolizer_path = ""; } static bool GetFlagValue(const char *env, const char *name, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h index cf2066a148f..a580acad86c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h @@ -30,6 +30,10 @@ struct CommonFlags { // in PATH. If it is empty (or if "symbolize" is false), external symbolizer // will not be started. const char *external_symbolizer_path; + // If set, allows online symbolizer to run addr2line binary to symbolize + // stack traces (addr2line will only be used if llvm-symbolizer binary is not + // available. + bool allow_addr2line; // Strips this prefix from file paths in error reports. const char *strip_path_prefix; // Use fast (frame-pointer-based) unwinder on fatal errors (if available). 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 4874532b8c9..a87bfbf1ad8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -16,6 +16,7 @@ #if SANITIZER_POSIX #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" +#include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" @@ -93,10 +94,20 @@ static const char *ExtractUptr(const char *str, const char *delims, return ret; } +class ExternalSymbolizerInterface { + public: + // Can't declare pure virtual functions in sanitizer runtimes: + // __cxa_pure_virtual might be unavailable. + virtual char *SendCommand(bool is_data, const char *module_name, + uptr module_offset) { + UNIMPLEMENTED(); + } +}; + // SymbolizerProcess encapsulates communication between the tool and // external symbolizer program, running in a different subprocess. // SymbolizerProcess may not be used from two threads simultaneously. -class SymbolizerProcess { +class SymbolizerProcess : public ExternalSymbolizerInterface { public: explicit SymbolizerProcess(const char *path) : path_(path), @@ -153,7 +164,7 @@ class SymbolizerProcess { uptr read_len = 0; while (true) { uptr just_read = internal_read(input_fd_, buffer + read_len, - max_length - read_len); + max_length - read_len - 1); // We can't read 0 bytes, as we don't expect external symbolizer to close // its stdout. if (just_read == 0 || just_read == (uptr)-1) { @@ -164,6 +175,7 @@ class SymbolizerProcess { if (ReachedEndOfOutput(buffer, read_len)) break; } + buffer[read_len] = '\0'; return true; } @@ -337,6 +349,74 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { } }; +class Addr2LineProcess : public SymbolizerProcess { + public: + Addr2LineProcess(const char *path, const char *module_name) + : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} + + const char *module_name() const { return module_name_; } + + private: + bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, + const char *module_name, uptr module_offset) const { + if (is_data) + return false; + CHECK_EQ(0, internal_strcmp(module_name, module_name_)); + internal_snprintf(buffer, max_length, "0x%zx\n", module_offset); + return true; + } + + bool ReachedEndOfOutput(const char *buffer, uptr length) const { + // Output should consist of two lines. + int num_lines = 0; + for (uptr i = 0; i < length; ++i) { + if (buffer[i] == '\n') + num_lines++; + if (num_lines >= 2) + return true; + } + return false; + } + + void ExecuteWithDefaultArgs(const char *path_to_binary) const { + execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0); + } + + const char *module_name_; // Owned, leaked. +}; + +class Addr2LinePool : public ExternalSymbolizerInterface { + public: + explicit Addr2LinePool(const char *addr2line_path, + LowLevelAllocator *allocator) + : addr2line_path_(addr2line_path), allocator_(allocator), + addr2line_pool_(16) {} + + char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { + if (is_data) + return 0; + Addr2LineProcess *addr2line = 0; + for (uptr i = 0; i < addr2line_pool_.size(); ++i) { + if (0 == + internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { + addr2line = addr2line_pool_[i]; + break; + } + } + if (!addr2line) { + addr2line = + new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); + addr2line_pool_.push_back(addr2line); + } + return addr2line->SendCommand(is_data, module_name, module_offset); + } + + private: + const char *addr2line_path_; + LowLevelAllocator *allocator_; + InternalMmapVector<Addr2LineProcess*> addr2line_pool_; +}; + #if SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE @@ -418,7 +498,7 @@ class InternalSymbolizer { class POSIXSymbolizer : public Symbolizer { public: - POSIXSymbolizer(SymbolizerProcess *external_symbolizer, + POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer, InternalSymbolizer *internal_symbolizer, LibbacktraceSymbolizer *libbacktrace_symbolizer) : Symbolizer(), @@ -630,27 +710,41 @@ class POSIXSymbolizer : public Symbolizer { bool modules_fresh_; BlockingMutex mu_; - SymbolizerProcess *external_symbolizer_; // Leaked. - InternalSymbolizer *const internal_symbolizer_; // Leaked. - LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked. + ExternalSymbolizerInterface *external_symbolizer_; // Leaked. + InternalSymbolizer *const internal_symbolizer_; // Leaked. + LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked. }; Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { + if (!common_flags()->symbolize) { + return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0); + } InternalSymbolizer* internal_symbolizer = InternalSymbolizer::get(&symbolizer_allocator_); - SymbolizerProcess *external_symbolizer = 0; + ExternalSymbolizerInterface *external_symbolizer = 0; LibbacktraceSymbolizer *libbacktrace_symbolizer = 0; if (!internal_symbolizer) { 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_) - LLVMSymbolizerProcess(path_to_external); + if (path_to_external && path_to_external[0] == '\0') { + // External symbolizer is explicitly disabled. Do nothing. + } else { + // Find path to llvm-symbolizer if it's not provided. + if (!path_to_external) + path_to_external = FindPathToBinary("llvm-symbolizer"); + if (path_to_external) { + external_symbolizer = new(symbolizer_allocator_) + LLVMSymbolizerProcess(path_to_external); + } else if (common_flags()->allow_addr2line) { + // If llvm-symbolizer is not found, try to use addr2line. + if (const char *addr2line_path = FindPathToBinary("addr2line")) { + external_symbolizer = new(symbolizer_allocator_) + Addr2LinePool(addr2line_path, &symbolizer_allocator_); + } + } + } } } diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/compiler-rt/lib/tsan/rtl/tsan_flags.cc index 4510f967c48..d11bf7ab69a 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc @@ -92,6 +92,8 @@ void InitializeFlags(Flags *f, const char *env) { f->die_after_fork = true; SetCommonFlagsDefaults(f); + // Override some common flags defaults. + f->allow_addr2line = true; // Let a frontend override. ParseFlags(f, __tsan_default_options()); diff --git a/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc b/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc index c90df413243..36e3a49bfd4 100644 --- a/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc +++ b/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc @@ -63,6 +63,7 @@ static const char *options1 = " symbolize=0" " external_symbolizer_path=asdfgh" + " allow_addr2line=true" " strip_path_prefix=zxcvb" " fast_unwind_on_fatal=0" " fast_unwind_on_malloc=0" @@ -105,6 +106,7 @@ static const char *options2 = " symbolize=true" " external_symbolizer_path=cccccc" + " allow_addr2line=false" " strip_path_prefix=ddddddd" " fast_unwind_on_fatal=true" " fast_unwind_on_malloc=true" @@ -146,7 +148,8 @@ void VerifyOptions1(Flags *f) { EXPECT_EQ(f->die_after_fork, true); EXPECT_EQ(f->symbolize, 0); - EXPECT_EQ(f->external_symbolizer_path, std::string("")); + EXPECT_EQ(f->external_symbolizer_path, std::string("asdfgh")); + EXPECT_EQ(f->allow_addr2line, true); EXPECT_EQ(f->strip_path_prefix, std::string("zxcvb")); EXPECT_EQ(f->fast_unwind_on_fatal, 0); EXPECT_EQ(f->fast_unwind_on_malloc, 0); @@ -189,6 +192,7 @@ void VerifyOptions2(Flags *f) { EXPECT_EQ(f->symbolize, true); EXPECT_EQ(f->external_symbolizer_path, std::string("cccccc")); + EXPECT_EQ(f->allow_addr2line, false); EXPECT_EQ(f->strip_path_prefix, std::string("ddddddd")); EXPECT_EQ(f->fast_unwind_on_fatal, true); EXPECT_EQ(f->fast_unwind_on_malloc, true); |