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