usr/src/cmd/sgs/rtld/common/dlfcns.c
changeset 12449 a87750d92895
parent 12029 3202400f09a4
child 12498 12c4df7d2890
--- a/usr/src/cmd/sgs/rtld/common/dlfcns.c	Wed May 19 21:10:39 2010 -0700
+++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c	Wed May 19 22:33:49 2010 -0700
@@ -20,13 +20,10 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
+ *
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -44,7 +41,7 @@
 #include	"_rtld.h"
 #include	"_audit.h"
 #include	"_elf.h"
-#include	"_inline.h"
+#include	"_inline_gen.h"
 #include	"msg.h"
 
 /*
@@ -1184,13 +1181,31 @@
 }
 
 /*
+ * Determine whether a symbol resides in a caller.  This may be a reference,
+ * which is associated with a specific dependency.
+ */
+inline static Sym *
+sym_lookup_in_caller(Rt_map *clmp, Slookup *slp, Sresult *srp, uint_t *binfo)
+{
+	if (THIS_IS_ELF(clmp) && SYMINTP(clmp)(slp, srp, binfo, NULL)) {
+		Sym	*sym = srp->sr_sym;
+
+		slp->sl_rsymndx = (((ulong_t)sym -
+		    (ulong_t)SYMTAB(clmp)) / SYMENT(clmp));
+		slp->sl_rsym = sym;
+		return (sym);
+	}
+	return (NULL);
+}
+
+/*
  * Core dlsym activity.  Selects symbol lookup method from handle.
  */
 static void *
 dlsym_core(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp,
     int *in_nfavl)
 {
-	Sym		*sym = NULL;
+	Sym		*sym;
 	int		ret = 0;
 	Syminfo		*sip;
 	Slookup		sl;
@@ -1215,14 +1230,7 @@
 	SLOOKUP_INIT(sl, name, clmp, clmp, ld_entry_cnt, elf_hash(name),
 	    0, 0, 0, LKUP_SYMNDX);
 	SRESULT_INIT(sr, name);
-
-	if (THIS_IS_ELF(clmp) && SYMINTP(clmp)(&sl, &sr, &binfo, NULL)) {
-		sym = sr.sr_sym;
-
-		sl.sl_rsymndx = (((ulong_t)sym -
-		    (ulong_t)SYMTAB(clmp)) / SYMENT(clmp));
-		sl.sl_rsym = sym;
-	}
+	sym = sym_lookup_in_caller(clmp, &sl, &sr, &binfo);
 
 	SRESULT_INIT(sr, name);
 
@@ -1238,9 +1246,10 @@
 		    DBG_DLSYM_SINGLETON));
 
 		sl.sl_imap = hlmp;
-		sl.sl_flags = LKUP_SPEC;
 		if (handle == RTLD_PROBE)
-			sl.sl_flags |= LKUP_NOFALLBACK;
+			sl.sl_flags = LKUP_NOFALLBACK;
+		else
+			sl.sl_flags = LKUP_SPEC;
 		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else if (handle == RTLD_NEXT) {
@@ -1272,7 +1281,7 @@
 		}
 
 		/*
-		 * If the handle is RTLD_NEXT start searching in the next link
+		 * If the handle is RTLD_NEXT, start searching in the next link
 		 * map from the callers.  Determine permissions from the
 		 * present link map.  Indicate to lookup_sym() that we're on an
 		 * RTLD_NEXT request so that it will use the callers link map to
@@ -1331,7 +1340,7 @@
 		    DBG_DLSYM_PROBE));
 
 		sl.sl_imap = hlmp;
-		sl.sl_flags = (LKUP_SPEC | LKUP_NOFALLBACK);
+		sl.sl_flags = LKUP_NOFALLBACK;
 		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else {
@@ -1731,6 +1740,31 @@
 }
 
 /*
+ * Set a new deferred dependency name.
+ */
+static int
+set_def_need(Lm_list *lml, Dyninfo *dyip, const char *name)
+{
+	/*
+	 * If this dependency has already been established, then this dlinfo()
+	 * call is too late.
+	 */
+	if (dyip->di_info) {
+		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_DEF_DEPLOADED),
+		    dyip->di_name);
+		return (-1);
+	}
+
+	/*
+	 * Assign the new dependency name.
+	 */
+	DBG_CALL(Dbg_file_deferred(lml, dyip->di_name, name));
+	dyip->di_flags |= FLG_DI_DEF_DONE;
+	dyip->di_name = name;
+	return (0);
+}
+
+/*
  * Extract information for a dlopen() handle.
  */
 static int
@@ -1947,7 +1981,7 @@
 			 */
 			(void) strcpy(strs, pdp->pd_pname);
 			path->dls_name = strs;
-			path->dls_flags = pdp->pd_flags;
+			path->dls_flags = (pdp->pd_flags & LA_SER_MASK);
 
 			strs = strs + _size;
 			path++;
@@ -2003,6 +2037,119 @@
 		return (0);
 	}
 
+	/*
+	 * Assign a new dependency name to a deferred dependency.
+	 */
+	if ((request == RTLD_DI_DEFERRED) ||
+	    (request == RTLD_DI_DEFERRED_SYM)) {
+		Dl_definfo_t	*dfip = (Dl_definfo_t *)p;
+		Dyninfo		*dyip;
+		const char	*dname, *rname;
+
+		/*
+		 * Verify the names.
+		 */
+		if ((dfip->dld_refname == NULL) ||
+		    (dfip->dld_depname == NULL)) {
+			eprintf(LIST(clmp), ERR_FATAL,
+			    MSG_INTL(MSG_ARG_ILLNAME));
+			return (-1);
+		}
+
+		dname = dfip->dld_depname;
+		rname = dfip->dld_refname;
+
+		/*
+		 * A deferred dependency can be determined by referencing a
+		 * symbol family member that is associated to the dependency,
+		 * or by looking for the dependency by its name.
+		 */
+		if (request == RTLD_DI_DEFERRED_SYM) {
+			Slookup		sl;
+			Sresult		sr;
+			uint_t		binfo;
+			Syminfo		*sip;
+
+			/*
+			 * Lookup the symbol in the associated object.
+			 */
+			SLOOKUP_INIT(sl, rname, lmp, lmp, ld_entry_cnt,
+			    elf_hash(rname), 0, 0, 0, LKUP_SYMNDX);
+			SRESULT_INIT(sr, rname);
+			if (sym_lookup_in_caller(clmp, &sl, &sr,
+			    &binfo) == NULL) {
+				eprintf(LIST(clmp), ERR_FATAL,
+				    MSG_INTL(MSG_DEF_NOSYMFOUND), rname);
+				return (-1);
+			}
+
+			/*
+			 * Use the symbols index to reference the Syminfo entry
+			 * and thus find the associated dependency.
+			 */
+			if (sl.sl_rsymndx && ((sip = SYMINFO(clmp)) != NULL)) {
+				/* LINTED */
+				sip = (Syminfo *)((char *)sip +
+				    (sl.sl_rsymndx * SYMINENT(lmp)));
+
+				if ((sip->si_flags & SYMINFO_FLG_DEFERRED) &&
+				    (sip->si_boundto < SYMINFO_BT_LOWRESERVE) &&
+				    ((dyip = DYNINFO(lmp)) != NULL)) {
+					dyip += sip->si_boundto;
+
+					if (!(dyip->di_flags & FLG_DI_IGNORE))
+						return (set_def_need(lml,
+						    dyip, dname));
+				}
+			}
+
+			/*
+			 * No deferred symbol found.
+			 */
+			eprintf(LIST(clmp), ERR_FATAL,
+			    MSG_INTL(MSG_DEF_NOSYMFOUND), rname);
+			return (-1);
+
+		} else {
+			Dyn	*dyn;
+
+			/*
+			 * Using the target objects dependency information, find
+			 * the associated deferred dependency.
+			 */
+			for (dyn = DYN(lmp), dyip = DYNINFO(lmp);
+			    !(dyip->di_flags & FLG_DI_IGNORE); dyn++, dyip++) {
+				const char	*oname;
+
+				if ((dyip->di_flags & FLG_DI_DEFERRED) == 0)
+					continue;
+
+				if (strcmp(rname, dyip->di_name) == 0)
+					return (set_def_need(lml, dyip, dname));
+
+				/*
+				 * If this dependency name has been changed by
+				 * a previous dlinfo(), check the original
+				 * dynamic entry string.  The user might be
+				 * attempting to re-change an entry using the
+				 * original name as the reference.
+				 */
+				if ((dyip->di_flags & FLG_DI_DEF_DONE) == 0)
+					continue;
+
+				oname = STRTAB(lmp) + dyn->d_un.d_val;
+				if (strcmp(rname, oname) == 0)
+					return (set_def_need(lml, dyip, dname));
+			}
+
+			/*
+			 * No deferred dependency found.
+			 */
+			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_DEF_NODEPFOUND),
+			    rname);
+			return (-1);
+		}
+	}
 	return (0);
 }
 
@@ -2028,7 +2175,6 @@
 	return (error);
 }
 
-
 /*
  * GNU defined function to iterate through the program headers for all
  * currently loaded dynamic objects. The caller supplies a callback function