changeset 6:9049f50e2cc0

6276905 dlinfo gives inconsistent results (relative vs absolute linkname) PSARC/2005/357 dlinfo(3c) RTLD_DI_ARGSINFO
author rie
date Wed, 15 Jun 2005 08:20:19 -0700
parents 3fb270f22f8d
children 420a1f4ae7e6
files usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/rtld.h usr/src/cmd/sgs/liblddbg/common/files.c usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/rtld/amd64/_setup.c usr/src/cmd/sgs/rtld/common/_rtld.h usr/src/cmd/sgs/rtld/common/a.out.c usr/src/cmd/sgs/rtld/common/dlfcns.c usr/src/cmd/sgs/rtld/common/elf.c usr/src/cmd/sgs/rtld/common/getcwd.c usr/src/cmd/sgs/rtld/common/globals.c usr/src/cmd/sgs/rtld/common/rtld.msg usr/src/cmd/sgs/rtld/common/setup.c usr/src/cmd/sgs/rtld/common/util.c usr/src/cmd/sgs/rtld/i386/_setup.c usr/src/cmd/sgs/rtld/i386/i386_elf.c usr/src/cmd/sgs/rtld/sparc/_setup.c usr/src/cmd/sgs/rtld/sparcv9/_setup.c usr/src/head/dlfcn.h
diffstat 20 files changed, 388 insertions(+), 330 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/include/debug.h	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/include/debug.h	Wed Jun 15 08:20:19 2005 -0700
@@ -318,8 +318,8 @@
 extern	void		Dbg_file_hdl_title(int);
 extern	void		Dbg_file_lazyload(const char *, const char *,
 			    const char *);
-extern	void		Dbg_file_ldso(const char *, ulong_t, ulong_t, ulong_t,
-			    ulong_t);
+extern	void		Dbg_file_ldso(const char *, ulong_t, ulong_t, char **,
+			    auxv_t *);
 extern	void		Dbg_file_mode_promote(const char *, int);
 extern	void		Dbg_file_needed(const char *, const char *);
 extern	void		Dbg_file_nl(void);
--- a/usr/src/cmd/sgs/include/rtld.h	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/include/rtld.h	Wed Jun 15 08:20:19 2005 -0700
@@ -254,6 +254,7 @@
 	Audit_list	*lm_alp;	/* audit list descripter */
 	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 */
 	Word		lm_tflags;	/* transferable flags */
 	int		lm_obj;		/* total number of objs on link-map */
 	int		lm_init;	/* new obj since last init processing */
@@ -278,6 +279,7 @@
 	Elf32_Addr	lm_alp;
 	Elf32_Addr	lm_fpavl;
 	Elf32_Addr	lm_lists;
+	Elf32_Addr	lm_environ;
 	Elf32_Word	lm_tflags;
 	int		lm_obj;
 	int		lm_init;
--- a/usr/src/cmd/sgs/liblddbg/common/files.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/files.c	Wed Jun 15 08:20:19 2005 -0700
@@ -27,6 +27,7 @@
 
 #include	"_synonyms.h"
 
+#include	<sys/auxv.h>
 #include	<string.h>
 #include	<unistd.h>
 #include	<fcntl.h>
@@ -130,8 +131,8 @@
 }
 
 void
-Dbg_file_ldso(const char *name, ulong_t dynamic, ulong_t base, ulong_t envp,
-    ulong_t auxv)
+Dbg_file_ldso(const char *name, ulong_t dynamic, ulong_t base, char **envp,
+    auxv_t *auxv)
 {
 	if (DBG_NOTCLASS(DBG_FILES))
 		return;
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Wed Jun 15 08:20:19 2005 -0700
@@ -30,6 +30,7 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <sys/types.h>
+#include <sys/auxv.h>
 #include <gelf.h>
 #include "debug.h"
 
@@ -99,8 +100,8 @@
 void Dbg_file_handle64(Grp_hdl *, Rt_map *, int);
 void Dbg_file_lazyload(const char *, const char *, const char *);
 void Dbg_file_lazyload64(const char *, const char *, const char *);
-void Dbg_file_ldso(const char *, ulong_t, ulong_t, ulong_t, ulong_t);
-void Dbg_file_ldso64(const char *, ulong_t, ulong_t, ulong_t, ulong_t);
+void Dbg_file_ldso(const char *, ulong_t, ulong_t, char **, auxv_t *);
+void Dbg_file_ldso64(const char *, ulong_t, ulong_t, char **, auxv_t *);
 void Dbg_file_mode_promote(const char *, int);
 void Dbg_file_needed(const char *, const char *);
 void Dbg_file_needed64(const char *, const char *);
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Wed Jun 15 08:20:19 2005 -0700
@@ -1475,3 +1475,5 @@
 --------------------------------------------------------------------------------
 6283601 The usr/src/cmd/sgs/packages/common/copyright contains old information
 	legally problematic
+6276905 dlinfo gives inconsistent results (relative vs absolute linkname) (D)
+	PSARC/2005/357 dlinfo(3c) RTLD_DI_ARGSINFO
--- a/usr/src/cmd/sgs/rtld/amd64/_setup.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/amd64/_setup.c	Wed Jun 15 08:20:19 2005 -0700
@@ -220,10 +220,10 @@
 	/*
 	 * Continue with generic startup processing.
 	 */
-	if ((lmp = setup((unsigned long)_envp, (unsigned long)_auxv, _flags,
-	    _platform, _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base,
-	    fd, phdr, _execname, _argv, dz_fd, uid, euid, gid, egid,
-	    NULL, auxflags, hwcap_1)) == NULL) {
+	if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
+	    _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base, fd, phdr,
+	    _execname, _argv, dz_fd, uid, euid, gid, egid, NULL, auxflags,
+	    hwcap_1)) == NULL) {
 		rtldexit(&lml_main, 1);
 	}
 
--- a/usr/src/cmd/sgs/rtld/common/_rtld.h	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/_rtld.h	Wed Jun 15 08:20:19 2005 -0700
@@ -410,11 +410,11 @@
 
 extern int		dyn_plt_ent_size; /* Size of dynamic plt's */
 extern ulong_t		at_flags;	/* machine specific file flags */
-extern const char	*pr_name;	/* file name of executing process */
+extern const char	*procname;	/* file name of executing process */
 extern Rtld_db_priv	r_debug;	/* debugging information */
 extern char		*lasterr;	/* string describing last error */
 extern Interp		*interp;	/* ELF executable interpreter info */
-extern const char	*rt_name;	/* name of the dynamic linker */
+extern const char	*rtldname;	/* name of the dynamic linker */
 extern List		hdl_list[];	/* dlopen() handle list */
 extern size_t		syspagsz;	/* system page size */
 extern char		*platform; 	/* platform name */
@@ -478,6 +478,9 @@
 extern const char	*profile_out;	/* profile output file */
 extern const char	*profile_lib;	/* audit library to perform profile */
 
+extern Dl_argsinfo	argsinfo;	/* process argument, environment and */
+					/*	auxv information */
+
 extern const char	*err_strs[];	/* diagnostic error string headers */
 extern const char	*nosym_str;	/* MSG_GEN_NOSYM message cache */
 
@@ -613,10 +616,11 @@
 extern void		rtld_db_preinit(void);
 extern void		rtld_db_postinit(void);
 extern void		rtldexit(Lm_list *, int);
-extern int		rtld_getopt(char **, Word *, Word *, int);
+extern int		rtld_getopt(char **, char ***, auxv_t **, Word *,
+			    Word *, int);
 extern void		security(uid_t, uid_t, gid_t, gid_t, int);
 extern void		set_environ(Lm_list *);
-extern Rt_map		*setup(ulong_t, ulong_t, Word, char *, int, char *,
+extern Rt_map		*setup(char **, auxv_t *, Word, char *, int, char *,
 			    Dyn *, ulong_t, ulong_t, int fd, Phdr *, char *,
 			    char **, int, uid_t, uid_t, gid_t, gid_t, void *,
 			    int, uint_t);
--- a/usr/src/cmd/sgs/rtld/common/a.out.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/a.out.c	Wed Jun 15 08:20:19 2005 -0700
@@ -504,20 +504,11 @@
 	caddr_t		addr;		/* mmap result temporary */
 	struct link_dynamic *ld;	/* dynamic pointer of object mapped */
 	size_t		size;		/* size of object */
-	const char	*name;		/* actual name stored for pathname */
 	Rt_map		*lmp;		/* link map created */
 	int		err;
 	struct nlist	*nl;
 
 	/*
-	 * Is object the executable?
-	 */
-	if (pname == (char *)0)
-		name = pr_name;
-	else
-		name = pname;
-
-	/*
 	 * Map text and allocate enough address space to fit the whole
 	 * library.  Note that we map enough to catch the first symbol
 	 * in the symbol table and thereby avoid an "lseek" & "read"
@@ -529,7 +520,7 @@
 	if ((addr = mmap(0, size, (PROT_READ | PROT_EXEC), MAP_PRIVATE,
 	    fd, 0)) == MAP_FAILED) {
 		err = errno;
-		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), name,
+		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname,
 		    strerror(err));
 		return (0);
 	}
@@ -558,7 +549,7 @@
 	    (int)exec->a_data, (PROT_READ | PROT_WRITE | PROT_EXEC),
 	    (MAP_FIXED | MAP_PRIVATE), fd, (off_t)exec->a_text) == MAP_FAILED) {
 		err = errno;
-		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), name,
+		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname,
 		    strerror(err));
 		return (0);
 	}
@@ -601,8 +592,8 @@
 	Rt_map	*lmp;
 	caddr_t offset;
 
-	DBG_CALL(Dbg_file_aout((pname ? pname : pr_name), (ulong_t)ld,
-	    (ulong_t)addr, (ulong_t)size));
+	DBG_CALL(Dbg_file_aout(pname, (ulong_t)ld, (ulong_t)addr,
+	    (ulong_t)size));
 
 	/*
 	 * Allocate space for the link-map and private a.out information.  Once
@@ -637,7 +628,7 @@
 	/*
 	 * Specific settings for a.out format.
 	 */
-	if (pname == 0) {
+	if (lml->lm_head == 0) {
 		offset = (caddr_t)MAIN_BASE;
 		FLAGS(lmp) |= FLG_RT_FIXED;
 	} else
--- a/usr/src/cmd/sgs/rtld/common/dlfcns.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c	Wed Jun 15 08:20:19 2005 -0700
@@ -1509,9 +1509,8 @@
 	return ((Lmid_t)lml);
 }
 
-
 /*
- * Extract information for a dlopen() handle.  The valid request are:
+ * Extract information for a dlopen() handle.
  */
 static int
 dlinfo_core(void *handle, int request, void *p, Rt_map *clmp)
@@ -1604,6 +1603,22 @@
 	}
 
 	/*
+	 * Obtain the process arguments, environment and auxv.  Note, as the
+	 * environment can be modified by the user (putenv(3c)), reinitialize
+	 * the environment pointer on each request.
+	 */
+	if (request == RTLD_DI_ARGSINFO) {
+		Dl_argsinfo	*aip = (Dl_argsinfo *)p;
+		Lm_list		*lml = LIST(lmp);
+
+		*aip = argsinfo;
+		if (lml->lm_flags & LML_FLG_ENVIRON)
+			aip->dla_envp = *(lml->lm_environ);
+
+		return (0);
+	}
+
+	/*
 	 * Return Lmid_t of the Link-Map list that the specified object is
 	 * loaded on.
 	 */
@@ -1708,17 +1723,13 @@
 	 * Basically return the dirname(1) of the objects fullpath.
 	 */
 	if (request == RTLD_DI_ORIGIN) {
-		char	*str;
-
-		if ((str = strrchr(PATHNAME(lmp), '/')) != 0) {
-			size_t	len = str - PATHNAME(lmp);
+		char	*str = (char *)p;
 
-			(void) strncpy((char *)p, PATHNAME(lmp), len);
-			str = (char *)p + len;
-		} else {
-			str = (char *)p;
-			*str++ = '.';
-		}
+		if (DIRSZ(lmp) == 0)
+			(void) fullpath(lmp, 0);
+
+		(void) strncpy(str, ORIGNAME(lmp), DIRSZ(lmp));
+		str += DIRSZ(lmp);
 		*str = '\0';
 
 		return (0);
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Wed Jun 15 08:20:19 2005 -0700
@@ -740,8 +740,7 @@
 
 	if (ioctl(pfd, PIOCNMAP, (void *)&num) == -1) {
 		err = errno;
-		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_PROC), pr_name,
-		    strerror(err));
+		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_PROC), name, strerror(err));
 		return (1);
 	}
 
@@ -750,8 +749,7 @@
 
 	if (ioctl(pfd, PIOCMAP, (void *)maps) == -1) {
 		err = errno;
-		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_PROC), pr_name,
-		    strerror(err));
+		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_PROC), name, strerror(err));
 		free(maps);
 		return (1);
 	}
@@ -2416,7 +2414,7 @@
 				remove_so(0, lmp);
 				return (0);
 			}
-			if (NAME(lmp)) {
+			if (lml_main.lm_head) {
 				if (audit_setup(lmp, AUDITORS(lmp)) == 0) {
 					remove_so(0, lmp);
 					return (0);
@@ -2491,21 +2489,12 @@
 	Rt_map		*lmp;		/* link map created */
 	caddr_t		paddr;		/* start of padded image */
 	Off		plen;		/* size of image including padding */
-	const char	*name;
 	Half		etype;
 	int		fixed;
 	Mmap		*mmaps;
 	uint_t		mmapcnt = 0;
 	Xword		align = 0;
 
-	/*
-	 * Establish the objects name.
-	 */
-	if (pname == (char *)0)
-		name = pr_name;
-	else
-		name = pname;
-
 	/* LINTED */
 	ehdr = (Ehdr *)fmap->fm_maddr;
 
@@ -2513,7 +2502,7 @@
 	 * If this a relocatable object then special processing is required.
 	 */
 	if ((etype = ehdr->e_type) == ET_REL)
-		return (elf_obj_file(lml, lmco, name, fd));
+		return (elf_obj_file(lml, lmco, pname, fd));
 
 	/*
 	 * If this isn't a dynamic executable or shared object we can't process
@@ -2524,7 +2513,7 @@
 	else if (etype == ET_DYN)
 		fixed = 0;
 	else {
-		eprintf(ERR_ELF, MSG_INTL(MSG_GEN_BADTYPE), name,
+		eprintf(ERR_ELF, MSG_INTL(MSG_GEN_BADTYPE), pname,
 		    conv_etype_str(etype));
 		return (0);
 	}
@@ -2536,7 +2525,7 @@
 	size = (size_t)((char *)ehdr->e_phoff +
 		(ehdr->e_phnum * ehdr->e_phentsize));
 	if (size > fmap->fm_fsize) {
-		eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_CORTRUNC), name);
+		eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_CORTRUNC), pname);
 		return (0);
 	}
 	if (size > fmap->fm_msize) {
@@ -2544,7 +2533,7 @@
 		if ((fmap->fm_maddr = mmap(fmap->fm_maddr, size, PROT_READ,
 		    fmap->fm_mflags, fd, 0)) == MAP_FAILED) {
 			int	err = errno;
-			eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), name,
+			eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname,
 			    strerror(err));
 			return (0);
 		}
@@ -2573,7 +2562,7 @@
 			/* LINTED argument lph is initialized in first pass */
 			} else if (pptr->p_vaddr <= lph->p_vaddr) {
 				eprintf(ERR_ELF, MSG_INTL(MSG_GEN_INVPRGHDR),
-				    name);
+				    pname);
 				return (0);
 			}
 
@@ -2611,7 +2600,7 @@
 	 * specified file and memory size.
 	 */
 	if ((fph == 0) || (lmph == 0) || (lfph == 0)) {
-		eprintf(ERR_ELF, MSG_INTL(MSG_GEN_NOLOADSEG), name);
+		eprintf(ERR_ELF, MSG_INTL(MSG_GEN_NOLOADSEG), pname);
 		return (0);
 	}
 
@@ -2621,7 +2610,7 @@
 	 * bus errors if we're given a truncated file).
 	 */
 	if (fmap->fm_fsize < ((size_t)lfph->p_offset + lfph->p_filesz)) {
-		eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_CORTRUNC), name);
+		eprintf(ERR_FATAL, MSG_INTL(MSG_GEN_CORTRUNC), pname);
 		return (0);
 	}
 
@@ -2636,7 +2625,7 @@
 	 * Determine if an existing mapping is acceptable.
 	 */
 	if (interp && (lml->lm_flags & LML_FLG_BASELM) &&
-	    (strcmp(name, interp->i_name) == 0)) {
+	    (strcmp(pname, interp->i_name) == 0)) {
 		/*
 		 * If this is the interpreter then it has already been mapped
 		 * and we have the address so don't map it again.  Note that
@@ -2707,7 +2696,7 @@
 		/*
 		 * Map the file.
 		 */
-		if (!(faddr = elf_map_it(name, memsize, ehdr, fph, lph,
+		if (!(faddr = elf_map_it(pname, memsize, ehdr, fph, lph,
 		    &phdr, &paddr, &plen, fixed, fd, align, mmaps, &mmapcnt)))
 			return (0);
 	}
--- a/usr/src/cmd/sgs/rtld/common/getcwd.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/getcwd.c	Wed Jun 15 08:20:19 2005 -0700
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -224,6 +224,13 @@
 /*
  * Take the given link-map file/pathname and prepend the current working
  * directory.
+ *
+ * When $ORIGIN was first introduced, the expansion of a relative pathname was
+ * deferred until it was required.  However now we insure a full pathname is
+ * always created - things like the analyzer wish to rely on librtld_db
+ * returning a full path.  The overhead of this is perceived to be low,
+ * providing the associated libc version of getcwd is available (see 4336878).
+ * This getcwd() was ported back to Solaris 8.1.
  */
 size_t
 fullpath(Rt_map *lmp, const char *rpath)
--- a/usr/src/cmd/sgs/rtld/common/globals.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/globals.c	Wed Jun 15 08:20:19 2005 -0700
@@ -24,7 +24,7 @@
  *	  All Rights Reserved
  *
  *
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -99,8 +99,9 @@
 /*
  * Various other global data.
  */
-const char	*pr_name;
-const char	*rt_name;		/* the run time linkers name */
+const char	*procname = (const char *)0;
+const char	*rtldname = MSG_ORIG(MSG_FIL_RTLD);
+
 char		*lasterr = (char *)0;	/* string describing last error */
 					/*	cleared by each dlerror() */
 Interp		*interp = 0;		/* ELF interpreter info */
@@ -154,6 +155,9 @@
 		0
 };
 
+Dl_argsinfo	argsinfo = { 0 };	/* process argument, environment and */
+					/*	auxv information. */
+
 /*
  * Frequently used messages are cached here to reduce _dgettext() overhead and
  * also provide for resetting should the locale change (see _ld_libc()).
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg	Wed Jun 15 08:20:19 2005 -0700
@@ -32,7 +32,7 @@
 
 # Usage error
 @ MSG_USG_BADOPT	"usage: ld.so.1 [-e option,...] \
-			 <dynamic object> [exec args ...]"
+			 dynamic-object [object args,...]"
 
 # Message formatting error.
 @ MSG_EMG_BUFOVRFLW	"ld.so.1: internal: message buffer overflow"
--- a/usr/src/cmd/sgs/rtld/common/setup.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/setup.c	Wed Jun 15 08:20:19 2005 -0700
@@ -164,29 +164,109 @@
 }
 
 Rt_map *
-setup(ulong_t envp, ulong_t _auxv, Word _flags, char *_platform, int _syspagsz,
-    char *_rt_name, Dyn *dyn_ptr, ulong_t ld_base, ulong_t interp_base, int fd,
-    Phdr *phdr, char *_execname, char **_argv, int dz_fd, uid_t uid, uid_t euid,
-    gid_t gid, gid_t egid, void *aoutdyn, int auxflags, uint_t hwcap_1)
+setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz,
+    char *_rtldname, Dyn *dyn_ptr, ulong_t ld_base, ulong_t interp_base, int fd,
+    Phdr *phdr, char *execname, char **argv, int dz_fd, uid_t uid,
+    uid_t euid, gid_t gid, gid_t egid, void *aoutdyn, int auxflags,
+    uint_t hwcap_1)
 {
 	Rt_map		*rlmp, *mlmp, **tobj = 0;
-	ulong_t		etext;
 	Ehdr		*ehdr;
 	struct stat	status;
-	int		features = 0, _name, i, ldsoexec = 0;
+	int		features = 0, ldsoexec = 0;
 	size_t		eaddr, esize;
-	char		*c;
+	char		*str, *argvname;
 	Mmap		*mmaps;
 
 	/*
-	 * Now that ld.so has relocated itself, initialize any global variables.
-	 * Initialize our own 'environ' so as to establish an address suitable
-	 * for libc's hardware mul/div magic (libc/sparc/crt/hwmuldiv.o).
+	 * Now that ld.so has relocated itself, initialize our own 'environ' so
+	 * as to establish an address suitable for libc's hardware mul/div
+	 * magic (libc/sparc/crt/hwmuldiv.o).
+	 */
+	_environ = (char **)((ulong_t)auxv - sizeof (char *));
+	_init();
+	_environ = envp;
+
+	/*
+	 * Far the most common application execution revolves around appending
+	 * the application name to the users PATH definition, thus a full name
+	 * is passed to exec() which will in turn be returned via
+	 * AT_SUN_EXECNAME.  Applications may also be invoked from the current
+	 * working directory, or via a relative name.
+	 *
+	 * Determine whether the kernel has supplied a AT_SUN_EXECNAME aux
+	 * vector.  This vector points to the full pathname, on the stack, of
+	 * the object that started the process.  If this is null, then
+	 * AT_SUN_EXECNAME isn't supported (if the pathname exceeded the system
+	 * limit (PATH_MAX) the exec would have failed).  This flag is used to
+	 * determine whether we can call resolvepath().
+	 */
+	if (execname)
+		rtld_flags |= RT_FL_EXECNAME;
+
+	/*
+	 * Determine how ld.so.1 has been executed.
 	 */
-	_environ = (char **)((ulong_t)_auxv - sizeof (char *));
-	_init();
-	_environ = (char **)envp;
+	if ((fd == -1) && (phdr == 0)) {
+		/*
+		 * If we received neither the AT_EXECFD nor the AT_PHDR aux
+		 * vector, ld.so.1 must have been invoked directly from the
+		 * command line.
+		 */
+		ldsoexec = 1;
 
+		/*
+		 * AT_SUN_EXECNAME provides the most precise name, if it is
+		 * available, otherwise fall back to argv[0].  At this time,
+		 * there is no process name.
+		 */
+		if (execname)
+			rtldname = execname;
+		else if (argv[0])
+			rtldname = argv[0];
+		else
+			rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN);
+	} else {
+		/*
+		 * Otherwise, we have a standard process.  AT_SUN_EXECNAME
+		 * provides the most precise name, if it is available,
+		 * otherwise fall back to argv[0].  Provided the application
+		 * is already mapped, the process is the application, so
+		 * simplify the application name for use in any diagnostics.
+		 */
+		if (execname)
+			argvname = execname;
+		else if (argv[0])
+			argvname = execname = argv[0];
+		else
+			argvname = execname = (char *)MSG_INTL(MSG_STR_UNKNOWN);
+
+		if (fd == -1) {
+			if ((str = strrchr(argvname, '/')) != 0)
+				procname = ++str;
+			else
+				procname = argvname;
+		}
+
+		/*
+		 * At this point, we don't know the runtime linkers full path
+		 * name.  The _rtldname passed to us is the SONAME of the
+		 * runtime linker, which is typically /lib/ld.so.1 no matter
+		 * what the full path is.   Use this for now, we'll reset the
+		 * runtime linkers name once the application is analyzed.
+		 */
+		if (_rtldname) {
+			if ((str = strrchr(_rtldname, '/')) != 0)
+				rtldname = ++str;
+			else
+				rtldname = _rtldname;
+		} else
+			rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN);
+	}
+
+	/*
+	 * Initialize any global variables.
+	 */
 	at_flags = _flags;
 	if (dz_fd != FD_UNAVAIL)
 		dz_init(dz_fd);
@@ -243,7 +323,6 @@
 		hwcap = (ulong_t)hwcap_1;
 	}
 #endif
-
 	/*
 	 * Look for environment strings (allows things like LD_NOAUDIT to be
 	 * established, although debugging isn't enabled until later).
@@ -268,84 +347,57 @@
 	mmaps[1].m_perm = (PROT_READ | PROT_WRITE | PROT_EXEC);
 
 	/*
-	 * Create a link map structure for ld.so.  We assign the NAME() after
-	 * link-map creation to avoid fullpath() processing within elf_new_lm().
-	 * This is carried out later when the true interpretor path (as defined
-	 * within the application) is known.
+	 * Create a link map structure for ld.so.1.
 	 */
-	if ((rlmp = elf_new_lm(&lml_rtld, 0, 0, dyn_ptr, ld_base,
+	if ((rlmp = elf_new_lm(&lml_rtld, _rtldname, rtldname, dyn_ptr, ld_base,
 	    (ulong_t)&_etext, ALO_DATA, (ulong_t)(eaddr - ld_base), 0, ld_base,
 	    (ulong_t)(eaddr - ld_base), mmaps, 2)) == 0) {
 		return (0);
 	}
-	NAME(rlmp) = _rt_name;
+
 	MODE(rlmp) |= (RTLD_LAZY | RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD);
 	FLAGS(rlmp) |= (FLG_RT_ANALYZED | FLG_RT_RELOCED | FLG_RT_INITDONE |
 		FLG_RT_INITCLCT | FLG_RT_FINICLCT | FLG_RT_MODESET);
+
+	/*
+	 * Initialize the runtime linkers information.
+	 */
+	interp = &_interp;
+	interp->i_name = NAME(rlmp);
+	interp->i_faddr = (caddr_t)ADDR(rlmp);
 	ldso_plt_init(rlmp);
 
 	/*
-	 * If we received neither the AT_EXECFD nor the AT_PHDR aux vector,
-	 * ld.so.1 must have been invoked directly from the command line.  In
-	 * this case examine argv to determine what file to execute.
+	 * If ld.so.1 has been invoked directly, process its arguments.
 	 */
-	if ((fd == -1) && (!phdr)) {
+	if (ldsoexec) {
 		/*
-		 * Set pr_name now to print error messages if required. It will
-		 * be reset below if an executable is found.
+		 * Process any arguments that are specific to ld.so.1, and
+		 * reorganize the process stack to effectively remove ld.so.1
+		 * from it.  Reinitialize the environment pointer, as this may
+		 * have been shifted after skipping ld.so.1's arguments.
 		 */
-		rt_name = pr_name = _argv[0];
-		if (rtld_getopt(_argv, &(lml_main.lm_flags),
-		    &(lml_main.lm_tflags), (aoutdyn != 0)) == 1)
+		if (rtld_getopt(argv, &envp, &auxv, &(lml_main.lm_flags),
+		    &(lml_main.lm_tflags), (aoutdyn != 0)) == 1) {
+			eprintf(ERR_NONE, MSG_INTL(MSG_USG_BADOPT));
 			return (0);
-		if ((fd = open(_argv[0], O_RDONLY)) == -1) {
+		}
+		_environ = envp;
+
+		/*
+		 * Open the object that ld.so.1 is to execute.
+		 */
+		argvname = execname = argv[0];
+
+		if ((fd = open(argvname, O_RDONLY)) == -1) {
 			int	err = errno;
-			eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), _argv[0],
+			eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), argvname,
 			    strerror(err));
 			return (0);
 		}
-		NAME(rlmp) = _execname;
-		interp = &_interp;
-		interp->i_name = NAME(rlmp);
-		interp->i_faddr = (caddr_t)ADDR(rlmp);
-		ldsoexec = 1;
 	}
 
 	/*
-	 * Duplicate the runtime linkers name so that it is available in a core
-	 * file.
-	 */
-	if ((NAME(rlmp) = strdup(NAME(rlmp))) == 0)
-		return (0);
-
-	/*
-	 * Get the filename of the rtld for use in any diagnostics (but
-	 * save the full name in the link map for future comparisons)
-	 */
-	rt_name = c = NAME(rlmp);
-	while (*c) {
-		if (*c++ == '/')
-			rt_name = c;
-	}
-
-	/*
-	 * Establish the applications name.  Note, if ld.so.1 was executed with
-	 * the application as its argument, argv[0] will now reflect the
-	 * application name.
-	 */
-	if (_argv[0]) {
-		/*
-		 * Some troublesome programs will change the value of argv[0].
-		 * Dupping this string protects ourselves from such programs.
-		 */
-		if ((pr_name = (const char *)strdup(_argv[0])) == 0)
-			return (0);
-	} else
-		pr_name = (const char *)MSG_INTL(MSG_STR_UNKNOWN);
-
-	_name = 0;
-
-	/*
 	 * Map in the file, if exec has not already done so.  If it has,
 	 * simply create a new link map structure for the executable.
 	 */
@@ -357,19 +409,27 @@
 		 * Find out what type of object we have.
 		 */
 		(void) fstat(fd, &status);
-		if ((ftp = are_u_this(&rej, fd, &status, pr_name)) == 0) {
+		if ((ftp = are_u_this(&rej, fd, &status, argvname)) == 0) {
 			eprintf(ERR_FATAL, MSG_INTL(err_reject[rej.rej_type]),
-			    pr_name, conv_reject_str(&rej));
+			    argvname, conv_reject_str(&rej));
 			return (0);
 		}
 
 		/*
 		 * Map in object.
 		 */
-		mlmp = (ftp->fct_map_so)(&lml_main, ALO_DATA, 0, pr_name, fd);
-		if (mlmp == 0)
+		if ((mlmp = (ftp->fct_map_so)(&lml_main, ALO_DATA, execname,
+		    argvname, fd)) == 0)
 			return (0);
 
+		/*
+		 * We now have a process name for error diagnostics.
+		 */
+		if ((str = strrchr(argvname, '/')) != 0)
+			procname = ++str;
+		else
+			procname = argvname;
+
 		if (ldsoexec) {
 			Addr	brkbase = 0;
 
@@ -384,6 +444,7 @@
 
 			if ((FCT(mlmp) == &elf_fct) &&
 			    (ehdr->e_type == ET_EXEC)) {
+				int	i;
 				Phdr *	_phdr = (Phdr *)((uintptr_t)ADDR(mlmp) +
 					ehdr->e_phoff);
 
@@ -405,13 +466,13 @@
 			if (_brk_unlocked((void *)brkbase) == -1) {
 				int	err = errno;
 				eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_BRK),
-				    pr_name, strerror(err));
+				    argvname, strerror(err));
 			}
 		}
 
 		/*
-		 * Object has now been mmaped in, we no longer
-		 * need the file descriptor.
+		 * The object has now been mmaped, we no longer need the file
+		 * descriptor.
 		 */
 		(void) close(fd);
 
@@ -424,10 +485,9 @@
 		 */
 		if (aoutdyn) {
 #ifdef A_OUT
-			if ((mlmp = aout_new_lm(&lml_main, 0, 0, aoutdyn, 0, 0,
-			    ALO_DATA)) == 0) {
+			if ((mlmp = aout_new_lm(&lml_main, execname, argvname,
+			    aoutdyn, 0, 0, ALO_DATA)) == 0)
 				return (0);
-			}
 
 			/*
 			 * Set the memory size.  Note, we only know the end of
@@ -453,23 +513,21 @@
 			 * Make sure no-direct bindings are in effect.
 			 */
 			lml_main.lm_tflags |= LML_TFLG_NODIRECT;
-
 #else
 			eprintf(ERR_FATAL, MSG_INTL(MSG_ERR_REJ_UNKFILE),
-			    pr_name);
+			    argvname);
 			return (0);
 #endif
 		} else if (phdr) {
 			Phdr		*pptr, *firstptr = 0, *lastptr;
-			Phdr		*tlsphdr = 0;
-			Phdr		*unwindphdr = 0;
+			Phdr		*tlsphdr = 0, *unwindphdr = 0;
 			Dyn		*dyn = 0;
 			Cap		*cap = 0;
-			Off		i_offset;
+			Off		i_offset = 0;
 			Addr		base = 0;
-			char		*name = 0;
-			ulong_t		memsize, phsize, entry;
+			ulong_t		memsize, phsize, entry, etext;
 			uint_t		mmapcnt = 0;
+			int		i;
 
 			/*
 			 * Using the executables phdr address determine the base
@@ -488,11 +546,8 @@
 			 */
 			ehdr = (Ehdr *)((Addr)phdr - phdr->p_offset);
 			phsize = ehdr->e_phentsize;
-			if (ehdr->e_type == ET_DYN) {
+			if (ehdr->e_type == ET_DYN)
 				base = (Addr)ehdr;
-				name = (char *)pr_name;
-				_name = 1;
-			}
 
 			/*
 			 * Allocate a mapping array to retain mapped segment
@@ -507,7 +562,6 @@
 			 */
 			for (i = 0, pptr = phdr; i < ehdr->e_phnum; i++) {
 				if (pptr->p_type == PT_INTERP) {
-					interp = &_interp;
 					i_offset = pptr->p_offset;
 					interp->i_faddr =
 					    (caddr_t)interp_base;
@@ -520,13 +574,14 @@
 					if (!firstptr)
 						firstptr = pptr;
 					lastptr = pptr;
-					if (!interp->i_name && pptr->p_filesz &&
+					if (i_offset && pptr->p_filesz &&
 					    (i_offset >= pptr->p_offset) &&
 					    (i_offset <=
 					    (pptr->p_memsz + pptr->p_offset))) {
 						interp->i_name = (char *)
 						    pptr->p_vaddr + i_offset -
 						    pptr->p_offset + base;
+						i_offset = 0;
 					}
 					if ((pptr->p_flags &
 					    (PF_R | PF_W)) == PF_R)
@@ -571,8 +626,8 @@
 			if (ehdr->e_type == ET_DYN)
 				entry += (ulong_t)ehdr;
 
-			if ((mlmp = elf_new_lm(&lml_main, name, 0, dyn,
-			    (Addr)ehdr, etext, ALO_DATA, memsize, entry,
+			if ((mlmp = elf_new_lm(&lml_main, execname, argvname,
+			    dyn, (Addr)ehdr, etext, ALO_DATA, memsize, entry,
 			    (ulong_t)ehdr, memsize, mmaps, mmapcnt)) == 0) {
 				return (0);
 			}
@@ -588,53 +643,47 @@
 	}
 
 	/*
-	 * Determine whether the kernel has supplied a AT_SUN_EXECNAME aux
-	 * vector.  This vector points to the full pathname, on the stack, of
-	 * the object that started the process.  If this is null, then
-	 * AT_SUN_EXECNAME isn't supported (if the pathname exceeded the system
-	 * limit (PATH_MAX) the exec would have failed).
+	 * Establish the interpretors name as that defined within the initial
+	 * object (executable).  This provides for ORIGIN processing of ld.so.1
+	 * dependencies.
 	 */
-	if (_execname)
-		rtld_flags |= RT_FL_EXECNAME;
+	if (ldsoexec == 0) {
+		size_t	len = strlen(interp->i_name);
+		(void) expand(&interp->i_name, &len, 0, 0,
+		    (PN_TKN_ISALIST | PN_TKN_HWCAP), rlmp);
+	}
+	PATHNAME(rlmp) = interp->i_name;
+
+	if (FLAGS1(rlmp) & FL1_RT_RELATIVE)
+		(void) fullpath(rlmp, 0);
+	else
+		ORIGNAME(rlmp) = PATHNAME(rlmp) = NAME(rlmp);
 
 	/*
-	 * Having mapped the executable in and created its link map, initialize
-	 * the name and flags entries as necessary.
-	 *
-	 * Note that any object that starts the process is identified as `main',
-	 * even shared objects.  This assumes that the starting object will call
-	 * .init and .fini from its own crt use (this is a pretty valid
-	 * assumption as the crts also provide the necessary entry point).
-	 * However, newer objects may contain .initarray or .finiarray which
-	 * the runtime linker must execute, and which require bindings to be
-	 * established to main for proper initarray/finiarray ordering.
+	 * Having established the true runtime linkers name, simplify the name
+	 * for error diagnostics.
 	 */
-	if (_name == 0) {
-		/*
-		 * If the argv[0] name is a full path, and an AT_SUN_EXECNAME
-		 * exists, and we haven't executed ld.so.1 directly, then use
-		 * this name for diagnostics.  Various commands use isaexec(3C)
-		 * to execute their 64-bit counterparts, however, the 64-bit
-		 * application simply obtains its argv[] from the parent, and
-		 * thus will contain the 32-bit application name.
-		 */
-		if ((*pr_name == '/') && _execname && (ldsoexec == 0))
-			pr_name = _execname;
-		NAME(mlmp) = (char *)pr_name;
-	}
+	if ((str = strrchr(PATHNAME(rlmp), '/')) != 0)
+		rtldname = ++str;
+	else
+		rtldname = PATHNAME(rlmp);
 
 	/*
-	 * Setup the PATHNAME()/ORIGNAME() for the main primary object and
-	 * for ld.so.1.  If we didn't receive a AT_SUN_EXECNAME or it
-	 * was ld.so.1 itself that was executed, then PATHNAME() will be
-	 * based off of argv[0].  Otherwise - the PATHNAME is AT_SUN_EXECNAME.
+	 * Expand the fullpath name of the application.  This typically occurs
+	 * as a part of loading an object, but as the kernel probably mapped
+	 * it in, complete this processing now.
 	 */
-	if ((ldsoexec) || (_execname == 0))
-		PATHNAME(mlmp) = NAME(mlmp);
-	else
-		PATHNAME(mlmp) = _execname;
+	if (FLAGS1(mlmp) & FL1_RT_RELATIVE)
+		(void) fullpath(mlmp, 0);
 
-	ORIGNAME(mlmp) = PATHNAME(mlmp);
+	/*
+	 * Some troublesome programs will change the value of argv[0].  Dupping
+	 * the process string protects us, and insures the string is left in
+	 * any core files.
+	 */
+	if ((str = (char *)strdup(procname)) == 0)
+		return (0);
+	procname = str;
 
 	/*
 	 * If the kernel has provided hardware capabilities information, and
@@ -663,48 +712,19 @@
 		FLAGS1(mlmp) |= FL1_RT_NOINIFIN;
 
 	/*
-	 * Establish the interpretors name as that defined within the initial
-	 * object (executable).  This provides for ORIGIN processing of ld.so.1
-	 * dependencies.
-	 */
-	if (interp) {
-		size_t	len;
-		ORIGNAME(rlmp) = interp->i_name;
-		len = strlen(interp->i_name);
-		(void) expand(&interp->i_name, &len, 0, 0,
-		    (PN_TKN_ISALIST | PN_TKN_HWCAP), mlmp);
-		PATHNAME(rlmp) = interp->i_name;
-	} else {
-		ORIGNAME(rlmp) = PATHNAME(rlmp) = NAME(rlmp);
-	}
-
-	/*
-	 * Far the most common application execution revolves around appending
-	 * the application name to the users PATH definition, thus a full name
-	 * is passed to exec() which will in turn be returned via
-	 * AT_SUN_EXECNAME.  Applications may also be invoked from the current
-	 * working directory, or via a relative name.
-	 *
-	 * When $ORIGIN was first introduced, the expansion of a relative
-	 * pathname was deferred until it was required.  However now we insure
-	 * a full pathname is always created - things like the analyzer wish to
-	 * rely on librtld_db returning a full path.  The overhead of this is
-	 * perceived to be low, providing the associated libc version of getcwd
-	 * is available (see 4336878), plus it only affects execing relative
-	 * paths.  Here we expand the application and ld.so.1 - see
-	 * elf_new_lm() for the expansion of all other dependencies.
-	 */
-	if (FLAGS1(mlmp) & FL1_RT_RELATIVE)
-		(void) fullpath(mlmp, 0);
-	if (FLAGS1(rlmp) & FL1_RT_RELATIVE)
-		(void) fullpath(rlmp, 0);
-
-	/*
 	 * Identify lddstub if necessary.
 	 */
 	if (lml_main.lm_flags & LML_FLG_TRC_LDDSTUB)
 		FLAGS1(mlmp) |= FL1_RT_LDDSTUB;
 
+	/*
+	 * Retain our argument information for use in dlinfo.
+	 */
+	argsinfo.dla_argv = argv--;
+	argsinfo.dla_argc = (long)*argv;
+	argsinfo.dla_envp = envp;
+	argsinfo.dla_auxv = auxv;
+
 	(void) enter();
 
 	/*
@@ -776,15 +796,18 @@
 	/*
 	 * Establish the modes of the initial object.  These modes are
 	 * propagated to any preloaded objects and explicit shared library
-	 * dependencies.
+	 * dependencies.  Note, RTLD_NOW may have been established during
+	 * analysis of the application had it been built -z now.
 	 */
 	MODE(mlmp) |= (RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD);
 	if (rtld_flags & RT_FL_CONFGEN)
 		MODE(mlmp) |= RTLD_CONFGEN;
-	if (rtld_flags2 & RT_FL2_BINDNOW)
-		MODE(mlmp) |= RTLD_NOW;
-	else
-		MODE(mlmp) |= RTLD_LAZY;
+	if ((MODE(mlmp) & RTLD_NOW) == 0) {
+		if (rtld_flags2 & RT_FL2_BINDNOW)
+			MODE(mlmp) |= RTLD_NOW;
+		else
+			MODE(mlmp) |= RTLD_LAZY;
+	}
 
 	/*
 	 * If debugging was requested initialize things now that any cache has
@@ -805,8 +828,8 @@
 		DBG_CALL(Dbg_file_config_dis(config->c_name, features));
 
 	if (dbg_mask) {
-		DBG_CALL(Dbg_file_ldso(rt_name, (ulong_t)DYN(rlmp),
-		    ADDR(rlmp), envp, _auxv));
+		DBG_CALL(Dbg_file_ldso(PATHNAME(rlmp), (ulong_t)DYN(rlmp),
+		    ADDR(rlmp), envp, auxv));
 
 		if (FCT(mlmp) == &elf_fct) {
 			DBG_CALL(Dbg_file_elf(PATHNAME(mlmp),
--- a/usr/src/cmd/sgs/rtld/common/util.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/common/util.c	Wed Jun 15 08:20:19 2005 -0700
@@ -208,7 +208,7 @@
  * accordingly.
  *
  * While the stack layout is platform specific - it just so happens that x86,
- * sparc, & sparcv9 all share the following initial stack layout.
+ * sparc, sparcv9, and amd64 all share the following initial stack layout.
  *
  *	!_______________________!  high addresses
  *	!			!
@@ -243,44 +243,52 @@
  *
  */
 static void
-stack_cleanup(char **argv, int rmcnt)
+stack_cleanup(char **argv, char ***envp, auxv_t **auxv, int rmcnt)
 {
-	int		i;
+	int		ndx;
 	long		*argc;
-	char		**_argv, **envp, **_envp;
-	auxv_t		*auxv, *_auxv;
+	char		**oargv, **nargv;
+	char		**oenvp, **nenvp;
+	auxv_t		*oauxv, *nauxv;
 
 	/*
-	 * Slide ARGV[] and update argc.
+	 * Slide ARGV[] and update argc.  The argv pointer remains the same,
+	 * however slide the applications arguments over the arguments to
+	 * ld.so.1.
 	 */
-	_argv = argv;
-	argv = &argv[rmcnt];
-	for (i = 0; argv[i]; i++) {
-		_argv[i] = argv[i];
-	}
-	_argv[i] = argv[i];
-	argc = (long *)((uintptr_t)_argv - sizeof (long *));
+	nargv = &argv[0];
+	oargv = &argv[rmcnt];
+
+	for (ndx = 0; oargv[ndx]; ndx++)
+		nargv[ndx] = oargv[ndx];
+	nargv[ndx] = oargv[ndx];
+
+	argc = (long *)((uintptr_t)argv - sizeof (long *));
 	*argc -= rmcnt;
 
 	/*
-	 * Slide ENVP[].
+	 * Slide ENVP[], and update the environment array pointer.
 	 */
-	envp = &argv[i + 1];
-	_envp = &_argv[i + 1];
-	for (i = 0; envp[i]; i++) {
-		_envp[i] = envp[i];
-	}
-	_envp[i] = envp[i];
+	ndx++;
+	nenvp = &nargv[ndx];
+	oenvp = &oargv[ndx];
+	*envp = nenvp;
+
+	for (ndx = 0; oenvp[ndx]; ndx++)
+		nenvp[ndx] = oenvp[ndx];
+	nenvp[ndx] = oenvp[ndx];
 
 	/*
-	 * Slide AUXV[].
+	 * Slide AUXV[], and update the aux vector pointer.
 	 */
-	auxv = (auxv_t *)&envp[i + 1];
-	_auxv = (auxv_t *)&_envp[i + 1];
-	for (i = 0; auxv[i].a_type != AT_NULL; i++) {
-		_auxv[i] = auxv[i];
-	}
-	_auxv[i] = auxv[i];
+	ndx++;
+	nauxv = (auxv_t *)&nenvp[ndx];
+	oauxv = (auxv_t *)&oenvp[ndx];
+	*auxv = nauxv;
+
+	for (ndx = 0; (oauxv[ndx].a_type != AT_NULL); ndx++)
+		nauxv[ndx] = oauxv[ndx];
+	nauxv[ndx] = oauxv[ndx];
 }
 #else
 /*
@@ -290,57 +298,61 @@
 #endif
 
 /*
- * The only command line argument recognized is -e, followed by an rtld
- * environment variable.
+ * The only command line argument recognized is -e, followed by a runtime
+ * linker environment variable.
  */
 int
-rtld_getopt(char **argv, Word *lmflags, Word *lmtflags, int aout)
+rtld_getopt(char **argv, char ***envp, auxv_t **auxv, Word *lmflags,
+    Word *lmtflags, int aout)
 {
-	int	i, errflg = 0;
-
-	for (i = 1; argv[i]; i++) {
+	int	ndx;
+
+	for (ndx = 1; argv[ndx]; ndx++) {
 		char	*str;
 
-		if (argv[i][0] != '-')
+		if (argv[ndx][0] != '-')
 			break;
 
-		if (argv[i][1] == '\0') {
-			i++;
+		if (argv[ndx][1] == '\0') {
+			ndx++;
 			break;
 		}
 
-		if (argv[i][1] != 'e') {
-			errflg++;
-			break;
-		}
-
-		if (argv[i][2] == '\0') {
-			i++;
-			if (argv[i] == NULL) {
-				errflg++;
-				break;
-			}
-			str = argv[i];
+		if (argv[ndx][1] != 'e')
+			return (1);
+
+		if (argv[ndx][2] == '\0') {
+			ndx++;
+			if (argv[ndx] == NULL)
+				return (1);
+			str = argv[ndx];
 		} else
-			str = &argv[i][2];
-
+			str = &argv[ndx][2];
+
+		/*
+		 * If the environment variable starts with LD_, strip the LD_.
+		 * Otherwise, take things as is.
+		 */
+		if ((str[0] == 'L') && (str[1] == 'D') && (str[2] == '_') &&
+		    (str[3] != '\0'))
+			str += 3;
 		if (ld_flags_env(str, lmflags, lmtflags, 0, aout) == 1)
 			return (1);
 	}
 
-	if (errflg || (argv[i] == 0)) {
-		eprintf(ERR_FATAL, MSG_INTL(MSG_USG_BADOPT));
+	/*
+	 * Make sure an object file has been specified.
+	 */
+	if (argv[ndx] == 0)
 		return (1);
-	}
 
 	/*
 	 * Having gotten the arguments, clean ourselves off of the stack.
 	 */
-	stack_cleanup(argv, i);
+	stack_cleanup(argv, envp, auxv, ndx);
 	return (0);
 }
 
-
 /*
  * Compare function for FullpathNode AVL tree.
  */
@@ -2707,10 +2719,16 @@
 			if (err_strs[ERR_ELF] == 0)
 			    err_strs[ERR_ELF] = MSG_INTL(MSG_ERR_ELF);
 		}
-		if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR1),
-		    rt_name, pr_name, err_strs[error]) == 0) {
-			overflow = 1;
+		if (procname) {
+			if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR1),
+			    rtldname, procname, err_strs[error]) == 0)
+				overflow = 1;
 		} else {
+			if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR2),
+			    rtldname, err_strs[error]) == 0)
+				overflow = 1;
+		}
+		if (overflow == 0) {
 			/*
 			 * Remove the terminating '\0'.
 			 */
@@ -3302,8 +3320,8 @@
  *  o	after loading a new shared object.  We can add shared objects to various
  *	link-maps, and any link-map dependencies requiring getopt() require
  *	their own environ.  In addition, lazy loading might bring in the
- *	supplier of environ (libc) after the link-map has been established and
- *	other objects are present.
+ *	supplier of environ (libc used to be a lazy loading candidate) after
+ *	the link-map has been established and other objects are present.
  *
  * This routine handles all these scenarios, without adding unnecessary overhead
  * to ld.so.1.
@@ -3324,12 +3342,13 @@
 	sl.sl_flags = LKUP_WEAK;
 
 	if (sym = LM_LOOKUP_SYM(lml->lm_head)(&sl, &dlmp, &binfo)) {
-		char **	addr = (char **)sym->st_value;
+		lml->lm_environ = (char ***)sym->st_value;
 
 		if (!(FLAGS(dlmp) & FLG_RT_FIXED))
-			addr = (char **)((uintptr_t)addr +
-				(uintptr_t)ADDR(dlmp));
-		*addr = (char *)environ;
+			lml->lm_environ =
+			    (char ***)((uintptr_t)lml->lm_environ +
+			    (uintptr_t)ADDR(dlmp));
+		*(lml->lm_environ) = (char **)environ;
 		lml->lm_flags |= LML_FLG_ENVIRON;
 	}
 }
--- a/usr/src/cmd/sgs/rtld/i386/_setup.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/i386/_setup.c	Wed Jun 15 08:20:19 2005 -0700
@@ -237,10 +237,10 @@
 	/*
 	 * Continue with generic startup processing.
 	 */
-	if ((lmp = setup((unsigned long)_envp, (unsigned long)_auxv, _flags,
-	    _platform, _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base,
-	    fd, phdr, _execname, _argv, dz_fd, uid, euid, gid, egid,
-	    NULL, auxflags, hwcap_1)) == NULL) {
+	if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
+	    _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base, fd, phdr,
+	    _execname, _argv, dz_fd, uid, euid, gid, egid, NULL, auxflags,
+	    hwcap_1)) == NULL) {
 		rtldexit(&lml_main, 1);
 	}
 
--- a/usr/src/cmd/sgs/rtld/i386/i386_elf.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/i386/i386_elf.c	Wed Jun 15 08:20:19 2005 -0700
@@ -1043,7 +1043,7 @@
 	    r_debug.rtd_rdebug.r_ldbase) &&
 	    !(strcmp(interp->i_name, MSG_ORIG(MSG_PTH_LIBC)))) {
 
-		DBG_CALL(Dbg_reloc_run(pr_name, M_REL_SHT_TYPE, 0,
+		DBG_CALL(Dbg_reloc_run(NAME(lmp), M_REL_SHT_TYPE, 0,
 		    DBG_REL_START));
 
 		if (_elf_copy_reloc(MSG_ORIG(MSG_SYM_CTYPE), lmp,
--- a/usr/src/cmd/sgs/rtld/sparc/_setup.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/sparc/_setup.c	Wed Jun 15 08:20:19 2005 -0700
@@ -232,9 +232,9 @@
 	/*
 	 * Continue with generic startup processing.
 	 */
-	if ((lmp = setup((unsigned long)_envp, (unsigned long)_auxv, _flags,
-	    _platform, _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base,
-	    fd, phdr, _execname, _argv, dz_fd, uid, euid, gid, egid,
+	if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
+	    _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base, fd, phdr,
+	    _execname, _argv, dz_fd, uid, euid, gid, egid,
 #ifdef	A_OUT
 	    aoutdyn, auxflags, hwcap_1)) == (Rt_map *)0) {
 #else
--- a/usr/src/cmd/sgs/rtld/sparcv9/_setup.c	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/cmd/sgs/rtld/sparcv9/_setup.c	Wed Jun 15 08:20:19 2005 -0700
@@ -228,10 +228,10 @@
 	/*
 	 * Continue with generic startup processing.
 	 */
-	if ((lmp = setup((unsigned long)_envp, (unsigned long)_auxv, _flags,
-	    _platform, _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base,
-	    fd, phdr, _execname, _argv, dz_fd, uid, euid, gid, egid,
-	    NULL, auxflags, hwcap_1)) == NULL) {
+	if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
+	    _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base, fd, phdr,
+	    _execname, _argv, dz_fd, uid, euid, gid, egid, NULL, auxflags,
+	    hwcap_1)) == NULL) {
 		rtldexit(&lml_main, 1);
 	}
 
--- a/usr/src/head/dlfcn.h	Tue Jun 14 19:12:41 2005 -0700
+++ b/usr/src/head/dlfcn.h	Wed Jun 15 08:20:19 2005 -0700
@@ -35,13 +35,14 @@
 
 #include <sys/feature_tests.h>
 #include <sys/types.h>
+#include <sys/auxv.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 /*
- * Information structure for libpath dlinfo() and dlamd64getunwind() request.
+ * Information structures for various dlinfo() requests.
  */
 #if !defined(_XOPEN_SOURCE) || defined(__EXTENSIONS__)
 #ifdef __STDC__
@@ -59,13 +60,7 @@
 	void		*dli_saddr;
 } Dl_info;
 #endif /* __STDC__ */
-#endif /* !defined(_XOPEN_SOURCE) || defined(__EXTENSIONS__) */
 
-
-/*
- * Information structure for libpath dlinfo() request.
- */
-#if !defined(_XOPEN_SOURCE) || defined(__EXTENSIONS__)
 typedef struct	dl_serpath {
 	char		*dls_name;	/* library search path name */
 	uint_t		dls_flags;	/* path information */
@@ -88,6 +83,13 @@
 	void	    *dlui_segend;	/* end of segment described */
 					/*  by unwind block */
 } Dl_amd64_unwindinfo;
+
+typedef struct	dl_argsinfo {
+	long		dla_argc;	/* process argument count */
+	char		**dla_argv;	/* process arguments */
+	char		**dla_envp;	/* process environment variables */
+	auxv_t		*dla_auxv;	/* process auxv vectors */
+} Dl_argsinfo;
 #endif /* !defined(_XOPEN_SOURCE) || defined(__EXTENSIONS__) */
 
 
@@ -208,7 +210,9 @@
 						/*	internal use only */
 #define	RTLD_DI_GETSIGNAL	9		/* get termination signal */
 #define	RTLD_DI_SETSIGNAL	10		/* set termination signal */
-#define	RTLD_DI_MAX		10
+#define	RTLD_DI_ARGSINFO	11		/* get process arguments */
+						/*	environment and auxv */
+#define	RTLD_DI_MAX		11
 
 #if !defined(_XOPEN_SOURCE) || defined(__EXTENSIONS__)
 /*