17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2111a2bb38Srie 227c478bd9Sstevel@tonic-gate /* 237257d1b4Sraf * Copyright (c) 1988 AT&T 247257d1b4Sraf * All Rights Reserved 25f441771bSRod Evans * 26f441771bSRod Evans * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 277257d1b4Sraf */ 28*b533f56bSRobert Mustacchi /* 29*b533f56bSRobert Mustacchi * Copyright (c) 2012, Joyent, Inc. All rights reserved. 30*b533f56bSRobert Mustacchi */ 317257d1b4Sraf 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * Object file dependent support for ELF objects. 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <stdio.h> 377c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 387c478bd9Sstevel@tonic-gate #include <sys/mman.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate #include <string.h> 417c478bd9Sstevel@tonic-gate #include <limits.h> 427c478bd9Sstevel@tonic-gate #include <dlfcn.h> 435aefb655Srie #include <debug.h> 445aefb655Srie #include <conv.h> 457c478bd9Sstevel@tonic-gate #include "_rtld.h" 467c478bd9Sstevel@tonic-gate #include "_audit.h" 477c478bd9Sstevel@tonic-gate #include "_elf.h" 48f441771bSRod Evans #include "_inline_gen.h" 49f441771bSRod Evans #include "_inline_reloc.h" 507c478bd9Sstevel@tonic-gate #include "msg.h" 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * Default and secure dependency search paths. 547c478bd9Sstevel@tonic-gate */ 5556deab07SRod Evans static Spath_defn _elf_def_dirs[] = { 567c478bd9Sstevel@tonic-gate #if defined(_ELF64) 5756deab07SRod Evans { MSG_ORIG(MSG_PTH_LIB_64), MSG_PTH_LIB_64_SIZE }, 5856deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIB_64), MSG_PTH_USRLIB_64_SIZE }, 597c478bd9Sstevel@tonic-gate #else 6056deab07SRod Evans { MSG_ORIG(MSG_PTH_LIB), MSG_PTH_LIB_SIZE }, 6156deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIB), MSG_PTH_USRLIB_SIZE }, 627c478bd9Sstevel@tonic-gate #endif 6356deab07SRod Evans { 0, 0 } 647c478bd9Sstevel@tonic-gate }; 657c478bd9Sstevel@tonic-gate 6656deab07SRod Evans static Spath_defn _elf_sec_dirs[] = { 677c478bd9Sstevel@tonic-gate #if defined(_ELF64) 6856deab07SRod Evans { MSG_ORIG(MSG_PTH_LIBSE_64), MSG_PTH_LIBSE_64_SIZE }, 6956deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIBSE_64), MSG_PTH_USRLIBSE_64_SIZE }, 707c478bd9Sstevel@tonic-gate #else 7156deab07SRod Evans { MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE }, 7256deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIBSE), MSG_PTH_USRLIBSE_SIZE }, 737c478bd9Sstevel@tonic-gate #endif 7456deab07SRod Evans { 0, 0 } 757c478bd9Sstevel@tonic-gate }; 767c478bd9Sstevel@tonic-gate 7756deab07SRod Evans Alist *elf_def_dirs = NULL; 7856deab07SRod Evans Alist *elf_sec_dirs = NULL; 7956deab07SRod Evans 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * Defines for local functions. 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate static void elf_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int); 8456deab07SRod Evans static Addr elf_entry_point(void); 8556deab07SRod Evans static int elf_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t); 8656deab07SRod Evans static Alist **elf_get_def_dirs(void); 8756deab07SRod Evans static Alist **elf_get_sec_dirs(void); 8856deab07SRod Evans static char *elf_get_so(const char *, const char *, size_t, size_t); 899aa23310Srie static int elf_needed(Lm_list *, Aliste, Rt_map *, int *); 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * Functions and data accessed through indirect pointers. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate Fct elf_fct = { 9556deab07SRod Evans elf_verify, 9656deab07SRod Evans elf_new_lmp, 9756deab07SRod Evans elf_entry_point, 987c478bd9Sstevel@tonic-gate elf_needed, 997c478bd9Sstevel@tonic-gate lookup_sym, 1007c478bd9Sstevel@tonic-gate elf_reloc, 10156deab07SRod Evans elf_get_def_dirs, 10256deab07SRod Evans elf_get_sec_dirs, 1037c478bd9Sstevel@tonic-gate elf_fix_name, 1047c478bd9Sstevel@tonic-gate elf_get_so, 1057c478bd9Sstevel@tonic-gate elf_dladdr, 10656deab07SRod Evans dlsym_handle 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 10956deab07SRod Evans /* 11056deab07SRod Evans * Default and secure dependency search paths. 11156deab07SRod Evans */ 11256deab07SRod Evans static Alist ** 11356deab07SRod Evans elf_get_def_dirs() 11456deab07SRod Evans { 11556deab07SRod Evans if (elf_def_dirs == NULL) 11656deab07SRod Evans set_dirs(&elf_def_dirs, _elf_def_dirs, LA_SER_DEFAULT); 11756deab07SRod Evans return (&elf_def_dirs); 11856deab07SRod Evans } 11956deab07SRod Evans 12056deab07SRod Evans static Alist ** 12156deab07SRod Evans elf_get_sec_dirs() 12256deab07SRod Evans { 12356deab07SRod Evans if (elf_sec_dirs == NULL) 12456deab07SRod Evans set_dirs(&elf_sec_dirs, _elf_sec_dirs, LA_SER_SECURE); 12556deab07SRod Evans return (&elf_sec_dirs); 12656deab07SRod Evans } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * Redefine NEEDED name if necessary. 1307c478bd9Sstevel@tonic-gate */ 13156deab07SRod Evans static int 13256deab07SRod Evans elf_fix_name(const char *name, Rt_map *clmp, Alist **alpp, Aliste alni, 13356deab07SRod Evans uint_t orig) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * For ABI compliance, if we are asked for ld.so.1, then really give 1377c478bd9Sstevel@tonic-gate * them libsys.so.1 (the SONAME of libsys.so.1 is ld.so.1). 1387c478bd9Sstevel@tonic-gate */ 1397c478bd9Sstevel@tonic-gate if (((*name == '/') && 140a953e2b1Srie /* BEGIN CSTYLED */ 1417c478bd9Sstevel@tonic-gate #if defined(_ELF64) 1427c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_PTH_RTLD_64)) == 0)) || 1437c478bd9Sstevel@tonic-gate #else 1447c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_PTH_RTLD)) == 0)) || 1457c478bd9Sstevel@tonic-gate #endif 1467c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_FIL_RTLD)) == 0)) { 147a953e2b1Srie /* END CSTYLED */ 14856deab07SRod Evans Pdesc *pdp; 1497c478bd9Sstevel@tonic-gate 1505aefb655Srie DBG_CALL(Dbg_file_fixname(LIST(clmp), name, 1515aefb655Srie MSG_ORIG(MSG_PTH_LIBSYS))); 152dde769a2SRod Evans if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), 153dde769a2SRod Evans alni)) == NULL) 1547c478bd9Sstevel@tonic-gate return (0); 15556deab07SRod Evans 15656deab07SRod Evans pdp->pd_pname = (char *)MSG_ORIG(MSG_PTH_LIBSYS); 15756deab07SRod Evans pdp->pd_plen = MSG_PTH_LIBSYS_SIZE; 15856deab07SRod Evans pdp->pd_flags = PD_FLG_PNSLASH; 15956deab07SRod Evans 16056deab07SRod Evans return (1); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 16356deab07SRod Evans return (expand_paths(clmp, name, alpp, alni, orig, 0)); 16456deab07SRod Evans } 16556deab07SRod Evans 16656deab07SRod Evans /* 16708278a5eSRod Evans * Determine whether this object requires capabilities. 16856deab07SRod Evans */ 16908278a5eSRod Evans inline static int 17056deab07SRod Evans elf_cap_check(Fdesc *fdp, Ehdr *ehdr, Rej_desc *rej) 17156deab07SRod Evans { 17256deab07SRod Evans Phdr *phdr; 17308278a5eSRod Evans Cap *cap = NULL; 17408278a5eSRod Evans Dyn *dyn = NULL; 17508278a5eSRod Evans char *str = NULL; 17608278a5eSRod Evans Addr base; 177f441771bSRod Evans uint_t cnt, dyncnt; 17856deab07SRod Evans 17908278a5eSRod Evans /* 18008278a5eSRod Evans * If this is a shared object, the base address of the shared object is 18108278a5eSRod Evans * added to all address values defined within the object. Otherwise, if 18208278a5eSRod Evans * this is an executable, all object addresses are used as is. 18308278a5eSRod Evans */ 18408278a5eSRod Evans if (ehdr->e_type == ET_EXEC) 18508278a5eSRod Evans base = 0; 18608278a5eSRod Evans else 18708278a5eSRod Evans base = (Addr)ehdr; 18808278a5eSRod Evans 18956deab07SRod Evans /* LINTED */ 19056deab07SRod Evans phdr = (Phdr *)((char *)ehdr + ehdr->e_phoff); 19156deab07SRod Evans for (cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) { 19208278a5eSRod Evans if (phdr->p_type == PT_DYNAMIC) { 19356deab07SRod Evans /* LINTED */ 19408278a5eSRod Evans dyn = (Dyn *)((uintptr_t)phdr->p_vaddr + base); 195f441771bSRod Evans dyncnt = phdr->p_filesz / sizeof (Dyn); 19608278a5eSRod Evans } else if (phdr->p_type == PT_SUNWCAP) { 19708278a5eSRod Evans /* LINTED */ 19808278a5eSRod Evans cap = (Cap *)((uintptr_t)phdr->p_vaddr + base); 19908278a5eSRod Evans } 20008278a5eSRod Evans } 20108278a5eSRod Evans 20208278a5eSRod Evans if (cap) { 20356deab07SRod Evans /* 20408278a5eSRod Evans * From the .dynamic section, determine the associated string 20508278a5eSRod Evans * table. Required for CA_SUNW_MACH and CA_SUNW_PLAT 20608278a5eSRod Evans * processing. 20756deab07SRod Evans */ 208f441771bSRod Evans while (dyn && dyncnt) { 20908278a5eSRod Evans if (dyn->d_tag == DT_NULL) { 21008278a5eSRod Evans break; 21108278a5eSRod Evans } else if (dyn->d_tag == DT_STRTAB) { 21208278a5eSRod Evans str = (char *)(dyn->d_un.d_ptr + base); 21308278a5eSRod Evans break; 21408278a5eSRod Evans } 215f441771bSRod Evans dyn++, dyncnt--; 21608278a5eSRod Evans } 21708278a5eSRod Evans } 21856deab07SRod Evans 21956deab07SRod Evans /* 22008278a5eSRod Evans * Establish any alternative capabilities, and validate this object 22108278a5eSRod Evans * if it defines it's own capabilities information. 22256deab07SRod Evans */ 22308278a5eSRod Evans return (cap_check_fdesc(fdp, cap, str, rej)); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* 2277c478bd9Sstevel@tonic-gate * Determine if we have been given an ELF file and if so determine if the file 2287c478bd9Sstevel@tonic-gate * is compatible. Returns 1 if true, else 0 and sets the reject descriptor 2297c478bd9Sstevel@tonic-gate * with associated error information. 2307c478bd9Sstevel@tonic-gate */ 23156deab07SRod Evans Fct * 23256deab07SRod Evans elf_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name, 23356deab07SRod Evans Rej_desc *rej) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate Ehdr *ehdr; 23656deab07SRod Evans char *caddr = (char *)addr; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * Determine if we're an elf file. If not simply return, we don't set 2407c478bd9Sstevel@tonic-gate * any rejection information as this test allows use to scroll through 2417c478bd9Sstevel@tonic-gate * the objects we support (ELF, AOUT). 2427c478bd9Sstevel@tonic-gate */ 24356deab07SRod Evans if (size < sizeof (Ehdr) || 24456deab07SRod Evans caddr[EI_MAG0] != ELFMAG0 || 24556deab07SRod Evans caddr[EI_MAG1] != ELFMAG1 || 24656deab07SRod Evans caddr[EI_MAG2] != ELFMAG2 || 24756deab07SRod Evans caddr[EI_MAG3] != ELFMAG3) { 24856deab07SRod Evans return (NULL); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * Check class and encoding. 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate /* LINTED */ 25556deab07SRod Evans ehdr = (Ehdr *)addr; 2567c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_CLASS] != M_CLASS) { 2577c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_CLASS; 2587c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_ident[EI_CLASS]; 25956deab07SRod Evans return (NULL); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_DATA] != M_DATA) { 2627c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_DATA; 2637c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_ident[EI_DATA]; 26456deab07SRod Evans return (NULL); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate if ((ehdr->e_type != ET_REL) && (ehdr->e_type != ET_EXEC) && 2677c478bd9Sstevel@tonic-gate (ehdr->e_type != ET_DYN)) { 2687c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_TYPE; 2697c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_type; 27056deab07SRod Evans return (NULL); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 27456deab07SRod Evans * Verify ELF version. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate if (ehdr->e_version > EV_CURRENT) { 2777c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_VERSION; 2787c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_version; 27956deab07SRod Evans return (NULL); 2807c478bd9Sstevel@tonic-gate } 28156deab07SRod Evans 28256deab07SRod Evans /* 28356deab07SRod Evans * Verify machine specific flags. 28456deab07SRod Evans */ 28556deab07SRod Evans if (elf_mach_flags_check(rej, ehdr) == 0) 28656deab07SRod Evans return (NULL); 28756deab07SRod Evans 28856deab07SRod Evans /* 28908278a5eSRod Evans * Verify any capability requirements. Note, if this object is a shared 29008278a5eSRod Evans * object that is explicitly defined on the ldd(1) command line, and it 29108278a5eSRod Evans * contains an incompatible capabilities requirement, then inform the 29208278a5eSRod Evans * user, but continue processing. 29356deab07SRod Evans */ 29456deab07SRod Evans if (elf_cap_check(fdp, ehdr, rej) == 0) { 29556deab07SRod Evans Rt_map *lmp = lml_main.lm_head; 29656deab07SRod Evans 297dde769a2SRod Evans if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp && 298dde769a2SRod Evans (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) { 29908278a5eSRod Evans /* LINTED */ 30008278a5eSRod Evans (void) printf(MSG_INTL(ldd_warn[rej->rej_type]), name, 30108278a5eSRod Evans rej->rej_str); 30256deab07SRod Evans return (&elf_fct); 30356deab07SRod Evans } 30456deab07SRod Evans return (NULL); 30556deab07SRod Evans } 30656deab07SRod Evans return (&elf_fct); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * The runtime linker employs lazy loading to provide the libraries needed for 3117c478bd9Sstevel@tonic-gate * debugging, preloading .o's and dldump(). As these are seldom used, the 3127c478bd9Sstevel@tonic-gate * standard startup of ld.so.1 doesn't initialize all the information necessary 3137c478bd9Sstevel@tonic-gate * to perform plt relocation on ld.so.1's link-map. The first time lazy loading 3147c478bd9Sstevel@tonic-gate * is called we get here to perform these initializations: 3157c478bd9Sstevel@tonic-gate * 316f441771bSRod Evans * - elf_needed() is called to establish any ld.so.1 dependencies. These 317f441771bSRod Evans * dependencies should all be lazy loaded, so this routine is typically a 318f441771bSRod Evans * no-op. However, we call elf_needed() for completeness, in case any 319f441771bSRod Evans * NEEDED initialization is required. 3207c478bd9Sstevel@tonic-gate * 3212017c965SRod Evans * - For intel, ld.so.1's JMPSLOT relocations need relative updates. These 3227c478bd9Sstevel@tonic-gate * are by default skipped thus delaying all relative relocation processing 3237c478bd9Sstevel@tonic-gate * on every invocation of ld.so.1. 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate int 3267c478bd9Sstevel@tonic-gate elf_rtld_load() 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate Lm_list *lml = &lml_rtld; 3297c478bd9Sstevel@tonic-gate Rt_map *lmp = lml->lm_head; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_PLTREL) 3327c478bd9Sstevel@tonic-gate return (1); 3337c478bd9Sstevel@tonic-gate 3349aa23310Srie if (elf_needed(lml, ALIST_OFF_DATA, lmp, NULL) == 0) 3357c478bd9Sstevel@tonic-gate return (0); 3367c478bd9Sstevel@tonic-gate 33702ca3e02Srie #if defined(__i386) 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * This is a kludge to give ld.so.1 a performance benefit on i386. 3407c478bd9Sstevel@tonic-gate * It's based around two factors. 3417c478bd9Sstevel@tonic-gate * 3422017c965SRod Evans * - JMPSLOT relocations (PLT's) actually need a relative relocation 3437c478bd9Sstevel@tonic-gate * applied to the GOT entry so that they can find PLT0. 3447c478bd9Sstevel@tonic-gate * 3452017c965SRod Evans * - ld.so.1 does not exercise *any* PLT's before it has made a call 3467c478bd9Sstevel@tonic-gate * to elf_lazy_load(). This is because all dynamic dependencies 3477c478bd9Sstevel@tonic-gate * are recorded as lazy dependencies. 3487c478bd9Sstevel@tonic-gate */ 34956deab07SRod Evans (void) elf_reloc_relative_count((ulong_t)JMPREL(lmp), 3507c478bd9Sstevel@tonic-gate (ulong_t)(PLTRELSZ(lmp) / RELENT(lmp)), (ulong_t)RELENT(lmp), 351f441771bSRod Evans (ulong_t)ADDR(lmp), lmp, NULL, 0); 3527c478bd9Sstevel@tonic-gate #endif 3537c478bd9Sstevel@tonic-gate lml->lm_flags |= LML_FLG_PLTREL; 3547c478bd9Sstevel@tonic-gate return (1); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * Lazy load an object. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate Rt_map * 3619aa23310Srie elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym, 3622017c965SRod Evans uint_t flags, Grp_hdl **hdl, int *in_nfavl) 3637c478bd9Sstevel@tonic-gate { 36456deab07SRod Evans Alist *palp = NULL; 365dde769a2SRod Evans Rt_map *nlmp; 36675e7992aSrie Dyninfo *dip = &DYNINFO(clmp)[ndx], *pdip; 3677c478bd9Sstevel@tonic-gate const char *name; 3687c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(clmp); 3697c478bd9Sstevel@tonic-gate Aliste lmco; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* 372f441771bSRod Evans * If this dependency should be ignored, or has already been processed, 373f441771bSRod Evans * we're done. 3747c478bd9Sstevel@tonic-gate */ 37556deab07SRod Evans if (((nlmp = (Rt_map *)dip->di_info) != NULL) || 376f441771bSRod Evans (dip->di_flags & (FLG_DI_IGNORE | FLG_DI_LDD_DONE))) 3777c478bd9Sstevel@tonic-gate return (nlmp); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 38075e7992aSrie * If we're running under ldd(1), indicate that this dependency has been 38175e7992aSrie * processed (see test above). It doesn't matter whether the object is 38275e7992aSrie * successfully loaded or not, this flag simply ensures that we don't 38375e7992aSrie * repeatedly attempt to load an object that has already failed to load. 38475e7992aSrie * To do so would create multiple failure diagnostics for the same 38575e7992aSrie * object under ldd(1). 38675e7992aSrie */ 38775e7992aSrie if (lml->lm_flags & LML_FLG_TRC_ENABLE) 38875e7992aSrie dip->di_flags |= FLG_DI_LDD_DONE; 38975e7992aSrie 39075e7992aSrie /* 39175e7992aSrie * Determine the initial dependency name. 3927c478bd9Sstevel@tonic-gate */ 393f441771bSRod Evans name = dip->di_name; 3945aefb655Srie DBG_CALL(Dbg_file_lazyload(clmp, name, sym)); 3957c478bd9Sstevel@tonic-gate 39675e7992aSrie /* 39775e7992aSrie * If this object needs to establish its own group, make sure a handle 39875e7992aSrie * is created. 39975e7992aSrie */ 4007c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_GROUP) 4012017c965SRod Evans flags |= (FLG_RT_SETGROUP | FLG_RT_PUBHDL); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 40475e7992aSrie * Lazy dependencies are identified as DT_NEEDED entries with a 40575e7992aSrie * DF_P1_LAZYLOAD flag in the previous DT_POSFLAG_1 element. The 40675e7992aSrie * dynamic information element that corresponds to the DT_POSFLAG_1 40775e7992aSrie * entry is free, and thus used to store the present entrance 40875e7992aSrie * identifier. This identifier is used to prevent multiple attempts to 40975e7992aSrie * load a failed lazy loadable dependency within the same runtime linker 41075e7992aSrie * operation. However, future attempts to reload this dependency are 41175e7992aSrie * still possible. 41275e7992aSrie */ 41375e7992aSrie if (ndx && (pdip = dip - 1) && (pdip->di_flags & FLG_DI_POSFLAG1)) 41475e7992aSrie pdip->di_info = (void *)slp->sl_id; 41575e7992aSrie 41675e7992aSrie /* 4177c478bd9Sstevel@tonic-gate * Expand the requested name if necessary. 4187c478bd9Sstevel@tonic-gate */ 41956deab07SRod Evans if (elf_fix_name(name, clmp, &palp, AL_CNT_NEEDED, 0) == 0) 42056deab07SRod Evans return (NULL); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 423dde769a2SRod Evans * Establish a link-map control list for this request. 4247c478bd9Sstevel@tonic-gate */ 425dde769a2SRod Evans if ((lmco = create_cntl(lml, 0)) == NULL) { 4262020b2b6SRod Evans remove_alist(&palp, 1); 42756deab07SRod Evans return (NULL); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* 4317c478bd9Sstevel@tonic-gate * Load the associated object. 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate dip->di_info = nlmp = 4342017c965SRod Evans load_one(lml, lmco, palp, clmp, MODE(clmp), flags, hdl, in_nfavl); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * Remove any expanded pathname infrastructure. Reduce the pending lazy 4387c478bd9Sstevel@tonic-gate * dependency count of the caller, together with the link-map lists 4397c478bd9Sstevel@tonic-gate * count of objects that still have lazy dependencies pending. 4407c478bd9Sstevel@tonic-gate */ 4412020b2b6SRod Evans remove_alist(&palp, 1); 4427c478bd9Sstevel@tonic-gate if (--LAZY(clmp) == 0) 4437c478bd9Sstevel@tonic-gate LIST(clmp)->lm_lazy--; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 44602ca3e02Srie * Finish processing the objects associated with this request, and 44702ca3e02Srie * create an association between the caller and this dependency. 4487c478bd9Sstevel@tonic-gate */ 44975e7992aSrie if (nlmp && ((bind_one(clmp, nlmp, BND_NEEDED) == 0) || 4502020b2b6SRod Evans ((nlmp = analyze_lmc(lml, lmco, nlmp, clmp, in_nfavl)) == NULL) || 4519aa23310Srie (relocate_lmc(lml, lmco, clmp, nlmp, in_nfavl) == 0))) 45256deab07SRod Evans dip->di_info = nlmp = NULL; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 45502ca3e02Srie * If this lazyload has failed, and we've created a new link-map 45602ca3e02Srie * control list to which this request has added objects, then remove 45702ca3e02Srie * all the objects that have been associated to this request. 4587c478bd9Sstevel@tonic-gate */ 459481bba9eSRod Evans if ((nlmp == NULL) && (lmco != ALIST_OFF_DATA)) 460481bba9eSRod Evans remove_lmc(lml, clmp, lmco, name); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 463dde769a2SRod Evans * Remove any temporary link-map control list. 4647c478bd9Sstevel@tonic-gate */ 465481bba9eSRod Evans if (lmco != ALIST_OFF_DATA) 4667c478bd9Sstevel@tonic-gate remove_cntl(lml, lmco); 4677c478bd9Sstevel@tonic-gate 46875e7992aSrie /* 46975e7992aSrie * If this lazy loading failed, record the fact, and bump the lazy 47075e7992aSrie * counts. 47175e7992aSrie */ 47256deab07SRod Evans if (nlmp == NULL) { 47375e7992aSrie dip->di_flags |= FLG_DI_LAZYFAIL; 47475e7992aSrie if (LAZY(clmp)++ == 0) 47575e7992aSrie LIST(clmp)->lm_lazy++; 47675e7992aSrie } 47775e7992aSrie 4787c478bd9Sstevel@tonic-gate return (nlmp); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Return the entry point of the ELF executable. 4837c478bd9Sstevel@tonic-gate */ 48456deab07SRod Evans static Addr 48556deab07SRod Evans elf_entry_point(void) 4867c478bd9Sstevel@tonic-gate { 48756deab07SRod Evans Rt_map *lmp = lml_main.lm_head; 48856deab07SRod Evans Ehdr *ehdr = (Ehdr *)ADDR(lmp); 48956deab07SRod Evans Addr addr = (Addr)(ehdr->e_entry); 4907c478bd9Sstevel@tonic-gate 49156deab07SRod Evans if ((FLAGS(lmp) & FLG_RT_FIXED) == 0) 49256deab07SRod Evans addr += ADDR(lmp); 4937c478bd9Sstevel@tonic-gate 49456deab07SRod Evans return (addr); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * Determine if a dependency requires a particular version and if so verify 4997c478bd9Sstevel@tonic-gate * that the version exists in the dependency. 5007c478bd9Sstevel@tonic-gate */ 50156deab07SRod Evans int 5027c478bd9Sstevel@tonic-gate elf_verify_vers(const char *name, Rt_map *clmp, Rt_map *nlmp) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate Verneed *vnd = VERNEED(clmp); 5057c478bd9Sstevel@tonic-gate int _num, num = VERNEEDNUM(clmp); 5067c478bd9Sstevel@tonic-gate char *cstrs = (char *)STRTAB(clmp); 5077c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(clmp); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * Traverse the callers version needed information and determine if any 5117c478bd9Sstevel@tonic-gate * specific versions are required from the dependency. 5127c478bd9Sstevel@tonic-gate */ 5135aefb655Srie DBG_CALL(Dbg_ver_need_title(LIST(clmp), NAME(clmp))); 5147c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5157c478bd9Sstevel@tonic-gate vnd = (Verneed *)((Xword)vnd + vnd->vn_next)) { 5167c478bd9Sstevel@tonic-gate Half cnt = vnd->vn_cnt; 5177c478bd9Sstevel@tonic-gate Vernaux *vnap; 5187c478bd9Sstevel@tonic-gate char *nstrs, *need; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * Determine if a needed entry matches this dependency. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate need = (char *)(cstrs + vnd->vn_file); 5247c478bd9Sstevel@tonic-gate if (strcmp(name, need) != 0) 5257c478bd9Sstevel@tonic-gate continue; 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate if ((lml->lm_flags & LML_FLG_TRC_VERBOSE) && 5287c478bd9Sstevel@tonic-gate ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)) 5297c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_VER_FIND), name); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Validate that each version required actually exists in the 5337c478bd9Sstevel@tonic-gate * dependency. 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate nstrs = (char *)STRTAB(nlmp); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate for (vnap = (Vernaux *)((Xword)vnd + vnd->vn_aux); cnt; 5387c478bd9Sstevel@tonic-gate cnt--, vnap = (Vernaux *)((Xword)vnap + vnap->vna_next)) { 5397c478bd9Sstevel@tonic-gate char *version, *define; 5407c478bd9Sstevel@tonic-gate Verdef *vdf = VERDEF(nlmp); 5417c478bd9Sstevel@tonic-gate ulong_t _num, num = VERDEFNUM(nlmp); 5427c478bd9Sstevel@tonic-gate int found = 0; 5437c478bd9Sstevel@tonic-gate 544090a8d9eSAli Bahrami /* 545090a8d9eSAli Bahrami * Skip validation of versions that are marked 546090a8d9eSAli Bahrami * INFO. This optimization is used for versions 547090a8d9eSAli Bahrami * that are inherited by another version. Verification 548090a8d9eSAli Bahrami * of the inheriting version is sufficient. 549090a8d9eSAli Bahrami * 550090a8d9eSAli Bahrami * Such versions are recorded in the object for the 551090a8d9eSAli Bahrami * benefit of VERSYM entries that refer to them. This 55208278a5eSRod Evans * provides a purely diagnostic benefit. 553090a8d9eSAli Bahrami */ 554090a8d9eSAli Bahrami if (vnap->vna_flags & VER_FLG_INFO) 555090a8d9eSAli Bahrami continue; 556090a8d9eSAli Bahrami 5577c478bd9Sstevel@tonic-gate version = (char *)(cstrs + vnap->vna_name); 5585aefb655Srie DBG_CALL(Dbg_ver_need_entry(lml, 0, need, version)); 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5617c478bd9Sstevel@tonic-gate vdf = (Verdef *)((Xword)vdf + vdf->vd_next)) { 5627c478bd9Sstevel@tonic-gate Verdaux *vdap; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate if (vnap->vna_hash != vdf->vd_hash) 5657c478bd9Sstevel@tonic-gate continue; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate vdap = (Verdaux *)((Xword)vdf + vdf->vd_aux); 5687c478bd9Sstevel@tonic-gate define = (char *)(nstrs + vdap->vda_name); 5697c478bd9Sstevel@tonic-gate if (strcmp(version, define) != 0) 5707c478bd9Sstevel@tonic-gate continue; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate found++; 5737c478bd9Sstevel@tonic-gate break; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * If we're being traced print out any matched version 5787c478bd9Sstevel@tonic-gate * when the verbose (-v) option is in effect. Always 5797c478bd9Sstevel@tonic-gate * print any unmatched versions. 5807c478bd9Sstevel@tonic-gate */ 5817c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) { 582a953e2b1Srie /* BEGIN CSTYLED */ 5837c478bd9Sstevel@tonic-gate if (found) { 5847c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_VERBOSE)) 5857c478bd9Sstevel@tonic-gate continue; 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_LDD_VER_FOUND), 5887c478bd9Sstevel@tonic-gate need, version, NAME(nlmp)); 5897c478bd9Sstevel@tonic-gate } else { 5907c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_SILENCERR) 5917c478bd9Sstevel@tonic-gate continue; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_VER_NFOUND), 5947c478bd9Sstevel@tonic-gate need, version); 5957c478bd9Sstevel@tonic-gate } 596a953e2b1Srie /* END CSTYLED */ 5977c478bd9Sstevel@tonic-gate continue; 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6017c478bd9Sstevel@tonic-gate * If the version hasn't been found then this is a 6027c478bd9Sstevel@tonic-gate * candidate for a fatal error condition. Weak 6037c478bd9Sstevel@tonic-gate * version definition requirements are silently 6047c478bd9Sstevel@tonic-gate * ignored. Also, if the image inspected for a version 6057c478bd9Sstevel@tonic-gate * definition has no versioning recorded at all then 6067c478bd9Sstevel@tonic-gate * silently ignore this (this provides better backward 6077c478bd9Sstevel@tonic-gate * compatibility to old images created prior to 6087c478bd9Sstevel@tonic-gate * versioning being available). Both of these skipped 6097c478bd9Sstevel@tonic-gate * diagnostics are available under tracing (see above). 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate if ((found == 0) && (num != 0) && 6127c478bd9Sstevel@tonic-gate (!(vnap->vna_flags & VER_FLG_WEAK))) { 6135aefb655Srie eprintf(lml, ERR_FATAL, 6145aefb655Srie MSG_INTL(MSG_VER_NFOUND), need, version, 6155aefb655Srie NAME(clmp)); 6167c478bd9Sstevel@tonic-gate return (0); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate } 62020272c2eSAli Bahrami DBG_CALL(Dbg_ver_need_done(lml)); 6217c478bd9Sstevel@tonic-gate return (1); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * Search through the dynamic section for DT_NEEDED entries and perform one 6267c478bd9Sstevel@tonic-gate * of two functions. If only the first argument is specified then load the 6277c478bd9Sstevel@tonic-gate * defined shared object, otherwise add the link map representing the defined 6287c478bd9Sstevel@tonic-gate * link map the the dlopen list. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate static int 6319aa23310Srie elf_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) 6327c478bd9Sstevel@tonic-gate { 63356deab07SRod Evans Alist *palp = NULL; 634f441771bSRod Evans Dyn *dyn; 635f441771bSRod Evans Dyninfo *dip; 6367c478bd9Sstevel@tonic-gate Word lmflags = lml->lm_flags; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* 639f441771bSRod Evans * A DYNINFO() structure is created during link-map generation that 640f441771bSRod Evans * parallels the DYN() information, and defines any flags that 641f441771bSRod Evans * influence a dependencies loading. 6427c478bd9Sstevel@tonic-gate */ 643f441771bSRod Evans for (dyn = DYN(clmp), dip = DYNINFO(clmp); 644f441771bSRod Evans !(dip->di_flags & FLG_DI_IGNORE); dyn++, dip++) { 645f441771bSRod Evans uint_t flags = 0, silent = 0; 646f441771bSRod Evans const char *name = dip->di_name; 647481bba9eSRod Evans Rt_map *nlmp = NULL; 6487c478bd9Sstevel@tonic-gate 649f441771bSRod Evans if ((dip->di_flags & FLG_DI_NEEDED) == 0) 6507c478bd9Sstevel@tonic-gate continue; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* 653f441771bSRod Evans * Skip any deferred dependencies, unless ldd(1) has forced 654f441771bSRod Evans * their processing. By default, deferred dependencies are 655f441771bSRod Evans * only processed when an explicit binding to an individual 656f441771bSRod Evans * deferred reference is made. 6577c478bd9Sstevel@tonic-gate */ 658f441771bSRod Evans if ((dip->di_flags & FLG_DI_DEFERRED) && 659f441771bSRod Evans ((rtld_flags & RT_FL_DEFERRED) == 0)) 660f441771bSRod Evans continue; 661f441771bSRod Evans 662f441771bSRod Evans /* 663f441771bSRod Evans * NOTE, libc.so.1 can't be lazy loaded. Although a lazy 664f441771bSRod Evans * position flag won't be produced when a RTLDINFO .dynamic 665f441771bSRod Evans * entry is found (introduced with the UPM in Solaris 10), it 666f441771bSRod Evans * was possible to mark libc for lazy loading on previous 667f441771bSRod Evans * releases. To reduce the overhead of testing for this 668f441771bSRod Evans * occurrence, only carry out this check for the first object 669f441771bSRod Evans * on the link-map list (there aren't many applications built 670f441771bSRod Evans * without libc). 671f441771bSRod Evans */ 672f441771bSRod Evans if ((dip->di_flags & FLG_DI_LAZY) && (lml->lm_head == clmp) && 6737c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_FIL_LIBC)) == 0)) 674f441771bSRod Evans dip->di_flags &= ~FLG_DI_LAZY; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* 677f441771bSRod Evans * Don't bring in lazy loaded objects yet unless we've been 678f441771bSRod Evans * asked to attempt to load all available objects (crle(1) sets 679f441771bSRod Evans * LD_FLAGS=loadavail). Even under RTLD_NOW we don't process 680f441771bSRod Evans * this - RTLD_NOW will cause relocation processing which in 681f441771bSRod Evans * turn might trigger lazy loading, but its possible that the 682f441771bSRod Evans * object has a lazy loaded file with no bindings (i.e., it 683f441771bSRod Evans * should never have been a dependency in the first place). 6847c478bd9Sstevel@tonic-gate */ 685f441771bSRod Evans if (dip->di_flags & FLG_DI_LAZY) { 6867c478bd9Sstevel@tonic-gate if ((lmflags & LML_FLG_LOADAVAIL) == 0) { 6877c478bd9Sstevel@tonic-gate LAZY(clmp)++; 6887c478bd9Sstevel@tonic-gate continue; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 692f441771bSRod Evans * Silence any error messages - see description under 693f441771bSRod Evans * elf_lookup_filtee(). 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) { 6967c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_SILENCERR; 6977c478bd9Sstevel@tonic-gate silent = 1; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7015aefb655Srie DBG_CALL(Dbg_file_needed(clmp, name)); 70275e7992aSrie 70375e7992aSrie /* 70475e7992aSrie * If we're running under ldd(1), indicate that this dependency 70575e7992aSrie * has been processed. It doesn't matter whether the object is 70675e7992aSrie * successfully loaded or not, this flag simply ensures that we 70775e7992aSrie * don't repeatedly attempt to load an object that has already 70875e7992aSrie * failed to load. To do so would create multiple failure 70975e7992aSrie * diagnostics for the same object under ldd(1). 71075e7992aSrie */ 7117c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) 71275e7992aSrie dip->di_flags |= FLG_DI_LDD_DONE; 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* 715f441771bSRod Evans * Identify any group permission requirements. 716f441771bSRod Evans */ 717f441771bSRod Evans if (dip->di_flags & FLG_DI_GROUP) 718f441771bSRod Evans flags = (FLG_RT_SETGROUP | FLG_RT_PUBHDL); 719f441771bSRod Evans 720f441771bSRod Evans /* 7217c478bd9Sstevel@tonic-gate * Establish the objects name, load it and establish a binding 7227c478bd9Sstevel@tonic-gate * with the caller. 7237c478bd9Sstevel@tonic-gate */ 72456deab07SRod Evans if ((elf_fix_name(name, clmp, &palp, AL_CNT_NEEDED, 0) == 0) || 72556deab07SRod Evans ((nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp), 72656deab07SRod Evans flags, 0, in_nfavl)) == NULL) || 72756deab07SRod Evans (bind_one(clmp, nlmp, BND_NEEDED) == 0)) 728481bba9eSRod Evans nlmp = NULL; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* 7317c478bd9Sstevel@tonic-gate * Clean up any infrastructure, including the removal of the 7327c478bd9Sstevel@tonic-gate * error suppression state, if it had been previously set in 7337c478bd9Sstevel@tonic-gate * this routine. 7347c478bd9Sstevel@tonic-gate */ 7352020b2b6SRod Evans remove_alist(&palp, 0); 73656deab07SRod Evans 7377c478bd9Sstevel@tonic-gate if (silent) 7387c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_SILENCERR; 73975e7992aSrie 740481bba9eSRod Evans if ((dip->di_info = (void *)nlmp) == NULL) { 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * If the object could not be mapped, continue if error 7437c478bd9Sstevel@tonic-gate * suppression is established or we're here with ldd(1). 7447c478bd9Sstevel@tonic-gate */ 7457c478bd9Sstevel@tonic-gate if ((MODE(clmp) & RTLD_CONFGEN) || (lmflags & 7467c478bd9Sstevel@tonic-gate (LML_FLG_LOADAVAIL | LML_FLG_TRC_ENABLE))) 7477c478bd9Sstevel@tonic-gate continue; 74856deab07SRod Evans else { 7492020b2b6SRod Evans remove_alist(&palp, 1); 7507c478bd9Sstevel@tonic-gate return (0); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate } 75356deab07SRod Evans } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate if (LAZY(clmp)) 7567c478bd9Sstevel@tonic-gate lml->lm_lazy++; 7577c478bd9Sstevel@tonic-gate 7582020b2b6SRod Evans remove_alist(&palp, 1); 7597c478bd9Sstevel@tonic-gate return (1); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * A null symbol interpretor. Used if a filter has no associated filtees. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 76608278a5eSRod Evans static int 76708278a5eSRod Evans elf_null_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl) 7687c478bd9Sstevel@tonic-gate { 76908278a5eSRod Evans return (0); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * Disable filtee use. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate static void 7767c478bd9Sstevel@tonic-gate elf_disable_filtee(Rt_map *lmp, Dyninfo *dip) 7777c478bd9Sstevel@tonic-gate { 7787c478bd9Sstevel@tonic-gate if ((dip->di_flags & FLG_DI_SYMFLTR) == 0) { 7797c478bd9Sstevel@tonic-gate /* 78056deab07SRod Evans * If this is an object filter, null out the reference name. 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate if (OBJFLTRNDX(lmp) != FLTR_DISABLED) { 78337ffaf83SRod Evans REFNAME(lmp) = NULL; 7847c478bd9Sstevel@tonic-gate OBJFLTRNDX(lmp) = FLTR_DISABLED; 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * Indicate that this filtee is no longer available. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_STDFLTR) 7907c478bd9Sstevel@tonic-gate SYMINTP(lmp) = elf_null_find_sym; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate } else if (dip->di_flags & FLG_DI_STDFLTR) { 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * Indicate that this standard filtee is no longer available. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate if (SYMSFLTRCNT(lmp)) 7987c478bd9Sstevel@tonic-gate SYMSFLTRCNT(lmp)--; 7997c478bd9Sstevel@tonic-gate } else { 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * Indicate that this auxiliary filtee is no longer available. 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate if (SYMAFLTRCNT(lmp)) 8047c478bd9Sstevel@tonic-gate SYMAFLTRCNT(lmp)--; 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate dip->di_flags &= ~MSK_DI_FILTER; 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * Find symbol interpreter - filters. 8117c478bd9Sstevel@tonic-gate * This function is called when the symbols from a shared object should 8127c478bd9Sstevel@tonic-gate * be resolved from the shared objects filtees instead of from within itself. 8137c478bd9Sstevel@tonic-gate * 8147c478bd9Sstevel@tonic-gate * A symbol name of 0 is used to trigger filtee loading. 8157c478bd9Sstevel@tonic-gate */ 81608278a5eSRod Evans static int 81708278a5eSRod Evans _elf_lookup_filtee(Slookup *slp, Sresult *srp, uint_t *binfo, uint_t ndx, 8189aa23310Srie int *in_nfavl) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate const char *name = slp->sl_name, *filtees; 8217c478bd9Sstevel@tonic-gate Rt_map *clmp = slp->sl_cmap; 8227c478bd9Sstevel@tonic-gate Rt_map *ilmp = slp->sl_imap; 82356deab07SRod Evans Pdesc *pdp; 8247c478bd9Sstevel@tonic-gate int any; 8257c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(ilmp)[ndx]; 8267c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(ilmp); 82756deab07SRod Evans Aliste idx; 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* 8307c478bd9Sstevel@tonic-gate * Indicate that the filter has been used. If a binding already exists 8317c478bd9Sstevel@tonic-gate * to the caller, indicate that this object is referenced. This insures 8327c478bd9Sstevel@tonic-gate * we don't generate false unreferenced diagnostics from ldd -u/U or 8337c478bd9Sstevel@tonic-gate * debugging. Don't create a binding regardless, as this filter may 8347c478bd9Sstevel@tonic-gate * have been dlopen()'ed. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate if (name && (ilmp != clmp)) { 8377c478bd9Sstevel@tonic-gate Word tracing = (LIST(clmp)->lm_flags & 8387c478bd9Sstevel@tonic-gate (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED)); 8397c478bd9Sstevel@tonic-gate 8405aefb655Srie if (tracing || DBG_ENABLED) { 841cce0e03bSab196087 Bnd_desc *bdp; 842cce0e03bSab196087 Aliste idx; 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate FLAGS1(ilmp) |= FL1_RT_USED; 8457c478bd9Sstevel@tonic-gate 8465aefb655Srie if ((tracing & LML_FLG_TRC_UNREF) || DBG_ENABLED) { 847cce0e03bSab196087 for (APLIST_TRAVERSE(CALLERS(ilmp), idx, bdp)) { 8487c478bd9Sstevel@tonic-gate if (bdp->b_caller == clmp) { 8497c478bd9Sstevel@tonic-gate bdp->b_flags |= BND_REFER; 8507c478bd9Sstevel@tonic-gate break; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* 8587c478bd9Sstevel@tonic-gate * If this is the first call to process this filter, establish the 8597c478bd9Sstevel@tonic-gate * filtee list. If a configuration file exists, determine if any 8607c478bd9Sstevel@tonic-gate * filtee associations for this filter, and its filtee reference, are 8617c478bd9Sstevel@tonic-gate * defined. Otherwise, process the filtee reference. Any token 8627c478bd9Sstevel@tonic-gate * expansion is also completed at this point (i.e., $PLATFORM). 8637c478bd9Sstevel@tonic-gate */ 864f441771bSRod Evans filtees = dip->di_name; 865481bba9eSRod Evans if (dip->di_info == NULL) { 86608278a5eSRod Evans if (rtld_flags2 & RT_FL2_FLTCFG) { 86756deab07SRod Evans elf_config_flt(lml, PATHNAME(ilmp), filtees, 86856deab07SRod Evans (Alist **)&dip->di_info, AL_CNT_FILTEES); 86908278a5eSRod Evans } 870481bba9eSRod Evans if (dip->di_info == NULL) { 8715aefb655Srie DBG_CALL(Dbg_file_filter(lml, NAME(ilmp), filtees, 0)); 8727c478bd9Sstevel@tonic-gate if ((lml->lm_flags & 8737c478bd9Sstevel@tonic-gate (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH)) && 8747c478bd9Sstevel@tonic-gate ((FLAGS1(ilmp) & FL1_RT_LDDSTUB) == 0)) 8757c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_FIL_FILTER), 8767c478bd9Sstevel@tonic-gate NAME(ilmp), filtees); 8777c478bd9Sstevel@tonic-gate 87856deab07SRod Evans if (expand_paths(ilmp, filtees, (Alist **)&dip->di_info, 87956deab07SRod Evans AL_CNT_FILTEES, 0, 0) == 0) { 8807c478bd9Sstevel@tonic-gate elf_disable_filtee(ilmp, dip); 88108278a5eSRod Evans return (0); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* 8877c478bd9Sstevel@tonic-gate * Traverse the filtee list, dlopen()'ing any objects specified and 8887c478bd9Sstevel@tonic-gate * using their group handle to lookup the symbol. 8897c478bd9Sstevel@tonic-gate */ 89056deab07SRod Evans any = 0; 89156deab07SRod Evans for (ALIST_TRAVERSE((Alist *)dip->di_info, idx, pdp)) { 8927c478bd9Sstevel@tonic-gate int mode; 8937c478bd9Sstevel@tonic-gate Grp_hdl *ghp; 894481bba9eSRod Evans Rt_map *nlmp = NULL; 8957c478bd9Sstevel@tonic-gate 89656deab07SRod Evans if (pdp->pd_plen == 0) 8977c478bd9Sstevel@tonic-gate continue; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate /* 9007c478bd9Sstevel@tonic-gate * Establish the mode of the filtee from the filter. As filtees 9017c478bd9Sstevel@tonic-gate * are loaded via a dlopen(), make sure that RTLD_GROUP is set 9027c478bd9Sstevel@tonic-gate * and the filtees aren't global. It would be nice to have 9037c478bd9Sstevel@tonic-gate * RTLD_FIRST used here also, but as filters got out long before 9047c478bd9Sstevel@tonic-gate * RTLD_FIRST was introduced it's a little too late now. 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate mode = MODE(ilmp) | RTLD_GROUP; 9077c478bd9Sstevel@tonic-gate mode &= ~RTLD_GLOBAL; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * Insure that any auxiliary filter can locate symbols from its 9117c478bd9Sstevel@tonic-gate * caller. 9127c478bd9Sstevel@tonic-gate */ 9137c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_AUXFLTR) 9147c478bd9Sstevel@tonic-gate mode |= RTLD_PARENT; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate /* 91708278a5eSRod Evans * Process any capability directory. Establish a new link-map 91808278a5eSRod Evans * control list from which to analyze any newly added objects. 9197c478bd9Sstevel@tonic-gate */ 92008278a5eSRod Evans if ((pdp->pd_info == NULL) && (pdp->pd_flags & PD_TKN_CAP)) { 92156deab07SRod Evans const char *dir = pdp->pd_pname; 92211a2bb38Srie Aliste lmco; 92311a2bb38Srie 924dde769a2SRod Evans /* 925dde769a2SRod Evans * Establish a link-map control list for this request. 926dde769a2SRod Evans */ 927dde769a2SRod Evans if ((lmco = create_cntl(lml, 0)) == NULL) 92837ffaf83SRod Evans return (NULL); 9297c478bd9Sstevel@tonic-gate 93056deab07SRod Evans /* 93108278a5eSRod Evans * Determine the capability filtees. If none can be 93208278a5eSRod Evans * found, provide suitable diagnostics. 93356deab07SRod Evans */ 93408278a5eSRod Evans DBG_CALL(Dbg_cap_filter(lml, dir, ilmp)); 93508278a5eSRod Evans if (cap_filtees((Alist **)&dip->di_info, idx, dir, 9362020b2b6SRod Evans lmco, ilmp, clmp, filtees, mode, 93708278a5eSRod Evans (FLG_RT_PUBHDL | FLG_RT_CAP), in_nfavl) == 0) { 93856deab07SRod Evans if ((lml->lm_flags & LML_FLG_TRC_ENABLE) && 93956deab07SRod Evans (dip->di_flags & FLG_DI_AUXFLTR) && 94056deab07SRod Evans (rtld_flags & RT_FL_WARNFLTR)) { 94156deab07SRod Evans (void) printf( 94208278a5eSRod Evans MSG_INTL(MSG_LDD_CAP_NFOUND), dir); 94356deab07SRod Evans } 94408278a5eSRod Evans DBG_CALL(Dbg_cap_filter(lml, dir, 0)); 94556deab07SRod Evans } 94656deab07SRod Evans 94756deab07SRod Evans /* 94808278a5eSRod Evans * Re-establish the originating path name descriptor, 94908278a5eSRod Evans * as the expansion of capabilities filtees may have 95008278a5eSRod Evans * re-allocated the controlling Alist. Mark this 95156deab07SRod Evans * original pathname descriptor as unused so that the 95256deab07SRod Evans * descriptor isn't revisited for processing. Any real 95308278a5eSRod Evans * capabilities filtees have been added as new pathname 95408278a5eSRod Evans * descriptors following this descriptor. 95556deab07SRod Evans */ 95656deab07SRod Evans pdp = alist_item((Alist *)dip->di_info, idx); 95708278a5eSRod Evans pdp->pd_flags &= ~PD_TKN_CAP; 95856deab07SRod Evans pdp->pd_plen = 0; 95911a2bb38Srie 96011a2bb38Srie /* 96108278a5eSRod Evans * Now that any capability objects have been processed, 96208278a5eSRod Evans * remove any temporary link-map control list. 96311a2bb38Srie */ 964481bba9eSRod Evans if (lmco != ALIST_OFF_DATA) 96511a2bb38Srie remove_cntl(lml, lmco); 96611a2bb38Srie } 9677c478bd9Sstevel@tonic-gate 96856deab07SRod Evans if (pdp->pd_plen == 0) 9697c478bd9Sstevel@tonic-gate continue; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * Process an individual filtee. 9737c478bd9Sstevel@tonic-gate */ 974481bba9eSRod Evans if (pdp->pd_info == NULL) { 97556deab07SRod Evans const char *filtee = pdp->pd_pname; 9767c478bd9Sstevel@tonic-gate int audit = 0; 9777c478bd9Sstevel@tonic-gate 9785aefb655Srie DBG_CALL(Dbg_file_filtee(lml, NAME(ilmp), filtee, 0)); 9797c478bd9Sstevel@tonic-gate 980481bba9eSRod Evans ghp = NULL; 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * Determine if the reference link map is already 9847c478bd9Sstevel@tonic-gate * loaded. As an optimization compare the filtee with 9857c478bd9Sstevel@tonic-gate * our interpretor. The most common filter is 9867c478bd9Sstevel@tonic-gate * libdl.so.1, which is a filter on ld.so.1. 9877c478bd9Sstevel@tonic-gate */ 9887c478bd9Sstevel@tonic-gate #if defined(_ELF64) 9897c478bd9Sstevel@tonic-gate if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD_64)) == 0) { 9907c478bd9Sstevel@tonic-gate #else 9917c478bd9Sstevel@tonic-gate if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD)) == 0) { 9927c478bd9Sstevel@tonic-gate #endif 9932017c965SRod Evans uint_t hflags, rdflags, cdflags; 9942017c965SRod Evans 9957c478bd9Sstevel@tonic-gate /* 9962017c965SRod Evans * Establish any flags for the handle (Grp_hdl). 9972017c965SRod Evans * 9982017c965SRod Evans * - This is a special, public, ld.so.1 9992017c965SRod Evans * handle. 10002017c965SRod Evans * - Only the first object on this handle 10012017c965SRod Evans * can supply symbols. 10022017c965SRod Evans * - This handle provides a filtee. 10032017c965SRod Evans * 10042017c965SRod Evans * Essentially, this handle allows a caller to 10052017c965SRod Evans * reference the dl*() family of interfaces from 10062017c965SRod Evans * ld.so.1. 10077c478bd9Sstevel@tonic-gate */ 10082017c965SRod Evans hflags = (GPH_PUBLIC | GPH_LDSO | 10092017c965SRod Evans GPH_FIRST | GPH_FILTEE); 10102017c965SRod Evans 10112017c965SRod Evans /* 10122017c965SRod Evans * Establish the flags for the referenced 10132017c965SRod Evans * dependency descriptor (Grp_desc). 10142017c965SRod Evans * 10152017c965SRod Evans * - ld.so.1 is available for dlsym(). 10162017c965SRod Evans * - ld.so.1 is available to relocate 10172017c965SRod Evans * against. 10182017c965SRod Evans * - There's no need to add an dependencies 10192017c965SRod Evans * to this handle. 10202017c965SRod Evans */ 10212017c965SRod Evans rdflags = (GPD_DLSYM | GPD_RELOC); 10222017c965SRod Evans 10232017c965SRod Evans /* 10242017c965SRod Evans * Establish the flags for this callers 10252017c965SRod Evans * dependency descriptor (Grp_desc). 10262017c965SRod Evans * 10272017c965SRod Evans * - The explicit creation of a handle 10282017c965SRod Evans * creates a descriptor for the referenced 10292017c965SRod Evans * object and the parent (caller). 10302017c965SRod Evans */ 10312017c965SRod Evans cdflags = GPD_PARENT; 10322017c965SRod Evans 10337c478bd9Sstevel@tonic-gate nlmp = lml_rtld.lm_head; 10347c478bd9Sstevel@tonic-gate if ((ghp = hdl_create(&lml_rtld, nlmp, ilmp, 10352017c965SRod Evans hflags, rdflags, cdflags)) == NULL) 1036481bba9eSRod Evans nlmp = NULL; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * Establish the filter handle to prevent any 10407c478bd9Sstevel@tonic-gate * recursion. 10417c478bd9Sstevel@tonic-gate */ 10427c478bd9Sstevel@tonic-gate if (nlmp && ghp) 104356deab07SRod Evans pdp->pd_info = (void *)ghp; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * Audit the filter/filtee established. Ignore 10477c478bd9Sstevel@tonic-gate * any return from the auditor, as we can't 10487c478bd9Sstevel@tonic-gate * allow ignore filtering to ld.so.1, otherwise 10497c478bd9Sstevel@tonic-gate * nothing is going to work. 10507c478bd9Sstevel@tonic-gate */ 105156deab07SRod Evans if (nlmp && ((lml->lm_tflags | AFLAGS(ilmp)) & 105202ca3e02Srie LML_TFLG_AUD_OBJFILTER)) 10537c478bd9Sstevel@tonic-gate (void) audit_objfilter(ilmp, filtees, 10547c478bd9Sstevel@tonic-gate nlmp, 0); 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate } else { 10577c478bd9Sstevel@tonic-gate Rej_desc rej = { 0 }; 105856deab07SRod Evans Fdesc fd = { 0 }; 105911a2bb38Srie Aliste lmco; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /* 106256deab07SRod Evans * Trace the inspection of this file, determine 106356deab07SRod Evans * any auditor substitution, and seed the file 106456deab07SRod Evans * descriptor with the originating name. 106556deab07SRod Evans */ 106656deab07SRod Evans if (load_trace(lml, pdp, clmp, &fd) == NULL) 106756deab07SRod Evans continue; 106856deab07SRod Evans 106956deab07SRod Evans /* 1070dde769a2SRod Evans * Establish a link-map control list for this 1071dde769a2SRod Evans * request. 10727c478bd9Sstevel@tonic-gate */ 1073dde769a2SRod Evans if ((lmco = create_cntl(lml, 0)) == NULL) 107437ffaf83SRod Evans return (NULL); 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* 107756deab07SRod Evans * Locate and load the filtee. 10787c478bd9Sstevel@tonic-gate */ 107956deab07SRod Evans if ((nlmp = load_path(lml, lmco, ilmp, mode, 10802017c965SRod Evans FLG_RT_PUBHDL, &ghp, &fd, &rej, 108156deab07SRod Evans in_nfavl)) == NULL) 10827c478bd9Sstevel@tonic-gate file_notfound(LIST(ilmp), filtee, ilmp, 10832017c965SRod Evans FLG_RT_PUBHDL, &rej); 108456deab07SRod Evans 108556deab07SRod Evans filtee = pdp->pd_pname; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * Establish the filter handle to prevent any 10897c478bd9Sstevel@tonic-gate * recursion. 10907c478bd9Sstevel@tonic-gate */ 10917c478bd9Sstevel@tonic-gate if (nlmp && ghp) { 10927c478bd9Sstevel@tonic-gate ghp->gh_flags |= GPH_FILTEE; 109356deab07SRod Evans pdp->pd_info = (void *)ghp; 10949aa23310Srie 10959aa23310Srie FLAGS1(nlmp) |= FL1_RT_USED; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * Audit the filter/filtee established. A 11007c478bd9Sstevel@tonic-gate * return of 0 indicates the auditor wishes to 11017c478bd9Sstevel@tonic-gate * ignore this filtee. 11027c478bd9Sstevel@tonic-gate */ 11037c478bd9Sstevel@tonic-gate if (nlmp && ((lml->lm_tflags | FLAGS1(ilmp)) & 11047c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJFILTER)) { 11057c478bd9Sstevel@tonic-gate if (audit_objfilter(ilmp, filtees, 11067c478bd9Sstevel@tonic-gate nlmp, 0) == 0) { 11077c478bd9Sstevel@tonic-gate audit = 1; 1108481bba9eSRod Evans nlmp = NULL; 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * Finish processing the objects associated with 11147c478bd9Sstevel@tonic-gate * this request. Create an association between 11157c478bd9Sstevel@tonic-gate * this object and the originating filter to 11167c478bd9Sstevel@tonic-gate * provide sufficient information to tear down 11177c478bd9Sstevel@tonic-gate * this filtee if necessary. 11187c478bd9Sstevel@tonic-gate */ 111956deab07SRod Evans if (nlmp && ghp && (((nlmp = analyze_lmc(lml, 11202020b2b6SRod Evans lmco, nlmp, clmp, in_nfavl)) == NULL) || 112156deab07SRod Evans (relocate_lmc(lml, lmco, ilmp, nlmp, 112256deab07SRod Evans in_nfavl) == 0))) 1123481bba9eSRod Evans nlmp = NULL; 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate /* 11267c478bd9Sstevel@tonic-gate * If the filtee has been successfully 112702ca3e02Srie * processed, then create an association 112802ca3e02Srie * between the filter and filtee. This 112902ca3e02Srie * association provides sufficient information 113002ca3e02Srie * to tear down the filter and filtee if 113102ca3e02Srie * necessary. 11327c478bd9Sstevel@tonic-gate */ 11338af2c5b9Srie DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); 11342017c965SRod Evans if (nlmp && ghp && (hdl_add(ghp, ilmp, 11352017c965SRod Evans GPD_FILTER, NULL) == NULL)) 1136481bba9eSRod Evans nlmp = NULL; 113711a2bb38Srie 113811a2bb38Srie /* 113956deab07SRod Evans * Generate a diagnostic if the filtee couldn't 114056deab07SRod Evans * be loaded. 114156deab07SRod Evans */ 1142481bba9eSRod Evans if (nlmp == NULL) 114356deab07SRod Evans DBG_CALL(Dbg_file_filtee(lml, 0, filtee, 114456deab07SRod Evans audit)); 114556deab07SRod Evans 114656deab07SRod Evans /* 114702ca3e02Srie * If this filtee loading has failed, and we've 114802ca3e02Srie * created a new link-map control list to which 114902ca3e02Srie * this request has added objects, then remove 115002ca3e02Srie * all the objects that have been associated to 115102ca3e02Srie * this request. 115211a2bb38Srie */ 1153481bba9eSRod Evans if ((nlmp == NULL) && (lmco != ALIST_OFF_DATA)) 1154481bba9eSRod Evans remove_lmc(lml, clmp, lmco, name); 115502ca3e02Srie 115602ca3e02Srie /* 1157dde769a2SRod Evans * Remove any temporary link-map control list. 115802ca3e02Srie */ 1159481bba9eSRod Evans if (lmco != ALIST_OFF_DATA) 116011a2bb38Srie remove_cntl(lml, lmco); 116111a2bb38Srie } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 116456deab07SRod Evans * If the filtee couldn't be loaded, null out the 116556deab07SRod Evans * path name descriptor entry, and continue the search. 116656deab07SRod Evans * Otherwise, the group handle is retained for future 116756deab07SRod Evans * symbol searches. 11687c478bd9Sstevel@tonic-gate */ 1169481bba9eSRod Evans if (nlmp == NULL) { 117056deab07SRod Evans pdp->pd_info = NULL; 117156deab07SRod Evans pdp->pd_plen = 0; 11727c478bd9Sstevel@tonic-gate continue; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate 117656deab07SRod Evans ghp = (Grp_hdl *)pdp->pd_info; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* 117908278a5eSRod Evans * If name is NULL, we're here to trigger filtee loading. 118008278a5eSRod Evans * Skip the symbol lookup so that we'll continue looking for 118108278a5eSRod Evans * additional filtees. 11827c478bd9Sstevel@tonic-gate */ 11837c478bd9Sstevel@tonic-gate if (name) { 11847c478bd9Sstevel@tonic-gate Grp_desc *gdp; 118508278a5eSRod Evans int ret = 0; 1186cce0e03bSab196087 Aliste idx; 11877c478bd9Sstevel@tonic-gate Slookup sl = *slp; 11887c478bd9Sstevel@tonic-gate 118908278a5eSRod Evans sl.sl_flags |= (LKUP_FIRST | LKUP_DLSYM); 11907c478bd9Sstevel@tonic-gate any++; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate /* 11937c478bd9Sstevel@tonic-gate * Look for the symbol in the handles dependencies. 11947c478bd9Sstevel@tonic-gate */ 1195cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 1196efb9e8b8Srie if ((gdp->gd_flags & GPD_DLSYM) == 0) 11977c478bd9Sstevel@tonic-gate continue; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * If our parent is a dependency don't look at 12017c478bd9Sstevel@tonic-gate * it (otherwise we are in a recursive loop). 12027c478bd9Sstevel@tonic-gate * This situation can occur with auxiliary 12037c478bd9Sstevel@tonic-gate * filters if the filtee has a dependency on the 12047c478bd9Sstevel@tonic-gate * filter. This dependency isn't necessary as 12057c478bd9Sstevel@tonic-gate * auxiliary filters are opened RTLD_PARENT, but 12067c478bd9Sstevel@tonic-gate * users may still unknowingly add an explicit 12077c478bd9Sstevel@tonic-gate * dependency to the parent. 12087c478bd9Sstevel@tonic-gate */ 12097c478bd9Sstevel@tonic-gate if ((sl.sl_imap = gdp->gd_depend) == ilmp) 12107c478bd9Sstevel@tonic-gate continue; 12117c478bd9Sstevel@tonic-gate 121208278a5eSRod Evans if (((ret = SYMINTP(sl.sl_imap)(&sl, srp, binfo, 121308278a5eSRod Evans in_nfavl)) != 0) || 12147c478bd9Sstevel@tonic-gate (ghp->gh_flags & GPH_FIRST)) 12157c478bd9Sstevel@tonic-gate break; 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate /* 121902ca3e02Srie * If a symbol has been found, indicate the binding 122002ca3e02Srie * and return the symbol. 12217c478bd9Sstevel@tonic-gate */ 122208278a5eSRod Evans if (ret) { 12237c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_FILTEE; 122408278a5eSRod Evans return (1); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * If this object is tagged to terminate filtee processing we're 12307c478bd9Sstevel@tonic-gate * done. 12317c478bd9Sstevel@tonic-gate */ 12325aefb655Srie if (FLAGS1(ghp->gh_ownlmp) & FL1_RT_ENDFILTE) 12337c478bd9Sstevel@tonic-gate break; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * If we're just here to trigger filtee loading then we're done. 12387c478bd9Sstevel@tonic-gate */ 1239481bba9eSRod Evans if (name == NULL) 124008278a5eSRod Evans return (0); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate /* 124356deab07SRod Evans * If no filtees have been found for a filter, clean up any path name 124456deab07SRod Evans * descriptors and disable their search completely. For auxiliary 12457c478bd9Sstevel@tonic-gate * filters we can reselect the symbol search function so that we never 12467c478bd9Sstevel@tonic-gate * enter this routine again for this object. For standard filters we 12477c478bd9Sstevel@tonic-gate * use the null symbol routine. 12487c478bd9Sstevel@tonic-gate */ 12497c478bd9Sstevel@tonic-gate if (any == 0) { 12502020b2b6SRod Evans remove_alist((Alist **)&(dip->di_info), 1); 12517c478bd9Sstevel@tonic-gate elf_disable_filtee(ilmp, dip); 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate 125408278a5eSRod Evans return (0); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * Focal point for disabling error messages for auxiliary filters. As an 12597c478bd9Sstevel@tonic-gate * auxiliary filter allows for filtee use, but provides a fallback should a 12607c478bd9Sstevel@tonic-gate * filtee not exist (or fail to load), any errors generated as a consequence of 12617c478bd9Sstevel@tonic-gate * trying to load the filtees are typically suppressed. Setting RT_FL_SILENCERR 126208278a5eSRod Evans * suppresses errors generated by eprintf(), but ensures a debug diagnostic is 126308278a5eSRod Evans * produced. ldd(1) employs printf(), and here the selection of whether to 12647c478bd9Sstevel@tonic-gate * print a diagnostic in regards to auxiliary filters is a little more complex. 12657c478bd9Sstevel@tonic-gate * 12662017c965SRod Evans * - The determination of whether to produce an ldd message, or a fatal 12677c478bd9Sstevel@tonic-gate * error message is driven by LML_FLG_TRC_ENABLE. 12682017c965SRod Evans * - More detailed ldd messages may also be driven off of LML_FLG_TRC_WARN, 12697c478bd9Sstevel@tonic-gate * (ldd -d/-r), LML_FLG_TRC_VERBOSE (ldd -v), LML_FLG_TRC_SEARCH (ldd -s), 12707c478bd9Sstevel@tonic-gate * and LML_FLG_TRC_UNREF/LML_FLG_TRC_UNUSED (ldd -U/-u). 12712017c965SRod Evans * - If the calling object is lddstub, then several classes of message are 12727c478bd9Sstevel@tonic-gate * suppressed. The user isn't trying to diagnose lddstub, this is simply 12737c478bd9Sstevel@tonic-gate * a stub executable employed to preload a user specified library against. 12742017c965SRod Evans * - If RT_FL_SILENCERR is in effect then any generic ldd() messages should 12757c478bd9Sstevel@tonic-gate * be suppressed. All detailed ldd messages should still be produced. 12767c478bd9Sstevel@tonic-gate */ 127708278a5eSRod Evans int 127808278a5eSRod Evans elf_lookup_filtee(Slookup *slp, Sresult *srp, uint_t *binfo, uint_t ndx, 12799aa23310Srie int *in_nfavl) 12807c478bd9Sstevel@tonic-gate { 12817c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(slp->sl_imap)[ndx]; 128208278a5eSRod Evans int ret, silent = 0; 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate /* 12857c478bd9Sstevel@tonic-gate * Make sure this entry is still acting as a filter. We may have tried 12867c478bd9Sstevel@tonic-gate * to process this previously, and disabled it if the filtee couldn't 12877c478bd9Sstevel@tonic-gate * be processed. However, other entries may provide different filtees 12887c478bd9Sstevel@tonic-gate * that are yet to be completed. 12897c478bd9Sstevel@tonic-gate */ 12907c478bd9Sstevel@tonic-gate if (dip->di_flags == 0) 129108278a5eSRod Evans return (0); 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * Indicate whether an error message is required should this filtee not 12957c478bd9Sstevel@tonic-gate * be found, based on the type of filter. 12967c478bd9Sstevel@tonic-gate */ 12977c478bd9Sstevel@tonic-gate if ((dip->di_flags & FLG_DI_AUXFLTR) && 12987c478bd9Sstevel@tonic-gate ((rtld_flags & (RT_FL_WARNFLTR | RT_FL_SILENCERR)) == 0)) { 12997c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_SILENCERR; 13007c478bd9Sstevel@tonic-gate silent = 1; 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 130308278a5eSRod Evans ret = _elf_lookup_filtee(slp, srp, binfo, ndx, in_nfavl); 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate if (silent) 13067c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_SILENCERR; 13077c478bd9Sstevel@tonic-gate 130808278a5eSRod Evans return (ret); 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* 13127c478bd9Sstevel@tonic-gate * Compute the elf hash value (as defined in the ELF access library). 13137c478bd9Sstevel@tonic-gate * The form of the hash table is: 13147c478bd9Sstevel@tonic-gate * 13157c478bd9Sstevel@tonic-gate * |--------------| 13167c478bd9Sstevel@tonic-gate * | # of buckets | 13177c478bd9Sstevel@tonic-gate * |--------------| 13187c478bd9Sstevel@tonic-gate * | # of chains | 13197c478bd9Sstevel@tonic-gate * |--------------| 13207c478bd9Sstevel@tonic-gate * | bucket[] | 13217c478bd9Sstevel@tonic-gate * |--------------| 13227c478bd9Sstevel@tonic-gate * | chain[] | 13237c478bd9Sstevel@tonic-gate * |--------------| 13247c478bd9Sstevel@tonic-gate */ 13257c478bd9Sstevel@tonic-gate ulong_t 13267c478bd9Sstevel@tonic-gate elf_hash(const char *name) 13277c478bd9Sstevel@tonic-gate { 13287c478bd9Sstevel@tonic-gate uint_t hval = 0; 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate while (*name) { 13317c478bd9Sstevel@tonic-gate uint_t g; 13327c478bd9Sstevel@tonic-gate hval = (hval << 4) + *name++; 13337c478bd9Sstevel@tonic-gate if ((g = (hval & 0xf0000000)) != 0) 13347c478bd9Sstevel@tonic-gate hval ^= g >> 24; 13357c478bd9Sstevel@tonic-gate hval &= ~g; 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate return ((ulong_t)hval); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* 134108278a5eSRod Evans * Look up a symbol. The callers lookup information is passed in the Slookup 134208278a5eSRod Evans * structure, and any resultant binding information is returned in the Sresult 134308278a5eSRod Evans * structure. 13447c478bd9Sstevel@tonic-gate */ 134508278a5eSRod Evans int 134608278a5eSRod Evans elf_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl) 13477c478bd9Sstevel@tonic-gate { 13487c478bd9Sstevel@tonic-gate const char *name = slp->sl_name; 13497c478bd9Sstevel@tonic-gate Rt_map *ilmp = slp->sl_imap; 13507c478bd9Sstevel@tonic-gate ulong_t hash = slp->sl_hash; 135108278a5eSRod Evans uint_t ndx, hashoff, buckets, *chainptr; 13527c478bd9Sstevel@tonic-gate Sym *sym, *symtabptr; 13537c478bd9Sstevel@tonic-gate char *strtabptr, *strtabname; 13547c478bd9Sstevel@tonic-gate uint_t flags1; 13557c478bd9Sstevel@tonic-gate Syminfo *sip; 13567c478bd9Sstevel@tonic-gate 1357660acd81Srie /* 1358660acd81Srie * If we're only here to establish a symbols index, skip the diagnostic 1359660acd81Srie * used to trace a symbol search. 1360660acd81Srie */ 13615aefb655Srie if ((slp->sl_flags & LKUP_SYMNDX) == 0) 13625aefb655Srie DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_ELF))); 13637c478bd9Sstevel@tonic-gate 1364481bba9eSRod Evans if (HASH(ilmp) == NULL) 136508278a5eSRod Evans return (0); 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate buckets = HASH(ilmp)[0]; 13687c478bd9Sstevel@tonic-gate /* LINTED */ 136908278a5eSRod Evans hashoff = ((uint_t)hash % buckets) + 2; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* 137208278a5eSRod Evans * Get the first symbol from the hash chain and initialize the string 13737c478bd9Sstevel@tonic-gate * and symbol table pointers. 13747c478bd9Sstevel@tonic-gate */ 137508278a5eSRod Evans if ((ndx = HASH(ilmp)[hashoff]) == 0) 137608278a5eSRod Evans return (0); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate chainptr = HASH(ilmp) + 2 + buckets; 13797c478bd9Sstevel@tonic-gate strtabptr = STRTAB(ilmp); 13807c478bd9Sstevel@tonic-gate symtabptr = SYMTAB(ilmp); 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate while (ndx) { 13837c478bd9Sstevel@tonic-gate sym = symtabptr + ndx; 13847c478bd9Sstevel@tonic-gate strtabname = strtabptr + sym->st_name; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * Compare the symbol found with the name required. If the 13887c478bd9Sstevel@tonic-gate * names don't match continue with the next hash entry. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate if ((*strtabname++ != *name) || strcmp(strtabname, &name[1])) { 139108278a5eSRod Evans hashoff = ndx + buckets + 2; 13927c478bd9Sstevel@tonic-gate if ((ndx = chainptr[ndx]) != 0) 13937c478bd9Sstevel@tonic-gate continue; 139408278a5eSRod Evans return (0); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* 139808278a5eSRod Evans * Symbols that are defined as hidden within an object usually 139908278a5eSRod Evans * have any references from within the same object bound at 140008278a5eSRod Evans * link-edit time, thus ld.so.1 is not involved. However, if 140108278a5eSRod Evans * these are capabilities symbols, then references to them must 140208278a5eSRod Evans * be resolved at runtime. A hidden symbol can only be bound 140308278a5eSRod Evans * to by the object that defines the symbol. 140408278a5eSRod Evans */ 140508278a5eSRod Evans if ((sym->st_shndx != SHN_UNDEF) && 140608278a5eSRod Evans (ELF_ST_VISIBILITY(sym->st_other) == STV_HIDDEN) && 140708278a5eSRod Evans (slp->sl_cmap != ilmp)) 140808278a5eSRod Evans return (0); 140908278a5eSRod Evans 141008278a5eSRod Evans /* 1411d840867fSab196087 * The Solaris ld does not put DT_VERSYM in the dynamic 1412d840867fSab196087 * section, but the GNU ld does. The GNU runtime linker 1413d840867fSab196087 * interprets the top bit of the 16-bit Versym value 1414d840867fSab196087 * (0x8000) as the "hidden" bit. If this bit is set, 1415d840867fSab196087 * the linker is supposed to act as if that symbol does 1416d840867fSab196087 * not exist. The hidden bit supports their versioning 1417d840867fSab196087 * scheme, which allows multiple incompatible functions 1418d840867fSab196087 * with the same name to exist at different versions 1419d840867fSab196087 * within an object. The Solaris linker does not support this 1420d840867fSab196087 * mechanism, or the model of interface evolution that 1421d840867fSab196087 * it allows, but we honor the hidden bit in GNU ld 1422d840867fSab196087 * produced objects in order to interoperate with them. 14233b41b08bSab196087 */ 142408278a5eSRod Evans if (VERSYM(ilmp) && (VERSYM(ilmp)[ndx] & 0x8000)) { 1425d840867fSab196087 DBG_CALL(Dbg_syms_ignore_gnuver(ilmp, name, 14263b41b08bSab196087 ndx, VERSYM(ilmp)[ndx])); 142708278a5eSRod Evans return (0); 14283b41b08bSab196087 } 14293b41b08bSab196087 14303b41b08bSab196087 /* 143108278a5eSRod Evans * If we're only here to establish a symbol's index, we're done. 1432660acd81Srie */ 143308278a5eSRod Evans if (slp->sl_flags & LKUP_SYMNDX) { 143408278a5eSRod Evans srp->sr_dmap = ilmp; 143508278a5eSRod Evans srp->sr_sym = sym; 143608278a5eSRod Evans return (1); 143708278a5eSRod Evans } 1438660acd81Srie 1439660acd81Srie /* 144008278a5eSRod Evans * If we find a match and the symbol is defined, capture the 14417c478bd9Sstevel@tonic-gate * symbol pointer and the link map in which it was found. 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate if (sym->st_shndx != SHN_UNDEF) { 144408278a5eSRod Evans srp->sr_dmap = ilmp; 144508278a5eSRod Evans srp->sr_sym = sym; 14467c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_FOUND; 144708278a5eSRod Evans 14489a411307Srie if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) || 14499a411307Srie ((FLAGS(ilmp) & FLG_RT_SYMINTPO) && 14509a411307Srie is_sym_interposer(ilmp, sym))) 14517c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_INTERPOSE; 14527c478bd9Sstevel@tonic-gate break; 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * If we find a match and the symbol is undefined, the 14567c478bd9Sstevel@tonic-gate * symbol type is a function, and the value of the symbol 14577c478bd9Sstevel@tonic-gate * is non zero, then this is a special case. This allows 14587c478bd9Sstevel@tonic-gate * the resolution of a function address to the plt[] entry. 14597c478bd9Sstevel@tonic-gate * See SPARC ABI, Dynamic Linking, Function Addresses for 14607c478bd9Sstevel@tonic-gate * more details. 14617c478bd9Sstevel@tonic-gate */ 1462660acd81Srie } else if ((slp->sl_flags & LKUP_SPEC) && 14637c478bd9Sstevel@tonic-gate (FLAGS(ilmp) & FLG_RT_ISMAIN) && (sym->st_value != 0) && 14647c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(sym->st_info) == STT_FUNC)) { 146508278a5eSRod Evans srp->sr_dmap = ilmp; 146608278a5eSRod Evans srp->sr_sym = sym; 14677c478bd9Sstevel@tonic-gate *binfo |= (DBG_BINFO_FOUND | DBG_BINFO_PLTADDR); 146808278a5eSRod Evans 14699a411307Srie if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) || 14709a411307Srie ((FLAGS(ilmp) & FLG_RT_SYMINTPO) && 14719a411307Srie is_sym_interposer(ilmp, sym))) 14727c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_INTERPOSE; 147308278a5eSRod Evans return (1); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate /* 14777c478bd9Sstevel@tonic-gate * Undefined symbol. 14787c478bd9Sstevel@tonic-gate */ 147908278a5eSRod Evans return (0); 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * We've found a match. Determine if the defining object contains 14847c478bd9Sstevel@tonic-gate * symbol binding information. 14857c478bd9Sstevel@tonic-gate */ 1486481bba9eSRod Evans if ((sip = SYMINFO(ilmp)) != NULL) 14879039eeafSab196087 sip += ndx; 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate /* 149060758829Srie * If this definition is a singleton, and we haven't followed a default 149160758829Srie * symbol search knowing that we're looking for a singleton (presumably 149260758829Srie * because the symbol definition has been changed since the referring 149360758829Srie * object was built), then reject this binding so that the caller can 149460758829Srie * fall back to a standard symbol search. 149560758829Srie */ 149660758829Srie if ((ELF_ST_VISIBILITY(sym->st_other) == STV_SINGLETON) && 149760758829Srie (((slp->sl_flags & LKUP_STANDARD) == 0) || 149860758829Srie (((slp->sl_flags & LKUP_SINGLETON) == 0) && 149960758829Srie (LIST(ilmp)->lm_flags & LML_FLG_GROUPSEXIST)))) { 150060758829Srie DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 150160758829Srie DBG_BNDREJ_SINGLE)); 150260758829Srie *binfo |= BINFO_REJSINGLE; 150360758829Srie *binfo &= ~DBG_BINFO_MSK; 150408278a5eSRod Evans return (0); 150560758829Srie } 150660758829Srie 150760758829Srie /* 15087c478bd9Sstevel@tonic-gate * If this is a direct binding request, but the symbol definition has 15097c478bd9Sstevel@tonic-gate * disabled directly binding to it (presumably because the symbol 15107c478bd9Sstevel@tonic-gate * definition has been changed since the referring object was built), 151137ffaf83SRod Evans * reject this binding so that the caller can fall back to a standard 151260758829Srie * symbol search. 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate if (sip && (slp->sl_flags & LKUP_DIRECT) && 15157c478bd9Sstevel@tonic-gate (sip->si_flags & SYMINFO_FLG_NOEXTDIRECT)) { 151660758829Srie DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 151737ffaf83SRod Evans DBG_BNDREJ_DIRECT)); 151860758829Srie *binfo |= BINFO_REJDIRECT; 15197c478bd9Sstevel@tonic-gate *binfo &= ~DBG_BINFO_MSK; 152008278a5eSRod Evans return (0); 152137ffaf83SRod Evans } 152237ffaf83SRod Evans 152337ffaf83SRod Evans /* 152437ffaf83SRod Evans * If this is a binding request within an RTLD_GROUP family, and the 152537ffaf83SRod Evans * symbol has disabled directly binding to it, reject this binding so 152637ffaf83SRod Evans * that the caller can fall back to a standard symbol search. 152737ffaf83SRod Evans * 152837ffaf83SRod Evans * Effectively, an RTLD_GROUP family achieves what can now be 152937ffaf83SRod Evans * established with direct bindings. However, various symbols have 153037ffaf83SRod Evans * been tagged as inappropriate for direct binding to (ie. libc:malloc). 153137ffaf83SRod Evans * 153237ffaf83SRod Evans * A symbol marked as no-direct cannot be used within a group without 153337ffaf83SRod Evans * first ensuring that the symbol has not been interposed upon outside 153437ffaf83SRod Evans * of the group. A common example occurs when users implement their own 153537ffaf83SRod Evans * version of malloc() in the executable. Such a malloc() interposes on 153637ffaf83SRod Evans * the libc:malloc, and this interposition must be honored within the 153737ffaf83SRod Evans * group as well. 153837ffaf83SRod Evans * 153937ffaf83SRod Evans * Following any rejection, LKUP_WORLD is established as a means of 154037ffaf83SRod Evans * overriding this test as we return to a standard search. 154137ffaf83SRod Evans */ 154237ffaf83SRod Evans if (sip && (sip->si_flags & SYMINFO_FLG_NOEXTDIRECT) && 154337ffaf83SRod Evans ((MODE(slp->sl_cmap) & (RTLD_GROUP | RTLD_WORLD)) == RTLD_GROUP) && 154437ffaf83SRod Evans ((slp->sl_flags & LKUP_WORLD) == 0)) { 154537ffaf83SRod Evans DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 154637ffaf83SRod Evans DBG_BNDREJ_GROUP)); 154737ffaf83SRod Evans *binfo |= BINFO_REJGROUP; 154837ffaf83SRod Evans *binfo &= ~DBG_BINFO_MSK; 154908278a5eSRod Evans return (0); 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate /* 155308278a5eSRod Evans * If this symbol is associated with capabilities, then each of the 155408278a5eSRod Evans * capabilities instances needs to be compared against the system 155508278a5eSRod Evans * capabilities. The best instance will be chosen to satisfy this 155608278a5eSRod Evans * binding. 155708278a5eSRod Evans */ 155808278a5eSRod Evans if (CAP(ilmp) && CAPINFO(ilmp) && ELF_C_GROUP(CAPINFO(ilmp)[ndx]) && 155908278a5eSRod Evans (cap_match(srp, ndx, symtabptr, strtabptr) == 0)) 156008278a5eSRod Evans return (0); 156108278a5eSRod Evans 156208278a5eSRod Evans /* 15637c478bd9Sstevel@tonic-gate * Determine whether this object is acting as a filter. 15647c478bd9Sstevel@tonic-gate */ 15657c478bd9Sstevel@tonic-gate if (((flags1 = FLAGS1(ilmp)) & MSK_RT_FILTER) == 0) 156608278a5eSRod Evans return (1); 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate /* 15697c478bd9Sstevel@tonic-gate * Determine if this object offers per-symbol filtering, and if so, 15707c478bd9Sstevel@tonic-gate * whether this symbol references a filtee. 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate if (sip && (flags1 & (FL1_RT_SYMSFLTR | FL1_RT_SYMAFLTR))) { 15737c478bd9Sstevel@tonic-gate /* 15747c478bd9Sstevel@tonic-gate * If this is a standard filter reference, and no standard 15757c478bd9Sstevel@tonic-gate * filtees remain to be inspected, we're done. If this is an 15767c478bd9Sstevel@tonic-gate * auxiliary filter reference, and no auxiliary filtees remain, 15777c478bd9Sstevel@tonic-gate * we'll fall through in case any object filtering is available. 15787c478bd9Sstevel@tonic-gate */ 15797c478bd9Sstevel@tonic-gate if ((sip->si_flags & SYMINFO_FLG_FILTER) && 15807c478bd9Sstevel@tonic-gate (SYMSFLTRCNT(ilmp) == 0)) 158108278a5eSRod Evans return (0); 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate if ((sip->si_flags & SYMINFO_FLG_FILTER) || 15847c478bd9Sstevel@tonic-gate ((sip->si_flags & SYMINFO_FLG_AUXILIARY) && 15857c478bd9Sstevel@tonic-gate SYMAFLTRCNT(ilmp))) { 158608278a5eSRod Evans Sresult sr; 158708278a5eSRod Evans 158808278a5eSRod Evans /* 158908278a5eSRod Evans * Initialize a local symbol result descriptor, using 159008278a5eSRod Evans * the original symbol name. 159108278a5eSRod Evans */ 159208278a5eSRod Evans SRESULT_INIT(sr, slp->sl_name); 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate /* 15957c478bd9Sstevel@tonic-gate * This symbol has an associated filtee. Lookup the 15967c478bd9Sstevel@tonic-gate * symbol in the filtee, and if it is found return it. 15977c478bd9Sstevel@tonic-gate * If the symbol doesn't exist, and this is a standard 15987c478bd9Sstevel@tonic-gate * filter, return an error, otherwise fall through to 15997c478bd9Sstevel@tonic-gate * catch any object filtering that may be available. 16007c478bd9Sstevel@tonic-gate */ 160108278a5eSRod Evans if (elf_lookup_filtee(slp, &sr, binfo, sip->si_boundto, 160208278a5eSRod Evans in_nfavl)) { 160308278a5eSRod Evans *srp = sr; 160408278a5eSRod Evans return (1); 160508278a5eSRod Evans } 16067c478bd9Sstevel@tonic-gate if (sip->si_flags & SYMINFO_FLG_FILTER) 160708278a5eSRod Evans return (0); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * Determine if this object provides global filtering. 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate if (flags1 & (FL1_RT_OBJSFLTR | FL1_RT_OBJAFLTR)) { 16157c478bd9Sstevel@tonic-gate if (OBJFLTRNDX(ilmp) != FLTR_DISABLED) { 161608278a5eSRod Evans Sresult sr; 161708278a5eSRod Evans 161808278a5eSRod Evans /* 161908278a5eSRod Evans * Initialize a local symbol result descriptor, using 162008278a5eSRod Evans * the original symbol name. 162108278a5eSRod Evans */ 162208278a5eSRod Evans SRESULT_INIT(sr, slp->sl_name); 162308278a5eSRod Evans 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * This object has an associated filtee. Lookup the 16267c478bd9Sstevel@tonic-gate * symbol in the filtee, and if it is found return it. 16277c478bd9Sstevel@tonic-gate * If the symbol doesn't exist, and this is a standard 16287c478bd9Sstevel@tonic-gate * filter, return and error, otherwise return the symbol 16297c478bd9Sstevel@tonic-gate * within the filter itself. 16307c478bd9Sstevel@tonic-gate */ 163108278a5eSRod Evans if (elf_lookup_filtee(slp, &sr, binfo, OBJFLTRNDX(ilmp), 163208278a5eSRod Evans in_nfavl)) { 163308278a5eSRod Evans *srp = sr; 163408278a5eSRod Evans return (1); 163508278a5eSRod Evans } 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate if (flags1 & FL1_RT_OBJSFLTR) 163908278a5eSRod Evans return (0); 16407c478bd9Sstevel@tonic-gate } 164108278a5eSRod Evans return (1); 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * Create a new Rt_map structure for an ELF object and initialize 16467c478bd9Sstevel@tonic-gate * all values. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate Rt_map * 164956deab07SRod Evans elf_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize, 16502020b2b6SRod Evans void *odyn, Rt_map *clmp, int *in_nfavl) 16517c478bd9Sstevel@tonic-gate { 165256deab07SRod Evans const char *name = fdp->fd_nname; 16537c478bd9Sstevel@tonic-gate Rt_map *lmp; 16547c478bd9Sstevel@tonic-gate Ehdr *ehdr = (Ehdr *)addr; 165556deab07SRod Evans Phdr *phdr, *tphdr = NULL, *dphdr = NULL, *uphdr = NULL; 165656deab07SRod Evans Dyn *dyn = (Dyn *)odyn; 165756deab07SRod Evans Cap *cap = NULL; 165856deab07SRod Evans int ndx; 165956deab07SRod Evans Addr base, fltr = 0, audit = 0, cfile = 0, crle = 0; 166056deab07SRod Evans Xword rpath = 0; 166156deab07SRod Evans size_t lmsz, rtsz, epsz, dynsz = 0; 166256deab07SRod Evans uint_t dyncnt = 0; 16637c478bd9Sstevel@tonic-gate 166456deab07SRod Evans DBG_CALL(Dbg_file_elf(lml, name, addr, msize, lml->lm_lmidstr, lmco)); 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate /* 166756deab07SRod Evans * If this is a shared object, the base address of the shared object is 166856deab07SRod Evans * added to all address values defined within the object. Otherwise, if 166956deab07SRod Evans * this is an executable, all object addresses are used as is. 16707c478bd9Sstevel@tonic-gate */ 167156deab07SRod Evans if (ehdr->e_type == ET_EXEC) 167256deab07SRod Evans base = 0; 167356deab07SRod Evans else 167456deab07SRod Evans base = addr; 167556deab07SRod Evans 167656deab07SRod Evans /* 167756deab07SRod Evans * Traverse the program header table, picking off required items. This 167856deab07SRod Evans * traversal also provides for the sizing of the PT_DYNAMIC section. 167956deab07SRod Evans */ 168056deab07SRod Evans phdr = (Phdr *)((uintptr_t)ehdr + ehdr->e_phoff); 168156deab07SRod Evans for (ndx = 0; ndx < (int)ehdr->e_phnum; ndx++, 168256deab07SRod Evans phdr = (Phdr *)((uintptr_t)phdr + ehdr->e_phentsize)) { 168356deab07SRod Evans switch (phdr->p_type) { 168456deab07SRod Evans case PT_DYNAMIC: 168556deab07SRod Evans dphdr = phdr; 168656deab07SRod Evans dyn = (Dyn *)((uintptr_t)phdr->p_vaddr + base); 168756deab07SRod Evans break; 168856deab07SRod Evans case PT_TLS: 168956deab07SRod Evans tphdr = phdr; 169056deab07SRod Evans break; 169156deab07SRod Evans case PT_SUNWCAP: 169256deab07SRod Evans cap = (Cap *)((uintptr_t)phdr->p_vaddr + base); 169356deab07SRod Evans break; 169456deab07SRod Evans case PT_SUNW_UNWIND: 16957e16fca0SAli Bahrami case PT_SUNW_EH_FRAME: 169656deab07SRod Evans uphdr = phdr; 169756deab07SRod Evans break; 169856deab07SRod Evans default: 169956deab07SRod Evans break; 17007c478bd9Sstevel@tonic-gate } 170156deab07SRod Evans } 170256deab07SRod Evans 170356deab07SRod Evans /* 170456deab07SRod Evans * Determine the number of PT_DYNAMIC entries for the DYNINFO() 170556deab07SRod Evans * allocation. Sadly, this is a little larger than we really need, 170656deab07SRod Evans * as there are typically padding DT_NULL entries. However, adding 170756deab07SRod Evans * this data to the initial link-map allocation is a win. 170856deab07SRod Evans */ 170956deab07SRod Evans if (dyn) { 171056deab07SRod Evans dyncnt = dphdr->p_filesz / sizeof (Dyn); 171156deab07SRod Evans dynsz = dyncnt * sizeof (Dyninfo); 171256deab07SRod Evans } 171356deab07SRod Evans 171456deab07SRod Evans /* 171556deab07SRod Evans * Allocate space for the link-map, private elf information, and 171656deab07SRod Evans * DYNINFO() data. Once these are allocated and initialized, 171756deab07SRod Evans * remove_so(0, lmp) can be used to tear down the link-map allocation 171856deab07SRod Evans * should any failures occur. 171956deab07SRod Evans */ 172056deab07SRod Evans rtsz = S_DROUND(sizeof (Rt_map)); 172156deab07SRod Evans epsz = S_DROUND(sizeof (Rt_elfp)); 172256deab07SRod Evans lmsz = rtsz + epsz + dynsz; 172356deab07SRod Evans if ((lmp = calloc(lmsz, 1)) == NULL) 172456deab07SRod Evans return (NULL); 172556deab07SRod Evans ELFPRV(lmp) = (void *)((uintptr_t)lmp + rtsz); 172656deab07SRod Evans DYNINFO(lmp) = (Dyninfo *)((uintptr_t)lmp + rtsz + epsz); 172756deab07SRod Evans LMSIZE(lmp) = lmsz; 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate /* 17307c478bd9Sstevel@tonic-gate * All fields not filled in were set to 0 by calloc. 17317c478bd9Sstevel@tonic-gate */ 173256deab07SRod Evans NAME(lmp) = (char *)name; 17337c478bd9Sstevel@tonic-gate ADDR(lmp) = addr; 17347c478bd9Sstevel@tonic-gate MSIZE(lmp) = msize; 17357c478bd9Sstevel@tonic-gate SYMINTP(lmp) = elf_find_sym; 17367c478bd9Sstevel@tonic-gate FCT(lmp) = &elf_fct; 17377c478bd9Sstevel@tonic-gate LIST(lmp) = lml; 17387c478bd9Sstevel@tonic-gate OBJFLTRNDX(lmp) = FLTR_DISABLED; 1739dffec89cSrie SORTVAL(lmp) = -1; 174056deab07SRod Evans DYN(lmp) = dyn; 174156deab07SRod Evans DYNINFOCNT(lmp) = dyncnt; 174256deab07SRod Evans PTUNWIND(lmp) = uphdr; 17437c478bd9Sstevel@tonic-gate 174456deab07SRod Evans if (ehdr->e_type == ET_EXEC) 17457c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_FIXED; 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate /* 17487c478bd9Sstevel@tonic-gate * Fill in rest of the link map entries with information from the file's 17497c478bd9Sstevel@tonic-gate * dynamic structure. 17507c478bd9Sstevel@tonic-gate */ 175156deab07SRod Evans if (dyn) { 1752f441771bSRod Evans Dyninfo *dip; 1753f441771bSRod Evans uint_t dynndx; 17547c478bd9Sstevel@tonic-gate Xword pltpadsz = 0; 175510a4fa49Srie Rti_desc *rti; 1756f441771bSRod Evans Dyn *pdyn; 1757f441771bSRod Evans Word lmtflags = lml->lm_tflags; 1758f441771bSRod Evans int ignore = 0; 17597c478bd9Sstevel@tonic-gate 1760f441771bSRod Evans /* 1761f441771bSRod Evans * Note, we use DT_NULL to terminate processing, and the 1762f441771bSRod Evans * dynamic entry count as a fall back. Normally, a DT_NULL 1763f441771bSRod Evans * entry marks the end of the dynamic section. Any non-NULL 1764f441771bSRod Evans * items following the first DT_NULL are silently ignored. 1765f441771bSRod Evans * This situation should only occur through use of elfedit(1) 1766f441771bSRod Evans * or a similar tool. 1767f441771bSRod Evans */ 1768f441771bSRod Evans for (dynndx = 0, pdyn = NULL, dip = DYNINFO(lmp); 1769f441771bSRod Evans dynndx < dyncnt; dynndx++, pdyn = dyn++, dip++) { 1770f441771bSRod Evans 1771f441771bSRod Evans if (ignore) { 1772f441771bSRod Evans dip->di_flags |= FLG_DI_IGNORE; 1773f441771bSRod Evans continue; 1774f441771bSRod Evans } 1775f441771bSRod Evans 177656deab07SRod Evans switch ((Xword)dyn->d_tag) { 1777f441771bSRod Evans case DT_NULL: 1778f441771bSRod Evans dip->di_flags |= ignore = FLG_DI_IGNORE; 1779f441771bSRod Evans break; 1780f441771bSRod Evans case DT_POSFLAG_1: 1781f441771bSRod Evans dip->di_flags |= FLG_DI_POSFLAG1; 1782f441771bSRod Evans break; 1783f441771bSRod Evans case DT_NEEDED: 1784f441771bSRod Evans case DT_USED: 1785f441771bSRod Evans dip->di_flags |= FLG_DI_NEEDED; 1786f441771bSRod Evans 1787f441771bSRod Evans /* BEGIN CSTYLED */ 1788f441771bSRod Evans if (pdyn && (pdyn->d_tag == DT_POSFLAG_1)) { 1789f441771bSRod Evans /* 1790f441771bSRod Evans * Identify any non-deferred lazy load for 1791f441771bSRod Evans * future processing, unless LD_NOLAZYLOAD 1792f441771bSRod Evans * has been set. 1793f441771bSRod Evans */ 1794f441771bSRod Evans if ((pdyn->d_un.d_val & DF_P1_LAZYLOAD) && 1795f441771bSRod Evans ((lmtflags & LML_TFLG_NOLAZYLD) == 0)) 1796f441771bSRod Evans dip->di_flags |= FLG_DI_LAZY; 1797f441771bSRod Evans 1798f441771bSRod Evans /* 1799f441771bSRod Evans * Identify any group permission 1800f441771bSRod Evans * requirements. 1801f441771bSRod Evans */ 1802f441771bSRod Evans if (pdyn->d_un.d_val & DF_P1_GROUPPERM) 1803f441771bSRod Evans dip->di_flags |= FLG_DI_GROUP; 1804f441771bSRod Evans 1805f441771bSRod Evans /* 1806f441771bSRod Evans * Identify any deferred dependencies. 1807f441771bSRod Evans */ 1808f441771bSRod Evans if (pdyn->d_un.d_val & DF_P1_DEFERRED) 1809f441771bSRod Evans dip->di_flags |= FLG_DI_DEFERRED; 1810f441771bSRod Evans } 1811f441771bSRod Evans /* END CSTYLED */ 1812f441771bSRod Evans break; 18137c478bd9Sstevel@tonic-gate case DT_SYMTAB: 181456deab07SRod Evans SYMTAB(lmp) = (void *)(dyn->d_un.d_ptr + base); 18157c478bd9Sstevel@tonic-gate break; 18169039eeafSab196087 case DT_SUNW_SYMTAB: 18179039eeafSab196087 SUNWSYMTAB(lmp) = 181856deab07SRod Evans (void *)(dyn->d_un.d_ptr + base); 18199039eeafSab196087 break; 18209039eeafSab196087 case DT_SUNW_SYMSZ: 182156deab07SRod Evans SUNWSYMSZ(lmp) = dyn->d_un.d_val; 18229039eeafSab196087 break; 18237c478bd9Sstevel@tonic-gate case DT_STRTAB: 182456deab07SRod Evans STRTAB(lmp) = (void *)(dyn->d_un.d_ptr + base); 18257c478bd9Sstevel@tonic-gate break; 18267c478bd9Sstevel@tonic-gate case DT_SYMENT: 182756deab07SRod Evans SYMENT(lmp) = dyn->d_un.d_val; 18287c478bd9Sstevel@tonic-gate break; 18297c478bd9Sstevel@tonic-gate case DT_FEATURE_1: 183056deab07SRod Evans if (dyn->d_un.d_val & DTF_1_CONFEXP) 18317c478bd9Sstevel@tonic-gate crle = 1; 18327c478bd9Sstevel@tonic-gate break; 18337c478bd9Sstevel@tonic-gate case DT_MOVESZ: 183456deab07SRod Evans MOVESZ(lmp) = dyn->d_un.d_val; 18357c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_MOVE; 18367c478bd9Sstevel@tonic-gate break; 18377c478bd9Sstevel@tonic-gate case DT_MOVEENT: 183856deab07SRod Evans MOVEENT(lmp) = dyn->d_un.d_val; 18397c478bd9Sstevel@tonic-gate break; 18407c478bd9Sstevel@tonic-gate case DT_MOVETAB: 184156deab07SRod Evans MOVETAB(lmp) = (void *)(dyn->d_un.d_ptr + base); 18427c478bd9Sstevel@tonic-gate break; 18437c478bd9Sstevel@tonic-gate case DT_REL: 18447c478bd9Sstevel@tonic-gate case DT_RELA: 18457c478bd9Sstevel@tonic-gate /* 184675e7992aSrie * At this time, ld.so. can only handle one 184775e7992aSrie * type of relocation per object. 18487c478bd9Sstevel@tonic-gate */ 184956deab07SRod Evans REL(lmp) = (void *)(dyn->d_un.d_ptr + base); 18507c478bd9Sstevel@tonic-gate break; 18517c478bd9Sstevel@tonic-gate case DT_RELSZ: 18527c478bd9Sstevel@tonic-gate case DT_RELASZ: 185356deab07SRod Evans RELSZ(lmp) = dyn->d_un.d_val; 18547c478bd9Sstevel@tonic-gate break; 18557c478bd9Sstevel@tonic-gate case DT_RELENT: 18567c478bd9Sstevel@tonic-gate case DT_RELAENT: 185756deab07SRod Evans RELENT(lmp) = dyn->d_un.d_val; 18587c478bd9Sstevel@tonic-gate break; 18597c478bd9Sstevel@tonic-gate case DT_RELCOUNT: 18607c478bd9Sstevel@tonic-gate case DT_RELACOUNT: 186156deab07SRod Evans RELACOUNT(lmp) = (uint_t)dyn->d_un.d_val; 18627c478bd9Sstevel@tonic-gate break; 18637c478bd9Sstevel@tonic-gate case DT_HASH: 186456deab07SRod Evans HASH(lmp) = (uint_t *)(dyn->d_un.d_ptr + base); 18657c478bd9Sstevel@tonic-gate break; 18667c478bd9Sstevel@tonic-gate case DT_PLTGOT: 186756deab07SRod Evans PLTGOT(lmp) = 186856deab07SRod Evans (uint_t *)(dyn->d_un.d_ptr + base); 18697c478bd9Sstevel@tonic-gate break; 18707c478bd9Sstevel@tonic-gate case DT_PLTRELSZ: 187156deab07SRod Evans PLTRELSZ(lmp) = dyn->d_un.d_val; 18727c478bd9Sstevel@tonic-gate break; 18737c478bd9Sstevel@tonic-gate case DT_JMPREL: 187456deab07SRod Evans JMPREL(lmp) = (void *)(dyn->d_un.d_ptr + base); 18757c478bd9Sstevel@tonic-gate break; 18767c478bd9Sstevel@tonic-gate case DT_INIT: 187756deab07SRod Evans if (dyn->d_un.d_ptr != NULL) 18785b59e4caSab196087 INIT(lmp) = 187956deab07SRod Evans (void (*)())(dyn->d_un.d_ptr + 188056deab07SRod Evans base); 18817c478bd9Sstevel@tonic-gate break; 18827c478bd9Sstevel@tonic-gate case DT_FINI: 188356deab07SRod Evans if (dyn->d_un.d_ptr != NULL) 18845b59e4caSab196087 FINI(lmp) = 188556deab07SRod Evans (void (*)())(dyn->d_un.d_ptr + 188656deab07SRod Evans base); 18877c478bd9Sstevel@tonic-gate break; 18887c478bd9Sstevel@tonic-gate case DT_INIT_ARRAY: 188956deab07SRod Evans INITARRAY(lmp) = (Addr *)(dyn->d_un.d_ptr + 18907c478bd9Sstevel@tonic-gate base); 18917c478bd9Sstevel@tonic-gate break; 18927c478bd9Sstevel@tonic-gate case DT_INIT_ARRAYSZ: 189356deab07SRod Evans INITARRAYSZ(lmp) = (uint_t)dyn->d_un.d_val; 18947c478bd9Sstevel@tonic-gate break; 18957c478bd9Sstevel@tonic-gate case DT_FINI_ARRAY: 189656deab07SRod Evans FINIARRAY(lmp) = (Addr *)(dyn->d_un.d_ptr + 18977c478bd9Sstevel@tonic-gate base); 18987c478bd9Sstevel@tonic-gate break; 18997c478bd9Sstevel@tonic-gate case DT_FINI_ARRAYSZ: 190056deab07SRod Evans FINIARRAYSZ(lmp) = (uint_t)dyn->d_un.d_val; 19017c478bd9Sstevel@tonic-gate break; 19027c478bd9Sstevel@tonic-gate case DT_PREINIT_ARRAY: 190356deab07SRod Evans PREINITARRAY(lmp) = (Addr *)(dyn->d_un.d_ptr + 19047c478bd9Sstevel@tonic-gate base); 19057c478bd9Sstevel@tonic-gate break; 19067c478bd9Sstevel@tonic-gate case DT_PREINIT_ARRAYSZ: 190756deab07SRod Evans PREINITARRAYSZ(lmp) = (uint_t)dyn->d_un.d_val; 19087c478bd9Sstevel@tonic-gate break; 19097c478bd9Sstevel@tonic-gate case DT_RPATH: 19107c478bd9Sstevel@tonic-gate case DT_RUNPATH: 191156deab07SRod Evans rpath = dyn->d_un.d_val; 19127c478bd9Sstevel@tonic-gate break; 19137c478bd9Sstevel@tonic-gate case DT_FILTER: 1914f441771bSRod Evans dip->di_flags |= FLG_DI_STDFLTR; 191556deab07SRod Evans fltr = dyn->d_un.d_val; 191675e7992aSrie OBJFLTRNDX(lmp) = dynndx; 19177c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_OBJSFLTR; 19187c478bd9Sstevel@tonic-gate break; 19197c478bd9Sstevel@tonic-gate case DT_AUXILIARY: 1920f441771bSRod Evans dip->di_flags |= FLG_DI_AUXFLTR; 19217c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUXFLTR)) { 192256deab07SRod Evans fltr = dyn->d_un.d_val; 192375e7992aSrie OBJFLTRNDX(lmp) = dynndx; 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_OBJAFLTR; 19267c478bd9Sstevel@tonic-gate break; 19277c478bd9Sstevel@tonic-gate case DT_SUNW_FILTER: 1928f441771bSRod Evans dip->di_flags |= 1929f441771bSRod Evans (FLG_DI_STDFLTR | FLG_DI_SYMFLTR); 19307c478bd9Sstevel@tonic-gate SYMSFLTRCNT(lmp)++; 19317c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMSFLTR; 19327c478bd9Sstevel@tonic-gate break; 19337c478bd9Sstevel@tonic-gate case DT_SUNW_AUXILIARY: 1934f441771bSRod Evans dip->di_flags |= 1935f441771bSRod Evans (FLG_DI_AUXFLTR | FLG_DI_SYMFLTR); 19367c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUXFLTR)) { 19377c478bd9Sstevel@tonic-gate SYMAFLTRCNT(lmp)++; 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMAFLTR; 19407c478bd9Sstevel@tonic-gate break; 19417c478bd9Sstevel@tonic-gate case DT_DEPAUDIT: 1942*b533f56bSRobert Mustacchi if (!(rtld_flags & RT_FL_NOAUDIT)) { 194356deab07SRod Evans audit = dyn->d_un.d_val; 1944*b533f56bSRobert Mustacchi FLAGS1(lmp) |= FL1_RT_DEPAUD; 1945*b533f56bSRobert Mustacchi } 19467c478bd9Sstevel@tonic-gate break; 19477c478bd9Sstevel@tonic-gate case DT_CONFIG: 194856deab07SRod Evans cfile = dyn->d_un.d_val; 19497c478bd9Sstevel@tonic-gate break; 19507c478bd9Sstevel@tonic-gate case DT_DEBUG: 19517c478bd9Sstevel@tonic-gate /* 19527c478bd9Sstevel@tonic-gate * DT_DEBUG entries are only created in 19537c478bd9Sstevel@tonic-gate * dynamic objects that require an interpretor 19547c478bd9Sstevel@tonic-gate * (ie. all dynamic executables and some shared 19557c478bd9Sstevel@tonic-gate * objects), and provide for a hand-shake with 1956dde769a2SRod Evans * old debuggers. This entry is initialized to 1957dde769a2SRod Evans * zero by the link-editor. If a debugger is 1958dde769a2SRod Evans * monitoring us, and has updated this entry, 1959dde769a2SRod Evans * set the debugger monitor flag, and finish 1960dde769a2SRod Evans * initializing the debugging structure. See 1961dde769a2SRod Evans * setup(). Also, switch off any configuration 1962dde769a2SRod Evans * object use as most debuggers can't handle 1963dde769a2SRod Evans * fixed dynamic executables as dependencies. 19647c478bd9Sstevel@tonic-gate */ 196556deab07SRod Evans if (dyn->d_un.d_ptr) 19667c478bd9Sstevel@tonic-gate rtld_flags |= 19677c478bd9Sstevel@tonic-gate (RT_FL_DEBUGGER | RT_FL_NOOBJALT); 196856deab07SRod Evans dyn->d_un.d_ptr = (Addr)&r_debug; 19697c478bd9Sstevel@tonic-gate break; 19707c478bd9Sstevel@tonic-gate case DT_VERNEED: 197156deab07SRod Evans VERNEED(lmp) = (Verneed *)(dyn->d_un.d_ptr + 19727c478bd9Sstevel@tonic-gate base); 19737c478bd9Sstevel@tonic-gate break; 19747c478bd9Sstevel@tonic-gate case DT_VERNEEDNUM: 19757c478bd9Sstevel@tonic-gate /* LINTED */ 197656deab07SRod Evans VERNEEDNUM(lmp) = (int)dyn->d_un.d_val; 19777c478bd9Sstevel@tonic-gate break; 19787c478bd9Sstevel@tonic-gate case DT_VERDEF: 197956deab07SRod Evans VERDEF(lmp) = (Verdef *)(dyn->d_un.d_ptr + 198056deab07SRod Evans base); 19817c478bd9Sstevel@tonic-gate break; 19827c478bd9Sstevel@tonic-gate case DT_VERDEFNUM: 19837c478bd9Sstevel@tonic-gate /* LINTED */ 198456deab07SRod Evans VERDEFNUM(lmp) = (int)dyn->d_un.d_val; 19857c478bd9Sstevel@tonic-gate break; 19863b41b08bSab196087 case DT_VERSYM: 1987d840867fSab196087 /* 1988d840867fSab196087 * The Solaris ld does not produce DT_VERSYM, 1989d840867fSab196087 * but the GNU ld does, in order to support 1990d840867fSab196087 * their style of versioning, which differs 1991d840867fSab196087 * from ours in some ways, while using the 1992d840867fSab196087 * same data structures. The presence of 1993d840867fSab196087 * DT_VERSYM therefore means that GNU 1994d840867fSab196087 * versioning rules apply to the given file. 1995d840867fSab196087 * If DT_VERSYM is not present, then Solaris 1996d840867fSab196087 * versioning rules apply. 1997d840867fSab196087 */ 199856deab07SRod Evans VERSYM(lmp) = (Versym *)(dyn->d_un.d_ptr + 199956deab07SRod Evans base); 20003b41b08bSab196087 break; 20017c478bd9Sstevel@tonic-gate case DT_BIND_NOW: 200256deab07SRod Evans if ((dyn->d_un.d_val & DF_BIND_NOW) && 200356deab07SRod Evans ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 20047c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 20057c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate break; 20087c478bd9Sstevel@tonic-gate case DT_FLAGS: 200956deab07SRod Evans FLAGS1(lmp) |= FL1_RT_DTFLAGS; 201056deab07SRod Evans if (dyn->d_un.d_val & DF_SYMBOLIC) 20117c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMBOLIC; 201256deab07SRod Evans if ((dyn->d_un.d_val & DF_BIND_NOW) && 2013dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 20147c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 20157c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 20167c478bd9Sstevel@tonic-gate } 2017d326b23bSrie /* 2018d326b23bSrie * Capture any static TLS use, and enforce that 2019d326b23bSrie * this object be non-deletable. 2020d326b23bSrie */ 202156deab07SRod Evans if (dyn->d_un.d_val & DF_STATIC_TLS) { 2022d326b23bSrie FLAGS1(lmp) |= FL1_RT_TLSSTAT; 2023d326b23bSrie MODE(lmp) |= RTLD_NODELETE; 2024d326b23bSrie } 20257c478bd9Sstevel@tonic-gate break; 20267c478bd9Sstevel@tonic-gate case DT_FLAGS_1: 202756deab07SRod Evans if (dyn->d_un.d_val & DF_1_DISPRELPND) 20287c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_DISPREL; 202956deab07SRod Evans if (dyn->d_un.d_val & DF_1_GROUP) 20307c478bd9Sstevel@tonic-gate FLAGS(lmp) |= 20312017c965SRod Evans (FLG_RT_SETGROUP | FLG_RT_PUBHDL); 203256deab07SRod Evans if ((dyn->d_un.d_val & DF_1_NOW) && 2033dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 20347c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 20357c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 20367c478bd9Sstevel@tonic-gate } 203756deab07SRod Evans if (dyn->d_un.d_val & DF_1_NODELETE) 20387c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NODELETE; 203956deab07SRod Evans if (dyn->d_un.d_val & DF_1_INITFIRST) 20407c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITFRST; 204156deab07SRod Evans if (dyn->d_un.d_val & DF_1_NOOPEN) 20427c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_NOOPEN; 204356deab07SRod Evans if (dyn->d_un.d_val & DF_1_LOADFLTR) 20447c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_LOADFLTR; 204556deab07SRod Evans if (dyn->d_un.d_val & DF_1_NODUMP) 20467c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_NODUMP; 204756deab07SRod Evans if (dyn->d_un.d_val & DF_1_CONFALT) 20487c478bd9Sstevel@tonic-gate crle = 1; 204956deab07SRod Evans if (dyn->d_un.d_val & DF_1_DIRECT) 20509a411307Srie FLAGS1(lmp) |= FL1_RT_DIRECT; 205156deab07SRod Evans if (dyn->d_un.d_val & DF_1_NODEFLIB) 20527c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_NODEFLIB; 205356deab07SRod Evans if (dyn->d_un.d_val & DF_1_ENDFILTEE) 20547c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_ENDFILTE; 205556deab07SRod Evans if (dyn->d_un.d_val & DF_1_TRANS) 20567c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_TRANS; 205756deab07SRod Evans 20587c478bd9Sstevel@tonic-gate /* 20597247f888Srie * Global auditing is only meaningful when 20607247f888Srie * specified by the initiating object of the 20617247f888Srie * process - typically the dynamic executable. 206208278a5eSRod Evans * If this is the initiating object, its link- 20637247f888Srie * map will not yet have been added to the 20647247f888Srie * link-map list, and consequently the link-map 20657247f888Srie * list is empty. (see setup()). 20667247f888Srie */ 206756deab07SRod Evans if (dyn->d_un.d_val & DF_1_GLOBAUDIT) { 2068481bba9eSRod Evans if (lml_main.lm_head == NULL) 20697247f888Srie FLAGS1(lmp) |= FL1_RT_GLOBAUD; 20707247f888Srie else 20717247f888Srie DBG_CALL(Dbg_audit_ignore(lmp)); 20727247f888Srie } 20737247f888Srie 20747247f888Srie /* 20757c478bd9Sstevel@tonic-gate * If this object identifies itself as an 20767c478bd9Sstevel@tonic-gate * interposer, but relocation processing has 20777c478bd9Sstevel@tonic-gate * already started, then demote it. It's too 20787c478bd9Sstevel@tonic-gate * late to guarantee complete interposition. 20797c478bd9Sstevel@tonic-gate */ 2080a953e2b1Srie /* BEGIN CSTYLED */ 208156deab07SRod Evans if (dyn->d_un.d_val & 20829a411307Srie (DF_1_INTERPOSE | DF_1_SYMINTPOSE)) { 20839a411307Srie if (lml->lm_flags & LML_FLG_STARTREL) { 20845aefb655Srie DBG_CALL(Dbg_util_intoolate(lmp)); 20857c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) 20867c478bd9Sstevel@tonic-gate (void) printf( 20877c478bd9Sstevel@tonic-gate MSG_INTL(MSG_LDD_REL_ERR2), 20887c478bd9Sstevel@tonic-gate NAME(lmp)); 208956deab07SRod Evans } else if (dyn->d_un.d_val & DF_1_INTERPOSE) 20909a411307Srie FLAGS(lmp) |= FLG_RT_OBJINTPO; 20919a411307Srie else 20929a411307Srie FLAGS(lmp) |= FLG_RT_SYMINTPO; 20937c478bd9Sstevel@tonic-gate } 2094a953e2b1Srie /* END CSTYLED */ 20957c478bd9Sstevel@tonic-gate break; 20967c478bd9Sstevel@tonic-gate case DT_SYMINFO: 209756deab07SRod Evans SYMINFO(lmp) = (Syminfo *)(dyn->d_un.d_ptr + 20987c478bd9Sstevel@tonic-gate base); 20997c478bd9Sstevel@tonic-gate break; 21007c478bd9Sstevel@tonic-gate case DT_SYMINENT: 210156deab07SRod Evans SYMINENT(lmp) = dyn->d_un.d_val; 21027c478bd9Sstevel@tonic-gate break; 21037c478bd9Sstevel@tonic-gate case DT_PLTPAD: 210456deab07SRod Evans PLTPAD(lmp) = (void *)(dyn->d_un.d_ptr + base); 21057c478bd9Sstevel@tonic-gate break; 21067c478bd9Sstevel@tonic-gate case DT_PLTPADSZ: 210756deab07SRod Evans pltpadsz = dyn->d_un.d_val; 21087c478bd9Sstevel@tonic-gate break; 21097c478bd9Sstevel@tonic-gate case DT_SUNW_RTLDINF: 21107c478bd9Sstevel@tonic-gate /* 211110a4fa49Srie * Maintain a list of RTLDINFO structures. 211210a4fa49Srie * Typically, libc is the only supplier, and 211310a4fa49Srie * only one structure is provided. However, 211410a4fa49Srie * multiple suppliers and multiple structures 211510a4fa49Srie * are supported. For example, one structure 211610a4fa49Srie * may provide thread_init, and another 211710a4fa49Srie * structure may provide atexit reservations. 21187c478bd9Sstevel@tonic-gate */ 2119dde769a2SRod Evans if ((rti = alist_append(&lml->lm_rti, NULL, 212056deab07SRod Evans sizeof (Rti_desc), 212156deab07SRod Evans AL_CNT_RTLDINFO)) == NULL) { 21222020b2b6SRod Evans remove_so(0, lmp, clmp); 212356deab07SRod Evans return (NULL); 21247c478bd9Sstevel@tonic-gate } 212510a4fa49Srie rti->rti_lmp = lmp; 212656deab07SRod Evans rti->rti_info = (void *)(dyn->d_un.d_ptr + 212756deab07SRod Evans base); 21287c478bd9Sstevel@tonic-gate break; 2129d579eb63Sab196087 case DT_SUNW_SORTENT: 213056deab07SRod Evans SUNWSORTENT(lmp) = dyn->d_un.d_val; 2131d579eb63Sab196087 break; 2132d579eb63Sab196087 case DT_SUNW_SYMSORT: 2133d579eb63Sab196087 SUNWSYMSORT(lmp) = 213456deab07SRod Evans (void *)(dyn->d_un.d_ptr + base); 2135d579eb63Sab196087 break; 2136d579eb63Sab196087 case DT_SUNW_SYMSORTSZ: 213756deab07SRod Evans SUNWSYMSORTSZ(lmp) = dyn->d_un.d_val; 2138d579eb63Sab196087 break; 21397c478bd9Sstevel@tonic-gate case DT_DEPRECATED_SPARC_REGISTER: 21407c478bd9Sstevel@tonic-gate case M_DT_REGISTER: 2141f441771bSRod Evans dip->di_flags |= FLG_DI_REGISTER; 21427c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_REGSYMS; 21437c478bd9Sstevel@tonic-gate break; 214408278a5eSRod Evans case DT_SUNW_CAP: 214508278a5eSRod Evans CAP(lmp) = (void *)(dyn->d_un.d_ptr + base); 214608278a5eSRod Evans break; 214708278a5eSRod Evans case DT_SUNW_CAPINFO: 214808278a5eSRod Evans CAPINFO(lmp) = (void *)(dyn->d_un.d_ptr + base); 214908278a5eSRod Evans break; 215008278a5eSRod Evans case DT_SUNW_CAPCHAIN: 215108278a5eSRod Evans CAPCHAIN(lmp) = (void *)(dyn->d_un.d_ptr + 215208278a5eSRod Evans base); 215308278a5eSRod Evans break; 215408278a5eSRod Evans case DT_SUNW_CAPCHAINENT: 215508278a5eSRod Evans CAPCHAINENT(lmp) = dyn->d_un.d_val; 215608278a5eSRod Evans break; 215708278a5eSRod Evans case DT_SUNW_CAPCHAINSZ: 215808278a5eSRod Evans CAPCHAINSZ(lmp) = dyn->d_un.d_val; 215908278a5eSRod Evans break; 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate } 21627c478bd9Sstevel@tonic-gate 2163f441771bSRod Evans /* 2164f441771bSRod Evans * Update any Dyninfo string pointers now that STRTAB() is 2165f441771bSRod Evans * known. 2166f441771bSRod Evans */ 2167f441771bSRod Evans for (dynndx = 0, dyn = DYN(lmp), dip = DYNINFO(lmp); 2168f441771bSRod Evans !(dip->di_flags & FLG_DI_IGNORE); dyn++, dip++) { 2169f441771bSRod Evans 2170f441771bSRod Evans switch ((Xword)dyn->d_tag) { 2171f441771bSRod Evans case DT_NEEDED: 2172f441771bSRod Evans case DT_USED: 2173f441771bSRod Evans case DT_FILTER: 2174f441771bSRod Evans case DT_AUXILIARY: 2175f441771bSRod Evans case DT_SUNW_FILTER: 2176f441771bSRod Evans case DT_SUNW_AUXILIARY: 2177f441771bSRod Evans dip->di_name = STRTAB(lmp) + dyn->d_un.d_val; 2178f441771bSRod Evans break; 2179f441771bSRod Evans } 2180f441771bSRod Evans } 2181f441771bSRod Evans 2182f441771bSRod Evans /* 2183f441771bSRod Evans * Assign any padding. 2184f441771bSRod Evans */ 21857c478bd9Sstevel@tonic-gate if (PLTPAD(lmp)) { 21867c478bd9Sstevel@tonic-gate if (pltpadsz == (Xword)0) 2187481bba9eSRod Evans PLTPAD(lmp) = NULL; 21887c478bd9Sstevel@tonic-gate else 21897c478bd9Sstevel@tonic-gate PLTPADEND(lmp) = (void *)((Addr)PLTPAD(lmp) + 21907c478bd9Sstevel@tonic-gate pltpadsz); 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate /* 21959039eeafSab196087 * A dynsym contains only global functions. We want to have 21969039eeafSab196087 * a version of it that also includes local functions, so that 21979039eeafSab196087 * dladdr() will be able to report names for local functions 21989039eeafSab196087 * when used to generate a stack trace for a stripped file. 21999039eeafSab196087 * This version of the dynsym is provided via DT_SUNW_SYMTAB. 22009039eeafSab196087 * 22019039eeafSab196087 * In producing DT_SUNW_SYMTAB, ld uses a non-obvious trick 22029039eeafSab196087 * in order to avoid having to have two copies of the global 22039039eeafSab196087 * symbols held in DT_SYMTAB: The local symbols are placed in 22049039eeafSab196087 * a separate section than the globals in the dynsym, but the 22059039eeafSab196087 * linker conspires to put the data for these two sections adjacent 22069039eeafSab196087 * to each other. DT_SUNW_SYMTAB points at the top of the local 22079039eeafSab196087 * symbols, and DT_SUNW_SYMSZ is the combined length of both tables. 22089039eeafSab196087 * 22099039eeafSab196087 * If the two sections are not adjacent, then something went wrong 22109039eeafSab196087 * at link time. We use ASSERT to kill the process if this is 22119039eeafSab196087 * a debug build. In a production build, we will silently ignore 22129039eeafSab196087 * the presence of the .ldynsym and proceed. We can detect this 22139039eeafSab196087 * situation by checking to see that DT_SYMTAB lies in 22149039eeafSab196087 * the range given by DT_SUNW_SYMTAB/DT_SUNW_SYMSZ. 22159039eeafSab196087 */ 22169039eeafSab196087 if ((SUNWSYMTAB(lmp) != NULL) && 22179039eeafSab196087 (((char *)SYMTAB(lmp) <= (char *)SUNWSYMTAB(lmp)) || 22189039eeafSab196087 (((char *)SYMTAB(lmp) >= 22199039eeafSab196087 (SUNWSYMSZ(lmp) + (char *)SUNWSYMTAB(lmp)))))) { 22209039eeafSab196087 ASSERT(0); 22219039eeafSab196087 SUNWSYMTAB(lmp) = NULL; 22229039eeafSab196087 SUNWSYMSZ(lmp) = 0; 22239039eeafSab196087 } 22249039eeafSab196087 22259039eeafSab196087 /* 22267c478bd9Sstevel@tonic-gate * If configuration file use hasn't been disabled, and a configuration 22277c478bd9Sstevel@tonic-gate * file hasn't already been set via an environment variable, see if any 22287c478bd9Sstevel@tonic-gate * application specific configuration file is specified. An LD_CONFIG 22297c478bd9Sstevel@tonic-gate * setting is used first, but if this image was generated via crle(1) 22307c478bd9Sstevel@tonic-gate * then a default configuration file is a fall-back. 22317c478bd9Sstevel@tonic-gate */ 2232481bba9eSRod Evans if ((!(rtld_flags & RT_FL_NOCFG)) && (config->c_name == NULL)) { 22337c478bd9Sstevel@tonic-gate if (cfile) 22347c478bd9Sstevel@tonic-gate config->c_name = (const char *)(cfile + 22357c478bd9Sstevel@tonic-gate (char *)STRTAB(lmp)); 223656deab07SRod Evans else if (crle) 22377c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_CONFAPP; 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate if (rpath) 22417c478bd9Sstevel@tonic-gate RPATH(lmp) = (char *)(rpath + (char *)STRTAB(lmp)); 224256deab07SRod Evans if (fltr) 224356deab07SRod Evans REFNAME(lmp) = (char *)(fltr + (char *)STRTAB(lmp)); 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate /* 22467c478bd9Sstevel@tonic-gate * For Intel ABI compatibility. It's possible that a JMPREL can be 22477c478bd9Sstevel@tonic-gate * specified without any other relocations (e.g. a dynamic executable 22487c478bd9Sstevel@tonic-gate * normally only contains .plt relocations). If this is the case then 22497c478bd9Sstevel@tonic-gate * no REL, RELSZ or RELENT will have been created. For us to be able 22507c478bd9Sstevel@tonic-gate * to traverse the .plt relocations under LD_BIND_NOW we need to know 22517c478bd9Sstevel@tonic-gate * the RELENT for these relocations. Refer to elf_reloc() for more 22527c478bd9Sstevel@tonic-gate * details. 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate if (!RELENT(lmp) && JMPREL(lmp)) 225556deab07SRod Evans RELENT(lmp) = sizeof (M_RELOC); 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate /* 2258f441771bSRod Evans * Establish any per-object auditing. If we're establishing main's 22597c478bd9Sstevel@tonic-gate * link-map its too early to go searching for audit objects so just 22607c478bd9Sstevel@tonic-gate * hold the object name for later (see setup()). 22617c478bd9Sstevel@tonic-gate */ 22627c478bd9Sstevel@tonic-gate if (audit) { 22637c478bd9Sstevel@tonic-gate char *cp = audit + (char *)STRTAB(lmp); 22647c478bd9Sstevel@tonic-gate 22657c478bd9Sstevel@tonic-gate if (*cp) { 22667c478bd9Sstevel@tonic-gate if (((AUDITORS(lmp) = 226756deab07SRod Evans calloc(1, sizeof (Audit_desc))) == NULL) || 226856deab07SRod Evans ((AUDITORS(lmp)->ad_name = strdup(cp)) == NULL)) { 22692020b2b6SRod Evans remove_so(0, lmp, clmp); 227056deab07SRod Evans return (NULL); 22717c478bd9Sstevel@tonic-gate } 227241072f3cSrie if (lml_main.lm_head) { 22739aa23310Srie if (audit_setup(lmp, AUDITORS(lmp), 0, 22749aa23310Srie in_nfavl) == 0) { 22752020b2b6SRod Evans remove_so(0, lmp, clmp); 227656deab07SRod Evans return (NULL); 22777c478bd9Sstevel@tonic-gate } 227856deab07SRod Evans AFLAGS(lmp) |= AUDITORS(lmp)->ad_flags; 22797c478bd9Sstevel@tonic-gate lml->lm_flags |= LML_FLG_LOCAUDIT; 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate 228456deab07SRod Evans if (tphdr && (tls_assign(lml, lmp, tphdr) == 0)) { 22852020b2b6SRod Evans remove_so(0, lmp, clmp); 228656deab07SRod Evans return (NULL); 22877c478bd9Sstevel@tonic-gate } 228856deab07SRod Evans 228908278a5eSRod Evans /* 229008278a5eSRod Evans * A capabilities section should be identified by a DT_SUNW_CAP entry, 229108278a5eSRod Evans * and if non-empty object capabilities are included, a PT_SUNWCAP 229208278a5eSRod Evans * header should reference the section. Make sure CAP() is set 229308278a5eSRod Evans * regardless. 229408278a5eSRod Evans */ 229508278a5eSRod Evans if ((CAP(lmp) == NULL) && cap) 229608278a5eSRod Evans CAP(lmp) = cap; 229708278a5eSRod Evans 229808278a5eSRod Evans /* 229908278a5eSRod Evans * Make sure any capabilities information or chain can be handled. 230008278a5eSRod Evans */ 230108278a5eSRod Evans if (CAPINFO(lmp) && (CAPINFO(lmp)[0] > CAPINFO_CURRENT)) 230208278a5eSRod Evans CAPINFO(lmp) = NULL; 230308278a5eSRod Evans if (CAPCHAIN(lmp) && (CAPCHAIN(lmp)[0] > CAPCHAIN_CURRENT)) 230408278a5eSRod Evans CAPCHAIN(lmp) = NULL; 230508278a5eSRod Evans 230608278a5eSRod Evans /* 230708278a5eSRod Evans * As part of processing dependencies, a file descriptor is populated 230808278a5eSRod Evans * with capabilities information following validation. 230908278a5eSRod Evans */ 231008278a5eSRod Evans if (fdp->fd_flags & FLG_FD_ALTCHECK) { 231108278a5eSRod Evans FLAGS1(lmp) |= FL1_RT_ALTCHECK; 231208278a5eSRod Evans CAPSET(lmp) = fdp->fd_scapset; 231308278a5eSRod Evans 231408278a5eSRod Evans if (fdp->fd_flags & FLG_FD_ALTCAP) 231508278a5eSRod Evans FLAGS1(lmp) |= FL1_RT_ALTCAP; 231608278a5eSRod Evans 231708278a5eSRod Evans } else if ((cap = CAP(lmp)) != NULL) { 231808278a5eSRod Evans /* 231908278a5eSRod Evans * Processing of the a.out and ld.so.1 does not involve a file 232008278a5eSRod Evans * descriptor as exec() did all the work, so capture the 232108278a5eSRod Evans * capabilities for these cases. 232208278a5eSRod Evans */ 232308278a5eSRod Evans while (cap->c_tag != CA_SUNW_NULL) { 232408278a5eSRod Evans switch (cap->c_tag) { 232508278a5eSRod Evans case CA_SUNW_HW_1: 232608278a5eSRod Evans CAPSET(lmp).sc_hw_1 = cap->c_un.c_val; 232708278a5eSRod Evans break; 232808278a5eSRod Evans case CA_SUNW_SF_1: 232908278a5eSRod Evans CAPSET(lmp).sc_sf_1 = cap->c_un.c_val; 233008278a5eSRod Evans break; 233108278a5eSRod Evans case CA_SUNW_HW_2: 233208278a5eSRod Evans CAPSET(lmp).sc_hw_2 = cap->c_un.c_val; 233308278a5eSRod Evans break; 233408278a5eSRod Evans case CA_SUNW_PLAT: 233508278a5eSRod Evans CAPSET(lmp).sc_plat = STRTAB(lmp) + 233608278a5eSRod Evans cap->c_un.c_ptr; 233708278a5eSRod Evans break; 233808278a5eSRod Evans case CA_SUNW_MACH: 233908278a5eSRod Evans CAPSET(lmp).sc_mach = STRTAB(lmp) + 234008278a5eSRod Evans cap->c_un.c_ptr; 234108278a5eSRod Evans break; 234208278a5eSRod Evans } 234308278a5eSRod Evans cap++; 234408278a5eSRod Evans } 234508278a5eSRod Evans } 234608278a5eSRod Evans 234708278a5eSRod Evans /* 234808278a5eSRod Evans * If a capabilities chain table exists, duplicate it. The chain table 234908278a5eSRod Evans * is inspected for each initial call to a capabilities family lead 235008278a5eSRod Evans * symbol. From this chain, each family member is inspected to 235108278a5eSRod Evans * determine the 'best' family member. The chain table is then updated 235208278a5eSRod Evans * so that the best member is immediately selected for any further 235308278a5eSRod Evans * family searches. 235408278a5eSRod Evans */ 235508278a5eSRod Evans if (CAPCHAIN(lmp)) { 235608278a5eSRod Evans Capchain *capchain; 235708278a5eSRod Evans 235808278a5eSRod Evans if ((capchain = calloc(CAPCHAINSZ(lmp), 1)) == NULL) 235908278a5eSRod Evans return (NULL); 236008278a5eSRod Evans (void) memcpy(capchain, CAPCHAIN(lmp), CAPCHAINSZ(lmp)); 236108278a5eSRod Evans CAPCHAIN(lmp) = capchain; 236208278a5eSRod Evans } 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate /* 23657c478bd9Sstevel@tonic-gate * Add the mapped object to the end of the link map list. 23667c478bd9Sstevel@tonic-gate */ 23677c478bd9Sstevel@tonic-gate lm_append(lml, lmco, lmp); 236856deab07SRod Evans 236956deab07SRod Evans /* 237056deab07SRod Evans * Start the system loading in the ELF information we'll be processing. 237156deab07SRod Evans */ 237256deab07SRod Evans if (REL(lmp)) { 237356deab07SRod Evans (void) madvise((void *)ADDR(lmp), (uintptr_t)REL(lmp) + 237456deab07SRod Evans (uintptr_t)RELSZ(lmp) - (uintptr_t)ADDR(lmp), 237556deab07SRod Evans MADV_WILLNEED); 237656deab07SRod Evans } 23777c478bd9Sstevel@tonic-gate return (lmp); 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate /* 23817c478bd9Sstevel@tonic-gate * Build full pathname of shared object from given directory name and filename. 23827c478bd9Sstevel@tonic-gate */ 23837c478bd9Sstevel@tonic-gate static char * 238456deab07SRod Evans elf_get_so(const char *dir, const char *file, size_t dlen, size_t flen) 23857c478bd9Sstevel@tonic-gate { 23867c478bd9Sstevel@tonic-gate static char pname[PATH_MAX]; 23877c478bd9Sstevel@tonic-gate 238856deab07SRod Evans (void) strncpy(pname, dir, dlen); 238956deab07SRod Evans pname[dlen++] = '/'; 239056deab07SRod Evans (void) strncpy(&pname[dlen], file, flen + 1); 23917c478bd9Sstevel@tonic-gate return (pname); 23927c478bd9Sstevel@tonic-gate } 23937c478bd9Sstevel@tonic-gate 23947c478bd9Sstevel@tonic-gate /* 23957c478bd9Sstevel@tonic-gate * The copy relocation is recorded in a copy structure which will be applied 23967c478bd9Sstevel@tonic-gate * after all other relocations are carried out. This provides for copying data 23977c478bd9Sstevel@tonic-gate * that must be relocated itself (ie. pointers in shared objects). This 23987c478bd9Sstevel@tonic-gate * structure also provides a means of binding RTLD_GROUP dependencies to any 23997c478bd9Sstevel@tonic-gate * copy relocations that have been taken from any group members. 24007c478bd9Sstevel@tonic-gate * 24017c478bd9Sstevel@tonic-gate * If the size of the .bss area available for the copy information is not the 24027c478bd9Sstevel@tonic-gate * same as the source of the data inform the user if we're under ldd(1) control 24037c478bd9Sstevel@tonic-gate * (this checking was only established in 5.3, so by only issuing an error via 24047c478bd9Sstevel@tonic-gate * ldd(1) we maintain the standard set by previous releases). 24057c478bd9Sstevel@tonic-gate */ 24067c478bd9Sstevel@tonic-gate int 24077c478bd9Sstevel@tonic-gate elf_copy_reloc(char *name, Sym *rsym, Rt_map *rlmp, void *radd, Sym *dsym, 24087c478bd9Sstevel@tonic-gate Rt_map *dlmp, const void *dadd) 24097c478bd9Sstevel@tonic-gate { 24107c478bd9Sstevel@tonic-gate Rel_copy rc; 24117c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(rlmp); 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate rc.r_name = name; 24147c478bd9Sstevel@tonic-gate rc.r_rsym = rsym; /* the new reference symbol and its */ 24157c478bd9Sstevel@tonic-gate rc.r_rlmp = rlmp; /* associated link-map */ 24167c478bd9Sstevel@tonic-gate rc.r_dlmp = dlmp; /* the defining link-map */ 24177c478bd9Sstevel@tonic-gate rc.r_dsym = dsym; /* the original definition */ 24187c478bd9Sstevel@tonic-gate rc.r_radd = radd; 24197c478bd9Sstevel@tonic-gate rc.r_dadd = dadd; 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate if (rsym->st_size > dsym->st_size) 24227c478bd9Sstevel@tonic-gate rc.r_size = (size_t)dsym->st_size; 24237c478bd9Sstevel@tonic-gate else 24247c478bd9Sstevel@tonic-gate rc.r_size = (size_t)rsym->st_size; 24257c478bd9Sstevel@tonic-gate 2426cce0e03bSab196087 if (alist_append(©_R(dlmp), &rc, sizeof (Rel_copy), 242756deab07SRod Evans AL_CNT_COPYREL) == NULL) { 24287c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_WARN)) 24297c478bd9Sstevel@tonic-gate return (0); 24307c478bd9Sstevel@tonic-gate else 24317c478bd9Sstevel@tonic-gate return (1); 24327c478bd9Sstevel@tonic-gate } 24337c478bd9Sstevel@tonic-gate if (!(FLAGS1(dlmp) & FL1_RT_COPYTOOK)) { 2434cce0e03bSab196087 if (aplist_append(©_S(rlmp), dlmp, 2435cce0e03bSab196087 AL_CNT_COPYREL) == NULL) { 24367c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_WARN)) 24377c478bd9Sstevel@tonic-gate return (0); 24387c478bd9Sstevel@tonic-gate else 24397c478bd9Sstevel@tonic-gate return (1); 24407c478bd9Sstevel@tonic-gate } 24417c478bd9Sstevel@tonic-gate FLAGS1(dlmp) |= FL1_RT_COPYTOOK; 24427c478bd9Sstevel@tonic-gate } 24437c478bd9Sstevel@tonic-gate 24447c478bd9Sstevel@tonic-gate /* 24457c478bd9Sstevel@tonic-gate * If we are tracing (ldd), warn the user if 24467c478bd9Sstevel@tonic-gate * 1) the size from the reference symbol differs from the 24477c478bd9Sstevel@tonic-gate * copy definition. We can only copy as much data as the 24487c478bd9Sstevel@tonic-gate * reference (dynamic executables) entry allows. 24497c478bd9Sstevel@tonic-gate * 2) the copy definition has STV_PROTECTED visibility. 24507c478bd9Sstevel@tonic-gate */ 24517c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_WARN) { 24527c478bd9Sstevel@tonic-gate if (rsym->st_size != dsym->st_size) { 24537c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_SIZDIF), 24545aefb655Srie _conv_reloc_type(M_R_COPY), demangle(name), 24557c478bd9Sstevel@tonic-gate NAME(rlmp), EC_XWORD(rsym->st_size), 24567c478bd9Sstevel@tonic-gate NAME(dlmp), EC_XWORD(dsym->st_size)); 24577c478bd9Sstevel@tonic-gate if (rsym->st_size > dsym->st_size) 24587c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_INSDATA), 24597c478bd9Sstevel@tonic-gate NAME(dlmp)); 24607c478bd9Sstevel@tonic-gate else 24617c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_DATRUNC), 24627c478bd9Sstevel@tonic-gate NAME(rlmp)); 24637c478bd9Sstevel@tonic-gate } 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate if (ELF_ST_VISIBILITY(dsym->st_other) == STV_PROTECTED) { 24667c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_PROT), 24675aefb655Srie _conv_reloc_type(M_R_COPY), demangle(name), 24687c478bd9Sstevel@tonic-gate NAME(dlmp)); 24697c478bd9Sstevel@tonic-gate } 24707c478bd9Sstevel@tonic-gate } 24717c478bd9Sstevel@tonic-gate 24725aefb655Srie DBG_CALL(Dbg_reloc_apply_val(lml, ELF_DBG_RTLD, (Xword)radd, 24735aefb655Srie (Xword)rc.r_size)); 24747c478bd9Sstevel@tonic-gate return (1); 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate /* 24787c478bd9Sstevel@tonic-gate * Determine the symbol location of an address within a link-map. Look for 24797c478bd9Sstevel@tonic-gate * the nearest symbol (whose value is less than or equal to the required 24807c478bd9Sstevel@tonic-gate * address). This is the object specific part of dladdr(). 24817c478bd9Sstevel@tonic-gate */ 24827c478bd9Sstevel@tonic-gate static void 24837c478bd9Sstevel@tonic-gate elf_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, int flags) 24847c478bd9Sstevel@tonic-gate { 24857c478bd9Sstevel@tonic-gate ulong_t ndx, cnt, base, _value; 24866221fe92Sab196087 Sym *sym, *_sym = NULL; 24877c478bd9Sstevel@tonic-gate const char *str; 24885343e1b3Sab196087 int _flags; 2489d579eb63Sab196087 uint_t *dynaddr_ndx; 2490d579eb63Sab196087 uint_t dynaddr_n = 0; 2491d579eb63Sab196087 ulong_t value; 24927c478bd9Sstevel@tonic-gate 24937c478bd9Sstevel@tonic-gate /* 24949039eeafSab196087 * If SUNWSYMTAB() is non-NULL, then it sees a special version of 24959039eeafSab196087 * the dynsym that starts with any local function symbols that exist in 24969039eeafSab196087 * the library and then moves to the data held in SYMTAB(). In this 24979039eeafSab196087 * case, SUNWSYMSZ tells us how long the symbol table is. The 24989039eeafSab196087 * availability of local function symbols will enhance the results 24999039eeafSab196087 * we can provide. 25009039eeafSab196087 * 2501d579eb63Sab196087 * If SUNWSYMTAB() is non-NULL, then there might also be a 2502d579eb63Sab196087 * SUNWSYMSORT() vector associated with it. SUNWSYMSORT() contains 2503d579eb63Sab196087 * an array of indices into SUNWSYMTAB, sorted by increasing 2504d579eb63Sab196087 * address. We can use this to do an O(log N) search instead of a 2505d579eb63Sab196087 * brute force search. 2506d579eb63Sab196087 * 25079039eeafSab196087 * If SUNWSYMTAB() is NULL, then SYMTAB() references a dynsym that 25089039eeafSab196087 * contains only global symbols. In that case, the length of 25099039eeafSab196087 * the symbol table comes from the nchain field of the related 25109039eeafSab196087 * symbol lookup hash table. 25119039eeafSab196087 */ 25129039eeafSab196087 str = STRTAB(lmp); 25139039eeafSab196087 if (SUNWSYMSZ(lmp) == NULL) { 25149039eeafSab196087 sym = SYMTAB(lmp); 25159039eeafSab196087 /* 25169039eeafSab196087 * If we don't have a .hash table there are no symbols 25179039eeafSab196087 * to look at. 25187c478bd9Sstevel@tonic-gate */ 2519481bba9eSRod Evans if (HASH(lmp) == NULL) 25207c478bd9Sstevel@tonic-gate return; 25217c478bd9Sstevel@tonic-gate cnt = HASH(lmp)[1]; 25229039eeafSab196087 } else { 25239039eeafSab196087 sym = SUNWSYMTAB(lmp); 25249039eeafSab196087 cnt = SUNWSYMSZ(lmp) / SYMENT(lmp); 2525d579eb63Sab196087 dynaddr_ndx = SUNWSYMSORT(lmp); 2526d579eb63Sab196087 if (dynaddr_ndx != NULL) 2527d579eb63Sab196087 dynaddr_n = SUNWSYMSORTSZ(lmp) / SUNWSORTENT(lmp); 25289039eeafSab196087 } 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 25317c478bd9Sstevel@tonic-gate base = 0; 25327c478bd9Sstevel@tonic-gate else 25337c478bd9Sstevel@tonic-gate base = ADDR(lmp); 25347c478bd9Sstevel@tonic-gate 2535d579eb63Sab196087 if (dynaddr_n > 0) { /* Binary search */ 2536d579eb63Sab196087 long low = 0, low_bnd; 2537d579eb63Sab196087 long high = dynaddr_n - 1, high_bnd; 2538d579eb63Sab196087 long mid; 2539d579eb63Sab196087 Sym *mid_sym; 25407c478bd9Sstevel@tonic-gate 25419039eeafSab196087 /* 2542d579eb63Sab196087 * Note that SUNWSYMSORT only contains symbols types that 2543d579eb63Sab196087 * supply memory addresses, so there's no need to check and 2544d579eb63Sab196087 * filter out any other types. 2545d579eb63Sab196087 */ 2546d579eb63Sab196087 low_bnd = low; 2547d579eb63Sab196087 high_bnd = high; 2548d579eb63Sab196087 while (low <= high) { 2549d579eb63Sab196087 mid = (low + high) / 2; 2550d579eb63Sab196087 mid_sym = &sym[dynaddr_ndx[mid]]; 2551d579eb63Sab196087 value = mid_sym->st_value + base; 2552d579eb63Sab196087 if (addr < value) { 2553d579eb63Sab196087 if ((sym[dynaddr_ndx[high]].st_value + base) >= 2554d579eb63Sab196087 addr) 2555d579eb63Sab196087 high_bnd = high; 2556d579eb63Sab196087 high = mid - 1; 2557d579eb63Sab196087 } else if (addr > value) { 2558d579eb63Sab196087 if ((sym[dynaddr_ndx[low]].st_value + base) <= 2559d579eb63Sab196087 addr) 2560d579eb63Sab196087 low_bnd = low; 2561d579eb63Sab196087 low = mid + 1; 2562d579eb63Sab196087 } else { 2563d579eb63Sab196087 _sym = mid_sym; 2564d579eb63Sab196087 _value = value; 2565d579eb63Sab196087 break; 2566d579eb63Sab196087 } 2567d579eb63Sab196087 } 2568d579eb63Sab196087 /* 2569d579eb63Sab196087 * If the above didn't find it exactly, then we must 2570d579eb63Sab196087 * return the closest symbol with a value that doesn't 2571d579eb63Sab196087 * exceed the one we are looking for. If that symbol exists, 2572d579eb63Sab196087 * it will lie in the range bounded by low_bnd and 2573d579eb63Sab196087 * high_bnd. This is a linear search, but a short one. 2574d579eb63Sab196087 */ 2575d579eb63Sab196087 if (_sym == NULL) { 2576d579eb63Sab196087 for (mid = low_bnd; mid <= high_bnd; mid++) { 2577d579eb63Sab196087 mid_sym = &sym[dynaddr_ndx[mid]]; 2578d579eb63Sab196087 value = mid_sym->st_value + base; 2579d579eb63Sab196087 if (addr >= value) { 2580d579eb63Sab196087 _sym = mid_sym; 2581d579eb63Sab196087 _value = value; 2582d579eb63Sab196087 } else { 2583d579eb63Sab196087 break; 2584d579eb63Sab196087 } 2585d579eb63Sab196087 } 2586d579eb63Sab196087 } 2587d579eb63Sab196087 } else { /* Linear search */ 2588d579eb63Sab196087 for (_value = 0, sym++, ndx = 1; ndx < cnt; ndx++, sym++) { 2589d579eb63Sab196087 /* 25909039eeafSab196087 * Skip expected symbol types that are not functions 25919039eeafSab196087 * or data: 25929039eeafSab196087 * - A symbol table starts with an undefined symbol 25939039eeafSab196087 * in slot 0. If we are using SUNWSYMTAB(), 25949039eeafSab196087 * there will be a second undefined symbol 25959039eeafSab196087 * right before the globals. 25969039eeafSab196087 * - The local part of SUNWSYMTAB() contains a 25979039eeafSab196087 * series of function symbols. Each section 25989039eeafSab196087 * starts with an initial STT_FILE symbol. 25999039eeafSab196087 */ 26009039eeafSab196087 if ((sym->st_shndx == SHN_UNDEF) || 26019039eeafSab196087 (ELF_ST_TYPE(sym->st_info) == STT_FILE)) 26027c478bd9Sstevel@tonic-gate continue; 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate value = sym->st_value + base; 26057c478bd9Sstevel@tonic-gate if (value > addr) 26067c478bd9Sstevel@tonic-gate continue; 26077c478bd9Sstevel@tonic-gate if (value < _value) 26087c478bd9Sstevel@tonic-gate continue; 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate _sym = sym; 26117c478bd9Sstevel@tonic-gate _value = value; 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate /* 2614d579eb63Sab196087 * Note, because we accept local and global symbols 2615d579eb63Sab196087 * we could find a section symbol that matches the 2616d579eb63Sab196087 * associated address, which means that the symbol 2617d579eb63Sab196087 * name will be null. In this case continue the 2618d579eb63Sab196087 * search in case we can find a global symbol of 2619d579eb63Sab196087 * the same value. 26207c478bd9Sstevel@tonic-gate */ 26217c478bd9Sstevel@tonic-gate if ((value == addr) && 26227c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(sym->st_info) != STT_SECTION)) 26237c478bd9Sstevel@tonic-gate break; 26247c478bd9Sstevel@tonic-gate } 2625d579eb63Sab196087 } 26267c478bd9Sstevel@tonic-gate 26275343e1b3Sab196087 _flags = flags & RTLD_DL_MASK; 26287c478bd9Sstevel@tonic-gate if (_sym) { 26297c478bd9Sstevel@tonic-gate if (_flags == RTLD_DL_SYMENT) 26307c478bd9Sstevel@tonic-gate *info = (void *)_sym; 26317c478bd9Sstevel@tonic-gate else if (_flags == RTLD_DL_LINKMAP) 26327c478bd9Sstevel@tonic-gate *info = (void *)lmp; 26337c478bd9Sstevel@tonic-gate 26347c478bd9Sstevel@tonic-gate dlip->dli_sname = str + _sym->st_name; 26357c478bd9Sstevel@tonic-gate dlip->dli_saddr = (void *)_value; 26365343e1b3Sab196087 } else { 26375343e1b3Sab196087 /* 26385343e1b3Sab196087 * addr lies between the beginning of the mapped segment and 26395343e1b3Sab196087 * the first global symbol. We have no symbol to return 26405343e1b3Sab196087 * and the caller requires one. We use _START_, the base 26415343e1b3Sab196087 * address of the mapping. 26425343e1b3Sab196087 */ 26435343e1b3Sab196087 26445343e1b3Sab196087 if (_flags == RTLD_DL_SYMENT) { 26455343e1b3Sab196087 /* 26465343e1b3Sab196087 * An actual symbol struct is needed, so we 26475343e1b3Sab196087 * construct one for _START_. To do this in a 26485343e1b3Sab196087 * fully accurate way requires a different symbol 26495343e1b3Sab196087 * for each mapped segment. This requires the 26505343e1b3Sab196087 * use of dynamic memory and a mutex. That's too much 26515343e1b3Sab196087 * plumbing for a fringe case of limited importance. 26525343e1b3Sab196087 * 26535343e1b3Sab196087 * Fortunately, we can simplify: 26545343e1b3Sab196087 * - Only the st_size and st_info fields are useful 26555343e1b3Sab196087 * outside of the linker internals. The others 26565343e1b3Sab196087 * reference things that outside code cannot see, 26575343e1b3Sab196087 * and can be set to 0. 26585343e1b3Sab196087 * - It's just a label and there is no size 26595343e1b3Sab196087 * to report. So, the size should be 0. 26605343e1b3Sab196087 * This means that only st_info needs a non-zero 26615343e1b3Sab196087 * (constant) value. A static struct will suffice. 26625343e1b3Sab196087 * It must be const (readonly) so the caller can't 26635343e1b3Sab196087 * change its meaning for subsequent callers. 26645343e1b3Sab196087 */ 26655343e1b3Sab196087 static const Sym fsym = { 0, 0, 0, 26665343e1b3Sab196087 ELF_ST_INFO(STB_LOCAL, STT_OBJECT) }; 26675343e1b3Sab196087 *info = (void *) &fsym; 26685343e1b3Sab196087 } 26695343e1b3Sab196087 26705343e1b3Sab196087 dlip->dli_sname = MSG_ORIG(MSG_SYM_START); 26715343e1b3Sab196087 dlip->dli_saddr = (void *) ADDR(lmp); 26727c478bd9Sstevel@tonic-gate } 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate /* 267675e7992aSrie * This routine is called as a last fall-back to search for a symbol from a 26772017c965SRod Evans * standard relocation or dlsym(). To maintain lazy loadings goal of reducing 26782017c965SRod Evans * the number of objects mapped, any symbol search is first carried out using 26792017c965SRod Evans * the objects that already exist in the process (either on a link-map list or 26802017c965SRod Evans * handle). If a symbol can't be found, and lazy dependencies are still 26812017c965SRod Evans * pending, this routine loads the dependencies in an attempt to locate the 26822017c965SRod Evans * symbol. 26837c478bd9Sstevel@tonic-gate */ 268408278a5eSRod Evans int 268508278a5eSRod Evans elf_lazy_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl) 26867c478bd9Sstevel@tonic-gate { 26872017c965SRod Evans static APlist *alist = NULL; 26882017c965SRod Evans Aliste idx1; 26892017c965SRod Evans Rt_map *lmp1, *lmp = slp->sl_imap, *clmp = slp->sl_cmap; 26907c478bd9Sstevel@tonic-gate const char *name = slp->sl_name; 26912017c965SRod Evans Slookup sl1 = *slp; 26922017c965SRod Evans Lm_list *lml; 26932017c965SRod Evans Lm_cntl *lmc; 26942017c965SRod Evans 26952017c965SRod Evans /* 26962017c965SRod Evans * It's quite possible we've been here before to process objects, 26972017c965SRod Evans * therefore reinitialize our dynamic list. 26982017c965SRod Evans */ 26992017c965SRod Evans if (alist) 27002017c965SRod Evans aplist_reset(alist); 27012017c965SRod Evans 27022017c965SRod Evans /* 27032017c965SRod Evans * Discard any relocation index from further symbol searches. This 27042017c965SRod Evans * index has already been used to trigger any necessary lazy-loads, 27052017c965SRod Evans * and it might be because one of these lazy loads has failed that 27062017c965SRod Evans * we're performing this fallback. By removing the relocation index 27072017c965SRod Evans * we don't try and perform the same failed lazy loading activity again. 27082017c965SRod Evans */ 27092017c965SRod Evans sl1.sl_rsymndx = 0; 27102017c965SRod Evans 27112017c965SRod Evans /* 27122017c965SRod Evans * Determine the callers link-map list so that we can monitor whether 27132017c965SRod Evans * new objects have been added. 27142017c965SRod Evans */ 27152017c965SRod Evans lml = LIST(clmp); 27162017c965SRod Evans lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, CNTL(clmp)); 27177c478bd9Sstevel@tonic-gate 271875e7992aSrie /* 271975e7992aSrie * Generate a local list of new objects to process. This list can grow 272075e7992aSrie * as each object supplies its own lazy dependencies. 272175e7992aSrie */ 2722cce0e03bSab196087 if (aplist_append(&alist, lmp, AL_CNT_LAZYFIND) == NULL) 2723cce0e03bSab196087 return (NULL); 27247c478bd9Sstevel@tonic-gate 27252017c965SRod Evans for (APLIST_TRAVERSE(alist, idx1, lmp1)) { 2726f441771bSRod Evans uint_t dynndx; 272775e7992aSrie Dyninfo *dip, *pdip; 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate /* 273075e7992aSrie * Loop through the lazy DT_NEEDED entries examining each object 273175e7992aSrie * for the required symbol. If the symbol is not found, the 273275e7992aSrie * object is in turn added to the local alist, so that the 273375e7992aSrie * objects lazy DT_NEEDED entries can be examined. 27347c478bd9Sstevel@tonic-gate */ 2735cce0e03bSab196087 lmp = lmp1; 2736f441771bSRod Evans for (dynndx = 0, dip = DYNINFO(lmp), pdip = NULL; 2737f441771bSRod Evans !(dip->di_flags & FLG_DI_IGNORE); dynndx++, pdip = dip++) { 27382017c965SRod Evans Grp_hdl *ghp; 27392017c965SRod Evans Grp_desc *gdp; 27402017c965SRod Evans Rt_map *nlmp, *llmp; 27412017c965SRod Evans Slookup sl2; 274208278a5eSRod Evans Sresult sr; 27432017c965SRod Evans Aliste idx2; 27447c478bd9Sstevel@tonic-gate 274575e7992aSrie if (((dip->di_flags & FLG_DI_LAZY) == 0) || 27467c478bd9Sstevel@tonic-gate dip->di_info) 27477c478bd9Sstevel@tonic-gate continue; 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate /* 275075e7992aSrie * If this object has already failed to lazy load, and 275175e7992aSrie * we're still processing the same runtime linker 275275e7992aSrie * operation that produced the failure, don't bother 275375e7992aSrie * to try and load the object again. 275475e7992aSrie */ 275575e7992aSrie if ((dip->di_flags & FLG_DI_LAZYFAIL) && pdip && 275675e7992aSrie (pdip->di_flags & FLG_DI_POSFLAG1)) { 275775e7992aSrie if (pdip->di_info == (void *)ld_entry_cnt) 275875e7992aSrie continue; 275975e7992aSrie 276075e7992aSrie dip->di_flags &= ~FLG_DI_LAZYFAIL; 276175e7992aSrie pdip->di_info = NULL; 276275e7992aSrie } 276375e7992aSrie 276475e7992aSrie /* 27652017c965SRod Evans * Determine the last link-map presently on the callers 27662017c965SRod Evans * link-map control list. 27672017c965SRod Evans */ 27682017c965SRod Evans llmp = lmc->lc_tail; 27692017c965SRod Evans 27702017c965SRod Evans /* 277175e7992aSrie * Try loading this lazy dependency. If the object 277275e7992aSrie * can't be loaded, consider this non-fatal and continue 277375e7992aSrie * the search. Lazy loaded dependencies need not exist 277475e7992aSrie * and their loading should only turn out to be fatal 277575e7992aSrie * if they are required to satisfy a relocation. 27767c478bd9Sstevel@tonic-gate * 27772017c965SRod Evans * A successful lazy load can mean one of two things: 27782017c965SRod Evans * 27792017c965SRod Evans * - new objects have been loaded, in which case the 27802017c965SRod Evans * objects will have been analyzed, relocated, and 27812017c965SRod Evans * finally moved to the callers control list. 27822017c965SRod Evans * - the objects are already loaded, and this lazy 27832017c965SRod Evans * load has simply associated the referenced object 27842017c965SRod Evans * with it's lazy dependencies. 27852017c965SRod Evans * 27862017c965SRod Evans * If new objects are loaded, look in these objects 27872017c965SRod Evans * first. Note, a new object can be the object being 27882017c965SRod Evans * referenced by this lazy load, however we can also 27892017c965SRod Evans * descend into multiple lazy loads as we relocate this 27902017c965SRod Evans * reference. 27912017c965SRod Evans * 27922017c965SRod Evans * If the symbol hasn't been found, use the referenced 27932017c965SRod Evans * objects handle, as it might have dependencies on 2794e0e63816SRod Evans * objects that are already loaded. Note that existing 2795e0e63816SRod Evans * objects might have already been searched and skipped 2796e0e63816SRod Evans * as non-available to this caller. However, a lazy 2797e0e63816SRod Evans * load might have caused the promotion of modes, or 2798e0e63816SRod Evans * added this object to the family of the caller. In 2799e0e63816SRod Evans * either case, the handle associated with the object 2800e0e63816SRod Evans * is then used to carry out the symbol search. 28017c478bd9Sstevel@tonic-gate */ 2802f441771bSRod Evans if ((nlmp = elf_lazy_load(lmp, &sl1, dynndx, name, 28032017c965SRod Evans FLG_RT_PRIHDL, &ghp, in_nfavl)) == NULL) 28047c478bd9Sstevel@tonic-gate continue; 28057c478bd9Sstevel@tonic-gate 28062017c965SRod Evans if (NEXT_RT_MAP(llmp)) { 28072017c965SRod Evans /* 28082017c965SRod Evans * Look in any new objects. 28092017c965SRod Evans */ 28102017c965SRod Evans sl1.sl_imap = NEXT_RT_MAP(llmp); 28112017c965SRod Evans sl1.sl_flags &= ~LKUP_STDRELOC; 28122017c965SRod Evans 281308278a5eSRod Evans /* 281408278a5eSRod Evans * Initialize a local symbol result descriptor, 281508278a5eSRod Evans * using the original symbol name. 281608278a5eSRod Evans */ 281708278a5eSRod Evans SRESULT_INIT(sr, slp->sl_name); 281808278a5eSRod Evans 281908278a5eSRod Evans if (lookup_sym(&sl1, &sr, binfo, in_nfavl)) { 282008278a5eSRod Evans *srp = sr; 282108278a5eSRod Evans return (1); 282208278a5eSRod Evans } 28232017c965SRod Evans } 28242017c965SRod Evans 28257c478bd9Sstevel@tonic-gate /* 2826e0e63816SRod Evans * Use the objects handle to inspect the family of 2827e0e63816SRod Evans * objects associated with the handle. Note, there's 28282017c965SRod Evans * a possibility of overlap with the above search, 28292017c965SRod Evans * should a lazy load bring in new objects and 28302017c965SRod Evans * reference existing objects. 28317c478bd9Sstevel@tonic-gate */ 28322017c965SRod Evans sl2 = sl1; 28332017c965SRod Evans for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 2834e0e63816SRod Evans if ((gdp->gd_depend != NEXT_RT_MAP(llmp)) && 28352017c965SRod Evans (gdp->gd_flags & GPD_DLSYM)) { 28362017c965SRod Evans 28372017c965SRod Evans sl2.sl_imap = gdp->gd_depend; 28382017c965SRod Evans sl2.sl_flags |= LKUP_FIRST; 28392017c965SRod Evans 284008278a5eSRod Evans /* 284108278a5eSRod Evans * Initialize a local symbol result 284208278a5eSRod Evans * descriptor, using the original 284308278a5eSRod Evans * symbol name. 284408278a5eSRod Evans */ 284508278a5eSRod Evans SRESULT_INIT(sr, slp->sl_name); 284608278a5eSRod Evans 284708278a5eSRod Evans if (lookup_sym(&sl2, &sr, binfo, 284808278a5eSRod Evans in_nfavl)) { 284908278a5eSRod Evans *srp = sr; 285008278a5eSRod Evans return (1); 285108278a5eSRod Evans } 2852e0e63816SRod Evans } 2853e0e63816SRod Evans } 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate /* 28567c478bd9Sstevel@tonic-gate * Some dlsym() operations are already traversing a 28577c478bd9Sstevel@tonic-gate * link-map (dlopen(0)), and thus there's no need to 28582017c965SRod Evans * save them on the dynamic dependency list. 28597c478bd9Sstevel@tonic-gate */ 28602017c965SRod Evans if (slp->sl_flags & LKUP_NODESCENT) 28612017c965SRod Evans continue; 28622017c965SRod Evans 28632017c965SRod Evans if (aplist_test(&alist, nlmp, AL_CNT_LAZYFIND) == NULL) 286408278a5eSRod Evans return (0); 28657c478bd9Sstevel@tonic-gate } 28667c478bd9Sstevel@tonic-gate } 28677c478bd9Sstevel@tonic-gate 286808278a5eSRod Evans return (0); 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate /* 28727c478bd9Sstevel@tonic-gate * Warning message for bad r_offset. 28737c478bd9Sstevel@tonic-gate */ 28747c478bd9Sstevel@tonic-gate void 28757c478bd9Sstevel@tonic-gate elf_reloc_bad(Rt_map *lmp, void *rel, uchar_t rtype, ulong_t roffset, 28767c478bd9Sstevel@tonic-gate ulong_t rsymndx) 28777c478bd9Sstevel@tonic-gate { 287837ffaf83SRod Evans const char *name = NULL; 28795aefb655Srie Lm_list *lml = LIST(lmp); 28807c478bd9Sstevel@tonic-gate int trace; 28817c478bd9Sstevel@tonic-gate 28825aefb655Srie if ((lml->lm_flags & LML_FLG_TRC_ENABLE) && 28837c478bd9Sstevel@tonic-gate (((rtld_flags & RT_FL_SILENCERR) == 0) || 28845aefb655Srie (lml->lm_flags & LML_FLG_TRC_VERBOSE))) 28857c478bd9Sstevel@tonic-gate trace = 1; 28867c478bd9Sstevel@tonic-gate else 28877c478bd9Sstevel@tonic-gate trace = 0; 28887c478bd9Sstevel@tonic-gate 28895aefb655Srie if ((trace == 0) && (DBG_ENABLED == 0)) 28907c478bd9Sstevel@tonic-gate return; 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate if (rsymndx) { 28937c478bd9Sstevel@tonic-gate Sym *symref = (Sym *)((ulong_t)SYMTAB(lmp) + 28947c478bd9Sstevel@tonic-gate (rsymndx * SYMENT(lmp))); 28957c478bd9Sstevel@tonic-gate 28967c478bd9Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) != STB_LOCAL) 28977c478bd9Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + symref->st_name); 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 2900481bba9eSRod Evans if (name == NULL) 290156deab07SRod Evans name = MSG_INTL(MSG_STR_UNKNOWN); 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate if (trace) { 29047c478bd9Sstevel@tonic-gate const char *rstr; 29057c478bd9Sstevel@tonic-gate 29065aefb655Srie rstr = _conv_reloc_type((uint_t)rtype); 29077c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_REL_ERR1), rstr, name, 29087c478bd9Sstevel@tonic-gate EC_ADDR(roffset)); 29097c478bd9Sstevel@tonic-gate return; 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29125aefb655Srie Dbg_reloc_error(lml, ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, name); 29137c478bd9Sstevel@tonic-gate } 2914d326b23bSrie 2915d326b23bSrie /* 2916d326b23bSrie * Resolve a static TLS relocation. 2917d326b23bSrie */ 2918d326b23bSrie long 2919d326b23bSrie elf_static_tls(Rt_map *lmp, Sym *sym, void *rel, uchar_t rtype, char *name, 2920d326b23bSrie ulong_t roffset, long value) 2921d326b23bSrie { 2922d326b23bSrie Lm_list *lml = LIST(lmp); 2923d326b23bSrie 2924d326b23bSrie /* 2925d326b23bSrie * Relocations against a static TLS block have limited support once 2926d326b23bSrie * process initialization has completed. Any error condition should be 2927d326b23bSrie * discovered by testing for DF_STATIC_TLS as part of loading an object, 2928d326b23bSrie * however individual relocations are tested in case the dynamic flag 2929d326b23bSrie * had not been set when this object was built. 2930d326b23bSrie */ 2931481bba9eSRod Evans if (PTTLS(lmp) == NULL) { 2932d326b23bSrie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, 2933e23c41c9SAli Bahrami M_REL_SHT_TYPE, rel, NULL, 0, name)); 2934d326b23bSrie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS), 2935d326b23bSrie _conv_reloc_type((uint_t)rtype), NAME(lmp), 2936d326b23bSrie name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)); 2937d326b23bSrie return (0); 2938d326b23bSrie } 2939d326b23bSrie 2940d326b23bSrie /* 2941d326b23bSrie * If no static TLS has been set aside for this object, determine if 2942d326b23bSrie * any can be obtained. Enforce that any object using static TLS is 2943d326b23bSrie * non-deletable. 2944d326b23bSrie */ 2945d326b23bSrie if (TLSSTATOFF(lmp) == 0) { 2946d326b23bSrie FLAGS1(lmp) |= FL1_RT_TLSSTAT; 2947d326b23bSrie MODE(lmp) |= RTLD_NODELETE; 2948d326b23bSrie 2949d326b23bSrie if (tls_assign(lml, lmp, PTTLS(lmp)) == 0) { 2950d326b23bSrie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, 2951e23c41c9SAli Bahrami M_REL_SHT_TYPE, rel, NULL, 0, name)); 2952d326b23bSrie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS), 2953d326b23bSrie _conv_reloc_type((uint_t)rtype), NAME(lmp), 2954d326b23bSrie name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)); 2955d326b23bSrie return (0); 2956d326b23bSrie } 2957d326b23bSrie } 2958d326b23bSrie 2959d326b23bSrie /* 2960d326b23bSrie * Typically, a static TLS offset is maintained as a symbols value. 2961d326b23bSrie * For local symbols that are not apart of the dynamic symbol table, 2962d326b23bSrie * the TLS relocation points to a section symbol, and the static TLS 2963d326b23bSrie * offset was deposited in the associated GOT table. Make sure the GOT 2964d326b23bSrie * is cleared, so that the value isn't reused in do_reloc(). 2965d326b23bSrie */ 2966d326b23bSrie if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 2967d326b23bSrie if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION)) { 2968d326b23bSrie value = *(long *)roffset; 2969d326b23bSrie *(long *)roffset = 0; 2970d326b23bSrie } else { 2971d326b23bSrie value = sym->st_value; 2972d326b23bSrie } 2973d326b23bSrie } 2974d326b23bSrie return (-(TLSSTATOFF(lmp) - value)); 2975d326b23bSrie } 2976dae2dfb7Srie 2977dae2dfb7Srie /* 2978dae2dfb7Srie * If the symbol is not found and the reference was not to a weak symbol, report 2979dae2dfb7Srie * an error. Weak references may be unresolved. 2980dae2dfb7Srie */ 2981dae2dfb7Srie int 2982dae2dfb7Srie elf_reloc_error(Rt_map *lmp, const char *name, void *rel, uint_t binfo) 2983dae2dfb7Srie { 2984dae2dfb7Srie Lm_list *lml = LIST(lmp); 2985dae2dfb7Srie 2986dae2dfb7Srie /* 2987dae2dfb7Srie * Under crle(1), relocation failures are ignored. 2988dae2dfb7Srie */ 2989dae2dfb7Srie if (lml->lm_flags & LML_FLG_IGNRELERR) 2990dae2dfb7Srie return (1); 2991dae2dfb7Srie 2992dae2dfb7Srie /* 2993dae2dfb7Srie * Under ldd(1), unresolved references are reported. However, if the 2994dae2dfb7Srie * original reference is EXTERN or PARENT these references are ignored 2995dae2dfb7Srie * unless ldd's -p option is in effect. 2996dae2dfb7Srie */ 2997dae2dfb7Srie if (lml->lm_flags & LML_FLG_TRC_WARN) { 2998dae2dfb7Srie if (((binfo & DBG_BINFO_REF_MSK) == 0) || 2999dae2dfb7Srie ((lml->lm_flags & LML_FLG_TRC_NOPAREXT) != 0)) { 3000dae2dfb7Srie (void) printf(MSG_INTL(MSG_LDD_SYM_NFOUND), 3001dae2dfb7Srie demangle(name), NAME(lmp)); 3002dae2dfb7Srie } 3003dae2dfb7Srie return (1); 3004dae2dfb7Srie } 3005dae2dfb7Srie 3006dae2dfb7Srie /* 3007dae2dfb7Srie * Otherwise, the unresolved references is fatal. 3008dae2dfb7Srie */ 3009dae2dfb7Srie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, 3010e23c41c9SAli Bahrami NULL, 0, name)); 3011dae2dfb7Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 3012dae2dfb7Srie demangle(name)); 3013dae2dfb7Srie 3014dae2dfb7Srie return (0); 3015dae2dfb7Srie } 3016