10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51618Srie * Common Development and Distribution License (the "License").
61618Srie * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211109Srie
220Sstevel@tonic-gate /*
236812Sraf * Copyright (c) 1988 AT&T
246812Sraf * All Rights Reserved
2512449SRod.Evans@Sun.COM *
2612449SRod.Evans@Sun.COM * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
276812Sraf */
286812Sraf
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Utility routines for run-time linker. some are duplicated here from libc
310Sstevel@tonic-gate * (with different names) to avoid name space collisions.
320Sstevel@tonic-gate */
3311827SRod.Evans@Sun.COM #include <sys/systeminfo.h>
340Sstevel@tonic-gate #include <stdio.h>
359577SRod.Evans@Sun.COM #include <sys/time.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/mman.h>
380Sstevel@tonic-gate #include <sys/lwp.h>
390Sstevel@tonic-gate #include <sys/debug.h>
400Sstevel@tonic-gate #include <stdarg.h>
410Sstevel@tonic-gate #include <fcntl.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <dlfcn.h>
440Sstevel@tonic-gate #include <unistd.h>
450Sstevel@tonic-gate #include <stdlib.h>
468598SRod.Evans@Sun.COM #include <sys/auxv.h>
477668SRod.Evans@Sun.COM #include <limits.h>
481618Srie #include <debug.h>
491618Srie #include <conv.h>
500Sstevel@tonic-gate #include "_rtld.h"
510Sstevel@tonic-gate #include "_audit.h"
521824Srie #include "_elf.h"
530Sstevel@tonic-gate #include "msg.h"
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate * Null function used as place where a debugger can set a breakpoint.
570Sstevel@tonic-gate */
580Sstevel@tonic-gate void
rtld_db_dlactivity(Lm_list * lml)591618Srie rtld_db_dlactivity(Lm_list *lml)
600Sstevel@tonic-gate {
611618Srie DBG_CALL(Dbg_util_dbnotify(lml, r_debug.rtd_rdebug.r_rdevent,
621618Srie r_debug.rtd_rdebug.r_state));
630Sstevel@tonic-gate }
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * Null function used as place where debugger can set a pre .init
670Sstevel@tonic-gate * processing breakpoint.
680Sstevel@tonic-gate */
690Sstevel@tonic-gate void
rtld_db_preinit(Lm_list * lml)701618Srie rtld_db_preinit(Lm_list *lml)
710Sstevel@tonic-gate {
721618Srie DBG_CALL(Dbg_util_dbnotify(lml, r_debug.rtd_rdebug.r_rdevent,
731618Srie r_debug.rtd_rdebug.r_state));
740Sstevel@tonic-gate }
750Sstevel@tonic-gate
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate * Null function used as place where debugger can set a post .init
780Sstevel@tonic-gate * processing breakpoint.
790Sstevel@tonic-gate */
800Sstevel@tonic-gate void
rtld_db_postinit(Lm_list * lml)811618Srie rtld_db_postinit(Lm_list *lml)
820Sstevel@tonic-gate {
831618Srie DBG_CALL(Dbg_util_dbnotify(lml, r_debug.rtd_rdebug.r_rdevent,
841618Srie r_debug.rtd_rdebug.r_state));
850Sstevel@tonic-gate }
860Sstevel@tonic-gate
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate * Debugger Event Notification
890Sstevel@tonic-gate *
900Sstevel@tonic-gate * This function centralizes all debugger event notification (ala rtld_db).
910Sstevel@tonic-gate *
920Sstevel@tonic-gate * There's a simple intent, focused on insuring the primary link-map control
930Sstevel@tonic-gate * list (or each link-map list) is consistent, and the indication that objects
940Sstevel@tonic-gate * have been added or deleted from this list. Although an RD_ADD and RD_DELETE
950Sstevel@tonic-gate * event are posted for each of these, most debuggers don't care, as their
960Sstevel@tonic-gate * view is that these events simply convey an "inconsistent" state.
970Sstevel@tonic-gate *
980Sstevel@tonic-gate * We also don't want to trigger multiple RD_ADD/RD_DELETE events any time we
990Sstevel@tonic-gate * enter ld.so.1.
1000Sstevel@tonic-gate *
10112877SRod.Evans@Sun.COM * Set an RD_ADD/RD_DELETE event and indicate that an RD_CONSISTENT event is
10212877SRod.Evans@Sun.COM * required later (RT_FL_DBNOTIF):
1030Sstevel@tonic-gate *
10412877SRod.Evans@Sun.COM * i. the first time we add or delete an object to the primary link-map
1050Sstevel@tonic-gate * control list.
10612877SRod.Evans@Sun.COM * ii. the first time we move a secondary link-map control list to the primary
1070Sstevel@tonic-gate * link-map control list (effectively, this is like adding a group of
1080Sstevel@tonic-gate * objects to the primary link-map control list).
1090Sstevel@tonic-gate *
11012877SRod.Evans@Sun.COM * Set an RD_CONSISTENT event when it is required (RT_FL_DBNOTIF is set):
1110Sstevel@tonic-gate *
11212877SRod.Evans@Sun.COM * i. each time we leave the runtime linker.
1130Sstevel@tonic-gate */
1140Sstevel@tonic-gate void
rd_event(Lm_list * lml,rd_event_e event,r_state_e state)1150Sstevel@tonic-gate rd_event(Lm_list *lml, rd_event_e event, r_state_e state)
1160Sstevel@tonic-gate {
1171824Srie void (*fptr)(Lm_list *);
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate switch (event) {
1200Sstevel@tonic-gate case RD_PREINIT:
1210Sstevel@tonic-gate fptr = rtld_db_preinit;
1220Sstevel@tonic-gate break;
1230Sstevel@tonic-gate case RD_POSTINIT:
1240Sstevel@tonic-gate fptr = rtld_db_postinit;
1250Sstevel@tonic-gate break;
1260Sstevel@tonic-gate case RD_DLACTIVITY:
1270Sstevel@tonic-gate switch (state) {
1280Sstevel@tonic-gate case RT_CONSISTENT:
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate * Do we need to send a notification?
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate if ((rtld_flags & RT_FL_DBNOTIF) == 0)
1330Sstevel@tonic-gate return;
1340Sstevel@tonic-gate rtld_flags &= ~RT_FL_DBNOTIF;
1350Sstevel@tonic-gate break;
1360Sstevel@tonic-gate case RT_ADD:
1370Sstevel@tonic-gate case RT_DELETE:
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate * If we are already in an inconsistent state, no
1400Sstevel@tonic-gate * notification is required.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate if (rtld_flags & RT_FL_DBNOTIF)
1430Sstevel@tonic-gate return;
1440Sstevel@tonic-gate rtld_flags |= RT_FL_DBNOTIF;
1450Sstevel@tonic-gate break;
1460Sstevel@tonic-gate };
1470Sstevel@tonic-gate fptr = rtld_db_dlactivity;
1480Sstevel@tonic-gate break;
1490Sstevel@tonic-gate default:
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * RD_NONE - do nothing
1520Sstevel@tonic-gate */
1530Sstevel@tonic-gate break;
1540Sstevel@tonic-gate };
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate * Set event state and call 'notification' function.
1580Sstevel@tonic-gate *
1590Sstevel@tonic-gate * The debugging clients have previously been told about these
1600Sstevel@tonic-gate * notification functions and have set breakpoints on them if they
1610Sstevel@tonic-gate * are interested in the notification.
1620Sstevel@tonic-gate */
1630Sstevel@tonic-gate r_debug.rtd_rdebug.r_state = state;
1640Sstevel@tonic-gate r_debug.rtd_rdebug.r_rdevent = event;
1651618Srie fptr(lml);
1660Sstevel@tonic-gate r_debug.rtd_rdebug.r_rdevent = RD_NONE;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1693731Srie #if defined(__sparc) || defined(__x86)
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * Stack Cleanup.
1720Sstevel@tonic-gate *
1730Sstevel@tonic-gate * This function is invoked to 'remove' arguments that were passed in on the
1740Sstevel@tonic-gate * stack. This is most likely if ld.so.1 was invoked directly. In that case
1750Sstevel@tonic-gate * we want to remove ld.so.1 as well as it's arguments from the argv[] array.
1760Sstevel@tonic-gate * Which means we then need to slide everything above it on the stack down
1770Sstevel@tonic-gate * accordingly.
1780Sstevel@tonic-gate *
1793731Srie * While the stack layout is platform specific - it just so happens that __x86,
1803731Srie * and __sparc platforms share the following initial stack layout.
1810Sstevel@tonic-gate *
1820Sstevel@tonic-gate * !_______________________! high addresses
1830Sstevel@tonic-gate * ! !
1840Sstevel@tonic-gate * ! Information !
1850Sstevel@tonic-gate * ! Block !
1860Sstevel@tonic-gate * ! (size varies) !
1870Sstevel@tonic-gate * !_______________________!
1880Sstevel@tonic-gate * ! 0 word !
1890Sstevel@tonic-gate * !_______________________!
1900Sstevel@tonic-gate * ! Auxiliary !
1910Sstevel@tonic-gate * ! vector !
1920Sstevel@tonic-gate * ! 2 word entries !
1930Sstevel@tonic-gate * ! !
1940Sstevel@tonic-gate * !_______________________!
1950Sstevel@tonic-gate * ! 0 word !
1960Sstevel@tonic-gate * !_______________________!
1970Sstevel@tonic-gate * ! Environment !
1980Sstevel@tonic-gate * ! pointers !
1990Sstevel@tonic-gate * ! ... !
2000Sstevel@tonic-gate * ! (one word each) !
2010Sstevel@tonic-gate * !_______________________!
2020Sstevel@tonic-gate * ! 0 word !
2030Sstevel@tonic-gate * !_______________________!
2040Sstevel@tonic-gate * ! Argument ! low addresses
2050Sstevel@tonic-gate * ! pointers !
2060Sstevel@tonic-gate * ! Argc words !
2070Sstevel@tonic-gate * !_______________________!
2080Sstevel@tonic-gate * ! !
2090Sstevel@tonic-gate * ! Argc !
2100Sstevel@tonic-gate * !_______________________!
2110Sstevel@tonic-gate * ! ... !
2120Sstevel@tonic-gate *
2130Sstevel@tonic-gate */
2140Sstevel@tonic-gate static void
stack_cleanup(char ** argv,char *** envp,auxv_t ** auxv,int rmcnt)2156Srie stack_cleanup(char **argv, char ***envp, auxv_t **auxv, int rmcnt)
2160Sstevel@tonic-gate {
2176Srie int ndx;
2180Sstevel@tonic-gate long *argc;
2196Srie char **oargv, **nargv;
2206Srie char **oenvp, **nenvp;
2216Srie auxv_t *oauxv, *nauxv;
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /*
2246Srie * Slide ARGV[] and update argc. The argv pointer remains the same,
2256Srie * however slide the applications arguments over the arguments to
2266Srie * ld.so.1.
2270Sstevel@tonic-gate */
2286Srie nargv = &argv[0];
2296Srie oargv = &argv[rmcnt];
2306Srie
2316Srie for (ndx = 0; oargv[ndx]; ndx++)
2326Srie nargv[ndx] = oargv[ndx];
2336Srie nargv[ndx] = oargv[ndx];
2346Srie
2356Srie argc = (long *)((uintptr_t)argv - sizeof (long *));
2360Sstevel@tonic-gate *argc -= rmcnt;
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate /*
2396Srie * Slide ENVP[], and update the environment array pointer.
2400Sstevel@tonic-gate */
2416Srie ndx++;
2426Srie nenvp = &nargv[ndx];
2436Srie oenvp = &oargv[ndx];
2446Srie *envp = nenvp;
2456Srie
2466Srie for (ndx = 0; oenvp[ndx]; ndx++)
2476Srie nenvp[ndx] = oenvp[ndx];
2486Srie nenvp[ndx] = oenvp[ndx];
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /*
2516Srie * Slide AUXV[], and update the aux vector pointer.
2520Sstevel@tonic-gate */
2536Srie ndx++;
2546Srie nauxv = (auxv_t *)&nenvp[ndx];
2556Srie oauxv = (auxv_t *)&oenvp[ndx];
2566Srie *auxv = nauxv;
2576Srie
2586Srie for (ndx = 0; (oauxv[ndx].a_type != AT_NULL); ndx++)
2596Srie nauxv[ndx] = oauxv[ndx];
2606Srie nauxv[ndx] = oauxv[ndx];
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate #else
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Verify that the above routine is appropriate for any new platforms.
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate #error unsupported architecture!
2670Sstevel@tonic-gate #endif
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /*
2706387Srie * Compare function for PathNode AVL tree.
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate static int
pnavl_compare(const void * n1,const void * n2)2736387Srie pnavl_compare(const void *n1, const void *n2)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate uint_t hash1, hash2;
2760Sstevel@tonic-gate const char *st1, *st2;
2770Sstevel@tonic-gate int rc;
2780Sstevel@tonic-gate
2796387Srie hash1 = ((PathNode *)n1)->pn_hash;
2806387Srie hash2 = ((PathNode *)n2)->pn_hash;
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate if (hash1 > hash2)
2830Sstevel@tonic-gate return (1);
2840Sstevel@tonic-gate if (hash1 < hash2)
2850Sstevel@tonic-gate return (-1);
2860Sstevel@tonic-gate
2876387Srie st1 = ((PathNode *)n1)->pn_name;
2886387Srie st2 = ((PathNode *)n2)->pn_name;
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate rc = strcmp(st1, st2);
2910Sstevel@tonic-gate if (rc > 0)
2920Sstevel@tonic-gate return (1);
2930Sstevel@tonic-gate if (rc < 0)
2940Sstevel@tonic-gate return (-1);
2950Sstevel@tonic-gate return (0);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate /*
2997668SRod.Evans@Sun.COM * Create an AVL tree.
3007668SRod.Evans@Sun.COM */
3017668SRod.Evans@Sun.COM static avl_tree_t *
pnavl_create(size_t size)3027668SRod.Evans@Sun.COM pnavl_create(size_t size)
3037668SRod.Evans@Sun.COM {
3047668SRod.Evans@Sun.COM avl_tree_t *avlt;
3057668SRod.Evans@Sun.COM
3067668SRod.Evans@Sun.COM if ((avlt = malloc(sizeof (avl_tree_t))) == NULL)
3077668SRod.Evans@Sun.COM return (NULL);
3087668SRod.Evans@Sun.COM avl_create(avlt, pnavl_compare, size, SGSOFFSETOF(PathNode, pn_avl));
3097668SRod.Evans@Sun.COM return (avlt);
3107668SRod.Evans@Sun.COM }
3117668SRod.Evans@Sun.COM
3127668SRod.Evans@Sun.COM /*
31311827SRod.Evans@Sun.COM * Determine whether a PathNode is recorded.
31411827SRod.Evans@Sun.COM */
31511827SRod.Evans@Sun.COM int
pnavl_recorded(avl_tree_t ** pnavl,const char * name,uint_t hash,avl_index_t * where)31611827SRod.Evans@Sun.COM pnavl_recorded(avl_tree_t **pnavl, const char *name, uint_t hash,
31711827SRod.Evans@Sun.COM avl_index_t *where)
31811827SRod.Evans@Sun.COM {
31911827SRod.Evans@Sun.COM PathNode pn;
32011827SRod.Evans@Sun.COM
32111827SRod.Evans@Sun.COM /*
32211827SRod.Evans@Sun.COM * Create the avl tree if required.
32311827SRod.Evans@Sun.COM */
32411827SRod.Evans@Sun.COM if ((*pnavl == NULL) &&
32511827SRod.Evans@Sun.COM ((*pnavl = pnavl_create(sizeof (PathNode))) == NULL))
32611827SRod.Evans@Sun.COM return (0);
32711827SRod.Evans@Sun.COM
32811827SRod.Evans@Sun.COM pn.pn_name = name;
32911827SRod.Evans@Sun.COM if ((pn.pn_hash = hash) == 0)
33011827SRod.Evans@Sun.COM pn.pn_hash = sgs_str_hash(name);
33111827SRod.Evans@Sun.COM
33211827SRod.Evans@Sun.COM if (avl_find(*pnavl, &pn, where) == NULL)
33311827SRod.Evans@Sun.COM return (0);
33411827SRod.Evans@Sun.COM
33511827SRod.Evans@Sun.COM return (1);
33611827SRod.Evans@Sun.COM }
33711827SRod.Evans@Sun.COM
33811827SRod.Evans@Sun.COM /*
3396387Srie * Determine if a pathname has already been recorded on the full path name
3406387Srie * AVL tree. This tree maintains a node for each path name that ld.so.1 has
3416387Srie * successfully loaded. If the path name does not exist in this AVL tree, then
3426387Srie * the next insertion point is deposited in "where". This value can be used by
3436387Srie * fpavl_insert() to expedite the insertion.
3440Sstevel@tonic-gate */
3450Sstevel@tonic-gate Rt_map *
fpavl_recorded(Lm_list * lml,const char * name,uint_t hash,avl_index_t * where)3468598SRod.Evans@Sun.COM fpavl_recorded(Lm_list *lml, const char *name, uint_t hash, avl_index_t *where)
3470Sstevel@tonic-gate {
3486387Srie FullPathNode fpn, *fpnp;
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate /*
3510Sstevel@tonic-gate * Create the avl tree if required.
3520Sstevel@tonic-gate */
3537668SRod.Evans@Sun.COM if ((lml->lm_fpavl == NULL) &&
3547668SRod.Evans@Sun.COM ((lml->lm_fpavl = pnavl_create(sizeof (FullPathNode))) == NULL))
3557668SRod.Evans@Sun.COM return (NULL);
3560Sstevel@tonic-gate
3576387Srie fpn.fpn_node.pn_name = name;
3588598SRod.Evans@Sun.COM if ((fpn.fpn_node.pn_hash = hash) == 0)
3598598SRod.Evans@Sun.COM fpn.fpn_node.pn_hash = sgs_str_hash(name);
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate if ((fpnp = avl_find(lml->lm_fpavl, &fpn, where)) == NULL)
3620Sstevel@tonic-gate return (NULL);
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate return (fpnp->fpn_lmp);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate /*
3686387Srie * Insert a name into the FullPathNode AVL tree for the link-map list. The
369422Srie * objects NAME() is the path that would have originally been searched for, and
370422Srie * is therefore the name to associate with any "where" value. If the object has
3710Sstevel@tonic-gate * a different PATHNAME(), perhaps because it has resolved to a different file
3726387Srie * (see fullpath()), then this name will be recorded as a separate FullPathNode
3736387Srie * (see load_file()).
3740Sstevel@tonic-gate */
3750Sstevel@tonic-gate int
fpavl_insert(Lm_list * lml,Rt_map * lmp,const char * name,avl_index_t where)3760Sstevel@tonic-gate fpavl_insert(Lm_list *lml, Rt_map *lmp, const char *name, avl_index_t where)
3770Sstevel@tonic-gate {
3786387Srie FullPathNode *fpnp;
3798598SRod.Evans@Sun.COM uint_t hash = sgs_str_hash(name);
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate if (where == 0) {
3820Sstevel@tonic-gate /* LINTED */
3838598SRod.Evans@Sun.COM Rt_map *_lmp = fpavl_recorded(lml, name, hash, &where);
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate * We better not get a hit now, we do not want duplicates in
3870Sstevel@tonic-gate * the tree.
3880Sstevel@tonic-gate */
3898883SRod.Evans@Sun.COM ASSERT(_lmp == NULL);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate /*
3936387Srie * Insert new node in tree.
3940Sstevel@tonic-gate */
3957668SRod.Evans@Sun.COM if ((fpnp = calloc(sizeof (FullPathNode), 1)) == NULL)
3960Sstevel@tonic-gate return (0);
3970Sstevel@tonic-gate
3986387Srie fpnp->fpn_node.pn_name = name;
3998598SRod.Evans@Sun.COM fpnp->fpn_node.pn_hash = hash;
4000Sstevel@tonic-gate fpnp->fpn_lmp = lmp;
4010Sstevel@tonic-gate
4025892Sab196087 if (aplist_append(&FPNODE(lmp), fpnp, AL_CNT_FPNODE) == NULL) {
4030Sstevel@tonic-gate free(fpnp);
4040Sstevel@tonic-gate return (0);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate ASSERT(lml->lm_fpavl != NULL);
4080Sstevel@tonic-gate avl_insert(lml->lm_fpavl, fpnp, where);
4090Sstevel@tonic-gate return (1);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate /*
4138598SRod.Evans@Sun.COM * Remove an object from the FullPathNode AVL tree.
4140Sstevel@tonic-gate */
4150Sstevel@tonic-gate void
fpavl_remove(Rt_map * lmp)4160Sstevel@tonic-gate fpavl_remove(Rt_map *lmp)
4170Sstevel@tonic-gate {
4186387Srie FullPathNode *fpnp;
4195892Sab196087 Aliste idx;
4205892Sab196087
4215892Sab196087 for (APLIST_TRAVERSE(FPNODE(lmp), idx, fpnp)) {
4220Sstevel@tonic-gate avl_remove(LIST(lmp)->lm_fpavl, fpnp);
4230Sstevel@tonic-gate free(fpnp);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate free(FPNODE(lmp));
4265892Sab196087 FPNODE(lmp) = NULL;
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4296387Srie /*
43011827SRod.Evans@Sun.COM * Insert a path name into the not-found AVL tree.
43111827SRod.Evans@Sun.COM *
4326387Srie * This tree maintains a node for each path name that ld.so.1 has explicitly
4336387Srie * inspected, but has failed to load during a single ld.so.1 operation. If the
4346387Srie * path name does not exist in this AVL tree, then the next insertion point is
4356387Srie * deposited in "where". This value can be used by nfavl_insert() to expedite
4366387Srie * the insertion.
4376387Srie */
4386387Srie void
nfavl_insert(const char * name,avl_index_t where)4396387Srie nfavl_insert(const char *name, avl_index_t where)
4406387Srie {
4416387Srie PathNode *pnp;
4428598SRod.Evans@Sun.COM uint_t hash = sgs_str_hash(name);
4436387Srie
4446387Srie if (where == 0) {
4456387Srie /* LINTED */
44611827SRod.Evans@Sun.COM int in_nfavl = pnavl_recorded(&nfavl, name, hash, &where);
4476387Srie
4486387Srie /*
4496387Srie * We better not get a hit now, we do not want duplicates in
4506387Srie * the tree.
4516387Srie */
4526387Srie ASSERT(in_nfavl == 0);
4536387Srie }
4546387Srie
4556387Srie /*
4566387Srie * Insert new node in tree.
4576387Srie */
4588598SRod.Evans@Sun.COM if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) {
4596387Srie pnp->pn_name = name;
4608598SRod.Evans@Sun.COM pnp->pn_hash = hash;
4616387Srie avl_insert(nfavl, pnp, where);
4626387Srie }
4636387Srie }
4640Sstevel@tonic-gate
4657668SRod.Evans@Sun.COM /*
46611827SRod.Evans@Sun.COM * Insert the directory name, of a full path name, into the secure path AVL
4677668SRod.Evans@Sun.COM * tree.
46811827SRod.Evans@Sun.COM *
46911827SRod.Evans@Sun.COM * This tree is used to maintain a list of directories in which the dependencies
47011827SRod.Evans@Sun.COM * of a secure process have been found. This list provides a fall-back in the
47111827SRod.Evans@Sun.COM * case that a $ORIGIN expansion is deemed insecure, when the expansion results
47211827SRod.Evans@Sun.COM * in a path name that has already provided dependencies.
4737668SRod.Evans@Sun.COM */
4747668SRod.Evans@Sun.COM void
spavl_insert(const char * name)4757668SRod.Evans@Sun.COM spavl_insert(const char *name)
4767668SRod.Evans@Sun.COM {
4777668SRod.Evans@Sun.COM char buffer[PATH_MAX], *str;
4787668SRod.Evans@Sun.COM size_t size;
4797668SRod.Evans@Sun.COM avl_index_t where;
4807668SRod.Evans@Sun.COM PathNode *pnp;
48111827SRod.Evans@Sun.COM uint_t hash;
4827668SRod.Evans@Sun.COM
4837668SRod.Evans@Sun.COM /*
4847668SRod.Evans@Sun.COM * Separate the directory name from the path name.
4857668SRod.Evans@Sun.COM */
4867668SRod.Evans@Sun.COM if ((str = strrchr(name, '/')) == name)
4877668SRod.Evans@Sun.COM size = 1;
4887668SRod.Evans@Sun.COM else
4897668SRod.Evans@Sun.COM size = str - name;
4907668SRod.Evans@Sun.COM
4917668SRod.Evans@Sun.COM (void) strncpy(buffer, name, size);
4927668SRod.Evans@Sun.COM buffer[size] = '\0';
49311827SRod.Evans@Sun.COM hash = sgs_str_hash(buffer);
4947668SRod.Evans@Sun.COM
4957668SRod.Evans@Sun.COM /*
4967668SRod.Evans@Sun.COM * Determine whether this directory name is already recorded, or if
4977668SRod.Evans@Sun.COM * not, 'where" will provide the insertion point for the new string.
4987668SRod.Evans@Sun.COM */
49911827SRod.Evans@Sun.COM if (pnavl_recorded(&spavl, buffer, hash, &where))
5007668SRod.Evans@Sun.COM return;
5017668SRod.Evans@Sun.COM
5027668SRod.Evans@Sun.COM /*
5037668SRod.Evans@Sun.COM * Insert new node in tree.
5047668SRod.Evans@Sun.COM */
5058883SRod.Evans@Sun.COM if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) {
5067668SRod.Evans@Sun.COM pnp->pn_name = strdup(buffer);
50711827SRod.Evans@Sun.COM pnp->pn_hash = hash;
5087668SRod.Evans@Sun.COM avl_insert(spavl, pnp, where);
5097668SRod.Evans@Sun.COM }
5107668SRod.Evans@Sun.COM }
5117668SRod.Evans@Sun.COM
5120Sstevel@tonic-gate /*
5138598SRod.Evans@Sun.COM * Inspect the generic string AVL tree for the given string. If the string is
5148598SRod.Evans@Sun.COM * not present, duplicate it, and insert the string in the AVL tree. Return the
5158598SRod.Evans@Sun.COM * duplicated string to the caller.
5168598SRod.Evans@Sun.COM *
5178598SRod.Evans@Sun.COM * These strings are maintained for the life of ld.so.1 and represent path
5188598SRod.Evans@Sun.COM * names, file names, and search paths. All other AVL trees that maintain
5198598SRod.Evans@Sun.COM * FullPathNode and not-found path names use the same string pointer
5208598SRod.Evans@Sun.COM * established for this string.
5218598SRod.Evans@Sun.COM */
5228598SRod.Evans@Sun.COM static avl_tree_t *stravl = NULL;
5238598SRod.Evans@Sun.COM static char *strbuf = NULL;
5248598SRod.Evans@Sun.COM static PathNode *pnbuf = NULL;
5258598SRod.Evans@Sun.COM static size_t strsize = 0, pnsize = 0;
5268598SRod.Evans@Sun.COM
5278598SRod.Evans@Sun.COM const char *
stravl_insert(const char * name,uint_t hash,size_t nsize,int substr)5288598SRod.Evans@Sun.COM stravl_insert(const char *name, uint_t hash, size_t nsize, int substr)
5298598SRod.Evans@Sun.COM {
5308598SRod.Evans@Sun.COM char str[PATH_MAX];
5318598SRod.Evans@Sun.COM PathNode *pnp;
5328598SRod.Evans@Sun.COM avl_index_t where;
5338598SRod.Evans@Sun.COM
5348598SRod.Evans@Sun.COM /*
5358598SRod.Evans@Sun.COM * Create the avl tree if required.
5368598SRod.Evans@Sun.COM */
5378598SRod.Evans@Sun.COM if ((stravl == NULL) &&
5388598SRod.Evans@Sun.COM ((stravl = pnavl_create(sizeof (PathNode))) == NULL))
5398598SRod.Evans@Sun.COM return (NULL);
5408598SRod.Evans@Sun.COM
5418598SRod.Evans@Sun.COM /*
5428598SRod.Evans@Sun.COM * Determine the string size if not provided by the caller.
5438598SRod.Evans@Sun.COM */
5448598SRod.Evans@Sun.COM if (nsize == 0)
5458598SRod.Evans@Sun.COM nsize = strlen(name) + 1;
5468598SRod.Evans@Sun.COM else if (substr) {
5478598SRod.Evans@Sun.COM /*
5488598SRod.Evans@Sun.COM * The string passed to us may be a multiple path string for
5498598SRod.Evans@Sun.COM * which we only need the first component. Using the provided
5508598SRod.Evans@Sun.COM * size, strip out the required string.
5518598SRod.Evans@Sun.COM */
5528598SRod.Evans@Sun.COM (void) strncpy(str, name, nsize);
5538598SRod.Evans@Sun.COM str[nsize - 1] = '\0';
5548598SRod.Evans@Sun.COM name = str;
5558598SRod.Evans@Sun.COM }
5568598SRod.Evans@Sun.COM
5578598SRod.Evans@Sun.COM /*
5588598SRod.Evans@Sun.COM * Allocate a PathNode buffer if one doesn't exist, or any existing
5598598SRod.Evans@Sun.COM * buffer has been used up.
5608598SRod.Evans@Sun.COM */
5618598SRod.Evans@Sun.COM if ((pnbuf == NULL) || (sizeof (PathNode) > pnsize)) {
5628598SRod.Evans@Sun.COM pnsize = syspagsz;
5638598SRod.Evans@Sun.COM if ((pnbuf = dz_map(0, 0, pnsize, (PROT_READ | PROT_WRITE),
5648598SRod.Evans@Sun.COM MAP_PRIVATE)) == MAP_FAILED)
5658598SRod.Evans@Sun.COM return (NULL);
5668598SRod.Evans@Sun.COM }
5678598SRod.Evans@Sun.COM /*
5688598SRod.Evans@Sun.COM * Determine whether this string already exists.
5698598SRod.Evans@Sun.COM */
5708598SRod.Evans@Sun.COM pnbuf->pn_name = name;
5718598SRod.Evans@Sun.COM if ((pnbuf->pn_hash = hash) == 0)
5728598SRod.Evans@Sun.COM pnbuf->pn_hash = sgs_str_hash(name);
5738598SRod.Evans@Sun.COM
5748598SRod.Evans@Sun.COM if ((pnp = avl_find(stravl, pnbuf, &where)) != NULL)
5758598SRod.Evans@Sun.COM return (pnp->pn_name);
5768598SRod.Evans@Sun.COM
5778598SRod.Evans@Sun.COM /*
5788598SRod.Evans@Sun.COM * Allocate a string buffer if one does not exist, or if there is
5798598SRod.Evans@Sun.COM * insufficient space for the new string in any existing buffer.
5808598SRod.Evans@Sun.COM */
5818598SRod.Evans@Sun.COM if ((strbuf == NULL) || (nsize > strsize)) {
5828598SRod.Evans@Sun.COM strsize = S_ROUND(nsize, syspagsz);
5838598SRod.Evans@Sun.COM
5848598SRod.Evans@Sun.COM if ((strbuf = dz_map(0, 0, strsize, (PROT_READ | PROT_WRITE),
5858598SRod.Evans@Sun.COM MAP_PRIVATE)) == MAP_FAILED)
5868598SRod.Evans@Sun.COM return (NULL);
5878598SRod.Evans@Sun.COM }
5888598SRod.Evans@Sun.COM
5898598SRod.Evans@Sun.COM (void) memcpy(strbuf, name, nsize);
5908598SRod.Evans@Sun.COM pnp = pnbuf;
5918598SRod.Evans@Sun.COM pnp->pn_name = strbuf;
5928598SRod.Evans@Sun.COM avl_insert(stravl, pnp, where);
5938598SRod.Evans@Sun.COM
5948598SRod.Evans@Sun.COM strbuf += nsize;
5958598SRod.Evans@Sun.COM strsize -= nsize;
5968598SRod.Evans@Sun.COM pnbuf++;
5978598SRod.Evans@Sun.COM pnsize -= sizeof (PathNode);
5988598SRod.Evans@Sun.COM return (pnp->pn_name);
5998598SRod.Evans@Sun.COM }
6008598SRod.Evans@Sun.COM
6018598SRod.Evans@Sun.COM /*
6020Sstevel@tonic-gate * Prior to calling an object, either via a .plt or through dlsym(), make sure
6030Sstevel@tonic-gate * its .init has fired. Through topological sorting, ld.so.1 attempts to fire
6040Sstevel@tonic-gate * init's in the correct order, however, this order is typically based on needed
6050Sstevel@tonic-gate * dependencies and non-lazy relocation bindings. Lazy relocations (.plts) can
6060Sstevel@tonic-gate * still occur and result in bindings that were not captured during topological
6070Sstevel@tonic-gate * sorting. This routine compensates for this lack of binding information, and
6080Sstevel@tonic-gate * provides for dynamic .init firing.
6090Sstevel@tonic-gate */
6100Sstevel@tonic-gate void
is_dep_init(Rt_map * dlmp,Rt_map * clmp)6116387Srie is_dep_init(Rt_map *dlmp, Rt_map *clmp)
6120Sstevel@tonic-gate {
6136387Srie Rt_map **tobj;
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate * If the caller is an auditor, and the destination isn't, then don't
6170Sstevel@tonic-gate * run any .inits (see comments in load_completion()).
6180Sstevel@tonic-gate */
61912877SRod.Evans@Sun.COM if ((LIST(clmp)->lm_tflags & LML_TFLG_NOAUDIT) &&
62012877SRod.Evans@Sun.COM ((LIST(dlmp)->lm_tflags & LML_TFLG_NOAUDIT) == 0))
6210Sstevel@tonic-gate return;
6220Sstevel@tonic-gate
6238598SRod.Evans@Sun.COM if ((dlmp == clmp) || (rtld_flags & RT_FL_INITFIRST))
6240Sstevel@tonic-gate return;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITDONE)) ==
6270Sstevel@tonic-gate (FLG_RT_RELOCED | FLG_RT_INITDONE))
6280Sstevel@tonic-gate return;
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITCALL)) ==
6310Sstevel@tonic-gate (FLG_RT_RELOCED | FLG_RT_INITCALL)) {
6321618Srie DBG_CALL(Dbg_util_no_init(dlmp));
6330Sstevel@tonic-gate return;
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate if ((tobj = calloc(2, sizeof (Rt_map *))) != NULL) {
6370Sstevel@tonic-gate tobj[0] = dlmp;
6380Sstevel@tonic-gate call_init(tobj, DBG_INIT_DYN);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate * Execute .{preinit|init|fini}array sections
6440Sstevel@tonic-gate */
6450Sstevel@tonic-gate void
call_array(Addr * array,uint_t arraysz,Rt_map * lmp,Word shtype)6461618Srie call_array(Addr *array, uint_t arraysz, Rt_map *lmp, Word shtype)
6470Sstevel@tonic-gate {
6481618Srie int start, stop, incr, ndx;
6490Sstevel@tonic-gate uint_t arraycnt = (uint_t)(arraysz / sizeof (Addr));
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate if (array == NULL)
6520Sstevel@tonic-gate return;
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * initarray & preinitarray are walked from beginning to end - while
6560Sstevel@tonic-gate * finiarray is walked from end to beginning.
6570Sstevel@tonic-gate */
6580Sstevel@tonic-gate if (shtype == SHT_FINI_ARRAY) {
6590Sstevel@tonic-gate start = arraycnt - 1;
6600Sstevel@tonic-gate stop = incr = -1;
6610Sstevel@tonic-gate } else {
6620Sstevel@tonic-gate start = 0;
6630Sstevel@tonic-gate stop = arraycnt;
6640Sstevel@tonic-gate incr = 1;
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate * Call the .*array[] entries
6690Sstevel@tonic-gate */
6701618Srie for (ndx = start; ndx != stop; ndx += incr) {
67112877SRod.Evans@Sun.COM uint_t rtldflags;
67212877SRod.Evans@Sun.COM void (*fptr)(void) = (void(*)())array[ndx];
6731618Srie
6741618Srie DBG_CALL(Dbg_util_call_array(lmp, (void *)fptr, ndx, shtype));
6751618Srie
67612877SRod.Evans@Sun.COM APPLICATION_ENTER(rtldflags);
6776652Srie leave(LIST(lmp), 0);
6780Sstevel@tonic-gate (*fptr)();
6796652Srie (void) enter(0);
68012877SRod.Evans@Sun.COM APPLICATION_RETURN(rtldflags);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate * Execute any .init sections. These are passed to us in an lmp array which
6860Sstevel@tonic-gate * (by default) will have been sorted.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate void
call_init(Rt_map ** tobj,int flag)6896387Srie call_init(Rt_map **tobj, int flag)
6900Sstevel@tonic-gate {
6916387Srie Rt_map **_tobj, **_nobj;
6929131SRod.Evans@Sun.COM static APlist *pending = NULL;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /*
6950Sstevel@tonic-gate * If we're in the middle of an INITFIRST, this must complete before
6960Sstevel@tonic-gate * any new init's are fired. In this case add the object list to the
6970Sstevel@tonic-gate * pending queue and return. We'll pick up the queue after any
6980Sstevel@tonic-gate * INITFIRST objects have their init's fired.
6990Sstevel@tonic-gate */
7000Sstevel@tonic-gate if (rtld_flags & RT_FL_INITFIRST) {
7019131SRod.Evans@Sun.COM (void) aplist_append(&pending, tobj, AL_CNT_PENDING);
7020Sstevel@tonic-gate return;
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate /*
7060Sstevel@tonic-gate * Traverse the tobj array firing each objects init.
7070Sstevel@tonic-gate */
7080Sstevel@tonic-gate for (_tobj = _nobj = tobj, _nobj++; *_tobj != NULL; _tobj++, _nobj++) {
7096387Srie Rt_map *lmp = *_tobj;
7106387Srie void (*iptr)() = INIT(lmp);
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_INITCALL)
7130Sstevel@tonic-gate continue;
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITCALL;
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate /*
7180Sstevel@tonic-gate * Establish an initfirst state if necessary - no other inits
719280Srie * will be fired (because of additional relocation bindings)
720280Srie * when in this state.
7210Sstevel@tonic-gate */
7220Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_INITFRST)
7230Sstevel@tonic-gate rtld_flags |= RT_FL_INITFIRST;
7240Sstevel@tonic-gate
7258598SRod.Evans@Sun.COM if (INITARRAY(lmp) || iptr)
7261618Srie DBG_CALL(Dbg_util_call_init(lmp, flag));
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate if (iptr) {
72912877SRod.Evans@Sun.COM uint_t rtldflags;
73012877SRod.Evans@Sun.COM
73112877SRod.Evans@Sun.COM APPLICATION_ENTER(rtldflags);
7326652Srie leave(LIST(lmp), 0);
7330Sstevel@tonic-gate (*iptr)();
7346652Srie (void) enter(0);
73512877SRod.Evans@Sun.COM APPLICATION_RETURN(rtldflags);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate call_array(INITARRAY(lmp), INITARRAYSZ(lmp), lmp,
7390Sstevel@tonic-gate SHT_INIT_ARRAY);
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate if (INITARRAY(lmp) || iptr)
7421618Srie DBG_CALL(Dbg_util_call_init(lmp, DBG_INIT_DONE));
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate /*
7450Sstevel@tonic-gate * Set the initdone flag regardless of whether this object
7460Sstevel@tonic-gate * actually contains an .init section. This flag prevents us
7470Sstevel@tonic-gate * from processing this section again for an .init and also
7480Sstevel@tonic-gate * signifies that a .fini must be called should it exist.
7490Sstevel@tonic-gate * Clear the sort field for use in later .fini processing.
7500Sstevel@tonic-gate */
7510Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITDONE;
752280Srie SORTVAL(lmp) = -1;
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate /*
7550Sstevel@tonic-gate * If we're firing an INITFIRST object, and other objects must
7560Sstevel@tonic-gate * be fired which are not INITFIRST, make sure we grab any
7570Sstevel@tonic-gate * pending objects that might have been delayed as this
7580Sstevel@tonic-gate * INITFIRST was processed.
7590Sstevel@tonic-gate */
7600Sstevel@tonic-gate if ((rtld_flags & RT_FL_INITFIRST) &&
7610Sstevel@tonic-gate ((*_nobj == NULL) || !(FLAGS(*_nobj) & FLG_RT_INITFRST))) {
7629131SRod.Evans@Sun.COM Aliste idx;
7639131SRod.Evans@Sun.COM Rt_map **pobj;
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate rtld_flags &= ~RT_FL_INITFIRST;
7660Sstevel@tonic-gate
7679131SRod.Evans@Sun.COM for (APLIST_TRAVERSE(pending, idx, pobj)) {
7689131SRod.Evans@Sun.COM aplist_delete(pending, &idx);
7690Sstevel@tonic-gate call_init(pobj, DBG_INIT_PEND);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate free(tobj);
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate /*
77712877SRod.Evans@Sun.COM * Call .fini sections for the topologically sorted list of objects. This
77812877SRod.Evans@Sun.COM * routine is called from remove_hdl() for any objects being torn down as part
77912877SRod.Evans@Sun.COM * of a dlclose() operation, and from atexit() processing for all the remaining
78012877SRod.Evans@Sun.COM * objects within the process.
7810Sstevel@tonic-gate */
7820Sstevel@tonic-gate void
call_fini(Lm_list * lml,Rt_map ** tobj,Rt_map * clmp)78312877SRod.Evans@Sun.COM call_fini(Lm_list *lml, Rt_map **tobj, Rt_map *clmp)
7840Sstevel@tonic-gate {
785280Srie Rt_map **_tobj;
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate for (_tobj = tobj; *_tobj != NULL; _tobj++) {
78812877SRod.Evans@Sun.COM Rt_map *lmp = *_tobj;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate /*
7918598SRod.Evans@Sun.COM * Only fire a .fini if the objects corresponding .init has
7928598SRod.Evans@Sun.COM * completed. We collect all .fini sections of objects that
7938598SRod.Evans@Sun.COM * had their .init collected, but that doesn't mean that at
7948598SRod.Evans@Sun.COM * the time of collection, that the .init had completed.
7950Sstevel@tonic-gate */
7968598SRod.Evans@Sun.COM if (FLAGS(lmp) & FLG_RT_INITDONE) {
7971824Srie void (*fptr)(void) = FINI(lmp);
7980Sstevel@tonic-gate
7998598SRod.Evans@Sun.COM if (FINIARRAY(lmp) || fptr)
8001618Srie DBG_CALL(Dbg_util_call_fini(lmp));
8010Sstevel@tonic-gate
8021618Srie call_array(FINIARRAY(lmp), FINIARRAYSZ(lmp), lmp,
8031618Srie SHT_FINI_ARRAY);
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate if (fptr) {
80612877SRod.Evans@Sun.COM uint_t rtldflags;
80712877SRod.Evans@Sun.COM
80812877SRod.Evans@Sun.COM APPLICATION_ENTER(rtldflags);
80912877SRod.Evans@Sun.COM leave(lml, 0);
8100Sstevel@tonic-gate (*fptr)();
8116652Srie (void) enter(0);
81212877SRod.Evans@Sun.COM APPLICATION_RETURN(rtldflags);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate /*
817280Srie * Skip main, this is explicitly called last in atexit_fini().
818280Srie */
819280Srie if (FLAGS(lmp) & FLG_RT_ISMAIN)
820280Srie continue;
821280Srie
822280Srie /*
82312877SRod.Evans@Sun.COM * This object has exercised its last instructions (regardless
82412877SRod.Evans@Sun.COM * of whether it will be unmapped or not). Audit this closure.
8250Sstevel@tonic-gate */
82612877SRod.Evans@Sun.COM if ((lml->lm_tflags & LML_TFLG_NOAUDIT) == 0)
82712877SRod.Evans@Sun.COM audit_objclose(lmp, clmp);
8280Sstevel@tonic-gate }
82912877SRod.Evans@Sun.COM
8301618Srie DBG_CALL(Dbg_bind_plt_summary(lml, M_MACH, pltcnt21d, pltcnt24d,
8311618Srie pltcntu32, pltcntu44, pltcntfull, pltcntfar));
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate free(tobj);
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate
83612877SRod.Evans@Sun.COM /*
83712877SRod.Evans@Sun.COM * Function called by atexit(3C). Calls all .fini sections within the objects
83812877SRod.Evans@Sun.COM * that make up the process. As .fini processing is the last opportunity for
83912877SRod.Evans@Sun.COM * any new bindings to be established, this is also a convenient location to
84012877SRod.Evans@Sun.COM * check for unused objects.
84112877SRod.Evans@Sun.COM */
8420Sstevel@tonic-gate void
atexit_fini()8430Sstevel@tonic-gate atexit_fini()
8440Sstevel@tonic-gate {
8459131SRod.Evans@Sun.COM Rt_map **tobj, *lmp;
8469131SRod.Evans@Sun.COM Lm_list *lml;
8479131SRod.Evans@Sun.COM Aliste idx;
8480Sstevel@tonic-gate
8496515Sraf (void) enter(0);
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate rtld_flags |= RT_FL_ATEXIT;
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate lml = &lml_main;
854280Srie lml->lm_flags |= LML_FLG_ATEXIT;
8553817Srie lml->lm_flags &= ~LML_FLG_INTRPOSETSORT;
8560Sstevel@tonic-gate lmp = (Rt_map *)lml->lm_head;
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate /*
8590Sstevel@tonic-gate * Reverse topologically sort the main link-map for .fini execution.
8600Sstevel@tonic-gate */
8618883SRod.Evans@Sun.COM if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
8620Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR))
86312877SRod.Evans@Sun.COM call_fini(lml, tobj, NULL);
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate * Now that all .fini code has been run, see what unreferenced objects
8676387Srie * remain.
8680Sstevel@tonic-gate */
8690Sstevel@tonic-gate unused(lml);
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate /*
87212877SRod.Evans@Sun.COM * Traverse any alternative link-map lists, looking for non-auditors.
8730Sstevel@tonic-gate */
8749131SRod.Evans@Sun.COM for (APLIST_TRAVERSE(dynlm_list, idx, lml)) {
8751824Srie /*
8761824Srie * Ignore the base-link-map list, which has already been
87712877SRod.Evans@Sun.COM * processed, the runtime linkers link-map list, which is
87812877SRod.Evans@Sun.COM * processed last, and any auditors.
8791824Srie */
88012877SRod.Evans@Sun.COM if ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) ||
88112877SRod.Evans@Sun.COM (lml->lm_tflags & LML_TFLG_AUD_MASK) ||
88212877SRod.Evans@Sun.COM ((lmp = (Rt_map *)lml->lm_head) == NULL))
8830Sstevel@tonic-gate continue;
8840Sstevel@tonic-gate
885280Srie lml->lm_flags |= LML_FLG_ATEXIT;
8863817Srie lml->lm_flags &= ~LML_FLG_INTRPOSETSORT;
887280Srie
8880Sstevel@tonic-gate /*
8890Sstevel@tonic-gate * Reverse topologically sort the link-map for .fini execution.
8900Sstevel@tonic-gate */
8918883SRod.Evans@Sun.COM if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
8920Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR))
89312877SRod.Evans@Sun.COM call_fini(lml, tobj, NULL);
89412877SRod.Evans@Sun.COM
89512877SRod.Evans@Sun.COM unused(lml);
89612877SRod.Evans@Sun.COM }
89712877SRod.Evans@Sun.COM
89812877SRod.Evans@Sun.COM /*
89912877SRod.Evans@Sun.COM * Add an explicit close to main and ld.so.1. Although main's .fini is
90012877SRod.Evans@Sun.COM * collected in call_fini() to provide for FINITARRAY processing, its
90112877SRod.Evans@Sun.COM * audit_objclose is explicitly skipped. This provides for it to be
90212877SRod.Evans@Sun.COM * called last, here. This is the reverse of the explicit calls to
90312877SRod.Evans@Sun.COM * audit_objopen() made in setup().
90412877SRod.Evans@Sun.COM */
90512877SRod.Evans@Sun.COM lml = &lml_main;
90612877SRod.Evans@Sun.COM lmp = (Rt_map *)lml->lm_head;
90712877SRod.Evans@Sun.COM
90812877SRod.Evans@Sun.COM if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK) {
90912877SRod.Evans@Sun.COM audit_objclose((Rt_map *)lml_rtld.lm_head, lmp);
91012877SRod.Evans@Sun.COM audit_objclose(lmp, lmp);
91112877SRod.Evans@Sun.COM }
91212877SRod.Evans@Sun.COM
91312877SRod.Evans@Sun.COM /*
91412877SRod.Evans@Sun.COM * Traverse any alternative link-map lists, looking for non-auditors.
91512877SRod.Evans@Sun.COM */
91612877SRod.Evans@Sun.COM for (APLIST_TRAVERSE(dynlm_list, idx, lml)) {
91712877SRod.Evans@Sun.COM /*
91812877SRod.Evans@Sun.COM * Ignore the base-link-map list, which has already been
91912877SRod.Evans@Sun.COM * processed, the runtime linkers link-map list, which is
92012877SRod.Evans@Sun.COM * processed last, and any non-auditors.
92112877SRod.Evans@Sun.COM */
92212877SRod.Evans@Sun.COM if ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) ||
92312877SRod.Evans@Sun.COM ((lml->lm_tflags & LML_TFLG_AUD_MASK) == 0) ||
92412877SRod.Evans@Sun.COM ((lmp = (Rt_map *)lml->lm_head) == NULL))
92512877SRod.Evans@Sun.COM continue;
92612877SRod.Evans@Sun.COM
92712877SRod.Evans@Sun.COM lml->lm_flags |= LML_FLG_ATEXIT;
92812877SRod.Evans@Sun.COM lml->lm_flags &= ~LML_FLG_INTRPOSETSORT;
92912877SRod.Evans@Sun.COM
93012877SRod.Evans@Sun.COM /*
93112877SRod.Evans@Sun.COM * Reverse topologically sort the link-map for .fini execution.
93212877SRod.Evans@Sun.COM */
93312877SRod.Evans@Sun.COM if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
93412877SRod.Evans@Sun.COM (tobj != (Rt_map **)S_ERROR))
93512877SRod.Evans@Sun.COM call_fini(lml, tobj, NULL);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate unused(lml);
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate /*
9410Sstevel@tonic-gate * Finally reverse topologically sort the runtime linkers link-map for
9420Sstevel@tonic-gate * .fini execution.
9430Sstevel@tonic-gate */
9440Sstevel@tonic-gate lml = &lml_rtld;
945280Srie lml->lm_flags |= LML_FLG_ATEXIT;
9463817Srie lml->lm_flags &= ~LML_FLG_INTRPOSETSORT;
9470Sstevel@tonic-gate lmp = (Rt_map *)lml->lm_head;
9480Sstevel@tonic-gate
9498883SRod.Evans@Sun.COM if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
9500Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR))
95112877SRod.Evans@Sun.COM call_fini(lml, tobj, NULL);
9520Sstevel@tonic-gate
9536515Sraf leave(&lml_main, 0);
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate /*
9570Sstevel@tonic-gate * This routine is called to complete any runtime linker activity which may have
9580Sstevel@tonic-gate * resulted in objects being loaded. This is called from all user entry points
9590Sstevel@tonic-gate * and from any internal dl*() requests.
9600Sstevel@tonic-gate */
9610Sstevel@tonic-gate void
load_completion(Rt_map * nlmp)9624679Srie load_completion(Rt_map *nlmp)
9630Sstevel@tonic-gate {
9648883SRod.Evans@Sun.COM Rt_map **tobj = NULL;
9654679Srie Lm_list *nlml;
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate /*
9680Sstevel@tonic-gate * Establish any .init processing. Note, in a world of lazy loading,
9690Sstevel@tonic-gate * objects may have been loaded regardless of whether the users request
9700Sstevel@tonic-gate * was fulfilled (i.e., a dlsym() request may have failed to find a
9710Sstevel@tonic-gate * symbol but objects might have been loaded during its search). Thus,
9720Sstevel@tonic-gate * any tsorting starts from the nlmp (new link-maps) pointer and not
9730Sstevel@tonic-gate * necessarily from the link-map that may have satisfied the request.
9740Sstevel@tonic-gate *
9751824Srie * Note, the primary link-map has an initialization phase where dynamic
9761824Srie * .init firing is suppressed. This provides for a simple and clean
9771824Srie * handshake with the primary link-maps libc, which is important for
9781824Srie * establishing uberdata. In addition, auditors often obtain handles
9791824Srie * to primary link-map objects as the objects are loaded, so as to
9801824Srie * inspect the link-map for symbols. This inspection is allowed without
9811824Srie * running any code on the primary link-map, as running this code may
9821824Srie * reenter the auditor, who may not yet have finished its own
9830Sstevel@tonic-gate * initialization.
9840Sstevel@tonic-gate */
9851824Srie if (nlmp)
9861824Srie nlml = LIST(nlmp);
9871824Srie
9886229Sedp if (nlmp && nlml->lm_init && ((nlml != &lml_main) ||
9896229Sedp (rtld_flags2 & (RT_FL2_PLMSETUP | RT_FL2_NOPLM)))) {
9908598SRod.Evans@Sun.COM if ((tobj = tsort(nlmp, nlml->lm_init,
991280Srie RT_SORT_REV)) == (Rt_map **)S_ERROR)
9928883SRod.Evans@Sun.COM tobj = NULL;
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate /*
9961824Srie * Make sure any alternative link-map retrieves any external interfaces
9971824Srie * and initializes threads.
9981824Srie */
9991824Srie if (nlmp && (nlml != &lml_main)) {
10001824Srie (void) rt_get_extern(nlml, nlmp);
10011824Srie rt_thr_init(nlml);
10021824Srie }
10031824Srie
10041824Srie /*
10051824Srie * Traverse the list of new link-maps and register any dynamic TLS.
10061824Srie * This storage is established for any objects not on the primary
10071824Srie * link-map, and for any objects added to the primary link-map after
10081824Srie * static TLS has been registered.
10091824Srie */
10106229Sedp if (nlmp && nlml->lm_tls && ((nlml != &lml_main) ||
10116229Sedp (rtld_flags2 & (RT_FL2_PLMSETUP | RT_FL2_NOPLM)))) {
10121824Srie Rt_map *lmp;
10131824Srie
10148394SAli.Bahrami@Sun.COM for (lmp = nlmp; lmp; lmp = NEXT_RT_MAP(lmp)) {
10151824Srie if (PTTLS(lmp) && PTTLS(lmp)->p_memsz)
10161824Srie tls_modaddrem(lmp, TM_FLG_MODADD);
10171824Srie }
10181824Srie nlml->lm_tls = 0;
10191824Srie }
10201824Srie
10211824Srie /*
10220Sstevel@tonic-gate * Fire any .init's.
10230Sstevel@tonic-gate */
10240Sstevel@tonic-gate if (tobj)
10250Sstevel@tonic-gate call_init(tobj, DBG_INIT_SORT);
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate /*
10290Sstevel@tonic-gate * Append an item to the specified link map control list.
10300Sstevel@tonic-gate */
10310Sstevel@tonic-gate void
lm_append(Lm_list * lml,Aliste lmco,Rt_map * lmp)10320Sstevel@tonic-gate lm_append(Lm_list *lml, Aliste lmco, Rt_map *lmp)
10330Sstevel@tonic-gate {
10340Sstevel@tonic-gate Lm_cntl *lmc;
10350Sstevel@tonic-gate int add = 1;
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate /*
10380Sstevel@tonic-gate * Indicate that this link-map list has a new object.
10390Sstevel@tonic-gate */
10400Sstevel@tonic-gate (lml->lm_obj)++;
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate /*
104312877SRod.Evans@Sun.COM * If we're about to add a new object to the main link-map control
104412877SRod.Evans@Sun.COM * list, alert the debuggers. Additions of individual objects to the
104512877SRod.Evans@Sun.COM * main link-map control list occur during initial setup as the
104612877SRod.Evans@Sun.COM * applications immediate dependencies are loaded. Additional objects
104712877SRod.Evans@Sun.COM * are loaded on the main link-map control list after they have been
104812877SRod.Evans@Sun.COM * fully initialized on an alternative link-map control list. See
104912877SRod.Evans@Sun.COM * lm_move().
10500Sstevel@tonic-gate */
105112877SRod.Evans@Sun.COM if (lmco == ALIST_OFF_DATA)
10522454Srie rd_event(lml, RD_DLACTIVITY, RT_ADD);
10530Sstevel@tonic-gate
10540Sstevel@tonic-gate /* LINTED */
10555892Sab196087 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate /*
10580Sstevel@tonic-gate * A link-map list header points to one of more link-map control lists
10590Sstevel@tonic-gate * (see include/rtld.h). The initial list, pointed to by lm_cntl, is
10600Sstevel@tonic-gate * the list of relocated objects. Other lists maintain objects that
10610Sstevel@tonic-gate * are still being analyzed or relocated. This list provides the core
10620Sstevel@tonic-gate * link-map list information used by all ld.so.1 routines.
10630Sstevel@tonic-gate */
10640Sstevel@tonic-gate if (lmc->lc_head == NULL) {
10650Sstevel@tonic-gate /*
10660Sstevel@tonic-gate * If this is the first link-map for the given control list,
10670Sstevel@tonic-gate * initialize the list.
10680Sstevel@tonic-gate */
10690Sstevel@tonic-gate lmc->lc_head = lmc->lc_tail = lmp;
10700Sstevel@tonic-gate add = 0;
10710Sstevel@tonic-gate
10723466Srie } else if (FLAGS(lmp) & FLG_RT_OBJINTPO) {
10730Sstevel@tonic-gate Rt_map *tlmp;
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate /*
10760Sstevel@tonic-gate * If this is an interposer then append the link-map following
10770Sstevel@tonic-gate * any other interposers (these are objects that have been
10780Sstevel@tonic-gate * previously preloaded, or were identified with -z interpose).
10790Sstevel@tonic-gate * Interposers can only be inserted on the first link-map
10800Sstevel@tonic-gate * control list, as once relocation has started, interposition
10810Sstevel@tonic-gate * from new interposers can't be guaranteed.
10820Sstevel@tonic-gate *
10830Sstevel@tonic-gate * NOTE: We do not interpose on the head of a list. This model
10840Sstevel@tonic-gate * evolved because dynamic executables have already been fully
10850Sstevel@tonic-gate * relocated within themselves and thus can't be interposed on.
10860Sstevel@tonic-gate * Nowadays it's possible to have shared objects at the head of
10870Sstevel@tonic-gate * a list, which conceptually means they could be interposed on.
10880Sstevel@tonic-gate * But, shared objects can be created via dldump() and may only
10890Sstevel@tonic-gate * be partially relocated (just relatives), in which case they
10900Sstevel@tonic-gate * are interposable, but are marked as fixed (ET_EXEC).
10910Sstevel@tonic-gate *
10920Sstevel@tonic-gate * Thus we really don't have a clear method of deciding when the
10930Sstevel@tonic-gate * head of a link-map is interposable. So, to be consistent,
10940Sstevel@tonic-gate * for now only add interposers after the link-map lists head
10950Sstevel@tonic-gate * object.
10960Sstevel@tonic-gate */
10978394SAli.Bahrami@Sun.COM for (tlmp = NEXT_RT_MAP(lmc->lc_head); tlmp;
10988394SAli.Bahrami@Sun.COM tlmp = NEXT_RT_MAP(tlmp)) {
10990Sstevel@tonic-gate
11003466Srie if (FLAGS(tlmp) & FLG_RT_OBJINTPO)
11010Sstevel@tonic-gate continue;
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate /*
11040Sstevel@tonic-gate * Insert the new link-map before this non-interposer,
11050Sstevel@tonic-gate * and indicate an interposer is found.
11060Sstevel@tonic-gate */
11078394SAli.Bahrami@Sun.COM NEXT(PREV_RT_MAP(tlmp)) = (Link_map *)lmp;
11080Sstevel@tonic-gate PREV(lmp) = PREV(tlmp);
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate NEXT(lmp) = (Link_map *)tlmp;
11110Sstevel@tonic-gate PREV(tlmp) = (Link_map *)lmp;
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate lmc->lc_flags |= LMC_FLG_REANALYZE;
11140Sstevel@tonic-gate add = 0;
11150Sstevel@tonic-gate break;
11160Sstevel@tonic-gate }
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate
11190Sstevel@tonic-gate /*
11200Sstevel@tonic-gate * Fall through to appending the new link map to the tail of the list.
11210Sstevel@tonic-gate * If we're processing the initial objects of this link-map list, add
11220Sstevel@tonic-gate * them to the backward compatibility list.
11230Sstevel@tonic-gate */
11240Sstevel@tonic-gate if (add) {
11250Sstevel@tonic-gate NEXT(lmc->lc_tail) = (Link_map *)lmp;
11260Sstevel@tonic-gate PREV(lmp) = (Link_map *)lmc->lc_tail;
11270Sstevel@tonic-gate lmc->lc_tail = lmp;
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate /*
11310Sstevel@tonic-gate * Having added this link-map to a control list, indicate which control
11320Sstevel@tonic-gate * list the link-map belongs to. Note, control list information is
11330Sstevel@tonic-gate * always maintained as an offset, as the Alist can be reallocated.
11340Sstevel@tonic-gate */
11350Sstevel@tonic-gate CNTL(lmp) = lmco;
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate /*
11380Sstevel@tonic-gate * Indicate if an interposer is found. Note that the first object on a
11390Sstevel@tonic-gate * link-map can be explicitly defined as an interposer so that it can
11400Sstevel@tonic-gate * provide interposition over direct binding requests.
11410Sstevel@tonic-gate */
11423466Srie if (FLAGS(lmp) & MSK_RT_INTPOSE)
11430Sstevel@tonic-gate lml->lm_flags |= LML_FLG_INTRPOSE;
11440Sstevel@tonic-gate
11450Sstevel@tonic-gate /*
11460Sstevel@tonic-gate * For backward compatibility with debuggers, the link-map list contains
11470Sstevel@tonic-gate * pointers to the main control list.
11480Sstevel@tonic-gate */
11495892Sab196087 if (lmco == ALIST_OFF_DATA) {
11500Sstevel@tonic-gate lml->lm_head = lmc->lc_head;
11510Sstevel@tonic-gate lml->lm_tail = lmc->lc_tail;
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate /*
11560Sstevel@tonic-gate * Delete an item from the specified link map control list.
11570Sstevel@tonic-gate */
11580Sstevel@tonic-gate void
lm_delete(Lm_list * lml,Rt_map * lmp,Rt_map * clmp)115912877SRod.Evans@Sun.COM lm_delete(Lm_list *lml, Rt_map *lmp, Rt_map *clmp)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate Lm_cntl *lmc;
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate /*
11640Sstevel@tonic-gate * If the control list pointer hasn't been initialized, this object
11650Sstevel@tonic-gate * never got added to a link-map list.
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate if (CNTL(lmp) == 0)
11680Sstevel@tonic-gate return;
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate /*
11712454Srie * If we're about to delete an object from the main link-map control
117212877SRod.Evans@Sun.COM * list, alert the debuggers.
11730Sstevel@tonic-gate */
117412877SRod.Evans@Sun.COM if (CNTL(lmp) == ALIST_OFF_DATA)
11750Sstevel@tonic-gate rd_event(lml, RD_DLACTIVITY, RT_DELETE);
11760Sstevel@tonic-gate
117712877SRod.Evans@Sun.COM /*
117812877SRod.Evans@Sun.COM * If we're being audited tell the audit library that we're
117912877SRod.Evans@Sun.COM * about to go deleting dependencies.
118012877SRod.Evans@Sun.COM */
118112877SRod.Evans@Sun.COM if (clmp && (aud_activity ||
118212877SRod.Evans@Sun.COM ((LIST(clmp)->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_ACTIVITY)))
118312877SRod.Evans@Sun.COM audit_activity(clmp, LA_ACT_DELETE);
118412877SRod.Evans@Sun.COM
11850Sstevel@tonic-gate /* LINTED */
11865892Sab196087 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, CNTL(lmp));
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate if (lmc->lc_head == lmp)
11898394SAli.Bahrami@Sun.COM lmc->lc_head = NEXT_RT_MAP(lmp);
11900Sstevel@tonic-gate else
11918394SAli.Bahrami@Sun.COM NEXT(PREV_RT_MAP(lmp)) = (void *)NEXT(lmp);
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate if (lmc->lc_tail == lmp)
11948394SAli.Bahrami@Sun.COM lmc->lc_tail = PREV_RT_MAP(lmp);
11950Sstevel@tonic-gate else
11968394SAli.Bahrami@Sun.COM PREV(NEXT_RT_MAP(lmp)) = PREV(lmp);
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate * For backward compatibility with debuggers, the link-map list contains
12000Sstevel@tonic-gate * pointers to the main control list.
12010Sstevel@tonic-gate */
12025892Sab196087 if (lmc == (Lm_cntl *)&lml->lm_lists->al_data) {
12030Sstevel@tonic-gate lml->lm_head = lmc->lc_head;
12040Sstevel@tonic-gate lml->lm_tail = lmc->lc_tail;
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate
12070Sstevel@tonic-gate /*
12080Sstevel@tonic-gate * Indicate we have one less object on this control list.
12090Sstevel@tonic-gate */
12100Sstevel@tonic-gate (lml->lm_obj)--;
12110Sstevel@tonic-gate }
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate /*
12140Sstevel@tonic-gate * Move a link-map control list to another. Objects that are being relocated
12150Sstevel@tonic-gate * are maintained on secondary control lists. Once their relocation is
12160Sstevel@tonic-gate * complete, the entire list is appended to the previous control list, as this
12170Sstevel@tonic-gate * list must have been the trigger for generating the new control list.
12180Sstevel@tonic-gate */
12190Sstevel@tonic-gate void
lm_move(Lm_list * lml,Aliste nlmco,Aliste plmco,Lm_cntl * nlmc,Lm_cntl * plmc)12200Sstevel@tonic-gate lm_move(Lm_list *lml, Aliste nlmco, Aliste plmco, Lm_cntl *nlmc, Lm_cntl *plmc)
12210Sstevel@tonic-gate {
12220Sstevel@tonic-gate Rt_map *lmp;
12230Sstevel@tonic-gate
12240Sstevel@tonic-gate /*
12252454Srie * If we're about to add a new family of objects to the main link-map
122612877SRod.Evans@Sun.COM * control list, alert the debuggers. Additions of object families to
122712877SRod.Evans@Sun.COM * the main link-map control list occur during lazy loading, filtering
122812877SRod.Evans@Sun.COM * and dlopen().
12290Sstevel@tonic-gate */
123012877SRod.Evans@Sun.COM if (plmco == ALIST_OFF_DATA)
12310Sstevel@tonic-gate rd_event(lml, RD_DLACTIVITY, RT_ADD);
12320Sstevel@tonic-gate
12332454Srie DBG_CALL(Dbg_file_cntl(lml, nlmco, plmco));
12342454Srie
12350Sstevel@tonic-gate /*
12360Sstevel@tonic-gate * Indicate each new link-map has been moved to the previous link-map
12370Sstevel@tonic-gate * control list.
12380Sstevel@tonic-gate */
12398598SRod.Evans@Sun.COM for (lmp = nlmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
12400Sstevel@tonic-gate CNTL(lmp) = plmco;
12410Sstevel@tonic-gate
12428598SRod.Evans@Sun.COM /*
12438598SRod.Evans@Sun.COM * If these objects are being added to the main link-map
12448598SRod.Evans@Sun.COM * control list, indicate that there are init's available
12458598SRod.Evans@Sun.COM * for harvesting.
12468598SRod.Evans@Sun.COM */
12478598SRod.Evans@Sun.COM if (plmco == ALIST_OFF_DATA) {
12488598SRod.Evans@Sun.COM lml->lm_init++;
12498598SRod.Evans@Sun.COM lml->lm_flags |= LML_FLG_OBJADDED;
12508598SRod.Evans@Sun.COM }
12518598SRod.Evans@Sun.COM }
12528598SRod.Evans@Sun.COM
12530Sstevel@tonic-gate /*
12540Sstevel@tonic-gate * Move the new link-map control list, to the callers link-map control
12550Sstevel@tonic-gate * list.
12560Sstevel@tonic-gate */
12577668SRod.Evans@Sun.COM if (plmc->lc_head == NULL) {
12580Sstevel@tonic-gate plmc->lc_head = nlmc->lc_head;
12597668SRod.Evans@Sun.COM PREV(nlmc->lc_head) = NULL;
12600Sstevel@tonic-gate } else {
12610Sstevel@tonic-gate NEXT(plmc->lc_tail) = (Link_map *)nlmc->lc_head;
12620Sstevel@tonic-gate PREV(nlmc->lc_head) = (Link_map *)plmc->lc_tail;
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate plmc->lc_tail = nlmc->lc_tail;
12667668SRod.Evans@Sun.COM nlmc->lc_head = nlmc->lc_tail = NULL;
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /*
12690Sstevel@tonic-gate * For backward compatibility with debuggers, the link-map list contains
12700Sstevel@tonic-gate * pointers to the main control list.
12710Sstevel@tonic-gate */
12725892Sab196087 if (plmco == ALIST_OFF_DATA) {
12730Sstevel@tonic-gate lml->lm_head = plmc->lc_head;
12740Sstevel@tonic-gate lml->lm_tail = plmc->lc_tail;
12750Sstevel@tonic-gate }
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate
12780Sstevel@tonic-gate /*
12799340SRod.Evans@Sun.COM * Create, or assign a link-map control list. Each link-map list contains a
12809340SRod.Evans@Sun.COM * main control list, which has an Alist offset of ALIST_OFF_DATA (see the
12819340SRod.Evans@Sun.COM * description in include/rtld.h). During the initial construction of a
12829340SRod.Evans@Sun.COM * process, objects are added to this main control list. This control list is
12839340SRod.Evans@Sun.COM * never deleted, unless an alternate link-map list has been requested (say for
12849340SRod.Evans@Sun.COM * auditors), and the associated objects could not be loaded or relocated.
12859340SRod.Evans@Sun.COM *
12869340SRod.Evans@Sun.COM * Once relocation has started, any lazy loadable objects, or filtees, are
12879340SRod.Evans@Sun.COM * processed on a new, temporary control list. Only when these objects have
12889340SRod.Evans@Sun.COM * been fully relocated, are they moved to the main link-map control list.
12899340SRod.Evans@Sun.COM * Once the objects are moved, this temporary control list is deleted (see
12909340SRod.Evans@Sun.COM * remove_cntl()).
12919340SRod.Evans@Sun.COM *
12929340SRod.Evans@Sun.COM * A dlopen() always requires a new temporary link-map control list.
12939340SRod.Evans@Sun.COM * Typically, a dlopen() occurs on a link-map list that had already started
12949340SRod.Evans@Sun.COM * relocation, however, auditors can dlopen() objects on the main link-map
12959340SRod.Evans@Sun.COM * list while under initial construction, before any relocation has begun.
12969340SRod.Evans@Sun.COM * Hence, dlopen() requests are explicitly flagged.
12979340SRod.Evans@Sun.COM */
12989340SRod.Evans@Sun.COM Aliste
create_cntl(Lm_list * lml,int dlopen)12999340SRod.Evans@Sun.COM create_cntl(Lm_list *lml, int dlopen)
13009340SRod.Evans@Sun.COM {
13019340SRod.Evans@Sun.COM /*
13029340SRod.Evans@Sun.COM * If the head link-map object has already been relocated, create a
13039340SRod.Evans@Sun.COM * new, temporary, control list.
13049340SRod.Evans@Sun.COM */
13059340SRod.Evans@Sun.COM if (dlopen || (lml->lm_head == NULL) ||
13069340SRod.Evans@Sun.COM (FLAGS(lml->lm_head) & FLG_RT_RELOCED)) {
13079340SRod.Evans@Sun.COM Lm_cntl *lmc;
13089340SRod.Evans@Sun.COM
13099340SRod.Evans@Sun.COM if ((lmc = alist_append(&lml->lm_lists, NULL, sizeof (Lm_cntl),
13109340SRod.Evans@Sun.COM AL_CNT_LMLISTS)) == NULL)
13119340SRod.Evans@Sun.COM return (NULL);
13129340SRod.Evans@Sun.COM
13139340SRod.Evans@Sun.COM return ((Aliste)((char *)lmc - (char *)lml->lm_lists));
13149340SRod.Evans@Sun.COM }
13159340SRod.Evans@Sun.COM
13169340SRod.Evans@Sun.COM return (ALIST_OFF_DATA);
13179340SRod.Evans@Sun.COM }
13189340SRod.Evans@Sun.COM
13199340SRod.Evans@Sun.COM /*
13200Sstevel@tonic-gate * Environment variables can have a variety of defined permutations, and thus
13210Sstevel@tonic-gate * the following infrastructure exists to allow this variety and to select the
13220Sstevel@tonic-gate * required definition.
13230Sstevel@tonic-gate *
13240Sstevel@tonic-gate * Environment variables can be defined as 32- or 64-bit specific, and if so
13250Sstevel@tonic-gate * they will take precedence over any instruction set neutral form. Typically
13260Sstevel@tonic-gate * this is only useful when the environment value is an informational string.
13270Sstevel@tonic-gate *
13280Sstevel@tonic-gate * Environment variables may be obtained from the standard user environment or
13290Sstevel@tonic-gate * from a configuration file. The latter provides a fallback if no user
13300Sstevel@tonic-gate * environment setting is found, and can take two forms:
13310Sstevel@tonic-gate *
13328883SRod.Evans@Sun.COM * - a replaceable definition - this will be used if no user environment
13330Sstevel@tonic-gate * setting has been seen, or
13340Sstevel@tonic-gate *
13358883SRod.Evans@Sun.COM * - an permanent definition - this will be used no matter what user
13360Sstevel@tonic-gate * environment setting is seen. In the case of list variables it will be
13370Sstevel@tonic-gate * appended to any process environment setting seen.
13380Sstevel@tonic-gate *
13390Sstevel@tonic-gate * Environment variables can be defined without a value (ie. LD_XXXX=) so as to
13400Sstevel@tonic-gate * override any replaceable environment variables from a configuration file.
13410Sstevel@tonic-gate */
134212650SRod.Evans@Sun.COM static u_longlong_t rplgen = 0; /* replaceable generic */
13430Sstevel@tonic-gate /* variables */
134412650SRod.Evans@Sun.COM static u_longlong_t rplisa = 0; /* replaceable ISA specific */
134512650SRod.Evans@Sun.COM /* variables */
134612650SRod.Evans@Sun.COM static u_longlong_t prmgen = 0; /* permanent generic */
13470Sstevel@tonic-gate /* variables */
134812650SRod.Evans@Sun.COM static u_longlong_t prmisa = 0; /* permanent ISA specific */
13490Sstevel@tonic-gate /* variables */
135012650SRod.Evans@Sun.COM static u_longlong_t cmdgen = 0; /* command line (-e) generic */
13510Sstevel@tonic-gate /* variables */
135212650SRod.Evans@Sun.COM static u_longlong_t cmdisa = 0; /* command line (-e) ISA */
135312650SRod.Evans@Sun.COM /* specific variables */
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate /*
13560Sstevel@tonic-gate * Classify an environment variables type.
13570Sstevel@tonic-gate */
135812650SRod.Evans@Sun.COM #define ENV_TYP_IGNORE 0x01 /* ignore - variable is for */
13590Sstevel@tonic-gate /* the wrong ISA */
136012650SRod.Evans@Sun.COM #define ENV_TYP_ISA 0x02 /* variable is ISA specific */
136112650SRod.Evans@Sun.COM #define ENV_TYP_CONFIG 0x04 /* variable obtained from a */
13620Sstevel@tonic-gate /* config file */
136312650SRod.Evans@Sun.COM #define ENV_TYP_PERMANT 0x08 /* variable is permanent */
136412650SRod.Evans@Sun.COM #define ENV_TYP_CMDLINE 0x10 /* variable provide with -e */
136512650SRod.Evans@Sun.COM #define ENV_TYP_NULL 0x20 /* variable is null */
13660Sstevel@tonic-gate
13670Sstevel@tonic-gate /*
13680Sstevel@tonic-gate * Identify all environment variables.
13690Sstevel@tonic-gate */
137011827SRod.Evans@Sun.COM #define ENV_FLG_AUDIT 0x0000000000001ULL
137111827SRod.Evans@Sun.COM #define ENV_FLG_AUDIT_ARGS 0x0000000000002ULL
137211827SRod.Evans@Sun.COM #define ENV_FLG_BIND_NOW 0x0000000000004ULL
137311827SRod.Evans@Sun.COM #define ENV_FLG_BIND_NOT 0x0000000000008ULL
137411827SRod.Evans@Sun.COM #define ENV_FLG_BINDINGS 0x0000000000010ULL
137511827SRod.Evans@Sun.COM #define ENV_FLG_CONFGEN 0x0000000000020ULL
137611827SRod.Evans@Sun.COM #define ENV_FLG_CONFIG 0x0000000000040ULL
137711827SRod.Evans@Sun.COM #define ENV_FLG_DEBUG 0x0000000000080ULL
137811827SRod.Evans@Sun.COM #define ENV_FLG_DEBUG_OUTPUT 0x0000000000100ULL
137911827SRod.Evans@Sun.COM #define ENV_FLG_DEMANGLE 0x0000000000200ULL
138011827SRod.Evans@Sun.COM #define ENV_FLG_FLAGS 0x0000000000400ULL
138111827SRod.Evans@Sun.COM #define ENV_FLG_INIT 0x0000000000800ULL
138211827SRod.Evans@Sun.COM #define ENV_FLG_LIBPATH 0x0000000001000ULL
138311827SRod.Evans@Sun.COM #define ENV_FLG_LOADAVAIL 0x0000000002000ULL
138411827SRod.Evans@Sun.COM #define ENV_FLG_LOADFLTR 0x0000000004000ULL
138511827SRod.Evans@Sun.COM #define ENV_FLG_NOAUDIT 0x0000000008000ULL
138611827SRod.Evans@Sun.COM #define ENV_FLG_NOAUXFLTR 0x0000000010000ULL
138711827SRod.Evans@Sun.COM #define ENV_FLG_NOBAPLT 0x0000000020000ULL
138811827SRod.Evans@Sun.COM #define ENV_FLG_NOCONFIG 0x0000000040000ULL
138911827SRod.Evans@Sun.COM #define ENV_FLG_NODIRCONFIG 0x0000000080000ULL
139011827SRod.Evans@Sun.COM #define ENV_FLG_NODIRECT 0x0000000100000ULL
139111827SRod.Evans@Sun.COM #define ENV_FLG_NOENVCONFIG 0x0000000200000ULL
139211827SRod.Evans@Sun.COM #define ENV_FLG_NOLAZY 0x0000000400000ULL
139311827SRod.Evans@Sun.COM #define ENV_FLG_NOOBJALTER 0x0000000800000ULL
139411827SRod.Evans@Sun.COM #define ENV_FLG_NOVERSION 0x0000001000000ULL
139511827SRod.Evans@Sun.COM #define ENV_FLG_PRELOAD 0x0000002000000ULL
139611827SRod.Evans@Sun.COM #define ENV_FLG_PROFILE 0x0000004000000ULL
139711827SRod.Evans@Sun.COM #define ENV_FLG_PROFILE_OUTPUT 0x0000008000000ULL
139811827SRod.Evans@Sun.COM #define ENV_FLG_SIGNAL 0x0000010000000ULL
139911827SRod.Evans@Sun.COM #define ENV_FLG_TRACE_OBJS 0x0000020000000ULL
140011827SRod.Evans@Sun.COM #define ENV_FLG_TRACE_PTHS 0x0000040000000ULL
140111827SRod.Evans@Sun.COM #define ENV_FLG_UNREF 0x0000080000000ULL
140211827SRod.Evans@Sun.COM #define ENV_FLG_UNUSED 0x0000100000000ULL
140311827SRod.Evans@Sun.COM #define ENV_FLG_VERBOSE 0x0000200000000ULL
140411827SRod.Evans@Sun.COM #define ENV_FLG_WARN 0x0000400000000ULL
140511827SRod.Evans@Sun.COM #define ENV_FLG_NOFLTCONFIG 0x0000800000000ULL
140611827SRod.Evans@Sun.COM #define ENV_FLG_BIND_LAZY 0x0001000000000ULL
140711827SRod.Evans@Sun.COM #define ENV_FLG_NOUNRESWEAK 0x0002000000000ULL
140811827SRod.Evans@Sun.COM #define ENV_FLG_NOPAREXT 0x0004000000000ULL
140911827SRod.Evans@Sun.COM #define ENV_FLG_HWCAP 0x0008000000000ULL
141011827SRod.Evans@Sun.COM #define ENV_FLG_SFCAP 0x0010000000000ULL
141111827SRod.Evans@Sun.COM #define ENV_FLG_MACHCAP 0x0020000000000ULL
141211827SRod.Evans@Sun.COM #define ENV_FLG_PLATCAP 0x0040000000000ULL
141311827SRod.Evans@Sun.COM #define ENV_FLG_CAP_FILES 0x0080000000000ULL
141412449SRod.Evans@Sun.COM #define ENV_FLG_DEFERRED 0x0100000000000ULL
141512650SRod.Evans@Sun.COM #define ENV_FLG_NOENVIRON 0x0200000000000ULL
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate #define SEL_REPLACE 0x0001
14180Sstevel@tonic-gate #define SEL_PERMANT 0x0002
14190Sstevel@tonic-gate #define SEL_ACT_RT 0x0100 /* setting rtld_flags */
14200Sstevel@tonic-gate #define SEL_ACT_RT2 0x0200 /* setting rtld_flags2 */
14210Sstevel@tonic-gate #define SEL_ACT_STR 0x0400 /* setting string value */
14220Sstevel@tonic-gate #define SEL_ACT_LML 0x0800 /* setting lml_flags */
14230Sstevel@tonic-gate #define SEL_ACT_LMLT 0x1000 /* setting lml_tflags */
142410792SRod.Evans@Sun.COM #define SEL_ACT_SPEC_1 0x2000 /* for FLG_{FLAGS, LIBPATH} */
14250Sstevel@tonic-gate #define SEL_ACT_SPEC_2 0x4000 /* need special handling */
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate /*
14280Sstevel@tonic-gate * Pattern match an LD_XXXX environment variable. s1 points to the XXXX part
14290Sstevel@tonic-gate * and len specifies its length (comparing a strings length before the string
14300Sstevel@tonic-gate * itself speed things up). s2 points to the token itself which has already
14310Sstevel@tonic-gate * had any leading white-space removed.
14320Sstevel@tonic-gate */
14330Sstevel@tonic-gate static void
ld_generic_env(const char * s1,size_t len,const char * s2,Word * lmflags,Word * lmtflags,uint_t env_flags,int aout)14340Sstevel@tonic-gate ld_generic_env(const char *s1, size_t len, const char *s2, Word *lmflags,
14350Sstevel@tonic-gate Word *lmtflags, uint_t env_flags, int aout)
14360Sstevel@tonic-gate {
14370Sstevel@tonic-gate u_longlong_t variable = 0;
14381824Srie ushort_t select = 0;
14391824Srie const char **str;
14401824Srie Word val = 0;
14410Sstevel@tonic-gate
14420Sstevel@tonic-gate /*
14430Sstevel@tonic-gate * Determine whether we're dealing with a replaceable or permanent
14440Sstevel@tonic-gate * string.
14450Sstevel@tonic-gate */
14460Sstevel@tonic-gate if (env_flags & ENV_TYP_PERMANT) {
14470Sstevel@tonic-gate /*
14480Sstevel@tonic-gate * If the string is from a configuration file and defined as
14490Sstevel@tonic-gate * permanent, assign it as permanent.
14500Sstevel@tonic-gate */
14510Sstevel@tonic-gate select |= SEL_PERMANT;
14520Sstevel@tonic-gate } else
14530Sstevel@tonic-gate select |= SEL_REPLACE;
14540Sstevel@tonic-gate
14550Sstevel@tonic-gate /*
14560Sstevel@tonic-gate * Parse the variable given.
14570Sstevel@tonic-gate *
14580Sstevel@tonic-gate * The LD_AUDIT family.
14590Sstevel@tonic-gate */
14600Sstevel@tonic-gate if (*s1 == 'A') {
14610Sstevel@tonic-gate if ((len == MSG_LD_AUDIT_SIZE) && (strncmp(s1,
14620Sstevel@tonic-gate MSG_ORIG(MSG_LD_AUDIT), MSG_LD_AUDIT_SIZE) == 0)) {
14630Sstevel@tonic-gate /*
14640Sstevel@tonic-gate * Replaceable and permanent audit objects can exist.
14650Sstevel@tonic-gate */
14660Sstevel@tonic-gate select |= SEL_ACT_STR;
14679340SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ? &rpl_audit : &prm_audit;
14680Sstevel@tonic-gate variable = ENV_FLG_AUDIT;
14690Sstevel@tonic-gate } else if ((len == MSG_LD_AUDIT_ARGS_SIZE) &&
14700Sstevel@tonic-gate (strncmp(s1, MSG_ORIG(MSG_LD_AUDIT_ARGS),
14710Sstevel@tonic-gate MSG_LD_AUDIT_ARGS_SIZE) == 0)) {
14720Sstevel@tonic-gate /*
14730Sstevel@tonic-gate * A specialized variable for plt_exit() use, not
14740Sstevel@tonic-gate * documented for general use.
14750Sstevel@tonic-gate */
14760Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
14770Sstevel@tonic-gate variable = ENV_FLG_AUDIT_ARGS;
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate }
14800Sstevel@tonic-gate /*
14818598SRod.Evans@Sun.COM * The LD_BIND family.
14820Sstevel@tonic-gate */
14830Sstevel@tonic-gate else if (*s1 == 'B') {
1484280Srie if ((len == MSG_LD_BIND_LAZY_SIZE) && (strncmp(s1,
1485280Srie MSG_ORIG(MSG_LD_BIND_LAZY),
1486280Srie MSG_LD_BIND_LAZY_SIZE) == 0)) {
1487280Srie select |= SEL_ACT_RT2;
1488280Srie val = RT_FL2_BINDLAZY;
1489280Srie variable = ENV_FLG_BIND_LAZY;
1490280Srie } else if ((len == MSG_LD_BIND_NOW_SIZE) && (strncmp(s1,
14910Sstevel@tonic-gate MSG_ORIG(MSG_LD_BIND_NOW), MSG_LD_BIND_NOW_SIZE) == 0)) {
14920Sstevel@tonic-gate select |= SEL_ACT_RT2;
14930Sstevel@tonic-gate val = RT_FL2_BINDNOW;
14940Sstevel@tonic-gate variable = ENV_FLG_BIND_NOW;
14950Sstevel@tonic-gate } else if ((len == MSG_LD_BIND_NOT_SIZE) && (strncmp(s1,
14960Sstevel@tonic-gate MSG_ORIG(MSG_LD_BIND_NOT), MSG_LD_BIND_NOT_SIZE) == 0)) {
14970Sstevel@tonic-gate /*
14980Sstevel@tonic-gate * Another trick, enabled to help debug AOUT
14990Sstevel@tonic-gate * applications under BCP, but not documented for
15000Sstevel@tonic-gate * general use.
15010Sstevel@tonic-gate */
15020Sstevel@tonic-gate select |= SEL_ACT_RT;
15030Sstevel@tonic-gate val = RT_FL_NOBIND;
15040Sstevel@tonic-gate variable = ENV_FLG_BIND_NOT;
15050Sstevel@tonic-gate } else if ((len == MSG_LD_BINDINGS_SIZE) && (strncmp(s1,
15060Sstevel@tonic-gate MSG_ORIG(MSG_LD_BINDINGS), MSG_LD_BINDINGS_SIZE) == 0)) {
15070Sstevel@tonic-gate /*
15080Sstevel@tonic-gate * This variable is simply for backward compatibility.
15090Sstevel@tonic-gate * If this and LD_DEBUG are both specified, only one of
15100Sstevel@tonic-gate * the strings is going to get processed.
15110Sstevel@tonic-gate */
15120Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
15130Sstevel@tonic-gate variable = ENV_FLG_BINDINGS;
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate /*
151711827SRod.Evans@Sun.COM * LD_CAP_FILES and LD_CONFIG family.
15180Sstevel@tonic-gate */
15190Sstevel@tonic-gate else if (*s1 == 'C') {
152011827SRod.Evans@Sun.COM if ((len == MSG_LD_CAP_FILES_SIZE) && (strncmp(s1,
152111827SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_CAP_FILES), MSG_LD_CAP_FILES_SIZE) == 0)) {
152211827SRod.Evans@Sun.COM select |= SEL_ACT_STR;
152311827SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ?
152411827SRod.Evans@Sun.COM &rpl_cap_files : &prm_cap_files;
152511827SRod.Evans@Sun.COM variable = ENV_FLG_CAP_FILES;
152611827SRod.Evans@Sun.COM } else if ((len == MSG_LD_CONFGEN_SIZE) && (strncmp(s1,
15270Sstevel@tonic-gate MSG_ORIG(MSG_LD_CONFGEN), MSG_LD_CONFGEN_SIZE) == 0)) {
15280Sstevel@tonic-gate /*
152912877SRod.Evans@Sun.COM * This variable is not documented for general use.
153012877SRod.Evans@Sun.COM * Although originaly designed for internal use with
153112877SRod.Evans@Sun.COM * crle(1), this variable is in use by the Studio
153212877SRod.Evans@Sun.COM * auditing tools. Hence, it can't be removed.
15330Sstevel@tonic-gate */
15340Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
15350Sstevel@tonic-gate variable = ENV_FLG_CONFGEN;
15360Sstevel@tonic-gate } else if ((len == MSG_LD_CONFIG_SIZE) && (strncmp(s1,
15370Sstevel@tonic-gate MSG_ORIG(MSG_LD_CONFIG), MSG_LD_CONFIG_SIZE) == 0)) {
15380Sstevel@tonic-gate /*
15390Sstevel@tonic-gate * Secure applications must use a default configuration
15400Sstevel@tonic-gate * file. A setting from a configuration file doesn't
15410Sstevel@tonic-gate * make sense (given we must be reading a configuration
15420Sstevel@tonic-gate * file to have gotten this).
15430Sstevel@tonic-gate */
15440Sstevel@tonic-gate if ((rtld_flags & RT_FL_SECURE) ||
15450Sstevel@tonic-gate (env_flags & ENV_TYP_CONFIG))
15460Sstevel@tonic-gate return;
15470Sstevel@tonic-gate select |= SEL_ACT_STR;
15480Sstevel@tonic-gate str = &config->c_name;
15490Sstevel@tonic-gate variable = ENV_FLG_CONFIG;
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate /*
155312449SRod.Evans@Sun.COM * The LD_DEBUG family, LD_DEFERRED (internal, used by ldd(1)), and
155412449SRod.Evans@Sun.COM * LD_DEMANGLE.
15550Sstevel@tonic-gate */
15560Sstevel@tonic-gate else if (*s1 == 'D') {
15570Sstevel@tonic-gate if ((len == MSG_LD_DEBUG_SIZE) && (strncmp(s1,
15580Sstevel@tonic-gate MSG_ORIG(MSG_LD_DEBUG), MSG_LD_DEBUG_SIZE) == 0)) {
15590Sstevel@tonic-gate select |= SEL_ACT_STR;
15609340SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ? &rpl_debug : &prm_debug;
15610Sstevel@tonic-gate variable = ENV_FLG_DEBUG;
15620Sstevel@tonic-gate } else if ((len == MSG_LD_DEBUG_OUTPUT_SIZE) && (strncmp(s1,
15630Sstevel@tonic-gate MSG_ORIG(MSG_LD_DEBUG_OUTPUT),
15640Sstevel@tonic-gate MSG_LD_DEBUG_OUTPUT_SIZE) == 0)) {
15650Sstevel@tonic-gate select |= SEL_ACT_STR;
15660Sstevel@tonic-gate str = &dbg_file;
15670Sstevel@tonic-gate variable = ENV_FLG_DEBUG_OUTPUT;
156812449SRod.Evans@Sun.COM } else if ((len == MSG_LD_DEFERRED_SIZE) && (strncmp(s1,
156912449SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_DEFERRED), MSG_LD_DEFERRED_SIZE) == 0)) {
157012449SRod.Evans@Sun.COM select |= SEL_ACT_RT;
157112449SRod.Evans@Sun.COM val = RT_FL_DEFERRED;
157212449SRod.Evans@Sun.COM variable = ENV_FLG_DEFERRED;
15730Sstevel@tonic-gate } else if ((len == MSG_LD_DEMANGLE_SIZE) && (strncmp(s1,
15740Sstevel@tonic-gate MSG_ORIG(MSG_LD_DEMANGLE), MSG_LD_DEMANGLE_SIZE) == 0)) {
15750Sstevel@tonic-gate select |= SEL_ACT_RT;
15760Sstevel@tonic-gate val = RT_FL_DEMANGLE;
15770Sstevel@tonic-gate variable = ENV_FLG_DEMANGLE;
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate /*
15810Sstevel@tonic-gate * LD_FLAGS - collect the best variable definition. On completion of
15820Sstevel@tonic-gate * environment variable processing pass the result to ld_flags_env()
15830Sstevel@tonic-gate * where they'll be decomposed and passed back to this routine.
15840Sstevel@tonic-gate */
15850Sstevel@tonic-gate else if (*s1 == 'F') {
15860Sstevel@tonic-gate if ((len == MSG_LD_FLAGS_SIZE) && (strncmp(s1,
15870Sstevel@tonic-gate MSG_ORIG(MSG_LD_FLAGS), MSG_LD_FLAGS_SIZE) == 0)) {
15880Sstevel@tonic-gate select |= SEL_ACT_SPEC_1;
15899340SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ? &rpl_ldflags :
15909340SRod.Evans@Sun.COM &prm_ldflags;
15910Sstevel@tonic-gate variable = ENV_FLG_FLAGS;
15920Sstevel@tonic-gate }
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate /*
159511827SRod.Evans@Sun.COM * LD_HWCAP.
159611827SRod.Evans@Sun.COM */
159711827SRod.Evans@Sun.COM else if (*s1 == 'H') {
159811827SRod.Evans@Sun.COM if ((len == MSG_LD_HWCAP_SIZE) && (strncmp(s1,
159911827SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_HWCAP), MSG_LD_HWCAP_SIZE) == 0)) {
160011827SRod.Evans@Sun.COM select |= SEL_ACT_STR;
160111827SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ?
160211827SRod.Evans@Sun.COM &rpl_hwcap : &prm_hwcap;
160311827SRod.Evans@Sun.COM variable = ENV_FLG_HWCAP;
160411827SRod.Evans@Sun.COM }
160511827SRod.Evans@Sun.COM }
160611827SRod.Evans@Sun.COM /*
16070Sstevel@tonic-gate * LD_INIT (internal, used by ldd(1)).
16080Sstevel@tonic-gate */
16090Sstevel@tonic-gate else if (*s1 == 'I') {
16100Sstevel@tonic-gate if ((len == MSG_LD_INIT_SIZE) && (strncmp(s1,
16110Sstevel@tonic-gate MSG_ORIG(MSG_LD_INIT), MSG_LD_INIT_SIZE) == 0)) {
16120Sstevel@tonic-gate select |= SEL_ACT_LML;
16130Sstevel@tonic-gate val = LML_FLG_TRC_INIT;
16140Sstevel@tonic-gate variable = ENV_FLG_INIT;
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate /*
16180Sstevel@tonic-gate * The LD_LIBRARY_PATH and LD_LOAD families.
16190Sstevel@tonic-gate */
16200Sstevel@tonic-gate else if (*s1 == 'L') {
16210Sstevel@tonic-gate if ((len == MSG_LD_LIBPATH_SIZE) && (strncmp(s1,
16220Sstevel@tonic-gate MSG_ORIG(MSG_LD_LIBPATH), MSG_LD_LIBPATH_SIZE) == 0)) {
16230Sstevel@tonic-gate select |= SEL_ACT_SPEC_1;
16249340SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ? &rpl_libpath :
16259340SRod.Evans@Sun.COM &prm_libpath;
16260Sstevel@tonic-gate variable = ENV_FLG_LIBPATH;
16270Sstevel@tonic-gate } else if ((len == MSG_LD_LOADAVAIL_SIZE) && (strncmp(s1,
16280Sstevel@tonic-gate MSG_ORIG(MSG_LD_LOADAVAIL), MSG_LD_LOADAVAIL_SIZE) == 0)) {
16290Sstevel@tonic-gate /*
163012877SRod.Evans@Sun.COM * This variable is not documented for general use.
163112877SRod.Evans@Sun.COM * Although originaly designed for internal use with
163212877SRod.Evans@Sun.COM * crle(1), this variable is in use by the Studio
163312877SRod.Evans@Sun.COM * auditing tools. Hence, it can't be removed.
16340Sstevel@tonic-gate */
16350Sstevel@tonic-gate select |= SEL_ACT_LML;
16360Sstevel@tonic-gate val = LML_FLG_LOADAVAIL;
16370Sstevel@tonic-gate variable = ENV_FLG_LOADAVAIL;
16380Sstevel@tonic-gate } else if ((len == MSG_LD_LOADFLTR_SIZE) && (strncmp(s1,
16390Sstevel@tonic-gate MSG_ORIG(MSG_LD_LOADFLTR), MSG_LD_LOADFLTR_SIZE) == 0)) {
16400Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
16410Sstevel@tonic-gate variable = ENV_FLG_LOADFLTR;
16420Sstevel@tonic-gate }
16430Sstevel@tonic-gate }
16440Sstevel@tonic-gate /*
164511827SRod.Evans@Sun.COM * LD_MACHCAP.
164611827SRod.Evans@Sun.COM */
164711827SRod.Evans@Sun.COM else if (*s1 == 'M') {
164811827SRod.Evans@Sun.COM if ((len == MSG_LD_MACHCAP_SIZE) && (strncmp(s1,
164911827SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_MACHCAP), MSG_LD_MACHCAP_SIZE) == 0)) {
165011827SRod.Evans@Sun.COM select |= SEL_ACT_STR;
165111827SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ?
165211827SRod.Evans@Sun.COM &rpl_machcap : &prm_machcap;
165311827SRod.Evans@Sun.COM variable = ENV_FLG_MACHCAP;
165411827SRod.Evans@Sun.COM }
165511827SRod.Evans@Sun.COM }
165611827SRod.Evans@Sun.COM /*
16570Sstevel@tonic-gate * The LD_NO family.
16580Sstevel@tonic-gate */
16590Sstevel@tonic-gate else if (*s1 == 'N') {
16600Sstevel@tonic-gate if ((len == MSG_LD_NOAUDIT_SIZE) && (strncmp(s1,
16610Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOAUDIT), MSG_LD_NOAUDIT_SIZE) == 0)) {
16620Sstevel@tonic-gate select |= SEL_ACT_RT;
16630Sstevel@tonic-gate val = RT_FL_NOAUDIT;
16640Sstevel@tonic-gate variable = ENV_FLG_NOAUDIT;
16650Sstevel@tonic-gate } else if ((len == MSG_LD_NOAUXFLTR_SIZE) && (strncmp(s1,
16660Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOAUXFLTR), MSG_LD_NOAUXFLTR_SIZE) == 0)) {
16670Sstevel@tonic-gate select |= SEL_ACT_RT;
16680Sstevel@tonic-gate val = RT_FL_NOAUXFLTR;
16690Sstevel@tonic-gate variable = ENV_FLG_NOAUXFLTR;
16700Sstevel@tonic-gate } else if ((len == MSG_LD_NOBAPLT_SIZE) && (strncmp(s1,
16710Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOBAPLT), MSG_LD_NOBAPLT_SIZE) == 0)) {
16720Sstevel@tonic-gate select |= SEL_ACT_RT;
16730Sstevel@tonic-gate val = RT_FL_NOBAPLT;
16740Sstevel@tonic-gate variable = ENV_FLG_NOBAPLT;
16750Sstevel@tonic-gate } else if ((len == MSG_LD_NOCONFIG_SIZE) && (strncmp(s1,
16760Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOCONFIG), MSG_LD_NOCONFIG_SIZE) == 0)) {
16770Sstevel@tonic-gate select |= SEL_ACT_RT;
16780Sstevel@tonic-gate val = RT_FL_NOCFG;
16790Sstevel@tonic-gate variable = ENV_FLG_NOCONFIG;
16800Sstevel@tonic-gate } else if ((len == MSG_LD_NODIRCONFIG_SIZE) && (strncmp(s1,
16810Sstevel@tonic-gate MSG_ORIG(MSG_LD_NODIRCONFIG),
16820Sstevel@tonic-gate MSG_LD_NODIRCONFIG_SIZE) == 0)) {
16830Sstevel@tonic-gate select |= SEL_ACT_RT;
16840Sstevel@tonic-gate val = RT_FL_NODIRCFG;
16850Sstevel@tonic-gate variable = ENV_FLG_NODIRCONFIG;
16860Sstevel@tonic-gate } else if ((len == MSG_LD_NODIRECT_SIZE) && (strncmp(s1,
16870Sstevel@tonic-gate MSG_ORIG(MSG_LD_NODIRECT), MSG_LD_NODIRECT_SIZE) == 0)) {
16880Sstevel@tonic-gate select |= SEL_ACT_LMLT;
16890Sstevel@tonic-gate val = LML_TFLG_NODIRECT;
16900Sstevel@tonic-gate variable = ENV_FLG_NODIRECT;
16910Sstevel@tonic-gate } else if ((len == MSG_LD_NOENVCONFIG_SIZE) && (strncmp(s1,
16920Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOENVCONFIG),
16930Sstevel@tonic-gate MSG_LD_NOENVCONFIG_SIZE) == 0)) {
16940Sstevel@tonic-gate select |= SEL_ACT_RT;
16950Sstevel@tonic-gate val = RT_FL_NOENVCFG;
16960Sstevel@tonic-gate variable = ENV_FLG_NOENVCONFIG;
16970Sstevel@tonic-gate } else if ((len == MSG_LD_NOFLTCONFIG_SIZE) && (strncmp(s1,
16980Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOFLTCONFIG),
16990Sstevel@tonic-gate MSG_LD_NOFLTCONFIG_SIZE) == 0)) {
17000Sstevel@tonic-gate select |= SEL_ACT_RT2;
17010Sstevel@tonic-gate val = RT_FL2_NOFLTCFG;
17020Sstevel@tonic-gate variable = ENV_FLG_NOFLTCONFIG;
17030Sstevel@tonic-gate } else if ((len == MSG_LD_NOLAZY_SIZE) && (strncmp(s1,
17040Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOLAZY), MSG_LD_NOLAZY_SIZE) == 0)) {
17050Sstevel@tonic-gate select |= SEL_ACT_LMLT;
17060Sstevel@tonic-gate val = LML_TFLG_NOLAZYLD;
17070Sstevel@tonic-gate variable = ENV_FLG_NOLAZY;
17080Sstevel@tonic-gate } else if ((len == MSG_LD_NOOBJALTER_SIZE) && (strncmp(s1,
17090Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOOBJALTER),
17100Sstevel@tonic-gate MSG_LD_NOOBJALTER_SIZE) == 0)) {
17110Sstevel@tonic-gate select |= SEL_ACT_RT;
17120Sstevel@tonic-gate val = RT_FL_NOOBJALT;
17130Sstevel@tonic-gate variable = ENV_FLG_NOOBJALTER;
17140Sstevel@tonic-gate } else if ((len == MSG_LD_NOVERSION_SIZE) && (strncmp(s1,
17150Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOVERSION), MSG_LD_NOVERSION_SIZE) == 0)) {
17160Sstevel@tonic-gate select |= SEL_ACT_RT;
17170Sstevel@tonic-gate val = RT_FL_NOVERSION;
17180Sstevel@tonic-gate variable = ENV_FLG_NOVERSION;
17194947Srie } else if ((len == MSG_LD_NOUNRESWEAK_SIZE) && (strncmp(s1,
17204947Srie MSG_ORIG(MSG_LD_NOUNRESWEAK),
17214947Srie MSG_LD_NOUNRESWEAK_SIZE) == 0)) {
17224947Srie /*
17234947Srie * LD_NOUNRESWEAK (internal, used by ldd(1)).
17244947Srie */
17254947Srie select |= SEL_ACT_LML;
17264947Srie val = LML_FLG_TRC_NOUNRESWEAK;
17274947Srie variable = ENV_FLG_NOUNRESWEAK;
17286150Srie } else if ((len == MSG_LD_NOPAREXT_SIZE) && (strncmp(s1,
17296150Srie MSG_ORIG(MSG_LD_NOPAREXT), MSG_LD_NOPAREXT_SIZE) == 0)) {
17306150Srie select |= SEL_ACT_LML;
17316150Srie val = LML_FLG_TRC_NOPAREXT;
17326150Srie variable = ENV_FLG_NOPAREXT;
173312650SRod.Evans@Sun.COM } else if ((len == MSG_LD_NOENVIRON_SIZE) && (strncmp(s1,
173412650SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_NOENVIRON), MSG_LD_NOENVIRON_SIZE) == 0)) {
173512650SRod.Evans@Sun.COM /*
173612650SRod.Evans@Sun.COM * LD_NOENVIRON can only be set with ld.so.1 -e.
173712650SRod.Evans@Sun.COM */
173812650SRod.Evans@Sun.COM select |= SEL_ACT_RT;
173912650SRod.Evans@Sun.COM val = RT_FL_NOENVIRON;
174012650SRod.Evans@Sun.COM variable = ENV_FLG_NOENVIRON;
17410Sstevel@tonic-gate }
17420Sstevel@tonic-gate }
17430Sstevel@tonic-gate /*
174411827SRod.Evans@Sun.COM * LD_PLATCAP, LD_PRELOAD and LD_PROFILE family.
17450Sstevel@tonic-gate */
17460Sstevel@tonic-gate else if (*s1 == 'P') {
174711827SRod.Evans@Sun.COM if ((len == MSG_LD_PLATCAP_SIZE) && (strncmp(s1,
174811827SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_PLATCAP), MSG_LD_PLATCAP_SIZE) == 0)) {
174911827SRod.Evans@Sun.COM select |= SEL_ACT_STR;
175011827SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ?
175111827SRod.Evans@Sun.COM &rpl_platcap : &prm_platcap;
175211827SRod.Evans@Sun.COM variable = ENV_FLG_PLATCAP;
175311827SRod.Evans@Sun.COM } else if ((len == MSG_LD_PRELOAD_SIZE) && (strncmp(s1,
17540Sstevel@tonic-gate MSG_ORIG(MSG_LD_PRELOAD), MSG_LD_PRELOAD_SIZE) == 0)) {
17550Sstevel@tonic-gate select |= SEL_ACT_STR;
17569340SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ? &rpl_preload :
17579340SRod.Evans@Sun.COM &prm_preload;
17580Sstevel@tonic-gate variable = ENV_FLG_PRELOAD;
17590Sstevel@tonic-gate } else if ((len == MSG_LD_PROFILE_SIZE) && (strncmp(s1,
17600Sstevel@tonic-gate MSG_ORIG(MSG_LD_PROFILE), MSG_LD_PROFILE_SIZE) == 0)) {
17610Sstevel@tonic-gate /*
17620Sstevel@tonic-gate * Only one user library can be profiled at a time.
17630Sstevel@tonic-gate */
17640Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
17650Sstevel@tonic-gate variable = ENV_FLG_PROFILE;
17660Sstevel@tonic-gate } else if ((len == MSG_LD_PROFILE_OUTPUT_SIZE) && (strncmp(s1,
17670Sstevel@tonic-gate MSG_ORIG(MSG_LD_PROFILE_OUTPUT),
17680Sstevel@tonic-gate MSG_LD_PROFILE_OUTPUT_SIZE) == 0)) {
17690Sstevel@tonic-gate /*
17700Sstevel@tonic-gate * Only one user library can be profiled at a time.
17710Sstevel@tonic-gate */
17720Sstevel@tonic-gate select |= SEL_ACT_STR;
17730Sstevel@tonic-gate str = &profile_out;
17740Sstevel@tonic-gate variable = ENV_FLG_PROFILE_OUTPUT;
17750Sstevel@tonic-gate }
17760Sstevel@tonic-gate }
17770Sstevel@tonic-gate /*
177811827SRod.Evans@Sun.COM * LD_SFCAP and LD_SIGNAL.
17790Sstevel@tonic-gate */
17800Sstevel@tonic-gate else if (*s1 == 'S') {
178111827SRod.Evans@Sun.COM if ((len == MSG_LD_SFCAP_SIZE) && (strncmp(s1,
178211827SRod.Evans@Sun.COM MSG_ORIG(MSG_LD_SFCAP), MSG_LD_SFCAP_SIZE) == 0)) {
178311827SRod.Evans@Sun.COM select |= SEL_ACT_STR;
178411827SRod.Evans@Sun.COM str = (select & SEL_REPLACE) ?
178511827SRod.Evans@Sun.COM &rpl_sfcap : &prm_sfcap;
178611827SRod.Evans@Sun.COM variable = ENV_FLG_SFCAP;
178711827SRod.Evans@Sun.COM } else if ((len == MSG_LD_SIGNAL_SIZE) &&
17880Sstevel@tonic-gate (strncmp(s1, MSG_ORIG(MSG_LD_SIGNAL),
178911827SRod.Evans@Sun.COM MSG_LD_SIGNAL_SIZE) == 0) &&
179011827SRod.Evans@Sun.COM ((rtld_flags & RT_FL_SECURE) == 0)) {
17910Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
17920Sstevel@tonic-gate variable = ENV_FLG_SIGNAL;
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate /*
17963511Srie * The LD_TRACE family (internal, used by ldd(1)). This definition is
17973511Srie * the key to enabling all other ldd(1) specific environment variables.
17983511Srie * In case an auditor is called, which in turn might exec(2) a
17993511Srie * subprocess, this variable is disabled, so that any subprocess
18003511Srie * escapes ldd(1) processing.
18010Sstevel@tonic-gate */
18020Sstevel@tonic-gate else if (*s1 == 'T') {
18030Sstevel@tonic-gate if (((len == MSG_LD_TRACE_OBJS_SIZE) &&
18040Sstevel@tonic-gate (strncmp(s1, MSG_ORIG(MSG_LD_TRACE_OBJS),
18050Sstevel@tonic-gate MSG_LD_TRACE_OBJS_SIZE) == 0)) ||
18060Sstevel@tonic-gate ((len == MSG_LD_TRACE_OBJS_E_SIZE) &&
18070Sstevel@tonic-gate (((strncmp(s1, MSG_ORIG(MSG_LD_TRACE_OBJS_E),
18080Sstevel@tonic-gate MSG_LD_TRACE_OBJS_E_SIZE) == 0) && !aout) ||
18090Sstevel@tonic-gate ((strncmp(s1, MSG_ORIG(MSG_LD_TRACE_OBJS_A),
18100Sstevel@tonic-gate MSG_LD_TRACE_OBJS_A_SIZE) == 0) && aout)))) {
18113511Srie char *s0 = (char *)s1;
18123511Srie
18130Sstevel@tonic-gate select |= SEL_ACT_SPEC_2;
18140Sstevel@tonic-gate variable = ENV_FLG_TRACE_OBJS;
18153511Srie
18163731Srie #if defined(__sparc) || defined(__x86)
18173511Srie /*
18183511Srie * The simplest way to "disable" this variable is to
18193511Srie * truncate this string to "LD_'\0'". This string is
18203511Srie * ignored by any ld.so.1 environment processing.
18213511Srie * Use of such interfaces as unsetenv(3c) are overkill,
18223511Srie * and would drag too much libc implementation detail
18233511Srie * into ld.so.1.
18243511Srie */
18254362Srie *s0 = '\0';
18263511Srie #else
18273511Srie /*
18283511Srie * Verify that the above write is appropriate for any new platforms.
18293511Srie */
18303511Srie #error unsupported architecture!
18313511Srie #endif
18320Sstevel@tonic-gate } else if ((len == MSG_LD_TRACE_PTHS_SIZE) && (strncmp(s1,
18330Sstevel@tonic-gate MSG_ORIG(MSG_LD_TRACE_PTHS),
18340Sstevel@tonic-gate MSG_LD_TRACE_PTHS_SIZE) == 0)) {
18350Sstevel@tonic-gate select |= SEL_ACT_LML;
18360Sstevel@tonic-gate val = LML_FLG_TRC_SEARCH;
18370Sstevel@tonic-gate variable = ENV_FLG_TRACE_PTHS;
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate /*
18410Sstevel@tonic-gate * LD_UNREF and LD_UNUSED (internal, used by ldd(1)).
18420Sstevel@tonic-gate */
18430Sstevel@tonic-gate else if (*s1 == 'U') {
18440Sstevel@tonic-gate if ((len == MSG_LD_UNREF_SIZE) && (strncmp(s1,
18450Sstevel@tonic-gate MSG_ORIG(MSG_LD_UNREF), MSG_LD_UNREF_SIZE) == 0)) {
18460Sstevel@tonic-gate select |= SEL_ACT_LML;
18470Sstevel@tonic-gate val = LML_FLG_TRC_UNREF;
18480Sstevel@tonic-gate variable = ENV_FLG_UNREF;
18490Sstevel@tonic-gate } else if ((len == MSG_LD_UNUSED_SIZE) && (strncmp(s1,
18500Sstevel@tonic-gate MSG_ORIG(MSG_LD_UNUSED), MSG_LD_UNUSED_SIZE) == 0)) {
18510Sstevel@tonic-gate select |= SEL_ACT_LML;
18520Sstevel@tonic-gate val = LML_FLG_TRC_UNUSED;
18530Sstevel@tonic-gate variable = ENV_FLG_UNUSED;
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate /*
18570Sstevel@tonic-gate * LD_VERBOSE (internal, used by ldd(1)).
18580Sstevel@tonic-gate */
18590Sstevel@tonic-gate else if (*s1 == 'V') {
18600Sstevel@tonic-gate if ((len == MSG_LD_VERBOSE_SIZE) && (strncmp(s1,
18610Sstevel@tonic-gate MSG_ORIG(MSG_LD_VERBOSE), MSG_LD_VERBOSE_SIZE) == 0)) {
18620Sstevel@tonic-gate select |= SEL_ACT_LML;
18630Sstevel@tonic-gate val = LML_FLG_TRC_VERBOSE;
18640Sstevel@tonic-gate variable = ENV_FLG_VERBOSE;
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate }
18670Sstevel@tonic-gate /*
18680Sstevel@tonic-gate * LD_WARN (internal, used by ldd(1)).
18690Sstevel@tonic-gate */
18700Sstevel@tonic-gate else if (*s1 == 'W') {
18710Sstevel@tonic-gate if ((len == MSG_LD_WARN_SIZE) && (strncmp(s1,
18720Sstevel@tonic-gate MSG_ORIG(MSG_LD_WARN), MSG_LD_WARN_SIZE) == 0)) {
18730Sstevel@tonic-gate select |= SEL_ACT_LML;
18740Sstevel@tonic-gate val = LML_FLG_TRC_WARN;
18750Sstevel@tonic-gate variable = ENV_FLG_WARN;
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate }
18788598SRod.Evans@Sun.COM
18790Sstevel@tonic-gate if (variable == 0)
18800Sstevel@tonic-gate return;
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate /*
188310792SRod.Evans@Sun.COM * If the variable is already processed with and ISA specific variable,
188410792SRod.Evans@Sun.COM * no further processing is needed.
18850Sstevel@tonic-gate */
18860Sstevel@tonic-gate if (((select & SEL_REPLACE) && (rplisa & variable)) ||
18870Sstevel@tonic-gate ((select & SEL_PERMANT) && (prmisa & variable)))
18880Sstevel@tonic-gate return;
18890Sstevel@tonic-gate
18900Sstevel@tonic-gate /*
189112650SRod.Evans@Sun.COM * If this variable has already been set via the command line, then
189212650SRod.Evans@Sun.COM * ignore this variable. The command line, -e, takes precedence.
189312650SRod.Evans@Sun.COM */
189412650SRod.Evans@Sun.COM if (env_flags & ENV_TYP_ISA) {
189512650SRod.Evans@Sun.COM if (cmdisa & variable)
189612650SRod.Evans@Sun.COM return;
189712650SRod.Evans@Sun.COM if (env_flags & ENV_TYP_CMDLINE)
189812650SRod.Evans@Sun.COM cmdisa |= variable;
189912650SRod.Evans@Sun.COM } else {
190012650SRod.Evans@Sun.COM if (cmdgen & variable)
190112650SRod.Evans@Sun.COM return;
190212650SRod.Evans@Sun.COM if (env_flags & ENV_TYP_CMDLINE)
190312650SRod.Evans@Sun.COM cmdgen |= variable;
190412650SRod.Evans@Sun.COM }
190512650SRod.Evans@Sun.COM
190612650SRod.Evans@Sun.COM /*
190710792SRod.Evans@Sun.COM * Mark the appropriate variables.
19080Sstevel@tonic-gate */
19090Sstevel@tonic-gate if (env_flags & ENV_TYP_ISA) {
19100Sstevel@tonic-gate /*
191110792SRod.Evans@Sun.COM * This is an ISA setting.
19120Sstevel@tonic-gate */
19130Sstevel@tonic-gate if (select & SEL_REPLACE) {
1914827Sseizo if (rplisa & variable)
1915827Sseizo return;
19160Sstevel@tonic-gate rplisa |= variable;
19170Sstevel@tonic-gate } else {
19180Sstevel@tonic-gate prmisa |= variable;
19190Sstevel@tonic-gate }
192010792SRod.Evans@Sun.COM } else {
19210Sstevel@tonic-gate /*
19229340SRod.Evans@Sun.COM * This is a non-ISA setting.
19230Sstevel@tonic-gate */
19240Sstevel@tonic-gate if (select & SEL_REPLACE) {
1925827Sseizo if (rplgen & variable)
1926827Sseizo return;
19270Sstevel@tonic-gate rplgen |= variable;
19280Sstevel@tonic-gate } else
19290Sstevel@tonic-gate prmgen |= variable;
193010792SRod.Evans@Sun.COM }
19310Sstevel@tonic-gate
19320Sstevel@tonic-gate /*
19330Sstevel@tonic-gate * Now perform the setting.
19340Sstevel@tonic-gate */
19350Sstevel@tonic-gate if (select & SEL_ACT_RT) {
19360Sstevel@tonic-gate if (s2)
19370Sstevel@tonic-gate rtld_flags |= val;
19380Sstevel@tonic-gate else
19390Sstevel@tonic-gate rtld_flags &= ~val;
19400Sstevel@tonic-gate } else if (select & SEL_ACT_RT2) {
19410Sstevel@tonic-gate if (s2)
19420Sstevel@tonic-gate rtld_flags2 |= val;
19430Sstevel@tonic-gate else
19440Sstevel@tonic-gate rtld_flags2 &= ~val;
194510792SRod.Evans@Sun.COM } else if (select & SEL_ACT_STR) {
194612650SRod.Evans@Sun.COM if (env_flags & ENV_TYP_NULL)
194712650SRod.Evans@Sun.COM *str = NULL;
194812650SRod.Evans@Sun.COM else
194912650SRod.Evans@Sun.COM *str = s2;
195010792SRod.Evans@Sun.COM } else if (select & SEL_ACT_LML) {
19510Sstevel@tonic-gate if (s2)
19520Sstevel@tonic-gate *lmflags |= val;
19530Sstevel@tonic-gate else
19540Sstevel@tonic-gate *lmflags &= ~val;
19550Sstevel@tonic-gate } else if (select & SEL_ACT_LMLT) {
19560Sstevel@tonic-gate if (s2)
19570Sstevel@tonic-gate *lmtflags |= val;
19580Sstevel@tonic-gate else
19590Sstevel@tonic-gate *lmtflags &= ~val;
19600Sstevel@tonic-gate } else if (select & SEL_ACT_SPEC_1) {
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate * variable is either ENV_FLG_FLAGS or ENV_FLG_LIBPATH
19630Sstevel@tonic-gate */
196412650SRod.Evans@Sun.COM if (env_flags & ENV_TYP_NULL)
196512650SRod.Evans@Sun.COM *str = NULL;
196612650SRod.Evans@Sun.COM else
196712650SRod.Evans@Sun.COM *str = s2;
19680Sstevel@tonic-gate if ((select & SEL_REPLACE) && (env_flags & ENV_TYP_CONFIG)) {
19690Sstevel@tonic-gate if (s2) {
19700Sstevel@tonic-gate if (variable == ENV_FLG_FLAGS)
19710Sstevel@tonic-gate env_info |= ENV_INF_FLAGCFG;
19720Sstevel@tonic-gate else
19730Sstevel@tonic-gate env_info |= ENV_INF_PATHCFG;
19740Sstevel@tonic-gate } else {
19750Sstevel@tonic-gate if (variable == ENV_FLG_FLAGS)
19760Sstevel@tonic-gate env_info &= ~ENV_INF_FLAGCFG;
19770Sstevel@tonic-gate else
19780Sstevel@tonic-gate env_info &= ~ENV_INF_PATHCFG;
19790Sstevel@tonic-gate }
19800Sstevel@tonic-gate }
19810Sstevel@tonic-gate } else if (select & SEL_ACT_SPEC_2) {
19820Sstevel@tonic-gate /*
19830Sstevel@tonic-gate * variables can be: ENV_FLG_
198410792SRod.Evans@Sun.COM * AUDIT_ARGS, BINDING, CONFGEN, LOADFLTR, PROFILE,
198510792SRod.Evans@Sun.COM * SIGNAL, TRACE_OBJS
19860Sstevel@tonic-gate */
198710792SRod.Evans@Sun.COM switch (variable) {
198810792SRod.Evans@Sun.COM case ENV_FLG_AUDIT_ARGS:
19890Sstevel@tonic-gate if (s2) {
19900Sstevel@tonic-gate audit_argcnt = atoi(s2);
19910Sstevel@tonic-gate audit_argcnt += audit_argcnt % 2;
19920Sstevel@tonic-gate } else
19930Sstevel@tonic-gate audit_argcnt = 0;
199410792SRod.Evans@Sun.COM break;
199510792SRod.Evans@Sun.COM case ENV_FLG_BINDINGS:
19960Sstevel@tonic-gate if (s2)
19970Sstevel@tonic-gate rpl_debug = MSG_ORIG(MSG_TKN_BINDINGS);
19980Sstevel@tonic-gate else
19998883SRod.Evans@Sun.COM rpl_debug = NULL;
200010792SRod.Evans@Sun.COM break;
200110792SRod.Evans@Sun.COM case ENV_FLG_CONFGEN:
20020Sstevel@tonic-gate if (s2) {
20030Sstevel@tonic-gate rtld_flags |= RT_FL_CONFGEN;
20040Sstevel@tonic-gate *lmflags |= LML_FLG_IGNRELERR;
20050Sstevel@tonic-gate } else {
20060Sstevel@tonic-gate rtld_flags &= ~RT_FL_CONFGEN;
20070Sstevel@tonic-gate *lmflags &= ~LML_FLG_IGNRELERR;
20080Sstevel@tonic-gate }
200910792SRod.Evans@Sun.COM break;
201010792SRod.Evans@Sun.COM case ENV_FLG_LOADFLTR:
20110Sstevel@tonic-gate if (s2) {
20120Sstevel@tonic-gate *lmtflags |= LML_TFLG_LOADFLTR;
20130Sstevel@tonic-gate if (*s2 == '2')
20140Sstevel@tonic-gate rtld_flags |= RT_FL_WARNFLTR;
20150Sstevel@tonic-gate } else {
20160Sstevel@tonic-gate *lmtflags &= ~LML_TFLG_LOADFLTR;
20170Sstevel@tonic-gate rtld_flags &= ~RT_FL_WARNFLTR;
20180Sstevel@tonic-gate }
201910792SRod.Evans@Sun.COM break;
202010792SRod.Evans@Sun.COM case ENV_FLG_PROFILE:
20210Sstevel@tonic-gate profile_name = s2;
20220Sstevel@tonic-gate if (s2) {
20230Sstevel@tonic-gate if (strcmp(s2, MSG_ORIG(MSG_FIL_RTLD)) == 0) {
20240Sstevel@tonic-gate return;
20250Sstevel@tonic-gate }
20264362Srie /* BEGIN CSTYLED */
20270Sstevel@tonic-gate if (rtld_flags & RT_FL_SECURE) {
20280Sstevel@tonic-gate profile_lib =
20290Sstevel@tonic-gate #if defined(_ELF64)
20300Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROFSE_64);
20310Sstevel@tonic-gate #else
20320Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROFSE);
20330Sstevel@tonic-gate #endif
20340Sstevel@tonic-gate } else {
20350Sstevel@tonic-gate profile_lib =
20360Sstevel@tonic-gate #if defined(_ELF64)
20370Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROF_64);
20380Sstevel@tonic-gate #else
20390Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROF);
20400Sstevel@tonic-gate #endif
20410Sstevel@tonic-gate }
20424362Srie /* END CSTYLED */
20430Sstevel@tonic-gate } else
20448598SRod.Evans@Sun.COM profile_lib = NULL;
204510792SRod.Evans@Sun.COM break;
204610792SRod.Evans@Sun.COM case ENV_FLG_SIGNAL:
20470Sstevel@tonic-gate killsig = s2 ? atoi(s2) : SIGKILL;
204810792SRod.Evans@Sun.COM break;
204910792SRod.Evans@Sun.COM case ENV_FLG_TRACE_OBJS:
20500Sstevel@tonic-gate if (s2) {
20510Sstevel@tonic-gate *lmflags |= LML_FLG_TRC_ENABLE;
20520Sstevel@tonic-gate if (*s2 == '2')
20530Sstevel@tonic-gate *lmflags |= LML_FLG_TRC_LDDSTUB;
20540Sstevel@tonic-gate } else
20550Sstevel@tonic-gate *lmflags &=
20569340SRod.Evans@Sun.COM ~(LML_FLG_TRC_ENABLE | LML_FLG_TRC_LDDSTUB);
205710792SRod.Evans@Sun.COM break;
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate }
20600Sstevel@tonic-gate }
20610Sstevel@tonic-gate
20620Sstevel@tonic-gate /*
20630Sstevel@tonic-gate * Determine whether we have an architecture specific environment variable.
20640Sstevel@tonic-gate * If we do, and we're the wrong architecture, it'll just get ignored.
20650Sstevel@tonic-gate * Otherwise the variable is processed in it's architecture neutral form.
20660Sstevel@tonic-gate */
20670Sstevel@tonic-gate static int
ld_arch_env(const char * s1,size_t * len)20680Sstevel@tonic-gate ld_arch_env(const char *s1, size_t *len)
20690Sstevel@tonic-gate {
20700Sstevel@tonic-gate size_t _len = *len - 3;
20710Sstevel@tonic-gate
20720Sstevel@tonic-gate if (s1[_len++] == '_') {
20730Sstevel@tonic-gate if ((s1[_len] == '3') && (s1[_len + 1] == '2')) {
20740Sstevel@tonic-gate #if defined(_ELF64)
20750Sstevel@tonic-gate return (ENV_TYP_IGNORE);
20760Sstevel@tonic-gate #else
20770Sstevel@tonic-gate *len = *len - 3;
20780Sstevel@tonic-gate return (ENV_TYP_ISA);
20790Sstevel@tonic-gate #endif
20800Sstevel@tonic-gate }
20810Sstevel@tonic-gate if ((s1[_len] == '6') && (s1[_len + 1] == '4')) {
20820Sstevel@tonic-gate #if defined(_ELF64)
20830Sstevel@tonic-gate *len = *len - 3;
20840Sstevel@tonic-gate return (ENV_TYP_ISA);
20850Sstevel@tonic-gate #else
20860Sstevel@tonic-gate return (ENV_TYP_IGNORE);
20870Sstevel@tonic-gate #endif
20880Sstevel@tonic-gate }
20890Sstevel@tonic-gate }
20900Sstevel@tonic-gate return (0);
20910Sstevel@tonic-gate }
20920Sstevel@tonic-gate
20930Sstevel@tonic-gate /*
20940Sstevel@tonic-gate * Process an LD_FLAGS environment variable. The value can be a comma
20950Sstevel@tonic-gate * separated set of tokens, which are sent (in upper case) into the generic
20960Sstevel@tonic-gate * LD_XXXX environment variable engine. For example:
20970Sstevel@tonic-gate *
209812650SRod.Evans@Sun.COM * LD_FLAGS=bind_now= -> LD_BIND_NOW=
20990Sstevel@tonic-gate * LD_FLAGS=bind_now -> LD_BIND_NOW=1
210012650SRod.Evans@Sun.COM * LD_FLAGS=library_path= -> LD_LIBRARY_PATH=
21010Sstevel@tonic-gate * LD_FLAGS=library_path=/foo:. -> LD_LIBRARY_PATH=/foo:.
21020Sstevel@tonic-gate * LD_FLAGS=debug=files:detail -> LD_DEBUG=files:detail
21030Sstevel@tonic-gate * or
21040Sstevel@tonic-gate * LD_FLAGS=bind_now,library_path=/foo:.,debug=files:detail
21050Sstevel@tonic-gate */
21060Sstevel@tonic-gate static int
ld_flags_env(const char * str,Word * lmflags,Word * lmtflags,uint_t env_flags,int aout)21070Sstevel@tonic-gate ld_flags_env(const char *str, Word *lmflags, Word *lmtflags,
21080Sstevel@tonic-gate uint_t env_flags, int aout)
21090Sstevel@tonic-gate {
21107668SRod.Evans@Sun.COM char *nstr, *sstr, *estr = NULL;
21110Sstevel@tonic-gate size_t nlen, len;
21120Sstevel@tonic-gate
21137668SRod.Evans@Sun.COM if (str == NULL)
21140Sstevel@tonic-gate return (0);
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate /*
21170Sstevel@tonic-gate * Create a new string as we're going to transform the token(s) into
21180Sstevel@tonic-gate * uppercase and separate tokens with nulls.
21190Sstevel@tonic-gate */
21200Sstevel@tonic-gate len = strlen(str);
21217668SRod.Evans@Sun.COM if ((nstr = malloc(len + 1)) == NULL)
21220Sstevel@tonic-gate return (1);
21230Sstevel@tonic-gate (void) strcpy(nstr, str);
21240Sstevel@tonic-gate
21250Sstevel@tonic-gate for (sstr = nstr; sstr; sstr++, len--) {
212612650SRod.Evans@Sun.COM int flags = 0;
21270Sstevel@tonic-gate
21280Sstevel@tonic-gate if ((*sstr != '\0') && (*sstr != ',')) {
21297668SRod.Evans@Sun.COM if (estr == NULL) {
21300Sstevel@tonic-gate if (*sstr == '=')
21310Sstevel@tonic-gate estr = sstr;
21320Sstevel@tonic-gate else {
21330Sstevel@tonic-gate /*
21340Sstevel@tonic-gate * Translate token to uppercase. Don't
21350Sstevel@tonic-gate * use toupper(3C) as including this
21360Sstevel@tonic-gate * code doubles the size of ld.so.1.
21370Sstevel@tonic-gate */
21380Sstevel@tonic-gate if ((*sstr >= 'a') && (*sstr <= 'z'))
21390Sstevel@tonic-gate *sstr = *sstr - ('a' - 'A');
21400Sstevel@tonic-gate }
21410Sstevel@tonic-gate }
21420Sstevel@tonic-gate continue;
21430Sstevel@tonic-gate }
21440Sstevel@tonic-gate
21450Sstevel@tonic-gate *sstr = '\0';
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate /*
214812650SRod.Evans@Sun.COM * Have we discovered an "=" string.
21490Sstevel@tonic-gate */
215012650SRod.Evans@Sun.COM if (estr) {
215112650SRod.Evans@Sun.COM nlen = estr - nstr;
215212650SRod.Evans@Sun.COM
215312650SRod.Evans@Sun.COM /*
215412650SRod.Evans@Sun.COM * If this is an unqualified "=", then this variable
215512650SRod.Evans@Sun.COM * is intended to ensure a feature is disabled.
215612650SRod.Evans@Sun.COM */
215712650SRod.Evans@Sun.COM if ((*++estr == '\0') || (*estr == ','))
215812650SRod.Evans@Sun.COM estr = NULL;
21590Sstevel@tonic-gate } else {
216012650SRod.Evans@Sun.COM nlen = sstr - nstr;
216112650SRod.Evans@Sun.COM
216212650SRod.Evans@Sun.COM /*
216312650SRod.Evans@Sun.COM * If there is no "=" found, fabricate a boolean
216412650SRod.Evans@Sun.COM * definition for any unqualified variable. Thus,
216512650SRod.Evans@Sun.COM * LD_FLAGS=bind_now is represented as BIND_NOW=1.
216612650SRod.Evans@Sun.COM * The value "1" is sufficient to assert any boolean
216712650SRod.Evans@Sun.COM * variables. Setting of ENV_TYP_NULL ensures any
216812650SRod.Evans@Sun.COM * string usage is reset to a NULL string, thus
216912650SRod.Evans@Sun.COM * LD_FLAGS=library_path is equivalent to
217012650SRod.Evans@Sun.COM * LIBRARY_PATH='\0'.
217112650SRod.Evans@Sun.COM */
217212650SRod.Evans@Sun.COM flags |= ENV_TYP_NULL;
217312650SRod.Evans@Sun.COM estr = (char *)MSG_ORIG(MSG_STR_ONE);
21740Sstevel@tonic-gate }
21750Sstevel@tonic-gate
21760Sstevel@tonic-gate /*
21770Sstevel@tonic-gate * Determine whether the environment variable is 32- or 64-bit
21780Sstevel@tonic-gate * specific. The length, len, will reflect the architecture
21790Sstevel@tonic-gate * neutral portion of the string.
21800Sstevel@tonic-gate */
218112650SRod.Evans@Sun.COM if ((flags |= ld_arch_env(nstr, &nlen)) != ENV_TYP_IGNORE) {
218212650SRod.Evans@Sun.COM ld_generic_env(nstr, nlen, estr, lmflags,
218312650SRod.Evans@Sun.COM lmtflags, (env_flags | flags), aout);
218412650SRod.Evans@Sun.COM }
218512650SRod.Evans@Sun.COM if (len == 0)
218612650SRod.Evans@Sun.COM break;
218712650SRod.Evans@Sun.COM
218812650SRod.Evans@Sun.COM nstr = sstr + 1;
218912650SRod.Evans@Sun.COM estr = NULL;
219012650SRod.Evans@Sun.COM }
219112650SRod.Evans@Sun.COM
219212650SRod.Evans@Sun.COM return (0);
219312650SRod.Evans@Sun.COM }
219412650SRod.Evans@Sun.COM
219512650SRod.Evans@Sun.COM /*
219612650SRod.Evans@Sun.COM * Variant of getopt(), intended for use when ld.so.1 is invoked directly
219712650SRod.Evans@Sun.COM * from the command line. The only command line option allowed is -e followed
219812650SRod.Evans@Sun.COM * by a runtime linker environment variable.
219912650SRod.Evans@Sun.COM */
220012650SRod.Evans@Sun.COM int
rtld_getopt(char ** argv,char *** envp,auxv_t ** auxv,Word * lmflags,Word * lmtflags,int aout)220112650SRod.Evans@Sun.COM rtld_getopt(char **argv, char ***envp, auxv_t **auxv, Word *lmflags,
220212650SRod.Evans@Sun.COM Word *lmtflags, int aout)
220312650SRod.Evans@Sun.COM {
220412650SRod.Evans@Sun.COM int ndx;
220512650SRod.Evans@Sun.COM
220612650SRod.Evans@Sun.COM for (ndx = 1; argv[ndx]; ndx++) {
220712650SRod.Evans@Sun.COM char *str;
220812650SRod.Evans@Sun.COM
220912650SRod.Evans@Sun.COM if (argv[ndx][0] != '-')
221012650SRod.Evans@Sun.COM break;
221112650SRod.Evans@Sun.COM
221212650SRod.Evans@Sun.COM if (argv[ndx][1] == '\0') {
221312650SRod.Evans@Sun.COM ndx++;
221412650SRod.Evans@Sun.COM break;
221512650SRod.Evans@Sun.COM }
221612650SRod.Evans@Sun.COM
221712650SRod.Evans@Sun.COM if (argv[ndx][1] != 'e')
221812650SRod.Evans@Sun.COM return (1);
221912650SRod.Evans@Sun.COM
222012650SRod.Evans@Sun.COM if (argv[ndx][2] == '\0') {
222112650SRod.Evans@Sun.COM ndx++;
222212650SRod.Evans@Sun.COM if (argv[ndx] == NULL)
222312650SRod.Evans@Sun.COM return (1);
222412650SRod.Evans@Sun.COM str = argv[ndx];
222512650SRod.Evans@Sun.COM } else
222612650SRod.Evans@Sun.COM str = &argv[ndx][2];
222712650SRod.Evans@Sun.COM
222812650SRod.Evans@Sun.COM /*
222912650SRod.Evans@Sun.COM * If the environment variable starts with LD_, strip the LD_.
223012650SRod.Evans@Sun.COM * Otherwise, take things as is. Indicate that this variable
223112650SRod.Evans@Sun.COM * originates from the command line, as these variables take
223212650SRod.Evans@Sun.COM * precedence over any environment variables, or configuration
223312650SRod.Evans@Sun.COM * file variables.
223412650SRod.Evans@Sun.COM */
223512650SRod.Evans@Sun.COM if ((str[0] == 'L') && (str[1] == 'D') && (str[2] == '_') &&
223612650SRod.Evans@Sun.COM (str[3] != '\0'))
223712650SRod.Evans@Sun.COM str += 3;
223812650SRod.Evans@Sun.COM if (ld_flags_env(str, lmflags, lmtflags,
223912650SRod.Evans@Sun.COM ENV_TYP_CMDLINE, aout) == 1)
224012650SRod.Evans@Sun.COM return (1);
224112650SRod.Evans@Sun.COM }
224212650SRod.Evans@Sun.COM
224312650SRod.Evans@Sun.COM /*
224412650SRod.Evans@Sun.COM * Make sure an object file has been specified.
224512650SRod.Evans@Sun.COM */
224612650SRod.Evans@Sun.COM if (argv[ndx] == NULL)
224712650SRod.Evans@Sun.COM return (1);
224812650SRod.Evans@Sun.COM
224912650SRod.Evans@Sun.COM /*
225012650SRod.Evans@Sun.COM * Having gotten the arguments, clean ourselves off of the stack.
225112650SRod.Evans@Sun.COM * This results in a process that looks as if it was executed directly
225212650SRod.Evans@Sun.COM * from the application.
225312650SRod.Evans@Sun.COM */
225412650SRod.Evans@Sun.COM stack_cleanup(argv, envp, auxv, ndx);
225512650SRod.Evans@Sun.COM return (0);
225612650SRod.Evans@Sun.COM }
225712650SRod.Evans@Sun.COM
225812650SRod.Evans@Sun.COM /*
225912650SRod.Evans@Sun.COM * Process a single LD_XXXX string.
226012650SRod.Evans@Sun.COM */
226112650SRod.Evans@Sun.COM static void
ld_str_env(const char * s1,Word * lmflags,Word * lmtflags,uint_t env_flags,int aout)226212650SRod.Evans@Sun.COM ld_str_env(const char *s1, Word *lmflags, Word *lmtflags, uint_t env_flags,
226312650SRod.Evans@Sun.COM int aout)
226412650SRod.Evans@Sun.COM {
226512650SRod.Evans@Sun.COM const char *s2;
226612650SRod.Evans@Sun.COM size_t len;
226712650SRod.Evans@Sun.COM int flags;
226812650SRod.Evans@Sun.COM
226912650SRod.Evans@Sun.COM /*
227012650SRod.Evans@Sun.COM * In a branded process we must ignore all LD_XXXX variables because
227112650SRod.Evans@Sun.COM * they are intended for the brand's linker. To affect the native
227212650SRod.Evans@Sun.COM * linker, use LD_BRAND_XXXX instead.
227312650SRod.Evans@Sun.COM */
227412650SRod.Evans@Sun.COM if (rtld_flags2 & RT_FL2_BRANDED) {
227512650SRod.Evans@Sun.COM if (strncmp(s1, MSG_ORIG(MSG_LD_BRAND_PREFIX),
227612650SRod.Evans@Sun.COM MSG_LD_BRAND_PREFIX_SIZE) != 0)
22770Sstevel@tonic-gate return;
227812650SRod.Evans@Sun.COM s1 += MSG_LD_BRAND_PREFIX_SIZE;
22790Sstevel@tonic-gate }
228012650SRod.Evans@Sun.COM
228112650SRod.Evans@Sun.COM /*
228212650SRod.Evans@Sun.COM * Variables with no value (ie. LD_XXXX=) turn a capability off.
228312650SRod.Evans@Sun.COM */
228412650SRod.Evans@Sun.COM if ((s2 = strchr(s1, '=')) == NULL) {
228512650SRod.Evans@Sun.COM len = strlen(s1);
228612650SRod.Evans@Sun.COM s2 = NULL;
228712650SRod.Evans@Sun.COM } else if (*++s2 == '\0') {
228812650SRod.Evans@Sun.COM len = strlen(s1) - 1;
228912650SRod.Evans@Sun.COM s2 = NULL;
229012650SRod.Evans@Sun.COM } else {
229112650SRod.Evans@Sun.COM len = s2 - s1 - 1;
229212650SRod.Evans@Sun.COM while (conv_strproc_isspace(*s2))
229312650SRod.Evans@Sun.COM s2++;
229412650SRod.Evans@Sun.COM }
229512650SRod.Evans@Sun.COM
229612650SRod.Evans@Sun.COM /*
229712650SRod.Evans@Sun.COM * Determine whether the environment variable is 32-bit or 64-bit
229812650SRod.Evans@Sun.COM * specific. The length, len, will reflect the architecture neutral
229912650SRod.Evans@Sun.COM * portion of the string.
230012650SRod.Evans@Sun.COM */
230112650SRod.Evans@Sun.COM if ((flags = ld_arch_env(s1, &len)) == ENV_TYP_IGNORE)
230212650SRod.Evans@Sun.COM return;
230312650SRod.Evans@Sun.COM env_flags |= flags;
230412650SRod.Evans@Sun.COM
230512650SRod.Evans@Sun.COM ld_generic_env(s1, len, s2, lmflags, lmtflags, env_flags, aout);
23060Sstevel@tonic-gate }
23070Sstevel@tonic-gate
23080Sstevel@tonic-gate /*
23090Sstevel@tonic-gate * Internal getenv routine. Called immediately after ld.so.1 initializes
231012650SRod.Evans@Sun.COM * itself to process any locale specific environment variables, and collect
231112650SRod.Evans@Sun.COM * any LD_XXXX variables for later processing.
231212650SRod.Evans@Sun.COM */
231312650SRod.Evans@Sun.COM #define LOC_LANG 1
231412650SRod.Evans@Sun.COM #define LOC_MESG 2
231512650SRod.Evans@Sun.COM #define LOC_ALL 3
231612650SRod.Evans@Sun.COM
231712650SRod.Evans@Sun.COM int
readenv_user(const char ** envp,APlist ** ealpp)231812650SRod.Evans@Sun.COM readenv_user(const char **envp, APlist **ealpp)
231912650SRod.Evans@Sun.COM {
232012650SRod.Evans@Sun.COM char *locale;
232112650SRod.Evans@Sun.COM const char *s1;
232212650SRod.Evans@Sun.COM int loc = 0;
232312650SRod.Evans@Sun.COM
232412650SRod.Evans@Sun.COM for (s1 = *envp; s1; envp++, s1 = *envp) {
232512650SRod.Evans@Sun.COM const char *s2;
232612650SRod.Evans@Sun.COM
232712650SRod.Evans@Sun.COM if (*s1++ != 'L')
232812650SRod.Evans@Sun.COM continue;
232912650SRod.Evans@Sun.COM
233012650SRod.Evans@Sun.COM /*
233112650SRod.Evans@Sun.COM * See if we have any locale environment settings. These
233212650SRod.Evans@Sun.COM * environment variables have a precedence, LC_ALL is higher
233312650SRod.Evans@Sun.COM * than LC_MESSAGES which is higher than LANG.
233412650SRod.Evans@Sun.COM */
233512650SRod.Evans@Sun.COM s2 = s1;
233612650SRod.Evans@Sun.COM if ((*s2++ == 'C') && (*s2++ == '_') && (*s2 != '\0')) {
233712650SRod.Evans@Sun.COM if (strncmp(s2, MSG_ORIG(MSG_LC_ALL),
233812650SRod.Evans@Sun.COM MSG_LC_ALL_SIZE) == 0) {
233912650SRod.Evans@Sun.COM s2 += MSG_LC_ALL_SIZE;
234012650SRod.Evans@Sun.COM if ((*s2 != '\0') && (loc < LOC_ALL)) {
234112650SRod.Evans@Sun.COM glcs[CI_LCMESSAGES].lc_un.lc_ptr =
234212650SRod.Evans@Sun.COM (char *)s2;
234312650SRod.Evans@Sun.COM loc = LOC_ALL;
234412650SRod.Evans@Sun.COM }
234512650SRod.Evans@Sun.COM } else if (strncmp(s2, MSG_ORIG(MSG_LC_MESSAGES),
234612650SRod.Evans@Sun.COM MSG_LC_MESSAGES_SIZE) == 0) {
234712650SRod.Evans@Sun.COM s2 += MSG_LC_MESSAGES_SIZE;
234812650SRod.Evans@Sun.COM if ((*s2 != '\0') && (loc < LOC_MESG)) {
234912650SRod.Evans@Sun.COM glcs[CI_LCMESSAGES].lc_un.lc_ptr =
235012650SRod.Evans@Sun.COM (char *)s2;
235112650SRod.Evans@Sun.COM loc = LOC_MESG;
235212650SRod.Evans@Sun.COM }
235312650SRod.Evans@Sun.COM }
235412650SRod.Evans@Sun.COM continue;
235512650SRod.Evans@Sun.COM }
235612650SRod.Evans@Sun.COM
235712650SRod.Evans@Sun.COM s2 = s1;
235812650SRod.Evans@Sun.COM if ((*s2++ == 'A') && (*s2++ == 'N') && (*s2++ == 'G') &&
235912650SRod.Evans@Sun.COM (*s2++ == '=') && (*s2 != '\0') && (loc < LOC_LANG)) {
236012650SRod.Evans@Sun.COM glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2;
236112650SRod.Evans@Sun.COM loc = LOC_LANG;
236212650SRod.Evans@Sun.COM continue;
236312650SRod.Evans@Sun.COM }
236412650SRod.Evans@Sun.COM
236512650SRod.Evans@Sun.COM /*
236612650SRod.Evans@Sun.COM * Pick off any LD_XXXX environment variables.
236712650SRod.Evans@Sun.COM */
236812650SRod.Evans@Sun.COM if ((*s1++ == 'D') && (*s1++ == '_') && (*s1 != '\0')) {
236912650SRod.Evans@Sun.COM if (aplist_append(ealpp, s1, AL_CNT_ENVIRON) == NULL)
237012650SRod.Evans@Sun.COM return (1);
237112650SRod.Evans@Sun.COM }
237212650SRod.Evans@Sun.COM }
237312650SRod.Evans@Sun.COM
237412650SRod.Evans@Sun.COM /*
237512650SRod.Evans@Sun.COM * If we have a locale setting make sure it's worth processing further.
237612650SRod.Evans@Sun.COM * C and POSIX locales don't need any processing. In addition, to
237712650SRod.Evans@Sun.COM * ensure no one escapes the /usr/lib/locale hierarchy, don't allow
237812650SRod.Evans@Sun.COM * the locale to contain a segment that leads upward in the file system
237912650SRod.Evans@Sun.COM * hierarchy (i.e. no '..' segments). Given that we'll be confined to
238012650SRod.Evans@Sun.COM * the /usr/lib/locale hierarchy, there is no need to extensively
238112650SRod.Evans@Sun.COM * validate the mode or ownership of any message file (as libc's
238212650SRod.Evans@Sun.COM * generic handling of message files does), or be concerned with
238312650SRod.Evans@Sun.COM * symbolic links that might otherwise send us elsewhere. Duplicate
238412650SRod.Evans@Sun.COM * the string so that new locale setting can generically cleanup any
238512650SRod.Evans@Sun.COM * previous locales.
238612650SRod.Evans@Sun.COM */
238712650SRod.Evans@Sun.COM if ((locale = glcs[CI_LCMESSAGES].lc_un.lc_ptr) != NULL) {
238812650SRod.Evans@Sun.COM if (((*locale == 'C') && (*(locale + 1) == '\0')) ||
238912650SRod.Evans@Sun.COM (strcmp(locale, MSG_ORIG(MSG_TKN_POSIX)) == 0) ||
239012650SRod.Evans@Sun.COM (strstr(locale, MSG_ORIG(MSG_TKN_DOTDOT)) != NULL))
239112650SRod.Evans@Sun.COM glcs[CI_LCMESSAGES].lc_un.lc_ptr = NULL;
239212650SRod.Evans@Sun.COM else
239312650SRod.Evans@Sun.COM glcs[CI_LCMESSAGES].lc_un.lc_ptr = strdup(locale);
239412650SRod.Evans@Sun.COM }
239512650SRod.Evans@Sun.COM return (0);
239612650SRod.Evans@Sun.COM }
239712650SRod.Evans@Sun.COM
239812650SRod.Evans@Sun.COM /*
239912650SRod.Evans@Sun.COM * Process any LD_XXXX environment variables collected by readenv_user().
24000Sstevel@tonic-gate */
24010Sstevel@tonic-gate int
procenv_user(APlist * ealp,Word * lmflags,Word * lmtflags,int aout)240212650SRod.Evans@Sun.COM procenv_user(APlist *ealp, Word *lmflags, Word *lmtflags, int aout)
24030Sstevel@tonic-gate {
240412650SRod.Evans@Sun.COM Aliste idx;
240512650SRod.Evans@Sun.COM const char *s1;
240612650SRod.Evans@Sun.COM
240712650SRod.Evans@Sun.COM for (APLIST_TRAVERSE(ealp, idx, s1))
240812650SRod.Evans@Sun.COM ld_str_env(s1, lmflags, lmtflags, 0, aout);
24090Sstevel@tonic-gate
24100Sstevel@tonic-gate /*
24110Sstevel@tonic-gate * Having collected the best representation of any LD_FLAGS, process
24120Sstevel@tonic-gate * these strings.
24130Sstevel@tonic-gate */
241412650SRod.Evans@Sun.COM if (rpl_ldflags) {
241512650SRod.Evans@Sun.COM if (ld_flags_env(rpl_ldflags, lmflags, lmtflags, 0, aout) == 1)
241612650SRod.Evans@Sun.COM return (1);
241712650SRod.Evans@Sun.COM rpl_ldflags = NULL;
241812650SRod.Evans@Sun.COM }
24190Sstevel@tonic-gate
24200Sstevel@tonic-gate /*
24210Sstevel@tonic-gate * Don't allow environment controlled auditing when tracing or if
24220Sstevel@tonic-gate * explicitly disabled. Trigger all tracing modes from
24230Sstevel@tonic-gate * LML_FLG_TRC_ENABLE.
24240Sstevel@tonic-gate */
24250Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) || (rtld_flags & RT_FL_NOAUDIT))
24268598SRod.Evans@Sun.COM rpl_audit = profile_lib = profile_name = NULL;
24270Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) == 0)
24280Sstevel@tonic-gate *lmflags &= ~LML_MSK_TRC;
24290Sstevel@tonic-gate
24300Sstevel@tonic-gate /*
2431280Srie * If both LD_BIND_NOW and LD_BIND_LAZY are specified, the former wins.
2432280Srie */
2433280Srie if ((rtld_flags2 & (RT_FL2_BINDNOW | RT_FL2_BINDLAZY)) ==
2434280Srie (RT_FL2_BINDNOW | RT_FL2_BINDLAZY))
2435280Srie rtld_flags2 &= ~RT_FL2_BINDLAZY;
2436280Srie
2437280Srie /*
24386150Srie * When using ldd(1) -r or -d against an executable, assert -p.
24396150Srie */
24406150Srie if ((*lmflags &
24416150Srie (LML_FLG_TRC_WARN | LML_FLG_TRC_LDDSTUB)) == LML_FLG_TRC_WARN)
24426150Srie *lmflags |= LML_FLG_TRC_NOPAREXT;
24436150Srie
24440Sstevel@tonic-gate return (0);
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate
24470Sstevel@tonic-gate /*
24480Sstevel@tonic-gate * Configuration environment processing. Called after the a.out has been
24490Sstevel@tonic-gate * processed (as the a.out can specify its own configuration file).
24500Sstevel@tonic-gate */
24510Sstevel@tonic-gate int
readenv_config(Rtc_env * envtbl,Addr addr,int aout)24520Sstevel@tonic-gate readenv_config(Rtc_env * envtbl, Addr addr, int aout)
24530Sstevel@tonic-gate {
245412650SRod.Evans@Sun.COM Word *lmflags = &(lml_main.lm_flags);
245512650SRod.Evans@Sun.COM Word *lmtflags = &(lml_main.lm_tflags);
24560Sstevel@tonic-gate
24578598SRod.Evans@Sun.COM if (envtbl == NULL)
24580Sstevel@tonic-gate return (0);
24590Sstevel@tonic-gate
24600Sstevel@tonic-gate while (envtbl->env_str) {
246112650SRod.Evans@Sun.COM uint_t env_flags = ENV_TYP_CONFIG;
246212650SRod.Evans@Sun.COM const char *s1 = (const char *)(envtbl->env_str + addr);
24630Sstevel@tonic-gate
24640Sstevel@tonic-gate if (envtbl->env_flags & RTC_ENV_PERMANT)
24650Sstevel@tonic-gate env_flags |= ENV_TYP_PERMANT;
24660Sstevel@tonic-gate
246712650SRod.Evans@Sun.COM if ((*s1++ == 'L') && (*s1++ == 'D') &&
246812650SRod.Evans@Sun.COM (*s1++ == '_') && (*s1 != '\0'))
246912650SRod.Evans@Sun.COM ld_str_env(s1, lmflags, lmtflags, env_flags, 0);
247012650SRod.Evans@Sun.COM
24710Sstevel@tonic-gate envtbl++;
24720Sstevel@tonic-gate }
24730Sstevel@tonic-gate
24740Sstevel@tonic-gate /*
24750Sstevel@tonic-gate * Having collected the best representation of any LD_FLAGS, process
24760Sstevel@tonic-gate * these strings.
24770Sstevel@tonic-gate */
24780Sstevel@tonic-gate if (ld_flags_env(rpl_ldflags, lmflags, lmtflags, 0, aout) == 1)
24790Sstevel@tonic-gate return (1);
24800Sstevel@tonic-gate if (ld_flags_env(prm_ldflags, lmflags, lmtflags, ENV_TYP_CONFIG,
24810Sstevel@tonic-gate aout) == 1)
24820Sstevel@tonic-gate return (1);
24830Sstevel@tonic-gate
24840Sstevel@tonic-gate /*
24850Sstevel@tonic-gate * Don't allow environment controlled auditing when tracing or if
24860Sstevel@tonic-gate * explicitly disabled. Trigger all tracing modes from
24870Sstevel@tonic-gate * LML_FLG_TRC_ENABLE.
24880Sstevel@tonic-gate */
24890Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) || (rtld_flags & RT_FL_NOAUDIT))
24908598SRod.Evans@Sun.COM prm_audit = profile_lib = profile_name = NULL;
24910Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) == 0)
24920Sstevel@tonic-gate *lmflags &= ~LML_MSK_TRC;
24930Sstevel@tonic-gate
24940Sstevel@tonic-gate return (0);
24950Sstevel@tonic-gate }
24960Sstevel@tonic-gate
24970Sstevel@tonic-gate int
dowrite(Prfbuf * prf)24980Sstevel@tonic-gate dowrite(Prfbuf * prf)
24990Sstevel@tonic-gate {
25000Sstevel@tonic-gate /*
25010Sstevel@tonic-gate * We do not have a valid file descriptor, so we are unable
25020Sstevel@tonic-gate * to flush the buffer.
25030Sstevel@tonic-gate */
25040Sstevel@tonic-gate if (prf->pr_fd == -1)
25050Sstevel@tonic-gate return (0);
25060Sstevel@tonic-gate (void) write(prf->pr_fd, prf->pr_buf, prf->pr_cur - prf->pr_buf);
25070Sstevel@tonic-gate prf->pr_cur = prf->pr_buf;
25080Sstevel@tonic-gate return (1);
25090Sstevel@tonic-gate }
25100Sstevel@tonic-gate
25110Sstevel@tonic-gate /*
25120Sstevel@tonic-gate * Simplified printing. The following conversion specifications are supported:
25130Sstevel@tonic-gate *
25140Sstevel@tonic-gate * % [#] [-] [min field width] [. precision] s|d|x|c
25150Sstevel@tonic-gate *
25160Sstevel@tonic-gate *
25170Sstevel@tonic-gate * dorprf takes the output buffer in the form of Prfbuf which permits
25180Sstevel@tonic-gate * the verification of the output buffer size and the concatenation
25190Sstevel@tonic-gate * of data to an already existing output buffer. The Prfbuf
25200Sstevel@tonic-gate * structure contains the following:
25210Sstevel@tonic-gate *
25220Sstevel@tonic-gate * pr_buf pointer to the beginning of the output buffer.
25230Sstevel@tonic-gate * pr_cur pointer to the next available byte in the output buffer. By
25240Sstevel@tonic-gate * setting pr_cur ahead of pr_buf you can append to an already
25250Sstevel@tonic-gate * existing buffer.
25260Sstevel@tonic-gate * pr_len the size of the output buffer. By setting pr_len to '0' you
25270Sstevel@tonic-gate * disable protection from overflows in the output buffer.
25280Sstevel@tonic-gate * pr_fd a pointer to the file-descriptor the buffer will eventually be
25290Sstevel@tonic-gate * output to. If pr_fd is set to '-1' then it's assumed there is
25303191Srie * no output buffer, and doprf() will return with an error to
25313191Srie * indicate an output buffer overflow. If pr_fd is > -1 then when
25323191Srie * the output buffer is filled it will be flushed to pr_fd and will
25333191Srie * then be available for additional data.
25340Sstevel@tonic-gate */
25350Sstevel@tonic-gate #define FLG_UT_MINUS 0x0001 /* - */
25360Sstevel@tonic-gate #define FLG_UT_SHARP 0x0002 /* # */
25370Sstevel@tonic-gate #define FLG_UT_DOTSEEN 0x0008 /* dot appeared in format spec */
25380Sstevel@tonic-gate
25390Sstevel@tonic-gate /*
25401824Srie * This macro is for use from within doprf only. It is to be used for checking
25411824Srie * the output buffer size and placing characters into the buffer.
25420Sstevel@tonic-gate */
25430Sstevel@tonic-gate #define PUTC(c) \
25440Sstevel@tonic-gate { \
25451824Srie char tmpc; \
25460Sstevel@tonic-gate \
25470Sstevel@tonic-gate tmpc = (c); \
25481824Srie if (bufsiz && (bp >= bufend)) { \
25490Sstevel@tonic-gate prf->pr_cur = bp; \
25500Sstevel@tonic-gate if (dowrite(prf) == 0) \
25510Sstevel@tonic-gate return (0); \
25520Sstevel@tonic-gate bp = prf->pr_cur; \
25530Sstevel@tonic-gate } \
25540Sstevel@tonic-gate *bp++ = tmpc; \
25550Sstevel@tonic-gate }
25560Sstevel@tonic-gate
25573191Srie /*
25583191Srie * Define a local buffer size for building a numeric value - large enough to
25593191Srie * hold a 64-bit value.
25603191Srie */
25613304Srie #define NUM_SIZE 22
25623191Srie
25630Sstevel@tonic-gate size_t
doprf(const char * format,va_list args,Prfbuf * prf)25640Sstevel@tonic-gate doprf(const char *format, va_list args, Prfbuf *prf)
25650Sstevel@tonic-gate {
25660Sstevel@tonic-gate char c;
25670Sstevel@tonic-gate char *bp = prf->pr_cur;
25680Sstevel@tonic-gate char *bufend = prf->pr_buf + prf->pr_len;
25690Sstevel@tonic-gate size_t bufsiz = prf->pr_len;
25700Sstevel@tonic-gate
25710Sstevel@tonic-gate while ((c = *format++) != '\0') {
25720Sstevel@tonic-gate if (c != '%') {
25730Sstevel@tonic-gate PUTC(c);
25740Sstevel@tonic-gate } else {
25750Sstevel@tonic-gate int base = 0, flag = 0, width = 0, prec = 0;
25760Sstevel@tonic-gate size_t _i;
25770Sstevel@tonic-gate int _c, _n;
25780Sstevel@tonic-gate char *_s;
25790Sstevel@tonic-gate int ls = 0;
25800Sstevel@tonic-gate again:
25810Sstevel@tonic-gate c = *format++;
25820Sstevel@tonic-gate switch (c) {
25830Sstevel@tonic-gate case '-':
25840Sstevel@tonic-gate flag |= FLG_UT_MINUS;
25850Sstevel@tonic-gate goto again;
25860Sstevel@tonic-gate case '#':
25870Sstevel@tonic-gate flag |= FLG_UT_SHARP;
25880Sstevel@tonic-gate goto again;
25890Sstevel@tonic-gate case '.':
25900Sstevel@tonic-gate flag |= FLG_UT_DOTSEEN;
25910Sstevel@tonic-gate goto again;
25920Sstevel@tonic-gate case '0':
25930Sstevel@tonic-gate case '1':
25940Sstevel@tonic-gate case '2':
25950Sstevel@tonic-gate case '3':
25960Sstevel@tonic-gate case '4':
25970Sstevel@tonic-gate case '5':
25980Sstevel@tonic-gate case '6':
25990Sstevel@tonic-gate case '7':
26000Sstevel@tonic-gate case '8':
26010Sstevel@tonic-gate case '9':
26020Sstevel@tonic-gate if (flag & FLG_UT_DOTSEEN)
26030Sstevel@tonic-gate prec = (prec * 10) + c - '0';
26040Sstevel@tonic-gate else
26050Sstevel@tonic-gate width = (width * 10) + c - '0';
26060Sstevel@tonic-gate goto again;
26070Sstevel@tonic-gate case 'x':
26080Sstevel@tonic-gate case 'X':
26090Sstevel@tonic-gate base = 16;
26100Sstevel@tonic-gate break;
26110Sstevel@tonic-gate case 'd':
26120Sstevel@tonic-gate case 'D':
26130Sstevel@tonic-gate case 'u':
26140Sstevel@tonic-gate base = 10;
26150Sstevel@tonic-gate flag &= ~FLG_UT_SHARP;
26160Sstevel@tonic-gate break;
26170Sstevel@tonic-gate case 'l':
26180Sstevel@tonic-gate base = 10;
26190Sstevel@tonic-gate ls++; /* number of l's (long or long long) */
26200Sstevel@tonic-gate if ((*format == 'l') ||
26210Sstevel@tonic-gate (*format == 'd') || (*format == 'D') ||
26220Sstevel@tonic-gate (*format == 'x') || (*format == 'X') ||
262311690SAli.Bahrami@Sun.COM (*format == 'o') || (*format == 'O') ||
262411690SAli.Bahrami@Sun.COM (*format == 'u') || (*format == 'U'))
26250Sstevel@tonic-gate goto again;
26260Sstevel@tonic-gate break;
26270Sstevel@tonic-gate case 'o':
26280Sstevel@tonic-gate case 'O':
26290Sstevel@tonic-gate base = 8;
26300Sstevel@tonic-gate break;
26310Sstevel@tonic-gate case 'c':
26320Sstevel@tonic-gate _c = va_arg(args, int);
26330Sstevel@tonic-gate
26340Sstevel@tonic-gate for (_i = 24; _i > 0; _i -= 8) {
26350Sstevel@tonic-gate if ((c = ((_c >> _i) & 0x7f)) != 0) {
26360Sstevel@tonic-gate PUTC(c);
26370Sstevel@tonic-gate }
26380Sstevel@tonic-gate }
26390Sstevel@tonic-gate if ((c = ((_c >> _i) & 0x7f)) != 0) {
26400Sstevel@tonic-gate PUTC(c);
26410Sstevel@tonic-gate }
26420Sstevel@tonic-gate break;
26430Sstevel@tonic-gate case 's':
26440Sstevel@tonic-gate _s = va_arg(args, char *);
26450Sstevel@tonic-gate _i = strlen(_s);
26460Sstevel@tonic-gate /* LINTED */
26470Sstevel@tonic-gate _n = (int)(width - _i);
26480Sstevel@tonic-gate if (!prec)
26490Sstevel@tonic-gate /* LINTED */
26500Sstevel@tonic-gate prec = (int)_i;
26510Sstevel@tonic-gate
26520Sstevel@tonic-gate if (width && !(flag & FLG_UT_MINUS)) {
26530Sstevel@tonic-gate while (_n-- > 0)
26540Sstevel@tonic-gate PUTC(' ');
26550Sstevel@tonic-gate }
26560Sstevel@tonic-gate while (((c = *_s++) != 0) && prec--) {
26570Sstevel@tonic-gate PUTC(c);
26580Sstevel@tonic-gate }
26590Sstevel@tonic-gate if (width && (flag & FLG_UT_MINUS)) {
26600Sstevel@tonic-gate while (_n-- > 0)
26610Sstevel@tonic-gate PUTC(' ');
26620Sstevel@tonic-gate }
26630Sstevel@tonic-gate break;
26640Sstevel@tonic-gate case '%':
26650Sstevel@tonic-gate PUTC('%');
26660Sstevel@tonic-gate break;
26670Sstevel@tonic-gate default:
26680Sstevel@tonic-gate break;
26690Sstevel@tonic-gate }
26700Sstevel@tonic-gate
26710Sstevel@tonic-gate /*
26720Sstevel@tonic-gate * Numeric processing
26730Sstevel@tonic-gate */
26740Sstevel@tonic-gate if (base) {
26753191Srie char local[NUM_SIZE];
26763191Srie size_t ssize = 0, psize = 0;
26770Sstevel@tonic-gate const char *string =
26784362Srie MSG_ORIG(MSG_STR_HEXNUM);
26790Sstevel@tonic-gate const char *prefix =
26804362Srie MSG_ORIG(MSG_STR_EMPTY);
26810Sstevel@tonic-gate u_longlong_t num;
26820Sstevel@tonic-gate
26830Sstevel@tonic-gate switch (ls) {
26840Sstevel@tonic-gate case 0: /* int */
26850Sstevel@tonic-gate num = (u_longlong_t)
26860Sstevel@tonic-gate va_arg(args, uint_t);
26870Sstevel@tonic-gate break;
26880Sstevel@tonic-gate case 1: /* long */
26890Sstevel@tonic-gate num = (u_longlong_t)
26900Sstevel@tonic-gate va_arg(args, ulong_t);
26910Sstevel@tonic-gate break;
26920Sstevel@tonic-gate case 2: /* long long */
26930Sstevel@tonic-gate num = va_arg(args, u_longlong_t);
26940Sstevel@tonic-gate break;
26950Sstevel@tonic-gate }
26960Sstevel@tonic-gate
26970Sstevel@tonic-gate if (flag & FLG_UT_SHARP) {
26980Sstevel@tonic-gate if (base == 16) {
26990Sstevel@tonic-gate prefix = MSG_ORIG(MSG_STR_HEX);
27000Sstevel@tonic-gate psize = 2;
27010Sstevel@tonic-gate } else {
27020Sstevel@tonic-gate prefix = MSG_ORIG(MSG_STR_ZERO);
27030Sstevel@tonic-gate psize = 1;
27040Sstevel@tonic-gate }
27050Sstevel@tonic-gate }
27060Sstevel@tonic-gate if ((base == 10) && (long)num < 0) {
27070Sstevel@tonic-gate prefix = MSG_ORIG(MSG_STR_NEGATE);
27080Sstevel@tonic-gate psize = MSG_STR_NEGATE_SIZE;
27090Sstevel@tonic-gate num = (u_longlong_t)(-(longlong_t)num);
27100Sstevel@tonic-gate }
27110Sstevel@tonic-gate
27120Sstevel@tonic-gate /*
27130Sstevel@tonic-gate * Convert the numeric value into a local
27140Sstevel@tonic-gate * string (stored in reverse order).
27150Sstevel@tonic-gate */
27160Sstevel@tonic-gate _s = local;
27170Sstevel@tonic-gate do {
27180Sstevel@tonic-gate *_s++ = string[num % base];
27190Sstevel@tonic-gate num /= base;
27200Sstevel@tonic-gate ssize++;
27210Sstevel@tonic-gate } while (num);
27220Sstevel@tonic-gate
27233191Srie ASSERT(ssize < sizeof (local));
27243191Srie
27250Sstevel@tonic-gate /*
27260Sstevel@tonic-gate * Provide any precision or width padding.
27270Sstevel@tonic-gate */
27280Sstevel@tonic-gate if (prec) {
27290Sstevel@tonic-gate /* LINTED */
27300Sstevel@tonic-gate _n = (int)(prec - ssize);
27313191Srie while ((_n-- > 0) &&
27323191Srie (ssize < sizeof (local))) {
27330Sstevel@tonic-gate *_s++ = '0';
27340Sstevel@tonic-gate ssize++;
27350Sstevel@tonic-gate }
27360Sstevel@tonic-gate }
27370Sstevel@tonic-gate if (width && !(flag & FLG_UT_MINUS)) {
27380Sstevel@tonic-gate /* LINTED */
27390Sstevel@tonic-gate _n = (int)(width - ssize - psize);
27400Sstevel@tonic-gate while (_n-- > 0) {
27410Sstevel@tonic-gate PUTC(' ');
27420Sstevel@tonic-gate }
27430Sstevel@tonic-gate }
27440Sstevel@tonic-gate
27450Sstevel@tonic-gate /*
27460Sstevel@tonic-gate * Print any prefix and the numeric string
27470Sstevel@tonic-gate */
27480Sstevel@tonic-gate while (*prefix)
27490Sstevel@tonic-gate PUTC(*prefix++);
27500Sstevel@tonic-gate do {
27510Sstevel@tonic-gate PUTC(*--_s);
27520Sstevel@tonic-gate } while (_s > local);
27530Sstevel@tonic-gate
27540Sstevel@tonic-gate /*
27550Sstevel@tonic-gate * Provide any width padding.
27560Sstevel@tonic-gate */
27570Sstevel@tonic-gate if (width && (flag & FLG_UT_MINUS)) {
27580Sstevel@tonic-gate /* LINTED */
27590Sstevel@tonic-gate _n = (int)(width - ssize - psize);
27600Sstevel@tonic-gate while (_n-- > 0)
27610Sstevel@tonic-gate PUTC(' ');
27620Sstevel@tonic-gate }
27630Sstevel@tonic-gate }
27640Sstevel@tonic-gate }
27650Sstevel@tonic-gate }
27661824Srie
27670Sstevel@tonic-gate PUTC('\0');
27680Sstevel@tonic-gate prf->pr_cur = bp;
27690Sstevel@tonic-gate return (1);
27700Sstevel@tonic-gate }
27710Sstevel@tonic-gate
27720Sstevel@tonic-gate static int
doprintf(const char * format,va_list args,Prfbuf * prf)27730Sstevel@tonic-gate doprintf(const char *format, va_list args, Prfbuf *prf)
27740Sstevel@tonic-gate {
27750Sstevel@tonic-gate char *ocur = prf->pr_cur;
27760Sstevel@tonic-gate
27770Sstevel@tonic-gate if (doprf(format, args, prf) == 0)
27780Sstevel@tonic-gate return (0);
27790Sstevel@tonic-gate /* LINTED */
27800Sstevel@tonic-gate return ((int)(prf->pr_cur - ocur));
27810Sstevel@tonic-gate }
27820Sstevel@tonic-gate
27830Sstevel@tonic-gate /* VARARGS2 */
27840Sstevel@tonic-gate int
sprintf(char * buf,const char * format,...)27850Sstevel@tonic-gate sprintf(char *buf, const char *format, ...)
27860Sstevel@tonic-gate {
27870Sstevel@tonic-gate va_list args;
27880Sstevel@tonic-gate int len;
27890Sstevel@tonic-gate Prfbuf prf;
27900Sstevel@tonic-gate
27910Sstevel@tonic-gate va_start(args, format);
27920Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = buf;
27930Sstevel@tonic-gate prf.pr_len = 0;
27940Sstevel@tonic-gate prf.pr_fd = -1;
27950Sstevel@tonic-gate len = doprintf(format, args, &prf);
27960Sstevel@tonic-gate va_end(args);
27970Sstevel@tonic-gate
27980Sstevel@tonic-gate /*
27990Sstevel@tonic-gate * sprintf() return value excludes the terminating null byte.
28000Sstevel@tonic-gate */
28010Sstevel@tonic-gate return (len - 1);
28020Sstevel@tonic-gate }
28030Sstevel@tonic-gate
28040Sstevel@tonic-gate /* VARARGS3 */
28050Sstevel@tonic-gate int
snprintf(char * buf,size_t n,const char * format,...)28060Sstevel@tonic-gate snprintf(char *buf, size_t n, const char *format, ...)
28070Sstevel@tonic-gate {
28080Sstevel@tonic-gate va_list args;
28090Sstevel@tonic-gate int len;
28100Sstevel@tonic-gate Prfbuf prf;
28110Sstevel@tonic-gate
28120Sstevel@tonic-gate va_start(args, format);
28130Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = buf;
28140Sstevel@tonic-gate prf.pr_len = n;
28150Sstevel@tonic-gate prf.pr_fd = -1;
28160Sstevel@tonic-gate len = doprintf(format, args, &prf);
28170Sstevel@tonic-gate va_end(args);
28180Sstevel@tonic-gate
28190Sstevel@tonic-gate return (len);
28200Sstevel@tonic-gate }
28210Sstevel@tonic-gate
28220Sstevel@tonic-gate /* VARARGS2 */
28230Sstevel@tonic-gate int
bufprint(Prfbuf * prf,const char * format,...)28240Sstevel@tonic-gate bufprint(Prfbuf *prf, const char *format, ...)
28250Sstevel@tonic-gate {
28260Sstevel@tonic-gate va_list args;
28270Sstevel@tonic-gate int len;
28280Sstevel@tonic-gate
28290Sstevel@tonic-gate va_start(args, format);
28300Sstevel@tonic-gate len = doprintf(format, args, prf);
28310Sstevel@tonic-gate va_end(args);
28320Sstevel@tonic-gate
28330Sstevel@tonic-gate return (len);
28340Sstevel@tonic-gate }
28350Sstevel@tonic-gate
28360Sstevel@tonic-gate /*PRINTFLIKE1*/
28370Sstevel@tonic-gate int
printf(const char * format,...)28380Sstevel@tonic-gate printf(const char *format, ...)
28390Sstevel@tonic-gate {
28400Sstevel@tonic-gate va_list args;
28410Sstevel@tonic-gate char buffer[ERRSIZE];
28420Sstevel@tonic-gate Prfbuf prf;
28430Sstevel@tonic-gate
28440Sstevel@tonic-gate va_start(args, format);
28450Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = buffer;
28460Sstevel@tonic-gate prf.pr_len = ERRSIZE;
28470Sstevel@tonic-gate prf.pr_fd = 1;
28480Sstevel@tonic-gate (void) doprf(format, args, &prf);
28490Sstevel@tonic-gate va_end(args);
28500Sstevel@tonic-gate /*
28510Sstevel@tonic-gate * Trim trailing '\0' form buffer
28520Sstevel@tonic-gate */
28530Sstevel@tonic-gate prf.pr_cur--;
28540Sstevel@tonic-gate return (dowrite(&prf));
28550Sstevel@tonic-gate }
28560Sstevel@tonic-gate
28578883SRod.Evans@Sun.COM static char errbuf[ERRSIZE], *nextptr = errbuf, *prevptr = NULL;
28580Sstevel@tonic-gate
28598598SRod.Evans@Sun.COM /*
28608598SRod.Evans@Sun.COM * All error messages go through eprintf(). During process initialization,
28618598SRod.Evans@Sun.COM * these messages are directed to the standard error, however once control has
28628598SRod.Evans@Sun.COM * been passed to the applications code these messages are stored in an internal
28638598SRod.Evans@Sun.COM * buffer for use with dlerror(). Note, fatal error conditions that may occur
28648598SRod.Evans@Sun.COM * while running the application will still cause a standard error message, see
28658598SRod.Evans@Sun.COM * rtldexit() in this file for details.
28668598SRod.Evans@Sun.COM * The RT_FL_APPLIC flag serves to indicate the transition between process
28678598SRod.Evans@Sun.COM * initialization and when the applications code is running.
28688598SRod.Evans@Sun.COM */
28690Sstevel@tonic-gate void
veprintf(Lm_list * lml,Error error,const char * format,va_list args)2870*13074SAli.Bahrami@Oracle.COM veprintf(Lm_list *lml, Error error, const char *format, va_list args)
28710Sstevel@tonic-gate {
28720Sstevel@tonic-gate int overflow = 0;
28730Sstevel@tonic-gate static int lock = 0;
28740Sstevel@tonic-gate Prfbuf prf;
28750Sstevel@tonic-gate
28760Sstevel@tonic-gate if (lock || (nextptr == (errbuf + ERRSIZE)))
28770Sstevel@tonic-gate return;
28780Sstevel@tonic-gate
28790Sstevel@tonic-gate /*
28800Sstevel@tonic-gate * Note: this lock is here to prevent the same thread from recursively
28810Sstevel@tonic-gate * entering itself during a eprintf. ie: during eprintf malloc() fails
28820Sstevel@tonic-gate * and we try and call eprintf ... and then malloc() fails ....
28830Sstevel@tonic-gate */
28840Sstevel@tonic-gate lock = 1;
28850Sstevel@tonic-gate
28860Sstevel@tonic-gate /*
28870Sstevel@tonic-gate * If we have completed startup initialization, all error messages
28880Sstevel@tonic-gate * must be saved. These are reported through dlerror(). If we're
28890Sstevel@tonic-gate * still in the initialization stage, output the error directly and
28900Sstevel@tonic-gate * add a newline.
28910Sstevel@tonic-gate */
28920Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = nextptr;
28930Sstevel@tonic-gate prf.pr_len = ERRSIZE - (nextptr - errbuf);
28940Sstevel@tonic-gate
289512877SRod.Evans@Sun.COM if ((rtld_flags & RT_FL_APPLIC) == 0)
28960Sstevel@tonic-gate prf.pr_fd = 2;
28970Sstevel@tonic-gate else
28980Sstevel@tonic-gate prf.pr_fd = -1;
28990Sstevel@tonic-gate
29000Sstevel@tonic-gate if (error > ERR_NONE) {
29010Sstevel@tonic-gate if ((error == ERR_FATAL) && (rtld_flags2 & RT_FL2_FTL2WARN))
29020Sstevel@tonic-gate error = ERR_WARNING;
2903*13074SAli.Bahrami@Oracle.COM switch (error) {
2904*13074SAli.Bahrami@Oracle.COM case ERR_WARNING_NF:
2905*13074SAli.Bahrami@Oracle.COM if (err_strs[ERR_WARNING_NF] == NULL)
2906*13074SAli.Bahrami@Oracle.COM err_strs[ERR_WARNING_NF] =
2907*13074SAli.Bahrami@Oracle.COM MSG_INTL(MSG_ERR_WARNING);
2908*13074SAli.Bahrami@Oracle.COM break;
2909*13074SAli.Bahrami@Oracle.COM case ERR_WARNING:
29108883SRod.Evans@Sun.COM if (err_strs[ERR_WARNING] == NULL)
29114362Srie err_strs[ERR_WARNING] =
29124362Srie MSG_INTL(MSG_ERR_WARNING);
2913*13074SAli.Bahrami@Oracle.COM break;
2914*13074SAli.Bahrami@Oracle.COM case ERR_GUIDANCE:
2915*13074SAli.Bahrami@Oracle.COM if (err_strs[ERR_GUIDANCE] == NULL)
2916*13074SAli.Bahrami@Oracle.COM err_strs[ERR_GUIDANCE] =
2917*13074SAli.Bahrami@Oracle.COM MSG_INTL(MSG_ERR_GUIDANCE);
2918*13074SAli.Bahrami@Oracle.COM break;
2919*13074SAli.Bahrami@Oracle.COM case ERR_FATAL:
29208883SRod.Evans@Sun.COM if (err_strs[ERR_FATAL] == NULL)
29214362Srie err_strs[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL);
2922*13074SAli.Bahrami@Oracle.COM break;
2923*13074SAli.Bahrami@Oracle.COM case ERR_ELF:
29248883SRod.Evans@Sun.COM if (err_strs[ERR_ELF] == NULL)
29254362Srie err_strs[ERR_ELF] = MSG_INTL(MSG_ERR_ELF);
2926*13074SAli.Bahrami@Oracle.COM break;
29270Sstevel@tonic-gate }
29286Srie if (procname) {
29296Srie if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR1),
29306Srie rtldname, procname, err_strs[error]) == 0)
29316Srie overflow = 1;
29320Sstevel@tonic-gate } else {
29336Srie if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR2),
29346Srie rtldname, err_strs[error]) == 0)
29356Srie overflow = 1;
29366Srie }
29376Srie if (overflow == 0) {
29380Sstevel@tonic-gate /*
29390Sstevel@tonic-gate * Remove the terminating '\0'.
29400Sstevel@tonic-gate */
29410Sstevel@tonic-gate prf.pr_cur--;
29420Sstevel@tonic-gate }
29430Sstevel@tonic-gate }
29440Sstevel@tonic-gate
29450Sstevel@tonic-gate if ((overflow == 0) && doprf(format, args, &prf) == 0)
29460Sstevel@tonic-gate overflow = 1;
29470Sstevel@tonic-gate
29480Sstevel@tonic-gate /*
29490Sstevel@tonic-gate * If this is an ELF error, it will have been generated by a support
29500Sstevel@tonic-gate * object that has a dependency on libelf. ld.so.1 doesn't generate any
29510Sstevel@tonic-gate * ELF error messages as it doesn't interact with libelf. Determine the
29520Sstevel@tonic-gate * ELF error string.
29530Sstevel@tonic-gate */
29540Sstevel@tonic-gate if ((overflow == 0) && (error == ERR_ELF)) {
29550Sstevel@tonic-gate static int (*elfeno)() = 0;
29560Sstevel@tonic-gate static const char *(*elfemg)();
29570Sstevel@tonic-gate const char *emsg;
29580Sstevel@tonic-gate Rt_map *dlmp, *lmp = lml_rtld.lm_head;
29590Sstevel@tonic-gate
29600Sstevel@tonic-gate if (NEXT(lmp) && (elfeno == 0)) {
29610Sstevel@tonic-gate if (((elfemg = (const char *(*)())dlsym_intn(RTLD_NEXT,
29628883SRod.Evans@Sun.COM MSG_ORIG(MSG_SYM_ELFERRMSG),
29638883SRod.Evans@Sun.COM lmp, &dlmp)) == NULL) ||
29640Sstevel@tonic-gate ((elfeno = (int (*)())dlsym_intn(RTLD_NEXT,
29658883SRod.Evans@Sun.COM MSG_ORIG(MSG_SYM_ELFERRNO), lmp, &dlmp)) == NULL))
29660Sstevel@tonic-gate elfeno = 0;
29670Sstevel@tonic-gate }
29680Sstevel@tonic-gate
29690Sstevel@tonic-gate /*
29700Sstevel@tonic-gate * Lookup the message; equivalent to elf_errmsg(elf_errno()).
29710Sstevel@tonic-gate */
29728883SRod.Evans@Sun.COM if (elfeno && ((emsg = (* elfemg)((* elfeno)())) != NULL)) {
29730Sstevel@tonic-gate prf.pr_cur--;
29740Sstevel@tonic-gate if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR2),
29750Sstevel@tonic-gate emsg) == 0)
29760Sstevel@tonic-gate overflow = 1;
29770Sstevel@tonic-gate }
29780Sstevel@tonic-gate }
29790Sstevel@tonic-gate
29800Sstevel@tonic-gate /*
29810Sstevel@tonic-gate * Push out any message that's been built. Note, in the case of an
29820Sstevel@tonic-gate * overflow condition, this message may be incomplete, in which case
29830Sstevel@tonic-gate * make sure any partial string is null terminated.
29840Sstevel@tonic-gate */
29850Sstevel@tonic-gate if ((rtld_flags & (RT_FL_APPLIC | RT_FL_SILENCERR)) == 0) {
29860Sstevel@tonic-gate *(prf.pr_cur - 1) = '\n';
29870Sstevel@tonic-gate (void) dowrite(&prf);
29880Sstevel@tonic-gate }
29898598SRod.Evans@Sun.COM if (overflow)
29908598SRod.Evans@Sun.COM *(prf.pr_cur - 1) = '\0';
29910Sstevel@tonic-gate
29921618Srie DBG_CALL(Dbg_util_str(lml, nextptr));
29930Sstevel@tonic-gate
29940Sstevel@tonic-gate /*
29950Sstevel@tonic-gate * Determine if there was insufficient space left in the buffer to
29960Sstevel@tonic-gate * complete the message. If so, we'll have printed out as much as had
29970Sstevel@tonic-gate * been processed if we're not yet executing the application.
29980Sstevel@tonic-gate * Otherwise, there will be some debugging diagnostic indicating
29990Sstevel@tonic-gate * as much of the error message as possible. Write out a final buffer
30000Sstevel@tonic-gate * overflow diagnostic - unlocalized, so we don't chance more errors.
30010Sstevel@tonic-gate */
30020Sstevel@tonic-gate if (overflow) {
30030Sstevel@tonic-gate char *str = (char *)MSG_INTL(MSG_EMG_BUFOVRFLW);
30040Sstevel@tonic-gate
30050Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) {
30060Sstevel@tonic-gate lasterr = str;
30070Sstevel@tonic-gate
30080Sstevel@tonic-gate if ((rtld_flags & RT_FL_APPLIC) == 0) {
30090Sstevel@tonic-gate (void) write(2, str, strlen(str));
30100Sstevel@tonic-gate (void) write(2, MSG_ORIG(MSG_STR_NL),
30110Sstevel@tonic-gate MSG_STR_NL_SIZE);
30120Sstevel@tonic-gate }
30130Sstevel@tonic-gate }
30141618Srie DBG_CALL(Dbg_util_str(lml, str));
30150Sstevel@tonic-gate
30160Sstevel@tonic-gate lock = 0;
30170Sstevel@tonic-gate nextptr = errbuf + ERRSIZE;
30180Sstevel@tonic-gate return;
30190Sstevel@tonic-gate }
30200Sstevel@tonic-gate
30210Sstevel@tonic-gate /*
30220Sstevel@tonic-gate * If the application has started, then error messages are being saved
30230Sstevel@tonic-gate * for retrieval by dlerror(), or possible flushing from rtldexit() in
30240Sstevel@tonic-gate * the case of a fatal error. In this case, establish the next error
30250Sstevel@tonic-gate * pointer. If we haven't started the application, the whole message
30260Sstevel@tonic-gate * buffer can be reused.
30270Sstevel@tonic-gate */
30280Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) {
30290Sstevel@tonic-gate lasterr = nextptr;
30300Sstevel@tonic-gate
30310Sstevel@tonic-gate /*
30320Sstevel@tonic-gate * Note, should we encounter an error such as ENOMEM, there may
30330Sstevel@tonic-gate * be a number of the same error messages (ie. an operation
30340Sstevel@tonic-gate * fails with ENOMEM, and then the attempts to construct the
30350Sstevel@tonic-gate * error message itself, which incurs additional ENOMEM errors).
30360Sstevel@tonic-gate * Compare any previous error message with the one we've just
30370Sstevel@tonic-gate * created to prevent any duplication clutter.
30380Sstevel@tonic-gate */
30390Sstevel@tonic-gate if ((rtld_flags & RT_FL_APPLIC) &&
30408883SRod.Evans@Sun.COM ((prevptr == NULL) || (strcmp(prevptr, nextptr) != 0))) {
30410Sstevel@tonic-gate prevptr = nextptr;
30420Sstevel@tonic-gate nextptr = prf.pr_cur;
30430Sstevel@tonic-gate *nextptr = '\0';
30440Sstevel@tonic-gate }
30450Sstevel@tonic-gate }
30460Sstevel@tonic-gate lock = 0;
30470Sstevel@tonic-gate }
30480Sstevel@tonic-gate
3049*13074SAli.Bahrami@Oracle.COM /*PRINTFLIKE3*/
3050*13074SAli.Bahrami@Oracle.COM void
eprintf(Lm_list * lml,Error error,const char * format,...)3051*13074SAli.Bahrami@Oracle.COM eprintf(Lm_list *lml, Error error, const char *format, ...)
3052*13074SAli.Bahrami@Oracle.COM {
3053*13074SAli.Bahrami@Oracle.COM va_list args;
3054*13074SAli.Bahrami@Oracle.COM
3055*13074SAli.Bahrami@Oracle.COM va_start(args, format);
3056*13074SAli.Bahrami@Oracle.COM veprintf(lml, error, format, args);
3057*13074SAli.Bahrami@Oracle.COM va_end(args);
3058*13074SAli.Bahrami@Oracle.COM }
3059*13074SAli.Bahrami@Oracle.COM
30600Sstevel@tonic-gate #if DEBUG
30610Sstevel@tonic-gate /*
30628598SRod.Evans@Sun.COM * Provide assfail() for ASSERT() statements. See <sys/debug.h> for further
30638598SRod.Evans@Sun.COM * details.
30640Sstevel@tonic-gate */
30650Sstevel@tonic-gate int
assfail(const char * a,const char * f,int l)30660Sstevel@tonic-gate assfail(const char *a, const char *f, int l)
30670Sstevel@tonic-gate {
30680Sstevel@tonic-gate (void) printf("assertion failed: %s, file: %s, line: %d\n", a, f, l);
30690Sstevel@tonic-gate (void) _lwp_kill(_lwp_self(), SIGABRT);
30700Sstevel@tonic-gate return (0);
30710Sstevel@tonic-gate }
30720Sstevel@tonic-gate #endif
30730Sstevel@tonic-gate
30740Sstevel@tonic-gate /*
30750Sstevel@tonic-gate * Exit. If we arrive here with a non zero status it's because of a fatal
30760Sstevel@tonic-gate * error condition (most commonly a relocation error). If the application has
30770Sstevel@tonic-gate * already had control, then the actual fatal error message will have been
30780Sstevel@tonic-gate * recorded in the dlerror() message buffer. Print the message before really
30790Sstevel@tonic-gate * exiting.
30800Sstevel@tonic-gate */
30810Sstevel@tonic-gate void
rtldexit(Lm_list * lml,int status)30820Sstevel@tonic-gate rtldexit(Lm_list * lml, int status)
30830Sstevel@tonic-gate {
30840Sstevel@tonic-gate if (status) {
30850Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) {
30860Sstevel@tonic-gate /*
30870Sstevel@tonic-gate * If the error buffer has been used, write out all
30880Sstevel@tonic-gate * pending messages - lasterr is simply a pointer to
30890Sstevel@tonic-gate * the last message in this buffer. However, if the
30900Sstevel@tonic-gate * buffer couldn't be created at all, lasterr points
30910Sstevel@tonic-gate * to a constant error message string.
30920Sstevel@tonic-gate */
30930Sstevel@tonic-gate if (*errbuf) {
30940Sstevel@tonic-gate char *errptr = errbuf;
30950Sstevel@tonic-gate char *errend = errbuf + ERRSIZE;
30960Sstevel@tonic-gate
30970Sstevel@tonic-gate while ((errptr < errend) && *errptr) {
30980Sstevel@tonic-gate size_t size = strlen(errptr);
30990Sstevel@tonic-gate (void) write(2, errptr, size);
31000Sstevel@tonic-gate (void) write(2, MSG_ORIG(MSG_STR_NL),
31010Sstevel@tonic-gate MSG_STR_NL_SIZE);
31020Sstevel@tonic-gate errptr += (size + 1);
31030Sstevel@tonic-gate }
31040Sstevel@tonic-gate }
31050Sstevel@tonic-gate if (lasterr && ((lasterr < errbuf) ||
31060Sstevel@tonic-gate (lasterr > (errbuf + ERRSIZE)))) {
31070Sstevel@tonic-gate (void) write(2, lasterr, strlen(lasterr));
31080Sstevel@tonic-gate (void) write(2, MSG_ORIG(MSG_STR_NL),
31090Sstevel@tonic-gate MSG_STR_NL_SIZE);
31100Sstevel@tonic-gate }
31110Sstevel@tonic-gate }
31126515Sraf leave(lml, 0);
31130Sstevel@tonic-gate (void) _lwp_kill(_lwp_self(), killsig);
31140Sstevel@tonic-gate }
31150Sstevel@tonic-gate _exit(status);
31160Sstevel@tonic-gate }
31170Sstevel@tonic-gate
31180Sstevel@tonic-gate /*
31198598SRod.Evans@Sun.COM * Map anonymous memory via MAP_ANON (added in Solaris 8).
31200Sstevel@tonic-gate */
31218598SRod.Evans@Sun.COM void *
dz_map(Lm_list * lml,caddr_t addr,size_t len,int prot,int flags)31221618Srie dz_map(Lm_list *lml, caddr_t addr, size_t len, int prot, int flags)
31230Sstevel@tonic-gate {
31240Sstevel@tonic-gate caddr_t va;
31258598SRod.Evans@Sun.COM
31268598SRod.Evans@Sun.COM if ((va = (caddr_t)mmap(addr, len, prot,
31278598SRod.Evans@Sun.COM (flags | MAP_ANON), -1, 0)) == MAP_FAILED) {
31288598SRod.Evans@Sun.COM int err = errno;
31298598SRod.Evans@Sun.COM eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON),
31308598SRod.Evans@Sun.COM strerror(err));
31310Sstevel@tonic-gate return (MAP_FAILED);
31320Sstevel@tonic-gate }
31330Sstevel@tonic-gate return (va);
31340Sstevel@tonic-gate }
31350Sstevel@tonic-gate
31360Sstevel@tonic-gate static int nu_fd = FD_UNAVAIL;
31370Sstevel@tonic-gate
31388598SRod.Evans@Sun.COM void *
nu_map(Lm_list * lml,caddr_t addr,size_t len,int prot,int flags)31391618Srie nu_map(Lm_list *lml, caddr_t addr, size_t len, int prot, int flags)
31400Sstevel@tonic-gate {
31410Sstevel@tonic-gate caddr_t va;
31420Sstevel@tonic-gate int err;
31430Sstevel@tonic-gate
31440Sstevel@tonic-gate if (nu_fd == FD_UNAVAIL) {
31450Sstevel@tonic-gate if ((nu_fd = open(MSG_ORIG(MSG_PTH_DEVNULL),
31460Sstevel@tonic-gate O_RDONLY)) == FD_UNAVAIL) {
31470Sstevel@tonic-gate err = errno;
31481618Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
31490Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVNULL), strerror(err));
31500Sstevel@tonic-gate return (MAP_FAILED);
31510Sstevel@tonic-gate }
31520Sstevel@tonic-gate }
31530Sstevel@tonic-gate
31540Sstevel@tonic-gate if ((va = (caddr_t)mmap(addr, len, prot, flags, nu_fd, 0)) ==
31550Sstevel@tonic-gate MAP_FAILED) {
31560Sstevel@tonic-gate err = errno;
31571618Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP),
31580Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVNULL), strerror(err));
31590Sstevel@tonic-gate }
31600Sstevel@tonic-gate return (va);
31610Sstevel@tonic-gate }
31620Sstevel@tonic-gate
31630Sstevel@tonic-gate /*
31645950Srie * Generic entry point from user code - simply grabs a lock, and bumps the
31655950Srie * entrance count.
31660Sstevel@tonic-gate */
31670Sstevel@tonic-gate int
enter(int flags)31686515Sraf enter(int flags)
31690Sstevel@tonic-gate {
31706515Sraf if (rt_bind_guard(THR_FLG_RTLD | thr_flg_nolock | flags)) {
31716515Sraf if (!thr_flg_nolock)
31726515Sraf (void) rt_mutex_lock(&rtldlock);
31739577SRod.Evans@Sun.COM if (rtld_flags & RT_FL_OPERATION) {
31746387Srie ld_entry_cnt++;
31759577SRod.Evans@Sun.COM
31769577SRod.Evans@Sun.COM /*
31779577SRod.Evans@Sun.COM * Reset the diagnostic time information for each new
31789577SRod.Evans@Sun.COM * "operation". Thus timing diagnostics are relative
31799577SRod.Evans@Sun.COM * to entering ld.so.1.
31809577SRod.Evans@Sun.COM */
31819577SRod.Evans@Sun.COM if (DBG_ISTIME() &&
31829577SRod.Evans@Sun.COM (gettimeofday(&DBG_TOTALTIME, NULL) == 0)) {
31839577SRod.Evans@Sun.COM DBG_DELTATIME = DBG_TOTALTIME;
31849577SRod.Evans@Sun.COM DBG_ONRESET();
31859577SRod.Evans@Sun.COM }
31869577SRod.Evans@Sun.COM }
31870Sstevel@tonic-gate return (1);
31880Sstevel@tonic-gate }
31890Sstevel@tonic-gate return (0);
31900Sstevel@tonic-gate }
31910Sstevel@tonic-gate
31920Sstevel@tonic-gate /*
31936387Srie * Determine whether a search path has been used.
31946387Srie */
31956387Srie static void
is_path_used(Lm_list * lml,Word unref,int * nl,Alist * alp,const char * obj)31968598SRod.Evans@Sun.COM is_path_used(Lm_list *lml, Word unref, int *nl, Alist *alp, const char *obj)
31976387Srie {
31988598SRod.Evans@Sun.COM Pdesc *pdp;
31998598SRod.Evans@Sun.COM Aliste idx;
32008598SRod.Evans@Sun.COM
32018598SRod.Evans@Sun.COM for (ALIST_TRAVERSE(alp, idx, pdp)) {
32026387Srie const char *fmt, *name;
32036387Srie
32048598SRod.Evans@Sun.COM if ((pdp->pd_plen == 0) || (pdp->pd_flags & PD_FLG_USED))
32056387Srie continue;
32066387Srie
32076387Srie /*
32086387Srie * If this pathname originated from an expanded token, use the
32096387Srie * original for any diagnostic output.
32106387Srie */
32118598SRod.Evans@Sun.COM if ((name = pdp->pd_oname) == NULL)
32128598SRod.Evans@Sun.COM name = pdp->pd_pname;
32136387Srie
32146387Srie if (unref == 0) {
32156387Srie if ((*nl)++ == 0)
32166387Srie DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
32178598SRod.Evans@Sun.COM DBG_CALL(Dbg_unused_path(lml, name, pdp->pd_flags,
32188598SRod.Evans@Sun.COM (pdp->pd_flags & PD_FLG_DUPLICAT), obj));
32196387Srie continue;
32206387Srie }
32216387Srie
32228598SRod.Evans@Sun.COM if (pdp->pd_flags & LA_SER_LIBPATH) {
32238598SRod.Evans@Sun.COM if (pdp->pd_flags & LA_SER_CONFIG) {
32248598SRod.Evans@Sun.COM if (pdp->pd_flags & PD_FLG_DUPLICAT)
32256387Srie fmt = MSG_INTL(MSG_DUP_LDLIBPATHC);
32266387Srie else
32276387Srie fmt = MSG_INTL(MSG_USD_LDLIBPATHC);
32286387Srie } else {
32298598SRod.Evans@Sun.COM if (pdp->pd_flags & PD_FLG_DUPLICAT)
32306387Srie fmt = MSG_INTL(MSG_DUP_LDLIBPATH);
32316387Srie else
32326387Srie fmt = MSG_INTL(MSG_USD_LDLIBPATH);
32336387Srie }
32348598SRod.Evans@Sun.COM } else if (pdp->pd_flags & LA_SER_RUNPATH) {
32356387Srie fmt = MSG_INTL(MSG_USD_RUNPATH);
32366387Srie } else
32376387Srie continue;
32386387Srie
32396387Srie if ((*nl)++ == 0)
32406387Srie (void) printf(MSG_ORIG(MSG_STR_NL));
32416387Srie (void) printf(fmt, name, obj);
32426387Srie }
32436387Srie }
32446387Srie
32456387Srie /*
32460Sstevel@tonic-gate * Generate diagnostics as to whether an object has been used. A symbolic
32470Sstevel@tonic-gate * reference that gets bound to an object marks it as used. Dependencies that
32480Sstevel@tonic-gate * are unused when RTLD_NOW is in effect should be removed from future builds
32490Sstevel@tonic-gate * of an object. Dependencies that are unused without RTLD_NOW in effect are
32500Sstevel@tonic-gate * candidates for lazy-loading.
32516387Srie *
32520Sstevel@tonic-gate * Unreferenced objects identify objects that are defined as dependencies but
32536387Srie * are unreferenced by the caller. These unreferenced objects may however be
32546387Srie * referenced by other objects within the process, and therefore don't qualify
32556387Srie * as completely unused. They are still an unnecessary overhead.
32566387Srie *
32576387Srie * Unreferenced runpaths are also captured under ldd -U, or "unused,detail"
32586387Srie * debugging.
32590Sstevel@tonic-gate */
32600Sstevel@tonic-gate void
unused(Lm_list * lml)32610Sstevel@tonic-gate unused(Lm_list *lml)
32620Sstevel@tonic-gate {
32630Sstevel@tonic-gate Rt_map *lmp;
32640Sstevel@tonic-gate int nl = 0;
32656387Srie Word unref, unuse;
32660Sstevel@tonic-gate
32670Sstevel@tonic-gate /*
32680Sstevel@tonic-gate * If we're not tracing unused references or dependencies, or debugging
32690Sstevel@tonic-gate * there's nothing to do.
32700Sstevel@tonic-gate */
32716387Srie unref = lml->lm_flags & LML_FLG_TRC_UNREF;
32726387Srie unuse = lml->lm_flags & LML_FLG_TRC_UNUSED;
32736387Srie
32746387Srie if ((unref == 0) && (unuse == 0) && (DBG_ENABLED == 0))
32750Sstevel@tonic-gate return;
32760Sstevel@tonic-gate
32770Sstevel@tonic-gate /*
32786387Srie * Detect unused global search paths.
32796387Srie */
32806387Srie if (rpl_libdirs)
32816387Srie is_path_used(lml, unref, &nl, rpl_libdirs, config->c_name);
32826387Srie if (prm_libdirs)
32836387Srie is_path_used(lml, unref, &nl, prm_libdirs, config->c_name);
32846387Srie
32856387Srie nl = 0;
32866387Srie lmp = lml->lm_head;
32876387Srie if (RLIST(lmp))
32886387Srie is_path_used(lml, unref, &nl, RLIST(lmp), NAME(lmp));
32896387Srie
32906387Srie /*
32910Sstevel@tonic-gate * Traverse the link-maps looking for unreferenced or unused
32920Sstevel@tonic-gate * dependencies. Ignore the first object on a link-map list, as this
32936387Srie * is always used.
32940Sstevel@tonic-gate */
32956387Srie nl = 0;
32968394SAli.Bahrami@Sun.COM for (lmp = NEXT_RT_MAP(lmp); lmp; lmp = NEXT_RT_MAP(lmp)) {
32976387Srie /*
32986387Srie * Determine if this object contains any runpaths that have
32996387Srie * not been used.
33006387Srie */
33016387Srie if (RLIST(lmp))
33026387Srie is_path_used(lml, unref, &nl, RLIST(lmp), NAME(lmp));
33036387Srie
33040Sstevel@tonic-gate /*
33050Sstevel@tonic-gate * If tracing unreferenced objects, or under debugging,
33060Sstevel@tonic-gate * determine whether any of this objects callers haven't
33070Sstevel@tonic-gate * referenced it.
33080Sstevel@tonic-gate */
33096387Srie if (unref || DBG_ENABLED) {
33105892Sab196087 Bnd_desc *bdp;
33115892Sab196087 Aliste idx;
33125892Sab196087
33135892Sab196087 for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp)) {
33146387Srie Rt_map *clmp;
33150Sstevel@tonic-gate
33160Sstevel@tonic-gate if (bdp->b_flags & BND_REFER)
33170Sstevel@tonic-gate continue;
33180Sstevel@tonic-gate
33190Sstevel@tonic-gate clmp = bdp->b_caller;
33200Sstevel@tonic-gate if (FLAGS1(clmp) & FL1_RT_LDDSTUB)
33210Sstevel@tonic-gate continue;
33220Sstevel@tonic-gate
33234362Srie /* BEGIN CSTYLED */
33240Sstevel@tonic-gate if (nl++ == 0) {
33256387Srie if (unref)
33260Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_STR_NL));
33270Sstevel@tonic-gate else
33281618Srie DBG_CALL(Dbg_util_nl(lml,
33291618Srie DBG_NL_STD));
33300Sstevel@tonic-gate }
33310Sstevel@tonic-gate
33326387Srie if (unref)
33330Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_UNREF_FMT),
33340Sstevel@tonic-gate NAME(lmp), NAME(clmp));
33350Sstevel@tonic-gate else
33361618Srie DBG_CALL(Dbg_unused_unref(lmp, NAME(clmp)));
33374362Srie /* END CSTYLED */
33380Sstevel@tonic-gate }
33390Sstevel@tonic-gate }
33400Sstevel@tonic-gate
33410Sstevel@tonic-gate /*
33420Sstevel@tonic-gate * If tracing unused objects simply display those objects that
33430Sstevel@tonic-gate * haven't been referenced by anyone.
33440Sstevel@tonic-gate */
33450Sstevel@tonic-gate if (FLAGS1(lmp) & FL1_RT_USED)
33460Sstevel@tonic-gate continue;
33470Sstevel@tonic-gate
33480Sstevel@tonic-gate if (nl++ == 0) {
33496387Srie if (unref || unuse)
33500Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_STR_NL));
33510Sstevel@tonic-gate else
33521618Srie DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
33530Sstevel@tonic-gate }
33540Sstevel@tonic-gate if (CYCGROUP(lmp)) {
33556387Srie if (unref || unuse)
33560Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_UNCYC_FMT),
33570Sstevel@tonic-gate NAME(lmp), CYCGROUP(lmp));
33580Sstevel@tonic-gate else
33591618Srie DBG_CALL(Dbg_unused_file(lml, NAME(lmp), 0,
33600Sstevel@tonic-gate CYCGROUP(lmp)));
33610Sstevel@tonic-gate } else {
33626387Srie if (unref || unuse)
33630Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_UNUSED_FMT),
33640Sstevel@tonic-gate NAME(lmp));
33650Sstevel@tonic-gate else
33661618Srie DBG_CALL(Dbg_unused_file(lml, NAME(lmp), 0, 0));
33670Sstevel@tonic-gate }
33680Sstevel@tonic-gate }
33690Sstevel@tonic-gate
33701618Srie DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
33710Sstevel@tonic-gate }
33720Sstevel@tonic-gate
33730Sstevel@tonic-gate /*
33740Sstevel@tonic-gate * Generic cleanup routine called prior to returning control to the user.
337512877SRod.Evans@Sun.COM * Ensures that any ld.so.1 specific file descriptors or temporary mapping are
33760Sstevel@tonic-gate * released, and any locks dropped.
33770Sstevel@tonic-gate */
33780Sstevel@tonic-gate void
leave(Lm_list * lml,int flags)33796515Sraf leave(Lm_list *lml, int flags)
33800Sstevel@tonic-gate {
33810Sstevel@tonic-gate /*
338212877SRod.Evans@Sun.COM * Alert the debuggers that the link-maps are consistent.
33830Sstevel@tonic-gate */
338412877SRod.Evans@Sun.COM rd_event(lml, RD_DLACTIVITY, RT_CONSISTENT);
33850Sstevel@tonic-gate
33864679Srie /*
33874679Srie * Alert any auditors that the link-maps are consistent.
33884679Srie */
338912877SRod.Evans@Sun.COM if (lml->lm_flags & LML_FLG_ACTAUDIT) {
339012877SRod.Evans@Sun.COM audit_activity(lml->lm_head, LA_ACT_CONSISTENT);
339112877SRod.Evans@Sun.COM lml->lm_flags &= ~LML_FLG_ACTAUDIT;
33924679Srie }
33934679Srie
33940Sstevel@tonic-gate if (nu_fd != FD_UNAVAIL) {
33950Sstevel@tonic-gate (void) close(nu_fd);
33960Sstevel@tonic-gate nu_fd = FD_UNAVAIL;
33970Sstevel@tonic-gate }
33980Sstevel@tonic-gate
33990Sstevel@tonic-gate /*
34000Sstevel@tonic-gate * Reinitialize error message pointer, and any overflow indication.
34010Sstevel@tonic-gate */
34020Sstevel@tonic-gate nextptr = errbuf;
34038883SRod.Evans@Sun.COM prevptr = NULL;
34040Sstevel@tonic-gate
34050Sstevel@tonic-gate /*
34068598SRod.Evans@Sun.COM * Defragment any freed memory.
34078598SRod.Evans@Sun.COM */
34088598SRod.Evans@Sun.COM if (aplist_nitems(free_alp))
34098598SRod.Evans@Sun.COM defrag();
34108598SRod.Evans@Sun.COM
34118598SRod.Evans@Sun.COM /*
34120Sstevel@tonic-gate * Don't drop our lock if we are running on our link-map list as
34130Sstevel@tonic-gate * there's little point in doing so since we are single-threaded.
34140Sstevel@tonic-gate *
34150Sstevel@tonic-gate * LML_FLG_HOLDLOCK is set for:
34168883SRod.Evans@Sun.COM * - The ld.so.1's link-map list.
34178883SRod.Evans@Sun.COM * - The auditor's link-map if the environment is pre-UPM.
34180Sstevel@tonic-gate */
341912877SRod.Evans@Sun.COM if (lml->lm_flags & LML_FLG_HOLDLOCK)
34200Sstevel@tonic-gate return;
34210Sstevel@tonic-gate
34220Sstevel@tonic-gate if (rt_bind_clear(0) & THR_FLG_RTLD) {
34236515Sraf if (!thr_flg_nolock)
34246515Sraf (void) rt_mutex_unlock(&rtldlock);
34256515Sraf (void) rt_bind_clear(THR_FLG_RTLD | thr_flg_nolock | flags);
34260Sstevel@tonic-gate }
34270Sstevel@tonic-gate }
34280Sstevel@tonic-gate
34290Sstevel@tonic-gate int
callable(Rt_map * clmp,Rt_map * dlmp,Grp_hdl * ghp,uint_t slflags)34305220Srie callable(Rt_map *clmp, Rt_map *dlmp, Grp_hdl *ghp, uint_t slflags)
34310Sstevel@tonic-gate {
34325892Sab196087 APlist *calp, *dalp;
34335892Sab196087 Aliste idx1, idx2;
34345892Sab196087 Grp_hdl *ghp1, *ghp2;
34350Sstevel@tonic-gate
34360Sstevel@tonic-gate /*
34370Sstevel@tonic-gate * An object can always find symbols within itself.
34380Sstevel@tonic-gate */
34390Sstevel@tonic-gate if (clmp == dlmp)
34400Sstevel@tonic-gate return (1);
34410Sstevel@tonic-gate
34420Sstevel@tonic-gate /*
34435220Srie * The search for a singleton must look in every loaded object.
34445220Srie */
34455220Srie if (slflags & LKUP_SINGLETON)
34465220Srie return (1);
34475220Srie
34485220Srie /*
34490Sstevel@tonic-gate * Don't allow an object to bind to an object that is being deleted
34500Sstevel@tonic-gate * unless the binder is also being deleted.
34510Sstevel@tonic-gate */
34520Sstevel@tonic-gate if ((FLAGS(dlmp) & FLG_RT_DELETE) &&
34530Sstevel@tonic-gate ((FLAGS(clmp) & FLG_RT_DELETE) == 0))
34540Sstevel@tonic-gate return (0);
34550Sstevel@tonic-gate
34560Sstevel@tonic-gate /*
34570Sstevel@tonic-gate * An object with world access can always bind to an object with global
34580Sstevel@tonic-gate * visibility.
34590Sstevel@tonic-gate */
34608388SRod.Evans@Sun.COM if (((MODE(clmp) & RTLD_WORLD) || (slflags & LKUP_WORLD)) &&
34618388SRod.Evans@Sun.COM (MODE(dlmp) & RTLD_GLOBAL))
34620Sstevel@tonic-gate return (1);
34630Sstevel@tonic-gate
34640Sstevel@tonic-gate /*
34650Sstevel@tonic-gate * An object with local access can only bind to an object that is a
34660Sstevel@tonic-gate * member of the same group.
34670Sstevel@tonic-gate */
34680Sstevel@tonic-gate if (((MODE(clmp) & RTLD_GROUP) == 0) ||
34695892Sab196087 ((calp = GROUPS(clmp)) == NULL) || ((dalp = GROUPS(dlmp)) == NULL))
34700Sstevel@tonic-gate return (0);
34710Sstevel@tonic-gate
34720Sstevel@tonic-gate /*
34730Sstevel@tonic-gate * Traverse the list of groups the caller is a part of.
34740Sstevel@tonic-gate */
34755892Sab196087 for (APLIST_TRAVERSE(calp, idx1, ghp1)) {
34760Sstevel@tonic-gate /*
34770Sstevel@tonic-gate * If we're testing for the ability of two objects to bind to
34780Sstevel@tonic-gate * each other regardless of a specific group, ignore that group.
34790Sstevel@tonic-gate */
34805892Sab196087 if (ghp && (ghp1 == ghp))
34810Sstevel@tonic-gate continue;
34820Sstevel@tonic-gate
34830Sstevel@tonic-gate /*
34840Sstevel@tonic-gate * Traverse the list of groups the destination is a part of.
34850Sstevel@tonic-gate */
34865892Sab196087 for (APLIST_TRAVERSE(dalp, idx2, ghp2)) {
34874699Srie Grp_desc *gdp;
34885892Sab196087 Aliste idx3;
34895892Sab196087
34905892Sab196087 if (ghp1 != ghp2)
34914699Srie continue;
34924699Srie
34934699Srie /*
34944699Srie * Make sure the relationship between the destination
34954699Srie * and the caller provide symbols for relocation.
34964699Srie * Parents are maintained as callers, but unless the
34974699Srie * destination object was opened with RTLD_PARENT, the
34984699Srie * parent doesn't provide symbols for the destination
34994699Srie * to relocate against.
35004699Srie */
35015892Sab196087 for (ALIST_TRAVERSE(ghp2->gh_depends, idx3, gdp)) {
35024699Srie if (dlmp != gdp->gd_depend)
35034699Srie continue;
35044699Srie
35054699Srie if (gdp->gd_flags & GPD_RELOC)
35064699Srie return (1);
35074699Srie }
35080Sstevel@tonic-gate }
35090Sstevel@tonic-gate }
35100Sstevel@tonic-gate return (0);
35110Sstevel@tonic-gate }
35120Sstevel@tonic-gate
35130Sstevel@tonic-gate /*
35140Sstevel@tonic-gate * Initialize the environ symbol. Traditionally this is carried out by the crt
35150Sstevel@tonic-gate * code prior to jumping to main. However, init sections get fired before this
35160Sstevel@tonic-gate * variable is initialized, so ld.so.1 sets this directly from the AUX vector
35170Sstevel@tonic-gate * information. In addition, a process may have multiple link-maps (ld.so.1's
35180Sstevel@tonic-gate * debugging and preloading objects), and link auditing, and each may need an
35190Sstevel@tonic-gate * environ variable set.
35200Sstevel@tonic-gate *
35210Sstevel@tonic-gate * This routine is called after a relocation() pass, and thus provides for:
35220Sstevel@tonic-gate *
35238883SRod.Evans@Sun.COM * - setting environ on the main link-map after the initial application and
35240Sstevel@tonic-gate * its dependencies have been established. Typically environ lives in the
35250Sstevel@tonic-gate * application (provided by its crt), but in older applications it might
35260Sstevel@tonic-gate * be in libc. Who knows what's expected of applications not built on
35270Sstevel@tonic-gate * Solaris.
35280Sstevel@tonic-gate *
35298883SRod.Evans@Sun.COM * - after loading a new shared object. We can add shared objects to various
35300Sstevel@tonic-gate * link-maps, and any link-map dependencies requiring getopt() require
35310Sstevel@tonic-gate * their own environ. In addition, lazy loading might bring in the
35326Srie * supplier of environ (libc used to be a lazy loading candidate) after
35336Srie * the link-map has been established and other objects are present.
35340Sstevel@tonic-gate *
35350Sstevel@tonic-gate * This routine handles all these scenarios, without adding unnecessary overhead
35360Sstevel@tonic-gate * to ld.so.1.
35370Sstevel@tonic-gate */
35380Sstevel@tonic-gate void
set_environ(Lm_list * lml)35390Sstevel@tonic-gate set_environ(Lm_list *lml)
35400Sstevel@tonic-gate {
35410Sstevel@tonic-gate Slookup sl;
354211827SRod.Evans@Sun.COM Sresult sr;
35430Sstevel@tonic-gate uint_t binfo;
35440Sstevel@tonic-gate
35455950Srie /*
354611827SRod.Evans@Sun.COM * Initialize the symbol lookup, and symbol result, data structures.
35475950Srie */
35485950Srie SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_ENVIRON), lml->lm_head, lml->lm_head,
35495950Srie ld_entry_cnt, 0, 0, 0, 0, LKUP_WEAK);
355011827SRod.Evans@Sun.COM SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_ENVIRON));
355111827SRod.Evans@Sun.COM
355211827SRod.Evans@Sun.COM if (LM_LOOKUP_SYM(lml->lm_head)(&sl, &sr, &binfo, 0)) {
355311827SRod.Evans@Sun.COM Rt_map *dlmp = sr.sr_dmap;
355411827SRod.Evans@Sun.COM
355511827SRod.Evans@Sun.COM lml->lm_environ = (char ***)sr.sr_sym->st_value;
35560Sstevel@tonic-gate
35570Sstevel@tonic-gate if (!(FLAGS(dlmp) & FLG_RT_FIXED))
35586Srie lml->lm_environ =
35596Srie (char ***)((uintptr_t)lml->lm_environ +
35606Srie (uintptr_t)ADDR(dlmp));
35616Srie *(lml->lm_environ) = (char **)environ;
35620Sstevel@tonic-gate lml->lm_flags |= LML_FLG_ENVIRON;
35630Sstevel@tonic-gate }
35640Sstevel@tonic-gate }
35650Sstevel@tonic-gate
35660Sstevel@tonic-gate /*
35670Sstevel@tonic-gate * Determine whether we have a secure executable. Uid and gid information
35680Sstevel@tonic-gate * can be passed to us via the aux vector, however if these values are -1
35690Sstevel@tonic-gate * then use the appropriate system call to obtain them.
35700Sstevel@tonic-gate *
35718883SRod.Evans@Sun.COM * - If the user is the root they can do anything
35720Sstevel@tonic-gate *
35738883SRod.Evans@Sun.COM * - If the real and effective uid's don't match, or the real and
35740Sstevel@tonic-gate * effective gid's don't match then this is determined to be a `secure'
35750Sstevel@tonic-gate * application.
35760Sstevel@tonic-gate *
35770Sstevel@tonic-gate * This function is called prior to any dependency processing (see _setup.c).
35780Sstevel@tonic-gate * Any secure setting will remain in effect for the life of the process.
35790Sstevel@tonic-gate */
35800Sstevel@tonic-gate void
security(uid_t uid,uid_t euid,gid_t gid,gid_t egid,int auxflags)35810Sstevel@tonic-gate security(uid_t uid, uid_t euid, gid_t gid, gid_t egid, int auxflags)
35820Sstevel@tonic-gate {
35830Sstevel@tonic-gate if (auxflags != -1) {
35840Sstevel@tonic-gate if ((auxflags & AF_SUN_SETUGID) != 0)
35850Sstevel@tonic-gate rtld_flags |= RT_FL_SECURE;
35860Sstevel@tonic-gate return;
35870Sstevel@tonic-gate }
35888598SRod.Evans@Sun.COM
35894362Srie if (uid == (uid_t)-1)
35900Sstevel@tonic-gate uid = getuid();
35910Sstevel@tonic-gate if (uid) {
35924362Srie if (euid == (uid_t)-1)
35930Sstevel@tonic-gate euid = geteuid();
35940Sstevel@tonic-gate if (uid != euid)
35950Sstevel@tonic-gate rtld_flags |= RT_FL_SECURE;
35960Sstevel@tonic-gate else {
35974362Srie if (gid == (gid_t)-1)
35980Sstevel@tonic-gate gid = getgid();
35994362Srie if (egid == (gid_t)-1)
36000Sstevel@tonic-gate egid = getegid();
36010Sstevel@tonic-gate if (gid != egid)
36020Sstevel@tonic-gate rtld_flags |= RT_FL_SECURE;
36030Sstevel@tonic-gate }
36040Sstevel@tonic-gate }
36050Sstevel@tonic-gate }
36060Sstevel@tonic-gate
36070Sstevel@tonic-gate /*
36087668SRod.Evans@Sun.COM * Determine whether ld.so.1 itself is owned by root and has its mode setuid.
36097668SRod.Evans@Sun.COM */
36107668SRod.Evans@Sun.COM int
is_rtld_setuid()36117668SRod.Evans@Sun.COM is_rtld_setuid()
36127668SRod.Evans@Sun.COM {
36138394SAli.Bahrami@Sun.COM rtld_stat_t status;
361412650SRod.Evans@Sun.COM const char *name;
361512650SRod.Evans@Sun.COM
361612650SRod.Evans@Sun.COM if (rtld_flags2 & RT_FL2_SETUID)
361712650SRod.Evans@Sun.COM return (1);
361812650SRod.Evans@Sun.COM
361912650SRod.Evans@Sun.COM if (interp && interp->i_name)
362012650SRod.Evans@Sun.COM name = interp->i_name;
362112650SRod.Evans@Sun.COM else
362212650SRod.Evans@Sun.COM name = NAME(lml_rtld.lm_head);
362312650SRod.Evans@Sun.COM
362412650SRod.Evans@Sun.COM if (((rtld_stat(name, &status) == 0) &&
36257668SRod.Evans@Sun.COM (status.st_uid == 0) && (status.st_mode & S_ISUID))) {
36267668SRod.Evans@Sun.COM rtld_flags2 |= RT_FL2_SETUID;
36277668SRod.Evans@Sun.COM return (1);
36287668SRod.Evans@Sun.COM }
36297668SRod.Evans@Sun.COM return (0);
36307668SRod.Evans@Sun.COM }
36317668SRod.Evans@Sun.COM
36327668SRod.Evans@Sun.COM /*
363311827SRod.Evans@Sun.COM * Determine that systems platform name. Normally, this name is provided from
363411827SRod.Evans@Sun.COM * the AT_SUN_PLATFORM aux vector from the kernel. This routine provides a
363511827SRod.Evans@Sun.COM * fall back.
363611827SRod.Evans@Sun.COM */
363711827SRod.Evans@Sun.COM void
platform_name(Syscapset * scapset)363811827SRod.Evans@Sun.COM platform_name(Syscapset *scapset)
363911827SRod.Evans@Sun.COM {
364011827SRod.Evans@Sun.COM char info[SYS_NMLN];
364111827SRod.Evans@Sun.COM size_t size;
364211827SRod.Evans@Sun.COM
364311827SRod.Evans@Sun.COM if ((scapset->sc_platsz = size =
364411827SRod.Evans@Sun.COM sysinfo(SI_PLATFORM, info, SYS_NMLN)) == (size_t)-1)
364511827SRod.Evans@Sun.COM return;
364611827SRod.Evans@Sun.COM
364711827SRod.Evans@Sun.COM if ((scapset->sc_plat = malloc(size)) == NULL) {
364811827SRod.Evans@Sun.COM scapset->sc_platsz = (size_t)-1;
364911827SRod.Evans@Sun.COM return;
365011827SRod.Evans@Sun.COM }
365111827SRod.Evans@Sun.COM (void) strcpy(scapset->sc_plat, info);
365211827SRod.Evans@Sun.COM }
365311827SRod.Evans@Sun.COM
365411827SRod.Evans@Sun.COM /*
365511827SRod.Evans@Sun.COM * Determine that systems machine name. Normally, this name is provided from
365611827SRod.Evans@Sun.COM * the AT_SUN_MACHINE aux vector from the kernel. This routine provides a
365711827SRod.Evans@Sun.COM * fall back.
365811827SRod.Evans@Sun.COM */
365911827SRod.Evans@Sun.COM void
machine_name(Syscapset * scapset)366011827SRod.Evans@Sun.COM machine_name(Syscapset *scapset)
366111827SRod.Evans@Sun.COM {
366211827SRod.Evans@Sun.COM char info[SYS_NMLN];
366311827SRod.Evans@Sun.COM size_t size;
366411827SRod.Evans@Sun.COM
366511827SRod.Evans@Sun.COM if ((scapset->sc_machsz = size =
366611827SRod.Evans@Sun.COM sysinfo(SI_MACHINE, info, SYS_NMLN)) == (size_t)-1)
366711827SRod.Evans@Sun.COM return;
366811827SRod.Evans@Sun.COM
366911827SRod.Evans@Sun.COM if ((scapset->sc_mach = malloc(size)) == NULL) {
367011827SRod.Evans@Sun.COM scapset->sc_machsz = (size_t)-1;
367111827SRod.Evans@Sun.COM return;
367211827SRod.Evans@Sun.COM }
367311827SRod.Evans@Sun.COM (void) strcpy(scapset->sc_mach, info);
367411827SRod.Evans@Sun.COM }
367511827SRod.Evans@Sun.COM
367611827SRod.Evans@Sun.COM /*
36770Sstevel@tonic-gate * _REENTRANT code gets errno redefined to a function so provide for return
36780Sstevel@tonic-gate * of the thread errno if applicable. This has no meaning in ld.so.1 which
36790Sstevel@tonic-gate * is basically singled threaded. Provide the interface for our dependencies.
36800Sstevel@tonic-gate */
36810Sstevel@tonic-gate #undef errno
36820Sstevel@tonic-gate int *
___errno()36830Sstevel@tonic-gate ___errno()
36840Sstevel@tonic-gate {
36850Sstevel@tonic-gate extern int errno;
36860Sstevel@tonic-gate
36870Sstevel@tonic-gate return (&errno);
36880Sstevel@tonic-gate }
36890Sstevel@tonic-gate
36900Sstevel@tonic-gate /*
36910Sstevel@tonic-gate * Determine whether a symbol name should be demangled.
36920Sstevel@tonic-gate */
36930Sstevel@tonic-gate const char *
demangle(const char * name)36940Sstevel@tonic-gate demangle(const char *name)
36950Sstevel@tonic-gate {
36960Sstevel@tonic-gate if (rtld_flags & RT_FL_DEMANGLE)
36971618Srie return (conv_demangle_name(name));
36980Sstevel@tonic-gate else
36990Sstevel@tonic-gate return (name);
37000Sstevel@tonic-gate }
37018394SAli.Bahrami@Sun.COM
37028394SAli.Bahrami@Sun.COM #ifndef _LP64
37038394SAli.Bahrami@Sun.COM /*
37048394SAli.Bahrami@Sun.COM * Wrappers on stat() and fstat() for 32-bit rtld that uses stat64()
37058394SAli.Bahrami@Sun.COM * underneath while preserving the object size limits of a non-largefile
37068394SAli.Bahrami@Sun.COM * enabled 32-bit process. The purpose of this is to prevent large inode
37078394SAli.Bahrami@Sun.COM * values from causing stat() to fail.
37088394SAli.Bahrami@Sun.COM */
37098394SAli.Bahrami@Sun.COM inline static int
rtld_stat_process(int r,struct stat64 * lbuf,rtld_stat_t * restrict buf)37108394SAli.Bahrami@Sun.COM rtld_stat_process(int r, struct stat64 *lbuf, rtld_stat_t *restrict buf)
37118394SAli.Bahrami@Sun.COM {
37128394SAli.Bahrami@Sun.COM extern int errno;
37138394SAli.Bahrami@Sun.COM
37148394SAli.Bahrami@Sun.COM /*
37158394SAli.Bahrami@Sun.COM * Although we used a 64-bit capable stat(), the 32-bit rtld
37168394SAli.Bahrami@Sun.COM * can only handle objects < 2GB in size. If this object is
37178394SAli.Bahrami@Sun.COM * too big, turn the success into an overflow error.
37188394SAli.Bahrami@Sun.COM */
37198394SAli.Bahrami@Sun.COM if ((lbuf->st_size & 0xffffffff80000000) != 0) {
37208394SAli.Bahrami@Sun.COM errno = EOVERFLOW;
37218394SAli.Bahrami@Sun.COM return (-1);
37228394SAli.Bahrami@Sun.COM }
37238394SAli.Bahrami@Sun.COM
37248394SAli.Bahrami@Sun.COM /*
37258394SAli.Bahrami@Sun.COM * Transfer the information needed by rtld into a rtld_stat_t
37268394SAli.Bahrami@Sun.COM * structure that preserves the non-largile types for everything
37278394SAli.Bahrami@Sun.COM * except inode.
37288394SAli.Bahrami@Sun.COM */
37298394SAli.Bahrami@Sun.COM buf->st_dev = lbuf->st_dev;
37308394SAli.Bahrami@Sun.COM buf->st_ino = lbuf->st_ino;
37318394SAli.Bahrami@Sun.COM buf->st_mode = lbuf->st_mode;
37328394SAli.Bahrami@Sun.COM buf->st_uid = lbuf->st_uid;
37338394SAli.Bahrami@Sun.COM buf->st_size = (off_t)lbuf->st_size;
37348394SAli.Bahrami@Sun.COM buf->st_mtim = lbuf->st_mtim;
37358394SAli.Bahrami@Sun.COM #ifdef sparc
37368394SAli.Bahrami@Sun.COM buf->st_blksize = lbuf->st_blksize;
37378394SAli.Bahrami@Sun.COM #endif
37388394SAli.Bahrami@Sun.COM
37398394SAli.Bahrami@Sun.COM return (r);
37408394SAli.Bahrami@Sun.COM }
37418394SAli.Bahrami@Sun.COM
37428394SAli.Bahrami@Sun.COM int
rtld_stat(const char * restrict path,rtld_stat_t * restrict buf)37438394SAli.Bahrami@Sun.COM rtld_stat(const char *restrict path, rtld_stat_t *restrict buf)
37448394SAli.Bahrami@Sun.COM {
37458394SAli.Bahrami@Sun.COM struct stat64 lbuf;
37468394SAli.Bahrami@Sun.COM int r;
37478394SAli.Bahrami@Sun.COM
37488394SAli.Bahrami@Sun.COM r = stat64(path, &lbuf);
37498394SAli.Bahrami@Sun.COM if (r != -1)
37508394SAli.Bahrami@Sun.COM r = rtld_stat_process(r, &lbuf, buf);
37518394SAli.Bahrami@Sun.COM return (r);
37528394SAli.Bahrami@Sun.COM }
37538394SAli.Bahrami@Sun.COM
37548394SAli.Bahrami@Sun.COM int
rtld_fstat(int fildes,rtld_stat_t * restrict buf)37558394SAli.Bahrami@Sun.COM rtld_fstat(int fildes, rtld_stat_t *restrict buf)
37568394SAli.Bahrami@Sun.COM {
37578394SAli.Bahrami@Sun.COM struct stat64 lbuf;
37588394SAli.Bahrami@Sun.COM int r;
37598394SAli.Bahrami@Sun.COM
37608394SAli.Bahrami@Sun.COM r = fstat64(fildes, &lbuf);
37618394SAli.Bahrami@Sun.COM if (r != -1)
37628394SAli.Bahrami@Sun.COM r = rtld_stat_process(r, &lbuf, buf);
37638394SAli.Bahrami@Sun.COM return (r);
37648394SAli.Bahrami@Sun.COM }
37658394SAli.Bahrami@Sun.COM #endif
3766