blob: d843f542cdd4f21620683992fe345dad534de5a0 [file] [log] [blame]
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +00001//===- 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.
Kostya Serebryanya00b2432016-09-14 02:13:06 +000010// This module implements __sanitizer_cov_trace_pc_guard[_init],
11// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000012//
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000013//===----------------------------------------------------------------------===//
14
Kostya Serebryany1c73f1b2016-10-05 22:56:21 +000015#include "FuzzerCorpus.h"
Kostya Serebryany86586182016-09-21 21:17:23 +000016#include "FuzzerDefs.h"
Kostya Serebryany6f5a8042016-09-21 01:50:50 +000017#include "FuzzerTracePC.h"
Kostya Serebryany86586182016-09-21 21:17:23 +000018#include "FuzzerValueBitMap.h"
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000019
20namespace fuzzer {
Mike Aizatsky1aa501e2016-05-10 23:43:15 +000021
Kostya Serebryanya00b2432016-09-14 02:13:06 +000022TracePC TPC;
Mike Aizatsky1aa501e2016-05-10 23:43:15 +000023
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000024void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) {
25 uint32_t Idx = *Guard;
Kostya Serebryany8e781a82016-09-18 04:52:23 +000026 if (!Idx) return;
Kostya Serebryany0800b812016-09-23 23:51:58 +000027 uint8_t *CounterPtr = &Counters[Idx % kNumCounters];
28 uint8_t Counter = *CounterPtr;
Kostya Serebryany87a598e2016-09-23 01:20:07 +000029 if (Counter == 0) {
Kostya Serebryanyd19919a2016-10-11 01:14:41 +000030 if (!PCs[Idx % kNumPCs]) {
Kostya Serebryany0800b812016-09-23 23:51:58 +000031 AddNewPCID(Idx);
Kostya Serebryany87a598e2016-09-23 01:20:07 +000032 TotalPCCoverage++;
Kostya Serebryanyd19919a2016-10-11 01:14:41 +000033 PCs[Idx % kNumPCs] = PC;
Kostya Serebryany87a598e2016-09-23 01:20:07 +000034 }
Kostya Serebryanya5277d52016-09-15 01:30:18 +000035 }
Kostya Serebryany0800b812016-09-23 23:51:58 +000036 if (UseCounters) {
37 if (Counter < 128)
38 *CounterPtr = Counter + 1;
39 else
40 *Guard = 0;
41 } else {
42 *CounterPtr = 1;
Kostya Serebryany87a598e2016-09-23 01:20:07 +000043 *Guard = 0;
Kostya Serebryany0800b812016-09-23 23:51:58 +000044 }
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000045}
Kostya Serebryanya5277d52016-09-15 01:30:18 +000046
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000047void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
Kostya Serebryany3e36ec12016-09-17 05:04:47 +000048 if (Start == Stop || *Start) return;
49 assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000050 for (uint32_t *P = Start; P < Stop; P++)
Kostya Serebryany8e781a82016-09-18 04:52:23 +000051 *P = ++NumGuards;
Kostya Serebryany3e36ec12016-09-17 05:04:47 +000052 Modules[NumModules].Start = Start;
53 Modules[NumModules].Stop = Stop;
54 NumModules++;
55}
56
57void TracePC::PrintModuleInfo() {
58 Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards);
59 for (size_t i = 0; i < NumModules; i++)
60 Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop);
61 Printf("\n");
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000062}
Kostya Serebryanya5277d52016-09-15 01:30:18 +000063
Kostya Serebryanybc3789a2016-09-17 06:01:55 +000064void TracePC::ResetGuards() {
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000065 uint32_t N = 0;
Kostya Serebryanybc3789a2016-09-17 06:01:55 +000066 for (size_t M = 0; M < NumModules; M++)
Kostya Serebryany17d176e12016-10-13 16:19:09 +000067 for (uint32_t *X = Modules[M].Start, *End = Modules[M].Stop; X < End; X++)
Kostya Serebryany8e781a82016-09-18 04:52:23 +000068 *X = ++N;
69 assert(N == NumGuards);
Kostya Serebryanybc3789a2016-09-17 06:01:55 +000070}
71
Kostya Serebryany1c73f1b2016-10-05 22:56:21 +000072size_t TracePC::FinalizeTrace(InputCorpus *C, size_t InputSize, bool Shrink) {
73 if (!UsingTracePcGuard()) return 0;
74 size_t Res = 0;
75 const size_t Step = 8;
76 assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
77 size_t N = Min(kNumCounters, NumGuards + 1);
78 N = (N + Step - 1) & ~(Step - 1); // Round up.
79 for (size_t Idx = 0; Idx < N; Idx += Step) {
80 uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]);
81 if (!Bundle) continue;
82 for (size_t i = Idx; i < Idx + Step; i++) {
83 uint8_t Counter = (Bundle >> (i * 8)) & 0xff;
84 if (!Counter) continue;
85 Counters[i] = 0;
86 unsigned Bit = 0;
87 /**/ if (Counter >= 128) Bit = 7;
88 else if (Counter >= 32) Bit = 6;
89 else if (Counter >= 16) Bit = 5;
90 else if (Counter >= 8) Bit = 4;
91 else if (Counter >= 4) Bit = 3;
92 else if (Counter >= 3) Bit = 2;
93 else if (Counter >= 2) Bit = 1;
94 size_t Feature = (i * 8 + Bit);
95 if (C->AddFeature(Feature, InputSize, Shrink))
96 Res++;
Kostya Serebryanya5277d52016-09-15 01:30:18 +000097 }
98 }
Kostya Serebryany1c73f1b2016-10-05 22:56:21 +000099 if (UseValueProfile)
100 ValueProfileMap.ForEach([&](size_t Idx) {
101 if (C->AddFeature(NumGuards + Idx, InputSize, Shrink))
102 Res++;
103 });
Kostya Serebryanyd2169222016-10-01 01:04:29 +0000104 return Res;
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000105}
106
Kostya Serebryany09845172016-09-15 22:16:15 +0000107void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
108 const uintptr_t kBits = 12;
109 const uintptr_t kMask = (1 << kBits) - 1;
Kostya Serebryany1c73f1b2016-10-05 22:56:21 +0000110 uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
111 HandleValueProfile(Idx);
Kostya Serebryany09845172016-09-15 22:16:15 +0000112}
113
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000114void TracePC::PrintCoverage() {
115 Printf("COVERAGE:\n");
Kostya Serebryany5ff481f2016-09-27 00:10:20 +0000116 for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) {
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000117 if (PCs[i])
118 PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]);
119 }
120}
121
Kostya Serebryany379359c2016-10-05 01:09:40 +0000122// Value profile.
123// We keep track of various values that affect control flow.
124// These values are inserted into a bit-set-based hash map.
125// Every new bit in the map is treated as a new coverage.
126//
127// For memcmp/strcmp/etc the interesting value is the length of the common
128// prefix of the parameters.
129// For cmp instructions the interesting value is a XOR of the parameters.
130// The interesting value is mixed up with the PC and is then added to the map.
131
132void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
133 size_t n) {
134 if (!n) return;
135 size_t Len = std::min(n, (size_t)32);
136 const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
137 const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
138 size_t I = 0;
139 for (; I < Len; I++)
140 if (A1[I] != A2[I])
141 break;
142 size_t PC = reinterpret_cast<size_t>(caller_pc);
143 size_t Idx = I;
144 // if (I < Len)
145 // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
146 TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
147}
148
149void TracePC::AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
150 size_t n) {
151 if (!n) return;
152 size_t Len = std::min(n, (size_t)32);
153 const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
154 const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
155 size_t I = 0;
156 for (; I < Len; I++)
157 if (A1[I] != A2[I] || A1[I] == 0)
158 break;
159 size_t PC = reinterpret_cast<size_t>(caller_pc);
160 size_t Idx = I;
161 // if (I < Len && A1[I])
162 // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
163 TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
164}
165
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000166template <class T>
Kostya Serebryany379359c2016-10-05 01:09:40 +0000167ATTRIBUTE_TARGET_POPCNT
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000168#ifdef __clang__ // g++ can't handle this __attribute__ here :(
169__attribute__((always_inline))
170#endif // __clang__
171void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) {
172 uintptr_t PCuint = reinterpret_cast<uintptr_t>(PC);
Kostya Serebryany1c73f1b2016-10-05 22:56:21 +0000173 uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) + 1; // [1,65]
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000174 uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance;
175 HandleValueProfile(Idx);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000176}
177
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +0000178} // namespace fuzzer
179
Dan Liew59144072016-06-06 20:27:09 +0000180extern "C" {
Kostya Serebryany32661f92016-08-18 20:52:52 +0000181__attribute__((visibility("default")))
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +0000182void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
Kostya Serebryanya00b2432016-09-14 02:13:06 +0000183 uintptr_t PC = (uintptr_t)__builtin_return_address(0);
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000184 fuzzer::TPC.HandleTrace(Guard, PC);
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +0000185}
Dan Liew59144072016-06-06 20:27:09 +0000186
Kostya Serebryany32661f92016-08-18 20:52:52 +0000187__attribute__((visibility("default")))
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +0000188void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000189 fuzzer::TPC.HandleInit(Start, Stop);
Dan Liew59144072016-06-06 20:27:09 +0000190}
Kostya Serebryany09845172016-09-15 22:16:15 +0000191
192__attribute__((visibility("default")))
193void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
194 uintptr_t PC = (uintptr_t)__builtin_return_address(0);
195 fuzzer::TPC.HandleCallerCallee(PC, Callee);
196}
Kostya Serebryany379359c2016-10-05 01:09:40 +0000197
Kostya Serebryany379359c2016-10-05 01:09:40 +0000198__attribute__((visibility("default")))
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000199void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
200 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000201}
202__attribute__((visibility("default")))
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000203void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
204 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000205}
206__attribute__((visibility("default")))
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000207void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
208 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000209}
210__attribute__((visibility("default")))
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000211void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
212 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000213}
214
215__attribute__((visibility("default")))
216void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
Kostya Serebryanyd19919a2016-10-11 01:14:41 +0000217 uint64_t N = Cases[0];
218 uint64_t *Vals = Cases + 2;
219 char *PC = (char*)__builtin_return_address(0);
220 for (size_t i = 0; i < N; i++)
221 if (Val != Vals[i])
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000222 fuzzer::TPC.HandleCmp(PC + i, Val, Vals[i]);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000223}
224
225__attribute__((visibility("default")))
226void __sanitizer_cov_trace_div4(uint32_t Val) {
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000227 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint32_t)0);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000228}
229__attribute__((visibility("default")))
230void __sanitizer_cov_trace_div8(uint64_t Val) {
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000231 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint64_t)0);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000232}
233__attribute__((visibility("default")))
234void __sanitizer_cov_trace_gep(uintptr_t Idx) {
Kostya Serebryany17d176e12016-10-13 16:19:09 +0000235 fuzzer::TPC.HandleCmp(__builtin_return_address(0), Idx, (uintptr_t)0);
Kostya Serebryany379359c2016-10-05 01:09:40 +0000236}
237
238} // extern "C"