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