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