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 (c) 1988 AT&T 24 * All Rights Reserved 25 * 26 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * Programmatic interface to the run_time linker. 34 */ 35 #include "_synonyms.h" 36 37 #include <sys/debug.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <dlfcn.h> 41 #include <synch.h> 42 #include <limits.h> 43 #include <debug.h> 44 #include "_rtld.h" 45 #include "_audit.h" 46 #include "_elf.h" 47 #include "msg.h" 48 49 /* 50 * Determine who called us - given a pc determine in which object it resides. 51 * 52 * For dlopen() the link map of the caller must be passed to load_so() so that 53 * the appropriate search rules (4.x or 5.0) are used to locate any 54 * dependencies. Also, if we've been called from a 4.x module it may be 55 * necessary to fix the specified pathname so that it conforms with the 5.0 elf 56 * rules. 57 * 58 * For dlsym() the link map of the caller is used to determine RTLD_NEXT 59 * requests, together with requests based off of a dlopen(0). 60 * For dladdr() this routines provides a generic means of scanning all loaded 61 * segments. 62 */ 63 Rt_map * 64 _caller(caddr_t cpc, int flags) 65 { 66 Lm_list * lml; 67 Listnode * lnp; 68 69 for (LIST_TRAVERSE(&dynlm_list, lnp, lml)) { 70 Aliste idx; 71 Lm_cntl *lmc; 72 73 for (ALIST_TRAVERSE(lml->lm_lists, idx, lmc)) { 74 Rt_map *lmp; 75 76 for (lmp = lmc->lc_head; lmp; 77 lmp = (Rt_map *)NEXT(lmp)) { 78 Mmap *mmap; 79 80 /* 81 * Traverse this objects mappings testing 82 * whether the pc falls within its range. 83 */ 84 for (mmap = MMAPS(lmp); mmap->m_vaddr; mmap++) { 85 if ((cpc >= mmap->m_vaddr) && (cpc < 86 (mmap->m_vaddr + mmap->m_msize))) 87 return (lmp); 88 } 89 } 90 } 91 } 92 93 /* 94 * No mapping can be determined. If asked for a default, assume this 95 * is from the executable. 96 */ 97 if (flags & CL_EXECDEF) 98 return ((Rt_map *)lml_main.lm_head); 99 100 return (0); 101 } 102 103 #pragma weak dlerror = _dlerror 104 105 /* 106 * External entry for dlerror(3dl). Returns a pointer to the string describing 107 * the last occurring error. The last occurring error is cleared. 108 */ 109 char * 110 _dlerror() 111 { 112 char *error; 113 Rt_map *clmp; 114 int entry; 115 116 entry = enter(0); 117 118 clmp = _caller(caller(), CL_EXECDEF); 119 120 error = lasterr; 121 lasterr = (char *)0; 122 123 if (entry) 124 leave(LIST(clmp), 0); 125 return (error); 126 } 127 128 /* 129 * Add a dependency as a group descriptor to a group handle. Returns 0 on 130 * failure, ALE_EXISTS if the dependency already exists, or ALE_CREATE if it 131 * is newly created. 132 */ 133 int 134 hdl_add(Grp_hdl *ghp, Rt_map *lmp, uint_t flags) 135 { 136 Grp_desc *gdp; 137 Aliste idx; 138 int found = ALE_CREATE; 139 uint_t oflags; 140 141 /* 142 * Make sure this dependency hasn't already been recorded. 143 */ 144 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 145 if (gdp->gd_depend == lmp) { 146 found = ALE_EXISTS; 147 break; 148 } 149 } 150 151 if (found == ALE_CREATE) { 152 Grp_desc gd; 153 154 /* 155 * Create a new handle descriptor. 156 */ 157 gd.gd_depend = lmp; 158 gd.gd_flags = 0; 159 160 /* 161 * Indicate this object is a part of this handles group. 162 */ 163 if (aplist_append(&GROUPS(lmp), ghp, 164 AL_CNT_GROUPS) == 0) 165 return (0); 166 167 /* 168 * Append the new dependency to this handle. 169 */ 170 if ((gdp = alist_append(&ghp->gh_depends, &gd, 171 sizeof (Grp_desc), AL_CNT_DEPENDS)) == 0) 172 return (0); 173 } 174 175 oflags = gdp->gd_flags; 176 gdp->gd_flags |= flags; 177 178 if (DBG_ENABLED) { 179 if (found == ALE_CREATE) 180 DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_ADD, 181 gdp->gd_flags)); 182 else if (gdp->gd_flags != oflags) 183 DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_UPDATE, 184 gdp->gd_flags)); 185 } 186 return (found); 187 } 188 189 /* 190 * Allocate a handle and record its existence on the handle list for future 191 * verification. 192 */ 193 Grp_hdl * 194 hdl_alloc() 195 { 196 Grp_hdl *ghp; 197 uint_t ndx; 198 199 if ((ghp = calloc(sizeof (Grp_hdl), 1)) == 0) 200 return (0); 201 202 /* LINTED */ 203 ndx = (uintptr_t)ghp % HDLIST_SZ; 204 205 if (list_append(&hdl_list[ndx], ghp) == 0) { 206 free(ghp); 207 return (0); 208 } 209 return (ghp); 210 } 211 212 /* 213 * Create a handle. 214 */ 215 Grp_hdl * 216 hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, 217 uint_t ndflags, uint_t cdflags) 218 { 219 Grp_hdl *ghp = 0, *_ghp; 220 APlist **alpp; 221 Aliste idx; 222 223 /* 224 * For dlopen(0) the handle is maintained as part of the link-map list, 225 * otherwise it is associated with the referenced link-map. 226 */ 227 if (hflags & GPH_ZERO) 228 alpp = &(lml->lm_handle); 229 else 230 alpp = &(HANDLES(nlmp)); 231 232 /* 233 * Objects can contain multiple handles depending on the handle flags 234 * supplied. Most RTLD flags pertain to the object itself and the 235 * bindings that it can achieve. Multiple handles for these flags 236 * don't make sense. But if the flag determines how the handle might 237 * be used, then multiple handles may exist. Presently this only makes 238 * sense for RTLD_FIRST. Determine if an appropriate handle already 239 * exists. 240 */ 241 for (APLIST_TRAVERSE(*alpp, idx, _ghp)) { 242 if ((_ghp->gh_flags & GPH_FIRST) == (hflags & GPH_FIRST)) { 243 ghp = _ghp; 244 break; 245 } 246 } 247 248 if (ghp == 0) { 249 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_CREATE)); 250 251 /* 252 * If this is the first dlopen() request for this handle 253 * allocate and initialize a new handle. 254 */ 255 if ((ghp = hdl_alloc()) == 0) 256 return (0); 257 258 if (aplist_append(alpp, ghp, AL_CNT_GROUPS) == 0) 259 return (0); 260 261 ghp->gh_refcnt = 1; 262 ghp->gh_flags = hflags; 263 264 /* 265 * A dlopen(0) handle is identified by the GPH_ZERO flag, the 266 * head of the link-map list is defined as the owner. There is 267 * no need to maintain a list of dependencies, for when this 268 * handle is used (for dlsym()) a dynamic search through the 269 * entire link-map list provides for searching all objects with 270 * GLOBAL visibility. 271 */ 272 if (hflags & GPH_ZERO) { 273 ghp->gh_ownlmp = lml->lm_head; 274 ghp->gh_ownlml = lml; 275 } else { 276 ghp->gh_ownlmp = nlmp; 277 ghp->gh_ownlml = LIST(nlmp); 278 279 if (hdl_add(ghp, nlmp, ndflags) == 0) 280 return (0); 281 282 /* 283 * Indicate that a local group now exists. This state 284 * allows singleton searches to be optimized. 285 */ 286 if ((hflags & GPH_LDSO) == 0) 287 LIST(nlmp)->lm_flags |= LML_FLG_GROUPSEXIST; 288 } 289 } else { 290 /* 291 * If a handle already exists, bump its reference count. 292 * 293 * If the previous reference count was 0, then this is a handle 294 * that an earlier call to dlclose() was unable to remove. Such 295 * handles are put on the orphan list. As this handle is back 296 * in use, it must be removed from the orphan list. 297 * 298 * Note, handles associated with a link-map list itself (i.e. 299 * dlopen(0)) can have a reference count of 0. However, these 300 * handles are never deleted, and therefore are never moved to 301 * the orphan list. 302 */ 303 if ((ghp->gh_refcnt++ == 0) && 304 ((ghp->gh_flags & GPH_ZERO) == 0)) { 305 uint_t ndx; 306 307 /* LINTED */ 308 ndx = (uintptr_t)ghp % HDLIST_SZ; 309 310 list_delete(&hdl_list[HDLIST_ORP], ghp); 311 (void) list_append(&hdl_list[ndx], ghp); 312 313 if (DBG_ENABLED) { 314 Aliste idx; 315 Grp_desc *gdp; 316 317 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_REINST)); 318 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) 319 DBG_CALL(Dbg_file_hdl_action(ghp, 320 gdp->gd_depend, DBG_DEP_REINST, 0)); 321 } 322 } 323 } 324 325 /* 326 * Keep track of the parent (caller). As this object could be opened 327 * by different parents, this processing is carried out every time a 328 * handle is requested. 329 */ 330 if (clmp && (hdl_add(ghp, clmp, cdflags) == 0)) 331 return (0); 332 333 return (ghp); 334 } 335 336 /* 337 * Initialize a handle that has been created for an object that is already 338 * loaded. The handle is initialized with the present dependencies of that 339 * object. Once this initialization has occurred, any new objects that might 340 * be loaded as dependencies (lazy-loading) are added to the handle as each new 341 * object is loaded. 342 */ 343 int 344 hdl_initialize(Grp_hdl *ghp, Rt_map *nlmp, int mode, int promote) 345 { 346 Aliste idx; 347 Grp_desc *gdp; 348 349 /* 350 * If the handle has already been initialized, and the initial object's 351 * mode hasn't been promoted, there's no need to recompute the modes of 352 * any dependencies. If the object we've added has just been opened, 353 * the objects dependencies will not yet have been processed. These 354 * dependencies will be added on later calls to load_one(). Otherwise, 355 * this object already exists, so add all of its dependencies to the 356 * handle were operating on. 357 */ 358 if (((ghp->gh_flags & GPH_INITIAL) && (promote == 0)) || 359 ((FLAGS(nlmp) & FLG_RT_ANALYZED) == 0)) { 360 ghp->gh_flags |= GPH_INITIAL; 361 return (1); 362 } 363 364 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); 365 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 366 Rt_map * lmp = gdp->gd_depend; 367 Aliste idx1; 368 Bnd_desc *bdp; 369 370 /* 371 * If this dependency doesn't indicate that its dependencies 372 * should be added to a handle, ignore it. This case identifies 373 * a parent of a dlopen(RTLD_PARENT) request. 374 */ 375 if ((gdp->gd_flags & GPD_ADDEPS) == 0) 376 continue; 377 378 for (APLIST_TRAVERSE(DEPENDS(lmp), idx1, bdp)) { 379 Rt_map *dlmp = bdp->b_depend; 380 381 if ((bdp->b_flags & BND_NEEDED) == 0) 382 continue; 383 384 if (hdl_add(ghp, dlmp, 385 (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS)) == 0) 386 return (0); 387 388 (void) update_mode(dlmp, MODE(dlmp), mode); 389 } 390 } 391 ghp->gh_flags |= GPH_INITIAL; 392 return (1); 393 } 394 395 /* 396 * Sanity check a program-provided handle. 397 */ 398 static int 399 hdl_validate(Grp_hdl *ghp) 400 { 401 Listnode *lnp; 402 Grp_hdl *lghp; 403 uint_t ndx; 404 405 /* LINTED */ 406 ndx = (uintptr_t)ghp % HDLIST_SZ; 407 408 for (LIST_TRAVERSE(&hdl_list[ndx], lnp, lghp)) { 409 if ((lghp == ghp) && (ghp->gh_refcnt != 0)) 410 return (1); 411 } 412 return (0); 413 } 414 415 /* 416 * Core dlclose activity. 417 */ 418 int 419 dlclose_core(Grp_hdl *ghp, Rt_map *clmp, Lm_list *lml) 420 { 421 int error; 422 423 /* 424 * If we're already at atexit() there's no point processing further, 425 * all objects have already been tsorted for fini processing. 426 */ 427 if ((rtld_flags & RT_FL_ATEXIT) != 0) 428 return (0); 429 430 /* 431 * Diagnose what we're up to. 432 */ 433 if (ghp->gh_flags & GPH_ZERO) { 434 DBG_CALL(Dbg_file_dlclose(LIST(clmp), MSG_ORIG(MSG_STR_ZERO), 435 DBG_DLCLOSE_IGNORE)); 436 } else { 437 DBG_CALL(Dbg_file_dlclose(LIST(clmp), NAME(ghp->gh_ownlmp), 438 DBG_DLCLOSE_NULL)); 439 } 440 441 442 /* 443 * Decrement reference count of this object. 444 */ 445 if (--(ghp->gh_refcnt)) 446 return (0); 447 448 /* 449 * If this handle is special (dlopen(0)), then leave it around - it 450 * has little overhead. 451 */ 452 if (ghp->gh_flags & GPH_ZERO) 453 return (0); 454 455 /* 456 * This handle is no longer being referenced, remove it. If this handle 457 * is part of an alternative link-map list, determine if the whole list 458 * can be removed also. 459 */ 460 error = remove_hdl(ghp, clmp, 0); 461 462 if ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) == 0) 463 remove_lml(lml); 464 465 return (error); 466 } 467 468 /* 469 * Internal dlclose activity. Called from user level or directly for internal 470 * error cleanup. 471 */ 472 int 473 dlclose_intn(Grp_hdl *ghp, Rt_map *clmp) 474 { 475 Rt_map *nlmp = 0; 476 Lm_list *olml = 0; 477 int error; 478 479 /* 480 * Although we're deleting object(s) it's quite possible that additional 481 * objects get loaded from running the .fini section(s) of the objects 482 * being deleted. These objects will have been added to the same 483 * link-map list as those objects being deleted. Remember this list 484 * for later investigation. 485 */ 486 olml = ghp->gh_ownlml; 487 488 error = dlclose_core(ghp, clmp, olml); 489 490 /* 491 * Determine whether the original link-map list still exists. In the 492 * case of a dlclose of an alternative (dlmopen) link-map the whole 493 * list may have been removed. 494 */ 495 if (olml) { 496 Listnode *lnp; 497 Lm_list *lml; 498 499 for (LIST_TRAVERSE(&dynlm_list, lnp, lml)) { 500 if (olml == lml) { 501 nlmp = olml->lm_head; 502 break; 503 } 504 } 505 } 506 load_completion(nlmp); 507 return (error); 508 } 509 510 /* 511 * Argument checking for dlclose. Only called via external entry. 512 */ 513 static int 514 dlclose_check(void *handle, Rt_map *clmp) 515 { 516 Grp_hdl *ghp = (Grp_hdl *)handle; 517 518 if (hdl_validate(ghp) == 0) { 519 eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL)); 520 return (1); 521 } 522 return (dlclose_intn(ghp, clmp)); 523 } 524 525 #pragma weak dlclose = _dlclose 526 527 /* 528 * External entry for dlclose(3dl). Returns 0 for success, non-zero otherwise. 529 */ 530 int 531 _dlclose(void *handle) 532 { 533 int error, entry; 534 Rt_map *clmp; 535 536 entry = enter(0); 537 538 clmp = _caller(caller(), CL_EXECDEF); 539 540 error = dlclose_check(handle, clmp); 541 542 if (entry) 543 leave(LIST(clmp), 0); 544 return (error); 545 } 546 547 static uint_t lmid = 0; 548 549 /* 550 * The addition of new link-map lists is assumed to be in small quantities. 551 * Here, we assign a unique link-map id for diagnostic use. Simply update the 552 * running link-map count until we max out. 553 */ 554 int 555 newlmid(Lm_list *lml) 556 { 557 char buffer[MSG_LMID_ALT_SIZE + 12]; 558 559 if (lmid == UINT_MAX) { 560 lml->lm_lmid = UINT_MAX; 561 (void) strncpy(buffer, MSG_ORIG(MSG_LMID_MAXED), 562 MSG_LMID_ALT_SIZE + 12); 563 } else { 564 lml->lm_lmid = lmid++; 565 (void) snprintf(buffer, MSG_LMID_ALT_SIZE + 12, 566 MSG_ORIG(MSG_LMID_FMT), MSG_ORIG(MSG_LMID_ALT), 567 lml->lm_lmid); 568 } 569 if ((lml->lm_lmidstr = strdup(buffer)) == 0) 570 return (0); 571 572 return (1); 573 } 574 575 /* 576 * Core dlopen activity. 577 */ 578 static Grp_hdl * 579 dlmopen_core(Lm_list *lml, const char *path, int mode, Rt_map *clmp, 580 uint_t flags, uint_t orig, int *in_nfavl) 581 { 582 Rt_map *nlmp; 583 Grp_hdl *ghp; 584 Pnode *pnp; 585 Aliste olmco, nlmco; 586 Lm_cntl *lmc; 587 588 DBG_CALL(Dbg_file_dlopen(clmp, 589 (path ? path : MSG_ORIG(MSG_STR_ZERO)), in_nfavl, mode)); 590 591 /* 592 * If the path specified is null then we're operating on global 593 * objects. Associate a dummy handle with the link-map list. 594 */ 595 if (path == 0) { 596 Grp_hdl *ghp; 597 uint_t hflags = GPH_ZERO, cdflags = GPD_PARENT; 598 int promote = 0; 599 600 /* 601 * Establish any flags for the handle (Grp_hdl). 602 * 603 * . This is a dummy handle (0) that provides for a dynamic 604 * search of all global objects within the process. 605 * 606 * . Use of the RTLD_FIRST flag indicates that only the first 607 * dependency on the handle (the new object) can be used 608 * to satisfy dlsym() requests. 609 */ 610 if (mode & RTLD_FIRST) 611 hflags |= GPH_FIRST; 612 613 /* 614 * Establish the flags for this callers dependency descriptor 615 * (Grp_desc). 616 * 617 * . The explicit creation of a handle creates a descriptor 618 * for the new object and the parent (caller), 619 * 620 * . Use of the RTLD_PARENT flag indicates that the parent 621 * can be relocated against. 622 */ 623 if (mode & RTLD_PARENT) 624 cdflags |= GPD_RELOC; 625 626 if ((ghp = hdl_create(lml, 0, clmp, hflags, 627 (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), cdflags)) == 0) 628 return (0); 629 630 /* 631 * Traverse the main link-map control list, updating the mode 632 * of any objects as necessary. Call the relocation engine if 633 * this mode promotes the existing state of any relocations. 634 * crle()'s first pass loads all objects necessary for building 635 * a configuration file, however none of them are relocated. 636 * crle()'s second pass relocates objects in preparation for 637 * dldump()'ing using dlopen(0, RTLD_NOW). 638 */ 639 if ((mode & (RTLD_NOW | RTLD_CONFGEN)) == RTLD_CONFGEN) 640 return (ghp); 641 642 for (nlmp = lml->lm_head; nlmp; nlmp = (Rt_map *)NEXT(nlmp)) { 643 if (((MODE(nlmp) & RTLD_GLOBAL) == 0) || 644 (FLAGS(nlmp) & FLG_RT_DELETE)) 645 continue; 646 647 if (update_mode(nlmp, MODE(nlmp), mode)) 648 promote = 1; 649 } 650 if (promote) 651 (void) relocate_lmc(lml, ALIST_OFF_DATA, clmp, 652 lml->lm_head, in_nfavl); 653 654 return (ghp); 655 } 656 657 /* 658 * Fix the pathname. If this object expands to multiple paths (ie. 659 * $ISALIST or $HWCAP have been used), then make sure the user has also 660 * furnished the RTLD_FIRST flag. As yet, we don't support opening 661 * more than one object at a time, so enforcing the RTLD_FIRST flag 662 * provides flexibility should we be able to support dlopening more 663 * than one object in the future. 664 */ 665 if ((pnp = LM_FIX_NAME(clmp)(path, clmp, orig)) == 0) 666 return (0); 667 668 if (((pnp->p_orig & (PN_TKN_ISALIST | PN_TKN_HWCAP)) || pnp->p_next) && 669 ((mode & RTLD_FIRST) == 0)) { 670 remove_pnode(pnp); 671 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_5)); 672 return (0); 673 } 674 675 /* 676 * Create a new link-map control list for this request, and load the 677 * associated object. 678 */ 679 if ((lmc = alist_append(&lml->lm_lists, 0, sizeof (Lm_cntl), 680 AL_CNT_LMLISTS)) == 0) { 681 remove_pnode(pnp); 682 return (0); 683 } 684 olmco = nlmco = (Aliste)((char *)lmc - (char *)lml->lm_lists); 685 686 nlmp = load_one(lml, nlmco, pnp, clmp, mode, 687 (flags | FLG_RT_HANDLE), &ghp, in_nfavl); 688 689 /* 690 * Remove any expanded pathname infrastructure, and if the dependency 691 * couldn't be loaded, cleanup. 692 */ 693 remove_pnode(pnp); 694 if (nlmp == 0) { 695 remove_cntl(lml, olmco); 696 return (0); 697 } 698 699 /* 700 * If loading an auditor was requested, and the auditor already existed, 701 * then the link-map returned will be to the original auditor. The new 702 * link-map list that was initially created, and the associated link-map 703 * control list are no longer needed. As the auditor is already loaded, 704 * we're probably done, but fall through in case additional relocations 705 * would be triggered by the mode of the caller. 706 */ 707 if ((flags & FLG_RT_AUDIT) && (LIST(nlmp) != lml)) { 708 remove_cntl(lml, olmco); 709 lml = LIST(nlmp); 710 olmco = 0; 711 nlmco = ALIST_OFF_DATA; 712 } 713 714 /* 715 * Finish processing the objects associated with this request. 716 */ 717 if ((analyze_lmc(lml, nlmco, nlmp, in_nfavl) == 0) || 718 (relocate_lmc(lml, nlmco, clmp, nlmp, in_nfavl) == 0)) { 719 ghp = 0; 720 nlmp = 0; 721 } 722 723 /* 724 * If this lazyload has failed, and we've created a new link-map 725 * control list to which this request has added objects, then remove 726 * all the objects that have been associated to this request. 727 */ 728 if ((nlmp == 0) && olmco && lmc->lc_head) 729 remove_lmc(lml, clmp, lmc, olmco, path); 730 731 /* 732 * Finally, remove any link-map control list that was created. 733 */ 734 if (olmco) 735 remove_cntl(lml, olmco); 736 737 return (ghp); 738 } 739 740 /* 741 * dlopen() and dlsym() operations are the means by which a process can 742 * test for the existence of required dependencies. If the necessary 743 * dependencies don't exist, then associated functionality can't be used. 744 * However, the lack of dependencies can be fixed, and the dlopen() and 745 * dlsym() requests can be repeated. As we use a "not-found" AVL tree to 746 * cache any failed full path loads, secondary dlopen() and dlsym() requests 747 * will fail, even if the dependencies have been installed. 748 * 749 * dlopen() and dlsym() retry any failures by removing the "not-found" AVL 750 * tree. Should any dependencies be found, their names are added to the 751 * FullPath AVL tree. This routine removes any new "not-found" AVL tree, 752 * so that the dlopen() or dlsym() can replace the original "not-found" tree. 753 */ 754 inline static void 755 nfavl_remove(avl_tree_t *avlt) 756 { 757 PathNode *pnp; 758 void *cookie = NULL; 759 760 if (avlt) { 761 while ((pnp = avl_destroy_nodes(avlt, &cookie)) != NULL) { 762 free((void *)pnp->pn_name); 763 free(pnp); 764 } 765 avl_destroy(avlt); 766 free(avlt); 767 } 768 } 769 770 /* 771 * Internal dlopen() activity. Called from user level or directly for internal 772 * opens that require a handle. 773 */ 774 Grp_hdl * 775 dlmopen_intn(Lm_list *lml, const char *path, int mode, Rt_map *clmp, 776 uint_t flags, uint_t orig) 777 { 778 Rt_map *dlmp = 0; 779 Grp_hdl *ghp; 780 int in_nfavl = 0; 781 782 /* 783 * Check for magic link-map list values: 784 * 785 * LM_ID_BASE: Operate on the PRIMARY (executables) link map 786 * LM_ID_LDSO: Operation on ld.so.1's link map 787 * LM_ID_NEWLM: Create a new link-map. 788 */ 789 if (lml == (Lm_list *)LM_ID_NEWLM) { 790 if ((lml = calloc(sizeof (Lm_list), 1)) == 0) 791 return (0); 792 793 /* 794 * Establish the new link-map flags from the callers and those 795 * explicitly provided. 796 */ 797 lml->lm_tflags = LIST(clmp)->lm_tflags; 798 if (flags & FLG_RT_AUDIT) { 799 /* 800 * Unset any auditing flags - an auditor shouldn't be 801 * audited. Insure all audit dependencies are loaded. 802 */ 803 lml->lm_tflags &= ~LML_TFLG_AUD_MASK; 804 lml->lm_tflags |= 805 (LML_TFLG_NOLAZYLD | LML_TFLG_LOADFLTR); 806 lml->lm_flags |= LML_FLG_NOAUDIT; 807 } 808 809 if (list_append(&dynlm_list, lml) == 0) { 810 free(lml); 811 return (0); 812 } 813 if (newlmid(lml) == 0) { 814 list_delete(&dynlm_list, lml); 815 free(lml); 816 return (0); 817 } 818 } else if ((uintptr_t)lml < LM_ID_NUM) { 819 if ((uintptr_t)lml == LM_ID_BASE) 820 lml = &lml_main; 821 else if ((uintptr_t)lml == LM_ID_LDSO) 822 lml = &lml_rtld; 823 } 824 825 /* 826 * Open the required object on the associated link-map list. 827 */ 828 ghp = dlmopen_core(lml, path, mode, clmp, flags, orig, &in_nfavl); 829 830 /* 831 * If the object could not be found it is possible that the "not-found" 832 * AVL tree had indicated that the file does not exist. In case the 833 * file system has changes since this "not-found" recording was made, 834 * retry the dlopen() with a clean "not-found" AVL tree. 835 */ 836 if ((ghp == 0) && in_nfavl) { 837 avl_tree_t *oavlt = nfavl; 838 839 nfavl = NULL; 840 ghp = dlmopen_core(lml, path, mode, clmp, flags, orig, NULL); 841 842 /* 843 * If the file is found, then its full path name will have been 844 * registered in the FullPath AVL tree. Remove any new 845 * "not-found" AVL information, and restore the former AVL tree. 846 */ 847 nfavl_remove(nfavl); 848 nfavl = oavlt; 849 } 850 851 /* 852 * Establish the new link-map from which .init processing will begin. 853 * Ignore .init firing when constructing a configuration file (crle(1)). 854 */ 855 if (ghp && ((mode & RTLD_CONFGEN) == 0)) 856 dlmp = ghp->gh_ownlmp; 857 858 /* 859 * If loading an auditor was requested, and the auditor already existed, 860 * then the link-map returned will be to the original auditor. Remove 861 * the link-map control list that was created for this request. 862 */ 863 if (dlmp && (flags & FLG_RT_AUDIT) && (LIST(dlmp) != lml)) { 864 remove_lml(lml); 865 lml = LIST(dlmp); 866 } 867 868 /* 869 * If this load failed, remove any alternative link-map list. 870 */ 871 if ((ghp == 0) && 872 ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) == 0)) { 873 remove_lml(lml); 874 lml = 0; 875 } 876 877 /* 878 * Finish this load request. If objects were loaded, .init processing 879 * is computed. Finally, the debuggers are informed of the link-map 880 * lists being stable. 881 */ 882 load_completion(dlmp); 883 884 return (ghp); 885 } 886 887 /* 888 * Argument checking for dlopen. Only called via external entry. 889 */ 890 static Grp_hdl * 891 dlmopen_check(Lm_list *lml, const char *path, int mode, Rt_map *clmp) 892 { 893 /* 894 * Verify that a valid pathname has been supplied. 895 */ 896 if (path && (*path == '\0')) { 897 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLPATH)); 898 return (0); 899 } 900 901 /* 902 * Historically we've always verified the mode is either RTLD_NOW or 903 * RTLD_LAZY. RTLD_NOLOAD is valid by itself. Use of LM_ID_NEWLM 904 * requires a specific pathname, and use of RTLD_PARENT is meaningless. 905 */ 906 if ((mode & (RTLD_NOW | RTLD_LAZY | RTLD_NOLOAD)) == 0) { 907 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_1)); 908 return (0); 909 } 910 if ((mode & (RTLD_NOW | RTLD_LAZY)) == (RTLD_NOW | RTLD_LAZY)) { 911 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_2)); 912 return (0); 913 } 914 if ((lml == (Lm_list *)LM_ID_NEWLM) && (path == 0)) { 915 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_3)); 916 return (0); 917 } 918 if ((lml == (Lm_list *)LM_ID_NEWLM) && (mode & RTLD_PARENT)) { 919 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_4)); 920 return (0); 921 } 922 if (((mode & (RTLD_GROUP | RTLD_WORLD)) == 0) && 923 ((mode & RTLD_NOLOAD) == 0)) 924 mode |= (RTLD_GROUP | RTLD_WORLD); 925 if ((mode & RTLD_NOW) && (rtld_flags2 & RT_FL2_BINDLAZY)) { 926 mode &= ~RTLD_NOW; 927 mode |= RTLD_LAZY; 928 } 929 930 return (dlmopen_intn(lml, path, mode, clmp, 0, 0)); 931 } 932 933 #pragma weak dlopen = _dlopen 934 935 /* 936 * External entry for dlopen(3dl). On success, returns a pointer (handle) to 937 * the structure containing information about the newly added object, ie. can 938 * be used by dlsym(). On failure, returns a null pointer. 939 */ 940 void * 941 _dlopen(const char *path, int mode) 942 { 943 int entry; 944 Rt_map *clmp; 945 Grp_hdl *ghp; 946 Lm_list *lml; 947 948 entry = enter(0); 949 950 clmp = _caller(caller(), CL_EXECDEF); 951 lml = LIST(clmp); 952 953 ghp = dlmopen_check(lml, path, mode, clmp); 954 955 if (entry) 956 leave(lml, 0); 957 return ((void *)ghp); 958 } 959 960 /* 961 * External entry for dlmopen(3dl). 962 */ 963 #pragma weak dlmopen = _dlmopen 964 965 void * 966 _dlmopen(Lmid_t lmid, const char *path, int mode) 967 { 968 int entry; 969 Rt_map *clmp; 970 Grp_hdl *ghp; 971 972 entry = enter(0); 973 974 clmp = _caller(caller(), CL_EXECDEF); 975 976 ghp = dlmopen_check((Lm_list *)lmid, path, mode, clmp); 977 978 if (entry) 979 leave(LIST(clmp), 0); 980 return ((void *)ghp); 981 } 982 983 /* 984 * Handle processing for dlsym. 985 */ 986 Sym * 987 dlsym_handle(Grp_hdl *ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo, 988 int *in_nfavl) 989 { 990 Rt_map *nlmp, * lmp = ghp->gh_ownlmp; 991 Rt_map *clmp = slp->sl_cmap; 992 const char *name = slp->sl_name; 993 Sym *sym = 0; 994 Slookup sl = *slp; 995 996 sl.sl_flags = (LKUP_FIRST | LKUP_SPEC); 997 998 /* 999 * Continue processing a dlsym request. Lookup the required symbol in 1000 * each link-map specified by the handle. 1001 * 1002 * To leverage off of lazy loading, dlsym() requests can result in two 1003 * passes. The first descends the link-maps of any objects already in 1004 * the address space. If the symbol isn't located, and lazy 1005 * dependencies still exist, then a second pass is made to load these 1006 * dependencies if applicable. This model means that in the case where 1007 * a symbols exists in more than one object, the one located may not be 1008 * constant - this is the standard issue with lazy loading. In addition, 1009 * attempting to locate a symbol that doesn't exist will result in the 1010 * loading of all lazy dependencies on the given handle, which can 1011 * defeat some of the advantages of lazy loading (look out JVM). 1012 */ 1013 if (ghp->gh_flags & GPH_ZERO) { 1014 Lm_list *lml; 1015 1016 /* 1017 * If this symbol lookup is triggered from a dlopen(0) handle, 1018 * traverse the present link-map list looking for promiscuous 1019 * entries. 1020 */ 1021 for (nlmp = lmp; nlmp; nlmp = (Rt_map *)NEXT(nlmp)) { 1022 1023 /* 1024 * If this handle indicates we're only to look in the 1025 * first object check whether we're done. 1026 */ 1027 if ((nlmp != lmp) && (ghp->gh_flags & GPH_FIRST)) 1028 return ((Sym *)0); 1029 1030 if (!(MODE(nlmp) & RTLD_GLOBAL)) 1031 continue; 1032 if ((FLAGS(nlmp) & FLG_RT_DELETE) && 1033 ((FLAGS(clmp) & FLG_RT_DELETE) == 0)) 1034 continue; 1035 1036 sl.sl_imap = nlmp; 1037 if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo, 1038 in_nfavl)) 1039 return (sym); 1040 } 1041 1042 /* 1043 * If we're unable to locate the symbol and this link-map still 1044 * has pending lazy dependencies, start loading them in an 1045 * attempt to exhaust the search. Note that as we're already 1046 * traversing a dynamic linked list of link-maps there's no 1047 * need for elf_lazy_find_sym() to descend the link-maps itself. 1048 */ 1049 lml = LIST(lmp); 1050 if ((lml->lm_lazy) && 1051 ((lml->lm_flags & LML_FLG_NOPENDGLBLAZY) == 0)) { 1052 int lazy = 0; 1053 1054 DBG_CALL(Dbg_syms_lazy_rescan(lml, name)); 1055 1056 sl.sl_flags |= LKUP_NODESCENT; 1057 1058 for (nlmp = lmp; nlmp; nlmp = (Rt_map *)NEXT(nlmp)) { 1059 1060 if (!(MODE(nlmp) & RTLD_GLOBAL) || !LAZY(nlmp)) 1061 continue; 1062 if ((FLAGS(nlmp) & FLG_RT_DELETE) && 1063 ((FLAGS(clmp) & FLG_RT_DELETE) == 0)) 1064 continue; 1065 1066 lazy = 1; 1067 sl.sl_imap = nlmp; 1068 if (sym = elf_lazy_find_sym(&sl, _lmp, binfo, 1069 in_nfavl)) 1070 return (sym); 1071 } 1072 1073 /* 1074 * If no global, lazy loadable dependencies are found, 1075 * then none exist for this link-map list. Pending lazy 1076 * loadable objects may still exist for non-local 1077 * objects that are associated with this link-map list, 1078 * which is why we entered this fallback. Tag this 1079 * link-map list to prevent further searching for lazy 1080 * dependencies. 1081 */ 1082 if (lazy == 0) 1083 lml->lm_flags |= LML_FLG_NOPENDGLBLAZY; 1084 } 1085 } else { 1086 /* 1087 * Traverse the dlopen() handle for the presently loaded 1088 * link-maps. 1089 */ 1090 Grp_desc *gdp; 1091 Aliste idx; 1092 1093 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 1094 if ((gdp->gd_flags & GPD_DLSYM) == 0) 1095 continue; 1096 1097 sl.sl_imap = gdp->gd_depend; 1098 if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo, 1099 in_nfavl)) 1100 return (sym); 1101 1102 if (ghp->gh_flags & GPH_FIRST) 1103 return ((Sym *)0); 1104 } 1105 1106 /* 1107 * If we're unable to locate the symbol and this link-map still 1108 * has pending lazy dependencies, start loading them in an 1109 * attempt to exhaust the search. 1110 */ 1111 if ((LIST(lmp)->lm_lazy) && 1112 ((ghp->gh_flags & GPH_NOPENDLAZY) == 0)) { 1113 int lazy = 0; 1114 1115 DBG_CALL(Dbg_syms_lazy_rescan(LIST(lmp), name)); 1116 1117 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 1118 nlmp = gdp->gd_depend; 1119 1120 if (((gdp->gd_flags & GPD_DLSYM) == 0) || 1121 (LAZY(nlmp) == 0)) 1122 continue; 1123 1124 lazy = 1; 1125 sl.sl_imap = nlmp; 1126 if (sym = elf_lazy_find_sym(&sl, _lmp, 1127 binfo, in_nfavl)) 1128 return (sym); 1129 } 1130 1131 /* 1132 * If no lazy loadable dependencies are found, then 1133 * none exist for this handle. Pending lazy loadable 1134 * objects may still exist for the associated link-map 1135 * list, which is why we entered this fallback. Tag 1136 * this handle to prevent further searching for lazy 1137 * dependencies. 1138 */ 1139 if (lazy == 0) 1140 ghp->gh_flags |= GPH_NOPENDLAZY; 1141 } 1142 } 1143 return ((Sym *)0); 1144 } 1145 1146 /* 1147 * Core dlsym activity. Selects symbol lookup method from handle. 1148 */ 1149 void * 1150 dlsym_core(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp, 1151 int *in_nfavl) 1152 { 1153 Sym *sym = NULL; 1154 Syminfo *sip; 1155 Slookup sl; 1156 uint_t binfo; 1157 1158 /* 1159 * Initialize the symbol lookup data structure. 1160 * 1161 * Standard relocations are evaluated using the symbol index of the 1162 * associated relocation symbol. This index provides for loading 1163 * any lazy dependency and establishing a direct binding if necessary. 1164 * If a dlsym() operation originates from an object that contains a 1165 * symbol table entry for the same name, then we need to establish the 1166 * symbol index so that any dependency requirements can be triggered. 1167 * 1168 * Therefore, the first symbol lookup that is carried out is for the 1169 * symbol name within the calling object. If this symbol exists, the 1170 * symbols index is computed, added to the Slookup data, and thus used 1171 * to seed the real symbol lookup. 1172 */ 1173 SLOOKUP_INIT(sl, name, clmp, clmp, ld_entry_cnt, elf_hash(name), 1174 0, 0, 0, LKUP_SYMNDX); 1175 1176 if ((FCT(clmp) == &elf_fct) && 1177 ((sym = SYMINTP(clmp)(&sl, 0, 0, NULL)) != NULL)) { 1178 sl.sl_rsymndx = (((ulong_t)sym - 1179 (ulong_t)SYMTAB(clmp)) / SYMENT(clmp)); 1180 sl.sl_rsym = sym; 1181 } 1182 1183 if (sym && (ELF_ST_VISIBILITY(sym->st_other) == STV_SINGLETON)) { 1184 Rt_map *hlmp = LIST(clmp)->lm_head; 1185 1186 /* 1187 * If a symbol reference is known, and that reference indicates 1188 * that the symbol is a singleton, then the search for the 1189 * symbol must follow the default search path. 1190 */ 1191 DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 0, 1192 DBG_DLSYM_SINGLETON)); 1193 1194 sl.sl_imap = hlmp; 1195 sl.sl_flags = LKUP_SPEC; 1196 if (handle == RTLD_PROBE) 1197 sl.sl_flags |= LKUP_NOFALLBACK; 1198 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl); 1199 1200 } else if (handle == RTLD_NEXT) { 1201 Rt_map *nlmp; 1202 1203 /* 1204 * If this handle is RTLD_NEXT determine whether a lazy load 1205 * from the caller might provide the next object. This mimics 1206 * the lazy loading initialization normally carried out by 1207 * lookup_sym(), however here, we must do this up-front, as 1208 * lookup_sym() will be used to inspect the next object. 1209 */ 1210 if ((sl.sl_rsymndx) && ((sip = SYMINFO(clmp)) != 0)) { 1211 /* LINTED */ 1212 sip = (Syminfo *)((char *)sip + 1213 (sl.sl_rsymndx * SYMINENT(clmp))); 1214 1215 if ((sip->si_flags & SYMINFO_FLG_DIRECT) && 1216 (sip->si_boundto < SYMINFO_BT_LOWRESERVE)) 1217 (void) elf_lazy_load(clmp, &sl, 1218 sip->si_boundto, name, in_nfavl); 1219 1220 /* 1221 * Clear the symbol index, so as not to confuse 1222 * lookup_sym() of the next object. 1223 */ 1224 sl.sl_rsymndx = 0; 1225 sl.sl_rsym = 0; 1226 } 1227 1228 /* 1229 * If the handle is RTLD_NEXT start searching in the next link 1230 * map from the callers. Determine permissions from the 1231 * present link map. Indicate to lookup_sym() that we're on an 1232 * RTLD_NEXT request so that it will use the callers link map to 1233 * start any possible lazy dependency loading. 1234 */ 1235 sl.sl_imap = nlmp = (Rt_map *)NEXT(clmp); 1236 1237 DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 1238 (nlmp ? NAME(nlmp) : MSG_INTL(MSG_STR_NULL)), 1239 DBG_DLSYM_NEXT)); 1240 1241 if (nlmp == 0) 1242 return (0); 1243 1244 sl.sl_flags = LKUP_NEXT; 1245 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl); 1246 1247 } else if (handle == RTLD_SELF) { 1248 /* 1249 * If the handle is RTLD_SELF start searching from the caller. 1250 */ 1251 DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, NAME(clmp), 1252 DBG_DLSYM_SELF)); 1253 1254 sl.sl_imap = clmp; 1255 sl.sl_flags = (LKUP_SPEC | LKUP_SELF); 1256 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl); 1257 1258 } else if (handle == RTLD_DEFAULT) { 1259 Rt_map *hlmp = LIST(clmp)->lm_head; 1260 1261 /* 1262 * If the handle is RTLD_DEFAULT mimic the standard symbol 1263 * lookup as would be triggered by a relocation. 1264 */ 1265 DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 0, 1266 DBG_DLSYM_DEFAULT)); 1267 1268 sl.sl_imap = hlmp; 1269 sl.sl_flags = LKUP_SPEC; 1270 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl); 1271 1272 } else if (handle == RTLD_PROBE) { 1273 Rt_map *hlmp = LIST(clmp)->lm_head; 1274 1275 /* 1276 * If the handle is RTLD_PROBE, mimic the standard symbol 1277 * lookup as would be triggered by a relocation, however do 1278 * not fall back to a lazy loading rescan if the symbol can't be 1279 * found within the currently loaded objects. Note, a lazy 1280 * loaded dependency required by the caller might still get 1281 * loaded to satisfy this request, but no exhaustive lazy load 1282 * rescan is carried out. 1283 */ 1284 DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 0, 1285 DBG_DLSYM_PROBE)); 1286 1287 sl.sl_imap = hlmp; 1288 sl.sl_flags = (LKUP_SPEC | LKUP_NOFALLBACK); 1289 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl); 1290 1291 } else { 1292 Grp_hdl *ghp = (Grp_hdl *)handle; 1293 1294 /* 1295 * Look in the shared object specified by the handle and in all 1296 * of its dependencies. 1297 */ 1298 DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 1299 NAME(ghp->gh_ownlmp), DBG_DLSYM_DEF)); 1300 1301 sym = LM_DLSYM(clmp)(ghp, &sl, dlmp, &binfo, in_nfavl); 1302 } 1303 1304 if (sym) { 1305 Lm_list *lml = LIST(clmp); 1306 Addr addr = sym->st_value; 1307 1308 if (!(FLAGS(*dlmp) & FLG_RT_FIXED)) 1309 addr += ADDR(*dlmp); 1310 1311 /* 1312 * Indicate that the defining object is now used. 1313 */ 1314 if (*dlmp != clmp) 1315 FLAGS1(*dlmp) |= FL1_RT_USED; 1316 1317 DBG_CALL(Dbg_bind_global(clmp, 0, 0, (Xword)-1, PLT_T_NONE, 1318 *dlmp, addr, sym->st_value, name, binfo)); 1319 1320 if ((lml->lm_tflags | FLAGS1(clmp)) & LML_TFLG_AUD_SYMBIND) { 1321 uint_t sb_flags = LA_SYMB_DLSYM; 1322 /* LINTED */ 1323 uint_t symndx = (uint_t)(((Xword)sym - 1324 (Xword)SYMTAB(*dlmp)) / SYMENT(*dlmp)); 1325 addr = audit_symbind(clmp, *dlmp, sym, symndx, addr, 1326 &sb_flags); 1327 } 1328 return ((void *)addr); 1329 } else 1330 return (0); 1331 } 1332 1333 /* 1334 * Internal dlsym activity. Called from user level or directly for internal 1335 * symbol lookup. 1336 */ 1337 void * 1338 dlsym_intn(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp) 1339 { 1340 Rt_map *llmp = 0; 1341 void *error; 1342 Aliste idx; 1343 Grp_desc *gdp; 1344 int in_nfavl = 0; 1345 1346 /* 1347 * While looking for symbols it's quite possible that additional objects 1348 * get loaded from lazy loading. These objects will have been added to 1349 * the same link-map list as those objects on the handle. Remember this 1350 * list for later investigation. 1351 */ 1352 if ((handle == RTLD_NEXT) || (handle == RTLD_DEFAULT) || 1353 (handle == RTLD_SELF) || (handle == RTLD_PROBE)) 1354 llmp = LIST(clmp)->lm_tail; 1355 else { 1356 Grp_hdl *ghp = (Grp_hdl *)handle; 1357 1358 if (ghp->gh_ownlmp) 1359 llmp = LIST(ghp->gh_ownlmp)->lm_tail; 1360 else { 1361 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 1362 if ((llmp = LIST(gdp->gd_depend)->lm_tail) != 0) 1363 break; 1364 } 1365 } 1366 } 1367 1368 error = dlsym_core(handle, name, clmp, dlmp, &in_nfavl); 1369 1370 /* 1371 * If the symbol could not be found it is possible that the "not-found" 1372 * AVL tree had indicated that a required file does not exist. In case 1373 * the file system has changed since this "not-found" recording was 1374 * made, retry the dlsym() with a clean "not-found" AVL tree. 1375 */ 1376 if ((error == 0) && in_nfavl) { 1377 avl_tree_t *oavlt = nfavl; 1378 1379 nfavl = NULL; 1380 error = dlsym_core(handle, name, clmp, dlmp, NULL); 1381 1382 /* 1383 * If the symbol is found, then any file that was loaded will 1384 * have had its full path name registered in the FullPath AVL 1385 * tree. Remove any new "not-found" AVL information, and 1386 * restore the former AVL tree. 1387 */ 1388 nfavl_remove(nfavl); 1389 nfavl = oavlt; 1390 } 1391 1392 if (error == 0) { 1393 /* 1394 * Cache the error message, as Java tends to fall through this 1395 * code many times. 1396 */ 1397 if (nosym_str == 0) 1398 nosym_str = MSG_INTL(MSG_GEN_NOSYM); 1399 eprintf(LIST(clmp), ERR_FATAL, nosym_str, name); 1400 } 1401 1402 load_completion(llmp); 1403 return (error); 1404 } 1405 1406 /* 1407 * Argument checking for dlsym. Only called via external entry. 1408 */ 1409 static void * 1410 dlsym_check(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp) 1411 { 1412 /* 1413 * Verify the arguments. 1414 */ 1415 if (name == 0) { 1416 eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_ILLSYM)); 1417 return (0); 1418 } 1419 if ((handle != RTLD_NEXT) && (handle != RTLD_DEFAULT) && 1420 (handle != RTLD_SELF) && (handle != RTLD_PROBE) && 1421 (hdl_validate((Grp_hdl *)handle) == 0)) { 1422 eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL)); 1423 return (0); 1424 } 1425 return (dlsym_intn(handle, name, clmp, dlmp)); 1426 } 1427 1428 1429 #pragma weak dlsym = _dlsym 1430 1431 /* 1432 * External entry for dlsym(). On success, returns the address of the specified 1433 * symbol. On error returns a null. 1434 */ 1435 void * 1436 _dlsym(void *handle, const char *name) 1437 { 1438 int entry; 1439 Rt_map *clmp, *dlmp = 0; 1440 void *addr; 1441 1442 entry = enter(0); 1443 1444 clmp = _caller(caller(), CL_EXECDEF); 1445 1446 addr = dlsym_check(handle, name, clmp, &dlmp); 1447 1448 if (dlmp) 1449 is_dep_ready(dlmp, clmp, DBG_WAIT_SYMBOL); 1450 1451 if (entry && dlmp) 1452 is_dep_init(dlmp, clmp); 1453 1454 if (entry) 1455 leave(LIST(clmp), 0); 1456 return (addr); 1457 } 1458 1459 /* 1460 * Core dladdr activity. 1461 */ 1462 static void 1463 dladdr_core(Rt_map *clmp, void *addr, Dl_info *dlip, void **info, int flags) 1464 { 1465 /* 1466 * Set up generic information and any defaults. 1467 */ 1468 dlip->dli_fname = PATHNAME(clmp); 1469 1470 dlip->dli_fbase = (void *)ADDR(clmp); 1471 dlip->dli_sname = 0; 1472 dlip->dli_saddr = 0; 1473 1474 /* 1475 * Determine the nearest symbol to this address. 1476 */ 1477 LM_DLADDR(clmp)((ulong_t)addr, clmp, dlip, info, flags); 1478 } 1479 1480 #pragma weak dladdr = _dladdr 1481 1482 /* 1483 * External entry for dladdr(3dl) and dladdr1(3dl). Returns an information 1484 * structure that reflects the symbol closest to the address specified. 1485 */ 1486 int 1487 _dladdr(void *addr, Dl_info *dlip) 1488 { 1489 int entry, error; 1490 Rt_map *clmp; 1491 1492 entry = enter(0); 1493 1494 /* 1495 * Use our calling technique to determine what object is associated 1496 * with the supplied address. If a caller can't be determined, 1497 * indicate the failure. 1498 */ 1499 if ((clmp = _caller((caddr_t)addr, CL_NONE)) == 0) { 1500 eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_INVADDR), 1501 EC_NATPTR(addr)); 1502 error = 0; 1503 } else { 1504 dladdr_core(clmp, addr, dlip, 0, 0); 1505 error = 1; 1506 } 1507 1508 if (entry) 1509 leave(0, 0); 1510 return (error); 1511 } 1512 1513 #pragma weak dladdr1 = _dladdr1 1514 1515 int 1516 _dladdr1(void *addr, Dl_info *dlip, void **info, int flags) 1517 { 1518 int entry, error = 0; 1519 Rt_map *clmp; 1520 1521 /* 1522 * Validate any flags. 1523 */ 1524 if (flags) { 1525 int request; 1526 1527 if (((request = (flags & RTLD_DL_MASK)) != RTLD_DL_SYMENT) && 1528 (request != RTLD_DL_LINKMAP)) { 1529 eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_ILLFLAGS), 1530 flags); 1531 return (0); 1532 } 1533 if (info == 0) { 1534 eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_ILLINFO), flags); 1535 return (0); 1536 } 1537 } 1538 1539 entry = enter(0); 1540 1541 /* 1542 * Use our calling technique to determine what object is associated 1543 * with the supplied address. If a caller can't be determined, 1544 * indicate the failure. 1545 */ 1546 if ((clmp = _caller((caddr_t)addr, CL_NONE)) == 0) { 1547 eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_INVADDR), 1548 EC_NATPTR(addr)); 1549 error = 0; 1550 } else { 1551 dladdr_core(clmp, addr, dlip, info, flags); 1552 error = 1; 1553 } 1554 1555 if (entry) 1556 leave(0, 0); 1557 return (error); 1558 } 1559 1560 /* 1561 * Core dldump activity. 1562 */ 1563 static int 1564 dldump_core(Lm_list *lml, const char *ipath, const char *opath, int flags) 1565 { 1566 Addr addr = 0; 1567 Rt_map *lmp; 1568 1569 /* 1570 * Verify any arguments first. 1571 */ 1572 if ((!opath || (*opath == '\0')) || (ipath && (*ipath == '\0'))) { 1573 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLPATH)); 1574 return (1); 1575 } 1576 1577 /* 1578 * If an input file is specified make sure its one of our dependencies 1579 * on the main link-map list. Note, this has really all evolved for 1580 * crle(), which uses libcrle.so on an alternative link-map to trigger 1581 * dumping objects from the main link-map list. If we ever want to 1582 * dump objects from alternative link-maps, this model is going to 1583 * have to be revisited. 1584 */ 1585 if (ipath) { 1586 if ((lmp = is_so_loaded(&lml_main, ipath, NULL)) == 0) { 1587 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NOFILE), 1588 ipath); 1589 return (1); 1590 } 1591 if (FLAGS(lmp) & FLG_RT_ALTER) { 1592 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_ALTER), ipath); 1593 return (1); 1594 } 1595 if (FLAGS(lmp) & FLG_RT_NODUMP) { 1596 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NODUMP), 1597 ipath); 1598 return (1); 1599 } 1600 } else 1601 lmp = lml_main.lm_head; 1602 1603 1604 DBG_CALL(Dbg_file_dldump(lmp, opath, flags)); 1605 1606 /* 1607 * If the object being dump'ed isn't fixed identify its mapping. 1608 */ 1609 if (!(FLAGS(lmp) & FLG_RT_FIXED)) 1610 addr = ADDR(lmp); 1611 1612 /* 1613 * As rt_dldump() will effectively lazy load the necessary support 1614 * libraries, make sure ld.so.1 is initialized for plt relocations. 1615 */ 1616 if (elf_rtld_load() == 0) 1617 return (0); 1618 1619 /* 1620 * Dump the required image. 1621 */ 1622 return (rt_dldump(lmp, opath, flags, addr)); 1623 } 1624 1625 #pragma weak dldump = _dldump 1626 1627 /* 1628 * External entry for dldump(3c). Returns 0 on success, non-zero otherwise. 1629 */ 1630 int 1631 _dldump(const char *ipath, const char *opath, int flags) 1632 { 1633 int error, entry; 1634 Rt_map *clmp; 1635 1636 entry = enter(0); 1637 1638 clmp = _caller(caller(), CL_EXECDEF); 1639 1640 error = dldump_core(LIST(clmp), ipath, opath, flags); 1641 1642 if (entry) 1643 leave(LIST(clmp), 0); 1644 return (error); 1645 } 1646 1647 /* 1648 * get_linkmap_id() translates Lm_list * pointers to the Link_map id as used by 1649 * the rtld_db and dlmopen() interfaces. It checks to see if the Link_map is 1650 * one of the primary ones and if so returns it's special token: 1651 * LM_ID_BASE 1652 * LM_ID_LDSO 1653 * 1654 * If it's not one of the primary link_map id's it will instead returns a 1655 * pointer to the Lm_list structure which uniquely identifies the Link_map. 1656 */ 1657 Lmid_t 1658 get_linkmap_id(Lm_list *lml) 1659 { 1660 if (lml->lm_flags & LML_FLG_BASELM) 1661 return (LM_ID_BASE); 1662 if (lml->lm_flags & LML_FLG_RTLDLM) 1663 return (LM_ID_LDSO); 1664 1665 return ((Lmid_t)lml); 1666 } 1667 1668 /* 1669 * Extract information for a dlopen() handle. 1670 */ 1671 static int 1672 dlinfo_core(void *handle, int request, void *p, Rt_map *clmp) 1673 { 1674 Lm_list *lml = LIST(clmp); 1675 Rt_map *lmp; 1676 1677 if ((request > RTLD_DI_MAX) || (p == 0)) { 1678 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL)); 1679 return (-1); 1680 } 1681 1682 /* 1683 * Return configuration cache name and address. 1684 */ 1685 if (request == RTLD_DI_CONFIGADDR) { 1686 Dl_info *dlip = (Dl_info *)p; 1687 1688 if ((config->c_name == 0) || (config->c_bgn == 0) || 1689 (config->c_end == 0)) { 1690 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_NOCONFIG)); 1691 return (-1); 1692 } 1693 dlip->dli_fname = config->c_name; 1694 dlip->dli_fbase = (void *)config->c_bgn; 1695 return (0); 1696 } 1697 1698 /* 1699 * Return profiled object name (used by ldprof audit library). 1700 */ 1701 if (request == RTLD_DI_PROFILENAME) { 1702 if (profile_name == 0) { 1703 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_NOPROFNAME)); 1704 return (-1); 1705 } 1706 1707 *(const char **)p = profile_name; 1708 return (0); 1709 } 1710 if (request == RTLD_DI_PROFILEOUT) { 1711 /* 1712 * If a profile destination directory hasn't been specified 1713 * provide a default. 1714 */ 1715 if (profile_out == 0) 1716 profile_out = MSG_ORIG(MSG_PTH_VARTMP); 1717 1718 *(const char **)p = profile_out; 1719 return (0); 1720 } 1721 1722 /* 1723 * Obtain or establish a termination signal. 1724 */ 1725 if (request == RTLD_DI_GETSIGNAL) { 1726 *(int *)p = killsig; 1727 return (0); 1728 } 1729 1730 if (request == RTLD_DI_SETSIGNAL) { 1731 sigset_t set; 1732 int sig = *(int *)p; 1733 1734 /* 1735 * Determine whether the signal is in range. 1736 */ 1737 (void) sigfillset(&set); 1738 if (sigismember(&set, sig) != 1) { 1739 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_INVSIG), sig); 1740 return (-1); 1741 } 1742 1743 killsig = sig; 1744 return (0); 1745 } 1746 1747 /* 1748 * For any other request a link-map is required. Verify the handle. 1749 */ 1750 if (handle == RTLD_SELF) 1751 lmp = clmp; 1752 else { 1753 Grp_hdl *ghp = (Grp_hdl *)handle; 1754 1755 if (!hdl_validate(ghp)) { 1756 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL)); 1757 return (-1); 1758 } 1759 lmp = ghp->gh_ownlmp; 1760 } 1761 1762 /* 1763 * Obtain the process arguments, environment and auxv. Note, as the 1764 * environment can be modified by the user (putenv(3c)), reinitialize 1765 * the environment pointer on each request. 1766 */ 1767 if (request == RTLD_DI_ARGSINFO) { 1768 Dl_argsinfo *aip = (Dl_argsinfo *)p; 1769 Lm_list *lml = LIST(lmp); 1770 1771 *aip = argsinfo; 1772 if (lml->lm_flags & LML_FLG_ENVIRON) 1773 aip->dla_envp = *(lml->lm_environ); 1774 1775 return (0); 1776 } 1777 1778 /* 1779 * Return Lmid_t of the Link-Map list that the specified object is 1780 * loaded on. 1781 */ 1782 if (request == RTLD_DI_LMID) { 1783 *(Lmid_t *)p = get_linkmap_id(LIST(lmp)); 1784 return (0); 1785 } 1786 1787 /* 1788 * Return a pointer to the Link-Map structure associated with the 1789 * specified object. 1790 */ 1791 if (request == RTLD_DI_LINKMAP) { 1792 *(Link_map **)p = (Link_map *)lmp; 1793 return (0); 1794 } 1795 1796 /* 1797 * Return search path information, or the size of the buffer required 1798 * to store the information. 1799 */ 1800 if ((request == RTLD_DI_SERINFO) || (request == RTLD_DI_SERINFOSIZE)) { 1801 Pnode *dir, *dirlist = (Pnode *)0; 1802 Dl_serinfo *info; 1803 Dl_serpath *path; 1804 char *strs; 1805 size_t size = sizeof (Dl_serinfo); 1806 uint_t cnt = 0; 1807 1808 info = (Dl_serinfo *)p; 1809 path = &info->dls_serpath[0]; 1810 strs = (char *)&info->dls_serpath[info->dls_cnt]; 1811 1812 /* 1813 * Traverse search path entries for this object. 1814 */ 1815 while ((dir = get_next_dir(&dirlist, lmp, 0)) != 0) { 1816 size_t _size; 1817 1818 if (dir->p_name == 0) 1819 continue; 1820 1821 /* 1822 * If configuration information exists, it's possible 1823 * this path has been identified as non-existent, if so 1824 * ignore it. 1825 */ 1826 if (dir->p_info) { 1827 Rtc_obj *dobj = (Rtc_obj *)dir->p_info; 1828 if (dobj->co_flags & RTC_OBJ_NOEXIST) 1829 continue; 1830 } 1831 1832 /* 1833 * Keep track of search path count and total info size. 1834 */ 1835 if (cnt++) 1836 size += sizeof (Dl_serpath); 1837 _size = strlen(dir->p_name) + 1; 1838 size += _size; 1839 1840 if (request == RTLD_DI_SERINFOSIZE) 1841 continue; 1842 1843 /* 1844 * If we're filling in search path information, confirm 1845 * there's sufficient space. 1846 */ 1847 if (size > info->dls_size) { 1848 eprintf(lml, ERR_FATAL, 1849 MSG_INTL(MSG_ARG_SERSIZE), 1850 EC_OFF(info->dls_size)); 1851 return (-1); 1852 } 1853 if (cnt > info->dls_cnt) { 1854 eprintf(lml, ERR_FATAL, 1855 MSG_INTL(MSG_ARG_SERCNT), info->dls_cnt); 1856 return (-1); 1857 } 1858 1859 /* 1860 * Append the path to the information buffer. 1861 */ 1862 (void) strcpy(strs, dir->p_name); 1863 path->dls_name = strs; 1864 path->dls_flags = dir->p_orig; 1865 1866 strs = strs + _size; 1867 path++; 1868 } 1869 1870 /* 1871 * If we're here to size the search buffer fill it in. 1872 */ 1873 if (request == RTLD_DI_SERINFOSIZE) { 1874 info->dls_size = size; 1875 info->dls_cnt = cnt; 1876 } 1877 } 1878 1879 /* 1880 * Return the origin of the object associated with this link-map. 1881 * Basically return the dirname(1) of the objects fullpath. 1882 */ 1883 if (request == RTLD_DI_ORIGIN) { 1884 char *str = (char *)p; 1885 1886 if (DIRSZ(lmp) == 0) 1887 (void) fullpath(lmp, 0); 1888 1889 (void) strncpy(str, ORIGNAME(lmp), DIRSZ(lmp)); 1890 str += DIRSZ(lmp); 1891 *str = '\0'; 1892 1893 return (0); 1894 } 1895 1896 return (0); 1897 } 1898 1899 #pragma weak dlinfo = _dlinfo 1900 1901 /* 1902 * External entry for dlinfo(3dl). 1903 */ 1904 int 1905 _dlinfo(void *handle, int request, void *p) 1906 { 1907 int error, entry; 1908 Rt_map *clmp; 1909 1910 entry = enter(0); 1911 1912 clmp = _caller(caller(), CL_EXECDEF); 1913 1914 error = dlinfo_core(handle, request, p, clmp); 1915 1916 if (entry) 1917 leave(LIST(clmp), 0); 1918 return (error); 1919 } 1920