163d1a8abSmrg /* DWARF2 EH unwinding support for AIX.
2*ec02198aSmrg    Copyright (C) 2011-2020 Free Software Foundation, Inc.
363d1a8abSmrg 
463d1a8abSmrg    This file is part of GCC.
563d1a8abSmrg 
663d1a8abSmrg    GCC is free software; you can redistribute it and/or modify it
763d1a8abSmrg    under the terms of the GNU General Public License as published by
863d1a8abSmrg    the Free Software Foundation; either version 3, or (at your option)
963d1a8abSmrg    any later version.
1063d1a8abSmrg 
1163d1a8abSmrg    GCC is distributed in the hope that it will be useful, but WITHOUT
1263d1a8abSmrg    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1363d1a8abSmrg    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1463d1a8abSmrg    License for more details.
1563d1a8abSmrg 
1663d1a8abSmrg    Under Section 7 of GPL version 3, you are granted additional
1763d1a8abSmrg    permissions described in the GCC Runtime Library Exception, version
1863d1a8abSmrg    3.1, as published by the Free Software Foundation.
1963d1a8abSmrg 
2063d1a8abSmrg    You should have received a copy of the GNU General Public License and
2163d1a8abSmrg    a copy of the GCC Runtime Library Exception along with this program;
2263d1a8abSmrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2363d1a8abSmrg    <http://www.gnu.org/licenses/>.  */
2463d1a8abSmrg 
2563d1a8abSmrg /* Useful register numbers.  */
2663d1a8abSmrg 
27*ec02198aSmrg #define R_LR             65
28*ec02198aSmrg #define R_CR2            70
29*ec02198aSmrg #define R_XER            76
30*ec02198aSmrg #define R_FIRST_ALTIVEC  77
31*ec02198aSmrg #define R_VRSAVE        109
32*ec02198aSmrg #define R_VSCR          110
3363d1a8abSmrg 
3463d1a8abSmrg /* If the current unwind info (FS) does not contain explicit info
3563d1a8abSmrg    saving R2, then we have to do a minor amount of code reading to
3663d1a8abSmrg    figure out if it was saved.  The big problem here is that the
3763d1a8abSmrg    code that does the save/restore is generated by the linker, so
3863d1a8abSmrg    we have no good way to determine at compile time what to do.  */
3963d1a8abSmrg 
4063d1a8abSmrg #ifdef __64BIT__
4163d1a8abSmrg #define MD_FROB_UPDATE_CONTEXT(CTX, FS)					\
4263d1a8abSmrg   do {									\
4363d1a8abSmrg     if ((FS)->regs.reg[2].how == REG_UNSAVED)				\
4463d1a8abSmrg       {									\
4563d1a8abSmrg 	unsigned int *insn						\
4663d1a8abSmrg 	  = (unsigned int *)						\
47*ec02198aSmrg 	    _Unwind_GetGR ((CTX), R_LR);				\
4863d1a8abSmrg 	if (*insn == 0xE8410028)					\
4963d1a8abSmrg 	  _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40);			\
5063d1a8abSmrg       }									\
5163d1a8abSmrg   } while (0)
5263d1a8abSmrg #else
5363d1a8abSmrg #define MD_FROB_UPDATE_CONTEXT(CTX, FS)					\
5463d1a8abSmrg   do {									\
5563d1a8abSmrg     if ((FS)->regs.reg[2].how == REG_UNSAVED)				\
5663d1a8abSmrg       {									\
5763d1a8abSmrg 	unsigned int *insn						\
5863d1a8abSmrg 	  = (unsigned int *)						\
59*ec02198aSmrg 	    _Unwind_GetGR ((CTX), R_LR);				\
6063d1a8abSmrg 	if (*insn == 0x80410014)					\
6163d1a8abSmrg 	  _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20);			\
6263d1a8abSmrg       }									\
6363d1a8abSmrg   } while (0)
6463d1a8abSmrg #endif
6563d1a8abSmrg 
6663d1a8abSmrg /* Now on to MD_FALLBACK_FRAME_STATE_FOR.
67c7a68eb7Smrg    32bit AIX 5.2, 5.3, 6.1, 7.X and
68c7a68eb7Smrg    64bit AIX 6.1, 7.X only at this stage.  */
6963d1a8abSmrg 
7063d1a8abSmrg #include <stdlib.h>
7163d1a8abSmrg #include <stddef.h>
7263d1a8abSmrg #include <signal.h>
7363d1a8abSmrg #include <sys/machine.h>
7463d1a8abSmrg 
7563d1a8abSmrg #ifdef __64BIT__
7663d1a8abSmrg 
7763d1a8abSmrg typedef struct __context64 mstate_t;
7863d1a8abSmrg 
7963d1a8abSmrg #else
8063d1a8abSmrg 
8163d1a8abSmrg typedef struct mstsave mstate_t;
8263d1a8abSmrg 
8363d1a8abSmrg #endif
8463d1a8abSmrg 
85c7a68eb7Smrg #define MD_FALLBACK_FRAME_STATE_FOR ppc_aix_fallback_frame_state
86c7a68eb7Smrg 
8763d1a8abSmrg /* If we are compiling on AIX < 5.3, the VMX related datastructs are not
8863d1a8abSmrg    defined and we take measures to obtain proper runtime behavior if the
8963d1a8abSmrg    compiled code happens to run on a later version with VMX enabled.  */
9063d1a8abSmrg 
9163d1a8abSmrg #ifndef MSR_VMX
9263d1a8abSmrg #define MSR_VMX 0x2000000
9363d1a8abSmrg #endif
9463d1a8abSmrg 
9563d1a8abSmrg typedef unsigned int uint;
9663d1a8abSmrg typedef struct { uint v[4]; } vreg_t;
9763d1a8abSmrg typedef struct {
9863d1a8abSmrg   vreg_t regs[32];
9963d1a8abSmrg   uint   pad1 [3];
10063d1a8abSmrg   uint   vscr;
10163d1a8abSmrg   uint   vrsave;
10263d1a8abSmrg   uint   pad2 [3];
10363d1a8abSmrg } vstate_t;
10463d1a8abSmrg 
10563d1a8abSmrg #define EXT_CONTEXT_MARK 0x45435458
10663d1a8abSmrg #define EXT_CONTEXT_SIZE 4096
10763d1a8abSmrg #define BUMPER_SIZE (EXT_CONTEXT_SIZE - sizeof(vstate_t) - (5 * sizeof(int)))
10863d1a8abSmrg 
10963d1a8abSmrg typedef struct {
11063d1a8abSmrg   uint     pad1 [4];
11163d1a8abSmrg   vstate_t vstate;
11263d1a8abSmrg   char     bumper [BUMPER_SIZE];
11363d1a8abSmrg   int      mark;
11463d1a8abSmrg } extended_context_t;
11563d1a8abSmrg 
11663d1a8abSmrg typedef struct {
11763d1a8abSmrg   char bumper [offsetof (ucontext_t, uc_stack) + sizeof (stack_t)];
11863d1a8abSmrg   extended_context_t * ectx;
11963d1a8abSmrg   int mark;
12063d1a8abSmrg } vmx_ucontext_t;
12163d1a8abSmrg 
12263d1a8abSmrg /* Determine whether CONTEXT designates a signal handler, and return the
12363d1a8abSmrg    associated ucontext_t address if so.  Return NULL otherwise.  */
12463d1a8abSmrg 
12563d1a8abSmrg static ucontext_t *
ucontext_for(struct _Unwind_Context * context)12663d1a8abSmrg ucontext_for (struct _Unwind_Context *context)
12763d1a8abSmrg {
12863d1a8abSmrg   const unsigned int * ra = context->ra;
12963d1a8abSmrg 
130c7a68eb7Smrg   /* AIX 5.2, 5.3, 6.1 and 7.X, threaded or not, share common patterns
13163d1a8abSmrg      and feature variants depending on the configured kernel (unix_mp
13263d1a8abSmrg      or unix_64).  */
13363d1a8abSmrg 
134c7a68eb7Smrg #ifdef __64BIT__
135c7a68eb7Smrg   if (*(ra - 5) == 0x4c00012c     /* isync             */
136c7a68eb7Smrg       && *(ra - 4) == 0xe8ec0000  /* ld      r7,0(r12) */
137c7a68eb7Smrg       && *(ra - 3) == 0xe84c0008  /* ld      r2,8(r12) */
138c7a68eb7Smrg       && *(ra - 2) == 0x7ce903a6  /* mtctr   r7        */
139c7a68eb7Smrg       && *(ra - 1) == 0x4e800421  /* bctrl             */
140c7a68eb7Smrg       && *(ra - 0) == 0x7de27b78) /* mr      r2,r15   <-- context->ra */
141c7a68eb7Smrg     {
142c7a68eb7Smrg       /* unix_64 */
143c7a68eb7Smrg       if (*(ra - 6) == 0x7d000164)  /* mtmsrd  r8 */
144c7a68eb7Smrg 	{
145c7a68eb7Smrg 	  /* AIX 6.1, 7.1 and 7.2 */
146c7a68eb7Smrg 	  return (ucontext_t *)(context->cfa + 0x70);
147c7a68eb7Smrg 	}
148c7a68eb7Smrg     }
149c7a68eb7Smrg #else
15063d1a8abSmrg   if (*(ra - 5) == 0x4c00012c     /* isync             */
15163d1a8abSmrg       && *(ra - 4) == 0x80ec0000  /* lwz     r7,0(r12) */
15263d1a8abSmrg       && *(ra - 3) == 0x804c0004  /* lwz     r2,4(r12) */
15363d1a8abSmrg       && *(ra - 2) == 0x7ce903a6  /* mtctr   r7        */
15463d1a8abSmrg       && *(ra - 1) == 0x4e800421  /* bctrl             */
15563d1a8abSmrg       && *(ra - 0) == 0x7dc37378) /* mr      r3,r14   <-- context->ra */
15663d1a8abSmrg     {
15763d1a8abSmrg       /* unix_64 */
15863d1a8abSmrg       if (*(ra - 6) == 0x7d000164)  /* mtmsrd  r8 */
15963d1a8abSmrg 	{
16063d1a8abSmrg 	  switch (*(ra + 18))
16163d1a8abSmrg 	    {
16263d1a8abSmrg 	      /* AIX 5.2 */
16363d1a8abSmrg 	    case 0x835a0520: /* lwz r26,1312(r26) */
16463d1a8abSmrg 	      return (ucontext_t *)(context->cfa + 0x70);
16563d1a8abSmrg 
16663d1a8abSmrg 	      /* AIX 5.3 */
16763d1a8abSmrg 	    case 0x835a0570:  /* lwz r26,1392(r26) */
16863d1a8abSmrg 	      return (ucontext_t *)(context->cfa + 0x40);
16963d1a8abSmrg 
170c7a68eb7Smrg 	      /* AIX 6.1 and 7.1 */
17163d1a8abSmrg 	    case 0x2c1a0000:  /* cmpwi   r26,0 */
17263d1a8abSmrg 	      return (ucontext_t *)(context->cfa + 0x40);
17363d1a8abSmrg 
174c7a68eb7Smrg 	      /* AIX 7.2 */
175c7a68eb7Smrg 	    case 0x3800000a:  /* li   r0,A */
176c7a68eb7Smrg 	      return (ucontext_t *)(context->cfa + 0x40);
177c7a68eb7Smrg 
17863d1a8abSmrg 	    default:
17963d1a8abSmrg 	      return 0;
18063d1a8abSmrg 	    }
18163d1a8abSmrg 	}
18263d1a8abSmrg 
18363d1a8abSmrg       /* unix_mp */
18463d1a8abSmrg       if (*(ra - 6) == 0x7d000124)  /* mtmsr  r8 */
18563d1a8abSmrg 	{
18663d1a8abSmrg 	  typedef struct {
18763d1a8abSmrg 	    char pad[56];
18863d1a8abSmrg 	    ucontext_t ucontext;
18963d1a8abSmrg 	    siginfo_t siginfo;
19063d1a8abSmrg 	  } aix52_stack_t;
19163d1a8abSmrg 
19263d1a8abSmrg 	  aix52_stack_t * frame = (aix52_stack_t *) context->cfa;
19363d1a8abSmrg 	  return &frame->ucontext;
19463d1a8abSmrg 	}
19563d1a8abSmrg     }
196c7a68eb7Smrg #endif
19763d1a8abSmrg   return 0;
19863d1a8abSmrg }
19963d1a8abSmrg 
20063d1a8abSmrg /* The fallback proper.  */
20163d1a8abSmrg 
20263d1a8abSmrg #ifdef __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__
20363d1a8abSmrg #define RETURN_COLUMN __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__
20463d1a8abSmrg #else
20563d1a8abSmrg #define RETURN_COLUMN ARG_POINTER_REGNUM
20663d1a8abSmrg #endif
20763d1a8abSmrg 
20863d1a8abSmrg #define REGISTER_CFA_OFFSET_FOR(FS,REGNO,ADDR,CFA)\
20963d1a8abSmrg do { \
21063d1a8abSmrg (FS)->regs.reg[REGNO].how = REG_SAVED_OFFSET; \
21163d1a8abSmrg (FS)->regs.reg[REGNO].loc.offset = (long) (ADDR) - (CFA); \
212c7a68eb7Smrg } while (0)
21363d1a8abSmrg 
21463d1a8abSmrg static _Unwind_Reason_Code
ppc_aix_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)21563d1a8abSmrg ppc_aix_fallback_frame_state (struct _Unwind_Context *context,
21663d1a8abSmrg 			      _Unwind_FrameState *fs)
21763d1a8abSmrg {
21863d1a8abSmrg   ucontext_t * uctx = ucontext_for (context);
21963d1a8abSmrg   mstate_t * mctx;
22063d1a8abSmrg 
22163d1a8abSmrg   long new_cfa;
22263d1a8abSmrg   int i;
22363d1a8abSmrg 
22463d1a8abSmrg   if (uctx == NULL)
22563d1a8abSmrg     return _URC_END_OF_STACK;
22663d1a8abSmrg 
22763d1a8abSmrg   mctx = &uctx->uc_mcontext.jmp_context;
22863d1a8abSmrg 
22963d1a8abSmrg   /* The "kernel" frame cfa is the stack pointer at the signal occurrence
23063d1a8abSmrg      point.  */
23163d1a8abSmrg   new_cfa = mctx->gpr[__LIBGCC_STACK_POINTER_REGNUM__];
23263d1a8abSmrg 
23363d1a8abSmrg   fs->regs.cfa_how = CFA_REG_OFFSET;
23463d1a8abSmrg   fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
23563d1a8abSmrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
23663d1a8abSmrg 
23763d1a8abSmrg   /* And we state how to find the various registers it has saved with
23863d1a8abSmrg      relative offset rules from there.  */
23963d1a8abSmrg 
24063d1a8abSmrg   for (i = 0; i < 32; i++)
24163d1a8abSmrg     if (i != __LIBGCC_STACK_POINTER_REGNUM__)
24263d1a8abSmrg       REGISTER_CFA_OFFSET_FOR (fs, i, &mctx->gpr[i], new_cfa);
24363d1a8abSmrg 
244*ec02198aSmrg   REGISTER_CFA_OFFSET_FOR (fs, R_CR2, &mctx->cr, new_cfa);
245*ec02198aSmrg   REGISTER_CFA_OFFSET_FOR (fs, R_XER, &mctx->xer, new_cfa);
246*ec02198aSmrg   REGISTER_CFA_OFFSET_FOR (fs, R_LR, &mctx->lr, new_cfa);
24763d1a8abSmrg 
24863d1a8abSmrg   fs->retaddr_column = RETURN_COLUMN;
24963d1a8abSmrg   REGISTER_CFA_OFFSET_FOR (fs, RETURN_COLUMN, &mctx->iar, new_cfa);
25063d1a8abSmrg   fs->signal_frame = 1;
25163d1a8abSmrg 
25263d1a8abSmrg   /* Honor FP Ever Used ...   */
25363d1a8abSmrg   if (mctx->fpeu)
25463d1a8abSmrg     {
25563d1a8abSmrg       for (i = 0; i < 32; i++)
25663d1a8abSmrg 	REGISTER_CFA_OFFSET_FOR (fs, i+32, &mctx->fpr[i], new_cfa);
25763d1a8abSmrg     }
25863d1a8abSmrg 
25963d1a8abSmrg   /* Honor VMX context, if any.  We expect the msr bit never to be set in
26063d1a8abSmrg      environments where there is no VMX support, e.g. on AIX < 5.3.  */
26163d1a8abSmrg   if (mctx->msr & MSR_VMX)
26263d1a8abSmrg     {
26363d1a8abSmrg       vmx_ucontext_t * uc = (vmx_ucontext_t *) uctx;
26463d1a8abSmrg 
26563d1a8abSmrg       if (uc->mark == EXT_CONTEXT_MARK && uc->ectx->mark == EXT_CONTEXT_MARK)
26663d1a8abSmrg 	{
26763d1a8abSmrg 	  vstate_t * vstate = &uc->ectx->vstate;
26863d1a8abSmrg 
26963d1a8abSmrg 	  for (i = 0; i < 32; i++)
27063d1a8abSmrg 	    REGISTER_CFA_OFFSET_FOR
271*ec02198aSmrg 	    (fs, i+R_FIRST_ALTIVEC, &vstate->regs[i], new_cfa);
27263d1a8abSmrg 
273*ec02198aSmrg 	  REGISTER_CFA_OFFSET_FOR (fs, R_VSCR, &vstate->vscr, new_cfa);
274*ec02198aSmrg 	  REGISTER_CFA_OFFSET_FOR (fs, R_VRSAVE, &vstate->vrsave, new_cfa);
27563d1a8abSmrg 	}
27663d1a8abSmrg     }
27763d1a8abSmrg 
27863d1a8abSmrg   return _URC_NO_REASON;
27963d1a8abSmrg }
280