11
11
#include " AArch64InstrInfo.h"
12
12
#include " AArch64Subtarget.h"
13
13
#include " AArch64TargetMachine.h"
14
+ #include " llvm/ADT/APInt.h"
14
15
#include " llvm/ADT/MapVector.h"
15
16
#include " llvm/ADT/SmallVector.h"
16
17
#include " llvm/ADT/Statistic.h"
21
22
#include " llvm/Analysis/ScalarEvolution.h"
22
23
#include " llvm/Analysis/ScalarEvolutionExpressions.h"
23
24
#include " llvm/Analysis/StackSafetyAnalysis.h"
25
+ #include " llvm/BinaryFormat/Dwarf.h"
24
26
#include " llvm/CodeGen/LiveRegUnits.h"
25
27
#include " llvm/CodeGen/MachineBasicBlock.h"
26
28
#include " llvm/CodeGen/MachineFunction.h"
@@ -82,6 +84,26 @@ static cl::opt<size_t> ClMaxLifetimes(
82
84
cl::desc(" How many lifetime ends to handle for a single alloca." ),
83
85
cl::Optional);
84
86
87
+ // Mode for selecting how to insert frame record info into the stack ring
88
+ // buffer.
89
+ enum RecordStackHistoryMode {
90
+ // Do not record frame record info.
91
+ none,
92
+
93
+ // Insert instructions into the prologue for storing into the stack ring
94
+ // buffer directly.
95
+ instr,
96
+ };
97
+
98
+ static cl::opt<RecordStackHistoryMode> ClRecordStackHistory (
99
+ " stack-tagging-record-stack-history" ,
100
+ cl::desc (" Record stack frames with tagged allocations in a thread-local "
101
+ " ring buffer" ),
102
+ cl::values(clEnumVal(none, " Do not record stack ring history" ),
103
+ clEnumVal(instr, " Insert instructions into the prologue for "
104
+ " storing into the stack ring buffer" )),
105
+ cl::Hidden, cl::init(none));
106
+
85
107
static const Align kTagGranuleSize = Align(16 );
86
108
87
109
namespace {
@@ -309,6 +331,7 @@ class AArch64StackTagging : public FunctionPass {
309
331
uint64_t Size , InitializerBuilder &IB);
310
332
311
333
Instruction *insertBaseTaggedPointer (
334
+ const Module &M,
312
335
const MapVector<AllocaInst *, memtag::AllocaInfo> &Allocas,
313
336
const DominatorTree *DT);
314
337
bool runOnFunction (Function &F) override ;
@@ -437,6 +460,7 @@ void AArch64StackTagging::untagAlloca(AllocaInst *AI, Instruction *InsertBefore,
437
460
}
438
461
439
462
Instruction *AArch64StackTagging::insertBaseTaggedPointer (
463
+ const Module &M,
440
464
const MapVector<AllocaInst *, memtag::AllocaInfo> &AllocasToInstrument,
441
465
const DominatorTree *DT) {
442
466
BasicBlock *PrologueBB = nullptr ;
@@ -458,6 +482,41 @@ Instruction *AArch64StackTagging::insertBaseTaggedPointer(
458
482
Instruction *Base =
459
483
IRB.CreateCall (IRG_SP, {Constant::getNullValue (IRB.getInt64Ty ())});
460
484
Base->setName (" basetag" );
485
+ auto TargetTriple = Triple (M.getTargetTriple ());
486
+ // This is not a stable ABI for now, so only allow in dev builds with API
487
+ // level 10000.
488
+ // The ThreadLong format is the same as with HWASan, but the entries for
489
+ // stack MTE take two slots (16 bytes).
490
+ if (ClRecordStackHistory == instr && TargetTriple.isAndroid () &&
491
+ TargetTriple.isAArch64 () && !TargetTriple.isAndroidVersionLT (10000 ) &&
492
+ !AllocasToInstrument.empty ()) {
493
+ constexpr int StackMteSlot = -3 ;
494
+ constexpr uint64_t TagMask = 0xFULL << 56 ;
495
+
496
+ auto *IntptrTy = IRB.getIntPtrTy (M.getDataLayout ());
497
+ Value *SlotPtr = memtag::getAndroidSlotPtr (IRB, StackMteSlot);
498
+ auto *ThreadLong = IRB.CreateLoad (IntptrTy, SlotPtr);
499
+ Value *TaggedFP = IRB.CreateOr (
500
+ memtag::getFP (IRB),
501
+ IRB.CreateAnd (IRB.CreatePtrToInt (Base, IntptrTy), TagMask));
502
+ Value *PC = memtag::getPC (TargetTriple, IRB);
503
+ Value *RecordPtr = IRB.CreateIntToPtr (ThreadLong, IRB.getPtrTy (0 ));
504
+ IRB.CreateStore (PC, RecordPtr);
505
+ IRB.CreateStore (TaggedFP, IRB.CreateConstGEP1_64 (IntptrTy, RecordPtr, 1 ));
506
+ // Update the ring buffer. Top byte of ThreadLong defines the size of the
507
+ // buffer in pages, it must be a power of two, and the start of the buffer
508
+ // must be aligned by twice that much. Therefore wrap around of the ring
509
+ // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
510
+ // The use of AShr instead of LShr is due to
511
+ // https://bugs.llvm.org/show_bug.cgi?id=39030
512
+ // Runtime library makes sure not to use the highest bit.
513
+ Value *WrapMask = IRB.CreateXor (
514
+ IRB.CreateShl (IRB.CreateAShr (ThreadLong, 56 ), 12 , " " , true , true ),
515
+ ConstantInt::get (IntptrTy, (uint64_t )-1 ));
516
+ Value *ThreadLongNew = IRB.CreateAnd (
517
+ IRB.CreateAdd (ThreadLong, ConstantInt::get (IntptrTy, 16 )), WrapMask);
518
+ IRB.CreateStore (ThreadLongNew, SlotPtr);
519
+ }
461
520
return Base;
462
521
}
463
522
@@ -513,7 +572,8 @@ bool AArch64StackTagging::runOnFunction(Function &Fn) {
513
572
SetTagFunc =
514
573
Intrinsic::getDeclaration (F->getParent (), Intrinsic::aarch64_settag);
515
574
516
- Instruction *Base = insertBaseTaggedPointer (SInfo.AllocasToInstrument , DT);
575
+ Instruction *Base =
576
+ insertBaseTaggedPointer (*Fn.getParent (), SInfo.AllocasToInstrument , DT);
517
577
518
578
int NextTag = 0 ;
519
579
for (auto &I : SInfo.AllocasToInstrument ) {
@@ -575,6 +635,8 @@ bool AArch64StackTagging::runOnFunction(Function &Fn) {
575
635
for (auto *II : Info.LifetimeEnd )
576
636
II->eraseFromParent ();
577
637
}
638
+
639
+ memtag::annotateDebugRecords (Info, static_cast <unsigned long >(Tag));
578
640
}
579
641
580
642
// If we have instrumented at least one alloca, all unrecognized lifetime
0 commit comments