(root)/
gcc-13.2.0/
libgcc/
config/
rs6000/
darwin-fallback.c
       1  /* Fallback frame-state unwinder for Darwin.
       2     Copyright (C) 2004-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of GCC.
       5  
       6     GCC is free software; you can redistribute it and/or modify it
       7     under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     GCC is distributed in the hope that it will be useful, but WITHOUT
      12     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      13     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      14     License for more details.
      15  
      16     Under Section 7 of GPL version 3, you are granted additional
      17     permissions described in the GCC Runtime Library Exception, version
      18     3.1, as published by the Free Software Foundation.
      19  
      20     You should have received a copy of the GNU General Public License and
      21     a copy of the GCC Runtime Library Exception along with this program;
      22     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23     <http://www.gnu.org/licenses/>.  */
      24  
      25  #ifdef __ppc__
      26  
      27  #include "tconfig.h"
      28  #include "tsystem.h"
      29  #include "coretypes.h"
      30  #include "tm.h"
      31  #include "libgcc_tm.h"
      32  #include "dwarf2.h"
      33  #include "unwind.h"
      34  #include "unwind-dw2.h"
      35  #include <stdint.h>
      36  #include <stdbool.h>
      37  #include <sys/types.h>
      38  #include <signal.h>
      39  
      40  #define R_LR		65
      41  #define R_CTR		66
      42  #define R_CR2		70
      43  #define R_XER		76
      44  #define R_VR0		77
      45  #define R_VRSAVE	109
      46  #define R_VSCR		110
      47  #define R_SPEFSCR	112
      48  
      49  typedef unsigned long reg_unit;
      50  
      51  /* Place in GPRS the parameters to the first 'sc' instruction that would
      52     have been executed if we were returning from this CONTEXT, or
      53     return false if an unexpected instruction is encountered.  */
      54  
      55  static bool
      56  interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context)
      57  {
      58    uint32_t *pc = (uint32_t *)_Unwind_GetIP (context);
      59    uint32_t cr;
      60    reg_unit lr = (reg_unit) pc;
      61    reg_unit ctr = 0;
      62    uint32_t *invalid_address = NULL;
      63  
      64    int i;
      65  
      66    for (i = 0; i < 13; i++)
      67      gprs[i] = 1;
      68    gprs[1] = _Unwind_GetCFA (context);
      69    for (; i < 32; i++)
      70      gprs[i] = _Unwind_GetGR (context, i);
      71    cr = _Unwind_GetGR (context, R_CR2);
      72  
      73    /* For each supported Libc, we have to track the code flow
      74       all the way back into the kernel.
      75    
      76       This code is believed to support all released Libc/Libsystem builds since
      77       Jaguar 6C115, including all the security updates.  To be precise,
      78  
      79       Libc	Libsystem	Build(s)
      80       262~1	60~37		6C115
      81       262~1	60.2~4		6D52
      82       262~1	61~3		6F21-6F22
      83       262~1	63~24		6G30-6G37
      84       262~1	63~32		6I34-6I35
      85       262~1	63~64		6L29-6L60
      86       262.4.1~1	63~84		6L123-6R172
      87       
      88       320~1	71~101		7B85-7D28
      89       320~1	71~266		7F54-7F56
      90       320~1	71~288		7F112
      91       320~1	71~289		7F113
      92       320.1.3~1	71.1.1~29	7H60-7H105
      93       320.1.3~1	71.1.1~30	7H110-7H113
      94       320.1.3~1	71.1.1~31	7H114
      95       
      96       That's a big table!  It would be insane to try to keep track of
      97       every little detail, so we just read the code itself and do what
      98       it would do.
      99    */
     100  
     101    for (;;)
     102      {
     103        uint32_t ins = *pc++;
     104        
     105        if ((ins & 0xFC000003) == 0x48000000)  /* b instruction */
     106  	{
     107  	  pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
     108  	  continue;
     109  	}
     110        if ((ins & 0xFC600000) == 0x2C000000)  /* cmpwi */
     111  	{
     112  	  int32_t val1 = (int16_t) ins;
     113  	  int32_t val2 = gprs[ins >> 16 & 0x1F];
     114  	  /* Only beq and bne instructions are supported, so we only
     115  	     need to set the EQ bit.  */
     116  	  uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C);
     117  	  if (val1 == val2)
     118  	    cr |= mask;
     119  	  else
     120  	    cr &= ~mask;
     121  	  continue;
     122  	}
     123        if ((ins & 0xFEC38003) == 0x40820000)  /* forwards beq/bne */
     124  	{
     125  	  if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1))
     126  	    pc += (ins & 0x7FFC) / 4 - 1;
     127  	  continue;
     128  	}
     129        if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */
     130  	{
     131  	  gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F] 
     132  				     | gprs [ins >> 21 & 0x1F]);
     133  	  continue;
     134  	}
     135        if (ins >> 26 == 0x0E)  /* addi, including li */
     136  	{
     137  	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
     138  	  gprs [ins >> 21 & 0x1F] = src + (int16_t) ins;
     139  	  continue;
     140  	}
     141        if (ins >> 26 == 0x0F)  /* addis, including lis */
     142  	{
     143  	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
     144  	  gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16);
     145  	  continue;
     146  	}
     147        if (ins >> 26 == 0x20)  /* lwz */
     148  	{
     149  	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
     150  	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
     151  	  if (p == invalid_address)
     152  	    return false;
     153  	  gprs [ins >> 21 & 0x1F] = *p;
     154  	  continue;
     155  	}
     156        if (ins >> 26 == 0x21)  /* lwzu */
     157  	{
     158  	  uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins);
     159  	  if (p == invalid_address)
     160  	    return false;
     161  	  gprs [ins >> 21 & 0x1F] = *p;
     162  	  continue;
     163  	}
     164        if (ins >> 26 == 0x24)  /* stw */
     165  	/* What we hope this is doing is '--in_sigtramp'.  We don't want
     166  	   to actually store to memory, so just make a note of the
     167  	   address and refuse to load from it.  */
     168  	{
     169  	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
     170  	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
     171  	  if (p == NULL || invalid_address != NULL)
     172  	    return false;
     173  	  invalid_address = p;
     174  	  continue;
     175  	}
     176        if (ins >> 26 == 0x2E) /* lmw */
     177  	{
     178  	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
     179  	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
     180  	  int i;
     181  
     182  	  for (i = (ins >> 21 & 0x1F); i < 32; i++)
     183  	    {
     184  	      if (p == invalid_address)
     185  		return false;
     186  	      gprs[i] = *p++;
     187  	    }
     188  	  continue;
     189  	}
     190        if ((ins & 0xFC1FFFFF) == 0x7c0803a6)  /* mtlr */
     191  	{
     192  	  lr = gprs [ins >> 21 & 0x1F];
     193  	  continue;
     194  	}
     195        if ((ins & 0xFC1FFFFF) == 0x7c0802a6)  /* mflr */
     196  	{
     197  	  gprs [ins >> 21 & 0x1F] = lr;
     198  	  continue;
     199  	}
     200        if ((ins & 0xFC1FFFFF) == 0x7c0903a6)  /* mtctr */
     201  	{
     202  	  ctr = gprs [ins >> 21 & 0x1F];
     203  	  continue;
     204  	}
     205        /* The PowerPC User's Manual says that bit 11 of the mtcrf
     206  	 instruction is reserved and should be set to zero, but it
     207  	 looks like the Darwin assembler doesn't do that... */
     208        if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */
     209  	{
     210  	  int i;
     211  	  uint32_t mask = 0;
     212  	  for (i = 0; i < 8; i++)
     213  	    mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i;
     214  	  cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask);
     215  	  continue;
     216  	}
     217        if (ins == 0x429f0005)  /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
     218  	{
     219  	  lr = (reg_unit) pc;
     220  	  continue;
     221  	}
     222        if (ins == 0x4e800420) /* bctr */
     223  	{
     224  	  pc = (uint32_t *) ctr;
     225  	  continue;
     226  	}
     227        if (ins == 0x44000002) /* sc */
     228  	return true;
     229  
     230        return false;
     231      }
     232  }
     233  
     234  /* We used to include <ucontext.h> and <mach/thread_status.h>,
     235     but they change so much between different Darwin system versions
     236     that it's much easier to just write the structures involved here
     237     directly.  */
     238  
     239  /* These defines are from the kernel's bsd/dev/ppc/unix_signal.c.  */
     240  #define UC_TRAD                 1
     241  #define UC_TRAD_VEC             6
     242  #define UC_TRAD64               20
     243  #define UC_TRAD64_VEC           25
     244  #define UC_FLAVOR               30
     245  #define UC_FLAVOR_VEC           35
     246  #define UC_FLAVOR64             40
     247  #define UC_FLAVOR64_VEC         45
     248  #define UC_DUAL                 50
     249  #define UC_DUAL_VEC             55
     250  
     251  struct gcc_ucontext 
     252  {
     253    int onstack;
     254    sigset_t sigmask;
     255    void * stack_sp;
     256    size_t stack_sz;
     257    int stack_flags;
     258    struct gcc_ucontext *link;
     259    size_t mcsize;
     260    struct gcc_mcontext32 *mcontext;
     261  };
     262  
     263  struct gcc_float_vector_state 
     264  {
     265    double fpregs[32];
     266    uint32_t fpscr_pad;
     267    uint32_t fpscr;
     268    uint32_t save_vr[32][4];
     269    uint32_t save_vscr[4];
     270  };
     271  
     272  struct gcc_mcontext32 {
     273    uint32_t dar;
     274    uint32_t dsisr;
     275    uint32_t exception;
     276    uint32_t padding1[5];
     277    uint32_t srr0;
     278    uint32_t srr1;
     279    uint32_t gpr[32];
     280    uint32_t cr;
     281    uint32_t xer;
     282    uint32_t lr;
     283    uint32_t ctr;
     284    uint32_t mq;
     285    uint32_t vrsave;
     286    struct gcc_float_vector_state fvs;
     287  };
     288  
     289  /* These are based on /usr/include/ppc/ucontext.h and
     290     /usr/include/mach/ppc/thread_status.h, but rewritten to be more
     291     convenient, to compile on Jaguar, and to work around Radar 3712064
     292     on Panther, which is that the 'es' field of 'struct mcontext64' has
     293     the wrong type (doh!).  */
     294  
     295  struct gcc_mcontext64 {
     296    uint64_t dar;
     297    uint32_t dsisr;
     298    uint32_t exception;
     299    uint32_t padding1[4];
     300    uint64_t srr0;
     301    uint64_t srr1;
     302    uint32_t gpr[32][2];
     303    uint32_t cr;
     304    uint32_t xer[2];  /* These are arrays because the original structure has them misaligned.  */
     305    uint32_t lr[2];
     306    uint32_t ctr[2];
     307    uint32_t vrsave;
     308    struct gcc_float_vector_state fvs;
     309  };
     310  
     311  #define UC_FLAVOR_SIZE \
     312    (sizeof (struct gcc_mcontext32) - 33*16)
     313  
     314  #define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32))
     315  
     316  #define UC_FLAVOR64_SIZE \
     317    (sizeof (struct gcc_mcontext64) - 33*16)
     318  
     319  #define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
     320  
     321  /* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS
     322     to represent the execution of a signal return; or, if not a signal
     323     return, return false.  */
     324  
     325  static bool
     326  handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32],
     327  		_Unwind_Ptr old_cfa)
     328  {
     329    struct gcc_ucontext *uctx;
     330    bool is_64, is_vector;
     331    struct gcc_float_vector_state * float_vector_state;
     332    _Unwind_Ptr new_cfa;
     333    int i;
     334    static _Unwind_Ptr return_addr;
     335    
     336    /* Yay!  We're in a Libc that we understand, and it's made a
     337       system call.  In Jaguar, this is a direct system call with value 103;
     338       in Panther and Tiger it is a SYS_syscall call for system call number 184,
     339       and in Leopard it is a direct syscall with number 184.  */
     340    
     341    if (gprs[0] == 0x67 /* SYS_SIGRETURN */)
     342      {
     343        uctx = (struct gcc_ucontext *) gprs[3];
     344        is_vector = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE
     345  		   || uctx->mcsize == UC_FLAVOR_VEC_SIZE);
     346        is_64 = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE
     347  	       || uctx->mcsize == UC_FLAVOR64_SIZE);
     348      }
     349    else if (gprs[0] == 0 /* SYS_syscall */ && gprs[3] == 184)
     350      {
     351        int ctxstyle = gprs[5];
     352        uctx = (struct gcc_ucontext *) gprs[4];
     353        is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
     354  		   || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
     355        is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
     356  	       || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
     357      }
     358    else if (gprs[0] == 184 /* SYS_sigreturn */)
     359      {
     360        int ctxstyle = gprs[4];
     361        uctx = (struct gcc_ucontext *) gprs[3];
     362        is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
     363  		   || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
     364        is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
     365  	       || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
     366      }
     367    else
     368      return false;
     369  
     370  #define set_offset(r, addr)					\
     371    (fs->regs.how[r] = REG_SAVED_OFFSET,			\
     372     fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
     373  
     374    /* Restore even the registers that are not call-saved, since they
     375       might be being used in the prologue to save other registers,
     376       for instance GPR0 is sometimes used to save LR.  */
     377  
     378    /* Handle the GPRs, and produce the information needed to do the rest.  */
     379    if (is_64)
     380      {
     381        /* The context is 64-bit, but it doesn't carry any extra information
     382  	 for us because only the low 32 bits of the registers are
     383  	 call-saved.  */
     384        struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->mcontext;
     385        int i;
     386  
     387        float_vector_state = &m64->fvs;
     388  
     389        new_cfa = m64->gpr[1][1];
     390        
     391        set_offset (R_CR2, &m64->cr);
     392        for (i = 0; i < 32; i++)
     393  	set_offset (i, m64->gpr[i] + 1);
     394        set_offset (R_XER, m64->xer + 1);
     395        set_offset (R_LR, m64->lr + 1);
     396        set_offset (R_CTR, m64->ctr + 1);
     397        if (is_vector)
     398  	set_offset (R_VRSAVE, &m64->vrsave);
     399        
     400        /* Sometimes, srr0 points to the instruction that caused the exception,
     401  	 and sometimes to the next instruction to be executed; we want
     402  	 the latter.  */
     403        if (m64->exception == 3 || m64->exception == 4
     404  	  || m64->exception == 6
     405  	  || (m64->exception == 7 && !(m64->srr1 & 0x10000)))
     406  	return_addr = m64->srr0 + 4;
     407        else
     408  	return_addr = m64->srr0;
     409      }
     410    else
     411      {
     412        struct gcc_mcontext32 *m = uctx->mcontext;
     413        int i;
     414  
     415        float_vector_state = &m->fvs;
     416        
     417        new_cfa = m->gpr[1];
     418  
     419        set_offset (R_CR2, &m->cr);
     420        for (i = 0; i < 32; i++)
     421  	set_offset (i, m->gpr + i);
     422        set_offset (R_XER, &m->xer);
     423        set_offset (R_LR, &m->lr);
     424        set_offset (R_CTR, &m->ctr);
     425  
     426        if (is_vector)
     427  	set_offset (R_VRSAVE, &m->vrsave);
     428  
     429        /* Sometimes, srr0 points to the instruction that caused the exception,
     430  	 and sometimes to the next instruction to be executed; we want
     431  	 the latter.  */
     432        if (m->exception == 3 || m->exception == 4
     433  	  || m->exception == 6
     434  	  || (m->exception == 7 && !(m->srr1 & 0x10000)))
     435  	return_addr = m->srr0 + 4;
     436        else
     437  	return_addr = m->srr0;
     438      }
     439  
     440    fs->regs.cfa_how = CFA_REG_OFFSET;
     441    fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
     442    fs->regs.cfa_offset = new_cfa - old_cfa;;
     443    
     444    /* The choice of column for the return address is somewhat tricky.
     445       Fortunately, the actual choice is private to this file, and
     446       the space it's reserved from is the GCC register space, not the
     447       DWARF2 numbering.  So any free element of the right size is an OK
     448       choice.  Thus: */
     449    fs->retaddr_column = ARG_POINTER_REGNUM;
     450    /* FIXME: this should really be done using a DWARF2 location expression,
     451       not using a static variable.  In fact, this entire file should
     452       be implemented in DWARF2 expressions.  */
     453    set_offset (ARG_POINTER_REGNUM, &return_addr);
     454  
     455    for (i = 0; i < 32; i++)
     456      set_offset (32 + i, float_vector_state->fpregs + i);
     457    set_offset (R_SPEFSCR, &float_vector_state->fpscr);
     458    
     459    if (is_vector)
     460      {
     461        for (i = 0; i < 32; i++)
     462  	set_offset (R_VR0 + i, float_vector_state->save_vr + i);
     463        set_offset (R_VSCR, float_vector_state->save_vscr);
     464      }
     465  
     466    return true;
     467  }
     468  
     469  /* This is also prototyped in rs6000/darwin.h, inside the
     470     MD_FALLBACK_FRAME_STATE_FOR macro.  */
     471  extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
     472  					      _Unwind_FrameState *fs);
     473  
     474  /* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
     475     returning true iff the frame was a sigreturn() frame that we
     476     can understand.  */
     477  
     478  bool
     479  _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
     480  				  _Unwind_FrameState *fs)
     481  {
     482    reg_unit gprs[32];
     483  
     484    if (!interpret_libc (gprs, context))
     485      return false;
     486    return handle_syscall (fs, gprs, _Unwind_GetCFA (context));
     487  }
     488  #endif