From: Kostya Serebryany Date: Sun, 18 Sep 2016 21:47:08 +0000 (+0000) Subject: [libFuzzer] add -print_coverage=1 flag to print coverage directly from libFuzzer X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=304a0b44f366f529a055828518dc11f34879d362;p=llvm [libFuzzer] add -print_coverage=1 flag to print coverage directly from libFuzzer git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281866 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index 93fa46a79d0..f7f65e05617 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -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; diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def index e2e490ea85d..c4de9974b51 100644 --- a/lib/Fuzzer/FuzzerFlags.def +++ b/lib/Fuzzer/FuzzerFlags.def @@ -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.") diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index 4d05c08f0dd..e4ac4413b63 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -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; }; diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index 348e7573773..3ef7c5f68ae 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -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(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() { diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index 888e7b3d532..db62345e272 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -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" { diff --git a/lib/Fuzzer/FuzzerUtil.cpp b/lib/Fuzzer/FuzzerUtil.cpp index 6764a46e7d6..f4c6fa7d0ba 100644 --- a/lib/Fuzzer/FuzzerUtil.cpp +++ b/lib/Fuzzer/FuzzerUtil.cpp @@ -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(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 index 00000000000..e1f542f53d0 --- /dev/null +++ b/lib/Fuzzer/test/coverage.test @@ -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 diff --git a/lib/Fuzzer/test/trace-pc/CMakeLists.txt b/lib/Fuzzer/test/trace-pc/CMakeLists.txt index 27a8b0f91b7..5b6f87acc6f 100644 --- a/lib/Fuzzer/test/trace-pc/CMakeLists.txt +++ b/lib/Fuzzer/test/trace-pc/CMakeLists.txt @@ -7,6 +7,7 @@ set(TracePCTests SimpleTest CounterTest CallerCalleeTest + NullDerefTest ) foreach(Test ${TracePCTests})