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