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. --- libgcc/config.host (revision 244672) +++ libgcc/config.host (revision 244674) @@ -284,6 +284,7 @@ extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o" tmake_file="${tmake_file} ${cpu_type}/t-aarch64" tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp" + md_unwind_header=aarch64/aarch64-unwind.h ;; aarch64*-*-linux*) md_unwind_header=aarch64/linux-unwind.h --- libgcc/config/aarch64/aarch64-unwind.h (nonexistent) +++ libgcc/config/aarch64/aarch64-unwind.h (revision 244674) @@ -0,0 +1,89 @@ +/* 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 +. */ + +#ifndef AARCH64_UNWIND_H +#define AARCH64_UNWIND_H + +#define DWARF_REGNUM_AARCH64_RA_STATE 34 + +#define MD_POST_EXTRACT_ROOT_ADDR(addr) \ + ({ void *__addr; asm ("mov x30, %0; hint 7; mov %0, x30" \ + : "=r" (__addr) : "0" (addr) : "x30", "cc"); __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 inline 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; + asm ("mov x17, %0; mov x16, %1; hint 12; mov %0, x17" + : "+r" (addr) : "r" (salt) : "x16", "x17", "cc"); + } + 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 inline 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) + asm ("mov x17, %0; mov x16, %1; hint 8; mov %0, x17" + : "+r" (handler_addr) : "r" ((_Unwind_Word) current->cfa) + : "x16", "x17", "cc"); + 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 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) + /* The flag is used for re-authenticating EH handler's address. */ + context->flags |= RA_A_SIGNED_BIT; + + return; +} + +#endif /* defined AARCH64_UNWIND_H */ --- libgcc/config/aarch64/linux-unwind.h (revision 244672) +++ libgcc/config/aarch64/linux-unwind.h (revision 244674) @@ -24,6 +24,7 @@ #include #include +#include "config/aarch64/aarch64-unwind.h" #define MD_FALLBACK_FRAME_STATE_FOR aarch64_fallback_frame_state --- libgcc/unwind-dw2.c (revision 244672) +++ libgcc/unwind-dw2.c (revision 244674) @@ -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. */ @@ -1189,6 +1191,11 @@ execute_cfa_program (const unsigned char 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 (DWARF_FRAME_REGISTERS >= 32) for (reg = 16; reg < 32; ++reg) @@ -1192,6 +1199,7 @@ execute_cfa_program (const unsigned char 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_Contex 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_Contex 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_Contex 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,10 @@ _Unwind_DebugHook (void *cfa __attribute #endif } +#ifndef MD_POST_FROB_EH_HANDLER_ADDR +#define MD_POST_FROB_EH_HANDLER_ADDR(c, t, r) r +#endif + /* 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. */ @@ -1621,6 +1644,8 @@ _Unwind_DebugHook (void *cfa __attribute { \ long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ + handler = (MD_POST_FROB_EH_HANDLER_ADDR ((CURRENT), (TARGET), \ + handler)); \ _Unwind_DebugHook ((TARGET)->cfa, handler); \ __builtin_eh_return (offset, handler); \ } \