]>
Commit | Line | Data |
---|---|---|
4798630c D |
1 | /* Exception handling routines for TPF. |
2 | Copyright (C) 2004 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 | |
8 | under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | In addition to the permissions in the GNU General Public License, the | |
13 | Free Software Foundation gives you unlimited permission to link the | |
14 | compiled version of this file into combinations with other programs, | |
15 | and to distribute those combinations without any restriction coming | |
16 | from the use of this file. (The General Public License restrictions | |
17 | do apply in other respects; for example, they cover modification of | |
18 | the file, and distribution when not linked into a combined | |
19 | executable.) | |
20 | ||
21 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
22 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
23 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
24 | License for more details. | |
25 | ||
26 | You should have received a copy of the GNU General Public License | |
27 | along with GCC; see the file COPYING. If not, write to the Free | |
28 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
29 | 02111-1307, USA. */ | |
30 | ||
31 | #define __USE_GNU 1 | |
32 | #define _GNU_SOURCE | |
33 | #include <dlfcn.h> | |
34 | #undef __USE_GNU | |
35 | #undef _GNU_SOURCE | |
36 | ||
37 | #define CURRENT_STACK_PTR() \ | |
38 | ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; }) | |
39 | ||
40 | #define PREVIOUS_STACK_PTR() \ | |
41 | ((unsigned long int *)(*(CURRENT_STACK_PTR()))) | |
42 | ||
43 | #define RA_OFFSET_FROM_START_OF_STACK_FRAME 112 | |
44 | #define CURRENT_STACK_PTR_OFFSET 120 | |
45 | #define TPFRA_OFFSET_FROM_START_OF_STACK_FRAME 168 | |
46 | #define MIN_PATRANGE 0x10000 | |
47 | #define MAX_PATRANGE 0x800000 | |
48 | #define INVALID_RETURN 0 | |
49 | ||
50 | /* Function Name: __isPATrange | |
51 | Parameters passed into it: address to check | |
52 | Return Value: A 1 if address is in pat code "range", 0 if not | |
53 | Description: This function simply checks to see if the address | |
54 | passed to it is in the CP pat code range. */ | |
55 | ||
56 | unsigned int __isPATrange(void *addr) | |
57 | { | |
58 | if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE) | |
59 | return 1; | |
60 | else | |
61 | return 0; | |
62 | } | |
63 | ||
64 | /* Function Name: __tpf_eh_return | |
65 | Parameters passed into it: Destination address to jump to. | |
66 | Return Value: Converted Destination address if a Pat Stub exists. | |
67 | Description: This function swaps the uwinding return address | |
68 | with the cp stub code. The original target return address is | |
69 | then stored into the tpf return address field. The cp stub | |
70 | code is searched for by climbing back up the stack and | |
71 | comparing the tpf stored return address object address to | |
72 | that of the targets object address. */ | |
73 | ||
74 | void *__tpf_eh_return (void *target) | |
75 | { | |
76 | Dl_info targetcodeInfo, currentcodeInfo; | |
77 | int retval; | |
78 | void *current, *stackptr; | |
79 | unsigned long int shifter; | |
80 | ||
81 | /* Get code info for target return's address. */ | |
82 | retval = dladdr (target, &targetcodeInfo); | |
83 | ||
84 | /* Get the return address of the stack frame to be replaced by | |
85 | the exception unwinder. So that the __cxa_throw return is | |
86 | replaced by the target return. */ | |
87 | current = (void *) *((unsigned long int *) | |
88 | ((*((unsigned long int *)*(PREVIOUS_STACK_PTR()))) | |
89 | + RA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
90 | ||
91 | /* Ensure the code info is valid (for target). */ | |
92 | if (retval != INVALID_RETURN) | |
93 | { | |
94 | /* Now check to see if the current RA is a PAT | |
95 | stub return address. */ | |
96 | if ( __isPATrange(current)) | |
97 | { | |
98 | /* It was! Then go into the TPF private stack area and fetch | |
99 | the real address. */ | |
100 | current = (void *) *((unsigned long int *) | |
101 | ((unsigned long int)*((unsigned long int *) | |
102 | *(PREVIOUS_STACK_PTR())) | |
103 | +TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
104 | } | |
105 | ||
106 | /* Get code info for current return address. */ | |
107 | retval = dladdr (current, ¤tcodeInfo); | |
108 | ||
109 | /* Ensure the code info is valid (for current frame). */ | |
110 | if (retval != INVALID_RETURN) | |
111 | { | |
112 | /* Get the stack pointer of the stack frame to be replaced by | |
113 | the exception unwinder. So that we can begin our climb | |
114 | there. */ | |
115 | stackptr = (void *) (*((unsigned long int *) | |
116 | (*((unsigned long int *)(*(PREVIOUS_STACK_PTR())))))); | |
117 | ||
118 | /* Begin looping through stack frames. Stop if invalid | |
119 | code information is retrieved or if a match between the | |
120 | current stack frame iteration shared object's address | |
121 | matches that of the target, calculated above. */ | |
122 | while (retval != INVALID_RETURN | |
123 | && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase) | |
124 | { | |
125 | /* Get return address based on our stackptr iterator. */ | |
126 | current = (void *) *((unsigned long int *) | |
127 | (stackptr+RA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
128 | ||
129 | /* Is it a Pat Stub? */ | |
130 | if (__isPATrange (current)) | |
131 | { | |
132 | /* Yes it was, get real return address | |
133 | in TPF stack area. */ | |
134 | current = (void *) *((unsigned long int *) | |
135 | (stackptr+TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
136 | } | |
137 | ||
138 | /* Get codeinfo on RA so that we can figure out | |
139 | the module address. */ | |
140 | retval = dladdr (current, ¤tcodeInfo); | |
141 | ||
142 | /* Check that codeinfo for current stack frame is valid. | |
143 | Then compare the module address of current stack frame | |
144 | to target stack frame to determine if we have the pat | |
145 | stub address we want. */ | |
146 | if (retval != INVALID_RETURN | |
147 | && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase) | |
148 | { | |
149 | /* Yes! They are in the same module. Now store the | |
150 | real target address into the TPF stack area of | |
151 | the target frame we are jumping to. */ | |
152 | *((unsigned long int *)(*((unsigned long int *) | |
153 | (*PREVIOUS_STACK_PTR() + CURRENT_STACK_PTR_OFFSET)) | |
154 | + TPFRA_OFFSET_FROM_START_OF_STACK_FRAME)) | |
155 | = (unsigned long int) target; | |
156 | ||
157 | /* Before returning the desired pat stub address to | |
158 | the exception handling unwinder so that it can | |
159 | actually do the "leap" shift out the low order | |
160 | bit designated to determine if we are in 64BIT mode. | |
161 | This is nececcary for CTOA stubs. | |
162 | Otherwise we leap one byte past where we want to | |
163 | go to in the TPF pat stub linkage code. */ | |
164 | shifter = *((unsigned long int *) | |
165 | (stackptr + RA_OFFSET_FROM_START_OF_STACK_FRAME)); | |
166 | ||
167 | shifter &= ~1ul; | |
168 | ||
169 | return (void *) shifter; | |
170 | } | |
171 | ||
172 | /* Desired module pat stub not found ... | |
173 | Bump stack frame iterator. */ | |
174 | stackptr = (void *) *(unsigned long int *) stackptr; | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
179 | /* No pat stub found, could be a problem? Simply return unmodified | |
180 | target address. */ | |
181 | return target; | |
182 | } | |
183 |