This patch reuses the existing SEH, stack unwinding and C++ exceptions from ix86 and implements the required unwinding for AArch64.
Co-authored-by: Zac Walker <[email protected]> Signed-off-by: Evgeny Karpov <[email protected]> gcc/ChangeLog: * common/config/aarch64/aarch64-common.cc (aarch64_except_unwind_info): Add unwinding for AArch64. * config/aarch64/aarch64-abi-ms-protos.h (aarch64_pe_seh_unwind_emit): Likewise. * config/aarch64/aarch64-abi-ms.cc (aarch64_seh_cfa_adjust_cfa): Likewise. (aarch64_seh_emit_save): Likewise. (aarch64_seh_emit_save_pair): Likewise. (aarch64_seh_pattern_emit): Likewise. (aarch64_pe_seh_unwind_emit): Likewise. * config/aarch64/aarch64-abi-ms.h (CALLEE_SAVED_REG_NUMBER): Define callee saved registers. * config/aarch64/aarch64.cc (TARGET_SEH): Add unwinding for AArch64. (aarch64_get_separate_components): Likewise. (aarch64_frame_pointer_required): Likewise. (aarch64_override_options_internal): Likewise. (aarch64_declare_function_name): Likewise. * config/aarch64/cygming.h (SYMBOL_REF_STUBVAR_P): Likewise. (TARGET_SEH): Likewise. (SEH_MAX_FRAME_SIZE): Likewise. (TARGET_ASM_UNWIND_EMIT): Likewise. (TARGET_ASM_UNWIND_EMIT_BEFORE_INSN): Likewise. (TARGET_ASM_FUNCTION_END_PROLOGUE): Likewise. (TARGET_ASM_EMIT_EXCEPT_PERSONALITY): Likewise. (TARGET_ASM_INIT_SECTIONS): Likewise. (TARGET_EXCEPT_UNWIND_INFO): Likewise. (SUBTARGET_ASM_UNWIND_INIT): Likewise. (ASM_DECLARE_FUNCTION_SIZE): Likewise. (ASM_DECLARE_COLD_FUNCTION_SIZE): Likewise. (ASM_DECLARE_COLD_FUNCTION_NAME): Likewise. libgcc/ChangeLog: * unwind-seh.c (defined): Update SEH handler for AArch64. (_Unwind_Backtrace): Add unwinding for AArch64. libstdc++-v3/ChangeLog: * libsupc++/eh_personality.cc (defined): Add unwinding for AArch64. --- gcc/common/config/aarch64/aarch64-common.cc | 23 ++ gcc/config/aarch64/aarch64-abi-ms-protos.h | 2 + gcc/config/aarch64/aarch64-abi-ms.cc | 310 ++++++++++++++++++++ gcc/config/aarch64/aarch64-abi-ms.h | 4 + gcc/config/aarch64/aarch64.cc | 17 +- gcc/config/aarch64/cygming.h | 40 ++- libgcc/unwind-seh.c | 41 ++- libstdc++-v3/libsupc++/eh_personality.cc | 15 + 8 files changed, 438 insertions(+), 14 deletions(-) diff --git a/gcc/common/config/aarch64/aarch64-common.cc b/gcc/common/config/aarch64/aarch64-common.cc index fc7e84ae966..e11f70ea8f9 100644 --- a/gcc/common/config/aarch64/aarch64-common.cc +++ b/gcc/common/config/aarch64/aarch64-common.cc @@ -842,6 +842,29 @@ is_host_cpu_not_armv8_base (int argc, const char **argv) return ""; } +#if TARGET_AARCH64_MS_ABI +/* Implement TARGET_EXCEPT_UNWIND_INFO. */ + +static enum unwind_info_type +aarch64_except_unwind_info (struct gcc_options *opts) +{ + /* Honor the --enable-sjlj-exceptions configure switch. */ +#ifdef CONFIG_SJLJ_EXCEPTIONS + if (CONFIG_SJLJ_EXCEPTIONS) + return UI_SJLJ; +#endif + + /* Prefer SEH exceptions over anything else. */ + if (opts->x_flag_unwind_tables) + return UI_SEH; + + if (DWARF2_UNWIND_INFO) + return UI_DWARF2; + + return UI_SJLJ; +} +#endif + struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; #undef AARCH64_CPU_NAME_LENGTH diff --git a/gcc/config/aarch64/aarch64-abi-ms-protos.h b/gcc/config/aarch64/aarch64-abi-ms-protos.h index f08ea29d0c2..29e82ae392e 100644 --- a/gcc/config/aarch64/aarch64-abi-ms-protos.h +++ b/gcc/config/aarch64/aarch64-abi-ms-protos.h @@ -28,6 +28,8 @@ extern tree aarch64_ms_variadic_abi_fn_abi_va_list (tree fndecl); extern tree aarch64_ms_variadic_abi_canonical_va_list_type (tree type); +extern void aarch64_pe_seh_unwind_emit (FILE *, rtx_insn *); + extern int aarch64_arg_partial_bytes (cumulative_args_t, const function_arg_info &); diff --git a/gcc/config/aarch64/aarch64-abi-ms.cc b/gcc/config/aarch64/aarch64-abi-ms.cc index 1eaab4246d3..d4db95868cb 100644 --- a/gcc/config/aarch64/aarch64-abi-ms.cc +++ b/gcc/config/aarch64/aarch64-abi-ms.cc @@ -32,6 +32,7 @@ #include "regs.h" #include "function-abi.h" #include "builtins.h" +#include "diagnostic-core.h" #include "aarch64-abi-ms-protos.h" /* Iterate through the target-specific builtin types for va_list. @@ -104,3 +105,312 @@ aarch64_arg_partial_bytes (cumulative_args_t pcum_v, return 0; } + +/* Emit SEH directive to adjust the stack pointer by offset. */ + +static void +aarch64_seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat) +{ + rtx src = SET_SRC (pat); + if (GET_CODE (src) != PLUS) + gcc_unreachable (); + + const HOST_WIDE_INT reg_offset = INTVAL (XEXP (src, 1)); + src = XEXP (src, 0); + + gcc_assert (src == stack_pointer_rtx); + gcc_assert (seh->cfa_reg == stack_pointer_rtx); + + rtx dest = SET_DEST (pat); + if (REGNO (dest) != STACK_POINTER_REGNUM) + gcc_unreachable (); + + mingw_pe_seh_emit_stackalloc (f, seh, reg_offset); +} + +/* Emit SEH directive to save a REG. */ + +static void +aarch64_seh_emit_save (FILE *f, rtx reg, HOST_WIDE_INT cfa_offset) +{ + const unsigned int regno = REGNO (reg); + fputs ((FP_REGNUM_P (regno) ? " \t.seh_save_freg\t" + : GP_REGNUM_P (regno) ? " \t.seh_save_reg\t" + : (gcc_unreachable (), "")), f); + if (REGNO (reg) >= V0_REGNUM) + fprintf (f, "d%d", REGNO (reg) - V0_REGNUM); + else + fprintf (f, "x%d", REGNO (reg)); + fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC " \n", abs (cfa_offset)); + return; +} + +/* Emit SEH directive to save REG or REG pair. */ + +static void +aarch64_seh_emit_save_pair (FILE *f, HOST_WIDE_INT regno[2], + HOST_WIDE_INT offset) +{ + const char *unwind_code_prefix = ".seh_save_"; + const char *unwind_code_infix = ""; + bool negative_offset = offset < 0; + const char *unwind_code_suffix = negative_offset ? "_x": ""; + offset = abs (offset); + + if (regno[0] == FP_REGNUM && regno[1] == LR_REGNUM) + { + unwind_code_infix = "fplr"; + fprintf (f, "\t%s%s%s\t%ld\n", + unwind_code_prefix, + unwind_code_infix, + unwind_code_suffix, + offset); + return; + } + + const unsigned save_r19r20_x_max_offset = 248; + if (regno[0] == R19_REGNUM && regno[1] == R20_REGNUM && negative_offset + && offset <= save_r19r20_x_max_offset) + { + unwind_code_infix = "r19r20"; + fprintf (f, "\t%s%s%s\t%ld\n", + unwind_code_prefix, + unwind_code_infix, + unwind_code_suffix, + offset); + return; + } + + bool callee_save_reg1 = CALLEE_SAVED_REG_NUMBER (regno[0]); + bool callee_save_reg2 = CALLEE_SAVED_REG_NUMBER (regno[1]); + + if (!callee_save_reg1 && !callee_save_reg2) + return; + + bool emit_single_register = false; + unsigned reg_count = 1; + if (callee_save_reg1 && callee_save_reg2) + { + emit_single_register = (regno[1] - regno[0]) != 1; + reg_count += emit_single_register ? 1: 0; + } + else + { + emit_single_register = true; + if (!callee_save_reg1) + regno[0] = regno[1]; + } + + unwind_code_infix = emit_single_register ? "reg": "regp"; + char reg_prefix = 'x'; + unsigned regno_offset = 0; + HOST_WIDE_INT offset_increment = 8; + + if (FP_REGNUM_P (regno[0])) + { + unwind_code_prefix = ".seh_save_f"; + reg_prefix = 'd'; + regno_offset = V0_REGNUM; + } + + for (unsigned i = 0; i < reg_count; ++i) + fprintf (f, "\t%s%s%s\t%c%ld, %ld\n", + unwind_code_prefix, + unwind_code_infix, + unwind_code_suffix, + reg_prefix, + regno[i] - regno_offset, + offset + i * offset_increment); +} + +/* Emmit SEH directive if the pattern is recognized. */ + +static void +aarch64_seh_pattern_emit (FILE *f, struct seh_frame_state *seh, const rtx pat) +{ + rtx dest, src; + + if (GET_CODE (pat) == PARALLEL) + { + HOST_WIDE_INT regno[2]; + HOST_WIDE_INT offsets[2]; + unsigned reg_count = 0; + + for (unsigned i = 0, n = XVECLEN (pat, 0); i < n; ++i) + { + rtx ele = XVECEXP (pat, 0, i); + + if (GET_CODE (ele) != SET) + continue; + + src = SET_SRC (ele); + dest = SET_DEST (ele); + if (GET_CODE (src) != REG || GET_CODE (dest) != MEM) + continue; + + dest = XEXP (dest, 0); + if (dest == stack_pointer_rtx) + offsets[reg_count] = 0; + else if (GET_CODE (dest) == PLUS + && XEXP (dest, 0) == stack_pointer_rtx) + { + if (GET_CODE (XEXP (dest, 1)) != CONST_INT) + { + sorry ("unexpected offset type"); + return; + } + offsets[reg_count] = INTVAL (XEXP (dest, 1)); + } + else + continue; + + + if (reg_count == 2) + gcc_unreachable (); + regno[reg_count] = REGNO (src); + + if (CALLEE_SAVED_REG_NUMBER (regno[reg_count])) + ++reg_count; + } + + if (reg_count == 1) + gcc_unreachable (); + + if (reg_count == 2) + { + if (offsets[0] > offsets[1]) + { + std::swap (offsets[0], offsets[1]); + std::swap (regno[0], regno[1]); + } + if (offsets[1]- offsets[0] != UNITS_PER_WORD) + gcc_unreachable (); + + aarch64_seh_emit_save_pair (f, regno, offsets[0]); + } + + return; + } + + if (GET_CODE (pat) != SET) + return; + + src = SET_SRC (pat); + dest = SET_DEST (pat); + switch (GET_CODE (dest)) + { + case REG: + switch (GET_CODE (src)) + { + case REG: + if (dest == hard_frame_pointer_rtx && src == stack_pointer_rtx) + fprintf (f, "\t.seh_set_fp\n"); + break; + + case PLUS: + if (dest == stack_pointer_rtx) + { + if (GET_CODE (XEXP (src, 1)) != CONST_INT) + { + sorry ("unexpected offset type"); + return; + } + const HOST_WIDE_INT offset = abs (INTVAL (XEXP (src, 1))); + mingw_pe_seh_emit_stackalloc (f, seh, -offset); + } + break; + + case MEM: + src = XEXP (src, 0); + if (GET_CODE (src) == PLUS + && XEXP (src, 0) == stack_pointer_rtx + && CALLEE_SAVED_REG_NUMBER (REGNO (dest))) + { + if (GET_CODE (XEXP (src, 1)) != CONST_INT) + { + sorry ("unexpected offset type"); + return; + } + aarch64_seh_emit_save (f, dest, INTVAL (XEXP (src, 1))); + } + break; + + default: + break; + } + break; + + case MEM: + dest = XEXP (dest, 0); + + if (GET_CODE (dest) == PLUS && XEXP (dest, 0) == stack_pointer_rtx + && GET_CODE (src) == REG && CALLEE_SAVED_REG_NUMBER (REGNO (src))) + { + if (GET_CODE (XEXP (dest, 1)) != CONST_INT) + { + sorry ("unexpected offset type"); + return; + } + + aarch64_seh_emit_save (f, src, INTVAL (XEXP (dest, 1))); + } + else if (GET_CODE (dest) == PLUS + && XEXP (dest, 0) == hard_frame_pointer_rtx + && GET_CODE (src) == UNSPEC + && XINT (src, 1) == UNSPEC_STP) + { + if (GET_CODE (XEXP (dest, 1)) != CONST_INT) + { + sorry ("unexpected offset type"); + return; + } + + HOST_WIDE_INT offset = INTVAL (XEXP (dest, 1)); + rtvec vec = XVEC (src, 0); + HOST_WIDE_INT regno[2] = { REGNO (RTVEC_ELT (vec, 0)), + REGNO (RTVEC_ELT (vec, 1))}; + aarch64_seh_emit_save_pair (f, regno, offset); + } + break; + + default: + break; + } +} + +/* This function looks at a single insn and emits any SEH directives + required to unwind of this insn. */ + +void +aarch64_pe_seh_unwind_emit (FILE *out_file, rtx_insn *insn) +{ + if (!TARGET_SEH || NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn)) + return; + + struct seh_frame_state *seh = cfun->machine->seh; + if (!seh || seh->after_prologue) + return; + + rtx pat = PATTERN (insn); + for (rtx note = REG_NOTES (insn); note ; note = XEXP (note, 1)) + { + switch (REG_NOTE_KIND (note)) + { + case REG_FRAME_RELATED_EXPR: + pat = XEXP (note, 0); + break; + + case REG_CFA_ADJUST_CFA: + if (XEXP (note, 0)) + pat = XEXP (note, 0); + if (GET_CODE (pat) == PARALLEL) + pat = XVECEXP (pat, 0, 0); + aarch64_seh_cfa_adjust_cfa (out_file, seh, pat); + return; + default: + break; + } + } + + aarch64_seh_pattern_emit (out_file, seh, pat); +} diff --git a/gcc/config/aarch64/aarch64-abi-ms.h b/gcc/config/aarch64/aarch64-abi-ms.h index 1e1fb3fa400..f25e476b3a8 100644 --- a/gcc/config/aarch64/aarch64-abi-ms.h +++ b/gcc/config/aarch64/aarch64-abi-ms.h @@ -31,6 +31,10 @@ along with GCC; see the file COPYING3. If not see #undef STATIC_CHAIN_REGNUM #define STATIC_CHAIN_REGNUM R17_REGNUM +#define CALLEE_SAVED_REG_NUMBER(r) \ + (((r) >= R19_REGNUM && (r) <= R30_REGNUM) \ + || ((r) >= V8_REGNUM && (r) <= V15_REGNUM)) + #define ASM_COMMENT_START "//" /* ASM_OUTPUT_TYPE_DIRECTIVE is not yet supported by binutils for the diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 9dd19d81d7b..892a0ea9f5c 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -123,6 +123,11 @@ #define TARGET_AARCH64_MS_ABI 0 #endif +/* Not on SEH unless explicitly set. */ +#ifndef TARGET_SEH +#define TARGET_SEH 0 +#endif + /* Flags that describe how a function shares certain architectural state with its callers. @@ -9799,6 +9804,9 @@ offset_12bit_unsigned_scaled_p (machine_mode mode, poly_int64 offset) static sbitmap aarch64_get_separate_components (void) { + if (TARGET_SEH) + return NULL; + aarch64_frame &frame = cfun->machine->frame; sbitmap components = sbitmap_alloc (LAST_SAVED_REGNUM + 1); bitmap_clear (components); @@ -13920,7 +13928,7 @@ aarch64_frame_pointer_required () { /* If the function needs to record the incoming value of PSTATE.SM, make sure that the slot is accessible from the frame pointer. */ - return aarch64_need_old_pstate_sm (); + return TARGET_SEH || aarch64_need_old_pstate_sm (); } static bool @@ -19995,6 +20003,10 @@ aarch64_override_options_internal (struct gcc_options *opts, aarch64_autovec_preference, opts->x_autovec_preference); + /* Enable unwind tables for MS ABI. */ + if (TARGET_AARCH64_MS_ABI) + SET_OPTION_IF_UNSET (opts, &global_options_set, flag_unwind_tables, 1); + aarch64_override_options_after_change_1 (opts); } @@ -26634,6 +26646,9 @@ aarch64_declare_function_name (FILE *stream, const char* name, /* Don't forget the type directive for ELF. */ ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function"); +#ifdef SUBTARGET_ASM_UNWIND_INIT + SUBTARGET_ASM_UNWIND_INIT (stream); +#endif ASM_OUTPUT_FUNCTION_LABEL (stream, name, fndecl); cfun->machine->label_is_assembled = true; diff --git a/gcc/config/aarch64/cygming.h b/gcc/config/aarch64/cygming.h index bb3c750df69..4ade1fd2085 100644 --- a/gcc/config/aarch64/cygming.h +++ b/gcc/config/aarch64/cygming.h @@ -45,14 +45,29 @@ along with GCC; see the file COPYING3. If not see #define SYMBOL_REF_STUBVAR_P(X) \ ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_STUBVAR) != 0) -/* Disable SEH and declare the required SEH-related macros that are -still needed for compilation. */ #undef TARGET_SEH -#define TARGET_SEH 0 +#define TARGET_SEH 1 #define SSE_REGNO_P(N) (gcc_unreachable (), 0) #define GENERAL_REGNO_P(N) (gcc_unreachable (), 0) -#define SEH_MAX_FRAME_SIZE (gcc_unreachable (), 0) + +/* Support hooks for SEH. */ +#undef TARGET_ASM_UNWIND_EMIT +#define TARGET_ASM_UNWIND_EMIT aarch64_pe_seh_unwind_emit +#undef TARGET_ASM_UNWIND_EMIT_BEFORE_INSN +#define TARGET_ASM_UNWIND_EMIT_BEFORE_INSN false +#undef TARGET_ASM_FUNCTION_END_PROLOGUE +#define TARGET_ASM_FUNCTION_END_PROLOGUE mingw_pe_seh_end_prologue +#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY +#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY mingw_pe_seh_emit_except_personality +#undef TARGET_ASM_INIT_SECTIONS +#define TARGET_ASM_INIT_SECTIONS mingw_pe_seh_init_sections +#undef TARGET_EXCEPT_UNWIND_INFO +#define TARGET_EXCEPT_UNWIND_INFO aarch64_except_unwind_info +#undef SUBTARGET_ASM_UNWIND_INIT +#define SUBTARGET_ASM_UNWIND_INIT mingw_pe_seh_init + +#define SEH_MAX_FRAME_SIZE (1 << 28) #undef TARGET_PECOFF #define TARGET_PECOFF 1 @@ -118,6 +133,7 @@ still needed for compilation. */ builtin_define ("__MSVCRT__"); \ builtin_define ("__MINGW32__"); \ builtin_define ("_WIN32"); \ + builtin_define ("__SEH__"); \ builtin_define_std ("WIN32"); \ builtin_define_std ("WINNT"); \ builtin_define_with_int_value ("_INTEGRAL_MAX_BITS", \ @@ -203,6 +219,14 @@ still needed for compilation. */ flag_stack_check = STATIC_BUILTIN_STACK_CHECK; \ } while (0) +#undef ASM_DECLARE_FUNCTION_SIZE +#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \ + mingw_pe_end_function (FILE, NAME, DECL) + +#undef ASM_DECLARE_COLD_FUNCTION_SIZE +#define ASM_DECLARE_COLD_FUNCTION_SIZE(FILE,NAME,DECL) \ + mingw_pe_end_cold_function (FILE, NAME, DECL) + #define SUBTARGET_ATTRIBUTE_TABLE \ { "selectany", 0, 0, true, false, false, false, \ mingw_handle_selectany_attribute, NULL }, \ @@ -231,6 +255,14 @@ still needed for compilation. */ aarch64_declare_function_name (STREAM, NAME, DECL); \ } while (0) +#define ASM_DECLARE_COLD_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + mingw_pe_declare_type (FILE, NAME, 0, 1); \ + mingw_pe_seh_init (FILE); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + while (0) /* Define this to be nonzero if static stack checking is supported. */ #define STACK_CHECK_STATIC_BUILTIN 1 diff --git a/libgcc/unwind-seh.c b/libgcc/unwind-seh.c index 3bd0c8a4e03..36da236a9ea 100644 --- a/libgcc/unwind-seh.c +++ b/libgcc/unwind-seh.c @@ -30,9 +30,9 @@ #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) -/* At the moment everything is written for x64, but in theory this could - also be used for i386, arm, mips and other extant embedded Windows. */ -#ifndef __x86_64__ +/* At the moment everything is written for x64 and aarch64, but in theory this + could also be used for i386, arm, mips and other extant embedded Windows. */ +#if !defined (__x86_64__) && !defined (__aarch64__) #error "Unsupported architecture." #endif @@ -209,7 +209,12 @@ _GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame, "installed" the target_ip and RAX value via the arguments to RtlUnwindEx. All that's left is to set the RDX value and "continue" to have the context installed. */ +#ifdef __x86_64__ ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; +#elif defined (__aarch64__) + ms_disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; +#endif + return ExceptionContinueSearch; } @@ -229,7 +234,11 @@ _GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame, return ExceptionContinueSearch; } +#ifdef __x86_64__ gcc_context.cfa = ms_disp->ContextRecord->Rsp; +#elif defined (__aarch64__) + gcc_context.cfa = ms_disp->ContextRecord->Sp; +#endif gcc_context.ra = ms_disp->ControlPc; gcc_context.reg[0] = 0xdeadbeef; /* These are write-only. */ gcc_context.reg[1] = 0xdeadbeef; @@ -438,6 +447,8 @@ _Unwind_Backtrace(_Unwind_Trace_Fn trace, CONTEXT ms_context; struct _Unwind_Context gcc_context; DISPATCHER_CONTEXT disp_context; + ULONG64 ip; + ULONG64 sp; memset (&ms_history, 0, sizeof(ms_history)); memset (&gcc_context, 0, sizeof(gcc_context)); @@ -452,31 +463,43 @@ _Unwind_Backtrace(_Unwind_Trace_Fn trace, while (1) { - gcc_context.disp->ControlPc = ms_context.Rip; +#ifdef __x86_64__ + ip = ms_context.Rip; +#elif defined (__aarch64__) + ip = ms_context.Pc; +#endif + gcc_context.disp->ControlPc = ip; gcc_context.disp->FunctionEntry - = RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp->ImageBase, + = RtlLookupFunctionEntry (ip, &gcc_context.disp->ImageBase, &ms_history); if (!gcc_context.disp->FunctionEntry) return _URC_END_OF_STACK; gcc_context.disp->LanguageHandler - = RtlVirtualUnwind (0, gcc_context.disp->ImageBase, ms_context.Rip, + = RtlVirtualUnwind (0, gcc_context.disp->ImageBase, ip, gcc_context.disp->FunctionEntry, &ms_context, &gcc_context.disp->HandlerData, &gcc_context.disp->EstablisherFrame, NULL); /* Set values that the callback can inspect via _Unwind_GetIP * and _Unwind_GetCFA. */ - gcc_context.ra = ms_context.Rip; - gcc_context.cfa = ms_context.Rsp; +#ifdef __x86_64__ + ip = ms_context.Rip; + sp = ms_context.Rsp; +#elif defined (__aarch64__) + ip = ms_context.Pc; + sp = ms_context.Sp; +#endif + gcc_context.ra = ip; + gcc_context.cfa = sp; /* Call trace function. */ if (trace (&gcc_context, trace_argument) != _URC_NO_REASON) return _URC_FATAL_PHASE1_ERROR; /* ??? Check for invalid stack pointer. */ - if (ms_context.Rip == 0) + if (ip == 0) return _URC_END_OF_STACK; } } diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc index 10458318f88..acf93edf648 100644 --- a/libstdc++-v3/libsupc++/eh_personality.cc +++ b/libstdc++-v3/libsupc++/eh_personality.cc @@ -23,6 +23,7 @@ // <http://www.gnu.org/licenses/>. #include <bits/c++config.h> +#include <cstdint> #include <cstdlib> #include <bits/exception_defines.h> #include <cxxabi.h> @@ -54,6 +55,20 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p, info->Start = (context ? _Unwind_GetRegionStart (context) : 0); +#if defined (__SEH__) && defined (__aarch64__) + /* Large functions on AArch64 (>= 1MB) are split into multiple fragments. + However, it is expected the most of the functions will have only one + fragment. The beginning of each SEH handler data in .xdata record starts + with a fragment offset and an address to .seh_handlerdata. + .seh_handlerdata is emitted only once for the .xdata record of the last + fragment. */ + uint32_t fragment_offset = *(uint32_t *) p; + p += sizeof (uint32_t); + info->Start -= fragment_offset; + uint32_t handler_data_rva = *(uint32_t *) p; + p = (unsigned char *) _Unwind_GetTextRelBase (context) + handler_data_rva; +#endif + // Find @LPStart, the base to which landing pad offsets are relative. lpstart_encoding = *p++; if (lpstart_encoding != DW_EH_PE_omit)
