]>
Commit | Line | Data |
---|---|---|
3ff688aa | 1 | /* DWARF2 EH unwinding support for TPF OS. |
5d5bf775 | 2 | Copyright (C) 2004-2013 Free Software Foundation, Inc. |
4798630c D |
3 | Contributed by P.J. Darcy (darcypj@us.ibm.com). |
4 | ||
3ff688aa | 5 | This file is part of GCC. |
4798630c | 6 | |
3ff688aa D |
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 | |
748086b7 | 9 | Software Foundation; either version 3, or (at your option) any later |
3ff688aa | 10 | version. |
4798630c | 11 | |
3ff688aa D |
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. | |
4798630c | 16 | |
748086b7 JJ |
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/>. */ | |
4798630c | 25 | |
4798630c | 26 | #include <dlfcn.h> |
4798630c | 27 | |
4798630c D |
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 | ||
3ff688aa D |
34 | #define MIN_PATRANGE 0x10000 |
35 | #define MAX_PATRANGE 0x800000 | |
36 | ||
37 | static inline unsigned int | |
38 | __isPATrange (void *addr) | |
4798630c D |
39 | { |
40 | if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE) | |
41 | return 1; | |
42 | else | |
43 | return 0; | |
44 | } | |
45 | ||
783d2650 J |
46 | /* TPF return address offset from start of stack frame. */ |
47 | #define TPFRA_OFFSET 168 | |
3ff688aa | 48 | |
f4aa3848 | 49 | /* Exceptions macro defined for TPF so that functions without |
3ff688aa D |
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 | ||
783d2650 J |
61 | regs = *((unsigned long int *) |
62 | (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET)); | |
3ff688aa D |
63 | |
64 | /* Are we going through special linkage code? */ | |
65 | if (__isPATrange (context->ra)) | |
66 | { | |
783d2650 J |
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 | ||
3ff688aa | 73 | /* No stack frame. */ |
6673f90b NF |
74 | fs->regs.cfa_how = CFA_REG_OFFSET; |
75 | fs->regs.cfa_reg = 15; | |
76 | fs->regs.cfa_offset = STACK_POINTER_OFFSET; | |
3ff688aa D |
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; | |
783d2650 | 88 | fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET; |
3ff688aa D |
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 | ||
6673f90b NF |
98 | fs->regs.cfa_how = CFA_REG_OFFSET; |
99 | fs->regs.cfa_reg = 15; | |
100 | fs->regs.cfa_offset = new_cfa - | |
3ff688aa D |
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 | ||
4798630c D |
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. | |
66efeafc | 123 | Description: This function swaps the unwinding return address |
4798630c D |
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 | ||
3ff688aa D |
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 | ||
783d2650 J |
136 | #define RA_OFFSET 112 |
137 | #define R15_OFFSET 120 | |
138 | #define TPFAREA_OFFSET 160 | |
139 | #define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET | |
3ff688aa D |
140 | #define INVALID_RETURN 0 |
141 | ||
142 | void * __tpf_eh_return (void *target); | |
143 | ||
144 | void * | |
145 | __tpf_eh_return (void *target) | |
4798630c D |
146 | { |
147 | Dl_info targetcodeInfo, currentcodeInfo; | |
148 | int retval; | |
783d2650 J |
149 | void *current, *stackptr, *destination_frame; |
150 | unsigned long int shifter, is_a_stub; | |
151 | ||
152 | is_a_stub = 0; | |
4798630c D |
153 | |
154 | /* Get code info for target return's address. */ | |
155 | retval = dladdr (target, &targetcodeInfo); | |
156 | ||
4798630c | 157 | /* Ensure the code info is valid (for target). */ |
783d2650 | 158 | if (retval != INVALID_RETURN) |
4798630c | 159 | { |
4798630c | 160 | |
783d2650 J |
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()))); | |
4798630c | 165 | |
783d2650 J |
166 | /* Begin looping through stack frames. Stop if invalid |
167 | code information is retrieved or if a match between the | |
f4aa3848 | 168 | current stack frame iteration shared object's address |
783d2650 J |
169 | matches that of the target, calculated above. */ |
170 | do | |
4798630c | 171 | { |
783d2650 | 172 | /* Get return address based on our stackptr iterator. */ |
f4aa3848 | 173 | current = (void *) *((unsigned long int *) |
783d2650 J |
174 | (stackptr+RA_OFFSET)); |
175 | ||
176 | /* Is it a Pat Stub? */ | |
f4aa3848 | 177 | if (__isPATrange (current)) |
4798630c | 178 | { |
f4aa3848 | 179 | /* Yes it was, get real return address |
783d2650 | 180 | in TPF stack area. */ |
f4aa3848 | 181 | current = (void *) *((unsigned long int *) |
783d2650 J |
182 | (stackptr+TPFRA_OFFSET)); |
183 | is_a_stub = 1; | |
4798630c | 184 | } |
783d2650 J |
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. */ | |
f4aa3848 | 201 | destination_frame = (void *) *((unsigned long int *) |
783d2650 J |
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. */ | |
f4aa3848 | 212 | *((unsigned long int *) (destination_frame + |
783d2650 J |
213 | TPFRA_OFFSET)) = (unsigned long int) target; |
214 | ||
215 | /* Before returning the desired pat stub address to | |
f4aa3848 AK |
216 | the exception handling unwinder so that it can |
217 | actually do the "leap" shift out the low order | |
783d2650 J |
218 | bit designated to determine if we are in 64BIT mode. |
219 | This is necessary for CTOA stubs. | |
f4aa3848 | 220 | Otherwise we leap one byte past where we want to |
783d2650 | 221 | go to in the TPF pat stub linkage code. */ |
f4aa3848 | 222 | shifter = *((unsigned long int *) |
783d2650 J |
223 | (stackptr + RA_OFFSET)); |
224 | ||
225 | shifter &= ~1ul; | |
226 | ||
227 | /* Store Pat Stub Address in destination Stack Frame. */ | |
228 | *((unsigned long int *) (destination_frame + | |
f4aa3848 | 229 | RA_OFFSET)) = shifter; |
783d2650 J |
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); | |
4798630c D |
246 | } |
247 | ||
248 | /* No pat stub found, could be a problem? Simply return unmodified | |
249 | target address. */ | |
250 | return target; | |
251 | } | |
252 |