[libFuzzer] print new functions as they are discovered in the fork mode
llvm-svn: 354092
GitOrigin-RevId: 77cbc62544cd0d3d0d6388bd23b5152f098743ca
diff --git a/FuzzerFork.cpp b/FuzzerFork.cpp
index 41fb5c1..eff9009 100644
--- a/FuzzerFork.cpp
+++ b/FuzzerFork.cpp
@@ -13,6 +13,7 @@
#include "FuzzerIO.h"
#include "FuzzerMerge.h"
#include "FuzzerSHA1.h"
+#include "FuzzerTracePC.h"
#include "FuzzerUtil.h"
#include <atomic>
@@ -86,11 +87,13 @@
Cmd.removeArgument(C);
Cmd.addFlag("reload", "0"); // working in an isolated dir, no reload.
Cmd.addFlag("print_final_stats", "1");
+ Cmd.addFlag("print_funcs", "0"); // no need to spend time symbolizing.
Cmd.addFlag("max_total_time", std::to_string(std::min((size_t)300, JobId)));
auto Job = new FuzzJob;
std::string Seeds;
- if (size_t CorpusSubsetSize = std::min(Files.size(), (size_t)100))
+ if (size_t CorpusSubsetSize =
+ std::min(Files.size(), (size_t)sqrt(Files.size() + 2)))
for (size_t i = 0; i < CorpusSubsetSize; i++)
Seeds += (Seeds.empty() ? "" : ",") +
Files[Rand->SkewTowardsLast(Files.size())];
@@ -135,6 +138,12 @@
RmDirRecursive(Job->CorpusDir);
Features.insert(NewFeatures.begin(), NewFeatures.end());
Cov.insert(NewCov.begin(), NewCov.end());
+ for (auto Idx : NewCov)
+ if (auto *TE = TPC.PCTableEntryByIdx(Idx))
+ if (TPC.PcIsFuncEntry(TE))
+ PrintPC(" NEW_FUNC: %p %F %L\n", "",
+ TPC.GetNextInstructionPc(TE->PC));
+
auto Stats = ParseFinalStatsFromLog(Job->LogPath);
NumRuns += Stats.number_of_executed_units;
if (!FilesToAdd.empty())
diff --git a/FuzzerMerge.cpp b/FuzzerMerge.cpp
index 870a875..d70aa3e 100644
--- a/FuzzerMerge.cpp
+++ b/FuzzerMerge.cpp
@@ -100,7 +100,7 @@
LastSeenStartMarker = kInvalidStartMarker;
if (ParseCoverage) {
TmpFeatures.clear(); // use a vector from outer scope to avoid resizes.
- while (ISS1 >> std::hex >> N)
+ while (ISS1 >> N)
TmpFeatures.push_back(N);
std::sort(TmpFeatures.begin(), TmpFeatures.end());
Files[CurrentFileIdx].Features = TmpFeatures;
@@ -108,7 +108,7 @@
} else if (Marker == "COV") {
size_t CurrentFileIdx = N;
if (ParseCoverage)
- while (ISS1 >> std::hex >> N)
+ while (ISS1 >> N)
if (PCs.insert(N).second)
Files[CurrentFileIdx].Cov.push_back(N);
} else {
@@ -220,7 +220,7 @@
}
std::ostringstream StartedLine;
// Write the pre-run marker.
- OF << "STARTED " << std::dec << i << " " << U.size() << "\n";
+ OF << "STARTED " << i << " " << U.size() << "\n";
OF.flush(); // Flush is important since Command::Execute may crash.
// Run.
TPC.ResetMaps();
@@ -242,9 +242,9 @@
// Write the post-run marker and the coverage.
OF << "FT " << i;
for (size_t F : UniqFeatures)
- OF << " " << std::hex << F;
+ OF << " " << F;
OF << "\n";
- OF << "COV " << std::dec << i;
+ OF << "COV " << i;
TPC.ForEachObservedPC([&](const TracePC::PCTableEntry *TE) {
if (AllPCs.insert(TE).second)
OF << " " << TPC.PCTableEntryIdx(TE);
diff --git a/FuzzerTracePC.cpp b/FuzzerTracePC.cpp
index f5fdbf5..a2d3b7e 100644
--- a/FuzzerTracePC.cpp
+++ b/FuzzerTracePC.cpp
@@ -174,7 +174,7 @@
/// \return the address of the next instruction.
/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cc`
-inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
+ALWAYS_INLINE uintptr_t TracePC::GetNextInstructionPc(uintptr_t PC) {
#if defined(__mips__)
return PC + 8;
#elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \
@@ -196,7 +196,7 @@
};
auto Observe = [&](const PCTableEntry *TE) {
- if (TE->PCFlags & 1)
+ if (PcIsFuncEntry(TE))
if (++ObservedFuncs[TE->PC] == 1 && NumPrintNewFuncs)
CoveredFuncs.push_back(TE->PC);
ObservePC(TE);
@@ -239,6 +239,16 @@
return 0;
}
+const TracePC::PCTableEntry *TracePC::PCTableEntryByIdx(uintptr_t Idx) {
+ for (size_t i = 0; i < NumPCTables; i++) {
+ auto &M = ModulePCTable[i];
+ size_t Size = M.Stop - M.Start;
+ if (Idx < Size) return &M.Start[Idx];
+ Idx -= Size;
+ }
+ return nullptr;
+}
+
static std::string GetModuleName(uintptr_t PC) {
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
void *OffsetRaw = nullptr;
@@ -257,10 +267,10 @@
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");
+ assert(PcIsFuncEntry(FE) && "Not a function entry point");
do {
NextFE++;
- } while (NextFE < M.Stop && !(NextFE->PCFlags & 1));
+ } while (NextFE < M.Stop && !(PcIsFuncEntry(NextFE)));
CB(FE, NextFE, ObservedFuncs[FE->PC]);
}
}
@@ -275,7 +285,7 @@
auto &PCTE = ModulePCTable[M];
size_t N = PCTE.Stop - PCTE.Start;
for (size_t I = 0; I < N; I++) {
- if (!(PCTE.Start[I].PCFlags & 1)) continue; // not a function entry.
+ if (!(PcIsFuncEntry(&PCTE.Start[I]))) continue; // not a function entry.
auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC));
if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ')
Name = Name.substr(3, std::string::npos);
diff --git a/FuzzerTracePC.h b/FuzzerTracePC.h
index f1d523e..4f5ebeb 100644
--- a/FuzzerTracePC.h
+++ b/FuzzerTracePC.h
@@ -127,6 +127,9 @@
};
uintptr_t PCTableEntryIdx(const PCTableEntry *TE);
+ const PCTableEntry *PCTableEntryByIdx(uintptr_t Idx);
+ static uintptr_t GetNextInstructionPc(uintptr_t PC);
+ bool PcIsFuncEntry(const PCTableEntry *TE) { return TE->PCFlags & 1; }
private:
bool UseCounters = false;