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 /* 23cce0e03bSab * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 26*7257d1b4Sraf 27*7257d1b4Sraf /* 28*7257d1b4Sraf * Copyright (c) 1988 AT&T 29*7257d1b4Sraf * All Rights Reserved 30*7257d1b4Sraf */ 31*7257d1b4Sraf 327c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Object file dependent support for ELF objects. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <stdio.h> 397c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 407c478bd9Sstevel@tonic-gate #include <sys/mman.h> 417c478bd9Sstevel@tonic-gate #include <sys/debug.h> 427c478bd9Sstevel@tonic-gate #include <string.h> 437c478bd9Sstevel@tonic-gate #include <limits.h> 447c478bd9Sstevel@tonic-gate #include <dlfcn.h> 455aefb655Srie #include <debug.h> 465aefb655Srie #include <conv.h> 477c478bd9Sstevel@tonic-gate #include "_rtld.h" 487c478bd9Sstevel@tonic-gate #include "_audit.h" 497c478bd9Sstevel@tonic-gate #include "_elf.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 */ 557c478bd9Sstevel@tonic-gate static Pnode elf_dflt_dirs[] = { 567c478bd9Sstevel@tonic-gate #if defined(_ELF64) 577c478bd9Sstevel@tonic-gate #ifndef SGS_PRE_UNIFIED_PROCESS 587c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_LIB_64), 0, MSG_PTH_LIB_64_SIZE, 597c478bd9Sstevel@tonic-gate LA_SER_DEFAULT, 0, &elf_dflt_dirs[1] }, 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_USRLIB_64), 0, MSG_PTH_USRLIB_64_SIZE, 627c478bd9Sstevel@tonic-gate LA_SER_DEFAULT, 0, 0 } 637c478bd9Sstevel@tonic-gate #else 647c478bd9Sstevel@tonic-gate #ifndef SGS_PRE_UNIFIED_PROCESS 657c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_LIB), 0, MSG_PTH_LIB_SIZE, 667c478bd9Sstevel@tonic-gate LA_SER_DEFAULT, 0, &elf_dflt_dirs[1] }, 677c478bd9Sstevel@tonic-gate #endif 687c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_USRLIB), 0, MSG_PTH_USRLIB_SIZE, 697c478bd9Sstevel@tonic-gate LA_SER_DEFAULT, 0, 0 } 707c478bd9Sstevel@tonic-gate #endif 717c478bd9Sstevel@tonic-gate }; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate static Pnode elf_secure_dirs[] = { 747c478bd9Sstevel@tonic-gate #if defined(_ELF64) 757c478bd9Sstevel@tonic-gate #ifndef SGS_PRE_UNIFIED_PROCESS 767c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_LIBSE_64), 0, MSG_PTH_LIBSE_64_SIZE, 777c478bd9Sstevel@tonic-gate LA_SER_SECURE, 0, &elf_secure_dirs[1] }, 787c478bd9Sstevel@tonic-gate #endif 797c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_USRLIBSE_64), 0, 807c478bd9Sstevel@tonic-gate MSG_PTH_USRLIBSE_64_SIZE, 817c478bd9Sstevel@tonic-gate LA_SER_SECURE, 0, 0 } 827c478bd9Sstevel@tonic-gate #else 837c478bd9Sstevel@tonic-gate #ifndef SGS_PRE_UNIFIED_PROCESS 847c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_LIBSE), 0, MSG_PTH_LIBSE_SIZE, 857c478bd9Sstevel@tonic-gate LA_SER_SECURE, 0, &elf_secure_dirs[1] }, 867c478bd9Sstevel@tonic-gate #endif 877c478bd9Sstevel@tonic-gate { MSG_ORIG(MSG_PTH_USRLIBSE), 0, MSG_PTH_USRLIBSE_SIZE, 887c478bd9Sstevel@tonic-gate LA_SER_SECURE, 0, 0 } 897c478bd9Sstevel@tonic-gate #endif 907c478bd9Sstevel@tonic-gate }; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Defines for local functions. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate static Pnode *elf_fix_name(const char *, Rt_map *, uint_t); 967c478bd9Sstevel@tonic-gate static int elf_are_u(Rej_desc *); 977c478bd9Sstevel@tonic-gate static void elf_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int); 987c478bd9Sstevel@tonic-gate static ulong_t elf_entry_pt(void); 997c478bd9Sstevel@tonic-gate static char *elf_get_so(const char *, const char *); 1009aa23310Srie static Rt_map *elf_map_so(Lm_list *, Aliste, const char *, const char *, 1019aa23310Srie int, int *); 1029aa23310Srie static int elf_needed(Lm_list *, Aliste, Rt_map *, int *); 1037c478bd9Sstevel@tonic-gate static void elf_unmap_so(Rt_map *); 1047c478bd9Sstevel@tonic-gate static int elf_verify_vers(const char *, Rt_map *, Rt_map *); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * Functions and data accessed through indirect pointers. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate Fct elf_fct = { 1107c478bd9Sstevel@tonic-gate elf_are_u, 1117c478bd9Sstevel@tonic-gate elf_entry_pt, 1127c478bd9Sstevel@tonic-gate elf_map_so, 1137c478bd9Sstevel@tonic-gate elf_unmap_so, 1147c478bd9Sstevel@tonic-gate elf_needed, 1157c478bd9Sstevel@tonic-gate lookup_sym, 1167c478bd9Sstevel@tonic-gate elf_reloc, 1177c478bd9Sstevel@tonic-gate elf_dflt_dirs, 1187c478bd9Sstevel@tonic-gate elf_secure_dirs, 1197c478bd9Sstevel@tonic-gate elf_fix_name, 1207c478bd9Sstevel@tonic-gate elf_get_so, 1217c478bd9Sstevel@tonic-gate elf_dladdr, 1227c478bd9Sstevel@tonic-gate dlsym_handle, 1237c478bd9Sstevel@tonic-gate elf_verify_vers, 1247c478bd9Sstevel@tonic-gate elf_set_prot 1257c478bd9Sstevel@tonic-gate }; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * Redefine NEEDED name if necessary. 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate static Pnode * 1327c478bd9Sstevel@tonic-gate elf_fix_name(const char *name, Rt_map *clmp, uint_t orig) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * For ABI compliance, if we are asked for ld.so.1, then really give 1367c478bd9Sstevel@tonic-gate * them libsys.so.1 (the SONAME of libsys.so.1 is ld.so.1). 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate if (((*name == '/') && 139a953e2b1Srie /* BEGIN CSTYLED */ 1407c478bd9Sstevel@tonic-gate #if defined(_ELF64) 1417c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_PTH_RTLD_64)) == 0)) || 1427c478bd9Sstevel@tonic-gate #else 1437c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_PTH_RTLD)) == 0)) || 1447c478bd9Sstevel@tonic-gate #endif 1457c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_FIL_RTLD)) == 0)) { 146a953e2b1Srie /* END CSTYLED */ 1477c478bd9Sstevel@tonic-gate Pnode *pnp; 1487c478bd9Sstevel@tonic-gate 1495aefb655Srie DBG_CALL(Dbg_file_fixname(LIST(clmp), name, 1505aefb655Srie MSG_ORIG(MSG_PTH_LIBSYS))); 1517c478bd9Sstevel@tonic-gate if (((pnp = calloc(sizeof (Pnode), 1)) == 0) || 1527c478bd9Sstevel@tonic-gate ((pnp->p_name = strdup(MSG_ORIG(MSG_PTH_LIBSYS))) == 0)) { 1537c478bd9Sstevel@tonic-gate if (pnp) 1547c478bd9Sstevel@tonic-gate free(pnp); 1557c478bd9Sstevel@tonic-gate return (0); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate pnp->p_len = MSG_PTH_LIBSYS_SIZE; 1587c478bd9Sstevel@tonic-gate return (pnp); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate return (expand_paths(clmp, name, orig, 0)); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Determine if we have been given an ELF file and if so determine if the file 1667c478bd9Sstevel@tonic-gate * is compatible. Returns 1 if true, else 0 and sets the reject descriptor 1677c478bd9Sstevel@tonic-gate * with associated error information. 1687c478bd9Sstevel@tonic-gate */ 1697c478bd9Sstevel@tonic-gate static int 1707c478bd9Sstevel@tonic-gate elf_are_u(Rej_desc *rej) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate Ehdr *ehdr; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * Determine if we're an elf file. If not simply return, we don't set 1767c478bd9Sstevel@tonic-gate * any rejection information as this test allows use to scroll through 1777c478bd9Sstevel@tonic-gate * the objects we support (ELF, AOUT). 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate if (fmap->fm_fsize < sizeof (Ehdr) || 1807c478bd9Sstevel@tonic-gate fmap->fm_maddr[EI_MAG0] != ELFMAG0 || 1817c478bd9Sstevel@tonic-gate fmap->fm_maddr[EI_MAG1] != ELFMAG1 || 1827c478bd9Sstevel@tonic-gate fmap->fm_maddr[EI_MAG2] != ELFMAG2 || 1837c478bd9Sstevel@tonic-gate fmap->fm_maddr[EI_MAG3] != ELFMAG3) { 1847c478bd9Sstevel@tonic-gate return (0); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * Check class and encoding. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate /* LINTED */ 1917c478bd9Sstevel@tonic-gate ehdr = (Ehdr *)fmap->fm_maddr; 1927c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_CLASS] != M_CLASS) { 1937c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_CLASS; 1947c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_ident[EI_CLASS]; 1957c478bd9Sstevel@tonic-gate return (0); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_DATA] != M_DATA) { 1987c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_DATA; 1997c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_ident[EI_DATA]; 2007c478bd9Sstevel@tonic-gate return (0); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate if ((ehdr->e_type != ET_REL) && (ehdr->e_type != ET_EXEC) && 2037c478bd9Sstevel@tonic-gate (ehdr->e_type != ET_DYN)) { 2047c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_TYPE; 2057c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_type; 2067c478bd9Sstevel@tonic-gate return (0); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate /* 2107c478bd9Sstevel@tonic-gate * Verify machine specific flags, and hardware capability requirements. 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate if ((elf_mach_flags_check(rej, ehdr) == 0) || 2137c478bd9Sstevel@tonic-gate ((rtld_flags2 & RT_FL2_HWCAP) && (hwcap_check(rej, ehdr) == 0))) 2147c478bd9Sstevel@tonic-gate return (0); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * Verify ELF version. ??? is this too restrictive ??? 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate if (ehdr->e_version > EV_CURRENT) { 2207c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_VERSION; 2217c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_version; 2227c478bd9Sstevel@tonic-gate return (0); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate return (1); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * The runtime linker employs lazy loading to provide the libraries needed for 2297c478bd9Sstevel@tonic-gate * debugging, preloading .o's and dldump(). As these are seldom used, the 2307c478bd9Sstevel@tonic-gate * standard startup of ld.so.1 doesn't initialize all the information necessary 2317c478bd9Sstevel@tonic-gate * to perform plt relocation on ld.so.1's link-map. The first time lazy loading 2327c478bd9Sstevel@tonic-gate * is called we get here to perform these initializations: 2337c478bd9Sstevel@tonic-gate * 2347c478bd9Sstevel@tonic-gate * o elf_needed() is called to set up the DYNINFO() indexes for each lazy 2357c478bd9Sstevel@tonic-gate * dependency. Typically, for all other objects, this is called during 2367c478bd9Sstevel@tonic-gate * analyze_so(), but as ld.so.1 is set-contained we skip this processing. 2377c478bd9Sstevel@tonic-gate * 2387c478bd9Sstevel@tonic-gate * o For intel, ld.so.1's JMPSLOT relocations need relative updates. These 2397c478bd9Sstevel@tonic-gate * are by default skipped thus delaying all relative relocation processing 2407c478bd9Sstevel@tonic-gate * on every invocation of ld.so.1. 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate int 2437c478bd9Sstevel@tonic-gate elf_rtld_load() 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate Lm_list *lml = &lml_rtld; 2467c478bd9Sstevel@tonic-gate Rt_map *lmp = lml->lm_head; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_PLTREL) 2497c478bd9Sstevel@tonic-gate return (1); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * As we need to refer to the DYNINFO() information, insure that it has 2537c478bd9Sstevel@tonic-gate * been initialized. 2547c478bd9Sstevel@tonic-gate */ 2559aa23310Srie if (elf_needed(lml, ALIST_OFF_DATA, lmp, NULL) == 0) 2567c478bd9Sstevel@tonic-gate return (0); 2577c478bd9Sstevel@tonic-gate 25802ca3e02Srie #if defined(__i386) 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * This is a kludge to give ld.so.1 a performance benefit on i386. 2617c478bd9Sstevel@tonic-gate * It's based around two factors. 2627c478bd9Sstevel@tonic-gate * 2637c478bd9Sstevel@tonic-gate * o JMPSLOT relocations (PLT's) actually need a relative relocation 2647c478bd9Sstevel@tonic-gate * applied to the GOT entry so that they can find PLT0. 2657c478bd9Sstevel@tonic-gate * 2667c478bd9Sstevel@tonic-gate * o ld.so.1 does not exercise *any* PLT's before it has made a call 2677c478bd9Sstevel@tonic-gate * to elf_lazy_load(). This is because all dynamic dependencies 2687c478bd9Sstevel@tonic-gate * are recorded as lazy dependencies. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate (void) elf_reloc_relacount((ulong_t)JMPREL(lmp), 2717c478bd9Sstevel@tonic-gate (ulong_t)(PLTRELSZ(lmp) / RELENT(lmp)), (ulong_t)RELENT(lmp), 2727c478bd9Sstevel@tonic-gate (ulong_t)ADDR(lmp)); 2737c478bd9Sstevel@tonic-gate #endif 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate lml->lm_flags |= LML_FLG_PLTREL; 2767c478bd9Sstevel@tonic-gate return (1); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Lazy load an object. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate Rt_map * 2839aa23310Srie elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym, 2849aa23310Srie int *in_nfavl) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate Rt_map *nlmp, *hlmp; 28775e7992aSrie Dyninfo *dip = &DYNINFO(clmp)[ndx], *pdip; 2887c478bd9Sstevel@tonic-gate uint_t flags = 0; 2897c478bd9Sstevel@tonic-gate Pnode *pnp; 2907c478bd9Sstevel@tonic-gate const char *name; 2917c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(clmp); 2927c478bd9Sstevel@tonic-gate Lm_cntl *lmc; 2937c478bd9Sstevel@tonic-gate Aliste lmco; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * If this dependency has already been processed, we're done. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate if (((nlmp = (Rt_map *)dip->di_info) != 0) || 29975e7992aSrie (dip->di_flags & FLG_DI_LDD_DONE)) 3007c478bd9Sstevel@tonic-gate return (nlmp); 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 30375e7992aSrie * If we're running under ldd(1), indicate that this dependency has been 30475e7992aSrie * processed (see test above). It doesn't matter whether the object is 30575e7992aSrie * successfully loaded or not, this flag simply ensures that we don't 30675e7992aSrie * repeatedly attempt to load an object that has already failed to load. 30775e7992aSrie * To do so would create multiple failure diagnostics for the same 30875e7992aSrie * object under ldd(1). 30975e7992aSrie */ 31075e7992aSrie if (lml->lm_flags & LML_FLG_TRC_ENABLE) 31175e7992aSrie dip->di_flags |= FLG_DI_LDD_DONE; 31275e7992aSrie 31375e7992aSrie /* 31475e7992aSrie * Determine the initial dependency name. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate name = STRTAB(clmp) + DYN(clmp)[ndx].d_un.d_val; 3175aefb655Srie DBG_CALL(Dbg_file_lazyload(clmp, name, sym)); 3187c478bd9Sstevel@tonic-gate 31975e7992aSrie /* 32075e7992aSrie * If this object needs to establish its own group, make sure a handle 32175e7992aSrie * is created. 32275e7992aSrie */ 3237c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_GROUP) 3247c478bd9Sstevel@tonic-gate flags |= (FLG_RT_SETGROUP | FLG_RT_HANDLE); 3257c478bd9Sstevel@tonic-gate 32675e7992aSrie /* 32775e7992aSrie * Lazy dependencies are identified as DT_NEEDED entries with a 32875e7992aSrie * DF_P1_LAZYLOAD flag in the previous DT_POSFLAG_1 element. The 32975e7992aSrie * dynamic information element that corresponds to the DT_POSFLAG_1 33075e7992aSrie * entry is free, and thus used to store the present entrance 33175e7992aSrie * identifier. This identifier is used to prevent multiple attempts to 33275e7992aSrie * load a failed lazy loadable dependency within the same runtime linker 33375e7992aSrie * operation. However, future attempts to reload this dependency are 33475e7992aSrie * still possible. 33575e7992aSrie */ 33675e7992aSrie if (ndx && (pdip = dip - 1) && (pdip->di_flags & FLG_DI_POSFLAG1)) 33775e7992aSrie pdip->di_info = (void *)slp->sl_id; 33875e7992aSrie 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * Expand the requested name if necessary. 3417c478bd9Sstevel@tonic-gate */ 3429aa23310Srie if ((pnp = elf_fix_name(name, clmp, 0)) == 0) 3437c478bd9Sstevel@tonic-gate return (0); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * Provided the object on the head of the link-map has completed its 3477c478bd9Sstevel@tonic-gate * relocation, create a new link-map control list for this request. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate hlmp = lml->lm_head; 3507c478bd9Sstevel@tonic-gate if (FLAGS(hlmp) & FLG_RT_RELOCED) { 351cce0e03bSab if ((lmc = alist_append(&lml->lm_lists, 0, sizeof (Lm_cntl), 3527c478bd9Sstevel@tonic-gate AL_CNT_LMLISTS)) == 0) { 3537c478bd9Sstevel@tonic-gate remove_pnode(pnp); 3547c478bd9Sstevel@tonic-gate return (0); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate lmco = (Aliste)((char *)lmc - (char *)lml->lm_lists); 3577c478bd9Sstevel@tonic-gate } else { 3587c478bd9Sstevel@tonic-gate lmc = 0; 359cce0e03bSab lmco = ALIST_OFF_DATA; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Load the associated object. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate dip->di_info = nlmp = 3669aa23310Srie load_one(lml, lmco, pnp, clmp, MODE(clmp), flags, 0, in_nfavl); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Remove any expanded pathname infrastructure. Reduce the pending lazy 3707c478bd9Sstevel@tonic-gate * dependency count of the caller, together with the link-map lists 3717c478bd9Sstevel@tonic-gate * count of objects that still have lazy dependencies pending. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate remove_pnode(pnp); 3747c478bd9Sstevel@tonic-gate if (--LAZY(clmp) == 0) 3757c478bd9Sstevel@tonic-gate LIST(clmp)->lm_lazy--; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 37802ca3e02Srie * Finish processing the objects associated with this request, and 37902ca3e02Srie * create an association between the caller and this dependency. 3807c478bd9Sstevel@tonic-gate */ 38175e7992aSrie if (nlmp && ((bind_one(clmp, nlmp, BND_NEEDED) == 0) || 3829aa23310Srie (analyze_lmc(lml, lmco, nlmp, in_nfavl) == 0) || 3839aa23310Srie (relocate_lmc(lml, lmco, clmp, nlmp, in_nfavl) == 0))) 3847c478bd9Sstevel@tonic-gate dip->di_info = nlmp = 0; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 38702ca3e02Srie * If this lazyload has failed, and we've created a new link-map 38802ca3e02Srie * control list to which this request has added objects, then remove 38902ca3e02Srie * all the objects that have been associated to this request. 3907c478bd9Sstevel@tonic-gate */ 39102ca3e02Srie if ((nlmp == 0) && lmc && lmc->lc_head) 39202ca3e02Srie remove_lmc(lml, clmp, lmc, lmco, name); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 39502ca3e02Srie * Finally, remove any link-map control list that was created. 3967c478bd9Sstevel@tonic-gate */ 39702ca3e02Srie if (lmc) 3987c478bd9Sstevel@tonic-gate remove_cntl(lml, lmco); 3997c478bd9Sstevel@tonic-gate 40075e7992aSrie /* 40175e7992aSrie * If this lazy loading failed, record the fact, and bump the lazy 40275e7992aSrie * counts. 40375e7992aSrie */ 40475e7992aSrie if (nlmp == 0) { 40575e7992aSrie dip->di_flags |= FLG_DI_LAZYFAIL; 40675e7992aSrie if (LAZY(clmp)++ == 0) 40775e7992aSrie LIST(clmp)->lm_lazy++; 40875e7992aSrie } 40975e7992aSrie 4107c478bd9Sstevel@tonic-gate return (nlmp); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * Return the entry point of the ELF executable. 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate static ulong_t 4177c478bd9Sstevel@tonic-gate elf_entry_pt(void) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate return (ENTRY(lml_main.lm_head)); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Unmap a given ELF shared object from the address space. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate static void 4267c478bd9Sstevel@tonic-gate elf_unmap_so(Rt_map *lmp) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate caddr_t addr; 4297c478bd9Sstevel@tonic-gate size_t size; 4307c478bd9Sstevel@tonic-gate Mmap *mmaps; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * If this link map represents a relocatable object concatenation, then 4347c478bd9Sstevel@tonic-gate * the image was simply generated in allocated memory. Free the memory. 4357c478bd9Sstevel@tonic-gate * 4367c478bd9Sstevel@tonic-gate * Note: the memory was originally allocated in the libelf:_elf_outmap 4377c478bd9Sstevel@tonic-gate * routine and would normally have been free'd in elf_outsync(), but 4387c478bd9Sstevel@tonic-gate * because we 'interpose' on that routine the memory wasn't free'd at 4397c478bd9Sstevel@tonic-gate * that time. 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_IMGALLOC) { 4427c478bd9Sstevel@tonic-gate free((void *)ADDR(lmp)); 4437c478bd9Sstevel@tonic-gate return; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * If padding was enabled via rtld_db, then we have at least one page 4487c478bd9Sstevel@tonic-gate * in front of the image - and possibly a trailing page. 4497c478bd9Sstevel@tonic-gate * Unmap the front page first: 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate if (PADSTART(lmp) != ADDR(lmp)) { 4527c478bd9Sstevel@tonic-gate addr = (caddr_t)M_PTRUNC(PADSTART(lmp)); 4537c478bd9Sstevel@tonic-gate size = ADDR(lmp) - (ulong_t)addr; 4547c478bd9Sstevel@tonic-gate (void) munmap(addr, size); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * Unmap any trailing padding. 4597c478bd9Sstevel@tonic-gate */ 4607c478bd9Sstevel@tonic-gate if (M_PROUND((PADSTART(lmp) + PADIMLEN(lmp))) > 4617c478bd9Sstevel@tonic-gate M_PROUND(ADDR(lmp) + MSIZE(lmp))) { 4627c478bd9Sstevel@tonic-gate addr = (caddr_t)M_PROUND(ADDR(lmp) + MSIZE(lmp)); 4637c478bd9Sstevel@tonic-gate size = M_PROUND(PADSTART(lmp) + PADIMLEN(lmp)) - (ulong_t)addr; 4647c478bd9Sstevel@tonic-gate (void) munmap(addr, size); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * Unmmap all mapped segments. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate for (mmaps = MMAPS(lmp); mmaps->m_vaddr; mmaps++) 4717c478bd9Sstevel@tonic-gate (void) munmap(mmaps->m_vaddr, mmaps->m_msize); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * Determine if a dependency requires a particular version and if so verify 4767c478bd9Sstevel@tonic-gate * that the version exists in the dependency. 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate static int 4797c478bd9Sstevel@tonic-gate elf_verify_vers(const char *name, Rt_map *clmp, Rt_map *nlmp) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate Verneed *vnd = VERNEED(clmp); 4827c478bd9Sstevel@tonic-gate int _num, num = VERNEEDNUM(clmp); 4837c478bd9Sstevel@tonic-gate char *cstrs = (char *)STRTAB(clmp); 4847c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(clmp); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Traverse the callers version needed information and determine if any 4887c478bd9Sstevel@tonic-gate * specific versions are required from the dependency. 4897c478bd9Sstevel@tonic-gate */ 4905aefb655Srie DBG_CALL(Dbg_ver_need_title(LIST(clmp), NAME(clmp))); 4917c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 4927c478bd9Sstevel@tonic-gate vnd = (Verneed *)((Xword)vnd + vnd->vn_next)) { 4937c478bd9Sstevel@tonic-gate Half cnt = vnd->vn_cnt; 4947c478bd9Sstevel@tonic-gate Vernaux *vnap; 4957c478bd9Sstevel@tonic-gate char *nstrs, *need; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * Determine if a needed entry matches this dependency. 4997c478bd9Sstevel@tonic-gate */ 5007c478bd9Sstevel@tonic-gate need = (char *)(cstrs + vnd->vn_file); 5017c478bd9Sstevel@tonic-gate if (strcmp(name, need) != 0) 5027c478bd9Sstevel@tonic-gate continue; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate if ((lml->lm_flags & LML_FLG_TRC_VERBOSE) && 5057c478bd9Sstevel@tonic-gate ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)) 5067c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_VER_FIND), name); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* 5097c478bd9Sstevel@tonic-gate * Validate that each version required actually exists in the 5107c478bd9Sstevel@tonic-gate * dependency. 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate nstrs = (char *)STRTAB(nlmp); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate for (vnap = (Vernaux *)((Xword)vnd + vnd->vn_aux); cnt; 5157c478bd9Sstevel@tonic-gate cnt--, vnap = (Vernaux *)((Xword)vnap + vnap->vna_next)) { 5167c478bd9Sstevel@tonic-gate char *version, *define; 5177c478bd9Sstevel@tonic-gate Verdef *vdf = VERDEF(nlmp); 5187c478bd9Sstevel@tonic-gate ulong_t _num, num = VERDEFNUM(nlmp); 5197c478bd9Sstevel@tonic-gate int found = 0; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate version = (char *)(cstrs + vnap->vna_name); 5225aefb655Srie DBG_CALL(Dbg_ver_need_entry(lml, 0, need, version)); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5257c478bd9Sstevel@tonic-gate vdf = (Verdef *)((Xword)vdf + vdf->vd_next)) { 5267c478bd9Sstevel@tonic-gate Verdaux *vdap; 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate if (vnap->vna_hash != vdf->vd_hash) 5297c478bd9Sstevel@tonic-gate continue; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate vdap = (Verdaux *)((Xword)vdf + vdf->vd_aux); 5327c478bd9Sstevel@tonic-gate define = (char *)(nstrs + vdap->vda_name); 5337c478bd9Sstevel@tonic-gate if (strcmp(version, define) != 0) 5347c478bd9Sstevel@tonic-gate continue; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate found++; 5377c478bd9Sstevel@tonic-gate break; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * If we're being traced print out any matched version 5427c478bd9Sstevel@tonic-gate * when the verbose (-v) option is in effect. Always 5437c478bd9Sstevel@tonic-gate * print any unmatched versions. 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) { 546a953e2b1Srie /* BEGIN CSTYLED */ 5477c478bd9Sstevel@tonic-gate if (found) { 5487c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_VERBOSE)) 5497c478bd9Sstevel@tonic-gate continue; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_LDD_VER_FOUND), 5527c478bd9Sstevel@tonic-gate need, version, NAME(nlmp)); 5537c478bd9Sstevel@tonic-gate } else { 5547c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_SILENCERR) 5557c478bd9Sstevel@tonic-gate continue; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_VER_NFOUND), 5587c478bd9Sstevel@tonic-gate need, version); 5597c478bd9Sstevel@tonic-gate } 560a953e2b1Srie /* END CSTYLED */ 5617c478bd9Sstevel@tonic-gate continue; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * If the version hasn't been found then this is a 5667c478bd9Sstevel@tonic-gate * candidate for a fatal error condition. Weak 5677c478bd9Sstevel@tonic-gate * version definition requirements are silently 5687c478bd9Sstevel@tonic-gate * ignored. Also, if the image inspected for a version 5697c478bd9Sstevel@tonic-gate * definition has no versioning recorded at all then 5707c478bd9Sstevel@tonic-gate * silently ignore this (this provides better backward 5717c478bd9Sstevel@tonic-gate * compatibility to old images created prior to 5727c478bd9Sstevel@tonic-gate * versioning being available). Both of these skipped 5737c478bd9Sstevel@tonic-gate * diagnostics are available under tracing (see above). 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate if ((found == 0) && (num != 0) && 5767c478bd9Sstevel@tonic-gate (!(vnap->vna_flags & VER_FLG_WEAK))) { 5775aefb655Srie eprintf(lml, ERR_FATAL, 5785aefb655Srie MSG_INTL(MSG_VER_NFOUND), need, version, 5795aefb655Srie NAME(clmp)); 5807c478bd9Sstevel@tonic-gate return (0); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate } 5845aefb655Srie DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD)); 5857c478bd9Sstevel@tonic-gate return (1); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * Search through the dynamic section for DT_NEEDED entries and perform one 5907c478bd9Sstevel@tonic-gate * of two functions. If only the first argument is specified then load the 5917c478bd9Sstevel@tonic-gate * defined shared object, otherwise add the link map representing the defined 5927c478bd9Sstevel@tonic-gate * link map the the dlopen list. 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate static int 5959aa23310Srie elf_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) 5967c478bd9Sstevel@tonic-gate { 59775e7992aSrie Dyn *dyn, *pdyn; 5987c478bd9Sstevel@tonic-gate ulong_t ndx = 0; 59975e7992aSrie uint_t lazy, flags; 6007c478bd9Sstevel@tonic-gate Word lmflags = lml->lm_flags; 6017c478bd9Sstevel@tonic-gate Word lmtflags = lml->lm_tflags; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * Process each shared object on needed list. 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate if (DYN(clmp) == 0) 6077c478bd9Sstevel@tonic-gate return (1); 6087c478bd9Sstevel@tonic-gate 60975e7992aSrie for (dyn = (Dyn *)DYN(clmp), pdyn = NULL; dyn->d_tag != DT_NULL; 61075e7992aSrie pdyn = dyn++, ndx++) { 6117c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(clmp)[ndx]; 6127c478bd9Sstevel@tonic-gate Rt_map *nlmp = 0; 6137c478bd9Sstevel@tonic-gate char *name; 6147c478bd9Sstevel@tonic-gate int silent = 0; 6157c478bd9Sstevel@tonic-gate Pnode *pnp; 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate switch (dyn->d_tag) { 6187c478bd9Sstevel@tonic-gate case DT_POSFLAG_1: 61975e7992aSrie dip->di_flags |= FLG_DI_POSFLAG1; 6207c478bd9Sstevel@tonic-gate continue; 6217c478bd9Sstevel@tonic-gate case DT_NEEDED: 6227c478bd9Sstevel@tonic-gate case DT_USED: 62375e7992aSrie lazy = flags = 0; 6247c478bd9Sstevel@tonic-gate dip->di_flags |= FLG_DI_NEEDED; 62575e7992aSrie 62675e7992aSrie if (pdyn && (pdyn->d_tag == DT_POSFLAG_1)) { 62775e7992aSrie if ((pdyn->d_un.d_val & DF_P1_LAZYLOAD) && 62875e7992aSrie ((lmtflags & LML_TFLG_NOLAZYLD) == 0)) { 62975e7992aSrie dip->di_flags |= FLG_DI_LAZY; 63075e7992aSrie lazy = 1; 63175e7992aSrie } 63275e7992aSrie if (pdyn->d_un.d_val & DF_P1_GROUPPERM) { 63375e7992aSrie dip->di_flags |= FLG_DI_GROUP; 63475e7992aSrie flags = 63575e7992aSrie (FLG_RT_SETGROUP | FLG_RT_HANDLE); 63675e7992aSrie } 63775e7992aSrie } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate name = (char *)STRTAB(clmp) + dyn->d_un.d_val; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * NOTE, libc.so.1 can't be lazy loaded. Although a 6437c478bd9Sstevel@tonic-gate * lazy position flag won't be produced when a RTLDINFO 6447c478bd9Sstevel@tonic-gate * .dynamic entry is found (introduced with the UPM in 6457c478bd9Sstevel@tonic-gate * Solaris 10), it was possible to mark libc for lazy 6467c478bd9Sstevel@tonic-gate * loading on previous releases. To reduce the overhead 6477c478bd9Sstevel@tonic-gate * of testing for this occurrence, only carry out this 6487c478bd9Sstevel@tonic-gate * check for the first object on the link-map list 6497c478bd9Sstevel@tonic-gate * (there aren't many applications built without libc). 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate if (lazy && (lml->lm_head == clmp) && 6527c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_FIL_LIBC)) == 0)) 6537c478bd9Sstevel@tonic-gate lazy = 0; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * Don't bring in lazy loaded objects yet unless we've 6577c478bd9Sstevel@tonic-gate * been asked to attempt to load all available objects 6587c478bd9Sstevel@tonic-gate * (crle(1) sets LD_FLAGS=loadavail). Even under 6597c478bd9Sstevel@tonic-gate * RTLD_NOW we don't process this - RTLD_NOW will cause 6607c478bd9Sstevel@tonic-gate * relocation processing which in turn might trigger 6617c478bd9Sstevel@tonic-gate * lazy loading, but its possible that the object has a 6627c478bd9Sstevel@tonic-gate * lazy loaded file with no bindings (i.e., it should 6637c478bd9Sstevel@tonic-gate * never have been a dependency in the first place). 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate if (lazy) { 6667c478bd9Sstevel@tonic-gate if ((lmflags & LML_FLG_LOADAVAIL) == 0) { 6677c478bd9Sstevel@tonic-gate LAZY(clmp)++; 6687c478bd9Sstevel@tonic-gate lazy = flags = 0; 6697c478bd9Sstevel@tonic-gate continue; 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Silence any error messages - see description 6747c478bd9Sstevel@tonic-gate * under elf_lookup_filtee(). 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) { 6777c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_SILENCERR; 6787c478bd9Sstevel@tonic-gate silent = 1; 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate break; 6827c478bd9Sstevel@tonic-gate case DT_AUXILIARY: 6837c478bd9Sstevel@tonic-gate dip->di_flags |= FLG_DI_AUXFLTR; 6847c478bd9Sstevel@tonic-gate continue; 6857c478bd9Sstevel@tonic-gate case DT_SUNW_AUXILIARY: 6867c478bd9Sstevel@tonic-gate dip->di_flags |= (FLG_DI_AUXFLTR | FLG_DI_SYMFLTR); 6877c478bd9Sstevel@tonic-gate continue; 6887c478bd9Sstevel@tonic-gate case DT_FILTER: 6897c478bd9Sstevel@tonic-gate dip->di_flags |= FLG_DI_STDFLTR; 6907c478bd9Sstevel@tonic-gate continue; 6917c478bd9Sstevel@tonic-gate case DT_SUNW_FILTER: 6927c478bd9Sstevel@tonic-gate dip->di_flags |= (FLG_DI_STDFLTR | FLG_DI_SYMFLTR); 6937c478bd9Sstevel@tonic-gate continue; 6947c478bd9Sstevel@tonic-gate default: 6957c478bd9Sstevel@tonic-gate continue; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6985aefb655Srie DBG_CALL(Dbg_file_needed(clmp, name)); 69975e7992aSrie 70075e7992aSrie /* 70175e7992aSrie * If we're running under ldd(1), indicate that this dependency 70275e7992aSrie * has been processed. It doesn't matter whether the object is 70375e7992aSrie * successfully loaded or not, this flag simply ensures that we 70475e7992aSrie * don't repeatedly attempt to load an object that has already 70575e7992aSrie * failed to load. To do so would create multiple failure 70675e7992aSrie * diagnostics for the same object under ldd(1). 70775e7992aSrie */ 7087c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) 70975e7992aSrie dip->di_flags |= FLG_DI_LDD_DONE; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * Establish the objects name, load it and establish a binding 7137c478bd9Sstevel@tonic-gate * with the caller. 7147c478bd9Sstevel@tonic-gate */ 7159aa23310Srie if (((pnp = elf_fix_name(name, clmp, 0)) == 0) || ((nlmp = 7169aa23310Srie load_one(lml, lmco, pnp, clmp, MODE(clmp), flags, 0, 7179aa23310Srie in_nfavl)) == 0) || (bind_one(clmp, nlmp, BND_NEEDED) == 0)) 7187c478bd9Sstevel@tonic-gate nlmp = 0; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Clean up any infrastructure, including the removal of the 7227c478bd9Sstevel@tonic-gate * error suppression state, if it had been previously set in 7237c478bd9Sstevel@tonic-gate * this routine. 7247c478bd9Sstevel@tonic-gate */ 7257c478bd9Sstevel@tonic-gate if (pnp) 7267c478bd9Sstevel@tonic-gate remove_pnode(pnp); 7277c478bd9Sstevel@tonic-gate if (silent) 7287c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_SILENCERR; 72975e7992aSrie 7307c478bd9Sstevel@tonic-gate if ((dip->di_info = (void *)nlmp) == 0) { 7317c478bd9Sstevel@tonic-gate /* 7327c478bd9Sstevel@tonic-gate * If the object could not be mapped, continue if error 7337c478bd9Sstevel@tonic-gate * suppression is established or we're here with ldd(1). 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate if ((MODE(clmp) & RTLD_CONFGEN) || (lmflags & 7367c478bd9Sstevel@tonic-gate (LML_FLG_LOADAVAIL | LML_FLG_TRC_ENABLE))) 7377c478bd9Sstevel@tonic-gate continue; 7387c478bd9Sstevel@tonic-gate else 7397c478bd9Sstevel@tonic-gate return (0); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if (LAZY(clmp)) 7447c478bd9Sstevel@tonic-gate lml->lm_lazy++; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate return (1); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate static int 7505aefb655Srie elf_map_check(Lm_list *lml, const char *name, caddr_t vaddr, Off size) 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate prmap_t *maps, *_maps; 7537c478bd9Sstevel@tonic-gate int pfd, num, _num; 7547c478bd9Sstevel@tonic-gate caddr_t eaddr = vaddr + size; 7557c478bd9Sstevel@tonic-gate int err; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * If memory reservations have been established for alternative objects 7597c478bd9Sstevel@tonic-gate * determine if this object falls within the reservation, if it does no 7607c478bd9Sstevel@tonic-gate * further checking is required. 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_MEMRESV) { 7637c478bd9Sstevel@tonic-gate Rtc_head *head = (Rtc_head *)config->c_bgn; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if ((vaddr >= (caddr_t)(uintptr_t)head->ch_resbgn) && 7667c478bd9Sstevel@tonic-gate (eaddr <= (caddr_t)(uintptr_t)head->ch_resend)) 7677c478bd9Sstevel@tonic-gate return (0); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * Determine the mappings presently in use by this process. 7727c478bd9Sstevel@tonic-gate */ 7735aefb655Srie if ((pfd = pr_open(lml)) == FD_UNAVAIL) 7747c478bd9Sstevel@tonic-gate return (1); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate if (ioctl(pfd, PIOCNMAP, (void *)&num) == -1) { 7777c478bd9Sstevel@tonic-gate err = errno; 7785aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), name, 7795aefb655Srie strerror(err)); 7807c478bd9Sstevel@tonic-gate return (1); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if ((maps = malloc((num + 1) * sizeof (prmap_t))) == 0) 7847c478bd9Sstevel@tonic-gate return (1); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate if (ioctl(pfd, PIOCMAP, (void *)maps) == -1) { 7877c478bd9Sstevel@tonic-gate err = errno; 7885aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), name, 7895aefb655Srie strerror(err)); 7907c478bd9Sstevel@tonic-gate free(maps); 7917c478bd9Sstevel@tonic-gate return (1); 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * Determine if the supplied address clashes with any of the present 7967c478bd9Sstevel@tonic-gate * process mappings. 7977c478bd9Sstevel@tonic-gate */ 7987c478bd9Sstevel@tonic-gate for (_num = 0, _maps = maps; _num < num; _num++, _maps++) { 7997c478bd9Sstevel@tonic-gate caddr_t _eaddr = _maps->pr_vaddr + _maps->pr_size; 8007c478bd9Sstevel@tonic-gate Rt_map *lmp; 8017c478bd9Sstevel@tonic-gate const char *str; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate if ((eaddr < _maps->pr_vaddr) || (vaddr >= _eaddr)) 8047c478bd9Sstevel@tonic-gate continue; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * We have a memory clash. See if one of the known dynamic 8087c478bd9Sstevel@tonic-gate * dependency mappings represents this space so as to provide 8097c478bd9Sstevel@tonic-gate * the user a more meaningful message. 8107c478bd9Sstevel@tonic-gate */ 8117c478bd9Sstevel@tonic-gate if ((lmp = _caller(vaddr, 0)) != 0) 8127c478bd9Sstevel@tonic-gate str = NAME(lmp); 8137c478bd9Sstevel@tonic-gate else 8147c478bd9Sstevel@tonic-gate str = MSG_INTL(MSG_STR_UNKNOWN); 8157c478bd9Sstevel@tonic-gate 8165aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_MAPINUSE), name, 8175aefb655Srie EC_NATPTR(vaddr), EC_OFF(size), str); 8187c478bd9Sstevel@tonic-gate return (1); 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate free(maps); 8217c478bd9Sstevel@tonic-gate return (0); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * Obtain a memory reservation. On newer systems, both MAP_ANON and MAP_ALIGN 8267c478bd9Sstevel@tonic-gate * are used to obtained an aligned reservation from anonymous memory. If 8277c478bd9Sstevel@tonic-gate * MAP_ANON isn't available, then MAP_ALIGN isn't either, so obtain a standard 8287c478bd9Sstevel@tonic-gate * reservation using the file as backing. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate static Am_ret 8315aefb655Srie elf_map_reserve(Lm_list *lml, const char *name, caddr_t *maddr, Off msize, 8325aefb655Srie int mperm, int fd, Xword align) 8337c478bd9Sstevel@tonic-gate { 8347c478bd9Sstevel@tonic-gate Am_ret amret; 8357c478bd9Sstevel@tonic-gate int mflag = MAP_PRIVATE | MAP_NORESERVE; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate #if defined(MAP_ALIGN) 8387c478bd9Sstevel@tonic-gate if ((rtld_flags2 & RT_FL2_NOMALIGN) == 0) { 8397c478bd9Sstevel@tonic-gate mflag |= MAP_ALIGN; 8407c478bd9Sstevel@tonic-gate *maddr = (caddr_t)align; 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate #endif 8435aefb655Srie if ((amret = anon_map(lml, maddr, msize, PROT_NONE, mflag)) == AM_ERROR) 8447c478bd9Sstevel@tonic-gate return (amret); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate if (amret == AM_OK) 8477c478bd9Sstevel@tonic-gate return (AM_OK); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * If an anonymous memory request failed (which should only be the 8517c478bd9Sstevel@tonic-gate * case if it is unsupported on the system we're running on), establish 8527c478bd9Sstevel@tonic-gate * the initial mapping directly from the file. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate *maddr = 0; 8557c478bd9Sstevel@tonic-gate if ((*maddr = mmap(*maddr, msize, mperm, MAP_PRIVATE, 8567c478bd9Sstevel@tonic-gate fd, 0)) == MAP_FAILED) { 8577c478bd9Sstevel@tonic-gate int err = errno; 8585aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), name, 8595aefb655Srie strerror(err)); 8607c478bd9Sstevel@tonic-gate return (AM_ERROR); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate return (AM_NOSUP); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate static void * 8667c478bd9Sstevel@tonic-gate elf_map_textdata(caddr_t addr, Off flen, int mperm, int phdr_mperm, int mflag, 8677c478bd9Sstevel@tonic-gate int fd, Off foff) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate #if defined(MAP_TEXT) && defined(MAP_INITDATA) 8707c478bd9Sstevel@tonic-gate static int notd = 0; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * If MAP_TEXT and MAP_INITDATA are available, select the appropriate 8747c478bd9Sstevel@tonic-gate * flag. 8757c478bd9Sstevel@tonic-gate */ 8767c478bd9Sstevel@tonic-gate if (notd == 0) { 8777c478bd9Sstevel@tonic-gate if ((phdr_mperm & (PROT_WRITE | PROT_EXEC)) == PROT_EXEC) 8787c478bd9Sstevel@tonic-gate mflag |= MAP_TEXT; 8797c478bd9Sstevel@tonic-gate else 8807c478bd9Sstevel@tonic-gate mflag |= MAP_INITDATA; 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate #endif 8837c478bd9Sstevel@tonic-gate if (mmap((caddr_t)addr, flen, mperm, mflag, fd, foff) != MAP_FAILED) 8847c478bd9Sstevel@tonic-gate return (0); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate #if defined(MAP_TEXT) && defined(MAP_INITDATA) 8877c478bd9Sstevel@tonic-gate if ((notd == 0) && (errno == EINVAL)) { 8887c478bd9Sstevel@tonic-gate /* 8897c478bd9Sstevel@tonic-gate * MAP_TEXT and MAP_INITDATA may not be supported on this 8907c478bd9Sstevel@tonic-gate * platform, try again without. 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate notd = 1; 8937c478bd9Sstevel@tonic-gate mflag &= ~(MAP_TEXT | MAP_INITDATA); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate return (mmap((caddr_t)addr, flen, mperm, mflag, fd, foff)); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate #endif 8987c478bd9Sstevel@tonic-gate return (MAP_FAILED); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * Map in a file. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate static caddr_t 9057c478bd9Sstevel@tonic-gate elf_map_it( 9065aefb655Srie Lm_list *lml, /* link-map list */ 9077c478bd9Sstevel@tonic-gate const char *name, /* actual name stored for pathname */ 9087c478bd9Sstevel@tonic-gate Off fsize, /* total mapping claim of the file */ 9097c478bd9Sstevel@tonic-gate Ehdr *ehdr, /* ELF header of file */ 9107c478bd9Sstevel@tonic-gate Phdr *fphdr, /* first loadable Phdr */ 9117c478bd9Sstevel@tonic-gate Phdr *lphdr, /* last loadable Phdr */ 9127c478bd9Sstevel@tonic-gate Phdr **rrphdr, /* return first Phdr in reservation */ 9137c478bd9Sstevel@tonic-gate caddr_t *rraddr, /* return start of reservation */ 9147c478bd9Sstevel@tonic-gate Off *rrsize, /* return total size of reservation */ 9157c478bd9Sstevel@tonic-gate int fixed, /* image is resolved to a fixed addr */ 9167c478bd9Sstevel@tonic-gate int fd, /* images file descriptor */ 9177c478bd9Sstevel@tonic-gate Xword align, /* image segments maximum alignment */ 9187c478bd9Sstevel@tonic-gate Mmap *mmaps, /* mmap information array and */ 9197c478bd9Sstevel@tonic-gate uint_t *mmapcnt) /* mapping count */ 9207c478bd9Sstevel@tonic-gate { 9217c478bd9Sstevel@tonic-gate caddr_t raddr; /* reservation address */ 9227c478bd9Sstevel@tonic-gate Off rsize; /* reservation size */ 9237c478bd9Sstevel@tonic-gate Phdr *phdr; /* working program header poiner */ 9247c478bd9Sstevel@tonic-gate caddr_t maddr; /* working mmap address */ 9257c478bd9Sstevel@tonic-gate caddr_t faddr; /* working file address */ 9267c478bd9Sstevel@tonic-gate size_t padsize; /* object padding requirement */ 9277c478bd9Sstevel@tonic-gate size_t padpsize = 0; /* padding size rounded to next page */ 9287c478bd9Sstevel@tonic-gate size_t padmsize = 0; /* padding size rounded for alignment */ 9297c478bd9Sstevel@tonic-gate int skipfseg; /* skip mapping first segment */ 9307c478bd9Sstevel@tonic-gate int mperm; /* segment permissions */ 9317c478bd9Sstevel@tonic-gate Am_ret amret = AM_NOSUP; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * If padding is required extend both the front and rear of the image. 9357c478bd9Sstevel@tonic-gate * To insure the image itself is mapped at the correct alignment the 9367c478bd9Sstevel@tonic-gate * initial padding is rounded up to the nearest page. Once the image is 9377c478bd9Sstevel@tonic-gate * mapped the excess can be pruned to the nearest page required for the 9387c478bd9Sstevel@tonic-gate * actual padding itself. 9397c478bd9Sstevel@tonic-gate */ 9407c478bd9Sstevel@tonic-gate if ((padsize = r_debug.rtd_objpad) != 0) { 9417c478bd9Sstevel@tonic-gate padpsize = M_PROUND(padsize); 9427c478bd9Sstevel@tonic-gate if (fixed) 9437c478bd9Sstevel@tonic-gate padmsize = padpsize; 9447c478bd9Sstevel@tonic-gate else 9457c478bd9Sstevel@tonic-gate padmsize = S_ROUND(padsize, align); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * Determine the initial permissions used to map in the first segment. 9507c478bd9Sstevel@tonic-gate * If this segments memsz is greater that its filesz then the difference 9517c478bd9Sstevel@tonic-gate * must be zeroed. Make sure this segment is writable. 9527c478bd9Sstevel@tonic-gate */ 9537c478bd9Sstevel@tonic-gate mperm = 0; 9547c478bd9Sstevel@tonic-gate if (fphdr->p_flags & PF_R) 9557c478bd9Sstevel@tonic-gate mperm |= PROT_READ; 9567c478bd9Sstevel@tonic-gate if (fphdr->p_flags & PF_X) 9577c478bd9Sstevel@tonic-gate mperm |= PROT_EXEC; 9587c478bd9Sstevel@tonic-gate if ((fphdr->p_flags & PF_W) || (fphdr->p_memsz > fphdr->p_filesz)) 9597c478bd9Sstevel@tonic-gate mperm |= PROT_WRITE; 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * Determine whether or not to let system reserve address space based on 9637c478bd9Sstevel@tonic-gate * whether this is a dynamic executable (addresses in object are fixed) 9647c478bd9Sstevel@tonic-gate * or a shared object (addresses in object are relative to the objects' 9657c478bd9Sstevel@tonic-gate * base). 9667c478bd9Sstevel@tonic-gate */ 9677c478bd9Sstevel@tonic-gate if (fixed) { 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * Determine the reservation address and size, and insure that 9707c478bd9Sstevel@tonic-gate * this reservation isn't already in use. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate faddr = maddr = (caddr_t)M_PTRUNC((ulong_t)fphdr->p_vaddr); 9737c478bd9Sstevel@tonic-gate raddr = maddr - padpsize; 9747c478bd9Sstevel@tonic-gate rsize = fsize + padpsize + padsize; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate if (lml_main.lm_head) { 9775aefb655Srie if (elf_map_check(lml, name, raddr, rsize) != 0) 9787c478bd9Sstevel@tonic-gate return (0); 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * As this is a fixed image, all segments must be individually 9837c478bd9Sstevel@tonic-gate * mapped. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate skipfseg = 0; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate } else { 9887c478bd9Sstevel@tonic-gate size_t esize; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * If this isn't a fixed image, reserve enough address space for 9927c478bd9Sstevel@tonic-gate * the entire image to be mapped. The amount of reservation is 9937c478bd9Sstevel@tonic-gate * the range between the beginning of the first, and end of the 9947c478bd9Sstevel@tonic-gate * last loadable segment, together with any padding, plus the 9957c478bd9Sstevel@tonic-gate * alignment of the first segment. 9967c478bd9Sstevel@tonic-gate * 9977c478bd9Sstevel@tonic-gate * The optimal reservation is made as a no-reserve mapping from 9987c478bd9Sstevel@tonic-gate * anonymous memory. Each segment is then mapped into this 9997c478bd9Sstevel@tonic-gate * reservation. If the anonymous mapping capability isn't 10007c478bd9Sstevel@tonic-gate * available, the reservation is obtained from the file itself. 10017c478bd9Sstevel@tonic-gate * In this case the first segment of the image is mapped as part 10027c478bd9Sstevel@tonic-gate * of the reservation, thus only the following segments need to 10037c478bd9Sstevel@tonic-gate * be remapped. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate rsize = fsize + padmsize + padsize; 10065aefb655Srie if ((amret = elf_map_reserve(lml, name, &raddr, rsize, mperm, 10077c478bd9Sstevel@tonic-gate fd, align)) == AM_ERROR) 10087c478bd9Sstevel@tonic-gate return (0); 10097c478bd9Sstevel@tonic-gate maddr = raddr + padmsize; 10107c478bd9Sstevel@tonic-gate faddr = (caddr_t)S_ROUND((Off)maddr, align); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * If this reservation has been obtained from anonymous memory, 10147c478bd9Sstevel@tonic-gate * then all segments must be individually mapped. Otherwise, 10157c478bd9Sstevel@tonic-gate * the first segment heads the reservation. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate if (amret == AM_OK) 10187c478bd9Sstevel@tonic-gate skipfseg = 0; 10197c478bd9Sstevel@tonic-gate else 10207c478bd9Sstevel@tonic-gate skipfseg = 1; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * For backward compatibility (where MAP_ALIGN isn't available), 10247c478bd9Sstevel@tonic-gate * insure the alignment of the reservation is adequate for this 10257c478bd9Sstevel@tonic-gate * object, and if not remap the object to obtain the correct 10267c478bd9Sstevel@tonic-gate * alignment. 10277c478bd9Sstevel@tonic-gate */ 10287c478bd9Sstevel@tonic-gate if (faddr != maddr) { 10297c478bd9Sstevel@tonic-gate (void) munmap(raddr, rsize); 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate rsize += align; 10325aefb655Srie if ((amret = elf_map_reserve(lml, name, &raddr, rsize, 10335aefb655Srie mperm, fd, align)) == AM_ERROR) 10347c478bd9Sstevel@tonic-gate return (0); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate maddr = faddr = (caddr_t)S_ROUND((Off)(raddr + 10377c478bd9Sstevel@tonic-gate padpsize), align); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate esize = maddr - raddr + padpsize; 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * As ths image has been realigned, the first segment 10437c478bd9Sstevel@tonic-gate * of the file needs to be remapped to its correct 10447c478bd9Sstevel@tonic-gate * location. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate skipfseg = 0; 10477c478bd9Sstevel@tonic-gate } else 10487c478bd9Sstevel@tonic-gate esize = padmsize - padpsize; 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* 10517c478bd9Sstevel@tonic-gate * If this reservation included padding, remove any excess for 10527c478bd9Sstevel@tonic-gate * the start of the image (the padding was adjusted to insure 10537c478bd9Sstevel@tonic-gate * the image was aligned appropriately). 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate if (esize) { 10567c478bd9Sstevel@tonic-gate (void) munmap(raddr, esize); 10577c478bd9Sstevel@tonic-gate raddr += esize; 10587c478bd9Sstevel@tonic-gate rsize -= esize; 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * At this point we know the initial location of the image, and its 10647c478bd9Sstevel@tonic-gate * size. Pass these back to the caller for inclusion in the link-map 10657c478bd9Sstevel@tonic-gate * that will eventually be created. 10667c478bd9Sstevel@tonic-gate */ 10677c478bd9Sstevel@tonic-gate *rraddr = raddr; 10687c478bd9Sstevel@tonic-gate *rrsize = rsize; 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * The first loadable segment is now pointed to by maddr. This segment 10727c478bd9Sstevel@tonic-gate * will eventually contain the elf header and program headers, so reset 10737c478bd9Sstevel@tonic-gate * the program header. Pass this back to the caller for inclusion in 10747c478bd9Sstevel@tonic-gate * the link-map so it can be used for later unmapping operations. 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate /* LINTED */ 10777c478bd9Sstevel@tonic-gate *rrphdr = (Phdr *)((char *)maddr + ehdr->e_phoff); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * If padding is required at the front of the image, obtain that now. 10817c478bd9Sstevel@tonic-gate * Note, if we've already obtained a reservation from anonymous memory 10827c478bd9Sstevel@tonic-gate * then this reservation will already include suitable padding. 10837c478bd9Sstevel@tonic-gate * Otherwise this reservation is backed by the file, or in the case of 10847c478bd9Sstevel@tonic-gate * a fixed image, doesn't yet exist. Map the padding so that it is 10857c478bd9Sstevel@tonic-gate * suitably protected (PROT_NONE), and insure the first segment of the 10867c478bd9Sstevel@tonic-gate * file is mapped to its correct location. 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate if (padsize) { 10897c478bd9Sstevel@tonic-gate if (amret == AM_NOSUP) { 10905aefb655Srie if (dz_map(lml, raddr, padpsize, PROT_NONE, 10915aefb655Srie (MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE)) == 10925aefb655Srie MAP_FAILED) 10937c478bd9Sstevel@tonic-gate return (0); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate skipfseg = 0; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate rsize -= padpsize; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate /* 11017c478bd9Sstevel@tonic-gate * Map individual segments. For a fixed image, these will each be 11027c478bd9Sstevel@tonic-gate * unique mappings. For a reservation these will fill in the 11037c478bd9Sstevel@tonic-gate * reservation. 11047c478bd9Sstevel@tonic-gate */ 11057c478bd9Sstevel@tonic-gate for (phdr = fphdr; phdr <= lphdr; 11067c478bd9Sstevel@tonic-gate phdr = (Phdr *)((Off)phdr + ehdr->e_phentsize)) { 11077c478bd9Sstevel@tonic-gate caddr_t addr; 11087c478bd9Sstevel@tonic-gate Off mlen, flen; 11097c478bd9Sstevel@tonic-gate size_t size; 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate /* 11127c478bd9Sstevel@tonic-gate * Skip non-loadable segments or segments that don't occupy 11137c478bd9Sstevel@tonic-gate * any memory. 11147c478bd9Sstevel@tonic-gate */ 11157c478bd9Sstevel@tonic-gate if (((phdr->p_type != PT_LOAD) && 11167c478bd9Sstevel@tonic-gate (phdr->p_type != PT_SUNWBSS)) || (phdr->p_memsz == 0)) 11177c478bd9Sstevel@tonic-gate continue; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * Establish this segments address relative to our base. 11217c478bd9Sstevel@tonic-gate */ 11227c478bd9Sstevel@tonic-gate addr = (caddr_t)M_PTRUNC((ulong_t)(phdr->p_vaddr + 11237c478bd9Sstevel@tonic-gate (fixed ? 0 : faddr))); 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate /* 11267c478bd9Sstevel@tonic-gate * Determine the mapping protection from the segment attributes. 11277c478bd9Sstevel@tonic-gate * Also determine the etext address from the last loadable 11287c478bd9Sstevel@tonic-gate * segment which has permissions but no write access. 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate mperm = 0; 11317c478bd9Sstevel@tonic-gate if (phdr->p_flags) { 11327c478bd9Sstevel@tonic-gate if (phdr->p_flags & PF_R) 11337c478bd9Sstevel@tonic-gate mperm |= PROT_READ; 11347c478bd9Sstevel@tonic-gate if (phdr->p_flags & PF_X) 11357c478bd9Sstevel@tonic-gate mperm |= PROT_EXEC; 11367c478bd9Sstevel@tonic-gate if (phdr->p_flags & PF_W) 11377c478bd9Sstevel@tonic-gate mperm |= PROT_WRITE; 11387c478bd9Sstevel@tonic-gate else 11397c478bd9Sstevel@tonic-gate fmap->fm_etext = phdr->p_vaddr + phdr->p_memsz + 11407c478bd9Sstevel@tonic-gate (ulong_t)(fixed ? 0 : faddr); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * Determine the type of mapping required. 11457c478bd9Sstevel@tonic-gate */ 11467c478bd9Sstevel@tonic-gate if (phdr->p_type == PT_SUNWBSS) { 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * Potentially, we can defer the loading of any SUNWBSS 11497c478bd9Sstevel@tonic-gate * segment, depending on whether the symbols it provides 11507c478bd9Sstevel@tonic-gate * have been bound to. In this manner, large segments 11517c478bd9Sstevel@tonic-gate * that are interposed upon between shared libraries 11527c478bd9Sstevel@tonic-gate * may not require mapping. Note, that the mapping 11537c478bd9Sstevel@tonic-gate * information is recorded in our mapping descriptor at 11547c478bd9Sstevel@tonic-gate * this time. 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate mlen = phdr->p_memsz; 11577c478bd9Sstevel@tonic-gate flen = 0; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate } else if ((phdr->p_filesz == 0) && (phdr->p_flags == 0)) { 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * If this segment has no backing file and no flags 11627c478bd9Sstevel@tonic-gate * specified, then it defines a reservation. At this 11637c478bd9Sstevel@tonic-gate * point all standard loadable segments will have been 11647c478bd9Sstevel@tonic-gate * processed. The segment reservation is mapped 11657c478bd9Sstevel@tonic-gate * directly from /dev/null. 11667c478bd9Sstevel@tonic-gate */ 11675aefb655Srie if (nu_map(lml, (caddr_t)addr, phdr->p_memsz, PROT_NONE, 11687c478bd9Sstevel@tonic-gate MAP_FIXED | MAP_PRIVATE) == MAP_FAILED) 11697c478bd9Sstevel@tonic-gate return (0); 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate mlen = phdr->p_memsz; 11727c478bd9Sstevel@tonic-gate flen = 0; 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate } else if (phdr->p_filesz == 0) { 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * If this segment has no backing file then it defines a 11777c478bd9Sstevel@tonic-gate * nobits segment and is mapped directly from /dev/zero. 11787c478bd9Sstevel@tonic-gate */ 11795aefb655Srie if (dz_map(lml, (caddr_t)addr, phdr->p_memsz, mperm, 11807c478bd9Sstevel@tonic-gate MAP_FIXED | MAP_PRIVATE) == MAP_FAILED) 11817c478bd9Sstevel@tonic-gate return (0); 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate mlen = phdr->p_memsz; 11847c478bd9Sstevel@tonic-gate flen = 0; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate } else { 11877c478bd9Sstevel@tonic-gate Off foff; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* 11907c478bd9Sstevel@tonic-gate * This mapping originates from the file. Determine the 11917c478bd9Sstevel@tonic-gate * file offset to which the mapping will be directed 11927c478bd9Sstevel@tonic-gate * (must be aligned) and how much to map (might be more 11937c478bd9Sstevel@tonic-gate * than the file in the case of .bss). 11947c478bd9Sstevel@tonic-gate */ 11957c478bd9Sstevel@tonic-gate foff = M_PTRUNC((ulong_t)phdr->p_offset); 11967c478bd9Sstevel@tonic-gate mlen = phdr->p_memsz + (phdr->p_offset - foff); 11977c478bd9Sstevel@tonic-gate flen = phdr->p_filesz + (phdr->p_offset - foff); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * If this is a non-fixed, non-anonymous mapping, and no 12017c478bd9Sstevel@tonic-gate * padding is involved, then the first loadable segment 12027c478bd9Sstevel@tonic-gate * is already part of the initial reservation. In this 12037c478bd9Sstevel@tonic-gate * case there is no need to remap this segment. 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate if ((skipfseg == 0) || (phdr != fphdr)) { 12067c478bd9Sstevel@tonic-gate int phdr_mperm = mperm; 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * If this segments memsz is greater that its 12097c478bd9Sstevel@tonic-gate * filesz then the difference must be zeroed. 12107c478bd9Sstevel@tonic-gate * Make sure this segment is writable. 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate if (phdr->p_memsz > phdr->p_filesz) 12137c478bd9Sstevel@tonic-gate mperm |= PROT_WRITE; 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if (elf_map_textdata((caddr_t)addr, flen, 12167c478bd9Sstevel@tonic-gate mperm, phdr_mperm, 12177c478bd9Sstevel@tonic-gate (MAP_FIXED | MAP_PRIVATE), fd, foff) == 12187c478bd9Sstevel@tonic-gate MAP_FAILED) { 12197c478bd9Sstevel@tonic-gate int err = errno; 12205aefb655Srie eprintf(lml, ERR_FATAL, 12217c478bd9Sstevel@tonic-gate MSG_INTL(MSG_SYS_MMAP), name, 12227c478bd9Sstevel@tonic-gate strerror(err)); 12237c478bd9Sstevel@tonic-gate return (0); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* 12287c478bd9Sstevel@tonic-gate * If the memory occupancy of the segment overflows the 12297c478bd9Sstevel@tonic-gate * definition in the file, we need to "zero out" the end 12307c478bd9Sstevel@tonic-gate * of the mapping we've established, and if necessary, 12317c478bd9Sstevel@tonic-gate * map some more space from /dev/zero. Note, zero'ed 12327c478bd9Sstevel@tonic-gate * memory must end on a double word boundary to satisfy 12337c478bd9Sstevel@tonic-gate * zero(). 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate if (phdr->p_memsz > phdr->p_filesz) { 12367c478bd9Sstevel@tonic-gate caddr_t zaddr; 12377c478bd9Sstevel@tonic-gate size_t zlen, zplen; 12387c478bd9Sstevel@tonic-gate Off fend; 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate foff = (Off)(phdr->p_vaddr + phdr->p_filesz + 12417c478bd9Sstevel@tonic-gate (fixed ? 0 : faddr)); 12427c478bd9Sstevel@tonic-gate zaddr = (caddr_t)M_PROUND(foff); 12437c478bd9Sstevel@tonic-gate zplen = (size_t)(zaddr - foff); 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate fend = (Off)S_DROUND((size_t)(phdr->p_vaddr + 12467c478bd9Sstevel@tonic-gate phdr->p_memsz + (fixed ? 0 : faddr))); 12477c478bd9Sstevel@tonic-gate zlen = (size_t)(fend - foff); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * Determine whether the number of bytes that 12517c478bd9Sstevel@tonic-gate * must be zero'ed overflow to the next page. 12527c478bd9Sstevel@tonic-gate * If not, simply clear the exact bytes 12537c478bd9Sstevel@tonic-gate * (filesz to memsz) from this page. Otherwise, 12547c478bd9Sstevel@tonic-gate * clear the remaining bytes of this page, and 12557c478bd9Sstevel@tonic-gate * map an following pages from /dev/zero. 12567c478bd9Sstevel@tonic-gate */ 12577c478bd9Sstevel@tonic-gate if (zlen < zplen) 12587c478bd9Sstevel@tonic-gate zero((caddr_t)foff, (long)zlen); 12597c478bd9Sstevel@tonic-gate else { 12607c478bd9Sstevel@tonic-gate zero((caddr_t)foff, (long)zplen); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate if ((zlen = (fend - (Off)zaddr)) > 0) { 12635aefb655Srie if (dz_map(lml, zaddr, zlen, 12645aefb655Srie mperm, 12657c478bd9Sstevel@tonic-gate MAP_FIXED | MAP_PRIVATE) == 12667c478bd9Sstevel@tonic-gate MAP_FAILED) 12677c478bd9Sstevel@tonic-gate return (0); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate /* 12747c478bd9Sstevel@tonic-gate * Unmap anything from the last mapping address to this one and 12757c478bd9Sstevel@tonic-gate * update the mapping claim pointer. 12767c478bd9Sstevel@tonic-gate */ 12777c478bd9Sstevel@tonic-gate if ((fixed == 0) && ((size = addr - maddr) != 0)) { 12787c478bd9Sstevel@tonic-gate (void) munmap(maddr, size); 12797c478bd9Sstevel@tonic-gate rsize -= size; 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate /* 12837c478bd9Sstevel@tonic-gate * Retain this segments mapping information. 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate mmaps[*mmapcnt].m_vaddr = addr; 12867c478bd9Sstevel@tonic-gate mmaps[*mmapcnt].m_msize = mlen; 12877c478bd9Sstevel@tonic-gate mmaps[*mmapcnt].m_fsize = flen; 12887c478bd9Sstevel@tonic-gate mmaps[*mmapcnt].m_perm = mperm; 12897c478bd9Sstevel@tonic-gate (*mmapcnt)++; 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate maddr = addr + M_PROUND(mlen); 12927c478bd9Sstevel@tonic-gate rsize -= M_PROUND(mlen); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* 12967c478bd9Sstevel@tonic-gate * If padding is required at the end of the image, obtain that now. 12977c478bd9Sstevel@tonic-gate * Note, if we've already obtained a reservation from anonymous memory 12987c478bd9Sstevel@tonic-gate * then this reservation will already include suitable padding. 12997c478bd9Sstevel@tonic-gate */ 13007c478bd9Sstevel@tonic-gate if (padsize) { 13017c478bd9Sstevel@tonic-gate if (amret == AM_NOSUP) { 13027c478bd9Sstevel@tonic-gate /* 13037c478bd9Sstevel@tonic-gate * maddr is currently page aligned from the last segment 13047c478bd9Sstevel@tonic-gate * mapping. 13057c478bd9Sstevel@tonic-gate */ 13065aefb655Srie if (dz_map(lml, maddr, padsize, PROT_NONE, 13075aefb655Srie (MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE)) == 13085aefb655Srie MAP_FAILED) 13097c478bd9Sstevel@tonic-gate return (0); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate maddr += padsize; 13127c478bd9Sstevel@tonic-gate rsize -= padsize; 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate /* 13167c478bd9Sstevel@tonic-gate * Unmap any final reservation. 13177c478bd9Sstevel@tonic-gate */ 13187c478bd9Sstevel@tonic-gate if ((fixed == 0) && (rsize != 0)) 13197c478bd9Sstevel@tonic-gate (void) munmap(maddr, rsize); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate return (faddr); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 13257c478bd9Sstevel@tonic-gate * A null symbol interpretor. Used if a filter has no associated filtees. 13267c478bd9Sstevel@tonic-gate */ 13277c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 13287c478bd9Sstevel@tonic-gate static Sym * 13299aa23310Srie elf_null_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 13307c478bd9Sstevel@tonic-gate { 13317c478bd9Sstevel@tonic-gate return ((Sym *)0); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * Disable filtee use. 13367c478bd9Sstevel@tonic-gate */ 13377c478bd9Sstevel@tonic-gate static void 13389a411307Srie elf_disable_filtee(Rt_map *lmp, Dyninfo *dip) 13397c478bd9Sstevel@tonic-gate { 13407c478bd9Sstevel@tonic-gate dip->di_info = 0; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if ((dip->di_flags & FLG_DI_SYMFLTR) == 0) { 13437c478bd9Sstevel@tonic-gate /* 13447c478bd9Sstevel@tonic-gate * If this is an object filter, free the filtee's duplication. 13457c478bd9Sstevel@tonic-gate */ 13467c478bd9Sstevel@tonic-gate if (OBJFLTRNDX(lmp) != FLTR_DISABLED) { 13477c478bd9Sstevel@tonic-gate free(REFNAME(lmp)); 13487c478bd9Sstevel@tonic-gate REFNAME(lmp) = (char *)0; 13497c478bd9Sstevel@tonic-gate OBJFLTRNDX(lmp) = FLTR_DISABLED; 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* 13527c478bd9Sstevel@tonic-gate * Indicate that this filtee is no longer available. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_STDFLTR) 13557c478bd9Sstevel@tonic-gate SYMINTP(lmp) = elf_null_find_sym; 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate } else if (dip->di_flags & FLG_DI_STDFLTR) { 13597c478bd9Sstevel@tonic-gate /* 13607c478bd9Sstevel@tonic-gate * Indicate that this standard filtee is no longer available. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate if (SYMSFLTRCNT(lmp)) 13637c478bd9Sstevel@tonic-gate SYMSFLTRCNT(lmp)--; 13647c478bd9Sstevel@tonic-gate } else { 13657c478bd9Sstevel@tonic-gate /* 13667c478bd9Sstevel@tonic-gate * Indicate that this auxiliary filtee is no longer available. 13677c478bd9Sstevel@tonic-gate */ 13687c478bd9Sstevel@tonic-gate if (SYMAFLTRCNT(lmp)) 13697c478bd9Sstevel@tonic-gate SYMAFLTRCNT(lmp)--; 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate dip->di_flags &= ~MSK_DI_FILTER; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate /* 13757c478bd9Sstevel@tonic-gate * Find symbol interpreter - filters. 13767c478bd9Sstevel@tonic-gate * This function is called when the symbols from a shared object should 13777c478bd9Sstevel@tonic-gate * be resolved from the shared objects filtees instead of from within itself. 13787c478bd9Sstevel@tonic-gate * 13797c478bd9Sstevel@tonic-gate * A symbol name of 0 is used to trigger filtee loading. 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate static Sym * 13829aa23310Srie _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, 13839aa23310Srie int *in_nfavl) 13847c478bd9Sstevel@tonic-gate { 13857c478bd9Sstevel@tonic-gate const char *name = slp->sl_name, *filtees; 13867c478bd9Sstevel@tonic-gate Rt_map *clmp = slp->sl_cmap; 13877c478bd9Sstevel@tonic-gate Rt_map *ilmp = slp->sl_imap; 13887c478bd9Sstevel@tonic-gate Pnode *pnp, **pnpp; 13897c478bd9Sstevel@tonic-gate int any; 13907c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(ilmp)[ndx]; 13917c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(ilmp); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * Indicate that the filter has been used. If a binding already exists 13957c478bd9Sstevel@tonic-gate * to the caller, indicate that this object is referenced. This insures 13967c478bd9Sstevel@tonic-gate * we don't generate false unreferenced diagnostics from ldd -u/U or 13977c478bd9Sstevel@tonic-gate * debugging. Don't create a binding regardless, as this filter may 13987c478bd9Sstevel@tonic-gate * have been dlopen()'ed. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate if (name && (ilmp != clmp)) { 14017c478bd9Sstevel@tonic-gate Word tracing = (LIST(clmp)->lm_flags & 14027c478bd9Sstevel@tonic-gate (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED)); 14037c478bd9Sstevel@tonic-gate 14045aefb655Srie if (tracing || DBG_ENABLED) { 1405cce0e03bSab Bnd_desc *bdp; 1406cce0e03bSab Aliste idx; 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate FLAGS1(ilmp) |= FL1_RT_USED; 14097c478bd9Sstevel@tonic-gate 14105aefb655Srie if ((tracing & LML_FLG_TRC_UNREF) || DBG_ENABLED) { 1411cce0e03bSab for (APLIST_TRAVERSE(CALLERS(ilmp), idx, bdp)) { 14127c478bd9Sstevel@tonic-gate if (bdp->b_caller == clmp) { 14137c478bd9Sstevel@tonic-gate bdp->b_flags |= BND_REFER; 14147c478bd9Sstevel@tonic-gate break; 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate /* 14227c478bd9Sstevel@tonic-gate * If this is the first call to process this filter, establish the 14237c478bd9Sstevel@tonic-gate * filtee list. If a configuration file exists, determine if any 14247c478bd9Sstevel@tonic-gate * filtee associations for this filter, and its filtee reference, are 14257c478bd9Sstevel@tonic-gate * defined. Otherwise, process the filtee reference. Any token 14267c478bd9Sstevel@tonic-gate * expansion is also completed at this point (i.e., $PLATFORM). 14277c478bd9Sstevel@tonic-gate */ 14287c478bd9Sstevel@tonic-gate filtees = (char *)STRTAB(ilmp) + DYN(ilmp)[ndx].d_un.d_val; 14297c478bd9Sstevel@tonic-gate if (dip->di_info == 0) { 14307c478bd9Sstevel@tonic-gate if (rtld_flags2 & RT_FL2_FLTCFG) 14315aefb655Srie dip->di_info = elf_config_flt(lml, PATHNAME(ilmp), 14325aefb655Srie filtees); 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate if (dip->di_info == 0) { 14355aefb655Srie DBG_CALL(Dbg_file_filter(lml, NAME(ilmp), filtees, 0)); 14367c478bd9Sstevel@tonic-gate if ((lml->lm_flags & 14377c478bd9Sstevel@tonic-gate (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH)) && 14387c478bd9Sstevel@tonic-gate ((FLAGS1(ilmp) & FL1_RT_LDDSTUB) == 0)) 14397c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_FIL_FILTER), 14407c478bd9Sstevel@tonic-gate NAME(ilmp), filtees); 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate if ((dip->di_info = (void *)expand_paths(ilmp, 14439aa23310Srie filtees, 0, 0)) == 0) { 14447c478bd9Sstevel@tonic-gate elf_disable_filtee(ilmp, dip); 14457c478bd9Sstevel@tonic-gate return ((Sym *)0); 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* 14517c478bd9Sstevel@tonic-gate * Traverse the filtee list, dlopen()'ing any objects specified and 14527c478bd9Sstevel@tonic-gate * using their group handle to lookup the symbol. 14537c478bd9Sstevel@tonic-gate */ 14547c478bd9Sstevel@tonic-gate for (any = 0, pnpp = (Pnode **)&(dip->di_info), pnp = *pnpp; pnp; 14559a411307Srie pnpp = &pnp->p_next, pnp = *pnpp) { 14567c478bd9Sstevel@tonic-gate int mode; 14577c478bd9Sstevel@tonic-gate Grp_hdl *ghp; 14587c478bd9Sstevel@tonic-gate Rt_map *nlmp = 0; 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate if (pnp->p_len == 0) 14617c478bd9Sstevel@tonic-gate continue; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate /* 14647c478bd9Sstevel@tonic-gate * Establish the mode of the filtee from the filter. As filtees 14657c478bd9Sstevel@tonic-gate * are loaded via a dlopen(), make sure that RTLD_GROUP is set 14667c478bd9Sstevel@tonic-gate * and the filtees aren't global. It would be nice to have 14677c478bd9Sstevel@tonic-gate * RTLD_FIRST used here also, but as filters got out long before 14687c478bd9Sstevel@tonic-gate * RTLD_FIRST was introduced it's a little too late now. 14697c478bd9Sstevel@tonic-gate */ 14707c478bd9Sstevel@tonic-gate mode = MODE(ilmp) | RTLD_GROUP; 14717c478bd9Sstevel@tonic-gate mode &= ~RTLD_GLOBAL; 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * Insure that any auxiliary filter can locate symbols from its 14757c478bd9Sstevel@tonic-gate * caller. 14767c478bd9Sstevel@tonic-gate */ 14777c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_AUXFLTR) 14787c478bd9Sstevel@tonic-gate mode |= RTLD_PARENT; 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate /* 14817c478bd9Sstevel@tonic-gate * Process any hardware capability directory. Establish a new 14827c478bd9Sstevel@tonic-gate * link-map control list from which to analyze any newly added 148324a6229eSrie * objects. 14847c478bd9Sstevel@tonic-gate */ 14857c478bd9Sstevel@tonic-gate if ((pnp->p_info == 0) && (pnp->p_orig & PN_TKN_HWCAP)) { 148611a2bb38Srie Lm_cntl *lmc; 148711a2bb38Srie Aliste lmco; 148811a2bb38Srie 148924a6229eSrie if (FLAGS(lml->lm_head) & FLG_RT_RELOCED) { 1490cce0e03bSab if ((lmc = alist_append(&lml->lm_lists, 0, 149124a6229eSrie sizeof (Lm_cntl), AL_CNT_LMLISTS)) == 0) 149224a6229eSrie return ((Sym *)0); 14937c478bd9Sstevel@tonic-gate lmco = (Aliste)((char *)lmc - 14947c478bd9Sstevel@tonic-gate (char *)lml->lm_lists); 149524a6229eSrie } else { 149624a6229eSrie lmc = 0; 1497cce0e03bSab lmco = ALIST_OFF_DATA; 149824a6229eSrie } 14997c478bd9Sstevel@tonic-gate 150002ca3e02Srie pnp = hwcap_filtees(pnpp, lmco, lmc, dip, ilmp, filtees, 15019aa23310Srie mode, (FLG_RT_HANDLE | FLG_RT_HWCAP), in_nfavl); 150211a2bb38Srie 150311a2bb38Srie /* 150411a2bb38Srie * Now that any hardware capability objects have been 150511a2bb38Srie * processed, remove any link-map control list. 150611a2bb38Srie */ 150702ca3e02Srie if (lmc) 150811a2bb38Srie remove_cntl(lml, lmco); 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate if (pnp->p_len == 0) 15127c478bd9Sstevel@tonic-gate continue; 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate * Process an individual filtee. 15167c478bd9Sstevel@tonic-gate */ 15177c478bd9Sstevel@tonic-gate if (pnp->p_info == 0) { 15187c478bd9Sstevel@tonic-gate const char *filtee = pnp->p_name; 15197c478bd9Sstevel@tonic-gate int audit = 0; 15207c478bd9Sstevel@tonic-gate 15215aefb655Srie DBG_CALL(Dbg_file_filtee(lml, NAME(ilmp), filtee, 0)); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate ghp = 0; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate /* 15267c478bd9Sstevel@tonic-gate * Determine if the reference link map is already 15277c478bd9Sstevel@tonic-gate * loaded. As an optimization compare the filtee with 15287c478bd9Sstevel@tonic-gate * our interpretor. The most common filter is 15297c478bd9Sstevel@tonic-gate * libdl.so.1, which is a filter on ld.so.1. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate #if defined(_ELF64) 15327c478bd9Sstevel@tonic-gate if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD_64)) == 0) { 15337c478bd9Sstevel@tonic-gate #else 15347c478bd9Sstevel@tonic-gate if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD)) == 0) { 15357c478bd9Sstevel@tonic-gate #endif 15367c478bd9Sstevel@tonic-gate /* 15378af2c5b9Srie * Create an association between ld.so.1 and the 15388af2c5b9Srie * filter. As an optimization, a handle for 15398af2c5b9Srie * ld.so.1 itself (required for the dlopen() 15408af2c5b9Srie * family filtering mechanism) shouldn't search 15418af2c5b9Srie * any dependencies of ld.so.1. Omitting 15428af2c5b9Srie * GPD_ADDEPS prevents the addition of any 15438af2c5b9Srie * ld.so.1 dependencies to this handle. 15447c478bd9Sstevel@tonic-gate */ 15457c478bd9Sstevel@tonic-gate nlmp = lml_rtld.lm_head; 15467c478bd9Sstevel@tonic-gate if ((ghp = hdl_create(&lml_rtld, nlmp, ilmp, 15478af2c5b9Srie (GPH_LDSO | GPH_FIRST | GPH_FILTEE), 15488af2c5b9Srie (GPD_DLSYM | GPD_RELOC), GPD_PARENT)) == 0) 15497c478bd9Sstevel@tonic-gate nlmp = 0; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* 15527c478bd9Sstevel@tonic-gate * Establish the filter handle to prevent any 15537c478bd9Sstevel@tonic-gate * recursion. 15547c478bd9Sstevel@tonic-gate */ 15557c478bd9Sstevel@tonic-gate if (nlmp && ghp) 15567c478bd9Sstevel@tonic-gate pnp->p_info = (void *)ghp; 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate /* 15597c478bd9Sstevel@tonic-gate * Audit the filter/filtee established. Ignore 15607c478bd9Sstevel@tonic-gate * any return from the auditor, as we can't 15617c478bd9Sstevel@tonic-gate * allow ignore filtering to ld.so.1, otherwise 15627c478bd9Sstevel@tonic-gate * nothing is going to work. 15637c478bd9Sstevel@tonic-gate */ 156402ca3e02Srie if (nlmp && ((lml->lm_tflags | FLAGS1(ilmp)) & 156502ca3e02Srie LML_TFLG_AUD_OBJFILTER)) 15667c478bd9Sstevel@tonic-gate (void) audit_objfilter(ilmp, filtees, 15677c478bd9Sstevel@tonic-gate nlmp, 0); 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate } else { 15707c478bd9Sstevel@tonic-gate Rej_desc rej = { 0 }; 157111a2bb38Srie Lm_cntl *lmc; 157211a2bb38Srie Aliste lmco; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Establish a new link-map control list from 15767c478bd9Sstevel@tonic-gate * which to analyze any newly added objects. 15777c478bd9Sstevel@tonic-gate */ 157824a6229eSrie if (FLAGS(lml->lm_head) & FLG_RT_RELOCED) { 157924a6229eSrie if ((lmc = 1580cce0e03bSab alist_append(&lml->lm_lists, 0, 158124a6229eSrie sizeof (Lm_cntl), 158224a6229eSrie AL_CNT_LMLISTS)) == 0) 158324a6229eSrie return ((Sym *)0); 15847c478bd9Sstevel@tonic-gate lmco = (Aliste)((char *)lmc - 15857c478bd9Sstevel@tonic-gate (char *)lml->lm_lists); 158624a6229eSrie } else { 158724a6229eSrie lmc = 0; 1588cce0e03bSab lmco = ALIST_OFF_DATA; 158924a6229eSrie } 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate /* 15927247f888Srie * Load the filtee. Note, an auditor can 15937247f888Srie * provide an alternative name. 15947c478bd9Sstevel@tonic-gate */ 15957247f888Srie if ((nlmp = load_path(lml, lmco, &(pnp->p_name), 15967247f888Srie ilmp, mode, FLG_RT_HANDLE, &ghp, 0, 15979aa23310Srie &rej, in_nfavl)) == 0) { 15987c478bd9Sstevel@tonic-gate file_notfound(LIST(ilmp), filtee, ilmp, 15997c478bd9Sstevel@tonic-gate FLG_RT_HANDLE, &rej); 16007c478bd9Sstevel@tonic-gate remove_rej(&rej); 16017c478bd9Sstevel@tonic-gate } 16027247f888Srie filtee = pnp->p_name; 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Establish the filter handle to prevent any 16067c478bd9Sstevel@tonic-gate * recursion. 16077c478bd9Sstevel@tonic-gate */ 16087c478bd9Sstevel@tonic-gate if (nlmp && ghp) { 16097c478bd9Sstevel@tonic-gate ghp->gh_flags |= GPH_FILTEE; 16107c478bd9Sstevel@tonic-gate pnp->p_info = (void *)ghp; 16119aa23310Srie 16129aa23310Srie FLAGS1(nlmp) |= FL1_RT_USED; 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * Audit the filter/filtee established. A 16177c478bd9Sstevel@tonic-gate * return of 0 indicates the auditor wishes to 16187c478bd9Sstevel@tonic-gate * ignore this filtee. 16197c478bd9Sstevel@tonic-gate */ 16207c478bd9Sstevel@tonic-gate if (nlmp && ((lml->lm_tflags | FLAGS1(ilmp)) & 16217c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJFILTER)) { 16227c478bd9Sstevel@tonic-gate if (audit_objfilter(ilmp, filtees, 16237c478bd9Sstevel@tonic-gate nlmp, 0) == 0) { 16247c478bd9Sstevel@tonic-gate audit = 1; 16257c478bd9Sstevel@tonic-gate nlmp = 0; 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate /* 16307c478bd9Sstevel@tonic-gate * Finish processing the objects associated with 16317c478bd9Sstevel@tonic-gate * this request. Create an association between 16327c478bd9Sstevel@tonic-gate * this object and the originating filter to 16337c478bd9Sstevel@tonic-gate * provide sufficient information to tear down 16347c478bd9Sstevel@tonic-gate * this filtee if necessary. 16357c478bd9Sstevel@tonic-gate */ 16369aa23310Srie if (nlmp && ghp && ((analyze_lmc(lml, lmco, 16379aa23310Srie nlmp, in_nfavl) == 0) || (relocate_lmc(lml, 16389aa23310Srie lmco, ilmp, nlmp, in_nfavl) == 0))) 16397c478bd9Sstevel@tonic-gate nlmp = 0; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate /* 16427c478bd9Sstevel@tonic-gate * If the filtee has been successfully 164302ca3e02Srie * processed, then create an association 164402ca3e02Srie * between the filter and filtee. This 164502ca3e02Srie * association provides sufficient information 164602ca3e02Srie * to tear down the filter and filtee if 164702ca3e02Srie * necessary. 16487c478bd9Sstevel@tonic-gate */ 16498af2c5b9Srie DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); 165002ca3e02Srie if (nlmp && ghp && 16517c478bd9Sstevel@tonic-gate (hdl_add(ghp, ilmp, GPD_FILTER) == 0)) 16527c478bd9Sstevel@tonic-gate nlmp = 0; 165311a2bb38Srie 165411a2bb38Srie /* 165502ca3e02Srie * If this filtee loading has failed, and we've 165602ca3e02Srie * created a new link-map control list to which 165702ca3e02Srie * this request has added objects, then remove 165802ca3e02Srie * all the objects that have been associated to 165902ca3e02Srie * this request. 166011a2bb38Srie */ 166102ca3e02Srie if ((nlmp == 0) && lmc && lmc->lc_head) 166202ca3e02Srie remove_lmc(lml, clmp, lmc, lmco, name); 166302ca3e02Srie 166402ca3e02Srie /* 166502ca3e02Srie * Remove any link-map control list that was 166602ca3e02Srie * created. 166702ca3e02Srie */ 166802ca3e02Srie if (lmc) 166911a2bb38Srie remove_cntl(lml, lmco); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * Generate a diagnostic if the filtee couldn't be 16747c478bd9Sstevel@tonic-gate * loaded, null out the pnode entry, and continue 16757c478bd9Sstevel@tonic-gate * the search. Otherwise, retain this group handle 16767c478bd9Sstevel@tonic-gate * for future symbol searches. 16777c478bd9Sstevel@tonic-gate */ 16787c478bd9Sstevel@tonic-gate if (nlmp == 0) { 16795aefb655Srie DBG_CALL(Dbg_file_filtee(lml, 0, filtee, 16805aefb655Srie audit)); 16817c478bd9Sstevel@tonic-gate 168202ca3e02Srie pnp->p_info = 0; 16837c478bd9Sstevel@tonic-gate pnp->p_len = 0; 16847c478bd9Sstevel@tonic-gate continue; 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate ghp = (Grp_hdl *)pnp->p_info; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate /* 16917c478bd9Sstevel@tonic-gate * If we're just here to trigger filtee loading skip the symbol 16927c478bd9Sstevel@tonic-gate * lookup so we'll continue looking for additional filtees. 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate if (name) { 16957c478bd9Sstevel@tonic-gate Grp_desc *gdp; 16967c478bd9Sstevel@tonic-gate Sym *sym = 0; 1697cce0e03bSab Aliste idx; 16987c478bd9Sstevel@tonic-gate Slookup sl = *slp; 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate sl.sl_flags |= LKUP_FIRST; 17017c478bd9Sstevel@tonic-gate any++; 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate /* 17047c478bd9Sstevel@tonic-gate * Look for the symbol in the handles dependencies. 17057c478bd9Sstevel@tonic-gate */ 1706cce0e03bSab for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 1707efb9e8b8Srie if ((gdp->gd_flags & GPD_DLSYM) == 0) 17087c478bd9Sstevel@tonic-gate continue; 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate * If our parent is a dependency don't look at 17127c478bd9Sstevel@tonic-gate * it (otherwise we are in a recursive loop). 17137c478bd9Sstevel@tonic-gate * This situation can occur with auxiliary 17147c478bd9Sstevel@tonic-gate * filters if the filtee has a dependency on the 17157c478bd9Sstevel@tonic-gate * filter. This dependency isn't necessary as 17167c478bd9Sstevel@tonic-gate * auxiliary filters are opened RTLD_PARENT, but 17177c478bd9Sstevel@tonic-gate * users may still unknowingly add an explicit 17187c478bd9Sstevel@tonic-gate * dependency to the parent. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate if ((sl.sl_imap = gdp->gd_depend) == ilmp) 17217c478bd9Sstevel@tonic-gate continue; 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate if (((sym = SYMINTP(sl.sl_imap)(&sl, dlmp, 172476396fccSrie binfo, in_nfavl)) != 0) || 17257c478bd9Sstevel@tonic-gate (ghp->gh_flags & GPH_FIRST)) 17267c478bd9Sstevel@tonic-gate break; 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate /* 173002ca3e02Srie * If a symbol has been found, indicate the binding 173102ca3e02Srie * and return the symbol. 17327c478bd9Sstevel@tonic-gate */ 17337c478bd9Sstevel@tonic-gate if (sym) { 17347c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_FILTEE; 17357c478bd9Sstevel@tonic-gate return (sym); 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * If this object is tagged to terminate filtee processing we're 17417c478bd9Sstevel@tonic-gate * done. 17427c478bd9Sstevel@tonic-gate */ 17435aefb655Srie if (FLAGS1(ghp->gh_ownlmp) & FL1_RT_ENDFILTE) 17447c478bd9Sstevel@tonic-gate break; 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate /* 17487c478bd9Sstevel@tonic-gate * If we're just here to trigger filtee loading then we're done. 17497c478bd9Sstevel@tonic-gate */ 17507c478bd9Sstevel@tonic-gate if (name == 0) 17517c478bd9Sstevel@tonic-gate return ((Sym *)0); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * If no filtees have been found for a filter, clean up any Pnode 17557c478bd9Sstevel@tonic-gate * structures and disable their search completely. For auxiliary 17567c478bd9Sstevel@tonic-gate * filters we can reselect the symbol search function so that we never 17577c478bd9Sstevel@tonic-gate * enter this routine again for this object. For standard filters we 17587c478bd9Sstevel@tonic-gate * use the null symbol routine. 17597c478bd9Sstevel@tonic-gate */ 17607c478bd9Sstevel@tonic-gate if (any == 0) { 17617c478bd9Sstevel@tonic-gate remove_pnode((Pnode *)dip->di_info); 17627c478bd9Sstevel@tonic-gate elf_disable_filtee(ilmp, dip); 17637c478bd9Sstevel@tonic-gate return ((Sym *)0); 17647c478bd9Sstevel@tonic-gate } 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate return ((Sym *)0); 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate /* 17707c478bd9Sstevel@tonic-gate * Focal point for disabling error messages for auxiliary filters. As an 17717c478bd9Sstevel@tonic-gate * auxiliary filter allows for filtee use, but provides a fallback should a 17727c478bd9Sstevel@tonic-gate * filtee not exist (or fail to load), any errors generated as a consequence of 17737c478bd9Sstevel@tonic-gate * trying to load the filtees are typically suppressed. Setting RT_FL_SILENCERR 17747c478bd9Sstevel@tonic-gate * suppresses errors generated by eprint(), but insures a debug diagnostic is 17757c478bd9Sstevel@tonic-gate * produced. ldd(1) employs printf(), and here, the selection of whether to 17767c478bd9Sstevel@tonic-gate * print a diagnostic in regards to auxiliary filters is a little more complex. 17777c478bd9Sstevel@tonic-gate * 17787c478bd9Sstevel@tonic-gate * . The determination of whether to produce an ldd message, or a fatal 17797c478bd9Sstevel@tonic-gate * error message is driven by LML_FLG_TRC_ENABLE. 17807c478bd9Sstevel@tonic-gate * . More detailed ldd messages may also be driven off of LML_FLG_TRC_WARN, 17817c478bd9Sstevel@tonic-gate * (ldd -d/-r), LML_FLG_TRC_VERBOSE (ldd -v), LML_FLG_TRC_SEARCH (ldd -s), 17827c478bd9Sstevel@tonic-gate * and LML_FLG_TRC_UNREF/LML_FLG_TRC_UNUSED (ldd -U/-u). 17837c478bd9Sstevel@tonic-gate * 17847c478bd9Sstevel@tonic-gate * . If the calling object is lddstub, then several classes of message are 17857c478bd9Sstevel@tonic-gate * suppressed. The user isn't trying to diagnose lddstub, this is simply 17867c478bd9Sstevel@tonic-gate * a stub executable employed to preload a user specified library against. 17877c478bd9Sstevel@tonic-gate * 17887c478bd9Sstevel@tonic-gate * . If RT_FL_SILENCERR is in effect then any generic ldd() messages should 17897c478bd9Sstevel@tonic-gate * be suppressed. All detailed ldd messages should still be produced. 17907c478bd9Sstevel@tonic-gate */ 17917c478bd9Sstevel@tonic-gate Sym * 17929aa23310Srie elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, 17939aa23310Srie int *in_nfavl) 17947c478bd9Sstevel@tonic-gate { 17957c478bd9Sstevel@tonic-gate Sym *sym; 17967c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(slp->sl_imap)[ndx]; 17977c478bd9Sstevel@tonic-gate int silent = 0; 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate /* 18007c478bd9Sstevel@tonic-gate * Make sure this entry is still acting as a filter. We may have tried 18017c478bd9Sstevel@tonic-gate * to process this previously, and disabled it if the filtee couldn't 18027c478bd9Sstevel@tonic-gate * be processed. However, other entries may provide different filtees 18037c478bd9Sstevel@tonic-gate * that are yet to be completed. 18047c478bd9Sstevel@tonic-gate */ 18057c478bd9Sstevel@tonic-gate if (dip->di_flags == 0) 18067c478bd9Sstevel@tonic-gate return ((Sym *)0); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate /* 18097c478bd9Sstevel@tonic-gate * Indicate whether an error message is required should this filtee not 18107c478bd9Sstevel@tonic-gate * be found, based on the type of filter. 18117c478bd9Sstevel@tonic-gate */ 18127c478bd9Sstevel@tonic-gate if ((dip->di_flags & FLG_DI_AUXFLTR) && 18137c478bd9Sstevel@tonic-gate ((rtld_flags & (RT_FL_WARNFLTR | RT_FL_SILENCERR)) == 0)) { 18147c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_SILENCERR; 18157c478bd9Sstevel@tonic-gate silent = 1; 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate 18189aa23310Srie sym = _elf_lookup_filtee(slp, dlmp, binfo, ndx, in_nfavl); 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate if (silent) 18217c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_SILENCERR; 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate return (sym); 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * Compute the elf hash value (as defined in the ELF access library). 18287c478bd9Sstevel@tonic-gate * The form of the hash table is: 18297c478bd9Sstevel@tonic-gate * 18307c478bd9Sstevel@tonic-gate * |--------------| 18317c478bd9Sstevel@tonic-gate * | # of buckets | 18327c478bd9Sstevel@tonic-gate * |--------------| 18337c478bd9Sstevel@tonic-gate * | # of chains | 18347c478bd9Sstevel@tonic-gate * |--------------| 18357c478bd9Sstevel@tonic-gate * | bucket[] | 18367c478bd9Sstevel@tonic-gate * |--------------| 18377c478bd9Sstevel@tonic-gate * | chain[] | 18387c478bd9Sstevel@tonic-gate * |--------------| 18397c478bd9Sstevel@tonic-gate */ 18407c478bd9Sstevel@tonic-gate ulong_t 18417c478bd9Sstevel@tonic-gate elf_hash(const char *name) 18427c478bd9Sstevel@tonic-gate { 18437c478bd9Sstevel@tonic-gate uint_t hval = 0; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate while (*name) { 18467c478bd9Sstevel@tonic-gate uint_t g; 18477c478bd9Sstevel@tonic-gate hval = (hval << 4) + *name++; 18487c478bd9Sstevel@tonic-gate if ((g = (hval & 0xf0000000)) != 0) 18497c478bd9Sstevel@tonic-gate hval ^= g >> 24; 18507c478bd9Sstevel@tonic-gate hval &= ~g; 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate return ((ulong_t)hval); 18537c478bd9Sstevel@tonic-gate } 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate /* 18567c478bd9Sstevel@tonic-gate * If flag argument has LKUP_SPEC set, we treat undefined symbols of type 18577c478bd9Sstevel@tonic-gate * function specially in the executable - if they have a value, even though 18587c478bd9Sstevel@tonic-gate * undefined, we use that value. This allows us to associate all references 18597c478bd9Sstevel@tonic-gate * to a function's address to a single place in the process: the plt entry 18607c478bd9Sstevel@tonic-gate * for that function in the executable. Calls to lookup from plt binding 18617c478bd9Sstevel@tonic-gate * routines do NOT set LKUP_SPEC in the flag. 18627c478bd9Sstevel@tonic-gate */ 18637c478bd9Sstevel@tonic-gate Sym * 18649aa23310Srie elf_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 18657c478bd9Sstevel@tonic-gate { 18667c478bd9Sstevel@tonic-gate const char *name = slp->sl_name; 18677c478bd9Sstevel@tonic-gate Rt_map *ilmp = slp->sl_imap; 18687c478bd9Sstevel@tonic-gate ulong_t hash = slp->sl_hash; 18697c478bd9Sstevel@tonic-gate uint_t ndx, htmp, buckets, *chainptr; 18707c478bd9Sstevel@tonic-gate Sym *sym, *symtabptr; 18717c478bd9Sstevel@tonic-gate char *strtabptr, *strtabname; 18727c478bd9Sstevel@tonic-gate uint_t flags1; 18737c478bd9Sstevel@tonic-gate Syminfo *sip; 18747c478bd9Sstevel@tonic-gate 1875660acd81Srie /* 1876660acd81Srie * If we're only here to establish a symbols index, skip the diagnostic 1877660acd81Srie * used to trace a symbol search. 1878660acd81Srie */ 18795aefb655Srie if ((slp->sl_flags & LKUP_SYMNDX) == 0) 18805aefb655Srie DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_ELF))); 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate if (HASH(ilmp) == 0) 18837c478bd9Sstevel@tonic-gate return ((Sym *)0); 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate buckets = HASH(ilmp)[0]; 18867c478bd9Sstevel@tonic-gate /* LINTED */ 18877c478bd9Sstevel@tonic-gate htmp = (uint_t)hash % buckets; 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * Get the first symbol on hash chain and initialize the string 18917c478bd9Sstevel@tonic-gate * and symbol table pointers. 18927c478bd9Sstevel@tonic-gate */ 18937c478bd9Sstevel@tonic-gate if ((ndx = HASH(ilmp)[htmp + 2]) == 0) 18947c478bd9Sstevel@tonic-gate return ((Sym *)0); 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate chainptr = HASH(ilmp) + 2 + buckets; 18977c478bd9Sstevel@tonic-gate strtabptr = STRTAB(ilmp); 18987c478bd9Sstevel@tonic-gate symtabptr = SYMTAB(ilmp); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate while (ndx) { 19017c478bd9Sstevel@tonic-gate sym = symtabptr + ndx; 19027c478bd9Sstevel@tonic-gate strtabname = strtabptr + sym->st_name; 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate /* 19057c478bd9Sstevel@tonic-gate * Compare the symbol found with the name required. If the 19067c478bd9Sstevel@tonic-gate * names don't match continue with the next hash entry. 19077c478bd9Sstevel@tonic-gate */ 19087c478bd9Sstevel@tonic-gate if ((*strtabname++ != *name) || strcmp(strtabname, &name[1])) { 19097c478bd9Sstevel@tonic-gate if ((ndx = chainptr[ndx]) != 0) 19107c478bd9Sstevel@tonic-gate continue; 19117c478bd9Sstevel@tonic-gate return ((Sym *)0); 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate 19143b41b08bSab /* 1915d840867fSab * The Solaris ld does not put DT_VERSYM in the dynamic 1916d840867fSab * section, but the GNU ld does. The GNU runtime linker 1917d840867fSab * interprets the top bit of the 16-bit Versym value 1918d840867fSab * (0x8000) as the "hidden" bit. If this bit is set, 1919d840867fSab * the linker is supposed to act as if that symbol does 1920d840867fSab * not exist. The hidden bit supports their versioning 1921d840867fSab * scheme, which allows multiple incompatible functions 1922d840867fSab * with the same name to exist at different versions 1923d840867fSab * within an object. The Solaris linker does not support this 1924d840867fSab * mechanism, or the model of interface evolution that 1925d840867fSab * it allows, but we honor the hidden bit in GNU ld 1926d840867fSab * produced objects in order to interoperate with them. 19273b41b08bSab */ 1928d840867fSab if ((VERSYM(ilmp) != NULL) && 1929d840867fSab ((VERSYM(ilmp)[ndx] & 0x8000) != 0)) { 1930d840867fSab DBG_CALL(Dbg_syms_ignore_gnuver(ilmp, name, 19313b41b08bSab ndx, VERSYM(ilmp)[ndx])); 19323b41b08bSab if ((ndx = chainptr[ndx]) != 0) 19333b41b08bSab continue; 19343b41b08bSab return ((Sym *)0); 19353b41b08bSab } 19363b41b08bSab 1937660acd81Srie /* 1938660acd81Srie * If we're only here to establish a symbols index, we're done. 1939660acd81Srie */ 1940660acd81Srie if (slp->sl_flags & LKUP_SYMNDX) 1941660acd81Srie return (sym); 1942660acd81Srie 19437c478bd9Sstevel@tonic-gate /* 19447c478bd9Sstevel@tonic-gate * If we find a match and the symbol is defined, return the 19457c478bd9Sstevel@tonic-gate * symbol pointer and the link map in which it was found. 19467c478bd9Sstevel@tonic-gate */ 19477c478bd9Sstevel@tonic-gate if (sym->st_shndx != SHN_UNDEF) { 19487c478bd9Sstevel@tonic-gate *dlmp = ilmp; 19497c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_FOUND; 19509a411307Srie if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) || 19519a411307Srie ((FLAGS(ilmp) & FLG_RT_SYMINTPO) && 19529a411307Srie is_sym_interposer(ilmp, sym))) 19537c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_INTERPOSE; 19547c478bd9Sstevel@tonic-gate break; 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate /* 19577c478bd9Sstevel@tonic-gate * If we find a match and the symbol is undefined, the 19587c478bd9Sstevel@tonic-gate * symbol type is a function, and the value of the symbol 19597c478bd9Sstevel@tonic-gate * is non zero, then this is a special case. This allows 19607c478bd9Sstevel@tonic-gate * the resolution of a function address to the plt[] entry. 19617c478bd9Sstevel@tonic-gate * See SPARC ABI, Dynamic Linking, Function Addresses for 19627c478bd9Sstevel@tonic-gate * more details. 19637c478bd9Sstevel@tonic-gate */ 1964660acd81Srie } else if ((slp->sl_flags & LKUP_SPEC) && 19657c478bd9Sstevel@tonic-gate (FLAGS(ilmp) & FLG_RT_ISMAIN) && (sym->st_value != 0) && 19667c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(sym->st_info) == STT_FUNC)) { 19677c478bd9Sstevel@tonic-gate *dlmp = ilmp; 19687c478bd9Sstevel@tonic-gate *binfo |= (DBG_BINFO_FOUND | DBG_BINFO_PLTADDR); 19699a411307Srie if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) || 19709a411307Srie ((FLAGS(ilmp) & FLG_RT_SYMINTPO) && 19719a411307Srie is_sym_interposer(ilmp, sym))) 19727c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_INTERPOSE; 19737c478bd9Sstevel@tonic-gate return (sym); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate /* 19777c478bd9Sstevel@tonic-gate * Undefined symbol. 19787c478bd9Sstevel@tonic-gate */ 19797c478bd9Sstevel@tonic-gate return ((Sym *)0); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate /* 19837c478bd9Sstevel@tonic-gate * We've found a match. Determine if the defining object contains 19847c478bd9Sstevel@tonic-gate * symbol binding information. 19857c478bd9Sstevel@tonic-gate */ 19867c478bd9Sstevel@tonic-gate if ((sip = SYMINFO(ilmp)) != 0) 19879039eeafSab sip += ndx; 19887c478bd9Sstevel@tonic-gate 198960758829Srie /* 199060758829Srie * If this definition is a singleton, and we haven't followed a default 199160758829Srie * symbol search knowing that we're looking for a singleton (presumably 199260758829Srie * because the symbol definition has been changed since the referring 199360758829Srie * object was built), then reject this binding so that the caller can 199460758829Srie * fall back to a standard symbol search. 199560758829Srie */ 199660758829Srie if ((ELF_ST_VISIBILITY(sym->st_other) == STV_SINGLETON) && 199760758829Srie (((slp->sl_flags & LKUP_STANDARD) == 0) || 199860758829Srie (((slp->sl_flags & LKUP_SINGLETON) == 0) && 199960758829Srie (LIST(ilmp)->lm_flags & LML_FLG_GROUPSEXIST)))) { 200060758829Srie DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 200160758829Srie DBG_BNDREJ_SINGLE)); 200260758829Srie *binfo |= BINFO_REJSINGLE; 200360758829Srie *binfo &= ~DBG_BINFO_MSK; 200460758829Srie return ((Sym *)0); 200560758829Srie } 200660758829Srie 20077c478bd9Sstevel@tonic-gate /* 20087c478bd9Sstevel@tonic-gate * If this is a direct binding request, but the symbol definition has 20097c478bd9Sstevel@tonic-gate * disabled directly binding to it (presumably because the symbol 20107c478bd9Sstevel@tonic-gate * definition has been changed since the referring object was built), 20117c478bd9Sstevel@tonic-gate * indicate this failure so that the caller can fall back to a standard 201260758829Srie * symbol search. 20137c478bd9Sstevel@tonic-gate */ 20147c478bd9Sstevel@tonic-gate if (sip && (slp->sl_flags & LKUP_DIRECT) && 20157c478bd9Sstevel@tonic-gate (sip->si_flags & SYMINFO_FLG_NOEXTDIRECT)) { 201660758829Srie DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 201760758829Srie DBG_BNDREJ_NODIR)); 201860758829Srie *binfo |= BINFO_REJDIRECT; 20197c478bd9Sstevel@tonic-gate *binfo &= ~DBG_BINFO_MSK; 20207c478bd9Sstevel@tonic-gate return ((Sym *)0); 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate /* 20247c478bd9Sstevel@tonic-gate * Determine whether this object is acting as a filter. 20257c478bd9Sstevel@tonic-gate */ 20267c478bd9Sstevel@tonic-gate if (((flags1 = FLAGS1(ilmp)) & MSK_RT_FILTER) == 0) 20277c478bd9Sstevel@tonic-gate return (sym); 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate /* 20307c478bd9Sstevel@tonic-gate * Determine if this object offers per-symbol filtering, and if so, 20317c478bd9Sstevel@tonic-gate * whether this symbol references a filtee. 20327c478bd9Sstevel@tonic-gate */ 20337c478bd9Sstevel@tonic-gate if (sip && (flags1 & (FL1_RT_SYMSFLTR | FL1_RT_SYMAFLTR))) { 20347c478bd9Sstevel@tonic-gate /* 20357c478bd9Sstevel@tonic-gate * If this is a standard filter reference, and no standard 20367c478bd9Sstevel@tonic-gate * filtees remain to be inspected, we're done. If this is an 20377c478bd9Sstevel@tonic-gate * auxiliary filter reference, and no auxiliary filtees remain, 20387c478bd9Sstevel@tonic-gate * we'll fall through in case any object filtering is available. 20397c478bd9Sstevel@tonic-gate */ 20407c478bd9Sstevel@tonic-gate if ((sip->si_flags & SYMINFO_FLG_FILTER) && 20417c478bd9Sstevel@tonic-gate (SYMSFLTRCNT(ilmp) == 0)) 20427c478bd9Sstevel@tonic-gate return ((Sym *)0); 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate if ((sip->si_flags & SYMINFO_FLG_FILTER) || 20457c478bd9Sstevel@tonic-gate ((sip->si_flags & SYMINFO_FLG_AUXILIARY) && 20467c478bd9Sstevel@tonic-gate SYMAFLTRCNT(ilmp))) { 204775e7992aSrie Sym *fsym; 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* 20507c478bd9Sstevel@tonic-gate * This symbol has an associated filtee. Lookup the 20517c478bd9Sstevel@tonic-gate * symbol in the filtee, and if it is found return it. 20527c478bd9Sstevel@tonic-gate * If the symbol doesn't exist, and this is a standard 20537c478bd9Sstevel@tonic-gate * filter, return an error, otherwise fall through to 20547c478bd9Sstevel@tonic-gate * catch any object filtering that may be available. 20557c478bd9Sstevel@tonic-gate */ 20567c478bd9Sstevel@tonic-gate if ((fsym = elf_lookup_filtee(slp, dlmp, binfo, 20579aa23310Srie sip->si_boundto, in_nfavl)) != 0) 20587c478bd9Sstevel@tonic-gate return (fsym); 20597c478bd9Sstevel@tonic-gate if (sip->si_flags & SYMINFO_FLG_FILTER) 20607c478bd9Sstevel@tonic-gate return ((Sym *)0); 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate /* 20657c478bd9Sstevel@tonic-gate * Determine if this object provides global filtering. 20667c478bd9Sstevel@tonic-gate */ 20677c478bd9Sstevel@tonic-gate if (flags1 & (FL1_RT_OBJSFLTR | FL1_RT_OBJAFLTR)) { 206875e7992aSrie Sym *fsym; 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate if (OBJFLTRNDX(ilmp) != FLTR_DISABLED) { 20717c478bd9Sstevel@tonic-gate /* 20727c478bd9Sstevel@tonic-gate * This object has an associated filtee. Lookup the 20737c478bd9Sstevel@tonic-gate * symbol in the filtee, and if it is found return it. 20747c478bd9Sstevel@tonic-gate * If the symbol doesn't exist, and this is a standard 20757c478bd9Sstevel@tonic-gate * filter, return and error, otherwise return the symbol 20767c478bd9Sstevel@tonic-gate * within the filter itself. 20777c478bd9Sstevel@tonic-gate */ 20787c478bd9Sstevel@tonic-gate if ((fsym = elf_lookup_filtee(slp, dlmp, binfo, 20799aa23310Srie OBJFLTRNDX(ilmp), in_nfavl)) != 0) 20807c478bd9Sstevel@tonic-gate return (fsym); 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate if (flags1 & FL1_RT_OBJSFLTR) 20847c478bd9Sstevel@tonic-gate return ((Sym *)0); 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate return (sym); 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate /* 20907c478bd9Sstevel@tonic-gate * Create a new Rt_map structure for an ELF object and initialize 20917c478bd9Sstevel@tonic-gate * all values. 20927c478bd9Sstevel@tonic-gate */ 20937c478bd9Sstevel@tonic-gate Rt_map * 20947c478bd9Sstevel@tonic-gate elf_new_lm(Lm_list *lml, const char *pname, const char *oname, Dyn *ld, 20957c478bd9Sstevel@tonic-gate ulong_t addr, ulong_t etext, Aliste lmco, ulong_t msize, ulong_t entry, 20969aa23310Srie ulong_t paddr, ulong_t padimsize, Mmap *mmaps, uint_t mmapcnt, 20979aa23310Srie int *in_nfavl) 20987c478bd9Sstevel@tonic-gate { 20997c478bd9Sstevel@tonic-gate Rt_map *lmp; 21007c478bd9Sstevel@tonic-gate ulong_t base, fltr = 0, audit = 0, cfile = 0, crle = 0; 21017c478bd9Sstevel@tonic-gate Xword rpath = 0; 21027c478bd9Sstevel@tonic-gate Ehdr *ehdr = (Ehdr *)addr; 21037c478bd9Sstevel@tonic-gate 21045aefb655Srie DBG_CALL(Dbg_file_elf(lml, pname, (ulong_t)ld, addr, msize, entry, 21055aefb655Srie lml->lm_lmidstr, lmco)); 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate /* 21087c478bd9Sstevel@tonic-gate * Allocate space for the link-map and private elf information. Once 21097c478bd9Sstevel@tonic-gate * these are allocated and initialized, we can use remove_so(0, lmp) to 21107c478bd9Sstevel@tonic-gate * tear down the link-map should any failures occur. 21117c478bd9Sstevel@tonic-gate */ 21127c478bd9Sstevel@tonic-gate if ((lmp = calloc(sizeof (Rt_map), 1)) == 0) 21137c478bd9Sstevel@tonic-gate return (0); 21147c478bd9Sstevel@tonic-gate if ((ELFPRV(lmp) = calloc(sizeof (Rt_elfp), 1)) == 0) { 21157c478bd9Sstevel@tonic-gate free(lmp); 21167c478bd9Sstevel@tonic-gate return (0); 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate /* 21207c478bd9Sstevel@tonic-gate * All fields not filled in were set to 0 by calloc. 21217c478bd9Sstevel@tonic-gate */ 21227c478bd9Sstevel@tonic-gate ORIGNAME(lmp) = PATHNAME(lmp) = NAME(lmp) = (char *)pname; 21237c478bd9Sstevel@tonic-gate DYN(lmp) = ld; 21247c478bd9Sstevel@tonic-gate ADDR(lmp) = addr; 21257c478bd9Sstevel@tonic-gate MSIZE(lmp) = msize; 21267c478bd9Sstevel@tonic-gate ENTRY(lmp) = (Addr)entry; 21277c478bd9Sstevel@tonic-gate SYMINTP(lmp) = elf_find_sym; 21287c478bd9Sstevel@tonic-gate ETEXT(lmp) = etext; 21297c478bd9Sstevel@tonic-gate FCT(lmp) = &elf_fct; 21307c478bd9Sstevel@tonic-gate LIST(lmp) = lml; 21317c478bd9Sstevel@tonic-gate PADSTART(lmp) = paddr; 21327c478bd9Sstevel@tonic-gate PADIMLEN(lmp) = padimsize; 21337c478bd9Sstevel@tonic-gate THREADID(lmp) = rt_thr_self(); 21347c478bd9Sstevel@tonic-gate OBJFLTRNDX(lmp) = FLTR_DISABLED; 2135dffec89cSrie SORTVAL(lmp) = -1; 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate MMAPS(lmp) = mmaps; 21387c478bd9Sstevel@tonic-gate MMAPCNT(lmp) = mmapcnt; 21397c478bd9Sstevel@tonic-gate ASSERT(mmapcnt != 0); 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate /* 21427c478bd9Sstevel@tonic-gate * If this is a shared object, add the base address to each address. 21437c478bd9Sstevel@tonic-gate * if this is an executable, use address as is. 21447c478bd9Sstevel@tonic-gate */ 21457c478bd9Sstevel@tonic-gate if (ehdr->e_type == ET_EXEC) { 21467c478bd9Sstevel@tonic-gate base = 0; 21477c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_FIXED; 21487c478bd9Sstevel@tonic-gate } else 21497c478bd9Sstevel@tonic-gate base = addr; 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate /* 21527c478bd9Sstevel@tonic-gate * Fill in rest of the link map entries with information from the file's 21537c478bd9Sstevel@tonic-gate * dynamic structure. 21547c478bd9Sstevel@tonic-gate */ 21557c478bd9Sstevel@tonic-gate if (ld) { 215675e7992aSrie uint_t dynndx = 0; 215710a4fa49Srie Xword pltpadsz = 0; 215810a4fa49Srie Rti_desc *rti; 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate /* CSTYLED */ 216175e7992aSrie for ( ; ld->d_tag != DT_NULL; ++ld, dynndx++) { 21627c478bd9Sstevel@tonic-gate switch ((Xword)ld->d_tag) { 21637c478bd9Sstevel@tonic-gate case DT_SYMTAB: 21647c478bd9Sstevel@tonic-gate SYMTAB(lmp) = (void *)(ld->d_un.d_ptr + base); 21657c478bd9Sstevel@tonic-gate break; 21669039eeafSab case DT_SUNW_SYMTAB: 21679039eeafSab SUNWSYMTAB(lmp) = 21689039eeafSab (void *)(ld->d_un.d_ptr + base); 21699039eeafSab break; 21709039eeafSab case DT_SUNW_SYMSZ: 21719039eeafSab SUNWSYMSZ(lmp) = ld->d_un.d_val; 21729039eeafSab break; 21737c478bd9Sstevel@tonic-gate case DT_STRTAB: 21747c478bd9Sstevel@tonic-gate STRTAB(lmp) = (void *)(ld->d_un.d_ptr + base); 21757c478bd9Sstevel@tonic-gate break; 21767c478bd9Sstevel@tonic-gate case DT_SYMENT: 21777c478bd9Sstevel@tonic-gate SYMENT(lmp) = ld->d_un.d_val; 21787c478bd9Sstevel@tonic-gate break; 21797c478bd9Sstevel@tonic-gate case DT_FEATURE_1: 21807c478bd9Sstevel@tonic-gate ld->d_un.d_val |= DTF_1_PARINIT; 21817c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DTF_1_CONFEXP) 21827c478bd9Sstevel@tonic-gate crle = 1; 21837c478bd9Sstevel@tonic-gate break; 21847c478bd9Sstevel@tonic-gate case DT_MOVESZ: 21857c478bd9Sstevel@tonic-gate MOVESZ(lmp) = ld->d_un.d_val; 21867c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_MOVE; 21877c478bd9Sstevel@tonic-gate break; 21887c478bd9Sstevel@tonic-gate case DT_MOVEENT: 21897c478bd9Sstevel@tonic-gate MOVEENT(lmp) = ld->d_un.d_val; 21907c478bd9Sstevel@tonic-gate break; 21917c478bd9Sstevel@tonic-gate case DT_MOVETAB: 21927c478bd9Sstevel@tonic-gate MOVETAB(lmp) = (void *)(ld->d_un.d_ptr + base); 21937c478bd9Sstevel@tonic-gate break; 21947c478bd9Sstevel@tonic-gate case DT_REL: 21957c478bd9Sstevel@tonic-gate case DT_RELA: 21967c478bd9Sstevel@tonic-gate /* 219775e7992aSrie * At this time, ld.so. can only handle one 219875e7992aSrie * type of relocation per object. 21997c478bd9Sstevel@tonic-gate */ 22007c478bd9Sstevel@tonic-gate REL(lmp) = (void *)(ld->d_un.d_ptr + base); 22017c478bd9Sstevel@tonic-gate break; 22027c478bd9Sstevel@tonic-gate case DT_RELSZ: 22037c478bd9Sstevel@tonic-gate case DT_RELASZ: 22047c478bd9Sstevel@tonic-gate RELSZ(lmp) = ld->d_un.d_val; 22057c478bd9Sstevel@tonic-gate break; 22067c478bd9Sstevel@tonic-gate case DT_RELENT: 22077c478bd9Sstevel@tonic-gate case DT_RELAENT: 22087c478bd9Sstevel@tonic-gate RELENT(lmp) = ld->d_un.d_val; 22097c478bd9Sstevel@tonic-gate break; 22107c478bd9Sstevel@tonic-gate case DT_RELCOUNT: 22117c478bd9Sstevel@tonic-gate case DT_RELACOUNT: 22127c478bd9Sstevel@tonic-gate RELACOUNT(lmp) = (uint_t)ld->d_un.d_val; 22137c478bd9Sstevel@tonic-gate break; 22147c478bd9Sstevel@tonic-gate case DT_TEXTREL: 22157c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_TEXTREL; 22167c478bd9Sstevel@tonic-gate break; 22177c478bd9Sstevel@tonic-gate case DT_HASH: 22187c478bd9Sstevel@tonic-gate HASH(lmp) = (uint_t *)(ld->d_un.d_ptr + base); 22197c478bd9Sstevel@tonic-gate break; 22207c478bd9Sstevel@tonic-gate case DT_PLTGOT: 22217c478bd9Sstevel@tonic-gate PLTGOT(lmp) = (uint_t *)(ld->d_un.d_ptr + base); 22227c478bd9Sstevel@tonic-gate break; 22237c478bd9Sstevel@tonic-gate case DT_PLTRELSZ: 22247c478bd9Sstevel@tonic-gate PLTRELSZ(lmp) = ld->d_un.d_val; 22257c478bd9Sstevel@tonic-gate break; 22267c478bd9Sstevel@tonic-gate case DT_JMPREL: 22277c478bd9Sstevel@tonic-gate JMPREL(lmp) = (void *)(ld->d_un.d_ptr + base); 22287c478bd9Sstevel@tonic-gate break; 22297c478bd9Sstevel@tonic-gate case DT_INIT: 22305b59e4caSab if (ld->d_un.d_ptr != NULL) 22315b59e4caSab INIT(lmp) = 22325b59e4caSab (void (*)())(ld->d_un.d_ptr + base); 22337c478bd9Sstevel@tonic-gate break; 22347c478bd9Sstevel@tonic-gate case DT_FINI: 22355b59e4caSab if (ld->d_un.d_ptr != NULL) 22365b59e4caSab FINI(lmp) = 22375b59e4caSab (void (*)())(ld->d_un.d_ptr + base); 22387c478bd9Sstevel@tonic-gate break; 22397c478bd9Sstevel@tonic-gate case DT_INIT_ARRAY: 22407c478bd9Sstevel@tonic-gate INITARRAY(lmp) = (Addr *)(ld->d_un.d_ptr + 22417c478bd9Sstevel@tonic-gate base); 22427c478bd9Sstevel@tonic-gate break; 22437c478bd9Sstevel@tonic-gate case DT_INIT_ARRAYSZ: 22447c478bd9Sstevel@tonic-gate INITARRAYSZ(lmp) = (uint_t)ld->d_un.d_val; 22457c478bd9Sstevel@tonic-gate break; 22467c478bd9Sstevel@tonic-gate case DT_FINI_ARRAY: 22477c478bd9Sstevel@tonic-gate FINIARRAY(lmp) = (Addr *)(ld->d_un.d_ptr + 22487c478bd9Sstevel@tonic-gate base); 22497c478bd9Sstevel@tonic-gate break; 22507c478bd9Sstevel@tonic-gate case DT_FINI_ARRAYSZ: 22517c478bd9Sstevel@tonic-gate FINIARRAYSZ(lmp) = (uint_t)ld->d_un.d_val; 22527c478bd9Sstevel@tonic-gate break; 22537c478bd9Sstevel@tonic-gate case DT_PREINIT_ARRAY: 22547c478bd9Sstevel@tonic-gate PREINITARRAY(lmp) = (Addr *)(ld->d_un.d_ptr + 22557c478bd9Sstevel@tonic-gate base); 22567c478bd9Sstevel@tonic-gate break; 22577c478bd9Sstevel@tonic-gate case DT_PREINIT_ARRAYSZ: 22587c478bd9Sstevel@tonic-gate PREINITARRAYSZ(lmp) = (uint_t)ld->d_un.d_val; 22597c478bd9Sstevel@tonic-gate break; 22607c478bd9Sstevel@tonic-gate case DT_RPATH: 22617c478bd9Sstevel@tonic-gate case DT_RUNPATH: 22627c478bd9Sstevel@tonic-gate rpath = ld->d_un.d_val; 22637c478bd9Sstevel@tonic-gate break; 22647c478bd9Sstevel@tonic-gate case DT_FILTER: 22657c478bd9Sstevel@tonic-gate fltr = ld->d_un.d_val; 226675e7992aSrie OBJFLTRNDX(lmp) = dynndx; 22677c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_OBJSFLTR; 22687c478bd9Sstevel@tonic-gate break; 22697c478bd9Sstevel@tonic-gate case DT_AUXILIARY: 22707c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUXFLTR)) { 22717c478bd9Sstevel@tonic-gate fltr = ld->d_un.d_val; 227275e7992aSrie OBJFLTRNDX(lmp) = dynndx; 22737c478bd9Sstevel@tonic-gate } 22747c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_OBJAFLTR; 22757c478bd9Sstevel@tonic-gate break; 22767c478bd9Sstevel@tonic-gate case DT_SUNW_FILTER: 22777c478bd9Sstevel@tonic-gate SYMSFLTRCNT(lmp)++; 22787c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMSFLTR; 22797c478bd9Sstevel@tonic-gate break; 22807c478bd9Sstevel@tonic-gate case DT_SUNW_AUXILIARY: 22817c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUXFLTR)) { 22827c478bd9Sstevel@tonic-gate SYMAFLTRCNT(lmp)++; 22837c478bd9Sstevel@tonic-gate } 22847c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMAFLTR; 22857c478bd9Sstevel@tonic-gate break; 22867c478bd9Sstevel@tonic-gate case DT_DEPAUDIT: 22877c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUDIT)) 22887c478bd9Sstevel@tonic-gate audit = ld->d_un.d_val; 22897c478bd9Sstevel@tonic-gate break; 22907c478bd9Sstevel@tonic-gate case DT_CONFIG: 22917c478bd9Sstevel@tonic-gate cfile = ld->d_un.d_val; 22927c478bd9Sstevel@tonic-gate break; 22937c478bd9Sstevel@tonic-gate case DT_DEBUG: 22947c478bd9Sstevel@tonic-gate /* 22957c478bd9Sstevel@tonic-gate * DT_DEBUG entries are only created in 22967c478bd9Sstevel@tonic-gate * dynamic objects that require an interpretor 22977c478bd9Sstevel@tonic-gate * (ie. all dynamic executables and some shared 22987c478bd9Sstevel@tonic-gate * objects), and provide for a hand-shake with 22997c478bd9Sstevel@tonic-gate * debuggers. This entry is initialized to 23007c478bd9Sstevel@tonic-gate * zero by the link-editor. If a debugger has 23017c478bd9Sstevel@tonic-gate * us and updated this entry set the debugger 23027c478bd9Sstevel@tonic-gate * flag, and finish initializing the debugging 23037c478bd9Sstevel@tonic-gate * structure (see setup() also). Switch off any 23047c478bd9Sstevel@tonic-gate * configuration object use as most debuggers 23057c478bd9Sstevel@tonic-gate * can't handle fixed dynamic executables as 23067c478bd9Sstevel@tonic-gate * dependencies, and we can't handle requests 23077c478bd9Sstevel@tonic-gate * like object padding for alternative objects. 23087c478bd9Sstevel@tonic-gate */ 23097c478bd9Sstevel@tonic-gate if (ld->d_un.d_ptr) 23107c478bd9Sstevel@tonic-gate rtld_flags |= 23117c478bd9Sstevel@tonic-gate (RT_FL_DEBUGGER | RT_FL_NOOBJALT); 23127c478bd9Sstevel@tonic-gate ld->d_un.d_ptr = (Addr)&r_debug; 23137c478bd9Sstevel@tonic-gate break; 23147c478bd9Sstevel@tonic-gate case DT_VERNEED: 23157c478bd9Sstevel@tonic-gate VERNEED(lmp) = (Verneed *)(ld->d_un.d_ptr + 23167c478bd9Sstevel@tonic-gate base); 23177c478bd9Sstevel@tonic-gate break; 23187c478bd9Sstevel@tonic-gate case DT_VERNEEDNUM: 23197c478bd9Sstevel@tonic-gate /* LINTED */ 23207c478bd9Sstevel@tonic-gate VERNEEDNUM(lmp) = (int)ld->d_un.d_val; 23217c478bd9Sstevel@tonic-gate break; 23227c478bd9Sstevel@tonic-gate case DT_VERDEF: 23237c478bd9Sstevel@tonic-gate VERDEF(lmp) = (Verdef *)(ld->d_un.d_ptr + base); 23247c478bd9Sstevel@tonic-gate break; 23257c478bd9Sstevel@tonic-gate case DT_VERDEFNUM: 23267c478bd9Sstevel@tonic-gate /* LINTED */ 23277c478bd9Sstevel@tonic-gate VERDEFNUM(lmp) = (int)ld->d_un.d_val; 23287c478bd9Sstevel@tonic-gate break; 23293b41b08bSab case DT_VERSYM: 2330d840867fSab /* 2331d840867fSab * The Solaris ld does not produce DT_VERSYM, 2332d840867fSab * but the GNU ld does, in order to support 2333d840867fSab * their style of versioning, which differs 2334d840867fSab * from ours in some ways, while using the 2335d840867fSab * same data structures. The presence of 2336d840867fSab * DT_VERSYM therefore means that GNU 2337d840867fSab * versioning rules apply to the given file. 2338d840867fSab * If DT_VERSYM is not present, then Solaris 2339d840867fSab * versioning rules apply. 2340d840867fSab */ 23413b41b08bSab VERSYM(lmp) = (Versym *)(ld->d_un.d_ptr + base); 23423b41b08bSab break; 23437c478bd9Sstevel@tonic-gate case DT_BIND_NOW: 2344dffec89cSrie if ((ld->d_un.d_val & DF_BIND_NOW) && 2345dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 23467c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 23477c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate break; 23507c478bd9Sstevel@tonic-gate case DT_FLAGS: 2351aa736cbeSrie FLAGS2(lmp) |= FL2_RT_DTFLAGS; 23527c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_SYMBOLIC) 23537c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMBOLIC; 23547c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_TEXTREL) 23557c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_TEXTREL; 2356dffec89cSrie if ((ld->d_un.d_val & DF_BIND_NOW) && 2357dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 23587c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 23597c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 23607c478bd9Sstevel@tonic-gate } 2361d326b23bSrie /* 2362d326b23bSrie * Capture any static TLS use, and enforce that 2363d326b23bSrie * this object be non-deletable. 2364d326b23bSrie */ 2365d326b23bSrie if (ld->d_un.d_val & DF_STATIC_TLS) { 2366d326b23bSrie FLAGS1(lmp) |= FL1_RT_TLSSTAT; 2367d326b23bSrie MODE(lmp) |= RTLD_NODELETE; 2368d326b23bSrie } 23697c478bd9Sstevel@tonic-gate break; 23707c478bd9Sstevel@tonic-gate case DT_FLAGS_1: 23717c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_DISPRELPND) 23727c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_DISPREL; 23737c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_GROUP) 23747c478bd9Sstevel@tonic-gate FLAGS(lmp) |= 23757c478bd9Sstevel@tonic-gate (FLG_RT_SETGROUP | FLG_RT_HANDLE); 2376dffec89cSrie if ((ld->d_un.d_val & DF_1_NOW) && 2377dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 23787c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 23797c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_NODELETE) 23827c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NODELETE; 23837c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_INITFIRST) 23847c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITFRST; 23857c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_NOOPEN) 23867c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_NOOPEN; 23877c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_LOADFLTR) 23887c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_LOADFLTR; 23897c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_NODUMP) 23907c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_NODUMP; 23917c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_CONFALT) 23927c478bd9Sstevel@tonic-gate crle = 1; 23937c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_DIRECT) 23949a411307Srie FLAGS1(lmp) |= FL1_RT_DIRECT; 23957c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_NODEFLIB) 23967c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_NODEFLIB; 23977c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_ENDFILTEE) 23987c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_ENDFILTE; 23997c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_TRANS) 24007c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_TRANS; 24017c478bd9Sstevel@tonic-gate #ifndef EXPAND_RELATIVE 24027c478bd9Sstevel@tonic-gate if (ld->d_un.d_val & DF_1_ORIGIN) 24037c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_RELATIVE; 24047c478bd9Sstevel@tonic-gate #endif 24057247f888Srie /* 24067247f888Srie * Global auditing is only meaningful when 24077247f888Srie * specified by the initiating object of the 24087247f888Srie * process - typically the dynamic executable. 24097247f888Srie * If this is the initiaiting object, its link- 24107247f888Srie * map will not yet have been added to the 24117247f888Srie * link-map list, and consequently the link-map 24127247f888Srie * list is empty. (see setup()). 24137247f888Srie */ 24147247f888Srie if (ld->d_un.d_val & DF_1_GLOBAUDIT) { 24157247f888Srie if (lml_main.lm_head == 0) 24167247f888Srie FLAGS1(lmp) |= FL1_RT_GLOBAUD; 24177247f888Srie else 24187247f888Srie DBG_CALL(Dbg_audit_ignore(lmp)); 24197247f888Srie } 24207247f888Srie 24217c478bd9Sstevel@tonic-gate /* 24227c478bd9Sstevel@tonic-gate * If this object identifies itself as an 24237c478bd9Sstevel@tonic-gate * interposer, but relocation processing has 24247c478bd9Sstevel@tonic-gate * already started, then demote it. It's too 24257c478bd9Sstevel@tonic-gate * late to guarantee complete interposition. 24267c478bd9Sstevel@tonic-gate */ 2427a953e2b1Srie /* BEGIN CSTYLED */ 24289a411307Srie if (ld->d_un.d_val & 24299a411307Srie (DF_1_INTERPOSE | DF_1_SYMINTPOSE)) { 24309a411307Srie if (lml->lm_flags & LML_FLG_STARTREL) { 24315aefb655Srie DBG_CALL(Dbg_util_intoolate(lmp)); 24327c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) 24337c478bd9Sstevel@tonic-gate (void) printf( 24347c478bd9Sstevel@tonic-gate MSG_INTL(MSG_LDD_REL_ERR2), 24357c478bd9Sstevel@tonic-gate NAME(lmp)); 24369a411307Srie } else if (ld->d_un.d_val & DF_1_INTERPOSE) 24379a411307Srie FLAGS(lmp) |= FLG_RT_OBJINTPO; 24389a411307Srie else 24399a411307Srie FLAGS(lmp) |= FLG_RT_SYMINTPO; 24407c478bd9Sstevel@tonic-gate } 2441a953e2b1Srie /* END CSTYLED */ 24427c478bd9Sstevel@tonic-gate break; 24437c478bd9Sstevel@tonic-gate case DT_SYMINFO: 24447c478bd9Sstevel@tonic-gate SYMINFO(lmp) = (Syminfo *)(ld->d_un.d_ptr + 24457c478bd9Sstevel@tonic-gate base); 24467c478bd9Sstevel@tonic-gate break; 24477c478bd9Sstevel@tonic-gate case DT_SYMINENT: 24487c478bd9Sstevel@tonic-gate SYMINENT(lmp) = ld->d_un.d_val; 24497c478bd9Sstevel@tonic-gate break; 24507c478bd9Sstevel@tonic-gate case DT_PLTPAD: 24517c478bd9Sstevel@tonic-gate PLTPAD(lmp) = (void *)(ld->d_un.d_ptr + base); 24527c478bd9Sstevel@tonic-gate break; 24537c478bd9Sstevel@tonic-gate case DT_PLTPADSZ: 24547c478bd9Sstevel@tonic-gate pltpadsz = ld->d_un.d_val; 24557c478bd9Sstevel@tonic-gate break; 24567c478bd9Sstevel@tonic-gate case DT_SUNW_RTLDINF: 24577c478bd9Sstevel@tonic-gate /* 245810a4fa49Srie * Maintain a list of RTLDINFO structures. 245910a4fa49Srie * Typically, libc is the only supplier, and 246010a4fa49Srie * only one structure is provided. However, 246110a4fa49Srie * multiple suppliers and multiple structures 246210a4fa49Srie * are supported. For example, one structure 246310a4fa49Srie * may provide thread_init, and another 246410a4fa49Srie * structure may provide atexit reservations. 24657c478bd9Sstevel@tonic-gate */ 246610a4fa49Srie if ((rti = alist_append(&lml->lm_rti, 0, 246710a4fa49Srie sizeof (Rti_desc), AL_CNT_RTLDINFO)) == 0) { 24687c478bd9Sstevel@tonic-gate remove_so(0, lmp); 24697c478bd9Sstevel@tonic-gate return (0); 24707c478bd9Sstevel@tonic-gate } 247110a4fa49Srie rti->rti_lmp = lmp; 247210a4fa49Srie rti->rti_info = (void *)(ld->d_un.d_ptr + base); 24737c478bd9Sstevel@tonic-gate break; 2474d579eb63Sab case DT_SUNW_SORTENT: 2475d579eb63Sab SUNWSORTENT(lmp) = ld->d_un.d_val; 2476d579eb63Sab break; 2477d579eb63Sab case DT_SUNW_SYMSORT: 2478d579eb63Sab SUNWSYMSORT(lmp) = 2479d579eb63Sab (void *)(ld->d_un.d_ptr + base); 2480d579eb63Sab break; 2481d579eb63Sab case DT_SUNW_SYMSORTSZ: 2482d579eb63Sab SUNWSYMSORTSZ(lmp) = ld->d_un.d_val; 2483d579eb63Sab break; 24847c478bd9Sstevel@tonic-gate case DT_DEPRECATED_SPARC_REGISTER: 24857c478bd9Sstevel@tonic-gate case M_DT_REGISTER: 24867c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_REGSYMS; 24877c478bd9Sstevel@tonic-gate break; 24887c478bd9Sstevel@tonic-gate case M_DT_PLTRESERVE: 24897c478bd9Sstevel@tonic-gate PLTRESERVE(lmp) = (void *)(ld->d_un.d_ptr + 24907c478bd9Sstevel@tonic-gate base); 24917c478bd9Sstevel@tonic-gate break; 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate } 24947c478bd9Sstevel@tonic-gate 24957c478bd9Sstevel@tonic-gate if (PLTPAD(lmp)) { 24967c478bd9Sstevel@tonic-gate if (pltpadsz == (Xword)0) 24977c478bd9Sstevel@tonic-gate PLTPAD(lmp) = 0; 24987c478bd9Sstevel@tonic-gate else 24997c478bd9Sstevel@tonic-gate PLTPADEND(lmp) = (void *)((Addr)PLTPAD(lmp) + 25007c478bd9Sstevel@tonic-gate pltpadsz); 25017c478bd9Sstevel@tonic-gate } 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate /* 250475e7992aSrie * Allocate a Dynamic Info structure. 25057c478bd9Sstevel@tonic-gate */ 250675e7992aSrie if ((DYNINFO(lmp) = calloc((size_t)dynndx, 25077c478bd9Sstevel@tonic-gate sizeof (Dyninfo))) == 0) { 25087c478bd9Sstevel@tonic-gate remove_so(0, lmp); 25097c478bd9Sstevel@tonic-gate return (0); 25107c478bd9Sstevel@tonic-gate } 251175e7992aSrie DYNINFOCNT(lmp) = dynndx; 25127c478bd9Sstevel@tonic-gate } 25137c478bd9Sstevel@tonic-gate 25149039eeafSab /* 25159039eeafSab * A dynsym contains only global functions. We want to have 25169039eeafSab * a version of it that also includes local functions, so that 25179039eeafSab * dladdr() will be able to report names for local functions 25189039eeafSab * when used to generate a stack trace for a stripped file. 25199039eeafSab * This version of the dynsym is provided via DT_SUNW_SYMTAB. 25209039eeafSab * 25219039eeafSab * In producing DT_SUNW_SYMTAB, ld uses a non-obvious trick 25229039eeafSab * in order to avoid having to have two copies of the global 25239039eeafSab * symbols held in DT_SYMTAB: The local symbols are placed in 25249039eeafSab * a separate section than the globals in the dynsym, but the 25259039eeafSab * linker conspires to put the data for these two sections adjacent 25269039eeafSab * to each other. DT_SUNW_SYMTAB points at the top of the local 25279039eeafSab * symbols, and DT_SUNW_SYMSZ is the combined length of both tables. 25289039eeafSab * 25299039eeafSab * If the two sections are not adjacent, then something went wrong 25309039eeafSab * at link time. We use ASSERT to kill the process if this is 25319039eeafSab * a debug build. In a production build, we will silently ignore 25329039eeafSab * the presence of the .ldynsym and proceed. We can detect this 25339039eeafSab * situation by checking to see that DT_SYMTAB lies in 25349039eeafSab * the range given by DT_SUNW_SYMTAB/DT_SUNW_SYMSZ. 25359039eeafSab */ 25369039eeafSab if ((SUNWSYMTAB(lmp) != NULL) && 25379039eeafSab (((char *)SYMTAB(lmp) <= (char *)SUNWSYMTAB(lmp)) || 25389039eeafSab (((char *)SYMTAB(lmp) >= 25399039eeafSab (SUNWSYMSZ(lmp) + (char *)SUNWSYMTAB(lmp)))))) { 25409039eeafSab ASSERT(0); 25419039eeafSab SUNWSYMTAB(lmp) = NULL; 25429039eeafSab SUNWSYMSZ(lmp) = 0; 25439039eeafSab } 25449039eeafSab 25457c478bd9Sstevel@tonic-gate /* 25467c478bd9Sstevel@tonic-gate * If configuration file use hasn't been disabled, and a configuration 25477c478bd9Sstevel@tonic-gate * file hasn't already been set via an environment variable, see if any 25487c478bd9Sstevel@tonic-gate * application specific configuration file is specified. An LD_CONFIG 25497c478bd9Sstevel@tonic-gate * setting is used first, but if this image was generated via crle(1) 25507c478bd9Sstevel@tonic-gate * then a default configuration file is a fall-back. 25517c478bd9Sstevel@tonic-gate */ 25527c478bd9Sstevel@tonic-gate if ((!(rtld_flags & RT_FL_NOCFG)) && (config->c_name == 0)) { 25537c478bd9Sstevel@tonic-gate if (cfile) 25547c478bd9Sstevel@tonic-gate config->c_name = (const char *)(cfile + 25557c478bd9Sstevel@tonic-gate (char *)STRTAB(lmp)); 25567c478bd9Sstevel@tonic-gate else if (crle) { 25577c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_CONFAPP; 25587c478bd9Sstevel@tonic-gate #ifndef EXPAND_RELATIVE 25597c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_RELATIVE; 25607c478bd9Sstevel@tonic-gate #endif 25617c478bd9Sstevel@tonic-gate } 25627c478bd9Sstevel@tonic-gate } 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate if (rpath) 25657c478bd9Sstevel@tonic-gate RPATH(lmp) = (char *)(rpath + (char *)STRTAB(lmp)); 25667c478bd9Sstevel@tonic-gate if (fltr) { 25677c478bd9Sstevel@tonic-gate /* 25687c478bd9Sstevel@tonic-gate * If this object is a global filter, duplicate the filtee 25697c478bd9Sstevel@tonic-gate * string name(s) so that REFNAME() is available in core files. 25707c478bd9Sstevel@tonic-gate * This cludge was useful for debuggers at one point, but only 25717c478bd9Sstevel@tonic-gate * when the filtee name was an individual full path. 25727c478bd9Sstevel@tonic-gate */ 25737c478bd9Sstevel@tonic-gate if ((REFNAME(lmp) = strdup(fltr + (char *)STRTAB(lmp))) == 0) { 25747c478bd9Sstevel@tonic-gate remove_so(0, lmp); 25757c478bd9Sstevel@tonic-gate return (0); 25767c478bd9Sstevel@tonic-gate } 25777c478bd9Sstevel@tonic-gate } 25787c478bd9Sstevel@tonic-gate 25797c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_RELATIVE) 25807c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_RELATIVE; 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate /* 25837c478bd9Sstevel@tonic-gate * For Intel ABI compatibility. It's possible that a JMPREL can be 25847c478bd9Sstevel@tonic-gate * specified without any other relocations (e.g. a dynamic executable 25857c478bd9Sstevel@tonic-gate * normally only contains .plt relocations). If this is the case then 25867c478bd9Sstevel@tonic-gate * no REL, RELSZ or RELENT will have been created. For us to be able 25877c478bd9Sstevel@tonic-gate * to traverse the .plt relocations under LD_BIND_NOW we need to know 25887c478bd9Sstevel@tonic-gate * the RELENT for these relocations. Refer to elf_reloc() for more 25897c478bd9Sstevel@tonic-gate * details. 25907c478bd9Sstevel@tonic-gate */ 25917c478bd9Sstevel@tonic-gate if (!RELENT(lmp) && JMPREL(lmp)) 25927c478bd9Sstevel@tonic-gate RELENT(lmp) = sizeof (Rel); 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate /* 25957c478bd9Sstevel@tonic-gate * Establish any per-object auditing. If we're establishing `main's 25967c478bd9Sstevel@tonic-gate * link-map its too early to go searching for audit objects so just 25977c478bd9Sstevel@tonic-gate * hold the object name for later (see setup()). 25987c478bd9Sstevel@tonic-gate */ 25997c478bd9Sstevel@tonic-gate if (audit) { 26007c478bd9Sstevel@tonic-gate char *cp = audit + (char *)STRTAB(lmp); 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate if (*cp) { 26037c478bd9Sstevel@tonic-gate if (((AUDITORS(lmp) = 26047c478bd9Sstevel@tonic-gate calloc(1, sizeof (Audit_desc))) == 0) || 26057c478bd9Sstevel@tonic-gate ((AUDITORS(lmp)->ad_name = strdup(cp)) == 0)) { 26067c478bd9Sstevel@tonic-gate remove_so(0, lmp); 26077c478bd9Sstevel@tonic-gate return (0); 26087c478bd9Sstevel@tonic-gate } 260941072f3cSrie if (lml_main.lm_head) { 26109aa23310Srie if (audit_setup(lmp, AUDITORS(lmp), 0, 26119aa23310Srie in_nfavl) == 0) { 26127c478bd9Sstevel@tonic-gate remove_so(0, lmp); 26137c478bd9Sstevel@tonic-gate return (0); 26147c478bd9Sstevel@tonic-gate } 26157c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= AUDITORS(lmp)->ad_flags; 26167c478bd9Sstevel@tonic-gate lml->lm_flags |= LML_FLG_LOCAUDIT; 26177c478bd9Sstevel@tonic-gate } 26187c478bd9Sstevel@tonic-gate } 26197c478bd9Sstevel@tonic-gate } 26207c478bd9Sstevel@tonic-gate 26217c478bd9Sstevel@tonic-gate if ((CONDVAR(lmp) = rt_cond_create()) == 0) { 26227c478bd9Sstevel@tonic-gate remove_so(0, lmp); 26237c478bd9Sstevel@tonic-gate return (0); 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate if (oname && ((append_alias(lmp, oname, 0)) == 0)) { 26267c478bd9Sstevel@tonic-gate remove_so(0, lmp); 26277c478bd9Sstevel@tonic-gate return (0); 26287c478bd9Sstevel@tonic-gate } 26297c478bd9Sstevel@tonic-gate 26307c478bd9Sstevel@tonic-gate /* 26317c478bd9Sstevel@tonic-gate * Add the mapped object to the end of the link map list. 26327c478bd9Sstevel@tonic-gate */ 26337c478bd9Sstevel@tonic-gate lm_append(lml, lmco, lmp); 26347c478bd9Sstevel@tonic-gate return (lmp); 26357c478bd9Sstevel@tonic-gate } 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate /* 26387c478bd9Sstevel@tonic-gate * Assign hardware/software capabilities. 26397c478bd9Sstevel@tonic-gate */ 26407c478bd9Sstevel@tonic-gate void 26417c478bd9Sstevel@tonic-gate cap_assign(Cap *cap, Rt_map *lmp) 26427c478bd9Sstevel@tonic-gate { 26437c478bd9Sstevel@tonic-gate while (cap->c_tag != CA_SUNW_NULL) { 26447c478bd9Sstevel@tonic-gate switch (cap->c_tag) { 26457c478bd9Sstevel@tonic-gate case CA_SUNW_HW_1: 26467c478bd9Sstevel@tonic-gate HWCAP(lmp) = cap->c_un.c_val; 26477c478bd9Sstevel@tonic-gate break; 26487c478bd9Sstevel@tonic-gate case CA_SUNW_SF_1: 26497c478bd9Sstevel@tonic-gate SFCAP(lmp) = cap->c_un.c_val; 26507c478bd9Sstevel@tonic-gate } 26517c478bd9Sstevel@tonic-gate cap++; 26527c478bd9Sstevel@tonic-gate } 26537c478bd9Sstevel@tonic-gate } 26547c478bd9Sstevel@tonic-gate 26557c478bd9Sstevel@tonic-gate /* 26567c478bd9Sstevel@tonic-gate * Map in an ELF object. 26577c478bd9Sstevel@tonic-gate * Takes an open file descriptor for the object to map and its pathname; returns 26587c478bd9Sstevel@tonic-gate * a pointer to a Rt_map structure for this object, or 0 on error. 26597c478bd9Sstevel@tonic-gate */ 26607c478bd9Sstevel@tonic-gate static Rt_map * 26617c478bd9Sstevel@tonic-gate elf_map_so(Lm_list *lml, Aliste lmco, const char *pname, const char *oname, 26629aa23310Srie int fd, int *in_nfavl) 26637c478bd9Sstevel@tonic-gate { 26647c478bd9Sstevel@tonic-gate int i; /* general temporary */ 26657c478bd9Sstevel@tonic-gate Off memsize = 0; /* total memory size of pathname */ 26667c478bd9Sstevel@tonic-gate Off mentry; /* entry point */ 26677c478bd9Sstevel@tonic-gate Ehdr *ehdr; /* ELF header of ld.so */ 26687c478bd9Sstevel@tonic-gate Phdr *phdr; /* first Phdr in file */ 26697c478bd9Sstevel@tonic-gate Phdr *phdr0; /* Saved first Phdr in file */ 26707c478bd9Sstevel@tonic-gate Phdr *pptr; /* working Phdr */ 26717c478bd9Sstevel@tonic-gate Phdr *fph = 0; /* first loadable Phdr */ 26727c478bd9Sstevel@tonic-gate Phdr *lph; /* last loadable Phdr */ 26737c478bd9Sstevel@tonic-gate Phdr *lfph = 0; /* last loadable (filesz != 0) Phdr */ 26747c478bd9Sstevel@tonic-gate Phdr *lmph = 0; /* last loadable (memsz != 0) Phdr */ 26757c478bd9Sstevel@tonic-gate Phdr *swph = 0; /* program header for SUNWBSS */ 26767c478bd9Sstevel@tonic-gate Phdr *tlph = 0; /* program header for PT_TLS */ 26777c478bd9Sstevel@tonic-gate Phdr *unwindph = 0; /* program header for PT_SUNW_UNWIND */ 26787c478bd9Sstevel@tonic-gate Cap *cap = 0; /* program header for SUNWCAP */ 26797c478bd9Sstevel@tonic-gate Dyn *mld = 0; /* DYNAMIC structure for pathname */ 26807c478bd9Sstevel@tonic-gate size_t size; /* size of elf and program headers */ 26817c478bd9Sstevel@tonic-gate caddr_t faddr = 0; /* mapping address of pathname */ 26827c478bd9Sstevel@tonic-gate Rt_map *lmp; /* link map created */ 26837c478bd9Sstevel@tonic-gate caddr_t paddr; /* start of padded image */ 26847c478bd9Sstevel@tonic-gate Off plen; /* size of image including padding */ 26857c478bd9Sstevel@tonic-gate Half etype; 26867c478bd9Sstevel@tonic-gate int fixed; 26877c478bd9Sstevel@tonic-gate Mmap *mmaps; 26887c478bd9Sstevel@tonic-gate uint_t mmapcnt = 0; 26897c478bd9Sstevel@tonic-gate Xword align = 0; 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate /* LINTED */ 26927c478bd9Sstevel@tonic-gate ehdr = (Ehdr *)fmap->fm_maddr; 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate /* 26957c478bd9Sstevel@tonic-gate * If this a relocatable object then special processing is required. 26967c478bd9Sstevel@tonic-gate */ 26977c478bd9Sstevel@tonic-gate if ((etype = ehdr->e_type) == ET_REL) 269841072f3cSrie return (elf_obj_file(lml, lmco, pname, fd)); 26997c478bd9Sstevel@tonic-gate 27007c478bd9Sstevel@tonic-gate /* 27017c478bd9Sstevel@tonic-gate * If this isn't a dynamic executable or shared object we can't process 27027c478bd9Sstevel@tonic-gate * it. If this is a dynamic executable then all addresses are fixed. 27037c478bd9Sstevel@tonic-gate */ 2704de777a60Sab if (etype == ET_EXEC) { 27057c478bd9Sstevel@tonic-gate fixed = 1; 2706de777a60Sab } else if (etype == ET_DYN) { 27077c478bd9Sstevel@tonic-gate fixed = 0; 2708de777a60Sab } else { 2709de777a60Sab Conv_inv_buf_t inv_buf; 2710de777a60Sab 27115aefb655Srie eprintf(lml, ERR_ELF, MSG_INTL(MSG_GEN_BADTYPE), pname, 2712de777a60Sab conv_ehdr_type(etype, 0, &inv_buf)); 27137c478bd9Sstevel@tonic-gate return (0); 27147c478bd9Sstevel@tonic-gate } 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate /* 27177c478bd9Sstevel@tonic-gate * If our original mapped page was not large enough to hold all the 27187c478bd9Sstevel@tonic-gate * program headers remap them. 27197c478bd9Sstevel@tonic-gate */ 27207c478bd9Sstevel@tonic-gate size = (size_t)((char *)ehdr->e_phoff + 2721a953e2b1Srie (ehdr->e_phnum * ehdr->e_phentsize)); 27227c478bd9Sstevel@tonic-gate if (size > fmap->fm_fsize) { 27235aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_CORTRUNC), pname); 27247c478bd9Sstevel@tonic-gate return (0); 27257c478bd9Sstevel@tonic-gate } 27267c478bd9Sstevel@tonic-gate if (size > fmap->fm_msize) { 27277c478bd9Sstevel@tonic-gate fmap_setup(); 27287c478bd9Sstevel@tonic-gate if ((fmap->fm_maddr = mmap(fmap->fm_maddr, size, PROT_READ, 27297c478bd9Sstevel@tonic-gate fmap->fm_mflags, fd, 0)) == MAP_FAILED) { 27307c478bd9Sstevel@tonic-gate int err = errno; 27315aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname, 27327c478bd9Sstevel@tonic-gate strerror(err)); 27337c478bd9Sstevel@tonic-gate return (0); 27347c478bd9Sstevel@tonic-gate } 27357c478bd9Sstevel@tonic-gate fmap->fm_msize = size; 27367c478bd9Sstevel@tonic-gate /* LINTED */ 27377c478bd9Sstevel@tonic-gate ehdr = (Ehdr *)fmap->fm_maddr; 27387c478bd9Sstevel@tonic-gate } 27397c478bd9Sstevel@tonic-gate /* LINTED */ 27407c478bd9Sstevel@tonic-gate phdr0 = phdr = (Phdr *)((char *)ehdr + ehdr->e_ehsize); 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate /* 27437c478bd9Sstevel@tonic-gate * Get entry point. 27447c478bd9Sstevel@tonic-gate */ 27457c478bd9Sstevel@tonic-gate mentry = ehdr->e_entry; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate /* 27487c478bd9Sstevel@tonic-gate * Point at program headers and perform some basic validation. 27497c478bd9Sstevel@tonic-gate */ 27507c478bd9Sstevel@tonic-gate for (i = 0, pptr = phdr; i < (int)ehdr->e_phnum; i++, 27517c478bd9Sstevel@tonic-gate pptr = (Phdr *)((Off)pptr + ehdr->e_phentsize)) { 27527c478bd9Sstevel@tonic-gate if ((pptr->p_type == PT_LOAD) || 27537c478bd9Sstevel@tonic-gate (pptr->p_type == PT_SUNWBSS)) { 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate if (fph == 0) { 27567c478bd9Sstevel@tonic-gate fph = pptr; 27577c478bd9Sstevel@tonic-gate /* LINTED argument lph is initialized in first pass */ 27587c478bd9Sstevel@tonic-gate } else if (pptr->p_vaddr <= lph->p_vaddr) { 27595aefb655Srie eprintf(lml, ERR_ELF, 27605aefb655Srie MSG_INTL(MSG_GEN_INVPRGHDR), pname); 27617c478bd9Sstevel@tonic-gate return (0); 27627c478bd9Sstevel@tonic-gate } 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate lph = pptr; 27657c478bd9Sstevel@tonic-gate 27667c478bd9Sstevel@tonic-gate if (pptr->p_memsz) 27677c478bd9Sstevel@tonic-gate lmph = pptr; 27687c478bd9Sstevel@tonic-gate if (pptr->p_filesz) 27697c478bd9Sstevel@tonic-gate lfph = pptr; 27707c478bd9Sstevel@tonic-gate if (pptr->p_type == PT_SUNWBSS) 27717c478bd9Sstevel@tonic-gate swph = pptr; 27727c478bd9Sstevel@tonic-gate if (pptr->p_align > align) 27737c478bd9Sstevel@tonic-gate align = pptr->p_align; 27747c478bd9Sstevel@tonic-gate 277510a4fa49Srie } else if (pptr->p_type == PT_DYNAMIC) { 27767c478bd9Sstevel@tonic-gate mld = (Dyn *)(pptr->p_vaddr); 277710a4fa49Srie } else if ((pptr->p_type == PT_TLS) && pptr->p_memsz) { 27787c478bd9Sstevel@tonic-gate tlph = pptr; 277910a4fa49Srie } else if (pptr->p_type == PT_SUNWCAP) { 27807c478bd9Sstevel@tonic-gate cap = (Cap *)(pptr->p_vaddr); 278110a4fa49Srie } else if (pptr->p_type == PT_SUNW_UNWIND) { 27827c478bd9Sstevel@tonic-gate unwindph = pptr; 278310a4fa49Srie } 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate #if defined(MAP_ALIGN) 27877c478bd9Sstevel@tonic-gate /* 2788a953e2b1Srie * Make sure the maximum page alignment is a power of 2 >= the default 2789a953e2b1Srie * segment alignment, for use with MAP_ALIGN. 27907c478bd9Sstevel@tonic-gate */ 2791a953e2b1Srie align = S_ROUND(align, M_SEGM_ALIGN); 27927c478bd9Sstevel@tonic-gate #endif 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate /* 27957c478bd9Sstevel@tonic-gate * We'd better have at least one loadable segment, together with some 27967c478bd9Sstevel@tonic-gate * specified file and memory size. 27977c478bd9Sstevel@tonic-gate */ 27987c478bd9Sstevel@tonic-gate if ((fph == 0) || (lmph == 0) || (lfph == 0)) { 27995aefb655Srie eprintf(lml, ERR_ELF, MSG_INTL(MSG_GEN_NOLOADSEG), pname); 28007c478bd9Sstevel@tonic-gate return (0); 28017c478bd9Sstevel@tonic-gate } 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate /* 28047c478bd9Sstevel@tonic-gate * Check that the files size accounts for the loadable sections 28057c478bd9Sstevel@tonic-gate * we're going to map in (failure to do this may cause spurious 28067c478bd9Sstevel@tonic-gate * bus errors if we're given a truncated file). 28077c478bd9Sstevel@tonic-gate */ 28087c478bd9Sstevel@tonic-gate if (fmap->fm_fsize < ((size_t)lfph->p_offset + lfph->p_filesz)) { 28095aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_CORTRUNC), pname); 28107c478bd9Sstevel@tonic-gate return (0); 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate /* 28147c478bd9Sstevel@tonic-gate * Memsize must be page rounded so that if we add object padding 28157c478bd9Sstevel@tonic-gate * at the end it will start at the beginning of a page. 28167c478bd9Sstevel@tonic-gate */ 28177c478bd9Sstevel@tonic-gate plen = memsize = M_PROUND((lmph->p_vaddr + lmph->p_memsz) - 28187c478bd9Sstevel@tonic-gate M_PTRUNC((ulong_t)fph->p_vaddr)); 28197c478bd9Sstevel@tonic-gate 28207c478bd9Sstevel@tonic-gate /* 28217c478bd9Sstevel@tonic-gate * Determine if an existing mapping is acceptable. 28227c478bd9Sstevel@tonic-gate */ 28237c478bd9Sstevel@tonic-gate if (interp && (lml->lm_flags & LML_FLG_BASELM) && 282441072f3cSrie (strcmp(pname, interp->i_name) == 0)) { 28257c478bd9Sstevel@tonic-gate /* 28267c478bd9Sstevel@tonic-gate * If this is the interpreter then it has already been mapped 28277c478bd9Sstevel@tonic-gate * and we have the address so don't map it again. Note that 28287c478bd9Sstevel@tonic-gate * the common occurrence of a reference to the interpretor 28297c478bd9Sstevel@tonic-gate * (libdl -> ld.so.1) will have been caught during filter 28307c478bd9Sstevel@tonic-gate * initialization (see elf_lookup_filtee()). However, some 28317c478bd9Sstevel@tonic-gate * ELF implementations are known to record libc.so.1 as the 28327c478bd9Sstevel@tonic-gate * interpretor, and thus this test catches this behavior. 28337c478bd9Sstevel@tonic-gate */ 28347c478bd9Sstevel@tonic-gate paddr = faddr = interp->i_faddr; 28357c478bd9Sstevel@tonic-gate 28367c478bd9Sstevel@tonic-gate } else if ((fixed == 0) && (r_debug.rtd_objpad == 0) && 28377c478bd9Sstevel@tonic-gate (memsize <= fmap->fm_msize) && ((fph->p_flags & PF_W) == 0) && 2838a953e2b1Srie (fph == lph) && (fph->p_filesz == fph->p_memsz) && 28397c478bd9Sstevel@tonic-gate (((Xword)fmap->fm_maddr % align) == 0)) { 2840a953e2b1Srie size_t rsize; 2841a953e2b1Srie 28427c478bd9Sstevel@tonic-gate /* 2843a953e2b1Srie * If the file contains a single segment, and the mapping 2844a953e2b1Srie * required has already been established from the initial fmap 2845a953e2b1Srie * mapping, then we don't need to do anything more. Reset the 2846a953e2b1Srie * fmap address so that any later files start a new fmap. This 2847a953e2b1Srie * is really an optimization for filters, such as libdl.so, 2848a953e2b1Srie * libthread, etc. that are constructed to be a single text 2849a953e2b1Srie * segment. 28507c478bd9Sstevel@tonic-gate */ 28517c478bd9Sstevel@tonic-gate paddr = faddr = fmap->fm_maddr; 2852a953e2b1Srie 2853a953e2b1Srie /* 2854a953e2b1Srie * Free any unused mapping by assigning the fmap buffer to the 2855a953e2b1Srie * unused region. fmap_setup() will unmap this area and 2856a953e2b1Srie * establish defaults for future mappings. 2857a953e2b1Srie */ 2858a953e2b1Srie rsize = M_PROUND(fph->p_filesz); 2859a953e2b1Srie fmap->fm_maddr += rsize; 2860a953e2b1Srie fmap->fm_msize -= rsize; 28617c478bd9Sstevel@tonic-gate fmap_setup(); 28627c478bd9Sstevel@tonic-gate } 28637c478bd9Sstevel@tonic-gate 28647c478bd9Sstevel@tonic-gate /* 28657c478bd9Sstevel@tonic-gate * Allocate a mapping array to retain mapped segment information. 28667c478bd9Sstevel@tonic-gate */ 28677c478bd9Sstevel@tonic-gate if ((mmaps = calloc(ehdr->e_phnum, sizeof (Mmap))) == 0) 28687c478bd9Sstevel@tonic-gate return (0); 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate /* 28717c478bd9Sstevel@tonic-gate * If we're reusing an existing mapping determine the objects etext 28727c478bd9Sstevel@tonic-gate * address. Otherwise map the file (which will calculate the etext 28737c478bd9Sstevel@tonic-gate * address as part of the mapping process). 28747c478bd9Sstevel@tonic-gate */ 28757c478bd9Sstevel@tonic-gate if (faddr) { 28767c478bd9Sstevel@tonic-gate caddr_t base; 28777c478bd9Sstevel@tonic-gate 28787c478bd9Sstevel@tonic-gate if (fixed) 28797c478bd9Sstevel@tonic-gate base = 0; 28807c478bd9Sstevel@tonic-gate else 28817c478bd9Sstevel@tonic-gate base = faddr; 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate /* LINTED */ 28847c478bd9Sstevel@tonic-gate phdr0 = phdr = (Phdr *)((char *)faddr + ehdr->e_ehsize); 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate for (i = 0, pptr = phdr; i < (int)ehdr->e_phnum; i++, 28877c478bd9Sstevel@tonic-gate pptr = (Phdr *)((Off)pptr + ehdr->e_phentsize)) { 28887c478bd9Sstevel@tonic-gate if (pptr->p_type != PT_LOAD) 28897c478bd9Sstevel@tonic-gate continue; 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate mmaps[mmapcnt].m_vaddr = (pptr->p_vaddr + base); 28927c478bd9Sstevel@tonic-gate mmaps[mmapcnt].m_msize = pptr->p_memsz; 28937c478bd9Sstevel@tonic-gate mmaps[mmapcnt].m_fsize = pptr->p_filesz; 28947c478bd9Sstevel@tonic-gate mmaps[mmapcnt].m_perm = (PROT_READ | PROT_EXEC); 28957c478bd9Sstevel@tonic-gate mmapcnt++; 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate if (!(pptr->p_flags & PF_W)) { 28987c478bd9Sstevel@tonic-gate fmap->fm_etext = (ulong_t)pptr->p_vaddr + 28997c478bd9Sstevel@tonic-gate (ulong_t)pptr->p_memsz + 29007c478bd9Sstevel@tonic-gate (ulong_t)(fixed ? 0 : faddr); 29017c478bd9Sstevel@tonic-gate } 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate } else { 29047c478bd9Sstevel@tonic-gate /* 29057c478bd9Sstevel@tonic-gate * Map the file. 29067c478bd9Sstevel@tonic-gate */ 29075aefb655Srie if (!(faddr = elf_map_it(lml, pname, memsize, ehdr, fph, lph, 29087c478bd9Sstevel@tonic-gate &phdr, &paddr, &plen, fixed, fd, align, mmaps, &mmapcnt))) 29097c478bd9Sstevel@tonic-gate return (0); 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate /* 29137c478bd9Sstevel@tonic-gate * Calculate absolute base addresses and entry points. 29147c478bd9Sstevel@tonic-gate */ 29157c478bd9Sstevel@tonic-gate if (!fixed) { 29167c478bd9Sstevel@tonic-gate if (mld) 29177c478bd9Sstevel@tonic-gate /* LINTED */ 29187c478bd9Sstevel@tonic-gate mld = (Dyn *)((Off)mld + faddr); 29197c478bd9Sstevel@tonic-gate if (cap) 29207c478bd9Sstevel@tonic-gate /* LINTED */ 29217c478bd9Sstevel@tonic-gate cap = (Cap *)((Off)cap + faddr); 29227c478bd9Sstevel@tonic-gate mentry += (Off)faddr; 29237c478bd9Sstevel@tonic-gate } 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate /* 29267c478bd9Sstevel@tonic-gate * Create new link map structure for newly mapped shared object. 29277c478bd9Sstevel@tonic-gate */ 29287c478bd9Sstevel@tonic-gate if (!(lmp = elf_new_lm(lml, pname, oname, mld, (ulong_t)faddr, 29297c478bd9Sstevel@tonic-gate fmap->fm_etext, lmco, memsize, mentry, (ulong_t)paddr, plen, mmaps, 29309aa23310Srie mmapcnt, in_nfavl))) { 29317c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)faddr, memsize); 29327c478bd9Sstevel@tonic-gate return (0); 29337c478bd9Sstevel@tonic-gate } 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate /* 29367c478bd9Sstevel@tonic-gate * Start the system loading in the ELF information we'll be processing. 29377c478bd9Sstevel@tonic-gate */ 29387c478bd9Sstevel@tonic-gate if (REL(lmp)) { 29397c478bd9Sstevel@tonic-gate (void) madvise((void *)ADDR(lmp), (uintptr_t)REL(lmp) + 29407c478bd9Sstevel@tonic-gate (uintptr_t)RELSZ(lmp) - (uintptr_t)ADDR(lmp), 29417c478bd9Sstevel@tonic-gate MADV_WILLNEED); 29427c478bd9Sstevel@tonic-gate } 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate /* 2945d326b23bSrie * If this shared object contains any special segments, record them. 29467c478bd9Sstevel@tonic-gate */ 29477c478bd9Sstevel@tonic-gate if (swph) { 29487c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_SUNWBSS; 29497c478bd9Sstevel@tonic-gate SUNWBSS(lmp) = phdr + (swph - phdr0); 29507c478bd9Sstevel@tonic-gate } 2951d326b23bSrie if (tlph && (tls_assign(lml, lmp, (phdr + (tlph - phdr0))) == 0)) { 2952d326b23bSrie remove_so(lml, lmp); 2953d326b23bSrie return (0); 29547c478bd9Sstevel@tonic-gate } 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate if (unwindph) 29577c478bd9Sstevel@tonic-gate PTUNWIND(lmp) = phdr + (unwindph - phdr0); 29587c478bd9Sstevel@tonic-gate 29597c478bd9Sstevel@tonic-gate if (cap) 29607c478bd9Sstevel@tonic-gate cap_assign(cap, lmp); 29617c478bd9Sstevel@tonic-gate 29627c478bd9Sstevel@tonic-gate return (lmp); 29637c478bd9Sstevel@tonic-gate } 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate /* 29667c478bd9Sstevel@tonic-gate * Function to correct protection settings. Segments are all mapped initially 29677c478bd9Sstevel@tonic-gate * with permissions as given in the segment header. We need to turn on write 29687c478bd9Sstevel@tonic-gate * permissions on a text segment if there are any relocations against that 29697c478bd9Sstevel@tonic-gate * segment, and them turn write permission back off again before returning 29707c478bd9Sstevel@tonic-gate * control to the user. This function turns the permission on or off depending 29717c478bd9Sstevel@tonic-gate * on the value of the argument. 29727c478bd9Sstevel@tonic-gate */ 29737c478bd9Sstevel@tonic-gate int 29745aefb655Srie elf_set_prot(Rt_map *lmp, int permission) 29757c478bd9Sstevel@tonic-gate { 29767c478bd9Sstevel@tonic-gate Mmap *mmaps; 29777c478bd9Sstevel@tonic-gate 29787c478bd9Sstevel@tonic-gate /* 29797c478bd9Sstevel@tonic-gate * If this is an allocated image (ie. a relocatable object) we can't 29807c478bd9Sstevel@tonic-gate * mprotect() anything. 29817c478bd9Sstevel@tonic-gate */ 29827c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_IMGALLOC) 29837c478bd9Sstevel@tonic-gate return (1); 29847c478bd9Sstevel@tonic-gate 29855aefb655Srie DBG_CALL(Dbg_file_prot(lmp, permission)); 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate for (mmaps = MMAPS(lmp); mmaps->m_vaddr; mmaps++) { 29887c478bd9Sstevel@tonic-gate if (mmaps->m_perm & PROT_WRITE) 29897c478bd9Sstevel@tonic-gate continue; 29907c478bd9Sstevel@tonic-gate 29917c478bd9Sstevel@tonic-gate if (mprotect(mmaps->m_vaddr, mmaps->m_msize, 29927c478bd9Sstevel@tonic-gate (mmaps->m_perm | permission)) == -1) { 29937c478bd9Sstevel@tonic-gate int err = errno; 29945aefb655Srie eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_SYS_MPROT), 29957c478bd9Sstevel@tonic-gate NAME(lmp), strerror(err)); 29967c478bd9Sstevel@tonic-gate return (0); 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate return (1); 30007c478bd9Sstevel@tonic-gate } 30017c478bd9Sstevel@tonic-gate 30027c478bd9Sstevel@tonic-gate /* 30037c478bd9Sstevel@tonic-gate * Build full pathname of shared object from given directory name and filename. 30047c478bd9Sstevel@tonic-gate */ 30057c478bd9Sstevel@tonic-gate static char * 30067c478bd9Sstevel@tonic-gate elf_get_so(const char *dir, const char *file) 30077c478bd9Sstevel@tonic-gate { 30087c478bd9Sstevel@tonic-gate static char pname[PATH_MAX]; 30097c478bd9Sstevel@tonic-gate 30107c478bd9Sstevel@tonic-gate (void) snprintf(pname, PATH_MAX, MSG_ORIG(MSG_FMT_PATH), dir, file); 30117c478bd9Sstevel@tonic-gate return (pname); 30127c478bd9Sstevel@tonic-gate } 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate /* 30157c478bd9Sstevel@tonic-gate * The copy relocation is recorded in a copy structure which will be applied 30167c478bd9Sstevel@tonic-gate * after all other relocations are carried out. This provides for copying data 30177c478bd9Sstevel@tonic-gate * that must be relocated itself (ie. pointers in shared objects). This 30187c478bd9Sstevel@tonic-gate * structure also provides a means of binding RTLD_GROUP dependencies to any 30197c478bd9Sstevel@tonic-gate * copy relocations that have been taken from any group members. 30207c478bd9Sstevel@tonic-gate * 30217c478bd9Sstevel@tonic-gate * If the size of the .bss area available for the copy information is not the 30227c478bd9Sstevel@tonic-gate * same as the source of the data inform the user if we're under ldd(1) control 30237c478bd9Sstevel@tonic-gate * (this checking was only established in 5.3, so by only issuing an error via 30247c478bd9Sstevel@tonic-gate * ldd(1) we maintain the standard set by previous releases). 30257c478bd9Sstevel@tonic-gate */ 30267c478bd9Sstevel@tonic-gate int 30277c478bd9Sstevel@tonic-gate elf_copy_reloc(char *name, Sym *rsym, Rt_map *rlmp, void *radd, Sym *dsym, 30287c478bd9Sstevel@tonic-gate Rt_map *dlmp, const void *dadd) 30297c478bd9Sstevel@tonic-gate { 30307c478bd9Sstevel@tonic-gate Rel_copy rc; 30317c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(rlmp); 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate rc.r_name = name; 30347c478bd9Sstevel@tonic-gate rc.r_rsym = rsym; /* the new reference symbol and its */ 30357c478bd9Sstevel@tonic-gate rc.r_rlmp = rlmp; /* associated link-map */ 30367c478bd9Sstevel@tonic-gate rc.r_dlmp = dlmp; /* the defining link-map */ 30377c478bd9Sstevel@tonic-gate rc.r_dsym = dsym; /* the original definition */ 30387c478bd9Sstevel@tonic-gate rc.r_radd = radd; 30397c478bd9Sstevel@tonic-gate rc.r_dadd = dadd; 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate if (rsym->st_size > dsym->st_size) 30427c478bd9Sstevel@tonic-gate rc.r_size = (size_t)dsym->st_size; 30437c478bd9Sstevel@tonic-gate else 30447c478bd9Sstevel@tonic-gate rc.r_size = (size_t)rsym->st_size; 30457c478bd9Sstevel@tonic-gate 3046cce0e03bSab if (alist_append(©_R(dlmp), &rc, sizeof (Rel_copy), 30477c478bd9Sstevel@tonic-gate AL_CNT_COPYREL) == 0) { 30487c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_WARN)) 30497c478bd9Sstevel@tonic-gate return (0); 30507c478bd9Sstevel@tonic-gate else 30517c478bd9Sstevel@tonic-gate return (1); 30527c478bd9Sstevel@tonic-gate } 30537c478bd9Sstevel@tonic-gate if (!(FLAGS1(dlmp) & FL1_RT_COPYTOOK)) { 3054cce0e03bSab if (aplist_append(©_S(rlmp), dlmp, 3055cce0e03bSab AL_CNT_COPYREL) == NULL) { 30567c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_WARN)) 30577c478bd9Sstevel@tonic-gate return (0); 30587c478bd9Sstevel@tonic-gate else 30597c478bd9Sstevel@tonic-gate return (1); 30607c478bd9Sstevel@tonic-gate } 30617c478bd9Sstevel@tonic-gate FLAGS1(dlmp) |= FL1_RT_COPYTOOK; 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate /* 30657c478bd9Sstevel@tonic-gate * If we are tracing (ldd), warn the user if 30667c478bd9Sstevel@tonic-gate * 1) the size from the reference symbol differs from the 30677c478bd9Sstevel@tonic-gate * copy definition. We can only copy as much data as the 30687c478bd9Sstevel@tonic-gate * reference (dynamic executables) entry allows. 30697c478bd9Sstevel@tonic-gate * 2) the copy definition has STV_PROTECTED visibility. 30707c478bd9Sstevel@tonic-gate */ 30717c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_WARN) { 30727c478bd9Sstevel@tonic-gate if (rsym->st_size != dsym->st_size) { 30737c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_SIZDIF), 30745aefb655Srie _conv_reloc_type(M_R_COPY), demangle(name), 30757c478bd9Sstevel@tonic-gate NAME(rlmp), EC_XWORD(rsym->st_size), 30767c478bd9Sstevel@tonic-gate NAME(dlmp), EC_XWORD(dsym->st_size)); 30777c478bd9Sstevel@tonic-gate if (rsym->st_size > dsym->st_size) 30787c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_INSDATA), 30797c478bd9Sstevel@tonic-gate NAME(dlmp)); 30807c478bd9Sstevel@tonic-gate else 30817c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_DATRUNC), 30827c478bd9Sstevel@tonic-gate NAME(rlmp)); 30837c478bd9Sstevel@tonic-gate } 30847c478bd9Sstevel@tonic-gate 30857c478bd9Sstevel@tonic-gate if (ELF_ST_VISIBILITY(dsym->st_other) == STV_PROTECTED) { 30867c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_PROT), 30875aefb655Srie _conv_reloc_type(M_R_COPY), demangle(name), 3088a953e2b1Srie NAME(dlmp)); 30897c478bd9Sstevel@tonic-gate } 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate 30925aefb655Srie DBG_CALL(Dbg_reloc_apply_val(lml, ELF_DBG_RTLD, (Xword)radd, 30935aefb655Srie (Xword)rc.r_size)); 30947c478bd9Sstevel@tonic-gate return (1); 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate /* 30987c478bd9Sstevel@tonic-gate * Determine the symbol location of an address within a link-map. Look for 30997c478bd9Sstevel@tonic-gate * the nearest symbol (whose value is less than or equal to the required 31007c478bd9Sstevel@tonic-gate * address). This is the object specific part of dladdr(). 31017c478bd9Sstevel@tonic-gate */ 31027c478bd9Sstevel@tonic-gate static void 31037c478bd9Sstevel@tonic-gate elf_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, int flags) 31047c478bd9Sstevel@tonic-gate { 31057c478bd9Sstevel@tonic-gate ulong_t ndx, cnt, base, _value; 31066221fe92Sab Sym *sym, *_sym = NULL; 31077c478bd9Sstevel@tonic-gate const char *str; 31085343e1b3Sab int _flags; 3109d579eb63Sab uint_t *dynaddr_ndx; 3110d579eb63Sab uint_t dynaddr_n = 0; 3111d579eb63Sab ulong_t value; 31127c478bd9Sstevel@tonic-gate 31137c478bd9Sstevel@tonic-gate /* 31149039eeafSab * If SUNWSYMTAB() is non-NULL, then it sees a special version of 31159039eeafSab * the dynsym that starts with any local function symbols that exist in 31169039eeafSab * the library and then moves to the data held in SYMTAB(). In this 31179039eeafSab * case, SUNWSYMSZ tells us how long the symbol table is. The 31189039eeafSab * availability of local function symbols will enhance the results 31199039eeafSab * we can provide. 31209039eeafSab * 3121d579eb63Sab * If SUNWSYMTAB() is non-NULL, then there might also be a 3122d579eb63Sab * SUNWSYMSORT() vector associated with it. SUNWSYMSORT() contains 3123d579eb63Sab * an array of indices into SUNWSYMTAB, sorted by increasing 3124d579eb63Sab * address. We can use this to do an O(log N) search instead of a 3125d579eb63Sab * brute force search. 3126d579eb63Sab * 31279039eeafSab * If SUNWSYMTAB() is NULL, then SYMTAB() references a dynsym that 31289039eeafSab * contains only global symbols. In that case, the length of 31299039eeafSab * the symbol table comes from the nchain field of the related 31309039eeafSab * symbol lookup hash table. 31317c478bd9Sstevel@tonic-gate */ 31327c478bd9Sstevel@tonic-gate str = STRTAB(lmp); 31339039eeafSab if (SUNWSYMSZ(lmp) == NULL) { 31349039eeafSab sym = SYMTAB(lmp); 31359039eeafSab /* 31369039eeafSab * If we don't have a .hash table there are no symbols 31379039eeafSab * to look at. 31389039eeafSab */ 31399039eeafSab if (HASH(lmp) == 0) 31409039eeafSab return; 31419039eeafSab cnt = HASH(lmp)[1]; 31429039eeafSab } else { 31439039eeafSab sym = SUNWSYMTAB(lmp); 31449039eeafSab cnt = SUNWSYMSZ(lmp) / SYMENT(lmp); 3145d579eb63Sab dynaddr_ndx = SUNWSYMSORT(lmp); 3146d579eb63Sab if (dynaddr_ndx != NULL) 3147d579eb63Sab dynaddr_n = SUNWSYMSORTSZ(lmp) / SUNWSORTENT(lmp); 31489039eeafSab } 31497c478bd9Sstevel@tonic-gate 31507c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 31517c478bd9Sstevel@tonic-gate base = 0; 31527c478bd9Sstevel@tonic-gate else 31537c478bd9Sstevel@tonic-gate base = ADDR(lmp); 31547c478bd9Sstevel@tonic-gate 3155d579eb63Sab if (dynaddr_n > 0) { /* Binary search */ 3156d579eb63Sab long low = 0, low_bnd; 3157d579eb63Sab long high = dynaddr_n - 1, high_bnd; 3158d579eb63Sab long mid; 3159d579eb63Sab Sym *mid_sym; 31607c478bd9Sstevel@tonic-gate 31619039eeafSab /* 3162d579eb63Sab * Note that SUNWSYMSORT only contains symbols types that 3163d579eb63Sab * supply memory addresses, so there's no need to check and 3164d579eb63Sab * filter out any other types. 31659039eeafSab */ 3166d579eb63Sab low_bnd = low; 3167d579eb63Sab high_bnd = high; 3168d579eb63Sab while (low <= high) { 3169d579eb63Sab mid = (low + high) / 2; 3170d579eb63Sab mid_sym = &sym[dynaddr_ndx[mid]]; 3171d579eb63Sab value = mid_sym->st_value + base; 3172d579eb63Sab if (addr < value) { 3173d579eb63Sab if ((sym[dynaddr_ndx[high]].st_value + base) >= 3174d579eb63Sab addr) 3175d579eb63Sab high_bnd = high; 3176d579eb63Sab high = mid - 1; 3177d579eb63Sab } else if (addr > value) { 3178d579eb63Sab if ((sym[dynaddr_ndx[low]].st_value + base) <= 3179d579eb63Sab addr) 3180d579eb63Sab low_bnd = low; 3181d579eb63Sab low = mid + 1; 3182d579eb63Sab } else { 3183d579eb63Sab _sym = mid_sym; 3184d579eb63Sab _value = value; 3185d579eb63Sab break; 3186d579eb63Sab } 3187d579eb63Sab } 3188d579eb63Sab /* 3189d579eb63Sab * If the above didn't find it exactly, then we must 3190d579eb63Sab * return the closest symbol with a value that doesn't 3191d579eb63Sab * exceed the one we are looking for. If that symbol exists, 3192d579eb63Sab * it will lie in the range bounded by low_bnd and 3193d579eb63Sab * high_bnd. This is a linear search, but a short one. 3194d579eb63Sab */ 3195d579eb63Sab if (_sym == NULL) { 3196d579eb63Sab for (mid = low_bnd; mid <= high_bnd; mid++) { 3197d579eb63Sab mid_sym = &sym[dynaddr_ndx[mid]]; 3198d579eb63Sab value = mid_sym->st_value + base; 3199d579eb63Sab if (addr >= value) { 3200d579eb63Sab _sym = mid_sym; 3201d579eb63Sab _value = value; 3202d579eb63Sab } else { 3203d579eb63Sab break; 3204d579eb63Sab } 3205d579eb63Sab } 3206d579eb63Sab } 3207d579eb63Sab } else { /* Linear search */ 3208d579eb63Sab for (_value = 0, sym++, ndx = 1; ndx < cnt; ndx++, sym++) { 3209d579eb63Sab /* 3210d579eb63Sab * Skip expected symbol types that are not functions 3211d579eb63Sab * or data: 3212d579eb63Sab * - A symbol table starts with an undefined symbol 3213d579eb63Sab * in slot 0. If we are using SUNWSYMTAB(), 3214d579eb63Sab * there will be a second undefined symbol 3215d579eb63Sab * right before the globals. 3216d579eb63Sab * - The local part of SUNWSYMTAB() contains a 3217d579eb63Sab * series of function symbols. Each section 3218d579eb63Sab * starts with an initial STT_FILE symbol. 3219d579eb63Sab */ 3220d579eb63Sab if ((sym->st_shndx == SHN_UNDEF) || 3221d579eb63Sab (ELF_ST_TYPE(sym->st_info) == STT_FILE)) 3222d579eb63Sab continue; 32237c478bd9Sstevel@tonic-gate 3224d579eb63Sab value = sym->st_value + base; 3225d579eb63Sab if (value > addr) 3226d579eb63Sab continue; 3227d579eb63Sab if (value < _value) 3228d579eb63Sab continue; 32297c478bd9Sstevel@tonic-gate 3230d579eb63Sab _sym = sym; 3231d579eb63Sab _value = value; 32327c478bd9Sstevel@tonic-gate 3233d579eb63Sab /* 3234d579eb63Sab * Note, because we accept local and global symbols 3235d579eb63Sab * we could find a section symbol that matches the 3236d579eb63Sab * associated address, which means that the symbol 3237d579eb63Sab * name will be null. In this case continue the 3238d579eb63Sab * search in case we can find a global symbol of 3239d579eb63Sab * the same value. 3240d579eb63Sab */ 3241d579eb63Sab if ((value == addr) && 3242d579eb63Sab (ELF_ST_TYPE(sym->st_info) != STT_SECTION)) 3243d579eb63Sab break; 3244d579eb63Sab } 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate 32475343e1b3Sab _flags = flags & RTLD_DL_MASK; 32487c478bd9Sstevel@tonic-gate if (_sym) { 32497c478bd9Sstevel@tonic-gate if (_flags == RTLD_DL_SYMENT) 32507c478bd9Sstevel@tonic-gate *info = (void *)_sym; 32517c478bd9Sstevel@tonic-gate else if (_flags == RTLD_DL_LINKMAP) 32527c478bd9Sstevel@tonic-gate *info = (void *)lmp; 32537c478bd9Sstevel@tonic-gate 32547c478bd9Sstevel@tonic-gate dlip->dli_sname = str + _sym->st_name; 32557c478bd9Sstevel@tonic-gate dlip->dli_saddr = (void *)_value; 32565343e1b3Sab } else { 32575343e1b3Sab /* 32585343e1b3Sab * addr lies between the beginning of the mapped segment and 32595343e1b3Sab * the first global symbol. We have no symbol to return 32605343e1b3Sab * and the caller requires one. We use _START_, the base 32615343e1b3Sab * address of the mapping. 32625343e1b3Sab */ 32635343e1b3Sab 32645343e1b3Sab if (_flags == RTLD_DL_SYMENT) { 32655343e1b3Sab /* 32665343e1b3Sab * An actual symbol struct is needed, so we 32675343e1b3Sab * construct one for _START_. To do this in a 32685343e1b3Sab * fully accurate way requires a different symbol 32695343e1b3Sab * for each mapped segment. This requires the 32705343e1b3Sab * use of dynamic memory and a mutex. That's too much 32715343e1b3Sab * plumbing for a fringe case of limited importance. 32725343e1b3Sab * 32735343e1b3Sab * Fortunately, we can simplify: 32745343e1b3Sab * - Only the st_size and st_info fields are useful 32755343e1b3Sab * outside of the linker internals. The others 32765343e1b3Sab * reference things that outside code cannot see, 32775343e1b3Sab * and can be set to 0. 32785343e1b3Sab * - It's just a label and there is no size 32795343e1b3Sab * to report. So, the size should be 0. 32805343e1b3Sab * This means that only st_info needs a non-zero 32815343e1b3Sab * (constant) value. A static struct will suffice. 32825343e1b3Sab * It must be const (readonly) so the caller can't 32835343e1b3Sab * change its meaning for subsequent callers. 32845343e1b3Sab */ 32855343e1b3Sab static const Sym fsym = { 0, 0, 0, 32865343e1b3Sab ELF_ST_INFO(STB_LOCAL, STT_OBJECT) }; 32875343e1b3Sab *info = (void *) &fsym; 32885343e1b3Sab } 32895343e1b3Sab 32905343e1b3Sab dlip->dli_sname = MSG_ORIG(MSG_SYM_START); 32915343e1b3Sab dlip->dli_saddr = (void *) ADDR(lmp); 32927c478bd9Sstevel@tonic-gate } 32937c478bd9Sstevel@tonic-gate } 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate static void 3296cce0e03bSab elf_lazy_cleanup(APlist *alp) 32977c478bd9Sstevel@tonic-gate { 3298cce0e03bSab Rt_map *lmp; 3299cce0e03bSab Aliste idx; 33007c478bd9Sstevel@tonic-gate 33017c478bd9Sstevel@tonic-gate /* 33027c478bd9Sstevel@tonic-gate * Cleanup any link-maps added to this dynamic list and free it. 33037c478bd9Sstevel@tonic-gate */ 3304cce0e03bSab for (APLIST_TRAVERSE(alp, idx, lmp)) 330575e7992aSrie FLAGS(lmp) &= ~FLG_RT_TMPLIST; 33067c478bd9Sstevel@tonic-gate free(alp); 33077c478bd9Sstevel@tonic-gate } 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate /* 331075e7992aSrie * This routine is called as a last fall-back to search for a symbol from a 331175e7992aSrie * standard relocation. To maintain lazy loadings goal of reducing the number 33127c478bd9Sstevel@tonic-gate * of objects mapped, any symbol search is first carried out using the objects 33137c478bd9Sstevel@tonic-gate * that already exist in the process (either on a link-map list or handle). 33147c478bd9Sstevel@tonic-gate * If a symbol can't be found, and lazy dependencies are still pending, this 33157c478bd9Sstevel@tonic-gate * routine loads the dependencies in an attempt to locate the symbol. 33167c478bd9Sstevel@tonic-gate * 33177c478bd9Sstevel@tonic-gate * Only new objects are inspected as we will have already inspected presently 33187c478bd9Sstevel@tonic-gate * loaded objects before calling this routine. However, a new object may not 33197c478bd9Sstevel@tonic-gate * be new - although the di_lmp might be zero, the object may have been mapped 33207c478bd9Sstevel@tonic-gate * as someone elses dependency. Thus there's a possibility of some symbol 33217c478bd9Sstevel@tonic-gate * search duplication. 33227c478bd9Sstevel@tonic-gate */ 33237c478bd9Sstevel@tonic-gate Sym * 33249aa23310Srie elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl) 33257c478bd9Sstevel@tonic-gate { 33267c478bd9Sstevel@tonic-gate Sym *sym = 0; 3327cce0e03bSab APlist *alist = NULL; 3328cce0e03bSab Aliste idx; 3329cce0e03bSab Rt_map *lmp1, *lmp = slp->sl_imap; 33307c478bd9Sstevel@tonic-gate const char *name = slp->sl_name; 33317c478bd9Sstevel@tonic-gate 333275e7992aSrie /* 333375e7992aSrie * Generate a local list of new objects to process. This list can grow 333475e7992aSrie * as each object supplies its own lazy dependencies. 333575e7992aSrie */ 3336cce0e03bSab if (aplist_append(&alist, lmp, AL_CNT_LAZYFIND) == NULL) 3337cce0e03bSab return (NULL); 333875e7992aSrie FLAGS(lmp) |= FLG_RT_TMPLIST; 33397c478bd9Sstevel@tonic-gate 3340cce0e03bSab for (APLIST_TRAVERSE(alist, idx, lmp1)) { 33417c478bd9Sstevel@tonic-gate uint_t cnt = 0; 33427c478bd9Sstevel@tonic-gate Slookup sl = *slp; 334375e7992aSrie Dyninfo *dip, *pdip; 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate /* 334675e7992aSrie * Discard any relocation index from further symbol searches. 334775e7992aSrie * This index will have already been used to trigger any 334875e7992aSrie * necessary lazy-loads, and it might be because one of these 334975e7992aSrie * lazy loads have failed that we're here performing this 335075e7992aSrie * fallback. By removing the relocation index we don't try 335175e7992aSrie * and perform the same failed lazy loading activity again. 335275e7992aSrie */ 335375e7992aSrie sl.sl_rsymndx = 0; 335475e7992aSrie 335575e7992aSrie /* 335675e7992aSrie * Loop through the lazy DT_NEEDED entries examining each object 335775e7992aSrie * for the required symbol. If the symbol is not found, the 335875e7992aSrie * object is in turn added to the local alist, so that the 335975e7992aSrie * objects lazy DT_NEEDED entries can be examined. 33607c478bd9Sstevel@tonic-gate */ 3361cce0e03bSab lmp = lmp1; 336275e7992aSrie for (dip = DYNINFO(lmp), pdip = NULL; cnt < DYNINFOCNT(lmp); 336375e7992aSrie cnt++, pdip = dip++) { 33647c478bd9Sstevel@tonic-gate Rt_map *nlmp; 33657c478bd9Sstevel@tonic-gate 336675e7992aSrie if (((dip->di_flags & FLG_DI_LAZY) == 0) || 33677c478bd9Sstevel@tonic-gate dip->di_info) 33687c478bd9Sstevel@tonic-gate continue; 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate /* 337175e7992aSrie * If this object has already failed to lazy load, and 337275e7992aSrie * we're still processing the same runtime linker 337375e7992aSrie * operation that produced the failure, don't bother 337475e7992aSrie * to try and load the object again. 337575e7992aSrie */ 337675e7992aSrie if ((dip->di_flags & FLG_DI_LAZYFAIL) && pdip && 337775e7992aSrie (pdip->di_flags & FLG_DI_POSFLAG1)) { 337875e7992aSrie if (pdip->di_info == (void *)ld_entry_cnt) 337975e7992aSrie continue; 338075e7992aSrie 338175e7992aSrie dip->di_flags &= ~FLG_DI_LAZYFAIL; 338275e7992aSrie pdip->di_info = NULL; 338375e7992aSrie } 338475e7992aSrie 338575e7992aSrie /* 338675e7992aSrie * Try loading this lazy dependency. If the object 338775e7992aSrie * can't be loaded, consider this non-fatal and continue 338875e7992aSrie * the search. Lazy loaded dependencies need not exist 338975e7992aSrie * and their loading should only turn out to be fatal 339075e7992aSrie * if they are required to satisfy a relocation. 33917c478bd9Sstevel@tonic-gate * 33927c478bd9Sstevel@tonic-gate * If the file is already loaded and relocated we must 33937c478bd9Sstevel@tonic-gate * still inspect it for symbols, even though it might 33947c478bd9Sstevel@tonic-gate * have already been searched. This lazy load operation 33957c478bd9Sstevel@tonic-gate * might have promoted the permissions of the object, 33967c478bd9Sstevel@tonic-gate * and thus made the object applicable for this symbol 33977c478bd9Sstevel@tonic-gate * search, whereas before the object might have been 33987c478bd9Sstevel@tonic-gate * skipped. 33997c478bd9Sstevel@tonic-gate */ 34009aa23310Srie if ((nlmp = elf_lazy_load(lmp, &sl, cnt, 34019aa23310Srie name, in_nfavl)) == 0) 34027c478bd9Sstevel@tonic-gate continue; 34037c478bd9Sstevel@tonic-gate 34047c478bd9Sstevel@tonic-gate /* 34057c478bd9Sstevel@tonic-gate * If this object isn't yet a part of the dynamic list 34067c478bd9Sstevel@tonic-gate * then inspect it for the symbol. If the symbol isn't 34077c478bd9Sstevel@tonic-gate * found add the object to the dynamic list so that we 34087c478bd9Sstevel@tonic-gate * can inspect its dependencies. 34097c478bd9Sstevel@tonic-gate */ 341075e7992aSrie if (FLAGS(nlmp) & FLG_RT_TMPLIST) 34117c478bd9Sstevel@tonic-gate continue; 34127c478bd9Sstevel@tonic-gate 34137c478bd9Sstevel@tonic-gate sl.sl_imap = nlmp; 34149aa23310Srie if (sym = LM_LOOKUP_SYM(sl.sl_cmap)(&sl, _lmp, 34159aa23310Srie binfo, in_nfavl)) 34167c478bd9Sstevel@tonic-gate break; 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate /* 34197c478bd9Sstevel@tonic-gate * Some dlsym() operations are already traversing a 34207c478bd9Sstevel@tonic-gate * link-map (dlopen(0)), and thus there's no need to 34217c478bd9Sstevel@tonic-gate * build our own dynamic dependency list. 34227c478bd9Sstevel@tonic-gate */ 34237c478bd9Sstevel@tonic-gate if ((sl.sl_flags & LKUP_NODESCENT) == 0) { 3424cce0e03bSab if (aplist_append(&alist, nlmp, 3425cce0e03bSab AL_CNT_LAZYFIND) == 0) { 34267c478bd9Sstevel@tonic-gate elf_lazy_cleanup(alist); 34277c478bd9Sstevel@tonic-gate return (0); 34287c478bd9Sstevel@tonic-gate } 342975e7992aSrie FLAGS(nlmp) |= FLG_RT_TMPLIST; 34307c478bd9Sstevel@tonic-gate } 34317c478bd9Sstevel@tonic-gate } 34327c478bd9Sstevel@tonic-gate if (sym) 34337c478bd9Sstevel@tonic-gate break; 34347c478bd9Sstevel@tonic-gate } 34357c478bd9Sstevel@tonic-gate 34367c478bd9Sstevel@tonic-gate elf_lazy_cleanup(alist); 34377c478bd9Sstevel@tonic-gate return (sym); 34387c478bd9Sstevel@tonic-gate } 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate /* 34417c478bd9Sstevel@tonic-gate * Warning message for bad r_offset. 34427c478bd9Sstevel@tonic-gate */ 34437c478bd9Sstevel@tonic-gate void 34447c478bd9Sstevel@tonic-gate elf_reloc_bad(Rt_map *lmp, void *rel, uchar_t rtype, ulong_t roffset, 34457c478bd9Sstevel@tonic-gate ulong_t rsymndx) 34467c478bd9Sstevel@tonic-gate { 34477c478bd9Sstevel@tonic-gate const char *name = (char *)0; 34485aefb655Srie Lm_list *lml = LIST(lmp); 34497c478bd9Sstevel@tonic-gate int trace; 34507c478bd9Sstevel@tonic-gate 34515aefb655Srie if ((lml->lm_flags & LML_FLG_TRC_ENABLE) && 34527c478bd9Sstevel@tonic-gate (((rtld_flags & RT_FL_SILENCERR) == 0) || 34535aefb655Srie (lml->lm_flags & LML_FLG_TRC_VERBOSE))) 34547c478bd9Sstevel@tonic-gate trace = 1; 34557c478bd9Sstevel@tonic-gate else 34567c478bd9Sstevel@tonic-gate trace = 0; 34577c478bd9Sstevel@tonic-gate 34585aefb655Srie if ((trace == 0) && (DBG_ENABLED == 0)) 34597c478bd9Sstevel@tonic-gate return; 34607c478bd9Sstevel@tonic-gate 34617c478bd9Sstevel@tonic-gate if (rsymndx) { 34627c478bd9Sstevel@tonic-gate Sym *symref = (Sym *)((ulong_t)SYMTAB(lmp) + 3463a953e2b1Srie (rsymndx * SYMENT(lmp))); 34647c478bd9Sstevel@tonic-gate 34657c478bd9Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) != STB_LOCAL) 34667c478bd9Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + symref->st_name); 34677c478bd9Sstevel@tonic-gate } 34687c478bd9Sstevel@tonic-gate 34697c478bd9Sstevel@tonic-gate if (name == 0) 34707c478bd9Sstevel@tonic-gate name = MSG_ORIG(MSG_STR_EMPTY); 34717c478bd9Sstevel@tonic-gate 34727c478bd9Sstevel@tonic-gate if (trace) { 34737c478bd9Sstevel@tonic-gate const char *rstr; 34747c478bd9Sstevel@tonic-gate 34755aefb655Srie rstr = _conv_reloc_type((uint_t)rtype); 34767c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_REL_ERR1), rstr, name, 34777c478bd9Sstevel@tonic-gate EC_ADDR(roffset)); 34787c478bd9Sstevel@tonic-gate return; 34797c478bd9Sstevel@tonic-gate } 34807c478bd9Sstevel@tonic-gate 34815aefb655Srie Dbg_reloc_error(lml, ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, name); 34827c478bd9Sstevel@tonic-gate } 3483d326b23bSrie 3484d326b23bSrie /* 3485d326b23bSrie * Resolve a static TLS relocation. 3486d326b23bSrie */ 3487d326b23bSrie long 3488d326b23bSrie elf_static_tls(Rt_map *lmp, Sym *sym, void *rel, uchar_t rtype, char *name, 3489d326b23bSrie ulong_t roffset, long value) 3490d326b23bSrie { 3491d326b23bSrie Lm_list *lml = LIST(lmp); 3492d326b23bSrie 3493d326b23bSrie /* 3494d326b23bSrie * Relocations against a static TLS block have limited support once 3495d326b23bSrie * process initialization has completed. Any error condition should be 3496d326b23bSrie * discovered by testing for DF_STATIC_TLS as part of loading an object, 3497d326b23bSrie * however individual relocations are tested in case the dynamic flag 3498d326b23bSrie * had not been set when this object was built. 3499d326b23bSrie */ 3500d326b23bSrie if (PTTLS(lmp) == 0) { 3501d326b23bSrie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, 3502d326b23bSrie M_REL_SHT_TYPE, rel, NULL, name)); 3503d326b23bSrie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS), 3504d326b23bSrie _conv_reloc_type((uint_t)rtype), NAME(lmp), 3505d326b23bSrie name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)); 3506d326b23bSrie return (0); 3507d326b23bSrie } 3508d326b23bSrie 3509d326b23bSrie /* 3510d326b23bSrie * If no static TLS has been set aside for this object, determine if 3511d326b23bSrie * any can be obtained. Enforce that any object using static TLS is 3512d326b23bSrie * non-deletable. 3513d326b23bSrie */ 3514d326b23bSrie if (TLSSTATOFF(lmp) == 0) { 3515d326b23bSrie FLAGS1(lmp) |= FL1_RT_TLSSTAT; 3516d326b23bSrie MODE(lmp) |= RTLD_NODELETE; 3517d326b23bSrie 3518d326b23bSrie if (tls_assign(lml, lmp, PTTLS(lmp)) == 0) { 3519d326b23bSrie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, 3520d326b23bSrie M_REL_SHT_TYPE, rel, NULL, name)); 3521d326b23bSrie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS), 3522d326b23bSrie _conv_reloc_type((uint_t)rtype), NAME(lmp), 3523d326b23bSrie name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)); 3524d326b23bSrie return (0); 3525d326b23bSrie } 3526d326b23bSrie } 3527d326b23bSrie 3528d326b23bSrie /* 3529d326b23bSrie * Typically, a static TLS offset is maintained as a symbols value. 3530d326b23bSrie * For local symbols that are not apart of the dynamic symbol table, 3531d326b23bSrie * the TLS relocation points to a section symbol, and the static TLS 3532d326b23bSrie * offset was deposited in the associated GOT table. Make sure the GOT 3533d326b23bSrie * is cleared, so that the value isn't reused in do_reloc(). 3534d326b23bSrie */ 3535d326b23bSrie if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 3536d326b23bSrie if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION)) { 3537d326b23bSrie value = *(long *)roffset; 3538d326b23bSrie *(long *)roffset = 0; 3539d326b23bSrie } else { 3540d326b23bSrie value = sym->st_value; 3541d326b23bSrie } 3542d326b23bSrie } 3543d326b23bSrie return (-(TLSSTATOFF(lmp) - value)); 3544d326b23bSrie } 3545dae2dfb7Srie 3546dae2dfb7Srie /* 3547dae2dfb7Srie * If the symbol is not found and the reference was not to a weak symbol, report 3548dae2dfb7Srie * an error. Weak references may be unresolved. 3549dae2dfb7Srie */ 3550dae2dfb7Srie int 3551dae2dfb7Srie elf_reloc_error(Rt_map *lmp, const char *name, void *rel, uint_t binfo) 3552dae2dfb7Srie { 3553dae2dfb7Srie Lm_list *lml = LIST(lmp); 3554dae2dfb7Srie 3555dae2dfb7Srie /* 3556dae2dfb7Srie * Under crle(1), relocation failures are ignored. 3557dae2dfb7Srie */ 3558dae2dfb7Srie if (lml->lm_flags & LML_FLG_IGNRELERR) 3559dae2dfb7Srie return (1); 3560dae2dfb7Srie 3561dae2dfb7Srie /* 3562dae2dfb7Srie * Under ldd(1), unresolved references are reported. However, if the 3563dae2dfb7Srie * original reference is EXTERN or PARENT these references are ignored 3564dae2dfb7Srie * unless ldd's -p option is in effect. 3565dae2dfb7Srie */ 3566dae2dfb7Srie if (lml->lm_flags & LML_FLG_TRC_WARN) { 3567dae2dfb7Srie if (((binfo & DBG_BINFO_REF_MSK) == 0) || 3568dae2dfb7Srie ((lml->lm_flags & LML_FLG_TRC_NOPAREXT) != 0)) { 3569dae2dfb7Srie (void) printf(MSG_INTL(MSG_LDD_SYM_NFOUND), 3570dae2dfb7Srie demangle(name), NAME(lmp)); 3571dae2dfb7Srie } 3572dae2dfb7Srie return (1); 3573dae2dfb7Srie } 3574dae2dfb7Srie 3575dae2dfb7Srie /* 3576dae2dfb7Srie * Otherwise, the unresolved references is fatal. 3577dae2dfb7Srie */ 3578dae2dfb7Srie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, 3579dae2dfb7Srie NULL, name)); 3580dae2dfb7Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 3581dae2dfb7Srie demangle(name)); 3582dae2dfb7Srie 3583dae2dfb7Srie return (0); 3584dae2dfb7Srie } 3585