xref: /illumos-gate/usr/src/cmd/sgs/librtld_db/sparcv9/plt64_resolution.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include	<proc_service.h>
30 #include	<link.h>
31 #include	<rtld_db.h>
32 #include	<_rtld_db.h>
33 #include	<msg.h>
34 
35 /*
36  * A un-initialized SPARCV9 PLT look like so:
37  *
38  * .PLT
39  *	sethi	(. - .PLT0), %g1
40  *	ba,a	%xcc, .PLT1
41  *	nop
42  *	nop
43  *	nop
44  *	nop
45  *	nop
46  *	nop
47  *
48  * To test to see if this is an uninitialized PLT we check
49  * the second instruction and confirm that it's a branch.
50  */
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)
55 {
56 	instr_t		instr[8];
57 	rd_err_e	rerr;
58 	psaddr_t	destaddr = 0;
59 	psaddr_t	pltoff;
60 	int		pltbound = 0;
61 
62 	if (rtld_db_version >= RD_VERSION3) {
63 		rpi->pi_flags = 0;
64 		rpi->pi_baddr = 0;
65 	}
66 
67 	pltoff = pc - pltbase;
68 
69 	if (pltoff >= (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE)) {
70 		psaddr_t	pltptr, pltptrval;
71 		psaddr_t	pltaddr;
72 		psaddr_t	pltblockoff;
73 
74 		/*
75 		 * Handle far PLT's
76 		 *
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
84 		 */
85 
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);
91 
92 
93 		pltaddr = pltbase + (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE) +
94 			pltblockoff;
95 
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);
101 
102 		}
103 
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);
108 		}
109 
110 		/*
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 :)
114 		 */
115 		pltptr = instr[3] & S_MASK(12);
116 		pltptr += pltaddr + 4;
117 		/*
118 		 * Load the pltptr to determine whether it is
119 		 * pointing to .PLT0 or to the final
120 		 * destination.
121 		 */
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);
127 		}
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);
134 			}
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++;
144 			}
145 		}
146 	} else  {
147 		psaddr_t	pltaddr;
148 
149 		pltaddr = pltbase +
150 			((pltoff / M64_PLT_ENTSIZE) * M64_PLT_ENTSIZE);
151 
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);
157 
158 		}
159 		/*
160 		 * ELF64 NEAR PLT's
161 		 */
162 		if ((instr[0] != M_NOP) &&
163 		    ((instr[1] & (~(S_MASK(19)))) == M_BA_A_XCC)) {
164 			/*
165 			 * Unbound PLT
166 			 */
167 			if ((rerr = rd_binder_exit_addr(rap,
168 			    MSG_ORIG(MSG_SYM_RTBIND),
169 			    &(rpi->pi_target))) != RD_OK) {
170 				return (rerr);
171 			}
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)) {
176 			/*
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
187 			 */
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++;
199 			}
200 		} else if ((instr[0] == M_NOP) &&
201 		    ((instr[1] & (~(S_MASK(19)))) == M_BA_A_PT)) {
202 			/*
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
213 			 */
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++;
225 			}
226 		} else if ((instr[6] & (~(S_MASK(13)))) == M_JMPL_G5G0) {
227 			/*
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
238 			 */
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++;
254 			}
255 		} else if (instr[3] == M_JMPL) {
256 			/*
257 			 * Resolved 64-bit PLT entry format (top-32):
258 			 *
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
268 			 */
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++;
279 			}
280 		} else if ((instr[2] & (~(S_MASK(13)))) == M_XNOR_G5G1) {
281 			/*
282 			 * Resolved 64-bit PLT entry format (top-44):
283 			 *
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
293 			 */
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++;
310 			}
311 		} else
312 			rpi->pi_skip_method = RD_RESOLVE_NONE;
313 	}
314 
315 	if ((rtld_db_version >= RD_VERSION3) && pltbound) {
316 		rpi->pi_flags |= RD_FLG_PI_PLTBOUND;
317 		rpi->pi_baddr = destaddr;
318 	}
319 
320 	return (RD_OK);
321 }
322