1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

[libFuzzer] simplify the implementation of -print_coverage=1

llvm-svn: 310324
This commit is contained in:
Kostya Serebryany 2017-08-08 00:12:09 +00:00
parent ad78181353
commit 7c5009600e
2 changed files with 69 additions and 103 deletions

View File

@ -174,6 +174,28 @@ void TracePC::UpdateObservedPCs() {
}
}
inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
// TODO: this implementation is x86 only.
// see sanitizer_common GetPreviousInstructionPc for full implementation.
return PC - 1;
}
inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
// TODO: this implementation is x86 only.
// see sanitizer_common GetPreviousInstructionPc for full implementation.
return PC + 1;
}
static std::string GetModuleName(uintptr_t PC) {
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
void *OffsetRaw = nullptr;
if (!EF->__sanitizer_get_module_and_offset_for_pc(
reinterpret_cast<void *>(PC), ModulePathRaw,
sizeof(ModulePathRaw), &OffsetRaw))
return "";
return ModulePathRaw;
}
void TracePC::PrintCoverage() {
if (!EF->__sanitizer_symbolize_pc ||
!EF->__sanitizer_get_module_and_offset_for_pc) {
@ -182,107 +204,54 @@ void TracePC::PrintCoverage() {
" 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> CoveredDirs, CoveredFiles, CoveredFunctions,
CoveredLines;
Printf("COVERAGE:\n");
for (size_t i = 1; i < GetNumPCs(); i++) {
uintptr_t PC = PCs()[i];
if (!PC) continue;
std::string FileStr = DescribePC("%s", PC);
if (!IsInterestingCoverageFile(FileStr)) continue;
std::string FixedPCStr = DescribePC("%p", PC);
std::string FunctionStr = DescribePC("%F", PC);
std::string LineStr = DescribePC("%l", PC);
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
void *OffsetRaw = nullptr;
if (!EF->__sanitizer_get_module_and_offset_for_pc(
reinterpret_cast<void *>(PC), ModulePathRaw,
sizeof(ModulePathRaw), &OffsetRaw))
continue;
std::string Module = ModulePathRaw;
uintptr_t FixedPC = std::stoull(FixedPCStr, 0, 16);
uintptr_t PcOffset = reinterpret_cast<uintptr_t>(OffsetRaw);
ModuleOffsets[Module] = FixedPC - PcOffset;
CoveredPCsPerModule[Module].push_back(PcOffset);
CoveredFunctions.insert(FunctionStr);
CoveredFiles.insert(FileStr);
CoveredDirs.insert(DirName(FileStr));
if (!CoveredLines.insert(FileStr + ":" + LineStr).second)
continue;
Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(),
FileStr.c_str(), LineStr.c_str());
}
std::string LastFunctionName = "";
std::string LastFileStr = "";
std::set<size_t> UncoveredLines;
std::set<size_t> CoveredLines;
std::string CoveredDirsStr;
for (auto &Dir : CoveredDirs) {
if (!CoveredDirsStr.empty())
CoveredDirsStr += ",";
CoveredDirsStr += Dir;
}
Printf("COVERED_DIRS: %s\n", CoveredDirsStr.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 = DisassembleCmd(ModuleName) + " | " +
SearchRegexCmd("call.*__sanitizer_cov_trace_pc_guard");
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')) {
size_t PcOffsetEnd = S.find(':');
if (PcOffsetEnd == std::string::npos)
continue;
S.resize(PcOffsetEnd);
uintptr_t PcOffset = std::stoull(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 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);
}
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());
}
}
inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
// TODO: this implementation is x86 only.
// see sanitizer_common GetPreviousInstructionPc for full implementation.
return PC - 1;
UncoveredLines.clear();
CoveredLines.clear();
LastFunctionName = CurrentFunc;
LastFileStr = CurrentFile;
}
};
for (size_t i = 0; i < NumPCTables; i++) {
auto &M = ModulePCTable[i];
assert(M.Start < M.Stop);
auto ModuleName = GetModuleName(*M.Start);
for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) {
auto PC = *Ptr;
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("", "");
}
void TracePC::DumpCoverage() {

View File

@ -1,16 +1,14 @@
XFAIL: darwin
RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest
RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so
RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so
RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest
RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/NullDerefTest.cpp -o %t-NullDerefTest
RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so
RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so
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-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:19
CHECK: COVERED_DIRS: {{.*}}lib{{[/\\]}}Fuzzer{{[/\\]}}test
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
@ -23,4 +21,3 @@ 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