From 5636faf2bcd1a82bb2a2b22a4146602c45c5508a Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Fri, 20 Jan 2017 00:19:01 +0000 Subject: [PATCH] [AArch64][4/4] libgcc unwinder support for return address signing libgcc/ * config/aarch64/aarch64-unwind.h: New file. (DWARF_REGNUM_AARCH64_RA_STATE): Define. (MD_POST_EXTRACT_ROOT_ADDR): New target marcro and define it on AArch64. (MD_POST_EXTRACT_FRAME_ADDR): Likewise. (MD_POST_FROB_EH_HANDLER_ADDR): Likewise. (MD_FROB_UPDATE_CONTEXT): Define it on AArch64. (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. (uw_install_context): Use uw_frob_return_addr. From-SVN: r244673 --- libgcc/ChangeLog | 23 +++++++++++++++ libgcc/config.host | 2 ++ libgcc/config/aarch64/linux-unwind.h | 1 + libgcc/unwind-dw2.c | 44 ++++++++++++++++++++++++---- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 256dc24a251..926312eca65 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,26 @@ +2017-01-19 Jiong Wang + + * config/aarch64/aarch64-unwind.h: New file. + (DWARF_REGNUM_AARCH64_RA_STATE): Define. + (MD_POST_EXTRACT_ROOT_ADDR): New target marcro and define it on AArch64. + (MD_POST_EXTRACT_FRAME_ADDR): Likewise. + (MD_POST_FROB_EH_HANDLER_ADDR): Likewise. + (MD_FROB_UPDATE_CONTEXT): Define it on AArch64. + (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. + (uw_install_context): Use uw_frob_return_addr. + 2017-01-17 Jakub Jelinek PR other/79046 diff --git a/libgcc/config.host b/libgcc/config.host index 6f2e458e74e..540bfa96358 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/linux-unwind.h b/libgcc/config/aarch64/linux-unwind.h index 1256f010007..a8fa1d50452 100644 --- a/libgcc/config/aarch64/linux-unwind.h +++ b/libgcc/config/aarch64/linux-unwind.h @@ -24,6 +24,7 @@ #include #include +#include "config/aarch64/aarch64-unwind.h" /* Since insns are always stored LE, on a BE system the opcodes will diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c index 8085a42ace1..fe74387992a 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,21 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)), #endif } +/* Frob exception handler's address kept in TARGET before installing into + CURRENT context. */ + +static inline void * +uw_frob_return_addr (struct _Unwind_Context *current + __attribute__ ((__unused__)), + 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 +1650,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); \ } \