util.c revision 466e2a6203d697dd110c04e84fc578f11a5601aa
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * CDDL HEADER START
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The contents of this file are subject to the terms of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Common Development and Distribution License (the "License").
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * You may not use this file except in compliance with the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * See the License for the specific language governing permissions
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * and limitations under the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * When distributing Covered Code, include this CDDL HEADER in each
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If applicable, add the following below this CDDL HEADER, with the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * fields enclosed by brackets "[]" replaced with your own identifying
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * information: Portions Copyright [yyyy] [name of copyright owner]
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * CDDL HEADER END
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright (c) 1988 AT&T
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * All Rights Reserved
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
fd21d481e26774c37a197c7cc8ab56096a21e7aaPhill Cunnington * Use is subject to license terms.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#pragma ident "%Z%%M% %I% %E% SMI"
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * Utility routines for run-time linker. some are duplicated here from libc
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * (with different names) to avoid name space collisions.
72450cb9c2ca854c6d3479832c2738196c1d3282Robert Wapshottstatic int ld_flags_env(const char *, Word *, Word *, uint_t, int);
3cfef899c650ea8fa23c64ad5a66b8986bf77bb2Tom Rumsey * All error messages go through eprintf(). During process initialization these
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell * messages should be directed to the standard error, however once control has
7b3fa0c4c626865e92012ef9f885e91d945850eaCraig McDonnell * been passed to the applications code these messages should be stored in an
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * internal buffer for use with dlerror(). Note, fatal error conditions that
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * may occur while running the application will still cause a standard error
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * message, see rtldexit() in this file for details.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The `application' flag serves to indicate the transition between process
01a939641aeb0a095851921879620c3fab295cb2Robert Wapshott * initialization and when the applications code is running.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Null function used as place where a debugger can set a breakpoint.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster DBG_CALL(Dbg_util_dbnotify(lml, r_debug.rtd_rdebug.r_rdevent,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Null function used as place where debugger can set a pre .init
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * processing breakpoint.
321cc59fdbbb9b6eebdfc714f2d86b785965d50eTom Rumsey DBG_CALL(Dbg_util_dbnotify(lml, r_debug.rtd_rdebug.r_rdevent,
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * Null function used as place where debugger can set a post .init
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * processing breakpoint.
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey DBG_CALL(Dbg_util_dbnotify(lml, r_debug.rtd_rdebug.r_rdevent,
7b3fa0c4c626865e92012ef9f885e91d945850eaCraig McDonnell * Debugger Event Notification
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This function centralizes all debugger event notification (ala rtld_db).
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * There's a simple intent, focused on insuring the primary link-map control
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * list (or each link-map list) is consistent, and the indication that objects
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * have been added or deleted from this list. Although an RD_ADD and RD_DELETE
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * event are posted for each of these, most debuggers don't care, as their
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * view is that these events simply convey an "inconsistent" state.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * We also don't want to trigger multiple RD_ADD/RD_DELETE events any time we
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * With auditors, we may be in the process of relocating a collection of
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * objects, and will leave() ld.so.1 to call the auditor. At this point we
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * must indicate an RD_CONSISTENT event, but librtld_db will not report an
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * object to the debuggers until relocation processing has been completed on it.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * To allow for the collection of these objects that are pending relocation, an
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * RD_ADD event is set after completing a series of relocations on the primary
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * link-map control list.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Set an RD_ADD/RD_DELETE event and indicate that an RD_CONSISTENT event is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * required later (LML_FLG_DBNOTIF):
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * i the first time we add or delete an object to the primary link-map
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * control list.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * ii the first time we move a secondary link-map control list to the primary
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * link-map control list (effectively, this is like adding a group of
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * objects to the primary link-map control list).
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Set an RD_CONSISTENT event when it is required (LML_FLG_DBNOTIF is set) and
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * i each time we leave the runtime linker.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterrd_event(Lm_list *lml, rd_event_e event, r_state_e state)
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell * Do we need to send a notification?
cc7c18212481f5e9ee508afe2ffcaecb6b9330f5Craig McDonnell * If we are already in an inconsistent state, no
cc7c18212481f5e9ee508afe2ffcaecb6b9330f5Craig McDonnell * notification is required.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * RD_NONE - do nothing
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Set event state and call 'notification' function.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The debugging clients have previously been told about these
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * notification functions and have set breakpoints on them if they
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * are interested in the notification.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Stack Cleanup.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This function is invoked to 'remove' arguments that were passed in on the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * stack. This is most likely if ld.so.1 was invoked directly. In that case
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * we want to remove ld.so.1 as well as it's arguments from the argv[] array.
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * Which means we then need to slide everything above it on the stack down
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * accordingly.
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * While the stack layout is platform specific - it just so happens that __x86,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * and __sparc platforms share the following initial stack layout.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * !_______________________! high addresses
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! Information !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! (size varies) !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * !_______________________!
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * ! 0 word !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * !_______________________!
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! Auxiliary !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! 2 word entries !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * !_______________________!
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * !_______________________!
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! Environment !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! pointers !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! (one word each) !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * !_______________________!
3cfef899c650ea8fa23c64ad5a66b8986bf77bb2Tom Rumsey * ! 0 word !
9d9fe1fc09ded5c22489a661631e1f34c2a7e989Tom Rumsey * !_______________________!
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! Argument ! low addresses
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * ! pointers !
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * ! Argc words !
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * !_______________________!
cc7c18212481f5e9ee508afe2ffcaecb6b9330f5Craig McDonnell * !_______________________!
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshottstack_cleanup(char **argv, char ***envp, auxv_t **auxv, int rmcnt)
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * Slide ARGV[] and update argc. The argv pointer remains the same,
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * however slide the applications arguments over the arguments to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster argc = (long *)((uintptr_t)argv - sizeof (long *));
6309b849c2de831a0eaed9c27b5794bed9bd8fd1Neil Madden * Slide ENVP[], and update the environment array pointer.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Slide AUXV[], and update the aux vector pointer.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (ndx = 0; (oauxv[ndx].a_type != AT_NULL); ndx++)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Verify that the above routine is appropriate for any new platforms.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The only command line argument recognized is -e, followed by a runtime
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * linker environment variable.
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamfordrtld_getopt(char **argv, char ***envp, auxv_t **auxv, Word *lmflags,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If the environment variable starts with LD_, strip the LD_.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Otherwise, take things as is.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((str[0] == 'L') && (str[1] == 'D') && (str[2] == '_') &&
ccf9d4a5c6453fa9f8b839baeee25147865fbb7dJames Phillpotts if (ld_flags_env(str, lmflags, lmtflags, 0, aout) == 1)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Make sure an object file has been specified.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Having gotten the arguments, clean ourselves off of the stack.
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * Compare function for PathNode AVL tree.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return (-1);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Determine if a pathname has already been recorded on the full path name
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * AVL tree. This tree maintains a node for each path name that ld.so.1 has
87d68743726585ee101ba2e7be2cf06cd34ebb80Neil Madden * successfully loaded. If the path name does not exist in this AVL tree, then
87d68743726585ee101ba2e7be2cf06cd34ebb80Neil Madden * the next insertion point is deposited in "where". This value can be used by
87d68743726585ee101ba2e7be2cf06cd34ebb80Neil Madden * fpavl_insert() to expedite the insertion.
47c2be2db219abf98d491a0a6625380421d61e42Phill Cunningtonfpavl_recorded(Lm_list *lml, const char *name, avl_index_t *where)
47c2be2db219abf98d491a0a6625380421d61e42Phill Cunnington * Create the avl tree if required.
47c2be2db219abf98d491a0a6625380421d61e42Phill Cunnington if ((avlt = calloc(sizeof (avl_tree_t), 1)) == 0)
87d68743726585ee101ba2e7be2cf06cd34ebb80Neil Madden avl_create(avlt, pnavl_compare, sizeof (FullPathNode),
321cc59fdbbb9b6eebdfc714f2d86b785965d50eTom Rumsey if ((fpnp = avl_find(lml->lm_fpavl, &fpn, where)) == NULL)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Insert a name into the FullPathNode AVL tree for the link-map list. The
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * objects NAME() is the path that would have originally been searched for, and
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * is therefore the name to associate with any "where" value. If the object has
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * a different PATHNAME(), perhaps because it has resolved to a different file
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * (see fullpath()), then this name will be recorded as a separate FullPathNode
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * (see load_file()).
321cc59fdbbb9b6eebdfc714f2d86b785965d50eTom Rumseyfpavl_insert(Lm_list *lml, Rt_map *lmp, const char *name, avl_index_t where)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* LINTED */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Rt_map *_lmp = fpavl_recorded(lml, name, &where);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * We better not get a hit now, we do not want duplicates in
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * Insert new node in tree.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((fpnp = calloc(sizeof (FullPathNode), 1)) == 0)
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott if (aplist_append(&FPNODE(lmp), fpnp, AL_CNT_FPNODE) == NULL) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Remove an object from the FullPath AVL tree. Note, this is called *before*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the objects link-map is torn down (remove_so), which is where any NAME() and
9d9fe1fc09ded5c22489a661631e1f34c2a7e989Tom Rumsey * PATHNAME() strings will be deallocated.
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott for (APLIST_TRAVERSE(FPNODE(lmp), idx, fpnp)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Determine if a pathname has already been recorded on the not-found AVL tree.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This tree maintains a node for each path name that ld.so.1 has explicitly
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * inspected, but has failed to load during a single ld.so.1 operation. If the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * path name does not exist in this AVL tree, then the next insertion point is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * deposited in "where". This value can be used by nfavl_insert() to expedite
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the insertion.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosternfavl_recorded(const char *name, avl_index_t *where)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Create the avl tree if required.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((avlt = calloc(sizeof (avl_tree_t), 1)) == 0)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster avl_create(avlt, pnavl_compare, sizeof (PathNode),
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Insert a name into the not-found AVL tree.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosternfavl_insert(const char *name, avl_index_t where)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* LINTED */
72450cb9c2ca854c6d3479832c2738196c1d3282Robert Wapshott * We better not get a hit now, we do not want duplicates in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Insert new node in tree.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((pnp = calloc(sizeof (PathNode), 1)) != 0) {
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * Prior to calling an object, either via a .plt or through dlsym(), make sure
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * its .init has fired. Through topological sorting, ld.so.1 attempts to fire
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * init's in the correct order, however, this order is typically based on needed
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * dependencies and non-lazy relocation bindings. Lazy relocations (.plts) can
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * still occur and result in bindings that were not captured during topological
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * sorting. This routine compensates for this lack of binding information, and
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * provides for dynamic .init firing.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If the caller is an auditor, and the destination isn't, then don't
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * run any .inits (see comments in load_completion()).
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) &&
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford if ((dlmp == clmp) || (rtld_flags & (RT_FL_BREADTH | RT_FL_INITFIRST)))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITDONE)) ==
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITCALL)) ==
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((tobj = calloc(2, sizeof (Rt_map *))) != NULL) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * In a threaded environment insure the thread responsible for loading an object
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * has completed .init processing for that object before any new thread is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * allowed to access the object. This check is only valid with libthread
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * TI_VERSION 2, where ld.so.1 implements locking through low level mutexes.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * When a new link-map is created, the thread that causes it to be loaded is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * identified by THREADID(dlmp). Compare this with the current thread to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * determine if it must be blocked.
72450cb9c2ca854c6d3479832c2738196c1d3282Robert Wapshott * NOTE, there are a number of instances (typically only for .plt processing)
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * where we must skip this test:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * . any thread id of 0 - threads that call thr_exit() may be in this state
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * thus we can't deduce what tid they used to be. Also some of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * lib/libthread worker threads have this id and must bind (to themselves
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * or libc) for libthread to function.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * . libthread itself binds to libc, and as libthread is INITFIRST
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * libc's .init can't have fired yet. Luckly libc's .init is not required
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * by libthreads binding.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * . if the caller is an auditor, and the destination isn't, then don't
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * block (see comments in load_completion()).
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/* ARGSUSED2 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosteris_dep_ready(Rt_map *dlmp, Rt_map *clmp, int what)
f79113ae65937c28690ec71f68f54f862b758baePhill Cunnington if ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) &&
cc7c18212481f5e9ee508afe2ffcaecb6b9330f5Craig McDonnell ((tid = rt_thr_self()) != 0) && (THREADID(dlmp) != tid)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Execute .{preinit|init|fini}array sections
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostercall_array(Addr *array, uint_t arraysz, Rt_map *lmp, Word shtype)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster uint_t arraycnt = (uint_t)(arraysz / sizeof (Addr));
26304a2a091af368cfc16c977bcce6d17195360aTom Rumsey * initarray & preinitarray are walked from beginning to end - while
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * finiarray is walked from end to beginning.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Call the .*array[] entries
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster DBG_CALL(Dbg_util_call_array(lmp, (void *)fptr, ndx, shtype));
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * Execute any .init sections. These are passed to us in an lmp array which
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * (by default) will have been sorted.
42c10b520a70c6b2c67ad812cfda98ac1663f0c5Craig McDonnell * If we're in the middle of an INITFIRST, this must complete before
42c10b520a70c6b2c67ad812cfda98ac1663f0c5Craig McDonnell * any new init's are fired. In this case add the object list to the
42c10b520a70c6b2c67ad812cfda98ac1663f0c5Craig McDonnell * pending queue and return. We'll pick up the queue after any
42c10b520a70c6b2c67ad812cfda98ac1663f0c5Craig McDonnell * INITFIRST objects have their init's fired.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Traverse the tobj array firing each objects init.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (_tobj = _nobj = tobj, _nobj++; *_tobj != NULL; _tobj++, _nobj++) {
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * Establish an initfirst state if necessary - no other inits
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * will be fired (because of additional relocation bindings)
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * when in this state.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Make sure that all dependencies that have been
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford * relocated to are initialized before this objects
fc8409d20f991d53ac0c4708efa04c121b73c449Tom Rumsey * .init is executed. This insures that a dependency
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * on an external item that must first be initialized
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * by its associated object is satisfied.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (APLIST_TRAVERSE(DEPENDS(lmp), idx, bdp)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster is_dep_ready(bdp->b_depend, lmp, DBG_WAIT_INIT);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster call_array(INITARRAY(lmp), INITARRAYSZ(lmp), lmp,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster DBG_CALL(Dbg_util_call_init(lmp, DBG_INIT_DONE));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Set the initdone flag regardless of whether this object
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * actually contains an .init section. This flag prevents us
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * from processing this section again for an .init and also
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * signifies that a .fini must be called should it exist.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Clear the sort field for use in later .fini processing.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Wake anyone up who might be waiting on this .init.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If we're firing an INITFIRST object, and other objects must
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * be fired which are not INITFIRST, make sure we grab any
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * pending objects that might have been delayed as this
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * INITFIRST was processed.
72450cb9c2ca854c6d3479832c2738196c1d3282Robert Wapshott ((*_nobj == NULL) || !(FLAGS(*_nobj) & FLG_RT_INITFRST))) {
7b3fa0c4c626865e92012ef9f885e91d945850eaCraig McDonnell * Function called by atexit(3C). Calls all .fini sections related with the
d0da70ccbba38b773e7a7cc71bc124b06206d201Robert Wapshott * mains dependent shared libraries in the order in which the shared libraries
d0da70ccbba38b773e7a7cc71bc124b06206d201Robert Wapshott * have been loaded. Skip any .fini defined in the main executable, as this
d0da70ccbba38b773e7a7cc71bc124b06206d201Robert Wapshott * will be called by crt0 (main was never marked as initdone).
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell for (_tobj = tobj; *_tobj != NULL; _tobj++) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If concurrency checking isn't enabled only fire .fini if
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * .init has completed. We collect all .fini sections of
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * objects that had their .init collected, but that doesn't
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * mean at the time that the .init had completed.
cc7c18212481f5e9ee508afe2ffcaecb6b9330f5Craig McDonnell * If concurrency checking is enabled make sure
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * this object's .init is completed before
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * calling any .fini.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster call_array(FINIARRAY(lmp), FINIARRAYSZ(lmp), lmp,
d0da70ccbba38b773e7a7cc71bc124b06206d201Robert Wapshott * Skip main, this is explicitly called last in atexit_fini().
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Audit `close' operations at this point. The library has
72450cb9c2ca854c6d3479832c2738196c1d3282Robert Wapshott * exercised its last instructions (regardless of whether it
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * will be unmapped or not).
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * First call any global auditing.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Finally determine whether this object has local auditing
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * requirements by inspecting itself and then its dependencies.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _audit_objclose(&(AUDITORS(lmp)->ad_list), lmp);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster DBG_CALL(Dbg_bind_plt_summary(lml, M_MACH, pltcnt21d, pltcnt24d,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Reverse topologically sort the main link-map for .fini execution.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != 0) &&
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Add an explicit close to main and ld.so.1. Although main's .fini is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * collected in call_fini() to provide for FINITARRAY processing, its
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * audit_objclose is explicitly skipped. This provides for it to be
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * called last, here. This is the reverse of the explicit calls to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * audit_objopen() made in setup().
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((lml->lm_tflags | FLAGS1(lmp)) & LML_TFLG_AUD_MASK) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster audit_objclose(lmp, (Rt_map *)lml_rtld.lm_head);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Now that all .fini code has been run, see what unreferenced objects
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Traverse any alternative link-map lists.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Ignore the base-link-map list, which has already been
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * processed, and the runtime linkers link-map list, which is
cc7c18212481f5e9ee508afe2ffcaecb6b9330f5Craig McDonnell * typically processed last.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM))
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott * Reverse topologically sort the link-map for .fini execution.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != 0) &&
87d68743726585ee101ba2e7be2cf06cd34ebb80Neil Madden * Finally reverse topologically sort the runtime linkers link-map for
87d68743726585ee101ba2e7be2cf06cd34ebb80Neil Madden * .fini execution.
321cc59fdbbb9b6eebdfc714f2d86b785965d50eTom Rumsey if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != 0) &&
if (nlmp)
tobj = 0;
if (tobj)
Listnode *
return (_lnp);
Listnode *
return (_lnp);
Listnode *
return (_lnp);
if (clnp == 0)
if (plnp)
* link-map list information used by all ld.so.1 routines.
add = 0;
add = 0;
if (add) {
#ifdef SIEBEL_DISABLE
const char **str;
rpl_audit = 0;
MSG_LD_AUDIT_ARGS_SIZE) == 0)) {
MSG_LD_BIND_LAZY_SIZE) == 0)) {
#ifndef LD_BREADTH_DISABLED
MSG_LD_CONCURRENCY_SIZE) == 0)) {
rpl_debug = 0;
MSG_LD_DEBUG_OUTPUT_SIZE) == 0)) {
rpl_ldflags = 0;
rpl_libpath = 0;
MSG_LD_NODIRCONFIG_SIZE) == 0)) {
MSG_LD_NOENVCONFIG_SIZE) == 0)) {
MSG_LD_NOFLTCONFIG_SIZE) == 0)) {
MSG_LD_NOOBJALTER_SIZE) == 0)) {
MSG_LD_NOUNRESWEAK_SIZE) == 0)) {
#ifndef EXPAND_RELATIVE
rpl_preload = 0;
MSG_LD_PROFILE_OUTPUT_SIZE) == 0)) {
MSG_LD_SIGNAL_SIZE) == 0)) {
MSG_LD_TRACE_OBJS_SIZE) == 0)) ||
* ignored by any ld.so.1 environment processing.
* into ld.so.1.
MSG_LD_TRACE_PTHS_SIZE) == 0)) {
#ifdef SIEBEL_DISABLE
if (variable == 0)
} else if (s2) {
if (s2)
if (s2)
if (s2)
if (s2)
if (s2) {
if (s2) {
audit_argcnt = 0;
if (s2)
rpl_debug = 0;
if (s2)
if (s2) {
if (s2) {
if (s2) {
#if defined(_ELF64)
#if defined(_ELF64)
profile_lib = 0;
if (s2) {
*lmflags &=
#if defined(_ELF64)
return (ENV_TYP_IGNORE);
return (ENV_TYP_ISA);
#if defined(_ELF64)
return (ENV_TYP_ISA);
return (ENV_TYP_IGNORE);
if (str == 0)
int flags;
if (estr == 0) {
* code doubles the size of ld.so.1.
if (estr) {
estr = 0;
if (estr == 0)
if (len == 0)
estr = 0;
int aout)
const char *s2;
MSG_LC_MESSAGES_SIZE) == 0) {
int flags;
MSG_LD_BRAND_PREFIX_SIZE) != 0)
s2 = 0;
s2 = 0;
s2++;
* Internal getenv routine. Called immediately after ld.so.1 initializes
char *locale;
if (envp == (const char **)0)
while (*envp != (const char *)0)
if ((*lmflags &
envtbl++;
#define PUTC(c) \
char tmpc; \
tmpc = (c); \
PUTC(c);
char *_s;
int ls = 0;
c = *format++;
goto again;
goto again;
goto again;
goto again;
goto again;
PUTC(c);
PUTC(c);
if (!prec)
while (_n-- > 0)
PUTC(c);
while (_n-- > 0)
if (base) {
const char *string =
const char *prefix =
switch (ls) {
ssize++;
} while (num);
if (prec) {
while ((_n-- > 0) &&
ssize++;
while (_n-- > 0) {
while (*prefix)
while (_n-- > 0)
int len;
int len;
return (len);
int len;
return (len);
int overflow = 0;
static int lock = 0;
if (procname) {
if (overflow == 0) {
* object that has a dependency on libelf. ld.so.1 doesn't generate any
static int (*elfeno)() = 0;
static const char *(*elfemg)();
const char *emsg;
elfeno = 0;
emsg) == 0)
if (overflow)
if (overflow) {
lock = 0;
lock = 0;
#if DEBUG
assfail(const char *a, const char *f, int l)
if (status) {
if (*errbuf) {
* dz_fd is exported for possible use by libld.so, and to insure it gets
* closed on leaving ld.so.1.
#if defined(MAP_ANON)
static int noanon = 0;
if (noanon == 0) {
return (AM_OK);
return (AM_ERROR);
return (AM_NOSUP);
int err;
return (addr);
return (MAP_FAILED);
return (MAP_FAILED);
return (va);
(int)getpid());
return (pr_fd);
int err;
return (MAP_FAILED);
MAP_FAILED) {
return (va);
if (!thr_flg_nolock)
ld_entry_cnt++;
if (unref == 0) {
if ((*nl)++ == 0)
if (unref)
if ((*nl)++ == 0)
int nl = 0;
if (rpl_libdirs)
if (prm_libdirs)
nl = 0;
nl = 0;
if (nl++ == 0) {
if (unref)
DBG_NL_STD));
if (unref)
if (nl++ == 0) {
#if defined(MAP_ALIGN)
* Insures that any ld.so.1 specific file descriptors or temporary mapping are
if (elml == 0)
fmap_setup();
prevptr = 0;
* *) The ld.so.1's link-map list.
if (!thr_flg_nolock)
* variable is initialized, so ld.so.1 sets this directly from the AUX vector
* information. In addition, a process may have multiple link-maps (ld.so.1's
* to ld.so.1.
* This function is called prior to any dependency processing (see _setup.c).
#ifdef AT_SUN_AUXFLAGS
if (uid) {
* of the thread errno if applicable. This has no meaning in ld.so.1 which
___errno()
extern int errno;
return (&errno);
* The interface with the c library which is supplied through libdl.so.1.
return (name);