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