[llvm] [BOLT] Gadget scanner: implement finer-grained --scanners option (PR #176135)

Anatoly Trosinenko via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 12 05:06:26 PDT 2026


https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/176135

>From b1c4456dd921c0831222d4b58c400297620ae509 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 14 Jan 2026 16:54:35 +0300
Subject: [PATCH 1/3] [BOLT] Gadget scanner: implement finer-grained --scanners
 option

Add separate options to enable each of the available gadget detectors.
Furthermore, add two meta-options enabling all PtrAuth scanners and all
available scanners of any type (which is only PtrAuth for now, though).

This commit renames `pacret` option to `ptrauth-pac-ret` and `pauth` to
`ptrauth-all`.
---
 bolt/include/bolt/Passes/PAuthGadgetScanner.h |  19 ++-
 bolt/include/bolt/Utils/CommandLineOpts.h     |  23 +++-
 bolt/lib/Passes/PAuthGadgetScanner.cpp        |  46 ++++---
 bolt/lib/Rewrite/RewriteInstance.cpp          |  37 +++---
 .../binary-analysis/AArch64/cmdline-args.test |  13 +-
 .../AArch64/gs-pacret-autiasp.s               |   2 +-
 .../AArch64/gs-pacret-multi-bb.s              |   2 +-
 .../AArch64/gs-pauth-address-checks.s         |   2 +-
 .../gs-pauth-address-materialization.s        |   2 +-
 .../AArch64/gs-pauth-authentication-oracles.s |   6 +-
 .../binary-analysis/AArch64/gs-pauth-calls.s  |   7 +-
 .../AArch64/gs-pauth-debug-output.s           |   8 +-
 .../AArch64/gs-pauth-scanners.s               | 124 ++++++++++++++++++
 .../AArch64/gs-pauth-signing-oracles.s        |   7 +-
 .../AArch64/gs-pauth-tail-calls.s             |   7 +-
 .../AArch64/trap-instructions.s               |   2 +-
 16 files changed, 235 insertions(+), 72 deletions(-)
 create mode 100644 bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s

diff --git a/bolt/include/bolt/Passes/PAuthGadgetScanner.h b/bolt/include/bolt/Passes/PAuthGadgetScanner.h
index cb865a725d72a..8482793339be6 100644
--- a/bolt/include/bolt/Passes/PAuthGadgetScanner.h
+++ b/bolt/include/bolt/Passes/PAuthGadgetScanner.h
@@ -161,7 +161,8 @@ class FunctionAnalysisContext {
   MCPlusBuilder::AllocatorIdTy AllocatorId;
   FunctionAnalysisResult Result;
 
-  bool PacRetGadgetsOnly;
+  /// Bitmask of detectors to run (see opts::GadgetScannerKind).
+  uint64_t EnabledDetectorsMask;
 
   void findUnsafeUses(SmallVector<PartialReport<MCPhysReg>> &Reports);
   void augmentUnsafeUseReports(ArrayRef<PartialReport<MCPhysReg>> Reports);
@@ -176,9 +177,9 @@ class FunctionAnalysisContext {
 public:
   FunctionAnalysisContext(BinaryFunction &BF,
                           MCPlusBuilder::AllocatorIdTy AllocatorId,
-                          bool PacRetGadgetsOnly)
+                          uint64_t EnabledDetectorsMask)
       : BC(BF.getBinaryContext()), BF(BF), AllocatorId(AllocatorId),
-        PacRetGadgetsOnly(PacRetGadgetsOnly) {}
+        EnabledDetectorsMask(EnabledDetectorsMask) {}
 
   void run();
 
@@ -186,8 +187,8 @@ class FunctionAnalysisContext {
 };
 
 class Analysis : public BinaryFunctionPass {
-  /// Only search for pac-ret violations.
-  bool PacRetGadgetsOnly;
+  /// Bitmask of detectors to run (see opts::GadgetScannerKind).
+  uint64_t EnabledDetectorsMask;
 
   void runOnFunction(BinaryFunction &Function,
                      MCPlusBuilder::AllocatorIdTy AllocatorId);
@@ -196,8 +197,12 @@ class Analysis : public BinaryFunctionPass {
   std::mutex AnalysisResultsMutex;
 
 public:
-  explicit Analysis(bool PacRetGadgetsOnly)
-      : BinaryFunctionPass(false), PacRetGadgetsOnly(PacRetGadgetsOnly) {}
+  /// Constructs the analysis pass.
+  ///
+  /// EnabledDetectorsMask selects the checks to perform, see
+  /// opts::GadgetScannerKind for the available GS_PTRAUTH_* options.
+  explicit Analysis(uint64_t EnabledDetectorsMask)
+      : BinaryFunctionPass(false), EnabledDetectorsMask(EnabledDetectorsMask) {}
 
   const char *getName() const override { return "pauth-gadget-scanner"; }
 
diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h
index 5c7f1b94315f0..5bd83c17aa900 100644
--- a/bolt/include/bolt/Utils/CommandLineOpts.h
+++ b/bolt/include/bolt/Utils/CommandLineOpts.h
@@ -130,9 +130,26 @@ bool processAllFunctions();
 /// Return true if we should dump dot graphs for the given function.
 bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
 
-enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
-
-extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
+enum GadgetScannerKind : uint64_t {
+  /// Scan for unprotected backward control-flow (return instructions).
+  GS_PTRAUTH_RETURN_TARGETS = (1 << 0),
+  /// Scan for tail calls performed with untrusted link register.
+  GS_PTRAUTH_TAIL_CALLS = (1 << 1),
+  /// Scan for unprotected forward control-flow (branch and call instructions).
+  GS_PTRAUTH_BRANCH_AND_CALL_TARGETS = (1 << 2),
+  /// Scan for signing oracles.
+  GS_PTRAUTH_SIGN_ORACLES = (1 << 3),
+  /// Scan for authentication oracles.
+  GS_PTRAUTH_AUTH_ORACLES = (1 << 4),
+
+  /// Scan for all Pointer Authentication issues.
+  GS_PTRAUTH_ALL_MASK = GS_PTRAUTH_RETURN_TARGETS | GS_PTRAUTH_TAIL_CALLS |
+                        GS_PTRAUTH_BRANCH_AND_CALL_TARGETS |
+                        GS_PTRAUTH_SIGN_ORACLES | GS_PTRAUTH_AUTH_ORACLES,
+
+  /// Run all implemented scanners.
+  GS_ALL_MASK = GS_PTRAUTH_ALL_MASK,
+};
 
 } // namespace opts
 
diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp
index 22ceeabe36c67..64a197ea9c5a1 100644
--- a/bolt/lib/Passes/PAuthGadgetScanner.cpp
+++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp
@@ -1553,6 +1553,12 @@ collectRegsToTrack(ArrayRef<PartialReport<MCPhysReg>> Reports) {
 
 void FunctionAnalysisContext::findUnsafeUses(
     SmallVector<PartialReport<MCPhysReg>> &Reports) {
+  using GSK = opts::GadgetScannerKind;
+  const uint64_t HandledDetectorsMask =
+      GSK::GS_PTRAUTH_ALL_MASK & ~GSK::GS_PTRAUTH_AUTH_ORACLES;
+  if (0 == (EnabledDetectorsMask & HandledDetectorsMask))
+    return;
+
   auto Analysis = SrcSafetyAnalysis::create(BF, AllocatorId, {});
   LLVM_DEBUG(dbgs() << "Running src register safety analysis...\n");
   Analysis->run();
@@ -1617,19 +1623,22 @@ void FunctionAnalysisContext::findUnsafeUses(
       return;
     }
 
-    if (auto Report = shouldReportReturnGadget(BC, Inst, S))
-      Reports.push_back(*Report);
-
-    if (PacRetGadgetsOnly)
-      return;
-
-    if (auto Report = shouldReportUnsafeTailCall(BC, BF, Inst, S))
-      Reports.push_back(*Report);
-
-    if (auto Report = shouldReportCallGadget(BC, Inst, S))
-      Reports.push_back(*Report);
-    if (auto Report = shouldReportSigningOracle(BC, Inst, S))
-      Reports.push_back(*Report);
+    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_RETURN_TARGETS) {
+      if (auto Report = shouldReportReturnGadget(BC, Inst, S))
+        Reports.push_back(*Report);
+    }
+    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_TAIL_CALLS) {
+      if (auto Report = shouldReportUnsafeTailCall(BC, BF, Inst, S))
+        Reports.push_back(*Report);
+    }
+    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_BRANCH_AND_CALL_TARGETS) {
+      if (auto Report = shouldReportCallGadget(BC, Inst, S))
+        Reports.push_back(*Report);
+    }
+    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_SIGN_ORACLES) {
+      if (auto Report = shouldReportSigningOracle(BC, Inst, S))
+        Reports.push_back(*Report);
+    }
   });
 }
 
@@ -1660,8 +1669,11 @@ void FunctionAnalysisContext::augmentUnsafeUseReports(
 
 void FunctionAnalysisContext::findUnsafeDefs(
     SmallVector<PartialReport<MCPhysReg>> &Reports) {
-  if (PacRetGadgetsOnly)
+  using GSK = opts::GadgetScannerKind;
+  const uint64_t HandledDetectorsMask = GSK::GS_PTRAUTH_AUTH_ORACLES;
+  if (0 == (EnabledDetectorsMask & HandledDetectorsMask))
     return;
+
   if (AuthTrapsOnFailure)
     return;
 
@@ -1741,7 +1753,7 @@ void FunctionAnalysisContext::run() {
 
 void Analysis::runOnFunction(BinaryFunction &BF,
                              MCPlusBuilder::AllocatorIdTy AllocatorId) {
-  FunctionAnalysisContext FA(BF, AllocatorId, PacRetGadgetsOnly);
+  FunctionAnalysisContext FA(BF, AllocatorId, EnabledDetectorsMask);
   FA.run();
 
   const FunctionAnalysisResult &FAR = FA.getResult();
@@ -1850,6 +1862,10 @@ void GenericDiagnostic::generateReport(raw_ostream &OS,
 }
 
 Error Analysis::runOnFunctions(BinaryContext &BC) {
+  using GSK = opts::GadgetScannerKind;
+  assert(0 == (EnabledDetectorsMask & ~GSK::GS_PTRAUTH_ALL_MASK) &&
+         "Unrelated detectors requested");
+
   ParallelUtilities::WorkFuncWithAllocTy WorkFun =
       [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
         runOnFunction(BF, AllocatorId);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index cd99b04057a18..c84aabfe2e4ca 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -286,13 +286,23 @@ static cl::opt<bool> WriteBoltInfoSection(
     "bolt-info", cl::desc("write bolt info section in the output binary"),
     cl::init(true), cl::Hidden, cl::cat(BoltOutputCategory));
 
-cl::bits<GadgetScannerKind> GadgetScannersToRun(
-    "scanners", cl::desc("which gadget scanners to run"),
+static cl::list<GadgetScannerKind> GadgetScannersToRun(
+    "scanners", cl::desc("Which gadget scanners to run"),
     cl::values(
-        clEnumValN(GS_PACRET, "pacret",
-                   "pac-ret: return address protection (subset of \"pauth\")"),
-        clEnumValN(GS_PAUTH, "pauth", "All Pointer Authentication scanners"),
-        clEnumValN(GS_ALL, "all", "All implemented scanners")),
+        clEnumValN(GS_PTRAUTH_RETURN_TARGETS, "ptrauth-pac-ret",
+                   "Unprotected returns (pac-ret)"),
+        clEnumValN(GS_PTRAUTH_TAIL_CALLS, "ptrauth-tail-calls",
+                   "Tail calls performed with unprotected link register"),
+        clEnumValN(GS_PTRAUTH_BRANCH_AND_CALL_TARGETS, "ptrauth-forward-cf",
+                   "Unprotected calls and branches (forward control-flow)"),
+        clEnumValN(GS_PTRAUTH_SIGN_ORACLES, "ptrauth-sign-oracles",
+                   "Signing of untrusted pointers (signing oracles)"),
+        clEnumValN(GS_PTRAUTH_AUTH_ORACLES, "ptrauth-auth-oracles",
+                   "Authentication oracles"),
+
+        clEnumValN(GS_PTRAUTH_ALL_MASK, "ptrauth-all",
+                   "All Pointer Authentication scanners"),
+        clEnumValN(GS_ALL_MASK, "all", "All implemented scanners")),
     cl::ZeroOrMore, cl::CommaSeparated, cl::cat(BinaryAnalysisCategory));
 
 // Primary targets for hooking runtime library initialization hooking
@@ -3872,16 +3882,13 @@ void RewriteInstance::runBinaryAnalyses() {
   using PAuthScanner = PAuthGadgetScanner::Analysis;
 
   // If no command line option was given, act as if "all" was specified.
-  bool RunAll = !opts::GadgetScannersToRun.getBits() ||
-                opts::GadgetScannersToRun.isSet(GSK::GS_ALL);
+  uint64_t AnalysesMask = 0;
+  for (uint64_t Submask : opts::GadgetScannersToRun)
+    AnalysesMask |= Submask;
 
-  if (RunAll || opts::GadgetScannersToRun.isSet(GSK::GS_PAUTH)) {
-    Manager.registerPass(
-        std::make_unique<PAuthScanner>(/*OnlyPacRetChecks=*/false));
-  } else if (RunAll || opts::GadgetScannersToRun.isSet(GSK::GS_PACRET)) {
-    Manager.registerPass(
-        std::make_unique<PAuthScanner>(/*OnlyPacRetChecks=*/true));
-  }
+  uint64_t PAuthAnalysesMask = AnalysesMask & GSK::GS_PTRAUTH_ALL_MASK;
+  if (PAuthAnalysesMask)
+    Manager.registerPass(std::make_unique<PAuthScanner>(PAuthAnalysesMask));
 
   BC->logBOLTErrorsAndQuitOnFatal(Manager.runPasses());
 }
diff --git a/bolt/test/binary-analysis/AArch64/cmdline-args.test b/bolt/test/binary-analysis/AArch64/cmdline-args.test
index 9660ad3bf80f7..3221078951ab3 100644
--- a/bolt/test/binary-analysis/AArch64/cmdline-args.test
+++ b/bolt/test/binary-analysis/AArch64/cmdline-args.test
@@ -34,9 +34,14 @@ HELP-EMPTY:
 HELP-NEXT:  BinaryAnalysis options:
 HELP-EMPTY:
 HELP-NEXT:   --auth-traps-on-failure - Assume authentication instructions always trap on failure
-HELP-NEXT:   --scanners=<value> - which gadget scanners to run
-HELP-NEXT:   =pacret - pac-ret: return address protection (subset of "pauth")
-HELP-NEXT:   =pauth - All Pointer Authentication scanners
-HELP-NEXT:   =all - All implemented scanners
+HELP-NEXT:   --scanners=<value> - Which gadget scanners to run
+HELP-NEXT:   =ptrauth-pac-ret        -   Unprotected returns (pac-ret)
+HELP-NEXT:   =ptrauth-tail-calls     -   Tail calls performed with unprotected link register
+HELP-NEXT:   =ptrauth-forward-cf     -   Unprotected calls and branches (forward control-flow)
+HELP-NEXT:   =ptrauth-sign-oracles   -   Signing of untrusted pointers (signing oracles)
+HELP-NEXT:   =ptrauth-auth-oracles   -   Authentication oracles
+HELP-NEXT:   =ptrauth-all            -   All Pointer Authentication scanners
+HELP-NEXT:   =all                    -   All implemented scanners
+
 HELP-EMPTY:
 HELP-NEXT:  Generic Options:
diff --git a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s
index 8e991fade2c86..c0aa91ce21935 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s
@@ -1,5 +1,5 @@
 // RUN: %clang %cflags -march=armv9.5-a+pauth-lr -mbranch-protection=pac-ret %s %p/../../Inputs/asm_main.c -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret %t.exe 2>&1 | FileCheck %s
 
         .text
 
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 bd8edbc676c34..89fdf9f20a74d 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pacret-multi-bb.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pacret-multi-bb.s
@@ -1,5 +1,5 @@
 // RUN: %clang %cflags -march=armv8.3-a -mbranch-protection=pac-ret %s %p/../../Inputs/asm_main.c -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret %t.exe 2>&1 | FileCheck %s
 
 
 // Verify that we can also detect gadgets across basic blocks
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-address-checks.s b/bolt/test/binary-analysis/AArch64/gs-pauth-address-checks.s
index 74f276197923f..84063960a31f0 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-address-checks.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-address-checks.s
@@ -1,5 +1,5 @@
 // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe -Wl,--emit-relocs
-// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all %t.exe 2>&1 | FileCheck %s
 
         .text
 
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-address-materialization.s b/bolt/test/binary-analysis/AArch64/gs-pauth-address-materialization.s
index 6648f96ad7d08..1c160f47468d7 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-address-materialization.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-address-materialization.s
@@ -1,6 +1,6 @@
 // -Wl,--no-relax prevents converting ADRP+ADD pairs into NOP+ADR.
 // RUN: %clang %cflags -march=armv8.3-a -Wl,--no-relax %s -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all %t.exe 2>&1 | FileCheck %s
 
 // Test various patterns that should or should not be considered safe
 // materialization of PC-relative addresses.
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s
index 9f580b66f47c7..69ae9a086b990 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s
@@ -1,14 +1,12 @@
 // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret                        %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefix=FPAC %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth                         %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-auth-oracles --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefix=FPAC %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-auth-oracles                         %t.exe 2>&1 | FileCheck %s
 
 // The detection of compiler-generated explicit pointer checks is tested in
 // gs-pauth-address-checks.s, for that reason only test here "dummy-load" and
 // "high-bits-notbi" checkers, as the shortest examples of checkers that are
 // detected per-instruction and per-BB.
 
-// PACRET-NOT: authentication oracle found in function
 // FPAC-NOT:   authentication oracle found in function
 
         .text
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s b/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s
index 5e88e105a33f0..c270fcaa26aa5 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s
@@ -1,9 +1,6 @@
 // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret                        %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth                         %t.exe 2>&1 | FileCheck %s
-
-// PACRET-NOT: non-protected call found in function
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-forward-cf --auth-traps-on-failure %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-forward-cf                         %t.exe 2>&1 | FileCheck %s
 
         .text
 
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 a3ad7effe4b0d..77ccec73f5fca 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s
@@ -1,13 +1,13 @@
 // REQUIRES: asserts
 //
 // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret --no-threads \
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret --no-threads \
 // RUN:    -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s
-// RUN: llvm-bolt-binary-analysis --scanners=pacret --no-threads --auth-traps-on-failure \
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret --no-threads --auth-traps-on-failure \
 // RUN:    -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth  --no-threads \
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all     --no-threads \
 // RUN:    -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC,AUTH-ORACLES,PAUTH %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth  --no-threads --auth-traps-on-failure \
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all     --no-threads --auth-traps-on-failure \
 // RUN:    -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC,PAUTH %s
 
 // Check the debug output generated by PAuth gadget scanner to make sure the
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s b/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s
new file mode 100644
index 0000000000000..2fb7b2e3d9d99
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s
@@ -0,0 +1,124 @@
+// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
+
+// Select single detector:
+//
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret      %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-tail-calls   %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=TAIL-CALLS-COMMON,TAIL-CALLS-NOFPAC
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-forward-cf   %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=FORWARD-CF
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-sign-oracles %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=SIGN-ORACLES-COMMON,SIGN-ORACLES-NOFPAC
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-auth-oracles %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=AUTH-ORACLES-NOFPAC
+
+// Select multiple options (either disjoint or not):
+//
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret,ptrauth-forward-cf %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET,FORWARD-CF
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-pac-ret,ptrauth-all %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET,TAIL-CALLS-COMMON,TAIL-CALLS-NOFPAC,FORWARD-CF,SIGN-ORACLES-COMMON,SIGN-ORACLES-NOFPAC,AUTH-ORACLES-NOFPAC
+
+// Select one of "all" options:
+//
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET,TAIL-CALLS-COMMON,TAIL-CALLS-NOFPAC,FORWARD-CF,SIGN-ORACLES-COMMON,SIGN-ORACLES-NOFPAC,AUTH-ORACLES-NOFPAC
+// RUN: llvm-bolt-binary-analysis --scanners=all %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET,TAIL-CALLS-COMMON,TAIL-CALLS-NOFPAC,FORWARD-CF,SIGN-ORACLES-COMMON,SIGN-ORACLES-NOFPAC,AUTH-ORACLES-NOFPAC
+
+// Test FPAC handling:
+//
+// RUN: llvm-bolt-binary-analysis --auth-traps-on-failure --scanners=ptrauth-all %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET,TAIL-CALLS-COMMON,FORWARD-CF,SIGN-ORACLES-COMMON
+// RUN: llvm-bolt-binary-analysis --auth-traps-on-failure --scanners=ptrauth-auth-oracles %t.exe 2>&1 | \
+// RUN:     FileCheck %s --check-prefixes=NO-REPORTS
+
+// NO-REPORTS-NOT: found in function
+
+        .text
+
+        .globl  callee
+        .type   callee, at function
+callee:
+        ret
+        .size callee, .-callee
+
+        .globl  bad_pacret
+        .type   bad_pacret, at function
+bad_pacret:
+// PACRET: GS-PAUTH: non-protected ret found in function bad_pacret
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        ldp     x29, x30, [sp], #16
+        ret
+        .size bad_pacret, .-bad_pacret
+
+        .globl  bad_tail_call_common
+        .type   bad_tail_call_common, at function
+bad_tail_call_common:
+// TAIL-CALLS-COMMON: GS-PAUTH: untrusted link register found before tail call in function bad_tail_call_common
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        ldp     x29, x30, [sp], #16
+        b       callee
+        .size bad_tail_call_common, .-bad_tail_call_common
+
+        .globl  bad_tail_call_nofpac
+        .type   bad_tail_call_nofpac, at function
+bad_tail_call_nofpac:
+// TAIL-CALLS-NOFPAC:   GS-PAUTH: untrusted link register found before tail call in function bad_tail_call_nofpac
+// AUTH-ORACLES-NOFPAC: GS-PAUTH: authentication oracle found in function bad_tail_call_nofpac
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        b       callee
+        .size bad_tail_call_nofpac, .-bad_tail_call_nofpac
+
+        .globl  bad_call
+        .type   bad_call, at function
+bad_call:
+// FORWARD-CF: GS-PAUTH: non-protected call found in function bad_call
+        br      x0
+        .size bad_call, .-bad_call
+
+        .globl  bad_signing_oracle_common
+        .type   bad_signing_oracle_common, at function
+bad_signing_oracle_common:
+// SIGN-ORACLES-COMMON: GS-PAUTH: signing oracle found in function bad_signing_oracle_common
+        pacda   x0, x1
+        ret
+        .size bad_signing_oracle_common, .-bad_signing_oracle_common
+
+        .globl  bad_signing_oracle_nofpac
+        .type   bad_signing_oracle_nofpac, at function
+bad_signing_oracle_nofpac:
+// SIGN-ORACLES-NOFPAC: GS-PAUTH: signing oracle found in function bad_signing_oracle_nofpac
+// AUTH-ORACLES-NOFPAC: GS-PAUTH: authentication oracle found in function bad_signing_oracle_nofpac
+        autda   x0, x1
+        pacdb   x0, x1
+        ret
+        .size bad_signing_oracle_nofpac, .-bad_signing_oracle_nofpac
+
+        .globl  bad_auth_oracle
+        .type   bad_auth_oracle, at function
+bad_auth_oracle:
+// AUTH-ORACLES-NOFPAC: GS-PAUTH: authentication oracle found in function bad_auth_oracle
+        autda   x0, x1
+        ret
+        .size bad_auth_oracle, .-bad_auth_oracle
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s b/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s
index 7d908f234d852..920782bbacab1 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s
@@ -1,15 +1,12 @@
 // RUN: %clang %cflags -march=armv8.3-a+pauth-lr -Wl,--no-relax %s -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret                        %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth                         %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-sign-oracles                         %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-sign-oracles --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s
 
 // The detection of compiler-generated explicit pointer checks is tested in
 // gs-pauth-address-checks.s, for that reason only test here "dummy-load" and
 // "high-bits-notbi" checkers, as the shortest examples of checkers that are
 // detected per-instruction and per-BB.
 
-// PACRET-NOT: signing oracle found in function
-
         .text
 
         .type   sym, at function
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s b/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s
index 59b7d929275a9..daef83c69cec0 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s
@@ -1,9 +1,6 @@
 // RUN: %clang %cflags -Wl,--entry=_custom_start -march=armv8.3-a %s -o %t.exe
-// RUN: llvm-bolt-binary-analysis --scanners=pacret                        %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s
-// RUN: llvm-bolt-binary-analysis --scanners=pauth                         %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s
-
-// PACRET-NOT: untrusted link register found before tail call
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all                         %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s
 
         .text
 
diff --git a/bolt/test/binary-analysis/AArch64/trap-instructions.s b/bolt/test/binary-analysis/AArch64/trap-instructions.s
index 7810b2d3c3626..0d61440a5ed5a 100644
--- a/bolt/test/binary-analysis/AArch64/trap-instructions.s
+++ b/bolt/test/binary-analysis/AArch64/trap-instructions.s
@@ -1,5 +1,5 @@
 // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe -Wl,--emit-relocs
-// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
+// RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all %t.exe 2>&1 | FileCheck %s
 
 // Test what instructions can be used to terminate the program abnormally
 // on security violation.

>From 86f93d95f38aa81bd1580c2617ad13c2b1ea4498 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 11 Mar 2026 21:50:29 +0300
Subject: [PATCH 2/3] Do not hardcode underlying type of bitmask

---
 bolt/include/bolt/Passes/PAuthGadgetScanner.h | 19 ++++-----
 bolt/include/bolt/Utils/CommandLineOpts.h     |  3 +-
 bolt/lib/Passes/PAuthGadgetScanner.cpp        | 39 ++++++++++++-------
 bolt/lib/Rewrite/RewriteInstance.cpp          | 20 +++++-----
 4 files changed, 43 insertions(+), 38 deletions(-)

diff --git a/bolt/include/bolt/Passes/PAuthGadgetScanner.h b/bolt/include/bolt/Passes/PAuthGadgetScanner.h
index 8482793339be6..4f8195c6920b0 100644
--- a/bolt/include/bolt/Passes/PAuthGadgetScanner.h
+++ b/bolt/include/bolt/Passes/PAuthGadgetScanner.h
@@ -13,6 +13,7 @@
 #include "bolt/Core/BinaryFunction.h"
 #include "bolt/Core/MCInstUtils.h"
 #include "bolt/Passes/BinaryPasses.h"
+#include "bolt/Utils/CommandLineOpts.h"
 #include "llvm/Support/raw_ostream.h"
 #include <memory>
 
@@ -161,8 +162,8 @@ class FunctionAnalysisContext {
   MCPlusBuilder::AllocatorIdTy AllocatorId;
   FunctionAnalysisResult Result;
 
-  /// Bitmask of detectors to run (see opts::GadgetScannerKind).
-  uint64_t EnabledDetectorsMask;
+  /// Bitmask of detectors to run (only GS_PTRAUTH_* are allowed).
+  opts::GadgetKindBitmask EnabledDetectors;
 
   void findUnsafeUses(SmallVector<PartialReport<MCPhysReg>> &Reports);
   void augmentUnsafeUseReports(ArrayRef<PartialReport<MCPhysReg>> Reports);
@@ -177,9 +178,7 @@ class FunctionAnalysisContext {
 public:
   FunctionAnalysisContext(BinaryFunction &BF,
                           MCPlusBuilder::AllocatorIdTy AllocatorId,
-                          uint64_t EnabledDetectorsMask)
-      : BC(BF.getBinaryContext()), BF(BF), AllocatorId(AllocatorId),
-        EnabledDetectorsMask(EnabledDetectorsMask) {}
+                          opts::GadgetKindBitmask EnabledDetectors);
 
   void run();
 
@@ -187,8 +186,8 @@ class FunctionAnalysisContext {
 };
 
 class Analysis : public BinaryFunctionPass {
-  /// Bitmask of detectors to run (see opts::GadgetScannerKind).
-  uint64_t EnabledDetectorsMask;
+  /// Bitmask of detectors to run.
+  opts::GadgetKindBitmask EnabledDetectors;
 
   void runOnFunction(BinaryFunction &Function,
                      MCPlusBuilder::AllocatorIdTy AllocatorId);
@@ -198,11 +197,7 @@ class Analysis : public BinaryFunctionPass {
 
 public:
   /// Constructs the analysis pass.
-  ///
-  /// EnabledDetectorsMask selects the checks to perform, see
-  /// opts::GadgetScannerKind for the available GS_PTRAUTH_* options.
-  explicit Analysis(uint64_t EnabledDetectorsMask)
-      : BinaryFunctionPass(false), EnabledDetectorsMask(EnabledDetectorsMask) {}
+  explicit Analysis(opts::GadgetKindBitmask EnabledDetectors);
 
   const char *getName() const override { return "pauth-gadget-scanner"; }
 
diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h
index 5bd83c17aa900..cb4b3c73bd3fc 100644
--- a/bolt/include/bolt/Utils/CommandLineOpts.h
+++ b/bolt/include/bolt/Utils/CommandLineOpts.h
@@ -130,7 +130,8 @@ bool processAllFunctions();
 /// Return true if we should dump dot graphs for the given function.
 bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
 
-enum GadgetScannerKind : uint64_t {
+/// Bitmask representing a subset of possible gadget scanner kinds.
+enum GadgetKindBitmask : unsigned {
   /// Scan for unprotected backward control-flow (return instructions).
   GS_PTRAUTH_RETURN_TARGETS = (1 << 0),
   /// Scan for tail calls performed with untrusted link register.
diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp
index 64a197ea9c5a1..542af49e26205 100644
--- a/bolt/lib/Passes/PAuthGadgetScanner.cpp
+++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp
@@ -1553,10 +1553,9 @@ collectRegsToTrack(ArrayRef<PartialReport<MCPhysReg>> Reports) {
 
 void FunctionAnalysisContext::findUnsafeUses(
     SmallVector<PartialReport<MCPhysReg>> &Reports) {
-  using GSK = opts::GadgetScannerKind;
-  const uint64_t HandledDetectorsMask =
-      GSK::GS_PTRAUTH_ALL_MASK & ~GSK::GS_PTRAUTH_AUTH_ORACLES;
-  if (0 == (EnabledDetectorsMask & HandledDetectorsMask))
+  const auto HandledDetectors =
+      opts::GS_PTRAUTH_ALL_MASK & ~opts::GS_PTRAUTH_AUTH_ORACLES;
+  if (!(EnabledDetectors & HandledDetectors))
     return;
 
   auto Analysis = SrcSafetyAnalysis::create(BF, AllocatorId, {});
@@ -1623,19 +1622,19 @@ void FunctionAnalysisContext::findUnsafeUses(
       return;
     }
 
-    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_RETURN_TARGETS) {
+    if (EnabledDetectors & opts::GS_PTRAUTH_RETURN_TARGETS) {
       if (auto Report = shouldReportReturnGadget(BC, Inst, S))
         Reports.push_back(*Report);
     }
-    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_TAIL_CALLS) {
+    if (EnabledDetectors & opts::GS_PTRAUTH_TAIL_CALLS) {
       if (auto Report = shouldReportUnsafeTailCall(BC, BF, Inst, S))
         Reports.push_back(*Report);
     }
-    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_BRANCH_AND_CALL_TARGETS) {
+    if (EnabledDetectors & opts::GS_PTRAUTH_BRANCH_AND_CALL_TARGETS) {
       if (auto Report = shouldReportCallGadget(BC, Inst, S))
         Reports.push_back(*Report);
     }
-    if (EnabledDetectorsMask & GSK::GS_PTRAUTH_SIGN_ORACLES) {
+    if (EnabledDetectors & opts::GS_PTRAUTH_SIGN_ORACLES) {
       if (auto Report = shouldReportSigningOracle(BC, Inst, S))
         Reports.push_back(*Report);
     }
@@ -1669,9 +1668,8 @@ void FunctionAnalysisContext::augmentUnsafeUseReports(
 
 void FunctionAnalysisContext::findUnsafeDefs(
     SmallVector<PartialReport<MCPhysReg>> &Reports) {
-  using GSK = opts::GadgetScannerKind;
-  const uint64_t HandledDetectorsMask = GSK::GS_PTRAUTH_AUTH_ORACLES;
-  if (0 == (EnabledDetectorsMask & HandledDetectorsMask))
+  const auto HandledDetectors = opts::GS_PTRAUTH_AUTH_ORACLES;
+  if (!(EnabledDetectors & HandledDetectors))
     return;
 
   if (AuthTrapsOnFailure)
@@ -1731,6 +1729,15 @@ void FunctionAnalysisContext::handleSimpleReports(
   llvm::erase_if(Reports, [](const auto &R) { return !R.RequestedDetails; });
 }
 
+FunctionAnalysisContext::FunctionAnalysisContext(
+    BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId,
+    opts::GadgetKindBitmask EnabledDetectors)
+    : BC(BF.getBinaryContext()), BF(BF), AllocatorId(AllocatorId),
+      EnabledDetectors(EnabledDetectors) {
+  assert(!(EnabledDetectors & ~opts::GS_PTRAUTH_ALL_MASK) &&
+         "Unrelated detectors requested");
+}
+
 void FunctionAnalysisContext::run() {
   LLVM_DEBUG({
     dbgs() << "Analyzing function " << BF.getPrintName()
@@ -1753,7 +1760,7 @@ void FunctionAnalysisContext::run() {
 
 void Analysis::runOnFunction(BinaryFunction &BF,
                              MCPlusBuilder::AllocatorIdTy AllocatorId) {
-  FunctionAnalysisContext FA(BF, AllocatorId, EnabledDetectorsMask);
+  FunctionAnalysisContext FA(BF, AllocatorId, EnabledDetectors);
   FA.run();
 
   const FunctionAnalysisResult &FAR = FA.getResult();
@@ -1861,11 +1868,13 @@ void GenericDiagnostic::generateReport(raw_ostream &OS,
   printBasicInfo(OS, BC, Text);
 }
 
-Error Analysis::runOnFunctions(BinaryContext &BC) {
-  using GSK = opts::GadgetScannerKind;
-  assert(0 == (EnabledDetectorsMask & ~GSK::GS_PTRAUTH_ALL_MASK) &&
+Analysis::Analysis(opts::GadgetKindBitmask EnabledDetectors)
+    : BinaryFunctionPass(false), EnabledDetectors(EnabledDetectors) {
+  assert(!(EnabledDetectors & ~opts::GS_PTRAUTH_ALL_MASK) &&
          "Unrelated detectors requested");
+}
 
+Error Analysis::runOnFunctions(BinaryContext &BC) {
   ParallelUtilities::WorkFuncWithAllocTy WorkFun =
       [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
         runOnFunction(BF, AllocatorId);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index c84aabfe2e4ca..82bdbc9affd04 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -286,7 +286,7 @@ static cl::opt<bool> WriteBoltInfoSection(
     "bolt-info", cl::desc("write bolt info section in the output binary"),
     cl::init(true), cl::Hidden, cl::cat(BoltOutputCategory));
 
-static cl::list<GadgetScannerKind> GadgetScannersToRun(
+static cl::list<GadgetKindBitmask> GadgetScannersToRun(
     "scanners", cl::desc("Which gadget scanners to run"),
     cl::values(
         clEnumValN(GS_PTRAUTH_RETURN_TARGETS, "ptrauth-pac-ret",
@@ -3878,17 +3878,17 @@ void RewriteInstance::runBinaryAnalyses() {
   BinaryFunctionPassManager Manager(*BC);
   // FIXME: add a pass that warns about which functions do not have CFG,
   // and therefore, analysis is most likely to be less accurate.
-  using GSK = opts::GadgetScannerKind;
-  using PAuthScanner = PAuthGadgetScanner::Analysis;
+  using PtrAuthScanner = PAuthGadgetScanner::Analysis;
 
   // If no command line option was given, act as if "all" was specified.
-  uint64_t AnalysesMask = 0;
-  for (uint64_t Submask : opts::GadgetScannersToRun)
-    AnalysesMask |= Submask;
-
-  uint64_t PAuthAnalysesMask = AnalysesMask & GSK::GS_PTRAUTH_ALL_MASK;
-  if (PAuthAnalysesMask)
-    Manager.registerPass(std::make_unique<PAuthScanner>(PAuthAnalysesMask));
+  decltype(~opts::GS_ALL_MASK) EnabledAnalyses = 0;
+  for (auto NamedOptionSubmask : opts::GadgetScannersToRun)
+    EnabledAnalyses |= NamedOptionSubmask;
+
+  const auto PtrAuthAnalyses = static_cast<opts::GadgetKindBitmask>(
+      EnabledAnalyses & opts::GS_PTRAUTH_ALL_MASK);
+  if (PtrAuthAnalyses)
+    Manager.registerPass(std::make_unique<PtrAuthScanner>(PtrAuthAnalyses));
 
   BC->logBOLTErrorsAndQuitOnFatal(Manager.runPasses());
 }

>From 89e313b839cf2e7c510f7be2b20134cac9914cfc Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 11 Mar 2026 22:20:47 +0300
Subject: [PATCH 3/3] Restore 'everything is enabled by default' behavior

---
 bolt/lib/Rewrite/RewriteInstance.cpp                  | 6 +++++-
 bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s | 6 ++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 82bdbc9affd04..b3208ac024ae6 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -3880,11 +3880,15 @@ void RewriteInstance::runBinaryAnalyses() {
   // and therefore, analysis is most likely to be less accurate.
   using PtrAuthScanner = PAuthGadgetScanner::Analysis;
 
-  // If no command line option was given, act as if "all" was specified.
+  // Accumulate all enabled analyses.
   decltype(~opts::GS_ALL_MASK) EnabledAnalyses = 0;
   for (auto NamedOptionSubmask : opts::GadgetScannersToRun)
     EnabledAnalyses |= NamedOptionSubmask;
 
+  // If no command line option was given, act as if "all" was specified.
+  if (opts::GadgetScannersToRun.empty())
+    EnabledAnalyses = opts::GS_ALL_MASK;
+
   const auto PtrAuthAnalyses = static_cast<opts::GadgetKindBitmask>(
       EnabledAnalyses & opts::GS_PTRAUTH_ALL_MASK);
   if (PtrAuthAnalyses)
diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s b/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s
index 2fb7b2e3d9d99..d6c96a671f9d2 100644
--- a/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s
+++ b/bolt/test/binary-analysis/AArch64/gs-pauth-scanners.s
@@ -36,6 +36,12 @@
 // RUN:     FileCheck %s --implicit-check-not="found in function" \
 // RUN:                  --check-prefixes=PACRET,TAIL-CALLS-COMMON,TAIL-CALLS-NOFPAC,FORWARD-CF,SIGN-ORACLES-COMMON,SIGN-ORACLES-NOFPAC,AUTH-ORACLES-NOFPAC
 
+// Implicitly select all scanners by omitting --scanners=... argument.
+//
+// RUN: llvm-bolt-binary-analysis %t.exe 2>&1 | \
+// RUN:     FileCheck %s --implicit-check-not="found in function" \
+// RUN:                  --check-prefixes=PACRET,TAIL-CALLS-COMMON,TAIL-CALLS-NOFPAC,FORWARD-CF,SIGN-ORACLES-COMMON,SIGN-ORACLES-NOFPAC,AUTH-ORACLES-NOFPAC
+
 // Test FPAC handling:
 //
 // RUN: llvm-bolt-binary-analysis --auth-traps-on-failure --scanners=ptrauth-all %t.exe 2>&1 | \



More information about the llvm-commits mailing list