110ab2aceSGeorge Karpenkov //===- FuzzerTracePC.cpp - PC tracing--------------------------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // Trace PCs.
910ab2aceSGeorge Karpenkov // This module implements __sanitizer_cov_trace_pc_guard[_init],
1010ab2aceSGeorge Karpenkov // the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
1110ab2aceSGeorge Karpenkov //
1210ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1310ab2aceSGeorge Karpenkov
1410ab2aceSGeorge Karpenkov #include "FuzzerTracePC.h"
1555ddb2c7SJonathan Metzman #include "FuzzerBuiltins.h"
1655ddb2c7SJonathan Metzman #include "FuzzerBuiltinsMsvc.h"
1710ab2aceSGeorge Karpenkov #include "FuzzerCorpus.h"
1810ab2aceSGeorge Karpenkov #include "FuzzerDefs.h"
19c5d72517SMarco Vanotti #include "FuzzerDictionary.h"
2010ab2aceSGeorge Karpenkov #include "FuzzerExtFunctions.h"
2110ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
22226866e1SDokyung Song #include "FuzzerPlatform.h"
2310ab2aceSGeorge Karpenkov #include "FuzzerUtil.h"
2410ab2aceSGeorge Karpenkov #include "FuzzerValueBitMap.h"
2510ab2aceSGeorge Karpenkov #include <set>
2610ab2aceSGeorge Karpenkov
27f65cf64fSKostya Serebryany // Used by -fsanitize-coverage=stack-depth to track stack depth
287e042bb1SMatt Morehouse ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack;
29f65cf64fSKostya Serebryany
3010ab2aceSGeorge Karpenkov namespace fuzzer {
3110ab2aceSGeorge Karpenkov
3210ab2aceSGeorge Karpenkov TracePC TPC;
3310ab2aceSGeorge Karpenkov
GetTotalPCCoverage()3410ab2aceSGeorge Karpenkov size_t TracePC::GetTotalPCCoverage() {
3510ab2aceSGeorge Karpenkov return ObservedPCs.size();
3610ab2aceSGeorge Karpenkov }
3710ab2aceSGeorge Karpenkov
3810ab2aceSGeorge Karpenkov
HandleInline8bitCountersInit(uint8_t * Start,uint8_t * Stop)3910ab2aceSGeorge Karpenkov void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
4010ab2aceSGeorge Karpenkov if (Start == Stop) return;
416fd4d8abSKostya Serebryany if (NumModules &&
426fd4d8abSKostya Serebryany Modules[NumModules - 1].Start() == Start)
436fd4d8abSKostya Serebryany return;
446fd4d8abSKostya Serebryany assert(NumModules <
456fd4d8abSKostya Serebryany sizeof(Modules) / sizeof(Modules[0]));
466fd4d8abSKostya Serebryany auto &M = Modules[NumModules++];
476fd4d8abSKostya Serebryany uint8_t *AlignedStart = RoundUpByPage(Start);
486fd4d8abSKostya Serebryany uint8_t *AlignedStop = RoundDownByPage(Stop);
496fd4d8abSKostya Serebryany size_t NumFullPages = AlignedStop > AlignedStart ?
506fd4d8abSKostya Serebryany (AlignedStop - AlignedStart) / PageSize() : 0;
516fd4d8abSKostya Serebryany bool NeedFirst = Start < AlignedStart || !NumFullPages;
526fd4d8abSKostya Serebryany bool NeedLast = Stop > AlignedStop && AlignedStop >= AlignedStart;
536fd4d8abSKostya Serebryany M.NumRegions = NumFullPages + NeedFirst + NeedLast;;
546fd4d8abSKostya Serebryany assert(M.NumRegions > 0);
556fd4d8abSKostya Serebryany M.Regions = new Module::Region[M.NumRegions];
566fd4d8abSKostya Serebryany assert(M.Regions);
576fd4d8abSKostya Serebryany size_t R = 0;
586fd4d8abSKostya Serebryany if (NeedFirst)
596fd4d8abSKostya Serebryany M.Regions[R++] = {Start, std::min(Stop, AlignedStart), true, false};
606fd4d8abSKostya Serebryany for (uint8_t *P = AlignedStart; P < AlignedStop; P += PageSize())
616fd4d8abSKostya Serebryany M.Regions[R++] = {P, P + PageSize(), true, true};
626fd4d8abSKostya Serebryany if (NeedLast)
636fd4d8abSKostya Serebryany M.Regions[R++] = {AlignedStop, Stop, true, false};
646fd4d8abSKostya Serebryany assert(R == M.NumRegions);
656fd4d8abSKostya Serebryany assert(M.Size() == (size_t)(Stop - Start));
666fd4d8abSKostya Serebryany assert(M.Stop() == Stop);
676fd4d8abSKostya Serebryany assert(M.Start() == Start);
686fd4d8abSKostya Serebryany NumInline8bitCounters += M.Size();
6910ab2aceSGeorge Karpenkov }
7010ab2aceSGeorge Karpenkov
HandlePCsInit(const uintptr_t * Start,const uintptr_t * Stop)71d3e4b7e2SKostya Serebryany void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
72d3e4b7e2SKostya Serebryany const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
73d3e4b7e2SKostya Serebryany const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
7410ab2aceSGeorge Karpenkov if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
7510ab2aceSGeorge Karpenkov assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0]));
7610ab2aceSGeorge Karpenkov ModulePCTable[NumPCTables++] = {B, E};
7710ab2aceSGeorge Karpenkov NumPCsInPCTables += E - B;
7810ab2aceSGeorge Karpenkov }
7910ab2aceSGeorge Karpenkov
PrintModuleInfo()8010ab2aceSGeorge Karpenkov void TracePC::PrintModuleInfo() {
816fd4d8abSKostya Serebryany if (NumModules) {
8210ab2aceSGeorge Karpenkov Printf("INFO: Loaded %zd modules (%zd inline 8-bit counters): ",
836fd4d8abSKostya Serebryany NumModules, NumInline8bitCounters);
846fd4d8abSKostya Serebryany for (size_t i = 0; i < NumModules; i++)
856fd4d8abSKostya Serebryany Printf("%zd [%p, %p), ", Modules[i].Size(), Modules[i].Start(),
866fd4d8abSKostya Serebryany Modules[i].Stop());
8710ab2aceSGeorge Karpenkov Printf("\n");
8810ab2aceSGeorge Karpenkov }
8910ab2aceSGeorge Karpenkov if (NumPCTables) {
9010ab2aceSGeorge Karpenkov Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables,
9110ab2aceSGeorge Karpenkov NumPCsInPCTables);
9210ab2aceSGeorge Karpenkov for (size_t i = 0; i < NumPCTables; i++) {
9310ab2aceSGeorge Karpenkov Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start,
9410ab2aceSGeorge Karpenkov ModulePCTable[i].Start, ModulePCTable[i].Stop);
9510ab2aceSGeorge Karpenkov }
9610ab2aceSGeorge Karpenkov Printf("\n");
9710ab2aceSGeorge Karpenkov
982891b257SKostya Serebryany if (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables) {
99fc307996SKostya Serebryany Printf("ERROR: The size of coverage PC tables does not match the\n"
100fc307996SKostya Serebryany "number of instrumented PCs. This might be a compiler bug,\n"
101fc307996SKostya Serebryany "please contact the libFuzzer developers.\n"
102fc307996SKostya Serebryany "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n"
103fc307996SKostya Serebryany "for possible workarounds (tl;dr: don't use the old GNU ld)\n");
10410ab2aceSGeorge Karpenkov _Exit(1);
10510ab2aceSGeorge Karpenkov }
10610ab2aceSGeorge Karpenkov }
107b7a3bc99SDan Liew if (size_t NumExtraCounters = ExtraCountersEnd() - ExtraCountersBegin())
108b7a3bc99SDan Liew Printf("INFO: %zd Extra Counters\n", NumExtraCounters);
1096708186cSAaron Green
1106708186cSAaron Green size_t MaxFeatures = CollectFeatures([](uint32_t) {});
1116708186cSAaron Green if (MaxFeatures > std::numeric_limits<uint32_t>::max())
1126708186cSAaron Green Printf("WARNING: The coverage PC tables may produce up to %zu features.\n"
1136708186cSAaron Green "This exceeds the maximum 32-bit value. Some features may be\n"
1146708186cSAaron Green "ignored, and fuzzing may become less precise. If possible,\n"
1156708186cSAaron Green "consider refactoring the fuzzer into several smaller fuzzers\n"
1166708186cSAaron Green "linked against only a portion of the current target.\n",
1176708186cSAaron Green MaxFeatures);
11810ab2aceSGeorge Karpenkov }
11910ab2aceSGeorge Karpenkov
12010ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
HandleCallerCallee(uintptr_t Caller,uintptr_t Callee)12110ab2aceSGeorge Karpenkov void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
12210ab2aceSGeorge Karpenkov const uintptr_t kBits = 12;
12310ab2aceSGeorge Karpenkov const uintptr_t kMask = (1 << kBits) - 1;
12410ab2aceSGeorge Karpenkov uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
12510ab2aceSGeorge Karpenkov ValueProfileMap.AddValueModPrime(Idx);
12610ab2aceSGeorge Karpenkov }
12710ab2aceSGeorge Karpenkov
128f28523bbSGeorge Karpenkov /// \return the address of the previous instruction.
129f28523bbSGeorge Karpenkov /// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.h`
GetPreviousInstructionPc(uintptr_t PC)130f28523bbSGeorge Karpenkov inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
131f28523bbSGeorge Karpenkov #if defined(__arm__)
132f28523bbSGeorge Karpenkov // T32 (Thumb) branch instructions might be 16 or 32 bit long,
133f28523bbSGeorge Karpenkov // so we return (pc-2) in that case in order to be safe.
134f28523bbSGeorge Karpenkov // For A32 mode we return (pc-4) because all instructions are 32 bit long.
135f28523bbSGeorge Karpenkov return (PC - 3) & (~1);
136f28523bbSGeorge Karpenkov #elif defined(__sparc__) || defined(__mips__)
137f28523bbSGeorge Karpenkov return PC - 8;
138fc0bd3c2SFangrui Song #elif defined(__riscv__)
139fc0bd3c2SFangrui Song return PC - 2;
140fc0bd3c2SFangrui Song #elif defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
141f28523bbSGeorge Karpenkov return PC - 1;
142fc0bd3c2SFangrui Song #else
143fc0bd3c2SFangrui Song return PC - 4;
144f28523bbSGeorge Karpenkov #endif
145f28523bbSGeorge Karpenkov }
146f28523bbSGeorge Karpenkov
147f28523bbSGeorge Karpenkov /// \return the address of the next instruction.
14865492d95SNico Weber /// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cpp`
GetNextInstructionPc(uintptr_t PC)14977cbc625SKostya Serebryany ALWAYS_INLINE uintptr_t TracePC::GetNextInstructionPc(uintptr_t PC) {
150f28523bbSGeorge Karpenkov #if defined(__mips__)
151f28523bbSGeorge Karpenkov return PC + 8;
152f28523bbSGeorge Karpenkov #elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \
153*9c2f792dSYouling Tang defined(__aarch64__) || defined(__loongarch__)
154f28523bbSGeorge Karpenkov return PC + 4;
155f28523bbSGeorge Karpenkov #else
156f28523bbSGeorge Karpenkov return PC + 1;
157f28523bbSGeorge Karpenkov #endif
158f28523bbSGeorge Karpenkov }
159f28523bbSGeorge Karpenkov
UpdateObservedPCs()16010ab2aceSGeorge Karpenkov void TracePC::UpdateObservedPCs() {
1617c921753SKostya Serebryany std::vector<uintptr_t> CoveredFuncs;
16296f81bc6SKostya Serebryany auto ObservePC = [&](const PCTableEntry *TE) {
16396f81bc6SKostya Serebryany if (ObservedPCs.insert(TE).second && DoPrintNewPCs) {
16496f81bc6SKostya Serebryany PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p",
16596f81bc6SKostya Serebryany GetNextInstructionPc(TE->PC));
1662bd02db9SKostya Serebryany Printf("\n");
1672bd02db9SKostya Serebryany }
16810ab2aceSGeorge Karpenkov };
1692eef816eSKostya Serebryany
17096f81bc6SKostya Serebryany auto Observe = [&](const PCTableEntry *TE) {
17177cbc625SKostya Serebryany if (PcIsFuncEntry(TE))
17296f81bc6SKostya Serebryany if (++ObservedFuncs[TE->PC] == 1 && NumPrintNewFuncs)
17396f81bc6SKostya Serebryany CoveredFuncs.push_back(TE->PC);
17496f81bc6SKostya Serebryany ObservePC(TE);
1752eef816eSKostya Serebryany };
1762eef816eSKostya Serebryany
177f65cf64fSKostya Serebryany if (NumPCsInPCTables) {
17810ab2aceSGeorge Karpenkov if (NumInline8bitCounters == NumPCsInPCTables) {
1796fd4d8abSKostya Serebryany for (size_t i = 0; i < NumModules; i++) {
1806fd4d8abSKostya Serebryany auto &M = Modules[i];
1816fd4d8abSKostya Serebryany assert(M.Size() ==
1829e14cccfSJonathan Metzman (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
1836fd4d8abSKostya Serebryany for (size_t r = 0; r < M.NumRegions; r++) {
1846fd4d8abSKostya Serebryany auto &R = M.Regions[r];
1856fd4d8abSKostya Serebryany if (!R.Enabled) continue;
1866fd4d8abSKostya Serebryany for (uint8_t *P = R.Start; P < R.Stop; P++)
1876fd4d8abSKostya Serebryany if (*P)
18896f81bc6SKostya Serebryany Observe(&ModulePCTable[i].Start[M.Idx(P)]);
1896fd4d8abSKostya Serebryany }
1909e14cccfSJonathan Metzman }
19110ab2aceSGeorge Karpenkov }
19210ab2aceSGeorge Karpenkov }
193c0700865SKostya Serebryany
19444edc281SKostya Serebryany for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N;
19544edc281SKostya Serebryany i++) {
196111d0b2aSKostya Serebryany Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size());
197f28523bbSGeorge Karpenkov PrintPC("%p %F %L", "%p", GetNextInstructionPc(CoveredFuncs[i]));
1982bd02db9SKostya Serebryany Printf("\n");
199c0700865SKostya Serebryany }
20010ab2aceSGeorge Karpenkov }
20110ab2aceSGeorge Karpenkov
PCTableEntryIdx(const PCTableEntry * TE)20296f81bc6SKostya Serebryany uintptr_t TracePC::PCTableEntryIdx(const PCTableEntry *TE) {
20396f81bc6SKostya Serebryany size_t TotalTEs = 0;
20496f81bc6SKostya Serebryany for (size_t i = 0; i < NumPCTables; i++) {
20596f81bc6SKostya Serebryany auto &M = ModulePCTable[i];
20696f81bc6SKostya Serebryany if (TE >= M.Start && TE < M.Stop)
20796f81bc6SKostya Serebryany return TotalTEs + TE - M.Start;
20896f81bc6SKostya Serebryany TotalTEs += M.Stop - M.Start;
20996f81bc6SKostya Serebryany }
21096f81bc6SKostya Serebryany assert(0);
21196f81bc6SKostya Serebryany return 0;
21296f81bc6SKostya Serebryany }
21310ab2aceSGeorge Karpenkov
PCTableEntryByIdx(uintptr_t Idx)21477cbc625SKostya Serebryany const TracePC::PCTableEntry *TracePC::PCTableEntryByIdx(uintptr_t Idx) {
21577cbc625SKostya Serebryany for (size_t i = 0; i < NumPCTables; i++) {
21677cbc625SKostya Serebryany auto &M = ModulePCTable[i];
21777cbc625SKostya Serebryany size_t Size = M.Stop - M.Start;
21877cbc625SKostya Serebryany if (Idx < Size) return &M.Start[Idx];
21977cbc625SKostya Serebryany Idx -= Size;
22077cbc625SKostya Serebryany }
22177cbc625SKostya Serebryany return nullptr;
22277cbc625SKostya Serebryany }
22377cbc625SKostya Serebryany
GetModuleName(uintptr_t PC)22410ab2aceSGeorge Karpenkov static std::string GetModuleName(uintptr_t PC) {
22510ab2aceSGeorge Karpenkov char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
22610ab2aceSGeorge Karpenkov void *OffsetRaw = nullptr;
22710ab2aceSGeorge Karpenkov if (!EF->__sanitizer_get_module_and_offset_for_pc(
22810ab2aceSGeorge Karpenkov reinterpret_cast<void *>(PC), ModulePathRaw,
22910ab2aceSGeorge Karpenkov sizeof(ModulePathRaw), &OffsetRaw))
23010ab2aceSGeorge Karpenkov return "";
23110ab2aceSGeorge Karpenkov return ModulePathRaw;
23210ab2aceSGeorge Karpenkov }
23310ab2aceSGeorge Karpenkov
2346a6e690dSKostya Serebryany template<class CallBack>
IterateCoveredFunctions(CallBack CB)2356a6e690dSKostya Serebryany void TracePC::IterateCoveredFunctions(CallBack CB) {
2366a6e690dSKostya Serebryany for (size_t i = 0; i < NumPCTables; i++) {
2376a6e690dSKostya Serebryany auto &M = ModulePCTable[i];
2386a6e690dSKostya Serebryany assert(M.Start < M.Stop);
2396a6e690dSKostya Serebryany auto ModuleName = GetModuleName(M.Start->PC);
2406a6e690dSKostya Serebryany for (auto NextFE = M.Start; NextFE < M.Stop; ) {
2416a6e690dSKostya Serebryany auto FE = NextFE;
24277cbc625SKostya Serebryany assert(PcIsFuncEntry(FE) && "Not a function entry point");
2436a6e690dSKostya Serebryany do {
2446a6e690dSKostya Serebryany NextFE++;
24577cbc625SKostya Serebryany } while (NextFE < M.Stop && !(PcIsFuncEntry(NextFE)));
24644edc281SKostya Serebryany CB(FE, NextFE, ObservedFuncs[FE->PC]);
2476a6e690dSKostya Serebryany }
2486a6e690dSKostya Serebryany }
2496a6e690dSKostya Serebryany }
2506a6e690dSKostya Serebryany
SetFocusFunction(const std::string & FuncName)251e9c6f06cSKostya Serebryany void TracePC::SetFocusFunction(const std::string &FuncName) {
252e9c6f06cSKostya Serebryany // This function should be called once.
2536fd4d8abSKostya Serebryany assert(!FocusFunctionCounterPtr);
254ad7b908bSMax Moroz // "auto" is not a valid function name. If this function is called with "auto"
255ad7b908bSMax Moroz // that means the auto focus functionality failed.
256ad7b908bSMax Moroz if (FuncName.empty() || FuncName == "auto")
257e9c6f06cSKostya Serebryany return;
2586fd4d8abSKostya Serebryany for (size_t M = 0; M < NumModules; M++) {
259e9c6f06cSKostya Serebryany auto &PCTE = ModulePCTable[M];
260e9c6f06cSKostya Serebryany size_t N = PCTE.Stop - PCTE.Start;
261e9c6f06cSKostya Serebryany for (size_t I = 0; I < N; I++) {
26277cbc625SKostya Serebryany if (!(PcIsFuncEntry(&PCTE.Start[I]))) continue; // not a function entry.
263e9c6f06cSKostya Serebryany auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC));
264e9c6f06cSKostya Serebryany if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ')
265e9c6f06cSKostya Serebryany Name = Name.substr(3, std::string::npos);
266e9c6f06cSKostya Serebryany if (FuncName != Name) continue;
267e9c6f06cSKostya Serebryany Printf("INFO: Focus function is set to '%s'\n", Name.c_str());
2686fd4d8abSKostya Serebryany FocusFunctionCounterPtr = Modules[M].Start() + I;
269e9c6f06cSKostya Serebryany return;
270e9c6f06cSKostya Serebryany }
271e9c6f06cSKostya Serebryany }
272ad7b908bSMax Moroz
273ad7b908bSMax Moroz Printf("ERROR: Failed to set focus function. Make sure the function name is "
274ad7b908bSMax Moroz "valid (%s) and symbolization is enabled.\n", FuncName.c_str());
275ad7b908bSMax Moroz exit(1);
276e9c6f06cSKostya Serebryany }
277e9c6f06cSKostya Serebryany
ObservedFocusFunction()278e9c6f06cSKostya Serebryany bool TracePC::ObservedFocusFunction() {
2796fd4d8abSKostya Serebryany return FocusFunctionCounterPtr && *FocusFunctionCounterPtr;
280e9c6f06cSKostya Serebryany }
281e9c6f06cSKostya Serebryany
PrintCoverage(bool PrintAllCounters)282dc62d5ecSMax Moroz void TracePC::PrintCoverage(bool PrintAllCounters) {
28310ab2aceSGeorge Karpenkov if (!EF->__sanitizer_symbolize_pc ||
28410ab2aceSGeorge Karpenkov !EF->__sanitizer_get_module_and_offset_for_pc) {
28510ab2aceSGeorge Karpenkov Printf("INFO: __sanitizer_symbolize_pc or "
28610ab2aceSGeorge Karpenkov "__sanitizer_get_module_and_offset_for_pc is not available,"
28710ab2aceSGeorge Karpenkov " not printing coverage\n");
28810ab2aceSGeorge Karpenkov return;
28910ab2aceSGeorge Karpenkov }
290dc62d5ecSMax Moroz Printf(PrintAllCounters ? "FULL COVERAGE:\n" : "COVERAGE:\n");
29144edc281SKostya Serebryany auto CoveredFunctionCallback = [&](const PCTableEntry *First,
29244edc281SKostya Serebryany const PCTableEntry *Last,
29344edc281SKostya Serebryany uintptr_t Counter) {
2946a6e690dSKostya Serebryany assert(First < Last);
2956a6e690dSKostya Serebryany auto VisualizePC = GetNextInstructionPc(First->PC);
2966a6e690dSKostya Serebryany std::string FileStr = DescribePC("%s", VisualizePC);
29744edc281SKostya Serebryany if (!IsInterestingCoverageFile(FileStr))
29844edc281SKostya Serebryany return;
2996a6e690dSKostya Serebryany std::string FunctionStr = DescribePC("%F", VisualizePC);
30044edc281SKostya Serebryany if (FunctionStr.find("in ") == 0)
30144edc281SKostya Serebryany FunctionStr = FunctionStr.substr(3);
3026a6e690dSKostya Serebryany std::string LineStr = DescribePC("%l", VisualizePC);
30344edc281SKostya Serebryany size_t NumEdges = Last - First;
3047c921753SKostya Serebryany std::vector<uintptr_t> UncoveredPCs;
3057c921753SKostya Serebryany std::vector<uintptr_t> CoveredPCs;
3066a6e690dSKostya Serebryany for (auto TE = First; TE < Last; TE++)
30796f81bc6SKostya Serebryany if (!ObservedPCs.count(TE))
3086a6e690dSKostya Serebryany UncoveredPCs.push_back(TE->PC);
309dc62d5ecSMax Moroz else
310dc62d5ecSMax Moroz CoveredPCs.push_back(TE->PC);
311dc62d5ecSMax Moroz
312dc62d5ecSMax Moroz if (PrintAllCounters) {
313dc62d5ecSMax Moroz Printf("U");
314dc62d5ecSMax Moroz for (auto PC : UncoveredPCs)
315dc62d5ecSMax Moroz Printf(DescribePC(" %l", GetNextInstructionPc(PC)).c_str());
316dc62d5ecSMax Moroz Printf("\n");
317dc62d5ecSMax Moroz
318dc62d5ecSMax Moroz Printf("C");
319dc62d5ecSMax Moroz for (auto PC : CoveredPCs)
320dc62d5ecSMax Moroz Printf(DescribePC(" %l", GetNextInstructionPc(PC)).c_str());
321dc62d5ecSMax Moroz Printf("\n");
322dc62d5ecSMax Moroz } else {
323bb01a098SKostya Serebryany Printf("%sCOVERED_FUNC: hits: %zd", Counter ? "" : "UN", Counter);
32444edc281SKostya Serebryany Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges);
32556b2d57cSKostya Serebryany Printf(" %s %s:%s\n", FunctionStr.c_str(), FileStr.c_str(),
32656b2d57cSKostya Serebryany LineStr.c_str());
327bb01a098SKostya Serebryany if (Counter)
32844edc281SKostya Serebryany for (auto PC : UncoveredPCs)
3296a6e690dSKostya Serebryany Printf(" UNCOVERED_PC: %s\n",
3306a6e690dSKostya Serebryany DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str());
331dc62d5ecSMax Moroz }
33210ab2aceSGeorge Karpenkov };
33310ab2aceSGeorge Karpenkov
3346a6e690dSKostya Serebryany IterateCoveredFunctions(CoveredFunctionCallback);
33510ab2aceSGeorge Karpenkov }
33610ab2aceSGeorge Karpenkov
33710ab2aceSGeorge Karpenkov // Value profile.
33810ab2aceSGeorge Karpenkov // We keep track of various values that affect control flow.
33910ab2aceSGeorge Karpenkov // These values are inserted into a bit-set-based hash map.
34010ab2aceSGeorge Karpenkov // Every new bit in the map is treated as a new coverage.
34110ab2aceSGeorge Karpenkov //
34210ab2aceSGeorge Karpenkov // For memcmp/strcmp/etc the interesting value is the length of the common
34310ab2aceSGeorge Karpenkov // prefix of the parameters.
34410ab2aceSGeorge Karpenkov // For cmp instructions the interesting value is a XOR of the parameters.
34510ab2aceSGeorge Karpenkov // The interesting value is mixed up with the PC and is then added to the map.
34610ab2aceSGeorge Karpenkov
34710ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
AddValueForMemcmp(void * caller_pc,const void * s1,const void * s2,size_t n,bool StopAtZero)34810ab2aceSGeorge Karpenkov void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
34910ab2aceSGeorge Karpenkov size_t n, bool StopAtZero) {
35010ab2aceSGeorge Karpenkov if (!n) return;
35110ab2aceSGeorge Karpenkov size_t Len = std::min(n, Word::GetMaxSize());
35210ab2aceSGeorge Karpenkov const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
35310ab2aceSGeorge Karpenkov const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
35410ab2aceSGeorge Karpenkov uint8_t B1[Word::kMaxSize];
35510ab2aceSGeorge Karpenkov uint8_t B2[Word::kMaxSize];
35610ab2aceSGeorge Karpenkov // Copy the data into locals in this non-msan-instrumented function
35710ab2aceSGeorge Karpenkov // to avoid msan complaining further.
35810ab2aceSGeorge Karpenkov size_t Hash = 0; // Compute some simple hash of both strings.
35910ab2aceSGeorge Karpenkov for (size_t i = 0; i < Len; i++) {
36010ab2aceSGeorge Karpenkov B1[i] = A1[i];
36110ab2aceSGeorge Karpenkov B2[i] = A2[i];
36210ab2aceSGeorge Karpenkov size_t T = B1[i];
36310ab2aceSGeorge Karpenkov Hash ^= (T << 8) | B2[i];
36410ab2aceSGeorge Karpenkov }
36510ab2aceSGeorge Karpenkov size_t I = 0;
3664a5793f7SKostya Serebryany uint8_t HammingDistance = 0;
3674a5793f7SKostya Serebryany for (; I < Len; I++) {
3684a5793f7SKostya Serebryany if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0)) {
3696708186cSAaron Green HammingDistance = static_cast<uint8_t>(Popcountll(B1[I] ^ B2[I]));
37010ab2aceSGeorge Karpenkov break;
3714a5793f7SKostya Serebryany }
3724a5793f7SKostya Serebryany }
37310ab2aceSGeorge Karpenkov size_t PC = reinterpret_cast<size_t>(caller_pc);
37410ab2aceSGeorge Karpenkov size_t Idx = (PC & 4095) | (I << 12);
3754a5793f7SKostya Serebryany Idx += HammingDistance;
37610ab2aceSGeorge Karpenkov ValueProfileMap.AddValue(Idx);
37710ab2aceSGeorge Karpenkov TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len));
37810ab2aceSGeorge Karpenkov }
37910ab2aceSGeorge Karpenkov
38010ab2aceSGeorge Karpenkov template <class T>
38110ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
38210ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
HandleCmp(uintptr_t PC,T Arg1,T Arg2)38310ab2aceSGeorge Karpenkov void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
38410ab2aceSGeorge Karpenkov uint64_t ArgXor = Arg1 ^ Arg2;
38510ab2aceSGeorge Karpenkov if (sizeof(T) == 4)
38610ab2aceSGeorge Karpenkov TORC4.Insert(ArgXor, Arg1, Arg2);
38710ab2aceSGeorge Karpenkov else if (sizeof(T) == 8)
38810ab2aceSGeorge Karpenkov TORC8.Insert(ArgXor, Arg1, Arg2);
38955ddb2c7SJonathan Metzman uint64_t HammingDistance = Popcountll(ArgXor); // [0,64]
39055ddb2c7SJonathan Metzman uint64_t AbsoluteDistance = (Arg1 == Arg2 ? 0 : Clzll(Arg1 - Arg2) + 1);
391cedebd59SKostya Serebryany ValueProfileMap.AddValue(PC * 128 + HammingDistance);
392cedebd59SKostya Serebryany ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
39310ab2aceSGeorge Karpenkov }
39410ab2aceSGeorge Karpenkov
3953c7960cbSVitaly Buka ATTRIBUTE_NO_SANITIZE_MEMORY
InternalStrnlen(const char * S,size_t MaxLen)39610ab2aceSGeorge Karpenkov static size_t InternalStrnlen(const char *S, size_t MaxLen) {
39710ab2aceSGeorge Karpenkov size_t Len = 0;
39810ab2aceSGeorge Karpenkov for (; Len < MaxLen && S[Len]; Len++) {}
39910ab2aceSGeorge Karpenkov return Len;
40010ab2aceSGeorge Karpenkov }
40110ab2aceSGeorge Karpenkov
40210ab2aceSGeorge Karpenkov // Finds min of (strlen(S1), strlen(S2)).
403a1e7e401SKazuaki Ishizaki // Needed because one of these strings may actually be non-zero terminated.
4043c7960cbSVitaly Buka ATTRIBUTE_NO_SANITIZE_MEMORY
InternalStrnlen2(const char * S1,const char * S2)40510ab2aceSGeorge Karpenkov static size_t InternalStrnlen2(const char *S1, const char *S2) {
40610ab2aceSGeorge Karpenkov size_t Len = 0;
40710ab2aceSGeorge Karpenkov for (; S1[Len] && S2[Len]; Len++) {}
40810ab2aceSGeorge Karpenkov return Len;
40910ab2aceSGeorge Karpenkov }
41010ab2aceSGeorge Karpenkov
ClearInlineCounters()41110ab2aceSGeorge Karpenkov void TracePC::ClearInlineCounters() {
4126fd4d8abSKostya Serebryany IterateCounterRegions([](const Module::Region &R){
4136fd4d8abSKostya Serebryany if (R.Enabled)
4146fd4d8abSKostya Serebryany memset(R.Start, 0, R.Stop - R.Start);
4156fd4d8abSKostya Serebryany });
41610ab2aceSGeorge Karpenkov }
41710ab2aceSGeorge Karpenkov
41833fb36c3SKostya Serebryany ATTRIBUTE_NO_SANITIZE_ALL
RecordInitialStack()419f65cf64fSKostya Serebryany void TracePC::RecordInitialStack() {
42033fb36c3SKostya Serebryany int stack;
42133fb36c3SKostya Serebryany __sancov_lowest_stack = InitialStack = reinterpret_cast<uintptr_t>(&stack);
422f65cf64fSKostya Serebryany }
423f65cf64fSKostya Serebryany
GetMaxStackOffset() const424f65cf64fSKostya Serebryany uintptr_t TracePC::GetMaxStackOffset() const {
425f65cf64fSKostya Serebryany return InitialStack - __sancov_lowest_stack; // Stack grows down
426f65cf64fSKostya Serebryany }
427f65cf64fSKostya Serebryany
WarnAboutDeprecatedInstrumentation(const char * flag)42850a1c697SKostya Serebryany void WarnAboutDeprecatedInstrumentation(const char *flag) {
429fc7faecbSJonathan Metzman // Use RawPrint because Printf cannot be used on Windows before OutputFile is
430fc7faecbSJonathan Metzman // initialized.
431fc7faecbSJonathan Metzman RawPrint(flag);
432fc7faecbSJonathan Metzman RawPrint(
433fc7faecbSJonathan Metzman " is no longer supported by libFuzzer.\n"
43450a1c697SKostya Serebryany "Please either migrate to a compiler that supports -fsanitize=fuzzer\n"
435fc7faecbSJonathan Metzman "or use an older version of libFuzzer\n");
43650a1c697SKostya Serebryany exit(1);
43750a1c697SKostya Serebryany }
43850a1c697SKostya Serebryany
43910ab2aceSGeorge Karpenkov } // namespace fuzzer
44010ab2aceSGeorge Karpenkov
44110ab2aceSGeorge Karpenkov extern "C" {
44210ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
44310ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
__sanitizer_cov_trace_pc_guard(uint32_t * Guard)44410ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
445fc7faecbSJonathan Metzman fuzzer::WarnAboutDeprecatedInstrumentation(
446fc7faecbSJonathan Metzman "-fsanitize-coverage=trace-pc-guard");
44710ab2aceSGeorge Karpenkov }
44810ab2aceSGeorge Karpenkov
44910ab2aceSGeorge Karpenkov // Best-effort support for -fsanitize-coverage=trace-pc, which is available
45010ab2aceSGeorge Karpenkov // in both Clang and GCC.
45110ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
45210ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
__sanitizer_cov_trace_pc()45310ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_pc() {
454fc7faecbSJonathan Metzman fuzzer::WarnAboutDeprecatedInstrumentation("-fsanitize-coverage=trace-pc");
45510ab2aceSGeorge Karpenkov }
45610ab2aceSGeorge Karpenkov
45710ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
__sanitizer_cov_trace_pc_guard_init(uint32_t * Start,uint32_t * Stop)45810ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
45950a1c697SKostya Serebryany fuzzer::WarnAboutDeprecatedInstrumentation(
46050a1c697SKostya Serebryany "-fsanitize-coverage=trace-pc-guard");
46110ab2aceSGeorge Karpenkov }
46210ab2aceSGeorge Karpenkov
46310ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
__sanitizer_cov_8bit_counters_init(uint8_t * Start,uint8_t * Stop)46410ab2aceSGeorge Karpenkov void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) {
46510ab2aceSGeorge Karpenkov fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop);
46610ab2aceSGeorge Karpenkov }
46710ab2aceSGeorge Karpenkov
46810ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
__sanitizer_cov_pcs_init(const uintptr_t * pcs_beg,const uintptr_t * pcs_end)469d3e4b7e2SKostya Serebryany void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
470d3e4b7e2SKostya Serebryany const uintptr_t *pcs_end) {
47110ab2aceSGeorge Karpenkov fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end);
47210ab2aceSGeorge Karpenkov }
47310ab2aceSGeorge Karpenkov
47410ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
47510ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
__sanitizer_cov_trace_pc_indir(uintptr_t Callee)47610ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
47755ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
47810ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCallerCallee(PC, Callee);
47910ab2aceSGeorge Karpenkov }
48010ab2aceSGeorge Karpenkov
48110ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
48210ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
48310ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_cmp8(uint64_t Arg1,uint64_t Arg2)48410ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
48555ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
48610ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
48710ab2aceSGeorge Karpenkov }
48810ab2aceSGeorge Karpenkov
48910ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
49010ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
49110ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
49210ab2aceSGeorge Karpenkov // Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic
49310ab2aceSGeorge Karpenkov // the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
49410ab2aceSGeorge Karpenkov // should be changed later to make full use of instrumentation.
__sanitizer_cov_trace_const_cmp8(uint64_t Arg1,uint64_t Arg2)49510ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
49655ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
49710ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
49810ab2aceSGeorge Karpenkov }
49910ab2aceSGeorge Karpenkov
50010ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
50110ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
50210ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_cmp4(uint32_t Arg1,uint32_t Arg2)50310ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
50455ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
50510ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
50610ab2aceSGeorge Karpenkov }
50710ab2aceSGeorge Karpenkov
50810ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
50910ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
51010ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_const_cmp4(uint32_t Arg1,uint32_t Arg2)51110ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
51255ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
51310ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
51410ab2aceSGeorge Karpenkov }
51510ab2aceSGeorge Karpenkov
51610ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
51710ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
51810ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_cmp2(uint16_t Arg1,uint16_t Arg2)51910ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
52055ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
52110ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
52210ab2aceSGeorge Karpenkov }
52310ab2aceSGeorge Karpenkov
52410ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
52510ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
52610ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_const_cmp2(uint16_t Arg1,uint16_t Arg2)52710ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
52855ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
52910ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
53010ab2aceSGeorge Karpenkov }
53110ab2aceSGeorge Karpenkov
53210ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
53310ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
53410ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_cmp1(uint8_t Arg1,uint8_t Arg2)53510ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
53655ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
53710ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
53810ab2aceSGeorge Karpenkov }
53910ab2aceSGeorge Karpenkov
54010ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
54110ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
54210ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_const_cmp1(uint8_t Arg1,uint8_t Arg2)54310ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
54455ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
54510ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
54610ab2aceSGeorge Karpenkov }
54710ab2aceSGeorge Karpenkov
54810ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
54910ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
55010ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_switch(uint64_t Val,uint64_t * Cases)55110ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
55210ab2aceSGeorge Karpenkov uint64_t N = Cases[0];
55310ab2aceSGeorge Karpenkov uint64_t ValSizeInBits = Cases[1];
55410ab2aceSGeorge Karpenkov uint64_t *Vals = Cases + 2;
555360bf5ffSKostya Serebryany // Skip the most common and the most boring case: all switch values are small.
556360bf5ffSKostya Serebryany // We may want to skip this at compile-time, but it will make the
557360bf5ffSKostya Serebryany // instrumentation less general.
558360bf5ffSKostya Serebryany if (Vals[N - 1] < 256)
559360bf5ffSKostya Serebryany return;
560360bf5ffSKostya Serebryany // Also skip small inputs values, they won't give good signal.
561360bf5ffSKostya Serebryany if (Val < 256)
56210ab2aceSGeorge Karpenkov return;
56355ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
56410ab2aceSGeorge Karpenkov size_t i;
565360bf5ffSKostya Serebryany uint64_t Smaller = 0;
566360bf5ffSKostya Serebryany uint64_t Larger = ~(uint64_t)0;
567360bf5ffSKostya Serebryany // Find two switch values such that Smaller < Val < Larger.
568360bf5ffSKostya Serebryany // Use 0 and 0xfff..f as the defaults.
56910ab2aceSGeorge Karpenkov for (i = 0; i < N; i++) {
570360bf5ffSKostya Serebryany if (Val < Vals[i]) {
571360bf5ffSKostya Serebryany Larger = Vals[i];
57210ab2aceSGeorge Karpenkov break;
57310ab2aceSGeorge Karpenkov }
574360bf5ffSKostya Serebryany if (Val > Vals[i]) Smaller = Vals[i];
575360bf5ffSKostya Serebryany }
57610ab2aceSGeorge Karpenkov
577360bf5ffSKostya Serebryany // Apply HandleCmp to {Val,Smaller} and {Val, Larger},
578360bf5ffSKostya Serebryany // use i as the PC modifier for HandleCmp.
579360bf5ffSKostya Serebryany if (ValSizeInBits == 16) {
580360bf5ffSKostya Serebryany fuzzer::TPC.HandleCmp(PC + 2 * i, static_cast<uint16_t>(Val),
581360bf5ffSKostya Serebryany (uint16_t)(Smaller));
582360bf5ffSKostya Serebryany fuzzer::TPC.HandleCmp(PC + 2 * i + 1, static_cast<uint16_t>(Val),
583360bf5ffSKostya Serebryany (uint16_t)(Larger));
584360bf5ffSKostya Serebryany } else if (ValSizeInBits == 32) {
585360bf5ffSKostya Serebryany fuzzer::TPC.HandleCmp(PC + 2 * i, static_cast<uint32_t>(Val),
586360bf5ffSKostya Serebryany (uint32_t)(Smaller));
587360bf5ffSKostya Serebryany fuzzer::TPC.HandleCmp(PC + 2 * i + 1, static_cast<uint32_t>(Val),
588360bf5ffSKostya Serebryany (uint32_t)(Larger));
589360bf5ffSKostya Serebryany } else {
590360bf5ffSKostya Serebryany fuzzer::TPC.HandleCmp(PC + 2*i, Val, Smaller);
591360bf5ffSKostya Serebryany fuzzer::TPC.HandleCmp(PC + 2*i + 1, Val, Larger);
592360bf5ffSKostya Serebryany }
59310ab2aceSGeorge Karpenkov }
59410ab2aceSGeorge Karpenkov
59510ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
59610ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
59710ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_div4(uint32_t Val)59810ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_div4(uint32_t Val) {
59955ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
60010ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
60110ab2aceSGeorge Karpenkov }
60210ab2aceSGeorge Karpenkov
60310ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
60410ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
60510ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_div8(uint64_t Val)60610ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_div8(uint64_t Val) {
60755ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
60810ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
60910ab2aceSGeorge Karpenkov }
61010ab2aceSGeorge Karpenkov
61110ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE
61210ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_ALL
61310ab2aceSGeorge Karpenkov ATTRIBUTE_TARGET_POPCNT
__sanitizer_cov_trace_gep(uintptr_t Idx)61410ab2aceSGeorge Karpenkov void __sanitizer_cov_trace_gep(uintptr_t Idx) {
61555ddb2c7SJonathan Metzman uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
61610ab2aceSGeorge Karpenkov fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
61710ab2aceSGeorge Karpenkov }
61810ab2aceSGeorge Karpenkov
61910ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_memcmp(void * caller_pc,const void * s1,const void * s2,size_t n,int result)62010ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
62110ab2aceSGeorge Karpenkov const void *s2, size_t n, int result) {
62243a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
62310ab2aceSGeorge Karpenkov if (result == 0) return; // No reason to mutate.
62410ab2aceSGeorge Karpenkov if (n <= 1) return; // Not interesting.
62510ab2aceSGeorge Karpenkov fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
62610ab2aceSGeorge Karpenkov }
62710ab2aceSGeorge Karpenkov
62810ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_strncmp(void * caller_pc,const char * s1,const char * s2,size_t n,int result)62910ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
63010ab2aceSGeorge Karpenkov const char *s2, size_t n, int result) {
63143a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
63210ab2aceSGeorge Karpenkov if (result == 0) return; // No reason to mutate.
63310ab2aceSGeorge Karpenkov size_t Len1 = fuzzer::InternalStrnlen(s1, n);
63410ab2aceSGeorge Karpenkov size_t Len2 = fuzzer::InternalStrnlen(s2, n);
63510ab2aceSGeorge Karpenkov n = std::min(n, Len1);
63610ab2aceSGeorge Karpenkov n = std::min(n, Len2);
63710ab2aceSGeorge Karpenkov if (n <= 1) return; // Not interesting.
63810ab2aceSGeorge Karpenkov fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
63910ab2aceSGeorge Karpenkov }
64010ab2aceSGeorge Karpenkov
64110ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_strcmp(void * caller_pc,const char * s1,const char * s2,int result)64210ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
64310ab2aceSGeorge Karpenkov const char *s2, int result) {
64443a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
64510ab2aceSGeorge Karpenkov if (result == 0) return; // No reason to mutate.
64610ab2aceSGeorge Karpenkov size_t N = fuzzer::InternalStrnlen2(s1, s2);
64710ab2aceSGeorge Karpenkov if (N <= 1) return; // Not interesting.
64810ab2aceSGeorge Karpenkov fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
64910ab2aceSGeorge Karpenkov }
65010ab2aceSGeorge Karpenkov
65110ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_strncasecmp(void * called_pc,const char * s1,const char * s2,size_t n,int result)65210ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
65310ab2aceSGeorge Karpenkov const char *s2, size_t n, int result) {
65443a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
65510ab2aceSGeorge Karpenkov return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
65610ab2aceSGeorge Karpenkov }
65710ab2aceSGeorge Karpenkov
65810ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_strcasecmp(void * called_pc,const char * s1,const char * s2,int result)65910ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
66010ab2aceSGeorge Karpenkov const char *s2, int result) {
66143a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
66210ab2aceSGeorge Karpenkov return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
66310ab2aceSGeorge Karpenkov }
66410ab2aceSGeorge Karpenkov
66510ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_strstr(void * called_pc,const char * s1,const char * s2,char * result)66610ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
66710ab2aceSGeorge Karpenkov const char *s2, char *result) {
66843a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
66910ab2aceSGeorge Karpenkov fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
67010ab2aceSGeorge Karpenkov }
67110ab2aceSGeorge Karpenkov
67210ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_strcasestr(void * called_pc,const char * s1,const char * s2,char * result)67310ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
67410ab2aceSGeorge Karpenkov const char *s2, char *result) {
67543a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
67610ab2aceSGeorge Karpenkov fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
67710ab2aceSGeorge Karpenkov }
67810ab2aceSGeorge Karpenkov
67910ab2aceSGeorge Karpenkov ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
__sanitizer_weak_hook_memmem(void * called_pc,const void * s1,size_t len1,const void * s2,size_t len2,void * result)68010ab2aceSGeorge Karpenkov void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
68110ab2aceSGeorge Karpenkov const void *s2, size_t len2, void *result) {
68243a22969SMatt Morehouse if (!fuzzer::RunningUserCallback) return;
68310ab2aceSGeorge Karpenkov fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2);
68410ab2aceSGeorge Karpenkov }
68510ab2aceSGeorge Karpenkov } // extern "C"
686