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