[compiler-rt] r201218 - [Sanitizer] Teach external symbolizer to work with addr2line if llvm-symbolizer is unavailable. Allow this mode in TSan.

Alexey Samsonov samsonov at google.com
Wed Feb 12 00:29:42 PST 2014


Author: samsonov
Date: Wed Feb 12 02:29:42 2014
New Revision: 201218

URL: http://llvm.org/viewvc/llvm-project?rev=201218&view=rev
Log:
[Sanitizer] Teach external symbolizer to work with addr2line if llvm-symbolizer is unavailable. Allow this mode in TSan.

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_flags.cc
    compiler-rt/trunk/lib/tsan/tests/unit/tsan_flags_test.cc

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc?rev=201218&r1=201217&r2=201218&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc Wed Feb 12 02:29:42 2014
@@ -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
 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(CommonFl
   // 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,

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h?rev=201218&r1=201217&r2=201218&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h Wed Feb 12 02:29:42 2014
@@ -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).

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc?rev=201218&r1=201217&r2=201218&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc Wed Feb 12 02:29:42 2014
@@ -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 cha
   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 Sym
   }
 };
 
+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 Symbolize
   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_);
+          }
+        }
+      }
     }
   }
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_flags.cc?rev=201218&r1=201217&r2=201218&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_flags.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_flags.cc Wed Feb 12 02:29:42 2014
@@ -92,6 +92,8 @@ void InitializeFlags(Flags *f, const cha
   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());

Modified: compiler-rt/trunk/lib/tsan/tests/unit/tsan_flags_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/tests/unit/tsan_flags_test.cc?rev=201218&r1=201217&r2=201218&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/tests/unit/tsan_flags_test.cc (original)
+++ compiler-rt/trunk/lib/tsan/tests/unit/tsan_flags_test.cc Wed Feb 12 02:29:42 2014
@@ -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);





More information about the llvm-commits mailing list