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 30 #include <link.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <sys/regset.h> 36 #include <sys/frame.h> 37 #include <sys/lwp.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <sys/mman.h> 41 #include <errno.h> 42 #include <signal.h> 43 #include <synch.h> 44 #include <string.h> 45 46 #include "bindings.h" 47 #include "env.h" 48 49 static Elist *bindto_list = 0; 50 static Elist *bindfrom_list = 0; 51 52 static bindhead *bhp = NULL; 53 static unsigned int current_map_len = 0; 54 static char *buffer_name; 55 static const sigset_t iset = { ~0U, ~0U, ~0U, ~0U }; 56 static lwp_mutex_t sharedmutex = SHAREDMUTEX; 57 58 /* 59 * This routine was stolen from libelf.so.1 60 */ 61 static unsigned long 62 ehash(const char *name) 63 { 64 register unsigned int g, h = 0; 65 register const unsigned char *nm = (unsigned char *)name; 66 67 while (*nm != '\0') { 68 h = (h << 4) + *nm++; 69 /* LINTED */ 70 if ((g = (unsigned int)(h & MASK)) != 0) 71 h ^= g >> 24; 72 h &= ~MASK; 73 } 74 return ((unsigned long)h); 75 } 76 77 78 static void 79 output_err_message(const char *msg) 80 { 81 int fd; 82 if ((fd = open("/tmp/bind_err", O_RDWR | O_CREAT, 0666)) == -1) { 83 (void) fprintf(stderr, "bindings.so: unable to open err_log\n"); 84 perror("open"); 85 } 86 (void) lseek(fd, 0, SEEK_END); 87 (void) write(fd, msg, strlen(msg)); 88 (void) close(fd); 89 } 90 91 /* 92 * common mutex locking & unlocking routines for this module. This is to 93 * control the setting of 'lock_held'. 94 */ 95 static void 96 bt_lock(lwp_mutex_t *lock) 97 { 98 if (_lwp_mutex_lock(lock) != 0) { 99 output_err_message("bt_lock failed!!\n"); 100 (void) fprintf(stderr, "bindings.so: unable to obtain lock\n"); 101 perror("_lwp_mutex_lock"); 102 } 103 } 104 105 static void 106 bt_unlock(lwp_mutex_t *lock) 107 { 108 if (_lwp_mutex_unlock(lock) != 0) { 109 output_err_message("bt_unlock failed!!\n"); 110 (void) fprintf(stderr, "bindings.so: unable to unlock lock\n"); 111 perror("_lwp_mutex_unlock"); 112 } 113 } 114 115 116 117 /* 118 * It's always possible that another process sharing our buffer 119 * has caused it to grow. If this is the case we must adjust our 120 * mappings to compensate. 121 */ 122 static void 123 remap_buffer(int fd) 124 { 125 void * new_bhp; 126 if ((new_bhp = mmap(0, bhp->bh_size, PROT_READ | PROT_WRITE, 127 MAP_SHARED, fd, 0)) == MAP_FAILED) { 128 (void) fprintf(stderr, "bindings: remap: mmap failed\n"); 129 perror("mmap"); 130 131 bt_unlock(&bhp->bh_lock); 132 exit(1); 133 } 134 /* 135 * clean up old mapping 136 */ 137 (void) munmap((caddr_t)bhp, current_map_len); 138 bhp = (bindhead *)new_bhp; 139 current_map_len = bhp->bh_size; 140 } 141 142 static void 143 grow_buffer() 144 { 145 int fd; 146 if ((fd = open(buffer_name, O_RDWR)) == -1) { 147 (void) fprintf(stderr, 148 "bidings: grow_buffer: open failed: %s\n", 149 buffer_name); 150 perror("open"); 151 bt_unlock(&bhp->bh_lock); 152 exit(1); 153 } 154 if (ftruncate(fd, bhp->bh_size + BLKSIZE) == -1) { 155 (void) fprintf(stderr, "grow_buffer failed\n"); 156 perror("ftruncate"); 157 bt_unlock(&bhp->bh_lock); 158 exit(1); 159 } 160 bhp->bh_size += BLKSIZE; 161 remap_buffer(fd); 162 (void) close(fd); 163 } 164 165 static void 166 get_new_strbuf() 167 { 168 bt_lock(&bhp->bh_lock); 169 while (bhp->bh_end + STRBLKSIZE > bhp->bh_size) 170 grow_buffer(); 171 172 bhp->bh_strcur = bhp->bh_end; 173 bhp->bh_end = bhp->bh_strend = bhp->bh_strcur + STRBLKSIZE; 174 bt_unlock(&bhp->bh_lock); 175 } 176 177 static unsigned int 178 save_str(const char *str) 179 { 180 char *sptr; 181 unsigned int bptr; 182 unsigned int slen; 183 184 bt_lock(&bhp->bh_strlock); 185 /* LINTED */ 186 slen = (unsigned int)strlen(str); 187 188 /* 189 * will string fit into our current string buffer? 190 */ 191 if ((slen + 1) > (bhp->bh_strend - bhp->bh_strcur)) 192 get_new_strbuf(); 193 bptr = bhp->bh_strcur; 194 sptr = (char *)bhp + bhp->bh_strcur; 195 bhp->bh_strcur += slen + 1; 196 (void) strncpy(sptr, str, slen); 197 sptr[slen] = '\0'; 198 bt_unlock(&bhp->bh_strlock); 199 return (bptr); 200 } 201 202 203 static unsigned int 204 get_new_entry() 205 { 206 unsigned int new_ent; 207 bt_lock(&bhp->bh_lock); 208 while ((sizeof (binding_entry) + bhp->bh_end) > bhp->bh_size) 209 grow_buffer(); 210 new_ent = bhp->bh_end; 211 bhp->bh_end += sizeof (binding_entry); 212 bt_unlock(&bhp->bh_lock); 213 return (new_ent); 214 } 215 216 217 218 static void 219 init_locks() 220 { 221 int i; 222 223 /* 224 * NOTE: I should call _lwp_mutex_init() but it doesn't 225 * yet exist. see bug#1179352 226 */ 227 (void) memcpy(&bhp->bh_lock, &sharedmutex, sizeof (lwp_mutex_t)); 228 for (i = 0; i < DEFBKTS; i++) 229 (void) memcpy(&bhp->bh_bkts[i].bb_lock, &sharedmutex, 230 sizeof (lwp_mutex_t)); 231 232 (void) memcpy(&bhp->bh_strlock, &sharedmutex, sizeof (lwp_mutex_t)); 233 } 234 235 uint_t 236 la_version(uint_t version) 237 { 238 int fd; 239 sigset_t omask; 240 241 if (version < LAV_CURRENT) { 242 (void) fprintf(stderr, 243 "bindings.so: unexpected link_audit version: %d\n", 244 version); 245 return (0); 246 } 247 248 build_env_list(&bindto_list, (const char *)"BT_BINDTO"); 249 build_env_list(&bindfrom_list, (const char *)"BT_BINDFROM"); 250 251 if ((buffer_name = getenv(FILEENV)) == NULL) 252 buffer_name = DEFFILE; 253 254 (void) sigprocmask(SIG_BLOCK, &iset, &omask); 255 if ((fd = open(buffer_name, O_RDWR | O_CREAT | O_EXCL, 0666)) != -1) { 256 int init_size = sizeof (bindhead) + BLKSIZE; 257 if (ftruncate(fd, init_size) == -1) { 258 perror("ftruncate"); 259 return (0); 260 } 261 262 /* LINTED */ 263 if ((bhp = (bindhead *)mmap(0, init_size, 264 PROT_READ | PROT_WRITE, 265 MAP_SHARED, fd, 0)) == MAP_FAILED) { 266 perror("bindings.so: mmap"); 267 return (0); 268 } 269 270 (void) close(fd); 271 272 init_locks(); 273 /* 274 * Lock our structure and then initialize the data 275 */ 276 bt_lock(&bhp->bh_lock); 277 bhp->bh_vers = BINDCURVERS; 278 current_map_len = bhp->bh_size = init_size; 279 bhp->bh_end = sizeof (bindhead); 280 bhp->bh_bktcnt = DEFBKTS; 281 bt_unlock(&bhp->bh_lock); 282 /* 283 * Set up our initial string buffer 284 */ 285 get_new_strbuf(); 286 } else if ((fd = open(buffer_name, O_RDWR)) != -1) { 287 struct stat stbuf; 288 int i; 289 for (i = 0; i < 4; i++) { 290 if (fstat(fd, &stbuf) == -1) { 291 (void) sleep(1); 292 continue; 293 } 294 if (stbuf.st_size < sizeof (bindhead)) { 295 (void) sleep(1); 296 continue; 297 } 298 /* LINTED */ 299 if ((bhp = (bindhead *)mmap(0, stbuf.st_size, 300 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == 301 MAP_FAILED) { 302 (void) fprintf(stderr, 303 "bindings: mmap failed\n"); 304 perror("mmap"); 305 return (0); 306 } 307 308 /* LINTED */ 309 current_map_len = (unsigned int)stbuf.st_size; 310 } 311 if (bhp == NULL) { 312 (void) fprintf(stderr, 313 "bindings: buffer mapping timed out\n"); 314 return (0); 315 } 316 for (i = 0; i < 4; i++) { 317 if (bhp->bh_vers == 0) { 318 (void) sleep(1); 319 continue; 320 } 321 } 322 if (bhp->bh_vers == 0) { 323 (void) fprintf(stderr, 324 "bindings: %s not initialized\n", buffer_name); 325 return (0); 326 } 327 328 bt_lock(&bhp->bh_lock); 329 330 if (bhp->bh_size != current_map_len) 331 remap_buffer(fd); 332 (void) close(fd); 333 } else { 334 (void) fprintf(stderr, "bindings: unable to open %s\n", 335 buffer_name); 336 perror("open"); 337 return (0); 338 } 339 340 (void) sigprocmask(SIG_SETMASK, &omask, NULL); 341 bt_unlock(&bhp->bh_lock); 342 343 return (LAV_CURRENT); 344 } 345 346 /* ARGSUSED 0 */ 347 uint_t 348 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) 349 { 350 uint_t flags; 351 352 if ((bindto_list == 0) || 353 (check_list(bindto_list, lmp->l_name))) 354 flags = LA_FLG_BINDTO; 355 else 356 flags = 0; 357 358 if ((bindfrom_list == 0) || 359 (check_list(bindfrom_list, lmp->l_name))) 360 flags |= LA_FLG_BINDFROM; 361 362 return (flags); 363 } 364 365 366 /* ARGSUSED 1 */ 367 #if defined(__sparcv9) 368 uintptr_t 369 la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcooke, 370 uintptr_t *defcook, La_sparcv9_regs *regset, uint_t *sb_flags, 371 const char *sym_name) 372 #elif defined(__sparc) 373 uintptr_t 374 la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, 375 uintptr_t *defcook, La_sparcv8_regs *regset, uint_t *sb_flags) 376 #elif defined(__amd64) 377 uintptr_t 378 la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcooke, 379 uintptr_t *defcook, La_amd64_regs *regset, uint_t *sb_flags, 380 const char *sym_name) 381 #elif defined(__i386) 382 uintptr_t 383 la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, 384 uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags) 385 #endif 386 { 387 unsigned long bktno; 388 Link_map *dlmp = (Link_map *)*defcook; 389 const char *lib_name; 390 sigset_t omask; 391 #if !defined(_LP64) 392 const char *sym_name = (const char *)symp->st_name; 393 #endif 394 395 396 lib_name = dlmp->l_name; 397 398 (void) sigprocmask(SIG_BLOCK, &iset, &omask); 399 if (sym_name == 0) { 400 output_err_message("null symname\n"); 401 return (symp->st_value); 402 } 403 404 bktno = ehash(sym_name) % bhp->bh_bktcnt; 405 406 bt_lock(&bhp->bh_bkts[bktno].bb_lock); 407 408 /* 409 * The buffer has been grown (by another process) and 410 * we need to remap it into memory. 411 */ 412 if (bhp->bh_size != current_map_len) { 413 int fd; 414 if ((fd = open(buffer_name, O_RDWR)) == -1) { 415 (void) fprintf(stderr, 416 "bidings: plt_enter: open failed: %s\n", 417 buffer_name); 418 perror("open"); 419 bt_unlock(&bhp->bh_lock); 420 exit(1); 421 } 422 bt_lock(&bhp->bh_lock); 423 remap_buffer(fd); 424 bt_unlock(&bhp->bh_lock); 425 (void) close(fd); 426 } 427 428 if (bhp->bh_bkts[bktno].bb_head == NULL) { 429 binding_entry * bep; 430 unsigned int be_off; 431 unsigned int sym_off; 432 unsigned int lib_off; 433 434 be_off = get_new_entry(); 435 sym_off = save_str(sym_name); 436 lib_off = save_str(lib_name); 437 /* LINTED */ 438 bep = (binding_entry *)((char *)bhp + be_off); 439 bep->be_next = 0; 440 bep->be_sym_name = sym_off; 441 bep->be_lib_name = lib_off; 442 bep->be_count = 1; 443 bhp->bh_bkts[bktno].bb_head = be_off; 444 } else { 445 int strcmp_res; 446 unsigned int prev_off = 0; 447 binding_entry * prev_bep = NULL; 448 unsigned int cur_off; 449 binding_entry * cur_bep; 450 unsigned int lib_off = 0; 451 452 /* 453 * Once we get to the bucket, we do a two tiered 454 * search. First we search for a library match, then 455 * we search for a symbol match. 456 */ 457 cur_off = bhp->bh_bkts[bktno].bb_head; 458 /* LINTED */ 459 cur_bep = (binding_entry *)((char *)bhp + 460 cur_off); 461 while (cur_off && (strcmp_res = strcmp((char *)bhp + 462 cur_bep->be_lib_name, lib_name)) < 0) { 463 prev_off = cur_off; 464 cur_off = cur_bep->be_next; 465 /* LINTED */ 466 cur_bep = (binding_entry *)((char *)bhp + 467 cur_off); 468 } 469 if (cur_off && (strcmp_res == 0)) { 470 /* 471 * This is a small optimization. For 472 * each bucket we will only record a library 473 * name once. Once it has been recorded in 474 * a bucket we will just re-use the same 475 * string. 476 */ 477 lib_off = cur_bep->be_lib_name; 478 while (cur_off && (strcmp_res = strcmp((char *)bhp + 479 cur_bep->be_sym_name, sym_name)) < 0) { 480 prev_off = cur_off; 481 cur_off = cur_bep->be_next; 482 /* LINTED */ 483 cur_bep = (binding_entry *)((char *)bhp + 484 cur_off); 485 } 486 } 487 if (strcmp_res == 0) { 488 /* 489 * We've got a match 490 */ 491 cur_bep->be_count++; 492 } else { 493 unsigned int new_off; 494 binding_entry * new_bep; 495 unsigned int sym_off; 496 497 new_off = get_new_entry(); 498 if (lib_off == 0) 499 lib_off = save_str(lib_name); 500 sym_off = save_str(sym_name); 501 502 /* LINTED */ 503 new_bep = (binding_entry *)((char *)bhp + 504 new_off); 505 new_bep->be_sym_name = sym_off; 506 new_bep->be_lib_name = lib_off; 507 new_bep->be_count = 1; 508 new_bep->be_next = cur_off; 509 if (prev_off) { 510 /* LINTED */ 511 prev_bep = (binding_entry *)((char *)bhp + 512 prev_off); 513 prev_bep->be_next = new_off; 514 } else 515 /* 516 * Insert at head of list. 517 */ 518 bhp->bh_bkts[bktno].bb_head = new_off; 519 520 } 521 } 522 bt_unlock(&bhp->bh_bkts[bktno].bb_lock); 523 (void) sigprocmask(SIG_SETMASK, &omask, NULL); 524 return (symp->st_value); 525 } 526