Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/tools/fuzzing/libfuzzer/FuzzerTracePC.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- FuzzerTracePC.cpp - PC tracing--------------------------------------===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
// Trace PCs.
10
// This module implements __sanitizer_cov_trace_pc_guard[_init],
11
// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "FuzzerTracePC.h"
16
#include "FuzzerCorpus.h"
17
#include "FuzzerDefs.h"
18
#include "FuzzerDictionary.h"
19
#include "FuzzerExtFunctions.h"
20
#include "FuzzerIO.h"
21
#include "FuzzerUtil.h"
22
#include "FuzzerValueBitMap.h"
23
#include <set>
24
25
// The coverage counters and PCs.
26
// These are declared as global variables named "__sancov_*" to simplify
27
// experiments with inlined instrumentation.
28
alignas(64) ATTRIBUTE_INTERFACE
29
uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs];
30
31
ATTRIBUTE_INTERFACE
32
uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
33
34
// Used by -fsanitize-coverage=stack-depth to track stack depth
35
ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack;
36
37
namespace fuzzer {
38
39
TracePC TPC;
40
41
16.2k
uint8_t *TracePC::Counters() const {
42
16.2k
  return __sancov_trace_pc_guard_8bit_counters;
43
16.2k
}
44
45
0
uintptr_t *TracePC::PCs() const {
46
0
  return __sancov_trace_pc_pcs;
47
0
}
48
49
14
size_t TracePC::GetTotalPCCoverage() {
50
14
  if (ObservedPCs.size())
51
14
    return ObservedPCs.size();
52
0
  size_t Res = 0;
53
0
  for (size_t i = 1, N = GetNumPCs(); i < N; i++)
54
0
    if (PCs()[i])
55
0
      Res++;
56
0
  return Res;
57
0
}
58
59
template<class CallBack>
60
10.4k
void TracePC::IterateInline8bitCounters(CallBack CB) const {
61
10.4k
  if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) {
62
10.4k
    size_t CounterIdx = 0;
63
20.8k
    for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
64
10.4k
      uint8_t *Beg = ModuleCounters[i].Start;
65
10.4k
      size_t Size = ModuleCounters[i].Stop - Beg;
66
10.4k
      assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
67
14.4G
      for (size_t j = 0; j < Size; j++, CounterIdx++)
68
14.4G
        CB(i, j, CounterIdx);
69
10.4k
    }
70
10.4k
  }
71
10.4k
}
Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::InitializeUnstableCounters()::$_0>(fuzzer::TracePC::InitializeUnstableCounters()::$_0) const
Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::UpdateUnstableCounters(int)::$_1>(fuzzer::TracePC::UpdateUnstableCounters(int)::$_1) const
Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::UpdateAndApplyUnstableCounters(int)::$_2>(fuzzer::TracePC::UpdateAndApplyUnstableCounters(int)::$_2) const
FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::UpdateObservedPCs()::$_3>(fuzzer::TracePC::UpdateObservedPCs()::$_3) const
Line
Count
Source
60
10.4k
void TracePC::IterateInline8bitCounters(CallBack CB) const {
61
10.4k
  if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) {
62
10.4k
    size_t CounterIdx = 0;
63
20.8k
    for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
64
10.4k
      uint8_t *Beg = ModuleCounters[i].Start;
65
10.4k
      size_t Size = ModuleCounters[i].Stop - Beg;
66
10.4k
      assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
67
14.4G
      for (size_t j = 0; j < Size; j++, CounterIdx++)
68
14.4G
        CB(i, j, CounterIdx);
69
10.4k
    }
70
10.4k
  }
71
10.4k
}
Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::PrintUnstableStats()::$_6>(fuzzer::TracePC::PrintUnstableStats()::$_6) const
72
73
// Initializes unstable counters by copying Inline8bitCounters to unstable
74
// counters.
75
0
void TracePC::InitializeUnstableCounters() {
76
0
  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
77
0
    UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
78
0
  });
79
0
}
80
81
// Compares the current counters with counters from previous runs
82
// and records differences as unstable edges.
83
0
bool TracePC::UpdateUnstableCounters(int UnstableMode) {
84
0
  bool Updated = false;
85
0
  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
86
0
    if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) {
87
0
      Updated = true;
88
0
      UnstableCounters[UnstableIdx].IsUnstable = true;
89
0
      if (UnstableMode == ZeroUnstable)
90
0
        UnstableCounters[UnstableIdx].Counter = 0;
91
0
      else if (UnstableMode == MinUnstable)
92
0
        UnstableCounters[UnstableIdx].Counter = std::min(
93
0
            ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter);
94
0
    }
95
0
  });
96
0
  return Updated;
97
0
}
98
99
// Updates and applies unstable counters to ModuleCounters in single iteration
100
0
void TracePC::UpdateAndApplyUnstableCounters(int UnstableMode) {
101
0
  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
102
0
    if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) {
103
0
      UnstableCounters[UnstableIdx].IsUnstable = true;
104
0
      if (UnstableMode == ZeroUnstable)
105
0
        ModuleCounters[i].Start[j] = 0;
106
0
      else if (UnstableMode == MinUnstable)
107
0
        ModuleCounters[i].Start[j] = std::min(
108
0
            ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter);
109
0
    }
110
0
  });
111
0
}
112
113
3
void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
114
3
  if (Start == Stop) return;
115
3
  if (NumModulesWithInline8bitCounters &&
116
3
      ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return;
117
3
  assert(NumModulesWithInline8bitCounters <
118
3
         sizeof(ModuleCounters) / sizeof(ModuleCounters[0]));
119
3
  ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop};
120
3
  NumInline8bitCounters += Stop - Start;
121
3
}
122
123
3
void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
124
3
  const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
125
3
  const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
126
3
  if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
127
3
  assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0]));
128
3
  ModulePCTable[NumPCTables++] = {B, E};
129
3
  NumPCsInPCTables += E - B;
130
3
}
131
132
0
void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
133
0
  if (Start == Stop || *Start) return;
134
0
  assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
135
0
  for (uint32_t *P = Start; P < Stop; P++) {
136
0
    NumGuards++;
137
0
    if (NumGuards == kNumPCs) {
138
0
      RawPrint(
139
0
          "WARNING: The binary has too many instrumented PCs.\n"
140
0
          "         You may want to reduce the size of the binary\n"
141
0
          "         for more efficient fuzzing and precise coverage data\n");
142
0
    }
143
0
    *P = NumGuards % kNumPCs;
144
0
  }
145
0
  Modules[NumModules].Start = Start;
146
0
  Modules[NumModules].Stop = Stop;
147
0
  NumModules++;
148
0
}
149
150
3
void TracePC::PrintModuleInfo() {
151
3
  if (NumGuards) {
152
0
    Printf("INFO: Loaded %zd modules   (%zd guards): ", NumModules, NumGuards);
153
0
    for (size_t i = 0; i < NumModules; i++)
154
0
      Printf("%zd [%p, %p), ", Modules[i].Stop - Modules[i].Start,
155
0
             Modules[i].Start, Modules[i].Stop);
156
0
    Printf("\n");
157
0
  }
158
3
  if (NumModulesWithInline8bitCounters) {
159
3
    Printf("INFO: Loaded %zd modules   (%zd inline 8-bit counters): ",
160
3
           NumModulesWithInline8bitCounters, NumInline8bitCounters);
161
6
    for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++)
162
3
      Printf("%zd [%p, %p), ", ModuleCounters[i].Stop - ModuleCounters[i].Start,
163
3
             ModuleCounters[i].Start, ModuleCounters[i].Stop);
164
3
    Printf("\n");
165
3
  }
166
3
  if (NumPCTables) {
167
3
    Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables,
168
3
           NumPCsInPCTables);
169
6
    for (size_t i = 0; i < NumPCTables; i++) {
170
3
      Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start,
171
3
             ModulePCTable[i].Start, ModulePCTable[i].Stop);
172
3
    }
173
3
    Printf("\n");
174
3
175
3
    if ((NumGuards && NumGuards != NumPCsInPCTables) ||
176
3
        (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) {
177
0
      Printf("ERROR: The size of coverage PC tables does not match the\n"
178
0
             "number of instrumented PCs. This might be a compiler bug,\n"
179
0
             "please contact the libFuzzer developers.\n"
180
0
             "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n"
181
0
             "for possible workarounds (tl;dr: don't use the old GNU ld)\n");
182
0
      _Exit(1);
183
0
    }
184
3
  }
185
3
  if (size_t NumExtraCounters = ExtraCountersEnd() - ExtraCountersBegin())
186
0
    Printf("INFO: %zd Extra Counters\n", NumExtraCounters);
187
3
}
188
189
ATTRIBUTE_NO_SANITIZE_ALL
190
265M
void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
191
265M
  const uintptr_t kBits = 12;
192
265M
  const uintptr_t kMask = (1 << kBits) - 1;
193
265M
  uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
194
265M
  ValueProfileMap.AddValueModPrime(Idx);
195
265M
}
196
197
10.4k
void TracePC::UpdateObservedPCs() {
198
10.4k
  Vector<uintptr_t> CoveredFuncs;
199
7.32M
  auto ObservePC = [&](uintptr_t PC) {
200
7.32M
    if (ObservedPCs.insert(PC).second && DoPrintNewPCs) {
201
0
      PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1);
202
0
      Printf("\n");
203
0
    }
204
7.32M
  };
205
10.4k
206
7.32M
  auto Observe = [&](const PCTableEntry &TE) {
207
7.32M
    if (TE.PCFlags & 1)
208
4.20M
      if (++ObservedFuncs[TE.PC] == 1 && NumPrintNewFuncs)
209
0
        CoveredFuncs.push_back(TE.PC);
210
7.32M
    ObservePC(TE.PC);
211
7.32M
  };
212
10.4k
213
10.4k
  if (NumPCsInPCTables) {
214
10.4k
    if (NumInline8bitCounters == NumPCsInPCTables) {
215
14.4G
      IterateInline8bitCounters([&](int i, int j, int CounterIdx) {
216
14.4G
        if (ModuleCounters[i].Start[j])
217
7.32M
          Observe(ModulePCTable[i].Start[j]);
218
14.4G
      });
219
10.4k
    } else if (NumGuards == NumPCsInPCTables) {
220
0
      size_t GuardIdx = 1;
221
0
      for (size_t i = 0; i < NumModules; i++) {
222
0
        uint32_t *Beg = Modules[i].Start;
223
0
        size_t Size = Modules[i].Stop - Beg;
224
0
        assert(Size ==
225
0
               (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
226
0
        for (size_t j = 0; j < Size; j++, GuardIdx++)
227
0
          if (Counters()[GuardIdx])
228
0
            Observe(ModulePCTable[i].Start[j]);
229
0
      }
230
0
    }
231
10.4k
  }
232
10.4k
233
10.4k
  for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N;
234
10.4k
       i++) {
235
0
    Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size());
236
0
    PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1);
237
0
    Printf("\n");
238
0
  }
239
10.4k
}
240
241
0
inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
242
0
  // TODO: this implementation is x86 only.
243
0
  // see sanitizer_common GetPreviousInstructionPc for full implementation.
244
0
  return PC - 1;
245
0
}
246
247
0
inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
248
0
  // TODO: this implementation is x86 only.
249
0
  // see sanitizer_common GetPreviousInstructionPc for full implementation.
250
0
  return PC + 1;
251
0
}
252
253
0
static std::string GetModuleName(uintptr_t PC) {
254
0
  char ModulePathRaw[4096] = "";  // What's PATH_MAX in portable C++?
255
0
  void *OffsetRaw = nullptr;
256
0
  if (!EF->__sanitizer_get_module_and_offset_for_pc(
257
0
      reinterpret_cast<void *>(PC), ModulePathRaw,
258
0
      sizeof(ModulePathRaw), &OffsetRaw))
259
0
    return "";
260
0
  return ModulePathRaw;
261
0
}
262
263
template<class CallBack>
264
0
void TracePC::IterateCoveredFunctions(CallBack CB) {
265
0
  for (size_t i = 0; i < NumPCTables; i++) {
266
0
    auto &M = ModulePCTable[i];
267
0
    assert(M.Start < M.Stop);
268
0
    auto ModuleName = GetModuleName(M.Start->PC);
269
0
    for (auto NextFE = M.Start; NextFE < M.Stop; ) {
270
0
      auto FE = NextFE;
271
0
      assert((FE->PCFlags & 1) && "Not a function entry point");
272
0
      do {
273
0
        NextFE++;
274
0
      } while (NextFE < M.Stop && !(NextFE->PCFlags & 1));
275
0
      if (ObservedFuncs.count(FE->PC))
276
0
        CB(FE, NextFE, ObservedFuncs[FE->PC]);
277
0
    }
278
0
  }
279
0
}
280
281
3
void TracePC::SetFocusFunction(const std::string &FuncName) {
282
3
  // This function should be called once.
283
3
  assert(FocusFunction.first > NumModulesWithInline8bitCounters);
284
3
  if (FuncName.empty())
285
3
    return;
286
0
  for (size_t M = 0; M < NumModulesWithInline8bitCounters; M++) {
287
0
    auto &PCTE = ModulePCTable[M];
288
0
    size_t N = PCTE.Stop - PCTE.Start;
289
0
    for (size_t I = 0; I < N; I++) {
290
0
      if (!(PCTE.Start[I].PCFlags & 1)) continue;  // not a function entry.
291
0
      auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC));
292
0
      if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ')
293
0
        Name = Name.substr(3, std::string::npos);
294
0
      if (FuncName != Name) continue;
295
0
      Printf("INFO: Focus function is set to '%s'\n", Name.c_str());
296
0
      FocusFunction = {M, I};
297
0
      return;
298
0
    }
299
0
  }
300
0
}
301
302
10.4k
bool TracePC::ObservedFocusFunction() {
303
10.4k
  size_t I = FocusFunction.first;
304
10.4k
  size_t J = FocusFunction.second;
305
10.4k
  if (I >= NumModulesWithInline8bitCounters)
306
10.4k
    return false;
307
0
  auto &MC = ModuleCounters[I];
308
0
  size_t Size = MC.Stop - MC.Start;
309
0
  if (J >= Size)
310
0
    return false;
311
0
  return MC.Start[J] != 0;
312
0
}
313
314
0
void TracePC::PrintCoverage() {
315
0
  if (!EF->__sanitizer_symbolize_pc ||
316
0
      !EF->__sanitizer_get_module_and_offset_for_pc) {
317
0
    Printf("INFO: __sanitizer_symbolize_pc or "
318
0
           "__sanitizer_get_module_and_offset_for_pc is not available,"
319
0
           " not printing coverage\n");
320
0
    return;
321
0
  }
322
0
  Printf("COVERAGE:\n");
323
0
  auto CoveredFunctionCallback = [&](const PCTableEntry *First,
324
0
                                     const PCTableEntry *Last,
325
0
                                     uintptr_t Counter) {
326
0
    assert(First < Last);
327
0
    auto VisualizePC = GetNextInstructionPc(First->PC);
328
0
    std::string FileStr = DescribePC("%s", VisualizePC);
329
0
    if (!IsInterestingCoverageFile(FileStr))
330
0
      return;
331
0
    std::string FunctionStr = DescribePC("%F", VisualizePC);
332
0
    if (FunctionStr.find("in ") == 0)
333
0
      FunctionStr = FunctionStr.substr(3);
334
0
    std::string LineStr = DescribePC("%l", VisualizePC);
335
0
    size_t Line = std::stoul(LineStr);
336
0
    size_t NumEdges = Last - First;
337
0
    Vector<uintptr_t> UncoveredPCs;
338
0
    for (auto TE = First; TE < Last; TE++)
339
0
      if (!ObservedPCs.count(TE->PC))
340
0
        UncoveredPCs.push_back(TE->PC);
341
0
    Printf("COVERED_FUNC: hits: %zd", Counter);
342
0
    Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges);
343
0
    Printf(" %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), Line);
344
0
    for (auto PC: UncoveredPCs)
345
0
      Printf("  UNCOVERED_PC: %s\n",
346
0
             DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str());
347
0
  };
348
0
349
0
  IterateCoveredFunctions(CoveredFunctionCallback);
350
0
}
351
352
0
void TracePC::DumpCoverage() {
353
0
  if (EF->__sanitizer_dump_coverage) {
354
0
    Vector<uintptr_t> PCsCopy(GetNumPCs());
355
0
    for (size_t i = 0; i < GetNumPCs(); i++)
356
0
      PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0;
357
0
    EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size());
358
0
  }
359
0
}
360
361
0
void TracePC::PrintUnstableStats() {
362
0
  size_t count = 0;
363
0
  Printf("UNSTABLE_FUNCTIONS:\n");
364
0
  IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
365
0
    const PCTableEntry &TE = ModulePCTable[i].Start[j];
366
0
    if (UnstableCounters[UnstableIdx].IsUnstable) {
367
0
      count++;
368
0
      if (ObservedFuncs.count(TE.PC)) {
369
0
        auto VisualizePC = GetNextInstructionPc(TE.PC);
370
0
        std::string FunctionStr = DescribePC("%F", VisualizePC);
371
0
        if (FunctionStr.find("in ") == 0)
372
0
          FunctionStr = FunctionStr.substr(3);
373
0
        Printf("%s\n", FunctionStr.c_str());
374
0
      }
375
0
    }
376
0
  });
377
0
378
0
  Printf("stat::stability_rate: %.2f\n",
379
0
         100 - static_cast<float>(count * 100) / NumInline8bitCounters);
380
0
}
381
382
// Value profile.
383
// We keep track of various values that affect control flow.
384
// These values are inserted into a bit-set-based hash map.
385
// Every new bit in the map is treated as a new coverage.
386
//
387
// For memcmp/strcmp/etc the interesting value is the length of the common
388
// prefix of the parameters.
389
// For cmp instructions the interesting value is a XOR of the parameters.
390
// The interesting value is mixed up with the PC and is then added to the map.
391
392
ATTRIBUTE_NO_SANITIZE_ALL
393
void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
394
0
                                size_t n, bool StopAtZero) {
395
0
  if (!n) return;
396
0
  size_t Len = std::min(n, Word::GetMaxSize());
397
0
  const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
398
0
  const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
399
0
  uint8_t B1[Word::kMaxSize];
400
0
  uint8_t B2[Word::kMaxSize];
401
0
  // Copy the data into locals in this non-msan-instrumented function
402
0
  // to avoid msan complaining further.
403
0
  size_t Hash = 0;  // Compute some simple hash of both strings.
404
0
  for (size_t i = 0; i < Len; i++) {
405
0
    B1[i] = A1[i];
406
0
    B2[i] = A2[i];
407
0
    size_t T = B1[i];
408
0
    Hash ^= (T << 8) | B2[i];
409
0
  }
410
0
  size_t I = 0;
411
0
  for (; I < Len; I++)
412
0
    if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0))
413
0
      break;
414
0
  size_t PC = reinterpret_cast<size_t>(caller_pc);
415
0
  size_t Idx = (PC & 4095) | (I << 12);
416
0
  ValueProfileMap.AddValue(Idx);
417
0
  TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len));
418
0
}
419
420
template <class T>
421
ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
422
ATTRIBUTE_NO_SANITIZE_ALL
423
9.25G
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
424
9.25G
  uint64_t ArgXor = Arg1 ^ Arg2;
425
9.25G
  if (sizeof(T) == 4)
426
4.59G
      TORC4.Insert(ArgXor, Arg1, Arg2);
427
4.66G
  else if (sizeof(T) == 8)
428
1.48G
      TORC8.Insert(ArgXor, Arg1, Arg2);
429
9.25G
  uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64]
430
9.25G
  uint64_t AbsoluteDistance =
431
9.25G
      (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1);
432
9.25G
  ValueProfileMap.AddValue(PC * 128 + HammingDistance);
433
9.25G
  ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
434
9.25G
}
void fuzzer::TracePC::HandleCmp<unsigned long>(unsigned long, unsigned long, unsigned long)
Line
Count
Source
423
1.48G
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
424
1.48G
  uint64_t ArgXor = Arg1 ^ Arg2;
425
1.48G
  if (sizeof(T) == 4)
426
0
      TORC4.Insert(ArgXor, Arg1, Arg2);
427
1.48G
  else if (sizeof(T) == 8)
428
1.48G
      TORC8.Insert(ArgXor, Arg1, Arg2);
429
1.48G
  uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64]
430
1.48G
  uint64_t AbsoluteDistance =
431
1.48G
      (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1);
432
1.48G
  ValueProfileMap.AddValue(PC * 128 + HammingDistance);
433
1.48G
  ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
434
1.48G
}
void fuzzer::TracePC::HandleCmp<unsigned int>(unsigned long, unsigned int, unsigned int)
Line
Count
Source
423
4.59G
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
424
4.59G
  uint64_t ArgXor = Arg1 ^ Arg2;
425
4.59G
  if (sizeof(T) == 4)
426
4.59G
      TORC4.Insert(ArgXor, Arg1, Arg2);
427
18.4E
  else if (sizeof(T) == 8)
428
0
      TORC8.Insert(ArgXor, Arg1, Arg2);
429
4.59G
  uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64]
430
4.59G
  uint64_t AbsoluteDistance =
431
4.59G
      (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1);
432
4.59G
  ValueProfileMap.AddValue(PC * 128 + HammingDistance);
433
4.59G
  ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
434
4.59G
}
void fuzzer::TracePC::HandleCmp<unsigned short>(unsigned long, unsigned short, unsigned short)
Line
Count
Source
423
1.16G
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
424
1.16G
  uint64_t ArgXor = Arg1 ^ Arg2;
425
1.16G
  if (sizeof(T) == 4)
426
0
      TORC4.Insert(ArgXor, Arg1, Arg2);
427
1.16G
  else if (sizeof(T) == 8)
428
0
      TORC8.Insert(ArgXor, Arg1, Arg2);
429
1.16G
  uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64]
430
1.16G
  uint64_t AbsoluteDistance =
431
1.16G
      (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1);
432
1.16G
  ValueProfileMap.AddValue(PC * 128 + HammingDistance);
433
1.16G
  ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
434
1.16G
}
void fuzzer::TracePC::HandleCmp<unsigned char>(unsigned long, unsigned char, unsigned char)
Line
Count
Source
423
2.01G
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
424
2.01G
  uint64_t ArgXor = Arg1 ^ Arg2;
425
2.01G
  if (sizeof(T) == 4)
426
0
      TORC4.Insert(ArgXor, Arg1, Arg2);
427
2.01G
  else if (sizeof(T) == 8)
428
0
      TORC8.Insert(ArgXor, Arg1, Arg2);
429
2.01G
  uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64]
430
2.01G
  uint64_t AbsoluteDistance =
431
2.01G
      (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1);
432
2.01G
  ValueProfileMap.AddValue(PC * 128 + HammingDistance);
433
2.01G
  ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
434
2.01G
}
435
436
0
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
437
0
  size_t Len = 0;
438
0
  for (; Len < MaxLen && S[Len]; Len++) {}
439
0
  return Len;
440
0
}
441
442
// Finds min of (strlen(S1), strlen(S2)).
443
// Needed bacause one of these strings may actually be non-zero terminated.
444
0
static size_t InternalStrnlen2(const char *S1, const char *S2) {
445
0
  size_t Len = 0;
446
0
  for (; S1[Len] && S2[Len]; Len++)  {}
447
0
  return Len;
448
0
}
449
450
16.2k
void TracePC::ClearInlineCounters() {
451
32.4k
  for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
452
16.2k
    uint8_t *Beg = ModuleCounters[i].Start;
453
16.2k
    size_t Size = ModuleCounters[i].Stop - Beg;
454
16.2k
    memset(Beg, 0, Size);
455
16.2k
  }
456
16.2k
}
457
458
ATTRIBUTE_NO_SANITIZE_ALL
459
16.2k
void TracePC::RecordInitialStack() {
460
16.2k
  int stack;
461
16.2k
  __sancov_lowest_stack = InitialStack = reinterpret_cast<uintptr_t>(&stack);
462
16.2k
}
463
464
16.2k
uintptr_t TracePC::GetMaxStackOffset() const {
465
16.2k
  return InitialStack - __sancov_lowest_stack;  // Stack grows down
466
16.2k
}
467
468
} // namespace fuzzer
469
470
extern "C" {
471
ATTRIBUTE_INTERFACE
472
ATTRIBUTE_NO_SANITIZE_ALL
473
0
void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
474
0
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
475
0
  uint32_t Idx = *Guard;
476
0
  __sancov_trace_pc_pcs[Idx] = PC;
477
0
  __sancov_trace_pc_guard_8bit_counters[Idx]++;
478
0
}
479
480
// Best-effort support for -fsanitize-coverage=trace-pc, which is available
481
// in both Clang and GCC.
482
ATTRIBUTE_INTERFACE
483
ATTRIBUTE_NO_SANITIZE_ALL
484
0
void __sanitizer_cov_trace_pc() {
485
0
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
486
0
  uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1);
487
0
  __sancov_trace_pc_pcs[Idx] = PC;
488
0
  __sancov_trace_pc_guard_8bit_counters[Idx]++;
489
0
}
490
491
ATTRIBUTE_INTERFACE
492
0
void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
493
0
  fuzzer::TPC.HandleInit(Start, Stop);
494
0
}
495
496
ATTRIBUTE_INTERFACE
497
3
void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) {
498
3
  fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop);
499
3
}
500
501
ATTRIBUTE_INTERFACE
502
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
503
3
                              const uintptr_t *pcs_end) {
504
3
  fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end);
505
3
}
506
507
ATTRIBUTE_INTERFACE
508
ATTRIBUTE_NO_SANITIZE_ALL
509
265M
void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
510
265M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
511
265M
  fuzzer::TPC.HandleCallerCallee(PC, Callee);
512
265M
}
513
514
ATTRIBUTE_INTERFACE
515
ATTRIBUTE_NO_SANITIZE_ALL
516
ATTRIBUTE_TARGET_POPCNT
517
659M
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
518
659M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
519
659M
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
520
659M
}
521
522
ATTRIBUTE_INTERFACE
523
ATTRIBUTE_NO_SANITIZE_ALL
524
ATTRIBUTE_TARGET_POPCNT
525
// Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic
526
// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
527
// should be changed later to make full use of instrumentation.
528
828M
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
529
828M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
530
828M
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
531
828M
}
532
533
ATTRIBUTE_INTERFACE
534
ATTRIBUTE_NO_SANITIZE_ALL
535
ATTRIBUTE_TARGET_POPCNT
536
3.32G
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
537
3.32G
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
538
3.32G
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
539
3.32G
}
540
541
ATTRIBUTE_INTERFACE
542
ATTRIBUTE_NO_SANITIZE_ALL
543
ATTRIBUTE_TARGET_POPCNT
544
1.26G
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
545
1.26G
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
546
1.26G
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
547
1.26G
}
548
549
ATTRIBUTE_INTERFACE
550
ATTRIBUTE_NO_SANITIZE_ALL
551
ATTRIBUTE_TARGET_POPCNT
552
708M
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
553
708M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
554
708M
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
555
708M
}
556
557
ATTRIBUTE_INTERFACE
558
ATTRIBUTE_NO_SANITIZE_ALL
559
ATTRIBUTE_TARGET_POPCNT
560
452M
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
561
452M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
562
452M
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
563
452M
}
564
565
ATTRIBUTE_INTERFACE
566
ATTRIBUTE_NO_SANITIZE_ALL
567
ATTRIBUTE_TARGET_POPCNT
568
127M
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
569
127M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
570
127M
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
571
127M
}
572
573
ATTRIBUTE_INTERFACE
574
ATTRIBUTE_NO_SANITIZE_ALL
575
ATTRIBUTE_TARGET_POPCNT
576
1.88G
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
577
1.88G
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
578
1.88G
  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
579
1.88G
}
580
581
ATTRIBUTE_INTERFACE
582
ATTRIBUTE_NO_SANITIZE_ALL
583
ATTRIBUTE_TARGET_POPCNT
584
91.6M
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
585
91.6M
  uint64_t N = Cases[0];
586
91.6M
  uint64_t ValSizeInBits = Cases[1];
587
91.6M
  uint64_t *Vals = Cases + 2;
588
91.6M
  // Skip the most common and the most boring case.
589
91.6M
  if (Vals[N - 1]  < 256 && Val < 256)
590
88.7M
    return;
591
2.89M
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
592
2.89M
  size_t i;
593
2.89M
  uint64_t Token = 0;
594
11.1M
  for (i = 0; i < N; i++) {
595
9.57M
    Token = Val ^ Vals[i];
596
9.57M
    if (Val < Vals[i])
597
1.30M
      break;
598
9.57M
  }
599
2.89M
600
2.89M
  if (ValSizeInBits == 16)
601
1.30M
    fuzzer::TPC.HandleCmp(PC + i, static_cast<uint16_t>(Token), (uint16_t)(0));
602
1.59M
  else if (ValSizeInBits == 32)
603
1.59M
    fuzzer::TPC.HandleCmp(PC + i, static_cast<uint32_t>(Token), (uint32_t)(0));
604
0
  else
605
0
    fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0));
606
2.89M
}
607
608
ATTRIBUTE_INTERFACE
609
ATTRIBUTE_NO_SANITIZE_ALL
610
ATTRIBUTE_TARGET_POPCNT
611
0
void __sanitizer_cov_trace_div4(uint32_t Val) {
612
0
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
613
0
  fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
614
0
}
615
616
ATTRIBUTE_INTERFACE
617
ATTRIBUTE_NO_SANITIZE_ALL
618
ATTRIBUTE_TARGET_POPCNT
619
0
void __sanitizer_cov_trace_div8(uint64_t Val) {
620
0
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
621
0
  fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
622
0
}
623
624
ATTRIBUTE_INTERFACE
625
ATTRIBUTE_NO_SANITIZE_ALL
626
ATTRIBUTE_TARGET_POPCNT
627
0
void __sanitizer_cov_trace_gep(uintptr_t Idx) {
628
0
  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
629
0
  fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
630
0
}
631
632
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
633
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
634
0
                                  const void *s2, size_t n, int result) {
635
0
  if (!fuzzer::RunningUserCallback) return;
636
0
  if (result == 0) return;  // No reason to mutate.
637
0
  if (n <= 1) return;  // Not interesting.
638
0
  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
639
0
}
640
641
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
642
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
643
0
                                   const char *s2, size_t n, int result) {
644
0
  if (!fuzzer::RunningUserCallback) return;
645
0
  if (result == 0) return;  // No reason to mutate.
646
0
  size_t Len1 = fuzzer::InternalStrnlen(s1, n);
647
0
  size_t Len2 = fuzzer::InternalStrnlen(s2, n);
648
0
  n = std::min(n, Len1);
649
0
  n = std::min(n, Len2);
650
0
  if (n <= 1) return;  // Not interesting.
651
0
  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
652
0
}
653
654
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
655
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
656
0
                                   const char *s2, int result) {
657
0
  if (!fuzzer::RunningUserCallback) return;
658
0
  if (result == 0) return;  // No reason to mutate.
659
0
  size_t N = fuzzer::InternalStrnlen2(s1, s2);
660
0
  if (N <= 1) return;  // Not interesting.
661
0
  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
662
0
}
663
664
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
665
void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
666
0
                                       const char *s2, size_t n, int result) {
667
0
  if (!fuzzer::RunningUserCallback) return;
668
0
  return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
669
0
}
670
671
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
672
void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
673
0
                                      const char *s2, int result) {
674
0
  if (!fuzzer::RunningUserCallback) return;
675
0
  return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
676
0
}
677
678
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
679
void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
680
0
                                  const char *s2, char *result) {
681
0
  if (!fuzzer::RunningUserCallback) return;
682
0
  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
683
0
}
684
685
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
686
void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
687
0
                                      const char *s2, char *result) {
688
0
  if (!fuzzer::RunningUserCallback) return;
689
0
  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
690
0
}
691
692
ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
693
void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
694
0
                                  const void *s2, size_t len2, void *result) {
695
0
  if (!fuzzer::RunningUserCallback) return;
696
0
  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2);
697
0
}
698
}  // extern "C"