llvm.org GIT mirror llvm / 6dcfafe
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311186 91177308-0d34-0410-b5e6-96231b3b80d8 Matt Morehouse 2 years ago
5 changed file(s) with 117 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
184184 bool Inline8bitCounters = false;
185185 bool PCTable = false;
186186 bool NoPrune = false;
187 bool StackDepth = false;
187188
188189 SanitizerCoverageOptions() = default;
189190 };
2929
3030 ATTRIBUTE_INTERFACE
3131 uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
32
33 // Used by -fsanitize-coverage=stack-depth to track stack depth
34 ATTRIBUTE_INTERFACE thread_local uintptr_t __sancov_lowest_stack;
3235
3336 namespace fuzzer {
3437
339342 }
340343 }
341344
345 void TracePC::RecordInitialStack() {
346 InitialStack = __sancov_lowest_stack;
347 }
348
349 uintptr_t TracePC::GetMaxStackOffset() const {
350 return InitialStack - __sancov_lowest_stack; // Stack grows down
351 }
352
342353 } // namespace fuzzer
343354
344355 extern "C" {
349360 uint32_t Idx = *Guard;
350361 __sancov_trace_pc_pcs[Idx] = PC;
351362 __sancov_trace_pc_guard_8bit_counters[Idx]++;
352 // Uncomment the following line to get stack-depth profiling.
353 // fuzzer::TPC.RecordCurrentStack();
354363 }
355364
356365 // Best-effort support for -fsanitize-coverage=trace-pc, which is available
119119 return PCs()[Idx];
120120 }
121121
122 void RecordCurrentStack() {
123 uintptr_t Stack = GetCurrentStack();
124 if (Stack < LowestStack)
125 LowestStack = Stack;
126 }
127 void RecordInitialStack() {
128 InitialStack = GetCurrentStack();
129 LowestStack = InitialStack;
130 }
131 uintptr_t GetCurrentStack() const {
132 return reinterpret_cast(__builtin_frame_address(0));
133 }
134 uintptr_t GetMaxStackOffset() const { return InitialStack - LowestStack; }
122 void RecordInitialStack();
123 uintptr_t GetMaxStackOffset() const;
135124
136125 template
137126 void ForEachObservedPC(CallBack CB) {
166155 std::set ObservedPCs;
167156
168157 ValueBitMap ValueProfileMap;
169 uintptr_t InitialStack, LowestStack; // Assume stack grows down.
158 uintptr_t InitialStack;
170159 };
171160
172161 template
1616 #include "llvm/Analysis/PostDominators.h"
1717 #include "llvm/IR/CFG.h"
1818 #include "llvm/IR/CallSite.h"
19 #include "llvm/IR/Constant.h"
1920 #include "llvm/IR/DataLayout.h"
2021 #include "llvm/IR/DebugInfo.h"
2122 #include "llvm/IR/Dominators.h"
2223 #include "llvm/IR/Function.h"
24 #include "llvm/IR/GlobalVariable.h"
2325 #include "llvm/IR/IRBuilder.h"
2426 #include "llvm/IR/InlineAsm.h"
27 #include "llvm/IR/Intrinsics.h"
2528 #include "llvm/IR/LLVMContext.h"
2629 #include "llvm/IR/MDBuilder.h"
2730 #include "llvm/IR/Module.h"
7275 static const char *const SanCovCountersSectionName = "sancov_cntrs";
7376 static const char *const SanCovPCsSectionName = "sancov_pcs";
7477
78 static const char *const SanCovLowestStackName = "__sancov_lowest_stack";
79 static const char *const SanCovLowestStackTLSWrapperName =
80 "_ZTW21__sancov_lowest_stack";
81
7582 static cl::opt ClCoverageLevel(
7683 "sanitizer-coverage-level",
7784 cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
117124 ClPruneBlocks("sanitizer-coverage-prune-blocks",
118125 cl::desc("Reduce the number of instrumented blocks"),
119126 cl::Hidden, cl::init(true));
127
128 static cl::opt ClStackDepth("sanitizer-coverage-stack-depth",
129 cl::desc("max stack depth tracing"),
130 cl::Hidden, cl::init(false));
120131
121132 namespace {
122133
155166 Options.TracePCGuard |= ClTracePCGuard;
156167 Options.Inline8bitCounters |= ClInline8bitCounters;
157168 Options.PCTable |= ClCreatePCTable;
158 if (!Options.TracePCGuard && !Options.TracePC && !Options.Inline8bitCounters)
169 Options.NoPrune |= !ClPruneBlocks;
170 Options.StackDepth |= ClStackDepth;
171 if (!Options.TracePCGuard && !Options.TracePC &&
172 !Options.Inline8bitCounters && !Options.StackDepth)
159173 Options.TracePCGuard = true; // TracePCGuard is default.
160 Options.NoPrune |= !ClPruneBlocks;
161174 return Options;
162175 }
163176
215228 Function *SanCovTraceDivFunction[2];
216229 Function *SanCovTraceGepFunction;
217230 Function *SanCovTraceSwitchFunction;
231 Function *SanCovLowestStackTLSWrapper;
232 GlobalVariable *SanCovLowestStack;
218233 InlineAsm *EmptyAsm;
219234 Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
220235 *Int16Ty, *Int8Ty, *Int8PtrTy;
332347 SanCovTraceSwitchFunction =
333348 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
334349 SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy));
350
351 Constant *SanCovLowestStackConstant =
352 M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
353 SanCovLowestStackTLSWrapper =
354 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
355 SanCovLowestStackTLSWrapperName, IntptrTy->getPointerTo()));
356 if (Options.StackDepth) {
357 assert(isa(SanCovLowestStackConstant));
358 SanCovLowestStack = cast(SanCovLowestStackConstant);
359 if (!SanCovLowestStack->isDeclaration()) {
360 // Check that the user has correctly defined:
361 // thread_local uintptr_t __sancov_lowest_stack
362 // and initialize it.
363 assert(SanCovLowestStack->isThreadLocal());
364 SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
365 }
366 }
367
335368 // Make sure smaller parameters are zero-extended to i64 as required by the
336369 // x86_64 ABI.
337370 if (TargetTriple.getArch() == Triple::x86_64) {
449482 // initialization.
450483 if (F.getName() == "__local_stdio_printf_options" ||
451484 F.getName() == "__local_stdio_scanf_options")
485 return false;
486 // Avoid infinite recursion by not instrumenting stack depth TLS wrapper
487 if (F.getName() == SanCovLowestStackTLSWrapperName)
452488 return false;
453489 // Don't instrument functions using SEH for now. Splitting basic blocks like
454490 // we do for coverage breaks WinEHPrepare.
727763 SetNoSanitizeMetadata(Load);
728764 SetNoSanitizeMetadata(Store);
729765 }
766 if (Options.StackDepth && IsEntryBB) {
767 // Check stack depth. If it's the deepest so far, record it.
768 Function *GetFrameAddr =
769 Intrinsic::getDeclaration(F.getParent(), Intrinsic::frameaddress);
770 auto FrameAddrPtr =
771 IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)});
772 auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy);
773 auto LowestStackPtr = IRB.CreateCall(SanCovLowestStackTLSWrapper);
774 auto LowestStack = IRB.CreateLoad(LowestStackPtr);
775 auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack);
776 auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false);
777 IRBuilder<> ThenIRB(ThenTerm);
778 ThenIRB.CreateStore(FrameAddrInt, LowestStackPtr);
779 }
730780 }
731781
732782 std::string
0 ; This check verifies that stack depth instrumentation works correctly.
1 ; RUN: opt < %s -sancov -sanitizer-coverage-level=1 \
2 ; RUN: -sanitizer-coverage-stack-depth -S | FileCheck %s --enable-var-scope
3 ; RUN: opt < %s -sancov -sanitizer-coverage-level=3 \
4 ; RUN: -sanitizer-coverage-stack-depth -sanitizer-coverage-trace-pc-guard \
5 ; RUN: -S | FileCheck %s --enable-var-scope
6
7 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8 target triple = "x86_64-unknown-linux-gnu"
9
10 ; CHECK: @__sancov_lowest_stack = thread_local global i64 -1
11 @__sancov_lowest_stack = thread_local global i64 0, align 8
12
13 define i32 @foo() {
14 entry:
15 ; CHECK-LABEL: define i32 @foo
16 ; CHECK: [[framePtr:%[^ \t]+]] = call i8* @llvm.frameaddress(i32 0)
17 ; CHECK: [[frameInt:%[^ \t]+]] = ptrtoint i8* [[framePtr]] to [[$intType:i[0-9]+]]
18 ; CHECK: [[lowestPtr:%[^ \t]+]] = call [[$intType]]* @_ZTW21__sancov_lowest_stack
19 ; CHECK: [[lowestInt:%[^ \t]+]] = load [[$intType]], [[$intType]]* [[lowestPtr]]
20 ; CHECK: [[cmp:%[^ \t]+]] = icmp ult [[$intType]] [[frameInt]], [[lowestInt]]
21 ; CHECK: br i1 [[cmp]], label %[[ifLabel:[^ \t]+]], label
22 ; CHECK:
23 ; CHECK: store [[$intType]] [[frameInt]], [[$intType]]* [[lowestPtr]]
24 ; CHECK: ret i32 7
25
26 ret i32 7
27 }
28
29 define i32 @bar() {
30 entry:
31 ; CHECK-LABEL: define i32 @bar
32 ; CHECK: [[framePtr:%[^ \t]+]] = call i8* @llvm.frameaddress(i32 0)
33 ; CHECK: [[frameInt:%[^ \t]+]] = ptrtoint i8* [[framePtr]] to [[$intType]]
34 ; CHECK: [[lowestPtr:%[^ \t]+]] = call [[$intType]]* @_ZTW21__sancov_lowest_stack
35 ; CHECK: [[lowestInt:%[^ \t]+]] = load [[$intType]], [[$intType]]* [[lowestPtr]]
36 ; CHECK: [[cmp:%[^ \t]+]] = icmp ult [[$intType]] [[frameInt]], [[lowestInt]]
37 ; CHECK: br i1 [[cmp]], label %[[ifLabel:[^ \t]+]], label
38 ; CHECK:
39 ; CHECK: store [[$intType]] [[frameInt]], [[$intType]]* [[lowestPtr]]
40 ; CHECK: %call = call i32 @foo()
41 ; CHECK: ret i32 %call
42
43 %call = call i32 @foo()
44 ret i32 %call
45 }
46
47 define weak_odr hidden i64* @_ZTW21__sancov_lowest_stack() {
48 ret i64* @__sancov_lowest_stack
49 }