/* DWARF2 exception handling and frame unwind runtime interface routines. Copyright (C) 1997-2015 Free Software Foundation, Inc. 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 . */ #include "tconfig.h" #include "tsystem.h" #include "coretypes.h" #include "tm.h" #include "libgcc_tm.h" #include "unwind.h" #include "unwind-pe.h" #include "unwind-dw2-fde.h" #include "unwind-dw2.h" #ifdef HAVE_SYS_SDT_H #include #endif #if defined __linux__ # include /* For SYS_{access_hw_stacks,set_backtrace} which . . . */ # include #elif defined __QNX__ # include /* . . . are not provided by QNX libc headers. */ # define SYS_access_hw_stacks __NR_access_hw_stacks # define SYS_set_backtrace __NR_set_backtrace #else #error "Unsupported OS" #endif #if ! defined (__ptr128__) # define syshw(m, f, b, s, r) \ syscall (SYS_access_hw_stacks, (unsigned long) m, f, b, s, r) #else /* defined (__ptr128__) */ # if ! defined (__NEW_PM_SYSCALLS) # define syshw(m, f, b, s, r) \ syscall (SYS_access_hw_stacks, (((unsigned long) m) << 32) | s, f, b, r) #else /* defined (__NEW_PM_SYSCALLS) */ # define syshw(m, f, b, s, r) \ syscall (SYS_access_hw_stacks, (void *) m, (void *) f, \ (void *) b, (void *) s, (void *) r) #endif /* defined __NEW_PM_SYSCALLS */ #endif /* defined (__ptr128__) */ #if ! defined (__ptr128__) || ! defined (__NEW_PM_SYSCALLS) # define sys_set_backtrace(a, b, c, d) syscall (SYS_set_backtrace, a, b, c, d) #else /* defined (__ptr128__) && defined (__NEW_PM_SYSCALLS) */ # define sys_set_backtrace(a, b, c, d) syscall (SYS_set_backtrace, \ (void *) a, (void *) b, \ (void *) c, (void *) d) #endif /* defined (__ptr128__) && defined (__NEW_PM_SYSCALLS) */ #ifndef __USING_SJLJ_EXCEPTIONS__ /* Definitions of E2K-specific register types and macros. */ #define E2K_VA_SIZE 48 #define E2K_VA_MSB (E2K_VA_SIZE - 1) typedef struct e2k_rusd_lo_fields { /* Fields of lower word */ unsigned long long base : E2K_VA_SIZE; /* [47: 0] */ unsigned long long unused2 : 57 - E2K_VA_MSB; /* [57:48] */ unsigned long long p : 1; /* [58] */ unsigned long long rw : 2; /* [60:59] */ unsigned long long unused : 3; /* [63:61] */ } e2k_rusd_lo_fields_t; /* Structure of lower word */ typedef union e2k_rusd_lo_struct { e2k_rusd_lo_fields_t fields; /* as USD fields */ unsigned long long word; /* as entire register */ } e2k_rusd_lo_struct_t; typedef struct e2k_rwap_lo_fields { /* Fields of lower word */ unsigned long long base : E2K_VA_SIZE; /* [47: 0] */ unsigned long long unused2 : 55 - E2K_VA_MSB; /* [55:48] */ unsigned long long stub3 : 1; /* [56] */ unsigned long long stub2 : 1; /* [57] */ unsigned long long stub1 : 1; /* [58] */ unsigned long long rw : 2; /* [60:59] */ unsigned long long itag : 3; /* [63:61] */ } e2k_rwap_lo_fields_t; /* Structure of lower word */ typedef union e2k_rwap_lo_struct { e2k_rwap_lo_fields_t fields; /* as AP fields */ unsigned long long word; /* as entire register */ } e2k_rwap_lo_struct_t; /* Fields of high word */ typedef struct e2k_rwap_hi_fields { unsigned long long curptr : 32; /* [31: 0] */ unsigned long long size : 32; /* [63:32] */ } e2k_rwap_hi_fields_t; /* Structure of high word */ typedef union e2k_rwap_hi_struct { e2k_rwap_hi_fields_t fields; /* as AP fields */ unsigned long long word; /* as entire register */ } e2k_rwap_hi_struct_t; typedef e2k_rwap_lo_struct_t e2k_pcsp_lo_t; typedef e2k_rwap_lo_struct_t e2k_psp_lo_t; typedef e2k_rwap_hi_struct_t e2k_pcsp_hi_t; typedef e2k_rwap_hi_struct_t e2k_psp_hi_t; typedef e2k_rusd_lo_struct_t e2k_rusd_lo_t; typedef e2k_rwap_hi_struct_t e2k_rusd_hi_t; /* Structure of cr0_hi chain reg */ typedef struct e2k_cr0_hi_fields { unsigned long long unused_1 : 3; /* [ 2: 0] */ unsigned long long ip : 45; /* [47: 3] */ unsigned long long unused_2 : 16; /* [48:63] */ } e2k_cr0_hi_fields_t; typedef union e2k_cr0_hi { e2k_cr0_hi_fields_t fields; /* as fields */ unsigned long long word; /* as entire register */ } e2k_cr0_hi_t; /* Structure of cr1_lo chain reg */ typedef union e2k_cr1_lo_fields { struct { unsigned long long tr : 15; /* [14: 0] */ unsigned long long unused1 : 1; /* [15] */ unsigned long long ein : 8; /* [23:16] */ unsigned long long unused2 : 1; /* [24] */ unsigned long long wfx : 1; /* [25] */ unsigned long long wpsz : 7; /* [32:26] */ unsigned long long wbs : 7; /* [39:33] */ unsigned long long cuir : 17; /* [56:40] */ unsigned long long psr : 7; /* [63:57] */ }; struct { unsigned long long __x1 : 57; /* [56:0] */ unsigned long long pm : 1; /* [57] */ unsigned long long ie : 1; /* [58] */ unsigned long long sge : 1; /* [59] */ unsigned long long lw : 1; /* [60] last wish */ unsigned long long uie : 1; /* [61] user interrupts enable */ unsigned long long nmie : 1; /* [62] not masked interrupts enable */ unsigned long long unmie : 1; /* [63] user not masked interrupts */ /* enable */ }; } e2k_cr1_lo_fields_t; typedef union e2k_cr1_lo { e2k_cr1_lo_fields_t fields; /* as fields */ unsigned long long word; /* as entire register */ } e2k_cr1_lo_t; typedef union e2k_cr1_hi_fields { /* Structure of cr1_hi chain reg */ struct { unsigned long long br : 28; /* [27: 0] */ unsigned long long unused : 7; /* [34:28] */ unsigned long long wdbl : 1; /* [35:35] */ unsigned long long ussz : 28; /* [63:36] */ }; } e2k_cr1_hi_fields_t; typedef union e2k_cr1_hi { e2k_cr1_hi_fields_t fields; /* as fields */ unsigned long long word; /* as entire register */ } e2k_cr1_hi_t; typedef struct e2k_mem_crstack { unsigned long long cr0_lo; e2k_cr0_hi_t cr0_hi; e2k_cr1_lo_t cr1_lo; e2k_cr1_hi_t cr1_hi; } e2k_mem_crs_t; #define AW(x) (x.word) #define AS(x) (x.fields) #define E2K_PSHTP_SIZE 12 #define PSHTP_SIGN_EXTEND(pshtp) \ ((unsigned long long) (((long long) (pshtp) << (64 - E2K_PSHTP_SIZE)) \ >> (64 - E2K_PSHTP_SIZE))) #define E2K_PCSHTP_SIZE 11 #define PCSHTP_SIGN_EXTEND(pcshtp) \ ((unsigned long long) (((long long) (pcshtp) << (64 - E2K_PCSHTP_SIZE)) \ >> (64 - E2K_PCSHTP_SIZE))) #define E2K_READ_STACK_REGS(pcsp_lo, pcsp_hi, psp_lo, psp_hi, pcshtp, pshtp) \ do { \ char tmp = 0, val; \ asm volatile ("1:\n" \ "ldb,0 0, %[tmp], %[val], mas=0x7\n" \ "rrd %%pcshtp, %[__pcshtp]\n" \ "rrd %%pcsp.lo, %[__pcsp_lo]\n" \ "rrd %%pcsp.hi, %[__pcsp_hi]\n" \ "rrd %%pshtp, %[__pshtp]\n" \ "rrd %%psp.lo, %[__psp_lo]\n" \ "rrd %%psp.hi, %[__psp_hi]\n" \ "{\n" \ " stb,2 0, %[tmp], %[val], mas = 0x2\n" \ " ibranch 1b ? %%MLOCK\n" \ "}\n" \ : [val] "=&r" (val), \ [__pcsp_lo] "=&r" (pcsp_lo), \ [__pcsp_hi] "=&r" (pcsp_hi), \ [__psp_lo] "=&r" (psp_lo), \ [__psp_hi] "=&r" (psp_hi), \ [__pcshtp] "=&r" (pcshtp), \ [__pshtp] "=&r" (pshtp) \ : [tmp] "r" (&tmp)); \ } while (0) #define EXT_QREG_SZ 32 #if ! defined (__ptr128__) typedef void * typeof_ra; #else /* defined (__ptr128__) */ typedef _Unwind_Ptr typeof_ra; #endif /* defined (__ptr128__) */ /* The length of chain stack cache allowing us not to make access_hw_stacks syscall for each unwound frame. */ #define CHAIN_STACK_CACHE_LEN 32 /* This is the register and unwind state for a particular frame. This provides the information necessary to unwind up past a frame and return to its caller. */ struct _Unwind_Context { size_t psp_offset; e2k_mem_crs_t *chain_stack; size_t chain_stack_size; size_t pcsp_idx; unsigned long long us_base; typeof_ra ra; unsigned long long prev_ps_frame_size; unsigned long long prev_us_size; void *lsda; struct dwarf_eh_bases bases; size_t level; /* Which parameters have been set by _Unwind_SetGR () and . . . */ int set[2]; /* . . . their values in case they have. */ #if ! defined __ptr128__ unsigned long long param0; #else /* defined __ptr128__ */ void *param0; #endif /* defined __ptr128__ */ unsigned long long param1; }; /* Read unaligned data from the instruction buffer. */ union unaligned { void *p; unsigned u2 __attribute__ ((mode (HI))); unsigned u4 __attribute__ ((mode (SI))); unsigned u8 __attribute__ ((mode (DI))); signed s2 __attribute__ ((mode (HI))); signed s4 __attribute__ ((mode (SI))); signed s8 __attribute__ ((mode (DI))); } __attribute__ ((packed)); static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, _Unwind_FrameState *); static inline void * read_pointer (const void *p) { const union unaligned *up = p; return up->p; } static inline int read_1u (const void *p) { return *(const unsigned char *) p; } static inline int read_1s (const void *p) { return *(const signed char *) p; } static inline int read_2u (const void *p) { const union unaligned *up = p; return up->u2; } static inline int read_2s (const void *p) { const union unaligned *up = p; return up->s2; } static inline unsigned int read_4u (const void *p) { const union unaligned *up = p; return up->u4; } static inline int read_4s (const void *p) { const union unaligned *up = p; return up->s4; } static inline unsigned long read_8u (const void *p) { const union unaligned *up = p; return up->u8; } static inline unsigned long read_8s (const void *p) { const union unaligned *up = p; return up->s8; } static inline _Unwind_Word _Unwind_IsSignalFrame (struct _Unwind_Context *context __attribute__ ((unused))) { return 0; } static inline void _Unwind_SetSignalFrame (struct _Unwind_Context *context __attribute__ ((unused)), int val __attribute__ ((unused))) { } /* Get the value of register INDEX as saved in CONTEXT. */ inline _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *context __attribute__ ((unused)), int index __attribute__ ((unused))) { return 0; } static inline void * _Unwind_GetPtr (struct _Unwind_Context *context, int index) { return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index); } /* Get the value of the CFA as saved in CONTEXT. */ _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *context) { return (_Unwind_Word) (context->us_base + context->prev_us_size); } /* Get the value of the previous %pcsp as saved in CONTEXT. */ _Unwind_Word _Unwind_GetPCSP (struct _Unwind_Context *context) { return (_Unwind_Word) ((context->pcsp_idx - 1) << 5); } /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ inline void _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) { /* LCC rather naively believes that `%b[0], . . ., %b[63]' registers have their "gnu numbers" (have you ever heard of such a concept?) in the range from 64 to 127 inclusively (see `mdes_e2k_RegTable[]' in `mdes/mdes_e2k_ reg.c'; interestingly enough `%b[64], . . ., %b[127]' have `-1' specified for their "gnu numbers"). Support this point of view here. FIXME: e2k-linux-gcc is currently aware only of `%r0, . . ., %r15' and `%b[0], . . ., %b[7]' and enumerates them from 0 to 15 and from 17 to 24 inclusively. This is almost sure to make libgcc compiled by `{e2k-linux-gcc ,lcc}' and other libraries like libstdc++ making use of `_Unwind_SetGR (__builtin_eh_return_data_regno ())' compiled by `{lcc,e2k-linux-gcc}' incompatible with each other at runtime. */ #if defined __LCC__ # define FIRST_DIRECT_REG 0 # define LAST_DIRECT_REG 63 # define FIRST_BASED_REG 64 # define LAST_BASED_REG 127 #else /* ! defined __LCC__ */ # define FIRST_DIRECT_REG 0 # define LAST_DIRECT_REG 15 # define FIRST_BASED_REG 17 # define LAST_BASED_REG 24 #endif /* ! defined __LCC__ */ #if ! defined __ptr128__ if (index == FIRST_BASED_REG) { context->param0 = (unsigned long long) val; context->set[0] = 1; } else #endif /* ! defined __ptr128__ */ if ( #if ! defined __ptr128__ index == FIRST_BASED_REG + 1 #else /* defined __ptr128__ */ index == FIRST_BASED_REG + 2 #endif /* defined __ptr128__ */ ) { context->param1 = (unsigned long long) val; context->set[1] = 1; } else abort (); } /* Get the pointer to a register INDEX as saved in CONTEXT. */ static inline void * _Unwind_GetGRPtr (struct _Unwind_Context *context __attribute__ ((unused)), int index __attribute__ ((unused))) { return (void *) 0; } /* Set the pointer to a register INDEX as saved in CONTEXT. */ #if defined (__ptr128__) void _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p) { if (index == FIRST_BASED_REG) { context->param0 = p; context->set[0] = 1; } else /* Should not be used otherwise. */ abort (); } #endif /* defined (__ptr128__) */ /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ static inline void _Unwind_SetGRValue (struct _Unwind_Context *context __attribute__ ((unused)), int index __attribute__ ((unused)), _Unwind_Word val __attribute__ ((unused))) { } /* Return nonzero if register INDEX is stored by value rather than by reference. */ static inline int _Unwind_GRByValue (struct _Unwind_Context *context __attribute__ ((unused)), int index __attribute__ ((unused))) { return 0; } /* Retrieve the return address for CONTEXT. */ inline _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *context) { return (_Unwind_Ptr) context->ra; } /* Retrieve the return address and flag whether that IP is before or after first not yet fully executed instruction. */ inline _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn __attribute__ ((unused))) { *ip_before_insn = _Unwind_IsSignalFrame (context); return (_Unwind_Ptr) context->ra; } /* Overwrite the return address for CONTEXT with VAL. */ inline void _Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) { context->ra = (typeof_ra) val; } void * _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) { return context->lsda; } _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *context) { return (_Unwind_Ptr) context->bases.func; } void * _Unwind_FindEnclosingFunction ( #ifndef __ptr128__ void *pc #else _Unwind_Ptr pc #endif ) { struct dwarf_eh_bases bases; const struct dwarf_fde *fde = _Unwind_Find_FDE (pc - 1, &bases); if (fde) return bases.func; else return NULL; } _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *context) { return (_Unwind_Ptr) context->bases.dbase; } _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *context) { return (_Unwind_Ptr) context->bases.tbase; } #include "md-unwind-support.h" /* Extract any interesting information from the CIE for the translation unit F belongs to. Return a pointer to the byte after the augmentation, or NULL if we encountered an undecipherable augmentation. */ static const unsigned char * extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, _Unwind_FrameState *fs) { const unsigned char *aug = cie->augmentation; const unsigned char *p = aug + strlen ((const char *)aug) + 1; const unsigned char *ret = NULL; _uleb128_t utmp; _sleb128_t stmp; /* g++ v2 "eh" has pointer immediately following augmentation string, so it must be handled first. */ if (aug[0] == 'e' && aug[1] == 'h') { fs->eh_ptr = read_pointer (p); p += sizeof (void *); aug += 2; } /* After the augmentation resp. pointer for "eh" augmentation follows for CIE version >= 4 address size byte and segment size byte. */ if (__builtin_expect (cie->version >= 4, 0)) { if (p[0] != sizeof (void *) || p[1] != 0) return NULL; p += 2; } /* Immediately following this are the code and data alignment and return address column. */ p = read_uleb128 (p, &utmp); fs->code_align = (_Unwind_Word)utmp; p = read_sleb128 (p, &stmp); fs->data_align = (_Unwind_Sword)stmp; if (cie->version == 1) fs->retaddr_column = *p++; else { p = read_uleb128 (p, &utmp); fs->retaddr_column = (_Unwind_Word)utmp; } fs->lsda_encoding = DW_EH_PE_omit; /* If the augmentation starts with 'z', then a uleb128 immediately follows containing the length of the augmentation field following the size. */ if (*aug == 'z') { p = read_uleb128 (p, &utmp); ret = p + utmp; fs->saw_z = 1; ++aug; } /* Iterate over recognized augmentation subsequences. */ while (*aug != '\0') { /* "L" indicates a byte showing how the LSDA pointer is encoded. */ if (aug[0] == 'L') { fs->lsda_encoding = *p++; aug += 1; } /* "R" indicates a byte indicating how FDE addresses are encoded. */ else if (aug[0] == 'R') { fs->fde_encoding = *p++; aug += 1; } /* "P" indicates a personality routine in the CIE augmentation. */ else if (aug[0] == 'P') { #ifndef __ptr128__ _Unwind_Ptr personality; p = read_encoded_value (context, *p, p + 1, &personality); fs->personality = (_Unwind_Personality_Fn) personality; #else p = read_encoded_ptr (context, *p, p + 1, (void **) (void *) &fs->personality); #endif aug += 1; } /* "S" indicates a signal frame. */ else if (aug[0] == 'S') { fs->signal_frame = 1; aug += 1; } /* Otherwise we have an unknown augmentation string. Bail unless we saw a 'z' prefix. */ else return ret; } return ret ? ret : p; } /* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for its caller and decode it into FS. This function also sets the args_size and lsda members of CONTEXT, as they are really information about the caller's frame. */ static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) { const struct dwarf_fde *fde; const struct dwarf_cie *cie; const unsigned char *aug, *insn; memset (fs, 0, sizeof (*fs)); context->lsda = 0; /* At `pcsp_idx == 1' we are almost certainly left with one or two pure C frames containing no unwind data. However, find out why it turns out to be impossible to reach `pcsp_idx == 0' here. */ if (context->pcsp_idx == 1 || context->ra == 0) return _URC_END_OF_STACK; fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1, &context->bases); /* Make E2K unwinder silently skip C frames compiled without `-fexceptions' instead of stopping at the first of them which was the reason for Bug #90378. This is a significant benefit of E2K architecture which is going to save us the trouble of recompiling tons of C sources intended for use in (together with) C++ exception throwing applications. */ if (fde == NULL) return _URC_NO_REASON; cie = get_cie (fde); insn = extract_cie_info (cie, context, fs); if (insn == NULL) /* CIE contained unknown augmentation. */ return _URC_FATAL_PHASE1_ERROR; /* Locate augmentation for the fde. */ aug = (const unsigned char *) fde + sizeof (*fde); aug += 2 * size_of_encoded_value (fs->fde_encoding); insn = NULL; if (fs->saw_z) { _uleb128_t i; aug = read_uleb128 (aug, &i); insn = aug + i; } if (fs->lsda_encoding != DW_EH_PE_omit) { #if ! defined (__ptr128__) _Unwind_Ptr lsda; aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); context->lsda = (void *) lsda; #else /* defined (__ptr128__) */ aug = read_encoded_ptr (context, fs->lsda_encoding, aug, &context->lsda); #endif /* defined (__ptr128__) */ } return _URC_NO_REASON; } typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp; static void fill_in_chain_stack_fragm (struct _Unwind_Context *context) { unsigned long long frames_num = (context->pcsp_idx < CHAIN_STACK_CACHE_LEN ? context->pcsp_idx : CHAIN_STACK_CACHE_LEN); size_t size = 32 * frames_num; unsigned long long top = 32 * (context->pcsp_idx - frames_num); if (syshw (E2K_READ_CHAIN_STACK_EX, &top, &context->chain_stack[CHAIN_STACK_CACHE_LEN - frames_num], size, NULL) != 0) abort (); } /* CONTEXT describes the unwind state for a frame, and FS describes the FDE of its caller. Update CONTEXT to refer to the caller as well. Note that the args_size and lsda members are not updated here, but later in uw_frame_state_for. */ static void uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs __attribute__ ((unused))) { do { e2k_mem_crs_t crs; context->psp_offset -= context->prev_ps_frame_size; if ((context->chain_stack_size - context->pcsp_idx) % CHAIN_STACK_CACHE_LEN == 0) fill_in_chain_stack_fragm (context); crs = context->chain_stack[CHAIN_STACK_CACHE_LEN - 1 - ((context->chain_stack_size - context->pcsp_idx) % CHAIN_STACK_CACHE_LEN)]; context->pcsp_idx--; context->prev_ps_frame_size = AS (crs.cr1_lo).wbs * EXT_QREG_SZ; context->prev_us_size = AS (crs.cr1_hi).ussz << 4; context->ra = (typeof_ra) (unsigned long) (AS (crs.cr0_hi).ip << 3); } while (context->ra == 0); ++context->level; } static void uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) { uw_update_context (context, fs); } /* This macro is separately called from `_Unwind_RaiseException ()' via `reinit _chain_stack_cache ()' to make chain stack cache in THIS_CONTEXT match its state prior to starting phase 2 as it may have been changed at phase 1 on behalf of CUR_CONTEXT now that it's shared between `{THIS,CUR}_CONTEXT'. FIXME: consider unifying it with `fill_in_chain_stack_fragm ()'. */ #define init_chain_stack_cache(context) \ { \ size_t fragm_idx; \ size_t fragm_size; \ size_t obtained_size; \ unsigned long long top; \ \ if (context->pcsp_idx < CHAIN_STACK_CACHE_LEN) \ { \ fragm_idx = CHAIN_STACK_CACHE_LEN - context->pcsp_idx; \ fragm_size = context->pcsp_idx; \ } \ else \ { \ fragm_idx = 0; \ fragm_size = CHAIN_STACK_CACHE_LEN; \ } \ \ obtained_size = 32 * fragm_size; \ \ top = 32 * (context->chain_stack_size - fragm_size); \ \ if (syshw (E2K_READ_CHAIN_STACK_EX, &top, \ &context->chain_stack[fragm_idx], \ obtained_size, NULL) \ != 0) \ abort (); \ \ } \ static void __attribute__ ((noinline)) reinit_chain_stack_cache (struct _Unwind_Context *context) { init_chain_stack_cache (context); } /* Fill in CONTEXT for top-of-stack. The only valid registers at this level will be the return address and the CFA. */ static void __attribute__((noinline)) uw_init_context (struct _Unwind_Context *context, e2k_mem_crs_t *chain_stack) { int i; e2k_rusd_lo_t usd_lo; e2k_rusd_hi_t usd_hi; typeof_ra ra; _Unwind_FrameState fs; _Unwind_Reason_Code code; #if defined (__ptr128__) && defined SHARED static int syscall_lazily_resolved; #endif /* defined (__ptr128__) && defined SHARED */ ra = (typeof_ra) __builtin_extract_return_addr (__builtin_return_address (0)); memset (context, 0, sizeof (struct _Unwind_Context)); /* I can't rely on the equivalent "standard" macro provided by since it has been renamed in linux-4.x (Bug #101373). */ #define GET_STATE_REG(reg_mnemonic) \ ({ \ register unsigned long long res; \ asm volatile ("rrd \t%%" #reg_mnemonic ", %0" \ : "=r" (res)); \ res; \ }) AW (usd_lo) = GET_STATE_REG (usd.lo); AW (usd_hi) = GET_STATE_REG (usd.hi); #undef GET_STATE_REG context->us_base = AS (usd_lo).base - AS (usd_hi).size; #if defined (__ptr128__) && defined SHARED /* Ensure that `syscall ()' has already been resolved lazily by the time of `syshw (E2K_GET_PROCEDURE_STACK_SIZE)' invocation below. Otherwise, one may get inconsistent sizes for procedure and chain stacks due to an extra call frame imposed by lazy binding in PM. */ if (! syscall_lazily_resolved) { /* Use any unimplemented syscall number here to avoid any side effects. However, avoid using `__NR_restart_syscall == 0' as this results in a rather weird halt or an infinite loop (?) if the thread is cancelled while being within a (restartable?) system call. */ syscall (424); /* FIXME: shouldn't this be done in MT-safe way? The failure to do so may probably result in redundant invocations of `syscall (0)' in the worst case. */ syscall_lazily_resolved = 1; } #endif /* defined (__ptr128__) && defined SHARED */ /* Determine the sizes of hardware stacks. */ if (syshw (E2K_GET_PROCEDURE_STACK_SIZE, NULL, NULL, 0, &context->psp_offset) != 0) abort ();/***/ if (syshw (E2K_GET_CHAIN_STACK_SIZE, NULL, NULL, 0, &context->chain_stack_size) != 0) abort (); if ((context->chain_stack_size & 0x1f) != 0) abort (); context->chain_stack_size >>= 5; context->pcsp_idx = context->chain_stack_size; #if defined __ptr128__ /* FIXME: chain stack cache needs to be zero out because of a rather suspicious LSIM behaviour in PM: something irrelevant is found in it after E2K_READ_CHAIN_STACK_EX if it hasn't been preinitialized. */ memset (chain_stack, 0, CHAIN_STACK_CACHE_LEN * sizeof (e2k_mem_crs_t)); #endif /* defined __ptr128__ */ context->chain_stack = chain_stack; init_chain_stack_cache (context); for (i = CHAIN_STACK_CACHE_LEN - 1; i >= 0 && context->pcsp_idx != 0; i--) { e2k_mem_crs_t crs; crs = context->chain_stack[i]; context->ra = (typeof_ra) (unsigned long) (AS (crs.cr0_hi).ip << 3); context->prev_ps_frame_size = AS (crs.cr1_lo).wbs * EXT_QREG_SZ; context->prev_us_size = AS (crs.cr1_hi).ussz << 4; context->pcsp_idx--; if (context->ra != ra) context->psp_offset -= context->prev_ps_frame_size; else break; } if (i < 0 || context->pcsp_idx == 0) abort (); context->level = 0; code = uw_frame_state_for (context, &fs); gcc_assert (code == _URC_NO_REASON); uw_update_context (context, &fs); } static void _Unwind_DebugHook (void *, void *) __attribute__ ((__noinline__, __used__, __noclone__)); /* This function is called during unwinding. It is intended as a hook for a debugger to intercept exceptions. CFA is the CFA of the target frame. HANDLER is the PC to which control will be transferred. */ static void _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)), void *handler __attribute__ ((__unused__))) { /* We only want to use stap probes starting with v3. Earlier versions added too much startup cost. */ #if defined (HAVE_SYS_SDT_H) && defined (STAP_PROBE2) && _SDT_NOTE_TYPE >= 3 STAP_PROBE2 (libgcc, unwind, cfa, handler); #else asm (""); #endif } /* Other platforms probably manage to do without `__attribute__ ((noreturn))' because `uw_install_context()' is implemented as a _macro_ containing `__builtin_eh_return ()' at the end. Without that one would obtain compiler warnings on returning from non-void functions in `libgcc/unwind.inc' ending with `uw_install_context ()' invocation. */ static void __attribute__ ((noinline)) __attribute__ ((noreturn)) uw_install_context (struct _Unwind_Context *current __attribute__ ((unused)), struct _Unwind_Context *target) { size_t i; int res; int old_stack_layout; /* Reuse (hopefully) no longer needed `context->chain_stack' so as to avoid redundant stack waste. */ #define SET_BACKTRACE_LEN (CHAIN_STACK_CACHE_LEN * sizeof (e2k_mem_crs_t) \ / sizeof (long)) unsigned long *buf = (unsigned long *) target->chain_stack; size_t level = target->level; /* Skip return address of `syscall ()', i.e. return from it to this function (or to `syscall ()' PLT entry in PM) in a regular way. */ size_t extra_frames_to_skip = 1; /* Install register values previously set up by _Unwind_SetGR{,Ptr} ()'. */ old_stack_layout = (__builtin_cpu_is ("elbrus-v1") || __builtin_cpu_is ("elbrus-v2") || __builtin_cpu_is ("elbrus-v3") || __builtin_cpu_is ("elbrus-v4")); for (i = 0; i < 2; i++) { unsigned long long off; int index; size_t len; void *p; if (! target->set[i]) continue; p = (i == 0 ? &target->param0 : &target->param1); #if ! defined __ptr128__ /* Whereas in ordinary modes `%db[{0,1}]' correspond to `param{0,1}' respectively, . . . */ index = i; #else /* defined __ptr128__ */ /* . . . in PM these are `%qb[0]' and `%db[2]'. */ index = (i == 0 ? 0 : 2); #endif /* defined __ptr128__ */ len = ( #if defined __ptr128__ (old_stack_layout && i == 0) ? 16 : #endif /* defined __ptr128__ */ 8); /* Take into account the layout of registers in procedure stack for different iset versions according to C.23.1.1. */ off = (target->psp_offset + (old_stack_layout ? 32 * (index >> 1) + 8 * (index & 0x1) : 16 * index)); if (syshw (E2K_WRITE_PROCEDURE_STACK_EX, &off, p, len, NULL) != 0) abort (); #if defined __ptr128__ /* With the new procedure stack layout in use we've written only the lower half of `%qb[0]' so far. */ if (i == 0 && len == 8) { off += 16; if (syshw (E2K_WRITE_PROCEDURE_STACK_EX, &off, (char *) p + 8, len, NULL) != 0) abort (); } #endif /* defined __ptr128__ */ } /* In PM a call via PLT pushes an extra "frame" on chain stack unlike ordinary modes. In case the address of a target function is resolved lazily during the call, two extra frames are pushed. However, `syscall ()' must have already been called by the time one finds himself here, therefore, exactly one extra frame should be skipped. This lets me return from `syscall ()' PLT entry to this function in a regular way. There's also an extra frame that should be skipped between syscall () and the actual kernel entry point in QNX. */ #if ((defined (__ptr128__) && defined SHARED) || defined (__QNX__)) extra_frames_to_skip += 1; #endif /* (defined (__ptr128__) && defined SHARED) || defined (__QNX__) */ /* There is probably no point in returning to any of our callers, therefore to "return" to the caller of TARGET (i.e. TARGET->ra) allocate a buffer containing (LEVEL + 1) return addresses (keep in mind that 'LEVEL == 0' corresponds to our current context in fact, whereas 'TARGET->level' should be greater or equal than 1). Set the first LEVEL entries to point to a return instruction (i.e. RET_ADDR) and the last one to 'TARGET->ra'. */ for (i = 0; i < level; ) { size_t j; if (i == 0) { /* All -1 elements can be set during the first iteration of the outer loop. */ for (j = 0; (j < SET_BACKTRACE_LEN) && (j < level); j++) buf[j] = -1UL; } else { j = level - i; if (j > SET_BACKTRACE_LEN) j = SET_BACKTRACE_LEN; } if (j < SET_BACKTRACE_LEN) { /* It's time that we set the trailing element in BUF[] to RA. */ buf[j++] = (unsigned long) target->ra; } /* Skip `extra_frames_to_skip' frames so as to return here in a regular way plus I elements set up at the preceding iterations. Note that there's no point in returning to any of our callers prior to passing control to `TARGET->ra', which is why all modifiable return addresses except for the last one are set up to `-1'. */ if ((res = sys_set_backtrace (buf, j, extra_frames_to_skip + i, 0UL)) < 0) { perror ("set_backtrace"); abort (); } i += j; } /* FIXME: currently this just lets me eliminate warnings on returning from `noreturn' function. For E2K the underlying builtin should be expanded to nothing and I don't even remember what its parameters mean . . . */ __builtin_eh_return (0, target->ra); } static inline #if ! defined (__ptr128__) _Unwind_Ptr #else /* defined (__ptr128__) */ /* The result of this function is used to set up `exc->private_2' which should be capable of holding `void *stop_argument' in PM in case of forced unwinding. */ void * #endif /* defined (__ptr128__) */ uw_identify_context (struct _Unwind_Context *context) { return ( #if defined (__ptr128__) (void *) #endif /* defined (__ptr128__) */ _Unwind_GetPCSP (context)); } #include "unwind.inc" #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) alias (_Unwind_Backtrace); alias (_Unwind_DeleteException); alias (_Unwind_FindEnclosingFunction); alias (_Unwind_ForcedUnwind); alias (_Unwind_GetDataRelBase); alias (_Unwind_GetTextRelBase); alias (_Unwind_GetCFA); alias (_Unwind_GetGR); alias (_Unwind_GetIP); alias (_Unwind_GetLanguageSpecificData); alias (_Unwind_GetRegionStart); alias (_Unwind_RaiseException); alias (_Unwind_Resume); alias (_Unwind_Resume_or_Rethrow); alias (_Unwind_SetGR); alias (_Unwind_SetIP); #endif #endif /* !USING_SJLJ_EXCEPTIONS */