xref: /illumos-gate/usr/src/cmd/sgs/librtld_db/sparc/plt32_resolution.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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	<stdio.h>
30 #include	<proc_service.h>
31 #include	<link.h>
32 #include	<rtld_db.h>
33 #include	<_rtld_db.h>
34 #include	<msg.h>
35 
36 
37 /*
38  * A un-initialized PLT look like so:
39  *
40  * .PLT
41  *	sethi	(.-.PLT0), %g1
42  *	ba,a	.PLT0
43  *	nop
44  *
45  * To test to see if this is an uninitialized PLT we check
46  * the second instruction and confirm that it's a branch.
47  */
48 /* ARGSUSED 2 */
49 rd_err_e
50 plt32_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid,
51 	psaddr_t pltbase, rd_plt_info_t *rpi)
52 {
53 	unsigned int	instr[4];
54 	rd_err_e	rerr;
55 	psaddr_t	destaddr = 0;
56 	psaddr_t	pltoff, pltaddr;
57 	int		pltbound = 0;
58 
59 	pltoff = pc - pltbase;
60 	pltaddr = pltbase +
61 		((pltoff / M32_PLT_ENTSIZE) * M32_PLT_ENTSIZE);
62 
63 	if (ps_pread(rap->rd_psp, pltaddr, (char *)instr,
64 	    M32_PLT_ENTSIZE) != PS_OK) {
65 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(pltaddr)));
66 		return (RD_ERR);
67 	}
68 
69 	if (rtld_db_version >= RD_VERSION3) {
70 		rpi->pi_flags = 0;
71 		rpi->pi_baddr = 0;
72 	}
73 
74 	if ((instr[0] != M_NOP) &&
75 	    ((instr[1] & (~(S_MASK(22)))) == M_BA_A)) {
76 		/*
77 		 * Unbound PLT
78 		 */
79 		if ((rerr = rd_binder_exit_addr(rap, MSG_ORIG(MSG_SYM_RTBIND),
80 		    &(rpi->pi_target))) != RD_OK) {
81 			return (rerr);
82 		}
83 		rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP;
84 		rpi->pi_nstep = 1;
85 	} else if ((instr[2] & (~(S_MASK(13)))) == M_JMPL) {
86 		/*
87 		 * Resolved 32-bit PLT entry format (full-32):
88 		 *
89 		 * .PLT:
90 		 * 0	sethi	(.-PLT0), %g1
91 		 * 1	sethi	%hi(dest), %g1
92 		 * 2	jmpl	%g1 + lo(dest), %g0
93 		 * 3	nop
94 		 */
95 		rpi->pi_skip_method = RD_RESOLVE_STEP;
96 		rpi->pi_nstep = 4;
97 		rpi->pi_target = 0;
98 		if (rtld_db_version >= RD_VERSION3) {
99 			uint_t		hi_bits;
100 			uint_t		lo_bits;
101 			hi_bits = instr[1] & S_MASK(22); /* 31..10 */
102 			lo_bits = instr[2] & S_MASK(10); /* 09..00 */
103 			destaddr = (hi_bits << 10) | lo_bits;
104 			pltbound++;
105 		}
106 	} else  if ((instr[0] == M_NOP) &&
107 	    ((instr[1] & (~(S_MASK(22)))) == M_BA_A)) {
108 		/*
109 		 * Resolved 32-bit PLT entry format (b+-8mb):
110 		 * .PLT
111 		 * 0	nop
112 		 * 1	ba,a	<dest>
113 		 * 2	nop
114 		 * 3	nop
115 		 */
116 		rpi->pi_skip_method = RD_RESOLVE_STEP;
117 		rpi->pi_nstep = 2;
118 		rpi->pi_target = 0;
119 		if (rtld_db_version >= RD_VERSION3) {
120 			uint_t	d22;
121 			d22 = instr[1] & S_MASK(22);
122 			destaddr = ((int)pltaddr + 4) +
123 				(((int)d22 << 10) >> 8);
124 			pltbound++;
125 		}
126 	} else if ((instr[0] == M_NOP) &&
127 	    ((instr[1] & (~(S_MASK(19)))) == M_BA_A_PT)) {
128 		/*
129 		 * Resolved 32-bit PLT entry format (b+-2mb):
130 		 * .PLT
131 		 * 0	nop
132 		 * 1	ba,a,pt	%icc, <dest>
133 		 * 2	nop
134 		 * 3	nop
135 		 */
136 		rpi->pi_skip_method = RD_RESOLVE_STEP;
137 		rpi->pi_nstep = 2;
138 		rpi->pi_target = 0;
139 		if (rtld_db_version >= RD_VERSION3) {
140 			uint_t	d19;
141 			d19 = instr[1] & S_MASK(22);
142 			destaddr = ((int)pltaddr + 4) +
143 				(((int)d19 << 13) >> 11);
144 			pltbound++;
145 		}
146 	} else
147 		rpi->pi_skip_method = RD_RESOLVE_NONE;
148 
149 	if ((rtld_db_version >= RD_VERSION3) && pltbound) {
150 		rpi->pi_flags |= RD_FLG_PI_PLTBOUND;
151 		rpi->pi_baddr = destaddr;
152 	}
153 	return (RD_OK);
154 }
155