forked from OSchip/llvm-project
[sanitizer-coverage] extend fsanitize-coverage=pc-table with flags for every PC
llvm-svn: 311794
This commit is contained in:
parent
50a446ef10
commit
d3e4b7e24a
|
@ -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.
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue