forked from OSchip/llvm-project
[asan] experimental tracing for indirect calls, llvm part.
llvm-svn: 220699
This commit is contained in:
parent
fe408a77f6
commit
4f8f0c5aa2
|
@ -83,6 +83,7 @@ static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
|
|||
static const char *const kAsanInitName = "__asan_init_v4";
|
||||
static const char *const kAsanCovModuleInitName = "__sanitizer_cov_module_init";
|
||||
static const char *const kAsanCovName = "__sanitizer_cov";
|
||||
static const char *const kAsanCovIndirCallName = "__sanitizer_cov_indir_call16";
|
||||
static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
|
||||
static const char *const kAsanPtrSub = "__sanitizer_ptr_sub";
|
||||
static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return";
|
||||
|
@ -136,7 +137,8 @@ static cl::opt<bool> ClGlobals("asan-globals",
|
|||
cl::desc("Handle global objects"), cl::Hidden, cl::init(true));
|
||||
static cl::opt<int> ClCoverage("asan-coverage",
|
||||
cl::desc("ASan coverage. 0: none, 1: entry block, 2: all blocks, "
|
||||
"3: all blocks and critical edges"),
|
||||
"3: all blocks and critical edges, "
|
||||
"4: above plus indirect calls"),
|
||||
cl::Hidden, cl::init(false));
|
||||
static cl::opt<int> ClCoverageBlockThreshold("asan-coverage-block-threshold",
|
||||
cl::desc("Add coverage instrumentation only to the entry block if there "
|
||||
|
@ -387,7 +389,10 @@ struct AddressSanitizer : public FunctionPass {
|
|||
|
||||
bool LooksLikeCodeInBug11395(Instruction *I);
|
||||
bool GlobalIsLinkerInitialized(GlobalVariable *G);
|
||||
bool InjectCoverage(Function &F, ArrayRef<BasicBlock*> AllBlocks);
|
||||
void InjectCoverageForIndirectCalls(Function &F,
|
||||
ArrayRef<Instruction *> IndirCalls);
|
||||
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
|
||||
ArrayRef<Instruction *> IndirCalls);
|
||||
void InjectCoverageAtBlock(Function &F, BasicBlock &BB);
|
||||
|
||||
LLVMContext *C;
|
||||
|
@ -399,6 +404,7 @@ struct AddressSanitizer : public FunctionPass {
|
|||
Function *AsanInitFunction;
|
||||
Function *AsanHandleNoReturnFunc;
|
||||
Function *AsanCovFunction;
|
||||
Function *AsanCovIndirCallFunction;
|
||||
Function *AsanPtrCmpFunction, *AsanPtrSubFunction;
|
||||
// This array is indexed by AccessIsWrite and log2(AccessSize).
|
||||
Function *AsanErrorCallback[2][kNumberOfAccessSizes];
|
||||
|
@ -1255,6 +1261,9 @@ void AddressSanitizer::initializeCallbacks(Module &M) {
|
|||
M.getOrInsertFunction(kAsanHandleNoReturnName, IRB.getVoidTy(), NULL));
|
||||
AsanCovFunction = checkInterfaceFunction(M.getOrInsertFunction(
|
||||
kAsanCovName, IRB.getVoidTy(), NULL));
|
||||
AsanCovIndirCallFunction = checkInterfaceFunction(M.getOrInsertFunction(
|
||||
kAsanCovIndirCallName, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL));
|
||||
|
||||
AsanPtrCmpFunction = checkInterfaceFunction(M.getOrInsertFunction(
|
||||
kAsanPtrCmp, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL));
|
||||
AsanPtrSubFunction = checkInterfaceFunction(M.getOrInsertFunction(
|
||||
|
@ -1368,7 +1377,8 @@ void AddressSanitizer::InjectCoverageAtBlock(Function &F, BasicBlock &BB) {
|
|||
// a) get the functionality to users earlier and
|
||||
// b) collect usage statistics to help improve Clang coverage design.
|
||||
bool AddressSanitizer::InjectCoverage(Function &F,
|
||||
ArrayRef<BasicBlock *> AllBlocks) {
|
||||
ArrayRef<BasicBlock *> AllBlocks,
|
||||
ArrayRef<Instruction*> IndirCalls) {
|
||||
if (!ClCoverage) return false;
|
||||
|
||||
if (ClCoverage == 1 ||
|
||||
|
@ -1378,9 +1388,36 @@ bool AddressSanitizer::InjectCoverage(Function &F,
|
|||
for (auto BB : AllBlocks)
|
||||
InjectCoverageAtBlock(F, *BB);
|
||||
}
|
||||
InjectCoverageForIndirectCalls(F, IndirCalls);
|
||||
return true;
|
||||
}
|
||||
|
||||
// On every indirect call we call a run-time function
|
||||
// __sanitizer_cov_indir_call* with two parameters:
|
||||
// - callee address,
|
||||
// - global cache array that contains kCacheSize pointers (zero-initialed).
|
||||
// The cache is used to speed up recording the caller-callee pairs.
|
||||
// The address of the caller is passed implicitly via caller PC.
|
||||
// kCacheSize is encoded in the name of the run-time function.
|
||||
void AddressSanitizer::InjectCoverageForIndirectCalls(
|
||||
Function &F, ArrayRef<Instruction *> IndirCalls) {
|
||||
if (ClCoverage < 4 || IndirCalls.empty()) return;
|
||||
const int kCacheSize = 16;
|
||||
const int kCacheAlignment = 64; // Align for better performance.
|
||||
Type *Ty = ArrayType::get(IntptrTy, kCacheSize);
|
||||
GlobalVariable *CalleeCache =
|
||||
new GlobalVariable(*F.getParent(), Ty, false, GlobalValue::PrivateLinkage,
|
||||
Constant::getNullValue(Ty), "__asan_gen_callee_cache");
|
||||
CalleeCache->setAlignment(kCacheAlignment);
|
||||
for (auto I : IndirCalls) {
|
||||
IRBuilder<> IRB(I);
|
||||
CallSite CS(I);
|
||||
IRB.CreateCall2(AsanCovIndirCallFunction,
|
||||
IRB.CreatePointerCast(CS.getCalledValue(), IntptrTy),
|
||||
IRB.CreatePointerCast(CalleeCache, IntptrTy));
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressSanitizer::runOnFunction(Function &F) {
|
||||
if (&F == AsanCtorFunction) return false;
|
||||
if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false;
|
||||
|
@ -1403,6 +1440,7 @@ bool AddressSanitizer::runOnFunction(Function &F) {
|
|||
SmallVector<Instruction*, 8> NoReturnCalls;
|
||||
SmallVector<BasicBlock*, 16> AllBlocks;
|
||||
SmallVector<Instruction*, 16> PointerComparisonsOrSubtracts;
|
||||
SmallVector<Instruction*, 8> IndirCalls;
|
||||
int NumAllocas = 0;
|
||||
bool IsWrite;
|
||||
unsigned Alignment;
|
||||
|
@ -1435,6 +1473,8 @@ bool AddressSanitizer::runOnFunction(Function &F) {
|
|||
TempsToInstrument.clear();
|
||||
if (CS.doesNotReturn())
|
||||
NoReturnCalls.push_back(CS.getInstruction());
|
||||
if (ClCoverage >= 4 && !CS.getCalledFunction())
|
||||
IndirCalls.push_back(&Inst);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1491,7 +1531,7 @@ bool AddressSanitizer::runOnFunction(Function &F) {
|
|||
|
||||
bool res = NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty();
|
||||
|
||||
if (InjectCoverage(F, AllBlocks))
|
||||
if (InjectCoverage(F, AllBlocks, IndirCalls))
|
||||
res = true;
|
||||
|
||||
DEBUG(dbgs() << "ASAN done instrumenting: " << res << " " << F << "\n");
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-coverage-block-threshold=10 -S | FileCheck %s --check-prefix=CHECK2
|
||||
; RUN: opt < %s -asan -asan-module -asan-coverage=2 -asan-coverage-block-threshold=1 -S | FileCheck %s --check-prefix=CHECK1
|
||||
; RUN: opt < %s -asan -asan-module -asan-coverage=3 -asan-coverage-block-threshold=10 -S | FileCheck %s --check-prefix=CHECK3
|
||||
; RUN: opt < %s -asan -asan-module -asan-coverage=4 -S | FileCheck %s --check-prefix=CHECK4
|
||||
|
||||
; RUN: opt < %s -asan -asan-module -asan-coverage=0 -asan-globals=0 -S | \
|
||||
; RUN: FileCheck %s --check-prefix=CHECK0
|
||||
|
@ -44,7 +45,7 @@ entry:
|
|||
|
||||
; CHECK1-LABEL: define internal void @asan.module_ctor
|
||||
; CHECK1-NOT: ret
|
||||
; CHECK1: call void @__sanitizer_cov_module_init(i64 1)
|
||||
; CHECK1: call void @__sanitizer_cov_module_init(i64 2)
|
||||
; CHECK1: ret
|
||||
|
||||
|
||||
|
@ -57,7 +58,7 @@ entry:
|
|||
|
||||
; CHECK2-LABEL: define internal void @asan.module_ctor
|
||||
; CHECK2-NOT: ret
|
||||
; CHECK2: call void @__sanitizer_cov_module_init(i64 3)
|
||||
; CHECK2: call void @__sanitizer_cov_module_init(i64 4)
|
||||
; CHECK2: ret
|
||||
|
||||
; CHECK3-LABEL: define void @foo
|
||||
|
@ -68,3 +69,18 @@ entry:
|
|||
; CHECK3-NOT: call void @__sanitizer_cov
|
||||
; CHECK3: ret void
|
||||
|
||||
|
||||
%struct.StructWithVptr = type { i32 (...)** }
|
||||
|
||||
define void @CallViaVptr(%struct.StructWithVptr* %foo) uwtable sanitize_address {
|
||||
entry:
|
||||
%0 = bitcast %struct.StructWithVptr* %foo to void (%struct.StructWithVptr*)***
|
||||
%vtable = load void (%struct.StructWithVptr*)*** %0, align 8
|
||||
%1 = load void (%struct.StructWithVptr*)** %vtable, align 8
|
||||
tail call void %1(%struct.StructWithVptr* %foo)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK4-LABEL: define void @CallViaVptr
|
||||
; CHECK4: call void @__sanitizer_cov_indir_call16
|
||||
; CHECK4: ret void
|
||||
|
|
Loading…
Reference in New Issue