]>
Commit | Line | Data |
---|---|---|
3ff688aa | 1 | /* DWARF2 EH unwinding support for TPF OS. |
4798630c D |
2 | Copyright (C) 2004 Free Software Foundation, Inc. |
3 | Contributed by P.J. Darcy (darcypj@us.ibm.com). | |
4 | ||
3ff688aa | 5 | This file is part of GCC. |
4798630c | 6 | |
3ff688aa D |
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. | |
4798630c | 11 | |
3ff688aa D |
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.) | |
4798630c | 20 | |
3ff688aa D |
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. | |
4798630c | 25 | |
3ff688aa D |
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 | |
28 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
29 | 02111-1307, USA. */ | |
4798630c D |
30 | |
31 | #define __USE_GNU 1 | |
32 | #define _GNU_SOURCE | |
33 | #include <dlfcn.h> | |
34 | #undef __USE_GNU | |
35 | #undef _GNU_SOURCE | |
36 | ||
4798630c D |
37 | /* Function Name: __isPATrange |
38 | Parameters passed into it: address to check | |
39 | Return Value: A 1 if address is in pat code "range", 0 if not | |
40 | Description: This function simply checks to see if the address | |
41 | passed to it is in the CP pat code range. */ | |
42 | ||
3ff688aa D |
43 | #define MIN_PATRANGE 0x10000 |
44 | #define MAX_PATRANGE 0x800000 | |
45 | ||
46 | static inline unsigned int | |
47 | __isPATrange (void *addr) | |
4798630c D |
48 | { |
49 | if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE) | |
50 | return 1; | |
51 | else | |
52 | return 0; | |
53 | } | |
54 | ||
3ff688aa D |
55 | /* TPF stack placeholder offset. */ |
56 | #define TPF_LOC_DIFF_OFFSET 168 | |
57 | ||
58 | /* Exceptions macro defined for TPF so that functions without | |
59 | dwarf frame information can be used with exceptions. */ | |
60 | #define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state | |
61 | ||
62 | static _Unwind_Reason_Code | |
63 | s390_fallback_frame_state (struct _Unwind_Context *context, | |
64 | _Unwind_FrameState *fs) | |
65 | { | |
66 | unsigned long int regs; | |
67 | unsigned long int new_cfa; | |
68 | int i; | |
69 | ||
70 | if (context->cfa == NULL) | |
71 | return _URC_END_OF_STACK; | |
72 | ||
73 | /* Are we going through special linkage code? */ | |
74 | if (__isPATrange (context->ra)) | |
75 | { | |
76 | /* No stack frame. */ | |
77 | fs->cfa_how = CFA_REG_OFFSET; | |
78 | fs->cfa_reg = 15; | |
79 | fs->cfa_offset = STACK_POINTER_OFFSET; | |
80 | ||
81 | /* All registers remain unchanged ... */ | |
82 | for (i = 0; i < 32; i++) | |
83 | { | |
84 | fs->regs.reg[i].how = REG_SAVED_REG; | |
85 | fs->regs.reg[i].loc.reg = i; | |
86 | } | |
87 | ||
88 | /* ... except for %r14, which is stored at CFA-112 | |
89 | and used as return address. */ | |
90 | fs->regs.reg[14].how = REG_SAVED_OFFSET; | |
91 | fs->regs.reg[14].loc.offset = TPF_LOC_DIFF_OFFSET - STACK_POINTER_OFFSET; | |
92 | fs->retaddr_column = 14; | |
93 | ||
94 | return _URC_NO_REASON; | |
95 | } | |
96 | ||
97 | regs = *((unsigned long int *) | |
98 | (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET)); | |
99 | new_cfa = regs + STACK_POINTER_OFFSET; | |
100 | ||
101 | fs->cfa_how = CFA_REG_OFFSET; | |
102 | fs->cfa_reg = 15; | |
103 | fs->cfa_offset = new_cfa - | |
104 | (unsigned long int) context->cfa + STACK_POINTER_OFFSET; | |
105 | ||
106 | for (i = 0; i < 16; i++) | |
107 | { | |
108 | fs->regs.reg[i].how = REG_SAVED_OFFSET; | |
109 | fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa; | |
110 | } | |
111 | ||
112 | for (i = 0; i < 4; i++) | |
113 | { | |
114 | fs->regs.reg[16 + i].how = REG_SAVED_OFFSET; | |
115 | fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa; | |
116 | } | |
117 | ||
118 | fs->retaddr_column = 14; | |
119 | ||
120 | return _URC_NO_REASON; | |
121 | } | |
122 | ||
4798630c D |
123 | /* Function Name: __tpf_eh_return |
124 | Parameters passed into it: Destination address to jump to. | |
125 | Return Value: Converted Destination address if a Pat Stub exists. | |
3ff688aa | 126 | Description: This function swaps the uwinding return address |
4798630c D |
127 | with the cp stub code. The original target return address is |
128 | then stored into the tpf return address field. The cp stub | |
129 | code is searched for by climbing back up the stack and | |
130 | comparing the tpf stored return address object address to | |
131 | that of the targets object address. */ | |
132 | ||
3ff688aa D |
133 | #define CURRENT_STACK_PTR() \ |
134 | ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; }) | |
135 | ||
136 | #define PREVIOUS_STACK_PTR() \ | |
137 | ((unsigned long int *)(*(CURRENT_STACK_PTR()))) | |
138 | ||
139 | #define RA_OFFSET_FROM_START_OF_STACK_FRAME 112 | |
140 | #define CURRENT_STACK_PTR_OFFSET 120 | |
141 | #define TPFRA_OFFSET_FROM_START_OF_STACK_FRAME 168 | |
142 | #define INVALID_RETURN 0 | |
143 | ||
144 | void * __tpf_eh_return (void *target); | |
145 | ||
146 | void * | |
147 | __tpf_eh_return (void *target) | |
4798630c D |
148 | { |
149 | Dl_info targetcodeInfo, currentcodeInfo; | |
150 | int retval; | |
151 | void *current, *stackptr; | |
152 | unsigned long int shifter; | |
153 | ||
154 | /* Get code info for target return's address. */ | |
155 | retval = dladdr (target, &targetcodeInfo); | |
156 | ||
157 | /* Get the return address of the stack frame to be replaced by | |
158 | the exception unwinder. So that the __cxa_throw return is | |
159 | replaced by the target return. */ | |
160 | current = (void *) *((unsigned long int *) | |
161 | ((*((unsigned long int *)*(PREVIOUS_STACK_PTR()))) | |
162 | + RA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
163 | ||
164 | /* Ensure the code info is valid (for target). */ | |
165 | if (retval != INVALID_RETURN) | |
166 | { | |
167 | /* Now check to see if the current RA is a PAT | |
168 | stub return address. */ | |
169 | if ( __isPATrange(current)) | |
170 | { | |
171 | /* It was! Then go into the TPF private stack area and fetch | |
172 | the real address. */ | |
173 | current = (void *) *((unsigned long int *) | |
174 | ((unsigned long int)*((unsigned long int *) | |
175 | *(PREVIOUS_STACK_PTR())) | |
176 | +TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
177 | } | |
178 | ||
179 | /* Get code info for current return address. */ | |
180 | retval = dladdr (current, ¤tcodeInfo); | |
181 | ||
182 | /* Ensure the code info is valid (for current frame). */ | |
183 | if (retval != INVALID_RETURN) | |
184 | { | |
185 | /* Get the stack pointer of the stack frame to be replaced by | |
186 | the exception unwinder. So that we can begin our climb | |
187 | there. */ | |
188 | stackptr = (void *) (*((unsigned long int *) | |
189 | (*((unsigned long int *)(*(PREVIOUS_STACK_PTR())))))); | |
190 | ||
191 | /* Begin looping through stack frames. Stop if invalid | |
192 | code information is retrieved or if a match between the | |
193 | current stack frame iteration shared object's address | |
194 | matches that of the target, calculated above. */ | |
195 | while (retval != INVALID_RETURN | |
196 | && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase) | |
197 | { | |
198 | /* Get return address based on our stackptr iterator. */ | |
199 | current = (void *) *((unsigned long int *) | |
200 | (stackptr+RA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
201 | ||
202 | /* Is it a Pat Stub? */ | |
203 | if (__isPATrange (current)) | |
204 | { | |
205 | /* Yes it was, get real return address | |
206 | in TPF stack area. */ | |
207 | current = (void *) *((unsigned long int *) | |
208 | (stackptr+TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
209 | } | |
210 | ||
211 | /* Get codeinfo on RA so that we can figure out | |
212 | the module address. */ | |
213 | retval = dladdr (current, ¤tcodeInfo); | |
214 | ||
215 | /* Check that codeinfo for current stack frame is valid. | |
216 | Then compare the module address of current stack frame | |
217 | to target stack frame to determine if we have the pat | |
218 | stub address we want. */ | |
219 | if (retval != INVALID_RETURN | |
220 | && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase) | |
221 | { | |
222 | /* Yes! They are in the same module. Now store the | |
223 | real target address into the TPF stack area of | |
224 | the target frame we are jumping to. */ | |
225 | *((unsigned long int *)(*((unsigned long int *) | |
226 | (*PREVIOUS_STACK_PTR() + CURRENT_STACK_PTR_OFFSET)) | |
227 | + TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)) | |
228 | = (unsigned long int) target; | |
229 | ||
230 | /* Before returning the desired pat stub address to | |
231 | the exception handling unwinder so that it can | |
232 | actually do the "leap" shift out the low order | |
233 | bit designated to determine if we are in 64BIT mode. | |
3ff688aa | 234 | This is nececcary for CTOA stubs. |
4798630c D |
235 | Otherwise we leap one byte past where we want to |
236 | go to in the TPF pat stub linkage code. */ | |
237 | shifter = *((unsigned long int *) | |
238 | (stackptr + RA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
239 | ||
240 | shifter &= ~1ul; | |
241 | ||
242 | return (void *) shifter; | |
243 | } | |
244 | ||
245 | /* Desired module pat stub not found ... | |
246 | Bump stack frame iterator. */ | |
247 | stackptr = (void *) *(unsigned long int *) stackptr; | |
248 | } | |
249 | } | |
250 | } | |
251 | ||
252 | /* No pat stub found, could be a problem? Simply return unmodified | |
253 | target address. */ | |
254 | return target; | |
255 | } | |
256 | ||
3ff688aa | 257 |