From 6a6e690d24f351f81169b341419e11794fb0c22d Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 11 May 2018 01:17:52 +0000 Subject: [PATCH] [libFuzzer] refactor the implementation of -print_coverage llvm-svn: 332073 --- compiler-rt/lib/fuzzer/FuzzerTracePC.cpp | 84 +++++++++++------------- compiler-rt/lib/fuzzer/FuzzerTracePC.h | 3 + compiler-rt/test/fuzzer/coverage.test | 18 ++--- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp index 4b106e57242c..20230d496e9c 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp @@ -211,6 +211,24 @@ static std::string GetModuleName(uintptr_t PC) { return ModulePathRaw; } +template +void TracePC::IterateCoveredFunctions(CallBack CB) { + for (size_t i = 0; i < NumPCTables; i++) { + auto &M = ModulePCTable[i]; + assert(M.Start < M.Stop); + auto ModuleName = GetModuleName(M.Start->PC); + for (auto NextFE = M.Start; NextFE < M.Stop; ) { + auto FE = NextFE; + assert((FE->PCFlags & 1) && "Not a function entry point"); + do { + NextFE++; + } while (NextFE < M.Stop && !(NextFE->PCFlags & 1)); + if (ObservedFuncs.count(FE->PC)) + CB(FE, NextFE); + } + } +} + void TracePC::PrintCoverage() { if (!EF->__sanitizer_symbolize_pc || !EF->__sanitizer_get_module_and_offset_for_pc) { @@ -220,53 +238,31 @@ void TracePC::PrintCoverage() { return; } Printf("COVERAGE:\n"); - std::string LastFunctionName = ""; - std::string LastFileStr = ""; - Set UncoveredLines; - Set CoveredLines; - - auto FunctionEndCallback = [&](const std::string &CurrentFunc, - const std::string &CurrentFile) { - if (LastFunctionName != CurrentFunc) { - if (CoveredLines.empty() && !UncoveredLines.empty()) { - Printf("UNCOVERED_FUNC: %s\n", LastFunctionName.c_str()); - } else { - for (auto Line : UncoveredLines) { - if (!CoveredLines.count(Line)) - Printf("UNCOVERED_LINE: %s %s:%zd\n", LastFunctionName.c_str(), - LastFileStr.c_str(), Line); - } - } - - UncoveredLines.clear(); - CoveredLines.clear(); - LastFunctionName = CurrentFunc; - LastFileStr = CurrentFile; + auto CoveredFunctionCallback = [&](const PCTableEntry *First, const PCTableEntry *Last) { + assert(First < Last); + auto VisualizePC = GetNextInstructionPc(First->PC); + std::string FileStr = DescribePC("%s", VisualizePC); + if (!IsInterestingCoverageFile(FileStr)) return; + std::string FunctionStr = DescribePC("%F", VisualizePC); + std::string LineStr = DescribePC("%l", VisualizePC); + size_t Line = std::stoul(LineStr); + std::vector UncoveredPCs; + for (auto TE = First; TE < Last; TE++) + if (!ObservedPCs.count(TE->PC)) + UncoveredPCs.push_back(TE->PC); + Printf("COVERED_FUNC: "); + UncoveredPCs.empty() + ? Printf("all") + : Printf("%zd/%zd", (Last - First) - UncoveredPCs.size(), Last - First); + Printf(" PCs covered %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), + Line); + for (auto PC: UncoveredPCs) { + Printf(" UNCOVERED_PC: %s\n", + DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str()); } }; - for (size_t i = 0; i < NumPCTables; i++) { - auto &M = ModulePCTable[i]; - assert(M.Start < M.Stop); - auto ModuleName = GetModuleName(M.Start->PC); - for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) { - auto PC = Ptr->PC; - auto VisualizePC = GetNextInstructionPc(PC); - bool IsObserved = ObservedPCs.count(PC); - std::string FileStr = DescribePC("%s", VisualizePC); - if (!IsInterestingCoverageFile(FileStr)) continue; - std::string FunctionStr = DescribePC("%F", VisualizePC); - FunctionEndCallback(FunctionStr, FileStr); - std::string LineStr = DescribePC("%l", VisualizePC); - size_t Line = std::stoul(LineStr); - if (IsObserved && CoveredLines.insert(Line).second) - Printf("COVERED: %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), - Line); - else - UncoveredLines.insert(Line); - } - } - FunctionEndCallback("", ""); + IterateCoveredFunctions(CoveredFunctionCallback); } // Value profile. diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.h b/compiler-rt/lib/fuzzer/FuzzerTracePC.h index 27ff47cd78b5..d68da76b2e2d 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.h +++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.h @@ -103,6 +103,9 @@ class TracePC { void PrintCoverage(); + template + void IterateCoveredFunctions(CallBack CB); + void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, size_t n, bool StopAtZero); diff --git a/compiler-rt/test/fuzzer/coverage.test b/compiler-rt/test/fuzzer/coverage.test index 9a2179d91add..00d504b6a6cf 100644 --- a/compiler-rt/test/fuzzer/coverage.test +++ b/compiler-rt/test/fuzzer/coverage.test @@ -4,18 +4,14 @@ RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC -shar RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest 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: COVERED_FUNC: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13 RUN: not %t-NullDerefTest -print_coverage=1 2>&1 | FileCheck %s RUN: %t-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO DSO: COVERAGE: -DSO-DAG: COVERED:{{.*}}DSO1{{.*}}DSO1.cpp -DSO-DAG: COVERED:{{.*}}DSO2{{.*}}DSO2.cpp -DSO-DAG: COVERED:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain -DSO-DAG: UNCOVERED_LINE:{{.*}}DSO1{{.*}}DSO1.cpp -DSO-DAG: UNCOVERED_LINE:{{.*}}DSO2{{.*}}DSO2.cpp -DSO-DAG: UNCOVERED_FUNC: in Uncovered1 -DSO-DAG: UNCOVERED_FUNC: in Uncovered2 -DSO-DAG: UNCOVERED_LINE: in LLVMFuzzerTestOneInput +DSO-DAG: COVERED_FUNC:{{.*}}DSO1{{.*}}DSO1.cpp +DSO-DAG: COVERED_FUNC:{{.*}}DSO2{{.*}}DSO2.cpp +DSO-DAG: COVERED_FUNC:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain +DSO-DAG: UNCOVERED_PC:{{.*}}DSO1.cpp +DSO-DAG: UNCOVERED_PC:{{.*}}DSO2.cpp +DSO-DAG: UNCOVERED_PC:{{.*}}DSOTestMain