Author: Jon Roelofs
Date: 2026-07-23T11:46:36-07:00
New Revision: 77e879f967294d76376bf7a022092a1d6f3ed583

URL: 
https://github.com/llvm/llvm-project/commit/77e879f967294d76376bf7a022092a1d6f3ed583
DIFF: 
https://github.com/llvm/llvm-project/commit/77e879f967294d76376bf7a022092a1d6f3ed583.diff

LOG: [libunwind][AArch64] Support .cfi_set_ra_state (#209950)

This new CFI directive directly assigns an RA signing state to the 
RA_SIGN_STATE DWARF pseudo-register for use when unwinding, to indicate whether 
the value of PC has been used as a diversifier for return address signing. The 
new directive subsumes and replaces .cfi_negate_ra_state_with_pc, which was 
found to be unsuitable for descibing some block layouts [1], particularly in 
hot-cold-split functions.

1: https://github.com/ARM-software/abi-aa/pull/346

Added: 
    

Modified: 
    libunwind/src/DwarfParser.hpp
    libunwind/src/dwarf2.h
    libunwind/test/CMakeLists.txt
    libunwind/test/configs/apple-libunwind-system.cfg.in
    libunwind/test/configs/llvm-libunwind-merged.cfg.in
    libunwind/test/configs/llvm-libunwind-shared.cfg.in
    libunwind/test/configs/llvm-libunwind-static.cfg.in
    libunwind/test/ra_sign_state.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index ba40b757ab977..d60e3e11325d3 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -859,6 +859,26 @@ bool CFI_Parser<A>::parseFDEInstructions(
       } break;
 #endif
 
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+      case DW_CFA_AARCH64_set_ra_state: {
+        int64_t value =
+            static_cast<int64_t>(addressSpace.getULEB128(p, instructionsEnd));
+        if (value < 0 || 2 < value) {
+          _LIBUNWIND_LOG0("malformed DW_CFA_AARCH64_set_ra_state DWARF "
+                          "unwind, RA_SIGN_STATE value not recognized");
+          return false;
+        }
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.codeAlignFactor;
+        results->setRegister(UNW_AARCH64_RA_SIGN_STATE, kRegisterIsPseudo,
+                             value, initialState);
+        results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset + offset;
+        _LIBUNWIND_TRACE_DWARF(
+            "DW_CFA_AARCH64_set_ra_state(state=%" PRId64 ",pc=0x%" PRIx64 
")\n",
+            value, static_cast<uint64_t>(results->ptrAuthDiversifier));
+      } break;
+#endif
+
 #else
         (void)arch;
 #endif

diff  --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h
index 68ad882347203..19f6e4de3fe34 100644
--- a/libunwind/src/dwarf2.h
+++ b/libunwind/src/dwarf2.h
@@ -51,6 +51,7 @@ enum {
   DW_CFA_GNU_negative_offset_extended = 0x2F,
 
   // AARCH64 extensions
+  DW_CFA_AARCH64_set_ra_state = 0x2B,
   DW_CFA_AARCH64_negate_ra_state_with_pc = 0x2C,
   DW_CFA_AARCH64_negate_ra_state = 0x2D
 };

diff  --git a/libunwind/test/CMakeLists.txt b/libunwind/test/CMakeLists.txt
index 3a4433689051c..780be2f13b85c 100644
--- a/libunwind/test/CMakeLists.txt
+++ b/libunwind/test/CMakeLists.txt
@@ -33,6 +33,24 @@ pythonize_bool(LIBUNWIND_ENABLE_GCS)
 pythonize_bool(LIBUNWIND_ENABLE_THREADS)
 pythonize_bool(LIBUNWIND_USES_ARM_EHABI)
 
+file(WRITE "${CMAKE_BINARY_DIR}/check_cfi_set_ra_state.s" "
+    .text
+    .global _test_cfi_set_ra_state
+_test_cfi_set_ra_state:
+    .cfi_startproc
+    .cfi_set_ra_state 0, 0
+    ret
+    .cfi_endproc
+")
+set(_previous_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+try_compile(HAVE_CFI_SET_RA_STATE
+    "${CMAKE_BINARY_DIR}/check_cfi_set_ra_state"
+    SOURCES "${CMAKE_BINARY_DIR}/check_cfi_set_ra_state.s"
+)
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_previous_CMAKE_TRY_COMPILE_TARGET_TYPE})
+pythonize_bool(HAVE_CFI_SET_RA_STATE)
+
 set(AUTO_GEN_COMMENT "## Autogenerated by libunwind configuration.\n# Do not 
edit!")
 set(SERIALIZED_LIT_PARAMS "# Lit parameters serialized here for llvm-lit to 
pick them up\n")
 

diff  --git a/libunwind/test/configs/apple-libunwind-system.cfg.in 
b/libunwind/test/configs/apple-libunwind-system.cfg.in
index 252448a756be9..2349ca394b58b 100644
--- a/libunwind/test/configs/apple-libunwind-system.cfg.in
+++ b/libunwind/test/configs/apple-libunwind-system.cfg.in
@@ -12,8 +12,13 @@ lit_config.load_config(config, 
'@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')
 config.substitutions.append(('%{flags}',
     '-isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else 
''
 ))
+
+compile_flags = ['-nostdinc++', '-I', '%{include}']
+if @HAVE_CFI_SET_RA_STATE@:
+    compile_flags.append('-DHAVE_CFI_SET_RA_STATE')
+
 config.substitutions.append(('%{compile_flags}',
-    '-nostdinc++ -I %{include}'
+    ' '.join(compile_flags)
 ))
 config.substitutions.append(('%{link_flags}',
     '-nostdlib++ -L %{lib} -lc++ -lunwind'

diff  --git a/libunwind/test/configs/llvm-libunwind-merged.cfg.in 
b/libunwind/test/configs/llvm-libunwind-merged.cfg.in
index 1ae1b515bff4d..231849f5c4e56 100644
--- a/libunwind/test/configs/llvm-libunwind-merged.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-merged.cfg.in
@@ -20,6 +20,9 @@ if @LIBUNWIND_ENABLE_CET@:
 if @LIBUNWIND_ENABLE_GCS@:
     compile_flags.append('-mbranch-protection=standard')
 
+if @HAVE_CFI_SET_RA_STATE@:
+    compile_flags.append('-DHAVE_CFI_SET_RA_STATE')
+
 # On ELF platforms, link tests with -Wl,--export-dynamic if supported by the 
linker.
 if len('@CMAKE_EXE_EXPORTS_CXX_FLAG@'):
     link_flags.append('@CMAKE_EXE_EXPORTS_CXX_FLAG@')

diff  --git a/libunwind/test/configs/llvm-libunwind-shared.cfg.in 
b/libunwind/test/configs/llvm-libunwind-shared.cfg.in
index 84af348a5c6cb..0a7a24eb08c5e 100644
--- a/libunwind/test/configs/llvm-libunwind-shared.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-shared.cfg.in
@@ -19,6 +19,9 @@ if @LIBUNWIND_ENABLE_CET@:
 if @LIBUNWIND_ENABLE_GCS@:
     compile_flags.append('-mbranch-protection=standard')
 
+if @HAVE_CFI_SET_RA_STATE@:
+    compile_flags.append('-DHAVE_CFI_SET_RA_STATE')
+
 # On ELF platforms, link tests with -Wl,--export-dynamic if supported by the 
linker.
 if len('@CMAKE_EXE_EXPORTS_CXX_FLAG@'):
     link_flags.append('@CMAKE_EXE_EXPORTS_CXX_FLAG@')

diff  --git a/libunwind/test/configs/llvm-libunwind-static.cfg.in 
b/libunwind/test/configs/llvm-libunwind-static.cfg.in
index 7e1fb5395c57a..f831c74948579 100644
--- a/libunwind/test/configs/llvm-libunwind-static.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-static.cfg.in
@@ -22,6 +22,9 @@ if @LIBUNWIND_ENABLE_CET@:
 if @LIBUNWIND_ENABLE_GCS@:
     compile_flags.append('-mbranch-protection=standard')
 
+if @HAVE_CFI_SET_RA_STATE@:
+    compile_flags.append('-DHAVE_CFI_SET_RA_STATE')
+
 # On ELF platforms, link tests with -Wl,--export-dynamic if supported by the 
linker.
 if len('@CMAKE_EXE_EXPORTS_CXX_FLAG@'):
     link_flags.append('@CMAKE_EXE_EXPORTS_CXX_FLAG@')

diff  --git a/libunwind/test/ra_sign_state.pass.cpp 
b/libunwind/test/ra_sign_state.pass.cpp
index 9187d039a761b..4c407890245a0 100644
--- a/libunwind/test/ra_sign_state.pass.cpp
+++ b/libunwind/test/ra_sign_state.pass.cpp
@@ -141,6 +141,34 @@ __attribute__((naked, target("pauth"))) static uint64_t 
check_negate() {
   // clang-format on
 }
 
+#if defined(HAVE_CFI_SET_RA_STATE)
+__attribute__((naked, target("pauth"))) uint64_t check_set() {
+  // clang-format off
+  asm(
+#if !defined(__APPLE__)
+      ".cfi_b_key_frame\n"
+#endif
+      ".cfi_set_ra_state 1, 0\n"
+      "pacibsp\n"
+
+      "stp x29, x30, [sp, #-16]!\n"
+      ".cfi_def_cfa_offset 16\n"
+      ".cfi_offset x29, -16\n"
+      ".cfi_offset x30, -8\n"
+
+      "bl " SYMBOL_NAME(get_main_ra_sign_state) "\n"
+
+      "ldp x29, x30, [sp], #16\n"
+      ".cfi_def_cfa_offset 0\n"
+      ".cfi_restore x29\n"
+      ".cfi_restore x30\n"
+
+      ".cfi_set_ra_state 0, -20\n"
+      "retab");
+  // clang-format on
+}
+#endif
+
 FUNC_ATTR(main_func) int main(int, char **) {
   uint64_t ret;
 
@@ -159,6 +187,12 @@ FUNC_ATTR(main_func) int main(int, char **) {
   fprintf(stderr, "check_negate: ret = 0x%" PRIx64 "\n", ret);
   assert(ret == 1);
 
-  printf("success\n");
+#if defined(HAVE_CFI_SET_RA_STATE)
+  ret = check_set();
+  fprintf(stderr, "check_set: ret = 0x%" PRIx64 "\n", ret);
+  assert(ret == 1);
+#endif
+
+  fprintf(stderr, "success\n");
   return 0;
 }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to