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 #include <proc_service.h> 28 #include <link.h> 29 #include <rtld_db.h> 30 #include <_rtld_db.h> 31 #include <msg.h> 32 33 /* 34 * A un-initialized SPARCV9 PLT look like so: 35 * 36 * .PLT 37 * sethi (. - .PLT0), %g1 38 * ba,a %xcc, .PLT1 39 * nop 40 * nop 41 * nop 42 * nop 43 * nop 44 * nop 45 * 46 * To test to see if this is an uninitialized PLT we check 47 * the second instruction and confirm that it's a branch. 48 */ 49 /* ARGSUSED 2 */ 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 instr_t instr[8]; 55 rd_err_e rerr; 56 psaddr_t destaddr = 0; 57 psaddr_t pltoff; 58 int pltbound = 0; 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 67 if (pltoff >= (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE)) { 68 psaddr_t pltptr, pltptrval; 69 psaddr_t pltaddr; 70 psaddr_t pltblockoff; 71 72 /* 73 * Handle far PLT's 74 * 75 * .PLT# 76 * 0 mov %o7, %g5 77 * 1 call . + 8 78 * 2 nop 79 * 3 ldx [%o7 + (.PLTP# - .PLT#+4)], %g1 80 * 4 jmpl %o7 + %g1, %g1 81 * 5 mov %g5, %o7 82 */ 83 84 pltblockoff = pltoff - (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE); 85 pltblockoff = 86 ((pltblockoff / M64_PLT_FBLOCKSZ) * M64_PLT_FBLOCKSZ) + 87 (((pltblockoff % M64_PLT_FBLOCKSZ) / M64_PLT_FENTSIZE) * 88 M64_PLT_FENTSIZE); 89 90 91 pltaddr = pltbase + (M64_PLT_NEARPLTS * M64_PLT_ENTSIZE) + 92 pltblockoff; 93 94 if (ps_pread(rap->rd_psp, pltaddr, (char *)instr, 95 M64_PLT_FENTSIZE) != PS_OK) { 96 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), 97 EC_ADDR(pltaddr))); 98 return (RD_ERR); 99 100 } 101 102 if (instr[0] != M_MOVO7TOG5) { 103 LOG(ps_plog(MSG_ORIG(MSG_DB_BADFPLT), 104 EC_ADDR(pltaddr), EC_ADDR(instr[0]))); 105 return (RD_ERR); 106 } 107 108 /* 109 * the offset is a positive displacement from the 110 * ldx [%o7 + #], %g1 instruction. So - we don't 111 * need to worry about the sign bit :) 112 */ 113 pltptr = instr[3] & S_MASK(12); 114 pltptr += pltaddr + 4; 115 /* 116 * Load the pltptr to determine whether it is 117 * pointing to .PLT0 or to the final 118 * destination. 119 */ 120 if (ps_pread(rap->rd_psp, pltptr, &pltptrval, 121 sizeof (long long)) != PS_OK) { 122 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), 123 EC_ADDR(pltptr))); 124 return (RD_ERR); 125 } 126 pltptrval += pltaddr + 4; 127 if (pltptrval == pltbase) { 128 if ((rerr = rd_binder_exit_addr(rap, 129 MSG_ORIG(MSG_SYM_RTBIND), 130 &(rpi->pi_target))) != RD_OK) { 131 return (rerr); 132 } 133 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP; 134 rpi->pi_nstep = 1; 135 } else { 136 rpi->pi_skip_method = RD_RESOLVE_STEP; 137 rpi->pi_nstep = 6; 138 rpi->pi_target = 0; 139 if (rtld_db_version >= RD_VERSION3) { 140 destaddr = pltptrval; 141 pltbound++; 142 } 143 } 144 } else { 145 psaddr_t pltaddr; 146 147 pltaddr = pltbase + 148 ((pltoff / M64_PLT_ENTSIZE) * M64_PLT_ENTSIZE); 149 150 if (ps_pread(rap->rd_psp, pltaddr, (char *)instr, 151 M64_PLT_ENTSIZE) != PS_OK) { 152 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), 153 EC_ADDR(pltaddr))); 154 return (RD_ERR); 155 156 } 157 /* 158 * ELF64 NEAR PLT's 159 */ 160 if ((instr[0] != M_NOP) && 161 ((instr[1] & (~(S_MASK(19)))) == M_BA_A_XCC)) { 162 /* 163 * Unbound PLT 164 */ 165 if ((rerr = rd_binder_exit_addr(rap, 166 MSG_ORIG(MSG_SYM_RTBIND), 167 &(rpi->pi_target))) != RD_OK) { 168 return (rerr); 169 } 170 rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP; 171 rpi->pi_nstep = 1; 172 } else if ((instr[0] == M_NOP) && 173 ((instr[1] & (~(S_MASK(22)))) == M_BA_A)) { 174 /* 175 * Resolved 64-bit PLT entry format (b+-8mb): 176 * .PLT 177 * 0 nop 178 * 1 ba,a <dest> 179 * 2 nop 180 * 3 nop 181 * 4 nop 182 * 5 nop 183 * 6 nop 184 * 7 nop 185 */ 186 rpi->pi_skip_method = RD_RESOLVE_STEP; 187 rpi->pi_nstep = 2; 188 rpi->pi_target = 0; 189 if (rtld_db_version >= RD_VERSION3) { 190 uint_t d22; 191 d22 = instr[1] & S_MASK(22); 192 /* LINTED */ 193 destaddr = ((long)pltaddr + 4) + 194 /* LINTED */ 195 (((int)d22 << 10) >> 8); 196 pltbound++; 197 } 198 } else if ((instr[0] == M_NOP) && 199 ((instr[1] & (~(S_MASK(19)))) == M_BA_A_PT)) { 200 /* 201 * Resolved 64-bit PLT entry format (b+-2mb): 202 * .PLT 203 * 0 nop 204 * 1 ba,a,pt %icc, <dest> 205 * 2 nop 206 * 3 nop 207 * 4 nop 208 * 5 nop 209 * 6 nop 210 * 7 nop 211 */ 212 rpi->pi_skip_method = RD_RESOLVE_STEP; 213 rpi->pi_nstep = 2; 214 rpi->pi_target = 0; 215 if (rtld_db_version >= RD_VERSION3) { 216 uint_t d19; 217 d19 = instr[1] & S_MASK(22); 218 /* LINTED */ 219 destaddr = ((long)pltaddr + 4) + 220 /* LINTED */ 221 (((int)d19 << 13) >> 11); 222 pltbound++; 223 } 224 } else if ((instr[6] & (~(S_MASK(13)))) == M_JMPL_G5G0) { 225 /* 226 * Resolved 64-bit PLT entry format (abs-64): 227 * .PLT 228 * 0 nop 229 * 1 sethi %hh(dest), %g1 230 * 2 sethi %lm(dest), %g5 231 * 3 or %g1, %hm(dest), %g1 232 * 4 sllx %g1, 32, %g1 233 * 5 or %g1, %g5, %g5 234 * 6 jmpl %g5 + %lo(dest), %g0 235 * 7 nop 236 */ 237 rpi->pi_skip_method = RD_RESOLVE_STEP; 238 rpi->pi_nstep = 8; 239 rpi->pi_target = 0; 240 if (rtld_db_version >= RD_VERSION3) { 241 uintptr_t hh_bits; 242 uintptr_t hm_bits; 243 uintptr_t lm_bits; 244 uintptr_t lo_bits; 245 hh_bits = instr[1] & S_MASK(22); /* 63..42 */ 246 hm_bits = instr[3] & S_MASK(10); /* 41..32 */ 247 lm_bits = instr[2] & S_MASK(22); /* 31..10 */ 248 lo_bits = instr[6] & S_MASK(10); /* 09..00 */ 249 destaddr = (hh_bits << 42) | (hm_bits << 32) | 250 (lm_bits << 10) | lo_bits; 251 pltbound++; 252 } 253 } else if (instr[3] == M_JMPL) { 254 /* 255 * Resolved 64-bit PLT entry format (top-32): 256 * 257 * .PLT: 258 * 0 nop 259 * 1 sethi %hi(~dest), %g5 260 * 2 xnor %g5, %lo(~dest), %g1 261 * 3 jmpl %g1, %g0 262 * 4 nop 263 * 5 nop 264 * 6 nop 265 * 7 nop 266 */ 267 rpi->pi_skip_method = RD_RESOLVE_STEP; 268 rpi->pi_nstep = 5; 269 rpi->pi_target = 0; 270 if (rtld_db_version >= RD_VERSION3) { 271 uintptr_t hi_bits; 272 uintptr_t lo_bits; 273 hi_bits = (instr[1] & S_MASK(22)) << 10; 274 lo_bits = (instr[2] & S_MASK(10)); 275 destaddr = hi_bits ^ ~lo_bits; 276 pltbound++; 277 } 278 } else if ((instr[2] & (~(S_MASK(13)))) == M_XNOR_G5G1) { 279 /* 280 * Resolved 64-bit PLT entry format (top-44): 281 * 282 * .PLT: 283 * 0 nop 284 * 1 sethi %h44(~dest), %g5 285 * 2 xnor %g5, %m44(~dest), %g1 286 * 3 slxx %g1, 12, %g1 287 * 4 jmpl %g1 + %l44(dest), %g0 288 * 5 nop 289 * 6 nop 290 * 7 nop 291 */ 292 rpi->pi_skip_method = RD_RESOLVE_STEP; 293 rpi->pi_nstep = 6; 294 rpi->pi_target = 0; 295 if (rtld_db_version >= RD_VERSION3) { 296 uintptr_t h44_bits; 297 uintptr_t m44_bits; 298 uintptr_t l44_bits; 299 h44_bits = (((long)instr[1] & S_MASK(22)) 300 << 10); 301 m44_bits = (((long)instr[2] & S_MASK(13)) 302 << 41) >> 41; 303 l44_bits = (((long)instr[4] & S_MASK(13)) 304 << 41) >> 41; 305 destaddr = (~(h44_bits ^ m44_bits) << 12) 306 + l44_bits; 307 pltbound++; 308 } 309 } else 310 rpi->pi_skip_method = RD_RESOLVE_NONE; 311 } 312 313 if ((rtld_db_version >= RD_VERSION3) && pltbound) { 314 rpi->pi_flags |= RD_FLG_PI_PLTBOUND; 315 rpi->pi_baddr = destaddr; 316 } 317 318 return (RD_OK); 319 } 320