OSDN Git Service

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