[llvm] [BOLT] Gadget scanner: reformulate the state for data-flow analysis (PR #131898)
Anatoly Trosinenko via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 21 09:57:12 PDT 2025
https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/131898
>From 7e77ccb948b535a4e6c13786fbde9bffc4d8e431 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Mon, 17 Mar 2025 22:27:53 +0300
Subject: [PATCH] [BOLT] Gadget scanner: reformulate the state for data-flow
analysis
In preparation for implementing support for detection of non-protected
call instructions, refine the definition of state which is computed for
each register by data-flow analysis.
Explicitly marking the registers which are known to be trusted at
function entry is crucial for finding non-protected calls. In addition,
it fixes less-common false negatives for pac-ret, such as `ret x1` in
`f_nonx30_ret_non_auted` test case.
---
bolt/include/bolt/Core/MCPlusBuilder.h | 10 ++
bolt/include/bolt/Passes/PAuthGadgetScanner.h | 7 +-
bolt/lib/Passes/PAuthGadgetScanner.cpp | 129 +++++++++++-------
.../Target/AArch64/AArch64MCPlusBuilder.cpp | 4 +
.../AArch64/gs-pacret-autiasp.s | 19 ++-
.../AArch64/gs-pacret-multi-bb.s | 3 +-
.../AArch64/gs-pauth-debug-output.s | 72 +++++-----
7 files changed, 139 insertions(+), 105 deletions(-)
diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index b285138b77fe7..76ea2489e7038 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -551,6 +551,16 @@ class MCPlusBuilder {
return Analysis->isReturn(Inst);
}
+ /// Returns the registers that are trusted at function entry.
+ ///
+ /// Each register should be treated as if a successfully authenticated
+ /// pointer was written to it before entering the function (i.e. the
+ /// pointer is safe to jump to as well as to be signed).
+ virtual SmallVector<MCPhysReg> getTrustedLiveInRegs() const {
+ llvm_unreachable("not implemented");
+ return {};
+ }
+
virtual ErrorOr<MCPhysReg> getAuthenticatedReg(const MCInst &Inst) const {
llvm_unreachable("not implemented");
return getNoRegister();
diff --git a/bolt/include/bolt/Passes/PAuthGadgetScanner.h b/bolt/include/bolt/Passes/PAuthGadgetScanner.h
index 1a8abffa09c46..700059b814ab9 100644
--- a/bolt/include/bolt/Passes/PAuthGadgetScanner.h
+++ b/bolt/include/bolt/Passes/PAuthGadgetScanner.h
@@ -212,7 +212,7 @@ struct GadgetReport : public Report {
// The particular kind of gadget that is detected.
const GadgetKind &Kind;
// The set of registers related to this gadget report (possibly empty).
- SmallVector<MCPhysReg> AffectedRegisters;
+ SmallVector<MCPhysReg, 1> AffectedRegisters;
// The instructions that clobber the affected registers.
// There is no one-to-one correspondence with AffectedRegisters: for example,
// the same register can be overwritten by different instructions in different
@@ -220,9 +220,8 @@ struct GadgetReport : public Report {
SmallVector<MCInstReference> OverwritingInstrs;
GadgetReport(const GadgetKind &Kind, MCInstReference Location,
- const BitVector &AffectedRegisters)
- : Report(Location), Kind(Kind),
- AffectedRegisters(AffectedRegisters.set_bits()) {}
+ MCPhysReg AffectedRegister)
+ : Report(Location), Kind(Kind), AffectedRegisters({AffectedRegister}) {}
void generateReport(raw_ostream &OS, const BinaryContext &BC) const override;
diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp
index 84c209ac838f8..5269710e1c995 100644
--- a/bolt/lib/Passes/PAuthGadgetScanner.cpp
+++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp
@@ -126,18 +126,16 @@ class TrackedRegisters {
// The security property that is checked is:
// When a register is used as the address to jump to in a return instruction,
-// that register must either:
-// (a) never be changed within this function, i.e. have the same value as when
-// the function started, or
+// that register must be safe-to-dereference. It must either
+// (a) be safe-to-dereference at function entry and never be changed within this
+// function, i.e. have the same value as when the function started, or
// (b) the last write to the register must be by an authentication instruction.
// This property is checked by using dataflow analysis to keep track of which
-// registers have been written (def-ed), since last authenticated. Those are
-// exactly the registers containing values that should not be trusted (as they
-// could have changed since the last time they were authenticated). For pac-ret,
-// any return instruction using such a register is a gadget to be reported. For
-// PAuthABI, probably at least any indirect control flow using such a register
-// should be reported.
+// registers have been written (def-ed), since last authenticated. For pac-ret,
+// any return instruction using a register which is not safe-to-dereference is
+// a gadget to be reported. For PAuthABI, probably at least any indirect control
+// flow using such a register should be reported.
// Furthermore, when producing a diagnostic for a found non-pac-ret protected
// return, the analysis also lists the last instructions that wrote to the
@@ -156,10 +154,29 @@ class TrackedRegisters {
// in the gadgets to be reported. This information is used in the second run
// to also track which instructions last wrote to those registers.
+/// A state representing which registers are safe to use by an instruction
+/// at a given program point.
+///
+/// To simplify reasoning, let's stick with the following approach:
+/// * when state is updated by the data-flow analysis, the sub-, super- and
+/// overlapping registers are marked as needed
+/// * when the particular instruction is checked if it represents a gadget,
+/// the specific bit of BitVector should be usable to answer this.
+///
+/// For example, on AArch64:
+/// * An AUTIZA X0 instruction marks both X0 and W0 (as well as W0_HI) as
+/// safe-to-dereference. It does not change the state of X0_X1, for example,
+/// as super-registers partially retain their old, unsafe values.
+/// * LDR X1, [X0] marks as unsafe both X1 itself and anything it overlaps
+/// with: W1, W1_HI, X0_X1 and so on.
+/// * RET (which is implicitly RET X30) is a protected return if and only if
+/// X30 is safe-to-dereference - the state computed for sub- and
+/// super-registers is not inspected.
struct State {
- /// A BitVector containing the registers that have been clobbered, and
- /// not authenticated.
- BitVector NonAutClobRegs;
+ /// A BitVector containing the registers that are either safe at function
+ /// entry and were not clobbered yet, or those not clobbered since being
+ /// authenticated.
+ BitVector SafeToDerefRegs;
/// A vector of sets, only used in the second data flow run.
/// Each element in the vector represents one of the registers for which we
/// track the set of last instructions that wrote to this register. For
@@ -169,16 +186,26 @@ struct State {
std::vector<SmallPtrSet<const MCInst *, 4>> LastInstWritingReg;
State() {}
State(unsigned NumRegs, unsigned NumRegsToTrack)
- : NonAutClobRegs(NumRegs), LastInstWritingReg(NumRegsToTrack) {}
- State &operator|=(const State &StateIn) {
- NonAutClobRegs |= StateIn.NonAutClobRegs;
+ : SafeToDerefRegs(NumRegs), LastInstWritingReg(NumRegsToTrack) {}
+
+ /// Returns S, so that S.merge(S1) == S1.merge(S) == S1.
+ static State getMergeNeutralElement(unsigned NumRegs,
+ unsigned NumRegsToTrack) {
+ State S(NumRegs, NumRegsToTrack);
+ S.SafeToDerefRegs.set();
+ return S;
+ }
+
+ State &merge(const State &StateIn) {
+ SafeToDerefRegs &= StateIn.SafeToDerefRegs;
for (unsigned I = 0; I < LastInstWritingReg.size(); ++I)
for (const MCInst *J : StateIn.LastInstWritingReg[I])
LastInstWritingReg[I].insert(J);
return *this;
}
+
bool operator==(const State &RHS) const {
- return NonAutClobRegs == RHS.NonAutClobRegs &&
+ return SafeToDerefRegs == RHS.SafeToDerefRegs &&
LastInstWritingReg == RHS.LastInstWritingReg;
}
bool operator!=(const State &RHS) const { return !((*this) == RHS); }
@@ -199,7 +226,7 @@ static void printLastInsts(
raw_ostream &operator<<(raw_ostream &OS, const State &S) {
OS << "pacret-state<";
- OS << "NonAutClobRegs: " << S.NonAutClobRegs << ", ";
+ OS << "SafeToDerefRegs: " << S.SafeToDerefRegs << ", ";
printLastInsts(OS, S.LastInstWritingReg);
OS << ">";
return OS;
@@ -217,8 +244,8 @@ class PacStatePrinter {
void PacStatePrinter::print(raw_ostream &OS, const State &S) const {
RegStatePrinter RegStatePrinter(BC);
OS << "pacret-state<";
- OS << "NonAutClobRegs: ";
- RegStatePrinter.print(OS, S.NonAutClobRegs);
+ OS << "SafeToDerefRegs: ";
+ RegStatePrinter.print(OS, S.SafeToDerefRegs);
OS << ", ";
printLastInsts(OS, S.LastInstWritingReg);
OS << ">";
@@ -257,12 +284,24 @@ class PacRetAnalysis
void preflight() {}
+ State createEntryState() {
+ State S(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
+ for (MCPhysReg Reg : BC.MIB->getTrustedLiveInRegs())
+ S.SafeToDerefRegs |= BC.MIB->getAliases(Reg, /*OnlySmaller=*/true);
+ return S;
+ }
+
State getStartingStateAtBB(const BinaryBasicBlock &BB) {
- return State(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
+ if (BB.isEntryPoint())
+ return createEntryState();
+
+ return State::getMergeNeutralElement(
+ NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
}
State getStartingStateAtPoint(const MCInst &Point) {
- return State(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
+ return State::getMergeNeutralElement(
+ NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
}
void doConfluence(State &StateOut, const State &StateIn) {
@@ -277,7 +316,7 @@ class PacRetAnalysis
dbgs() << ")\n";
});
- StateOut |= StateIn;
+ StateOut.merge(StateIn);
LLVM_DEBUG({
dbgs() << " merged state: ";
@@ -298,7 +337,7 @@ class PacRetAnalysis
});
State Next = Cur;
- BitVector Written = BitVector(NumRegs, false);
+ BitVector Clobbered(NumRegs, false);
// Assume a call can clobber all registers, including callee-saved
// registers. There's a good chance that callee-saved registers will be
// saved on the stack at some point during execution of the callee.
@@ -307,36 +346,27 @@ class PacRetAnalysis
// Also, not all functions may respect the AAPCS ABI rules about
// caller/callee-saved registers.
if (BC.MIB->isCall(Point))
- Written.set();
+ Clobbered.set();
else
- // FIXME: `getWrittenRegs` only sets the register directly written in the
- // instruction, and the smaller aliasing registers. It does not set the
- // larger aliasing registers. To also set the larger aliasing registers,
- // we'd have to call `getClobberedRegs`.
- // It is unclear if there is any test case which shows a different
- // behaviour between using `getWrittenRegs` vs `getClobberedRegs`. We'd
- // first would like to see such a test case before making a decision
- // on whether using `getClobberedRegs` below would be better.
- // Also see the discussion on this at
- // https://github.com/llvm/llvm-project/pull/122304#discussion_r1939511909
- BC.MIB->getWrittenRegs(Point, Written);
- Next.NonAutClobRegs |= Written;
+ BC.MIB->getClobberedRegs(Point, Clobbered);
+ Next.SafeToDerefRegs.reset(Clobbered);
// Keep track of this instruction if it writes to any of the registers we
// need to track that for:
for (MCPhysReg Reg : RegsToTrackInstsFor.getRegisters())
- if (Written[Reg])
+ if (Clobbered[Reg])
lastWritingInsts(Next, Reg) = {&Point};
ErrorOr<MCPhysReg> AutReg = BC.MIB->getAuthenticatedReg(Point);
if (AutReg && *AutReg != BC.MIB->getNoRegister()) {
- // FIXME: should we use `OnlySmaller=false` below? See similar
- // FIXME about `getWrittenRegs` above and further discussion about this
- // at
- // https://github.com/llvm/llvm-project/pull/122304#discussion_r1939515516
- Next.NonAutClobRegs.reset(
- BC.MIB->getAliases(*AutReg, /*OnlySmaller=*/true));
- if (RegsToTrackInstsFor.isTracked(*AutReg))
- lastWritingInsts(Next, *AutReg).clear();
+ // The sub-registers of *AutReg are also trusted now, but not its
+ // super-registers (as they retain untrusted register units).
+ BitVector AuthenticatedSubregs =
+ BC.MIB->getAliases(*AutReg, /*OnlySmaller=*/true);
+ for (MCPhysReg Reg : AuthenticatedSubregs.set_bits()) {
+ Next.SafeToDerefRegs.set(Reg);
+ if (RegsToTrackInstsFor.isTracked(Reg))
+ lastWritingInsts(Next, Reg).clear();
+ }
}
LLVM_DEBUG({
@@ -397,14 +427,11 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
});
if (BC.MIB->isAuthenticationOfReg(Inst, RetReg))
return nullptr;
- BitVector UsedDirtyRegs = S.NonAutClobRegs;
- LLVM_DEBUG({ traceRegMask(BC, "NonAutClobRegs at Ret", UsedDirtyRegs); });
- UsedDirtyRegs &= BC.MIB->getAliases(RetReg, /*OnlySmaller=*/true);
- LLVM_DEBUG({ traceRegMask(BC, "Intersection with RetReg", UsedDirtyRegs); });
- if (!UsedDirtyRegs.any())
+ LLVM_DEBUG({ traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs); });
+ if (S.SafeToDerefRegs[RetReg])
return nullptr;
- return std::make_shared<GadgetReport>(RetKind, Inst, UsedDirtyRegs);
+ return std::make_shared<GadgetReport>(RetKind, Inst, RetReg);
}
FunctionAnalysisResult
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 613b24c4553e2..d238a1df5c7d7 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -191,6 +191,10 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
return false;
}
+ SmallVector<MCPhysReg> getTrustedLiveInRegs() const override {
+ return {AArch64::LR};
+ }
+
ErrorOr<MCPhysReg> getAuthenticatedReg(const MCInst &Inst) const override {
switch (Inst.getOpcode()) {
case AArch64::AUTIAZ:
diff --git a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s
index 0d263199b376f..586da6d2a92e4 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s
@@ -183,17 +183,14 @@ f_tail_called:
.globl f_nonx30_ret_non_auted
.type f_nonx30_ret_non_auted, at function
f_nonx30_ret_non_auted:
-// FIXME: x1 is not authenticated, so should this be reported?
-// Note that we assume it's fine for x30 to not be authenticated before
-// returning to, as assuming that x30 is not attacker controlled at function
-// entry is part (implicitly) of the pac-ret hardening scheme.
-// It's probably an open question whether for other hardening schemes, such as
-// PAuthABI, which registers should be considered "clean" or not at function entry.
-// In other words, which registers have to be authenticated before being used as
-// a pointer and which ones not?
-// For a more detailed discussion, see
-// https://github.com/llvm/llvm-project/pull/122304#discussion_r1923662744
-// CHECK-NOT: f_nonx30_ret_non_auted
+// x1 is neither authenticated nor implicitly considered safe at function entry.
+// Note that we assume it's fine for x30 to not be authenticated before
+// returning to, as assuming that x30 is not attacker controlled at function
+// entry is part (implicitly) of the pac-ret hardening scheme.
+//
+// CHECK-LABEL: GS-PAUTH: non-protected ret found in function f_nonx30_ret_non_auted, basic block {{[0-9a-zA-Z.]+}}, at address
+// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret
+// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
ret x1
.size f_nonx30_ret_non_auted, .-f_nonx30_ret_non_auted
diff --git a/bolt/test/binary-analysis/AArch64/gs-pacret-multi-bb.s b/bolt/test/binary-analysis/AArch64/gs-pacret-multi-bb.s
index f74e825ed8fc1..bd8edbc676c34 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pacret-multi-bb.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pacret-multi-bb.s
@@ -17,9 +17,8 @@ f_crossbb1:
.size f_crossbb1, .-f_crossbb1
// CHECK-LABEL: GS-PAUTH: non-protected ret found in function f_crossbb1, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret
-// CHECK-NEXT: The 2 instructions that write to the affected registers after any authentication are:
+// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10
-// CHECK-NEXT: 2. {{[0-9a-f]+}}: autiasp
// A test that checks that the dataflow state tracking across when merging BBs
// seems to work:
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s
index 18e0fbfb850e7..d4371abdd12b0 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s
@@ -40,26 +40,26 @@ simple:
// CHECK-NEXT: <empty>
// CHECK-NEXT: End of Function "simple"
// CHECK-EMPTY:
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #25, pacret-state<NonAutClobRegs: , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( b [[BB1]], pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #25, pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: , Insts: >)
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( b [[BB1]], pacret-state<SafeToDerefRegs: , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: PacRetAnalysis::Confluence(
-// CHECK-NEXT: State 1: pacret-state<NonAutClobRegs: , Insts: >
-// CHECK-NEXT: State 2: pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
-// CHECK-NEXT: merged state: pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #29, pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: , Insts: >)
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<NonAutClobRegs: , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: , Insts: >)
+// CHECK-NEXT: State 1: pacret-state<SafeToDerefRegs: (all), Insts: >
+// CHECK-NEXT: State 2: pacret-state<SafeToDerefRegs: , Insts: >)
+// CHECK-NEXT: merged state: pacret-state<SafeToDerefRegs: , Insts: >
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #29, pacret-state<SafeToDerefRegs: , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: PacRetAnalysis::Confluence(
-// CHECK-NEXT: State 1: pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >
-// CHECK-NEXT: State 2: pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
-// CHECK-NEXT: merged state: pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #29, pacret-state<NonAutClobRegs: LR W30 W30_HI , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: , Insts: >)
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<NonAutClobRegs: , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: , Insts: >)
+// CHECK-NEXT: State 1: pacret-state<SafeToDerefRegs: , Insts: >
+// CHECK-NEXT: State 2: pacret-state<SafeToDerefRegs: , Insts: >)
+// CHECK-NEXT: merged state: pacret-state<SafeToDerefRegs: , Insts: >
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #29, pacret-state<SafeToDerefRegs: , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: After PacRetAnalysis:
// CHECK-NEXT: Binary Function "simple" {
// CHECK-NEXT: Number : 1
@@ -69,24 +69,23 @@ simple:
// CHECK-NEXT: }
// CHECK-NEXT: [[BB0]] (2 instructions, align : 1)
// CHECK-NEXT: Entry Point
-// CHECK-NEXT: 00000000: paciasp # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: >
-// CHECK-NEXT: 00000004: b [[BB1]] # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: >
+// CHECK-NEXT: 00000000: paciasp # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: >
+// CHECK-NEXT: 00000004: b [[BB1]] # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: Successors: [[BB1]]
// CHECK-EMPTY:
// CHECK-NEXT: [[BB1]] (2 instructions, align : 1)
// CHECK-NEXT: Predecessors: [[BB0]]
-// CHECK-NEXT: 00000008: autiasp # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: >
-// CHECK-NEXT: 0000000c: ret # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: >
+// CHECK-NEXT: 00000008: autiasp # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: >
+// CHECK-NEXT: 0000000c: ret # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-EMPTY:
// CHECK-NEXT: DWARF CFI Instructions:
// CHECK-NEXT: <empty>
// CHECK-NEXT: End of Function "simple"
// CHECK-EMPTY:
-// CHECK-NEXT: Found RET inst: 00000000: ret # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: >
+// CHECK-NEXT: Found RET inst: 00000000: ret # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: RetReg: LR
// CHECK-NEXT: Authenticated reg: (none)
-// CHECK-NEXT: NonAutClobRegs at Ret:{{[ \t]*$}}
-// CHECK-NEXT: Intersection with RetReg:{{[ \t]*$}}
+// CHECK-NEXT: SafeToDerefRegs: LR W30 W30_HI{{[ \t]*$}}
.globl clobber
.type clobber, at function
@@ -97,10 +96,10 @@ clobber:
// CHECK-LABEL:Analyzing in function clobber, AllocatorId 1
// ...
-// CHECK: PacRetAnalysis::ComputeNext( mov w30, #0x0, pacret-state<NonAutClobRegs: , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: W30 , Insts: >)
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<NonAutClobRegs: W30 , Insts: >)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: W30 , Insts: >)
+// CHECK: PacRetAnalysis::ComputeNext( mov w30, #0x0, pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: W30_HI , Insts: >)
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<SafeToDerefRegs: W30_HI , Insts: >)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: W30_HI , Insts: >)
// CHECK-NEXT: After PacRetAnalysis:
// CHECK-NEXT: Binary Function "clobber" {
// ...
@@ -109,15 +108,14 @@ clobber:
// The above output was printed after first run of analysis
// CHECK-EMPTY:
-// CHECK-NEXT: Found RET inst: 00000000: ret # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: >
+// CHECK-NEXT: Found RET inst: 00000000: ret # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: RetReg: LR
// CHECK-NEXT: Authenticated reg: (none)
-// CHECK-NEXT: NonAutClobRegs at Ret: W30
-// CHECK-NEXT: Intersection with RetReg: W30
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( mov w30, #0x0, pacret-state<NonAutClobRegs: , Insts: [0]()>)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: W30 , Insts: [0](0x{{[0-9a-f]+}} )>)
-// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<NonAutClobRegs: W30 , Insts: [0](0x{{[0-9a-f]+}} )>)
-// CHECK-NEXT: .. result: (pacret-state<NonAutClobRegs: W30 , Insts: [0](0x{{[0-9a-f]+}} )>)
+// CHECK-NEXT: SafeToDerefRegs: W30_HI{{[ \t]*$}}
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( mov w30, #0x0, pacret-state<SafeToDerefRegs: LR W30 W30_HI , Insts: [0]()>)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
+// CHECK-NEXT: PacRetAnalysis::ComputeNext( ret x30, pacret-state<SafeToDerefRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
+// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: After detailed PacRetAnalysis:
// CHECK-NEXT: Binary Function "clobber" {
// ...
@@ -127,7 +125,7 @@ clobber:
// Iterating over the reports and attaching clobbering info:
// CHECK-EMPTY:
-// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # PacRetAnalysis: pacret-state<NonAutClobRegs: BitVector, Insts: [0](0x{{[0-9a-f]+}} )>
+// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # PacRetAnalysis: pacret-state<SafeToDerefRegs: BitVector, Insts: [0](0x{{[0-9a-f]+}} )>
// CHECK-LABEL:Analyzing in function main, AllocatorId 1
More information about the llvm-commits
mailing list