+2020-04-27 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ PR target/94515
+ * dwarf2cfi.c (struct GTY): Add ra_mangled.
+ (cfi_row_equal_p): Check ra_mangled.
+ (dwarf2out_frame_debug_cfa_window_save): Remove the argument,
+ this only handles the sparc logic now.
+ (dwarf2out_frame_debug_cfa_toggle_ra_mangle): New function for
+ the aarch64 specific logic.
+ (dwarf2out_frame_debug): Update to use the new subroutines.
+ (change_cfi_row): Check ra_mangled.
+
2020-04-27 Jakub Jelinek <jakub@redhat.com>
PR target/94704
/* True if the register window is saved. */
bool window_save;
+
+ /* True if the return address is in a mangled state. */
+ bool ra_mangled;
};
/* The caller's ORIG_REG is saved in SAVED_IN_REG. */
if (a->window_save != b->window_save)
return false;
+ if (a->ra_mangled != b->ra_mangled)
+ return false;
+
return true;
}
}
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_WINDOW_SAVE.
- FAKE is true if this is not really a window save but something else.
??? Perhaps we should note in the CIE where windows are saved (instead
of assuming 0(cfa)) and what registers are in the window. */
static void
-dwarf2out_frame_debug_cfa_window_save (bool fake)
+dwarf2out_frame_debug_cfa_window_save (void)
{
dw_cfi_ref cfi = new_cfi ();
cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
add_cfi (cfi);
- if (!fake)
- cur_row->window_save = true;
+ cur_row->window_save = true;
+}
+
+/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_TOGGLE_RA_MANGLE.
+ 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. */
+
+static void
+dwarf2out_frame_debug_cfa_toggle_ra_mangle (void)
+{
+ dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
+ add_cfi (cfi);
+ cur_row->ra_mangled = !cur_row->ra_mangled;
}
/* Record call frame debugging information for an expression EXPR,
break;
case REG_CFA_TOGGLE_RA_MANGLE:
- /* This uses the same DWARF opcode as the next operation. */
- dwarf2out_frame_debug_cfa_window_save (true);
+ dwarf2out_frame_debug_cfa_toggle_ra_mangle ();
handled_one = true;
break;
case REG_CFA_WINDOW_SAVE:
- dwarf2out_frame_debug_cfa_window_save (false);
+ dwarf2out_frame_debug_cfa_window_save ();
handled_one = true;
break;
{
dw_cfi_ref cfi = new_cfi ();
+ gcc_assert (!old_row->ra_mangled && !new_row->ra_mangled);
+ cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
+ add_cfi (cfi);
+ }
+
+ if (old_row->ra_mangled != new_row->ra_mangled)
+ {
+ 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;
add_cfi (cfi);
}
--- /dev/null
+/* PR target/94515. Check .cfi_window_save with multiple return paths. */
+/* { dg-do run } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-additional-options "-O2 --save-temps" } */
+
+volatile int zero = 0;
+
+__attribute__((noinline, target("branch-protection=none")))
+void unwind (void)
+{
+ if (zero == 0)
+ throw 42;
+}
+
+__attribute__((noinline, noipa, target("branch-protection=pac-ret")))
+int test (int z)
+{
+ if (z) {
+ asm volatile ("":::"x20","x21");
+ unwind ();
+ return 1;
+ } else {
+ unwind ();
+ return 2;
+ }
+}
+
+__attribute__((target("branch-protection=none")))
+int main ()
+{
+ try {
+ test (zero);
+ __builtin_abort ();
+ } catch (...) {
+ return 0;
+ }
+ __builtin_abort ();
+}
+
+/* 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
+ plus cfi_restore_state. This is currently the case with -O2. */
+
+/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */
--- /dev/null
+/* PR target/94515. Check .cfi_window_save with multiple return paths. */
+/* { dg-do run } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-additional-options "-O2 -mbranch-protection=pac-ret" } */
+
+volatile int zero = 0;
+int global = 0;
+
+__attribute__((noinline))
+int bar(void)
+{
+ if (zero == 0) return 3;
+ return 0;
+}
+
+__attribute__((noinline, noreturn))
+void unwind (void)
+{
+ throw 42;
+}
+
+__attribute__((noinline, noipa))
+int test(int x)
+{
+ if (x==1) return 2; /* This return path may not use the stack. */
+ int y = bar();
+ if (y > global) global=y;
+ if (y==3) unwind(); /* This return path must have RA mangle state set. */
+ return 0;
+}
+
+int main ()
+{
+ try {
+ test (zero);
+ __builtin_abort ();
+ } catch (...) {
+ return 0;
+ }
+ __builtin_abort ();
+}