[llvm] [BOLT][binary-analysis] Fix pac-ret scanner's "major limitation" (PR #136664)

Gergely Bálint via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 22 06:10:56 PDT 2025


https://github.com/bgergely0 updated https://github.com/llvm/llvm-project/pull/136664

>From 1deada421efad6d9587b906773bf36b1bca38631 Mon Sep 17 00:00:00 2001
From: Gergely Balint <gergely.balint at arm.com>
Date: Tue, 22 Apr 2025 09:31:47 +0200
Subject: [PATCH 1/2] [BOLT] Fix pac-ret binary analysis tool's CFI issue

- llvm-bolt-binary-analysis, and other tools which don't produce a
  binary as output can be run without NegateRAState CFIs.
- during FillCFIInfo, added a better error message about NegateRAState
  CFIs when running llvm-bolt.
- updated docs.
- updated a unit test about NegateRAState CFI handling.
---
 bolt/docs/BinaryAnalysis.md                   |  6 ------
 bolt/include/bolt/Core/Exceptions.h           |  6 +++++-
 bolt/lib/Core/Exceptions.cpp                  | 15 ++++++++++++---
 bolt/lib/Rewrite/RewriteInstance.cpp          |  3 ++-
 bolt/test/AArch64/dw_cfa_gnu_window_save.test |  6 +++---
 5 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/bolt/docs/BinaryAnalysis.md b/bolt/docs/BinaryAnalysis.md
index 9f0f018980517..b13410cd96355 100644
--- a/bolt/docs/BinaryAnalysis.md
+++ b/bolt/docs/BinaryAnalysis.md
@@ -180,12 +180,6 @@ The following are current known cases of false negatives:
    [prototype branch](
    https://github.com/llvm/llvm-project/compare/main...kbeyls:llvm-project:bolt-gadget-scanner-prototype).
 
-BOLT cannot currently handle functions with `cfi_negate_ra_state` correctly,
-i.e. any binaries built with `-mbranch-protection=pac-ret`. The scanner is meant
-to be used on specifically such binaries, so this is a major limitation! Work is
-going on in PR [#120064](https://github.com/llvm/llvm-project/pull/120064) to
-fix this.
-
 ## How to add your own binary analysis
 
 _TODO: this section needs to be written. Ideally, we should have a simple
diff --git a/bolt/include/bolt/Core/Exceptions.h b/bolt/include/bolt/Core/Exceptions.h
index f10cf776f0943..54e7fc50078da 100644
--- a/bolt/include/bolt/Core/Exceptions.h
+++ b/bolt/include/bolt/Core/Exceptions.h
@@ -37,7 +37,8 @@ class BinaryFunction;
 /// BinaryFunction, as well as rewriting CFI sections.
 class CFIReaderWriter {
 public:
-  explicit CFIReaderWriter(BinaryContext &BC, const DWARFDebugFrame &EHFrame);
+  explicit CFIReaderWriter(BinaryContext &BC, const DWARFDebugFrame &EHFrame,
+                           StringRef ToolName);
 
   bool fillCFIInfoFor(BinaryFunction &Function) const;
 
@@ -56,9 +57,12 @@ class CFIReaderWriter {
 
   const FDEsMap &getFDEs() const { return FDEs; }
 
+  StringRef getToolName() const { return ToolName; }
+
 private:
   BinaryContext &BC;
   FDEsMap FDEs;
+  StringRef ToolName;
 };
 
 /// Parse an existing .eh_frame and invoke the callback for each
diff --git a/bolt/lib/Core/Exceptions.cpp b/bolt/lib/Core/Exceptions.cpp
index 0b2e63b8ca6a7..cbb29a05bee20 100644
--- a/bolt/lib/Core/Exceptions.cpp
+++ b/bolt/lib/Core/Exceptions.cpp
@@ -463,8 +463,10 @@ void BinaryFunction::updateEHRanges() {
 const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
 
 CFIReaderWriter::CFIReaderWriter(BinaryContext &BC,
-                                 const DWARFDebugFrame &EHFrame)
+                                 const DWARFDebugFrame &EHFrame,
+                                 StringRef ToolName)
     : BC(BC) {
+  this->ToolName = ToolName;
   // Prepare FDEs for fast lookup
   for (const dwarf::FrameEntry &Entry : EHFrame.entries()) {
     const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry);
@@ -632,8 +634,15 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
       // DW_CFA_GNU_window_save and DW_CFA_GNU_NegateRAState just use the same
       // id but mean different things. The latter is used in AArch64.
       if (Function.getBinaryContext().isAArch64()) {
-        Function.addCFIInstruction(
-            Offset, MCCFIInstruction::createNegateRAState(nullptr));
+        // .cfi_negate_ra_state is only needed for tools producing binaries (so
+        // BOLT itself). Other BOLT-based tools (perf2bolt, merge-fdata,
+        // llvm-bolt-binary-analysis, etc.) can safely drop this CFI.
+        if (getToolName() == "llvm-bolt") {
+          BC.errs() << "BOLT-ERROR: pointer authentication is not supported "
+                       "yet. Please compile "
+                       "your target binary using '-mbranch-protection=none'.\n";
+          exit(1);
+        }
         break;
       }
       if (opts::Verbosity >= 1)
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 69fb736d7bde0..6dc7cad4f538c 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2048,7 +2048,8 @@ Error RewriteInstance::readSpecialSections() {
   Expected<const DWARFDebugFrame *> EHFrameOrError = BC->DwCtx->getEHFrame();
   if (!EHFrameOrError)
     report_error("expected valid eh_frame section", EHFrameOrError.takeError());
-  CFIRdWrt.reset(new CFIReaderWriter(*BC, *EHFrameOrError.get()));
+  StringRef ToolName = llvm::sys::path::stem(Argv[0]);
+  CFIRdWrt.reset(new CFIReaderWriter(*BC, *EHFrameOrError.get(), ToolName));
 
   processSectionMetadata();
 
diff --git a/bolt/test/AArch64/dw_cfa_gnu_window_save.test b/bolt/test/AArch64/dw_cfa_gnu_window_save.test
index 2e044b399720a..97b257ee04666 100644
--- a/bolt/test/AArch64/dw_cfa_gnu_window_save.test
+++ b/bolt/test/AArch64/dw_cfa_gnu_window_save.test
@@ -1,8 +1,8 @@
-# Check that llvm-bolt can handle DW_CFA_GNU_window_save on AArch64.
+# Check that llvm-bolt refuses binaries with DW_CFA_GNU_window_save on AArch64.
 
 RUN: yaml2obj %p/Inputs/dw_cfa_gnu_window_save.yaml &> %t.exe
-RUN: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
+RUN not: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
 
 CHECK-NOT: paciasp
 CHECK-NOT: autiasp
-CHECK-NOT: ERROR: unable to fill CFI.
+CHECK: BOLT-ERROR: pointer authentication is not supported yet.

>From 9e95938895222debdae1d1892c26bf0fc202cde0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gergely=20B=C3=A1lint?=
 <50703923+bgergely0 at users.noreply.github.com>
Date: Tue, 22 Apr 2025 15:10:48 +0200
Subject: [PATCH 2/2] [BOLT] Fix dw_cfa_gnu_window_save.test

change "RUN not:" to "RUN: not"

Co-authored-by: Anatoly Trosinenko <anatoly.trosinenko at gmail.com>
---
 bolt/test/AArch64/dw_cfa_gnu_window_save.test | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bolt/test/AArch64/dw_cfa_gnu_window_save.test b/bolt/test/AArch64/dw_cfa_gnu_window_save.test
index 97b257ee04666..aed7c73f6a704 100644
--- a/bolt/test/AArch64/dw_cfa_gnu_window_save.test
+++ b/bolt/test/AArch64/dw_cfa_gnu_window_save.test
@@ -1,7 +1,7 @@
 # Check that llvm-bolt refuses binaries with DW_CFA_GNU_window_save on AArch64.
 
 RUN: yaml2obj %p/Inputs/dw_cfa_gnu_window_save.yaml &> %t.exe
-RUN not: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
+RUN: not llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
 
 CHECK-NOT: paciasp
 CHECK-NOT: autiasp



More information about the llvm-commits mailing list