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