blob: 44149922a15effc80b1c8a888fbcf301a99a34ee [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 Serebryany86586182016-09-21 21:17:23 +000015#include "FuzzerDefs.h"
Kostya Serebryany6f5a8042016-09-21 01:50:50 +000016#include "FuzzerTracePC.h"
Kostya Serebryany86586182016-09-21 21:17:23 +000017#include "FuzzerValueBitMap.h"
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000018
19namespace fuzzer {
Mike Aizatsky1aa501e2016-05-10 23:43:15 +000020
Kostya Serebryanya00b2432016-09-14 02:13:06 +000021TracePC TPC;
Mike Aizatsky1aa501e2016-05-10 23:43:15 +000022
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000023void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) {
24 uint32_t Idx = *Guard;
Kostya Serebryany8e781a82016-09-18 04:52:23 +000025 if (!Idx) return;
Kostya Serebryany0800b812016-09-23 23:51:58 +000026 uint8_t *CounterPtr = &Counters[Idx % kNumCounters];
27 uint8_t Counter = *CounterPtr;
Kostya Serebryany87a598e2016-09-23 01:20:07 +000028 if (Counter == 0) {
Kostya Serebryany87a598e2016-09-23 01:20:07 +000029 if (!PCs[Idx]) {
Kostya Serebryany0800b812016-09-23 23:51:58 +000030 AddNewPCID(Idx);
Kostya Serebryany87a598e2016-09-23 01:20:07 +000031 TotalPCCoverage++;
32 PCs[Idx] = PC;
33 }
Kostya Serebryanya5277d52016-09-15 01:30:18 +000034 }
Kostya Serebryany0800b812016-09-23 23:51:58 +000035 if (UseCounters) {
36 if (Counter < 128)
37 *CounterPtr = Counter + 1;
38 else
39 *Guard = 0;
40 } else {
41 *CounterPtr = 1;
Kostya Serebryany87a598e2016-09-23 01:20:07 +000042 *Guard = 0;
Kostya Serebryany0800b812016-09-23 23:51:58 +000043 }
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000044}
Kostya Serebryanya5277d52016-09-15 01:30:18 +000045
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000046void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
Kostya Serebryany3e36ec12016-09-17 05:04:47 +000047 if (Start == Stop || *Start) return;
48 assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000049 for (uint32_t *P = Start; P < Stop; P++)
Kostya Serebryany8e781a82016-09-18 04:52:23 +000050 *P = ++NumGuards;
Kostya Serebryany3e36ec12016-09-17 05:04:47 +000051 Modules[NumModules].Start = Start;
52 Modules[NumModules].Stop = Stop;
53 NumModules++;
54}
55
56void TracePC::PrintModuleInfo() {
57 Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards);
58 for (size_t i = 0; i < NumModules; i++)
59 Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop);
60 Printf("\n");
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +000061}
Kostya Serebryanya5277d52016-09-15 01:30:18 +000062
Kostya Serebryanybc3789a2016-09-17 06:01:55 +000063void TracePC::ResetGuards() {
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000064 uint32_t N = 0;
Kostya Serebryanybc3789a2016-09-17 06:01:55 +000065 for (size_t M = 0; M < NumModules; M++)
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +000066 for (uint32_t *X = Modules[M].Start; X < Modules[M].Stop; X++)
Kostya Serebryany8e781a82016-09-18 04:52:23 +000067 *X = ++N;
68 assert(N == NumGuards);
Kostya Serebryanybc3789a2016-09-17 06:01:55 +000069}
70
Kostya Serebryanya5277d52016-09-15 01:30:18 +000071void TracePC::FinalizeTrace() {
Kostya Serebryany87a598e2016-09-23 01:20:07 +000072 if (TotalPCCoverage) {
Kostya Serebryany3ee6c212016-09-28 01:16:24 +000073 const size_t Step = 8;
74 assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
75 size_t N = Min(kNumCounters, NumGuards + 1);
76 N = (N + Step - 1) & ~(Step - 1); // Round up.
77 for (size_t Idx = 0; Idx < N; Idx += Step) {
78 uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]);
79 if (!Bundle) continue;
80 for (size_t i = Idx; i < Idx + Step; i++) {
81 uint8_t Counter = (Bundle >> (i * 8)) & 0xff;
82 if (!Counter) continue;
83 Counters[i] = 0;
84 unsigned Bit = 0;
85 /**/ if (Counter >= 128) Bit = 7;
86 else if (Counter >= 32) Bit = 6;
87 else if (Counter >= 16) Bit = 5;
88 else if (Counter >= 8) Bit = 4;
89 else if (Counter >= 4) Bit = 3;
90 else if (Counter >= 3) Bit = 2;
91 else if (Counter >= 2) Bit = 1;
92 CounterMap.AddValue(i * 8 + Bit);
93 }
Kostya Serebryanya5277d52016-09-15 01:30:18 +000094 }
95 }
96}
97
Kostya Serebryany09845172016-09-15 22:16:15 +000098void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
99 const uintptr_t kBits = 12;
100 const uintptr_t kMask = (1 << kBits) - 1;
101 CounterMap.AddValue((Caller & kMask) | ((Callee & kMask) << kBits));
102}
103
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000104void TracePC::PrintCoverage() {
105 Printf("COVERAGE:\n");
Kostya Serebryany5ff481f2016-09-27 00:10:20 +0000106 for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) {
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000107 if (PCs[i])
108 PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]);
109 }
110}
111
Kostya Serebryany0800b812016-09-23 23:51:58 +0000112
113void TracePC::UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize) {
114 if (!CurrentElementSize) return;
115 for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) {
116 if (!CounterMap.Get(Idx)) continue;
117 Feature &Fe = FeatureSet[Idx];
118 Fe.Count++;
119 if (!Fe.SmallestElementSize || Fe.SmallestElementSize > CurrentElementSize) {
120 Fe.SmallestElementIdx = CurrentElementIdx;
121 Fe.SmallestElementSize = CurrentElementSize;
122 }
123 }
124}
125
126void TracePC::PrintFeatureSet() {
127 Printf("[id: cnt idx sz] ");
128 for (size_t i = 0; i < kFeatureSetSize; i++) {
129 auto &Fe = FeatureSet[i];
130 if (!Fe.Count) continue;
131 Printf("[%zd: %zd %zd %zd] ", i, Fe.Count, Fe.SmallestElementIdx,
132 Fe.SmallestElementSize);
133 }
134 Printf("\n");
135}
136
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +0000137} // namespace fuzzer
138
Dan Liew59144072016-06-06 20:27:09 +0000139extern "C" {
Kostya Serebryany32661f92016-08-18 20:52:52 +0000140__attribute__((visibility("default")))
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +0000141void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
Kostya Serebryanya00b2432016-09-14 02:13:06 +0000142 uintptr_t PC = (uintptr_t)__builtin_return_address(0);
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000143 fuzzer::TPC.HandleTrace(Guard, PC);
Kostya Serebryanyda63c1d2016-02-26 21:33:56 +0000144}
Dan Liew59144072016-06-06 20:27:09 +0000145
Kostya Serebryany32661f92016-08-18 20:52:52 +0000146__attribute__((visibility("default")))
Kostya Serebryanya9b0dd02016-09-29 17:43:24 +0000147void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
Kostya Serebryanya5277d52016-09-15 01:30:18 +0000148 fuzzer::TPC.HandleInit(Start, Stop);
Dan Liew59144072016-06-06 20:27:09 +0000149}
Kostya Serebryany09845172016-09-15 22:16:15 +0000150
151__attribute__((visibility("default")))
152void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
153 uintptr_t PC = (uintptr_t)__builtin_return_address(0);
154 fuzzer::TPC.HandleCallerCallee(PC, Callee);
155}
Dan Liew59144072016-06-06 20:27:09 +0000156}