# HG changeset patch # User rie # Date 1190053970 25200 # Node ID d64dc195fe92c854f9ac71d1b38dfa124dbc84d3 # Parent be9489708c481b25afaf69a57d6c2aad0de26743 6603313 dlclose() can fail to unload objects after fix for 6573641 diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/include/conv.h --- a/usr/src/cmd/sgs/include/conv.h Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/include/conv.h Mon Sep 17 11:32:50 2007 -0700 @@ -246,7 +246,7 @@ /* conv_grphdl_flags() */ -#define CONV_GRPHDL_FLAGS_BUFSIZE 80 +#define CONV_GRPHDL_FLAGS_BUFSIZE 82 typedef union { Conv32_inv_buf_t inv_buf; @@ -260,7 +260,7 @@ /* conv_grpdesc_flags() */ -#define CONV_GRPDESC_FLAGS_BUFSIZE 80 +#define CONV_GRPDESC_FLAGS_BUFSIZE 92 typedef union { Conv32_inv_buf_t inv_buf; diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/include/debug.h --- a/usr/src/cmd/sgs/include/debug.h Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/include/debug.h Mon Sep 17 11:32:50 2007 -0700 @@ -57,7 +57,7 @@ /* * Define Dbg_*() interface flags. These flags direct the debugging routine to * generate different diagnostics, thus the strings themselves are maintained - * in this library. + * in the debugging library. */ #define DBG_SUP_ENVIRON 1 #define DBG_SUP_CMDLINE 2 @@ -98,13 +98,27 @@ #define DBG_SYM_REDUCE_GLOBAL 1 /* reporting global symbols to local */ #define DBG_SYM_REDUCE_RETAIN 2 /* reporting non reduced local syms */ -#define DBG_DEP_CREATE 1 /* Group handle operations */ -#define DBG_DEP_ADD 2 -#define DBG_DEP_DELETE 3 -#define DBG_DEP_REMOVE 4 -#define DBG_DEP_REMAIN 5 -#define DBG_DEP_ORPHAN 6 -#define DBG_DEP_REINST 7 +/* + * Group handle operations - passed to Dbg_file_hdl_title(). Indicate why + * handle dependencies are being manipulated. + */ +#define DBG_HDL_CREATE 0 /* handle creation */ +#define DBG_HDL_ADD 1 /* addition to existing handle */ +#define DBG_HDL_DELETE 2 /* deletion from a handle */ +#define DBG_HDL_ORPHAN 3 /* handle being moved to orphan list */ +#define DBG_HDL_REINST 4 /* handle reinstated from orphan list */ + +/* + * Group handle dependency operations - passed to Dbg_file_hdl_action(). + * Indicates depdenencies assocation to handle. + */ +#define DBG_DEP_ADD 0 /* dependency added */ +#define DBG_DEP_UPDATE 1 /* dependency updated */ +#define DBG_DEP_DELETE 2 /* dependency deleted */ +#define DBG_DEP_REMOVE 3 /* dependency removed from handle */ +#define DBG_DEP_REMAIN 4 /* dependency must remain on handle */ +#define DBG_DEP_ORPHAN 5 /* dependency must remain an orphan */ +#define DBG_DEP_REINST 6 /* dependency reinstated from orphan */ #define DBG_BINFO_FOUND 0x0001 /* information regarding binding */ #define DBG_BINFO_DIRECT 0x0002 /* bound directly */ diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/include/rtld.h --- a/usr/src/cmd/sgs/include/rtld.h Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/include/rtld.h Mon Sep 17 11:32:50 2007 -0700 @@ -268,7 +268,7 @@ * END: Exposed to rtld_db - don't move, don't delete */ Alist *lm_rti; /* list of RTLDINFO tables */ - Audit_list *lm_alp; /* audit list descripter */ + Audit_list *lm_alp; /* audit list descriptor */ avl_tree_t *lm_fpavl; /* avl tree of objects loaded */ Alist *lm_lists; /* active and pending link-map lists */ char ***lm_environ; /* pointer to environment array */ @@ -385,38 +385,76 @@ */ #define LML_TFLG_AUD_MASK 0xfff00000 /* audit interfaces mask */ - /* - * Information for dlopen(), dlsym(), and dlclose() on libraries linked by rtld. - * Each shared object referred from a dlopen call has an associated group - * handle structure returned that describes a group of one or more objects. + * Define a Group Handle. + * + * The capability of ld.so.1 to associate a group of objects, look for symbols + * within that group, ensure that groups are isolated from one another (with + * regard to relocations), and to unload a group, centers around a handle. This + * data structure is tracked from the link-map HANDLE(), and is the structure + * returned from dlopen(), and similar object loading capabilities such as + * filter/filtee processing. + * + * A handle keeps track of all the dependencies of the associated object. + * These dependencies may be added as objects are lazily loaded. The core + * dependencies on the handle are the ldd(1) list of the associated object. + * The object assigned the handle, and the parent (or caller) who requested the + * handle are also maintained as dependencies on the handle. + * + * Presently, an object may have two handles, one requested with RTLD_FIRST + * and one without. + * + * A handle may be referenced by any number of parents (callers). A reference + * count tracks the number. A dlclose() operation drops the reference count, + * and when the count is zero, the handle is used to determine the family of + * objects to unload. As bindings may occur to objects on the handle from + * other handles, it may not be possible to remove a complete family of + * objects or that handle itself. Handles in this state are moved to an orphan + * list. A handle on the orphan list is taken off the orphan list if the + * associated object is reopened. Otherwise, the handle remains on the orphan + * list for the duration of the process. The orphan list is inspected any time + * objects are unloaded, to determine if the orphaned objects can also be + * unloaded. + * + * Objects can be dlopened using RTLD_NOW. This attribute requires that all + * relocations of the object, and its dependencies are processed immediately, + * before return to the caller. Typically, an object is loaded without + * RTLD_NOW, and procedure linkage relocations are satisfied when their + * associated function is first called. If an object is already loaded, and an + * RTLD_NOW request is made, then the object, and its dependencies, most undergo + * additional relocation processing. This promotion from lazy binding to + * immediate binding is carried out using handles, as the handle defines the + * dependencies that must be processed. A temporary handle is created for this + * purpose, and is discarded immediately after the promotion operation has been + * completed. */ typedef struct { Alist *gh_depends; /* handle dependency list */ Rt_map *gh_ownlmp; /* handle owners link-map */ Lm_list *gh_ownlml; /* handle owners link-map list */ uint_t gh_refcnt; /* handle reference count */ - uint_t gh_flags; /* handle flags */ + uint_t gh_flags; /* handle flags (GPH_ values) */ } Grp_hdl; #define GPH_ZERO 0x0001 /* special handle for dlopen(0) */ #define GPH_LDSO 0x0002 /* special handle for ld.so.1 */ #define GPH_FIRST 0x0004 /* dlsym() can only use originating */ /* dependency */ -#define GPH_PARENT 0x0008 /* assign caller as a parent */ -#define GPH_FILTEE 0x0010 /* handle used to specify a filtee */ -#define GPH_INITIAL 0x0020 /* handle is initialized */ -#define GPH_NOPENDLAZY 0x0040 /* no pending lazy dependencies */ +#define GPH_FILTEE 0x0008 /* handle used to specify a filtee */ +#define GPH_INITIAL 0x0010 /* handle is initialized */ +#define GPH_NOPENDLAZY 0x0020 /* no pending lazy dependencies */ /* remain for this handle */ /* - * A group descriptor. A group handle (Grp_hdl) refers to a group of objects, - * each object, and its relationship to the handle, is maintained within a - * group descriptor. + * Define a Group Descriptor. + * + * Each dependency associated with a group handle is maintained by a group + * descriptor. The descriptor defines the associated dependency together with + * flags that indicate how the dependency can be used. */ typedef struct { Rt_map * gd_depend; /* dependency */ - uint_t gd_flags; /* dependency flags */ + uint_t gd_flags; /* dependency flags (GPD_ values) */ } Grp_desc; #define GPD_DLSYM 0x0001 /* dependency available to dlsym() */ @@ -426,6 +464,8 @@ /* should be added to handle */ #define GPD_PARENT 0x0008 /* dependency is a parent */ #define GPD_FILTER 0x0010 /* dependency is our filter */ +#define GPD_PROMOTE 0x0020 /* dependency is our RTLD_NOW */ + /* promoter */ #define GPD_REMOVE 0x1000 /* descriptor is a candidate for */ /* removal from the group */ @@ -689,7 +729,7 @@ #define FL1_RT_OBJAFLTR 0x00002000 /* or auxiliary filter */ #define FL1_RT_SYMSFLTR 0x00004000 /* symbol is acting as a standard */ #define FL1_RT_SYMAFLTR 0x00008000 /* or auxiliary filter */ -#define MSK_RT_FILTER 0x0000f000 /* mask for all filter possibilites */ +#define MSK_RT_FILTER 0x0000f000 /* mask for all filter possibilities */ #define FL1_RT_TLSADD 0x00010000 /* objects TLS has been registered */ #define FL1_RT_TLSSTAT 0x00020000 /* object requires static TLS */ diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/libconv/common/group.c --- a/usr/src/cmd/sgs/libconv/common/group.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/libconv/common/group.c Mon Sep 17 11:32:50 2007 -0700 @@ -34,9 +34,9 @@ MSG_GPH_ZERO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPH_LDSO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPH_FIRST_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ - MSG_GPH_PARENT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPH_FILTEE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPH_INITIAL_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ + MSG_GPH_NOPENDLAZY_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE /* @@ -62,9 +62,9 @@ { GPH_ZERO, MSG_ORIG(MSG_GPH_ZERO) }, { GPH_LDSO, MSG_ORIG(MSG_GPH_LDSO) }, { GPH_FIRST, MSG_ORIG(MSG_GPH_FIRST) }, - { GPH_PARENT, MSG_ORIG(MSG_GPH_PARENT) }, { GPH_FILTEE, MSG_ORIG(MSG_GPH_FILTEE) }, { GPH_INITIAL, MSG_ORIG(MSG_GPH_INITIAL) }, + { GPH_NOPENDLAZY, MSG_ORIG(MSG_GPH_NOPENDLAZY) }, { 0, 0 } }; static CONV_EXPN_FIELD_ARG conv_arg = { @@ -86,6 +86,7 @@ MSG_GPD_ADDEPS_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPD_PARENT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPD_FILTER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ + MSG_GPD_PROMOTE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ MSG_GPD_REMOVE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE @@ -114,6 +115,7 @@ { GPD_ADDEPS, MSG_ORIG(MSG_GPD_ADDEPS) }, { GPD_PARENT, MSG_ORIG(MSG_GPD_PARENT) }, { GPD_FILTER, MSG_ORIG(MSG_GPD_FILTER) }, + { GPD_PROMOTE, MSG_ORIG(MSG_GPD_PROMOTE) }, { GPD_REMOVE, MSG_ORIG(MSG_GPD_REMOVE) }, { 0, 0 } }; diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/libconv/common/group.msg --- a/usr/src/cmd/sgs/libconv/common/group.msg Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/libconv/common/group.msg Mon Sep 17 11:32:50 2007 -0700 @@ -28,15 +28,16 @@ @ MSG_GPH_ZERO "GPH_ZERO" @ MSG_GPH_LDSO "GPH_LDSO" @ MSG_GPH_FIRST "GPH_FIRST" -@ MSG_GPH_PARENT "GPH_PARENT" @ MSG_GPH_FILTEE "GPH_FILTEE" @ MSG_GPH_INITIAL "GPH_INITIAL" +@ MSG_GPH_NOPENDLAZY "GPH_NOPENDLAZY" @ MSG_GPD_DLSYM "GPD_DLSYM" @ MSG_GPD_RELOC "GPD_RELOC" @ MSG_GPD_ADDEPS "GPD_ADDEPS" @ MSG_GPD_PARENT "GPD_PARENT" @ MSG_GPD_FILTER "GPD_FILTER" +@ MSG_GPD_PROMOTE "GPD_PROMOTE" @ MSG_GPD_REMOVE "GPD_REMOVE" @ MSG_GBL_NULL "" diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/liblddbg/common/files.c --- a/usr/src/cmd/sgs/liblddbg/common/files.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/files.c Mon Sep 17 11:32:50 2007 -0700 @@ -137,45 +137,28 @@ void Dbg_file_hdl_title(int type) { + static const Msg titles[] = { + MSG_FIL_HDL_CREATE, /* MSG_INTL(MSG_FIL_HDL_CREATE) */ + MSG_FIL_HDL_ADD, /* MSG_INTL(MSG_FIL_HDL_ADD) */ + MSG_FIL_HDL_DELETE, /* MSG_INTL(MSG_FIL_HDL_DELETE) */ + MSG_FIL_HDL_ORPHAN, /* MSG_INTL(MSG_FIL_HDL_ORPHAN) */ + MSG_FIL_HDL_REINST, /* MSG_INTL(MSG_FIL_HDL_REINST) */ + }; + if (DBG_NOTCLASS(DBG_C_FILES)) return; if (DBG_NOTDETAIL()) return; - hdl_title = 1; - /* - * Establish a binding title for later use in Dbg_file_bind_entry. - * These are to be used with the MSG_INTL() macro. - * - * Note: The following are to convince chkmsg.sh that these - * messages are actually used: - * - * MSG_INTL(MSG_FIL_HDL_CREATE) - * MSG_INTL(MSG_FIL_HDL_ADD) - * MSG_INTL(MSG_FIL_HDL_DELETE) - * MSG_INTL(MSG_FIL_HDL_ORPHAN) - * MSG_INTL(MSG_FIL_HDL_REINST) + * Establish a binding title for later use in Dbg_file_hdl_action. */ - switch (type) { - case DBG_DEP_CREATE: - hdl_str = MSG_FIL_HDL_CREATE; - break; - case DBG_DEP_ADD: - hdl_str = MSG_FIL_HDL_ADD; - break; - case DBG_DEP_DELETE: - hdl_str = MSG_FIL_HDL_DELETE; - break; - case DBG_DEP_ORPHAN: - hdl_str = MSG_FIL_HDL_ORPHAN; - break; - case DBG_DEP_REINST: - hdl_str = MSG_FIL_HDL_REINST; - break; - default: + if (type <= DBG_HDL_REINST) { + hdl_str = titles[type]; + hdl_title = 1; + } else { hdl_str = 0; - break; + hdl_title = 0; } } @@ -215,6 +198,15 @@ Lm_list *lml = LIST(lmp); Msg str; + static const Msg fmt[] = { + MSG_FIL_DEP_ADD, /* MSG_INTL(MSG_FIL_DEP_ADD) */ + MSG_FIL_DEP_UPDATE, /* MSG_INTL(MSG_FIL_DEP_UPDATE) */ + MSG_FIL_DEP_DELETE, /* MSG_INTL(MSG_FIL_DEP_DELETE) */ + MSG_FIL_DEP_REMOVE, /* MSG_INTL(MSG_FIL_DEP_REMOVE) */ + MSG_FIL_DEP_REMAIN, /* MSG_INTL(MSG_FIL_DEP_REMAIN) */ + MSG_FIL_DEP_ORPHAN, /* MSG_INTL(MSG_FIL_DEP_ORPHAN) */ + MSG_FIL_DEP_REINST, /* MSG_INTL(MSG_FIL_DEP_REINST) */ + }; if (DBG_NOTCLASS(DBG_C_FILES)) return; if (DBG_NOTDETAIL()) @@ -240,40 +232,14 @@ } /* - * Note: The following are to convince chkmsg.sh that these - * messages are actually used: - * - * MSG_INTL(MSG_FIL_DEP_ADD) - * MSG_INTL(MSG_FIL_DEP_DELETE) - * MSG_INTL(MSG_FIL_DEP_REMOVE) - * MSG_INTL(MSG_FIL_DEP_REMAIN) - * MSG_INTL(MSG_FIL_DEP_ORPHAN) - * MSG_INTL(MSG_FIL_DEP_REINST) + * Establish a binding descriptor format string. */ - switch (type) { - case DBG_DEP_ADD: - str = MSG_FIL_DEP_ADD; - break; - case DBG_DEP_DELETE: - str = MSG_FIL_DEP_DELETE; - break; - case DBG_DEP_REMOVE: - str = MSG_FIL_DEP_REMOVE; - break; - case DBG_DEP_REMAIN: - str = MSG_FIL_DEP_REMAIN; - break; - case DBG_DEP_ORPHAN: - str = MSG_FIL_DEP_ORPHAN; - break; - case DBG_DEP_REINST: - str = MSG_FIL_DEP_REINST; - break; - default: + if (type > DBG_DEP_REINST) return; - } - if ((type == DBG_DEP_ADD) && flags) + str = fmt[type]; + + if (((type == DBG_DEP_ADD) || (type == DBG_DEP_UPDATE)) && flags) group = conv_grpdesc_flags(flags, &grpdesc_flags_buf); else group = MSG_ORIG(MSG_STR_EMPTY); @@ -283,7 +249,6 @@ mode = MSG_ORIG(MSG_MODE_GLOBNODEL); else if (MODE(lmp) & RTLD_GLOBAL) mode = MSG_ORIG(MSG_MODE_GLOB); - else if (MODE(lmp) & RTLD_NODELETE) mode = MSG_ORIG(MSG_MODE_NODEL); else diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/liblddbg/common/liblddbg.msg --- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Mon Sep 17 11:32:50 2007 -0700 @@ -408,6 +408,7 @@ @ MSG_FIL_DEP_ENT " file=%s; depends on:" @ MSG_FIL_DEP_ADD " file=%s; object added %s %s" +@ MSG_FIL_DEP_UPDATE " file=%s; object updated %s %s" @ MSG_FIL_DEP_DELETE " file=%s; object deleting %s" @ MSG_FIL_DEP_REMOVE " file=%s; object removed from handle %s" @ MSG_FIL_DEP_REMAIN " file=%s; object must remain on handle %s" @@ -415,15 +416,15 @@ @ MSG_FIL_DEP_REINST " file=%s; object reinstated %s" @ MSG_FIL_HDL_CREATE "handle=%s; creating:" -@ MSG_FIL_HDL_COLLECT "handle=%s; collected for possible removal %s" -@ MSG_FIL_HDL_RETAIN "handle=%s; externally referenced from %s: handle \ - retained" @ MSG_FIL_HDL_ADD "handle=%s; adding dependent objects:" @ MSG_FIL_HDL_DELETE "handle=%s; inspecting for deletion:" @ MSG_FIL_HDL_ORPHAN "handle=%s; deletion cannot be completed: moving to \ orphan list:" @ MSG_FIL_HDL_REINST "handle=%s; reinstating from orphan list:" +@ MSG_FIL_HDL_COLLECT "handle=%s; collected for possible removal %s" +@ MSG_FIL_HDL_RETAIN "handle=%s; externally referenced from %s: handle \ + retained" @ MSG_FIL_DEL_RESCAN "pending deletions; rescanning orphan list for \ available deletions" diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/packages/common/SUNWonld-README --- a/usr/src/cmd/sgs/packages/common/SUNWonld-README Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README Mon Sep 17 11:32:50 2007 -0700 @@ -1256,3 +1256,6 @@ shared object reference 6595139 various applications should export yy* global variables for libl 6597841 gelf_getdyn() reads one too many dynamic entries +6602294 ps_pbrandname breaks apps linked directly against librtld_db + (link-editor components only) +6603313 dlclose() can fail to unload objects after fix for 6573641 diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/common/_rtld.h --- a/usr/src/cmd/sgs/rtld/common/_rtld.h Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/common/_rtld.h Mon Sep 17 11:32:50 2007 -0700 @@ -552,7 +552,7 @@ extern uint_t expand(char **, size_t *, char **, uint_t, uint_t, Rt_map *); extern Pnode *expand_paths(Rt_map *, const char *, uint_t, uint_t); -extern void free_hdl(Grp_hdl *); +extern void free_hdl(Grp_hdl *, Rt_map *, uint_t); extern void file_notfound(Lm_list *, const char *, Rt_map *, uint_t, Rej_desc *); extern int find_path(Lm_list *, const char *, Rt_map *, uint_t, @@ -567,7 +567,8 @@ extern Lmid_t get_linkmap_id(Lm_list *); extern Pnode *get_next_dir(Pnode **, Rt_map *, uint_t); extern int hdl_add(Grp_hdl *, Rt_map *, uint_t); -extern Grp_hdl *hdl_create(Lm_list *, Rt_map *, Rt_map *, uint_t); +extern Grp_hdl *hdl_create(Lm_list *, Rt_map *, Rt_map *, uint_t, + uint_t, uint_t); extern int hdl_initialize(Grp_hdl *, Rt_map *, int, int); extern int hwcap_check(Rej_desc *, Ehdr *); extern Pnode *hwcap_filtees(Pnode **, Aliste, Lm_cntl *, Dyninfo *, diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/common/analyze.c --- a/usr/src/cmd/sgs/rtld/common/analyze.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/common/analyze.c Mon Sep 17 11:32:50 2007 -0700 @@ -1068,7 +1068,7 @@ /* * If this is an auditor, it will have been opened on a new link-map. - * To prevent multiple occurrances of the same auditor on multiple + * To prevent multiple occurrences of the same auditor on multiple * link-maps, search the head of each link-map list and see if this * object is already loaded as an auditor. */ @@ -1212,7 +1212,7 @@ * silent failure, where no rejection message is created, free * the original name to simplify the life of the caller. For * any other reference that expands to a directory, fall through - * to contruct a meaningful rejection message. + * to construct a meaningful rejection message. */ if ((flags & FLG_RT_HWCAP) && ((status.st_mode & S_IFMT) == S_IFDIR)) { @@ -1717,7 +1717,7 @@ return (lml_rtld.lm_head); /* - * If this isn't a hardware capabilites pathname, which is already a + * If this isn't a hardware capabilities pathname, which is already a * full, duplicated pathname, determine whether the pathname contains * a slash, and if not determine the input filename (for max path * length verification). @@ -1770,7 +1770,7 @@ /* * If the name and resolved pathname differ, duplicate the path - * name once more to provide for genric cleanup by the caller. + * name once more to provide for generic cleanup by the caller. */ if (nfdp->fd_pname && (nfdp->fd_nname != nfdp->fd_pname)) { char *pname; @@ -2015,12 +2015,39 @@ */ if (((FLAGS(nlmp) | flags) & FLG_RT_HANDLE) || (promote && (FLAGS(nlmp) & FLG_RT_ANALYZED))) { - uint_t oflags, hflags = 0; + uint_t oflags, hflags = 0, cdflags; + + /* + * Establish any flags for the handle (Grp_hdl). + * + * . Use of the RTLD_FIRST flag indicates that only the first + * dependency on the handle (the new object) can be used + * to satisfy dlsym() requests. + */ + if (nmode & RTLD_FIRST) + hflags = GPH_FIRST; + /* + * Establish the flags for this callers dependency descriptor + * (Grp_desc). + * + * . The creation of a handle associated a descriptor for the + * new object and descriptor for the parent (caller). + * Typically, the handle is created for dlopen() or for + * filtering. A handle may also be created to promote + * the callers modes (RTLD_NOW) to the new object. In this + * latter case, the handle/descriptor are torn down once + * the mode propagation has occurred. + * + * . Use of the RTLD_PARENT flag indicates that the parent + * can be relocated against. + */ + if (((FLAGS(nlmp) | flags) & FLG_RT_HANDLE) == 0) + cdflags = GPD_PROMOTE; + else + cdflags = GPD_PARENT; if (nmode & RTLD_PARENT) - hflags |= GPH_PARENT; - if (nmode & RTLD_FIRST) - hflags |= GPH_FIRST; + cdflags |= GPD_RELOC; /* * Now that a handle is being created, remove this state from @@ -2030,7 +2057,9 @@ oflags = FLAGS(nlmp); FLAGS(nlmp) &= ~FLG_RT_HANDLE; - if ((ghp = hdl_create(lml, nlmp, clmp, hflags)) == 0) + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); + if ((ghp = hdl_create(lml, nlmp, clmp, hflags, + (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), cdflags)) == 0) return (0); /* @@ -2043,16 +2072,25 @@ *hdl = ghp; /* - * If we were asked to create a handle, we're done. Otherwise, - * remove the handle. The handle was only used to establish this - * objects dependencies and promote any modes, so we don't want - * this handle preventing the objects deletion. Fall through to - * carry out any group processing. + * If we were asked to create a handle, we're done. */ if ((oflags | flags) & FLG_RT_HANDLE) return (1); - free_hdl(ghp); + /* + * If the handle was created to promote modes from the parent + * (caller) to the new object, then this relationship needs to + * be removed to ensure the handle doesn't prevent the new + * objects from being deleted if required. If the parent is + * the only dependency on the handle, then the handle can be + * completely removed. However, the handle may have already + * existed, in which case only the parent descriptor can be + * deleted from the handle, or at least the GPD_PROMOTE flag + * removed from the descriptor. + * + * Fall through to carry out any group processing. + */ + free_hdl(ghp, clmp, GPD_PROMOTE); } /* @@ -2067,7 +2105,7 @@ * Traverse the list of groups our caller is a member of and add this * new link-map to those groups. */ - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_ADD)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); for (ALIST_TRAVERSE(GROUPS(clmp), off, ghpp)) { Aliste off1; Grp_desc *gdp; diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/common/cap.c --- a/usr/src/cmd/sgs/rtld/common/cap.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/common/cap.c Mon Sep 17 11:32:50 2007 -0700 @@ -403,7 +403,7 @@ * association provides sufficient information to tear down the * filter and filtee if necessary. */ - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_ADD)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); if (nlmp && ghp && (hdl_add(ghp, flmp, GPD_FILTER) == 0)) nlmp = 0; diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/common/dlfcns.c --- a/usr/src/cmd/sgs/rtld/common/dlfcns.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c Mon Sep 17 11:32:50 2007 -0700 @@ -135,6 +135,7 @@ Grp_desc *gdp; Aliste off; int found = ALE_CREATE; + uint_t oflags; /* * Make sure this dependency hasn't already been recorded. @@ -170,11 +171,17 @@ return (0); } + oflags = gdp->gd_flags; gdp->gd_flags |= flags; - if (found == ALE_CREATE) - DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_ADD, flags)); - + if (DBG_ENABLED) { + if (found == ALE_CREATE) + DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_ADD, + gdp->gd_flags)); + else if (gdp->gd_flags != oflags) + DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_UPDATE, + gdp->gd_flags)); + } return (found); } @@ -205,10 +212,10 @@ * Create a handle. */ Grp_hdl * -hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t flags) +hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, + uint_t ndflags, uint_t cdflags) { Grp_hdl *ghp = 0, **ghpp; - uint_t hflags; Alist **alpp; Aliste off; @@ -216,29 +223,29 @@ * For dlopen(0) the handle is maintained as part of the link-map list, * otherwise it is associated with the referenced link-map. */ - if (flags & GPH_ZERO) + if (hflags & GPH_ZERO) alpp = &(lml->lm_handle); else alpp = &(HANDLES(nlmp)); /* - * Objects can contain multiple handles depending on the flags supplied. - * Most RTLD flags pertain to the object itself and the bindings that it - * can achieve. Multiple handles for these flags don't make sense. But - * if the flag determines how the handle might be used, then multiple - * handles may exist. Presently this only makes sense for RTLD_FIRST. - * Determine if an appropriate handle already exists. + * Objects can contain multiple handles depending on the handle flags + * supplied. Most RTLD flags pertain to the object itself and the + * bindings that it can achieve. Multiple handles for these flags + * don't make sense. But if the flag determines how the handle might + * be used, then multiple handles may exist. Presently this only makes + * sense for RTLD_FIRST. Determine if an appropriate handle already + * exists. */ - hflags = flags & GPH_FIRST; for (ALIST_TRAVERSE(*alpp, off, ghpp)) { - if (((*ghpp)->gh_flags & GPH_FIRST) == hflags) { + if (((*ghpp)->gh_flags & GPH_FIRST) == (hflags & GPH_FIRST)) { ghp = *ghpp; break; } } if (ghp == 0) { - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_CREATE)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_CREATE)); /* * If this is the first dlopen() request for this handle @@ -263,7 +270,7 @@ FLAGS1(nlmp) |= FL1_RT_USED; ghp->gh_refcnt = 1; - ghp->gh_flags = flags; + ghp->gh_flags = hflags; /* * A dlopen(0) handle is identified by the GPH_ZERO flag, the @@ -273,25 +280,14 @@ * entire link-map list provides for searching all objects with * GLOBAL visibility. */ - if (flags & GPH_ZERO) { + if (hflags & GPH_ZERO) { ghp->gh_ownlmp = lml->lm_head; ghp->gh_ownlml = lml; } else { - uint_t hflags = (GPD_DLSYM | GPD_RELOC); - ghp->gh_ownlmp = nlmp; ghp->gh_ownlml = LIST(nlmp); - /* - * As an optimization, a handle for ld.so.1 itself - * (required for libdl's filtering mechanism) shouldn't - * search any dependencies of ld.so.1. Omitting - * GPD_ADDEPS prevents the addition of any ld.so.1 - * dependencies to this handle. - */ - if ((flags & GPH_LDSO) == 0) - hflags |= GPD_ADDEPS; - if (hdl_add(ghp, nlmp, hflags) == 0) + if (hdl_add(ghp, nlmp, ndflags) == 0) return (0); } } else { @@ -322,7 +318,7 @@ Aliste off; Grp_desc *gdp; - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_REINST)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_REINST)); for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) DBG_CALL(Dbg_file_hdl_action(ghp, gdp->gd_depend, DBG_DEP_REINST, 0)); @@ -331,26 +327,13 @@ } /* - * Keep track of the parent (caller). If this request stems from a - * dlopen(..., RTLD_PARENT) call, then the parent is made available to - * satisfy relocation bindings. Note, that individual, explicit, - * direct bindings can also be made to the parent should this object - * have been built defining PARENT symbol references. Also note that a - * parent doesn't provide symbols to dlsym() requests, so it isn't - * necessary to add the parents dependencies to the handle. - * - * As this object could be opened by different parents, this test is - * carried out every time a handle is requested. + * Keep track of the parent (caller). As this object could be opened + * by different parents, this processing is carried out every time a + * handle is requested. */ - if (clmp) { - if (flags & GPH_PARENT) - flags = (GPD_PARENT | GPD_RELOC); - else - flags = GPD_PARENT; + if (clmp && (hdl_add(ghp, clmp, cdflags) == 0)) + return (0); - if (hdl_add(ghp, clmp, flags) == 0) - return (0); - } return (ghp); } @@ -382,7 +365,7 @@ return (1); } - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_ADD)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) { Rt_map * lmp = gdp->gd_depend; Aliste off1; @@ -616,15 +599,37 @@ */ if (path == 0) { Grp_hdl *ghp; - uint_t hflags = GPH_ZERO; + uint_t hflags = GPH_ZERO, cdflags = GPD_PARENT; int promote = 0; - if (mode & RTLD_PARENT) - hflags |= GPH_PARENT; + /* + * Establish any flags for the handle (Grp_hdl). + * + * . This is a dummy handle (0) that provides for a dynamic + * search of all global objects within the process. + * + * . Use of the RTLD_FIRST flag indicates that only the first + * dependency on the handle (the new object) can be used + * to satisfy dlsym() requests. + */ if (mode & RTLD_FIRST) - hflags |= GPH_FIRST; + hflags |= GPH_FIRST; - if ((ghp = hdl_create(lml, 0, clmp, hflags)) == 0) + /* + * Establish the flags for this callers dependency descriptor + * (Grp_desc). + * + * . The explicit creation of a handle creates a descriptor + * for the new object and the parent (caller), + * + * . Use of the RTLD_PARENT flag indicates that the parent + * can be relocated against. + */ + if (mode & RTLD_PARENT) + cdflags |= GPD_RELOC; + + if ((ghp = hdl_create(lml, 0, clmp, hflags, + (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), cdflags)) == 0) return (0); /* diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/common/elf.c --- a/usr/src/cmd/sgs/rtld/common/elf.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/common/elf.c Mon Sep 17 11:32:50 2007 -0700 @@ -1484,12 +1484,18 @@ if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD)) == 0) { #endif /* - * Create an association between ld.so.1 and - * the filter. + * Create an association between ld.so.1 and the + * filter. As an optimization, a handle for + * ld.so.1 itself (required for the dlopen() + * family filtering mechanism) shouldn't search + * any dependencies of ld.so.1. Omitting + * GPD_ADDEPS prevents the addition of any + * ld.so.1 dependencies to this handle. */ nlmp = lml_rtld.lm_head; if ((ghp = hdl_create(&lml_rtld, nlmp, ilmp, - (GPH_LDSO | GPH_FIRST | GPH_FILTEE))) == 0) + (GPH_LDSO | GPH_FIRST | GPH_FILTEE), + (GPD_DLSYM | GPD_RELOC), GPD_PARENT)) == 0) nlmp = 0; /* @@ -1588,7 +1594,7 @@ * to tear down the filter and filtee if * necessary. */ - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_ADD)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); if (nlmp && ghp && (hdl_add(ghp, ilmp, GPD_FILTER) == 0)) nlmp = 0; diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/common/remove.c --- a/usr/src/cmd/sgs/rtld/common/remove.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/common/remove.c Mon Sep 17 11:32:50 2007 -0700 @@ -788,12 +788,13 @@ * by another user). */ void -free_hdl(Grp_hdl *ghp) +free_hdl(Grp_hdl *ghp, Rt_map *clmp, uint_t cdflags) { + Grp_desc *gdp; + Aliste off; + if (--(ghp->gh_refcnt) == 0) { - Grp_desc *gdp; uintptr_t ndx; - Aliste off; for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) { Rt_map *lmp = gdp->gd_depend; @@ -809,6 +810,25 @@ list_delete(&hdl_list[ndx], ghp); (void) free(ghp); + + } else if (clmp) { + /* + * It's possible that an RTLD_NOW promotion (via GPD_PROMOTE) + * has associated a caller with a handle that is already in use. + * In this case, find the caller and either remove the caller + * from the handle, or if the caller is used for any other + * reason, clear the promotion flag. + */ + for (ALIST_TRAVERSE(ghp->gh_depends, off, gdp)) { + if (gdp->gd_depend != clmp) + continue; + + if (gdp->gd_flags == cdflags) + (void) alist_delete(ghp->gh_depends, 0, &off); + else + gdp->gd_flags &= ~cdflags; + return; + } } } @@ -861,7 +881,8 @@ * Establish a handle, and should anything fail, fall through * to remove the link-map control list. */ - if (((ghp = hdl_create(lml, lmc->lc_head, 0, 0)) == 0) || + if (((ghp = + hdl_create(lml, lmc->lc_head, 0, 0, GPD_ADDEPS, 0)) == 0) || (hdl_initialize(ghp, lmc->lc_head, 0, 0) == 0)) lmc->lc_flags &= ~LMC_FLG_RELOCATING; } else { @@ -877,7 +898,7 @@ if (ghp) { ghp->gh_refcnt = 1; - free_hdl(ghp); + free_hdl(ghp, 0, 0); } return; } @@ -1012,7 +1033,7 @@ return (0); } - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_DELETE)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE)); /* * Traverse the groups we've collected to determine if any filtees are @@ -1243,7 +1264,7 @@ for (ALIST_TRAVERSE(ghalp, off1, ghpp)) { Grp_hdl *ghp = *ghpp; - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_DELETE)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE)); for (ALIST_TRAVERSE(ghp->gh_depends, off2, gdp)) { int flag; @@ -1496,7 +1517,7 @@ (void) list_append(&hdl_list[HDLIST_ORP], ghp); if (DBG_ENABLED) { - DBG_CALL(Dbg_file_hdl_title(DBG_DEP_ORPHAN)); + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ORPHAN)); for (ALIST_TRAVERSE(ghp->gh_depends, off1, gdp)) DBG_CALL(Dbg_file_hdl_action(ghp, gdp->gd_depend, DBG_DEP_ORPHAN, 0)); diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c --- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c Mon Sep 17 11:32:50 2007 -0700 @@ -150,7 +150,6 @@ { MSG_ORIG(MSG_GPH_ZERO), GPH_ZERO, GPH_ZERO }, { MSG_ORIG(MSG_GPH_LDSO), GPH_LDSO, GPH_LDSO }, { MSG_ORIG(MSG_GPH_FIRST), GPH_FIRST, GPH_FIRST }, - { MSG_ORIG(MSG_GPH_PARENT), GPH_PARENT, GPH_PARENT }, { MSG_ORIG(MSG_GPH_FILTEE), GPH_FILTEE, GPH_FILTEE }, { MSG_ORIG(MSG_GPH_INITIAL), GPH_INITIAL, GPH_INITIAL }, { MSG_ORIG(MSG_GPH_NOPENDLAZY), GPH_NOPENDLAZY, GPH_NOPENDLAZY }, @@ -163,6 +162,7 @@ { MSG_ORIG(MSG_GPD_ADDEPS), GPD_ADDEPS, GPD_ADDEPS }, { MSG_ORIG(MSG_GPD_PARENT), GPD_PARENT, GPD_PARENT }, { MSG_ORIG(MSG_GPD_FILTER), GPD_FILTER, GPD_FILTER }, + { MSG_ORIG(MSG_GPD_PROMOTE), GPD_PROMOTE, GPD_PROMOTE }, { MSG_ORIG(MSG_GPD_REMOVE), GPD_REMOVE, GPD_REMOVE }, { NULL, 0, 0} }; diff -r be9489708c48 -r d64dc195fe92 usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg --- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg Mon Sep 17 11:28:46 2007 -0700 +++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg Mon Sep 17 11:32:50 2007 -0700 @@ -134,7 +134,6 @@ @ MSG_GPH_ZERO "ZERO" @ MSG_GPH_LDSO "LD.SO.1" @ MSG_GPH_FIRST "FIRST-ONLY" -@ MSG_GPH_PARENT "PARENT-REQUIRED" @ MSG_GPH_FILTEE "FILTEE" @ MSG_GPH_INITIAL "INITIALIZED" @ MSG_GPH_NOPENDLAZY "NO-PENDING-LAZY-DEPENDENCIES" @@ -145,6 +144,7 @@ @ MSG_GPD_PARENT "PARENT" @ MSG_GPD_FILTER "FILTER" @ MSG_GPD_REMOVE "REMOVAL-CANDIDATE" +@ MSG_GPD_PROMOTE "RTLD_NOW-PROMOTER" @ MSG_LFL_BASELM "BASELM" @ MSG_LFL_RTLDLM "RTLDLM"