mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[libFuzzer] experimental support for Clang's coverage (fprofile-instr-generate), Linux-only
llvm-svn: 310771
This commit is contained in:
parent
03422abc5b
commit
a2bcec7132
@ -31,6 +31,7 @@ endif()
|
||||
|
||||
if (LIBFUZZER_ENABLE)
|
||||
add_library(LLVMFuzzerNoMainObjects OBJECT
|
||||
FuzzerClangCounters.cpp
|
||||
FuzzerCrossOver.cpp
|
||||
FuzzerDriver.cpp
|
||||
FuzzerExtFunctionsDlsym.cpp
|
||||
|
49
lib/Fuzzer/FuzzerClangCounters.cpp
Normal file
49
lib/Fuzzer/FuzzerClangCounters.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Coverage counters from Clang's SourceBasedCodeCoverage.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Support for SourceBasedCodeCoverage is experimental:
|
||||
// * Works only for the main binary, not DSOs yet.
|
||||
// * Works only on Linux.
|
||||
// * Does not implement print_pcs/print_coverage yet.
|
||||
// * Is not fully evaluated for performance and sensitivity.
|
||||
// We expect large performance drop due to 64-bit counters,
|
||||
// and *maybe* better sensitivity due to more fine-grained counters.
|
||||
// Preliminary comparison on a single benchmark (RE2) shows
|
||||
// a bit worse sensitivity though.
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
#if LIBFUZZER_LINUX
|
||||
__attribute__((weak)) extern uint64_t __start___llvm_prf_cnts;
|
||||
__attribute__((weak)) extern uint64_t __stop___llvm_prf_cnts;
|
||||
namespace fuzzer {
|
||||
uint64_t *ClangCountersBegin() { return &__start___llvm_prf_cnts; }
|
||||
uint64_t *ClangCountersEnd() { return &__stop___llvm_prf_cnts; }
|
||||
} // namespace fuzzer
|
||||
#else
|
||||
// TODO: Implement on Mac (if the data shows it's worth it).
|
||||
//__attribute__((visibility("hidden")))
|
||||
//extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts");
|
||||
//__attribute__((visibility("hidden")))
|
||||
//extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts");
|
||||
namespace fuzzer {
|
||||
uint64_t *ClangCountersBegin() { return nullptr; }
|
||||
uint64_t *ClangCountersEnd() { return nullptr; }
|
||||
} // namespace fuzzer
|
||||
#endif
|
||||
|
||||
namespace fuzzer {
|
||||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
void ClearClangCounters() { // hand-written memset, don't asan-ify.
|
||||
for (auto P = ClangCountersBegin(); P < ClangCountersEnd(); P++)
|
||||
*P = 0;
|
||||
}
|
||||
}
|
@ -123,6 +123,10 @@ uint8_t *ExtraCountersBegin();
|
||||
uint8_t *ExtraCountersEnd();
|
||||
void ClearExtraCounters();
|
||||
|
||||
uint64_t *ClangCountersBegin();
|
||||
uint64_t *ClangCountersEnd();
|
||||
void ClearClangCounters();
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_DEFS_H
|
||||
|
@ -126,6 +126,8 @@ void TracePC::PrintModuleInfo() {
|
||||
_Exit(1);
|
||||
}
|
||||
}
|
||||
if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin())
|
||||
Printf("INFO: %zd Clang Coverage Counters\n", NumClangCounters);
|
||||
}
|
||||
|
||||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
@ -137,13 +139,12 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
|
||||
}
|
||||
|
||||
void TracePC::UpdateObservedPCs() {
|
||||
auto Observe = [&](uintptr_t PC) {
|
||||
bool Inserted = ObservedPCs.insert(PC).second;
|
||||
if (Inserted && DoPrintNewPCs)
|
||||
PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1);
|
||||
};
|
||||
if (NumPCsInPCTables) {
|
||||
auto Observe = [&](uintptr_t PC) {
|
||||
bool Inserted = ObservedPCs.insert(PC).second;
|
||||
if (Inserted && DoPrintNewPCs)
|
||||
PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1);
|
||||
};
|
||||
|
||||
if (NumInline8bitCounters == NumPCsInPCTables) {
|
||||
for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
|
||||
uint8_t *Beg = ModuleCounters[i].Start;
|
||||
@ -167,6 +168,13 @@ void TracePC::UpdateObservedPCs() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (size_t NumClangCounters =
|
||||
ClangCountersEnd() - ClangCountersBegin()) {
|
||||
auto P = ClangCountersBegin();
|
||||
for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
|
||||
if (P[Idx])
|
||||
Observe((uintptr_t)Idx);
|
||||
}
|
||||
}
|
||||
|
||||
inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
|
||||
|
@ -91,6 +91,7 @@ class TracePC {
|
||||
memset(Counters(), 0, GetNumPCs());
|
||||
ClearExtraCounters();
|
||||
ClearInlineCounters();
|
||||
ClearClangCounters();
|
||||
}
|
||||
|
||||
void ClearInlineCounters();
|
||||
@ -196,14 +197,9 @@ void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End,
|
||||
Handle8bitCounter(FirstFeature, P - Begin, V);
|
||||
}
|
||||
|
||||
template <class Callback> // bool Callback(size_t Feature)
|
||||
ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
__attribute__((noinline))
|
||||
void TracePC::CollectFeatures(Callback HandleFeature) const {
|
||||
uint8_t *Counters = this->Counters();
|
||||
size_t N = GetNumPCs();
|
||||
auto Handle8bitCounter = [&](size_t FirstFeature,
|
||||
size_t Idx, uint8_t Counter) {
|
||||
// Given a non-zero Counters returns a number in [0,7].
|
||||
template<class T>
|
||||
unsigned CounterToFeature(T Counter) {
|
||||
assert(Counter);
|
||||
unsigned Bit = 0;
|
||||
/**/ if (Counter >= 128) Bit = 7;
|
||||
@ -213,7 +209,18 @@ void TracePC::CollectFeatures(Callback HandleFeature) const {
|
||||
else if (Counter >= 4) Bit = 3;
|
||||
else if (Counter >= 3) Bit = 2;
|
||||
else if (Counter >= 2) Bit = 1;
|
||||
HandleFeature(FirstFeature + Idx * 8 + Bit);
|
||||
return Bit;
|
||||
}
|
||||
|
||||
template <class Callback> // bool Callback(size_t Feature)
|
||||
ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
__attribute__((noinline))
|
||||
void TracePC::CollectFeatures(Callback HandleFeature) const {
|
||||
uint8_t *Counters = this->Counters();
|
||||
size_t N = GetNumPCs();
|
||||
auto Handle8bitCounter = [&](size_t FirstFeature,
|
||||
size_t Idx, uint8_t Counter) {
|
||||
HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Counter));
|
||||
};
|
||||
|
||||
size_t FirstFeature = 0;
|
||||
@ -231,6 +238,14 @@ void TracePC::CollectFeatures(Callback HandleFeature) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) {
|
||||
auto P = ClangCountersBegin();
|
||||
for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
|
||||
if (auto Cnt = P[Idx])
|
||||
HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Cnt));
|
||||
FirstFeature += NumClangCounters;
|
||||
}
|
||||
|
||||
ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature,
|
||||
Handle8bitCounter);
|
||||
FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8;
|
||||
|
7
lib/Fuzzer/test/fprofile-instr-generate.test
Normal file
7
lib/Fuzzer/test/fprofile-instr-generate.test
Normal file
@ -0,0 +1,7 @@
|
||||
# Test libFuzzer + -fprofile-instr-generate
|
||||
REQUIRES: linux
|
||||
RUN: %cpp_compiler %S/SimpleTest.cpp -fsanitize-coverage=0 -fprofile-instr-generate -o %t-SimpleTest-fprofile-instr-generate
|
||||
CHECK-NOT: INFO: Loaded 1 modules
|
||||
CHECK: INFO: {{.*}} Clang Coverage Counters
|
||||
CHECK: BINGO
|
||||
RUN: not %t-SimpleTest-fprofile-instr-generate -runs=1000000 -seed=1 2>&1 | FileCheck %s
|
Loading…
Reference in New Issue
Block a user