1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <proc_service.h>
28 #include <link.h>
29 #include <rtld_db.h>
30 #include <_rtld_db.h>
31 #include <msg.h>
32
33 /*
34 * A un-initialized SPARCV9 PLT look like so:
35 *
36 * .PLT
37 * sethi (. - .PLT0), %g1
38 * ba,a %xcc, .PLT1
39 * nop
40 * nop
41 * nop
42 * nop
43 * nop
44 * nop
45 *
46 * To test to see if this is an uninitialized PLT we check
47 * the second instruction and confirm that it's a branch.
48 */
49 /* ARGSUSED 2 */
50 rd_err_e
plt64_resolution(rd_agent_t * rap,psaddr_t pc,lwpid_t lwpid,psaddr_t pltbase,rd_plt_info_t * rpi)51 plt64_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid,
52 psaddr_t pltbase, rd_plt_info_t *rpi)
53 {
54 instr_t instr[8];
55 rd_err_e rerr;
56 psaddr_t destaddr = 0;
57 psaddr_t pltoff;
58 int pltbound = 0;
59
60 if (rtld_db_version >= RD_VERSION3) {
61 rpi->pi_flags = 0;
62 rpi->pi_baddr = 0;
63 }
64
65 pltoff = pc - pltbase;
66
67 if (pltoff >= (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE)) {
68 psaddr_t pltptr, pltptrval;
69 psaddr_t pltaddr;
70 psaddr_t pltblockoff;
71
72 /*
73 * Handle far PLT's
74 *
75 * .PLT#
76 * 0 mov %o7, %g5
77 * 1 call . + 8
78 * 2 nop
79 * 3 ldx [%o7 + (.PLTP# - .PLT#+4)], %g1
80 * 4 jmpl %o7 + %g1, %g1
81 * 5 mov %g5, %o7
82 */
83
84 pltblockoff = pltoff - (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE);
85 pltblockoff =
86 ((pltblockoff / M64_PLT_FBLOCKSZ) * M64_PLT_FBLOCKSZ) +
87 (((pltblockoff % M64_PLT_FBLOCKSZ) / M64_PLT_FENTSIZE) *
88 M64_PLT_FENTSIZE);
89
90
91 pltaddr = pltbase + (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE) +
92 pltblockoff;
93
94 if (ps_pread(rap->rd_psp, pltaddr, (char *)instr,
95 M64_PLT_FENTSIZE) != PS_OK) {
96 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2),
97 EC_ADDR(pltaddr)));
98 return (RD_ERR);
99
100 }
101
102 if (instr[0] != M_MOVO7TOG5) {
103 LOG(ps_plog(MSG_ORIG(MSG_DB_BADFPLT),
104 EC_ADDR(pltaddr), EC_ADDR(instr[0])));
105 return (RD_ERR);
106 }
107
108 /*
109 * the offset is a positive displacement from the
110 * ldx [%o7 + #], %g1 instruction. So - we don't
111 * need to worry about the sign bit :)
112 */
113 pltptr = instr[3] & S_MASK(12);
114 pltptr += pltaddr + 4;
115 /*
116 * Load the pltptr to determine whether it is
117 * pointing to .PLT0 or to the final
118 * destination.
119 */
120 if (ps_pread(rap->rd_psp, pltptr, &pltptrval,
121 sizeof (long long)) != PS_OK) {
122 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2),
123 EC_ADDR(pltptr)));
124 return (RD_ERR);
125 }
126 pltptrval += pltaddr + 4;
127 if (pltptrval == pltbase) {
128 if ((rerr = rd_binder_exit_addr(rap,
129 MSG_ORIG(MSG_SYM_RTBIND),
130 &(rpi->pi_target))) != RD_OK) {
131 return (rerr);
132 }
133 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP;
134 rpi->pi_nstep = 1;
135 } else {
136 rpi->pi_skip_method = RD_RESOLVE_STEP;
137 rpi->pi_nstep = 6;
138 rpi->pi_target = 0;
139 if (rtld_db_version >= RD_VERSION3) {
140 destaddr = pltptrval;
141 pltbound++;
142 }
143 }
144 } else {
145 psaddr_t pltaddr;
146
147 pltaddr = pltbase +
148 ((pltoff / M64_PLT_ENTSIZE) * M64_PLT_ENTSIZE);
149
150 if (ps_pread(rap->rd_psp, pltaddr, (char *)instr,
151 M64_PLT_ENTSIZE) != PS_OK) {
152 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2),
153 EC_ADDR(pltaddr)));
154 return (RD_ERR);
155
156 }
157 /*
158 * ELF64 NEAR PLT's
159 */
160 if ((instr[0] != M_NOP) &&
161 ((instr[1] & (~(S_MASK(19)))) == M_BA_A_XCC)) {
162 /*
163 * Unbound PLT
164 */
165 if ((rerr = rd_binder_exit_addr(rap,
166 MSG_ORIG(MSG_SYM_RTBIND),
167 &(rpi->pi_target))) != RD_OK) {
168 return (rerr);
169 }
170 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP;
171 rpi->pi_nstep = 1;
172 } else if ((instr[0] == M_NOP) &&
173 ((instr[1] & (~(S_MASK(22)))) == M_BA_A)) {
174 /*
175 * Resolved 64-bit PLT entry format (b+-8mb):
176 * .PLT
177 * 0 nop
178 * 1 ba,a <dest>
179 * 2 nop
180 * 3 nop
181 * 4 nop
182 * 5 nop
183 * 6 nop
184 * 7 nop
185 */
186 rpi->pi_skip_method = RD_RESOLVE_STEP;
187 rpi->pi_nstep = 2;
188 rpi->pi_target = 0;
189 if (rtld_db_version >= RD_VERSION3) {
190 uint_t d22;
191 d22 = instr[1] & S_MASK(22);
192 /* LINTED */
193 destaddr = ((long)pltaddr + 4) +
194 /* LINTED */
195 (((int)d22 << 10) >> 8);
196 pltbound++;
197 }
198 } else if ((instr[0] == M_NOP) &&
199 ((instr[1] & (~(S_MASK(19)))) == M_BA_A_PT)) {
200 /*
201 * Resolved 64-bit PLT entry format (b+-2mb):
202 * .PLT
203 * 0 nop
204 * 1 ba,a,pt %icc, <dest>
205 * 2 nop
206 * 3 nop
207 * 4 nop
208 * 5 nop
209 * 6 nop
210 * 7 nop
211 */
212 rpi->pi_skip_method = RD_RESOLVE_STEP;
213 rpi->pi_nstep = 2;
214 rpi->pi_target = 0;
215 if (rtld_db_version >= RD_VERSION3) {
216 uint_t d19;
217 d19 = instr[1] & S_MASK(22);
218 /* LINTED */
219 destaddr = ((long)pltaddr + 4) +
220 /* LINTED */
221 (((int)d19 << 13) >> 11);
222 pltbound++;
223 }
224 } else if ((instr[6] & (~(S_MASK(13)))) == M_JMPL_G5G0) {
225 /*
226 * Resolved 64-bit PLT entry format (abs-64):
227 * .PLT
228 * 0 nop
229 * 1 sethi %hh(dest), %g1
230 * 2 sethi %lm(dest), %g5
231 * 3 or %g1, %hm(dest), %g1
232 * 4 sllx %g1, 32, %g1
233 * 5 or %g1, %g5, %g5
234 * 6 jmpl %g5 + %lo(dest), %g0
235 * 7 nop
236 */
237 rpi->pi_skip_method = RD_RESOLVE_STEP;
238 rpi->pi_nstep = 8;
239 rpi->pi_target = 0;
240 if (rtld_db_version >= RD_VERSION3) {
241 uintptr_t hh_bits;
242 uintptr_t hm_bits;
243 uintptr_t lm_bits;
244 uintptr_t lo_bits;
245 hh_bits = instr[1] & S_MASK(22); /* 63..42 */
246 hm_bits = instr[3] & S_MASK(10); /* 41..32 */
247 lm_bits = instr[2] & S_MASK(22); /* 31..10 */
248 lo_bits = instr[6] & S_MASK(10); /* 09..00 */
249 destaddr = (hh_bits << 42) | (hm_bits << 32) |
250 (lm_bits << 10) | lo_bits;
251 pltbound++;
252 }
253 } else if (instr[3] == M_JMPL) {
254 /*
255 * Resolved 64-bit PLT entry format (top-32):
256 *
257 * .PLT:
258 * 0 nop
259 * 1 sethi %hi(~dest), %g5
260 * 2 xnor %g5, %lo(~dest), %g1
261 * 3 jmpl %g1, %g0
262 * 4 nop
263 * 5 nop
264 * 6 nop
265 * 7 nop
266 */
267 rpi->pi_skip_method = RD_RESOLVE_STEP;
268 rpi->pi_nstep = 5;
269 rpi->pi_target = 0;
270 if (rtld_db_version >= RD_VERSION3) {
271 uintptr_t hi_bits;
272 uintptr_t lo_bits;
273 hi_bits = (instr[1] & S_MASK(22)) << 10;
274 lo_bits = (instr[2] & S_MASK(10));
275 destaddr = hi_bits ^ ~lo_bits;
276 pltbound++;
277 }
278 } else if ((instr[2] & (~(S_MASK(13)))) == M_XNOR_G5G1) {
279 /*
280 * Resolved 64-bit PLT entry format (top-44):
281 *
282 * .PLT:
283 * 0 nop
284 * 1 sethi %h44(~dest), %g5
285 * 2 xnor %g5, %m44(~dest), %g1
286 * 3 slxx %g1, 12, %g1
287 * 4 jmpl %g1 + %l44(dest), %g0
288 * 5 nop
289 * 6 nop
290 * 7 nop
291 */
292 rpi->pi_skip_method = RD_RESOLVE_STEP;
293 rpi->pi_nstep = 6;
294 rpi->pi_target = 0;
295 if (rtld_db_version >= RD_VERSION3) {
296 uintptr_t h44_bits;
297 uintptr_t m44_bits;
298 uintptr_t l44_bits;
299 h44_bits = (((long)instr[1] & S_MASK(22))
300 << 10);
301 m44_bits = (((long)instr[2] & S_MASK(13))
302 << 41) >> 41;
303 l44_bits = (((long)instr[4] & S_MASK(13))
304 << 41) >> 41;
305 destaddr = (~(h44_bits ^ m44_bits) << 12)
306 + l44_bits;
307 pltbound++;
308 }
309 } else
310 rpi->pi_skip_method = RD_RESOLVE_NONE;
311 }
312
313 if ((rtld_db_version >= RD_VERSION3) && pltbound) {
314 rpi->pi_flags |= RD_FLG_PI_PLTBOUND;
315 rpi->pi_baddr = destaddr;
316 }
317
318 return (RD_OK);
319 }
320