114 lines
4.3 KiB
Diff
114 lines
4.3 KiB
Diff
|
A recent change only initializes the regs.how[] during Dwarf unwinding
|
||
|
which resulted in an uninitialized offset used in return address signing
|
||
|
and random failures during unwinding. The fix is to encode the return
|
||
|
address signing state in REG_UNSAVED and REG_UNDEFINED.
|
||
|
|
||
|
2023-01-10 Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
|
|
||
|
PR target/107678
|
||
|
* unwind-dw2.c (RA_SIGNED_BIT): Remove.
|
||
|
* unwind-dw2-execute_cfa.h: Use REG_UNSAVED/UNDEFINED
|
||
|
to encode return address signing state.
|
||
|
* config/aarch64/aarch64-unwind.h (aarch64_demangle_return_addr)
|
||
|
Check current return address signing state.
|
||
|
(aarch64_frob_update_contex): Remove.
|
||
|
|
||
|
--- libgcc/config/aarch64/aarch64-unwind.h
|
||
|
+++ libgcc/config/aarch64/aarch64-unwind.h
|
||
|
@@ -29,8 +29,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||
|
|
||
|
#define MD_DEMANGLE_RETURN_ADDR(context, fs, addr) \
|
||
|
aarch64_demangle_return_addr (context, fs, addr)
|
||
|
-#define MD_FROB_UPDATE_CONTEXT(context, fs) \
|
||
|
- aarch64_frob_update_context (context, fs)
|
||
|
|
||
|
static inline int
|
||
|
aarch64_cie_signed_with_b_key (struct _Unwind_Context *context)
|
||
|
@@ -55,42 +53,27 @@ aarch64_cie_signed_with_b_key (struct _Unwind_Context *context)
|
||
|
|
||
|
static inline void *
|
||
|
aarch64_demangle_return_addr (struct _Unwind_Context *context,
|
||
|
- _Unwind_FrameState *fs ATTRIBUTE_UNUSED,
|
||
|
+ _Unwind_FrameState *fs,
|
||
|
_Unwind_Word addr_word)
|
||
|
{
|
||
|
void *addr = (void *)addr_word;
|
||
|
- if (context->flags & RA_SIGNED_BIT)
|
||
|
+ const int reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||
|
+
|
||
|
+ if (fs->regs.how[reg] == REG_UNSAVED)
|
||
|
+ return addr;
|
||
|
+
|
||
|
+ /* Return-address signing state is toggled by DW_CFA_GNU_window_save (where
|
||
|
+ REG_UNDEFINED means enabled), or set by a DW_CFA_expression. */
|
||
|
+ if (fs->regs.how[reg] == REG_UNDEFINED
|
||
|
+ || (_Unwind_GetGR (context, reg) & 0x1) != 0)
|
||
|
{
|
||
|
_Unwind_Word salt = (_Unwind_Word) context->cfa;
|
||
|
if (aarch64_cie_signed_with_b_key (context) != 0)
|
||
|
return __builtin_aarch64_autib1716 (addr, salt);
|
||
|
return __builtin_aarch64_autia1716 (addr, salt);
|
||
|
}
|
||
|
- else
|
||
|
- return addr;
|
||
|
-}
|
||
|
-
|
||
|
-/* Do AArch64 private initialization on CONTEXT based on frame info FS. Mark
|
||
|
- CONTEXT as return address signed if bit 0 of DWARF_REGNUM_AARCH64_RA_STATE is
|
||
|
- set. */
|
||
|
-
|
||
|
-static inline void
|
||
|
-aarch64_frob_update_context (struct _Unwind_Context *context,
|
||
|
- _Unwind_FrameState *fs)
|
||
|
-{
|
||
|
- const int reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||
|
- int ra_signed;
|
||
|
- if (fs->regs.how[reg] == 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
|
||
|
- context->flags &= ~RA_SIGNED_BIT;
|
||
|
|
||
|
- return;
|
||
|
+ return addr;
|
||
|
}
|
||
|
|
||
|
#endif /* defined AARCH64_UNWIND_H && defined __ILP32__ */
|
||
|
--- libgcc/unwind-dw2.c
|
||
|
+++ libgcc/unwind-dw2.c
|
||
|
@@ -137,9 +137,6 @@ struct _Unwind_Context
|
||
|
#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
|
||
|
/* Context which has version/args_size/by_value fields. */
|
||
|
#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
|
||
|
- /* Bit reserved on AArch64, return address has been signed with A or B
|
||
|
- key. */
|
||
|
-#define RA_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1)
|
||
|
_Unwind_Word flags;
|
||
|
/* 0 for now, can be increased when further fields are added to
|
||
|
struct _Unwind_Context. */
|
||
|
--- libgcc/unwind-dw2-execute_cfa.h 2023-01-02 17:53:56.003021412 +0100
|
||
|
+++ libgcc/unwind-dw2-execute_cfa.h 2023-01-12 19:52:05.456327742 +0100
|
||
|
@@ -278,10 +278,15 @@
|
||
|
case DW_CFA_GNU_window_save:
|
||
|
#if defined (__aarch64__) && !defined (__ILP32__)
|
||
|
/* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle
|
||
|
- return address signing status. */
|
||
|
+ return address signing status. The REG_UNDEFINED/UNSAVED states
|
||
|
+ mean RA signing is enabled/disabled. */
|
||
|
reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||
|
- gcc_assert (fs->regs.how[reg] == REG_UNSAVED);
|
||
|
- fs->regs.reg[reg].loc.offset ^= 1;
|
||
|
+ gcc_assert (fs->regs.how[reg] == REG_UNSAVED
|
||
|
+ || fs->regs.how[reg] == REG_UNDEFINED);
|
||
|
+ if (fs->regs.how[reg] == REG_UNSAVED)
|
||
|
+ fs->regs.how[reg] = REG_UNDEFINED;
|
||
|
+ else
|
||
|
+ fs->regs.how[reg] = REG_UNSAVED;
|
||
|
#else
|
||
|
/* ??? Hardcoded for SPARC register window configuration. */
|
||
|
if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
|