diff mbox series

[v2,2/4] dwarf2: add hooks for architecture-specific CFIs

Message ID 20240918140535.1538392-3-matthieu.longo@arm.com
State New
Headers show
Series dwarf2: add hooks for architecture-specific CFIs | expand

Commit Message

Matthieu Longo Sept. 18, 2024, 2:05 p.m. UTC
Architecture-specific CFI directives are currently declared an processed
among others architecture-independent CFI directives in gcc/dwarf2* files.
This approach creates confusion, specifically in the case of DWARF
instructions in the vendor space and using the same instruction code.

Such a clash currently happen between DW_CFA_GNU_window_save (used on
SPARC) and DW_CFA_AARCH64_negate_ra_state (used on AArch64), and both
having the same instruction code 0x2d.
Then AArch64 compilers generates a SPARC CFI directive (.cfi_window_save)
instead of .cfi_negate_ra_state, contrarilly to what is expected in
[DWARF for the Arm 64-bit Architecture (AArch64)](https://github.com/
ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst).

This refactoring does not solve completely the problem, but improve the
situation by moving some of the processing of those directives (more
specifically their output in the assembly) to the backend via 2 target
hooks:
- DW_CFI_OPRND1_DESC: parse the first operand of the directive (if any).
- OUTPUT_CFI_DIRECTIVE: output the CFI directive as a string.

Additionally, this patch also contains a renaming of an enum used for
return address mangling on AArch64.

gcc/ChangeLog:

        * config/aarch64/aarch64.cc
        (aarch64_output_cfi_directive): New hook for CFI directives.
        (aarch64_dw_cfi_oprnd1_desc): Same.
        (TARGET_OUTPUT_CFI_DIRECTIVE): Hook for output_cfi_directive.
        (TARGET_DW_CFI_OPRND1_DESC): Hook for dw_cfi_oprnd1_desc.
        * config/sparc/sparc.cc
        (sparc_output_cfi_directive): New hook for CFI directives.
        (sparc_dw_cfi_oprnd1_desc): Same.
        (TARGET_OUTPUT_CFI_DIRECTIVE): Hook for output_cfi_directive.
        (TARGET_DW_CFI_OPRND1_DESC): Hook for dw_cfi_oprnd1_desc.
        * coretypes.h
        (struct dw_cfi_node): Forward declaration of CFI type from
        gcc/dwarf2out.h.
        (enum dw_cfi_oprnd_type): Same.
        (enum dwarf_call_frame_info): Same.
        * doc/tm.texi: Regenerated from doc/tm.texi.in.
        * doc/tm.texi.in: Add doc for new target hooks.
        * dwarf2.h (enum dwarf_call_frame_info): specify underlying
        type of enum to allow forward declaration.
        * dwarf2cfi.cc
        (struct dw_cfi_row): Update the description for window_save
        and ra_mangled.
        (dwarf2out_frame_debug_cfa_negate_ra_state): Use AArch64 CFI
        directive instead of the SPARC one.
        (change_cfi_row): Use the right CFI directive's name for RA
        mangling.
        (output_cfi): Remove explicit architecture-specific CFI
        directive DW_CFA_GNU_window_save that falls into default case.
        (output_cfi_directive): Use target hook as default.
        * dwarf2out.cc (dw_cfi_oprnd1_desc): Use target hook as default.
        * dwarf2out.h (enum dw_cfi_oprnd_type): specify underlying type
        of enum to allow forward declaration.
        (dw_cfi_oprnd1_desc): Call target hook.
        (output_cfi_directive): Use dw_cfi_ref instead of struct
        dw_cfi_node *.
        * hooks.cc
        (hook_bool_dwcfi_dwcfioprndtyperef_false): New.
        (hook_bool_FILEptr_dwcfiptr_false): New.
        * hooks.h
        (hook_bool_dwcfi_dwcfioprndtyperef_false): New.
        (hook_bool_FILEptr_dwcfiptr_false): New.
        * target.def: Documentation for new hooks.

libffi/ChangeLog:

        * include/ffi_cfi.h (cfi_negate_ra_state): Declare AArch64 cfi
        directive.

libgcc/ChangeLog:

        * config/aarch64/aarch64-asm.h (PACIASP): Replace SPARC CFI
        directive by AArch64 one.
        (AUTIASP): Same.

libitm/ChangeLog:

        * config/aarch64/sjlj.S: Replace SPARC CFI directive by
        AArch64 one.

gcc/testsuite/ChangeLog:

        * g++.target/aarch64/pr94515-1.C: Replace SPARC CFI directive by
        AArch64 one.
        * g++.target/aarch64/pr94515-2.C: Same.
---
 gcc/config/aarch64/aarch64.cc                | 33 ++++++++++++++++++
 gcc/config/sparc/sparc.cc                    | 35 ++++++++++++++++++++
 gcc/coretypes.h                              |  6 ++++
 gcc/doc/tm.texi                              | 16 ++++++++-
 gcc/doc/tm.texi.in                           |  5 ++-
 gcc/dwarf2cfi.cc                             | 31 ++++++-----------
 gcc/dwarf2out.cc                             | 13 +++++---
 gcc/dwarf2out.h                              | 11 +++---
 gcc/hooks.cc                                 | 14 ++++++++
 gcc/hooks.h                                  |  3 ++
 gcc/target.def                               | 20 +++++++++++
 gcc/testsuite/g++.target/aarch64/pr94515-1.C |  6 ++--
 gcc/testsuite/g++.target/aarch64/pr94515-2.C |  2 +-
 include/dwarf2.h                             |  5 +++
 libffi/include/ffi_cfi.h                     |  2 ++
 libgcc/config/aarch64/aarch64-asm.h          |  4 +--
 libitm/config/aarch64/sjlj.S                 | 10 +++---
 17 files changed, 171 insertions(+), 45 deletions(-)
diff mbox series

Patch

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index acb2ddb9170..2e33f96749a 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -60,6 +60,7 @@ 
 #include "opts.h"
 #include "gimplify.h"
 #include "dwarf2.h"
+#include "dwarf2out.h"
 #include "gimple-iterator.h"
 #include "tree-vectorizer.h"
 #include "aarch64-cost-tables.h"
@@ -1450,6 +1451,32 @@  aarch64_dwarf_frame_reg_mode (int regno)
   return default_dwarf_frame_reg_mode (regno);
 }
 
+/* Implement TARGET_OUTPUT_CFI_DIRECTIVE.  */
+static bool
+aarch64_output_cfi_directive (FILE *f, dw_cfi_ref cfi)
+{
+  bool found = false;
+  if (cfi->dw_cfi_opc == DW_CFA_AARCH64_negate_ra_state)
+    {
+      fprintf (f, "\t.cfi_negate_ra_state\n");
+      found = true;
+    }
+  return found;
+}
+
+/* Implement TARGET_DW_CFI_OPRND1_DESC.  */
+static bool
+aarch64_dw_cfi_oprnd1_desc (dwarf_call_frame_info cfi_opc,
+			    dw_cfi_oprnd_type &oprnd_type)
+{
+  if (cfi_opc == DW_CFA_AARCH64_negate_ra_state)
+    {
+      oprnd_type = dw_cfi_oprnd_unused;
+      return true;
+    }
+  return false;
+}
+
 /* If X is a CONST_DOUBLE, return its bit representation as a constant
    integer, otherwise return X unmodified.  */
 static rtx
@@ -30822,6 +30849,12 @@  aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_DWARF_FRAME_REG_MODE
 #define TARGET_DWARF_FRAME_REG_MODE aarch64_dwarf_frame_reg_mode
 
+#undef TARGET_OUTPUT_CFI_DIRECTIVE
+#define TARGET_OUTPUT_CFI_DIRECTIVE aarch64_output_cfi_directive
+
+#undef TARGET_DW_CFI_OPRND1_DESC
+#define TARGET_DW_CFI_OPRND1_DESC aarch64_dw_cfi_oprnd1_desc
+
 #undef TARGET_PROMOTED_TYPE
 #define TARGET_PROMOTED_TYPE aarch64_promoted_type
 
diff --git a/gcc/config/sparc/sparc.cc b/gcc/config/sparc/sparc.cc
index 3a4c13a14e5..4bc249da825 100644
--- a/gcc/config/sparc/sparc.cc
+++ b/gcc/config/sparc/sparc.cc
@@ -61,6 +61,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "tree-vector-builder.h"
 #include "opts.h"
+#include "dwarf2out.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -681,6 +682,9 @@  static rtx sparc_libcall_value (machine_mode, const_rtx);
 static bool sparc_function_value_regno_p (const unsigned int);
 static unsigned HOST_WIDE_INT sparc_asan_shadow_offset (void);
 static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
+static bool sparc_output_cfi_directive (FILE *, dw_cfi_ref);
+static bool sparc_dw_cfi_oprnd1_desc (dwarf_call_frame_info,
+				      dw_cfi_oprnd_type &);
 static void sparc_file_end (void);
 static bool sparc_frame_pointer_required (void);
 static bool sparc_can_eliminate (const int, const int);
@@ -878,6 +882,12 @@  char sparc_hard_reg_printed[8];
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
 #endif
 
+#undef TARGET_OUTPUT_CFI_DIRECTIVE
+#define TARGET_OUTPUT_CFI_DIRECTIVE sparc_output_cfi_directive
+
+#undef TARGET_DW_CFI_OPRND1_DESC
+#define TARGET_DW_CFI_OPRND1_DESC sparc_dw_cfi_oprnd1_desc
+
 #undef TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END sparc_file_end
 
@@ -12621,6 +12631,31 @@  sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
   fputs (")", file);
 }
 
+/* Implement TARGET_OUTPUT_CFI_DIRECTIVE.  */
+static bool
+sparc_output_cfi_directive (FILE *f, dw_cfi_ref cfi)
+{
+  if (cfi->dw_cfi_opc == DW_CFA_GNU_window_save)
+    {
+      fprintf (f, "\t.cfi_window_save\n");
+      return true;
+    }
+  return false;
+}
+
+/* Implement TARGET_DW_CFI_OPRND1_DESC.  */
+static bool
+sparc_dw_cfi_oprnd1_desc (dwarf_call_frame_info cfi_opc,
+			  dw_cfi_oprnd_type &oprnd_type)
+{
+  if (cfi_opc == DW_CFA_GNU_window_save)
+    {
+      oprnd_type = dw_cfi_oprnd_unused;
+      return true;
+    }
+  return false;
+}
+
 /* Do whatever processing is required at the end of a file.  */
 
 static void
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 0544bb8fd97..991312534cd 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -141,6 +141,12 @@  struct gomp_single;
 struct gomp_target;
 struct gomp_teams;
 
+/* Forward declaration of CFI's and DWARF's types.  */
+struct dw_cfi_node;
+using dw_cfi_ref = struct dw_cfi_node *;
+enum dw_cfi_oprnd_type: int;
+enum dwarf_call_frame_info: int;
+
 /* Subclasses of symtab_node, using indentation to show the class
    hierarchy.  */
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index cc33084ed32..d4ebe36b0ff 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3911,7 +3911,6 @@  used in .eh_frame or .debug_frame is different from that used in other
 debug info sections.  Given a GCC hard register number, this macro
 should return the .eh_frame register number.  The default is
 @code{DEBUGGER_REGNO (@var{regno})}.
-
 @end defmac
 
 @defmac DWARF2_FRAME_REG_OUT (@var{regno}, @var{for_eh})
@@ -10050,6 +10049,21 @@  used to return a smaller mode than the raw mode to prevent call
 clobbered parts of a register altering the frame register size
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_OUTPUT_CFI_DIRECTIVE (FILE * @var{f}, dw_cfi_ref @var{cfi})
+This hook handles architecture-specific CFI directives and prints
+them out to the assembly file @var{f}.
+Return true if a architecture-specific directive was found, false
+otherwise.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_DW_CFI_OPRND1_DESC (dwarf_call_frame_info @var{cfi_opc}, dw_cfi_oprnd_type & @var{oprnd_type})
+This hook informs the caller what the architecture-specific directives
+takes as a first operand.
+Return true if a architecture-specific directive was found and
+@var{oprnd_type} is set, false otherwise and @var{oprnd_type} is not
+modified.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_INIT_DWARF_REG_SIZES_EXTRA (tree @var{address})
 If some registers are represented in Dwarf-2 unwind information in
 multiple pieces, define this hook to fill in information about the
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 8af3f414505..36541cbcc09 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -3108,7 +3108,6 @@  used in .eh_frame or .debug_frame is different from that used in other
 debug info sections.  Given a GCC hard register number, this macro
 should return the .eh_frame register number.  The default is
 @code{DEBUGGER_REGNO (@var{regno})}.
-
 @end defmac
 
 @defmac DWARF2_FRAME_REG_OUT (@var{regno}, @var{for_eh})
@@ -6614,6 +6613,10 @@  the target supports DWARF 2 frame unwind information.
 
 @hook TARGET_DWARF_FRAME_REG_MODE
 
+@hook TARGET_OUTPUT_CFI_DIRECTIVE
+
+@hook TARGET_DW_CFI_OPRND1_DESC
+
 @hook TARGET_INIT_DWARF_REG_SIZES_EXTRA
 
 @hook TARGET_ASM_TTYPE
diff --git a/gcc/dwarf2cfi.cc b/gcc/dwarf2cfi.cc
index 4ad9acbd6fd..f8d19d52429 100644
--- a/gcc/dwarf2cfi.cc
+++ b/gcc/dwarf2cfi.cc
@@ -69,10 +69,12 @@  struct GTY(()) dw_cfi_row
   /* The expressions for any register column that is saved.  */
   cfi_vec reg_save;
 
-  /* True if the register window is saved.  */
+  /* SPARC extension for DW_CFA_GNU_window_save.
+     True if the register window is saved.  */
   bool window_save;
 
-  /* True if the return address is in a mangled state.  */
+  /* AArch64 extension for DW_CFA_AARCH64_negate_ra_state.
+     True if the return address is in a mangled state.  */
   bool ra_mangled;
 };
 
@@ -801,8 +803,6 @@  cfi_oprnd_equal_p (enum dw_cfi_oprnd_type t, dw_cfi_oprnd *a, dw_cfi_oprnd *b)
 static bool
 cfi_equal_p (dw_cfi_ref a, dw_cfi_ref b)
 {
-  enum dwarf_call_frame_info opc;
-
   /* Make things easier for our callers, including missing operands.  */
   if (a == b)
     return true;
@@ -810,7 +810,7 @@  cfi_equal_p (dw_cfi_ref a, dw_cfi_ref b)
     return false;
 
   /* Obviously, the opcodes must match.  */
-  opc = a->dw_cfi_opc;
+  dwarf_call_frame_info opc = a->dw_cfi_opc;
   if (opc != b->dw_cfi_opc)
     return false;
 
@@ -1547,17 +1547,13 @@  dwarf2out_frame_debug_cfa_window_save (void)
   cur_row->window_save = true;
 }
 
-/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_NEGATE_RA_STATE.
-   Note: DW_CFA_GNU_window_save dwarf opcode is reused for toggling RA mangle
-   state, this is a target specific operation on AArch64 and can only be used
-   on other targets if they don't use the window save operation otherwise.  */
+/* A subroutine of dwarf2out_frame_debug, process REG_CFA_NEGATE_RA_STATE.  */
 
 static void
 dwarf2out_frame_debug_cfa_negate_ra_state (void)
 {
   dw_cfi_ref cfi = new_cfi ();
-
-  cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
+  cfi->dw_cfi_opc = DW_CFA_AARCH64_negate_ra_state;
   add_cfi (cfi);
   cur_row->ra_mangled = !cur_row->ra_mangled;
 }
@@ -2426,8 +2422,7 @@  change_cfi_row (dw_cfi_row *old_row, dw_cfi_row *new_row)
       dw_cfi_ref cfi = new_cfi ();
 
       gcc_assert (!old_row->window_save && !new_row->window_save);
-      /* DW_CFA_GNU_window_save is reused for toggling RA mangle state.  */
-      cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
+      cfi->dw_cfi_opc = DW_CFA_AARCH64_negate_ra_state;
       add_cfi (cfi);
     }
 }
@@ -3516,9 +3511,6 @@  output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
 	  dw2_asm_output_data_sleb128 (off, NULL);
 	  break;
 
-	case DW_CFA_GNU_window_save:
-	  break;
-
 	case DW_CFA_def_cfa_expression:
 	case DW_CFA_expression:
 	case DW_CFA_val_expression:
@@ -3631,10 +3623,6 @@  output_cfi_directive (FILE *f, dw_cfi_ref cfi)
 	}
       break;
 
-    case DW_CFA_GNU_window_save:
-      fprintf (f, "\t.cfi_window_save\n");
-      break;
-
     case DW_CFA_def_cfa_expression:
     case DW_CFA_expression:
     case DW_CFA_val_expression:
@@ -3651,7 +3639,8 @@  output_cfi_directive (FILE *f, dw_cfi_ref cfi)
       break;
 
     default:
-      gcc_unreachable ();
+      if (!targetm.output_cfi_directive (f, cfi))
+	gcc_unreachable ();
     }
 }
 
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index a7ec359bd0c..38aedb64470 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -516,12 +516,11 @@  switch_to_frame_table_section (int for_eh, bool back)
 /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used.  */
 
 enum dw_cfi_oprnd_type
-dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
+dw_cfi_oprnd1_desc (dwarf_call_frame_info cfi)
 {
   switch (cfi)
     {
     case DW_CFA_nop:
-    case DW_CFA_GNU_window_save:
     case DW_CFA_remember_state:
     case DW_CFA_restore_state:
       return dw_cfi_oprnd_unused;
@@ -557,14 +556,20 @@  dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
       return dw_cfi_oprnd_loc;
 
     default:
-      gcc_unreachable ();
+      {
+	dw_cfi_oprnd_type oprnd_type;
+	if (targetm.dw_cfi_oprnd1_desc (cfi, oprnd_type))
+	  return oprnd_type;
+	else
+	  gcc_unreachable ();
+      }
     }
 }
 
 /* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used.  */
 
 enum dw_cfi_oprnd_type
-dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
+dw_cfi_oprnd2_desc (dwarf_call_frame_info cfi)
 {
   switch (cfi)
     {
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index ded1697ecf6..27919594bef 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -37,8 +37,7 @@  typedef struct dw_wide_int *dw_wide_int_ptr;
    Information instructions.  The register number, offset
    and address fields are provided as possible operands;
    their use is selected by the opcode field.  */
-
-enum dw_cfi_oprnd_type {
+enum dw_cfi_oprnd_type: int {
   dw_cfi_oprnd_unused,
   dw_cfi_oprnd_reg_num,
   dw_cfi_oprnd_offset,
@@ -405,12 +404,10 @@  extern void output_cfi (dw_cfi_ref, dw_fde_ref, int);
 extern GTY(()) cfi_vec cie_cfi_vec;
 
 /* Interface from dwarf2*.c to the rest of the compiler.  */
-extern enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc
-  (enum dwarf_call_frame_info cfi);
-extern enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc
-  (enum dwarf_call_frame_info cfi);
+extern enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc (dwarf_call_frame_info cfi);
+extern enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc (dwarf_call_frame_info cfi);
 
-extern void output_cfi_directive (FILE *f, struct dw_cfi_node *cfi);
+extern void output_cfi_directive (FILE *f, dw_cfi_ref cfi);
 
 extern void dwarf2out_emit_cfi (dw_cfi_ref cfi);
 
diff --git a/gcc/hooks.cc b/gcc/hooks.cc
index 28769074222..4eb3d32d978 100644
--- a/gcc/hooks.cc
+++ b/gcc/hooks.cc
@@ -62,6 +62,20 @@  hook_bool_bool_gcc_optionsp_false (bool, struct gcc_options *)
   return false;
 }
 
+/* Generic hook that takes (dwarf_call_frame_info, dw_cfi_oprnd_type &) and
+   return false.  */
+bool hook_bool_dwcfi_dwcfioprndtyperef_false (dwarf_call_frame_info,
+					      dw_cfi_oprnd_type &)
+{
+  return false;
+}
+
+/* Generic hook that takes (FILE *, dw_cfi_ref) and return false.  */
+bool hook_bool_FILEptr_dwcfiptr_false (FILE *, dw_cfi_ref)
+{
+  return false;
+}
+
 /* Generic hook that takes const int, const int) and returns true.  */
 bool hook_bool_const_int_const_int_true (const int, const int)
 {
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 924748420e6..3b84a7d564e 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -27,6 +27,9 @@  extern bool hook_bool_void_false (void);
 extern bool hook_bool_void_true (void);
 extern bool hook_bool_bool_false (bool);
 extern bool hook_bool_bool_gcc_optionsp_false (bool, struct gcc_options *);
+extern bool hook_bool_dwcfi_dwcfioprndtyperef_false (dwarf_call_frame_info,
+						     dw_cfi_oprnd_type &);
+extern bool hook_bool_FILEptr_dwcfiptr_false (FILE *, dw_cfi_ref);
 extern bool hook_bool_const_int_const_int_true (const int, const int);
 extern bool hook_bool_mode_false (machine_mode);
 extern bool hook_bool_mode_true (machine_mode);
diff --git a/gcc/target.def b/gcc/target.def
index 1d0ea6f30ca..b3155010888 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4127,6 +4127,26 @@  clobbered parts of a register altering the frame register size",
  machine_mode, (int regno),
  default_dwarf_frame_reg_mode)
 
+/* Print out architecture-specific CFI directives to the assembly file.  */
+DEFHOOK
+(output_cfi_directive,
+ "This hook handles architecture-specific CFI directives and prints\n\
+them out to the assembly file @var{f}.\n\
+Return true if a architecture-specific directive was found, false\n\
+otherwise.",
+ bool, (FILE * f, dw_cfi_ref cfi),
+ hook_bool_FILEptr_dwcfiptr_false)
+
+DEFHOOK
+(dw_cfi_oprnd1_desc,
+ "This hook informs the caller what the architecture-specific directives\n\
+takes as a first operand.\n\
+Return true if a architecture-specific directive was found and\n\
+@var{oprnd_type} is set, false otherwise and @var{oprnd_type} is not\n\
+modified.",
+ bool, (dwarf_call_frame_info cfi_opc, dw_cfi_oprnd_type & oprnd_type),
+ hook_bool_dwcfi_dwcfioprndtyperef_false)
+
 /* If expand_builtin_init_dwarf_reg_sizes needs to fill in table
    entries not corresponding directly to registers below
    FIRST_PSEUDO_REGISTER, this hook should generate the necessary
diff --git a/gcc/testsuite/g++.target/aarch64/pr94515-1.C b/gcc/testsuite/g++.target/aarch64/pr94515-1.C
index 20ae81215fc..d5c114a83a8 100644
--- a/gcc/testsuite/g++.target/aarch64/pr94515-1.C
+++ b/gcc/testsuite/g++.target/aarch64/pr94515-1.C
@@ -1,4 +1,4 @@ 
-/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
+/* PR target/94515. Check .cfi_negate_ra_state with multiple return paths.  */
 /* { dg-do run } */
 /* { dg-require-effective-target lp64 } */
 /* { dg-additional-options "-O2 --save-temps" } */
@@ -38,7 +38,7 @@  int main ()
 }
 
 /* This check only works if there are two return paths in test and
-   cfi_window_save is used for both instead of cfi_remember_state
+   cfi_negate_ra_state is used for both instead of cfi_remember_state
    plus cfi_restore_state.  This is currently the case with -O2.  */
 
-/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */
+/* { dg-final { scan-assembler-times {\t\.cfi_negate_ra_state\n} 4 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/pr94515-2.C b/gcc/testsuite/g++.target/aarch64/pr94515-2.C
index e73df499070..f4a3333beed 100644
--- a/gcc/testsuite/g++.target/aarch64/pr94515-2.C
+++ b/gcc/testsuite/g++.target/aarch64/pr94515-2.C
@@ -1,4 +1,4 @@ 
-/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
+/* PR target/94515. Check .cfi_negate_ra_state with multiple return paths.  */
 /* { dg-do run } */
 /* { dg-require-effective-target lp64 } */
 /* { dg-additional-options "-O2 -mbranch-protection=pac-ret" } */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index b3d3731ee83..7235575f74b 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -72,8 +72,13 @@ 
 #define DW_FIRST_ATE(name, value) enum dwarf_type { \
   name = value
 #define DW_END_ATE };
+#ifdef __cplusplus
+#define DW_FIRST_CFA(name, value) enum dwarf_call_frame_info: int { \
+  name = value
+#else
 #define DW_FIRST_CFA(name, value) enum dwarf_call_frame_info { \
   name = value
+#endif
 #define DW_END_CFA };
 #define DW_FIRST_IDX(name, value) enum dwarf_name_index_attribute { \
   name = value
diff --git a/libffi/include/ffi_cfi.h b/libffi/include/ffi_cfi.h
index f4c292d0040..2beb165c9a1 100644
--- a/libffi/include/ffi_cfi.h
+++ b/libffi/include/ffi_cfi.h
@@ -46,6 +46,7 @@ 
 # define cfi_remember_state		.cfi_remember_state
 # define cfi_restore_state		.cfi_restore_state
 # define cfi_window_save		.cfi_window_save
+# define cfi_negate_ra_state		.cfi_negate_ra_state
 # define cfi_personality(enc, exp)	.cfi_personality enc, exp
 # define cfi_lsda(enc, exp)		.cfi_lsda enc, exp
 # define cfi_escape(...)		.cfi_escape __VA_ARGS__
@@ -68,6 +69,7 @@ 
 # define cfi_remember_state
 # define cfi_restore_state
 # define cfi_window_save
+# define cfi_negate_ra_state
 # define cfi_personality(enc, exp)
 # define cfi_lsda(enc, exp)
 # define cfi_escape(...)
diff --git a/libgcc/config/aarch64/aarch64-asm.h b/libgcc/config/aarch64/aarch64-asm.h
index 83c2e5944b3..d8ab91d52f1 100644
--- a/libgcc/config/aarch64/aarch64-asm.h
+++ b/libgcc/config/aarch64/aarch64-asm.h
@@ -50,8 +50,8 @@ 
 
 #if __ARM_FEATURE_PAC_DEFAULT & 3
 # define PAC_FLAG FEATURE_1_PAC
-# define PACIASP hint	25; .cfi_window_save
-# define AUTIASP hint	29; .cfi_window_save
+# define PACIASP hint	25; .cfi_negate_ra_state
+# define AUTIASP hint	29; .cfi_negate_ra_state
 #else
 # define PAC_FLAG 0
 # define PACIASP
diff --git a/libitm/config/aarch64/sjlj.S b/libitm/config/aarch64/sjlj.S
index 6b248f7c040..aeffd4d1070 100644
--- a/libitm/config/aarch64/sjlj.S
+++ b/libitm/config/aarch64/sjlj.S
@@ -31,20 +31,20 @@ 
 #define AUTIBSP	hint	31
 
 #if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
-# define cfi_window_save .cfi_window_save
-# define cfi_b_key_frame .cfi_b_key_frame
+# define cfi_negate_ra_state .cfi_negate_ra_state
+# define cfi_b_key_frame     .cfi_b_key_frame
 #else
-# define cfi_window_save
+# define cfi_negate_ra_state
 # define cfi_b_key_frame
 #endif
 
 #if __ARM_FEATURE_PAC_DEFAULT & 1
-# define CFI_PAC_TOGGLE	cfi_window_save
+# define CFI_PAC_TOGGLE	cfi_negate_ra_state
 # define CFI_PAC_KEY
 # define PAC_AND_BTI	PACIASP
 # define AUT	AUTIASP
 #elif __ARM_FEATURE_PAC_DEFAULT & 2
-# define CFI_PAC_TOGGLE	cfi_window_save
+# define CFI_PAC_TOGGLE	cfi_negate_ra_state
 # define CFI_PAC_KEY	cfi_b_key_frame
 # define PAC_AND_BTI	PACIBSP
 # define AUT	AUTIBSP