On 12/01/17 18:10, Jiong Wang wrote:
On 06/01/17 11:47, Jiong Wang wrote:
This is the update on libgcc unwinder support according to new DWARF proposal.
As Joseph commented, duplication of unwind-dw2.c is not encouraged in libgcc,
But from this patch, you can see there are a few places we need to modify for
AArch64 in unwind-aarch64.c, so the file duplication approach is acceptable?
libgcc/
2017-01-06 Jiong Wang <jiong.w...@arm.com>
* config/aarch64/unwind-aarch64.c (DWARF_REGNUM_AARCH64_RA_STATE,
RA_A_SIGNED_BIT): New macros.
(execute_cfa_program): Multiplex DW_CFA_GNU_window_save on AArch64.
(uw_frame_state_for): Clear bit[0] of DWARF_REGNUM_AARCH64_RA_STATE.
(uw_update_context): Authenticate return address according to
DWARF_REGNUM_AARCH64_RA_STATE.
(uw_init_context_1): Strip signature of seed address.
(uw_install_context): Re-authenticate EH handler's address.
Ping~
For comparision, I have also attached the patch using the target macros.
Four new target macros are introduced:
MD_POST_EXTRACT_ROOT_ADDR
MD_POST_EXTRACT_FRAME_ADDR
MD_POST_FROB_EH_HANDLER_ADDR
MD_POST_INIT_CONTEXT
MD_POST_EXTRACT_ROOT_ADDR is to do target private post processing on the address
inside _Unwind* functions, they are serving as root address to start the
unwinding. MD_POST_EXTRACT_FRAME_ADDR is to do target private post processing
on th address inside the real user program which throws the exceptions.
MD_POST_FROB_EH_HANDLER_ADDR is to do target private frob on the EH handler's
address before we install it into current context.
MD_POST_INIT_CONTEXT it to do target private initialization on the context
structure after common initialization.
One "__aarch64__" macro check is needed to multiplex DW_CFA_window_save.
Ping ~
Could global reviewers or libgcc maintainers please give a review on the generic
part change?
One small change is I removed MD_POST_INIT_CONTEXT as I found there is
MD_FROB_UPDATE_CONTEXT which serve the same purpose. I still need to define
MD_POST_EXTRACT_ROOT_ADDR
MD_POST_EXTRACT_FRAME_ADDR
MD_POST_FROB_EH_HANDLER_ADDR
And do one __aarch64__ check to multiplexing DW_CFA_GNU_window_save.
Thanks.
libgcc/ChangeLog:
2017-01-18 Jiong Wang <jiong.w...@arm.com>
* config/aarch64/aarch64-unwind.h: New file.
(DWARF_REGNUM_AARCH64_RA_STATE): Define.
(MD_POST_EXTRACT_ROOT_ADDR): Define.
(MD_POST_EXTRACT_FRAME_ADDR): Define.
(MD_POST_FROB_EH_HANDLER_ADDR): Define.
(MD_FROB_UPDATE_CONTEXT): Define.
(aarch64_post_extract_frame_addr): New function.
(aarch64_post_frob_eh_handler_addr): New function.
(aarch64_frob_update_context): New function.
* config/aarch64/linux-unwind.h: Include aarch64-unwind.h
* config.host (aarch64*-*-elf, aarch64*-*-rtems*, aarch64*-*-freebsd*):
Initialize md_unwind_header to include aarch64-unwind.h.
* unwind-dw2.c (struct _Unwind_Context): Define "RA_A_SIGNED_BIT".
(execute_cfa_program): Multiplex DW_CFA_GNU_window_save for __aarch64__.
(uw_update_context): Honor MD_POST_EXTRACT_FRAME_ADDR.
(uw_init_context_1): Honor MD_POST_EXTRACT_ROOT_ADDR.
(uw_frob_return_addr): New function.
(_Unwind_DebugHook): Use uw_frob_return_addr.
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index 8085a42ace15d53f4cb0c6681717012d906a6d47..cf640135275deb76b820f8209fa51eacfd64c4a2 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -136,6 +136,8 @@ 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 key. */
+#define RA_A_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. */
@@ -1185,6 +1187,11 @@ execute_cfa_program (const unsigned char *insn_ptr,
break;
case DW_CFA_GNU_window_save:
+#ifdef __aarch64__
+ /* 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;
+#else
/* ??? Hardcoded for SPARC register window configuration. */
if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
for (reg = 16; reg < 32; ++reg)
@@ -1192,6 +1199,7 @@ execute_cfa_program (const unsigned char *insn_ptr,
fs->regs.reg[reg].how = REG_SAVED_OFFSET;
fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
}
+#endif
break;
case DW_CFA_GNU_args_size:
@@ -1513,10 +1521,15 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
stack frame. */
context->ra = 0;
else
- /* Compute the return address now, since the return address column
- can change from frame to frame. */
- context->ra = __builtin_extract_return_addr
- (_Unwind_GetPtr (context, fs->retaddr_column));
+ {
+ /* Compute the return address now, since the return address column
+ can change from frame to frame. */
+ context->ra = __builtin_extract_return_addr
+ (_Unwind_GetPtr (context, fs->retaddr_column));
+#ifdef MD_POST_EXTRACT_FRAME_ADDR
+ context->ra = MD_POST_EXTRACT_FRAME_ADDR (context, fs, context->ra);
+#endif
+ }
}
static void
@@ -1550,6 +1563,9 @@ uw_init_context_1 (struct _Unwind_Context *context,
void *outer_cfa, void *outer_ra)
{
void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
+#ifdef MD_POST_EXTRACT_ROOT_ADDR
+ ra = MD_POST_EXTRACT_ROOT_ADDR (ra);
+#endif
_Unwind_FrameState fs;
_Unwind_SpTmp sp_slot;
_Unwind_Reason_Code code;
@@ -1586,6 +1602,9 @@ uw_init_context_1 (struct _Unwind_Context *context,
initialization context, then we can't see it in the given
call frame data. So have the initialization context tell us. */
context->ra = __builtin_extract_return_addr (outer_ra);
+#ifdef MD_POST_EXTRACT_ROOT_ADDR
+ context->ra = MD_POST_EXTRACT_ROOT_ADDR (context->ra);
+#endif
}
static void _Unwind_DebugHook (void *, void *)
@@ -1608,6 +1627,20 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
#endif
}
+/* Frob exception handler's address kept in TARGET before installing into
+ CURRENT context. */
+
+static void *
+uw_frob_return_addr (struct _Unwind_Context *current,
+ struct _Unwind_Context *target)
+{
+ void *ret_addr = __builtin_frob_return_addr (target->ra);
+#ifdef MD_POST_FROB_EH_HANDLER_ADDR
+ ret_addr = MD_POST_FROB_EH_HANDLER_ADDR (current, target, ret_addr);
+#endif
+ return ret_addr;
+}
+
/* Install TARGET into CURRENT so that we can return to it. This is a
macro because __builtin_eh_return must be invoked in the context of
our caller. */
@@ -1616,7 +1649,7 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
do \
{ \
long offset = uw_install_context_1 ((CURRENT), (TARGET)); \
- void *handler = __builtin_frob_return_addr ((TARGET)->ra); \
+ void *handler = uw_frob_return_addr ((CURRENT), (TARGET)); \
_Unwind_DebugHook ((TARGET)->cfa, handler); \
__builtin_eh_return (offset, handler); \
} \
diff --git a/libgcc/config.host b/libgcc/config.host
index 6f2e458e74e776a6b7a310919558bcca76389232..540bfa9635802adabb36a2d1b7cf3416462c59f3 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -331,11 +331,13 @@ aarch64*-*-elf | aarch64*-*-rtems*)
extra_parts="$extra_parts crtfastmath.o"
tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
+ md_unwind_header=aarch64/aarch64-unwind.h
;;
aarch64*-*-freebsd*)
extra_parts="$extra_parts crtfastmath.o"
tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
+ md_unwind_header=aarch64/aarch64-unwind.h
;;
aarch64*-*-linux*)
extra_parts="$extra_parts crtfastmath.o"
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
new file mode 100644
index 0000000000000000000000000000000000000000..a57cae0ff54ea7e11c32362677c0b51501a9f727
--- /dev/null
+++ b/libgcc/config/aarch64/aarch64-unwind.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+ Contributed by ARM Ltd.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef AARCH64_UNWIND_H
+#define AARCH64_UNWIND_H
+
+#define DWARF_REGNUM_AARCH64_RA_STATE 34
+
+#define MD_POST_EXTRACT_ROOT_ADDR(addr) __builtin_aarch64_xpaclri (addr)
+#define MD_POST_EXTRACT_FRAME_ADDR(context, fs, addr) \
+ aarch64_post_extract_frame_addr (context, fs, addr)
+#define MD_POST_FROB_EH_HANDLER_ADDR(current, target, addr) \
+ aarch64_post_frob_eh_handler_addr (current, target, addr)
+#define MD_FROB_UPDATE_CONTEXT(context, fs) \
+ aarch64_frob_update_context (context, fs)
+
+/* Do AArch64 private extraction on ADDR based on context info CONTEXT and
+ unwind frame info FS. If ADDR is signed, we do address authentication on it
+ using CFA of current frame. */
+
+static void *
+aarch64_post_extract_frame_addr (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs, void *addr)
+{
+ if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
+ {
+ _Unwind_Word salt = (_Unwind_Word) context->cfa;
+ return __builtin_aarch64_autia1716 (addr, salt);
+ }
+ else
+ return addr;
+}
+
+/* Do AArch64 private frob on exception handler's address HANDLER_ADDR before
+ installing it into current context CURRENT. TARGET is currently not used.
+ We need to sign exception handler's address if CURRENT itself is signed. */
+
+static void *
+aarch64_post_frob_eh_handler_addr (struct _Unwind_Context *current,
+ struct _Unwind_Context *target
+ ATTRIBUTE_UNUSED,
+ void *handler_addr)
+{
+ if (current->flags & RA_A_SIGNED_BIT)
+ return __builtin_aarch64_pacia1716 (handler_addr,
+ (_Unwind_Word) current->cfa);
+ else
+ return handler_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 void
+aarch64_frob_update_context (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
+ /* The flag is used for re-authenticating EH handler's address. */
+ context->flags |= RA_A_SIGNED_BIT;
+
+ return;
+}
+
+#endif /* defined AARCH64_UNWIND_H */
diff --git a/libgcc/config/aarch64/linux-unwind.h b/libgcc/config/aarch64/linux-unwind.h
index 1256f010007ac964de8bb895379a7d893a446bd9..75774b30c080ad2361fb37c7208bcf3d3b57d77a 100644
--- a/libgcc/config/aarch64/linux-unwind.h
+++ b/libgcc/config/aarch64/linux-unwind.h
@@ -24,6 +24,7 @@
#include <signal.h>
#include <sys/ucontext.h>
+#include "aarch64-unwind.h"
/* Since insns are always stored LE, on a BE system the opcodes will