1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[SanitizerCoverage] Add stack depth tracing instrumentation.

Summary:
Augment SanitizerCoverage to insert maximum stack depth tracing for
use by libFuzzer.  The new instrumentation is enabled by the flag
-fsanitize-coverage=stack-depth and is compatible with the existing
trace-pc-guard coverage.  The user must also declare the following
global variable in their code:
  thread_local uintptr_t __sancov_lowest_stack

https://bugs.llvm.org/show_bug.cgi?id=33857

Reviewers: vitalybuka, kcc

Reviewed By: vitalybuka

Subscribers: kubamracek, hiraditya, cfe-commits, llvm-commits

Differential Revision: https://reviews.llvm.org/D36839

llvm-svn: 311186
This commit is contained in:
Matt Morehouse 2017-08-18 18:43:30 +00:00
parent 0cbccbe294
commit 38756d86aa
5 changed files with 117 additions and 18 deletions

View File

@ -185,6 +185,7 @@ struct SanitizerCoverageOptions {
bool Inline8bitCounters = false;
bool PCTable = false;
bool NoPrune = false;
bool StackDepth = false;
SanitizerCoverageOptions() = default;
};

View File

@ -31,6 +31,9 @@ uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs];
ATTRIBUTE_INTERFACE
uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
// Used by -fsanitize-coverage=stack-depth to track stack depth
ATTRIBUTE_INTERFACE thread_local uintptr_t __sancov_lowest_stack;
namespace fuzzer {
TracePC TPC;
@ -340,6 +343,14 @@ void TracePC::ClearInlineCounters() {
}
}
void TracePC::RecordInitialStack() {
InitialStack = __sancov_lowest_stack;
}
uintptr_t TracePC::GetMaxStackOffset() const {
return InitialStack - __sancov_lowest_stack; // Stack grows down
}
} // namespace fuzzer
extern "C" {
@ -350,8 +361,6 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
uint32_t Idx = *Guard;
__sancov_trace_pc_pcs[Idx] = PC;
__sancov_trace_pc_guard_8bit_counters[Idx]++;
// Uncomment the following line to get stack-depth profiling.
// fuzzer::TPC.RecordCurrentStack();
}
// Best-effort support for -fsanitize-coverage=trace-pc, which is available

View File

@ -120,19 +120,8 @@ class TracePC {
return PCs()[Idx];
}
void RecordCurrentStack() {
uintptr_t Stack = GetCurrentStack();
if (Stack < LowestStack)
LowestStack = Stack;
}
void RecordInitialStack() {
InitialStack = GetCurrentStack();
LowestStack = InitialStack;
}
uintptr_t GetCurrentStack() const {
return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
}
uintptr_t GetMaxStackOffset() const { return InitialStack - LowestStack; }
void RecordInitialStack();
uintptr_t GetMaxStackOffset() const;
template<class CallBack>
void ForEachObservedPC(CallBack CB) {
@ -167,7 +156,7 @@ private:
std::set<uintptr_t> ObservedPCs;
ValueBitMap ValueProfileMap;
uintptr_t InitialStack, LowestStack; // Assume stack grows down.
uintptr_t InitialStack;
};
template <class Callback>

View File

@ -17,12 +17,15 @@
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
@ -73,6 +76,10 @@ static const char *const SanCovGuardsSectionName = "sancov_guards";
static const char *const SanCovCountersSectionName = "sancov_cntrs";
static const char *const SanCovPCsSectionName = "sancov_pcs";
static const char *const SanCovLowestStackName = "__sancov_lowest_stack";
static const char *const SanCovLowestStackTLSWrapperName =
"_ZTW21__sancov_lowest_stack";
static cl::opt<int> ClCoverageLevel(
"sanitizer-coverage-level",
cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
@ -119,6 +126,10 @@ static cl::opt<bool>
cl::desc("Reduce the number of instrumented blocks"),
cl::Hidden, cl::init(true));
static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth",
cl::desc("max stack depth tracing"),
cl::Hidden, cl::init(false));
namespace {
SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
@ -156,9 +167,11 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
Options.TracePCGuard |= ClTracePCGuard;
Options.Inline8bitCounters |= ClInline8bitCounters;
Options.PCTable |= ClCreatePCTable;
if (!Options.TracePCGuard && !Options.TracePC && !Options.Inline8bitCounters)
Options.TracePCGuard = true; // TracePCGuard is default.
Options.NoPrune |= !ClPruneBlocks;
Options.StackDepth |= ClStackDepth;
if (!Options.TracePCGuard && !Options.TracePC &&
!Options.Inline8bitCounters && !Options.StackDepth)
Options.TracePCGuard = true; // TracePCGuard is default.
return Options;
}
@ -216,6 +229,8 @@ private:
Function *SanCovTraceDivFunction[2];
Function *SanCovTraceGepFunction;
Function *SanCovTraceSwitchFunction;
Function *SanCovLowestStackTLSWrapper;
GlobalVariable *SanCovLowestStack;
InlineAsm *EmptyAsm;
Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
*Int16Ty, *Int8Ty, *Int8PtrTy;
@ -333,6 +348,24 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {
SanCovTraceSwitchFunction =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy));
Constant *SanCovLowestStackConstant =
M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
SanCovLowestStackTLSWrapper =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
SanCovLowestStackTLSWrapperName, IntptrTy->getPointerTo()));
if (Options.StackDepth) {
assert(isa<GlobalVariable>(SanCovLowestStackConstant));
SanCovLowestStack = cast<GlobalVariable>(SanCovLowestStackConstant);
if (!SanCovLowestStack->isDeclaration()) {
// Check that the user has correctly defined:
// thread_local uintptr_t __sancov_lowest_stack
// and initialize it.
assert(SanCovLowestStack->isThreadLocal());
SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
}
}
// Make sure smaller parameters are zero-extended to i64 as required by the
// x86_64 ABI.
if (TargetTriple.getArch() == Triple::x86_64) {
@ -451,6 +484,9 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) {
if (F.getName() == "__local_stdio_printf_options" ||
F.getName() == "__local_stdio_scanf_options")
return false;
// Avoid infinite recursion by not instrumenting stack depth TLS wrapper
if (F.getName() == SanCovLowestStackTLSWrapperName)
return false;
// Don't instrument functions using SEH for now. Splitting basic blocks like
// we do for coverage breaks WinEHPrepare.
// FIXME: Remove this when SEH no longer uses landingpad pattern matching.
@ -728,6 +764,20 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
SetNoSanitizeMetadata(Load);
SetNoSanitizeMetadata(Store);
}
if (Options.StackDepth && IsEntryBB) {
// Check stack depth. If it's the deepest so far, record it.
Function *GetFrameAddr =
Intrinsic::getDeclaration(F.getParent(), Intrinsic::frameaddress);
auto FrameAddrPtr =
IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)});
auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy);
auto LowestStackPtr = IRB.CreateCall(SanCovLowestStackTLSWrapper);
auto LowestStack = IRB.CreateLoad(LowestStackPtr);
auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack);
auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false);
IRBuilder<> ThenIRB(ThenTerm);
ThenIRB.CreateStore(FrameAddrInt, LowestStackPtr);
}
}
std::string

View File

@ -0,0 +1,50 @@
; This check verifies that stack depth instrumentation works correctly.
; RUN: opt < %s -sancov -sanitizer-coverage-level=1 \
; RUN: -sanitizer-coverage-stack-depth -S | FileCheck %s --enable-var-scope
; RUN: opt < %s -sancov -sanitizer-coverage-level=3 \
; RUN: -sanitizer-coverage-stack-depth -sanitizer-coverage-trace-pc-guard \
; RUN: -S | FileCheck %s --enable-var-scope
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; CHECK: @__sancov_lowest_stack = thread_local global i64 -1
@__sancov_lowest_stack = thread_local global i64 0, align 8
define i32 @foo() {
entry:
; CHECK-LABEL: define i32 @foo
; CHECK: [[framePtr:%[^ \t]+]] = call i8* @llvm.frameaddress(i32 0)
; CHECK: [[frameInt:%[^ \t]+]] = ptrtoint i8* [[framePtr]] to [[$intType:i[0-9]+]]
; CHECK: [[lowestPtr:%[^ \t]+]] = call [[$intType]]* @_ZTW21__sancov_lowest_stack
; CHECK: [[lowestInt:%[^ \t]+]] = load [[$intType]], [[$intType]]* [[lowestPtr]]
; CHECK: [[cmp:%[^ \t]+]] = icmp ult [[$intType]] [[frameInt]], [[lowestInt]]
; CHECK: br i1 [[cmp]], label %[[ifLabel:[^ \t]+]], label
; CHECK: <label>:[[ifLabel]]:
; CHECK: store [[$intType]] [[frameInt]], [[$intType]]* [[lowestPtr]]
; CHECK: ret i32 7
ret i32 7
}
define i32 @bar() {
entry:
; CHECK-LABEL: define i32 @bar
; CHECK: [[framePtr:%[^ \t]+]] = call i8* @llvm.frameaddress(i32 0)
; CHECK: [[frameInt:%[^ \t]+]] = ptrtoint i8* [[framePtr]] to [[$intType]]
; CHECK: [[lowestPtr:%[^ \t]+]] = call [[$intType]]* @_ZTW21__sancov_lowest_stack
; CHECK: [[lowestInt:%[^ \t]+]] = load [[$intType]], [[$intType]]* [[lowestPtr]]
; CHECK: [[cmp:%[^ \t]+]] = icmp ult [[$intType]] [[frameInt]], [[lowestInt]]
; CHECK: br i1 [[cmp]], label %[[ifLabel:[^ \t]+]], label
; CHECK: <label>:[[ifLabel]]:
; CHECK: store [[$intType]] [[frameInt]], [[$intType]]* [[lowestPtr]]
; CHECK: %call = call i32 @foo()
; CHECK: ret i32 %call
%call = call i32 @foo()
ret i32 %call
}
define weak_odr hidden i64* @_ZTW21__sancov_lowest_stack() {
ret i64* @__sancov_lowest_stack
}