Index: compiler-rt/lib/fuzzer/FuzzerDriver.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ compiler-rt/lib/fuzzer/FuzzerDriver.cpp @@ -294,6 +294,14 @@ T.detach(); } +int RunOneTestCov(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { + Unit U = FileToVector(InputFilePath); + if (MaxLen && MaxLen < U.size()) + U.resize(MaxLen); + F->RunOneTestHelper(U.data(), U.size()); + return 0; +} + int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { Unit U = FileToVector(InputFilePath); if (MaxLen && MaxLen < U.size()) @@ -698,6 +706,7 @@ Options.PrintNewCovFuncs = Flags.print_funcs; Options.PrintFinalStats = Flags.print_final_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; + Options.PrintRawCoverage = Flags.print_raw_coverage; Options.PrintCoverage = Flags.print_coverage; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; @@ -790,6 +799,20 @@ if (Flags.cleanse_crash) return CleanseCrashInput(Args, Options); + if (Flags.print_raw_coverage) { + if (!RunIndividualFiles) { + Printf("ERROR: -print-raw-coverage=1 can only be used with " + "individual files.\n"); + exit(1); + } + Options.SaveArtifacts = false; + for (auto &Path : *Inputs) { + RunOneTestCov(F, Path.c_str(), Options.MaxLen); + } + F->PrintFinalStats(); + exit(0); + } + if (RunIndividualFiles) { Options.SaveArtifacts = false; int Runs = std::max(1, Flags.runs); Index: compiler-rt/lib/fuzzer/FuzzerFlags.def =================================================================== --- compiler-rt/lib/fuzzer/FuzzerFlags.def +++ compiler-rt/lib/fuzzer/FuzzerFlags.def @@ -111,6 +111,8 @@ FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") FUZZER_FLAG_INT(print_corpus_stats, 0, "If 1, print statistics on corpus elements at exit.") +FUZZER_FLAG_INT(print_raw_coverage, 0, "If 1, print raw coverage information " + "(all branches) as text at exit.") FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" " at exit.") FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated.") Index: compiler-rt/lib/fuzzer/FuzzerInternal.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerInternal.h +++ compiler-rt/lib/fuzzer/FuzzerInternal.h @@ -66,6 +66,7 @@ static void StaticGracefulExitCallback(); void ExecuteCallback(const uint8_t *Data, size_t Size); + void RunOneTestHelper(const uint8_t *Data, size_t Size); bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr); Index: compiler-rt/lib/fuzzer/FuzzerLoop.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -354,6 +354,8 @@ } void Fuzzer::PrintFinalStats() { + if (Options.PrintRawCoverage) + TPC.PrintRawCoverage(); if (Options.PrintCoverage) TPC.PrintCoverage(); if (Options.PrintCorpusStats) @@ -463,6 +465,12 @@ DirPlusFile(FeaturesDir, NewFile)); } +void Fuzzer::RunOneTestHelper(const uint8_t *Data, size_t Size) { + ExecuteCallback(Data, Size); + TryDetectingAMemoryLeak(Data, Size, true); + TPC.UpdateObservedPCs(); +} + bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, InputInfo *II, bool *FoundUniqFeatures) { if (!Size) Index: compiler-rt/lib/fuzzer/FuzzerOptions.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerOptions.h +++ compiler-rt/lib/fuzzer/FuzzerOptions.h @@ -63,6 +63,7 @@ int PrintNewCovFuncs = 0; bool PrintFinalStats = false; bool PrintCorpusStats = false; + bool PrintRawCoverage = false; bool PrintCoverage = false; bool DumpCoverage = false; bool DetectLeaks = true; Index: compiler-rt/lib/fuzzer/FuzzerTracePC.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerTracePC.h +++ compiler-rt/lib/fuzzer/FuzzerTracePC.h @@ -94,6 +94,7 @@ void PrintModuleInfo(); + void PrintRawCoverage(); void PrintCoverage(); template Index: compiler-rt/lib/fuzzer/FuzzerTracePC.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ compiler-rt/lib/fuzzer/FuzzerTracePC.cpp @@ -269,6 +269,60 @@ return FocusFunctionCounterPtr && *FocusFunctionCounterPtr; } +void TracePC::PrintRawCoverage() { + if (!EF->__sanitizer_symbolize_pc || + !EF->__sanitizer_get_module_and_offset_for_pc) { + Printf("INFO: __sanitizer_symbolize_pc or " + "__sanitizer_get_module_and_offset_for_pc is not available," + " not printing raw coverage\n"); + return; + } + Printf("RAW COVERAGE:\n"); + + auto RawCoveredFunctionCallback = [&](const PCTableEntry *First, + const PCTableEntry *Last, + uintptr_t Counter) { + assert(First < Last); + auto VisualizePC = GetNextInstructionPc(First->PC); + + // Grabs filename as a string. + std::string FileStr = DescribePC("%s", VisualizePC); + if (!IsInterestingCoverageFile(FileStr)) + return; + + // Gets all uncovered (and covered) program counters. + Vector UncoveredPCs; + Vector CoveredPCs; + for (auto TE = First; TE < Last; TE++) { + if (!ObservedPCs.count(TE)) { + UncoveredPCs.push_back(TE->PC); + } else { + CoveredPCs.push_back(TE->PC); + } + } + + // Print all the program counters (whether covered or not) in consistent + // fashion. + if (UncoveredPCs.size() > 0) { + Printf("U"); + for (auto PC : UncoveredPCs) { + Printf(DescribePC(" %l", GetNextInstructionPc(PC)).c_str()); + } + Printf("\n"); + } + + if (CoveredPCs.size() > 0) { + Printf("C"); + for (auto PC : CoveredPCs) { + Printf(DescribePC(" %l", GetNextInstructionPc(PC)).c_str()); + } + Printf("\n"); + } + }; + + IterateCoveredFunctions(RawCoveredFunctionCallback); +} + void TracePC::PrintCoverage() { if (!EF->__sanitizer_symbolize_pc || !EF->__sanitizer_get_module_and_offset_for_pc) { @@ -304,7 +358,6 @@ Printf(" UNCOVERED_PC: %s\n", DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str()); }; - IterateCoveredFunctions(CoveredFunctionCallback); }