8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / cmd / sgs / librtld_db / sparcv9 / plt64_resolution.c
blob11992558052e6af02449fd000b9009de34bfb624
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <proc_service.h>
30 #include <link.h>
31 #include <rtld_db.h>
32 #include <_rtld_db.h>
33 #include <msg.h>
36 * A un-initialized SPARCV9 PLT look like so:
38 * .PLT
39 * sethi (. - .PLT0), %g1
40 * ba,a %xcc, .PLT1
41 * nop
42 * nop
43 * nop
44 * nop
45 * nop
46 * nop
48 * To test to see if this is an uninitialized PLT we check
49 * the second instruction and confirm that it's a branch.
51 /* ARGSUSED 2 */
52 rd_err_e
53 plt64_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid,
54 psaddr_t pltbase, rd_plt_info_t *rpi)
56 instr_t instr[8];
57 rd_err_e rerr;
58 psaddr_t destaddr = 0;
59 psaddr_t pltoff;
60 int pltbound = 0;
62 if (rtld_db_version >= RD_VERSION3) {
63 rpi->pi_flags = 0;
64 rpi->pi_baddr = 0;
67 pltoff = pc - pltbase;
69 if (pltoff >= (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE)) {
70 psaddr_t pltptr, pltptrval;
71 psaddr_t pltaddr;
72 psaddr_t pltblockoff;
75 * Handle far PLT's
77 * .PLT#
78 * 0 mov %o7, %g5
79 * 1 call . + 8
80 * 2 nop
81 * 3 ldx [%o7 + (.PLTP# - .PLT#+4)], %g1
82 * 4 jmpl %o7 + %g1, %g1
83 * 5 mov %g5, %o7
86 pltblockoff = pltoff - (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE);
87 pltblockoff =
88 ((pltblockoff / M64_PLT_FBLOCKSZ) * M64_PLT_FBLOCKSZ) +
89 (((pltblockoff % M64_PLT_FBLOCKSZ) / M64_PLT_FENTSIZE) *
90 M64_PLT_FENTSIZE);
93 pltaddr = pltbase + (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE) +
94 pltblockoff;
96 if (ps_pread(rap->rd_psp, pltaddr, (char *)instr,
97 M64_PLT_FENTSIZE) != PS_OK) {
98 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2),
99 EC_ADDR(pltaddr)));
100 return (RD_ERR);
104 if (instr[0] != M_MOVO7TOG5) {
105 LOG(ps_plog(MSG_ORIG(MSG_DB_BADFPLT),
106 EC_ADDR(pltaddr), EC_ADDR(instr[0])));
107 return (RD_ERR);
111 * the offset is a positive displacement from the
112 * ldx [%o7 + #], %g1 instruction. So - we don't
113 * need to worry about the sign bit :)
115 pltptr = instr[3] & S_MASK(12);
116 pltptr += pltaddr + 4;
118 * Load the pltptr to determine whether it is
119 * pointing to .PLT0 or to the final
120 * destination.
122 if (ps_pread(rap->rd_psp, pltptr, &pltptrval,
123 sizeof (long long)) != PS_OK) {
124 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2),
125 EC_ADDR(pltptr)));
126 return (RD_ERR);
128 pltptrval += pltaddr + 4;
129 if (pltptrval == pltbase) {
130 if ((rerr = rd_binder_exit_addr(rap,
131 MSG_ORIG(MSG_SYM_RTBIND),
132 &(rpi->pi_target))) != RD_OK) {
133 return (rerr);
135 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP;
136 rpi->pi_nstep = 1;
137 } else {
138 rpi->pi_skip_method = RD_RESOLVE_STEP;
139 rpi->pi_nstep = 6;
140 rpi->pi_target = 0;
141 if (rtld_db_version >= RD_VERSION3) {
142 destaddr = pltptrval;
143 pltbound++;
146 } else {
147 psaddr_t pltaddr;
149 pltaddr = pltbase +
150 ((pltoff / M64_PLT_ENTSIZE) * M64_PLT_ENTSIZE);
152 if (ps_pread(rap->rd_psp, pltaddr, (char *)instr,
153 M64_PLT_ENTSIZE) != PS_OK) {
154 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2),
155 EC_ADDR(pltaddr)));
156 return (RD_ERR);
160 * ELF64 NEAR PLT's
162 if ((instr[0] != M_NOP) &&
163 ((instr[1] & (~(S_MASK(19)))) == M_BA_A_XCC)) {
165 * Unbound PLT
167 if ((rerr = rd_binder_exit_addr(rap,
168 MSG_ORIG(MSG_SYM_RTBIND),
169 &(rpi->pi_target))) != RD_OK) {
170 return (rerr);
172 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP;
173 rpi->pi_nstep = 1;
174 } else if ((instr[0] == M_NOP) &&
175 ((instr[1] & (~(S_MASK(22)))) == M_BA_A)) {
177 * Resolved 64-bit PLT entry format (b+-8mb):
178 * .PLT
179 * 0 nop
180 * 1 ba,a <dest>
181 * 2 nop
182 * 3 nop
183 * 4 nop
184 * 5 nop
185 * 6 nop
186 * 7 nop
188 rpi->pi_skip_method = RD_RESOLVE_STEP;
189 rpi->pi_nstep = 2;
190 rpi->pi_target = 0;
191 if (rtld_db_version >= RD_VERSION3) {
192 uint_t d22;
193 d22 = instr[1] & S_MASK(22);
194 /* LINTED */
195 destaddr = ((long)pltaddr + 4) +
196 /* LINTED */
197 (((int)d22 << 10) >> 8);
198 pltbound++;
200 } else if ((instr[0] == M_NOP) &&
201 ((instr[1] & (~(S_MASK(19)))) == M_BA_A_PT)) {
203 * Resolved 64-bit PLT entry format (b+-2mb):
204 * .PLT
205 * 0 nop
206 * 1 ba,a,pt %icc, <dest>
207 * 2 nop
208 * 3 nop
209 * 4 nop
210 * 5 nop
211 * 6 nop
212 * 7 nop
214 rpi->pi_skip_method = RD_RESOLVE_STEP;
215 rpi->pi_nstep = 2;
216 rpi->pi_target = 0;
217 if (rtld_db_version >= RD_VERSION3) {
218 uint_t d19;
219 d19 = instr[1] & S_MASK(22);
220 /* LINTED */
221 destaddr = ((long)pltaddr + 4) +
222 /* LINTED */
223 (((int)d19 << 13) >> 11);
224 pltbound++;
226 } else if ((instr[6] & (~(S_MASK(13)))) == M_JMPL_G5G0) {
228 * Resolved 64-bit PLT entry format (abs-64):
229 * .PLT
230 * 0 nop
231 * 1 sethi %hh(dest), %g1
232 * 2 sethi %lm(dest), %g5
233 * 3 or %g1, %hm(dest), %g1
234 * 4 sllx %g1, 32, %g1
235 * 5 or %g1, %g5, %g5
236 * 6 jmpl %g5 + %lo(dest), %g0
237 * 7 nop
239 rpi->pi_skip_method = RD_RESOLVE_STEP;
240 rpi->pi_nstep = 8;
241 rpi->pi_target = 0;
242 if (rtld_db_version >= RD_VERSION3) {
243 uintptr_t hh_bits;
244 uintptr_t hm_bits;
245 uintptr_t lm_bits;
246 uintptr_t lo_bits;
247 hh_bits = instr[1] & S_MASK(22); /* 63..42 */
248 hm_bits = instr[3] & S_MASK(10); /* 41..32 */
249 lm_bits = instr[2] & S_MASK(22); /* 31..10 */
250 lo_bits = instr[6] & S_MASK(10); /* 09..00 */
251 destaddr = (hh_bits << 42) | (hm_bits << 32) |
252 (lm_bits << 10) | lo_bits;
253 pltbound++;
255 } else if (instr[3] == M_JMPL) {
257 * Resolved 64-bit PLT entry format (top-32):
259 * .PLT:
260 * 0 nop
261 * 1 sethi %hi(~dest), %g5
262 * 2 xnor %g5, %lo(~dest), %g1
263 * 3 jmpl %g1, %g0
264 * 4 nop
265 * 5 nop
266 * 6 nop
267 * 7 nop
269 rpi->pi_skip_method = RD_RESOLVE_STEP;
270 rpi->pi_nstep = 5;
271 rpi->pi_target = 0;
272 if (rtld_db_version >= RD_VERSION3) {
273 uintptr_t hi_bits;
274 uintptr_t lo_bits;
275 hi_bits = (instr[1] & S_MASK(22)) << 10;
276 lo_bits = (instr[2] & S_MASK(10));
277 destaddr = hi_bits ^ ~lo_bits;
278 pltbound++;
280 } else if ((instr[2] & (~(S_MASK(13)))) == M_XNOR_G5G1) {
282 * Resolved 64-bit PLT entry format (top-44):
284 * .PLT:
285 * 0 nop
286 * 1 sethi %h44(~dest), %g5
287 * 2 xnor %g5, %m44(~dest), %g1
288 * 3 slxx %g1, 12, %g1
289 * 4 jmpl %g1 + %l44(dest), %g0
290 * 5 nop
291 * 6 nop
292 * 7 nop
294 rpi->pi_skip_method = RD_RESOLVE_STEP;
295 rpi->pi_nstep = 6;
296 rpi->pi_target = 0;
297 if (rtld_db_version >= RD_VERSION3) {
298 uintptr_t h44_bits;
299 uintptr_t m44_bits;
300 uintptr_t l44_bits;
301 h44_bits = (((long)instr[1] & S_MASK(22))
302 << 10);
303 m44_bits = (((long)instr[2] & S_MASK(13))
304 << 41) >> 41;
305 l44_bits = (((long)instr[4] & S_MASK(13))
306 << 41) >> 41;
307 destaddr = (~(h44_bits ^ m44_bits) << 12)
308 + l44_bits;
309 pltbound++;
311 } else
312 rpi->pi_skip_method = RD_RESOLVE_NONE;
315 if ((rtld_db_version >= RD_VERSION3) && pltbound) {
316 rpi->pi_flags |= RD_FLG_PI_PLTBOUND;
317 rpi->pi_baddr = destaddr;
320 return (RD_OK);