mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 11:42:57 +01:00
[asan] Add instrumentation support for Myriad
1. Define Myriad-specific ASan constants. 2. Add code to generate an outer loop that checks that the address is in DRAM range, and strip the cache bit from the address. The former is required because Myriad has no memory protection, and it is up to the instrumentation to range-check before using it to index into the shadow memory. 3. Do not add an unreachable instruction after the error reporting function; on Myriad such function may return if the run-time has not been initialized. 4. Add a test. Differential Revision: https://reviews.llvm.org/D46451 llvm-svn: 332692
This commit is contained in:
parent
a8af86a953
commit
c7675c4977
@ -112,6 +112,13 @@ static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46;
|
|||||||
static const uint64_t kPS4CPU_ShadowOffset64 = 1ULL << 40;
|
static const uint64_t kPS4CPU_ShadowOffset64 = 1ULL << 40;
|
||||||
static const uint64_t kWindowsShadowOffset32 = 3ULL << 28;
|
static const uint64_t kWindowsShadowOffset32 = 3ULL << 28;
|
||||||
|
|
||||||
|
static const uint64_t kMyriadShadowScale = 5;
|
||||||
|
static const uint64_t kMyriadMemoryOffset32 = 0x80000000ULL;
|
||||||
|
static const uint64_t kMyriadMemorySize32 = 0x20000000ULL;
|
||||||
|
static const uint64_t kMyriadTagShift = 29;
|
||||||
|
static const uint64_t kMyriadDDRTag = 4;
|
||||||
|
static const uint64_t kMyriadCacheBitMask32 = 0x40000000ULL;
|
||||||
|
|
||||||
// The shadow memory space is dynamically allocated.
|
// The shadow memory space is dynamically allocated.
|
||||||
static const uint64_t kWindowsShadowOffset64 = kDynamicShadowSentinel;
|
static const uint64_t kWindowsShadowOffset64 = kDynamicShadowSentinel;
|
||||||
|
|
||||||
@ -494,10 +501,11 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
|||||||
bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64;
|
bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64;
|
||||||
bool IsWindows = TargetTriple.isOSWindows();
|
bool IsWindows = TargetTriple.isOSWindows();
|
||||||
bool IsFuchsia = TargetTriple.isOSFuchsia();
|
bool IsFuchsia = TargetTriple.isOSFuchsia();
|
||||||
|
bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad;
|
||||||
|
|
||||||
ShadowMapping Mapping;
|
ShadowMapping Mapping;
|
||||||
|
|
||||||
Mapping.Scale = kDefaultShadowScale;
|
Mapping.Scale = IsMyriad ? kMyriadShadowScale : kDefaultShadowScale;
|
||||||
if (ClMappingScale.getNumOccurrences() > 0) {
|
if (ClMappingScale.getNumOccurrences() > 0) {
|
||||||
Mapping.Scale = ClMappingScale;
|
Mapping.Scale = ClMappingScale;
|
||||||
}
|
}
|
||||||
@ -516,6 +524,11 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
|||||||
Mapping.Offset = IsX86 ? kIOSSimShadowOffset32 : kIOSShadowOffset32;
|
Mapping.Offset = IsX86 ? kIOSSimShadowOffset32 : kIOSShadowOffset32;
|
||||||
else if (IsWindows)
|
else if (IsWindows)
|
||||||
Mapping.Offset = kWindowsShadowOffset32;
|
Mapping.Offset = kWindowsShadowOffset32;
|
||||||
|
else if (IsMyriad) {
|
||||||
|
uint64_t ShadowOffset = (kMyriadMemoryOffset32 + kMyriadMemorySize32 -
|
||||||
|
(kMyriadMemorySize32 >> Mapping.Scale));
|
||||||
|
Mapping.Offset = ShadowOffset - (kMyriadMemoryOffset32 >> Mapping.Scale);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Mapping.Offset = kDefaultShadowOffset32;
|
Mapping.Offset = kDefaultShadowOffset32;
|
||||||
} else { // LongSize == 64
|
} else { // LongSize == 64
|
||||||
@ -1495,6 +1508,8 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
|
|||||||
uint32_t TypeSize, bool IsWrite,
|
uint32_t TypeSize, bool IsWrite,
|
||||||
Value *SizeArgument, bool UseCalls,
|
Value *SizeArgument, bool UseCalls,
|
||||||
uint32_t Exp) {
|
uint32_t Exp) {
|
||||||
|
bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad;
|
||||||
|
|
||||||
IRBuilder<> IRB(InsertBefore);
|
IRBuilder<> IRB(InsertBefore);
|
||||||
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
|
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
|
||||||
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
||||||
@ -1509,6 +1524,23 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsMyriad) {
|
||||||
|
// Strip the cache bit and do range check.
|
||||||
|
// AddrLong &= ~kMyriadCacheBitMask32
|
||||||
|
AddrLong = IRB.CreateAnd(AddrLong, ~kMyriadCacheBitMask32);
|
||||||
|
// Tag = AddrLong >> kMyriadTagShift
|
||||||
|
Value *Tag = IRB.CreateLShr(AddrLong, kMyriadTagShift);
|
||||||
|
// Tag == kMyriadDDRTag
|
||||||
|
Value *TagCheck =
|
||||||
|
IRB.CreateICmpEQ(Tag, ConstantInt::get(IntptrTy, kMyriadDDRTag));
|
||||||
|
|
||||||
|
TerminatorInst *TagCheckTerm = SplitBlockAndInsertIfThen(
|
||||||
|
TagCheck, InsertBefore, false, MDBuilder(*C).createBranchWeights(1, 100000));
|
||||||
|
assert(cast<BranchInst>(TagCheckTerm)->isUnconditional());
|
||||||
|
IRB.SetInsertPoint(TagCheckTerm);
|
||||||
|
InsertBefore = TagCheckTerm;
|
||||||
|
}
|
||||||
|
|
||||||
Type *ShadowTy =
|
Type *ShadowTy =
|
||||||
IntegerType::get(*C, std::max(8U, TypeSize >> Mapping.Scale));
|
IntegerType::get(*C, std::max(8U, TypeSize >> Mapping.Scale));
|
||||||
Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
|
Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
|
||||||
|
84
test/Instrumentation/AddressSanitizer/basic-myriad.ll
Normal file
84
test/Instrumentation/AddressSanitizer/basic-myriad.ll
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
; Test basic address sanitizer instrumentation for Myriad.
|
||||||
|
;
|
||||||
|
; RUN: opt -asan -asan-module -S < %s | FileCheck %s
|
||||||
|
|
||||||
|
target triple = "sparc-myriad-rtems"
|
||||||
|
target datalayout = "E-m:e-p:32:32-i64:64-f128:64-n32-S64"
|
||||||
|
; CHECK: @llvm.global_ctors = {{.*}}@asan.module_ctor
|
||||||
|
|
||||||
|
define i32 @test_load(i32* %a) sanitize_address {
|
||||||
|
; CHECK-LABEL: @test_load
|
||||||
|
; CHECK-NOT: load
|
||||||
|
; CHECK: ptrtoint i32* %a to i32
|
||||||
|
; CHECK: %[[LOAD_ADDR:[^ ]*]] = and i32 %{{.*}}, -1073741825
|
||||||
|
; CHECK: lshr i32 %{{.*}}, 29
|
||||||
|
; CHECK: icmp eq i32 %{{.*}}, 4
|
||||||
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]]
|
||||||
|
;
|
||||||
|
; This block checks whether the shadow byte is 0.
|
||||||
|
; CHECK: lshr i32 %[[LOAD_ADDR]], 5
|
||||||
|
; CHECK: add i32 %{{.*}}, -1694498816
|
||||||
|
; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr
|
||||||
|
; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8, i8* %[[LOAD_SHADOW_PTR]]
|
||||||
|
; CHECK: icmp ne i8
|
||||||
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]]
|
||||||
|
;
|
||||||
|
; This block refines the shadow test.
|
||||||
|
; CHECK: and i32 %[[LOAD_ADDR]], 31
|
||||||
|
; CHECK: add i32 %{{.*}}, 3
|
||||||
|
; CHECK: trunc i32 %{{.*}} to i8
|
||||||
|
; CHECK: icmp sge i8 %{{.*}}, %[[LOAD_SHADOW]]
|
||||||
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
|
||||||
|
;
|
||||||
|
; The crash block reports the error.
|
||||||
|
; CHECK: call void @__asan_report_load4(i32 %[[LOAD_ADDR]])
|
||||||
|
; CHECK: unreachable
|
||||||
|
;
|
||||||
|
; The actual load.
|
||||||
|
; CHECK: %tmp1 = load i32, i32* %a
|
||||||
|
; CHECK: ret i32 %tmp1
|
||||||
|
|
||||||
|
entry:
|
||||||
|
%tmp1 = load i32, i32* %a, align 4
|
||||||
|
ret i32 %tmp1
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @test_store(i32* %a) sanitize_address {
|
||||||
|
; CHECK-LABEL: @test_store
|
||||||
|
; CHECK-NOT: store
|
||||||
|
; CHECK: ptrtoint i32* %a to i32
|
||||||
|
; CHECK: %[[STORE_ADDR:[^ ]*]] = and i32 %{{.*}}, -1073741825
|
||||||
|
; CHECK: lshr i32 %{{.*}}, 29
|
||||||
|
; CHECK: icmp eq i32 %{{.*}}, 4
|
||||||
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]]
|
||||||
|
;
|
||||||
|
; This block checks whether the shadow byte is 0.
|
||||||
|
; CHECK: lshr i32 %[[STORE_ADDR]], 5
|
||||||
|
; CHECK: add i32 %{{.*}}, -1694498816
|
||||||
|
; CHECK: %[[STORE_SHADOW_PTR:[^ ]*]] = inttoptr
|
||||||
|
; CHECK: %[[STORE_SHADOW:[^ ]*]] = load i8, i8* %[[STORE_SHADOW_PTR]]
|
||||||
|
; CHECK: icmp ne i8
|
||||||
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
|
||||||
|
;
|
||||||
|
; This block refines the shadow test.
|
||||||
|
; CHECK: and i32 %[[STORE_ADDR]], 31
|
||||||
|
; CHECK: add i32 %{{.*}}, 3
|
||||||
|
; CHECK: trunc i32 %{{.*}} to i8
|
||||||
|
; CHECK: icmp sge i8 %{{.*}}, %[[STORE_SHADOW]]
|
||||||
|
; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
|
||||||
|
;
|
||||||
|
; The crash block reports the error.
|
||||||
|
; CHECK: call void @__asan_report_store4(i32 %[[STORE_ADDR]])
|
||||||
|
; CHECK: unreachable
|
||||||
|
; The actual store.
|
||||||
|
; CHECK: store i32 42, i32* %a
|
||||||
|
; CHECK: ret void
|
||||||
|
;
|
||||||
|
|
||||||
|
entry:
|
||||||
|
store i32 42, i32* %a, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: define internal void @asan.module_ctor()
|
||||||
|
; CHECK: call void @__asan_init()
|
Loading…
Reference in New Issue
Block a user