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