xref: /illumos-gate/usr/src/cmd/sgs/librtld_db/amd64/plt64_resolution.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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	<libelf.h>
30 #include	<sys/reg.h>
31 #include	<rtld_db.h>
32 #include	"_rtld_db.h"
33 #include	"msg.h"
34 
35 
36 /*
37  * On amd64, basically, a PLT entry looks like this:
38  *
39  *	0x00  ff 25 00 00 00 00  jmpq   *func@got(%rip)  ; jmp GOT[N]
40  *	0x06  68 01 00 00 00     pushq  $0x1	       ; push index
41  *	0x0b  e9 00 00 00 00     jmpq   .plt0	       ; jmp plt[0]
42  *	0x10  ...
43  *
44  *  The first time around GOT[N] contains address of pushq; this forces
45  *	first time resolution to go thru PLT's first entry (which is a call)
46  *  The nth time around, the GOT[N] actually contains the resolved
47  *	address of the symbol(name), so the jmp is direct
48  */
49 /* ARGSUSED 3 */
50 rd_err_e
51 plt64_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid,
52 	psaddr_t pltbase, rd_plt_info_t *rpi)
53 {
54 	uint32_t	pcrel;
55 	psaddr_t	destaddr;
56 	psaddr_t	pltoff, pltaddr;
57 	prgregset_t	gr;
58 
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 	pltaddr = pltbase +
67 		((pltoff / M_PLT_ENTSIZE) * M_PLT_ENTSIZE);
68 	/*
69 	 * This is the target of the jmp instruction
70 	 */
71 	if (ps_pread(rap->rd_psp, pltaddr + 2, (char *)&pcrel,
72 	    sizeof (pcrel)) != PS_OK) {
73 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(pltaddr + 2)));
74 		return (RD_ERR);
75 	}
76 
77 	/*
78 	 * the offset to the GOT table entry is
79 	 * PC-relative.
80 	 */
81 	destaddr = pcrel + pltaddr + 6;
82 
83 	/*
84 	 * Find out what's pointed to by @OFFSET_INTO_GOT
85 	 */
86 	if (ps_pread(rap->rd_psp, destaddr, (char *)&destaddr,
87 	    sizeof (destaddr)) != PS_OK) {
88 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(destaddr)));
89 		return (RD_ERR);
90 	}
91 	if (destaddr == (pltaddr + 6)) {
92 		rd_err_e	rerr;
93 		/*
94 		 * If GOT[ind] points to PLT+6 then this is the first
95 		 * time through this PLT.
96 		 */
97 		if ((rerr = rd_binder_exit_addr(rap, MSG_ORIG(MSG_SYM_RTBIND),
98 		    &(rpi->pi_target))) != RD_OK) {
99 			return (rerr);
100 		}
101 		rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP;
102 		rpi->pi_nstep = 1;
103 	} else {
104 		/*
105 		 * This is the n'th time through and GOT[ind] points
106 		 * to the final destination.
107 		 */
108 		rpi->pi_skip_method = RD_RESOLVE_STEP;
109 		rpi->pi_nstep = 1;
110 		rpi->pi_target = 0;
111 		if (rtld_db_version >= RD_VERSION3) {
112 			rpi->pi_flags |= RD_FLG_PI_PLTBOUND;
113 			rpi->pi_baddr = destaddr;
114 		}
115 	}
116 
117 	return (RD_OK);
118 }
119