diff options
Diffstat (limited to 'lib/fuzzer/FuzzerTracePC.cpp')
-rw-r--r-- | lib/fuzzer/FuzzerTracePC.cpp | 240 |
1 files changed, 160 insertions, 80 deletions
diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 5e9f9f2f6dcc..29ffc8e34fc0 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -39,8 +39,6 @@ namespace fuzzer { TracePC TPC; -int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr; - uint8_t *TracePC::Counters() const { return __sancov_trace_pc_guard_8bit_counters; } @@ -59,6 +57,49 @@ size_t TracePC::GetTotalPCCoverage() { return Res; } +template<class CallBack> +void TracePC::IterateInline8bitCounters(CallBack CB) const { + if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) { + size_t CounterIdx = 0; + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + uint8_t *Beg = ModuleCounters[i].Start; + size_t Size = ModuleCounters[i].Stop - Beg; + assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); + for (size_t j = 0; j < Size; j++, CounterIdx++) + CB(i, j, CounterIdx); + } + } +} + +// Initializes unstable counters by copying Inline8bitCounters to unstable +// counters. +void TracePC::InitializeUnstableCounters() { + IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { + UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j]; + }); +} + +// Compares the current counters with counters from previous runs +// and records differences as unstable edges. +void TracePC::UpdateUnstableCounters(int UnstableMode) { + IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { + if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) { + UnstableCounters[UnstableIdx].IsUnstable = true; + if (UnstableMode == ZeroUnstable) + UnstableCounters[UnstableIdx].Counter = 0; + else if (UnstableMode == MinUnstable) + UnstableCounters[UnstableIdx].Counter = std::min( + ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter); + } + }); +} + +// Moves the minimum hit counts to ModuleCounters. +void TracePC::ApplyUnstableCounters() { + IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { + ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter; + }); +} void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { if (Start == Stop) return; @@ -132,8 +173,8 @@ void TracePC::PrintModuleInfo() { _Exit(1); } } - if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) - Printf("INFO: %zd Clang Coverage Counters\n", NumClangCounters); + if (size_t NumExtraCounters = ExtraCountersEnd() - ExtraCountersBegin()) + Printf("INFO: %zd Extra Counters\n", NumExtraCounters); } ATTRIBUTE_NO_SANITIZE_ALL @@ -147,28 +188,25 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { void TracePC::UpdateObservedPCs() { Vector<uintptr_t> CoveredFuncs; auto ObservePC = [&](uintptr_t PC) { - if (ObservedPCs.insert(PC).second && DoPrintNewPCs) - PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); + if (ObservedPCs.insert(PC).second && DoPrintNewPCs) { + PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1); + Printf("\n"); + } }; auto Observe = [&](const PCTableEntry &TE) { if (TE.PCFlags & 1) - if (ObservedFuncs.insert(TE.PC).second && NumPrintNewFuncs) + if (++ObservedFuncs[TE.PC] == 1 && NumPrintNewFuncs) CoveredFuncs.push_back(TE.PC); ObservePC(TE.PC); }; if (NumPCsInPCTables) { if (NumInline8bitCounters == NumPCsInPCTables) { - for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { - uint8_t *Beg = ModuleCounters[i].Start; - size_t Size = ModuleCounters[i].Stop - Beg; - assert(Size == - (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); - for (size_t j = 0; j < Size; j++) - if (Beg[j]) - Observe(ModulePCTable[i].Start[j]); - } + IterateInline8bitCounters([&](int i, int j, int CounterIdx) { + if (ModuleCounters[i].Start[j]) + Observe(ModulePCTable[i].Start[j]); + }); } else if (NumGuards == NumPCsInPCTables) { size_t GuardIdx = 1; for (size_t i = 0; i < NumModules; i++) { @@ -182,17 +220,12 @@ void TracePC::UpdateObservedPCs() { } } } - if (size_t NumClangCounters = - ClangCountersEnd() - ClangCountersBegin()) { - auto P = ClangCountersBegin(); - for (size_t Idx = 0; Idx < NumClangCounters; Idx++) - if (P[Idx]) - ObservePC((uintptr_t)Idx); - } - for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; i++) { - Printf("\tNEW_FUNC[%zd/%zd]: ", i, CoveredFuncs.size()); - PrintPC("%p %F %L\n", "%p\n", CoveredFuncs[i] + 1); + for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; + i++) { + Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size()); + PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1); + Printf("\n"); } } @@ -218,6 +251,57 @@ static std::string GetModuleName(uintptr_t PC) { return ModulePathRaw; } +template<class CallBack> +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, ObservedFuncs[FE->PC]); + } + } +} + +void TracePC::SetFocusFunction(const std::string &FuncName) { + // This function should be called once. + assert(FocusFunction.first > NumModulesWithInline8bitCounters); + if (FuncName.empty()) + return; + for (size_t M = 0; M < NumModulesWithInline8bitCounters; M++) { + 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. + 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); + if (FuncName != Name) continue; + Printf("INFO: Focus function is set to '%s'\n", Name.c_str()); + FocusFunction = {M, I}; + return; + } + } +} + +bool TracePC::ObservedFocusFunction() { + size_t I = FocusFunction.first; + size_t J = FocusFunction.second; + if (I >= NumModulesWithInline8bitCounters) + return false; + auto &MC = ModuleCounters[I]; + size_t Size = MC.Stop - MC.Start; + if (J >= Size) + return false; + return MC.Start[J] != 0; +} + void TracePC::PrintCoverage() { if (!EF->__sanitizer_symbolize_pc || !EF->__sanitizer_get_module_and_offset_for_pc) { @@ -227,53 +311,33 @@ void TracePC::PrintCoverage() { return; } Printf("COVERAGE:\n"); - std::string LastFunctionName = ""; - std::string LastFileStr = ""; - Set<size_t> UncoveredLines; - Set<size_t> 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, + uintptr_t Counter) { + assert(First < Last); + auto VisualizePC = GetNextInstructionPc(First->PC); + std::string FileStr = DescribePC("%s", VisualizePC); + if (!IsInterestingCoverageFile(FileStr)) + return; + std::string FunctionStr = DescribePC("%F", VisualizePC); + if (FunctionStr.find("in ") == 0) + FunctionStr = FunctionStr.substr(3); + std::string LineStr = DescribePC("%l", VisualizePC); + size_t Line = std::stoul(LineStr); + size_t NumEdges = Last - First; + Vector<uintptr_t> UncoveredPCs; + for (auto TE = First; TE < Last; TE++) + if (!ObservedPCs.count(TE->PC)) + UncoveredPCs.push_back(TE->PC); + Printf("COVERED_FUNC: hits: %zd", Counter); + Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges); + Printf(" %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); } void TracePC::DumpCoverage() { @@ -285,6 +349,15 @@ void TracePC::DumpCoverage() { } } +void TracePC::PrintUnstableStats() { + size_t count = 0; + for (size_t i = 0; i < NumInline8bitCounters; i++) + if (UnstableCounters[i].IsUnstable) + count++; + Printf("stat::stability_rate: %.2f\n", + 100 - static_cast<float>(count * 100) / NumInline8bitCounters); +} + // Value profile. // We keep track of various values that affect control flow. // These values are inserted into a bit-set-based hash map. @@ -334,7 +407,14 @@ void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { TORC4.Insert(ArgXor, Arg1, Arg2); else if (sizeof(T) == 8) TORC8.Insert(ArgXor, Arg1, Arg2); - ValueProfileMap.AddValue(Idx); + // TODO: remove these flags and instead use all metrics at once. + if (UseValueProfileMask & 1) + ValueProfileMap.AddValue(Idx); + if (UseValueProfileMask & 2) + ValueProfileMap.AddValue( + PC * 64 + (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1)); + if (UseValueProfileMask & 4) // alternative way to use the hamming distance + ValueProfileMap.AddValue(PC * 64 + ArgDistance); } static size_t InternalStrnlen(const char *S, size_t MaxLen) { @@ -536,7 +616,7 @@ void __sanitizer_cov_trace_gep(uintptr_t Idx) { ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, size_t n, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; if (result == 0) return; // No reason to mutate. if (n <= 1) return; // Not interesting. fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false); @@ -545,7 +625,7 @@ void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, size_t n, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; if (result == 0) return; // No reason to mutate. size_t Len1 = fuzzer::InternalStrnlen(s1, n); size_t Len2 = fuzzer::InternalStrnlen(s2, n); @@ -558,7 +638,7 @@ void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; if (result == 0) return; // No reason to mutate. size_t N = fuzzer::InternalStrnlen2(s1, s2); if (N <= 1) return; // Not interesting. @@ -568,35 +648,35 @@ void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, const char *s2, size_t n, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result); } ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, const char *s2, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result); } ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, const char *s2, char *result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2)); } ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, const char *s2, char *result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2)); } ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, const void *s2, size_t len2, void *result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (!fuzzer::RunningUserCallback) return; fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2); } } // extern "C" |