summaryrefslogtreecommitdiffstats
path: root/compiler-rt
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2014-02-12 08:29:42 +0000
committerAlexey Samsonov <samsonov@google.com>2014-02-12 08:29:42 +0000
commit7304b4201f7f5b64cb44c540d98182cea1f630da (patch)
treeaebab3e230b7ceb6e7bc88db4a435ef782e8dca3 /compiler-rt
parentc34a997669646c0f87f6eb63a57173f4e2e2ac71 (diff)
downloadbcm5719-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')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_flags.cc4
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_flags.h4
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc120
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_flags.cc2
-rw-r--r--compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc6
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);
OpenPOWER on IntegriCloud