[Lldb-commits] [lldb] [lldb] Interpret the ptrauth intrinsics in IRInterpreter (PR #232467)

Yao Qi via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 16 02:36:33 PDT 2026


https://github.com/qiyao updated https://github.com/llvm/llvm-project/pull/232467

>From bf633e42f1f20567a01a1e243271a9f9ea9fa6df Mon Sep 17 00:00:00 2001
From: Yao Qi <yao_qi at apple.com>
Date: Thu, 15 Oct 2026 13:41:54 +0100
Subject: [PATCH 1/3] [lldb] Interpret the ptrauth intrinsics in IRInterpreter

When lldb evaluates an expression with `IRInterpreter` on arm64e, it reads
through a `__ptrauth`-qualified pointer compiles to calls to
`@llvm.ptrauth.blend` and `@llvm.ptrauth.auth`. The interpreter knows
neither, so the read fails:

```
(lldb) expr -j 0 -- *s_ptr->p
error: Can't evaluate the expression without a running target due to: Interpreter doesn't handle one of the expression's opcodes
```

Interpret the three intrinsics instead. The same read now works:

```
(lldb) expr -j 0 -- *s_ptr->p
(int) $0 = 123
```

The test forces the interpreter with `expr -j 0` and runs on arm64e only.

This upstreams the implementation and the test, where the co-authors
below wrote them.

Co-authored-by: Adrian Prantl <aprantl at apple.com>
Co-authored-by: Vedant Kumar <vsk at apple.com>
Co-authored-by: Fred Riss <friss at apple.com>
---
 lldb/source/Expression/IRInterpreter.cpp      | 52 +++++++++++++++++++
 .../ptrauth_blend/Makefile                    |  2 +
 .../ptrauth_blend/TestPtrauthBlendInterp.py   | 11 ++++
 .../ptrauth_diagnostics/ptrauth_blend/main.c  | 15 ++++++
 4 files changed, 80 insertions(+)
 create mode 100644 lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/Makefile
 create mode 100644 lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py
 create mode 100644 lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c

diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp
index e1b5afd4a97bc2..b39e7ef3cd2b65 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/source/Expression/IRInterpreter.cpp
@@ -83,6 +83,9 @@ static bool CanIgnoreCall(const CallInst *call) {
       break;
     case llvm::Intrinsic::dbg_declare:
     case llvm::Intrinsic::dbg_value:
+    case llvm::Intrinsic::ptrauth_auth:
+    case llvm::Intrinsic::ptrauth_blend:
+    case llvm::Intrinsic::ptrauth_strip:
       return true;
     }
   }
@@ -1453,6 +1456,55 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
     case Instruction::Call: {
       const CallInst *call_inst = cast<CallInst>(inst);
 
+      if (auto *fn = call_inst->getCalledFunction()) {
+        if (fn->isIntrinsic() &&
+            ((fn->getIntrinsicID() == llvm::Intrinsic::ptrauth_auth &&
+              call_inst->arg_size() == 3) ||
+             (fn->getIntrinsicID() == llvm::Intrinsic::ptrauth_strip &&
+              call_inst->arg_size() == 2)) &&
+            exe_ctx.GetProcessPtr()) {
+          llvm::Value *auth_ptr = call_inst->getArgOperand(0);
+          // Extract the argument's value.
+          lldb_private::Scalar auth_ptr_val;
+          if (!frame.EvaluateValue(auth_ptr_val, auth_ptr, module)) {
+            error = lldb_private::Status::FromErrorStringWithFormat(
+                "unable to evaluate argument %d", 0);
+            return false;
+          }
+
+          if (lldb::ABISP abi_sp = exe_ctx.GetProcessPtr()->GetABI()) {
+            auto stripped_ptr = lldb_private::Scalar(
+                abi_sp->FixCodeAddress(auth_ptr_val.ULongLong()));
+            frame.AssignValue(call_inst, stripped_ptr, module);
+          }
+        }
+
+        if (fn->isIntrinsic() &&
+            fn->getIntrinsicID() == llvm::Intrinsic::ptrauth_blend) {
+          llvm::Value *addr = call_inst->getArgOperand(0);
+          llvm::Value *lobits = call_inst->getArgOperand(1);
+
+          // Extract the address.
+          lldb_private::Scalar addr_val;
+          if (!frame.EvaluateValue(addr_val, addr, module)) {
+            error = lldb_private::Status::FromErrorStringWithFormat(
+                "unable to evaluate argument %d", 0);
+            return false;
+          }
+
+          // Extract the low bits to blend in.
+          lldb_private::Scalar lobits_val;
+          if (!frame.EvaluateValue(lobits_val, lobits, module)) {
+            error = lldb_private::Status::FromErrorStringWithFormat(
+                "unable to evaluate argument %d", 1);
+            return false;
+          }
+
+          lldb_private::Scalar blend_val = addr_val | (lobits_val << 48);
+          frame.AssignValue(call_inst, blend_val, module);
+        }
+      }
+
       if (CanIgnoreCall(call_inst))
         break;
 
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/Makefile b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/Makefile
new file mode 100644
index 00000000000000..c9319d6e6888a4
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py
new file mode 100644
index 00000000000000..a04390f04ae2cc
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py
@@ -0,0 +1,11 @@
+from lldbsuite.test import lldbinline
+from lldbsuite.test import decorators
+
+lldbinline.MakeInlineTest(
+    __file__,
+    globals(),
+    [
+        decorators.skipIf(archs=decorators.no_match(["arm64e"])),
+        decorators.skipIf(dwarf_version=["<", "4"]),
+    ],
+)
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c
new file mode 100644
index 00000000000000..a2977cd4564720
--- /dev/null
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c
@@ -0,0 +1,15 @@
+#define auth __ptrauth(2, 1, 9484)
+
+struct mytype {
+  int *auth p;
+};
+
+int main() {
+  int x = 123;
+  struct mytype s;
+  s.p = &x;
+  struct mytype *s_ptr = &s;
+  //% self.filecheck("expr -j 0 -- *s_ptr->p", "main.c")
+  // CHECK: (int) {{.*}} = 123
+  return 0;
+}

>From 72c502ef52bb36c2ec4bc1b2b87419aa075343e2 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao_qi at apple.com>
Date: Thu, 15 Oct 2026 19:46:08 +0100
Subject: [PATCH 2/3] [lldb][test] Use Arm64eTestBase in TestPtrauthBlendInterp

`TestPtrauthBlendInterp.py` runs only when the whole test suite targets
arm64e. A normal run on an arm64 skips it:

```
SKIPPED: lldb-api :: functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py (1 of 1)
```

Derive the test from `Arm64eTestBase`, like the other arm64e tests.
---
 .../ptrauth_blend/TestPtrauthBlendInterp.py   | 34 +++++++++++++------
 .../ptrauth_diagnostics/ptrauth_blend/main.c  |  4 +--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py
index a04390f04ae2cc..23b4f98b8b774d 100644
--- a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/TestPtrauthBlendInterp.py
@@ -1,11 +1,23 @@
-from lldbsuite.test import lldbinline
-from lldbsuite.test import decorators
-
-lldbinline.MakeInlineTest(
-    __file__,
-    globals(),
-    [
-        decorators.skipIf(archs=decorators.no_match(["arm64e"])),
-        decorators.skipIf(dwarf_version=["<", "4"]),
-    ],
-)
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbsuite.test.lldbarm64e import Arm64eTestBase
+
+
+class TestPtrauthBlendInterp(Arm64eTestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+    SHARED_BUILD_TESTCASE = False
+
+    def test_interpreter_reads_ptrauth_field(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.c", False)
+        )
+
+        # Disable the JIT, so that IRInterpreter evaluates the expression.
+        options = lldb.SBExpressionOptions()
+        options.SetAllowJIT(False)
+        self.expect_expr(
+            "*s_ptr->p", result_type="int", result_value="123", options=options
+        )
diff --git a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c
index a2977cd4564720..dc0ab08d02a0c6 100644
--- a/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c
+++ b/lldb/test/API/functionalities/ptrauth_diagnostics/ptrauth_blend/main.c
@@ -9,7 +9,5 @@ int main() {
   struct mytype s;
   s.p = &x;
   struct mytype *s_ptr = &s;
-  //% self.filecheck("expr -j 0 -- *s_ptr->p", "main.c")
-  // CHECK: (int) {{.*}} = 123
-  return 0;
+  return 0; // break here
 }

>From 98091c279d214dccc7175b7938ee83f553b306a6 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao_qi at apple.com>
Date: Fri, 16 Oct 2026 10:35:12 +0100
Subject: [PATCH 3/3] Replace FromErrorStringWithFormat with FromErrorString

the argument is known in advance.
---
 lldb/source/Expression/IRInterpreter.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp
index b39e7ef3cd2b65..30373301503acf 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/source/Expression/IRInterpreter.cpp
@@ -1467,8 +1467,8 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
           // Extract the argument's value.
           lldb_private::Scalar auth_ptr_val;
           if (!frame.EvaluateValue(auth_ptr_val, auth_ptr, module)) {
-            error = lldb_private::Status::FromErrorStringWithFormat(
-                "unable to evaluate argument %d", 0);
+            error = lldb_private::Status::FromErrorString(
+                "unable to evaluate argument 0");
             return false;
           }
 



More information about the lldb-commits mailing list