Skip to content

Commit 0ed1763

Browse files
committed
[MTE] add stack frame history buffer
this will allow us to find offending objects in a symbolization step, like we can do with hwasan. needs matching changes in AOSP: https://android-review.git.corp.google.com/q/topic:%22stackhistorybuffer%22 Pull Request: llvm#86356
1 parent d484c4d commit 0ed1763

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2497,7 +2497,8 @@ AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
24972497
return resolveFrameIndexReference(
24982498
MF, FI, FrameReg,
24992499
/*PreferFP=*/
2500-
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress),
2500+
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress) ||
2501+
MF.getFunction().hasFnAttribute(Attribute::SanitizeMemTag),
25012502
/*ForSimm=*/false);
25022503
}
25032504

llvm/lib/Target/AArch64/AArch64StackTagging.cpp

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "AArch64InstrInfo.h"
1212
#include "AArch64Subtarget.h"
1313
#include "AArch64TargetMachine.h"
14+
#include "llvm/ADT/APInt.h"
1415
#include "llvm/ADT/MapVector.h"
1516
#include "llvm/ADT/SmallVector.h"
1617
#include "llvm/ADT/Statistic.h"
@@ -21,6 +22,7 @@
2122
#include "llvm/Analysis/ScalarEvolution.h"
2223
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
2324
#include "llvm/Analysis/StackSafetyAnalysis.h"
25+
#include "llvm/BinaryFormat/Dwarf.h"
2426
#include "llvm/CodeGen/LiveRegUnits.h"
2527
#include "llvm/CodeGen/MachineBasicBlock.h"
2628
#include "llvm/CodeGen/MachineFunction.h"
@@ -82,6 +84,26 @@ static cl::opt<size_t> ClMaxLifetimes(
8284
cl::desc("How many lifetime ends to handle for a single alloca."),
8385
cl::Optional);
8486

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+
85107
static const Align kTagGranuleSize = Align(16);
86108

87109
namespace {
@@ -309,6 +331,7 @@ class AArch64StackTagging : public FunctionPass {
309331
uint64_t Size, InitializerBuilder &IB);
310332

311333
Instruction *insertBaseTaggedPointer(
334+
const Module &M,
312335
const MapVector<AllocaInst *, memtag::AllocaInfo> &Allocas,
313336
const DominatorTree *DT);
314337
bool runOnFunction(Function &F) override;
@@ -437,6 +460,7 @@ void AArch64StackTagging::untagAlloca(AllocaInst *AI, Instruction *InsertBefore,
437460
}
438461

439462
Instruction *AArch64StackTagging::insertBaseTaggedPointer(
463+
const Module &M,
440464
const MapVector<AllocaInst *, memtag::AllocaInfo> &AllocasToInstrument,
441465
const DominatorTree *DT) {
442466
BasicBlock *PrologueBB = nullptr;
@@ -458,6 +482,39 @@ Instruction *AArch64StackTagging::insertBaseTaggedPointer(
458482
Instruction *Base =
459483
IRB.CreateCall(IRG_SP, {Constant::getNullValue(IRB.getInt64Ty())});
460484
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+
if (ClRecordStackHistory == instr && TargetTriple.isAndroid() &&
489+
TargetTriple.isAArch64() && !TargetTriple.isAndroidVersionLT(10000) &&
490+
!AllocasToInstrument.empty()) {
491+
constexpr int StackMteSlot = -3;
492+
constexpr uint64_t TagMask = 0xFULL << 56;
493+
494+
auto *IntptrTy = IRB.getIntPtrTy(M.getDataLayout());
495+
Value *SlotPtr = memtag::getAndroidSlotPtr(IRB, StackMteSlot);
496+
auto *ThreadLong = IRB.CreateLoad(IntptrTy, SlotPtr);
497+
Value *TaggedFP = IRB.CreateOr(
498+
memtag::getFP(IRB),
499+
IRB.CreateAnd(IRB.CreatePtrToInt(Base, IntptrTy), TagMask));
500+
Value *PC = memtag::getPC(TargetTriple, IRB);
501+
Value *RecordPtr = IRB.CreateIntToPtr(ThreadLong, IRB.getPtrTy(0));
502+
IRB.CreateStore(PC, RecordPtr);
503+
IRB.CreateStore(TaggedFP, IRB.CreateConstGEP1_64(IntptrTy, RecordPtr, 1));
504+
// Update the ring buffer. Top byte of ThreadLong defines the size of the
505+
// buffer in pages, it must be a power of two, and the start of the buffer
506+
// must be aligned by twice that much. Therefore wrap around of the ring
507+
// buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
508+
// The use of AShr instead of LShr is due to
509+
// https://bugs.llvm.org/show_bug.cgi?id=39030
510+
// Runtime library makes sure not to use the highest bit.
511+
Value *WrapMask = IRB.CreateXor(
512+
IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),
513+
ConstantInt::get(IntptrTy, (uint64_t)-1));
514+
Value *ThreadLongNew = IRB.CreateAnd(
515+
IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 16)), WrapMask);
516+
IRB.CreateStore(ThreadLongNew, SlotPtr);
517+
}
461518
return Base;
462519
}
463520

@@ -513,7 +570,8 @@ bool AArch64StackTagging::runOnFunction(Function &Fn) {
513570
SetTagFunc =
514571
Intrinsic::getDeclaration(F->getParent(), Intrinsic::aarch64_settag);
515572

516-
Instruction *Base = insertBaseTaggedPointer(SInfo.AllocasToInstrument, DT);
573+
Instruction *Base =
574+
insertBaseTaggedPointer(*Fn.getParent(), SInfo.AllocasToInstrument, DT);
517575

518576
int NextTag = 0;
519577
for (auto &I : SInfo.AllocasToInstrument) {
@@ -575,6 +633,8 @@ bool AArch64StackTagging::runOnFunction(Function &Fn) {
575633
for (auto *II : Info.LifetimeEnd)
576634
II->eraseFromParent();
577635
}
636+
637+
memtag::annotateDebugRecords(Info, static_cast<unsigned long>(Tag));
578638
}
579639

580640
// If we have instrumented at least one alloca, all unrecognized lifetime

0 commit comments

Comments
 (0)