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