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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 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 58 59 if (rtld_db_version >= RD_VERSION3) { 60 rpi->pi_flags = 0; 61 rpi->pi_baddr = 0; 62 } 63 64 pltoff = pc - pltbase; 65 pltaddr = pltbase + 66 ((pltoff / M_PLT_ENTSIZE) * M_PLT_ENTSIZE); 67 /* 68 * This is the target of the jmp instruction 69 */ 70 if (ps_pread(rap->rd_psp, pltaddr + 2, (char *)&pcrel, 71 sizeof (pcrel)) != PS_OK) { 72 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(pltaddr + 2))); 73 return (RD_ERR); 74 } 75 76 /* 77 * the offset to the GOT table entry is 78 * PC-relative. 79 */ 80 destaddr = pcrel + pltaddr + 6; 81 82 /* 83 * Find out what's pointed to by @OFFSET_INTO_GOT 84 */ 85 if (ps_pread(rap->rd_psp, destaddr, (char *)&destaddr, 86 sizeof (destaddr)) != PS_OK) { 87 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(destaddr))); 88 return (RD_ERR); 89 } 90 if (destaddr == (pltaddr + 6)) { 91 rd_err_e rerr; 92 /* 93 * If GOT[ind] points to PLT+6 then this is the first 94 * time through this PLT. 95 */ 96 if ((rerr = rd_binder_exit_addr(rap, MSG_ORIG(MSG_SYM_RTBIND), 97 &(rpi->pi_target))) != RD_OK) { 98 return (rerr); 99 } 100 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP; 101 rpi->pi_nstep = 1; 102 } else { 103 /* 104 * This is the n'th time through and GOT[ind] points 105 * to the final destination. 106 */ 107 rpi->pi_skip_method = RD_RESOLVE_STEP; 108 rpi->pi_nstep = 1; 109 rpi->pi_target = 0; 110 if (rtld_db_version >= RD_VERSION3) { 111 rpi->pi_flags |= RD_FLG_PI_PLTBOUND; 112 rpi->pi_baddr = destaddr; 113 } 114 } 115 116 return (RD_OK); 117 } 118