blob: aa5bd9b60877ea732d1cab0e0020b2d5210538f2 [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 Serebryany87a598e2016-09-23 01:20:07 +000030 if (!PCs[Idx]) {
Kostya Serebryany0800b812016-09-23 23:51:58 +000031 AddNewPCID(Idx);
Kostya Serebryany87a598e2016-09-23 01:20:07 +000032 TotalPCCoverage++;
33 PCs[Idx] = PC;
34 }
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 Serebryanya9b0dd02016-09-29 17:43:24 +000067 for (uint32_t *X = Modules[M].Start; X < Modules[M].Stop; 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
166ATTRIBUTE_TARGET_POPCNT
167static void AddValueForCmp(void *PCptr, uint64_t Arg1, uint64_t Arg2) {
Kostya Serebryany379359c2016-10-05 01:09:40 +0000168 uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
Kostya Serebryany1c73f1b2016-10-05 22:56:21 +0000169 uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) + 1; // [1,65]
170 uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance;
Kostya Serebryany379359c2016-10-05 01:09:40 +0000171 TPC.HandleValueProfile(Idx);
172}
173
174static void AddValueForSingleVal(void *PCptr, uintptr_t Val) {
175 if (!Val) return;
176 uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
177 uint64_t ArgDistance = __builtin_popcountl(Val) - 1; // [0,63]
178 uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
179 TPC.HandleValueProfile(Idx);
180}
181
182
183
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +0000184} // namespace fuzzer
185
Dan Liew59144072016-06-06 20:27:09 +0000186extern "C" {
Kostya Serebryany32661f92016-08-18 20:52:52 +0000187__attribute__((visibility("default")))
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +0000188void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
Kostya Serebryanya00b2432016-09-14 02:13:06 +0000189 uintptr_t PC = (uintptr_t)__builtin_return_address(0);
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000190 fuzzer::TPC.HandleTrace(Guard, PC);
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +0000191}
Dan Liew59144072016-06-06 20:27:09 +0000192
Kostya Serebryany32661f92016-08-18 20:52:52 +0000193__attribute__((visibility("default")))
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +0000194void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000195 fuzzer::TPC.HandleInit(Start, Stop);
Dan Liew59144072016-06-06 20:27:09 +0000196}
Kostya Serebryany09845172016-09-15 22:16:15 +0000197
198__attribute__((visibility("default")))
199void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
200 uintptr_t PC = (uintptr_t)__builtin_return_address(0);
201 fuzzer::TPC.HandleCallerCallee(PC, Callee);
202}
Kostya Serebryany379359c2016-10-05 01:09:40 +0000203
204// TODO: this one will not be used with the newest clang. Remove it.
205__attribute__((visibility("default")))
206void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
207 uint64_t Arg2) {
208 fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
Dan Liew59144072016-06-06 20:27:09 +0000209}
Kostya Serebryany379359c2016-10-05 01:09:40 +0000210
211__attribute__((visibility("default")))
212void __sanitizer_cov_trace_cmp8(uint64_t Arg1, int64_t Arg2) {
213 fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
214}
215__attribute__((visibility("default")))
216void __sanitizer_cov_trace_cmp4(uint32_t Arg1, int32_t Arg2) {
217 fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
218}
219__attribute__((visibility("default")))
220void __sanitizer_cov_trace_cmp2(uint16_t Arg1, int16_t Arg2) {
221 fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
222}
223__attribute__((visibility("default")))
224void __sanitizer_cov_trace_cmp1(uint8_t Arg1, int8_t Arg2) {
225 fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
226}
227
228__attribute__((visibility("default")))
229void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
230 // TODO(kcc): support value profile here.
231}
232
233__attribute__((visibility("default")))
234void __sanitizer_cov_trace_div4(uint32_t Val) {
235 fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
236}
237__attribute__((visibility("default")))
238void __sanitizer_cov_trace_div8(uint64_t Val) {
239 fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
240}
241__attribute__((visibility("default")))
242void __sanitizer_cov_trace_gep(uintptr_t Idx) {
243 fuzzer::AddValueForSingleVal(__builtin_return_address(0), Idx);
244}
245
246} // extern "C"