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