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