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:
parent
ad78181353
commit
7c5009600e
@ -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() {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user