Index: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp +++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp @@ -433,6 +433,7 @@ Options.PrintFinalStats = Flags.print_final_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; + Options.DumpCoverage = Flags.dump_coverage; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; if (Flags.exit_on_item) Index: llvm/trunk/lib/Fuzzer/FuzzerFlags.def =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerFlags.def +++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def @@ -81,6 +81,8 @@ "If 1, print statistics on corpus elements at exit.") FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information at exit." " Experimental, only with trace-pc-guard") +FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump 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: llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp +++ llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp @@ -375,6 +375,8 @@ void Fuzzer::PrintFinalStats() { if (Options.PrintCoverage) TPC.PrintCoverage(); + if (Options.DumpCoverage) + TPC.DumpCoverage(); if (Options.PrintCorpusStats) Corpus.PrintStats(); if (!Options.PrintFinalStats) return; Index: llvm/trunk/lib/Fuzzer/FuzzerOptions.h =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerOptions.h +++ llvm/trunk/lib/Fuzzer/FuzzerOptions.h @@ -51,6 +51,7 @@ bool PrintFinalStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; + bool DumpCoverage = false; bool DetectLeaks = true; int TraceMalloc = 0; bool HandleAbrt = false; Index: llvm/trunk/lib/Fuzzer/FuzzerTracePC.h =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerTracePC.h +++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.h @@ -71,6 +71,7 @@ void PrintModuleInfo(); void PrintCoverage(); + void DumpCoverage(); void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, size_t n); Index: llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp +++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp @@ -20,6 +20,7 @@ #include "FuzzerTracePC.h" #include "FuzzerValueBitMap.h" #include +#include #include #include @@ -188,6 +189,10 @@ } } +void TracePC::DumpCoverage() { + __sanitizer_dump_coverage(PCs, GetNumPCs()); +} + // Value profile. // We keep track of various values that affect control flow. // These values are inserted into a bit-set-based hash map. Index: llvm/trunk/lib/Fuzzer/test/dump_coverage.test =================================================================== --- llvm/trunk/lib/Fuzzer/test/dump_coverage.test +++ llvm/trunk/lib/Fuzzer/test/dump_coverage.test @@ -0,0 +1,16 @@ +RUN: DIR=%t_workdir +RUN: BUILD_DIR=$(pwd) +RUN: rm -rf $DIR && mkdir -p $DIR && cd $DIR +RUN: not $BUILD_DIR/LLVMFuzzer-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s +RUN: $BUILD_DIR/LLVMFuzzer-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO +RUN: not $BUILD_DIR/LLVMFuzzer-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV +RUN: rm -rf $DIR + + +CHECK: SanitizerCoverage: ./LLVMFuzzer-NullDerefTest.{{.*}}.sancov {{.*}} PCs written + +DSO: SanitizerCoverage: ./LLVMFuzzer-DSOTest.{{.*}}.sancov {{.*}} PCs written +DSO-DAG: SanitizerCoverage: ./libLLVMFuzzer-DSO1.{{.*}}.sancov {{.*}} PCs written +DSO-DAG: SanitizerCoverage: ./libLLVMFuzzer-DSO2.{{.*}}.sancov {{.*}} PCs written + +NOCOV-NOT: SanitizerCoverage: {{.*}} PCs written