tsan: print matched suppressions if print_suppressions=1 flag is provided



git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@178159 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index 27f1db3..7150e2e 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -162,6 +162,7 @@
 class RegionAlloc;
 class StackTrace;
 struct MBlock;
+struct Suppression;
 
 }  // namespace __tsan
 
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 722ffdf..c2ae9d3 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -49,6 +49,7 @@
   f->force_seq_cst_atomics = false;
   f->strip_path_prefix = "";
   f->suppressions = "";
+  f->print_suppressions = false;
   f->exitcode = 66;
   f->log_path = "stderr";
   f->atexit_sleep_ms = 1000;
@@ -78,6 +79,7 @@
   ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics");
   ParseFlag(env, &f->strip_path_prefix, "strip_path_prefix");
   ParseFlag(env, &f->suppressions, "suppressions");
+  ParseFlag(env, &f->print_suppressions, "print_suppressions");
   ParseFlag(env, &f->exitcode, "exitcode");
   ParseFlag(env, &f->log_path, "log_path");
   ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index edeac04..572d96c 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -52,6 +52,8 @@
   const char *strip_path_prefix;
   // Suppressions filename.
   const char *suppressions;
+  // Print matched suppressions at exit.
+  bool print_suppressions;
   // Override exit status if something was reported.
   int exitcode;
   // Write logs to "log_path.pid".
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index d67c912..28113c6 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -277,6 +277,9 @@
         ctx->nmissed_expected);
   }
 
+  if (flags()->print_suppressions)
+    PrintMatchedSuppressions();
+
   failed = OnFinalize(failed);
 
   StatAggregate(ctx->stat, thr->stat);
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 80ec302..99dceb4 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -512,6 +512,7 @@
 struct FiredSuppression {
   ReportType type;
   uptr pc;
+  Suppression *supp;
 };
 
 struct Context {
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index fd61f4a..e7109f6 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -501,12 +501,13 @@
                   const ReportStack *suppress_stack2) {
   atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
   const ReportDesc *rep = srep.GetReport();
-  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
+  Suppression *supp = 0;
+  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1, &supp);
   if (suppress_pc == 0)
-    suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
+    suppress_pc = IsSuppressed(rep->typ, suppress_stack2, &supp);
   if (suppress_pc != 0) {
-    FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
-    ctx->fired_suppressions.PushBack(supp);
+    FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
+    ctx->fired_suppressions.PushBack(s);
   }
   if (OnReport(rep, suppress_pc != 0))
     return false;
@@ -522,8 +523,12 @@
     if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
       continue;
     for (uptr j = 0; j < trace.Size(); j++) {
-      if (trace.Get(j) == ctx->fired_suppressions[k].pc)
+      FiredSuppression *s = &ctx->fired_suppressions[k];
+      if (trace.Get(j) == s->pc) {
+        if (s->supp)
+          s->supp->hit_count++;
         return true;
+      }
     }
   }
   return false;
@@ -560,7 +565,7 @@
           || (frame->func == 0 && frame->file == 0 && frame->line == 0
           && frame->module == 0)) {
         if (frame) {
-          FiredSuppression supp = {rep->typ, frame->pc};
+          FiredSuppression supp = {rep->typ, frame->pc, 0};
           CTX()->fired_suppressions.PushBack(supp);
         }
         return true;
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 941c208..47fe7b2 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -127,6 +127,7 @@
       s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
       internal_memcpy(s->templ, line, end2 - line);
       s->templ[end2 - line] = 0;
+      s->hit_count = 0;
     }
     if (end[0] == 0)
       break;
@@ -144,7 +145,7 @@
 #endif
 }
 
-uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
   if (g_suppressions == 0 || stack == 0)
     return 0;
   SuppressionType stype;
@@ -165,10 +166,38 @@
            SuppressionMatch(supp->templ, frame->file) ||
            SuppressionMatch(supp->templ, frame->module))) {
         DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
+        supp->hit_count++;
+        *sp = supp;
         return frame->pc;
       }
     }
   }
   return 0;
 }
+
+static const char *SuppTypeStr(SuppressionType t) {
+  switch (t) {
+  case SuppressionRace:   return "race";
+  case SuppressionMutex:  return "mutex";
+  case SuppressionThread: return "thread";
+  case SuppressionSignal: return "signal";
+  }
+  CHECK(0);
+  return "unknown";
+}
+
+void PrintMatchedSuppressions() {
+  int hit_count = 0;
+  for (Suppression *supp = g_suppressions; supp; supp = supp->next)
+    hit_count += supp->hit_count;
+  if (hit_count == 0)
+    return;
+  Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n",
+      hit_count, GetPid());
+  for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
+    if (supp->hit_count == 0)
+      continue;
+    Printf("%d %s:%s\n", supp->hit_count, SuppTypeStr(supp->type), supp->templ);
+  }
+}
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h
index c588316..1c98363 100644
--- a/lib/tsan/rtl/tsan_suppressions.h
+++ b/lib/tsan/rtl/tsan_suppressions.h
@@ -17,10 +17,6 @@
 
 namespace __tsan {
 
-void InitializeSuppressions();
-void FinalizeSuppressions();
-uptr IsSuppressed(ReportType typ, const ReportStack *stack);
-
 // Exposed for testing.
 enum SuppressionType {
   SuppressionRace,
@@ -33,8 +29,13 @@
   Suppression *next;
   SuppressionType type;
   char *templ;
+  int hit_count;
 };
 
+void InitializeSuppressions();
+void FinalizeSuppressions();
+void PrintMatchedSuppressions();
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
 Suppression *SuppressionParse(Suppression *head, const char* supp);
 bool SuppressionMatch(char *templ, const char *str);