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