OSDN Git Service

Latest updates from FSF 4.7 branch
[pf3gnuchains/gcc-fork.git] / libgcc / config / s390 / tpf-unwind.h
1 /* DWARF2 EH unwinding support for TPF OS.
2    Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
3    Contributed by P.J. Darcy (darcypj@us.ibm.com).
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25
26 #include <dlfcn.h>
27
28 /*
29 ** UNWIND_CFA_NOT_UNIQUE tells the unwinder that it's legitimate to
30 ** see the same CFA twice.
31 */
32 #define UNWIND_CFA_NOT_UNIQUE   1
33
34 /* Function Name: __isPATrange
35    Parameters passed into it:  address to check
36    Return Value: A 1 if address is in pat code "range", 0 if not
37    Description: This function simply checks to see if the address
38    passed to it is in the CP pat code range.  */
39
40 #define MIN_PATRANGE 0x10000
41 #define MAX_PATRANGE 0x800000
42
43 static inline unsigned int
44 __isPATrange (void *addr)
45 {
46   if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE)
47     return 1;
48   else
49     return 0;
50 }
51
52 /* TPF return address offset from start of stack frame.  */
53 #define TPFRA_OFFSET 168
54
55 /* Exceptions macro defined for TPF so that functions without
56    dwarf frame information can be used with exceptions.  */
57 #define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
58
59 static _Unwind_Reason_Code
60 s390_fallback_frame_state (struct _Unwind_Context *context,
61                            _Unwind_FrameState *fs)
62 {
63   unsigned long int regs;
64   unsigned long int new_cfa;
65   int i;
66
67   regs = *((unsigned long int *)
68         (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
69
70   /* Are we going through special linkage code?  */
71   if (__isPATrange (context->ra))
72     {
73
74       /* Our return register isn't zero for end of stack, so
75          check backward stackpointer to see if it is zero.  */
76       if (regs == NULL)
77          return _URC_END_OF_STACK;
78
79       /* No stack frame.  */
80       fs->regs.cfa_how = CFA_REG_OFFSET;
81       fs->regs.cfa_reg = 15;
82       fs->regs.cfa_offset = STACK_POINTER_OFFSET;
83
84       /* All registers remain unchanged ...  */
85       for (i = 0; i < 32; i++)
86         {
87           fs->regs.reg[i].how = REG_SAVED_REG;
88           fs->regs.reg[i].loc.reg = i;
89         }
90
91       /* ... except for %r14, which is stored at CFA-112
92          and used as return address.  */
93       fs->regs.reg[14].how = REG_SAVED_OFFSET;
94       fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET;
95       fs->retaddr_column = 14;
96
97       return _URC_NO_REASON;
98     }
99
100   regs = *((unsigned long int *)
101         (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
102   new_cfa = regs + STACK_POINTER_OFFSET;
103
104   fs->regs.cfa_how = CFA_REG_OFFSET;
105   fs->regs.cfa_reg = 15;
106   fs->regs.cfa_offset = new_cfa -
107         (unsigned long int) context->cfa + STACK_POINTER_OFFSET;
108
109   for (i = 0; i < 16; i++)
110     {
111       fs->regs.reg[i].how = REG_SAVED_OFFSET;
112       fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa;
113     }
114
115   for (i = 0; i < 4; i++)
116     {
117       fs->regs.reg[16 + i].how = REG_SAVED_OFFSET;
118       fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa;
119     }
120
121   fs->retaddr_column = 14;
122
123   return _URC_NO_REASON;
124 }
125
126 /* Function Name: __tpf_eh_return
127    Parameters passed into it: Destination address to jump to.
128    Return Value: Converted Destination address if a Pat Stub exists.
129    Description: This function swaps the unwinding return address
130       with the cp stub code.  The original target return address is
131       then stored into the tpf return address field.  The cp stub
132       code is searched for by climbing back up the stack and
133       comparing the tpf stored return address object address to
134       that of the targets object address.  */
135
136 #define CURRENT_STACK_PTR() \
137   ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; })
138
139 #define PREVIOUS_STACK_PTR() \
140   ((unsigned long int *)(*(CURRENT_STACK_PTR())))
141
142 #define RA_OFFSET 112
143 #define R15_OFFSET 120
144 #define TPFAREA_OFFSET 160
145 #define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
146 #define INVALID_RETURN 0
147
148 void * __tpf_eh_return (void *target);
149
150 void *
151 __tpf_eh_return (void *target)
152 {
153   Dl_info targetcodeInfo, currentcodeInfo;
154   int retval;
155   void *current, *stackptr, *destination_frame;
156   unsigned long int shifter, is_a_stub;
157
158   is_a_stub = 0;
159
160   /* Get code info for target return's address.  */
161   retval = dladdr (target, &targetcodeInfo);
162
163   /* Ensure the code info is valid (for target).  */
164   if (retval != INVALID_RETURN)
165     {
166
167       /* Get the stack pointer of the stack frame to be modified by
168          the exception unwinder.  So that we can begin our climb
169          there.  */
170       stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
171
172       /* Begin looping through stack frames.  Stop if invalid
173          code information is retrieved or if a match between the
174          current stack frame iteration shared object's address
175          matches that of the target, calculated above.  */
176       do
177         {
178           /* Get return address based on our stackptr iterator.  */
179           current = (void *) *((unsigned long int *)
180                       (stackptr+RA_OFFSET));
181
182           /* Is it a Pat Stub?  */
183           if (__isPATrange (current))
184             {
185               /* Yes it was, get real return address
186                  in TPF stack area.  */
187               current = (void *) *((unsigned long int *)
188                           (stackptr+TPFRA_OFFSET));
189               is_a_stub = 1;
190             }
191
192           /* Get codeinfo on RA so that we can figure out
193              the module address.  */
194           retval = dladdr (current, &currentcodeInfo);
195
196           /* Check that codeinfo for current stack frame is valid.
197              Then compare the module address of current stack frame
198              to target stack frame to determine if we have the pat
199              stub address we want.  Also ensure we are dealing
200              with a module crossing, stub return address. */
201           if (is_a_stub && retval != INVALID_RETURN
202              && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase)
203              {
204                /* Yes! They are in the same module.
205                   Force copy of TPF private stack area to
206                   destination stack frame TPF private area. */
207                destination_frame = (void *) *((unsigned long int *)
208                    (*PREVIOUS_STACK_PTR() + R15_OFFSET));
209
210                /* Copy TPF linkage area from current frame to
211                   destination frame.  */
212                memcpy((void *) (destination_frame + TPFAREA_OFFSET),
213                  (void *) (stackptr + TPFAREA_OFFSET), TPFAREA_SIZE);
214
215                /* Now overlay the
216                   real target address into the TPF stack area of
217                   the target frame we are jumping to.  */
218                *((unsigned long int *) (destination_frame +
219                    TPFRA_OFFSET)) = (unsigned long int) target;
220
221                /* Before returning the desired pat stub address to
222                   the exception handling unwinder so that it can
223                   actually do the "leap" shift out the low order
224                   bit designated to determine if we are in 64BIT mode.
225                   This is necessary for CTOA stubs.
226                   Otherwise we leap one byte past where we want to
227                   go to in the TPF pat stub linkage code.  */
228                shifter = *((unsigned long int *)
229                      (stackptr + RA_OFFSET));
230
231                shifter &= ~1ul;
232
233                /* Store Pat Stub Address in destination Stack Frame.  */
234                *((unsigned long int *) (destination_frame +
235                    RA_OFFSET)) = shifter;
236
237                /* Re-adjust pat stub address to go to correct place
238                   in linkage.  */
239                shifter = shifter - 4;
240
241                return (void *) shifter;
242              }
243
244           /* Desired module pat stub not found ...
245              Bump stack frame iterator.  */
246           stackptr = (void *) *(unsigned long int *) stackptr;
247
248           is_a_stub = 0;
249
250         }  while (stackptr && retval != INVALID_RETURN
251                 && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);
252     }
253
254   /* No pat stub found, could be a problem?  Simply return unmodified
255      target address.  */
256   return target;
257 }
258