diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Fuzzer/FuzzerDefs.h | 2 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/FuzzerTracePC.cpp | 98 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/FuzzerUtil.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/DSO1.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/DSO2.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/DSOTestMain.cpp | 16 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/coverage.test | 12 |
7 files changed, 133 insertions, 8 deletions
diff --git a/llvm/lib/Fuzzer/FuzzerDefs.h b/llvm/lib/Fuzzer/FuzzerDefs.h index 6a9e323d429..287e23c7afd 100644 --- a/llvm/lib/Fuzzer/FuzzerDefs.h +++ b/llvm/lib/Fuzzer/FuzzerDefs.h @@ -93,6 +93,8 @@ void SetSigIntHandler(); void SetSigTermHandler(); std::string Base64(const Unit &U); int ExecuteCommand(const std::string &Command); +bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out); + size_t GetPeakRSSMb(); // Private copy of SHA1 implementation. diff --git a/llvm/lib/Fuzzer/FuzzerTracePC.cpp b/llvm/lib/Fuzzer/FuzzerTracePC.cpp index 6b9e21068a2..ddfee218f3b 100644 --- a/llvm/lib/Fuzzer/FuzzerTracePC.cpp +++ b/llvm/lib/Fuzzer/FuzzerTracePC.cpp @@ -12,9 +12,14 @@ // //===----------------------------------------------------------------------===// +#include <map> +#include <set> +#include <sstream> + #include "FuzzerCorpus.h" #include "FuzzerDefs.h" #include "FuzzerDictionary.h" +#include "FuzzerExtFunctions.h" #include "FuzzerTracePC.h" #include "FuzzerValueBitMap.h" @@ -112,11 +117,100 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { HandleValueProfile(Idx); } +static bool IsInterestingCoverageFile(std::string &File) { + if (File.find("compiler-rt/lib/") != std::string::npos) + return false; // sanitizer internal. + if (File.find("/usr/lib/") != std::string::npos) + return false; + if (File.find("/usr/include/") != std::string::npos) + return false; + if (File == "<null>") + return false; + return true; +} + void TracePC::PrintCoverage() { + if (!EF->__sanitizer_symbolize_pc) { + Printf("INFO: __sanitizer_symbolize_pc is not available," + " not printing coverage\n"); + return; + } + std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule; + std::map<std::string, uintptr_t> ModuleOffsets; + std::set<std::string> CoveredFiles, CoveredFunctions, CoveredLines; Printf("COVERAGE:\n"); for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) { - if (PCs[i]) - PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]); + if (!PCs[i]) continue; + std::string FileStr = DescribePC("%s", PCs[i]); + if (!IsInterestingCoverageFile(FileStr)) continue; + std::string FixedPCStr = DescribePC("%p", PCs[i]); + std::string FunctionStr = DescribePC("%F", PCs[i]); + std::string LineStr = DescribePC("%l", PCs[i]); + // TODO(kcc): get the module using some other way since this + // does not work with ASAN_OPTIONS=strip_path_prefix=something. + std::string Module = DescribePC("%m", PCs[i]); + std::string OffsetStr = DescribePC("%o", PCs[i]); + uintptr_t FixedPC = std::stol(FixedPCStr, 0, 16); + uintptr_t PcOffset = std::stol(OffsetStr, 0, 16); + ModuleOffsets[Module] = FixedPC - PcOffset; + CoveredPCsPerModule[Module].push_back(PcOffset); + CoveredFunctions.insert(FunctionStr); + CoveredFiles.insert(FileStr); + if (!CoveredLines.insert(FileStr + ":" + LineStr).second) + continue; + Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(), + FileStr.c_str(), LineStr.c_str()); + } + + for (auto &M : CoveredPCsPerModule) { + std::set<std::string> UncoveredFiles, UncoveredFunctions; + std::map<std::string, std::set<int> > UncoveredLines; // Func+File => lines + auto &ModuleName = M.first; + auto &CoveredOffsets = M.second; + uintptr_t ModuleOffset = ModuleOffsets[ModuleName]; + std::sort(CoveredOffsets.begin(), CoveredOffsets.end()); + Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str()); + // sancov does not yet fully support DSOs. + // std::string Cmd = "sancov -print-coverage-pcs " + ModuleName; + std::string Cmd = "objdump -d " + ModuleName + + " | grep 'call.*__sanitizer_cov_trace_pc_guard' | awk -F: '{print $1}'"; + std::string SanCovOutput; + if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) { + Printf("INFO: Command failed: %s\n", Cmd.c_str()); + continue; + } + std::istringstream ISS(SanCovOutput); + std::string S; + while (std::getline(ISS, S, '\n')) { + uintptr_t PcOffset = std::stol(S, 0, 16); + if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(), + PcOffset)) { + uintptr_t PC = ModuleOffset + PcOffset; + auto FileStr = DescribePC("%s", PC); + if (!IsInterestingCoverageFile(FileStr)) continue; + if (CoveredFiles.count(FileStr) == 0) { + UncoveredFiles.insert(FileStr); + continue; + } + auto FunctionStr = DescribePC("%F", PC); + if (CoveredFunctions.count(FunctionStr) == 0) { + UncoveredFunctions.insert(FunctionStr); + continue; + } + std::string LineStr = DescribePC("%l", PC); + uintptr_t Line = std::stoi(LineStr); + std::string FileLineStr = FileStr + ":" + LineStr; + if (CoveredLines.count(FileLineStr) == 0) + UncoveredLines[FunctionStr + " " + FileStr].insert(Line); + } + } + for (auto &FileLine: UncoveredLines) + for (int Line : FileLine.second) + Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line); + for (auto &Func : UncoveredFunctions) + Printf("UNCOVERED_FUNC: %s\n", Func.c_str()); + for (auto &File : UncoveredFiles) + Printf("UNCOVERED_FILE: %s\n", File.c_str()); } } diff --git a/llvm/lib/Fuzzer/FuzzerUtil.cpp b/llvm/lib/Fuzzer/FuzzerUtil.cpp index 254d9c826df..d845333a169 100644 --- a/llvm/lib/Fuzzer/FuzzerUtil.cpp +++ b/llvm/lib/Fuzzer/FuzzerUtil.cpp @@ -19,6 +19,7 @@ #include <cassert> #include <chrono> #include <cstring> +#include <stdio.h> #include <signal.h> #include <sstream> #include <unistd.h> @@ -306,4 +307,14 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { Printf(FallbackFMT, PC); } +bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) { + FILE *Pipe = popen(Command.c_str(), "r"); + if (!Pipe) return false; + char Buff[1024]; + size_t N; + while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0) + Out->append(Buff, N); + return true; +} + } // namespace fuzzer diff --git a/llvm/lib/Fuzzer/test/DSO1.cpp b/llvm/lib/Fuzzer/test/DSO1.cpp index c362593f779..4a293890f4b 100644 --- a/llvm/lib/Fuzzer/test/DSO1.cpp +++ b/llvm/lib/Fuzzer/test/DSO1.cpp @@ -9,3 +9,4 @@ int DSO1(int a) { return 1; } +void Uncovered1() { } diff --git a/llvm/lib/Fuzzer/test/DSO2.cpp b/llvm/lib/Fuzzer/test/DSO2.cpp index 46c80e4b6fe..04b308d193a 100644 --- a/llvm/lib/Fuzzer/test/DSO2.cpp +++ b/llvm/lib/Fuzzer/test/DSO2.cpp @@ -9,3 +9,4 @@ int DSO2(int a) { return 1; } +void Uncovered2() {} diff --git a/llvm/lib/Fuzzer/test/DSOTestMain.cpp b/llvm/lib/Fuzzer/test/DSOTestMain.cpp index 49cd185e97d..3e225d88612 100644 --- a/llvm/lib/Fuzzer/test/DSOTestMain.cpp +++ b/llvm/lib/Fuzzer/test/DSOTestMain.cpp @@ -11,17 +11,21 @@ extern int DSO1(int a); extern int DSO2(int a); extern int DSOTestExtra(int a); +static volatile int *nil = 0; extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < sizeof(int) * 3) return 0; int x, y, z; - memcpy(&x, Data + 0 * sizeof(int), sizeof(int)); - memcpy(&y, Data + 1 * sizeof(int), sizeof(int)); - memcpy(&z, Data + 2 * sizeof(int), sizeof(int)); - int sum = DSO1(x) + DSO2(y) + DSOTestExtra(z); + if (Size < sizeof(int) * 3) { + x = y = z = 0; + } else { + memcpy(&x, Data + 0 * sizeof(int), sizeof(int)); + memcpy(&y, Data + 1 * sizeof(int), sizeof(int)); + memcpy(&z, Data + 2 * sizeof(int), sizeof(int)); + } + int sum = DSO1(x) + DSO2(y) + (z ? DSOTestExtra(z) : 0); if (sum == 3) { fprintf(stderr, "BINGO %d %d %d\n", x, y, z); - exit(1); + *nil = 0; } return 0; } diff --git a/llvm/lib/Fuzzer/test/coverage.test b/llvm/lib/Fuzzer/test/coverage.test index f6b43048417..b41a262c462 100644 --- a/llvm/lib/Fuzzer/test/coverage.test +++ b/llvm/lib/Fuzzer/test/coverage.test @@ -4,3 +4,15 @@ CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:14 CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16 CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:19 RUN: not LLVMFuzzer-NullDerefTest-TracePC -print_coverage=1 2>&1 | FileCheck %s + +RUN: LLVMFuzzer-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: UNCOVERED_FILE:{{.*}}DSOTestExtra.cpp |