Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/s390/tpf-unwind.h @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 77e2b8dfacca |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
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 /* Function Name: __isPATrange | |
29 Parameters passed into it: address to check | |
30 Return Value: A 1 if address is in pat code "range", 0 if not | |
31 Description: This function simply checks to see if the address | |
32 passed to it is in the CP pat code range. */ | |
33 | |
34 #define MIN_PATRANGE 0x10000 | |
35 #define MAX_PATRANGE 0x800000 | |
36 | |
37 static inline unsigned int | |
38 __isPATrange (void *addr) | |
39 { | |
40 if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE) | |
41 return 1; | |
42 else | |
43 return 0; | |
44 } | |
45 | |
46 /* TPF return address offset from start of stack frame. */ | |
47 #define TPFRA_OFFSET 168 | |
48 | |
49 /* Exceptions macro defined for TPF so that functions without | |
50 dwarf frame information can be used with exceptions. */ | |
51 #define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state | |
52 | |
53 static _Unwind_Reason_Code | |
54 s390_fallback_frame_state (struct _Unwind_Context *context, | |
55 _Unwind_FrameState *fs) | |
56 { | |
57 unsigned long int regs; | |
58 unsigned long int new_cfa; | |
59 int i; | |
60 | |
61 regs = *((unsigned long int *) | |
62 (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET)); | |
63 | |
64 /* Are we going through special linkage code? */ | |
65 if (__isPATrange (context->ra)) | |
66 { | |
67 | |
68 /* Our return register isn't zero for end of stack, so | |
69 check backward stackpointer to see if it is zero. */ | |
70 if (regs == NULL) | |
71 return _URC_END_OF_STACK; | |
72 | |
73 /* No stack frame. */ | |
74 fs->regs.cfa_how = CFA_REG_OFFSET; | |
75 fs->regs.cfa_reg = 15; | |
76 fs->regs.cfa_offset = STACK_POINTER_OFFSET; | |
77 | |
78 /* All registers remain unchanged ... */ | |
79 for (i = 0; i < 32; i++) | |
80 { | |
81 fs->regs.reg[i].how = REG_SAVED_REG; | |
82 fs->regs.reg[i].loc.reg = i; | |
83 } | |
84 | |
85 /* ... except for %r14, which is stored at CFA-112 | |
86 and used as return address. */ | |
87 fs->regs.reg[14].how = REG_SAVED_OFFSET; | |
88 fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET; | |
89 fs->retaddr_column = 14; | |
90 | |
91 return _URC_NO_REASON; | |
92 } | |
93 | |
94 regs = *((unsigned long int *) | |
95 (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET)); | |
96 new_cfa = regs + STACK_POINTER_OFFSET; | |
97 | |
98 fs->regs.cfa_how = CFA_REG_OFFSET; | |
99 fs->regs.cfa_reg = 15; | |
100 fs->regs.cfa_offset = new_cfa - | |
101 (unsigned long int) context->cfa + STACK_POINTER_OFFSET; | |
102 | |
103 for (i = 0; i < 16; i++) | |
104 { | |
105 fs->regs.reg[i].how = REG_SAVED_OFFSET; | |
106 fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa; | |
107 } | |
108 | |
109 for (i = 0; i < 4; i++) | |
110 { | |
111 fs->regs.reg[16 + i].how = REG_SAVED_OFFSET; | |
112 fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa; | |
113 } | |
114 | |
115 fs->retaddr_column = 14; | |
116 | |
117 return _URC_NO_REASON; | |
118 } | |
119 | |
120 /* Function Name: __tpf_eh_return | |
121 Parameters passed into it: Destination address to jump to. | |
122 Return Value: Converted Destination address if a Pat Stub exists. | |
123 Description: This function swaps the unwinding return address | |
124 with the cp stub code. The original target return address is | |
125 then stored into the tpf return address field. The cp stub | |
126 code is searched for by climbing back up the stack and | |
127 comparing the tpf stored return address object address to | |
128 that of the targets object address. */ | |
129 | |
130 #define CURRENT_STACK_PTR() \ | |
131 ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; }) | |
132 | |
133 #define PREVIOUS_STACK_PTR() \ | |
134 ((unsigned long int *)(*(CURRENT_STACK_PTR()))) | |
135 | |
136 #define RA_OFFSET 112 | |
137 #define R15_OFFSET 120 | |
138 #define TPFAREA_OFFSET 160 | |
139 #define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET | |
140 #define INVALID_RETURN 0 | |
141 | |
142 void * __tpf_eh_return (void *target); | |
143 | |
144 void * | |
145 __tpf_eh_return (void *target) | |
146 { | |
147 Dl_info targetcodeInfo, currentcodeInfo; | |
148 int retval; | |
149 void *current, *stackptr, *destination_frame; | |
150 unsigned long int shifter, is_a_stub; | |
151 | |
152 is_a_stub = 0; | |
153 | |
154 /* Get code info for target return's address. */ | |
155 retval = dladdr (target, &targetcodeInfo); | |
156 | |
157 /* Ensure the code info is valid (for target). */ | |
158 if (retval != INVALID_RETURN) | |
159 { | |
160 | |
161 /* Get the stack pointer of the stack frame to be modified by | |
162 the exception unwinder. So that we can begin our climb | |
163 there. */ | |
164 stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR()))); | |
165 | |
166 /* Begin looping through stack frames. Stop if invalid | |
167 code information is retrieved or if a match between the | |
168 current stack frame iteration shared object's address | |
169 matches that of the target, calculated above. */ | |
170 do | |
171 { | |
172 /* Get return address based on our stackptr iterator. */ | |
173 current = (void *) *((unsigned long int *) | |
174 (stackptr+RA_OFFSET)); | |
175 | |
176 /* Is it a Pat Stub? */ | |
177 if (__isPATrange (current)) | |
178 { | |
179 /* Yes it was, get real return address | |
180 in TPF stack area. */ | |
181 current = (void *) *((unsigned long int *) | |
182 (stackptr+TPFRA_OFFSET)); | |
183 is_a_stub = 1; | |
184 } | |
185 | |
186 /* Get codeinfo on RA so that we can figure out | |
187 the module address. */ | |
188 retval = dladdr (current, ¤tcodeInfo); | |
189 | |
190 /* Check that codeinfo for current stack frame is valid. | |
191 Then compare the module address of current stack frame | |
192 to target stack frame to determine if we have the pat | |
193 stub address we want. Also ensure we are dealing | |
194 with a module crossing, stub return address. */ | |
195 if (is_a_stub && retval != INVALID_RETURN | |
196 && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase) | |
197 { | |
198 /* Yes! They are in the same module. | |
199 Force copy of TPF private stack area to | |
200 destination stack frame TPF private area. */ | |
201 destination_frame = (void *) *((unsigned long int *) | |
202 (*PREVIOUS_STACK_PTR() + R15_OFFSET)); | |
203 | |
204 /* Copy TPF linkage area from current frame to | |
205 destination frame. */ | |
206 memcpy((void *) (destination_frame + TPFAREA_OFFSET), | |
207 (void *) (stackptr + TPFAREA_OFFSET), TPFAREA_SIZE); | |
208 | |
209 /* Now overlay the | |
210 real target address into the TPF stack area of | |
211 the target frame we are jumping to. */ | |
212 *((unsigned long int *) (destination_frame + | |
213 TPFRA_OFFSET)) = (unsigned long int) target; | |
214 | |
215 /* Before returning the desired pat stub address to | |
216 the exception handling unwinder so that it can | |
217 actually do the "leap" shift out the low order | |
218 bit designated to determine if we are in 64BIT mode. | |
219 This is necessary for CTOA stubs. | |
220 Otherwise we leap one byte past where we want to | |
221 go to in the TPF pat stub linkage code. */ | |
222 shifter = *((unsigned long int *) | |
223 (stackptr + RA_OFFSET)); | |
224 | |
225 shifter &= ~1ul; | |
226 | |
227 /* Store Pat Stub Address in destination Stack Frame. */ | |
228 *((unsigned long int *) (destination_frame + | |
229 RA_OFFSET)) = shifter; | |
230 | |
231 /* Re-adjust pat stub address to go to correct place | |
232 in linkage. */ | |
233 shifter = shifter - 4; | |
234 | |
235 return (void *) shifter; | |
236 } | |
237 | |
238 /* Desired module pat stub not found ... | |
239 Bump stack frame iterator. */ | |
240 stackptr = (void *) *(unsigned long int *) stackptr; | |
241 | |
242 is_a_stub = 0; | |
243 | |
244 } while (stackptr && retval != INVALID_RETURN | |
245 && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase); | |
246 } | |
247 | |
248 /* No pat stub found, could be a problem? Simply return unmodified | |
249 target address. */ | |
250 return target; | |
251 } | |
252 |