[sanitizer-coverage] extend fsanitize-coverage=pc-table with flags for every PC

llvm-svn: 311794
This commit is contained in:
Kostya Serebryany 2017-08-25 19:29:47 +00:00
parent 50a446ef10
commit d3e4b7e24a
7 changed files with 58 additions and 36 deletions

View File

@ -148,19 +148,21 @@ With ``-fsanitize-coverage=pc-table`` the compiler will create a table of
instrumented PCs. Requires either ``-fsanitize-coverage=inline-8bit-counters`` or
``-fsanitize-coverage=trace-pc-guard``.
Users need to implement a single function to capture the counters at startup:
Users need to implement a single function to capture the PC table at startup:
.. code-block:: c++
extern "C"
void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg,
const uint8_t *pcs_end) {
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
const uintptr_t *pcs_end) {
// [pcs_beg,pcs_end) is the array of ptr-sized integers representing
// PCs of the instrumented blocks in the current DSO.
// Capture this array in order to read the PCs.
// The number of PCs for a given DSO is the same as the number of
// 8-bit counters (-fsanitize-coverage=inline-8bit-counters) or
// pairs [PC,PCFlags] for every instrumented block in the current DSO.
// Capture this array in order to read the PCs and their Flags.
// The number of PCs and PCFlags for a given DSO is the same as the number
// of 8-bit counters (-fsanitize-coverage=inline-8bit-counters) or
// trace_pc_guard callbacks (-fsanitize-coverage=trace-pc-guard)
// A PCFlags describes the basic block:
// * bit0: 1 if the block is the function entry block, 0 otherwise.
}

View File

@ -70,9 +70,9 @@ void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
NumInline8bitCounters += Stop - Start;
}
void TracePC::HandlePCsInit(const uint8_t *Start, const uint8_t *Stop) {
const uintptr_t *B = reinterpret_cast<const uintptr_t *>(Start);
const uintptr_t *E = reinterpret_cast<const uintptr_t *>(Stop);
void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0]));
ModulePCTable[NumPCTables++] = {B, E};
@ -157,7 +157,7 @@ void TracePC::UpdateObservedPCs() {
(size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
for (size_t j = 0; j < Size; j++)
if (Beg[j])
Observe(ModulePCTable[i].Start[j]);
Observe(ModulePCTable[i].Start[j].PC);
}
} else if (NumGuards == NumPCsInPCTables) {
size_t GuardIdx = 1;
@ -168,7 +168,7 @@ void TracePC::UpdateObservedPCs() {
(size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
for (size_t j = 0; j < Size; j++, GuardIdx++)
if (Counters()[GuardIdx])
Observe(ModulePCTable[i].Start[j]);
Observe(ModulePCTable[i].Start[j].PC);
}
}
}
@ -240,9 +240,9 @@ void TracePC::PrintCoverage() {
for (size_t i = 0; i < NumPCTables; i++) {
auto &M = ModulePCTable[i];
assert(M.Start < M.Stop);
auto ModuleName = GetModuleName(*M.Start);
auto ModuleName = GetModuleName(M.Start->PC);
for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) {
auto PC = *Ptr;
auto PC = Ptr->PC;
auto VisualizePC = GetNextInstructionPc(PC);
bool IsObserved = ObservedPCs.count(PC);
std::string FileStr = DescribePC("%s", VisualizePC);
@ -388,7 +388,8 @@ void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) {
}
ATTRIBUTE_INTERFACE
void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg, const uint8_t *pcs_end) {
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
const uintptr_t *pcs_end) {
fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end);
}

View File

@ -75,7 +75,7 @@ class TracePC {
void HandleInit(uint32_t *Start, uint32_t *Stop);
void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);
void HandlePCsInit(const uint8_t *Start, const uint8_t *Stop);
void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop);
void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee);
template <class T> void HandleCmp(uintptr_t PC, T Arg1, T Arg2);
size_t GetTotalPCCoverage();
@ -146,7 +146,11 @@ private:
size_t NumModulesWithInline8bitCounters; // linker-initialized.
size_t NumInline8bitCounters;
struct { const uintptr_t *Start, *Stop; } ModulePCTable[4096];
struct PCTableEntry {
uintptr_t PC, PCFlags;
};
struct { const PCTableEntry *Start, *Stop; } ModulePCTable[4096];
size_t NumPCTables;
size_t NumPCsInPCTables;

View File

@ -19,6 +19,7 @@ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
assert(argv0);
if (Size == strlen(argv0) &&
!memmem(Data, Size, argv0, Size)) {
fprintf(stderr, "BINGO %s\n", argv0);

View File

@ -3,7 +3,9 @@
// REQUIRES: has_sancovcc,stable-runtime
// UNSUPPORTED: i386-darwin
//
// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters,pc-table 2>&1
// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters,pc-table -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// XFAIL: tsan
#include <stdio.h>
#include <stdint.h>
@ -19,13 +21,15 @@ void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) {
}
uintptr_t FirstPC;
uintptr_t FirstPCFlag;
extern "C" void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg,
const uint8_t *pcs_end) {
extern "C" void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
const uintptr_t *pcs_end) {
const uintptr_t *B = (const uintptr_t *)pcs_beg;
const uintptr_t *E = (const uintptr_t *)pcs_end;
assert(B < E);
FirstPC = *B;
assert(B + 1 < E);
FirstPC = B[0];
FirstPCFlag = B[1];
}
@ -33,4 +37,7 @@ int main() {
assert(first_counter);
assert(*first_counter == 1);
assert(FirstPC == (uintptr_t)&main);
assert(FirstPCFlag == 1);
fprintf(stderr, "PASS\n");
// CHECK: PASS
}

View File

@ -389,13 +389,13 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {
Ctor = CreateInitCallsForSections(M, SanCov8bitCountersInitName, Int8PtrTy,
SanCovCountersSectionName);
if (Ctor && Options.PCTable) {
auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, Int8PtrTy);
auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy);
Function *InitFunction = declareSanitizerInitFunction(
M, SanCovPCsInitName, {Int8PtrTy, Int8PtrTy});
M, SanCovPCsInitName, {IntptrPtrTy, IntptrPtrTy});
IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
IRBCtor.CreateCall(InitFunction,
{IRB.CreatePointerCast(SecStartEnd.first, Int8PtrTy),
IRB.CreatePointerCast(SecStartEnd.second, Int8PtrTy)});
{IRB.CreatePointerCast(SecStartEnd.first, IntptrPtrTy),
IRB.CreatePointerCast(SecStartEnd.second, IntptrPtrTy)});
}
return true;
}
@ -545,17 +545,24 @@ void SanitizerCoverageModule::CreatePCArray(Function &F,
ArrayRef<BasicBlock *> AllBlocks) {
size_t N = AllBlocks.size();
assert(N);
SmallVector<Constant *, 16> PCs;
SmallVector<Constant *, 32> PCs;
IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt());
for (size_t i = 0; i < N; i++)
if (&F.getEntryBlock() == AllBlocks[i])
PCs.push_back((Constant *)IRB.CreatePointerCast(&F, Int8PtrTy));
else
PCs.push_back(BlockAddress::get(AllBlocks[i]));
FunctionPCsArray =
CreateFunctionLocalArrayInSection(N, F, Int8PtrTy, SanCovPCsSectionName);
for (size_t i = 0; i < N; i++) {
if (&F.getEntryBlock() == AllBlocks[i]) {
PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy));
PCs.push_back((Constant *)IRB.CreateIntToPtr(
ConstantInt::get(IntptrTy, 1), IntptrPtrTy));
} else {
PCs.push_back((Constant *)IRB.CreatePointerCast(
BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
PCs.push_back((Constant *)IRB.CreateIntToPtr(
ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
}
}
FunctionPCsArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy,
SanCovPCsSectionName);
FunctionPCsArray->setInitializer(
ConstantArray::get(ArrayType::get(Int8PtrTy, N), PCs));
ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs));
FunctionPCsArray->setConstant(true);
// We don't reference the PCs array in any of our runtime functions, so we

View File

@ -17,7 +17,7 @@ entry:
ret void
}
; CHECK: private constant [3 x i8*] [{{.*}}@foo{{.*}}blockaddress{{.*}}blockaddress{{.*}}], section "__sancov_pcs", align 8
; CHECK: private constant [6 x i64*] [{{.*}}@foo{{.*}}blockaddress{{.*}}blockaddress{{.*}}], section "__sancov_pcs", align 8
; CHECK: define internal void @sancov.module_ctor
; CHECK: call void @__sanitizer_cov
; CHECK: call void @__sanitizer_cov_pcs_init