diff options
author | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2022-02-10 17:42:56 +0000 |
---|---|---|
committer | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2022-05-25 09:17:06 +0100 |
commit | 0d344b557604e966dc7f91739881f03e1f221efd (patch) | |
tree | 1f4c049fd1aea8937286c1d1d678b3fea1500985 /libgcc/unwind-dw2.c | |
parent | 768f49a20f467648c8e006e2431d0da3eab11846 (diff) | |
download | gcc-0d344b557604e966dc7f91739881f03e1f221efd.zip gcc-0d344b557604e966dc7f91739881f03e1f221efd.tar.gz gcc-0d344b557604e966dc7f91739881f03e1f221efd.tar.bz2 |
aarch64: Fix pac-ret with unusual dwarf in libgcc unwinder [PR104689]
The RA_SIGN_STATE dwarf pseudo-register is normally only set using the
DW_CFA_AARCH64_negate_ra_state (== DW_CFA_window_save) operation which
toggles the return address signedness state (the default state is 0).
(It may be set by remember/restore_state CFI too, those save/restore
the state of all registers.)
However RA_SIGN_STATE can be set directly via DW_CFA_val_expression too.
GCC does not generate such CFI but some other compilers reportedly do.
Note: the toggle operation must not be mixed with other dwarf register
rule CFI within the same CIE and FDE.
In libgcc we assume REG_UNSAVED means the RA_STATE is set using toggle
operations, otherwise we assume its value is set by other CFI.
libgcc/ChangeLog:
PR target/104689
* config/aarch64/aarch64-unwind.h (aarch64_frob_update_context):
Handle the !REG_UNSAVED case.
* unwind-dw2.c (execute_cfa_program): Fail toggle if !REG_UNSAVED.
gcc/testsuite/ChangeLog:
PR target/104689
* gcc.target/aarch64/pr104689.c: New test.
Diffstat (limited to 'libgcc/unwind-dw2.c')
-rw-r--r-- | libgcc/unwind-dw2.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c index 6ccd885..a2eb66d 100644 --- a/libgcc/unwind-dw2.c +++ b/libgcc/unwind-dw2.c @@ -1204,7 +1204,9 @@ execute_cfa_program (const unsigned char *insn_ptr, #if defined (__aarch64__) && !defined (__ILP32__) /* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle return address signing status. */ - fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1; + reg = DWARF_REGNUM_AARCH64_RA_STATE; + gcc_assert (fs->regs.reg[reg].how == REG_UNSAVED); + fs->regs.reg[reg].loc.offset ^= 1; #else /* ??? Hardcoded for SPARC register window configuration. */ if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32) |