| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 1 | //===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===// | 
|  | 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 | // fuzzer::TracePC | 
|  | 10 | //===----------------------------------------------------------------------===// | 
|  | 11 |  | 
|  | 12 | #ifndef LLVM_FUZZER_TRACE_PC | 
|  | 13 | #define LLVM_FUZZER_TRACE_PC | 
|  | 14 |  | 
|  | 15 | #include "FuzzerDefs.h" | 
| Kostya Serebryany | 1d8c2ce | 2017-01-17 23:09:05 +0000 | [diff] [blame] | 16 | #include "FuzzerDictionary.h" | 
| Kostya Serebryany | 8658618 | 2016-09-21 21:17:23 +0000 | [diff] [blame] | 17 | #include "FuzzerValueBitMap.h" | 
| Kostya Serebryany | 1d8c2ce | 2017-01-17 23:09:05 +0000 | [diff] [blame] | 18 |  | 
| Marcos Pividori | 178fe58 | 2016-12-13 17:46:11 +0000 | [diff] [blame] | 19 | #include <set> | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 20 |  | 
|  | 21 | namespace fuzzer { | 
|  | 22 |  | 
| Kostya Serebryany | a5f94fb | 2016-10-14 20:20:33 +0000 | [diff] [blame] | 23 | // TableOfRecentCompares (TORC) remembers the most recently performed | 
|  | 24 | // comparisons of type T. | 
|  | 25 | // We record the arguments of CMP instructions in this table unconditionally | 
|  | 26 | // because it seems cheaper this way than to compute some expensive | 
|  | 27 | // conditions inside __sanitizer_cov_trace_cmp*. | 
|  | 28 | // After the unit has been executed we may decide to use the contents of | 
|  | 29 | // this table to populate a Dictionary. | 
|  | 30 | template<class T, size_t kSizeT> | 
|  | 31 | struct TableOfRecentCompares { | 
|  | 32 | static const size_t kSize = kSizeT; | 
| Kostya Serebryany | 3364f90 | 2016-10-25 02:04:43 +0000 | [diff] [blame] | 33 | struct Pair { | 
|  | 34 | T A, B; | 
|  | 35 | }; | 
| Kostya Serebryany | 7f05897 | 2017-01-27 00:09:59 +0000 | [diff] [blame] | 36 | ATTRIBUTE_NO_SANITIZE_ALL | 
| Kostya Serebryany | af2dfce | 2017-03-31 02:21:28 +0000 | [diff] [blame] | 37 | void Insert(size_t Idx, const T &Arg1, const T &Arg2) { | 
| Kostya Serebryany | a5f94fb | 2016-10-14 20:20:33 +0000 | [diff] [blame] | 38 | Idx = Idx % kSize; | 
| Kostya Serebryany | 3364f90 | 2016-10-25 02:04:43 +0000 | [diff] [blame] | 39 | Table[Idx].A = Arg1; | 
|  | 40 | Table[Idx].B = Arg2; | 
| Kostya Serebryany | a5f94fb | 2016-10-14 20:20:33 +0000 | [diff] [blame] | 41 | } | 
| Kostya Serebryany | 3364f90 | 2016-10-25 02:04:43 +0000 | [diff] [blame] | 42 |  | 
|  | 43 | Pair Get(size_t I) { return Table[I % kSize]; } | 
|  | 44 |  | 
|  | 45 | Pair Table[kSize]; | 
| Kostya Serebryany | a5f94fb | 2016-10-14 20:20:33 +0000 | [diff] [blame] | 46 | }; | 
|  | 47 |  | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 48 | class TracePC { | 
|  | 49 | public: | 
| Kostya Serebryany | 68382d0 | 2017-02-02 19:56:01 +0000 | [diff] [blame] | 50 | static const size_t kNumPCs = 1 << 21; | 
| Kostya Serebryany | d7d1d51 | 2017-03-30 01:27:20 +0000 | [diff] [blame] | 51 | // How many bits of PC are used from __sanitizer_cov_trace_pc. | 
|  | 52 | static const size_t kTracePcBits = 18; | 
| Kostya Serebryany | 2c55613 | 2016-09-30 01:19:56 +0000 | [diff] [blame] | 53 |  | 
| Kostya Serebryany | a9b0dd0 | 2016-09-29 17:43:24 +0000 | [diff] [blame] | 54 | void HandleInit(uint32_t *start, uint32_t *stop); | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 55 | void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); | 
| Mike Aizatsky | 0e37f8e | 2017-01-17 23:11:32 +0000 | [diff] [blame] | 56 | template <class T> void HandleCmp(uintptr_t PC, T Arg1, T Arg2); | 
| Kostya Serebryany | 275e260 | 2016-10-25 23:52:25 +0000 | [diff] [blame] | 57 | size_t GetTotalPCCoverage(); | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 58 | void SetUseCounters(bool UC) { UseCounters = UC; } | 
| Kostya Serebryany | ab73c69 | 2016-09-23 00:46:18 +0000 | [diff] [blame] | 59 | void SetUseValueProfile(bool VP) { UseValueProfile = VP; } | 
| Kostya Serebryany | a5b2e54 | 2016-10-26 00:20:51 +0000 | [diff] [blame] | 60 | void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } | 
| Kostya Serebryany | a617e16 | 2017-03-31 04:17:45 +0000 | [diff] [blame] | 61 | template <class Callback> void CollectFeatures(Callback CB) const; | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 62 |  | 
| Kostya Serebryany | ce1cab1 | 2016-09-23 02:18:59 +0000 | [diff] [blame] | 63 | void ResetMaps() { | 
| Kostya Serebryany | 16a145f | 2016-09-23 01:58:51 +0000 | [diff] [blame] | 64 | ValueProfileMap.Reset(); | 
| Kostya Serebryany | 68382d0 | 2017-02-02 19:56:01 +0000 | [diff] [blame] | 65 | memset(Counters(), 0, GetNumPCs()); | 
| Kostya Serebryany | 6ca44f9 | 2017-03-23 22:43:12 +0000 | [diff] [blame] | 66 | ClearExtraCounters(); | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 67 | } | 
|  | 68 |  | 
| Kostya Serebryany | 0800b81 | 2016-09-23 23:51:58 +0000 | [diff] [blame] | 69 | void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize); | 
|  | 70 | void PrintFeatureSet(); | 
|  | 71 |  | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 72 | void PrintModuleInfo(); | 
|  | 73 |  | 
|  | 74 | void PrintCoverage(); | 
| Mike Aizatsky | 9b415be | 2016-12-19 22:18:08 +0000 | [diff] [blame] | 75 | void DumpCoverage(); | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 76 |  | 
| Kostya Serebryany | 379359c | 2016-10-05 01:09:40 +0000 | [diff] [blame] | 77 | void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, | 
| Kostya Serebryany | 1d8c2ce | 2017-01-17 23:09:05 +0000 | [diff] [blame] | 78 | size_t n, bool StopAtZero); | 
| Kostya Serebryany | 379359c | 2016-10-05 01:09:40 +0000 | [diff] [blame] | 79 |  | 
| Kostya Serebryany | 1d8c2ce | 2017-01-17 23:09:05 +0000 | [diff] [blame] | 80 | TableOfRecentCompares<uint32_t, 32> TORC4; | 
|  | 81 | TableOfRecentCompares<uint64_t, 32> TORC8; | 
|  | 82 | TableOfRecentCompares<Word, 32> TORCW; | 
| Kostya Serebryany | a5f94fb | 2016-10-14 20:20:33 +0000 | [diff] [blame] | 83 |  | 
| Kostya Serebryany | a5b2e54 | 2016-10-26 00:20:51 +0000 | [diff] [blame] | 84 | void PrintNewPCs(); | 
| Kostya Serebryany | 11a22bc | 2016-12-30 01:13:07 +0000 | [diff] [blame] | 85 | void InitializePrintNewPCs(); | 
| Kostya Serebryany | d7d1d51 | 2017-03-30 01:27:20 +0000 | [diff] [blame] | 86 | size_t GetNumPCs() const { | 
|  | 87 | return NumGuards == 0 ? (1 << kTracePcBits) : Min(kNumPCs, NumGuards + 1); | 
|  | 88 | } | 
| Kostya Serebryany | 06b8757 | 2016-10-26 00:42:52 +0000 | [diff] [blame] | 89 | uintptr_t GetPC(size_t Idx) { | 
|  | 90 | assert(Idx < GetNumPCs()); | 
| Kostya Serebryany | 68382d0 | 2017-02-02 19:56:01 +0000 | [diff] [blame] | 91 | return PCs()[Idx]; | 
| Kostya Serebryany | 06b8757 | 2016-10-26 00:42:52 +0000 | [diff] [blame] | 92 | } | 
| Kostya Serebryany | a5b2e54 | 2016-10-26 00:20:51 +0000 | [diff] [blame] | 93 |  | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 94 | private: | 
|  | 95 | bool UseCounters = false; | 
| Kostya Serebryany | ab73c69 | 2016-09-23 00:46:18 +0000 | [diff] [blame] | 96 | bool UseValueProfile = false; | 
| Kostya Serebryany | a5b2e54 | 2016-10-26 00:20:51 +0000 | [diff] [blame] | 97 | bool DoPrintNewPCs = false; | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 98 |  | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 99 | struct Module { | 
| Kostya Serebryany | a9b0dd0 | 2016-09-29 17:43:24 +0000 | [diff] [blame] | 100 | uint32_t *Start, *Stop; | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 101 | }; | 
|  | 102 |  | 
|  | 103 | Module Modules[4096]; | 
| Kostya Serebryany | 2356791 | 2016-11-11 23:06:53 +0000 | [diff] [blame] | 104 | size_t NumModules;  // linker-initialized. | 
|  | 105 | size_t NumGuards;  // linker-initialized. | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 106 |  | 
| Kostya Serebryany | 68382d0 | 2017-02-02 19:56:01 +0000 | [diff] [blame] | 107 | uint8_t *Counters() const; | 
|  | 108 | uintptr_t *PCs() const; | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 109 |  | 
| Kostya Serebryany | a5b2e54 | 2016-10-26 00:20:51 +0000 | [diff] [blame] | 110 | std::set<uintptr_t> *PrintedPCs; | 
|  | 111 |  | 
| Kostya Serebryany | ab73c69 | 2016-09-23 00:46:18 +0000 | [diff] [blame] | 112 | ValueBitMap ValueProfileMap; | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 113 | }; | 
|  | 114 |  | 
| Kostya Serebryany | 6ca44f9 | 2017-03-23 22:43:12 +0000 | [diff] [blame] | 115 | template <class Callback> // void Callback(size_t Idx, uint8_t Value); | 
|  | 116 | ATTRIBUTE_NO_SANITIZE_ALL | 
|  | 117 | void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End, | 
|  | 118 | size_t FirstFeature, Callback Handle8bitCounter) { | 
|  | 119 | typedef uintptr_t LargeType; | 
|  | 120 | const size_t Step = sizeof(LargeType) / sizeof(uint8_t); | 
|  | 121 | assert(!(reinterpret_cast<uintptr_t>(Begin) % 64)); | 
|  | 122 | for (auto P = Begin; P < End; P += Step) | 
|  | 123 | if (LargeType Bundle = *reinterpret_cast<const LargeType *>(P)) | 
|  | 124 | for (size_t I = 0; I < Step; I++, Bundle >>= 8) | 
|  | 125 | if (uint8_t V = Bundle & 0xff) | 
|  | 126 | Handle8bitCounter(FirstFeature + P - Begin + I, V); | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | template <class Callback>  // bool Callback(size_t Feature) | 
|  | 130 | ATTRIBUTE_NO_SANITIZE_ALL | 
|  | 131 | __attribute__((noinline)) | 
| Kostya Serebryany | a617e16 | 2017-03-31 04:17:45 +0000 | [diff] [blame] | 132 | void TracePC::CollectFeatures(Callback HandleFeature) const { | 
| Kostya Serebryany | 68382d0 | 2017-02-02 19:56:01 +0000 | [diff] [blame] | 133 | uint8_t *Counters = this->Counters(); | 
| Kostya Serebryany | 7856fb3 | 2017-01-26 01:34:58 +0000 | [diff] [blame] | 134 | size_t N = GetNumPCs(); | 
| Kostya Serebryany | 6ca44f9 | 2017-03-23 22:43:12 +0000 | [diff] [blame] | 135 | auto Handle8bitCounter = [&](size_t Idx, uint8_t Counter) { | 
|  | 136 | assert(Counter); | 
|  | 137 | unsigned Bit = 0; | 
|  | 138 | /**/ if (Counter >= 128) Bit = 7; | 
|  | 139 | else if (Counter >= 32) Bit = 6; | 
|  | 140 | else if (Counter >= 16) Bit = 5; | 
|  | 141 | else if (Counter >= 8) Bit = 4; | 
|  | 142 | else if (Counter >= 4) Bit = 3; | 
|  | 143 | else if (Counter >= 3) Bit = 2; | 
|  | 144 | else if (Counter >= 2) Bit = 1; | 
| Kostya Serebryany | a617e16 | 2017-03-31 04:17:45 +0000 | [diff] [blame] | 145 | HandleFeature(Idx * 8 + Bit); | 
| Kostya Serebryany | 6ca44f9 | 2017-03-23 22:43:12 +0000 | [diff] [blame] | 146 | }; | 
|  | 147 |  | 
|  | 148 | ForEachNonZeroByte(Counters, Counters + N, 0, Handle8bitCounter); | 
|  | 149 | ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), N * 8, | 
|  | 150 | Handle8bitCounter); | 
|  | 151 |  | 
| Kostya Serebryany | fe1094b | 2016-12-05 23:35:22 +0000 | [diff] [blame] | 152 | if (UseValueProfile) | 
|  | 153 | ValueProfileMap.ForEach([&](size_t Idx) { | 
| Kostya Serebryany | a617e16 | 2017-03-31 04:17:45 +0000 | [diff] [blame] | 154 | HandleFeature(N * 8 + Idx); | 
| Kostya Serebryany | fe1094b | 2016-12-05 23:35:22 +0000 | [diff] [blame] | 155 | }); | 
| Kostya Serebryany | fe1094b | 2016-12-05 23:35:22 +0000 | [diff] [blame] | 156 | } | 
|  | 157 |  | 
| Kostya Serebryany | 6f5a804 | 2016-09-21 01:50:50 +0000 | [diff] [blame] | 158 | extern TracePC TPC; | 
|  | 159 |  | 
|  | 160 | }  // namespace fuzzer | 
|  | 161 |  | 
|  | 162 | #endif  // LLVM_FUZZER_TRACE_PC |