OSDN Git Service

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