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