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 = (uintptr_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 = (uintptr_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 = (uintptr_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, uint_t orig) 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, orig)) == 0) { 689 remove_lml(lml); 690 return (0); 691 } 692 if (((pnp->p_orig & (PN_TKN_ISALIST | PN_TKN_HWCAP)) || pnp->p_next) && 693 ((mode & RTLD_FIRST) == 0)) { 694 remove_pnode(pnp); 695 remove_lml(lml); 696 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_5)); 697 return (0); 698 } 699 700 /* 701 * Create a new link-map control list for this request, and load the 702 * associated object. 703 */ 704 if ((lmc = alist_append(&(lml->lm_lists), 0, sizeof (Lm_cntl), 705 AL_CNT_LMLISTS)) == 0) { 706 remove_pnode(pnp); 707 remove_lml(lml); 708 return (0); 709 } 710 olmco = nlmco = (Aliste)((char *)lmc - (char *)lml->lm_lists); 711 712 nlmp = load_one(lml, nlmco, pnp, clmp, mode, 713 (flags | FLG_RT_HANDLE), &ghp); 714 715 /* 716 * Remove any expanded pathname infrastructure, and if the dependency 717 * couldn't be loaded, cleanup. 718 */ 719 remove_pnode(pnp); 720 if (nlmp == 0) { 721 remove_cntl(lml, olmco); 722 remove_lml(lml); 723 return (0); 724 } 725 726 /* 727 * If loading an auditor was requested, and the auditor already existed, 728 * then the link-map returned will be to the original auditor. The new 729 * link-map list that was initially created, and the associated link-map 730 * control list are no longer needed. As the auditor is already loaded, 731 * we're probably done, but fall through in case additional relocations 732 * would be triggered by the mode of the caller. 733 */ 734 if ((flags & FLG_RT_AUDIT) && (LIST(nlmp) != lml)) { 735 remove_cntl(lml, olmco); 736 remove_lml(lml); 737 lml = LIST(nlmp); 738 olmco = 0; 739 nlmco = ALO_DATA; 740 } 741 742 /* 743 * Finish processing the objects associated with this request. 744 */ 745 if ((analyze_lmc(lml, nlmco, nlmp) == 0) || 746 (relocate_lmc(lml, nlmco, nlmp) == 0)) { 747 (void) dlclose_core(ghp, clmp); 748 if (olmco && lm_salvage(lml, 1, olmco)) { 749 remove_cntl(lml, olmco); 750 remove_lml(lml); 751 } 752 return (0); 753 } 754 755 /* 756 * After a successful load, any objects collected on the new link-map 757 * control list will have been moved to the callers link-map control 758 * list. This control list can now be deleted. 759 */ 760 if (olmco) 761 remove_cntl(lml, olmco); 762 763 return (ghp); 764 } 765 766 /* 767 * Internal dlopen() activity. Called from user level or directly for internal 768 * opens that require a handle. 769 */ 770 Grp_hdl * 771 dlmopen_intn(Lm_list * lml, const char *path, int mode, Rt_map * clmp, 772 uint_t flags, uint_t orig, int *loaded) 773 { 774 Rt_map * dlmp = 0; 775 Grp_hdl * ghp; 776 777 /* 778 * Determine the link-map that has just been loaded. 779 */ 780 if ((ghp = dlmopen_core(lml, path, mode, clmp, flags, 781 (orig | PN_SER_DLOPEN))) != 0) { 782 /* 783 * Establish the new link-map from which .init processing will 784 * begin. Ignore .init firing when constructing a configuration 785 * file (crle(1)). 786 */ 787 if ((mode & RTLD_CONFGEN) == 0) 788 dlmp = ghp->gh_owner; 789 } 790 791 /* 792 * Return the number of objects loaded if required. This is used to 793 * trigger used() processing on return from a dlopen(). 794 */ 795 if (loaded && dlmp) 796 *loaded = LIST(dlmp)->lm_init; 797 798 load_completion(dlmp, clmp); 799 return (ghp); 800 } 801 802 /* 803 * Argument checking for dlopen. Only called via external entry. 804 */ 805 static Grp_hdl * 806 dlmopen_check(Lm_list * lml, const char *path, int mode, Rt_map * clmp, 807 int *loaded) 808 { 809 /* 810 * Verify that a valid pathname has been supplied. 811 */ 812 if (path && (*path == '\0')) { 813 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLPATH)); 814 return (0); 815 } 816 817 /* 818 * Historically we've always verified the mode is either RTLD_NOW or 819 * RTLD_LAZY. RTLD_NOLOAD is valid by itself. Use of LM_ID_NEWLM 820 * requires a specific pathname, and use of RTLD_PARENT is meaningless. 821 */ 822 if ((mode & (RTLD_NOW | RTLD_LAZY | RTLD_NOLOAD)) == 0) { 823 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_1)); 824 return (0); 825 } 826 if ((mode & (RTLD_NOW | RTLD_LAZY)) == (RTLD_NOW | RTLD_LAZY)) { 827 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_2)); 828 return (0); 829 } 830 if ((lml == (Lm_list *)LM_ID_NEWLM) && (path == 0)) { 831 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_3)); 832 return (0); 833 } 834 if ((lml == (Lm_list *)LM_ID_NEWLM) && (mode & RTLD_PARENT)) { 835 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_4)); 836 return (0); 837 } 838 if (((mode & (RTLD_GROUP | RTLD_WORLD)) == 0) && 839 ((mode & RTLD_NOLOAD) == 0)) 840 mode |= (RTLD_GROUP | RTLD_WORLD); 841 if ((mode & RTLD_NOW) && (rtld_flags2 & RT_FL2_BINDLAZY)) { 842 mode &= ~RTLD_NOW; 843 mode |= RTLD_LAZY; 844 } 845 846 return (dlmopen_intn(lml, path, mode, clmp, 0, 0, loaded)); 847 } 848 849 #pragma weak dlopen = _dlopen 850 851 /* 852 * External entry for dlopen(3dl). On success, returns a pointer (handle) to 853 * the structure containing information about the newly added object, ie. can 854 * be used by dlsym(). On failure, returns a null pointer. 855 */ 856 void * 857 _dlopen(const char *path, int mode) 858 { 859 int entry, loaded = 0; 860 uint_t dbg_save; 861 Word lmflags; 862 Rt_map * clmp; 863 Grp_hdl * ghp; 864 Lm_list * lml; 865 866 entry = enter(); 867 868 clmp = _caller(caller(), CL_EXECDEF); 869 lml = LIST(clmp); 870 871 if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) { 872 dbg_save = dbg_mask; 873 dbg_mask = 0; 874 } 875 876 ghp = dlmopen_check(lml, path, mode, clmp, &loaded); 877 878 if (entry && ghp && loaded) 879 unused(lml); 880 881 if (lmflags & LML_FLG_RTLDLM) 882 dbg_mask = dbg_save; 883 884 if (entry) 885 leave(lml); 886 return ((void *)ghp); 887 } 888 889 /* 890 * External entry for dlmopen(3dl). 891 */ 892 #pragma weak dlmopen = _dlmopen 893 894 void * 895 _dlmopen(Lmid_t lmid, const char *path, int mode) 896 { 897 int entry, loaded = 0; 898 uint_t dbg_save; 899 Word lmflags; 900 Rt_map * clmp; 901 Grp_hdl * ghp; 902 903 entry = enter(); 904 905 clmp = _caller(caller(), CL_EXECDEF); 906 907 if ((lmflags = LIST(clmp)->lm_flags) & LML_FLG_RTLDLM) { 908 dbg_save = dbg_mask; 909 dbg_mask = 0; 910 } 911 912 ghp = dlmopen_check((Lm_list *)lmid, path, mode, clmp, &loaded); 913 914 if (entry && ghp && ghp->gh_owner && loaded) 915 unused(LIST(ghp->gh_owner)); 916 917 if (lmflags & LML_FLG_RTLDLM) 918 dbg_mask = dbg_save; 919 920 if (entry) 921 leave(LIST(clmp)); 922 return ((void *)ghp); 923 } 924 925 /* 926 * Handle processing for dlsym. 927 */ 928 Sym * 929 dlsym_handle(Grp_hdl * ghp, Slookup * slp, Rt_map ** _lmp, uint_t *binfo) 930 { 931 Rt_map *nlmp, * lmp = ghp->gh_owner; 932 Rt_map *clmp = slp->sl_cmap; 933 const char *name = slp->sl_name; 934 Sym *sym = 0; 935 Slookup sl = *slp; 936 937 sl.sl_flags = (LKUP_FIRST | LKUP_SPEC); 938 939 /* 940 * Continue processing a dlsym request. Lookup the required symbol in 941 * each link-map specified by the handle. 942 * 943 * To leverage off of lazy loading, dlsym() requests can result in two 944 * passes. The first descends the link-maps of any objects already in 945 * the address space. If the symbol isn't located, and lazy 946 * dependencies still exist, then a second pass is made to load these 947 * dependencies if applicable. This model means that in the case where 948 * a symbols exists in more than one object, the one located may not be 949 * constant - this is the standard issue with lazy loading. In addition, 950 * attempting to locate a symbol that doesn't exist will result in the 951 * loading of all lazy dependencies on the given handle, which can 952 * defeat some of the advantages of lazy loading (look out JVM). 953 */ 954 if (ghp->gh_flags & GPH_ZERO) { 955 /* 956 * If this symbol lookup is triggered from a dlopen(0) handle, 957 * traverse the present link-map list looking for promiscuous 958 * entries. 959 */ 960 for (nlmp = lmp; nlmp; nlmp = (Rt_map *)NEXT(nlmp)) { 961 962 /* 963 * If this handle indicates we're only to look in the 964 * first object check whether we're done. 965 */ 966 if ((nlmp != lmp) && (ghp->gh_flags & GPH_FIRST)) 967 return ((Sym *)0); 968 969 if (!(MODE(nlmp) & RTLD_GLOBAL)) 970 continue; 971 if ((FLAGS(nlmp) & FLG_RT_DELETE) && 972 ((FLAGS(clmp) & FLG_RT_DELETE) == 0)) 973 continue; 974 975 sl.sl_imap = nlmp; 976 if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo)) 977 return (sym); 978 } 979 980 /* 981 * If we're unable to locate the symbol and this link-map still 982 * has pending lazy dependencies, start loading them in an 983 * attempt to exhaust the search. Note that as we're already 984 * traversing a dynamic linked list of link-maps there's no 985 * need for elf_lazy_find_sym() to descend the link-maps itself. 986 */ 987 if (LIST(lmp)->lm_lazy) { 988 DBG_CALL(Dbg_syms_lazy_rescan(name)); 989 990 sl.sl_flags |= LKUP_NODESCENT; 991 992 for (nlmp = lmp; nlmp; nlmp = (Rt_map *)NEXT(nlmp)) { 993 994 if (!(MODE(nlmp) & RTLD_GLOBAL) || !LAZY(nlmp)) 995 continue; 996 if ((FLAGS(nlmp) & FLG_RT_DELETE) && 997 ((FLAGS(clmp) & FLG_RT_DELETE) == 0)) 998 continue; 999 1000 sl.sl_imap = nlmp; 1001 if (sym = elf_lazy_find_sym(&sl, _lmp, binfo)) 1002 return (sym); 1003 } 1004 } 1005 } else { 1006 /* 1007 * Traverse the dlopen() handle for the presently loaded 1008 * link-maps. 1009 */ 1010 Grp_desc * gdp; 1011 Aliste off; 1012 1013 for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) { 1014 if ((gdp->gd_flags & GPD_AVAIL) == 0) 1015 continue; 1016 1017 sl.sl_imap = gdp->gd_depend; 1018 if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo)) 1019 return (sym); 1020 1021 if (ghp->gh_flags & GPH_FIRST) 1022 return ((Sym *)0); 1023 } 1024 1025 /* 1026 * If we're unable to locate the symbol and this link-map still 1027 * has pending lazy dependencies, start loading them in an 1028 * attempt to exhaust the search. 1029 */ 1030 if (LIST(lmp)->lm_lazy) { 1031 DBG_CALL(Dbg_syms_lazy_rescan(name)); 1032 1033 for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) { 1034 nlmp = gdp->gd_depend; 1035 1036 if (((gdp->gd_flags & GPD_AVAIL) == 0) || 1037 (LAZY(nlmp) == 0)) 1038 continue; 1039 sl.sl_imap = nlmp; 1040 if (sym = elf_lazy_find_sym(&sl, _lmp, binfo)) 1041 return (sym); 1042 } 1043 } 1044 } 1045 return ((Sym *)0); 1046 } 1047 1048 /* 1049 * Core dlsym activity. Selects symbol lookup method from handle. 1050 */ 1051 void * 1052 dlsym_core(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp) 1053 { 1054 Sym *sym; 1055 Syminfo *sip; 1056 Slookup sl; 1057 uint_t binfo; 1058 1059 sl.sl_name = name; 1060 sl.sl_cmap = clmp; 1061 sl.sl_hash = 0; 1062 sl.sl_rsymndx = 0; 1063 1064 /* 1065 * Standard relocations are evaluated using the symbol index of the 1066 * associated relocation symbol. This index provides for loading 1067 * any lazy dependency and establishing a direct binding if necessary. 1068 * If a dlsym() operation originates from an object that contains a 1069 * symbol table entry for the same name, then establish the symbol 1070 * index so that any dependency requirements can be triggered. 1071 */ 1072 if (((intptr_t)handle < 0) && (sip = SYMINFO(clmp)) != 0) { 1073 sl.sl_imap = clmp; 1074 sl.sl_flags = LKUP_SYMNDX; 1075 sl.sl_hash = elf_hash(name); 1076 1077 if ((sym = SYMINTP(clmp)(&sl, 0, 0)) != NULL) { 1078 sl.sl_rsymndx = (((ulong_t)sym - 1079 (ulong_t)SYMTAB(clmp)) / SYMENT(clmp)); 1080 } 1081 } 1082 1083 if (handle == RTLD_NEXT) { 1084 Rt_map *nlmp; 1085 1086 /* 1087 * If this handle is RTLD_NEXT determine whether a lazy load 1088 * from the caller might provide the next object. This mimics 1089 * the lazy loading initialization normally carried out by 1090 * lookup_sym(), however here, we must do this up-front, as 1091 * lookup_sym() will be used to inspect the next object. 1092 */ 1093 if (sl.sl_rsymndx) { 1094 /* LINTED */ 1095 sip = (Syminfo *)((char *)sip + 1096 (sl.sl_rsymndx * SYMINENT(clmp))); 1097 1098 if ((sip->si_flags & SYMINFO_FLG_DIRECT) && 1099 (sip->si_boundto < SYMINFO_BT_LOWRESERVE)) 1100 (void) elf_lazy_load(clmp, 1101 sip->si_boundto, name); 1102 1103 /* 1104 * Clear the symbol index, so as not to confuse 1105 * lookup_sym() of the next object. 1106 */ 1107 sl.sl_rsymndx = 0; 1108 } 1109 1110 /* 1111 * If the handle is RTLD_NEXT start searching in the next link 1112 * map from the callers. Determine permissions from the 1113 * present link map. Indicate to lookup_sym() that we're on an 1114 * RTLD_NEXT request so that it will use the callers link map to 1115 * start any possible lazy dependency loading. 1116 */ 1117 sl.sl_imap = nlmp = (Rt_map *)NEXT(clmp); 1118 1119 DBG_CALL(Dbg_syms_dlsym(name, NAME(clmp), (nlmp ? NAME(nlmp) : 1120 MSG_INTL(MSG_STR_NULL)), DBG_DLSYM_NEXT)); 1121 1122 if (nlmp == 0) 1123 return (0); 1124 1125 sl.sl_flags = LKUP_NEXT; 1126 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo); 1127 1128 } else if (handle == RTLD_SELF) { 1129 /* 1130 * If the handle is RTLD_SELF start searching from the caller. 1131 */ 1132 DBG_CALL(Dbg_syms_dlsym(name, NAME(clmp), NAME(clmp), 1133 DBG_DLSYM_SELF)); 1134 1135 sl.sl_imap = clmp; 1136 sl.sl_flags = LKUP_SPEC; 1137 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo); 1138 1139 } else if (handle == RTLD_DEFAULT) { 1140 Rt_map *hlmp = LIST(clmp)->lm_head; 1141 1142 /* 1143 * If the handle is RTLD_DEFAULT mimic the standard symbol 1144 * lookup as would be triggered by a relocation. 1145 */ 1146 DBG_CALL(Dbg_syms_dlsym(name, NAME(clmp), 0, 1147 DBG_DLSYM_DEFAULT)); 1148 1149 sl.sl_imap = hlmp; 1150 sl.sl_flags = LKUP_SPEC; 1151 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo); 1152 1153 } else if (handle == RTLD_PROBE) { 1154 Rt_map *hlmp = LIST(clmp)->lm_head; 1155 1156 /* 1157 * If the handle is RTLD_PROBE, mimic the standard symbol 1158 * lookup as would be triggered by a relocation, however do 1159 * not fall back to a lazy loading rescan if the symbol can't be 1160 * found within the currently loaded objects. Note, a lazy 1161 * loaded dependency required by the caller might still get 1162 * loaded to satisfy this request, but no exhaustive lazy load 1163 * rescan is carried out. 1164 */ 1165 DBG_CALL(Dbg_syms_dlsym(name, NAME(clmp), 0, DBG_DLSYM_PROBE)); 1166 1167 sl.sl_imap = hlmp; 1168 sl.sl_flags = (LKUP_SPEC | LKUP_NOFALBACK); 1169 sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo); 1170 1171 } else { 1172 Grp_hdl *ghp = (Grp_hdl *)handle; 1173 1174 /* 1175 * Look in the shared object specified by the handle and in all 1176 * of its dependencies. 1177 */ 1178 DBG_CALL(Dbg_syms_dlsym(name, NAME(clmp), NAME(ghp->gh_owner), 1179 DBG_DLSYM_DEF)); 1180 sym = LM_DLSYM(clmp)(ghp, &sl, dlmp, &binfo); 1181 } 1182 1183 if (sym) { 1184 Addr addr = sym->st_value; 1185 1186 if (!(FLAGS(*dlmp) & FLG_RT_FIXED)) 1187 addr += ADDR(*dlmp); 1188 1189 DBG_CALL(Dbg_bind_global(NAME(clmp), 0, 0, (Xword)-1, 1190 PLT_T_NONE, NAME(*dlmp), (caddr_t)addr, 1191 (caddr_t)sym->st_value, name, binfo)); 1192 1193 if ((LIST(clmp)->lm_tflags | FLAGS1(clmp)) & 1194 LML_TFLG_AUD_SYMBIND) { 1195 uint_t sb_flags = LA_SYMB_DLSYM; 1196 /* LINTED */ 1197 uint_t symndx = (uint_t)(((Xword)sym - 1198 (Xword)SYMTAB(*dlmp)) / SYMENT(*dlmp)); 1199 addr = audit_symbind(clmp, *dlmp, sym, symndx, addr, 1200 &sb_flags); 1201 } 1202 return ((void *)addr); 1203 } else 1204 return (0); 1205 } 1206 1207 /* 1208 * Internal dlsym activity. Called from user level or directly for internal 1209 * symbol lookup. 1210 */ 1211 void * 1212 dlsym_intn(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp) 1213 { 1214 Rt_map * llmp = 0; 1215 void * error; 1216 Aliste off; 1217 Grp_desc * gdp; 1218 1219 /* 1220 * While looking for symbols it's quite possible that additional objects 1221 * get loaded from lazy loading. These objects will have been added to 1222 * the same link-map list as those objects on the handle. Remember this 1223 * list for later investigation. 1224 */ 1225 if ((handle == RTLD_NEXT) || (handle == RTLD_DEFAULT) || 1226 (handle == RTLD_SELF) || (handle == RTLD_PROBE)) 1227 llmp = LIST(clmp)->lm_tail; 1228 else { 1229 Grp_hdl * ghp = (Grp_hdl *)handle; 1230 1231 if (ghp->gh_owner) 1232 llmp = LIST(ghp->gh_owner)->lm_tail; 1233 else { 1234 for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) { 1235 if ((llmp = LIST(gdp->gd_depend)->lm_tail) != 0) 1236 break; 1237 } 1238 } 1239 } 1240 1241 if ((error = dlsym_core(handle, name, clmp, dlmp)) == 0) { 1242 /* 1243 * Cache the error message, as Java tends to fall through this 1244 * code many times. 1245 */ 1246 if (nosym_str == 0) 1247 nosym_str = MSG_INTL(MSG_GEN_NOSYM); 1248 eprintf(ERR_FATAL, nosym_str, name); 1249 } 1250 1251 load_completion(llmp, clmp); 1252 1253 return (error); 1254 } 1255 1256 /* 1257 * Argument checking for dlsym. Only called via external entry. 1258 */ 1259 static void * 1260 dlsym_check(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp) 1261 { 1262 /* 1263 * Verify the arguments. 1264 */ 1265 if (name == 0) { 1266 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLSYM)); 1267 return (0); 1268 } 1269 if ((handle != RTLD_NEXT) && (handle != RTLD_DEFAULT) && 1270 (handle != RTLD_SELF) && (handle != RTLD_PROBE) && 1271 (hdl_validate((Grp_hdl *)handle) == 0)) { 1272 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL)); 1273 return (0); 1274 } 1275 return (dlsym_intn(handle, name, clmp, dlmp)); 1276 } 1277 1278 1279 #pragma weak dlsym = _dlsym 1280 1281 /* 1282 * External entry for dlsym(). On success, returns the address of the specified 1283 * symbol. On error returns a null. 1284 */ 1285 void * 1286 _dlsym(void *handle, const char *name) 1287 { 1288 int entry; 1289 uint_t dbg_save; 1290 Word lmflags; 1291 Rt_map *clmp, *dlmp = 0; 1292 void *addr; 1293 1294 entry = enter(); 1295 1296 clmp = _caller(caller(), CL_EXECDEF); 1297 1298 if ((lmflags = LIST(clmp)->lm_flags) & LML_FLG_RTLDLM) { 1299 dbg_save = dbg_mask; 1300 dbg_mask = 0; 1301 } 1302 1303 addr = dlsym_check(handle, name, clmp, &dlmp); 1304 1305 if (dlmp) 1306 is_dep_ready(dlmp, clmp, DBG_WAIT_SYMBOL); 1307 1308 if (entry && dlmp) 1309 is_dep_init(dlmp, clmp); 1310 1311 if (lmflags & LML_FLG_RTLDLM) 1312 dbg_mask = dbg_save; 1313 1314 if (entry) 1315 leave(LIST(clmp)); 1316 return (addr); 1317 } 1318 1319 /* 1320 * Core dladdr activity. 1321 */ 1322 static void 1323 dladdr_core(Rt_map *clmp, void *addr, Dl_info *dlip, void **info, int flags) 1324 { 1325 /* 1326 * Set up generic information and any defaults. 1327 */ 1328 dlip->dli_fname = PATHNAME(clmp); 1329 1330 dlip->dli_fbase = (void *)ADDR(clmp); 1331 dlip->dli_sname = 0; 1332 dlip->dli_saddr = 0; 1333 1334 /* 1335 * Determine the nearest symbol to this address. 1336 */ 1337 LM_DLADDR(clmp)((ulong_t)addr, clmp, dlip, info, flags); 1338 } 1339 1340 #pragma weak dladdr = _dladdr 1341 1342 /* 1343 * External entry for dladdr(3dl) and dladdr1(3dl). Returns an information 1344 * structure that reflects the symbol closest to the address specified. 1345 */ 1346 int 1347 _dladdr(void *addr, Dl_info *dlip) 1348 { 1349 int entry, error; 1350 uint_t dbg_save; 1351 Word lmflags; 1352 Rt_map *clmp; 1353 1354 entry = enter(); 1355 1356 /* 1357 * Use our calling technique to determine what object is associated 1358 * with the supplied address. If a caller can't be determined, 1359 * indicate the failure. 1360 */ 1361 if ((clmp = _caller((caddr_t)addr, CL_NONE)) == 0) { 1362 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_INVADDR), EC_ADDR(addr)); 1363 error = 0; 1364 } else { 1365 if ((lmflags = LIST(clmp)->lm_flags) & LML_FLG_RTLDLM) { 1366 dbg_save = dbg_mask; 1367 dbg_mask = 0; 1368 } 1369 1370 dladdr_core(clmp, addr, dlip, 0, 0); 1371 1372 if (lmflags & LML_FLG_RTLDLM) 1373 dbg_mask = dbg_save; 1374 error = 1; 1375 } 1376 1377 if (entry) 1378 leave(0); 1379 return (error); 1380 } 1381 1382 #pragma weak dladdr1 = _dladdr1 1383 1384 int 1385 _dladdr1(void *addr, Dl_info *dlip, void **info, int flags) 1386 { 1387 int entry, error = 0; 1388 uint_t dbg_save; 1389 Word lmflags; 1390 Rt_map *clmp; 1391 1392 /* 1393 * Validate any flags. 1394 */ 1395 if (flags) { 1396 int request; 1397 1398 if (((request = (flags & RTLD_DL_MASK)) != RTLD_DL_SYMENT) && 1399 (request != RTLD_DL_LINKMAP)) { 1400 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLFLAGS), flags); 1401 return (0); 1402 } 1403 if (info == 0) { 1404 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLINFO), flags); 1405 return (0); 1406 } 1407 } 1408 1409 entry = enter(); 1410 1411 /* 1412 * Use our calling technique to determine what object is associated 1413 * with the supplied address. If a caller can't be determined, 1414 * indicate the failure. 1415 */ 1416 if ((clmp = _caller((caddr_t)addr, CL_NONE)) == 0) { 1417 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_INVADDR), EC_ADDR(addr)); 1418 error = 0; 1419 } else { 1420 if ((lmflags = LIST(clmp)->lm_flags) & LML_FLG_RTLDLM) { 1421 dbg_save = dbg_mask; 1422 dbg_mask = 0; 1423 } 1424 1425 dladdr_core(clmp, addr, dlip, info, flags); 1426 1427 if (lmflags & LML_FLG_RTLDLM) 1428 dbg_mask = dbg_save; 1429 error = 1; 1430 } 1431 if (entry) 1432 leave(0); 1433 return (error); 1434 } 1435 1436 /* 1437 * Core dldump activity. 1438 */ 1439 static int 1440 dldump_core(const char *ipath, const char *opath, int flags) 1441 { 1442 Addr addr = 0; 1443 Rt_map *lmp; 1444 1445 /* 1446 * Verify any arguments first. 1447 */ 1448 if ((!opath || (*opath == '\0')) || (ipath && (*ipath == '\0'))) { 1449 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLPATH)); 1450 return (1); 1451 } 1452 1453 /* 1454 * If an input file is specified make sure its one of our dependencies. 1455 */ 1456 if (ipath) { 1457 if ((lmp = is_so_loaded(&lml_main, ipath, 0)) == 0) 1458 lmp = is_so_loaded(&lml_main, ipath, 1); 1459 1460 if (lmp == 0) { 1461 eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_NOFILE), ipath); 1462 return (1); 1463 } 1464 if (FLAGS(lmp) & FLG_RT_ALTER) { 1465 eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_ALTER), ipath); 1466 return (1); 1467 } 1468 if (FLAGS(lmp) & FLG_RT_NODUMP) { 1469 eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_NODUMP), ipath); 1470 return (1); 1471 } 1472 } else 1473 lmp = lml_main.lm_head; 1474 1475 1476 DBG_CALL(Dbg_file_dldump(NAME(lmp), opath, flags)); 1477 1478 /* 1479 * If the object being dump'ed isn't fixed identify its mapping. 1480 */ 1481 if (!(FLAGS(lmp) & FLG_RT_FIXED)) 1482 addr = ADDR(lmp); 1483 1484 /* 1485 * As rt_dldump() will effectively lazy load the necessary support 1486 * libraries, make sure ld.so.1 is initialized for plt relocations. 1487 */ 1488 if (elf_rtld_load() == 0) 1489 return (0); 1490 1491 /* 1492 * Dump the required image. 1493 */ 1494 return (rt_dldump(lmp, opath, flags, addr)); 1495 } 1496 1497 #pragma weak dldump = _dldump 1498 1499 /* 1500 * External entry for dldump(3dl). Returns 0 on success, non-zero otherwise. 1501 */ 1502 int 1503 _dldump(const char *ipath, const char *opath, int flags) 1504 { 1505 int error, entry; 1506 uint_t dbg_save; 1507 Word lmflags; 1508 Rt_map *clmp; 1509 1510 entry = enter(); 1511 1512 clmp = _caller(caller(), CL_EXECDEF); 1513 1514 if ((lmflags = LIST(clmp)->lm_flags) & LML_FLG_RTLDLM) { 1515 dbg_save = dbg_mask; 1516 dbg_mask = 0; 1517 } 1518 1519 error = dldump_core(ipath, opath, flags); 1520 1521 if (lmflags & LML_FLG_RTLDLM) 1522 dbg_mask = dbg_save; 1523 1524 if (entry) 1525 leave(LIST(clmp)); 1526 return (error); 1527 } 1528 1529 /* 1530 * get_linkmap_id() translates Lm_list * pointers to the Link_map id as used by 1531 * the rtld_db and dlmopen() interfaces. It checks to see if the Link_map is 1532 * one of the primary ones and if so returns it's special token: 1533 * LM_ID_BASE 1534 * LM_ID_LDSO 1535 * 1536 * If it's not one of the primary link_map id's it will instead returns a 1537 * pointer to the Lm_list structure which uniquely identifies the Link_map. 1538 */ 1539 Lmid_t 1540 get_linkmap_id(Lm_list *lml) 1541 { 1542 if (lml->lm_flags & LML_FLG_BASELM) 1543 return (LM_ID_BASE); 1544 if (lml->lm_flags & LML_FLG_RTLDLM) 1545 return (LM_ID_LDSO); 1546 1547 return ((Lmid_t)lml); 1548 } 1549 1550 /* 1551 * Extract information for a dlopen() handle. 1552 */ 1553 static int 1554 dlinfo_core(void *handle, int request, void *p, Rt_map *clmp) 1555 { 1556 Rt_map *lmp; 1557 1558 if ((request > RTLD_DI_MAX) || (p == 0)) { 1559 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL)); 1560 return (-1); 1561 } 1562 1563 /* 1564 * Return configuration cache name and address. 1565 */ 1566 if (request == RTLD_DI_CONFIGADDR) { 1567 Dl_info *dlip = (Dl_info *)p; 1568 1569 if ((config->c_name == 0) || (config->c_bgn == 0) || 1570 (config->c_end == 0)) { 1571 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_NOCONFIG)); 1572 return (-1); 1573 } 1574 dlip->dli_fname = config->c_name; 1575 dlip->dli_fbase = (void *)config->c_bgn; 1576 return (0); 1577 } 1578 1579 /* 1580 * Return profiled object name (used by ldprof audit library). 1581 */ 1582 if (request == RTLD_DI_PROFILENAME) { 1583 if (profile_name == 0) { 1584 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_NOPROFNAME)); 1585 return (-1); 1586 } 1587 1588 *(const char **)p = profile_name; 1589 return (0); 1590 } 1591 if (request == RTLD_DI_PROFILEOUT) { 1592 /* 1593 * If a profile destination directory hasn't been specified 1594 * provide a default. 1595 */ 1596 if (profile_out == 0) 1597 profile_out = MSG_ORIG(MSG_PTH_VARTMP); 1598 1599 *(const char **)p = profile_out; 1600 return (0); 1601 } 1602 1603 /* 1604 * Obtain or establish a termination signal. 1605 */ 1606 if (request == RTLD_DI_GETSIGNAL) { 1607 *(int *)p = killsig; 1608 return (0); 1609 } 1610 1611 if (request == RTLD_DI_SETSIGNAL) { 1612 sigset_t set; 1613 int sig = *(int *)p; 1614 1615 /* 1616 * Determine whether the signal is in range. 1617 */ 1618 (void) sigfillset(&set); 1619 if (sigismember(&set, sig) != 1) { 1620 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_INVSIG), sig); 1621 return (-1); 1622 } 1623 1624 killsig = sig; 1625 return (0); 1626 } 1627 1628 /* 1629 * For any other request a link-map is required. Verify the handle. 1630 */ 1631 if (handle == RTLD_SELF) 1632 lmp = clmp; 1633 else { 1634 Grp_hdl * ghp = (Grp_hdl *)handle; 1635 1636 if (!hdl_validate(ghp)) { 1637 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL)); 1638 return (-1); 1639 } 1640 lmp = ghp->gh_owner; 1641 } 1642 1643 /* 1644 * Obtain the process arguments, environment and auxv. Note, as the 1645 * environment can be modified by the user (putenv(3c)), reinitialize 1646 * the environment pointer on each request. 1647 */ 1648 if (request == RTLD_DI_ARGSINFO) { 1649 Dl_argsinfo *aip = (Dl_argsinfo *)p; 1650 Lm_list *lml = LIST(lmp); 1651 1652 *aip = argsinfo; 1653 if (lml->lm_flags & LML_FLG_ENVIRON) 1654 aip->dla_envp = *(lml->lm_environ); 1655 1656 return (0); 1657 } 1658 1659 /* 1660 * Return Lmid_t of the Link-Map list that the specified object is 1661 * loaded on. 1662 */ 1663 if (request == RTLD_DI_LMID) { 1664 *(Lmid_t *)p = get_linkmap_id(LIST(lmp)); 1665 return (0); 1666 } 1667 1668 /* 1669 * Return a pointer to the Link-Map structure associated with the 1670 * specified object. 1671 */ 1672 if (request == RTLD_DI_LINKMAP) { 1673 *(Link_map **)p = (Link_map *)lmp; 1674 return (0); 1675 } 1676 1677 /* 1678 * Return search path information, or the size of the buffer required 1679 * to store the information. 1680 */ 1681 if ((request == RTLD_DI_SERINFO) || (request == RTLD_DI_SERINFOSIZE)) { 1682 Pnode *dir, *dirlist = (Pnode *)0; 1683 Dl_serinfo *info; 1684 Dl_serpath *path; 1685 char *strs; 1686 size_t size = sizeof (Dl_serinfo); 1687 uint_t cnt = 0; 1688 1689 info = (Dl_serinfo *)p; 1690 path = &info->dls_serpath[0]; 1691 strs = (char *)&info->dls_serpath[info->dls_cnt]; 1692 1693 /* 1694 * Traverse search path entries for this object. 1695 */ 1696 while ((dir = get_next_dir(&dirlist, lmp, 0)) != 0) { 1697 size_t _size; 1698 1699 if (dir->p_name == 0) 1700 continue; 1701 1702 /* 1703 * If configuration information exists, it's possible 1704 * this path has been identified as non-existent, if so 1705 * ignore it. 1706 */ 1707 if (dir->p_info) { 1708 Rtc_obj *dobj = (Rtc_obj *)dir->p_info; 1709 if (dobj->co_flags & RTC_OBJ_NOEXIST) 1710 continue; 1711 } 1712 1713 /* 1714 * Keep track of search path count and total info size. 1715 */ 1716 if (cnt++) 1717 size += sizeof (Dl_serpath); 1718 _size = strlen(dir->p_name) + 1; 1719 size += _size; 1720 1721 if (request == RTLD_DI_SERINFOSIZE) 1722 continue; 1723 1724 /* 1725 * If we're filling in search path information, confirm 1726 * there's sufficient space. 1727 */ 1728 if (size > info->dls_size) { 1729 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_SERSIZE), 1730 EC_OFF(info->dls_size)); 1731 return (-1); 1732 } 1733 if (cnt > info->dls_cnt) { 1734 eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_SERCNT), 1735 info->dls_cnt); 1736 return (-1); 1737 } 1738 1739 /* 1740 * Append the path to the information buffer. 1741 */ 1742 (void) strcpy(strs, dir->p_name); 1743 path->dls_name = strs; 1744 path->dls_flags = dir->p_orig; 1745 1746 strs = strs + _size; 1747 path++; 1748 } 1749 1750 /* 1751 * If we're here to size the search buffer fill it in. 1752 */ 1753 if (request == RTLD_DI_SERINFOSIZE) { 1754 info->dls_size = size; 1755 info->dls_cnt = cnt; 1756 } 1757 } 1758 1759 /* 1760 * Return the origin of the object associated with this link-map. 1761 * Basically return the dirname(1) of the objects fullpath. 1762 */ 1763 if (request == RTLD_DI_ORIGIN) { 1764 char *str = (char *)p; 1765 1766 if (DIRSZ(lmp) == 0) 1767 (void) fullpath(lmp, 0); 1768 1769 (void) strncpy(str, ORIGNAME(lmp), DIRSZ(lmp)); 1770 str += DIRSZ(lmp); 1771 *str = '\0'; 1772 1773 return (0); 1774 } 1775 1776 return (0); 1777 } 1778 1779 #pragma weak dlinfo = _dlinfo 1780 1781 /* 1782 * External entry for dlinfo(3dl). 1783 */ 1784 int 1785 _dlinfo(void *handle, int request, void *p) 1786 { 1787 int error, entry; 1788 uint_t dbg_save; 1789 Word lmflags; 1790 Rt_map *clmp; 1791 1792 entry = enter(); 1793 1794 clmp = _caller(caller(), CL_EXECDEF); 1795 1796 if ((lmflags = LIST(clmp)->lm_flags) & LML_FLG_RTLDLM) { 1797 dbg_save = dbg_mask; 1798 dbg_mask = 0; 1799 } 1800 1801 error = dlinfo_core(handle, request, p, clmp); 1802 1803 if (lmflags & LML_FLG_RTLDLM) 1804 dbg_mask = dbg_save; 1805 1806 if (entry) 1807 leave(LIST(clmp)); 1808 return (error); 1809 } 1810