Index: lib/Fuzzer/FuzzerDriver.cpp =================================================================== --- lib/Fuzzer/FuzzerDriver.cpp +++ lib/Fuzzer/FuzzerDriver.cpp @@ -281,6 +281,7 @@ if (Flags.verbosity > 0 && !Dictionary.empty()) Printf("Dictionary: %zd entries\n", Dictionary.size()); Options.SaveArtifacts = !Flags.test_single_input; + Options.PrintNewCovPcs = Flags.print_new_cov_pcs; Fuzzer F(USF, Options); Index: lib/Fuzzer/FuzzerFlags.def =================================================================== --- lib/Fuzzer/FuzzerFlags.def +++ lib/Fuzzer/FuzzerFlags.def @@ -72,3 +72,5 @@ FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed " "corpus, then merge with the initial corpus") FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.") +FUZZER_FLAG_INT(print_new_cov_pcs, 0, "If 1, print out new covered pcs.") + Index: lib/Fuzzer/FuzzerInternal.h =================================================================== --- lib/Fuzzer/FuzzerInternal.h +++ lib/Fuzzer/FuzzerInternal.h @@ -97,6 +97,7 @@ bool SaveArtifacts = true; bool PrintNEW = true; // Print a status line when new units are found; bool OutputCSV = false; + bool PrintNewCovPcs = false; }; Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options); void AddToCorpus(const Unit &U) { Corpus.push_back(U); } @@ -188,6 +189,7 @@ long EpochOfLastReadOfOutputCorpus = 0; size_t LastRecordedBlockCoverage = 0; size_t LastRecordedCallerCalleeCoverage = 0; + size_t LastCoveragePcBufferLen = 0; }; class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer { Index: lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- lib/Fuzzer/FuzzerLoop.cpp +++ lib/Fuzzer/FuzzerLoop.cpp @@ -31,6 +31,8 @@ __attribute__((weak)) size_t __sanitizer_get_number_of_counters(); __attribute__((weak)) uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); +__attribute__((weak)) uintptr_t +__sanitizer_get_coverage_pc_buffer(uintptr_t **data); } namespace fuzzer { @@ -249,7 +251,21 @@ size_t Fuzzer::RecordBlockCoverage() { CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage); - return LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); + uintptr_t PrevCoverage = LastRecordedBlockCoverage; + LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); + + if (PrevCoverage == LastRecordedBlockCoverage || !Options.PrintNewCovPcs) + return LastRecordedBlockCoverage; + + uintptr_t PrevBufferLen = LastCoveragePcBufferLen; + uintptr_t *CoverageBuf; + LastCoveragePcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf); + assert(CoverageBuf); + for (size_t i = PrevBufferLen; i < LastCoveragePcBufferLen; ++i) { + Printf("0x%x\n", CoverageBuf[i]); + } + + return LastRecordedBlockCoverage; } size_t Fuzzer::RecordCallerCalleeCoverage() { Index: lib/Fuzzer/test/fuzzer.test =================================================================== --- lib/Fuzzer/test/fuzzer.test +++ lib/Fuzzer/test/fuzzer.test @@ -30,3 +30,9 @@ RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. + +RUN: LLVMFuzzer-SimpleTest -print_new_cov_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS +PCS:0x +PCS:NEW +PCS:BINGO +