OSDN Git Service

Sort the remaining #include lines in include/... and lib/....
[android-x86/external-llvm.git] / lib / Fuzzer / FuzzerTracePC.cpp
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 <map>
24 #include <set>
25 #include <sstream>
26
27 // The coverage counters and PCs.
28 // These are declared as global variables named "__sancov_*" to simplify
29 // experiments with inlined instrumentation.
30 alignas(64) ATTRIBUTE_INTERFACE
31 uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs];
32
33 ATTRIBUTE_INTERFACE
34 uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
35
36 namespace fuzzer {
37
38 TracePC TPC;
39
40 uint8_t *TracePC::Counters() const {
41   return __sancov_trace_pc_guard_8bit_counters;
42 }
43
44 uintptr_t *TracePC::PCs() const {
45   return __sancov_trace_pc_pcs;
46 }
47
48 size_t TracePC::GetTotalPCCoverage() {
49   size_t Res = 0;
50   for (size_t i = 1, N = GetNumPCs(); i < N; i++)
51     if (PCs()[i])
52       Res++;
53   return Res;
54 }
55
56 void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
57   if (Start == Stop || *Start) return;
58   assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
59   for (uint32_t *P = Start; P < Stop; P++) {
60     NumGuards++;
61     if (NumGuards == kNumPCs) {
62       RawPrint(
63           "WARNING: The binary has too many instrumented PCs.\n"
64           "         You may want to reduce the size of the binary\n"
65           "         for more efficient fuzzing and precise coverage data\n");
66     }
67     *P = NumGuards % kNumPCs;
68   }
69   Modules[NumModules].Start = Start;
70   Modules[NumModules].Stop = Stop;
71   NumModules++;
72 }
73
74 void TracePC::PrintModuleInfo() {
75   Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards);
76   for (size_t i = 0; i < NumModules; i++)
77     Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop);
78   Printf("\n");
79 }
80
81 ATTRIBUTE_NO_SANITIZE_ALL
82 void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
83   const uintptr_t kBits = 12;
84   const uintptr_t kMask = (1 << kBits) - 1;
85   uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
86   ValueProfileMap.AddValueModPrime(Idx);
87 }
88
89 void TracePC::InitializePrintNewPCs() {
90   if (!DoPrintNewPCs) return;
91   assert(!PrintedPCs);
92   PrintedPCs = new std::set<uintptr_t>;
93   for (size_t i = 1; i < GetNumPCs(); i++)
94     if (PCs()[i])
95       PrintedPCs->insert(PCs()[i]);
96 }
97
98 void TracePC::PrintNewPCs() {
99   if (!DoPrintNewPCs) return;
100   assert(PrintedPCs);
101   for (size_t i = 1; i < GetNumPCs(); i++)
102     if (PCs()[i] && PrintedPCs->insert(PCs()[i]).second)
103       PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PCs()[i]);
104 }
105
106 void TracePC::PrintCoverage() {
107   if (!EF->__sanitizer_symbolize_pc ||
108       !EF->__sanitizer_get_module_and_offset_for_pc) {
109     Printf("INFO: __sanitizer_symbolize_pc or "
110            "__sanitizer_get_module_and_offset_for_pc is not available,"
111            " not printing coverage\n");
112     return;
113   }
114   std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule;
115   std::map<std::string, uintptr_t> ModuleOffsets;
116   std::set<std::string> CoveredDirs, CoveredFiles, CoveredFunctions,
117       CoveredLines;
118   Printf("COVERAGE:\n");
119   for (size_t i = 1; i < GetNumPCs(); i++) {
120     uintptr_t PC = PCs()[i];
121     if (!PC) continue;
122     std::string FileStr = DescribePC("%s", PC);
123     if (!IsInterestingCoverageFile(FileStr)) continue;
124     std::string FixedPCStr = DescribePC("%p", PC);
125     std::string FunctionStr = DescribePC("%F", PC);
126     std::string LineStr = DescribePC("%l", PC);
127     char ModulePathRaw[4096] = "";  // What's PATH_MAX in portable C++?
128     void *OffsetRaw = nullptr;
129     if (!EF->__sanitizer_get_module_and_offset_for_pc(
130             reinterpret_cast<void *>(PC), ModulePathRaw,
131             sizeof(ModulePathRaw), &OffsetRaw))
132       continue;
133     std::string Module = ModulePathRaw;
134     uintptr_t FixedPC = std::stoull(FixedPCStr, 0, 16);
135     uintptr_t PcOffset = reinterpret_cast<uintptr_t>(OffsetRaw);
136     ModuleOffsets[Module] = FixedPC - PcOffset;
137     CoveredPCsPerModule[Module].push_back(PcOffset);
138     CoveredFunctions.insert(FunctionStr);
139     CoveredFiles.insert(FileStr);
140     CoveredDirs.insert(DirName(FileStr));
141     if (!CoveredLines.insert(FileStr + ":" + LineStr).second)
142       continue;
143     Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(),
144            FileStr.c_str(), LineStr.c_str());
145   }
146
147   std::string CoveredDirsStr;
148   for (auto &Dir : CoveredDirs) {
149     if (!CoveredDirsStr.empty())
150       CoveredDirsStr += ",";
151     CoveredDirsStr += Dir;
152   }
153   Printf("COVERED_DIRS: %s\n", CoveredDirsStr.c_str());
154
155   for (auto &M : CoveredPCsPerModule) {
156     std::set<std::string> UncoveredFiles, UncoveredFunctions;
157     std::map<std::string, std::set<int> > UncoveredLines;  // Func+File => lines
158     auto &ModuleName = M.first;
159     auto &CoveredOffsets = M.second;
160     uintptr_t ModuleOffset = ModuleOffsets[ModuleName];
161     std::sort(CoveredOffsets.begin(), CoveredOffsets.end());
162     Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str());
163     // sancov does not yet fully support DSOs.
164     // std::string Cmd = "sancov -print-coverage-pcs " + ModuleName;
165     std::string Cmd = DisassembleCmd(ModuleName) + " | " +
166         SearchRegexCmd("call.*__sanitizer_cov_trace_pc_guard");
167     std::string SanCovOutput;
168     if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) {
169       Printf("INFO: Command failed: %s\n", Cmd.c_str());
170       continue;
171     }
172     std::istringstream ISS(SanCovOutput);
173     std::string S;
174     while (std::getline(ISS, S, '\n')) {
175       size_t PcOffsetEnd = S.find(':');
176       if (PcOffsetEnd == std::string::npos)
177         continue;
178       S.resize(PcOffsetEnd);
179       uintptr_t PcOffset = std::stoull(S, 0, 16);
180       if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(),
181                               PcOffset)) {
182         uintptr_t PC = ModuleOffset + PcOffset;
183         auto FileStr = DescribePC("%s", PC);
184         if (!IsInterestingCoverageFile(FileStr)) continue;
185         if (CoveredFiles.count(FileStr) == 0) {
186           UncoveredFiles.insert(FileStr);
187           continue;
188         }
189         auto FunctionStr = DescribePC("%F", PC);
190         if (CoveredFunctions.count(FunctionStr) == 0) {
191           UncoveredFunctions.insert(FunctionStr);
192           continue;
193         }
194         std::string LineStr = DescribePC("%l", PC);
195         uintptr_t Line = std::stoi(LineStr);
196         std::string FileLineStr = FileStr + ":" + LineStr;
197         if (CoveredLines.count(FileLineStr) == 0)
198           UncoveredLines[FunctionStr + " " + FileStr].insert(Line);
199       }
200     }
201     for (auto &FileLine: UncoveredLines)
202       for (int Line : FileLine.second)
203         Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line);
204     for (auto &Func : UncoveredFunctions)
205       Printf("UNCOVERED_FUNC: %s\n", Func.c_str());
206     for (auto &File : UncoveredFiles)
207       Printf("UNCOVERED_FILE: %s\n", File.c_str());
208   }
209 }
210
211 inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
212   // TODO: this implementation is x86 only.
213   // see sanitizer_common GetPreviousInstructionPc for full implementation.
214   return PC - 1;
215 }
216
217 void TracePC::DumpCoverage() {
218   if (EF->__sanitizer_dump_coverage) {
219     std::vector<uintptr_t> PCsCopy(GetNumPCs());
220     for (size_t i = 0; i < GetNumPCs(); i++)
221       PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0;
222     EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size());
223   }
224 }
225
226 // Value profile.
227 // We keep track of various values that affect control flow.
228 // These values are inserted into a bit-set-based hash map.
229 // Every new bit in the map is treated as a new coverage.
230 //
231 // For memcmp/strcmp/etc the interesting value is the length of the common
232 // prefix of the parameters.
233 // For cmp instructions the interesting value is a XOR of the parameters.
234 // The interesting value is mixed up with the PC and is then added to the map.
235
236 ATTRIBUTE_NO_SANITIZE_ALL
237 void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
238                                 size_t n, bool StopAtZero) {
239   if (!n) return;
240   size_t Len = std::min(n, Word::GetMaxSize());
241   const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
242   const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
243   uint8_t B1[Word::kMaxSize];
244   uint8_t B2[Word::kMaxSize];
245   // Copy the data into locals in this non-msan-instrumented function
246   // to avoid msan complaining further.
247   size_t Hash = 0;  // Compute some simple hash of both strings.
248   for (size_t i = 0; i < Len; i++) {
249     B1[i] = A1[i];
250     B2[i] = A2[i];
251     size_t T = B1[i];
252     Hash ^= (T << 8) | B2[i];
253   }
254   size_t I = 0;
255   for (; I < Len; I++)
256     if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0))
257       break;
258   size_t PC = reinterpret_cast<size_t>(caller_pc);
259   size_t Idx = (PC & 4095) | (I << 12);
260   ValueProfileMap.AddValue(Idx);
261   TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len));
262 }
263
264 template <class T>
265 ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
266 ATTRIBUTE_NO_SANITIZE_ALL
267 void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
268   uint64_t ArgXor = Arg1 ^ Arg2;
269   uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65]
270   uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance;
271   if (sizeof(T) == 4)
272       TORC4.Insert(ArgXor, Arg1, Arg2);
273   else if (sizeof(T) == 8)
274       TORC8.Insert(ArgXor, Arg1, Arg2);
275   ValueProfileMap.AddValue(Idx);
276 }
277
278 } // namespace fuzzer
279
280 extern "C" {
281 ATTRIBUTE_INTERFACE
282 ATTRIBUTE_NO_SANITIZE_ALL
283 void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
284   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
285   uint32_t Idx = *Guard;
286   __sancov_trace_pc_pcs[Idx] = PC;
287   __sancov_trace_pc_guard_8bit_counters[Idx]++;
288 }
289
290 // Best-effort support for -fsanitize-coverage=trace-pc, which is available
291 // in both Clang and GCC.
292 ATTRIBUTE_INTERFACE
293 ATTRIBUTE_NO_SANITIZE_ALL
294 void __sanitizer_cov_trace_pc() {
295   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
296   uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1);
297   __sancov_trace_pc_pcs[Idx] = PC;
298   __sancov_trace_pc_guard_8bit_counters[Idx]++;
299 }
300
301 ATTRIBUTE_INTERFACE
302 void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
303   fuzzer::TPC.HandleInit(Start, Stop);
304 }
305
306 ATTRIBUTE_INTERFACE
307 ATTRIBUTE_NO_SANITIZE_ALL
308 void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
309   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
310   fuzzer::TPC.HandleCallerCallee(PC, Callee);
311 }
312
313 ATTRIBUTE_INTERFACE
314 ATTRIBUTE_NO_SANITIZE_ALL
315 ATTRIBUTE_TARGET_POPCNT
316 void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
317   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
318   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
319 }
320
321 ATTRIBUTE_INTERFACE
322 ATTRIBUTE_NO_SANITIZE_ALL
323 ATTRIBUTE_TARGET_POPCNT
324 void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
325   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
326   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
327 }
328
329 ATTRIBUTE_INTERFACE
330 ATTRIBUTE_NO_SANITIZE_ALL
331 ATTRIBUTE_TARGET_POPCNT
332 void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
333   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
334   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
335 }
336
337 ATTRIBUTE_INTERFACE
338 ATTRIBUTE_NO_SANITIZE_ALL
339 ATTRIBUTE_TARGET_POPCNT
340 void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
341   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
342   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
343 }
344
345 ATTRIBUTE_INTERFACE
346 ATTRIBUTE_NO_SANITIZE_ALL
347 ATTRIBUTE_TARGET_POPCNT
348 void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
349   uint64_t N = Cases[0];
350   uint64_t ValSizeInBits = Cases[1];
351   uint64_t *Vals = Cases + 2;
352   // Skip the most common and the most boring case.
353   if (Vals[N - 1]  < 256 && Val < 256)
354     return;
355   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
356   size_t i;
357   uint64_t Token = 0;
358   for (i = 0; i < N; i++) {
359     Token = Val ^ Vals[i];
360     if (Val < Vals[i])
361       break;
362   }
363
364   if (ValSizeInBits == 16)
365     fuzzer::TPC.HandleCmp(PC + i, static_cast<uint16_t>(Token), (uint16_t)(0));
366   else if (ValSizeInBits == 32)
367     fuzzer::TPC.HandleCmp(PC + i, static_cast<uint32_t>(Token), (uint32_t)(0));
368   else
369     fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0));
370 }
371
372 ATTRIBUTE_INTERFACE
373 ATTRIBUTE_NO_SANITIZE_ALL
374 ATTRIBUTE_TARGET_POPCNT
375 void __sanitizer_cov_trace_div4(uint32_t Val) {
376   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
377   fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
378 }
379
380 ATTRIBUTE_INTERFACE
381 ATTRIBUTE_NO_SANITIZE_ALL
382 ATTRIBUTE_TARGET_POPCNT
383 void __sanitizer_cov_trace_div8(uint64_t Val) {
384   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
385   fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
386 }
387
388 ATTRIBUTE_INTERFACE
389 ATTRIBUTE_NO_SANITIZE_ALL
390 ATTRIBUTE_TARGET_POPCNT
391 void __sanitizer_cov_trace_gep(uintptr_t Idx) {
392   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
393   fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
394 }
395 }  // extern "C"