aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorSzabolcs Nagy <szabolcs.nagy@arm.com>2022-02-10 17:42:56 +0000
committerSzabolcs Nagy <szabolcs.nagy@arm.com>2022-05-25 09:17:06 +0100
commit0d344b557604e966dc7f91739881f03e1f221efd (patch)
tree1f4c049fd1aea8937286c1d1d678b3fea1500985 /libgcc
parent768f49a20f467648c8e006e2431d0da3eab11846 (diff)
downloadgcc-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')
-rw-r--r--libgcc/config/aarch64/aarch64-unwind.h8
-rw-r--r--libgcc/unwind-dw2.c4
2 files changed, 10 insertions, 2 deletions
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
index 40b22d3..e082e95 100644
--- a/libgcc/config/aarch64/aarch64-unwind.h
+++ b/libgcc/config/aarch64/aarch64-unwind.h
@@ -78,7 +78,13 @@ static inline void
aarch64_frob_update_context (struct _Unwind_Context *context,
_Unwind_FrameState *fs)
{
- if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
+ const int reg = DWARF_REGNUM_AARCH64_RA_STATE;
+ int ra_signed;
+ if (fs->regs.reg[reg].how == REG_UNSAVED)
+ ra_signed = fs->regs.reg[reg].loc.offset & 0x1;
+ else
+ ra_signed = _Unwind_GetGR (context, reg) & 0x1;
+ if (ra_signed)
/* The flag is used for re-authenticating EH handler's address. */
context->flags |= RA_SIGNED_BIT;
else
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)