123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /* DWARF2 EH unwinding support for AIX.
- Copyright (C) 2011-2022 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
- <http://www.gnu.org/licenses/>. */
- /* Useful register numbers. */
- #define R_LR 65
- #define R_CR2 70
- #define R_XER 76
- #define R_FIRST_ALTIVEC 77
- #define R_VRSAVE 109
- #define R_VSCR 110
- /* If the current unwind info (FS) does not contain explicit info
- saving R2, then we have to do a minor amount of code reading to
- figure out if it was saved. The big problem here is that the
- code that does the save/restore is generated by the linker, so
- we have no good way to determine at compile time what to do. */
- #ifdef __64BIT__
- #define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
- do { \
- if ((FS)->regs.reg[2].how == REG_UNSAVED) \
- { \
- unsigned int *insn \
- = (unsigned int *) \
- _Unwind_GetGR ((CTX), R_LR); \
- if (*insn == 0xE8410028) \
- _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \
- } \
- } while (0)
- #else
- #define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
- do { \
- if ((FS)->regs.reg[2].how == REG_UNSAVED) \
- { \
- unsigned int *insn \
- = (unsigned int *) \
- _Unwind_GetGR ((CTX), R_LR); \
- if (*insn == 0x80410014) \
- _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20); \
- } \
- } while (0)
- #endif
- /* Now on to MD_FALLBACK_FRAME_STATE_FOR.
- 32bit AIX 5.2, 5.3, 6.1, 7.X and
- 64bit AIX 6.1, 7.X only at this stage. */
- #include <stdlib.h>
- #include <stddef.h>
- #include <signal.h>
- #include <sys/machine.h>
- #ifdef __64BIT__
- typedef struct __context64 mstate_t;
- #else
- typedef struct mstsave mstate_t;
- #endif
- #define MD_FALLBACK_FRAME_STATE_FOR ppc_aix_fallback_frame_state
- /* If we are compiling on AIX < 5.3, the VMX related datastructs are not
- defined and we take measures to obtain proper runtime behavior if the
- compiled code happens to run on a later version with VMX enabled. */
- #ifndef MSR_VMX
- #define MSR_VMX 0x2000000
- #endif
- typedef unsigned int uint;
- typedef struct { uint v[4]; } vreg_t;
- typedef struct {
- vreg_t regs[32];
- uint pad1 [3];
- uint vscr;
- uint vrsave;
- uint pad2 [3];
- } vstate_t;
- #define EXT_CONTEXT_MARK 0x45435458
- #define EXT_CONTEXT_SIZE 4096
- #define BUMPER_SIZE (EXT_CONTEXT_SIZE - sizeof(vstate_t) - (5 * sizeof(int)))
- typedef struct {
- uint pad1 [4];
- vstate_t vstate;
- char bumper [BUMPER_SIZE];
- int mark;
- } extended_context_t;
- typedef struct {
- char bumper [offsetof (ucontext_t, uc_stack) + sizeof (stack_t)];
- extended_context_t * ectx;
- int mark;
- } vmx_ucontext_t;
- /* Determine whether CONTEXT designates a signal handler, and return the
- associated ucontext_t address if so. Return NULL otherwise. */
- static ucontext_t *
- ucontext_for (struct _Unwind_Context *context)
- {
- const unsigned int * ra = context->ra;
- /* AIX 5.2, 5.3, 6.1 and 7.X, threaded or not, share common patterns
- and feature variants depending on the configured kernel (unix_mp
- or unix_64). */
- #ifdef __64BIT__
- if (*(ra - 5) == 0x4c00012c /* isync */
- && *(ra - 4) == 0xe8ec0000 /* ld r7,0(r12) */
- && *(ra - 3) == 0xe84c0008 /* ld r2,8(r12) */
- && *(ra - 2) == 0x7ce903a6 /* mtctr r7 */
- && *(ra - 1) == 0x4e800421 /* bctrl */
- && *(ra - 0) == 0x7de27b78) /* mr r2,r15 <-- context->ra */
- {
- /* unix_64 */
- if (*(ra - 6) == 0x7d000164) /* mtmsrd r8 */
- {
- /* AIX 6.1, 7.1 and 7.2 */
- return (ucontext_t *)(context->cfa + 0x70);
- }
- }
- #else
- if (*(ra - 5) == 0x4c00012c /* isync */
- && *(ra - 4) == 0x80ec0000 /* lwz r7,0(r12) */
- && *(ra - 3) == 0x804c0004 /* lwz r2,4(r12) */
- && *(ra - 2) == 0x7ce903a6 /* mtctr r7 */
- && *(ra - 1) == 0x4e800421 /* bctrl */
- && *(ra - 0) == 0x7dc37378) /* mr r3,r14 <-- context->ra */
- {
- /* unix_64 */
- if (*(ra - 6) == 0x7d000164) /* mtmsrd r8 */
- {
- switch (*(ra + 18))
- {
- /* AIX 5.2 */
- case 0x835a0520: /* lwz r26,1312(r26) */
- return (ucontext_t *)(context->cfa + 0x70);
- /* AIX 5.3 */
- case 0x835a0570: /* lwz r26,1392(r26) */
- return (ucontext_t *)(context->cfa + 0x40);
- /* AIX 6.1 and 7.1 */
- case 0x2c1a0000: /* cmpwi r26,0 */
- return (ucontext_t *)(context->cfa + 0x40);
- /* AIX 7.2 */
- case 0x3800000a: /* li r0,A */
- return (ucontext_t *)(context->cfa + 0x40);
- default:
- return 0;
- }
- }
- /* unix_mp */
- if (*(ra - 6) == 0x7d000124) /* mtmsr r8 */
- {
- typedef struct {
- char pad[56];
- ucontext_t ucontext;
- siginfo_t siginfo;
- } aix52_stack_t;
- aix52_stack_t * frame = (aix52_stack_t *) context->cfa;
- return &frame->ucontext;
- }
- }
- #endif
- return 0;
- }
- /* The fallback proper. */
- #ifdef __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__
- #define RETURN_COLUMN __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__
- #else
- #define RETURN_COLUMN ARG_POINTER_REGNUM
- #endif
- #define REGISTER_CFA_OFFSET_FOR(FS,REGNO,ADDR,CFA)\
- do { \
- (FS)->regs.reg[REGNO].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[REGNO].loc.offset = (long) (ADDR) - (CFA); \
- } while (0)
- static _Unwind_Reason_Code
- ppc_aix_fallback_frame_state (struct _Unwind_Context *context,
- _Unwind_FrameState *fs)
- {
- ucontext_t * uctx = ucontext_for (context);
- mstate_t * mctx;
- long new_cfa;
- int i;
- if (uctx == NULL)
- return _URC_END_OF_STACK;
- mctx = &uctx->uc_mcontext.jmp_context;
- /* The "kernel" frame cfa is the stack pointer at the signal occurrence
- point. */
- new_cfa = mctx->gpr[__LIBGCC_STACK_POINTER_REGNUM__];
- fs->regs.cfa_how = CFA_REG_OFFSET;
- fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
- fs->regs.cfa_offset = new_cfa - (long) context->cfa;
- /* And we state how to find the various registers it has saved with
- relative offset rules from there. */
- for (i = 0; i < 32; i++)
- if (i != __LIBGCC_STACK_POINTER_REGNUM__)
- REGISTER_CFA_OFFSET_FOR (fs, i, &mctx->gpr[i], new_cfa);
- REGISTER_CFA_OFFSET_FOR (fs, R_CR2, &mctx->cr, new_cfa);
- REGISTER_CFA_OFFSET_FOR (fs, R_XER, &mctx->xer, new_cfa);
- REGISTER_CFA_OFFSET_FOR (fs, R_LR, &mctx->lr, new_cfa);
- fs->retaddr_column = RETURN_COLUMN;
- REGISTER_CFA_OFFSET_FOR (fs, RETURN_COLUMN, &mctx->iar, new_cfa);
- fs->signal_frame = 1;
- /* Honor FP Ever Used ... */
- if (mctx->fpeu)
- {
- for (i = 0; i < 32; i++)
- REGISTER_CFA_OFFSET_FOR (fs, i+32, &mctx->fpr[i], new_cfa);
- }
- /* Honor VMX context, if any. We expect the msr bit never to be set in
- environments where there is no VMX support, e.g. on AIX < 5.3. */
- if (mctx->msr & MSR_VMX)
- {
- vmx_ucontext_t * uc = (vmx_ucontext_t *) uctx;
- if (uc->mark == EXT_CONTEXT_MARK && uc->ectx->mark == EXT_CONTEXT_MARK)
- {
- vstate_t * vstate = &uc->ectx->vstate;
- for (i = 0; i < 32; i++)
- REGISTER_CFA_OFFSET_FOR
- (fs, i+R_FIRST_ALTIVEC, &vstate->regs[i], new_cfa);
- REGISTER_CFA_OFFSET_FOR (fs, R_VSCR, &vstate->vscr, new_cfa);
- REGISTER_CFA_OFFSET_FOR (fs, R_VRSAVE, &vstate->vrsave, new_cfa);
- }
- }
- return _URC_NO_REASON;
- }
|