mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
[asan] add two new hidden compile-time flags for asan: asan-instrumentation-with-call-threshold and asan-memory-access-callback-prefix. This is part of the workaround for PR17409 (instrument huge functions with callbacks instead of inlined code). These flags will also help us experiment with kasan (kernel-asan) and clang
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206383 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
115d4f407b
commit
8cc4741d85
@ -148,6 +148,16 @@ static cl::opt<unsigned> ClRealignStack("asan-realign-stack",
|
||||
static cl::opt<std::string> ClBlacklistFile("asan-blacklist",
|
||||
cl::desc("File containing the list of objects to ignore "
|
||||
"during instrumentation"), cl::Hidden);
|
||||
static cl::opt<int> ClInstrumentationWithCallsThreshold(
|
||||
"asan-instrumentation-with-call-threshold",
|
||||
cl::desc("If the function being instrumented contains more than "
|
||||
"this number of memory accesses, use callbacks instead of "
|
||||
"inline checks (-1 means never use callbacks)."),
|
||||
cl::Hidden, cl::init(-1));
|
||||
static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
|
||||
"asan-memory-access-callback-prefix",
|
||||
cl::desc("Prefix for memory access callbacks"), cl::Hidden,
|
||||
cl::init("__asan_"));
|
||||
|
||||
// This is an experimental feature that will allow to choose between
|
||||
// instrumented and non-instrumented code at link-time.
|
||||
@ -303,20 +313,20 @@ struct AddressSanitizer : public FunctionPass {
|
||||
const char *getPassName() const override {
|
||||
return "AddressSanitizerFunctionPass";
|
||||
}
|
||||
void instrumentMop(Instruction *I);
|
||||
void instrumentMop(Instruction *I, bool UseCalls);
|
||||
void instrumentPointerComparisonOrSubtraction(Instruction *I);
|
||||
void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
|
||||
Value *Addr, uint32_t TypeSize, bool IsWrite,
|
||||
Value *SizeArgument);
|
||||
Value *SizeArgument, bool UseCalls);
|
||||
Value *createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
|
||||
Value *ShadowValue, uint32_t TypeSize);
|
||||
Instruction *generateCrashCode(Instruction *InsertBefore, Value *Addr,
|
||||
bool IsWrite, size_t AccessSizeIndex,
|
||||
Value *SizeArgument);
|
||||
bool instrumentMemIntrinsic(MemIntrinsic *MI);
|
||||
bool instrumentMemIntrinsic(MemIntrinsic *MI, bool UseCalls);
|
||||
void instrumentMemIntrinsicParam(Instruction *OrigIns, Value *Addr,
|
||||
Value *Size,
|
||||
Instruction *InsertBefore, bool IsWrite);
|
||||
Value *Size, Instruction *InsertBefore,
|
||||
bool IsWrite, bool UseCalls);
|
||||
Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
|
||||
bool runOnFunction(Function &F) override;
|
||||
bool maybeInsertAsanInitAtFunctionEntry(Function &F);
|
||||
@ -349,6 +359,7 @@ struct AddressSanitizer : public FunctionPass {
|
||||
std::unique_ptr<SpecialCaseList> BL;
|
||||
// This array is indexed by AccessIsWrite and log2(AccessSize).
|
||||
Function *AsanErrorCallback[2][kNumberOfAccessSizes];
|
||||
Function *AsanMemoryAccessCallback[2][kNumberOfAccessSizes];
|
||||
// This array is indexed by AccessIsWrite.
|
||||
Function *AsanErrorCallbackSized[2];
|
||||
InlineAsm *EmptyAsm;
|
||||
@ -588,24 +599,27 @@ Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
|
||||
return IRB.CreateAdd(Shadow, ConstantInt::get(IntptrTy, Mapping.Offset));
|
||||
}
|
||||
|
||||
void AddressSanitizer::instrumentMemIntrinsicParam(
|
||||
Instruction *OrigIns,
|
||||
Value *Addr, Value *Size, Instruction *InsertBefore, bool IsWrite) {
|
||||
void AddressSanitizer::instrumentMemIntrinsicParam(Instruction *OrigIns,
|
||||
Value *Addr, Value *Size,
|
||||
Instruction *InsertBefore,
|
||||
bool IsWrite,
|
||||
bool UseCalls) {
|
||||
IRBuilder<> IRB(InsertBefore);
|
||||
if (Size->getType() != IntptrTy)
|
||||
Size = IRB.CreateIntCast(Size, IntptrTy, false);
|
||||
// Check the first byte.
|
||||
instrumentAddress(OrigIns, InsertBefore, Addr, 8, IsWrite, Size);
|
||||
instrumentAddress(OrigIns, InsertBefore, Addr, 8, IsWrite, Size, UseCalls);
|
||||
// Check the last byte.
|
||||
IRB.SetInsertPoint(InsertBefore);
|
||||
Value *SizeMinusOne = IRB.CreateSub(Size, ConstantInt::get(IntptrTy, 1));
|
||||
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
|
||||
Value *AddrLast = IRB.CreateAdd(AddrLong, SizeMinusOne);
|
||||
instrumentAddress(OrigIns, InsertBefore, AddrLast, 8, IsWrite, Size);
|
||||
instrumentAddress(OrigIns, InsertBefore, AddrLast, 8, IsWrite, Size,
|
||||
UseCalls);
|
||||
}
|
||||
|
||||
// Instrument memset/memmove/memcpy
|
||||
bool AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
|
||||
bool AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI, bool UseCalls) {
|
||||
Value *Dst = MI->getDest();
|
||||
MemTransferInst *MemTran = dyn_cast<MemTransferInst>(MI);
|
||||
Value *Src = MemTran ? MemTran->getSource() : 0;
|
||||
@ -624,9 +638,9 @@ bool AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
|
||||
InsertBefore = SplitBlockAndInsertIfThen(Cmp, InsertBefore, false);
|
||||
}
|
||||
|
||||
instrumentMemIntrinsicParam(MI, Dst, Length, InsertBefore, true);
|
||||
instrumentMemIntrinsicParam(MI, Dst, Length, InsertBefore, true, UseCalls);
|
||||
if (Src)
|
||||
instrumentMemIntrinsicParam(MI, Src, Length, InsertBefore, false);
|
||||
instrumentMemIntrinsicParam(MI, Src, Length, InsertBefore, false, UseCalls);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -698,7 +712,7 @@ AddressSanitizer::instrumentPointerComparisonOrSubtraction(Instruction *I) {
|
||||
IRB.CreateCall2(F, Param[0], Param[1]);
|
||||
}
|
||||
|
||||
void AddressSanitizer::instrumentMop(Instruction *I) {
|
||||
void AddressSanitizer::instrumentMop(Instruction *I, bool UseCalls) {
|
||||
bool IsWrite = false;
|
||||
Value *Addr = isInterestingMemoryAccess(I, &IsWrite);
|
||||
assert(Addr);
|
||||
@ -738,7 +752,7 @@ void AddressSanitizer::instrumentMop(Instruction *I) {
|
||||
// Instrument a 1-, 2-, 4-, 8-, or 16- byte access with one check.
|
||||
if (TypeSize == 8 || TypeSize == 16 ||
|
||||
TypeSize == 32 || TypeSize == 64 || TypeSize == 128)
|
||||
return instrumentAddress(I, I, Addr, TypeSize, IsWrite, 0);
|
||||
return instrumentAddress(I, I, Addr, TypeSize, IsWrite, 0, UseCalls);
|
||||
// Instrument unusual size (but still multiple of 8).
|
||||
// We can not do it with a single check, so we do 1-byte check for the first
|
||||
// and the last bytes. We call __asan_report_*_n(addr, real_size) to be able
|
||||
@ -749,8 +763,8 @@ void AddressSanitizer::instrumentMop(Instruction *I) {
|
||||
ConstantInt::get(IntptrTy, TypeSize / 8 - 1)),
|
||||
OrigPtrTy);
|
||||
Value *Size = ConstantInt::get(IntptrTy, TypeSize / 8);
|
||||
instrumentAddress(I, I, Addr, 8, IsWrite, Size);
|
||||
instrumentAddress(I, I, LastByte, 8, IsWrite, Size);
|
||||
instrumentAddress(I, I, Addr, 8, IsWrite, Size, UseCalls);
|
||||
instrumentAddress(I, I, LastByte, 8, IsWrite, Size, UseCalls);
|
||||
}
|
||||
|
||||
// Validate the result of Module::getOrInsertFunction called for an interface
|
||||
@ -798,11 +812,18 @@ Value *AddressSanitizer::createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
|
||||
}
|
||||
|
||||
void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
|
||||
Instruction *InsertBefore,
|
||||
Value *Addr, uint32_t TypeSize,
|
||||
bool IsWrite, Value *SizeArgument) {
|
||||
Instruction *InsertBefore, Value *Addr,
|
||||
uint32_t TypeSize, bool IsWrite,
|
||||
Value *SizeArgument, bool UseCalls) {
|
||||
IRBuilder<> IRB(InsertBefore);
|
||||
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
|
||||
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
||||
|
||||
if (UseCalls) {
|
||||
IRB.CreateCall(AsanMemoryAccessCallback[IsWrite][AccessSizeIndex],
|
||||
AddrLong);
|
||||
return;
|
||||
}
|
||||
|
||||
Type *ShadowTy = IntegerType::get(
|
||||
*C, std::max(8U, TypeSize >> Mapping.Scale));
|
||||
@ -813,7 +834,6 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
|
||||
IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy));
|
||||
|
||||
Value *Cmp = IRB.CreateICmpNE(ShadowValue, CmpVal);
|
||||
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
||||
size_t Granularity = 1 << Mapping.Scale;
|
||||
TerminatorInst *CrashTerm = 0;
|
||||
|
||||
@ -1108,12 +1128,16 @@ void AddressSanitizer::initializeCallbacks(Module &M) {
|
||||
for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
|
||||
AccessSizeIndex++) {
|
||||
// IsWrite and TypeSize are encoded in the function name.
|
||||
std::string FunctionName = std::string(kAsanReportErrorTemplate) +
|
||||
std::string Suffix =
|
||||
(AccessIsWrite ? "store" : "load") + itostr(1 << AccessSizeIndex);
|
||||
// If we are merging crash callbacks, they have two parameters.
|
||||
AsanErrorCallback[AccessIsWrite][AccessSizeIndex] =
|
||||
checkInterfaceFunction(M.getOrInsertFunction(
|
||||
FunctionName, IRB.getVoidTy(), IntptrTy, NULL));
|
||||
checkInterfaceFunction(
|
||||
M.getOrInsertFunction(kAsanReportErrorTemplate + Suffix,
|
||||
IRB.getVoidTy(), IntptrTy, NULL));
|
||||
AsanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
|
||||
checkInterfaceFunction(
|
||||
M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + Suffix,
|
||||
IRB.getVoidTy(), IntptrTy, NULL));
|
||||
}
|
||||
}
|
||||
AsanErrorCallbackSized[0] = checkInterfaceFunction(M.getOrInsertFunction(
|
||||
@ -1324,6 +1348,11 @@ bool AddressSanitizer::runOnFunction(Function &F) {
|
||||
F.getParent()->getFunctionList().push_back(UninstrumentedDuplicate);
|
||||
}
|
||||
|
||||
bool UseCalls = false;
|
||||
if (ClInstrumentationWithCallsThreshold >= 0 &&
|
||||
ToInstrument.size() > (unsigned)ClInstrumentationWithCallsThreshold)
|
||||
UseCalls = true;
|
||||
|
||||
// Instrument.
|
||||
int NumInstrumented = 0;
|
||||
for (size_t i = 0, n = ToInstrument.size(); i != n; i++) {
|
||||
@ -1331,9 +1360,9 @@ bool AddressSanitizer::runOnFunction(Function &F) {
|
||||
if (ClDebugMin < 0 || ClDebugMax < 0 ||
|
||||
(NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) {
|
||||
if (isInterestingMemoryAccess(Inst, &IsWrite))
|
||||
instrumentMop(Inst);
|
||||
instrumentMop(Inst, UseCalls);
|
||||
else
|
||||
instrumentMemIntrinsic(cast<MemIntrinsic>(Inst));
|
||||
instrumentMemIntrinsic(cast<MemIntrinsic>(Inst), UseCalls);
|
||||
}
|
||||
NumInstrumented++;
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
; Test asan internal compiler flags:
|
||||
; -asan-instrumentation-with-call-threshold
|
||||
; -asan-memory-access-callback-prefix
|
||||
|
||||
; RUN: opt < %s -asan -asan-module -asan-instrumentation-with-call-threshold=1 -S | FileCheck %s --check-prefix=CHECK-CALL
|
||||
; RUN: opt < %s -asan -asan-module -asan-instrumentation-with-call-threshold=0 -S | FileCheck %s --check-prefix=CHECK-CALL
|
||||
; RUN: opt < %s -asan -asan-module -asan-instrumentation-with-call-threshold=0 -asan-memory-access-callback-prefix=__foo_ -S | FileCheck %s --check-prefix=CHECK-CUSTOM-PREFIX
|
||||
; RUN: opt < %s -asan -asan-module -asan-instrumentation-with-call-threshold=5 -S | FileCheck %s --check-prefix=CHECK-INLINE
|
||||
; RUN: opt < %s -asan -asan-module -S | FileCheck %s --check-prefix=CHECK-INLINE
|
||||
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define void @test_load(i32* %a, i64* %b) sanitize_address {
|
||||
entry:
|
||||
; CHECK-CALL: call void @__asan_load4
|
||||
; CHECK-CALL: call void @__asan_load8
|
||||
; CHECK-CUSTOM-PREFIX: call void @__foo_load4
|
||||
; CHECK-CUSTOM-PREFIX: call void @__foo_load8
|
||||
; CHECK-INLINE-NOT: call void @__asan_load
|
||||
%tmp1 = load i32* %a
|
||||
%tmp2 = load i64* %b
|
||||
ret void
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user