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, a callback required
11// for -fsanitize-coverage=trace-pc instrumentation.
12//
13//===----------------------------------------------------------------------===//
14
15#include "FuzzerInternal.h"
16
17namespace fuzzer {
18
19void PcCoverageMap::Reset() { memset(Map, 0, sizeof(Map)); }
20
21void PcCoverageMap::Update(uintptr_t Addr) {
22  uintptr_t Idx = Addr % kMapSizeInBits;
23  uintptr_t WordIdx = Idx / kBitsInWord;
24  uintptr_t BitIdx = Idx % kBitsInWord;
25  Map[WordIdx] |= 1UL << BitIdx;
26}
27
28size_t PcCoverageMap::MergeFrom(const PcCoverageMap &Other) {
29  uintptr_t Res = 0;
30  for (size_t i = 0; i < kMapSizeInWords; i++)
31    Res += __builtin_popcountl(Map[i] |= Other.Map[i]);
32  return Res;
33}
34
35static PcCoverageMap CurrentMap;
36static thread_local uintptr_t Prev;
37
38void PcMapResetCurrent() {
39  if (Prev) {
40    Prev = 0;
41    CurrentMap.Reset();
42  }
43}
44
45size_t PcMapMergeInto(PcCoverageMap *Map) {
46  if (!Prev)
47    return 0;
48  return Map->MergeFrom(CurrentMap);
49}
50
51static void HandlePC(uint32_t PC) {
52  // We take 12 bits of PC and mix it with the previous PCs.
53  uintptr_t Next = (Prev << 5) ^ (PC & 4095);
54  CurrentMap.Update(Next);
55  Prev = Next;
56}
57
58} // namespace fuzzer
59
60extern "C" {
61void __sanitizer_cov_trace_pc() {
62  fuzzer::HandlePC(static_cast<uint32_t>(
63      reinterpret_cast<uintptr_t>(__builtin_return_address(0))));
64}
65
66void __sanitizer_cov_trace_pc_indir(int *) {
67  // Stub to allow linking with code built with
68  // -fsanitize=indirect-calls,trace-pc.
69  // This isn't used currently.
70}
71}
72