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