[TSan] add a new option 'use_internal_symbolizer' that allows to choose between addr2line-based and llvm-based symbolizer w/o having to rebuild the runtime. This is hopefully a temporary solution that simplifies testing process. In the end, we should leave a single symbolizer.

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@159730 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 7224f4b..1474450 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -51,6 +51,7 @@
   f->flush_memory_ms = 0;
   f->stop_on_start = false;
   f->running_on_valgrind = false;
+  f->use_internal_symbolizer = false;
 
 
   // Let a frontend override.
@@ -72,6 +73,7 @@
   Flag(env, &f->profile_memory, "profile_memory");
   Flag(env, &f->flush_memory_ms, "flush_memory_ms");
   Flag(env, &f->stop_on_start, "stop_on_start");
+  Flag(env, &f->use_internal_symbolizer, "use_internal_symbolizer");
 }
 
 static const char *GetFlagValue(const char *env, const char *name,
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index 66d3cf8..c22132f 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -60,6 +60,8 @@
   bool stop_on_start;
   // Controls whether RunningOnValgrind() returns true or false.
   bool running_on_valgrind;
+  // If set, uses in-process symbolizer from common sanitizer runtime.
+  bool use_internal_symbolizer;
 };
 
 Flags *flags();
diff --git a/lib/tsan/rtl/tsan_symbolize.cc b/lib/tsan/rtl/tsan_symbolize.cc
new file mode 100644
index 0000000..f757d07
--- /dev/null
+++ b/lib/tsan/rtl/tsan_symbolize.cc
@@ -0,0 +1,78 @@
+//===-- tsan_symbolize.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 a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tsan_symbolize.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "tsan_flags.h"
+#include "tsan_report.h"
+
+namespace __tsan {
+
+ReportStack *NewReportStackEntry(uptr addr) {
+  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
+                                                  sizeof(ReportStack));
+  internal_memset(ent, 0, sizeof(*ent));
+  ent->pc = addr;
+  return ent;
+}
+
+static ReportStack *NewReportStackEntry(const AddressInfo &info) {
+  ReportStack *ent = NewReportStackEntry(info.address);
+  if (info.module)
+    ent->module = internal_strdup(info.module);
+  ent->offset = info.module_offset;
+  if (info.function) {
+    ent->func = internal_strdup(info.function);
+  }
+  if (info.file)
+    ent->file = internal_strdup(info.file);
+  ent->line = info.line;
+  ent->col = info.column;
+  return ent;
+}
+
+ReportStack *SymbolizeCode(uptr addr) {
+  if (flags()->use_internal_symbolizer) {
+    static const uptr kMaxAddrFrames = 16;
+    InternalScopedBuf<AddressInfo> addr_frames(kMaxAddrFrames);
+    for (uptr i = 0; i < kMaxAddrFrames; i++)
+      new(&addr_frames[i]) AddressInfo();
+    uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames,
+                                                      kMaxAddrFrames);
+    if (addr_frames_num == 0)
+      return NewReportStackEntry(addr);
+    ReportStack *top = 0;
+    ReportStack *bottom = 0;
+    for (uptr i = 0; i < addr_frames_num; i++) {
+      ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
+      CHECK(cur_entry);
+      addr_frames[i].Clear();
+      if (i == 0)
+        top = cur_entry;
+      else
+        bottom->next = cur_entry;
+      bottom = cur_entry;
+    }
+    return top;
+  }
+  return SymbolizeCodeAddr2Line(addr);
+}
+
+ReportStack *SymbolizeData(uptr addr) {
+  return SymbolizeDataAddr2Line(addr);
+}
+
+}  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_symbolize.h b/lib/tsan/rtl/tsan_symbolize.h
index 4eaec4a..115339b 100644
--- a/lib/tsan/rtl/tsan_symbolize.h
+++ b/lib/tsan/rtl/tsan_symbolize.h
@@ -21,6 +21,11 @@
 ReportStack *SymbolizeCode(uptr addr);
 ReportStack *SymbolizeData(uptr addr);
 
+ReportStack *SymbolizeCodeAddr2Line(uptr addr);
+ReportStack *SymbolizeDataAddr2Line(uptr addr);
+
+ReportStack *NewReportStackEntry(uptr addr);
+
 }  // namespace __tsan
 
 #endif  // TSAN_SYMBOLIZE_H
diff --git a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
index c5bed5d..5eed977 100644
--- a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
+++ b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
@@ -146,18 +146,10 @@
   return 0;
 }
 
-static ReportStack *NewFrame(uptr addr) {
-  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
-                                                  sizeof(ReportStack));
-  internal_memset(ent, 0, sizeof(*ent));
-  ent->pc = addr;
-  return ent;
-}
-
-ReportStack *SymbolizeCode(uptr addr) {
+ReportStack *SymbolizeCodeAddr2Line(uptr addr) {
   SectionDesc *s = GetSectionDesc(addr);
   if (s == 0)
-    return NewFrame(addr);
+    return NewReportStackEntry(addr);
   ModuleDesc *m = s->module;
   uptr offset = addr - m->base;
   char addrstr[32];
@@ -175,7 +167,7 @@
     Die();
   }
   func.Ptr()[len] = 0;
-  ReportStack *res = NewFrame(addr);
+  ReportStack *res = NewReportStackEntry(addr);
   res->module = internal_strdup(m->name);
   res->offset = offset;
   char *pos = (char*)internal_strchr(func, '\n');
@@ -194,7 +186,7 @@
   return res;
 }
 
-ReportStack *SymbolizeData(uptr addr) {
+ReportStack *SymbolizeDataAddr2Line(uptr addr) {
   return 0;
 }