]> granicus.if.org Git - llvm/commitdiff
[libFuzzer] add -print_coverage=1 flag to print coverage directly from libFuzzer
authorKostya Serebryany <kcc@google.com>
Sun, 18 Sep 2016 21:47:08 +0000 (21:47 +0000)
committerKostya Serebryany <kcc@google.com>
Sun, 18 Sep 2016 21:47:08 +0000 (21:47 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281866 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Fuzzer/FuzzerDriver.cpp
lib/Fuzzer/FuzzerFlags.def
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerLoop.cpp
lib/Fuzzer/FuzzerTracePC.cpp
lib/Fuzzer/FuzzerUtil.cpp
lib/Fuzzer/test/coverage.test [new file with mode: 0644]
lib/Fuzzer/test/trace-pc/CMakeLists.txt

index 93fa46a79d0be2c3fd292e21fe77391c951e7337..f7f65e056177f4f39b052895d4858c62e9523985 100644 (file)
@@ -425,6 +425,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
       !DoPlainRun || Flags.minimize_crash_internal_step;
   Options.PrintNewCovPcs = Flags.print_pcs;
   Options.PrintFinalStats = Flags.print_final_stats;
+  Options.PrintCoverage = Flags.print_coverage;
   Options.TruncateUnits = Flags.truncate_units;
   Options.PruneCorpus = Flags.prune_corpus;
 
index e2e490ea85dbce76ab91d47fe7ae0a5f9d42fe68..c4de9974b51f3487f81b6e16bea063c5a2e7a072 100644 (file)
@@ -76,7 +76,8 @@ FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed "
 FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.")
 FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
 FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
-
+FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information at exit."
+                                   " Experimental, only with trace-pc-guard")
 FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
 FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGSEGV.")
 FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
index 4d05c08f0dddfe748eb93754250846b4b6207fcd..e4ac4413b6353e82ae7691e0927b84c863d956c6 100644 (file)
@@ -108,6 +108,7 @@ void PrintHexArray(const uint8_t *Data, size_t Size,
 void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
 void PrintASCII(const Unit &U, const char *PrintAfter = "");
 void PrintASCII(const Word &W, const char *PrintAfter = "");
+void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);
 std::string Hash(const Unit &U);
 void SetTimer(int Seconds);
 void SetSigSegvHandler();
@@ -243,6 +244,7 @@ struct FuzzingOptions {
   bool OutputCSV = false;
   bool PrintNewCovPcs = false;
   bool PrintFinalStats = false;
+  bool PrintCoverage = false;
   bool DetectLeaks = true;
   bool TruncateUnits = false;
   bool PruneCorpus = true;
@@ -385,6 +387,8 @@ class TracePC {
 
   void PrintModuleInfo();
 
+  void PrintCoverage();
+
 private:
   bool UseCounters = false;
   size_t TotalCoverage = 0;
@@ -408,6 +412,9 @@ private:
   static const size_t kNumCounters = 1 << 14;
   uint8_t Counters[kNumCounters];
 
+  static const size_t kNumPCs = 1 << 20;
+  uintptr_t PCs[kNumPCs];
+
   ValueBitMap CounterMap;
   ValueBitMap TotalCoverageMap;
 };
index 348e7573773490632245c899ace51c6d4281fad1..3ef7c5f68aedfc46406c6614ab48c445fe1c7b29 100644 (file)
@@ -329,6 +329,8 @@ void Fuzzer::PrintStats(const char *Where, const char *End) {
 }
 
 void Fuzzer::PrintFinalStats() {
+  if (Options.PrintCoverage)
+    TPC.PrintCoverage();
   if (!Options.PrintFinalStats) return;
   size_t ExecPerSec = execPerSec();
   Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
@@ -560,15 +562,8 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
 }
 
 void Fuzzer::PrintOneNewPC(uintptr_t PC) {
-  if (EF->__sanitizer_symbolize_pc) {
-    char PcDescr[1024];
-    EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
-                                 "%p %F %L", PcDescr, sizeof(PcDescr));
-    PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
-    Printf("\tNEW_PC: %s\n", PcDescr);
-  } else {
-    Printf("\tNEW_PC: %p\n", PC);
-  }
+  PrintPC("\tNEW_PC: %p %F %L\n",
+          "\tNEW_PC: %p\n", PC);
 }
 
 void Fuzzer::PrintNewPCs() {
index 888e7b3d532a364c5944bdbbca5999db9c466ef7..db62345e272fa53835bb405baf24a74fd4359c45 100644 (file)
@@ -18,6 +18,7 @@ namespace fuzzer {
 
 TracePC TPC;
 const size_t TracePC::kNumCounters;
+const size_t TracePC::kNumPCs;
 
 void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) {
   uintptr_t Idx = *Guard;
@@ -25,6 +26,7 @@ void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) {
   if (UseCounters) {
     uint8_t Counter = Counters[Idx % kNumCounters];
     if (Counter == 0) {
+      PCs[Idx] = PC;
       if (TotalCoverageMap.AddValue(Idx)) {
         TotalCoverage++;
         AddNewPC(PC);
@@ -38,6 +40,7 @@ void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) {
     *Guard = 0;
     TotalCoverage++;
     AddNewPC(PC);
+    PCs[Idx] = PC;
   }
 }
 
@@ -100,6 +103,14 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
   CounterMap.AddValue((Caller & kMask) | ((Callee & kMask) << kBits));
 }
 
+void TracePC::PrintCoverage() {
+  Printf("COVERAGE:\n");
+  for (size_t i = 0; i < std::min(NumGuards, kNumPCs); i++) {
+    if (PCs[i])
+      PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]);
+  }
+}
+
 } // namespace fuzzer
 
 extern "C" {
index 6764a46e7d62397589f8b4a8d487320c060f570b..f4c6fa7d0ba658a24ed98209d27ccf164f9ccde5 100644 (file)
@@ -294,4 +294,16 @@ size_t GetPeakRSSMb() {
   return 0;
 }
 
+void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
+  if (EF->__sanitizer_symbolize_pc) {
+    char PcDescr[1024];
+    EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
+                                 SymbolizedFMT, PcDescr, sizeof(PcDescr));
+    PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
+    Printf("%s", PcDescr);
+  } else {
+    Printf(FallbackFMT, PC);
+  }
+}
+
 }  // namespace fuzzer
diff --git a/lib/Fuzzer/test/coverage.test b/lib/Fuzzer/test/coverage.test
new file mode 100644 (file)
index 0000000..e1f542f
--- /dev/null
@@ -0,0 +1,7 @@
+CHECK: COVERAGE:
+CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13
+CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:14
+CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16
+CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:18
+CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:19
+RUN: not LLVMFuzzer-NullDerefTest-TracePC -print_coverage=1 2>&1 | FileCheck %s
index 27a8b0f91b7b229f58e120e76f50696dfc16cfa5..5b6f87acc6fbf13de9bed3c2d7dd81fcd9798963 100644 (file)
@@ -7,6 +7,7 @@ set(TracePCTests
   SimpleTest
   CounterTest
   CallerCalleeTest
+  NullDerefTest
   )
 
 foreach(Test ${TracePCTests})