changeset 11827:d7ef53deac3f

6918143 symbol capabilities 6910387 .tdata and .tbss separation invalidates TLS program header information
author Rod Evans <Rod.Evans@Sun.COM>
date Mon, 01 Mar 2010 10:20:48 -0800
parents f769bc37a3d0
children 90325c8c5951
files usr/src/cmd/sgs/Makefile usr/src/cmd/sgs/Makefile.com usr/src/cmd/sgs/crle/Makefile.com usr/src/cmd/sgs/dump/common/dump.c usr/src/cmd/sgs/elfdump/Makefile.com usr/src/cmd/sgs/elfdump/common/elfdump.c usr/src/cmd/sgs/elfdump/common/elfdump.msg usr/src/cmd/sgs/elfdump/common/fake_shdr.c usr/src/cmd/sgs/elfedit/Makefile.com usr/src/cmd/sgs/elfedit/common/elfconst.c usr/src/cmd/sgs/elfedit/common/elfedit.msg usr/src/cmd/sgs/elfedit/modules/Makefile.com usr/src/cmd/sgs/elfedit/modules/common/cap.c usr/src/cmd/sgs/elfedit/modules/common/cap.msg usr/src/cmd/sgs/elfedit/modules/common/dyn.c usr/src/cmd/sgs/elfwrap/Makefile.com usr/src/cmd/sgs/include/_machelf.h usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/elfedit.h usr/src/cmd/sgs/include/i386/machdep_x86.h usr/src/cmd/sgs/include/libld.h usr/src/cmd/sgs/include/rtld.h usr/src/cmd/sgs/include/sgs.h usr/src/cmd/sgs/include/sparc/machdep_sparc.h usr/src/cmd/sgs/ld/Makefile.com usr/src/cmd/sgs/ldd/Makefile.com usr/src/cmd/sgs/ldprof/Makefile.com usr/src/cmd/sgs/libconv/common/cap.c usr/src/cmd/sgs/libconv/common/cap.msg usr/src/cmd/sgs/libconv/common/cap_machelf.c usr/src/cmd/sgs/libconv/common/dynamic.c usr/src/cmd/sgs/libconv/common/dynamic.msg usr/src/cmd/sgs/libconv/common/elf.c usr/src/cmd/sgs/libconv/common/llib-lconv usr/src/cmd/sgs/libconv/common/sections.c usr/src/cmd/sgs/libconv/common/sections.msg usr/src/cmd/sgs/libconv/common/syminfo.c usr/src/cmd/sgs/libconv/common/syminfo.msg usr/src/cmd/sgs/libcrle/Makefile.com usr/src/cmd/sgs/libelf/common/xlate.m4 usr/src/cmd/sgs/libelf/common/xlate64.m4 usr/src/cmd/sgs/libld/Makefile.com usr/src/cmd/sgs/libld/common/_libld.h usr/src/cmd/sgs/libld/common/_map.h usr/src/cmd/sgs/libld/common/args.c usr/src/cmd/sgs/libld/common/entry.c usr/src/cmd/sgs/libld/common/files.c usr/src/cmd/sgs/libld/common/globals.c usr/src/cmd/sgs/libld/common/libld.msg usr/src/cmd/sgs/libld/common/machrel.amd.c usr/src/cmd/sgs/libld/common/machrel.intel.c usr/src/cmd/sgs/libld/common/machrel.sparc.c usr/src/cmd/sgs/libld/common/map.c usr/src/cmd/sgs/libld/common/map_support.c usr/src/cmd/sgs/libld/common/map_v2.c usr/src/cmd/sgs/libld/common/place.c usr/src/cmd/sgs/libld/common/relocate.c usr/src/cmd/sgs/libld/common/resolve.c usr/src/cmd/sgs/libld/common/sections.c usr/src/cmd/sgs/libld/common/support.c usr/src/cmd/sgs/libld/common/syms.c usr/src/cmd/sgs/libld/common/update.c usr/src/cmd/sgs/libld/common/util.c usr/src/cmd/sgs/libld/common/version.c usr/src/cmd/sgs/liblddbg/Makefile.com usr/src/cmd/sgs/liblddbg/common/cap.c usr/src/cmd/sgs/liblddbg/common/debug.c usr/src/cmd/sgs/liblddbg/common/files.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/liblddbg/common/map.c usr/src/cmd/sgs/liblddbg/common/mapfile-vers usr/src/cmd/sgs/liblddbg/common/syminfo.c usr/src/cmd/sgs/liblddbg/common/syms.c usr/src/cmd/sgs/libldmake/Makefile.com usr/src/cmd/sgs/libldstab/Makefile.com usr/src/cmd/sgs/librtld/Makefile.com usr/src/cmd/sgs/librtld/common/relocate.c usr/src/cmd/sgs/link_audit/Makefile.com usr/src/cmd/sgs/moe/Makefile.com usr/src/cmd/sgs/moe/common/moe.c usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/pvs/Makefile.com usr/src/cmd/sgs/rtld/Makefile.com usr/src/cmd/sgs/rtld/Makefile.targ usr/src/cmd/sgs/rtld/amd64/amd64_elf.c usr/src/cmd/sgs/rtld/common/_a.out.h usr/src/cmd/sgs/rtld/common/_elf.h usr/src/cmd/sgs/rtld/common/_rtld.h usr/src/cmd/sgs/rtld/common/a.out.c usr/src/cmd/sgs/rtld/common/analyze.c usr/src/cmd/sgs/rtld/common/audit.c usr/src/cmd/sgs/rtld/common/cap.c usr/src/cmd/sgs/rtld/common/config_elf.c usr/src/cmd/sgs/rtld/common/dlfcns.c usr/src/cmd/sgs/rtld/common/elf.c usr/src/cmd/sgs/rtld/common/globals.c usr/src/cmd/sgs/rtld/common/object.c usr/src/cmd/sgs/rtld/common/paths.c usr/src/cmd/sgs/rtld/common/remove.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/i386_elf.c usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg usr/src/cmd/sgs/rtld/sparc/sparc_a.out.c usr/src/cmd/sgs/rtld/sparc/sparc_elf.c usr/src/cmd/sgs/rtld/sparcv9/sparc_elf.c usr/src/cmd/sgs/tools/Makefile.com usr/src/head/link.h usr/src/uts/common/sys/elf.h usr/src/uts/common/sys/link.h usr/src/uts/common/sys/machelf.h
diffstat 115 files changed, 7699 insertions(+), 2195 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/Makefile	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/Makefile	Mon Mar 01 10:20:48 2010 -0800
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 include		$(SRC)/cmd/Makefile.cmd
 
@@ -192,6 +190,7 @@
 # we want xref to list the source file.
 #
 XRDIRS=		. \
+		../../common/elfcap \
 		../../head \
 		../../uts/common/krtld \
 		../../uts/common/sys \
--- a/usr/src/cmd/sgs/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,6 +18,7 @@
 #
 # CDDL HEADER END
 #
+
 #
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -118,12 +119,14 @@
 
 native :=	DYNFLAGS = -R$(SGSPROTO) -L$(SGSPROTO) $(ZNOVERSION)
 
-USE_PROTO =	-Yl,$(SGSPROTO)
+# Comment out the following two lines to have the sgs built from the system
+# link-editor, rather than the local proto link-editor.
+CC_USE_PROTO =	-Yl,$(SGSPROTO)
+LD_USE_PROTO =	$(SGSPROTO)/
 
 #
 # lint-related stuff
 #
-
 LIBNAME32 =	$(LIBNAME:%=%32)
 LIBNAME64 =	$(LIBNAME:%=%64)
 LIBNAMES =	$(LIBNAME32) $(LIBNAME64)
@@ -141,7 +144,20 @@
 
 LINTFLAGS =	-m -errtags=yes -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
 LINTFLAGS64 =	-m -errtags=yes -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED \
-		    $(VAR_LINTFLAGS64) \
+		    $(VAR_LINTFLAGS64)
+
+#
+# When building a lint library, no other lint libraries are verified as
+# dependencies, nor is the stardard C lint library processed.  All dependency
+# verification is carried out through linting the sources themselves.
+#
+$(LINTLIB) :=	LINTFLAGS += -n
+$(LINTLIB) :=	LINTFLAGS64 += -n
+
+$(LINTLIB32) :=	LINTFLAGS += -n
+$(LINTLIB32) :=	LINTFLAGS64 += -n
+$(LINTLIB64) :=	LINTFLAGS += -n
+$(LINTLIB64) :=	LINTFLAGS64 += -n
 
 #
 # These libraries have two resulting lint libraries.  If a dependency is
--- a/usr/src/cmd/sgs/crle/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/crle/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -43,7 +43,7 @@
 		-D__EXTENSIONS__
 LLDFLAGS =	'-R$$ORIGIN/../lib'
 LLDFLAGS64 =	'-R$$ORIGIN/../../lib/$(MACH64)'
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPT) \
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) $(MAPOPT) \
 			$(LLDFLAGS) $(ZNOLAZYLOAD)
 LDLIBS +=	-lelf $(CONVLIBDIR) $(CONV_LIB) $(DLLIB)
 LINTFLAGS +=	-x
--- a/usr/src/cmd/sgs/dump/common/dump.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/dump/common/dump.c	Mon Mar 01 10:20:48 2010 -0800
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1154,6 +1154,8 @@
 			case DT_PREINIT_ARRAYSZ:
 			case DT_SUNW_RTLDINF:
 			case DT_SUNW_CAP:
+			case DT_SUNW_CAPINFO:
+			case DT_SUNW_CAPCHAIN:
 			case DT_SUNW_SYMTAB:
 			case DT_SUNW_SYMSORT:
 			case DT_SUNW_TLSSORT:
@@ -1222,6 +1224,8 @@
 			case DT_SUNW_SYMSORTSZ:
 			case DT_SUNW_TLSSORTSZ:
 			case DT_SUNW_STRPAD:
+			case DT_SUNW_CAPCHAINENT:
+			case DT_SUNW_CAPCHAINSZ:
 				(void) printf(pdyn_Fmtptr,
 				    EC_XWORD(p_dyn.d_un.d_val));
 				break;
--- a/usr/src/cmd/sgs/elfdump/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -52,7 +52,7 @@
 		$(CPPFLAGS.master) -I$(ELFCAP)
 LLDFLAGS =	$(VAR_ELFDUMP_LLDFLAGS)
 LLDFLAGS64 =	$(VAR_LD_LLDFLAGS64)
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPT) $(LLDFLAGS)
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) $(MAPOPT) $(LLDFLAGS)
 LDLIBS +=	$(ELFLIBDIR) -lelf $(LDDBGLIBDIR) $(LDDBG_LIB) \
 		    $(CONVLIBDIR) $(CONV_LIB)
 
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c	Mon Mar 01 10:20:48 2010 -0800
@@ -812,9 +812,8 @@
 	 * We match these sections by name, rather than section type,
 	 * because they can come in as either SHT_AMD64_UNWIND, or as
 	 * SHT_PROGBITS, and because the type isn't enough to determine
-	 * how they should be interprteted.
+	 * how they should be interpreted.
 	 */
-
 	/* Find the program header for .eh_frame_hdr if present */
 	if (phnum)
 		uphdr = getphdr(phnum, phdr_types,
@@ -822,7 +821,7 @@
 
 	/*
 	 * eh_state is used to retain data used by unwind_eh_frame()
-	 * accross calls.
+	 * across calls.
 	 */
 	bzero(&eh_state, sizeof (eh_state));
 
@@ -882,12 +881,739 @@
 }
 
 /*
- * Print the hardware/software capabilities.  For executables and shared objects
- * this should be accompanied with a program header.
+ * Initialize a symbol table state structure
+ *
+ * entry:
+ *	state - State structure to be initialized
+ *	cache - Cache of all section headers
+ *	shnum - # of sections in cache
+ *	secndx - Index of symbol table section
+ *	ehdr - ELF header for file
+ *	versym - Information about versym section
+ *	file - Name of file
+ *	flags - Command line option flags
+ */
+static int
+init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx,
+    Ehdr *ehdr, uchar_t osabi, VERSYM_STATE *versym, const char *file,
+    uint_t flags)
+{
+	Shdr *shdr;
+
+	state->file = file;
+	state->ehdr = ehdr;
+	state->cache = cache;
+	state->osabi = osabi;
+	state->shnum = shnum;
+	state->seccache = &cache[secndx];
+	state->secndx = secndx;
+	state->secname = state->seccache->c_name;
+	state->flags = flags;
+	state->shxndx.checked = 0;
+	state->shxndx.data = NULL;
+	state->shxndx.n = 0;
+
+	shdr = state->seccache->c_shdr;
+
+	/*
+	 * Check the symbol data and per-item size.
+	 */
+	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
+		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
+		    file, state->secname);
+		return (0);
+	}
+	if (state->seccache->c_data == NULL)
+		return (0);
+
+	/* LINTED */
+	state->symn = (Word)(shdr->sh_size / shdr->sh_entsize);
+	state->sym = (Sym *)state->seccache->c_data->d_buf;
+
+	/*
+	 * Check associated string table section.
+	 */
+	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
+		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
+		    file, state->secname, EC_WORD(shdr->sh_link));
+		return (0);
+	}
+
+	/*
+	 * Determine if there is a associated Versym section
+	 * with this Symbol Table.
+	 */
+	if (versym && versym->cache &&
+	    (versym->cache->c_shdr->sh_link == state->secndx))
+		state->versym = versym;
+	else
+		state->versym = NULL;
+
+
+	return (1);
+}
+
+/*
+ * Determine the extended section index used for symbol tables entries.
+ */
+static void
+symbols_getxindex(SYMTBL_STATE *state)
+{
+	uint_t	symn;
+	Word	symcnt;
+
+	state->shxndx.checked = 1;   /* Note that we've been called */
+	for (symcnt = 1; symcnt < state->shnum; symcnt++) {
+		Cache	*_cache = &state->cache[symcnt];
+		Shdr	*shdr = _cache->c_shdr;
+
+		if ((shdr->sh_type != SHT_SYMTAB_SHNDX) ||
+		    (shdr->sh_link != state->secndx))
+			continue;
+
+		if ((shdr->sh_entsize) &&
+		    /* LINTED */
+		    ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0))
+			continue;
+
+		if (_cache->c_data == NULL)
+			continue;
+
+		state->shxndx.data = _cache->c_data->d_buf;
+		state->shxndx.n = symn;
+		return;
+	}
+}
+
+/*
+ * Produce a line of output for the given symbol
+ *
+ * entry:
+ *	state - Symbol table state
+ *	symndx - Index of symbol within the table
+ *	info - Value of st_info (indicates local/global range)
+ *	symndx_disp - Index to display. This may not be the same
+ *		as symndx if the display is relative to the logical
+ *		combination of the SUNW_ldynsym/dynsym tables.
+ *	sym - Symbol to display
+ */
+static void
+output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx,
+    Sym *sym)
+{
+	/*
+	 * Symbol types for which we check that the specified
+	 * address/size land inside the target section.
+	 */
+	static const int addr_symtype[] = {
+		0,			/* STT_NOTYPE */
+		1,			/* STT_OBJECT */
+		1,			/* STT_FUNC */
+		0,			/* STT_SECTION */
+		0,			/* STT_FILE */
+		1,			/* STT_COMMON */
+		0,			/* STT_TLS */
+		0,			/* 7 */
+		0,			/* 8 */
+		0,			/* 9 */
+		0,			/* 10 */
+		0,			/* 11 */
+		0,			/* 12 */
+		0,			/* STT_SPARC_REGISTER */
+		0,			/* 14 */
+		0,			/* 15 */
+	};
+#if STT_NUM != (STT_TLS + 1)
+#error "STT_NUM has grown. Update addr_symtype[]"
+#endif
+
+	char		index[MAXNDXSIZE];
+	const char	*symname, *sec;
+	Versym		verndx;
+	int		gnuver;
+	uchar_t		type;
+	Shdr		*tshdr;
+	Word		shndx;
+	Conv_inv_buf_t	inv_buf;
+
+	/* Ensure symbol index is in range */
+	if (symndx >= state->symn) {
+		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYMNDX),
+		    state->file, state->secname, EC_WORD(symndx));
+		return;
+	}
+
+	/*
+	 * If we are using extended symbol indexes, find the
+	 * corresponding SHN_SYMTAB_SHNDX table.
+	 */
+	if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0))
+		symbols_getxindex(state);
+
+	/* LINTED */
+	symname = string(state->seccache, symndx,
+	    &state->cache[state->seccache->c_shdr->sh_link], state->file,
+	    sym->st_name);
+
+	tshdr = NULL;
+	sec = NULL;
+
+	if (state->ehdr->e_type == ET_CORE) {
+		sec = (char *)MSG_INTL(MSG_STR_UNKNOWN);
+	} else if (state->flags & FLG_CTL_FAKESHDR) {
+		/*
+		 * If we are using fake section headers derived from
+		 * the program headers, then the section indexes
+		 * in the symbols do not correspond to these headers.
+		 * The section names are not available, so all we can
+		 * do is to display them in numeric form.
+		 */
+		sec = conv_sym_shndx(state->osabi, state->ehdr->e_machine,
+		    sym->st_shndx, CONV_FMT_DECIMAL, &inv_buf);
+	} else if ((sym->st_shndx < SHN_LORESERVE) &&
+	    (sym->st_shndx < state->shnum)) {
+		shndx = sym->st_shndx;
+		tshdr = state->cache[shndx].c_shdr;
+		sec = state->cache[shndx].c_name;
+	} else if (sym->st_shndx == SHN_XINDEX) {
+		if (state->shxndx.data) {
+			Word	_shxndx;
+
+			if (symndx > state->shxndx.n) {
+				(void) fprintf(stderr,
+				    MSG_INTL(MSG_ERR_BADSYMXINDEX1),
+				    state->file, state->secname,
+				    EC_WORD(symndx));
+			} else if ((_shxndx =
+			    state->shxndx.data[symndx]) > state->shnum) {
+				(void) fprintf(stderr,
+				    MSG_INTL(MSG_ERR_BADSYMXINDEX2),
+				    state->file, state->secname,
+				    EC_WORD(symndx), EC_WORD(_shxndx));
+			} else {
+				shndx = _shxndx;
+				tshdr = state->cache[shndx].c_shdr;
+				sec = state->cache[shndx].c_name;
+			}
+		} else {
+			(void) fprintf(stderr,
+			    MSG_INTL(MSG_ERR_BADSYMXINDEX3),
+			    state->file, state->secname, EC_WORD(symndx));
+		}
+	} else if ((sym->st_shndx < SHN_LORESERVE) &&
+	    (sym->st_shndx >= state->shnum)) {
+		(void) fprintf(stderr,
+		    MSG_INTL(MSG_ERR_BADSYM5), state->file,
+		    state->secname, EC_WORD(symndx),
+		    demangle(symname, state->flags), sym->st_shndx);
+	}
+
+	/*
+	 * If versioning is available display the
+	 * version index. If not, then use 0.
+	 */
+	if (state->versym) {
+		Versym test_verndx;
+
+		verndx = test_verndx = state->versym->data[symndx];
+		gnuver = state->versym->gnu_full;
+
+		/*
+		 * Check to see if this is a defined symbol with a
+		 * version index that is outside the valid range for
+		 * the file. The interpretation of this depends on
+		 * the style of versioning used by the object.
+		 *
+		 * Versions >= VER_NDX_LORESERVE have special meanings,
+		 * and are exempt from this checking.
+		 *
+		 * GNU style version indexes use the top bit of the
+		 * 16-bit index value (0x8000) as the "hidden bit".
+		 * We must mask off this bit in order to compare
+		 * the version against the maximum value.
+		 */
+		if (gnuver)
+			test_verndx &= ~0x8000;
+
+		if ((test_verndx > state->versym->max_verndx) &&
+		    (verndx < VER_NDX_LORESERVE))
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER),
+			    state->file, state->secname, EC_WORD(symndx),
+			    EC_HALF(test_verndx), state->versym->max_verndx);
+	} else {
+		verndx = 0;
+		gnuver = 0;
+	}
+
+	/*
+	 * Error checking for TLS.
+	 */
+	type = ELF_ST_TYPE(sym->st_info);
+	if (type == STT_TLS) {
+		if (tshdr &&
+		    (sym->st_shndx != SHN_UNDEF) &&
+		    ((tshdr->sh_flags & SHF_TLS) == 0)) {
+			(void) fprintf(stderr,
+			    MSG_INTL(MSG_ERR_BADSYM3), state->file,
+			    state->secname, EC_WORD(symndx),
+			    demangle(symname, state->flags));
+		}
+	} else if ((type != STT_SECTION) && sym->st_size &&
+	    tshdr && (tshdr->sh_flags & SHF_TLS)) {
+		(void) fprintf(stderr,
+		    MSG_INTL(MSG_ERR_BADSYM4), state->file,
+		    state->secname, EC_WORD(symndx),
+		    demangle(symname, state->flags));
+	}
+
+	/*
+	 * If a symbol with non-zero size has a type that
+	 * specifies an address, then make sure the location
+	 * it references is actually contained within the
+	 * section.  UNDEF symbols don't count in this case,
+	 * so we ignore them.
+	 *
+	 * The meaning of the st_value field in a symbol
+	 * depends on the type of object. For a relocatable
+	 * object, it is the offset within the section.
+	 * For sharable objects, it is the offset relative to
+	 * the base of the object, and for other types, it is
+	 * the virtual address. To get an offset within the
+	 * section for non-ET_REL files, we subtract the
+	 * base address of the section.
+	 */
+	if (addr_symtype[type] && (sym->st_size > 0) &&
+	    (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) ||
+	    (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) {
+		Word v = sym->st_value;
+			if (state->ehdr->e_type != ET_REL)
+				v -= tshdr->sh_addr;
+		if (((v + sym->st_size) > tshdr->sh_size)) {
+			(void) fprintf(stderr,
+			    MSG_INTL(MSG_ERR_BADSYM6), state->file,
+			    state->secname, EC_WORD(symndx),
+			    demangle(symname, state->flags),
+			    EC_WORD(shndx), EC_XWORD(tshdr->sh_size),
+			    EC_XWORD(sym->st_value), EC_XWORD(sym->st_size));
+		}
+	}
+
+	/*
+	 * A typical symbol table uses the sh_info field to indicate one greater
+	 * than the symbol table index of the last local symbol, STB_LOCAL.
+	 * Therefore, symbol indexes less than sh_info should have local
+	 * binding.  Symbol indexes greater than, or equal to sh_info, should
+	 * have global binding.  Note, we exclude UNDEF/NOTY symbols with zero
+	 * value and size, as these symbols may be the result of an mcs(1)
+	 * section deletion.
+	 */
+	if (info) {
+		uchar_t	bind = ELF_ST_BIND(sym->st_info);
+
+		if ((symndx < info) && (bind != STB_LOCAL)) {
+			(void) fprintf(stderr,
+			    MSG_INTL(MSG_ERR_BADSYM7), state->file,
+			    state->secname, EC_WORD(symndx),
+			    demangle(symname, state->flags), EC_XWORD(info));
+
+		} else if ((symndx >= info) && (bind == STB_LOCAL) &&
+		    ((sym->st_shndx != SHN_UNDEF) ||
+		    (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) ||
+		    (sym->st_size != 0) || (sym->st_value != 0))) {
+			(void) fprintf(stderr,
+			    MSG_INTL(MSG_ERR_BADSYM8), state->file,
+			    state->secname, EC_WORD(symndx),
+			    demangle(symname, state->flags), EC_XWORD(info));
+		}
+	}
+
+	(void) snprintf(index, MAXNDXSIZE,
+	    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx));
+	Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, state->osabi,
+	    state->ehdr->e_machine, sym, verndx, gnuver, sec, symname);
+}
+
+/*
+ * Process a SHT_SUNW_cap capabilities section.
+ */
+static int
+cap_section(const char *file, Cache *cache, Word shnum, Cache *ccache,
+    uchar_t osabi, Ehdr *ehdr, uint_t flags)
+{
+	SYMTBL_STATE	state;
+	Word		cnum, capnum, nulls, symcaps;
+	int		descapndx, objcap, title;
+	Cap		*cap = (Cap *)ccache->c_data->d_buf;
+	Shdr		*cishdr, *cshdr = ccache->c_shdr;
+	Cache		*cicache, *strcache;
+	Capinfo		*capinfo = NULL;
+	Word		capinfonum;
+	const char	*strs = NULL;
+	size_t		strs_size;
+
+	if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) {
+		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
+		    file, ccache->c_name);
+		return (0);
+	}
+
+	/*
+	 * If this capabilities section is associated with symbols, then the
+	 * sh_link field points to the associated capabilities information
+	 * section.  The sh_link field of the capabilities information section
+	 * points to the associated symbol table.
+	 */
+	if (cshdr->sh_link) {
+		Cache	*scache;
+		Shdr	*sshdr;
+
+		/*
+		 * Validate that the sh_link field points to a capabilities
+		 * information section.
+		 */
+		if (cshdr->sh_link >= shnum) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
+			    file, ccache->c_name, EC_WORD(cshdr->sh_link));
+			return (0);
+		}
+
+		cicache = &cache[cshdr->sh_link];
+		cishdr = cicache->c_shdr;
+
+		if (cishdr->sh_type != SHT_SUNW_capinfo) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAP),
+			    file, ccache->c_name, EC_WORD(cshdr->sh_link));
+			return (0);
+		}
+
+		capinfo = cicache->c_data->d_buf;
+		capinfonum = (Word)(cishdr->sh_size / cishdr->sh_entsize);
+
+		/*
+		 * Validate that the sh_link field of the capabilities
+		 * information section points to a valid symbol table.
+		 */
+		if ((cishdr->sh_link == 0) || (cishdr->sh_link >= shnum)) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
+			    file, cicache->c_name, EC_WORD(cishdr->sh_link));
+			return (0);
+		}
+		scache = &cache[cishdr->sh_link];
+		sshdr = scache->c_shdr;
+
+		if ((sshdr->sh_type != SHT_SYMTAB) &&
+		    (sshdr->sh_type != SHT_DYNSYM)) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAPINFO1),
+			    file, cicache->c_name, EC_WORD(cishdr->sh_link));
+			return (0);
+		}
+
+		if (!init_symtbl_state(&state, cache, shnum,
+		    cishdr->sh_link, ehdr, osabi, NULL, file, flags))
+			return (0);
+	}
+
+	/*
+	 * If this capabilities section contains capability string entries,
+	 * then determine the associated string table.  Capabilities entries
+	 * that define names require that the capability section indicate
+	 * which string table to use via sh_info.
+	 */
+	if (cshdr->sh_info) {
+		Shdr	*strshdr;
+
+		/*
+		 * Validate that the sh_info field points to a string table.
+		 */
+		if (cshdr->sh_info >= shnum) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
+			    file, ccache->c_name, EC_WORD(cshdr->sh_info));
+			return (0);
+		}
+
+		strcache = &cache[cshdr->sh_info];
+		strshdr = strcache->c_shdr;
+
+		if (strshdr->sh_type != SHT_STRTAB) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAP),
+			    file, ccache->c_name, EC_WORD(cshdr->sh_info));
+			return (0);
+		}
+		strs = (const char *)strcache->c_data->d_buf;
+		strs_size = strcache->c_data->d_size;
+	}
+
+	dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
+	dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name);
+
+	capnum = (Word)(cshdr->sh_size / cshdr->sh_entsize);
+
+	nulls = symcaps = 0;
+	objcap = title = 1;
+	descapndx = -1;
+
+	/*
+	 * Traverse the capabilities section printing each capability group.
+	 * The first capabilities group defines any object capabilities.  Any
+	 * following groups define symbol capabilities.  In the case where no
+	 * object capabilities exist, but symbol capabilities do, a single
+	 * CA_SUNW_NULL terminator for the object capabilities exists.
+	 */
+	for (cnum = 0; cnum < capnum; cap++, cnum++) {
+		if (cap->c_tag == CA_SUNW_NULL) {
+			/*
+			 * A CA_SUNW_NULL tag terminates a capabilities group.
+			 * If the first capabilities tag is CA_SUNW_NULL, then
+			 * no object capabilities exist.
+			 */
+			if ((nulls++ == 0) && (cnum == 0))
+				objcap = 0;
+			title = 1;
+		} else {
+			if (title) {
+				if (nulls == 0) {
+					/*
+					 * If this capabilities group represents
+					 * the object capabilities (i.e., no
+					 * CA_SUNW_NULL tag has been processed
+					 * yet), then display an object
+					 * capabilities title.
+					 */
+					dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
+					dbg_print(0,
+					    MSG_INTL(MSG_OBJ_CAP_TITLE));
+				} else {
+					/*
+					 * If this is a symbols capabilities
+					 * group (i.e., a CA_SUNW_NULL tag has
+					 * already be found that terminates
+					 * the object capabilities group), then
+					 * display a symbol capabilities title,
+					 * and retain this capabilities index
+					 * for later processing.
+					 */
+					dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
+					dbg_print(0,
+					    MSG_INTL(MSG_SYM_CAP_TITLE));
+					descapndx = cnum;
+				}
+				Elf_cap_title(0);
+				title = 0;
+			}
+
+			/*
+			 * Print the capabilities data.
+			 *
+			 * Note that CA_SUNW_PLAT, CA_SUNW_MACH and CA_SUNW_ID
+			 * entries require a string table, which should have
+			 * already been established.
+			 */
+			if ((strs == NULL) && ((cap->c_tag == CA_SUNW_PLAT) ||
+			    (cap->c_tag == CA_SUNW_MACH) ||
+			    (cap->c_tag == CA_SUNW_ID))) {
+				(void) fprintf(stderr,
+				    MSG_INTL(MSG_WARN_INVCAP4), file,
+				    EC_WORD(elf_ndxscn(ccache->c_scn)),
+				    ccache->c_name, EC_WORD(cshdr->sh_info));
+			}
+			Elf_cap_entry(0, cap, cnum, strs, strs_size,
+			    ehdr->e_machine);
+		}
+
+		/*
+		 * If this CA_SUNW_NULL tag terminates a symbol capabilities
+		 * group, determine the associated symbols.
+		 */
+		if ((cap->c_tag == CA_SUNW_NULL) && (nulls > 1) &&
+		    (descapndx != -1)) {
+			Capinfo	*cip;
+			Word	inum;
+
+			symcaps++;
+
+			/*
+			 * Make sure we've discovered a SHT_SUNW_capinfo table.
+			 */
+			if ((cip = capinfo) == NULL) {
+				(void) fprintf(stderr,
+				    MSG_INTL(MSG_ERR_INVCAP), file,
+				    ccache->c_name, EC_WORD(cshdr->sh_link));
+				return (0);
+			}
+
+			/*
+			 * Determine what symbols reference this capabilities
+			 * group.
+			 */
+			dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
+			dbg_print(0, MSG_INTL(MSG_CAPINFO_ENTRIES));
+			Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
+
+			for (inum = 1, cip++; inum < capinfonum;
+			    inum++, cip++) {
+				Word	gndx = (Word)ELF_C_GROUP(*cip);
+
+				if (gndx && (gndx == descapndx)) {
+					output_symbol(&state, inum, 0,
+					    inum, state.sym + inum);
+				}
+			}
+			descapndx = -1;
+			continue;
+		}
+
+		/*
+		 * An SF1_SUNW_ADDR32 software capability tag in a 32-bit
+		 * object is suspicious as it has no effect.
+		 */
+		if ((cap->c_tag == CA_SUNW_SF_1) &&
+		    (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+		    (cap->c_un.c_val & SF1_SUNW_ADDR32)) {
+			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INADDR32SF1),
+			    file, ccache->c_name);
+		}
+	}
+
+	/*
+	 * If this is a dynamic object, with symbol capabilities, then a
+	 * .SUNW_capchain section should exist.  This section contains a chain
+	 * of symbol indexes for each capabilities family.  This is the list
+	 * that is searched by ld.so.1 to determine the best capabilities
+	 * candidate.
+	 *
+	 * Note, more than one capabilities lead symbol can point to the same
+	 * family chain.  For example, a weak/global pair of symbols can both
+	 * represent the same family of capabilities symbols.  Therefore, to
+	 * display all possible families we traverse the capabilities
+	 * information section looking for CAPINFO_SUNW_GLOB lead symbols.
+	 * From these we determine the associated capabilities chain to inspect.
+	 */
+	if (symcaps &&
+	    ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) {
+		Capinfo		*cip;
+		Capchain	*chain;
+		Cache   	*chcache;
+		Shdr		*chshdr;
+		Word		chainnum, inum;
+
+		/*
+		 * Validate that the sh_info field of the capabilities
+		 * information section points to a capabilities chain section.
+		 */
+		if (cishdr->sh_info >= shnum) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
+			    file, cicache->c_name, EC_WORD(cishdr->sh_info));
+			return (0);
+		}
+
+		chcache = &cache[cishdr->sh_info];
+		chshdr = chcache->c_shdr;
+
+		if (chshdr->sh_type != SHT_SUNW_capchain) {
+			(void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAPINFO2),
+			    file, cicache->c_name, EC_WORD(cishdr->sh_info));
+			return (0);
+		}
+
+		chainnum = (Word)(chshdr->sh_size / chshdr->sh_entsize);
+		chain = (Capchain *)chcache->c_data->d_buf;
+
+		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
+		dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAPCHAIN), chcache->c_name);
+
+		/*
+		 * Traverse the capabilities information section looking for
+		 * CAPINFO_SUNW_GLOB lead capabilities symbols.
+		 */
+		cip = capinfo;
+		for (inum = 1, cip++; inum < capinfonum; inum++, cip++) {
+			const char	*name;
+			Sym		*sym;
+			Word		sndx, cndx;
+			Word		gndx = (Word)ELF_C_GROUP(*cip);
+
+			if ((gndx == 0) || (gndx != CAPINFO_SUNW_GLOB))
+				continue;
+
+			/*
+			 * Determine the symbol that is associated with this
+			 * capability information entry, and use this to
+			 * identify this capability family.
+			 */
+			sym = (Sym *)(state.sym + inum);
+			name = string(cicache, inum, strcache, file,
+			    sym->st_name);
+
+			dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
+			dbg_print(0, MSG_INTL(MSG_CAPCHAIN_TITLE), name);
+			dbg_print(0, MSG_INTL(MSG_CAPCHAIN_ENTRY));
+
+			cndx = (Word)ELF_C_SYM(*cip);
+
+			/*
+			 * Traverse this families chain and identify each
+			 * family member.
+			 */
+			for (;;) {
+				char	_chain[MAXNDXSIZE], _symndx[MAXNDXSIZE];
+
+				if (cndx >= chainnum) {
+					(void) fprintf(stderr,
+					    MSG_INTL(MSG_ERR_INVCAPINFO3), file,
+					    cicache->c_name, EC_WORD(inum),
+					    EC_WORD(cndx));
+					break;
+				}
+				if ((sndx = chain[cndx]) == 0)
+					break;
+
+				/*
+				 * Determine this entries symbol reference.
+				 */
+				if (sndx > state.symn) {
+					(void) fprintf(stderr,
+					    MSG_INTL(MSG_ERR_CHBADSYMNDX), file,
+					    EC_WORD(sndx), chcache->c_name,
+					    EC_WORD(cndx));
+					name = MSG_INTL(MSG_STR_UNKNOWN);
+				} else {
+					sym = (Sym *)(state.sym + sndx);
+					name = string(chcache, sndx,
+					    strcache, file, sym->st_name);
+				}
+
+				/*
+				 * Display the family member.
+				 */
+				(void) snprintf(_chain, MAXNDXSIZE,
+				    MSG_ORIG(MSG_FMT_INTEGER), cndx);
+				(void) snprintf(_symndx, MAXNDXSIZE,
+				    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(sndx));
+				dbg_print(0, MSG_ORIG(MSG_FMT_CHAIN_INFO),
+				    _chain, _symndx, demangle(name, flags));
+
+				cndx++;
+			}
+		}
+	}
+	return (objcap);
+}
+
+/*
+ * Print the capabilities.
+ *
+ * A .SUNW_cap section can contain one or more, CA_SUNW_NULL terminated,
+ * capabilities groups.  The first group defines the object capabilities.
+ * This group defines the minimum capability requirements of the entire
+ * object file.  If this is a dynamic object, this group should be associated
+ * with a PT_SUNWCAP program header.
+ *
+ * Additional capabilities groups define the association of individual symbols
+ * to specific capabilities.
  */
 static void
 cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr,
-    Elf *elf)
+    uchar_t osabi, Elf *elf, uint_t flags)
 {
 	Word		cnt;
 	Shdr		*cshdr = NULL;
@@ -896,7 +1622,7 @@
 	Xword		cphdr_sz;
 
 	/*
-	 * Determine if a hardware/software capabilities header exists.
+	 * Determine if a global capabilities header exists.
 	 */
 	if (phnum) {
 		Phdr	*phdr;
@@ -916,84 +1642,52 @@
 	}
 
 	/*
-	 * Determine if a hardware/software capabilities section exists.
+	 * Determine if a capabilities section exists.
 	 */
 	for (cnt = 1; cnt < shnum; cnt++) {
 		Cache	*_cache = &cache[cnt];
 		Shdr	*shdr = _cache->c_shdr;
 
-		if (shdr->sh_type != SHT_SUNW_cap)
-			continue;
-
-		if (cphdr_off && ((cphdr_off < shdr->sh_offset) ||
-		    (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size)))
+		/*
+		 * Process any capabilities information.
+		 */
+		if (shdr->sh_type == SHT_SUNW_cap) {
+			if (cap_section(file, cache, shnum, _cache, osabi,
+			    ehdr, flags)) {
+				/*
+				 * If this section defined an object capability
+				 * group, retain the section information for
+				 * program header validation.
+				 */
+				ccache = _cache;
+				cshdr = shdr;
+			}
 			continue;
-
-		if (_cache->c_data == NULL)
-			continue;
-
-		ccache = _cache;
-		cshdr = shdr;
-		break;
+		}
 	}
 
 	if ((cshdr == NULL) && (cphdr_off == 0))
 		return;
 
-	/*
-	 * Print the hardware/software capabilities section.
-	 */
-	if (cshdr) {
-		Word	ndx, capn;
-		Cap	*cap = (Cap *)ccache->c_data->d_buf;
-
-		if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) {
-			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
-			    file, ccache->c_name);
-			return;
-		}
-
-		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
-		dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name);
-
-		Elf_cap_title(0);
-
-		capn = (Word)(cshdr->sh_size / cshdr->sh_entsize);
-
-		for (ndx = 0; ndx < capn; cap++, ndx++) {
-			if (cap->c_tag == CA_SUNW_NULL)
-				continue;
-
-			Elf_cap_entry(0, cap, ndx, ehdr->e_machine);
-
-			/*
-			 * An SF1_SUNW_ADDR32 software capability in a 32-bit
-			 * object is suspicious as it has no effect.
-			 */
-			if ((cap->c_tag == CA_SUNW_SF_1) &&
-			    (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
-			    (cap->c_un.c_val & SF1_SUNW_ADDR32)) {
-				(void) fprintf(stderr,
-				    MSG_INTL(MSG_WARN_INADDR32SF1),
-				    file, ccache->c_name);
-			}
-		}
-	} else
+	if (cphdr_off && (cshdr == NULL))
 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file);
 
 	/*
-	 * If this object is an executable or shared object, then the
-	 * hardware/software capabilities section should have an accompanying
-	 * program header.
+	 * If this object is an executable or shared object, and it provided
+	 * an object capabilities group, then the group should have an
+	 * accompanying PT_SUNWCAP program header.
 	 */
 	if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) {
-		if (cphdr_off == 0)
+		if (cphdr_off == 0) {
 			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2),
-			    file, ccache->c_name);
-		else if ((cphdr_off != cshdr->sh_offset) ||
-		    (cphdr_sz != cshdr->sh_size))
+			    file, EC_WORD(elf_ndxscn(ccache->c_scn)),
+			    ccache->c_name);
+		} else if ((cphdr_off != cshdr->sh_offset) ||
+		    (cphdr_sz != cshdr->sh_size)) {
 			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3),
-			    file, ccache->c_name);
+			    file, EC_WORD(elf_ndxscn(ccache->c_scn)),
+			    ccache->c_name);
+		}
 	}
 }
 
@@ -1532,359 +2226,6 @@
 }
 
 /*
- * Initialize a symbol table state structure
- *
- * entry:
- *	state - State structure to be initialized
- *	cache - Cache of all section headers
- *	shnum - # of sections in cache
- *	secndx - Index of symbol table section
- *	ehdr - ELF header for file
- *	versym - Information about versym section
- *	file - Name of file
- *	flags - Command line option flags
- */
-static int
-init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx,
-    Ehdr *ehdr, uchar_t osabi, VERSYM_STATE *versym, const char *file,
-    uint_t flags)
-{
-	Shdr *shdr;
-
-	state->file = file;
-	state->ehdr = ehdr;
-	state->cache = cache;
-	state->osabi = osabi;
-	state->shnum = shnum;
-	state->seccache = &cache[secndx];
-	state->secndx = secndx;
-	state->secname = state->seccache->c_name;
-	state->flags = flags;
-	state->shxndx.checked = 0;
-	state->shxndx.data = NULL;
-	state->shxndx.n = 0;
-
-	shdr = state->seccache->c_shdr;
-
-	/*
-	 * Check the symbol data and per-item size.
-	 */
-	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
-		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
-		    file, state->secname);
-		return (0);
-	}
-	if (state->seccache->c_data == NULL)
-		return (0);
-
-	/* LINTED */
-	state->symn = (Word)(shdr->sh_size / shdr->sh_entsize);
-	state->sym = (Sym *)state->seccache->c_data->d_buf;
-
-	/*
-	 * Check associated string table section.
-	 */
-	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
-		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
-		    file, state->secname, EC_WORD(shdr->sh_link));
-		return (0);
-	}
-
-	/*
-	 * Determine if there is a associated Versym section
-	 * with this Symbol Table.
-	 */
-	if (versym->cache &&
-	    (versym->cache->c_shdr->sh_link == state->secndx))
-		state->versym = versym;
-	else
-		state->versym = NULL;
-
-
-	return (1);
-}
-
-/*
- * Determine the extended section index used for symbol tables entries.
- */
-static void
-symbols_getxindex(SYMTBL_STATE *state)
-{
-	uint_t	symn;
-	Word	symcnt;
-
-	state->shxndx.checked = 1;   /* Note that we've been called */
-	for (symcnt = 1; symcnt < state->shnum; symcnt++) {
-		Cache	*_cache = &state->cache[symcnt];
-		Shdr	*shdr = _cache->c_shdr;
-
-		if ((shdr->sh_type != SHT_SYMTAB_SHNDX) ||
-		    (shdr->sh_link != state->secndx))
-			continue;
-
-		if ((shdr->sh_entsize) &&
-		    /* LINTED */
-		    ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0))
-			continue;
-
-		if (_cache->c_data == NULL)
-			continue;
-
-		state->shxndx.data = _cache->c_data->d_buf;
-		state->shxndx.n = symn;
-		return;
-	}
-}
-
-/*
- * Produce a line of output for the given symbol
- *
- * entry:
- *	state - Symbol table state
- *	symndx - Index of symbol within the table
- *	info - Value of st_info (indicates local/global range)
- *	symndx_disp - Index to display. This may not be the same
- *		as symndx if the display is relative to the logical
- *		combination of the SUNW_ldynsym/dynsym tables.
- *	sym - Symbol to display
- */
-static void
-output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx,
-    Sym *sym)
-{
-	/*
-	 * Symbol types for which we check that the specified
-	 * address/size land inside the target section.
-	 */
-	static const int addr_symtype[] = {
-		0,			/* STT_NOTYPE */
-		1,			/* STT_OBJECT */
-		1,			/* STT_FUNC */
-		0,			/* STT_SECTION */
-		0,			/* STT_FILE */
-		1,			/* STT_COMMON */
-		0,			/* STT_TLS */
-		0,			/* 7 */
-		0,			/* 8 */
-		0,			/* 9 */
-		0,			/* 10 */
-		0,			/* 11 */
-		0,			/* 12 */
-		0,			/* STT_SPARC_REGISTER */
-		0,			/* 14 */
-		0,			/* 15 */
-	};
-#if STT_NUM != (STT_TLS + 1)
-#error "STT_NUM has grown. Update addr_symtype[]"
-#endif
-
-	char		index[MAXNDXSIZE];
-	const char	*symname, *sec;
-	Versym		verndx;
-	int		gnuver;
-	uchar_t		type;
-	Shdr		*tshdr;
-	Word		shndx;
-	Conv_inv_buf_t	inv_buf;
-
-	/* Ensure symbol index is in range */
-	if (symndx >= state->symn) {
-		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX),
-		    state->file, state->secname, EC_WORD(symndx));
-		return;
-	}
-
-	/*
-	 * If we are using extended symbol indexes, find the
-	 * corresponding SHN_SYMTAB_SHNDX table.
-	 */
-	if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0))
-		symbols_getxindex(state);
-
-	/* LINTED */
-	symname = string(state->seccache, symndx,
-	    &state->cache[state->seccache->c_shdr->sh_link], state->file,
-	    sym->st_name);
-
-	tshdr = NULL;
-	sec = NULL;
-
-	if (state->ehdr->e_type == ET_CORE) {
-		sec = (char *)MSG_INTL(MSG_STR_UNKNOWN);
-	} else if (state->flags & FLG_CTL_FAKESHDR) {
-		/*
-		 * If we are using fake section headers derived from
-		 * the program headers, then the section indexes
-		 * in the symbols do not correspond to these headers.
-		 * The section names are not available, so all we can
-		 * do is to display them in numeric form.
-		 */
-		sec = conv_sym_shndx(state->osabi, state->ehdr->e_machine,
-		    sym->st_shndx, CONV_FMT_DECIMAL, &inv_buf);
-	} else if ((sym->st_shndx < SHN_LORESERVE) &&
-	    (sym->st_shndx < state->shnum)) {
-		shndx = sym->st_shndx;
-		tshdr = state->cache[shndx].c_shdr;
-		sec = state->cache[shndx].c_name;
-	} else if (sym->st_shndx == SHN_XINDEX) {
-		if (state->shxndx.data) {
-			Word	_shxndx;
-
-			if (symndx > state->shxndx.n) {
-				(void) fprintf(stderr,
-				    MSG_INTL(MSG_ERR_BADSYMXINDEX1),
-				    state->file, state->secname,
-				    EC_WORD(symndx));
-			} else if ((_shxndx =
-			    state->shxndx.data[symndx]) > state->shnum) {
-				(void) fprintf(stderr,
-				    MSG_INTL(MSG_ERR_BADSYMXINDEX2),
-				    state->file, state->secname,
-				    EC_WORD(symndx), EC_WORD(_shxndx));
-			} else {
-				shndx = _shxndx;
-				tshdr = state->cache[shndx].c_shdr;
-				sec = state->cache[shndx].c_name;
-			}
-		} else {
-			(void) fprintf(stderr,
-			    MSG_INTL(MSG_ERR_BADSYMXINDEX3),
-			    state->file, state->secname, EC_WORD(symndx));
-		}
-	} else if ((sym->st_shndx < SHN_LORESERVE) &&
-	    (sym->st_shndx >= state->shnum)) {
-		(void) fprintf(stderr,
-		    MSG_INTL(MSG_ERR_BADSYM5), state->file,
-		    state->secname, EC_WORD(symndx),
-		    demangle(symname, state->flags), sym->st_shndx);
-	}
-
-	/*
-	 * If versioning is available display the
-	 * version index. If not, then use 0.
-	 */
-	if (state->versym) {
-		Versym test_verndx;
-
-		verndx = test_verndx = state->versym->data[symndx];
-		gnuver = state->versym->gnu_full;
-
-		/*
-		 * Check to see if this is a defined symbol with a
-		 * version index that is outside the valid range for
-		 * the file. The interpretation of this depends on
-		 * the style of versioning used by the object.
-		 *
-		 * Versions >= VER_NDX_LORESERVE have special meanings,
-		 * and are exempt from this checking.
-		 *
-		 * GNU style version indexes use the top bit of the
-		 * 16-bit index value (0x8000) as the "hidden bit".
-		 * We must mask off this bit in order to compare
-		 * the version against the maximum value.
-		 */
-		if (gnuver)
-			test_verndx &= ~0x8000;
-
-		if ((test_verndx > state->versym->max_verndx) &&
-		    (verndx < VER_NDX_LORESERVE))
-			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER),
-			    state->file, state->secname, EC_WORD(symndx),
-			    EC_HALF(test_verndx), state->versym->max_verndx);
-	} else {
-		verndx = 0;
-		gnuver = 0;
-	}
-
-	/*
-	 * Error checking for TLS.
-	 */
-	type = ELF_ST_TYPE(sym->st_info);
-	if (type == STT_TLS) {
-		if (tshdr &&
-		    (sym->st_shndx != SHN_UNDEF) &&
-		    ((tshdr->sh_flags & SHF_TLS) == 0)) {
-			(void) fprintf(stderr,
-			    MSG_INTL(MSG_ERR_BADSYM3), state->file,
-			    state->secname, EC_WORD(symndx),
-			    demangle(symname, state->flags));
-		}
-	} else if ((type != STT_SECTION) && sym->st_size &&
-	    tshdr && (tshdr->sh_flags & SHF_TLS)) {
-		(void) fprintf(stderr,
-		    MSG_INTL(MSG_ERR_BADSYM4), state->file,
-		    state->secname, EC_WORD(symndx),
-		    demangle(symname, state->flags));
-	}
-
-	/*
-	 * If a symbol with non-zero size has a type that
-	 * specifies an address, then make sure the location
-	 * it references is actually contained within the
-	 * section.  UNDEF symbols don't count in this case,
-	 * so we ignore them.
-	 *
-	 * The meaning of the st_value field in a symbol
-	 * depends on the type of object. For a relocatable
-	 * object, it is the offset within the section.
-	 * For sharable objects, it is the offset relative to
-	 * the base of the object, and for other types, it is
-	 * the virtual address. To get an offset within the
-	 * section for non-ET_REL files, we subtract the
-	 * base address of the section.
-	 */
-	if (addr_symtype[type] && (sym->st_size > 0) &&
-	    (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) ||
-	    (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) {
-		Word v = sym->st_value;
-			if (state->ehdr->e_type != ET_REL)
-				v -= tshdr->sh_addr;
-		if (((v + sym->st_size) > tshdr->sh_size)) {
-			(void) fprintf(stderr,
-			    MSG_INTL(MSG_ERR_BADSYM6), state->file,
-			    state->secname, EC_WORD(symndx),
-			    demangle(symname, state->flags),
-			    EC_WORD(shndx), EC_XWORD(tshdr->sh_size),
-			    EC_XWORD(sym->st_value), EC_XWORD(sym->st_size));
-		}
-	}
-
-	/*
-	 * A typical symbol table uses the sh_info field to indicate one greater
-	 * than the symbol table index of the last local symbol, STB_LOCAL.
-	 * Therefore, symbol indexes less than sh_info should have local
-	 * binding.  Symbol indexes greater than, or equal to sh_info, should
-	 * have global binding.  Note, we exclude UNDEF/NOTY symbols with zero
-	 * value and size, as these symbols may be the result of an mcs(1)
-	 * section deletion.
-	 */
-	if (info) {
-		uchar_t	bind = ELF_ST_BIND(sym->st_info);
-
-		if ((symndx < info) && (bind != STB_LOCAL)) {
-			(void) fprintf(stderr,
-			    MSG_INTL(MSG_ERR_BADSYM7), state->file,
-			    state->secname, EC_WORD(symndx),
-			    demangle(symname, state->flags), EC_XWORD(info));
-
-		} else if ((symndx >= info) && (bind == STB_LOCAL) &&
-		    ((sym->st_shndx != SHN_UNDEF) ||
-		    (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) ||
-		    (sym->st_size != 0) || (sym->st_value != 0))) {
-			(void) fprintf(stderr,
-			    MSG_INTL(MSG_ERR_BADSYM8), state->file,
-			    state->secname, EC_WORD(symndx),
-			    demangle(symname, state->flags), EC_XWORD(info));
-		}
-	}
-
-	(void) snprintf(index, MAXNDXSIZE,
-	    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx));
-	Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, state->osabi,
-	    state->ehdr->e_machine, sym, verndx, gnuver, sec, symname);
-}
-
-/*
  * Search for and process any symbol tables.
  */
 void
@@ -2039,7 +2380,7 @@
 		}
 		Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
 
-		/* If not first one, insert a line of whitespace */
+		/* If not first one, insert a line of white space */
 		if (output_cnt++ > 0)
 			dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
 
@@ -2315,7 +2656,6 @@
 	}
 }
 
-
 /*
  * There are some DT_ entries that have corresponding symbols
  * (e.g. DT_INIT and _init). It is expected that these items will
@@ -2368,7 +2708,6 @@
 	}
 }
 
-
 /*
  * Search for and process a .dynamic section.
  */
@@ -2388,6 +2727,8 @@
 		Cache	*rel;
 		Cache	*rela;
 		Cache	*sunw_cap;
+		Cache	*sunw_capinfo;
+		Cache	*sunw_capchain;
 		Cache	*sunw_ldynsym;
 		Cache	*sunw_move;
 		Cache	*sunw_syminfo;
@@ -2484,6 +2825,8 @@
 		GRAB(SHT_SUNW_move,	sunw_move);
 		GRAB(SHT_PREINIT_ARRAY,	preinit_array);
 		GRAB(SHT_SUNW_cap,	sunw_cap);
+		GRAB(SHT_SUNW_capinfo,	sunw_capinfo);
+		GRAB(SHT_SUNW_capchain,	sunw_capchain);
 		GRAB(SHT_SUNW_LDYNSYM,	sunw_ldynsym);
 		GRAB(SHT_SUNW_syminfo,	sunw_syminfo);
 		GRAB(SHT_SUNW_symsort,	sunw_symsort);
@@ -2674,7 +3017,7 @@
 			/*
 			 * Cases below this point are strictly sanity checking,
 			 * and do not generate a name string. The TEST_ macros
-			 * are used to hide the boilerplate arguments neeeded
+			 * are used to hide the boiler plate arguments neeeded
 			 * by dyn_test().
 			 */
 #define	TEST_ADDR(_sh_type, _sec_field) \
@@ -2774,6 +3117,14 @@
 				TEST_ADDR(SHT_SUNW_cap, sunw_cap);
 				break;
 
+			case DT_SUNW_CAPINFO:
+				TEST_ADDR(SHT_SUNW_capinfo, sunw_capinfo);
+				break;
+
+			case DT_SUNW_CAPCHAIN:
+				TEST_ADDR(SHT_SUNW_capchain, sunw_capchain);
+				break;
+
 			case DT_SUNW_SYMTAB:
 				TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym);
 				break;
@@ -4657,7 +5008,7 @@
 		checksum(elf);
 
 	if ((flags & FLG_SHOW_CAP) && (osabi == ELFOSABI_SOLARIS))
-		cap(file, cache, shnum, phnum, ehdr, elf);
+		cap(file, cache, shnum, phnum, ehdr, osabi, elf, flags);
 
 	if ((flags & FLG_SHOW_UNWIND) &&
 	    ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX)))
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -42,8 +42,7 @@
 @ MSG_USAGE_DETAIL5	"\t[-g]\t\tdump the contents of the .group sections\n"
 @ MSG_USAGE_DETAIL6	"\t[-G]\t\tdump the contents of the .got section\n"
 @ MSG_USAGE_DETAIL7	"\t[-h]\t\tdump the contents of the .hash section\n"
-@ MSG_USAGE_DETAIL8	"\t[-H]\t\tdump the contents of the .SUNW_hwcap \
-			 section\n"
+@ MSG_USAGE_DETAIL8	"\t[-H]\t\tdump the contents of the .SUNW_cap section\n"
 @ MSG_USAGE_DETAIL9	"\t[-i]\t\tdump the contents of the .interp section\n"
 @ MSG_USAGE_DETAIL10	"\t[-I index]\tqualify an option with an index\n"
 @ MSG_USAGE_DETAIL11	"\t[-l]\t\tdump with no truncated section names\n"
@@ -75,7 +74,8 @@
 # Errors
 
 @ MSG_ERR_BADFILE	"%s: invalid file type\n"
-@ MSG_ERR_BADREL1       "%s: bad relocation entry: %s: relocation requires symbol\n"
+@ MSG_ERR_BADREL1	"%s: bad relocation entry: %s: relocation requires \
+			 symbol\n"
 @ MSG_ERR_NOSHDR	"%s: section headers are not present: synthesizing \
 			 from program headers (-P option)\n"
 @ MSG_ERR_PNEEDSPH	"%s: file without program headers is incompatible \
@@ -92,21 +92,21 @@
 @ MSG_ERR_BADSHINFO	"%s: %s: invalid sh_info: %d\n"
 @ MSG_ERR_BADSHTYPE	"%s: %s: invalid sh_type: %d\n"
 @ MSG_ERR_BADALIGN	"%s: %s: bad sh_offset alignment\n"
-@ MSG_ERR_BADSYM2	"%s: %s: index[%d]: bad symbol entry: %s: must be SHN_COMMON or \
-			 defined in SHT_NOBITS section\n"
-@ MSG_ERR_BADSYM3	"%s: %s: index[%d]: bad symbol entry: %s: must be defined in \
-			 a SHF_TLS section\n"
-@ MSG_ERR_BADSYM4	"%s: %s: index[%d]: bad symbol entry: %s: must be defined in \
-			 a non-SHF_TLS section\n"
+@ MSG_ERR_BADSYM2	"%s: %s: index[%d]: bad symbol entry: %s: must be \
+			 SHN_COMMON or defined in SHT_NOBITS section\n"
+@ MSG_ERR_BADSYM3	"%s: %s: index[%d]: bad symbol entry: %s: must be \
+			 defined in a SHF_TLS section\n"
+@ MSG_ERR_BADSYM4	"%s: %s: index[%d]: bad symbol entry: %s: must be \
+			 defined in a non-SHF_TLS section\n"
 @ MSG_ERR_BADSYM5	"%s: %s: index[%d]: bad symbol entry: %s: \
 			 invalid shndx: %d\n"
 @ MSG_ERR_BADSYM6	"%s: %s: index[%d]: bad symbol entry: %s: section[%d] \
 			 size: %#llx: symbol (address %#llx, size %#llx) \
 			 lies outside of containing section\n"
-@ MSG_ERR_BADSYM7	"%s: %s: index[%d]: suspicious global symbol entry: %s: lies \
-			 within local symbol range (index < %lld)\n"
-@ MSG_ERR_BADSYM8	"%s: %s: index[%d]: suspicious local symbol entry: %s: lies \
-			 within global symbol range (index >= %lld)\n"
+@ MSG_ERR_BADSYM7	"%s: %s: index[%d]: suspicious global symbol entry: \
+			 %s: lies within local symbol range (index < %lld)\n"
+@ MSG_ERR_BADSYM8	"%s: %s: index[%d]: suspicious local symbol entry: \
+			 %s: lies within global symbol range (index >= %lld)\n"
 
 @ MSG_ERR_RELBADSYMNDX	"%s: bad symbol reference %d: from relocation \
 			 entry: %d\n"
@@ -127,7 +127,7 @@
 @ MSG_ERR_NODYNSYM	"%s: %s: associated SHT_DYNSYM section not found\n"
 @ MSG_ERR_BADNDXSEC	"%s: %s: unexpected section type associated with \
 			 index section: %s\n"
-@ MSG_ERR_BADSORTNDX	"%s: %s: sort section has bad symbol index: %d\n"
+@ MSG_ERR_BADSYMNDX	"%s: %s: bad symbol index: %d\n"
 @ MSG_ERR_BADVER	"%s: %s: index[%d]: version %d is out of range: \
 			 version definitions available: 0-%d\n"
 @ MSG_ERR_NOTSTRTAB	"%s: section[%d] is not a string table as expected \
@@ -150,9 +150,10 @@
 			 shdr[%d: %s].sh_entsize (%#llx)\n"
 @ MSG_ERR_DYNSYMVAL	"%s: %s: symbol value does not match \
 			 DT_%s entry: %s: value: %#llx\n"
-@ MSG_ERR_MALSTR	"%s: %s: malformed string table, initial or final byte\n"
+@ MSG_ERR_MALSTR	"%s: %s: malformed string table, initial or final \
+			 byte\n"
 @ MSG_ERR_MULTEHFRMHDR	"%s: [%d: %s] multiple .eh_frame_hdr sections seen \
-			(1 expected)\n"
+			 (1 expected)\n"
 @ MSG_ERR_BADEHFRMPTR	"%s: section[%d: %s] FramePtr (%#llx) does not match \
 			 shdr[%d: %s].sh_addr (%#llx)\n"
 @ MSG_ERR_BADSORT	"%s: %s: index[%d]: invalid sort order\n"
@@ -162,10 +163,12 @@
 @ MSG_WARN_INVINTERP2	"%s: interp section: %s: and PT_INTERP program \
 			 header have conflicting size or offsets\n"
 @ MSG_WARN_INVCAP1	"%s: PT_SUNWCAP header has no associated section\n"
-@ MSG_WARN_INVCAP2	"%s: capabilities section: %s: requires PT_CAP program \
-			 header\n"
-@ MSG_WARN_INVCAP3	"%s: capabilities section: %s: and PT_CAP program \
+@ MSG_WARN_INVCAP2	"%s: capabilities section[%d]: %s: requires PT_CAP \
+			 program header\n"
+@ MSG_WARN_INVCAP3	"%s: capabilities section[%d]: %s: and PT_CAP program \
 			 header have conflicting size or offsets\n"
+@ MSG_WARN_INVCAP4	"%s: capabilities section[%d]: %s: requires string \
+			 table: invalid sh_info: %d\n";
 @ MSG_WARN_INADDR32SF1	"%s: capabilities section %s: software capability \
 			 ADDR32: is ineffective within a 32-bit object\n"
 @ MSG_WARN_MULTEHFRM	"%s: section[%d: %s]: %s object has multiple \
@@ -193,7 +196,8 @@
 @ MSG_ELF_SHDR		"Section Header[%d]:  sh_name: %s"
 @ MSG_ELF_PHDR		"Program Header[%d]:"
 
-@ MSG_ELF_SCN_CAP	"Hardware/Software Capabilities Section:  %s"
+@ MSG_ELF_SCN_CAP	"Capabilities Section:  %s"
+@ MSG_ELF_SCN_CAPCHAIN	"Capabilities Chain Section:  %s"
 @ MSG_ELF_SCN_INTERP	"Interpreter Section:  %s"
 @ MSG_ELF_SCN_VERDEF	"Version Definition Section:  %s"
 @ MSG_ELF_SCN_VERNEED	"Version Needed Section:  %s"
@@ -210,6 +214,23 @@
 @ MSG_ELF_SCN_SYMSORT1	"Symbol Sort Section:  %s (%s)"
 @ MSG_ELF_SCN_SYMSORT2	"Symbol Sort Section:  %s (%s / %s)"
 
+@ MSG_OBJ_CAP_TITLE	" Object Capabilities:"
+@ MSG_SYM_CAP_TITLE	" Symbol Capabilities:"
+@ MSG_CAPINFO_ENTRIES	"  Symbols:"
+@ MSG_CAPCHAIN_TITLE	" Capabilities family: %s"
+@ MSG_CAPCHAIN_ENTRY	"  chainndx  symndx      name"
+@ MSG_ERR_INVCAP	"%s: capabilities section: %s: contains symbol \
+			 capabilities groups, but no capabilities information \
+			 section is defined: invalid sh_link: %d\n"
+@ MSG_ERR_INVCAPINFO1	"%s: capabilities information section: %s: no symbol \
+			 table is defined: invalid sh_link: %d\n"
+@ MSG_ERR_INVCAPINFO2	"%s: capabilities information section: %s: no \
+			 capabilities chain is defined: invalid sh_info: %d\n"
+@ MSG_ERR_INVCAPINFO3	"%s: capabilities information section: %s: index %d: \
+			 bad capabilities chain index defined: %d\n"
+@ MSG_ERR_CHBADSYMNDX	"%s: bad symbol reference %d: from capability chain: \
+			 %s entry: %d\n"
+
 @ MSG_ELF_HASH_BKTS1	"%10.10s  buckets contain %8d symbols"
 @ MSG_ELF_HASH_BKTS2	"%10.10s  buckets         %8d symbols (globals)"
 @ MSG_ELF_HASH_INFO	"    bucket  symndx      name"
@@ -274,7 +295,7 @@
 			 offset: 0x%x datasize: 0x%x\n"
 @ MSG_NOTE_BADCOREARCH	"%s: elfdump core file note support not available for \
 			 architecture: %s\n"
-@ MSG_NOTE_BADCOREDATA	"%s: elfdump core file note data trunctated or \
+@ MSG_NOTE_BADCOREDATA	"%s: elfdump core file note data truncated or \
 			 otherwise malformed\n"
 
 @ _END_
@@ -331,6 +352,7 @@
 @ MSG_FMT_INDEXRNG	"[%d-%d]"
 @ MSG_FMT_INTEGER	" %d"
 @ MSG_FMT_HASH_INFO	"%10.10s  %-10s  %s"
+@ MSG_FMT_CHAIN_INFO	"%10.10s  %-10s  %s"
 @ MSG_FMT_ARSYM1	"%10.10s  0x%8.8x  (%s):%s"
 @ MSG_FMT_ARSYM2	"%10.10s  0x%8.8x"
 @ MSG_FMT_ARNAME	"%s(%s)"
@@ -384,7 +406,7 @@
 @ MSG_UNW_FDECFI	"   CallFrameInstructions:"
 
 # Unwind section Call Frame Instructions. These all start with a leading
-# "%*s%s", used to insert leading whitespace and the opcode name.
+# "%*s%s", used to insert leading white space and the opcode name.
 
 @ MSG_CFA_ADV_LOC	"%*s%s: %s + %llu => %#llx"
 @ MSG_CFA_CFAOFF	"%*s%s: %s, cfa%+lld"
@@ -590,6 +612,8 @@
 
 # Names of fake sections generated from program header data
 @ MSG_PHDRNAM_CAP		".SUNW_cap(phdr)"
+@ MSG_PHDRNAM_CAPINFO		".SUNW_capinfo(phdr)"
+@ MSG_PHDRNAM_CAPCHAIN		".SUNW_capchain(phdr)"
 @ MSG_PHDRNAM_DYN		".dynamic(phdr)"
 @ MSG_PHDRNAM_DYNSTR		".dynstr(phdr)"
 @ MSG_PHDRNAM_DYNSYM		".dynsym(phdr)"
--- a/usr/src/cmd/sgs/elfdump/common/fake_shdr.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfdump/common/fake_shdr.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -120,16 +120,18 @@
 	SINFO_T_VERSYM =	11,
 	SINFO_T_INTERP =	12,
 	SINFO_T_CAP =		13,
-	SINFO_T_UNWIND =	14,
-	SINFO_T_MOVE =		15,
-	SINFO_T_REL =		16,
-	SINFO_T_RELA =		17,
-	SINFO_T_PREINITARR =	18,
-	SINFO_T_INITARR =	19,
-	SINFO_T_FINIARR =	20,
-	SINFO_T_NOTE =		21,
+	SINFO_T_CAPINFO =	14,
+	SINFO_T_CAPCHAIN =	15,
+	SINFO_T_UNWIND =	16,
+	SINFO_T_MOVE =		17,
+	SINFO_T_REL =		18,
+	SINFO_T_RELA =		19,
+	SINFO_T_PREINITARR =	20,
+	SINFO_T_INITARR =	21,
+	SINFO_T_FINIARR =	22,
+	SINFO_T_NOTE =		23,
 
-	SINFO_T_NUM =		22 /* Count of items. Must come last */
+	SINFO_T_NUM =		24 /* Count of items. Must come last */
 } SINFO_TYPE;
 
 
@@ -225,13 +227,21 @@
 	{ MSG_ORIG(MSG_PHDRNAM_CAP), SHT_SUNW_cap, SHF_ALLOC,
 	    sizeof (Addr), sizeof (Cap), ELF_T_CAP },
 
+	/* SINFO_T_CAPINFO */
+	{ MSG_ORIG(MSG_PHDRNAM_CAPINFO), SHT_SUNW_capinfo, SHF_ALLOC,
+	    FAKE_M_WORD_ALIGN, sizeof (Capinfo), ELF_T_WORD },
+
+	/* SINFO_T_CAPCHAIN */
+	{ MSG_ORIG(MSG_PHDRNAM_CAPCHAIN), SHT_SUNW_capchain, SHF_ALLOC,
+	    FAKE_M_WORD_ALIGN, sizeof (Capchain), ELF_T_WORD },
+
 	/* SINFO_T_UNWIND */
 	{ MSG_ORIG(MSG_PHDRNAM_UNWIND), SHT_AMD64_UNWIND, SHF_ALLOC,
 	    sizeof (Addr), 0, ELF_T_BYTE },
 
 	/* SINFO_T_MOVE */
 	{ MSG_ORIG(MSG_PHDRNAM_MOVE), SHT_SUNW_move, SHF_ALLOC,
-	    sizeof (Lword), sizeof (Move),  ELF_T_MOVE },
+	    sizeof (Lword), sizeof (Move), ELF_T_MOVE },
 
 	/* SINFO_T_REL */
 	{ MSG_ORIG(MSG_PHDRNAM_REL), SHT_REL, SHF_ALLOC,
@@ -1091,6 +1101,8 @@
 		SINFO	versym;
 		SINFO	interp;
 		SINFO	cap;
+		SINFO	capinfo;
+		SINFO	capchain;
 		SINFO	unwind;
 		SINFO	move;
 		SINFO	rel;
@@ -1267,6 +1279,16 @@
 				sec.preinitarr.size = dyn->d_un.d_val;
 				break;
 
+			case DT_SUNW_CAPINFO:
+				sec.capinfo.type = SINFO_T_CAPINFO;
+				sec.capinfo.vaddr = dyn->d_un.d_ptr;
+				break;
+
+			case DT_SUNW_CAPCHAIN:
+				sec.capchain.type = SINFO_T_CAPCHAIN;
+				sec.capchain.vaddr = dyn->d_un.d_ptr;
+				break;
+
 			case DT_SUNW_SYMTAB:
 				sec.ldynsym.type = SINFO_T_LDYNSYM;
 				sec.ldynsym.vaddr = dyn->d_un.d_ptr;
--- a/usr/src/cmd/sgs/elfedit/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -46,7 +46,7 @@
 		$(CPPFLAGS.master) -I$(ELFCAP)
 LLDFLAGS =	$(VAR_ELFEDIT_LLDFLAGS)
 LLDFLAGS64 =	$(VAR_ELFEDIT_LLDFLAGS64)
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) -M$(MAPFILE) $(LLDFLAGS)
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) -M$(MAPFILE) $(LLDFLAGS)
 LDLIBS +=	$(ELFLIBDIR) -lelf $(LDDBGLIBDIR) $(LDDBG_LIB) \
 		    $(CONVLIBDIR) $(CONV_LIB) -ltecla
 
--- a/usr/src/cmd/sgs/elfedit/common/elfconst.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/common/elfconst.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -408,8 +408,9 @@
 	LC(ELFEDIT_CONST_SYMINFO_BT,		conv_iter_syminfo_boundto);
 	LC(ELFEDIT_CONST_SYMINFO_FLG,		conv_iter_syminfo_flags);
 	LC(ELFEDIT_CONST_CA,			conv_iter_cap_tags);
-	LC_MACH(ELFEDIT_CONST_AV,		conv_iter_cap_val_hw1);
+	LC_MACH(ELFEDIT_CONST_HW1_SUNW,		conv_iter_cap_val_hw1);
 	LC(ELFEDIT_CONST_SF1_SUNW,		conv_iter_cap_val_sf1);
+	LC_MACH(ELFEDIT_CONST_HW2_SUNW,		conv_iter_cap_val_hw2);
 
 #undef LC
 #undef LC_OS
--- a/usr/src/cmd/sgs/elfedit/common/elfedit.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/common/elfedit.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -86,7 +86,8 @@
 @ MSG_DEBUG_UNLINKFILE	"unlink unsaved output file: %s\n";
 @ MSG_DEBUG_VERSION	"%d-bit version\n"
 @ MSG_DEBUG_READONLY	"session is readonly\n";
-@ MSG_DEBUG_NOFILE	"no ELF object specified. Limited functionalty is available\n";
+@ MSG_DEBUG_NOFILE	"no ELF object specified. Limited functionality is \
+			 available\n";
 @ MSG_DEBUG_DIRTYEXIT	"discarding unsaved edits\n";
 @ MSG_DEBUG_FNDSEC	"[%d: %s]: section\n"
 @ MSG_DEBUG_FNDCAP	"[%d: %s]: capabilities section\n"
@@ -244,7 +245,7 @@
 @ MSG_HLPFMT_INFILERO	"Input File:  %s (readonly)\n"
 @ MSG_HLPFMT_INFILENONE	"Input File: <not present>\n"
 @ MSG_HLPFMT_OUTFILE	"Output File: %s\n"
-@ MSG_HLPFMT_CNGPENDING	"    (changes pending)\n"   
+@ MSG_HLPFMT_CNGPENDING	"    (changes pending)\n"
 @ MSG_HLPFMT_VARHDR	"\nOptions:\n"
 @ MSG_HLPFMT_AFLG	"    a (Autoprint):    %s\n"
 @ MSG_HLPFMT_DFLG	"    d (Debug):        %s\n"
@@ -424,9 +425,6 @@
    about the available modules and commands and how they can be used\n\
    to edit ELF files.\n"
 
-
-   
-
 @ MSG_SYS_HELP_HELP	"   \
    The sys:help command provides information on elfedit modules\n\
    and commands:\n\
@@ -478,7 +476,7 @@
 @ MSG_SYS_HELP_SET	"\
    Set options that control how elfedit works.\n\
    \n\
-   Most variables accept boolen (true/false) values. The sys:set\n\
+   Most variables accept boolean (true/false) values. The sys:set\n\
    command accepts any of the following as a boolean value:\n\
    0/1, true/false, t/f, yes/no, y/n, on/off.\n\
    \n\
--- a/usr/src/cmd/sgs/elfedit/modules/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/modules/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,12 +18,11 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 include		../../../../../lib/Makefile.lib
 include		../../../Makefile.com
@@ -94,7 +93,7 @@
 		-I../$(SRCBASE)/lib/libc/inc  -D_REENTRANT
 LLDFLAGS =	'-R$$ORIGIN/../../../lib'
 LLDFLAGS64 =	'-R$$ORIGIN/../../../../lib/$(MACH64)'
-LDFLAGS +=	$(USE_PROTO) $(LLDFLAGS)
+LDFLAGS +=	$(CC_USE_PROTO) $(LLDFLAGS)
 DYNFLAGS +=	$(VERSREF)
 
 LINTFLAGS +=	-uaxs $(LDLIBS)
--- a/usr/src/cmd/sgs/elfedit/modules/common/cap.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/modules/common/cap.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -58,6 +58,7 @@
 	/* Commands that embody tag specific knowledge */
 	CAP_CMD_T_HW1 =		5,	/* cap:hw1 */
 	CAP_CMD_T_SF1 =		6,	/* cap:sf1 */
+	CAP_CMD_T_HW2 =		7,	/* cap:hw2 */
 } CAP_CMD_T;
 
 
@@ -102,9 +103,12 @@
 typedef enum {
 	CAP_OPT_F_AND =		1,	/* -and: AND (&) values to dest */
 	CAP_OPT_F_CMP =		2,	/* -cmp: Complement (~) values */
-	CAP_OPT_F_CAPNDX =	4,	/* -capndx: elt is tag index, */
+	CAP_OPT_F_CAPID =	4,	/* -capid id: elt limited to given */
+					/*	capabilities group */
+	CAP_OPT_F_CAPNDX =	8,	/* -capndx: elt is tag index, */
 					/*	not name */
-	CAP_OPT_F_OR =		8,	/* -or: OR (|) values to dest */
+	CAP_OPT_F_OR =		16,	/* -or: OR (|) values to dest */
+	CAP_OPT_F_STRVAL =	32	/* -s: value is string, not integer */
 } cap_opt_t;
 
 
@@ -119,7 +123,13 @@
 		elfedit_section_t *sec;	/* Capabilities section reference */
 		Cap	*data;		/* Start of capabilities section data */
 		Word	num;		/* # Capabilities elts */
+		Boolean	grp_set;	/* TRUE when cap group is set */
+		Word	grp_start_ndx;	/* capabilities group starting index */
+		Word	grp_end_ndx;	/* capabilities group ending index */
 	} cap;
+	struct {			/* String table */
+		elfedit_section_t *sec;
+	} str;
 	cap_opt_t	optmask;   	/* Mask of options used */
 	int		argc;		/* # of plain arguments */
 	const char	**argv;		/* Plain arguments */
@@ -128,6 +138,149 @@
 
 
 /*
+ * Lookup the string table associated with the capabilities
+ * section.
+ *
+ * entry:
+ *	argstate - Argument state block
+ *	required - If TRUE, failure to obtain a string table should be
+ *		considered to be an error.
+ *
+ * exit:
+ *	If a string table is found, argstate->str is updated to reference it.
+ *	If no string table is found, and required is TRUE, an error is issued
+ *	and this routine does not return to the caller. Otherwise, this
+ *	routine returns quietly without modifying argstate->str.
+ */
+static void
+argstate_add_str(ARGSTATE *argstate, Boolean required)
+{
+	/* String table already loaded? */
+	if (argstate->str.sec != NULL)
+		return;
+
+	/*
+	 * We can't proceed if the capabilities section does not have
+	 * an associated string table.
+	 */
+	if (argstate->cap.sec->sec_shdr->sh_info == 0) {
+		/* Error if the operation requires a string table */
+		if (required)
+			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRTAB),
+			    EC_WORD(argstate->cap.sec->sec_shndx),
+			    argstate->cap.sec->sec_name);
+		return;
+	}
+
+	argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
+	    argstate->cap.sec->sec_shdr->sh_info, 0);
+}
+
+/*
+ * Given an index into the capabilities array, locate the index of the
+ * initial element in its capabilities group, and the number of elements
+ * in the group.
+ */
+static void
+cap_group_extents(ARGSTATE *argstate, Word ndx, Word *ret_start_ndx,
+    Word *ret_end_ndx)
+{
+	*ret_end_ndx = ndx;
+
+	/*
+	 * The group starts with a non-NULL tag that is either the
+	 * first tag in the array, or is preceded by a NULL tag.
+	 */
+	while ((ndx > 0) && (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL))
+		ndx--;
+	while ((ndx > 0) && (argstate->cap.data[ndx - 1].c_tag != CA_SUNW_NULL))
+		ndx--;
+	*ret_start_ndx = ndx;
+
+
+	/*
+	 * The group is terminated by a series of 1 or more NULL tags.
+	 */
+	ndx = *ret_end_ndx;
+	while (((ndx + 1) < argstate->cap.num) &&
+	    (argstate->cap.data[ndx].c_tag != CA_SUNW_NULL))
+		ndx++;
+	while (((ndx + 1) < argstate->cap.num) &&
+	    (argstate->cap.data[ndx + 1].c_tag == CA_SUNW_NULL))
+		ndx++;
+	*ret_end_ndx = ndx;
+}
+
+/*
+ * If a CA_SUNW_ID element exists within the current capabilities group
+ * in the given argument state, return the string pointer to the name.
+ * Otherwise return a pointer to a descriptive "noname" string.
+ */
+static const char *
+cap_group_id(ARGSTATE *argstate)
+{
+	Word		ndx = argstate->cap.grp_start_ndx;
+	Cap		*cap = argstate->cap.data + ndx;
+
+	for (; ndx <= argstate->cap.grp_end_ndx; ndx++, cap++) {
+		if (cap->c_tag == CA_SUNW_ID) {
+			argstate_add_str(argstate, TRUE);
+			return (elfedit_offset_to_str(argstate->str.sec,
+			    cap->c_un.c_val, ELFEDIT_MSG_ERR, 0));
+			break;
+		}
+
+		if (cap->c_tag == CA_SUNW_NULL)
+			break;
+	}
+
+	return ((argstate->cap.grp_start_ndx == 0) ?
+	    MSG_INTL(MSG_STR_OBJECT) : MSG_INTL(MSG_STR_NONAME));
+}
+
+
+/*
+ * Given an index into the capabilities array, set the argstate cap.grp_*
+ * fields to reflect the capabilities group containing the index.
+ *
+ * The group concept is used to limit operations to a related group
+ * of capabilities, and prevent insert/delete/move operations from
+ * spilling across groups.
+ */
+static void
+argstate_cap_group(ARGSTATE *argstate, Word ndx)
+{
+	if (argstate->cap.grp_set == TRUE)
+		return;
+
+	cap_group_extents(argstate, ndx, &argstate->cap.grp_start_ndx,
+	    &argstate->cap.grp_end_ndx);
+
+	argstate->cap.grp_set = TRUE;
+	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CAPGRP),
+	    EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name,
+	    EC_WORD(argstate->cap.grp_start_ndx),
+	    EC_WORD(argstate->cap.grp_end_ndx), cap_group_id(argstate));
+}
+
+/*
+ * Given an index into the capabilities array, issue a group title for
+ * the capabilities group that contains it.
+ */
+static void
+group_title(ARGSTATE *argstate, Word ndx)
+{
+	ARGSTATE	loc_argstate;
+
+	loc_argstate = *argstate;
+	cap_group_extents(argstate, ndx, &loc_argstate.cap.grp_start_ndx,
+	    &loc_argstate.cap.grp_end_ndx);
+	elfedit_printf(MSG_INTL(MSG_FMT_CAPGRP),
+	    EC_WORD(loc_argstate.cap.grp_start_ndx),
+	    EC_WORD(loc_argstate.cap.grp_end_ndx), cap_group_id(&loc_argstate));
+}
+
+/*
  * Standard argument processing for cap module
  *
  * entry
@@ -144,6 +297,7 @@
 {
 	elfedit_getopt_state_t	getopt_state;
 	elfedit_getopt_ret_t	*getopt_ret;
+	const char		*capid = NULL;
 
 	bzero(argstate, sizeof (*argstate));
 	argstate->obj_state = obj_state;
@@ -151,9 +305,13 @@
 	elfedit_getopt_init(&getopt_state, &argc, &argv);
 
 	/* Add each new option to the options mask */
-	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
+	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
 		argstate->optmask |= getopt_ret->gor_idmask;
 
+		if (getopt_ret->gor_idmask == CAP_OPT_F_CAPID)
+			capid = getopt_ret->gor_value;
+	}
+
 	/* If there may be an arbitrary amount of output, use a pager */
 	if (argc == 0)
 		elfedit_pager_init();
@@ -165,6 +323,38 @@
 	/* Locate the capabilities section */
 	argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data,
 	    &argstate->cap.num);
+
+	/*
+	 * If -capid was specified, locate the specified capabilities group,
+	 * and narrow the section data to use only that group. Otherwise,
+	 * use the whole array.
+	 */
+	if (capid != NULL) {
+		Word	i;
+		Cap	*cap = argstate->cap.data;
+
+		/*
+		 * -capid requires the capability section to have an
+		 * associated string table.
+		 */
+		argstate_add_str(argstate, TRUE);
+
+		for (i = 0; i < argstate->cap.num; i++, cap++)
+			if ((cap->c_tag == CA_SUNW_ID) &&
+			    (strcmp(capid, elfedit_offset_to_str(
+			    argstate->str.sec, cap->c_un.c_val,
+			    ELFEDIT_MSG_ERR, 0)) == 0))
+				break;
+
+		if (i == argstate->cap.num)
+			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCAPID),
+			    EC_WORD(argstate->cap.sec->sec_shndx),
+			    argstate->cap.sec->sec_name, capid);
+		argstate_cap_group(argstate, i);
+	} else {
+		argstate->cap.grp_start_ndx = 0;
+		argstate->cap.grp_end_ndx = argstate->cap.num - 1;
+	}
 }
 
 
@@ -196,8 +386,7 @@
 	elfedit_outstyle_t	outstyle;
 	Word	cnt, ndx, printed = 0;
 	Cap	*cap;
-	int	header_done = 0;
-	Xword	last_c_val = 0;
+	Boolean	header_done = FALSE, null_seen = FALSE;
 
 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
 		return;
@@ -216,69 +405,134 @@
 		ndx = arg;
 		cnt = 1;
 	} else {
-		ndx = 0;
-		cnt = argstate->cap.num;
+		ndx = argstate->cap.grp_start_ndx;
+		cnt = argstate->cap.grp_end_ndx - ndx + 1;
 	}
 
+	/* Load string table if there is one */
+	argstate_add_str(argstate, FALSE);
+
 	cap = &argstate->cap.data[ndx];
 	for (; cnt--; cap++, ndx++) {
 		/*
 		 * If we are only displaying certain tag types and
 		 * this isn't one of those, move on to next element.
 		 */
-		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg))
+		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg)) {
+			if (cap->c_tag == CA_SUNW_NULL)
+				null_seen = TRUE;
 			continue;
+		}
+
+		/*
+		 * If capability type requires a string table, and we don't
+		 * have one, force an error.
+		 */
+		switch (cap->c_tag) {
+		case CA_SUNW_PLAT:
+		case CA_SUNW_MACH:
+		case CA_SUNW_ID:
+			if (argstate->str.sec == NULL)
+				argstate_add_str(argstate, TRUE);
+			break;
+		}
 
 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
-			if (header_done == 0) {
-				header_done = 1;
+			if (null_seen && (cap->c_tag != CA_SUNW_NULL)) {
+				null_seen = FALSE;
+				if (header_done) {
+					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+					    MSG_ORIG(MSG_STR_EMPTY));
+					header_done = FALSE;
+				}
+			}
+
+			if (header_done == FALSE) {
+				header_done = TRUE;
+				group_title(argstate, ndx);
 				Elf_cap_title(0);
 			}
 			Elf_cap_entry(NULL, cap, ndx,
+			    (const char *)argstate->str.sec->sec_data->d_buf,
+			    argstate->str.sec->sec_data->d_size,
 			    argstate->obj_state->os_ehdr->e_machine);
 		} else {
 			/*
-			 * In simple or numeric mode under a print type
-			 * that is based on tag type rather than on index,
-			 * quietly: If we've already printed this value,
-			 * don't print it again. A common example of this
-			 * is PRINT_CAP_T_RUNPATH when both CA_RPATH and
-			 * CA_RUNPATH are present with the same value.
+			 * If CAP_CMD_T_TAG, and not in default output
+			 * style, display the tag rather than the value.
 			 */
-			if ((print_type == PRINT_CAP_T_TAG) && printed &&
-			    (last_c_val == cap->c_un.c_val))
+			if (cmd == CAP_CMD_T_TAG) {
+				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
+					Conv_inv_buf_t	inv_buf;
+
+					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+					    conv_cap_tag(cap->c_tag, 0,
+					    &inv_buf));
+				} else {
+					elfedit_printf(
+					    MSG_ORIG(MSG_FMT_WORDVALNL),
+					    EC_WORD(cap->c_tag));
+				}
+				printed = 1;
 				continue;
+			}
 
+			/* Displaying the value in simple or numeric mode */
 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
-				union {
-					Conv_cap_val_hw1_buf_t	hw1;
-					Conv_cap_val_sf1_buf_t	sf1;
-				} c_buf;
+				Conv_cap_val_buf_t	cap_val_buf;
+
+				if (print_type == PRINT_CAP_T_TAG) {
+					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+					    conv_cap_val_hw1(cap->c_un.c_val,
+					    argstate->obj_state->os_ehdr->
+					    e_machine, CONV_FMT_NOBKT,
+					    &cap_val_buf.cap_val_hw1_buf));
+					printed = 1;
+					continue;
+				}
 
 				switch (cap->c_tag) {
 				case CA_SUNW_HW_1:
 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
 					    conv_cap_val_hw1(cap->c_un.c_val,
 					    argstate->obj_state->os_ehdr->
-					    e_machine,
-					    CONV_FMT_NOBKT, &c_buf.hw1));
+					    e_machine, CONV_FMT_NOBKT,
+					    &cap_val_buf.cap_val_hw1_buf));
 					printed = 1;
 					continue;
 				case CA_SUNW_SF_1:
 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
 					    conv_cap_val_sf1(cap->c_un.c_val,
 					    argstate->obj_state->os_ehdr->
-					    e_machine,
-					    CONV_FMT_NOBKT, &c_buf.sf1));
+					    e_machine, CONV_FMT_NOBKT,
+					    &cap_val_buf.cap_val_sf1_buf));
+					printed = 1;
+					continue;
+				case CA_SUNW_HW_2:
+					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+					    conv_cap_val_hw2(cap->c_un.c_val,
+					    argstate->obj_state->os_ehdr->
+					    e_machine, CONV_FMT_NOBKT,
+					    &cap_val_buf.cap_val_hw2_buf));
+					printed = 1;
+					continue;
+				case CA_SUNW_PLAT:
+				case CA_SUNW_MACH:
+				case CA_SUNW_ID:
+					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+					    elfedit_offset_to_str(
+					    argstate->str.sec, cap->c_un.c_val,
+					    ELFEDIT_MSG_ERR, 0));
 					printed = 1;
 					continue;
 				}
 			}
 			elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
-			    cap->c_un.c_val);
+			    EC_XWORD(cap->c_un.c_val));
 		}
 		printed = 1;
-		last_c_val = cap->c_un.c_val;
+		if (cap->c_tag == CA_SUNW_NULL)
+			null_seen = TRUE;
 	}
 
 	/*
@@ -286,11 +540,12 @@
 	 * based on tag type, issue an error saying it doesn't exist.
 	 */
 	if (!printed && (print_type == PRINT_CAP_T_TAG)) {
-		Conv_inv_buf_t inv_buf;
+		Conv_inv_buf_t	inv_buf;
 
 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
 		    EC_WORD(argstate->cap.sec->sec_shndx),
-		    argstate->cap.sec->sec_name,
+		    argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx,
+		    argstate->cap.grp_end_ndx, cap_group_id(argstate),
 		    conv_cap_tag(arg, 0, &inv_buf));
 	}
 }
@@ -327,16 +582,23 @@
 arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname,
     int print_request, PRINT_CAP_T *print_type)
 {
-	Word	ndx, ca_value;
+	Word		ndx, ca_value;
 
 
 	/* Assume we are returning an index, alter as needed below */
 	*print_type = PRINT_CAP_T_NDX;
 
-	/* If -capndx was used, this is a simple numeric index */
-	if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0)
-		return ((Word) elfedit_atoui_range(arg, argname, 0,
-		    argstate->cap.num - 1, NULL));
+	/*
+	 * If -capndx was used, this is a simple numeric index.
+	 * Determine its capability group because some operations
+	 * (move, delete) are limited to operate within it.
+	 */
+	if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0) {
+		ndx = (Word) elfedit_atoui_range(arg, argname, 0,
+		    argstate->cap.num - 1, NULL);
+		argstate_cap_group(argstate, ndx);
+		return (ndx);
+	}
 
 	/* The argument is a CA_ tag type, not a numeric index */
 	ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA);
@@ -350,8 +612,20 @@
 		return (ca_value);
 	}
 
-	/* Locate the first entry with the given tag type */
-	for (ndx = 0; ndx < argstate->cap.num; ndx++) {
+	/*
+	 * If we haven't determined a capability group yet, either via
+	 * -capid, or -capndx, then make it the initial group, which
+	 * represent the object capabilities.
+	 */
+	if (!argstate->cap.grp_set)
+		argstate_cap_group(argstate, 0);
+
+	/*
+	 * Locate the first entry with the given tag type within the
+	 * capabilities group.
+	 */
+	for (ndx = argstate->cap.grp_start_ndx;
+	    ndx <= argstate->cap.grp_end_ndx; ndx++) {
 		if (argstate->cap.data[ndx].c_tag == ca_value) {
 			elfedit_msg(ELFEDIT_MSG_DEBUG,
 			    MSG_INTL(MSG_DEBUG_CA2NDX),
@@ -359,12 +633,36 @@
 			    argstate->cap.sec->sec_name, EC_WORD(ndx), arg);
 			return (ndx);
 		}
+
+		/*
+		 * If we hit a NULL, then only more NULLs can follow it and
+		 * there's no need to look further. If there is more than
+		 * one NULL, we can grab the first one and turn it into
+		 * an element of the desired type.
+		 */
+		if (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL) {
+			if (ndx < argstate->cap.grp_end_ndx) {
+				Conv_inv_buf_t	inv_buf;
+
+				elfedit_msg(ELFEDIT_MSG_DEBUG,
+				    MSG_INTL(MSG_DEBUG_CONVNULL),
+				    EC_WORD(argstate->cap.sec->sec_shndx),
+				    argstate->cap.sec->sec_name, EC_WORD(ndx),
+				    conv_cap_tag(ca_value, 0, &inv_buf));
+				argstate->cap.data[ndx].c_tag = ca_value;
+				bzero(&argstate->cap.data[ndx].c_un,
+				    sizeof (argstate->cap.data[ndx].c_un));
+				return (ndx);
+			}
+			break;
+		}
 	}
 
 	/* No room to create one, so we're out of options and must fail */
 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
 	    EC_WORD(argstate->cap.sec->sec_shndx),
-	    argstate->cap.sec->sec_name, arg);
+	    argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx,
+	    argstate->cap.grp_end_ndx, cap_group_id(argstate), arg);
 
 	/*NOTREACHED*/
 	return (0);		/* For lint */
@@ -404,7 +702,46 @@
 	return (flags);
 }
 
+/*
+ * Common processing for capabilities value setting.
+ *
+ * entry:
+ *	argstate - Argument state block
+ *	cap - capabilities data pointer
+ *	ndx - capabilities data index
+ *	cap_ndx - capabilities section index
+ *	cap_name - capabilities section name
+ *	cap_tag - capabilities tag
+ *	const_type - data conversion type
+ */
+static elfedit_cmdret_t
+cap_set(ARGSTATE *argstate, Cap *cap, Word ndx, Word cap_ndx,
+    const char *cap_name, Xword cap_tag, elfedit_const_t const_type)
+{
+	Conv_cap_val_buf_t	buf1, buf2;
+	Half			mach = argstate->obj_state->os_ehdr->e_machine;
+	Xword			ncap, ocap;
 
+	ncap = flag_bitop(argstate, cap[ndx].c_un.c_val,
+	    elfedit_const_to_atoui(const_type));
+
+	/* Set the value */
+	if ((ocap = cap[ndx].c_un.c_val) == ncap) {
+		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_OK),
+		    cap_ndx, cap_name, EC_WORD(ndx),
+		    conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1));
+
+		return (ELFEDIT_CMDRET_NONE);
+	} else {
+		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_CHG),
+		    cap_ndx, cap_name, EC_WORD(ndx),
+		    conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1),
+		    conv_cap_val(cap_tag, ncap, mach, CONV_FMT_NOBKT, &buf2));
+
+		cap[ndx].c_un.c_val = ncap;
+		return (ELFEDIT_CMDRET_MOD);
+	}
+}
 
 /*
  * Common body for the cap: module commands. These commands
@@ -424,7 +761,7 @@
 	ARGSTATE		argstate;
 	Cap			*cap;
 	const char		*cap_name;
-	Word			cap_ndx, cap_num;
+	Word			cap_ndx;
 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
 	PRINT_CAP_T		print_type = PRINT_CAP_T_ALL;
 	Word			ndx;
@@ -435,7 +772,6 @@
 	process_args(obj_state, argc, argv, &argstate);
 
 	cap = argstate.cap.data;
-	cap_num = argstate.cap.num;
 	cap_name = argstate.cap.sec->sec_name;
 	cap_ndx = argstate.cap.sec->sec_shndx;
 
@@ -493,6 +829,13 @@
 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
 		break;
 
+	case CAP_CMD_T_HW2:
+		print_only = (argstate.argc == 0);
+		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
+		    ELFEDIT_CONST_CA, CA_SUNW_HW_2, 1),
+		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
+		break;
+
 	default:
 		/* Note expected: All commands should have been caught above */
 		elfedit_command_usage();
@@ -538,8 +881,16 @@
 
 	case CAP_CMD_T_VALUE:
 		{
-			Xword c_val = (Xword)
-			    elfedit_atoui(argstate.argv[1], NULL);
+			Xword c_val;
+
+			if (argstate.optmask & CAP_OPT_F_STRVAL) {
+				argstate_add_str(&argstate, TRUE);
+				c_val = elfedit_strtab_insert(obj_state,
+				    argstate.str.sec, NULL, argstate.argv[1]);
+			} else {
+				c_val = (Xword)
+				    elfedit_atoui(argstate.argv[1], NULL);
+			}
 
 			if (cap[ndx].c_un.c_val == c_val) {
 				elfedit_msg(ELFEDIT_MSG_DEBUG,
@@ -564,12 +915,34 @@
 		{
 			Word cnt = (argstate.argc == 1) ? 1 :
 			    (Word) elfedit_atoui_range(argstate.argv[1],
-			    MSG_ORIG(MSG_STR_COUNT), 1, cap_num - ndx, NULL);
+			    MSG_ORIG(MSG_STR_COUNT), 1,
+			    argstate.cap.grp_end_ndx - ndx + 1, NULL);
 			const char *msg_prefix =
 			    elfedit_sec_msgprefix(argstate.cap.sec);
 
-			elfedit_array_elts_delete(msg_prefix, argstate.cap.data,
-			    sizeof (Cap), cap_num, ndx, cnt);
+			/*
+			 * We want to limit the deleted elements to be
+			 * in the range of the current capabilities group,
+			 * and for the resulting NULL elements to be inserted
+			 * at the end of the group, rather than at the end
+			 * of the section. To do this, we set the array length
+			 * in the call to the delete function so that it thinks
+			 * the array ends with the current group.
+			 *
+			 * The delete function will catch attempts to delete
+			 * past this virtual end, but the error message will
+			 * not make sense to the user. In order to prevent that,
+			 * we check for the condition here and provide a more
+			 * useful error.
+			 */
+			if ((ndx + cnt - 1) > argstate.cap.grp_end_ndx)
+				elfedit_msg(ELFEDIT_MSG_ERR,
+				    MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix,
+				    argstate.cap.grp_start_ndx,
+				    argstate.cap.grp_end_ndx,
+				    cap_group_id(&argstate));
+			elfedit_array_elts_delete(msg_prefix, cap, sizeof (Cap),
+			    argstate.cap.grp_end_ndx + 1, ndx, cnt);
 			ret = ELFEDIT_CMDRET_MOD;
 		}
 		break;
@@ -584,17 +957,41 @@
 
 			dstndx = (Word)
 			    elfedit_atoui_range(argstate.argv[1],
-			    MSG_ORIG(MSG_STR_DST_INDEX), 0, cap_num - 1,
-			    NULL);
+			    MSG_ORIG(MSG_STR_DST_INDEX),
+			    argstate.cap.grp_start_ndx,
+			    argstate.cap.grp_end_ndx, NULL);
 			if (argstate.argc == 2) {
 				cnt = 1;
 			} else {
+				Word max;
+
+				max = argstate.cap.grp_end_ndx -
+				    ((ndx > dstndx) ? ndx : dstndx) + 1;
 				cnt = (Word) elfedit_atoui_range(
 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
-				    1, cap_num, NULL);
+				    1, max, NULL);
 			}
-			elfedit_array_elts_move(msg_prefix, argstate.cap.data,
-			    sizeof (save), cap_num, ndx, dstndx, cnt, &save);
+
+			/*
+			 * Moves are required to be self contained within
+			 * the bounds of the selected capability group.
+			 * The move utility function contains bounds checking,
+			 * but is not sub-array aware. Hence, we bounds check
+			 * check it here, and then hand of the validated
+			 * operation to the move utility function to execute.
+			 */
+			if ((ndx < argstate.cap.grp_start_ndx) ||
+			    ((ndx + cnt) > argstate.cap.grp_end_ndx) ||
+			    (dstndx < argstate.cap.grp_start_ndx) ||
+			    ((dstndx + cnt) > argstate.cap.grp_end_ndx))
+				elfedit_msg(ELFEDIT_MSG_ERR,
+				    MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix,
+				    argstate.cap.grp_start_ndx,
+				    argstate.cap.grp_end_ndx,
+				    cap_group_id(&argstate));
+			elfedit_array_elts_move(msg_prefix, cap, sizeof (save),
+			    argstate.cap.grp_end_ndx + 1, ndx, dstndx,
+			    cnt, &save);
 			ret = ELFEDIT_CMDRET_MOD;
 		}
 		break;
@@ -602,61 +999,22 @@
 
 	case CAP_CMD_T_HW1:
 		{
-			Conv_cap_val_hw1_buf_t buf1, buf2;
-			Half	mach = argstate.obj_state->os_ehdr->e_machine;
-			Xword	hw1;
-
-			hw1 = flag_bitop(&argstate, cap[ndx].c_un.c_val,
-			    elfedit_const_to_atoui(ELFEDIT_CONST_AV));
-
-			/* Set the value */
-			if (cap[ndx].c_un.c_val == hw1) {
-				elfedit_msg(ELFEDIT_MSG_DEBUG,
-				    MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx,
-				    cap_name, EC_WORD(ndx),
-				    conv_cap_val_hw1(cap[ndx].c_un.c_val, mach,
-				    CONV_FMT_NOBKT, &buf1));
-			} else {
-				elfedit_msg(ELFEDIT_MSG_DEBUG,
-				    MSG_INTL(MSG_DEBUG_BSB_CHG),
-				    cap_ndx, cap_name, EC_WORD(ndx),
-				    conv_cap_val_hw1(cap[ndx].c_un.c_val, mach,
-				    CONV_FMT_NOBKT, &buf1),
-				    conv_cap_val_hw1(hw1, mach,
-				    CONV_FMT_NOBKT, &buf2));
-				ret = ELFEDIT_CMDRET_MOD;
-				cap[ndx].c_un.c_val = hw1;
-			}
+			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
+			    CA_SUNW_HW_1, ELFEDIT_CONST_HW1_SUNW);
 		}
 		break;
 
 	case CAP_CMD_T_SF1:
 		{
-			Conv_cap_val_sf1_buf_t buf1, buf2;
-			Half	mach = argstate.obj_state->os_ehdr->e_machine;
-			Xword	sf1;
-
-			sf1 = flag_bitop(&argstate, cap[ndx].c_un.c_val,
-			    elfedit_const_to_atoui(ELFEDIT_CONST_SF1_SUNW));
+			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
+			    CA_SUNW_SF_1, ELFEDIT_CONST_SF1_SUNW);
+		}
+		break;
 
-			/* Set the value */
-			if (cap[ndx].c_un.c_val == sf1) {
-				elfedit_msg(ELFEDIT_MSG_DEBUG,
-				    MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx,
-				    cap_name, EC_WORD(ndx),
-				    conv_cap_val_sf1(cap[ndx].c_un.c_val, mach,
-				    CONV_FMT_NOBKT, &buf1));
-			} else {
-				elfedit_msg(ELFEDIT_MSG_DEBUG,
-				    MSG_INTL(MSG_DEBUG_BSB_CHG),
-				    cap_ndx, cap_name, EC_WORD(ndx),
-				    conv_cap_val_sf1(cap[ndx].c_un.c_val, mach,
-				    CONV_FMT_NOBKT, &buf1),
-				    conv_cap_val_sf1(sf1, mach,
-				    CONV_FMT_NOBKT, &buf2));
-				ret = ELFEDIT_CMDRET_MOD;
-				cap[ndx].c_un.c_val = sf1;
-			}
+	case CAP_CMD_T_HW2:
+		{
+			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
+			    CA_SUNW_HW_2, ELFEDIT_CONST_HW2_SUNW);
 		}
 		break;
 	}
@@ -681,6 +1039,38 @@
  */
 
 /*
+ * -capid command completion: Supply all CA_SUNW_ID names found in the object.
+ */
+static void
+cpl_capid_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
+    const char *argv[], int num_opt)
+{
+	elfedit_section_t	*cap_sec, *str_sec;
+	Cap			*cap;
+	Word			num;
+
+	if (obj_state == NULL)	 /* No object available */
+		return;
+
+	if ((argc > num_opt) || (argc < 2) ||
+	    (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_CAPID)) != 0))
+		return;
+
+	cap_sec = elfedit_sec_getcap(obj_state, &cap, &num);
+
+	/* If no associated string table, we have no strings to complete */
+	if (cap_sec->sec_shdr->sh_info == 0)
+		return;
+
+	str_sec = elfedit_sec_getstr(obj_state, cap_sec->sec_shdr->sh_info, 0);
+
+	for (; num--; cap++)
+		if (cap->c_tag == CA_SUNW_ID)
+			elfedit_cpl_match(cpldata, elfedit_offset_to_str(
+			    str_sec, cap->c_un.c_val, ELFEDIT_MSG_ERR, 0), 0);
+}
+
+/*
  * Command completion for the first argument, which specifies
  * the capabilities element to use. Examines the options to see if
  * -capndx is present, and if not, supplies the completion
@@ -691,7 +1081,13 @@
 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
     const char *argv[], int num_opt)
 {
-	Word			i;
+	Word	i;
+
+	/* -capid id_name */
+	if (argc <= num_opt) {
+		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
+		return;
+	}
 
 	/* Make sure it's the first argument */
 	if ((argc - num_opt) != 1)
@@ -710,13 +1106,18 @@
 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
 }
 
-
 /*ARGSUSED*/
 static void
 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
     const char *argv[], int num_opt)
 {
-	/* First argument */
+	/* -capid id_name */
+	if (argc <= num_opt) {
+		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
+		return;
+	}
+
+	/* First plain argument */
 	if ((argc - num_opt) == 1) {
 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
 		return;
@@ -732,9 +1133,14 @@
 cpl_hw1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
     const char *argv[], int num_opt)
 {
-	/* This routine allows multiple flags to be specified */
+	/* -capid id_name */
+	if (argc <= num_opt) {
+		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
+		return;
+	}
 
-	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV);
+	/* This routine allows multiple flags to be specified */
+	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW1_SUNW);
 }
 
 /*ARGSUSED*/
@@ -742,10 +1148,30 @@
 cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
     const char *argv[], int num_opt)
 {
+	/* -capid id_name */
+	if (argc <= num_opt) {
+		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
+		return;
+	}
+
 	/* This routine allows multiple flags to be specified */
 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW);
 }
 
+/*ARGSUSED*/
+static void
+cpl_hw2(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
+    const char *argv[], int num_opt)
+{
+	/* -capid id_name */
+	if (argc <= num_opt) {
+		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
+		return;
+	}
+
+	/* This routine allows multiple flags to be specified */
+	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW2_SUNW);
+}
 
 /*
  * Implementation functions for the commands
@@ -792,16 +1218,25 @@
 	return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv));
 }
 
-
+static elfedit_cmdret_t
+cmd_hw2(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+	return (cmd_body(CAP_CMD_T_HW2, obj_state, argc, argv));
+}
 
 /*ARGSUSED*/
 elfedit_module_t *
 elfedit_init(elfedit_module_version_t version)
 {
-	/* For commands that only accept -and, -cmp, -o, and -or */
-	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
+	/* For commands that only accept -capid, -and, -cmp, -o, and -or */
+	static elfedit_cmd_optarg_t opt_ostyle_capid_bitop[] = {
 		{ ELFEDIT_STDOA_OPT_AND, NULL,
 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR },
+		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
+		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
+		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
+		{ MSG_ORIG(MSG_STR_IDNAME), NULL, 0 },
 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
 		{ ELFEDIT_STDOA_OPT_O, NULL,
@@ -811,23 +1246,17 @@
 		{ NULL }
 	};
 
-	/* For commands that only accept -capndx */
-	static elfedit_cmd_optarg_t opt_capndx[] = {
+	/* For commands that only accept -capid and -capndx */
+	static elfedit_cmd_optarg_t opt_capid_capndx[] = {
+		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
+		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
+		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
+		{ MSG_ORIG(MSG_STR_IDNAME), NULL, 0 },
 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
-		    CAP_OPT_F_CAPNDX, 0 },
-		{ NULL }
-	};
-
-	/* For commands thataccept -capndx and output styles */
-	static elfedit_cmd_optarg_t opt_ostyle_capndx[] = {
-		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
-		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
-		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
-		    CAP_OPT_F_CAPNDX, 0 },
-		{ ELFEDIT_STDOA_OPT_O, NULL,
-		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
+		    CAP_OPT_F_CAPNDX, CAP_OPT_F_CAPID },
 		{ NULL }
 	};
 
@@ -849,6 +1278,20 @@
 
 	/* cap:tag */
 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
+	static elfedit_cmd_optarg_t opt_tag[] = {
+		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
+		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
+		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
+		{ MSG_ORIG(MSG_STR_IDNAME), NULL, 0 },
+		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
+		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
+		    CAP_OPT_F_CAPNDX, 0 },
+		{ ELFEDIT_STDOA_OPT_O, NULL,
+		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
+		{ NULL }
+	};
 	static elfedit_cmd_optarg_t arg_tag[] = {
 		{ MSG_ORIG(MSG_STR_ELT),
 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
@@ -864,6 +1307,24 @@
 
 	/* cap:value */
 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
+	static elfedit_cmd_optarg_t opt_value[] = {
+		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
+		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
+		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
+		{ MSG_ORIG(MSG_STR_IDNAME), NULL, 0 },
+		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
+		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
+		    CAP_OPT_F_CAPNDX, 0 },
+		{ ELFEDIT_STDOA_OPT_O, NULL,
+		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
+		{ MSG_ORIG(MSG_STR_MINUS_S),
+		    /* MSG_INTL(MSG_OPTDESC_S) */
+		    ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
+		    CAP_OPT_F_STRVAL, 0 },
+		{ NULL }
+	};
 	static elfedit_cmd_optarg_t arg_value[] = {
 		{ MSG_ORIG(MSG_STR_ELT),
 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
@@ -928,7 +1389,15 @@
 		{ NULL }
 	};
 
-
+	/* cap:hw2 */
+	static const char *name_hw2[] = { MSG_ORIG(MSG_CMD_HW2), NULL };
+	static elfedit_cmd_optarg_t arg_hw2[] = {
+		{ MSG_ORIG(MSG_STR_VALUE),
+		    /* MSG_INTL(MSG_A1_HW2_VALUE) */
+		    ELFEDIT_I18NHDL(MSG_A1_HW2_VALUE),
+		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
+		{ NULL }
+	};
 
 
 	static elfedit_cmd_t cmds[] = {
@@ -938,7 +1407,7 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
 		    /* MSG_INTL(MSG_HELP_DUMP) */
 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
-		    opt_capndx, arg_dump },
+		    opt_capid_capndx, arg_dump },
 
 		/* cap:tag */
 		{ cmd_tag, cpl_tag, name_tag,
@@ -946,7 +1415,7 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
 		    /* MSG_INTL(MSG_HELP_TAG) */
 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
-		    opt_ostyle_capndx, arg_tag },
+		    opt_tag, arg_tag },
 
 		/* cap:value */
 		{ cmd_value, cpl_eltarg, name_value,
@@ -954,7 +1423,7 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
 		    /* MSG_INTL(MSG_HELP_VALUE) */
 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
-		    opt_ostyle_capndx, arg_value },
+		    opt_value, arg_value },
 
 		/* cap:delete */
 		{ cmd_delete, cpl_eltarg, name_delete,
@@ -962,7 +1431,7 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
 		    /* MSG_INTL(MSG_HELP_DELETE) */
 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
-		    opt_capndx, arg_delete },
+		    opt_capid_capndx, arg_delete },
 
 		/* cap:move */
 		{ cmd_move, cpl_eltarg, name_move,
@@ -970,7 +1439,7 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
 		    /* MSG_INTL(MSG_HELP_MOVE) */
 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
-		    opt_capndx, arg_move },
+		    opt_capid_capndx, arg_move },
 
 		/* cap:hw1 */
 		{ cmd_hw1, cpl_hw1, name_hw1,
@@ -978,7 +1447,7 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_HW1),
 		    /* MSG_INTL(MSG_HELP_HW1) */
 		    ELFEDIT_I18NHDL(MSG_HELP_HW1),
-		    opt_ostyle_bitop, arg_hw1 },
+		    opt_ostyle_capid_bitop, arg_hw1 },
 
 		/* cap:sf1 */
 		{ cmd_sf1, cpl_sf1, name_sf1,
@@ -986,7 +1455,15 @@
 		    ELFEDIT_I18NHDL(MSG_DESC_SF1),
 		    /* MSG_INTL(MSG_HELP_SF1) */
 		    ELFEDIT_I18NHDL(MSG_HELP_SF1),
-		    opt_ostyle_bitop, arg_sf1 },
+		    opt_ostyle_capid_bitop, arg_sf1 },
+
+		/* cap:hw2 */
+		{ cmd_hw2, cpl_hw2, name_hw2,
+		    /* MSG_INTL(MSG_DESC_HW2) */
+		    ELFEDIT_I18NHDL(MSG_DESC_HW2),
+		    /* MSG_INTL(MSG_HELP_HW2) */
+		    ELFEDIT_I18NHDL(MSG_HELP_HW2),
+		    opt_ostyle_capid_bitop, arg_hw2 },
 
 		{ NULL }
 	};
--- a/usr/src/cmd/sgs/elfedit/modules/common/cap.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/modules/common/cap.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -20,10 +20,9 @@
 #
 
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 @ _START_
 
@@ -40,20 +39,32 @@
 @ MSG_DEBUG_BSB_CHG	"[%d: %s][%d]: change from [%s] to [%s]\n"
 @ MSG_DEBUG_X_OK	"[%d: %s][%d]: value unchanged: %#llx\n"
 @ MSG_DEBUG_X_CHG	"[%d: %s][%d]: change from %#llx to %#llx\n"
-@ MSG_DEBUG_CA2NDX	"[%d: %s][%d]: Capability entry for tag: %s\n"
-
+@ MSG_DEBUG_CA2NDX	"[%d: %s][%d]: capability entry for tag: %s\n"
+@ MSG_DEBUG_CAPGRP	"[%d: %s][%u-%u: %s]: capability group\n"
+@ MSG_DEBUG_CONVNULL	"[%d: %s][%d]: no existing %s to modify, converting \
+			 extra CA_SUNW_NULL\n"
 
 # Errors
 
-@ MSG_ERR_NOCAELT	"[%d: %s]: Capabilities section does not contain \
-			 tag: %s\n"
-
+@ MSG_ERR_NOCAELT	"[%d: %s][%u-%u: %s]: capabilities group does not \
+			 contain tag: %s\n"
+@ MSG_ERR_NOSTRTAB	"[%d: %s]: capabilities section does not have an \
+			 associated string table\n"
+@ MSG_ERR_BADCAPID	"[%d: %s]: capabilities section does not contain \
+			 specified id: %s\n"
+@ MSG_ERR_GRPARRBNDS	"%s[%u-%u: %s]: attempt to access elements outside \
+			 of capabilities group\n"
 
 # Module description
 
 @ MSG_MOD_DESC		"Capabilities Section"
 
+# Strings
+@ MSG_STR_OBJECT	"<object>"
+@ MSG_STR_NONAME	"<noname>"
 
+# Format strings
+@ MSG_FMT_CAPGRP	"   Group[%u-%u]: %s\n"
 
 # 1-line description strings
 
@@ -62,16 +73,30 @@
 @ MSG_DESC_VALUE	"Change element value"
 @ MSG_DESC_DELETE	"Delete elements"
 @ MSG_DESC_MOVE		"Move elements"
-@ MSG_DESC_HW1		"Hardware capabilities bit values"
-@ MSG_DESC_SF1		"Software capabilities bit values"
+@ MSG_DESC_HW1		"Hardware capabilities (CA_SUNW_HW_1) bit values"
+@ MSG_DESC_SF1		"Software capabilities (CA_SUNW_SF_1) bit values"
+@ MSG_DESC_HW2		"Hardware capabilities (CA_SUNW_HW_2) bit values"
 
 
-# Commmand option description strings
+# Command option description strings
 
 @ MSG_OPTDESC_CAPNDX		"\
    Interpret the elt argument as a direct index into the\n\
    capabilities section, rather than as a CA_ tag value.\n"
 
+@ MSG_OPTDESC_CAPID		"\
+   Restrict the elt argument to the capability elements belonging\n\
+   to the capabilities group with a CA_SUNW_ID entry matching the\n\
+   specified id name.\n"
+
+@ MSG_OPTDESC_S		"\
+   Interpret the value argument as a string rather than an\n\
+   integer. If the specified string already exists in the\n\
+   string table, the offset of that string is stored in the\n\
+   capability entry. If the string does not exist in the string\n\
+   table, but there is room to add it, the new string is added\n\
+   and then the offset is placed in the capability entry.\n"
+
 
 # Command argument description strings
 
@@ -98,7 +123,9 @@
    can be specified using the well known CA_ symbolic constants\n\
    from /usr/include/sys/elf.h, or as integers. If the -capndx\n\
    option is specified, then elt is instead interpreted as a\n\
-   direct numeric index into the capabilities section.\n"
+   direct numeric index into the capabilities section. If the\n\
+   -capid option is specified, the search is limited to elements\n\
+   within the named capabilities group.\n"
 
 @ MSG_A2_VALUE_VALUE	"\
    Value to set for specified capabilities section element.\n\
@@ -107,30 +134,34 @@
 @ MSG_A2_DELETE_COUNT	"\
    Number of capabilities elements to delete, starting at the\n\
    specified position. This value cannot exceed the number\n\
-   of slots remaining in the table below the specified position.\n\
-   If count is not supplied, a single element is deleted.\n"
+   of slots remaining in the capabilities group below the specified\n\
+   position. If count is not supplied, a single element is deleted.\n"
 
 @ MSG_A2_MOVE_DST_INDEX	"\
    Numeric index within capabilities section to which the element(s)\n\
-   should be moved.\n"
+   should be moved. The destination index must lie within the same\n\
+   capabilities group as elt.\n"
 
 @ MSG_A3_MOVE_COUNT	"\
    Number of capabilities elements to move. This value cannot\n\
-   exceed the number of slots remaining in the table below\n\
-   the specified position. If count is not supplied, a\n\
+   exceed the number of slots remaining in the capabilities group\n\
+   below the specified position. If count is not supplied, a\n\
    single element is moved.\n"
 
 @ MSG_A1_HW1_VALUE	"\
-   Hardware capability values. This can be an integer value,\n\
-   any of the AV_386_ symbolic constants defined in\n\
+   Hardware capability (CA_SUNW_HW_1) values. This can be an integer\n\
+   value, any of the AV_386_ symbolic constants defined in\n\
    /usr/include/sys/auxv_386.h, or the AV_SPARC symbolic\n\
-   constants defined in /usr/include/sys/auxv_SPARC.h\n"
+   constants defined in /usr/include/sys/auxv_SPARC.h.\n"
 
 @ MSG_A1_SF1_VALUE	"\
-   Software capability values. This can be an integer value,\n\
-   any of the SF1_SUNW_ symbolic constants defined in\n\
-   /usr/include/sys/elf.h\n"
+   Software capability (CA_SUNW_SF_1) values. This can be an integer\n\
+   value, any of the SF1_SUNW_ symbolic constants defined in\n\
+   /usr/include/sys/elf.h.\n"
 
+@ MSG_A1_HW2_VALUE	"\
+   Hardware capability (CA_SUNW_HW_2) values. This is available for\n\
+   future expansion.\n"
 
 
 # Help strings
@@ -165,14 +196,16 @@
 
 @ MSG_HELP_DELETE	"   \
    The cap:delete command is used to delete one or more elements\n\
-   in the capabilities section. The elements following the deleted\n\
-   items move up, and new CA_NULL elements are inserted at the\n\
-   end of the capabilities section to fill the vacated space.\n"
+   from a capabilities group within the capabilities section. The\n\
+   elements following the deleted items move up, and new CA_NULL\n\
+   elements are inserted at the end of the capabilities group to\n\
+   fill the vacated space.\n"
 
 @ MSG_HELP_MOVE	"   \
    The cap:move command is used to move the position of one\n\
-   or more elements in the capabilities section. The specified\n\
-   number of elements are moved from elt to dst_index.\n"
+   or more elements in a capabilities group within in the\n\
+   capabilities section. The specified number of elements are\n\
+   moved from elt to dst_index.\n"
 
 @ MSG_HELP_HW1	"   \
    The cap:hw1 command is used to display or alter the\n\
@@ -214,6 +247,25 @@
    \tvalue. If neither -and or -or are specified, the new value\n\
    replaces the existing value.\n"
 
+@ MSG_HELP_HW2	"   \
+   The cap:hw2 command is used to display or alter the\n\
+   value of the hardware capabilities element (CA_SUNW_HW_2).\n\
+   \n\
+   If cap:hw2 is called without arguments, the current\n\
+   value is shown. If one or more value arguments are present,\n\
+   the following steps are taken:\n\
+   \n   \
+   o\tAll the value arguments are OR'd together.\n\
+   \n   \
+   o\tIf the -cmp option has been specified, the new value\n\
+   \tis complemented.\n\
+   \n   \
+   o\tThe CA_SUNW_HW_2 element of the capabilities section is\n\
+   \tupdated with the new value. If -and is specified, the new\n\
+   \tvalue is AND'd against the existing value. If -or is\n\
+   \tspecified, the new value is OR'd against the existing\n\
+   \tvalue. If neither -and or -or are specified, the new value\n\
+   \treplaces the existing value.\n"
 @ _END_
 
 
@@ -227,12 +279,16 @@
 @ MSG_STR_COUNT		"count"
 @ MSG_STR_ELT		"elt"
 @ MSG_STR_DST_INDEX	"dst_index"
+@ MSG_STR_MINUS_CAPID	"-capid"
 @ MSG_STR_MINUS_CAPNDX	"-capndx"
+@ MSG_STR_MINUS_S	"-s"
 @ MSG_STR_VALUE		"value"
+@ MSG_STR_IDNAME	"id_name"
 
 # Format strings
 @ MSG_FMT_STRNL		"%s\n"
 @ MSG_FMT_HEXXWORDNL	"%#llx\n"
+@ MSG_FMT_WORDVALNL	"%u\n"
 
 
 # Module name
@@ -249,3 +305,4 @@
 @ MSG_CMD_MOVE		"move"
 @ MSG_CMD_HW1		"hw1"
 @ MSG_CMD_SF1		"sf1"
+@ MSG_CMD_HW2		"hw2"
--- a/usr/src/cmd/sgs/elfedit/modules/common/dyn.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/modules/common/dyn.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -553,7 +553,7 @@
 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name);
 			} else {
 				elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
-				    dyn->d_un.d_val);
+				    EC_XWORD(dyn->d_un.d_val));
 			}
 		}
 		printed = 1;
--- a/usr/src/cmd/sgs/elfwrap/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/elfwrap/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -51,7 +51,7 @@
 CPPFLAGS =	-I. -I../common -I../../include $(CPPFLAGS.master) -I$(ELFCAP)
 LLDFLAGS =
 LLDFLAGS64 =
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
 LDLIBS +=	$(ELFLIBDIR) -lelf $(CONVLIBDIR) $(CONV_LIB)
 
 LINTFLAGS +=	-x
--- a/usr/src/cmd/sgs/include/_machelf.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/_machelf.h	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Wrapper around the <sys/machelf.h> header that adds
@@ -30,8 +30,6 @@
 #ifndef	_MACHELF_H
 #define	_MACHELF_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/machelf.h>
 #include <string.h>		/* memcpy() */
 
@@ -61,6 +59,9 @@
 #define	ELF_M_SYM			ELF64_M_SYM
 #define	ELF_M_SIZE			ELF64_M_SIZE
 #define	ELF_M_INFO			ELF64_M_INFO
+#define	ELF_C_SYM			ELF64_C_SYM
+#define	ELF_C_GROUP			ELF64_C_GROUP
+#define	ELF_C_INFO			ELF64_C_INFO
 #define	elf_checksum			elf64_checksum
 #define	elf_fsize			elf64_fsize
 #define	elf_getehdr			elf64_getehdr
@@ -84,6 +85,9 @@
 #define	ELF_M_SYM			ELF32_M_SYM
 #define	ELF_M_SIZE			ELF32_M_SIZE
 #define	ELF_M_INFO			ELF32_M_INFO
+#define	ELF_C_SYM			ELF32_C_SYM
+#define	ELF_C_GROUP			ELF32_C_GROUP
+#define	ELF_C_INFO			ELF32_C_INFO
 #define	elf_checksum			elf32_checksum
 #define	elf_fsize			elf32_fsize
 #define	elf_getehdr			elf32_getehdr
--- a/usr/src/cmd/sgs/include/conv.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/conv.h	Mon Mar 01 10:20:48 2010 -0800
@@ -127,10 +127,10 @@
 } Conv_reject_desc_buf_t;
 
 /*
- * conv_cap_val_hw1()
+ * conv_cap_val_hw/sf()
  *
- * This size is based on the maximum number of hardware capabilities
- * that exist.  See common/elfcap.
+ * These sizes are based on the maximum number of capabilities that exist.
+ * See common/elfcap.
  */
 #define	CONV_CAP_VAL_HW1_BUFSIZE	195
 typedef union {
@@ -138,12 +138,12 @@
 	char				buf[CONV_CAP_VAL_HW1_BUFSIZE];
 } Conv_cap_val_hw1_buf_t;
 
-/*
- * conv_cap_val_sf1()
- *
- * This size is based on the maximum number of software capabilities
- * that exist.  See common/elfcap.
- */
+#define	CONV_CAP_VAL_HW2_BUFSIZE	CONV_INV_BUFSIZE	/* for now */
+typedef union {
+	Conv_inv_buf_t			inv_buf;
+	char				buf[CONV_CAP_VAL_HW2_BUFSIZE];
+} Conv_cap_val_hw2_buf_t;
+
 #define	CONV_CAP_VAL_SF1_BUFSIZE	45
 typedef union {
 	Conv_inv_buf_t			inv_buf;
@@ -155,6 +155,7 @@
 	Conv_inv_buf_t			inv_buf;
 	Conv_cap_val_hw1_buf_t		cap_val_hw1_buf;
 	Conv_cap_val_sf1_buf_t		cap_val_sf1_buf;
+	Conv_cap_val_hw2_buf_t		cap_val_hw2_buf;
 } Conv_cap_val_buf_t;
 
 /* conv_config_feat() */
@@ -362,7 +363,7 @@
 } Conv_ent_flags_buf_t;
 
 /* conv_ent_files_flags() */
-#define	CONV_ENT_FILES_FLAGS_BUFSIZE		89
+#define	CONV_ENT_FILES_FLAGS_BUFSIZE	89
 typedef union {
 	Conv_inv_buf_t			inv_buf;
 	char				buf[CONV_ENT_FILES_FLAGS_BUFSIZE];
@@ -896,6 +897,8 @@
 			    void *);
 extern	conv_iter_ret_t	conv_iter_cap_val_hw1(Half, Conv_fmt_flags_t,
 			    conv_iter_cb_t, void *);
+extern	conv_iter_ret_t	conv_iter_cap_val_hw2(Half, Conv_fmt_flags_t,
+			    conv_iter_cb_t, void *);
 extern	conv_iter_ret_t	conv_iter_cap_val_sf1(Conv_fmt_flags_t, conv_iter_cb_t,
 			    void *);
 
@@ -962,6 +965,7 @@
 #define	conv_cap_tag		conv64_cap_tag
 #define	conv_cap_val		conv64_cap_val
 #define	conv_cap_val_hw1	conv64_cap_val_hw1
+#define	conv_cap_val_hw2	conv64_cap_val_hw2
 #define	conv_cap_val_sf1	conv64_cap_val_sf1
 #define	conv_dyn_feature1	conv64_dyn_feature1
 #define	conv_dyn_flag1		conv64_dyn_flag1
@@ -979,6 +983,7 @@
 #define	conv_cap_tag		conv32_cap_tag
 #define	conv_cap_val		conv32_cap_val
 #define	conv_cap_val_hw1	conv32_cap_val_hw1
+#define	conv_cap_val_hw2	conv32_cap_val_hw2
 #define	conv_cap_val_sf1	conv32_cap_val_sf1
 #define	conv_dyn_feature1	conv32_dyn_feature1
 #define	conv_dyn_flag1		conv32_dyn_flag1
@@ -1010,9 +1015,12 @@
  */
 extern	const char	*conv_cap_tag(Xword, Conv_fmt_flags_t,
 			    Conv_inv_buf_t *);
-extern	const char	*conv_cap_val(Xword, Xword, Half, Conv_cap_val_buf_t *);
+extern	const char	*conv_cap_val(Xword, Xword, Half, Conv_fmt_flags_t,
+			    Conv_cap_val_buf_t *);
 extern	const char	*conv_cap_val_hw1(Xword, Half, Conv_fmt_flags_t,
 			    Conv_cap_val_hw1_buf_t *);
+extern	const char	*conv_cap_val_hw2(Xword, Half, Conv_fmt_flags_t,
+			    Conv_cap_val_hw2_buf_t *);
 extern	const char	*conv_cap_val_sf1(Xword, Half, Conv_fmt_flags_t,
 			    Conv_cap_val_sf1_buf_t *);
 extern	const char	*conv_dyn_flag1(Xword, Conv_fmt_flags_t,
--- a/usr/src/cmd/sgs/include/debug.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/debug.h	Mon Mar 01 10:20:48 2010 -0800
@@ -133,6 +133,18 @@
 #define	DBG_BINFO_REF_PARENT	0x2000	/* reference to PARENT */
 #define	DBG_BINFO_REF_MSK	0xf000
 
+/*
+ * ld.so.1(1) symbol capabilities processing.
+ */
+#define	DBG_CAP_DEFAULT		0
+#define	DBG_CAP_USED		1
+#define	DBG_CAP_CANDIDATE	2
+#define	DBG_CAP_REJECTED	3
+#define	DBG_CAP_HW_1		4
+#define	DBG_CAP_SF_1		5
+#define	DBG_CAP_HW_2		6
+#define	DBG_CAP_PLAT		7
+#define	DBG_CAP_MACH		8
 
 #define	DBG_REL_START		1
 #define	DBG_REL_FINISH		2
@@ -159,8 +171,8 @@
 #define	DBG_STATE_MOD_AFTER	5	/* modify (after) */
 #define	DBG_STATE_NEW 		6	/* new */
 #define	DBG_STATE_NEW_IMPLICIT	7	/* new (implicit) */
-#define	DBG_STATE_OUT		8	/* out */
-#define	DBG_STATE_RESET		9	/* reset */
+#define	DBG_STATE_RESET		8	/* reset */
+#define	DBG_STATE_ORIGINAL	9	/* original */
 #define	DBG_STATE_RESOLVED	10	/* resolved */
 
 #define	DBG_STATE_NUM		11
@@ -280,14 +292,15 @@
 #define	Dbg_bind_reject		Dbg64_bind_reject
 #define	Dbg_bind_weak		Dbg64_bind_weak
 
-#define	Dbg_cap_entry		Dbg64_cap_entry
-#define	Dbg_cap_entry2		Dbg64_cap_entry2
-#define	Dbg_cap_val_hw1		Dbg64_cap_val_hw1
-#define	Dbg_cap_hw_candidate	Dbg64_cap_hw_candidate
-#define	Dbg_cap_hw_filter	Dbg64_cap_hw_filter
+#define	Dbg_cap_candidate	Dbg64_cap_candidate
+#define	Dbg_cap_filter		Dbg64_cap_filter
+#define	Dbg_cap_id		Dbg64_cap_id
 #define	Dbg_cap_mapfile_title	Dbg64_cap_mapfile_title
-#define	Dbg_cap_out_title	Dbg64_cap_out_title
+#define	Dbg_cap_post_title	Dbg64_cap_post_title
 #define	Dbg_cap_sec_title	Dbg64_cap_sec_title
+#define	Dbg_cap_val		Dbg64_cap_val
+#define	Dbg_cap_ptr_entry	Dbg64_cap_ptr_entry
+#define	Dbg_cap_val_entry	Dbg64_cap_val_entry
 
 #define	Dbg_cb_iphdr_enter	Dbg64_cb_iphdr_enter
 #define	Dbg_cb_iphdr_callback	Dbg64_cb_iphdr_callback
@@ -435,6 +448,10 @@
 #define	Dbg_syms_ar_entry	Dbg64_syms_ar_entry
 #define	Dbg_syms_ar_resolve	Dbg64_syms_ar_resolve
 #define	Dbg_syms_ar_title	Dbg64_syms_ar_title
+#define	Dbg_syms_cap_convert	Dbg64_syms_cap_convert
+#define	Dbg_syms_cap_local	Dbg64_syms_cap_local
+#define	Dbg_syms_cap_lookup	Dbg64_syms_cap_lookup
+#define	Dbg_syms_cap_title	Dbg64_syms_cap_title
 #define	Dbg_syms_created	Dbg64_syms_created
 #define	Dbg_syms_discarded	Dbg64_syms_discarded
 #define	Dbg_syms_dlsym		Dbg64_syms_dlsym
@@ -502,14 +519,15 @@
 #define	Dbg_bind_reject		Dbg32_bind_reject
 #define	Dbg_bind_weak		Dbg32_bind_weak
 
-#define	Dbg_cap_entry		Dbg32_cap_entry
-#define	Dbg_cap_entry2		Dbg32_cap_entry2
-#define	Dbg_cap_val_hw1		Dbg32_cap_val_hw1
-#define	Dbg_cap_hw_candidate	Dbg32_cap_hw_candidate
-#define	Dbg_cap_hw_filter	Dbg32_cap_hw_filter
+#define	Dbg_cap_candidate	Dbg32_cap_candidate
+#define	Dbg_cap_filter		Dbg32_cap_filter
+#define	Dbg_cap_id		Dbg32_cap_id
 #define	Dbg_cap_mapfile_title	Dbg32_cap_mapfile_title
-#define	Dbg_cap_out_title	Dbg32_cap_out_title
+#define	Dbg_cap_post_title	Dbg32_cap_post_title
 #define	Dbg_cap_sec_title	Dbg32_cap_sec_title
+#define	Dbg_cap_val		Dbg32_cap_val
+#define	Dbg_cap_ptr_entry	Dbg32_cap_ptr_entry
+#define	Dbg_cap_val_entry	Dbg32_cap_val_entry
 
 #define	Dbg_cb_iphdr_enter	Dbg32_cb_iphdr_enter
 #define	Dbg_cb_iphdr_callback	Dbg32_cb_iphdr_callback
@@ -657,6 +675,10 @@
 #define	Dbg_syms_ar_entry	Dbg32_syms_ar_entry
 #define	Dbg_syms_ar_resolve	Dbg32_syms_ar_resolve
 #define	Dbg_syms_ar_title	Dbg32_syms_ar_title
+#define	Dbg_syms_cap_convert	Dbg32_syms_cap_convert
+#define	Dbg_syms_cap_local	Dbg32_syms_cap_local
+#define	Dbg_syms_cap_lookup	Dbg32_syms_cap_lookup
+#define	Dbg_syms_cap_title	Dbg32_syms_cap_title
 #define	Dbg_syms_created	Dbg32_syms_created
 #define	Dbg_syms_discarded	Dbg32_syms_discarded
 #define	Dbg_syms_dlsym		Dbg32_syms_dlsym
@@ -754,14 +776,15 @@
 extern	void	Dbg_bind_reject(Rt_map *, Rt_map *, const char *, int);
 extern	void	Dbg_bind_weak(Rt_map *, Addr, Addr, const char *);
 
-extern	void	Dbg_cap_entry(Lm_list *, dbg_state_t, Xword, Xword, Half);
-extern	void	Dbg_cap_entry2(Lm_list *, dbg_state_t, Xword, CapMask *, Half);
-extern	void	Dbg_cap_hw_candidate(Lm_list *, const char *);
-extern	void	Dbg_cap_hw_filter(Lm_list *, const char *, Rt_map *);
+extern	void	Dbg_cap_candidate(Lm_list *, const char *);
+extern	void	Dbg_cap_filter(Lm_list *, const char *, Rt_map *);
+extern	void	Dbg_cap_id(Lm_list *, Lineno, const char *, const char *);
 extern	void	Dbg_cap_mapfile_title(Lm_list *, Lineno);
-extern	void	Dbg_cap_out_title(Lm_list *);
+extern	void	Dbg_cap_post_title(Lm_list *, int *);
 extern	void	Dbg_cap_sec_title(Lm_list *, const char *);
-extern	void	Dbg_cap_val_hw1(Lm_list *, Xword, Half);
+extern	void	Dbg_cap_val(Lm_list *, Syscapset *, Syscapset *, Half);
+extern	void	Dbg_cap_ptr_entry(Lm_list *, dbg_state_t, Xword, const char *);
+extern	void	Dbg_cap_val_entry(Lm_list *, dbg_state_t, Xword, Xword, Half);
 
 extern	void	Dbg_cb_iphdr_enter(Lm_list *, u_longlong_t, u_longlong_t);
 extern	void	Dbg_cb_iphdr_callback(Lm_list *, struct dl_phdr_info *);
@@ -935,6 +958,12 @@
 extern	void	Dbg_syms_ar_resolve(Lm_list *, Xword, Elf_Arsym *,
 		    const char *, int);
 extern	void	Dbg_syms_ar_title(Lm_list *, const char *, int);
+extern	void	Dbg_syms_cap_convert(Ofl_desc *, Word, const char *, Sym *);
+extern	void	Dbg_syms_cap_local(Ofl_desc *, Word, const char *, Sym *,
+		    Sym_desc *);
+extern	void	Dbg_syms_cap_lookup(Rt_map *, uint_t, const char *, uint_t,
+		    Half, Syscapset *);
+extern	void	Dbg_syms_cap_title(Ofl_desc *);
 extern	void	Dbg_syms_created(Lm_list *, const char *);
 extern	void	Dbg_syms_discarded(Lm_list *, Sym_desc *);
 extern	void	Dbg_syms_dlsym(Rt_map *, const char *, int *, const char *,
@@ -1099,7 +1128,8 @@
 
 #endif
 
-extern	void	Elf_cap_entry(Lm_list *, Cap *, int, Half);
+extern	void	Elf_cap_entry(Lm_list *, Cap *, int, const char *, size_t,
+		    Half);
 extern	void	Elf_cap_title(Lm_list *);
 
 extern	const char \
--- a/usr/src/cmd/sgs/include/elfedit.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/elfedit.h	Mon Mar 01 10:20:48 2010 -0800
@@ -736,10 +736,11 @@
 	ELFEDIT_CONST_SYMINFO_BT =	30,	/* Syminfo boundto */
 	ELFEDIT_CONST_SYMINFO_FLG =	31,	/* Syminfo flags */
 	ELFEDIT_CONST_CA =		32,	/* Capabilities tags */
-	ELFEDIT_CONST_AV =		33,	/* hardware capabilities */
+	ELFEDIT_CONST_HW1_SUNW =	33,	/* hardware capabilities */
 	ELFEDIT_CONST_SF1_SUNW =	34,	/* software capabilities */
+	ELFEDIT_CONST_HW2_SUNW =	35,	/* hardware capabilities */
 
-	ELFEDIT_CONST_NUM =		35,	/* # of constant types */
+	ELFEDIT_CONST_NUM =		36,	/* # of constant types */
 } elfedit_const_t;
 
 /*
--- a/usr/src/cmd/sgs/include/i386/machdep_x86.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/i386/machdep_x86.h	Mon Mar 01 10:20:48 2010 -0800
@@ -243,20 +243,23 @@
 #define	M_ID_NULL	0x00
 #define	M_ID_USER	0x01
 
-#define	M_ID_INTERP	0x03			/* SHF_ALLOC */
-#define	M_ID_CAP	0x04
+#define	M_ID_INTERP	0x02			/* SHF_ALLOC */
+#define	M_ID_CAP	0x03
+
 #define	M_ID_UNWINDHDR	0x06
 #define	M_ID_UNWIND	0x07
-#define	M_ID_SYMINFO	0x08
-#define	M_ID_HASH	0x09
-#define	M_ID_LDYNSYM	0x0a			/* always right before DYNSYM */
-#define	M_ID_DYNSYM	0x0b
-#define	M_ID_DYNSTR	0x0c
-#define	M_ID_VERSION	0x0d
-#define	M_ID_DYNSORT	0x0e
-#define	M_ID_REL	0x0f
-#define	M_ID_PLT	0x10			/* SHF_ALLOC + SHF_EXECISNTR */
-#define	M_ID_TEXT	0x11
+#define	M_ID_CAPINFO	0x08
+#define	M_ID_CAPCHAIN	0x09
+#define	M_ID_SYMINFO	0x0a
+#define	M_ID_HASH	0x0b
+#define	M_ID_LDYNSYM	0x0c			/* always right before DYNSYM */
+#define	M_ID_DYNSYM	0x0d
+#define	M_ID_DYNSTR	0x0e
+#define	M_ID_VERSION	0x0f
+#define	M_ID_DYNSORT	0x10
+#define	M_ID_REL	0x11
+#define	M_ID_PLT	0x12			/* SHF_ALLOC + SHF_EXECINSTR */
+#define	M_ID_TEXT	0x13
 #define	M_ID_DATA	0x20
 
 /*	M_ID_USER	0x01			dual entry - listed above */
--- a/usr/src/cmd/sgs/include/libld.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/libld.h	Mon Mar 01 10:20:48 2010 -0800
@@ -163,6 +163,50 @@
 	const char	*wsn_wrapname;	/* Wrap symbol name: __wrap_XXX */
 } WrapSymNode;
 
+/*
+ * Capabilities structures, used to maintain a capabilities set.
+ *
+ * Capabilities can be defined within input relocatable objects, and can be
+ * augmented or replaced by mapfile directives.  In addition, mapfile directives
+ * can be used to exclude capabilities that would otherwise be carried over to
+ * the output object.
+ *
+ * CA_SUNW_HW_1, CA_SUNW_SF_1 and CA_SUNW_HW_2 values are bitmasks.  A current
+ * value, and an exclude value are maintained for each capability.
+ *
+ * There can be multiple CA_SUNW_PLAT and CA_SUNW_MACH entries and thus Alists
+ * are used to collect these entries.  A current list for each capability is
+ * maintained as Capstr entries, which provide for maintaining the strings
+ * eventual index into a string table.  An exclude list is maintained as a
+ * list of string pointers.
+ */
+typedef struct {
+	elfcap_mask_t	cm_val;		/* bitmask value */
+	elfcap_mask_t	cm_exc;		/* bits to exclude from final object */
+} Capmask;
+
+typedef struct {
+	Alist		*cl_val;	/* string (Capstr) value */
+	APlist		*cl_exc;	/* strings to exclude from final */
+} Caplist;				/*	object */
+
+typedef	struct {
+	char		*cs_str;	/* platform or machine name */
+	Word		cs_ndx;		/* the entries output Cap index */
+} Capstr;
+
+typedef	uint_t		oc_flag_t;
+typedef	struct {
+	Capmask		oc_hw_1;	/* CA_SUNW_HW_1 capabilities */
+	Capmask		oc_sf_1;	/* CA_SUNW_SF_1 capabilities */
+	Capmask		oc_hw_2;	/* CA_SUNW_HW_2 capabilities */
+	Caplist		oc_plat;	/* CA_SUNW_PLAT capabilities */
+	Caplist		oc_mach;	/* CA_SUNW_MACH capabilities */
+	Capstr		oc_id;		/* CA_SUNW_ID capability */
+	oc_flag_t	oc_flags;
+} Objcapset;
+
+#define	FLG_OCS_USRDEFID	0x1	/* user defined CA_SUNW_ID */
 
 /*
  * Bitmasks for a single capability. Capabilities come from input objects,
@@ -277,6 +321,12 @@
 	Word		ofl_dyntlssortcnt; /* no. ndx in .SUNW_dyntlssort */
 	Word		ofl_dynshdrcnt;	/* no. of output section in .dynsym */
 	Word		ofl_shdrcnt;	/* no. of output sections */
+	Word		ofl_caploclcnt;	/* no. of local capabilities symbols */
+	Word		ofl_capsymcnt;	/* no. of symbol capabilities entries */
+					/*	required */
+	Word		ofl_capchaincnt; /* no. of Capchain symbols */
+	APlist		*ofl_capgroups;	/* list of capabilities groups */
+	avl_tree_t	*ofl_capfamilies; /* capability family AVL tree */
 	Str_tbl		*ofl_shdrsttab;	/* Str_tbl for shdr strtab */
 	Str_tbl		*ofl_strtab;	/* Str_tbl for symtab strtab */
 	Str_tbl		*ofl_dynstrtab;	/* Str_tbl for dymsym strtab */
@@ -313,6 +363,8 @@
 	Os_desc		*ofl_ospreinitarray; /* .preinitarray output section */
 	Os_desc		*ofl_osinterp;	/* .interp output section */
 	Os_desc		*ofl_oscap;	/* .SUNW_cap output section */
+	Os_desc		*ofl_oscapinfo;	/* .SUNW_capinfo output section */
+	Os_desc		*ofl_oscapchain; /* .SUNW_capchain output section */
 	Os_desc		*ofl_osplt;	/* .plt output section */
 	Os_desc		*ofl_osmove;	/* .SUNW_move output section */
 	Os_desc		*ofl_osrelhead;	/* first relocation section */
@@ -337,7 +389,7 @@
 	char		*ofl_audit;	/* object auditing required (-p) */
 	Alist		*ofl_symfltrs;	/* per-symbol filtees and their */
 	Alist		*ofl_dtsfltrs;	/*	associated .dynamic/.dynstrs */
-	Outcapset	ofl_ocapset;	/* object capabilities */
+	Objcapset	ofl_ocapset;	/* object capabilities */
 	Lm_list		*ofl_lml;	/* runtime link-map list */
 	Gottable	*ofl_gottable;	/* debugging got information */
 	Rlxrel_cache	ofl_sr_cache;	/* Cache last result from */
@@ -395,8 +447,12 @@
 #define	FLG_OF_REDLSYM	0x004000000000	/* reduce local symbols */
 #define	FLG_OF_OS_ORDER	0x008000000000	/* output section ordering required */
 #define	FLG_OF_OSABI	0x010000000000	/* tag object as ELFOSABI_SOLARIS */
-#define	FLG_OF_ADJOSCNT	0x020000000000	/* ajust ofl_shdrcnt to accommodate */
+#define	FLG_OF_ADJOSCNT	0x020000000000	/* adjust ofl_shdrcnt to accommodate */
 					/*	discarded sections */
+#define	FLG_OF_OTOSCAP	0x040000000000	/* convert object capabilities to */
+					/*	symbol capabilities */
+#define	FLG_OF_PTCAP	0x080000000000	/* PT_SUNWCAP required */
+#define	FLG_OF_CAPSTRS	0x100000000000	/* capability strings are required */
 
 /*
  * In the flags1 arena, establish any options that are applicable to archive
@@ -418,7 +474,6 @@
 #define	FLG_OF1_NRLXREL	0x0000000200	/* -z norelaxreloc flag set */
 #define	FLG_OF1_RLXREL	0x0000000400	/* -z relaxreloc flag set */
 #define	FLG_OF1_IGNORE	0x0000000800	/* ignore unused dependencies */
-
 #define	FLG_OF1_NOSGHND	0x0000001000	/* -z nosighandler flag set */
 #define	FLG_OF1_TEXTOFF 0x0000002000	/* text relocations are ok */
 #define	FLG_OF1_ABSEXEC	0x0000004000	/* -zabsexec set */
@@ -434,7 +489,7 @@
 					/*	section */
 #define	FLG_OF1_MEMORY	0x0000200000	/* produce a memory model */
 #define	FLG_OF1_NGLBDIR	0x0000400000	/* no DT_1_DIRECT flag allowed */
-#define	FLG_OF1_ENCDIFF	0x0000800000	/* Host running linker has different */
+#define	FLG_OF1_ENCDIFF	0x0000800000	/* host running linker has different */
 					/*	byte order than output object */
 #define	FLG_OF1_VADDR	0x0001000000	/* a segment defines explicit vaddr */
 #define	FLG_OF1_EXTRACT	0x0002000000	/* archive member has been extracted */
@@ -449,6 +504,9 @@
 #define	FLG_OF1_OVHWCAP1 0x0100000000	/* override CA_SUNW_HW_1 capabilities */
 #define	FLG_OF1_OVSFCAP1 0x0200000000	/* override CA_SUNW_SF_1 capabilities */
 #define	FLG_OF1_OVHWCAP2 0x0400000000	/* override CA_SUNW_HW_2 capabilities */
+#define	FLG_OF1_OVMACHCAP 0x0800000000	/* override CA_SUNW_MACH capability */
+#define	FLG_OF1_OVPLATCAP 0x1000000000	/* override CA_SUNW_PLAT capability */
+#define	FLG_OF1_OVIDCAP	0x2000000000	/* override CA_SUNW_ID capability */
 
 /*
  * Test to see if the output file would allow the presence of
@@ -497,6 +555,7 @@
 #define	SYMTAB_LOC_CNT(_ofl)		/* local .symtab entries */	\
 	(2 +				/*    NULL and STT_FILE */	\
 	(_ofl)->ofl_shdrcnt +		/*    section symbol */		\
+	(_ofl)->ofl_caploclcnt +	/*    local capabilities */	\
 	(_ofl)->ofl_scopecnt +		/*    scoped symbols */		\
 	(_ofl)->ofl_locscnt)		/*    standard locals */
 #define	SYMTAB_ALL_CNT(_ofl)		/* all .symtab entries */	\
@@ -506,6 +565,7 @@
 #define	DYNSYM_LOC_CNT(_ofl)		/* local .dynsym entries */	\
 	(1 +				/*    NULL */			\
 	(_ofl)->ofl_dynshdrcnt +	/*    section symbols */	\
+	(_ofl)->ofl_caploclcnt +	/*    local capabilities */	\
 	(_ofl)->ofl_lregsymcnt)		/*    local register symbols */
 #define	DYNSYM_ALL_CNT(_ofl)		/* all .dynsym entries */	\
 	(DYNSYM_LOC_CNT(_ofl) +		/*    .dynsym locals */		\
@@ -598,7 +658,7 @@
  * Symbol value descriptor.  For relocatable objects, each symbols value is
  * its offset within its associated section.  Therefore, to uniquely define
  * each symbol within a reloctable object, record and sort the sh_offset and
- * symbol value.  This information is used to seach for displacement
+ * symbol value.  This information is used to search for displacement
  * relocations as part of copy relocation validation.
  */
 typedef struct {
@@ -634,6 +694,7 @@
 	APlist		*ifl_verdesc;	/* version descriptor list */
 	APlist		*ifl_relsect;	/* relocation section list */
 	Alist		*ifl_groups;	/* SHT_GROUP section list */
+	Cap_desc	*ifl_caps;	/* capabilities descriptor */
 };
 
 #define	FLG_IF_CMDLINE	0x00000001	/* full filename specified from the */
@@ -667,6 +728,8 @@
 #define	FLG_IF_GNUVER	0x00010000	/* file used GNU-style versioning */
 #define	FLG_IF_ORDERED	0x00020000	/* ordered section processing */
 					/*	required */
+#define	FLG_IF_OTOSCAP	0x00040000	/* convert object capabilities to */
+					/*	symbol capabilities */
 
 struct is_desc {			/* input section descriptor */
 	const char	*is_name;	/* original section name */
@@ -679,7 +742,7 @@
 	Is_desc		*is_comdatkeep;	/* If COMDAT section is discarded, */
 					/* 	this is section that was kept */
 	Word		is_scnndx;	/* original section index in file */
-	Word		is_ordndx;	/* Index for section.  Used to decide */
+	Word		is_ordndx;	/* index for section.  Used to decide */
 					/*	where to insert section when */
 					/* 	reordering sections */
 	Word		is_keyident;	/* key for SHF_{ORDERED|LINK_ORDER} */
@@ -993,7 +1056,6 @@
 #define	FLG_SY_VERSPROM	0x00000080	/* version definition has been */
 					/*	promoted to output file */
 #define	FLG_SY_PROT	0x00000100	/* stv_protected visibility seen */
-
 #define	FLG_SY_MAPREF	0x00000200	/* symbol reference generated by user */
 					/*	from mapfile */
 #define	FLG_SY_REFRSD	0x00000400	/* symbols sd_ref has been raised */
@@ -1068,6 +1130,14 @@
 #define	FLG_SY_DIR	0x0020000000000	/* global symbol, direct bindings */
 #define	FLG_SY_NDIR	0x0040000000000	/* global symbol, nondirect bindings */
 #define	FLG_SY_OVERLAP	0x0080000000000	/* move entry overlap detected */
+#define	FLG_SY_CAP	0x0100000000000	/* symbol is associated with */
+					/*    capabilities */
+
+/*
+ * A symbol can only be truly hidden if it is not a capabilities symbol.
+ */
+#define	SYM_IS_HIDDEN(_sdp) \
+	(((_sdp)->sd_flags & (FLG_SY_HIDDEN | FLG_SY_CAP)) == FLG_SY_HIDDEN)
 
 /*
  * Create a mask for (sym.st_other & visibility) since the gABI does not yet
@@ -1142,7 +1212,7 @@
 struct	ver_index {
 	const char	*vi_name;	/* dependency version name */
 	Half		vi_flags;	/* communicates availability */
-	Half		vi_overndx;	/* Index asssigned to this version in */
+	Half		vi_overndx;	/* index assigned to this version in */
 					/*	output object Verneed section */
 	Ver_desc	*vi_desc;	/* cross reference to descriptor */
 };
--- a/usr/src/cmd/sgs/include/rtld.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/rtld.h	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_RTLD_H
@@ -38,6 +38,7 @@
 #include <sys/avl.h>
 #include <alist.h>
 #include <libc_int.h>
+#include <elfcap.h>
 
 #ifdef	_SYSCALL32
 #include <inttypes.h>
@@ -59,6 +60,7 @@
 
 typedef struct rt_map	Rt_map;
 typedef struct slookup	Slookup;
+typedef struct sresult	Sresult;
 
 /*
  * A binding descriptor.  Establishes the binding relationship between two
@@ -666,7 +668,7 @@
 	 * END: Exposed to rtld_db - don't move, don't delete
 	 */
 	APlist		*rt_alias;	/* list of linked file names */
-	APlist		*rt_fpnode;	/* list of FullpathNode AVL nodes */
+	APlist		*rt_fpnode;	/* list of FullPathNode AVL nodes */
 	char		*rt_runpath;	/* LD_RUN_PATH and its equivalent */
 	Alist		*rt_runlist;	/*	Pdesc structures */
 	APlist		*rt_depends;	/* list of dependencies */
@@ -707,8 +709,8 @@
 	uint_t		rt_idx;		/* hold index within linkmap list */
 	uint_t		rt_lazy;	/* number of lazy dependencies */
 					/*	pending */
-	Xword		rt_hwcap;	/* hardware capabilities */
-	Xword		rt_sfcap;	/* software capabilities */
+	Cap		*rt_cap;	/* capabilities data */
+	Capchain	*rt_capchain;	/* capabilities chain data */
 	uint_t		rt_cntl;	/* link-map control list we belong to */
 	uint_t		rt_aflags;	/* auditor flags, see LML_TFLG_AUD_ */
 					/* address of _init */
@@ -716,7 +718,7 @@
 					/* address of _fini */
 	void		(*rt_fini)(void);
 					/* link map symbol interpreter */
-	Sym		*(*rt_symintp)(Slookup *, Rt_map **, uint_t *, int *);
+	int		(*rt_symintp)(Slookup *, Sresult *, uint_t *, int *);
 };
 
 #ifdef _SYSCALL32
@@ -781,8 +783,8 @@
 	uint32_t	rt_relacount;
 	uint32_t	rt_idx;
 	uint32_t	rt_lazy;
-	uint32_t	rt_hwcap;
-	uint32_t	rt_sfcap;
+	uint32_t	rt_cap;
+	uint32_t	rt_capchain;
 	uint32_t	rt_cntl;
 	uint32_t	rt_aflags;
 	uint32_t 	rt_init;
@@ -808,7 +810,7 @@
  * END: Exposed to rtld_db - don't move, don't delete
  */
 #define	FLG_RT_SETGROUP	0x00000008	/* group establishment required */
-#define	FLG_RT_HWCAP	0x00000010	/* process $HWCAP expansion */
+#define	FLG_RT_CAP	0x00000010	/* process $CAPABILITY expansion */
 #define	FLG_RT_OBJECT	0x00000020	/* object processing (ie. .o's) */
 #define	FLG_RT_NEWLOAD	0x00000040	/* object is newly loaded */
 #define	FLG_RT_NODUMP	0x00000080	/* object can't be dldump(3x)'ed */
@@ -839,13 +841,15 @@
 #define	FLG_RT_PRIHDL	0x40000000	/*	either public or private */
 
 #define	FL1_RT_COPYTOOK	0x00000001	/* copy relocation taken */
-
-#define	FL1_RT_CONFSET	0x00000004	/* object was loaded by crle(1) */
-#define	FL1_RT_NODEFLIB	0x00000008	/* ignore default library search */
-#define	FL1_RT_ENDFILTE	0x00000010	/* filtee terminates filters search */
-#define	FL1_RT_DISPREL	0x00000020	/* object has *disp* relocation */
-#define	FL1_RT_DTFLAGS	0x00000040	/* DT_FLAGS element exists */
-
+#define	FL1_RT_ALTCHECK	0x00000002	/* alternative system capabilities */
+					/*	checked */
+#define	FL1_RT_ALTCAP	0x00000004	/* alternative system capabilities */
+					/*	should be used */
+#define	FL1_RT_CONFSET	0x00000008	/* object was loaded by crle(1) */
+#define	FL1_RT_NODEFLIB	0x00000010	/* ignore default library search */
+#define	FL1_RT_ENDFILTE	0x00000020	/* filtee terminates filters search */
+#define	FL1_RT_DISPREL	0x00000040	/* object has *disp* relocation */
+#define	FL1_RT_DTFLAGS	0x00000080	/* DT_FLAGS element exists */
 #define	FL1_RT_LDDSTUB	0x00000100	/* identify lddstub */
 #define	FL1_RT_NOINIFIN	0x00000200	/* no .init or .fini exists */
 #define	FL1_RT_USED	0x00000400	/* symbol referenced from this object */
@@ -965,8 +969,8 @@
 #define	IDX(X)		((X)->rt_idx)
 #define	LAZY(X)		((X)->rt_lazy)
 #define	CNTL(X)		((X)->rt_cntl)
-#define	HWCAP(X)	((X)->rt_hwcap)
-#define	SFCAP(X)	((X)->rt_sfcap)
+#define	CAP(X)		((X)->rt_cap)
+#define	CAPCHAIN(X)	((X)->rt_capchain)
 
 /*
  * Flags for tsorting.
@@ -1004,6 +1008,7 @@
 #define	LKUP_STANDARD	0x2000		/* standard lookup - originated from */
 					/* 	head link-map element */
 #define	LKUP_WORLD	0x4000		/* ensure world lookup */
+#define	LKUP_DLSYM	0x8000		/* lookup stems from dlsym() request */
 
 /*
  * For the runtime linker to perform a symbol search, a number of data items
@@ -1064,6 +1069,49 @@
 	    sl.sl_flags = (flags))
 
 /*
+ * After a symbol lookup has been resolved, the runtime linker needs to retain
+ * information regarding the bound definition.  An Sresult data structure is
+ * used to provide this information.
+ *
+ * The symbol name (sr_name) may differ from the original referenced symbol if
+ * a symbol capabilities family member has resolved the binding.  The defining
+ * object (sr_dmap) indicates the object in which the definition has been found.
+ * The symbol table entry (sr_sym) defines the bound symbol definition.
+ *
+ * Note, a symbol lookup may start with one Sresult buffer, but underlying
+ * routines (for example, those that probe filters) might employ their own
+ * Sresult buffer.  If a binding is allowed, the latter buffer may get inherited
+ * by the former.  Along with this chain of requests, binding info (binfo) and
+ * not-found information (in_nfavl), may be passed between all the associated
+ * functions.  Hence, the binfo and in_nfavl data is not maintained as part of
+ * a Sresult structure.
+ */
+struct sresult {
+	const char	*sr_name;	/* symbol definition name */
+	Rt_map		*sr_dmap;	/* defining objects link-map */
+	Sym		*sr_sym;	/* symbol table pointer */
+};
+
+#define	SRESULT_INIT(sr, name) \
+	(void) (sr.sr_name = (name), sr.sr_dmap = NULL, sr.sr_sym = NULL)
+
+/*
+ * Define a system capabilities structure for maintaining the various
+ * capabilities of the system.  This structure follows the Objcapset definition
+ * from libld.h, however the system can only have one platform or machine
+ * hardware name, thus this structure is a little simpler.
+ */
+typedef	struct {
+	elfcap_mask_t	sc_hw_1;	/* CA_SUNW_HW_1 capabilities */
+	elfcap_mask_t	sc_sf_1;	/* CA_SUNW_SF_1 capabilities */
+	elfcap_mask_t	sc_hw_2;	/* CA_SUNW_HW_2 capabilities */
+	char		*sc_plat;	/* CA_SUNW_PLAT capability */
+	size_t		sc_platsz;	/*	and size */
+	char		*sc_mach;	/* CA_SUNW_MACH capability */
+	size_t		sc_machsz;	/*	and size */
+} Syscapset;
+
+/*
  * Define a number of .plt lookup outcomes, for use in binding diagnostics.
  */
 typedef	enum {
@@ -1089,7 +1137,7 @@
 extern Pltbindtype	elf_plt_write(uintptr_t, uintptr_t, void *, uintptr_t,
 			    Xword);
 extern Rt_map		*is_so_loaded(Lm_list *, const char *, int *);
-extern Sym		*lookup_sym(Slookup *, Rt_map **, uint_t *, int *);
+extern int		lookup_sym(Slookup *, Sresult *, uint_t *, int *);
 extern int		rt_dldump(Rt_map *, const char *, int, Addr);
 
 #ifdef	__cplusplus
--- a/usr/src/cmd/sgs/include/sgs.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/sgs.h	Mon Mar 01 10:20:48 2010 -0800
@@ -145,6 +145,18 @@
 #endif
 
 /*
+ * CTF currently does not handle automatic array variables sized via function
+ * arguments (VLA arrays) properly, when the code is compiled with gcc.
+ * Adding 1 to the size is a workaround.  VLA_SIZE, and its use, should be
+ * pulled when CTF is fixed or replaced.
+ */
+#ifdef __GNUC__
+#define	VLA_SIZE(_arg)	((_arg) + 1)
+#else
+#define	VLA_SIZE(_arg)	(_arg)
+#endif
+
+/*
  * Structure to maintain rejected files elf information.  Files that are not
  * applicable to the present link-edit are rejected and a search for an
  * appropriate file may be resumed.  The first rejected files information is
@@ -173,8 +185,12 @@
 					/*	required */
 #define	SGS_REJ_STR		10	/* generic error - info is a string */
 #define	SGS_REJ_UNKFILE		11	/* unknown file type */
-#define	SGS_REJ_HWCAP_1		12	/* hardware capabilities mismatch */
-#define	SGS_REJ_SFCAP_1		13	/* software capabilities mismatch */
+#define	SGS_REJ_UNKCAP		12	/* unknown capabilities */
+#define	SGS_REJ_HWCAP_1		13	/* hardware capabilities mismatch */
+#define	SGS_REJ_SFCAP_1		14	/* software capabilities mismatch */
+#define	SGS_REJ_MACHCAP		15	/* machine capability mismatch */
+#define	SGS_REJ_PLATCAP		16	/* platform capability mismatch */
+#define	SGS_REJ_HWCAP_2		17	/* hardware capabilities mismatch */
 
 #define	FLG_REJ_ALTER		0x01	/* object name is an alternative */
 
@@ -199,29 +215,30 @@
 /*
  * Data structures (defined in libld.h).
  */
+typedef	struct audit_desc	Audit_desc;
+typedef	struct audit_info	Audit_info;
+typedef	struct audit_list	Audit_list;
+typedef struct cap_desc		Cap_desc;
 typedef struct ent_desc		Ent_desc;
 typedef	struct group_desc	Group_desc;
 typedef struct ifl_desc		Ifl_desc;
 typedef struct is_desc		Is_desc;
 typedef struct isa_desc		Isa_desc;
 typedef struct isa_opt		Isa_opt;
+typedef struct os_desc		Os_desc;
 typedef struct ofl_desc		Ofl_desc;
-typedef struct os_desc		Os_desc;
 typedef	struct rel_cache	Rel_cache;
 typedef	struct sdf_desc		Sdf_desc;
 typedef	struct sdv_desc		Sdv_desc;
+typedef struct sec_order	Sec_order;
 typedef struct sg_desc		Sg_desc;
 typedef struct sort_desc	Sort_desc;
-typedef struct sec_order	Sec_order;
+typedef	struct sym_avlnode	Sym_avlnode;
+typedef struct sym_aux		Sym_aux;
 typedef struct sym_desc		Sym_desc;
-typedef struct sym_aux		Sym_aux;
-typedef	struct sym_avlnode	Sym_avlnode;
 typedef	struct uts_desc		Uts_desc;
 typedef struct ver_desc		Ver_desc;
 typedef struct ver_index	Ver_index;
-typedef	struct audit_desc	Audit_desc;
-typedef	struct audit_info	Audit_info;
-typedef	struct audit_list	Audit_list;
 
 /*
  * Data structures defined in machrel.h.
--- a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h	Mon Mar 01 10:20:48 2010 -0800
@@ -229,18 +229,20 @@
 
 #define	M_ID_INTERP	0x02			/* SHF_ALLOC */
 #define	M_ID_CAP	0x03
+
 #define	M_ID_UNWINDHDR	0x06
 #define	M_ID_UNWIND	0x07
-
-#define	M_ID_SYMINFO	0x08
-#define	M_ID_HASH	0x09
-#define	M_ID_LDYNSYM	0x0a			/* always right before DYNSYM */
-#define	M_ID_DYNSYM	0x0b
-#define	M_ID_DYNSTR	0x0c
-#define	M_ID_VERSION	0x0d
-#define	M_ID_DYNSORT	0x0e
-#define	M_ID_REL	0x0f
-#define	M_ID_TEXT	0x10			/* SHF_ALLOC + SHF_EXECINSTR */
+#define	M_ID_CAPINFO 	0x08
+#define	M_ID_CAPCHAIN 	0x09
+#define	M_ID_SYMINFO	0x0a
+#define	M_ID_HASH	0x0b
+#define	M_ID_LDYNSYM	0x0c			/* always right before DYNSYM */
+#define	M_ID_DYNSYM	0x0d
+#define	M_ID_DYNSTR	0x0e
+#define	M_ID_VERSION	0x0f
+#define	M_ID_DYNSORT	0x10
+#define	M_ID_REL	0x11
+#define	M_ID_TEXT	0x12			/* SHF_ALLOC + SHF_EXECINSTR */
 #define	M_ID_DATA	0x20
 
 /*	M_ID_USER	0x01			dual entry - listed above */
--- a/usr/src/cmd/sgs/ld/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/ld/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -20,11 +20,9 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 PROG =		ld
 
@@ -40,7 +38,7 @@
 MAPFILES =	../common/mapfile-intf $(MAPFILE.NGB)
 MAPOPTS =	$(MAPFILES:%=-M%)
 
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPTS) $(VAR_LD_LLDFLAGS)
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) $(MAPOPTS) $(VAR_LD_LLDFLAGS)
 LDLIBS +=	$(LDLIBDIR) $(LD_LIB) $(ELFLIBDIR) -lelf \
 		    $(LDDBGLIBDIR) $(LDDBG_LIB) $(CONVLIBDIR) $(CONV_LIB)
 
--- a/usr/src/cmd/sgs/ldd/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/ldd/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -43,7 +43,7 @@
 		$(CPPFLAGS.master)
 LLDFLAGS =	'-R$$ORIGIN/../../lib'
 LLDFLAGS64 =	'-R$$ORIGIN/../../../lib/$(MACH64)'
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) -lelf $(DLLIB)
 LINTFLAGS +=	-x
 LINTFLAGS64 +=	-x
--- a/usr/src/cmd/sgs/ldprof/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/ldprof/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,6 +18,7 @@
 #
 # CDDL HEADER END
 #
+
 #
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -38,7 +39,7 @@
 
 MAPFILES =	mapfile-vers
 
-DYNFLAGS +=	$(USE_PROTO)
+DYNFLAGS +=	$(CC_USE_PROTO)
 CPPFLAGS=	-I. -I../common -I../../include \
 		-I../../rtld/common \
 		-I../../include/$(MACH) \
--- a/usr/src/cmd/sgs/libconv/common/cap.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/cap.c	Mon Mar 01 10:20:48 2010 -0800
@@ -36,16 +36,20 @@
 const conv_ds_t **
 conv_cap_tag_strings(Conv_fmt_flags_t fmt_flags)
 {
-#if	(CA_SUNW_NUM != (CA_SUNW_HW_2 + 1))
+#if	(CA_SUNW_NUM != (CA_SUNW_ID + 1))
 #error	"CA_SUNW_NUM has grown"
 #endif
 	static const Msg	tags_cf[] = {
 		MSG_CA_SUNW_NULL_CF,	MSG_CA_SUNW_HW_1_CF,
-		MSG_CA_SUNW_SF_1_CF,	MSG_CA_SUNW_HW_2_CF
+		MSG_CA_SUNW_SF_1_CF,	MSG_CA_SUNW_HW_2_CF,
+		MSG_CA_SUNW_PLAT_CF,	MSG_CA_SUNW_MACH_CF,
+		MSG_CA_SUNW_ID_CF
 	};
 	static const Msg	tags_nf[] = {
 		MSG_CA_SUNW_NULL_NF,	MSG_CA_SUNW_HW_1_NF,
 		MSG_CA_SUNW_SF_1_NF,	MSG_CA_SUNW_HW_2_NF,
+		MSG_CA_SUNW_PLAT_NF,	MSG_CA_SUNW_MACH_NF,
+		MSG_CA_SUNW_ID_NF
 	};
 	static const conv_ds_msg_t ds_tags_cf = {
 	    CONV_DS_MSG_INIT(ELFCLASSNONE, tags_cf) };
@@ -108,7 +112,7 @@
 }
 
 /*
- * Iterate the strings for CA_SUNW_HW1
+ * Iterate the strings for CA_SUNW_HW.
  */
 conv_iter_ret_t
 conv_iter_cap_val_hw1(Half mach, Conv_fmt_flags_t fmt_flags,
@@ -131,6 +135,14 @@
 	return (CONV_ITER_CONT);
 }
 
+conv_iter_ret_t
+/* ARGSUSED0 */
+conv_iter_cap_val_hw2(Half mach, Conv_fmt_flags_t fmt_flags,
+    conv_iter_cb_t func, void *uvalue)
+{
+	return (CONV_ITER_DONE);
+}
+
 /*
  * Iterate the strings for CA_SUNW_SF1
  */
--- a/usr/src/cmd/sgs/libconv/common/cap.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/cap.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -32,6 +32,12 @@
 @ MSG_CA_SUNW_SF_1_NF			"sf_1"
 @ MSG_CA_SUNW_HW_2_CF		"CA_SUNW_HW_2"			# 3
 @ MSG_CA_SUNW_HW_2_NF			"hw_2"
+@ MSG_CA_SUNW_PLAT_CF		"CA_SUNW_PLAT"			# 4
+@ MSG_CA_SUNW_PLAT_NF			"plat"
+@ MSG_CA_SUNW_MACH_CF		"CA_SUNW_MACH"			# 5
+@ MSG_CA_SUNW_MACH_NF			"mach"
+@ MSG_CA_SUNW_ID_CF		  "CA_SUNW_ID"			# 6
+@ MSG_CA_SUNW_ID_NF			  "id"
 
 @ MSG_GBL_ZERO		"0"
 @ MSG_GBL_OSQBRKT	"0x%llx  [ "
--- a/usr/src/cmd/sgs/libconv/common/cap_machelf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/cap_machelf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,7 +35,7 @@
 #include	"_conv.h"
 
 static int
-conv_cap_1(Xword val, char *str, size_t len, Half mach,
+conv_cap(Xword val, char *str, size_t len, Half mach,
     Conv_fmt_flags_t fmt_flags, elfcap_to_str_func_t *fptr)
 {
 	size_t	_len;
@@ -75,20 +75,33 @@
 	if (val == 0)
 		return (MSG_ORIG(MSG_GBL_ZERO));
 
-	if (conv_cap_1(val, cap_val_hw1_buf->buf, sizeof (cap_val_hw1_buf->buf),
+	if (conv_cap(val, cap_val_hw1_buf->buf, sizeof (cap_val_hw1_buf->buf),
 	    mach, fmt_flags, elfcap_hw1_to_str) == 0)
 		return (conv_invalid_val(&cap_val_hw1_buf->inv_buf, val, 0));
 	return ((const char *)cap_val_hw1_buf->buf);
 }
 
 const char *
+conv_cap_val_hw2(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
+    Conv_cap_val_hw2_buf_t *cap_val_hw2_buf)
+{
+	if (val == 0)
+		return (MSG_ORIG(MSG_GBL_ZERO));
+
+	if (conv_cap(val, cap_val_hw2_buf->buf, sizeof (cap_val_hw2_buf->buf),
+	    mach, fmt_flags, elfcap_hw2_to_str) == 0)
+		return (conv_invalid_val(&cap_val_hw2_buf->inv_buf, val, 0));
+	return ((const char *)cap_val_hw2_buf->buf);
+}
+
+const char *
 conv_cap_val_sf1(Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
     Conv_cap_val_sf1_buf_t *cap_val_sf1_buf)
 {
 	if (val == 0)
 		return (MSG_ORIG(MSG_GBL_ZERO));
 
-	if (conv_cap_1(val, cap_val_sf1_buf->buf, sizeof (cap_val_sf1_buf->buf),
+	if (conv_cap(val, cap_val_sf1_buf->buf, sizeof (cap_val_sf1_buf->buf),
 	    mach, fmt_flags, elfcap_sf1_to_str) == 0)
 		return (conv_invalid_val(&cap_val_sf1_buf->inv_buf, val, 0));
 	return ((const char *)cap_val_sf1_buf->buf);
@@ -115,14 +128,23 @@
 }
 
 const char *
-conv_cap_val(Xword tag, Xword val, Half mach, Conv_cap_val_buf_t *cap_val_buf)
+conv_cap_val(Xword tag, Xword val, Half mach, Conv_fmt_flags_t fmt_flags,
+    Conv_cap_val_buf_t *cap_val_buf)
 {
-	if (tag == CA_SUNW_HW_1)
-		return (conv_cap_val_hw1(val, mach, 0,
+	switch (tag) {
+	case CA_SUNW_HW_1:
+		return (conv_cap_val_hw1(val, mach, fmt_flags,
 		    &cap_val_buf->cap_val_hw1_buf));
-	else if (tag == CA_SUNW_SF_1)
-		return (conv_cap_val_sf1(val, mach, 0,
+
+	case CA_SUNW_SF_1:
+		return (conv_cap_val_sf1(val, mach, fmt_flags,
 		    &cap_val_buf->cap_val_sf1_buf));
-	else
+
+	case CA_SUNW_HW_2:
+		return (conv_cap_val_hw2(val, mach, fmt_flags,
+		    &cap_val_buf->cap_val_hw2_buf));
+
+	default:
 		return (conv_invalid_val(&cap_val_buf->inv_buf, val, 0));
+	}
 }
--- a/usr/src/cmd/sgs/libconv/common/dynamic.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -548,9 +548,11 @@
 		MSG_DT_SUNW_SYMTAB_CF,		MSG_DT_SUNW_SYMSZ_CF,
 		MSG_DT_SUNW_SORTENT_CF,		MSG_DT_SUNW_SYMSORT_CF,
 		MSG_DT_SUNW_SYMSORTSZ_CF,	MSG_DT_SUNW_TLSSORT_CF,
-		MSG_DT_SUNW_TLSSORTSZ_CF,	0,
-		MSG_DT_SUNW_STRPAD_CF,		0,
-		MSG_DT_SUNW_LDMACH_CF
+		MSG_DT_SUNW_TLSSORTSZ_CF,	MSG_DT_SUNW_CAPINFO_CF,
+		MSG_DT_SUNW_STRPAD_CF,		MSG_DT_SUNW_CAPCHAIN_CF,
+		MSG_DT_SUNW_LDMACH_CF,		0,
+		MSG_DT_SUNW_CAPCHAINENT_CF,	0,
+		MSG_DT_SUNW_CAPCHAINSZ_CF
 	};
 	static const Msg	tags_sunw_auxiliary_cfnp[] = {
 		MSG_DT_SUNW_AUXILIARY_CFNP,	MSG_DT_SUNW_RTLDINF_CFNP,
@@ -558,9 +560,11 @@
 		MSG_DT_SUNW_SYMTAB_CFNP,	MSG_DT_SUNW_SYMSZ_CFNP,
 		MSG_DT_SUNW_SORTENT_CFNP,	MSG_DT_SUNW_SYMSORT_CFNP,
 		MSG_DT_SUNW_SYMSORTSZ_CFNP,	MSG_DT_SUNW_TLSSORT_CFNP,
-		MSG_DT_SUNW_TLSSORTSZ_CFNP,	0,
-		MSG_DT_SUNW_STRPAD_CFNP,	0,
-		MSG_DT_SUNW_LDMACH_CFNP
+		MSG_DT_SUNW_TLSSORTSZ_CFNP,	MSG_DT_SUNW_CAPINFO_CFNP,
+		MSG_DT_SUNW_STRPAD_CFNP,	MSG_DT_SUNW_CAPCHAIN_CFNP,
+		MSG_DT_SUNW_LDMACH_CFNP,	0,
+		MSG_DT_SUNW_CAPCHAINENT_CFNP,	0,
+		MSG_DT_SUNW_CAPCHAINSZ_CFNP
 	};
 	static const Msg	tags_sunw_auxiliary_nf[] = {
 		MSG_DT_SUNW_AUXILIARY_NF,	MSG_DT_SUNW_RTLDINF_NF,
@@ -568,9 +572,11 @@
 		MSG_DT_SUNW_SYMTAB_NF,		MSG_DT_SUNW_SYMSZ_NF,
 		MSG_DT_SUNW_SORTENT_NF,		MSG_DT_SUNW_SYMSORT_NF,
 		MSG_DT_SUNW_SYMSORTSZ_NF,	MSG_DT_SUNW_TLSSORT_NF,
-		MSG_DT_SUNW_TLSSORTSZ_NF,	0,
-		MSG_DT_SUNW_STRPAD_NF,		0,
-		MSG_DT_SUNW_LDMACH_NF
+		MSG_DT_SUNW_TLSSORTSZ_NF,	MSG_DT_SUNW_CAPINFO_NF,
+		MSG_DT_SUNW_STRPAD_NF,		MSG_DT_SUNW_CAPCHAIN_NF,
+		MSG_DT_SUNW_LDMACH_NF,		0,
+		MSG_DT_SUNW_CAPCHAINENT_NF,	0,
+		MSG_DT_SUNW_CAPCHAINSZ_NF
 	};
 	static const conv_ds_msg_t ds_sunw_auxiliary_cf = {
 	    CONV_DS_MSG_INIT(DT_SUNW_AUXILIARY, tags_sunw_auxiliary_cf) };
--- a/usr/src/cmd/sgs/libconv/common/dynamic.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -161,12 +161,25 @@
 @ MSG_DT_SUNW_TLSSORTSZ_CF	"DT_SUNW_TLSSORTSZ"		# 0x60000017
 @ MSG_DT_SUNW_TLSSORTSZ_CFNP		"SUNW_TLSSORTSZ"
 @ MSG_DT_SUNW_TLSSORTSZ_NF		"sunw_tlssortsz"
+@ MSG_DT_SUNW_CAPINFO_CF	"DT_SUNW_CAPINFO"		# 0x60000018
+@ MSG_DT_SUNW_CAPINFO_CFNP		"SUNW_CAPINFO"
+@ MSG_DT_SUNW_CAPINFO_NF		"sunw_capinfo"
 @ MSG_DT_SUNW_STRPAD_CF		"DT_SUNW_STRPAD"		# 0x60000019
 @ MSG_DT_SUNW_STRPAD_CFNP		"SUNW_STRPAD"
 @ MSG_DT_SUNW_STRPAD_NF			"sunw_strpad"
+@ MSG_DT_SUNW_CAPCHAIN_CF	"DT_SUNW_CAPCHAIN"		# 0x6000001a
+@ MSG_DT_SUNW_CAPCHAIN_CFNP		"SUNW_CAPCHAIN"
+@ MSG_DT_SUNW_CAPCHAIN_NF		"sunw_capchain"
 @ MSG_DT_SUNW_LDMACH_CF		"DT_SUNW_LDMACH"		# 0x6000001b
 @ MSG_DT_SUNW_LDMACH_CFNP		"SUNW_LDMACH"
 @ MSG_DT_SUNW_LDMACH_NF			"sunw_ldmach"
+@ MSG_DT_SUNW_CAPCHAINENT_CF	"DT_SUNW_CAPCHAINENT"		# 0x6000001d
+@ MSG_DT_SUNW_CAPCHAINENT_CFNP		"SUNW_CAPCHAINENT"
+@ MSG_DT_SUNW_CAPCHAINENT_NF		"sunw_capchainent"
+@ MSG_DT_SUNW_CAPCHAINSZ_CF	"DT_SUNW_CAPCHAINSZ"		# 0x6000001d
+@ MSG_DT_SUNW_CAPCHAINSZ_CFNP		"SUNW_CAPCHAINSZ"
+@ MSG_DT_SUNW_CAPCHAINSZ_NF		"sunw_capchainsz"
+
 @ MSG_DT_GNU_PRELINKED_CF	"DT_GNU_PRELINKED"		# 0x6ffffdf5
 @ MSG_DT_GNU_PRELINKED_CFNP		"GNU_PRELINKED"
 @ MSG_DT_GNU_PRELINKED_NF		"gnu_prelinked"
--- a/usr/src/cmd/sgs/libconv/common/elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -954,6 +954,9 @@
 	case SGS_REJ_STR:
 	case SGS_REJ_HWCAP_1:
 	case SGS_REJ_SFCAP_1:
+	case SGS_REJ_HWCAP_2:
+	case SGS_REJ_MACHCAP:
+	case SGS_REJ_PLATCAP:
 		if (rej->rej_str)
 			return ((const char *)rej->rej_str);
 		else
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/llib-lconv	Mon Mar 01 10:20:48 2010 -0800
@@ -187,6 +187,8 @@
 conv_iter_ret_t	conv_iter_cap_tags(Conv_fmt_flags_t, conv_iter_cb_t, void *);
 conv_iter_ret_t	conv_iter_cap_val_hw1(Half, Conv_fmt_flags_t,
 		    conv_iter_cb_t, void *);
+conv_iter_ret_t	conv_iter_cap_val_hw2(Half, Conv_fmt_flags_t,
+		    conv_iter_cb_t, void *);
 conv_iter_ret_t	conv_iter_cap_val_sf1(Conv_fmt_flags_t, conv_iter_cb_t, void *);
 
 conv_iter_ret_t	conv_iter_dyn_feature1(Conv_fmt_flags_t,
@@ -256,13 +258,17 @@
 const char	*conv64_cap_tag(Elf64_Xword, Conv_fmt_flags_t,
 		    Conv_inv_buf_t *);
 const char	*conv32_cap_val(Elf32_Word, Elf32_Word, Half,
-		    Conv_cap_val_buf_t *);
+		    Conv_fmt_flags_t, Conv_cap_val_buf_t *);
 const char	*conv64_cap_val(Elf64_Xword, Elf64_Xword, Half,
-		    Conv_cap_val_buf_t *);
+		    Conv_fmt_flags_t, Conv_cap_val_buf_t *);
 const char	*conv32_cap_val_hw1(Elf32_Word, Half, Conv_fmt_flags_t,
 		    Conv_cap_val_hw1_buf_t *);
+const char	*conv32_cap_val_hw2(Elf32_Word, Half, Conv_fmt_flags_t,
+		    Conv_cap_val_hw2_buf_t *);
 const char	*conv64_cap_val_hw1(Elf64_Xword, Half, Conv_fmt_flags_t,
 		    Conv_cap_val_hw1_buf_t *);
+const char	*conv64_cap_val_hw2(Elf64_Xword, Half, Conv_fmt_flags_t,
+		    Conv_cap_val_hw2_buf_t *);
 const char	*conv32_cap_val_sf1(Elf32_Word, Half, Conv_fmt_flags_t,
 		    Conv_cap_val_sf1_buf_t *);
 const char	*conv64_cap_val_sf1(Elf64_Xword, Half, Conv_fmt_flags_t,
--- a/usr/src/cmd/sgs/libconv/common/sections.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/sections.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -106,6 +106,7 @@
 
 
 	static const Msg usecs_def[SHT_HISUNW - SHT_LOSUNW + 1] = {
+		MSG_SHT_SUNW_CAPCHAIN,		MSG_SHT_SUNW_CAPINFO,
 		MSG_SHT_SUNW_SYMSORT,		MSG_SHT_SUNW_TLSSORT,
 		MSG_SHT_SUNW_LDYNSYM,		MSG_SHT_SUNW_DOF,
 		MSG_SHT_SUNW_CAP,		MSG_SHT_SUNW_SIGNATURE,
@@ -116,6 +117,7 @@
 		MSG_SHT_SUNW_VERSYM
 	};
 	static const Msg usecs_dmp[SHT_HISUNW - SHT_LOSUNW + 1] = {
+		MSG_SHT_SUNW_CAPCHAIN_DMP,	MSG_SHT_SUNW_CAPINFO_DMP,
 		MSG_SHT_SUNW_SYMSORT_DMP,	MSG_SHT_SUNW_TLSSORT_DMP,
 		MSG_SHT_SUNW_LDYNSYM_DMP,	MSG_SHT_SUNW_DOF_DMP,
 		MSG_SHT_SUNW_CAP_DMP,		MSG_SHT_SUNW_SIGNATURE_DMP,
@@ -126,6 +128,7 @@
 		MSG_SHT_SUNW_VERSYM_DMP
 	};
 	static const Msg usecs_cf[SHT_HISUNW - SHT_LOSUNW + 1] = {
+		MSG_SHT_SUNW_CAPCHAIN_CF,	MSG_SHT_SUNW_CAPINFO_CF,
 		MSG_SHT_SUNW_SYMSORT_CF,	MSG_SHT_SUNW_TLSSORT_CF,
 		MSG_SHT_SUNW_LDYNSYM_CF,	MSG_SHT_SUNW_DOF_CF,
 		MSG_SHT_SUNW_CAP_CF,		MSG_SHT_SUNW_SIGNATURE_CF,
@@ -136,6 +139,7 @@
 		MSG_SHT_SUNW_VERSYM_CF
 	};
 	static const Msg usecs_nf[SHT_HISUNW - SHT_LOSUNW + 1] = {
+		MSG_SHT_SUNW_CAPCHAIN_NF,	MSG_SHT_SUNW_CAPINFO_NF,
 		MSG_SHT_SUNW_SYMSORT_NF,	MSG_SHT_SUNW_TLSSORT_NF,
 		MSG_SHT_SUNW_LDYNSYM_NF,	MSG_SHT_SUNW_DOF_NF,
 		MSG_SHT_SUNW_CAP_NF,		MSG_SHT_SUNW_SIGNATURE_NF,
@@ -145,17 +149,17 @@
 		MSG_SHT_SUNW_VERDEF_NF,		MSG_SHT_SUNW_VERNEED_NF,
 		MSG_SHT_SUNW_VERSYM_NF
 	};
-#if	(SHT_LOSUNW != SHT_SUNW_symsort)
+#if	(SHT_LOSUNW != SHT_SUNW_capchain)
 #error	"SHT_LOSUNW has moved"
 #endif
 	static const conv_ds_msg_t ds_usecs_def = {
-	    CONV_DS_MSG_INIT(SHT_SUNW_symsort, usecs_def) };
+	    CONV_DS_MSG_INIT(SHT_SUNW_capchain, usecs_def) };
 	static const conv_ds_msg_t ds_usecs_dmp = {
-	    CONV_DS_MSG_INIT(SHT_SUNW_symsort, usecs_dmp) };
+	    CONV_DS_MSG_INIT(SHT_SUNW_capchain, usecs_dmp) };
 	static const conv_ds_msg_t ds_usecs_cf = {
-	    CONV_DS_MSG_INIT(SHT_SUNW_symsort, usecs_cf) };
+	    CONV_DS_MSG_INIT(SHT_SUNW_capchain, usecs_cf) };
 	static const conv_ds_msg_t ds_usecs_nf = {
-	    CONV_DS_MSG_INIT(SHT_SUNW_symsort, usecs_nf) };
+	    CONV_DS_MSG_INIT(SHT_SUNW_capchain, usecs_nf) };
 
 
 	/* The Linux osabi range has two separate sequences */
--- a/usr/src/cmd/sgs/libconv/common/sections.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/sections.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -100,6 +100,14 @@
 @ MSG_SHT_SYMTAB_SHNDX_CF		"SHT_SYMTAB_SHNDX"
 @ MSG_SHT_SYMTAB_SHNDX_NF		"symtab_shndx"
 
+@ MSG_SHT_SUNW_CAPCHAIN		"[ SHT_SUNW_capchain ]"		# 0x6fffffef
+@ MSG_SHT_SUNW_CAPCHAIN_DMP		"CAPCHAIN "
+@ MSG_SHT_SUNW_CAPCHAIN_CF		"SHT_SUNW_capchain"
+@ MSG_SHT_SUNW_CAPCHAIN_NF		"sunw_capchain"
+@ MSG_SHT_SUNW_CAPINFO		"[ SHT_SUNW_capinfo ]"		# 0x6ffffff0
+@ MSG_SHT_SUNW_CAPINFO_DMP		"CAPINFO "
+@ MSG_SHT_SUNW_CAPINFO_CF		"SHT_SUNW_capinfo"
+@ MSG_SHT_SUNW_CAPINFO_NF		"sunw_capinfo"
 @ MSG_SHT_SUNW_SYMSORT		"[ SHT_SUNW_symsort ]"		# 0x6ffffff1
 @ MSG_SHT_SUNW_SYMSORT_DMP		"SSRT"
 @ MSG_SHT_SUNW_SYMSORT_CF		"SHT_SUNW_symsort"
--- a/usr/src/cmd/sgs/libconv/common/syminfo.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/syminfo.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -73,6 +73,7 @@
 		{ SYMINFO_FLG_NOEXTDIRECT, MSG_SYMINFO_FLG_NOEXTDIRECT_CF },
 		{ SYMINFO_FLG_AUXILIARY, MSG_SYMINFO_FLG_AUXILIARY_CF },
 		{ SYMINFO_FLG_INTERPOSE, MSG_SYMINFO_FLG_INTERPOSE_CF },
+		{ SYMINFO_FLG_CAP,	MSG_SYMINFO_FLG_CAP_CF },
 		{ 0 }
 	};
 	static const Val_desc vda_cfnp[] = {
@@ -84,6 +85,7 @@
 		{ SYMINFO_FLG_NOEXTDIRECT, MSG_SYMINFO_FLG_NOEXTDIRECT_CFNP },
 		{ SYMINFO_FLG_AUXILIARY, MSG_SYMINFO_FLG_AUXILIARY_CFNP },
 		{ SYMINFO_FLG_INTERPOSE, MSG_SYMINFO_FLG_INTERPOSE_CFNP },
+		{ SYMINFO_FLG_CAP,	MSG_SYMINFO_FLG_CAP_CFNP },
 		{ 0 }
 	};
 	static const Val_desc vda_nf[] = {
@@ -95,6 +97,7 @@
 		{ SYMINFO_FLG_NOEXTDIRECT, MSG_SYMINFO_FLG_NOEXTDIRECT_NF },
 		{ SYMINFO_FLG_AUXILIARY, MSG_SYMINFO_FLG_AUXILIARY_NF },
 		{ SYMINFO_FLG_INTERPOSE, MSG_SYMINFO_FLG_INTERPOSE_NF },
+		{ SYMINFO_FLG_CAP,	MSG_SYMINFO_FLG_CAP_NF },
 		{ 0 }
 	};
 
--- a/usr/src/cmd/sgs/libconv/common/syminfo.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/syminfo.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -19,34 +19,37 @@
 # CDDL HEADER END
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
-@ MSG_SYMINFO_FLG_DIRECT_CF		"SYMINFO_FLG_DIRECT"		# 0x01
+@ MSG_SYMINFO_FLG_DIRECT_CF		"SYMINFO_FLG_DIRECT"		# 0x001
 @ MSG_SYMINFO_FLG_DIRECT_CFNP			"DIRECT"
 @ MSG_SYMINFO_FLG_DIRECT_NF			"direct"
-@ MSG_SYMINFO_FLG_FILTER_CF		"SYMINFO_FLG_FILTER"		# 0x02
+@ MSG_SYMINFO_FLG_FILTER_CF		"SYMINFO_FLG_FILTER"		# 0x002
 @ MSG_SYMINFO_FLG_FILTER_CFNP			"FILTER"
 @ MSG_SYMINFO_FLG_FILTER_NF			"filter"
-@ MSG_SYMINFO_FLG_COPY_CF		"SYMINFO_FLG_COPY"		# 0x04
+@ MSG_SYMINFO_FLG_COPY_CF		"SYMINFO_FLG_COPY"		# 0x004
 @ MSG_SYMINFO_FLG_COPY_CFNP			"COPY"
 @ MSG_SYMINFO_FLG_COPY_NF			"copy"
-@ MSG_SYMINFO_FLG_LAZYLOAD_CF		"SYMINFO_FLG_LAZYLOAD"		# 0x08
+@ MSG_SYMINFO_FLG_LAZYLOAD_CF		"SYMINFO_FLG_LAZYLOAD"		# 0x008
 @ MSG_SYMINFO_FLG_LAZYLOAD_CFNP			"LAZYLOAD"
 @ MSG_SYMINFO_FLG_LAZYLOAD_NF			"lazyload"
-@ MSG_SYMINFO_FLG_DIRECTBIND_CF		"SYMINFO_FLG_DIRECTBIND"	# 0x10
+@ MSG_SYMINFO_FLG_DIRECTBIND_CF		"SYMINFO_FLG_DIRECTBIND"	# 0x010
 @ MSG_SYMINFO_FLG_DIRECTBIND_CFNP		"DIRECTBIND"
 @ MSG_SYMINFO_FLG_DIRECTBIND_NF			"directbind"
-@ MSG_SYMINFO_FLG_NOEXTDIRECT_CF	"SYMINFO_FLG_NOEXTDIRECT"	# 0x20
+@ MSG_SYMINFO_FLG_NOEXTDIRECT_CF	"SYMINFO_FLG_NOEXTDIRECT"	# 0x020
 @ MSG_SYMINFO_FLG_NOEXTDIRECT_CFNP		"NOEXTDIRECT"
 @ MSG_SYMINFO_FLG_NOEXTDIRECT_NF		"noextdirect"
-@ MSG_SYMINFO_FLG_AUXILIARY_CF		"SYMINFO_FLG_AUXILIARY"		# 0x40
+@ MSG_SYMINFO_FLG_AUXILIARY_CF		"SYMINFO_FLG_AUXILIARY"		# 0x040
 @ MSG_SYMINFO_FLG_AUXILIARY_CFNP		"AUXILIARY"
 @ MSG_SYMINFO_FLG_AUXILIARY_NF			"auxiliary"
-@ MSG_SYMINFO_FLG_INTERPOSE_CF		"SYMINFO_FLG_INTERPOSE"		# 0x80
+@ MSG_SYMINFO_FLG_INTERPOSE_CF		"SYMINFO_FLG_INTERPOSE"		# 0x080
 @ MSG_SYMINFO_FLG_INTERPOSE_CFNP		"INTERPOSE"
 @ MSG_SYMINFO_FLG_INTERPOSE_NF			"interpose"
+@ MSG_SYMINFO_FLG_CAP_CF		"SYMINFO_FLG_CAP"		# 0x100
+@ MSG_SYMINFO_FLG_CAP_CFNP			"CAP"
+@ MSG_SYMINFO_FLG_CAP_NF			"cap"
 
 @ MSG_SYMINFO_BT_EXTERN_CF	"SYMINFO_BT_EXTERN"		# 0xfffc
 @ MSG_SYMINFO_BT_EXTERN_CFNP		"EXTERN"
--- a/usr/src/cmd/sgs/libcrle/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libcrle/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,8 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -44,7 +45,7 @@
 LINTFLAGS64 +=	-u
 
 CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc -I$(SRC)/common/sgsrtcid
-DYNFLAGS +=	$(VERSREF) $(CONVLIBDIR) -lconv $(USE_PROTO)
+DYNFLAGS +=	$(VERSREF) $(CONVLIBDIR) -lconv $(CC_USE_PROTO)
 
 
 BLTDEFS=	msg.h
--- a/usr/src/cmd/sgs/libelf/common/xlate.m4	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libelf/common/xlate.m4	Mon Mar 01 10:20:48 2010 -0800
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <memory.h>
 #include <libelf.h>
 #include <link.h>
@@ -35,7 +32,6 @@
 #include <msg.h>
 #include <sgs.h>
 
-
 /*
  * fmsize:  Array used to determine what size the the structures
  *	    are (for memory image & file image).
@@ -722,6 +718,10 @@
 		return (ELF_T_BYTE);
 	case SHT_SUNW_cap:
 		return (ELF_T_CAP);
+	case SHT_SUNW_capchain:
+		return (ELF_T_WORD);
+	case SHT_SUNW_capinfo:
+		return (ELF_T_WORD);
 	case SHT_SUNW_SIGNATURE:
 		return (ELF_T_BYTE);
 	case SHT_SUNW_ANNOTATE:
--- a/usr/src/cmd/sgs/libelf/common/xlate64.m4	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libelf/common/xlate64.m4	Mon Mar 01 10:20:48 2010 -0800
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <memory.h>
 #include <libelf.h>
 #include <link.h>
@@ -35,7 +32,6 @@
 #include <msg.h>
 #include <sgs.h>
 
-
 /*
  * fmsize:  Array used to determine what size the the structures
  *	    are (for memory image & file image).
@@ -779,6 +775,10 @@
 		return (ELF_T_BYTE);
 	case SHT_SUNW_cap:
 		return (ELF_T_CAP);
+	case SHT_SUNW_capchain:
+		return (ELF_T_WORD);
+	case SHT_SUNW_capinfo:
+		return (ELF_T_XWORD);
 	case SHT_SUNW_SIGNATURE:
 		return (ELF_T_BYTE);
 	case SHT_SUNW_ANNOTATE:
--- a/usr/src/cmd/sgs/libld/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,6 +18,7 @@
 #
 # CDDL HEADER END
 #
+
 #
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -103,7 +104,7 @@
 LINTFLAGS +=	-u -D_REENTRANT
 LINTFLAGS64 +=	-u -D_REENTRANT
 
-DYNFLAGS +=	$(VERSREF) $(USE_PROTO) '-R$$ORIGIN'
+DYNFLAGS +=	$(VERSREF) $(CC_USE_PROTO) '-R$$ORIGIN'
 
 native:=	DYNFLAGS	+= $(CONVLIBDIR)
 
--- a/usr/src/cmd/sgs/libld/common/_libld.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/_libld.h	Mon Mar 01 10:20:48 2010 -0800
@@ -113,6 +113,8 @@
 	Word		id_array;
 	Word		id_bss;
 	Word		id_cap;
+	Word		id_capinfo;
+	Word		id_capchain;
 	Word		id_data;
 	Word		id_dynamic;
 	Word		id_dynsort;
@@ -168,11 +170,11 @@
  * target architecture, it may be desirable to instead fill with executable
  * NOP instructions. There are two reasons to do this:
  *
- * -	So that .init/.fini sections will not contain unexecutable gaps
+ *  -	So that .init/.fini sections will not contain unexecutable gaps
  *	that cause the executing program to trap and die.
  *
- * -	To eliminate confusing garbage instructions between sections containing
- *	executable code when viewed with a dissassembler.
+ *  -	To eliminate confusing garbage instructions between sections containing
+ *	executable code when viewed with a disassembler.
  *
  * The ff_execfill function is allowed to be NULL if the underlying target
  * does not require a special fill for executable sections.
@@ -330,11 +332,88 @@
 } Sfltr_desc;
 
 /*
+ * Capabilities descriptor, and capabilities group descriptor, used to track
+ * the symbol capabilities of any input files and the output file.
+ *
+ * A relocatable object input file may contain one or more symbol capabilities
+ * groups.  The Cap_desc structures keep track of all unique groups that are
+ * collected for the output file.  Relocatable objects that contain an object
+ * capabilities group, and the -z symbolcap option is in effect, have their
+ * object group translated to a symbol capabilities group.
+ *
+ * Individual capabilities groups are maintained with the Cap_group descriptor.
+ * A group can consist of one or more capabilities definitions.  One or more
+ * symbols can be associated with each group.
+ *
+ * For the output file, capabilities families are used to track the symbols of
+ * a given family, each symbol being associated with a different group.  This
+ * collection of data is used to create the final Capinfo structure, and for
+ * dynamic objects, the Capchain structure.
+ *
+ * For example, an object may contain two capabilities groups:
+ *
+ *	CA_SUNW_MACH - sun4u		CA_SUNW_MACH - sun4v
+ *
+ * Two symbols can be associated with each group:
+ *
+ *	foo%sun4u			foo%sun4v
+ *	bar%sun4u			bar%sun4v
+ *
+ * Two families are maintained, and include the generic, or lead, instance of
+ * the capabilities members:
+ *
+ *	foo,  foo%sun4u,  foo%sun4v
+ *	bar,  bar%sun4u,  bar%sun4v
+ */
+struct cap_desc {
+	APlist		*ca_groups;	/* capabilities groups (Cap_group) */
+	APlist		*ca_syms;	/* copies of symbols that are being */
+					/*	translated from object to */
+};					/*	symbol capabilities */
+
+typedef struct {
+	Objcapset	cg_set;		/* unpacked SHT_SUNW_cap elements */
+	APlist		*cg_secs;	/* sections, and hence files, that */
+					/*	use this descriptor */
+	Word		cg_num;		/* number of comparable elements in */
+					/*	the group */
+	Word		cg_ndx;		/* final capability group index */
+} Cap_group;
+
+/*
+ * A Capabilities family node, extends a symbol node, and provides for tracking
+ * capabilities families.  A family is defined by its lead symbol (for example,
+ * a generic, non-capabilities aware foo()), and one or more capabilities
+ * members (for example, capabilities instances foo%sun4u(), foo%sun4v(), etc.).
+ *
+ * Each member associates a symbol with its group using a Cap_sym structure.
+ */
+typedef struct {
+	Sym_avlnode	cn_symavlnode;
+	APlist		*cn_members;
+	APlist		*cn_aliases;
+} Cap_avlnode;
+
+typedef struct {
+	Sym_desc	*cs_sdp;	/* capabilities symbol descriptor */
+	Cap_group	*cs_group;	/* associated capabilities group */
+} Cap_sym;
+
+/*
  * Define Alist initialization sizes.
  */
 #define	AL_CNT_IFL_GROUPS	20	/* ifl_groups */
 #define	AL_CNT_IFL_RELSECS	6	/* ifl_relsect */
 
+#define	AL_CNT_CAP_DESCS	4	/* symbol capabilities descriptors */
+#define	AL_CNT_CAP_SYMS		20	/* capabilities symbols */
+#define	AL_CNT_CAP_SECS		10	/* capabilities sections */
+#define	AL_CNT_CAP_NAMES	10	/* Objcapset platform and machine */
+					/*	names */
+#define	AL_CNT_CAP_MEMS		10	/* capability family members */
+#define	AL_CNT_CAP_PAIRS	10	/* capability symbol pairs */
+#define	AL_CNT_CAP_ALIASES	2	/* capability lead symbol aliases */
+
 #define	AL_CNT_OFL_DTSFLTRS	4	/* ofl_dtsfltrs */
 #define	AL_CNT_OFL_SYMFLTRS	20	/* ofl_symfltrs */
 #define	AL_CNT_OFL_MAPSECS	10	/* ofl_map{text|data} */
@@ -582,6 +661,7 @@
  */
 extern char		*add_string(char *, char *);
 extern const char	*demangle(const char *);
+extern int		cap_names_match(Alist *, Alist *);
 
 extern void		lds_atexit(Ofl_desc *, int);
 
@@ -606,6 +686,8 @@
 #define	ld_assign_got_TLS	ld64_assign_got_TLS
 #define	ld_bswap_Word		ld64_bswap_Word
 #define	ld_bswap_Xword		ld64_bswap_Xword
+#define	ld_cap_add_family	ld64_cap_add_family
+#define	ld_cap_move_symtoobj	ld64_cap_move_symtoobj
 #define	ld_disp_errmsg		ld64_disp_errmsg
 #define	ld_ent_check		ld64_ent_check
 #define	ld_ent_lookup		ld64_ent_lookup
@@ -697,6 +779,8 @@
 #define	ld_assign_got_TLS	ld32_assign_got_TLS
 #define	ld_bswap_Word		ld32_bswap_Word
 #define	ld_bswap_Xword		ld32_bswap_Xword
+#define	ld_cap_add_family	ld32_cap_add_family
+#define	ld_cap_move_symtoobj	ld32_cap_move_symtoobj
 #define	ld_disp_errmsg		ld32_disp_errmsg
 #define	ld_ent_check		ld32_ent_check
 #define	ld_ent_lookup		ld32_ent_lookup
@@ -797,6 +881,10 @@
 extern Word		ld_bswap_Word(Word);
 extern Xword		ld_bswap_Xword(Xword);
 
+extern uintptr_t	ld_cap_add_family(Ofl_desc *, Sym_desc *, Sym_desc *,
+			    Cap_group *, APlist **);
+extern void		ld_cap_move_symtoobj(Ofl_desc *);
+
 extern void		ld_disp_errmsg(const char *, Rel_desc *, Ofl_desc *);
 
 extern void		ld_ent_check(Ofl_desc *);
--- a/usr/src/cmd/sgs/libld/common/_map.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/_map.h	Mon Mar 01 10:20:48 2010 -0800
@@ -330,7 +330,7 @@
  * Support code shared between the different mapfile parsing code, used to
  * provide a common implementation manipulating link-editor state.
  */
-extern Boolean		ld_map_cap_sanitize(Mapfile *, Word, CapMask *);
+extern Boolean		ld_map_cap_sanitize(Mapfile *, Word, Capmask *);
 extern void		ld_map_cap_set_ovflag(Mapfile *, Word);
 extern void		*ld_map_kwfind(const char *, void *, size_t, size_t);
 extern char		*ld_map_kwnames(void *, size_t, size_t, char *, size_t);
--- a/usr/src/cmd/sgs/libld/common/args.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/args.c	Mon Mar 01 10:20:48 2010 -0800
@@ -208,6 +208,7 @@
 	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZRS));
 	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZRSN));
 	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZRSGRP));
+	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZSCAP));
 	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZTARG));
 	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZT));
 	(void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZTO));
@@ -305,6 +306,18 @@
 		ofl->ofl_flags |= FLG_OF_RELOBJ;
 	} else {
 		/*
+		 * Translating object capabilities to symbol capabilities is
+		 * only meaningful when creating a relocatable object.
+		 */
+		if (ofl->ofl_flags & FLG_OF_OTOSCAP) {
+			eprintf(ofl->ofl_lml, ERR_FATAL,
+			    MSG_INTL(MSG_MARG_ONLY),
+			    MSG_ORIG(MSG_ARG_ZSYMBOLCAP),
+			    MSG_INTL(MSG_MARG_REL));
+			ofl->ofl_flags |= FLG_OF_FATAL;
+		}
+
+		/*
 		 * If the user hasn't explicitly requested that relocations
 		 * not be combined, combine them by default.
 		 */
@@ -1249,6 +1262,9 @@
 			} else if (strcmp(optarg,
 			    MSG_ORIG(MSG_ARG_NOSIGHANDLER)) == 0) {
 				ofl->ofl_flags1 |= FLG_OF1_NOSGHND;
+			} else if (strcmp(optarg,
+			    MSG_ORIG(MSG_ARG_SYMBOLCAP)) == 0) {
+				ofl->ofl_flags |= FLG_OF_OTOSCAP;
 
 			/*
 			 * Check archive group usage
--- a/usr/src/cmd/sgs/libld/common/entry.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/entry.c	Mon Mar 01 10:20:48 2010 -0800
@@ -193,38 +193,61 @@
  * As with the segment descriptors, the EC_DESC_INIT macro is used
  * to reduce boilerplate clutter.
  */
-#define	EC_DESC_INIT(ec_type, ec_attrmask, ec_attrbits, _seg_field, ec_flags) \
-	{ NULL, NULL, NULL, ec_type, ec_attrmask, ec_attrbits, \
+#define	EC_DESC_INIT(ec_is_name, ec_type, ec_attrmask, ec_attrbits, \
+    _seg_field, ec_flags) \
+	{ NULL, NULL, ec_is_name, ec_type, ec_attrmask, ec_attrbits, \
 	    &sg_desc.psg_ ## _seg_field, 0, FLG_EC_BUILTIN | ec_flags }
 
 static const Ent_desc	ent_desc[] = {
-	EC_DESC_INIT(SHT_NOTE, 0, 0, note, 0),
-
+	EC_DESC_INIT(NULL, SHT_NOTE, 0, 0, note, 0),
 
 #if	defined(_ELF64)		/* (amd64-only) */
-	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
 	    SHF_ALLOC + SHF_AMD64_LARGE, lrodata, 0),
 #endif
-	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC, text, 0),
+	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC, text, 0),
 
-	EC_DESC_INIT(SHT_NOBITS, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
-	    bss, 0),
+	/*
+	 * Explicitly assign the .tdata section to bss.  The design of TLS
+	 * provides for initialized data being assigned to a .tdata section,
+	 * and uninitialized data being assigned to a .tbss section.  These
+	 * sections should be laid out adjacent to each other, with little or
+	 * no gap between them.  A PT_TLS program header is created that
+	 * defines the address range of the two sections.  This header is
+	 * passed to libc to instantiate the appropriate thread allocation.
+	 *
+	 * By default a separate bss segment is disabled, however users can
+	 * trigger the creation of a bss segment with a mapfile.  By default,
+	 * all bss sections are assigned to the data segment, and the section
+	 * identifiers of .tdata and .tbss ensure that these two sections are
+	 * adjacent to each other.
+	 *
+	 * However, if a bss segment is enabled, the adjacency of the .tdata
+	 * and .tbss sections can only be retained by having an explicit .tdata
+	 * entrance criteria.
+	 */
+	EC_DESC_INIT(MSG_ORIG(MSG_SCN_TDATA), 0, SHF_ALLOC + SHF_WRITE,
+	    SHF_ALLOC + SHF_WRITE, bss, 0),
+
+	EC_DESC_INIT(NULL, SHT_NOBITS, SHF_ALLOC + SHF_WRITE,
+	    SHF_ALLOC + SHF_WRITE, bss, 0),
 
 #if	defined(_ELF64)		/* (amd64-only) */
-	EC_DESC_INIT(SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+	EC_DESC_INIT(NULL, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
 	    SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, data, 0),
 
-	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
 	    SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, ldata, 0),
 #endif
-	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE, data, 0),
+	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
+	    data, 0),
 
 	/*
 	 * Final catchall rule sends remaining sections to "extra"
 	 * NULL segment, which has been tagged as FLG_SG_NODISABLE,
 	 * and which will therefore always accept them.
 	 */
-	EC_DESC_INIT(0, 0, 0, extra, FLG_EC_CATCHALL)
+	EC_DESC_INIT(NULL, 0, 0, 0, extra, FLG_EC_CATCHALL)
 };
 #undef EC_DESC_INIT
 
@@ -375,7 +398,7 @@
 	/*
 	 * The data segment and stack permissions can differ:
 	 *
-	 *	- Architecural/ABI per-platform differences
+	 *	- Architectural/ABI per-platform differences
 	 *	- Whether the object is built statically or dynamically
 	 *
 	 * Those segments so affected have their program header flags
--- a/usr/src/cmd/sgs/libld/common/files.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/files.c	Mon Mar 01 10:20:48 2010 -0800
@@ -245,17 +245,17 @@
 	Xword	badval;
 
 	/*
-	 * If a mapfile has established definitions to override any input
-	 * capabilities, ignore any new input capabilities.
+	 * If a mapfile has established definitions to override any object
+	 * capabilities, ignore any new object capabilities.
 	 */
 	if (ofl->ofl_flags1 & FLG_OF1_OVSFCAP1) {
-		DBG_CALL(Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+		DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
 		    CA_SUNW_SF_1, val, ld_targ.t_m.m_mach));
 		return;
 	}
 
 #if	!defined(_ELF64)
-	if (ifl->ifl_ehdr->e_type == ET_REL) {
+	if (ifl && (ifl->ifl_ehdr->e_type == ET_REL)) {
 		/*
 		 * The SF1_SUNW_ADDR32 is only meaningful when building a 64-bit
 		 * object.  Warn the user, and remove the setting, if we're
@@ -309,7 +309,7 @@
 		 * The runtime linker will refuse to use this dependency.
 		 */
 		if ((val & SF1_SUNW_ADDR32) && (ofl->ofl_flags & FLG_OF_EXEC) &&
-		    ((ofl->ofl_ocapset.c_sf_1.cm_value &
+		    ((ofl->ofl_ocapset.oc_sf_1.cm_val &
 		    SF1_SUNW_ADDR32) == 0)) {
 			eprintf(ofl->ofl_lml, ERR_WARNING,
 			    MSG_INTL(MSG_FIL_EXADDR32SF1), ifl->ifl_name,
@@ -320,9 +320,9 @@
 	}
 
 	if (DBG_ENABLED) {
-		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_SF_1,
-		    &ofl->ofl_ocapset.c_sf_1, ld_targ.t_m.m_mach);
-		Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_SF_1,
+		Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_SF_1,
+		    ofl->ofl_ocapset.oc_sf_1.cm_val, ld_targ.t_m.m_mach);
+		Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_SF_1,
 		    val, ld_targ.t_m.m_mach);
 	}
 
@@ -330,13 +330,13 @@
 	 * Determine the resolution of the present frame pointer and the
 	 * new input relocatable objects frame pointer.
 	 */
-	if ((ofl->ofl_ocapset.c_sf_1.cm_value & FP_FLAGS) == FP_FLAGS) {
+	if ((ofl->ofl_ocapset.oc_sf_1.cm_val & FP_FLAGS) == FP_FLAGS) {
 		/*
 		 * If the new relocatable object isn't using a frame pointer,
 		 * reduce the present state to unused.
 		 */
 		if ((val & FP_FLAGS) != FP_FLAGS)
-			ofl->ofl_ocapset.c_sf_1.cm_value &= ~SF1_SUNW_FPUSED;
+			ofl->ofl_ocapset.oc_sf_1.cm_val &= ~SF1_SUNW_FPUSED;
 
 		/*
 		 * Having processed the frame pointer bits, remove them from
@@ -344,22 +344,22 @@
 		 */
 		val &= ~FP_FLAGS;
 
-	} else if ((ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_FPKNWN) == 0) {
+	} else if ((ofl->ofl_ocapset.oc_sf_1.cm_val & SF1_SUNW_FPKNWN) == 0) {
 		/*
 		 * If the present frame pointer state is unknown, mask it out
 		 * and allow the values from the new relocatable object
 		 * to overwrite them.
 		 */
-		ofl->ofl_ocapset.c_sf_1.cm_value &= ~FP_FLAGS;
+		ofl->ofl_ocapset.oc_sf_1.cm_val &= ~FP_FLAGS;
 	} else {
 		/* Do not take the frame pointer flags from the object */
 		val &= ~FP_FLAGS;
 	}
 
-	ofl->ofl_ocapset.c_sf_1.cm_value |= val;
-
-	DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, CA_SUNW_SF_1,
-	    &ofl->ofl_ocapset.c_sf_1, ld_targ.t_m.m_mach));
+	ofl->ofl_ocapset.oc_sf_1.cm_val |= val;
+
+	DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_RESOLVED,
+	    CA_SUNW_SF_1, ofl->ofl_ocapset.oc_sf_1.cm_val, ld_targ.t_m.m_mach));
 
 #undef FP_FLAGS
 }
@@ -371,15 +371,26 @@
  * additive.
  */
 static void
-hw1_cap(Ofl_desc *ofl, Xword val)
+hw_cap(Ofl_desc *ofl, Xword tag, Xword val)
 {
+	elfcap_mask_t	*hwcap;
+	ofl_flag_t	flags1;
+
+	if (tag == CA_SUNW_HW_1) {
+		hwcap = &ofl->ofl_ocapset.oc_hw_1.cm_val;
+		flags1 = FLG_OF1_OVHWCAP1;
+	} else {
+		hwcap = &ofl->ofl_ocapset.oc_hw_2.cm_val;
+		flags1 = FLG_OF1_OVHWCAP2;
+	}
+
 	/*
-	 * If a mapfile has established definitions to override any input
-	 * capabilities, ignore any new input capabilities.
+	 * If a mapfile has established definitions to override any object
+	 * capabilities, ignore any new object capabilities.
 	 */
-	if (ofl->ofl_flags1 & FLG_OF1_OVHWCAP1) {
-		DBG_CALL(Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
-		    CA_SUNW_HW_1, val, ld_targ.t_m.m_mach));
+	if (ofl->ofl_flags1 & flags1) {
+		DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+		    tag, val, ld_targ.t_m.m_mach));
 		return;
 	}
 
@@ -391,70 +402,878 @@
 		return;
 
 	if (DBG_ENABLED) {
-		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
-		    &ofl->ofl_ocapset.c_hw_1, ld_targ.t_m.m_mach);
-		Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_HW_1, val,
-		    ld_targ.t_m.m_mach);
+		Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
+		    ofl->ofl_ocapset.oc_hw_1.cm_val, ld_targ.t_m.m_mach);
+		Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_HW_1,
+		    val, ld_targ.t_m.m_mach);
+	}
+
+	*hwcap |= val;
+
+	DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_RESOLVED, tag,
+	    *hwcap, ld_targ.t_m.m_mach));
+}
+
+/*
+ * Promote a machine capability or platform capability to the output file.
+ * Multiple instances of these names can be defined.
+ */
+static void
+str_cap(Ofl_desc *ofl, char *pstr, ofl_flag_t flags, Xword tag, Caplist *list)
+{
+	Capstr		*capstr;
+	Aliste		idx;
+	Boolean		found = FALSE;
+
+	/*
+	 * If a mapfile has established definitions to override this capability,
+	 * ignore any new capability.
+	 */
+	if (ofl->ofl_flags1 & flags) {
+		DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+		    tag, pstr));
+		return;
+	}
+
+	for (ALIST_TRAVERSE(list->cl_val, idx, capstr)) {
+		DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml,
+		    DBG_STATE_CURRENT, tag, capstr->cs_str));
+		if (strcmp(capstr->cs_str, pstr) == 0)
+			found = TRUE;
+	}
+
+	DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml, DBG_STATE_NEW, tag, pstr));
+
+	if (found == FALSE) {
+		if ((capstr = alist_append(&list->cl_val, NULL,
+		    sizeof (Capstr), AL_CNT_CAP_NAMES)) == NULL) {
+			ofl->ofl_flags |= FLG_OF_FATAL;
+			return;
+		}
+		capstr->cs_str = pstr;
+	}
+
+	if (DBG_ENABLED) {
+		for (ALIST_TRAVERSE(list->cl_val, idx, capstr)) {
+			DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml,
+			    DBG_STATE_RESOLVED, tag, capstr->cs_str));
+		}
 	}
-
-	ofl->ofl_ocapset.c_hw_1.cm_value |= val;
-
-	DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, CA_SUNW_HW_1,
-	    &ofl->ofl_ocapset.c_hw_1, ld_targ.t_m.m_mach));
+}
+
+/*
+ * Promote a capability identifier to the output file.  A capability group can
+ * only have one identifier, and thus only the first identifier seen from any
+ * input relocatable objects is retained.  An explicit user defined identifier,
+ * rather than an an identifier fabricated by ld(1) with -z symbcap processing,
+ * takes precedence.  Note, a user may have defined an identifier via a mapfile,
+ * in which case the mapfile identifier is retained.
+ */
+static void
+id_cap(Ofl_desc *ofl, char *pstr, oc_flag_t flags)
+{
+	Objcapset	*ocapset = &ofl->ofl_ocapset;
+
+	if (ocapset->oc_id.cs_str) {
+		DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml, DBG_STATE_CURRENT,
+		    CA_SUNW_ID, ocapset->oc_id.cs_str));
+
+		if ((ocapset->oc_flags & FLG_OCS_USRDEFID) ||
+		    ((flags & FLG_OCS_USRDEFID) == 0)) {
+			DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml,
+			    DBG_STATE_IGNORED, CA_SUNW_ID, pstr));
+			return;
+		}
+	}
+
+	DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml, DBG_STATE_NEW,
+	    CA_SUNW_ID, pstr));
+
+	ocapset->oc_id.cs_str = pstr;
+	ocapset->oc_flags |= flags;
+
+	DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml, DBG_STATE_RESOLVED,
+	    CA_SUNW_ID, pstr));
+}
+
+/*
+ * Promote a capabilities group to the object capabilities.  This catches a
+ * corner case.  An object capabilities file can be converted to symbol
+ * capabilities with -z symbolcap.  However, if the user has indicated that all
+ * the symbols should be demoted, we'd be left with a symbol capabilities file,
+ * with no associated symbols.  Catch this case by promoting the symbol
+ * capabilities back to object capabilities.
+ */
+void
+ld_cap_move_symtoobj(Ofl_desc *ofl)
+{
+	Cap_group	*cgp;
+	Aliste		idx1;
+
+	for (APLIST_TRAVERSE(ofl->ofl_capgroups, idx1, cgp)) {
+		Objcapset	*scapset = &cgp->cg_set;
+		Capstr		*capstr;
+		Aliste		idx2;
+
+		if (scapset->oc_id.cs_str) {
+			if (scapset->oc_flags & FLG_OCS_USRDEFID)
+				id_cap(ofl, scapset->oc_id.cs_str,
+				    scapset->oc_flags);
+		}
+		if (scapset->oc_plat.cl_val) {
+			for (ALIST_TRAVERSE(scapset->oc_plat.cl_val, idx2,
+			    capstr)) {
+				str_cap(ofl, capstr->cs_str, FLG_OF1_OVPLATCAP,
+				    CA_SUNW_PLAT, &ofl->ofl_ocapset.oc_plat);
+			}
+		}
+		if (scapset->oc_mach.cl_val) {
+			for (ALIST_TRAVERSE(scapset->oc_mach.cl_val, idx2,
+			    capstr)) {
+				str_cap(ofl, capstr->cs_str, FLG_OF1_OVMACHCAP,
+				    CA_SUNW_MACH, &ofl->ofl_ocapset.oc_mach);
+			}
+		}
+		if (scapset->oc_hw_2.cm_val)
+			hw_cap(ofl, CA_SUNW_HW_2, scapset->oc_hw_2.cm_val);
+
+		if (scapset->oc_hw_1.cm_val)
+			hw_cap(ofl, CA_SUNW_HW_1, scapset->oc_hw_1.cm_val);
+
+		if (scapset->oc_sf_1.cm_val)
+			sf1_cap(ofl, scapset->oc_sf_1.cm_val, NULL, NULL);
+	}
 }
 
 /*
- * Process a hardware/software capabilities section.  Traverse the section
- * updating the global capabilities variables as necessary.
+ * Determine whether a capabilities group already exists that describes this
+ * new capabilities group.
+ *
+ * Note, a capability group identifier, CA_SUNW_ID, isn't used as part of the
+ * comparison.  This attribute simply assigns a diagnostic name to the group,
+ * and in the case of multiple identifiers, the first will be taken.
  */
-static void
-process_cap(Ifl_desc *ifl, Is_desc *cisp, Ofl_desc *ofl)
+static Cap_group *
+get_cap_group(Objcapset *ocapset, Word cnum, Ofl_desc *ofl, Is_desc *isp)
 {
-	Cap	*cdata;
-	Word	ndx, cnum;
+	Aliste		idx;
+	Cap_group	*cgp;
+	Word		ccnum = cnum;
+
+	/*
+	 * If the new capabilities contains a CA_SUNW_ID, drop the count of the
+	 * number of comparable items.
+	 */
+	if (ocapset->oc_id.cs_str)
+		ccnum--;
+
+	/*
+	 * Traverse the existing symbols capabilities groups.
+	 */
+	for (APLIST_TRAVERSE(ofl->ofl_capgroups, idx, cgp)) {
+		Word	onum = cgp->cg_num;
+		Alist	*calp, *oalp;
+
+		if (cgp->cg_set.oc_id.cs_str)
+			onum--;
+
+		if (onum != ccnum)
+			continue;
+
+		if (cgp->cg_set.oc_hw_1.cm_val != ocapset->oc_hw_1.cm_val)
+			continue;
+		if (cgp->cg_set.oc_sf_1.cm_val != ocapset->oc_sf_1.cm_val)
+			continue;
+		if (cgp->cg_set.oc_hw_2.cm_val != ocapset->oc_hw_2.cm_val)
+			continue;
+
+		calp = cgp->cg_set.oc_plat.cl_val;
+		oalp = ocapset->oc_plat.cl_val;
+		if ((calp == NULL) && oalp)
+			continue;
+		if (calp && ((oalp == NULL) || cap_names_match(calp, oalp)))
+			continue;
+
+		calp = cgp->cg_set.oc_mach.cl_val;
+		oalp = ocapset->oc_mach.cl_val;
+		if ((calp == NULL) && oalp)
+			continue;
+		if (calp && ((oalp == NULL) || cap_names_match(calp, oalp)))
+			continue;
+
+		/*
+		 * If a matching group is found, then this new group has
+		 * already been supplied by a previous file, and hence the
+		 * existing group can be used.  Record this new input section,
+		 * from which we can also derive the input file name, on the
+		 * existing groups input sections.
+		 */
+		if (aplist_append(&(cgp->cg_secs), isp,
+		    AL_CNT_CAP_SECS) == NULL)
+			return (NULL);
+		return (cgp);
+	}
+
+	/*
+	 * If a capabilities group is not found, create a new one.
+	 */
+	if (((cgp = libld_calloc(sizeof (Cap_group), 1)) == NULL) ||
+	    (aplist_append(&(ofl->ofl_capgroups), cgp,
+	    AL_CNT_CAP_DESCS) == NULL))
+		return (NULL);
+
+	/*
+	 * If we're converting object capabilities to symbol capabilities and
+	 * no CA_SUNW_ID is defined, fabricate one.  This identifier is appended
+	 * to all symbol names that are converted into capabilities symbols,
+	 * see ld_sym_process().
+	 */
+	if ((isp->is_file->ifl_flags & FLG_IF_OTOSCAP) &&
+	    (ocapset->oc_id.cs_str == NULL)) {
+		size_t	len;
+
+		/*
+		 * Create an identifier using the group number together with a
+		 * default template.  We allocate a buffer large enough for any
+		 * possible number of items (way more than we need).
+		 */
+		len = MSG_STR_CAPGROUPID_SIZE + CONV_INV_BUFSIZE;
+		if ((ocapset->oc_id.cs_str = libld_malloc(len)) == NULL)
+			return (NULL);
+
+		(void) snprintf(ocapset->oc_id.cs_str, len,
+		    MSG_ORIG(MSG_STR_CAPGROUPID),
+		    aplist_nitems(ofl->ofl_capgroups));
+		cnum++;
+	}
+
+	cgp->cg_set = *ocapset;
+	cgp->cg_num = cnum;
+
+	/*
+	 * Null the callers alist's as they've effectively been transferred
+	 * to this new Cap_group.
+	 */
+	ocapset->oc_plat.cl_val = ocapset->oc_mach.cl_val = NULL;
+
+	/*
+	 * Keep track of which input section, and hence input file, established
+	 * this group.
+	 */
+	if (aplist_append(&(cgp->cg_secs), isp, AL_CNT_CAP_SECS) == NULL)
+		return (NULL);
+
+	/*
+	 * Keep track of the number of symbol capabilities entries that will be
+	 * required in the output file.  Each group requires a terminating
+	 * CA_SUNW_NULL.
+	 */
+	ofl->ofl_capsymcnt += (cnum + 1);
+	return (cgp);
+}
+
+/*
+ * Capture symbol capability family information.  This data structure is focal
+ * in maintaining all symbol capability relationships, and provides for the
+ * eventual creation of a capabilities information section, and possibly a
+ * capabilities chain section.
+ *
+ * Capabilities families are lead by a CAPINFO_SUNW_GLOB symbol.  This symbol
+ * provides the visible global symbol that is referenced by all external
+ * callers.  This symbol may have aliases.  For example, a weak/global symbol
+ * pair, such as memcpy()/_memcpy() may lead the same capabilities family.
+ * Each family contains one or more local symbol members.  These members provide
+ * the capabilities specific functions, and are associated to a capabilities
+ * group.  For example, the capability members memcpy%sun4u and memcpy%sun4v
+ * might be associated with the memcpy() capability family.
+ *
+ * This routine is called when a relocatable object that provides object
+ * capabilities is transformed into a symbol capabilities object, using the
+ * -z symbolcap option.
+ *
+ * This routine is also called to collect the SUNW_capinfo section information
+ * of a relocatable object that contains symbol capability definitions.
+ */
+uintptr_t
+ld_cap_add_family(Ofl_desc *ofl, Sym_desc *lsdp, Sym_desc *csdp, Cap_group *cgp,
+    APlist **csyms)
+{
+	Cap_avlnode	qcav, *cav;
+	avl_tree_t	*avlt;
+	avl_index_t	where = 0;
+	Cap_sym		*mcsp;
+	Aliste		idx;
+
+	/*
+	 * Make sure the capability families have an initialized AVL tree.
+	 */
+	if ((avlt = ofl->ofl_capfamilies) == NULL) {
+		if ((avlt = libld_calloc(sizeof (avl_tree_t), 1)) == NULL)
+			return (S_ERROR);
+		avl_create(avlt, &ld_sym_avl_comp, sizeof (Cap_avlnode),
+		    SGSOFFSETOF(Cap_avlnode, cn_symavlnode.sav_node));
+		ofl->ofl_capfamilies = avlt;
+
+		/*
+		 * When creating a dynamic object, capability family members
+		 * are maintained in a .SUNW_capchain, the first entry of
+		 * which is the version number of the chain.
+		 */
+		ofl->ofl_capchaincnt = 1;
+	}
+
+	/*
+	 * Determine whether a family already exists, and if not, create one
+	 * using the lead family symbol.
+	 */
+	qcav.cn_symavlnode.sav_hash = (Word)elf_hash(lsdp->sd_name);
+	qcav.cn_symavlnode.sav_name = lsdp->sd_name;
+
+	if ((cav = avl_find(avlt, &qcav, &where)) == NULL) {
+		if ((cav = libld_calloc(sizeof (Cap_avlnode), 1)) == NULL)
+			return (S_ERROR);
+		cav->cn_symavlnode.sav_hash = qcav.cn_symavlnode.sav_hash;
+		cav->cn_symavlnode.sav_name = qcav.cn_symavlnode.sav_name;
+		cav->cn_symavlnode.sav_sdp = lsdp;
+
+		avl_insert(avlt, cav, where);
+
+		/*
+		 * When creating a dynamic object, capability family members
+		 * are maintained in a .SUNW_capchain, each family starts with
+		 * this lead symbol, and is terminated with a 0 element.
+		 */
+		ofl->ofl_capchaincnt += 2;
+	}
+
+	/*
+	 * If no group information is provided then this request is to add a
+	 * lead capability symbol, or lead symbol alias.  If this is the lead
+	 * symbol there's nothing more to do.  Otherwise save the alias.
+	 */
+	if (cgp == NULL) {
+		if ((lsdp != csdp) && (aplist_append(&cav->cn_aliases, csdp,
+		    AL_CNT_CAP_ALIASES) == NULL))
+			return (S_ERROR);
+
+		return (0);
+	}
+
+	/*
+	 * Determine whether a member of the same group as this new member is
+	 * already defined within this family.  If so, we have a multiply
+	 * defined symbol.
+	 */
+	for (APLIST_TRAVERSE(cav->cn_members, idx, mcsp)) {
+		Sym_desc	*msdp;
+
+		if (cgp != mcsp->cs_group)
+			continue;
+
+		/*
+		 * Diagnose that a multiple symbol definition exists.
+		 */
+		msdp = mcsp->cs_sdp;
+
+		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_CAP_MULDEF),
+		    demangle(lsdp->sd_name));
+		eprintf(ofl->ofl_lml, ERR_NONE, MSG_INTL(MSG_CAP_MULDEFSYMS),
+		    msdp->sd_file->ifl_name, msdp->sd_name,
+		    csdp->sd_file->ifl_name, csdp->sd_name);
+		ofl->ofl_flags |= FLG_OF_FATAL;
+	}
+
+	/*
+	 * Add this capabilities symbol member to the family.
+	 */
+	if (((mcsp = libld_malloc(sizeof (Cap_sym))) == NULL) ||
+	    (aplist_append(&cav->cn_members, mcsp, AL_CNT_CAP_MEMS) == NULL))
+		return (S_ERROR);
+
+	mcsp->cs_sdp = csdp;
+	mcsp->cs_group = cgp;
+
+	/*
+	 * When creating a dynamic object, capability family members are
+	 * maintained in a .SUNW_capchain.  Account for this family member.
+	 */
+	ofl->ofl_capchaincnt++;
+
+	/*
+	 * If this input file is undergoing object capabilities to symbol
+	 * capabilities conversion, then this member is a new local symbol
+	 * that has been generated from an original global symbol.  Keep track
+	 * of this symbol so that the output file symbol table can be populated
+	 * with these new symbol entries.
+	 */
+	if (csyms && (aplist_append(csyms, mcsp, AL_CNT_CAP_SYMS) == NULL))
+		return (S_ERROR);
+
+	return (0);
+}
+
+/*
+ * Process a SHT_SUNW_cap capabilities section.
+ */
+static uintptr_t
+process_cap(Ofl_desc *ofl, Ifl_desc *ifl, Is_desc *cisp)
+{
+	Objcapset	ocapset = { 0 };
+	Cap_desc	*cdp;
+	Cap		*data, *cdata;
+	char		*strs;
+	Word		ndx, cnum;
+	int		objcapndx, descapndx, symcapndx;
+	int		nulls, capstrs = 0;
+
+	/*
+	 * Determine the capabilities data and size.
+	 */
+	cdata = (Cap *)cisp->is_indata->d_buf;
+	cnum = (Word)(cisp->is_shdr->sh_size / cisp->is_shdr->sh_entsize);
+
+	if ((cdata == NULL) || (cnum == 0))
+		return (0);
 
 	DBG_CALL(Dbg_cap_sec_title(ofl->ofl_lml, ifl->ifl_name));
 
 	/*
-	 * The capabilities are supposed to be terminated with a CA_SUNW_NULL
-	 * entry.  However, the compilers have been known to not follow this
-	 * convention.  Use the section information to determine the number
-	 * of capabilities, and skip any CA_SUNW_NULL entries.
+	 * Traverse the section to determine what capabilities groups are
+	 * available.
+	 *
+	 * A capabilities section can contain one or more, CA_SUNW_NULL
+	 * terminated groups.
+	 *
+	 *  -	The first group defines the object capabilities.
+	 *  -	Additional groups define symbol capabilities.
+	 *  -	Since the initial group is always reserved for object
+	 *	capabilities, any object with symbol capabilities must also
+	 *	have an object capabilities group.  If the object has no object
+	 *	capabilities, an empty object group is defined, consisting of a
+	 *	CA_SUNW_NULL element in index [0].
+	 *  -	If any capabilities require references to a named string, then
+	 *	the section header sh_info points to the associated string
+	 *	table.
+	 *  -	If an object contains symbol capability groups, then the
+	 *	section header sh_link points to the associated capinfo table.
 	 */
-	cdata = (Cap *)cisp->is_indata->d_buf;
-	cnum = (Word)(cisp->is_shdr->sh_size / cisp->is_shdr->sh_entsize);
-
-	for (ndx = 0; ndx < cnum; cdata++, ndx++) {
-		switch (cdata->c_tag) {
-			case CA_SUNW_HW_1:
-				/*
-				 * Only the hardware capabilities that are
-				 * defined in a relocatable object become part
-				 * of the hardware capabilities in the output
-				 * file.
-				 */
-				if (ifl->ifl_ehdr->e_type == ET_REL)
-					hw1_cap(ofl, cdata->c_un.c_val);
-				break;
-			case CA_SUNW_SF_1:
-				/*
-				 * Only the software capabilities that are
-				 * defined in a relocatable object become part
-				 * of the software capabilities in the output
-				 * file.  However, check the validity of the
-				 * software capabilities of any dependencies.
-				 */
-				sf1_cap(ofl, cdata->c_un.c_val, ifl, cisp);
-				break;
-			case CA_SUNW_NULL:
-				break;
-			default:
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    MSG_INTL(MSG_FIL_UNKCAP), ifl->ifl_name,
-				    EC_WORD(cisp->is_scnndx), cisp->is_name,
-				    cdata->c_tag);
+	objcapndx = 0;
+	descapndx = symcapndx = -1;
+	nulls = 0;
+
+	for (ndx = 0, data = cdata; ndx < cnum; ndx++, data++) {
+		switch (data->c_tag) {
+		case CA_SUNW_NULL:
+			/*
+			 * If this is the first CA_SUNW_NULL entry, and no
+			 * capabilities group has been found, then this object
+			 * does not define any object capabilities.
+			 */
+			if (nulls++ == 0) {
+				if (ndx == 0)
+					objcapndx = -1;
+			} else if ((symcapndx == -1) && (descapndx != -1))
+				symcapndx = descapndx;
+
+			break;
+
+		case CA_SUNW_PLAT:
+		case CA_SUNW_MACH:
+		case CA_SUNW_ID:
+			capstrs++;
+			/* FALLTHROUGH */
+
+		case CA_SUNW_HW_1:
+		case CA_SUNW_SF_1:
+		case CA_SUNW_HW_2:
+			/*
+			 * If this is the start of a new group, save it.
+			 */
+			if (descapndx == -1)
+				descapndx = ndx;
+			break;
+
+		default:
+			eprintf(ofl->ofl_lml, ERR_WARNING,
+			    MSG_INTL(MSG_FIL_UNKCAP), ifl->ifl_name,
+			    EC_WORD(cisp->is_scnndx), cisp->is_name,
+			    data->c_tag);
 		}
 	}
+
+	/*
+	 * If a string capabilities entry has been found, the capabilities
+	 * section must reference the associated string table.
+	 */
+	if (capstrs) {
+		Word	info = cisp->is_shdr->sh_info;
+
+		if ((info == 0) || (info > ifl->ifl_shnum)) {
+			eprintf(ofl->ofl_lml, ERR_FATAL,
+			    MSG_INTL(MSG_FIL_INVSHINFO), ifl->ifl_name,
+			    EC_WORD(cisp->is_scnndx), cisp->is_name,
+			    EC_XWORD(info));
+			ofl->ofl_flags |= FLG_OF_FATAL;
+			return (S_ERROR);
+		}
+		strs = (char *)ifl->ifl_isdesc[info]->is_indata->d_buf;
+	}
+
+	/*
+	 * The processing of capabilities groups is as follows:
+	 *
+	 *  -	if a relocatable object provides only object capabilities, and
+	 *	the -z symbolcap option is in effect, then the object
+	 *	capabilities are transformed into symbol capabilities and the
+	 *	symbol capabilities are carried over to the output file.
+	 *  -	in all other cases, any capabilities present in an input
+	 *	relocatable object are carried from the input object to the
+	 *	output without any transformation or conversion.
+	 *
+	 * Capture any object capabilities that are to be carried over to the
+	 * output file.
+	 */
+	if ((objcapndx == 0) &&
+	    ((symcapndx != -1) || ((ofl->ofl_flags & FLG_OF_OTOSCAP) == 0))) {
+		for (ndx = 0, data = cdata; ndx < cnum; ndx++, data++) {
+			/*
+			 * Object capabilities end at the first null.
+			 */
+			if (data->c_tag == CA_SUNW_NULL)
+				break;
+
+			/*
+			 * Only the object software capabilities that are
+			 * defined in a relocatable object become part of the
+			 * object software capabilities in the output file.
+			 * However, check the validity of any object software
+			 * capabilities of any dependencies.
+			 */
+			if (data->c_tag == CA_SUNW_SF_1) {
+				sf1_cap(ofl, data->c_un.c_val, ifl, cisp);
+				continue;
+			}
+
+			/*
+			 * The remaining capability types must come from a
+			 * relocatable object in order to contribute to the
+			 * output.
+			 */
+			if (ifl->ifl_ehdr->e_type != ET_REL)
+				continue;
+
+			switch (data->c_tag) {
+			case CA_SUNW_HW_1:
+			case CA_SUNW_HW_2:
+				hw_cap(ofl, data->c_tag, data->c_un.c_val);
+				break;
+
+			case CA_SUNW_PLAT:
+				str_cap(ofl, strs + data->c_un.c_ptr,
+				    FLG_OF1_OVPLATCAP, CA_SUNW_PLAT,
+				    &ofl->ofl_ocapset.oc_plat);
+				break;
+
+			case CA_SUNW_MACH:
+				str_cap(ofl, strs + data->c_un.c_ptr,
+				    FLG_OF1_OVMACHCAP, CA_SUNW_MACH,
+				    &ofl->ofl_ocapset.oc_mach);
+				break;
+
+			case CA_SUNW_ID:
+				id_cap(ofl, strs + data->c_un.c_ptr,
+				    FLG_OCS_USRDEFID);
+				break;
+
+			default:
+				assert(0);	/* Unknown capability type */
+			}
+		}
+
+		/*
+		 * If there are no symbol capabilities, or this objects
+		 * capabilities aren't being transformed into a symbol
+		 * capabilities, then we're done.
+		 */
+		if ((symcapndx == -1) &&
+		    ((ofl->ofl_flags & FLG_OF_OTOSCAP) == 0))
+			return (1);
+	}
+
+	/*
+	 * If these capabilities don't originate from a relocatable object
+	 * there's no further processing required.
+	 */
+	if (ifl->ifl_ehdr->e_type != ET_REL)
+		return (1);
+
+	/*
+	 * If this object only defines an object capabilities group, and the
+	 * -z symbolcap option is in effect, then all global function symbols
+	 * and initialized global data symbols are renamed and assigned to the
+	 * transformed symbol capabilities group.
+	 */
+	if ((objcapndx == 0) &&
+	    (symcapndx == -1) && (ofl->ofl_flags & FLG_OF_OTOSCAP))
+		ifl->ifl_flags |= FLG_IF_OTOSCAP;
+
+	/*
+	 * Allocate a capabilities descriptor to collect the capabilities data
+	 * for this input file.  Allocate a mirror of the raw capabilities data
+	 * that points to the individual symbol capabilities groups.  An APlist
+	 * is used, although it will be sparsely populated, as the list provides
+	 * a convenient mechanism for traversal later.
+	 */
+	if (((cdp = libld_calloc(sizeof (Cap_desc), 1)) == NULL) ||
+	    (aplist_append(&(cdp->ca_groups), NULL, cnum) == NULL))
+		return (S_ERROR);
+
+	/*
+	 * Clear the allocated APlist data array, and assign the number of
+	 * items as the total number of array items.
+	 */
+	(void) memset(&cdp->ca_groups->apl_data[0], 0,
+	    (cnum * sizeof (void *)));
+	cdp->ca_groups->apl_nitems = cnum;
+
+	ifl->ifl_caps = cdp;
+
+	/*
+	 * Traverse the capabilities data, unpacking the data into a
+	 * capabilities set.  Process each capabilities set as a unique group.
+	 */
+	descapndx = -1;
+	nulls = 0;
+
+	for (ndx = 0, data = cdata; ndx < cnum; ndx++, data++) {
+		Capstr	*capstr;
+
+		switch (data->c_tag) {
+		case CA_SUNW_NULL:
+			nulls++;
+
+			/*
+			 * Process the capabilities group that this null entry
+			 * terminates.  The capabilities group that is returned
+			 * will either point to this file's data, or to a
+			 * matching capabilities group that has already been
+			 * processed.
+			 *
+			 * Note, if this object defines object capabilities,
+			 * the first group descriptor points to these object
+			 * capabilities.  It is only necessary to save this
+			 * descriptor when object capabilities are being
+			 * transformed into symbol capabilities (-z symbolcap).
+			 */
+			if (descapndx != -1) {
+				if ((nulls > 1) ||
+				    (ifl->ifl_flags & FLG_IF_OTOSCAP)) {
+					APlist	*alp = cdp->ca_groups;
+
+					if ((alp->apl_data[descapndx] =
+					    get_cap_group(&ocapset,
+					    (ndx - descapndx), ofl,
+					    cisp)) == NULL)
+						return (S_ERROR);
+				}
+
+				/*
+				 * Clean up the capabilities data in preparation
+				 * for processing additional groups.  If the
+				 * collected capabilities strings were used to
+				 * establish a new output group, they will have
+				 * been saved in get_cap_group().  If these
+				 * descriptors still exist, then an existing
+				 * descriptor has been used to associate with
+				 * this file, and these string descriptors can
+				 * be freed.
+				 */
+				ocapset.oc_hw_1.cm_val =
+				    ocapset.oc_sf_1.cm_val =
+				    ocapset.oc_hw_2.cm_val = 0;
+				if (ocapset.oc_plat.cl_val) {
+					free((void *)ocapset.oc_plat.cl_val);
+					ocapset.oc_plat.cl_val = NULL;
+				}
+				if (ocapset.oc_mach.cl_val) {
+					free((void *)ocapset.oc_mach.cl_val);
+					ocapset.oc_mach.cl_val = NULL;
+				}
+				descapndx = -1;
+			}
+			continue;
+
+		case CA_SUNW_HW_1:
+			ocapset.oc_hw_1.cm_val = data->c_un.c_val;
+			DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml,
+			    DBG_STATE_ORIGINAL, CA_SUNW_HW_1,
+			    ocapset.oc_hw_1.cm_val, ld_targ.t_m.m_mach));
+			break;
+
+		case CA_SUNW_SF_1:
+			ocapset.oc_sf_1.cm_val = data->c_un.c_val;
+			DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml,
+			    DBG_STATE_ORIGINAL, CA_SUNW_SF_1,
+			    ocapset.oc_sf_1.cm_val, ld_targ.t_m.m_mach));
+			break;
+
+		case CA_SUNW_HW_2:
+			ocapset.oc_hw_2.cm_val = data->c_un.c_val;
+			DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml,
+			    DBG_STATE_ORIGINAL, CA_SUNW_HW_2,
+			    ocapset.oc_hw_2.cm_val, ld_targ.t_m.m_mach));
+			break;
+
+		case CA_SUNW_PLAT:
+			if ((capstr = alist_append(&ocapset.oc_plat.cl_val,
+			    NULL, sizeof (Capstr), AL_CNT_CAP_NAMES)) == NULL)
+				return (S_ERROR);
+			capstr->cs_str = strs + data->c_un.c_ptr;
+			DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml,
+			    DBG_STATE_ORIGINAL, CA_SUNW_PLAT, capstr->cs_str));
+			break;
+
+		case CA_SUNW_MACH:
+			if ((capstr = alist_append(&ocapset.oc_mach.cl_val,
+			    NULL, sizeof (Capstr), AL_CNT_CAP_NAMES)) == NULL)
+				return (S_ERROR);
+			capstr->cs_str = strs + data->c_un.c_ptr;
+			DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml,
+			    DBG_STATE_ORIGINAL, CA_SUNW_MACH, capstr->cs_str));
+			break;
+
+		case CA_SUNW_ID:
+			ocapset.oc_id.cs_str = strs + data->c_un.c_ptr;
+			DBG_CALL(Dbg_cap_ptr_entry(ofl->ofl_lml,
+			    DBG_STATE_ORIGINAL, CA_SUNW_ID,
+			    ocapset.oc_id.cs_str));
+			break;
+		}
+
+		/*
+		 * Save the start of this new group.
+		 */
+		if (descapndx == -1)
+			descapndx = ndx;
+	}
+	return (1);
+}
+
+/*
+ * Capture any symbol capabilities symbols.  An object file that contains symbol
+ * capabilities has an associated .SUNW_capinfo section.  This section
+ * identifies which symbols are associated to which capabilities, together with
+ * their associated lead symbol.  Each of these symbol pairs are recorded for
+ * processing later.
+ */
+static uintptr_t
+process_capinfo(Ofl_desc *ofl, Ifl_desc *ifl, Is_desc *isp)
+{
+	Cap_desc	*cdp = ifl->ifl_caps;
+	Capinfo		*capinfo = isp->is_indata->d_buf;
+	Shdr		*shdr = isp->is_shdr;
+	Word		cndx, capinfonum;
+
+	capinfonum = (Word)(shdr->sh_size / shdr->sh_entsize);
+
+	if ((cdp == NULL) || (capinfo == NULL) || (capinfonum == 0))
+		return (0);
+
+	for (cndx = 1, capinfo++; cndx < capinfonum; cndx++, capinfo++) {
+		Sym_desc	*sdp, *lsdp;
+		Word		lndx;
+		uchar_t		gndx;
+
+		if ((gndx = (uchar_t)ELF_C_GROUP(*capinfo)) == 0)
+			continue;
+		lndx = (Word)ELF_C_SYM(*capinfo);
+
+		/*
+		 * Catch any anomalies.  A capabilities symbol should be valid,
+		 * and the capabilities lead symbol should also be global.
+		 * Note, ld(1) -z symbolcap would create local capabilities
+		 * symbols, but we don't enforce this so as to give the
+		 * compilation environment a little more freedom.
+		 */
+		if ((sdp = ifl->ifl_oldndx[cndx]) == NULL) {
+			eprintf(ofl->ofl_lml, ERR_WARNING,
+			    MSG_INTL(MSG_CAPINFO_INVALSYM), ifl->ifl_name,
+			    EC_WORD(isp->is_scnndx), isp->is_name, cndx,
+			    MSG_INTL(MSG_STR_UNKNOWN));
+			continue;
+		}
+		if ((lndx == 0) || (lndx >= ifl->ifl_symscnt) ||
+		    ((lsdp = ifl->ifl_oldndx[lndx]) == NULL) ||
+		    (ELF_ST_BIND(lsdp->sd_sym->st_info) != STB_GLOBAL)) {
+			eprintf(ofl->ofl_lml, ERR_WARNING,
+			    MSG_INTL(MSG_CAPINFO_INVALLEAD), ifl->ifl_name,
+			    EC_WORD(isp->is_scnndx), isp->is_name, cndx, lsdp ?
+			    demangle(lsdp->sd_name) : MSG_INTL(MSG_STR_UNKNOWN),
+			    lndx);
+			continue;
+		}
+
+		/*
+		 * Indicate that this is a capabilities symbol.
+		 */
+		sdp->sd_flags |= FLG_SY_CAP;
+
+		/*
+		 * Save any global capability symbols.  Global capability
+		 * symbols are identified with a CAPINFO_SUNW_GLOB group id.
+		 * The lead symbol for this global capability symbol is either
+		 * the symbol itself, or an alias.
+		 */
+		if (gndx == CAPINFO_SUNW_GLOB) {
+			if (ld_cap_add_family(ofl, lsdp, sdp,
+			    NULL, NULL) == S_ERROR)
+				return (S_ERROR);
+			continue;
+		}
+
+		/*
+		 * Track the number of non-global capabilities symbols, as these
+		 * are used to size any symbol tables.  If we're generating a
+		 * dynamic object, this symbol will be added to the dynamic
+		 * symbol table, therefore ensure there is space in the dynamic
+		 * string table.
+		 */
+		ofl->ofl_caploclcnt++;
+		if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) &&
+		    (st_insert(ofl->ofl_dynstrtab, sdp->sd_name) == -1))
+			return (S_ERROR);
+
+		/*
+		 * As we're tracking this local symbol as a capabilities symbol,
+		 * reduce the local symbol count to compensate.
+		 */
+		ofl->ofl_locscnt--;
+
+		/*
+		 * Determine whether the associated lead symbol indicates
+		 * NODYNSORT.  If so, remove this local entry from the
+		 * SUNW_dynsort section too.  NODYNSORT tagging can only be
+		 * obtained from a mapfile symbol definition, and thus any
+		 * global definition that has this tagging has already been
+		 * instantiated and this instance resolved to it.
+		 */
+		if (lsdp->sd_flags & FLG_SY_NODYNSORT) {
+			Sym	*lsym = lsdp->sd_sym;
+			uchar_t ltype = ELF_ST_TYPE(lsym->st_info);
+
+			DYNSORT_COUNT(lsdp, lsym, ltype, --);
+			lsdp->sd_flags |= FLG_SY_NODYNSORT;
+		}
+
+		/*
+		 * Track this family member, together with its associated group.
+		 */
+		if (ld_cap_add_family(ofl, lsdp, sdp,
+		    cdp->ca_groups->apl_data[gndx], NULL) == S_ERROR)
+			return (S_ERROR);
+	}
+
+	return (0);
 }
 
 /*
@@ -500,7 +1319,6 @@
 	return (1);
 }
 
-
 /*
  * Process a string table section.  A valid section contains an initial and
  * final null byte.
@@ -949,8 +1767,9 @@
 
 /*
  * Expand implicit references.  Dependencies can be specified in terms of the
- * $ORIGIN, $PLATFORM, $OSREL and $OSNAME tokens, either from their needed name,
- * or via a runpath.  In addition runpaths may also specify the $ISALIST token.
+ * $ORIGIN, $MACHINE, $PLATFORM, $OSREL and $OSNAME tokens, either from their
+ * needed name, or via a runpath.  In addition runpaths may also specify the
+ * $ISALIST token.
  *
  * Probably the most common reference to explicit dependencies (via -L) will be
  * sufficient to find any associated implicit dependencies, but just in case we
@@ -960,6 +1779,8 @@
  *
  * This code is remarkably similar to expand() in rtld/common/paths.c.
  */
+static char		*machine = NULL;
+static size_t		machine_sz = 0;
 static char		*platform = NULL;
 static size_t		platform_sz = 0;
 static Isa_desc		*isa = NULL;
@@ -1014,6 +1835,35 @@
 			optr += MSG_STR_ORIGIN_SIZE;
 			expanded = _expanded = 1;
 
+		} else if (strncmp(optr, MSG_ORIG(MSG_STR_MACHINE),
+		    MSG_STR_MACHINE_SIZE) == 0) {
+			/*
+			 * Establish the machine from sysconf - like uname -i.
+			 */
+			if ((machine == NULL) && (machine_sz == 0)) {
+				char	info[SYS_NMLN];
+				long	size;
+
+				size = sysinfo(SI_MACHINE, info, SYS_NMLN);
+				if ((size != -1) &&
+				    (machine = libld_malloc((size_t)size))) {
+					(void) strcpy(machine, info);
+					machine_sz = (size_t)size - 1;
+				} else
+					machine_sz = 1;
+			}
+			if (machine) {
+				if (machine_sz >= nrem)
+					return ((char *)name);
+
+				(void) strncpy(nptr, machine, machine_sz);
+				nptr = nptr + machine_sz;
+				nrem -= machine_sz;
+
+				optr += MSG_STR_MACHINE_SIZE;
+				expanded = _expanded = 1;
+			}
+
 		} else if (strncmp(optr, MSG_ORIG(MSG_STR_PLATFORM),
 		    MSG_STR_PLATFORM_SIZE) == 0) {
 			/*
@@ -1625,7 +2475,8 @@
 	Word		row, column;
 	int		ident;
 	uintptr_t	error;
-	Is_desc		*vdfisp, *vndisp, *vsyisp, *sifisp, *capisp;
+	Is_desc		*vdfisp, *vndisp, *vsyisp, *sifisp;
+	Is_desc		*capinfoisp, *capisp;
 	Sdf_desc	*sdf;
 	Place_path_info	path_info_buf, *path_info;
 
@@ -1700,7 +2551,7 @@
 
 	DBG_CALL(Dbg_file_generic(ofl->ofl_lml, ifl));
 	ndx = 0;
-	vdfisp = vndisp = vsyisp = sifisp = capisp = NULL;
+	vdfisp = vndisp = vsyisp = sifisp = capinfoisp = capisp = NULL;
 	scn = NULL;
 	while (scn = elf_nextscn(elf, scn)) {
 		ndx++;
@@ -1786,6 +2637,12 @@
 					return (S_ERROR);
 				capisp = ifl->ifl_isdesc[ndx];
 				break;
+			case SHT_SUNW_capinfo:
+				if (process_section(name, ifl, shdr, scn, ndx,
+				    ld_targ.t_id.id_null, ofl) == S_ERROR)
+					return (S_ERROR);
+				capinfoisp = ifl->ifl_isdesc[ndx];
+				break;
 			case SHT_SUNW_DEBUGSTR:
 			case SHT_SUNW_DEBUG:
 				if (process_debug(name, ifl, shdr, scn,
@@ -1991,13 +2848,14 @@
 	}
 
 	/*
-	 * Process any hardware/software capabilities sections.  Only the
-	 * capabilities for input relocatable objects are propagated.  If the
-	 * relocatable objects don't contain any capabilities, any capability
-	 * state that has already been gathered will prevail.
+	 * Before symbol processing, process any capabilities.  Capabilities
+	 * can reference a string table, which is why this processing is
+	 * carried out after the initial section processing.  Capabilities,
+	 * together with -z symbolcap, can require the conversion of global
+	 * symbols to local symbols.
 	 */
-	if (capisp)
-		process_cap(ifl, capisp, ofl);
+	if (capisp && (process_cap(ofl, ifl, capisp) == S_ERROR))
+		return (S_ERROR);
 
 	/*
 	 * Process any version dependencies.  These will establish shared object
@@ -2075,6 +2933,16 @@
 	}
 
 	/*
+	 * Following symbol processing, if this relocatable object input file
+	 * provides symbol capabilities, tag the associated symbols so that
+	 * the symbols can be re-assigned to the new capabilities symbol
+	 * section that will be created for the output file.
+	 */
+	if (capinfoisp && (ifl->ifl_ehdr->e_type == ET_REL) &&
+	    (process_capinfo(ofl, ifl, capinfoisp) == S_ERROR))
+		return (S_ERROR);
+
+	/*
 	 * After processing any symbol resolution, and if this dependency
 	 * indicates it contains symbols that can't be directly bound to,
 	 * set the symbols appropriately.
--- a/usr/src/cmd/sgs/libld/common/globals.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/globals.c	Mon Mar 01 10:20:48 2010 -0800
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -73,7 +73,12 @@
 		MSG_REJ_US3,		/* MSG_INTL(MSG_REJ_US3) */
 		MSG_REJ_STR,		/* MSG_INTL(MSG_REJ_STR) */
 		MSG_REJ_UNKFILE,	/* MSG_INTL(MSG_REJ_UNKFILE) */
+		MSG_REJ_UNKCAP,		/* MSG_INTL(MSG_REJ_UNKCAP) */
 		MSG_REJ_HWCAP_1,	/* MSG_INTL(MSG_REJ_HWCAP_1) */
+		MSG_REJ_SFCAP_1,	/* MSG_INTL(MSG_REJ_SFCAP_1) */
+		MSG_REJ_MACHCAP,	/* MSG_INTL(MSG_REJ_MACHCAP) */
+		MSG_REJ_PLATCAP,	/* MSG_INTL(MSG_REJ_PLATCAP) */
+		MSG_REJ_HWCAP_2		/* MSG_INTL(MSG_REJ_HWCAP_2) */
 	};
 
 /*
--- a/usr/src/cmd/sgs/libld/common/libld.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/libld.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -220,6 +220,8 @@
 			 \t\t\trescan specified archive group upon reaching\n\
 			 \t\t\tthe end of the group, until no further\n\
 			 \t\t\tmember extraction occurs\n"
+@ MSG_ARG_DETAIL_ZSCAP	"\t[-z symbolcap]\tconvert object capabilities to \
+			 symbol capabilities\n"
 @ MSG_ARG_DETAIL_ZTARG	"\t[-z target=platform]\n\
 			 \t\t\ttarget machine for cross linking\n"
 @ MSG_ARG_DETAIL_ZT	"\t[-z text]\tdisallow output relocations against \
@@ -425,6 +427,7 @@
 
 
 # Messages related to platform support
+
 @ MSG_TARG_UNSUPPORTED	"unsupported ELF machine type: %s"
 
 
@@ -589,6 +592,17 @@
 @ MSG_VER_ADDVER	"\t%s"
 @ MSG_VER_CYCLIC	"following versions generate cyclic dependency:"
 
+# Capabilities messages
+
+@ MSG_CAP_MULDEF	"capabilities symbol '%s' has multiply-defined members:"
+@ MSG_CAP_MULDEFSYMS	"\t(file %s symbol '%s'; file %s symbol '%s');"
+@ MSG_CAP_REDUNDANT	"file %s: section [%u]%s: symbol capabilities \
+			 redundant, as object capabilities are more restrictive"
+
+@ MSG_CAPINFO_INVALSYM	"file %s: capabilities info section [%u]%s: index %d: \
+			 family member symbol '%s': invalid"
+@ MSG_CAPINFO_INVALLEAD	"file %s: capabilities info section [%u]%s: index %d: \
+			 family lead symbol '%s': invalid symbol index %d"
 
 # Basic strings
 
@@ -635,7 +649,17 @@
 @ MSG_REJ_US3		"file %s: Sun UltraSPARC III extensions required"
 @ MSG_REJ_STR		"file %s: %s"
 @ MSG_REJ_UNKFILE	"file %s: unknown file type"
-@ MSG_REJ_HWCAP_1	"file %s: hardware capability unsupported: %s"
+@ MSG_REJ_UNKCAP	"file=%s; unknown capability: %d"
+@ MSG_REJ_HWCAP_1	"file %s: hardware capability (CA_SUNW_HW_1) \
+			 unsupported: %s"
+@ MSG_REJ_SFCAP_1	"file %s: software capability (CA_SUNW_SF_1) \
+			 unsupported: %s"
+@ MSG_REJ_MACHCAP	"file %s: machine capability (CA_SUNW_MACH) \
+			 unsupported: %s"
+@ MSG_REJ_PLATCAP	"file %s: platform capability (CA_SUNW_PLAT) \
+			 unsupported: %s"
+@ MSG_REJ_HWCAP_2	"file %s: hardware capability (CA_SUNW_HW_2) \
+			 unsupported: %s"
 
 
 @ _END_
@@ -664,6 +688,7 @@
 @ MSG_STR_SLASH		"/"
 @ MSG_STR_DYNAMIC	"(.dynamic)"
 @ MSG_STR_ORIGIN	"$ORIGIN"
+@ MSG_STR_MACHINE	"$MACHINE"
 @ MSG_STR_PLATFORM	"$PLATFORM"
 @ MSG_STR_ISALIST	"$ISALIST"
 @ MSG_STR_OSNAME	"$OSNAME"
@@ -747,6 +772,8 @@
 @ MSG_SCN_SUNWVERSION	".SUNW_version"
 @ MSG_SCN_SUNWVERSYM	".SUNW_versym"
 @ MSG_SCN_SUNWCAP	".SUNW_cap"
+@ MSG_SCN_SUNWCAPINFO	".SUNW_capinfo"
+@ MSG_SCN_SUNWCAPCHAIN	".SUNW_capchain"
 @ MSG_SCN_SYMTAB	".symtab"
 @ MSG_SCN_SYMTAB_SHNDX	".symtab_shndx"
 @ MSG_SCN_TBSS		".tbss"
@@ -860,6 +887,7 @@
 			 but no runpaths have been specified via %s"
 @ MSG_ARG_NOENTRY	"entry point symbol '%s' is undefined"
 @ MSG_ARG_UNSUPPORTED	"option %s is no longer supported; ignored"
+@ MSG_MARG_ONLY		"option %s can only be used with a %s"
 
 @ MSG_ARG_FLAGS		"flags processing errors"
 @ MSG_ARG_FILES		"file processing errors. No output written to %s"
@@ -1199,7 +1227,7 @@
 
 
 # Software identification.  Note, the SGU strings is historic, and has
-# little relevence.  It is preserved as applications have used this
+# little relevance.  It is preserved as applications have used this
 # string to identify the Solaris link-editor.
 
 @ MSG_SGS_ID		"ld: Software Generation Utilities - \
@@ -1222,6 +1250,7 @@
 @ MSG_STR_PATH		"%s/%s"
 @ MSG_STR_STRNL		"%s\n"
 @ MSG_STR_NL		"\n"
+@ MSG_STR_CAPGROUPID 	"CAP_GROUP_%d"
 
 @ MSG_STR_LD_DYNAMIC	"dynamic"
 @ MSG_STR_SYMBOLIC	"symbolic"
@@ -1243,7 +1272,6 @@
 @ MSG_STR_OPTIONS	"3:6:abc:d:e:f:h:il:mo:p:rstu:z:B:CD:F:GI:L:M:N:P:Q:R:\
 			 S:VW:Y:?"
 
-
 # Argument processing strings
 
 @ MSG_ARG_3		"-3"
@@ -1283,6 +1311,7 @@
 @ MSG_ARG_ZTEXTALL	"-z[text|textwarn|textoff]"
 @ MSG_ARG_ZLOADFLTR	"-zloadfltr"
 @ MSG_ARG_ZCOMBRELOC	"-zcombreloc"
+@ MSG_ARG_ZSYMBOLCAP	"-zsymbolcap"
 
 @ MSG_ARG_ABSEXEC	"absexec"
 @ MSG_ARG_ALTEXEC64	"altexec64"
@@ -1345,6 +1374,7 @@
 @ MSG_ARG_GROUP		"group"
 @ MSG_ARG_REDUCE	"reduce"
 @ MSG_ARG_STATIC	"static"
+@ MSG_ARG_SYMBOLCAP	"symbolcap"
 
 @ MSG_ARG_LCOM		"L,"
 @ MSG_ARG_PCOM		"P,"
--- a/usr/src/cmd/sgs/libld/common/machrel.amd.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c	Mon Mar 01 10:20:48 2010 -0800
@@ -780,12 +780,19 @@
 				 * Size relocations require the symbols size.
 				 */
 				value = sdp->sd_sym->st_size;
-			} else {
+
+			} else if ((sdp->sd_flags & FLG_SY_CAP) &&
+			    sdp->sd_aux && sdp->sd_aux->sa_PLTndx) {
 				/*
-				 * Else the value is the symbols value.
+				 * If this relocation is against a capabilities
+				 * symbol, then we need to jump to an associated
+				 * PLT, so that at runtime ld.so.1 is involved
+				 * to determine the best binding choice.
+				 * Otherwise, the value is the symbols value.
 				 */
+				value = ld_calc_plt_addr(sdp, ofl);
+			} else
 				value = sdp->sd_sym->st_value;
-			}
 
 			/*
 			 * Relocation against the GLOBAL_OFFSET_TABLE.
@@ -1097,9 +1104,11 @@
 			else
 				ofl->ofl_flags1 |= FLG_OF1_TLSOREL;
 		} else {
-			Os_desc	*osp = sdp->sd_isc->is_osdesc;
+			Os_desc *osp;
+			Is_desc *isp = sdp->sd_isc;
 
-			if (osp && ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
+			if (isp && ((osp = isp->is_osdesc) != NULL) &&
+			    ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
 				ofl->ofl_dynshdrcnt++;
 				osp->os_flags |= FLG_OS_OUTREL;
 			}
@@ -1580,6 +1589,8 @@
 			M_ID_ARRAY,		/* id_array */
 			M_ID_BSS,		/* id_bss */
 			M_ID_CAP,		/* id_cap */
+			M_ID_CAPINFO,		/* id_capinfo */
+			M_ID_CAPCHAIN,		/* id_capchain */
 			M_ID_DATA,		/* id_data */
 			M_ID_DYNAMIC,		/* id_dynamic */
 			M_ID_DYNSORT,		/* id_dynsort */
--- a/usr/src/cmd/sgs/libld/common/machrel.intel.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/machrel.intel.c	Mon Mar 01 10:20:48 2010 -0800
@@ -881,12 +881,20 @@
 				 * Size relocations require the symbols size.
 				 */
 				value = sdp->sd_sym->st_size;
-			} else {
+
+			} else if ((sdp->sd_flags & FLG_SY_CAP) &&
+			    sdp->sd_aux && sdp->sd_aux->sa_PLTndx) {
 				/*
-				 * Else the value is the symbols value.
+				 * If this relocation is against a capabilities
+				 * symbol, then we need to jump to an associated
+				 * PLT, so that at runtime ld.so.1 is involved
+				 * to determine the best binding choice.
+				 * Otherwise, the value is the symbols value.
 				 */
+				value = ld_calc_plt_addr(sdp, ofl);
+
+			} else
 				value = sdp->sd_sym->st_value;
-			}
 
 			/*
 			 * Relocation against the GLOBAL_OFFSET_TABLE.
@@ -1185,9 +1193,11 @@
 			else
 				ofl->ofl_flags1 |= FLG_OF1_TLSOREL;
 		} else {
-			Os_desc	*osp = sdp->sd_isc->is_osdesc;
+			Os_desc *osp;
+			Is_desc *isp = sdp->sd_isc;
 
-			if (osp && ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
+			if (isp && ((osp = isp->is_osdesc) != NULL) &&
+			    ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
 				ofl->ofl_dynshdrcnt++;
 				osp->os_flags |= FLG_OS_OUTREL;
 			}
@@ -1677,6 +1687,8 @@
 			M_ID_ARRAY,		/* id_array */
 			M_ID_BSS,		/* id_bss */
 			M_ID_CAP,		/* id_cap */
+			M_ID_CAPINFO,		/* id_capinfo */
+			M_ID_CAPCHAIN,		/* id_capchain */
 			M_ID_DATA,		/* id_data */
 			M_ID_DYNAMIC,		/* id_dynamic */
 			M_ID_DYNSORT,		/* id_dynsort */
--- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Mon Mar 01 10:20:48 2010 -0800
@@ -1174,12 +1174,20 @@
 				 * Size relocations require the symbols size.
 				 */
 				value = sdp->sd_sym->st_size;
-			} else {
+
+			} else if ((sdp->sd_flags & FLG_SY_CAP) &&
+			    sdp->sd_aux && sdp->sd_aux->sa_PLTndx) {
 				/*
-				 * Else the value is the symbols value.
+				 * If this relocation is against a capabilities
+				 * symbol, then we need to jump to an associated
+				 * PLT, so that at runtime ld.so.1 is involved
+				 * to determine the best binding choice.
+				 * Otherwise, the value is the symbols value.
 				 */
+				value = ld_calc_plt_addr(sdp, ofl);
+
+			} else
 				value = sdp->sd_sym->st_value;
-			}
 
 			/*
 			 * Relocation against the GLOBAL_OFFSET_TABLE.
@@ -1506,9 +1514,11 @@
 			else
 				ofl->ofl_flags1 |= FLG_OF1_TLSOREL;
 		} else {
-			Os_desc	*osp = sdp->sd_isc->is_osdesc;
+			Os_desc	*osp;
+			Is_desc	*isp = sdp->sd_isc;
 
-			if (osp && ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
+			if (isp && ((osp = isp->is_osdesc) != NULL) &&
+			    ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
 				ofl->ofl_dynshdrcnt++;
 				osp->os_flags |= FLG_OS_OUTREL;
 			}
@@ -2213,6 +2223,8 @@
 			M_ID_ARRAY,		/* id_array */
 			M_ID_BSS,		/* id_bss */
 			M_ID_CAP,		/* id_cap */
+			M_ID_CAPINFO,		/* id_capinfo */
+			M_ID_CAPCHAIN,		/* id_capchain */
 			M_ID_DATA,		/* id_data */
 			M_ID_DYNAMIC,		/* id_dynamic */
 			M_ID_DYNSORT,		/* id_dynsort */
--- a/usr/src/cmd/sgs/libld/common/map.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/map.c	Mon Mar 01 10:20:48 2010 -0800
@@ -43,11 +43,13 @@
 #include	"_libld.h"
 #include	"_map.h"
 
-
 /*
  * Process a hardware/software capabilities segment declaration definition.
  *	hwcap_1	= val,... [ OVERRIDE ]
  *	sfcap_1	= val,... [ OVERRIDE ]
+ *	hwcap_2	= val,... [ OVERRIDE ]
+ *	platcap	= name,... [ OVERRIDE ]
+ *	machcap	= name,... [ OVERRIDE ]
  *
  * The values can be defined as a list of machine specify tokens, or numerics.
  * Tokens are representations of the sys/auxv_$MACH.h capabilities, for example:
@@ -58,15 +60,15 @@
  * Or, the above two capabilities could be represented as V0x3.  Note, the
  * OVERRIDE flag is used to ensure that only those values provided via this
  * mapfile entry are recorded in the final image, ie. this overrides any
- * hardware capabilities that may be defined in the objects read as part of this
- * link-edit.  Specifying:
+ * hardware capabilities that may be defined in the objects read as part of
+ * this link-edit.  Specifying:
  *
  *	V0x0 OVERRIDE
  *
  * effectively removes any capabilities information from the final image.
  */
 static Boolean
-map_cap(Mapfile *mf, Word type, CapMask *capmask)
+map_cap(Mapfile *mf, Word type, Capmask *capmask)
 {
 	Token		tok;		/* Current token. */
 	Xword		number;
@@ -77,8 +79,8 @@
 
 	if (DBG_ENABLED) {
 		Dbg_cap_mapfile_title(ofl->ofl_lml, mf->mf_lineno);
-		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
-		    capmask, ld_targ.t_m.m_mach);
+		Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
+		    capmask->cm_val, ld_targ.t_m.m_mach);
 	}
 
 	while ((tok = ld_map_gettoken(mf, TK_F_STRLC, &tkv)) !=
@@ -137,17 +139,14 @@
 		return (TRUE);
 	}
 
-	Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, type, value,
-	    ld_targ.t_m.m_mach);
-	capmask->cm_value |= value;
+	DBG_CALL(Dbg_cap_val_entry(ofl->ofl_lml, DBG_STATE_NEW, type, value,
+	    ld_targ.t_m.m_mach));
+	capmask->cm_val |= value;
 
 	/* Sanity check the resulting bits */
 	if (!ld_map_cap_sanitize(mf, type, capmask))
 		return (FALSE);
 
-	DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, type,
-	    capmask, ld_targ.t_m.m_mach));
-
 	return (TRUE);
 }
 
@@ -1318,18 +1317,16 @@
 			if (strcmp(sgp1->sg_name,
 			    MSG_ORIG(MSG_STR_HWCAP_1)) == 0) {
 				if (!map_cap(mf, CA_SUNW_HW_1,
-				    &ofl->ofl_ocapset.c_hw_1))
+				    &ofl->ofl_ocapset.oc_hw_1))
 					return (FALSE);
 				continue;
-
 			}
 			if (strcmp(sgp1->sg_name,
 			    MSG_ORIG(MSG_STR_SFCAP_1)) == 0) {
 				if (!map_cap(mf, CA_SUNW_SF_1,
-				    &ofl->ofl_ocapset.c_sf_1))
+				    &ofl->ofl_ocapset.oc_sf_1))
 					return (FALSE);
 				continue;
-
 			}
 
 			/*
--- a/usr/src/cmd/sgs/libld/common/map_support.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/map_support.c	Mon Mar 01 10:20:48 2010 -0800
@@ -198,12 +198,14 @@
 		0, 			/* CA_SUNW_NULL */
 		FLG_OF1_OVHWCAP1,	/* CA_SUNW_HW_1 */
 		FLG_OF1_OVSFCAP1,	/* CA_SUNW_SF_1 */
-		FLG_OF1_OVHWCAP2	/* CA_SUNW_HW_2 */
+		FLG_OF1_OVHWCAP2,	/* CA_SUNW_HW_2 */
+		FLG_OF1_OVPLATCAP,	/* CA_SUNW_PLAT */
+		FLG_OF1_OVMACHCAP,	/* CA_SUNW_MACH */
+		FLG_OF1_OVIDCAP		/* CA_SUNW_ID */
 	};
-#if CA_SUNW_NUM != (CA_SUNW_HW_2 + 1)
+#if CA_SUNW_NUM != (CA_SUNW_ID + 1)
 #error "CA_SUNW_NUM has grown"
 #endif
-
 	mf->mf_ofl->ofl_flags1 |= override_flag[type];
 }
 
@@ -211,7 +213,7 @@
  * Sanity check the given capability bitmask.
  */
 Boolean
-ld_map_cap_sanitize(Mapfile *mf, Word type, CapMask *capmask)
+ld_map_cap_sanitize(Mapfile *mf, Word type, Capmask *capmask)
 {
 	elfcap_mask_t	mask;
 
@@ -224,16 +226,16 @@
 		 * as the bits can affect each others meaning (see sf1_cap()
 		 * in files.c).
 		 */
-		if ((mask = (capmask->cm_value & ~SF1_SUNW_MASK)) != 0) {
+		if ((mask = (capmask->cm_val & ~SF1_SUNW_MASK)) != 0) {
 			mf_warn(mf, MSG_INTL(MSG_MAP_BADSF1),
 			    EC_XWORD(mask));
-			capmask->cm_value &= SF1_SUNW_MASK;
+			capmask->cm_val &= SF1_SUNW_MASK;
 		}
-		if ((capmask->cm_value &
+		if ((capmask->cm_val &
 		    (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
 			mf_warn(mf, MSG_INTL(MSG_MAP_BADSF1),
 			    EC_XWORD(SF1_SUNW_FPUSED));
-			capmask->cm_value &= ~SF1_SUNW_FPUSED;
+			capmask->cm_val &= ~SF1_SUNW_FPUSED;
 		}
 #if	!defined(_ELF64)
 		/*
@@ -241,9 +243,9 @@
 		 * when building a 64-bit object.  Warn the user, and remove the
 		 * setting, if we're building a 32-bit object.
 		 */
-		if (capmask->cm_value & SF1_SUNW_ADDR32) {
+		if (capmask->cm_val & SF1_SUNW_ADDR32) {
 			mf_warn0(mf, MSG_INTL(MSG_MAP_INADDR32SF1));
-			capmask->cm_value &= ~SF1_SUNW_ADDR32;
+			capmask->cm_val &= ~SF1_SUNW_ADDR32;
 		}
 #endif
 	}
@@ -946,7 +948,7 @@
 	scope = ld_map_kwfind(scope_name, scope_list,
 	    SGSOFFSETOF(scope_t, name), sizeof (scope_list[0]));
 	if (scope == NULL) {
-		char buf[scope_list_bufsize];
+		char buf[VLA_SIZE(scope_list_bufsize)];
 
 		mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMSCOPE),
 		    ld_map_kwnames(scope_list, SGSOFFSETOF(scope_t, name),
--- a/usr/src/cmd/sgs/libld/common/map_v2.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/map_v2.c	Mon Mar 01 10:20:48 2010 -0800
@@ -219,11 +219,11 @@
 }
 
 /*
- * Apply one of the three equal tokens to a capabilities CapMask.
+ * Apply one of the three equal tokens to a capabilities Capmask.
  *
  * entry:
  *	mf - Mapfile descriptor
- *	capmask - Address of CapMask variable to alter
+ *	capmask - Address of Capmask variable to alter
  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
  *		the operation to carry out.
  *	type - Capability type (CA_SUNW_*)
@@ -234,34 +234,35 @@
  *	On success, returns TRUE (1), otherwise FALSE (0)
  */
 static Boolean
-set_capmask(Mapfile *mf, CapMask *capmask, Token eq_tok,
+set_capmask(Mapfile *mf, Capmask *capmask, Token eq_tok,
     Word type, elfcap_mask_t value, Boolean title)
 {
 	if (title)
 		DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml,
 		    mf->mf_lineno));
-	DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml, DBG_STATE_CURRENT,
-	    type, capmask, ld_targ.t_m.m_mach));
+	DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml, DBG_STATE_CURRENT,
+	    type, capmask->cm_val, ld_targ.t_m.m_mach));
 
 	switch (eq_tok) {
 	case TK_EQUAL:
-		capmask->cm_value = value;
-		capmask->cm_exclude = 0;
+		capmask->cm_val = value;
+		capmask->cm_exc = 0;
 		ld_map_cap_set_ovflag(mf, type);
-		DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
-		    DBG_STATE_RESET, type, capmask, ld_targ.t_m.m_mach));
+		DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
+		    DBG_STATE_RESET, type, capmask->cm_val,
+		    ld_targ.t_m.m_mach));
 		break;
 	case TK_PLUSEQ:
-		DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_ADD,
-		    type, value, ld_targ.t_m.m_mach));
-		capmask->cm_value |= value;
-		capmask->cm_exclude &= ~value;
+		DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
+		    DBG_STATE_ADD, type, value, ld_targ.t_m.m_mach));
+		capmask->cm_val |= value;
+		capmask->cm_exc &= ~value;
 		break;
 	case TK_MINUSEQ:
-		DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_EXCLUDE,
-		    type, value, ld_targ.t_m.m_mach));
-		capmask->cm_value &= ~value;
-		capmask->cm_exclude |= value;
+		DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
+		    DBG_STATE_EXCLUDE, type, value, ld_targ.t_m.m_mach));
+		capmask->cm_val &= ~value;
+		capmask->cm_exc |= value;
 		break;
 	default:
 		/*NOTREACHED*/
@@ -273,8 +274,159 @@
 		return (FALSE);
 
 	/* Report the final configuration */
-	DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
-	    DBG_STATE_RESOLVED, type, capmask, ld_targ.t_m.m_mach));
+	DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
+	    DBG_STATE_RESOLVED, type, capmask->cm_val, ld_targ.t_m.m_mach));
+
+	return (TRUE);
+}
+
+/*
+ * Apply one of the three equal tokens to a capabilities Caplist.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	caplist - Address of Caplist variable to alter
+ *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ *		the operation to carry out.
+ *	type - Capability type (CA_SUNW_*)
+ *	str - String for right hand side
+ *	title - True if a title is needed, False otherwise.
+ *
+ * exit:
+ *	On success, returns TRUE (1), otherwise FALSE (0)
+ */
+static Boolean
+set_capstr(Mapfile *mf, Caplist *caplist, Token eq_tok,
+    Word type, APlist *strs)
+{
+	Capstr		*capstr;
+	Aliste		idx1;
+	char		*str;
+
+	DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml, mf->mf_lineno));
+
+	if ((caplist->cl_val == NULL) || (alist_nitems(caplist->cl_val) == 0)) {
+		DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+		    DBG_STATE_CURRENT, type, NULL));
+	} else {
+		for (ALIST_TRAVERSE(caplist->cl_val, idx1, capstr)) {
+			DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+			    DBG_STATE_CURRENT, type, capstr->cs_str));
+		}
+	}
+
+	switch (eq_tok) {
+	case TK_EQUAL:
+		if (caplist->cl_val) {
+			(void) free(caplist->cl_val);
+			caplist->cl_val = NULL;
+		}
+		if (caplist->cl_exc) {
+			(void) free(caplist->cl_exc);
+			caplist->cl_exc = NULL;
+		}
+		if (strs) {
+			for (APLIST_TRAVERSE(strs, idx1, str)) {
+				if ((capstr = alist_append(&caplist->cl_val,
+				    NULL, sizeof (Capstr),
+				    AL_CNT_CAP_NAMES)) == NULL)
+					return (FALSE);
+				capstr->cs_str = str;
+				DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+				    DBG_STATE_RESET, type, capstr->cs_str));
+			}
+		} else {
+			DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+			    DBG_STATE_RESET, type, NULL));
+		}
+		ld_map_cap_set_ovflag(mf, type);
+		break;
+	case TK_PLUSEQ:
+		for (APLIST_TRAVERSE(strs, idx1, str)) {
+			Aliste		idx2;
+			const char	*ostr;
+			int		found = 0;
+
+			/*
+			 * Add this name to the list of names, provided the
+			 * name doesn't already exist.
+			 */
+			for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
+				if (strcmp(str, capstr->cs_str) == 0) {
+					found++;
+					break;
+				}
+			}
+			if ((found == 0) && ((capstr =
+			    (Capstr *)alist_append(&caplist->cl_val, NULL,
+			    sizeof (Capstr), AL_CNT_CAP_NAMES)) == NULL))
+				return (FALSE);
+			capstr->cs_str = str;
+
+			/*
+			 * Remove this name from the list of excluded names,
+			 * provided the name already exists.
+			 */
+			for (APLIST_TRAVERSE(caplist->cl_exc, idx2, ostr)) {
+				if (strcmp(str, ostr) == 0) {
+					aplist_delete(caplist->cl_exc, &idx2);
+					break;
+				}
+			}
+			DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+			    DBG_STATE_ADD, type, str));
+		}
+		break;
+	case TK_MINUSEQ:
+		for (APLIST_TRAVERSE(strs, idx1, str)) {
+			Aliste		idx2;
+			const char	*ostr;
+			int		found = 0;
+
+			/*
+			 * Delete this name from the list of names, provided
+			 * the name already exists.
+			 */
+			for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
+				if (strcmp(str, capstr->cs_str) == 0) {
+					alist_delete(caplist->cl_val, &idx2);
+					break;
+				}
+			}
+
+			/*
+			 * Add this name to the list of excluded names,
+			 * provided the name already exists.
+			 */
+			for (APLIST_TRAVERSE(caplist->cl_exc, idx2, ostr)) {
+				if (strcmp(str, ostr) == 0) {
+					found++;
+					break;
+				}
+			}
+			if ((found == 0) && (aplist_append(&caplist->cl_exc,
+			    str, AL_CNT_CAP_NAMES) == NULL))
+				return (FALSE);
+
+			DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+			    DBG_STATE_EXCLUDE, type, str));
+		}
+		break;
+	default:
+		/*NOTREACHED*/
+		assert(0);
+	}
+
+	/* Report the final configuration */
+	if ((caplist->cl_val == NULL) || (alist_nitems(caplist->cl_val) == 0)) {
+		DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+		    DBG_STATE_RESOLVED, type, NULL));
+	} else {
+		for (ALIST_TRAVERSE(caplist->cl_val, idx1, capstr)) {
+			DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
+			    DBG_STATE_RESOLVED, type, capstr->cs_str));
+		}
+	}
 
 	return (TRUE);
 }
@@ -555,7 +707,7 @@
 		default:
 		bad_attr:
 			{
-				char buf[attr_list_bufsize];
+				char buf[VLA_SIZE(attr_list_bufsize)];
 
 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ATTR),
 				    ld_map_kwnames(attr_list,
@@ -679,7 +831,7 @@
 		default:
 		bad_flag:
 			{
-				char buf[flag_list_bufsize];
+				char buf[VLA_SIZE(flag_list_bufsize)];
 
 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGFLAG),
 				    ld_map_kwnames(flag_list,
@@ -704,10 +856,9 @@
 #undef PF_STACK
 }
 
-
 /*
- * Parse one of the capabilities attributes that corresponds directly
- * to a capabilities bitmask value (HW_xxx, SF_xxx). Values can be
+ * Parse one of the capabilities attributes that corresponds directly to a
+ * capabilities bitmask value (CA_SUNW_HW_x, CA_SUNW_SF_xx).  Values can be
  * integers, or symbolic names that correspond to the capabilities mask
  * in question.
  *
@@ -715,7 +866,7 @@
  *	mf - Mapfile descriptor
  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
  *		the operation to carry out.
- *	capmask - CapMask from output descriptor for capability being processed.
+ *	capmask - Capmask from output descriptor for capability being processed.
  *	type - Capability type (CA_SUNW_*)
  *	elfcap_from_str_func - pointer to elfcap-string-to-value function
  *		for capability being processed.
@@ -724,7 +875,7 @@
  *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
  */
 static Token
-parse_cap_mask(Mapfile *mf, Token eq_tok, CapMask *capmask,
+parse_cap_mask(Mapfile *mf, Token eq_tok, Capmask *capmask,
     Word type, elfcap_from_str_func_t *elfcap_from_str_func)
 {
 	int		done;
@@ -770,56 +921,51 @@
 }
 
 /*
- * XXXRIEXXX
- *
- * This routine is the name version of parse_cap_mask. You need to
- * add the argument that corresponds to capmask. Also, remove the
- * ARGSUSED lint comment.
- */
-/*
  * Parse one of the capabilities attributes that manages lists of names
- * (CA_SUNW_PLATFORM, CA_SUNW_MACHINE).
+ * (CA_SUNW_PLAT and CA_SUNW_MACH).  Values are symbolic names that correspond
+ * to the capabilities mask in question.
  *
  * entry:
  *	mf - Mapfile descriptor
  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
  *		the operation to carry out.
+ *	caplist - Caplist from output descriptor for capability being processed.
  *	type - Capability type (CA_SUNW_*)
  *
  * exit:
  *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
  */
-/*ARGSUSED*/
 static Token
-parse_cap_list(Mapfile *mf, Token eq_tok, Word type)
+parse_cap_list(Mapfile *mf, Token eq_tok, Caplist *caplist,
+    Word type)
 {
-	int		done;
+	int		done, found;
 	Token		tok;
 	ld_map_tkval_t	tkv;
 	Conv_inv_buf_t	inv_buf;
-
-	/*
-	 * XXXRIEXXX
-	 *
-	 * If eq_tok is TK_EQUAL, you must clear the value and exclude lists,
-	 * and set the 'override' bit so that the capability from the input
-	 * objects is ignored. See set_capmask() for the logic used for
-	 * bitmasks.
-	 */
-	for (done = 0; done == 0; ) {
+	APlist		*strs = NULL;
+	Aliste		idx;
+	const char	*str;
+
+	for (done = 0, found = 0; done == 0; found = 0) {
 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
 		case TK_ERROR:
 			return (TK_ERROR);
 
 		case TK_STRING:
 			/*
-			 * XXXRIEXXX
-			 *
-			 * The name is in tkv.tkv_str. If eq_tok is TK_MINUSEQ,
-			 * you add the name to the exclude list, and remove it
-			 * from the value list. Otherwise, you add it to the
-			 * value list and remove it from the exclude list.
+			 * The name is in tkv.tkv_str.  Save this string for
+			 * set_capstr() processing, but remove any duplicates.
 			 */
+			for (APLIST_TRAVERSE(strs, idx, str)) {
+				if (strcmp(str, tkv.tkv_str) == 0) {
+					found++;
+					break;
+				}
+			}
+			if ((found == 0) && (aplist_append(&strs, tkv.tkv_str,
+			    AL_CNT_CAP_NAMES) == NULL))
+				return (TK_ERROR);
 			break;
 
 		case TK_SEMICOLON:
@@ -834,6 +980,8 @@
 		}
 	}
 
+	if (!set_capstr(mf, caplist, eq_tok, type, strs))
+		return (TK_ERROR);
 	return (tok);
 }
 
@@ -883,10 +1031,10 @@
 		}
 	}
 
-	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_1, eq_tok,
+	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_1, eq_tok,
 	    CA_SUNW_HW_1, hw1, TRUE))
 		return (TK_ERROR);
-	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_2, eq_tok,
+	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_2, eq_tok,
 	    CA_SUNW_HW_2, hw2, FALSE))
 		return (TK_ERROR);
 	return (tok);
@@ -900,7 +1048,7 @@
 static Token
 at_cap_hw_1(Mapfile *mf, Token eq_tok, void *uvalue)
 {
-	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_1,
+	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_hw_1,
 	    CA_SUNW_HW_1, elfcap_hw1_from_str));
 }
 
@@ -912,7 +1060,7 @@
 static Token
 at_cap_hw_2(Mapfile *mf, Token eq_tok, void *uvalue)
 {
-	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_2,
+	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_hw_2,
 	    CA_SUNW_HW_2, elfcap_hw2_from_str));
 }
 
@@ -957,7 +1105,7 @@
 		}
 	}
 
-	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_sf_1, eq_tok,
+	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_sf_1, eq_tok,
 	    CA_SUNW_SF_1, sf1, TRUE))
 		return (TK_ERROR);
 
@@ -972,7 +1120,7 @@
 static Token
 at_cap_sf_1(Mapfile *mf, Token eq_tok, void *uvalue)
 {
-	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_sf_1,
+	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_sf_1,
 	    CA_SUNW_SF_1, elfcap_sf1_from_str));
 }
 
@@ -984,14 +1132,8 @@
 static Token
 at_cap_mach(Mapfile *mf, Token eq_tok, void *uvalue)
 {
-	/*
-	 * XXXRIEXXX
-	 *
-	 * Add the missing argument, and replace the 0 with
-	 * CA_SUNW_MACH.
-	 */
-	return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
-	    /* CA_SUNW_MACH */0));
+	return (parse_cap_list(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_mach,
+	    CA_SUNW_MACH));
 }
 
 /*
@@ -1002,14 +1144,8 @@
 static Token
 at_cap_plat(Mapfile *mf, Token eq_tok, void *uvalue)
 {
-	/*
-	 * XXXRIEXXX
-	 *
-	 * Add the missing argument, and replace the 0 with
-	 * CA_SUNW_PLAT.
-	 */
-	return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
-	    /* CA_SUNW_PLAT */0));
+	return (parse_cap_list(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_plat,
+	    CA_SUNW_PLAT));
 }
 
 /*
@@ -1032,6 +1168,7 @@
 
 		{ MSG_ORIG(MSG_MAPKW_SF),	at_cap_sf, ATTR_FMT_EQ_ALL },
 		{ MSG_ORIG(MSG_MAPKW_SF_1),	at_cap_sf_1, ATTR_FMT_EQ_ALL },
+
 		/* List must be null terminated */
 		{ 0 }
 	};
@@ -1049,7 +1186,7 @@
 	    KW_NAME_SIZE(MSG_MAPKW_SF) +
 	    KW_NAME_SIZE(MSG_MAPKW_SF_1);
 
-	const char	*capid = NULL;
+	Capstr		*capstr;
 	Token		tok;
 	ld_map_tkval_t	tkv;
 	Conv_inv_buf_t	inv_buf;
@@ -1066,19 +1203,24 @@
 		return (TK_ERROR);
 
 	case TK_STRING:
+		capstr = &mf->mf_ofl->ofl_ocapset.oc_id;
+
 		/*
-		 * XXXRIEXXX
-		 *
-		 * The ID name is in tkv.tkv_str. It needs to be saved,
-		 * and eventually converted into a CA_SUNW_ID entry.
+		 * The ID name is in tkv.tkv_str.  Save this name in the output
+		 * capabilities structure.  Note, should multiple ID entries
+		 * be encounterd, the last entry wins.
 		 */
-		capid = tkv.tkv_str;
+		DBG_CALL(Dbg_cap_id(mf->mf_ofl->ofl_lml, mf->mf_lineno,
+		    capstr->cs_str, tkv.tkv_str));
+
+		capstr->cs_str = tkv.tkv_str;
+		mf->mf_ofl->ofl_ocapset.oc_flags |= FLG_OCS_USRDEFID;
 
 		/*
 		 * The name can be followed by an opening '{', or a
 		 * terminating ';'
 		 */
-		switch (tok = gettoken_optattr(mf, capid)) {
+		switch (tok = gettoken_optattr(mf, capstr->cs_str)) {
 		case TK_SEMICOLON:
 			return (TK_SEMICOLON);
 		case TK_LEFTBKT:
@@ -1497,7 +1639,7 @@
 		default:
 		bad_flag:
 			{
-				char buf[flag_list_bufsize];
+				char buf[VLA_SIZE(flag_list_bufsize)];
 
 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECFLAG),
 				    ld_map_kwnames(flag_list,
@@ -2687,7 +2829,7 @@
 		default:
 		bad_flag:
 			{
-				char buf[symflag_list_bufsize];
+				char buf[VLA_SIZE(symflag_list_bufsize)];
 
 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMFLAG),
 				    ld_map_kwnames(symflag_list,
@@ -2762,7 +2904,7 @@
 gts_efunc_at_sym_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
 {
 	Conv_inv_buf_t	inv_buf;
-	char		buf[at_sym_type_list_bufsize];
+	char		buf[VLA_SIZE(at_sym_type_list_bufsize)];
 
 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMTYPE),
 	    ld_map_kwnames(at_sym_type_list, SGSOFFSETOF(at_sym_type_t, name),
@@ -3165,7 +3307,7 @@
 		default:
 		bad_dirtok:
 			{
-				char buf[dirlist_bufsize];
+				char buf[VLA_SIZE(dirlist_bufsize)];
 
 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_DIR),
 				    ld_map_kwnames(dirlist,
--- a/usr/src/cmd/sgs/libld/common/place.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/place.c	Mon Mar 01 10:20:48 2010 -0800
@@ -595,7 +595,7 @@
 
 	/*
 	 * Define any sections that must be thought of as referenced.  These
-	 * sections may not be referenced externaly in a manner ld(1) can
+	 * sections may not be referenced externally in a manner ld(1) can
 	 * discover, but they must be retained (ie. not removed by -zignore).
 	 */
 	static const Msg RefSecs[] = {
@@ -614,7 +614,7 @@
 	DBG_CALL(Dbg_sec_in(ofl->ofl_lml, isp));
 
 	/*
-	 * If this section identfies group members, or this section indicates
+	 * If this section identifies group members, or this section indicates
 	 * that it is a member of a group, determine whether the section is
 	 * still required.
 	 */
--- a/usr/src/cmd/sgs/libld/common/relocate.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/relocate.c	Mon Mar 01 10:20:48 2010 -0800
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -282,7 +282,7 @@
 		 * either symbol.  Note, this test is very similar to the test
 		 * used in ld_sym_adjust_vis().
 		 */
-		if ((rlocal == TRUE) && ((tsdp->sd_flags & FLG_SY_HIDDEN) ||
+		if ((rlocal == TRUE) && (SYM_IS_HIDDEN(tsdp) ||
 		    (ELF_ST_BIND(tsdp->sd_sym->st_info) != STB_GLOBAL) ||
 		    ((ofl->ofl_flags & (FLG_OF_AUTOLCL | FLG_OF_AUTOELM)) &&
 		    ((tsdp->sd_flags & MSK_SY_NOAUTO) == 0))))
@@ -1201,7 +1201,7 @@
 	    ((ELF_ST_BIND(sdp->sd_sym->st_info) == STB_WEAK) ||
 	    (sdp->sd_flags & FLG_SY_WEAKDEF)) &&
 	    (!(sdp->sd_flags & FLG_SY_MVTOCOMM))) {
-		Sym_desc *	_sdp;
+		Sym_desc	*_sdp;
 
 		_sdp = sdp->sd_file->ifl_oldndx[sap->sa_linkndx];
 		if (_sdp->sd_ref != REF_DYN_SEEN)
@@ -1247,7 +1247,8 @@
 		} else if (!(flags & FLG_OF_RELOBJ) &&
 		    (IS_LOCALBND(rtype) || IS_SEG_RELATIVE(rtype))) {
 			local = TRUE;
-		} else if (sdp->sd_ref == REF_REL_NEED) {
+		} else if ((sdp->sd_ref == REF_REL_NEED) &&
+		    ((sdp->sd_flags & FLG_SY_CAP) == 0)) {
 			/*
 			 * Global symbols may have been individually reduced in
 			 * scope.  If the whole object is to be self contained,
@@ -1350,7 +1351,9 @@
 	if (local)
 		return ((*ld_targ.t_mr.mr_reloc_local)(reld, ofl));
 
-	if (IS_PLT(rtype) && ((flags & FLG_OF_BFLAG) == 0))
+	if ((IS_PLT(rtype) || ((sdp->sd_flags & FLG_SY_CAP) &&
+	    (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_FUNC))) &&
+	    ((flags & FLG_OF_BFLAG) == 0))
 		return (ld_reloc_plt(reld, ofl));
 
 	if ((sdp->sd_ref == REF_REL_NEED) ||
--- a/usr/src/cmd/sgs/libld/common/resolve.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/resolve.c	Mon Mar 01 10:20:48 2010 -0800
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -414,13 +414,26 @@
 
 		if (nsym->st_shndx == SHN_UNDEF) {
 			/*
-			 * If this is an undefined symbol it must be a
-			 * relocatable object overriding a shared object.  In
-			 * this case also override the reference name so that
-			 * any undefined symbol diagnostics will refer to the
-			 * relocatable object name.
+			 * If this is an undefined symbol, then we can only be
+			 * attempting to override an existing undefined symbol.
+			 * The original symbol is either:
+			 *
+			 *  -	a mapfile definition
+			 *  -	a previous relocatable object whose visibility
+			 *	or type should be overridden by this new symbol
+			 *  -	a previous shared object
+			 *
+			 * If the original undefined symbol stems from a mapfile
+			 * then don't alter the reference file name.  Should we
+			 * end up with some form of 'undefined' symbol error,
+			 * the characteristics of that error are most likely to
+			 * have originated from a mapfile.
+			 *
+			 * Otherwise, update the reference file name to indicate
+			 * this symbol.
 			 */
-			sdp->sd_aux->sa_rfile = ifl->ifl_name;
+			if ((sdp->sd_flags & FLG_SY_MAPREF) == 0)
+				sdp->sd_aux->sa_rfile = ifl->ifl_name;
 		} else {
 			/*
 			 * Under -Bnodirect, all exported interfaces that have
@@ -513,7 +526,9 @@
 {
 	Sym	*osym = sdp->sd_sym;
 	uchar_t	obind = ELF_ST_BIND(osym->st_info);
+	uchar_t	otype = ELF_ST_TYPE(osym->st_info);
 	uchar_t	nbind = ELF_ST_BIND(nsym->st_info);
+	uchar_t	ntype = ELF_ST_TYPE(nsym->st_info);
 
 	/*
 	 * If two relocatable objects define a weak and non-weak undefined
@@ -525,7 +540,7 @@
 	 * take the other.
 	 */
 	if (((obind == STB_WEAK) && (nbind != STB_WEAK)) ||
-	    (obind == STT_NOTYPE) && (nbind != STT_NOTYPE)) {
+	    (otype == STT_NOTYPE) && (ntype != STT_NOTYPE)) {
 		sym_override(sdp, nsym, ifl, ofl, ndx, nshndx, nsdflags);
 		return;
 	}
@@ -1079,6 +1094,7 @@
 {
 	int		row, column;		/* State table coordinates */
 	Sym		*osym = sdp->sd_sym;
+	sd_flag_t	osdflags = sdp->sd_flags;
 	Is_desc		*isp;
 	Half		vis = 0, nfile = ifl->ifl_ehdr->e_type;
 	Half		oref = sdp->sd_ref;
@@ -1086,7 +1102,7 @@
 	/*
 	 * Determine the original symbols definition (defines row in Action[]).
 	 */
-	if (sdp->sd_flags & FLG_SY_TENTSYM)
+	if (osdflags & FLG_SY_TENTSYM)
 		row = SYM_TENTATIVE;
 	else if ((sdp->sd_sym->st_shndx == SHN_UNDEF) ||
 	    (sdp->sd_sym->st_shndx == SHN_SUNW_IGNORE))
@@ -1243,6 +1259,12 @@
 			sdp->sd_flags |= FLG_SY_MAPUSED;
 	}
 
+	/*
+	 * Make sure any special symbol requirements are carried over.
+	 */
+	if ((osdflags & FLG_SY_CAP) || (nsdflags & FLG_SY_CAP))
+		sdp->sd_flags |= FLG_SY_CAP;
+
 	DBG_CALL(Dbg_syms_resolved(ofl, sdp));
 
 	return (1);
--- a/usr/src/cmd/sgs/libld/common/sections.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/sections.c	Mon Mar 01 10:20:48 2010 -0800
@@ -129,7 +129,7 @@
 		 * Global symbols can only be eliminated when the interfaces of
 		 * an object have been defined via versioning/scoping.
 		 */
-		if ((sdp->sd_flags & FLG_SY_HIDDEN) == 0)
+		if (!SYM_IS_HIDDEN(sdp))
 			return;
 
 		/*
@@ -568,13 +568,25 @@
 		SET_SEC_INFO_WORD_ALIGN(ELF_T_CAP, SHF_ALLOC, sizeof (Cap));
 		break;
 
+	case SHT_SUNW_capchain:
+		ofl->ofl_flags |= FLG_OF_OSABI;
+		SET_SEC_INFO_WORD_ALIGN(ELF_T_WORD, SHF_ALLOC,
+		    sizeof (Capchain));
+		break;
+
+	case SHT_SUNW_capinfo:
+		ofl->ofl_flags |= FLG_OF_OSABI;
+#if	_ELF64
+		SET_SEC_INFO(ELF_T_XWORD, sizeof (Xword), SHF_ALLOC,
+		    sizeof (Capinfo));
+#else
+		SET_SEC_INFO(ELF_T_WORD, sizeof (Word), SHF_ALLOC,
+		    sizeof (Capinfo));
+#endif
+		break;
+
 	case SHT_SUNW_move:
 		ofl->ofl_flags |= FLG_OF_OSABI;
-		/*
-		 * The sh_info field of the SHT_*_syminfo section points
-		 * to the header index of the associated .dynamic section,
-		 * so we also set SHF_INFO_LINK.
-		 */
 		SET_SEC_INFO(ELF_T_BYTE, sizeof (Lword),
 		    SHF_ALLOC | SHF_WRITE, sizeof (Move));
 		break;
@@ -1215,11 +1227,26 @@
 		}
 
 		/*
-		 * Any hardware/software capabilities?
+		 * Capabilities require a .dynamic entry for the .SUNW_cap
+		 * section.
 		 */
 		if (ofl->ofl_oscap)
 			cnt++;			/* SUNW_CAP */
 
+		/*
+		 * Symbol capabilities require a .dynamic entry for the
+		 * .SUNW_capinfo section.
+		 */
+		if (ofl->ofl_oscapinfo)
+			cnt++;			/* SUNW_CAPINFO */
+
+		/*
+		 * Capabilities chain information requires a .SUNW_capchain
+		 * entry, an entry size, and total size.
+		 */
+		if (ofl->ofl_oscapchain)
+			cnt += 3;		/* SUNW_CAPCHAIN/ENT/SZ */
+
 		if (flags & FLG_OF_SYMBOLIC)
 			cnt++;			/* SYMBOLIC */
 	}
@@ -1349,97 +1376,502 @@
 }
 
 /*
- * Output debugging information for the given capability mask.
+ * Common function used to build the SHT_SUNW_versym section, SHT_SUNW_syminfo
+ * section, and SHT_SUNW_capinfo section.  Each of these sections provide
+ * additional symbol information, and their size parallels the associated
+ * symbol table.
  */
-static void
-dbg_capmask(Ofl_desc *ofl, Word type, CapMask *capmask)
-{
-	/*
-	 * If this capability has excluded bits, then show the current
-	 * internal state. Otherwise, don't bother, because it's identical
-	 * to the final output value.
-	 */
-	if (capmask->cm_exclude)
-		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, type,
-		    capmask, ld_targ.t_m.m_mach);
-
-	Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_OUT, type,
-	    CAPMASK_VALUE(capmask), ld_targ.t_m.m_mach);
-}
-
-/*
- * Build a hardware/software capabilities section.
- */
-static uintptr_t
-make_cap(Ofl_desc *ofl)
+static Os_desc *
+make_sym_sec(Ofl_desc *ofl, const char *sectname, Word stype, int ident)
 {
 	Shdr		*shdr;
 	Elf_Data	*data;
 	Is_desc		*isec;
-	Os_desc		*osec;
-	Cap		*cap;
-	size_t		size = 0;
-	elfcap_mask_t	hw_1, sf_1;
-
-	/* Final capability masks with excluded bits removed */
-	hw_1 = CAPMASK_VALUE(&ofl->ofl_ocapset.c_hw_1);
-	sf_1 = CAPMASK_VALUE(&ofl->ofl_ocapset.c_sf_1);
+
+	/*
+	 * We don't know the size of this section yet, so set it to 0.  The
+	 * size gets filled in after the associated symbol table is sized.
+	 */
+	if (new_section(ofl, stype, sectname, 0, &isec, &shdr, &data) ==
+	    S_ERROR)
+		return ((Os_desc *)S_ERROR);
+
+	return (ld_place_section(ofl, isec, NULL, ident, NULL));
+}
+
+/*
+ * Determine whether a symbol capability is redundant because the object
+ * capabilities are more restrictive.
+ */
+inline static int
+is_cap_redundant(Objcapset *ocapset, Objcapset *scapset)
+{
+	Alist		*oalp, *salp;
+	elfcap_mask_t	omsk, smsk;
+
+	/*
+	 * Inspect any platform capabilities.  If the object defines platform
+	 * capabilities, then the object will only be loaded for those
+	 * platforms.  A symbol capability set that doesn't define the same
+	 * platforms is redundant, and a symbol capability that does not provide
+	 * at least one platform name that matches a platform name in the object
+	 * capabilities will never execute (as the object wouldn't have been
+	 * loaded).
+	 */
+	oalp = ocapset->oc_plat.cl_val;
+	salp = scapset->oc_plat.cl_val;
+	if (oalp && ((salp == NULL) || cap_names_match(oalp, salp)))
+		return (1);
+
+	/*
+	 * If the symbol capability set defines platforms, and the object
+	 * doesn't, then the symbol set is more restrictive.
+	 */
+	if (salp && (oalp == NULL))
+		return (0);
+
+	/*
+	 * Next, inspect any machine name capabilities.  If the object defines
+	 * machine name capabilities, then the object will only be loaded for
+	 * those machines.  A symbol capability set that doesn't define the same
+	 * machine names is redundant, and a symbol capability that does not
+	 * provide at least one machine name that matches a machine name in the
+	 * object capabilities will never execute (as the object wouldn't have
+	 * been loaded).
+	 */
+	oalp = ocapset->oc_plat.cl_val;
+	salp = scapset->oc_plat.cl_val;
+	if (oalp && ((salp == NULL) || cap_names_match(oalp, salp)))
+		return (1);
+
+	/*
+	 * If the symbol capability set defines machine names, and the object
+	 * doesn't, then the symbol set is more restrictive.
+	 */
+	if (salp && (oalp == NULL))
+		return (0);
+
+	/*
+	 * Next, inspect any hardware capabilities.  If the objects hardware
+	 * capabilities are greater than or equal to that of the symbols
+	 * capabilities, then the symbol capability set is redundant.  If the
+	 * symbols hardware capabilities are greater that the objects, then the
+	 * symbol set is more restrictive.
+	 *
+	 * Note that this is a somewhat arbitrary definition, as each capability
+	 * bit is independent of the others, and some of the higher order bits
+	 * could be considered to be less important than lower ones.  However,
+	 * this is the only reasonable non-subjective definition.
+	 */
+	omsk = ocapset->oc_hw_2.cm_val;
+	smsk = scapset->oc_hw_2.cm_val;
+	if ((omsk > smsk) || (omsk && (omsk == smsk)))
+		return (1);
+	if (omsk < smsk)
+		return (0);
+
+	/*
+	 * Finally, inspect the remaining hardware capabilities.
+	 */
+	omsk = ocapset->oc_hw_1.cm_val;
+	smsk = scapset->oc_hw_1.cm_val;
+	if ((omsk > smsk) || (omsk && (omsk == smsk)))
+		return (1);
+
+	return (0);
+}
+
+/*
+ * Capabilities values might have been assigned excluded values.  These
+ * excluded values should be removed before calculating any capabilities
+ * sections size.
+ */
+static void
+capmask_value(Lm_list *lml, Word type, Capmask *capmask, int *title)
+{
+	/*
+	 * First determine whether any bits should be excluded.
+	 */
+	if ((capmask->cm_val & capmask->cm_exc) == 0)
+		return;
+
+	DBG_CALL(Dbg_cap_post_title(lml, title));
+
+	DBG_CALL(Dbg_cap_val_entry(lml, DBG_STATE_CURRENT, type,
+	    capmask->cm_val, ld_targ.t_m.m_mach));
+	DBG_CALL(Dbg_cap_val_entry(lml, DBG_STATE_EXCLUDE, type,
+	    capmask->cm_exc, ld_targ.t_m.m_mach));
+
+	capmask->cm_val &= ~capmask->cm_exc;
+
+	DBG_CALL(Dbg_cap_val_entry(lml, DBG_STATE_RESOLVED, type,
+	    capmask->cm_val, ld_targ.t_m.m_mach));
+}
+
+static void
+capstr_value(Lm_list *lml, Word type, Caplist *caplist, int *title)
+{
+	Aliste	idx1, idx2;
+	char	*estr;
+	Capstr	*capstr;
+	Boolean	found = FALSE;
 
 	/*
-	 * Determine how many entries are required.
+	 * First determine whether any strings should be excluded.
+	 */
+	for (APLIST_TRAVERSE(caplist->cl_exc, idx1, estr)) {
+		for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
+			if (strcmp(estr, capstr->cs_str) == 0) {
+				found = TRUE;
+				break;
+			}
+		}
+	}
+
+	if (found == FALSE)
+		return;
+
+	/*
+	 * Traverse the current strings, then delete the excluded strings,
+	 * and finally display the resolved strings.
 	 */
-	if (hw_1)
-		size++;
-	if (sf_1)
-		size++;
-	if (size == 0)
-		return (1);
-	size++;				/* Add CA_SUNW_NULL */
-
+	if (DBG_ENABLED) {
+		Dbg_cap_post_title(lml, title);
+		for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
+			Dbg_cap_ptr_entry(lml, DBG_STATE_CURRENT, type,
+			    capstr->cs_str);
+		}
+	}
+	for (APLIST_TRAVERSE(caplist->cl_exc, idx1, estr)) {
+		for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
+			if (strcmp(estr, capstr->cs_str) == 0) {
+				DBG_CALL(Dbg_cap_ptr_entry(lml,
+				    DBG_STATE_EXCLUDE, type, capstr->cs_str));
+				alist_delete(caplist->cl_val, &idx2);
+				break;
+			}
+		}
+	}
 	if (DBG_ENABLED) {
-		Dbg_cap_out_title(ofl->ofl_lml);
-
-		if (hw_1)
-			dbg_capmask(ofl, CA_SUNW_HW_1,
-			    &ofl->ofl_ocapset.c_hw_1);
-
-		if (sf_1)
-			dbg_capmask(ofl, CA_SUNW_SF_1,
-			    &ofl->ofl_ocapset.c_sf_1);
+		for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
+			Dbg_cap_ptr_entry(lml, DBG_STATE_RESOLVED, type,
+			    capstr->cs_str);
+		}
+	}
+}
+
+/*
+ * Build a capabilities section.
+ */
+#define	CAP_UPDATE(cap, capndx, tag, val)	\
+	cap->c_tag = tag; \
+	cap->c_un.c_val = val; \
+	cap++, capndx++;
+
+static uintptr_t
+make_cap(Ofl_desc *ofl, Word shtype, const char *shname, int ident)
+{
+	Shdr		*shdr;
+	Elf_Data	*data;
+	Is_desc		*isec;
+	Cap		*cap;
+	size_t		size = 0;
+	Word		capndx = 0;
+	Str_tbl		*strtbl;
+	Objcapset	*ocapset = &ofl->ofl_ocapset;
+	Aliste		idx1;
+	Capstr		*capstr;
+	int		title = 0;
+
+	/*
+	 * Determine which string table to use for any CA_SUNW_MACH,
+	 * CA_SUNW_PLAT, or CA_SUNW_ID strings.
+	 */
+	if (OFL_IS_STATIC_OBJ(ofl))
+		strtbl = ofl->ofl_strtab;
+	else
+		strtbl = ofl->ofl_dynstrtab;
+
+	/*
+	 * If symbol capabilities have been collected, but no symbols are left
+	 * referencing these capabilities, promote the capability groups back
+	 * to an object capability definition.
+	 */
+	if ((ofl->ofl_flags & FLG_OF_OTOSCAP) && ofl->ofl_capsymcnt &&
+	    (ofl->ofl_capfamilies == NULL)) {
+		ld_cap_move_symtoobj(ofl);
+		ofl->ofl_capsymcnt = 0;
+		ofl->ofl_capgroups = NULL;
 	}
 
-
-	if (new_section(ofl, SHT_SUNW_cap, MSG_ORIG(MSG_SCN_SUNWCAP), size,
-	    &isec, &shdr, &data) == S_ERROR)
+	/*
+	 * Remove any excluded capabilities.
+	 */
+	capstr_value(ofl->ofl_lml, CA_SUNW_PLAT, &ocapset->oc_plat, &title);
+	capstr_value(ofl->ofl_lml, CA_SUNW_MACH, &ocapset->oc_mach, &title);
+	capmask_value(ofl->ofl_lml, CA_SUNW_HW_2, &ocapset->oc_hw_2, &title);
+	capmask_value(ofl->ofl_lml, CA_SUNW_HW_1, &ocapset->oc_hw_1, &title);
+	capmask_value(ofl->ofl_lml, CA_SUNW_SF_1, &ocapset->oc_sf_1, &title);
+
+	/*
+	 * Determine how many entries are required for any object capabilities.
+	 */
+	size += alist_nitems(ocapset->oc_plat.cl_val);
+	size += alist_nitems(ocapset->oc_mach.cl_val);
+	if (ocapset->oc_hw_2.cm_val)
+		size++;
+	if (ocapset->oc_hw_1.cm_val)
+		size++;
+	if (ocapset->oc_sf_1.cm_val)
+		size++;
+
+	/*
+	 * Only identify a capabilities group if the group has content.  If a
+	 * capabilities identifier exists, and no other capabilities have been
+	 * supplied, remove the identifier.  This scenario could exist if a
+	 * user mistakenly defined a lone identifier, or if an identified group
+	 * was overridden so as to clear the existing capabilities and the
+	 * identifier was not also cleared.
+	 */
+	if (ocapset->oc_id.cs_str) {
+		if (size)
+			size++;
+		else
+			ocapset->oc_id.cs_str = NULL;
+	}
+	if (size)
+		size++;			/* Add CA_SUNW_NULL */
+
+	/*
+	 * Determine how many entries are required for any symbol capabilities.
+	 */
+	if (ofl->ofl_capsymcnt) {
+		/*
+		 * If there are no object capabilities, a CA_SUNW_NULL entry
+		 * is required before any symbol capabilities.
+		 */
+		if (size == 0)
+			size++;
+		size += ofl->ofl_capsymcnt;
+	}
+
+	if (size == 0)
+		return (NULL);
+
+	if (new_section(ofl, shtype, shname, size, &isec,
+	    &shdr, &data) == S_ERROR)
 		return (S_ERROR);
 
 	if ((data->d_buf = libld_malloc(shdr->sh_size)) == NULL)
 		return (S_ERROR);
 
 	cap = (Cap *)data->d_buf;
-	if (hw_1) {
-		cap->c_tag = CA_SUNW_HW_1;
-		cap->c_un.c_val = hw_1;
-		cap++;
+
+	/*
+	 * Fill in any object capabilities.  If there is an identifier, then the
+	 * identifier comes first.  The remaining items follow in precedence
+	 * order, although the order isn't important for runtime verification.
+	 */
+	if (ocapset->oc_id.cs_str) {
+		ofl->ofl_flags |= FLG_OF_CAPSTRS;
+		if (st_insert(strtbl, ocapset->oc_id.cs_str) == -1)
+			return (S_ERROR);
+		ocapset->oc_id.cs_ndx = capndx;
+		CAP_UPDATE(cap, capndx, CA_SUNW_ID, 0);
+	}
+	if (ocapset->oc_plat.cl_val) {
+		ofl->ofl_flags |= (FLG_OF_PTCAP | FLG_OF_CAPSTRS);
+
+		/*
+		 * Insert any platform name strings in the appropriate string
+		 * table.  The capability value can't be filled in yet, as the
+		 * final offset of the strings isn't known until later.
+		 */
+		for (ALIST_TRAVERSE(ocapset->oc_plat.cl_val, idx1, capstr)) {
+			if (st_insert(strtbl, capstr->cs_str) == -1)
+				return (S_ERROR);
+			capstr->cs_ndx = capndx;
+			CAP_UPDATE(cap, capndx, CA_SUNW_PLAT, 0);
+		}
 	}
-	if (sf_1) {
-		cap->c_tag = CA_SUNW_SF_1;
-		cap->c_un.c_val = sf_1;
-		cap++;
+	if (ocapset->oc_mach.cl_val) {
+		ofl->ofl_flags |= (FLG_OF_PTCAP | FLG_OF_CAPSTRS);
+
+		/*
+		 * Insert the machine name strings in the appropriate string
+		 * table.  The capability value can't be filled in yet, as the
+		 * final offset of the strings isn't known until later.
+		 */
+		for (ALIST_TRAVERSE(ocapset->oc_mach.cl_val, idx1, capstr)) {
+			if (st_insert(strtbl, capstr->cs_str) == -1)
+				return (S_ERROR);
+			capstr->cs_ndx = capndx;
+			CAP_UPDATE(cap, capndx, CA_SUNW_MACH, 0);
+		}
 	}
-	cap->c_tag = CA_SUNW_NULL;
-	cap->c_un.c_val = 0;
+	if (ocapset->oc_hw_2.cm_val) {
+		ofl->ofl_flags |= FLG_OF_PTCAP;
+		CAP_UPDATE(cap, capndx, CA_SUNW_HW_2, ocapset->oc_hw_2.cm_val);
+	}
+	if (ocapset->oc_hw_1.cm_val) {
+		ofl->ofl_flags |= FLG_OF_PTCAP;
+		CAP_UPDATE(cap, capndx, CA_SUNW_HW_1, ocapset->oc_hw_1.cm_val);
+	}
+	if (ocapset->oc_sf_1.cm_val) {
+		ofl->ofl_flags |= FLG_OF_PTCAP;
+		CAP_UPDATE(cap, capndx, CA_SUNW_SF_1, ocapset->oc_sf_1.cm_val);
+	}
+	CAP_UPDATE(cap, capndx, CA_SUNW_NULL, 0);
 
 	/*
-	 * If we're not creating a relocatable object, save the output section
-	 * to trigger the creation of an associated program header.
+	 * Fill in any symbol capabilities.
 	 */
-	osec = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_cap, NULL);
-	if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)
-		ofl->ofl_oscap = osec;
-
-	return ((uintptr_t)osec);
+	if (ofl->ofl_capgroups) {
+		Cap_group	*cgp;
+
+		for (APLIST_TRAVERSE(ofl->ofl_capgroups, idx1, cgp)) {
+			Objcapset	*scapset = &cgp->cg_set;
+			Aliste		idx2;
+			Is_desc		*isp;
+
+			cgp->cg_ndx = capndx;
+
+			if (scapset->oc_id.cs_str) {
+				ofl->ofl_flags |= FLG_OF_CAPSTRS;
+				/*
+				 * Insert the identifier string in the
+				 * appropriate string table.  The capability
+				 * value can't be filled in yet, as the final
+				 * offset of the string isn't known until later.
+				 */
+				if (st_insert(strtbl,
+				    scapset->oc_id.cs_str) == -1)
+					return (S_ERROR);
+				scapset->oc_id.cs_ndx = capndx;
+				CAP_UPDATE(cap, capndx, CA_SUNW_ID, 0);
+			}
+
+			if (scapset->oc_plat.cl_val) {
+				ofl->ofl_flags |= FLG_OF_CAPSTRS;
+
+				/*
+				 * Insert the platform name string in the
+				 * appropriate string table.  The capability
+				 * value can't be filled in yet, as the final
+				 * offset of the string isn't known until later.
+				 */
+				for (ALIST_TRAVERSE(scapset->oc_plat.cl_val,
+				    idx2, capstr)) {
+					if (st_insert(strtbl,
+					    capstr->cs_str) == -1)
+						return (S_ERROR);
+					capstr->cs_ndx = capndx;
+					CAP_UPDATE(cap, capndx,
+					    CA_SUNW_PLAT, 0);
+				}
+			}
+			if (scapset->oc_mach.cl_val) {
+				ofl->ofl_flags |= FLG_OF_CAPSTRS;
+
+				/*
+				 * Insert the machine name string in the
+				 * appropriate string table.  The capability
+				 * value can't be filled in yet, as the final
+				 * offset of the string isn't known until later.
+				 */
+				for (ALIST_TRAVERSE(scapset->oc_mach.cl_val,
+				    idx2, capstr)) {
+					if (st_insert(strtbl,
+					    capstr->cs_str) == -1)
+						return (S_ERROR);
+					capstr->cs_ndx = capndx;
+					CAP_UPDATE(cap, capndx,
+					    CA_SUNW_MACH, 0);
+				}
+			}
+			if (scapset->oc_hw_2.cm_val) {
+				CAP_UPDATE(cap, capndx, CA_SUNW_HW_2,
+				    scapset->oc_hw_2.cm_val);
+			}
+			if (scapset->oc_hw_1.cm_val) {
+				CAP_UPDATE(cap, capndx, CA_SUNW_HW_1,
+				    scapset->oc_hw_1.cm_val);
+			}
+			if (scapset->oc_sf_1.cm_val) {
+				CAP_UPDATE(cap, capndx, CA_SUNW_SF_1,
+				    scapset->oc_sf_1.cm_val);
+			}
+			CAP_UPDATE(cap, capndx, CA_SUNW_NULL, 0);
+
+			/*
+			 * If any object capabilities are available, determine
+			 * whether these symbol capabilities are less
+			 * restrictive, and hence redundant.
+			 */
+			if (((ofl->ofl_flags & FLG_OF_PTCAP) == 0) ||
+			    (is_cap_redundant(ocapset, scapset) == 0))
+				continue;
+
+			/*
+			 * Indicate any files that provide redundant symbol
+			 * capabilities.
+			 */
+			for (APLIST_TRAVERSE(cgp->cg_secs, idx2, isp)) {
+				eprintf(ofl->ofl_lml, ERR_WARNING,
+				    MSG_INTL(MSG_CAP_REDUNDANT),
+				    isp->is_file->ifl_name,
+				    EC_WORD(isp->is_scnndx), isp->is_name);
+			}
+		}
+	}
+
+	/*
+	 * If capabilities strings are required, the sh_info field of the
+	 * section header will be set to the associated string table.
+	 */
+	if (ofl->ofl_flags & FLG_OF_CAPSTRS)
+		shdr->sh_flags |= SHF_INFO_LINK;
+
+	/*
+	 * Place these capabilities in the output file.
+	 */
+	if ((ofl->ofl_oscap = ld_place_section(ofl, isec,
+	    NULL, ident, NULL)) == (Os_desc *)S_ERROR)
+		return (S_ERROR);
+
+	/*
+	 * If symbol capabilities are required, then a .SUNW_capinfo section is
+	 * also created.  This table will eventually be sized to match the
+	 * associated symbol table.
+	 */
+	if (ofl->ofl_capfamilies) {
+		if ((ofl->ofl_oscapinfo = make_sym_sec(ofl,
+		    MSG_ORIG(MSG_SCN_SUNWCAPINFO), SHT_SUNW_capinfo,
+		    ld_targ.t_id.id_capinfo)) == (Os_desc *)S_ERROR)
+			return (S_ERROR);
+
+		/*
+		 * If we're generating a dynamic object, capabilities family
+		 * members are maintained in a .SUNW_capchain section.
+		 */
+		if (ofl->ofl_capchaincnt &&
+		    ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)) {
+			if (new_section(ofl, SHT_SUNW_capchain,
+			    MSG_ORIG(MSG_SCN_SUNWCAPCHAIN),
+			    ofl->ofl_capchaincnt, &isec, &shdr,
+			    &data) == S_ERROR)
+				return (S_ERROR);
+
+			ofl->ofl_oscapchain = ld_place_section(ofl, isec,
+			    NULL, ld_targ.t_id.id_capchain, NULL);
+			if (ofl->ofl_oscapchain == (Os_desc *)S_ERROR)
+				return (S_ERROR);
+
+		}
+	}
+	return (1);
 }
+#undef	CAP_UPDATE
 
 /*
  * Build the PLT section and its associated relocation entries.
@@ -1617,7 +2049,6 @@
 	return (1);
 }
 
-
 /*
  * Build a dynamic symbol table. These tables reside in the text
  * segment of a dynamic executable or shared library.
@@ -1893,7 +2324,6 @@
 		ofl->ofl_dynscopecnt++;
 	}
 
-
 	/*
 	 * Account for any local, named register symbols.  These locals are
 	 * required for reference from DT_REGISTER .dynamic entries.
@@ -1907,7 +2337,7 @@
 			if ((sdp = ofl->ofl_regsyms[ndx]) == NULL)
 				continue;
 
-			if (((sdp->sd_flags & FLG_SY_HIDDEN) == 0) &&
+			if (!SYM_IS_HIDDEN(sdp) &&
 			    (ELF_ST_BIND(sdp->sd_sym->st_info) != STB_LOCAL))
 				continue;
 
@@ -2145,29 +2575,6 @@
 }
 
 /*
- * Common function used to build both the SHT_SUNW_versym
- * section and the SHT_SUNW_syminfo section.  Each of these sections
- * provides additional symbol information.
- */
-static Os_desc *
-make_sym_sec(Ofl_desc *ofl, const char *sectname, Word stype, int ident)
-{
-	Shdr		*shdr;
-	Elf_Data	*data;
-	Is_desc		*isec;
-
-	/*
-	 * We don't know the size of this section yet, so set it to 0.
-	 * It gets filled in after the dynsym is sized.
-	 */
-	if (new_section(ofl, stype, sectname, 0, &isec, &shdr, &data) ==
-	    S_ERROR)
-		return ((Os_desc *)S_ERROR);
-
-	return (ld_place_section(ofl, isec, NULL, ident, NULL));
-}
-
-/*
  * This routine is called when -z nopartial is in effect.
  */
 uintptr_t
@@ -2314,7 +2721,7 @@
  *
  * exit:
  *	On success, rel_alpp and sym_alpp are updated, and
- *	any strings in the mergable input sections referenced by
+ *	any strings in the mergeable input sections referenced by
  *	a relocation has been entered into mstrtab. True (1) is returned.
  *
  *	On failure, False (0) is returned.
@@ -2446,7 +2853,7 @@
 	 * This routine has to make 3 passes:
 	 *
 	 *	1) Examine all relocations, insert strings from relocations
-	 *		to the mergable input sections into the string table.
+	 *		to the mergeable input sections into the string table.
 	 *	2) Modify the relocation values to be correct for the
 	 *		new merged section.
 	 *	3) Modify the symbols used by the relocations to reference
@@ -2691,9 +3098,16 @@
 	if (make_interp(ofl) == S_ERROR)
 		return (S_ERROR);
 
-	if (make_cap(ofl) == S_ERROR)
+	/*
+	 * Create a capabilities section if required.
+	 */
+	if (make_cap(ofl, SHT_SUNW_cap, MSG_ORIG(MSG_SCN_SUNWCAP),
+	    ld_targ.t_id.id_cap) == S_ERROR)
 		return (S_ERROR);
 
+	/*
+	 * Create any init/fini array sections.
+	 */
 	if (make_array(ofl, SHT_INIT_ARRAY, MSG_ORIG(MSG_SCN_INITARRAY),
 	    ofl->ofl_initarray) == S_ERROR)
 		return (S_ERROR);
@@ -2935,6 +3349,27 @@
 			update_data_size(ofl->ofl_ossyminfo, cnt);
 	}
 
+	/*
+	 * Now that we've created all output sections, adjust the size of the
+	 * SHT_SUNW_capinfo, which is dependent on the associated symbol table
+	 * size.
+	 */
+	if (ofl->ofl_oscapinfo) {
+		ulong_t	cnt;
+
+		/*
+		 * Symbol capabilities symbols are placed directly after the
+		 * STT_FILE symbol, section symbols, and any register symbols.
+		 * Effectively these are the first of any series of demoted
+		 * (scoped) symbols.
+		 */
+		if (OFL_IS_STATIC_OBJ(ofl))
+			cnt = SYMTAB_ALL_CNT(ofl);
+		else
+			cnt = DYNSYM_ALL_CNT(ofl);
+
+		update_data_size(ofl->ofl_oscapinfo, cnt);
+	}
 	return (1);
 }
 
--- a/usr/src/cmd/sgs/libld/common/support.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/support.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -216,8 +216,8 @@
 		 * hasn't nulled out data ld(1) will try and dereference.
 		 */
 		if ((npath != *opath) || (nfd != *ofd) || (nelf != *oelf)) {
-			Dbg_file_modified(ofl->ofl_lml, flp->fl_obj, *opath,
-			    npath, *ofd, nfd, *oelf, nelf);
+			DBG_CALL(Dbg_file_modified(ofl->ofl_lml, flp->fl_obj,
+			    *opath, npath, *ofd, nfd, *oelf, nelf));
 			if (npath)
 				*opath = npath;
 			if (nfile)
@@ -289,10 +289,11 @@
 		 * difference and return the new section header.
 		 */
 		if (nshdr != *oshdr) {
-			Dbg_shdr_modified(ofl->ofl_lml, flp->fl_obj,
-			    ifl->ifl_ehdr->e_ident[EI_OSABI],
-			    ifl->ifl_ehdr->e_machine, ndx, *oshdr, nshdr,
-			    sname);
+			Ehdr	*ehdr = ifl->ifl_ehdr;
+
+			DBG_CALL(Dbg_shdr_modified(ofl->ofl_lml, flp->fl_obj,
+			    ehdr->e_ident[EI_OSABI], ehdr->e_machine, ndx,
+			    *oshdr, nshdr, sname));
 			*oshdr = nshdr;
 		}
 	}
--- a/usr/src/cmd/sgs/libld/common/syms.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/syms.c	Mon Mar 01 10:20:48 2010 -0800
@@ -551,10 +551,10 @@
 	 * The `sa_dfiles' list is used to maintain the list of files that
 	 * define the same symbol.  This list can be used for two reasons:
 	 *
-	 *   -	To save the first definition of a symbol that is not available
+	 *  -	To save the first definition of a symbol that is not available
 	 *	for this link-edit.
 	 *
-	 *   -	To save all definitions of a symbol when the -m option is in
+	 *  -	To save all definitions of a symbol when the -m option is in
 	 *	effect.  This is optional as it is used to list multiple
 	 *	(interposed) definitions of a symbol (refer to ldmap_out()),
 	 *	and can be quite expensive.
@@ -674,7 +674,7 @@
 			 * should be defined protected, whereas all other
 			 * special symbols are tagged as no-direct.
 			 */
-			if (((usdp->sd_flags & FLG_SY_HIDDEN) == 0) &&
+			if (!SYM_IS_HIDDEN(usdp) &&
 			    (sdflags & FLG_SY_DEFAULT)) {
 				usdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
 				if (sdaux_id == SDAUX_ID_GOT) {
@@ -764,7 +764,7 @@
 		 * automatic scoping).  The GOT should be defined protected,
 		 * whereas all other special symbols are tagged as no-direct.
 		 */
-		if (((sdp->sd_flags & FLG_SY_HIDDEN) == 0) &&
+		if (!SYM_IS_HIDDEN(sdp) &&
 		    (sdflags & FLG_SY_DEFAULT)) {
 			sdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
 			if (sdaux_id == SDAUX_ID_GOT) {
@@ -941,6 +941,68 @@
 }
 
 /*
+ * Determine a potential capability symbol's visibility.
+ *
+ * The -z symbolcap option transforms an object capabilities relocatable object
+ * into a symbol capabilities relocatable object.  Any global function symbols,
+ * or initialized global data symbols are candidates for transforming into local
+ * symbol capabilities definitions.  However, if a user indicates that a symbol
+ * should be demoted to local using a mapfile, then there is no need to
+ * transform the associated global symbol.
+ *
+ * Normally, a symbol's visibility is determined after the symbol resolution
+ * process, after all symbol state has been gathered and resolved.  However,
+ * for -z symbolcap, this determination is too late.  When a global symbol is
+ * read from an input file we need to determine it's visibility so as to decide
+ * whether to create a local or not.
+ *
+ * If a user has explicitly defined this symbol as having local scope within a
+ * mapfile, then a symbol of the same name already exists.  However, explicit
+ * local definitions are uncommon, as most mapfiles define the global symbol
+ * requirements together with an auto-reduction directive '*'.  If this state
+ * has been defined, then we must make sure that the new symbol isn't a type
+ * that can not be demoted to local.
+ */
+static int
+sym_cap_vis(const char *name, Word hash, Sym *sym, Ofl_desc *ofl)
+{
+	Sym_desc	*sdp;
+	uchar_t		vis;
+	avl_index_t	where;
+	sd_flag_t	sdflags = 0;
+
+	/*
+	 * Determine the visibility of the new symbol.
+	 */
+	vis = ELF_ST_VISIBILITY(sym->st_other);
+	switch (vis) {
+	case STV_EXPORTED:
+		sdflags |= FLG_SY_EXPORT;
+		break;
+	case STV_SINGLETON:
+		sdflags |= FLG_SY_SINGLE;
+		break;
+	}
+
+	/*
+	 * Determine whether a symbol definition already exists, and if so
+	 * obtain the visibility.
+	 */
+	if ((sdp = ld_sym_find(name, hash, &where, ofl)) != NULL)
+		sdflags |= sdp->sd_flags;
+
+	/*
+	 * Determine whether the symbol flags indicate this symbol should be
+	 * hidden.
+	 */
+	if ((ofl->ofl_flags & (FLG_OF_AUTOLCL | FLG_OF_AUTOELM)) &&
+	    ((sdflags & MSK_SY_NOAUTO) == 0))
+		sdflags |= FLG_SY_HIDDEN;
+
+	return ((sdflags & FLG_SY_HIDDEN) == 0);
+}
+
+/*
  * This routine checks to see if a symbols visibility needs to be reduced to
  * either SYMBOLIC or LOCAL.  This routine can be called from either
  * reloc_init() or sym_validate().
@@ -955,10 +1017,7 @@
 	    (sdp->sd_sym->st_shndx != SHN_UNDEF)) {
 		/*
 		 * If auto-reduction/elimination is enabled, reduce any
-		 * non-versioned global symbols.  This routine is called either
-		 * from any initial relocation processing that references this
-		 * symbol, or from the symbol validation processing.
-		 *
+		 * non-versioned, and non-local capabilities global symbols.
 		 * A symbol is a candidate for auto-reduction/elimination if:
 		 *
 		 *  -	the symbol wasn't explicitly defined within a mapfile
@@ -1066,17 +1125,17 @@
  * counting has been carried out (ie. no more symbols will be read, generated,
  * or modified), validate and count the relevant entries:
  *
- *	-	check and print any undefined symbols remaining.  Note that
- *		if a symbol has been defined by virtue of the inclusion of
- *		an implicit shared library, it is still classed as undefined.
+ *  -	check and print any undefined symbols remaining.  Note that if a symbol
+ *	has been defined by virtue of the inclusion of 	an implicit shared
+ *	library, it is still classed as undefined.
  *
- * 	-	count the number of global needed symbols together with the
- *		size of their associated name strings (if scoping has been
- *		indicated these symbols may be reduced to locals).
+ *  -	count the number of global needed symbols together with the size of
+ *	their associated name strings (if scoping has been indicated these
+ *	symbols may be reduced to locals).
  *
- *	-	establish the size and alignment requirements for the global
- *		.bss section (the alignment of this section is based on the
- *		first symbol that it will contain).
+ *  -	establish the size and alignment requirements for the global .bss
+ *	section (the alignment of this section is based on the 	first symbol
+ *	that it will contain).
  */
 uintptr_t
 ld_sym_validate(Ofl_desc *ofl)
@@ -1093,8 +1152,7 @@
 	Xword		lbssalign = 0, lbsssize = 0;
 	Boolean		need_lbss;
 #endif
-	int		ret;
-	int		allow_ldynsym;
+	int		ret, allow_ldynsym;
 	uchar_t		type;
 
 	DBG_CALL(Dbg_basic_validate(ofl->ofl_lml));
@@ -1406,8 +1464,7 @@
 				if (sdp->sd_aux && sdp->sd_aux->sa_overndx)
 					sdp->sd_aux->sa_overndx = 0;
 			} else {
-				if ((!(sdp->sd_flags & FLG_SY_HIDDEN)) &&
-				    sdp->sd_aux &&
+				if (!SYM_IS_HIDDEN(sdp) && sdp->sd_aux &&
 				    (sdp->sd_aux->sa_overndx == 0)) {
 					sym_undef_entry(ofl, sdp, NOVERSION);
 					ofl->ofl_flags |= verdesc;
@@ -1438,8 +1495,7 @@
 		 */
 		if ((sym->st_shndx == SHN_COMMON) &&
 		    (((oflags & FLG_OF_RELOBJ) == 0) ||
-		    ((sdp->sd_flags & FLG_SY_HIDDEN) &&
-		    (oflags & FLG_OF_PROCRED)))) {
+		    (SYM_IS_HIDDEN(sdp) && (oflags & FLG_OF_PROCRED)))) {
 			if ((sdp->sd_move == NULL) ||
 			    ((sdp->sd_flags & FLG_SY_PAREXPN) == 0)) {
 				if (type != STT_TLS) {
@@ -1473,7 +1529,6 @@
 				lbssalign = sym->st_value;
 		}
 #endif
-
 		/*
 		 * If a symbol was referenced via the command line
 		 * (ld -u <>, ...), then this counts as a reference against the
@@ -1487,9 +1542,12 @@
 
 		/*
 		 * Update the symbol count and the associated name string size.
+		 * Note, a capabilities symbol must remain as visible as a
+		 * global symbol.  However, the runtime linker recognizes the
+		 * hidden requirement and ensures the symbol isn't made globally
+		 * available at runtime.
 		 */
-		if ((sdp->sd_flags & FLG_SY_HIDDEN) &&
-		    (oflags & FLG_OF_PROCRED)) {
+		if (SYM_IS_HIDDEN(sdp) && (oflags & FLG_OF_PROCRED)) {
 			/*
 			 * If any reductions are being processed, keep a count
 			 * of eliminated symbols, and if the symbol is being
@@ -1590,7 +1648,7 @@
 			if (sdp->sd_sym->st_name == 0)
 				sdp->sd_name = MSG_ORIG(MSG_STR_EMPTY);
 
-			if ((sdp->sd_flags & FLG_SY_HIDDEN) ||
+			if (SYM_IS_HIDDEN(sdp) ||
 			    (ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL))
 				ofl->ofl_lregsymcnt++;
 		}
@@ -1787,18 +1845,30 @@
 	ofl->ofl_flags |= flag;
 }
 
+/*
+ * Global symbols that are candidates for translation to local capability
+ * symbols under -z symbolcap, are maintained on a local symbol list.  Once
+ * all symbols of a file are processed, this list is traversed to cull any
+ * unnecessary weak symbol aliases.
+ */
+typedef struct {
+	Sym_desc	*c_nsdp;	/* new lead symbol */
+	Sym_desc	*c_osdp;	/* original symbol */
+	Cap_group	*c_group;	/* symbol capability group */
+	Word		c_ndx;		/* symbol index */
+} Cap_pair;
 
 /*
  * Process the symbol table for the specified input file.  At this point all
  * input sections from this input file have been assigned an input section
  * descriptor which is saved in the `ifl_isdesc' array.
  *
- *	-	local symbols are saved (as is) if the input file is a
- *		relocatable object
+ *  -	local symbols are saved (as is) if the input file is a 	relocatable
+ *	object
  *
- *	-	global symbols are added to the linkers internal symbol
- *		table if they are not already present, otherwise a symbol
- *		resolution function is called upon to resolve the conflict.
+ *  -	global symbols are added to the linkers internal symbol table if they
+ *	are not already present, otherwise a symbol resolution function is
+ *	called upon to resolve the conflict.
  */
 uintptr_t
 ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
@@ -1850,6 +1920,8 @@
 	Word		symsecndx;
 	avl_index_t	where;
 	int		test_gnu_hidden_bit, weak;
+	Cap_desc	*cdp = NULL;
+	Alist		*cappairs = NULL;
 
 	/*
 	 * Its possible that a file may contain more that one symbol table,
@@ -2240,6 +2312,15 @@
 	    (ifl->ifl_versym != NULL);
 
 	/*
+	 * Determine whether object capabilities for this file are being
+	 * converted into symbol capabilities.  If so, global function symbols,
+	 * and initialized global data symbols, need special translation and
+	 * processing.
+	 */
+	if ((etype == ET_REL) && (ifl->ifl_flags & FLG_IF_OTOSCAP))
+		cdp = ifl->ifl_caps;
+
+	/*
 	 * Now scan the global symbols entering them in the internal symbol
 	 * table or resolving them as necessary.
 	 */
@@ -2253,6 +2334,8 @@
 		Word		shndx;
 		int		shndx_bad = 0;
 		Sym		*nsym = sym;
+		Cap_pair	*cpp = NULL;
+		uchar_t		ntype;
 
 		/*
 		 * Determine and validate the associated section index.
@@ -2276,8 +2359,7 @@
 		}
 
 		/*
-		 * Now that we have the name, if the section index
-		 * was bad, report it.
+		 * Now that we have the name, report an erroneous section index.
 		 */
 		if (shndx_bad) {
 			eprintf(ofl->ofl_lml, ERR_WARNING,
@@ -2289,7 +2371,6 @@
 			continue;
 		}
 
-
 		/*
 		 * Test for the GNU hidden bit, and ignore symbols that
 		 * have it set.
@@ -2323,8 +2404,8 @@
 		 * The '-z wrap=XXX' option emulates the GNU ld --wrap=XXX
 		 * option. When XXX is the symbol to be wrapped:
 		 *
-		 * -	An undefined reference to XXX is converted to __wrap_XXX
-		 * -	An undefined reference to __real_XXX is converted to XXX
+		 *  -	An undefined reference to XXX is converted to __wrap_XXX
+		 *  -	An undefined reference to __real_XXX is converted to XXX
 		 *
 		 * The idea is that the user can supply a wrapper function
 		 * __wrap_XXX that does some work, and then uses the name
@@ -2424,13 +2505,107 @@
 		}
 
 		/*
+		 * If object capabilities for this file are being converted
+		 * into symbol capabilities, then:
+		 *
+		 *  -	Any global function, or initialized global data symbol
+		 *	definitions (ie., those that are not associated with
+		 *	special symbol types, ie., ABS, COMMON, etc.), and which
+		 *	have not been reduced to locals, are converted to symbol
+		 *	references (UNDEF).  This ensures that any reference to
+		 *	the original symbol, for example from a relocation, get
+		 *	associated to a capabilities family lead symbol, ie., a
+		 *	generic instance.
+		 *
+		 *  -	For each global function, or object symbol definition,
+		 *	a new local symbol is created.  The function or object
+		 *	is renamed using the capabilities CA_SUNW_ID definition
+		 *	(which might have been fabricated for this purpose -
+		 *	see get_cap_group()).  The new symbol name is:
+		 *
+		 *	    <original name>%<capability group identifier>
+		 *
+		 *	This symbol is associated to the same location, and
+		 *	becomes a capabilities family member.
+		 */
+		/* LINTED */
+		hash = (Word)elf_hash(name);
+
+		ntype = ELF_ST_TYPE(nsym->st_info);
+		if (cdp && (nsym->st_shndx != SHN_UNDEF) &&
+		    ((sdflags & FLG_SY_SPECSEC) == 0) &&
+		    ((ntype == STT_FUNC) || (ntype == STT_OBJECT))) {
+			/*
+			 * Determine this symbol's visibility.  If a mapfile has
+			 * indicated this symbol should be local, then there's
+			 * no point in transforming this global symbol to a
+			 * capabilities symbol.  Otherwise, create a symbol
+			 * capability pair descriptor to record this symbol as
+			 * a candidate for translation.
+			 */
+			if (sym_cap_vis(name, hash, sym, ofl) &&
+			    ((cpp = alist_append(&cappairs, NULL,
+			    sizeof (Cap_pair), AL_CNT_CAP_PAIRS)) == NULL))
+				return (S_ERROR);
+		}
+
+		if (cpp) {
+			Sym	*rsym;
+
+			DBG_CALL(Dbg_syms_cap_convert(ofl, ndx, name, nsym));
+
+			/*
+			 * Allocate a new symbol descriptor to represent the
+			 * transformed global symbol.  The descriptor points
+			 * to the original symbol information (which might
+			 * indicate a global or weak visibility).  The symbol
+			 * information will be transformed into a local symbol
+			 * later, after any weak aliases are culled.
+			 */
+			if ((cpp->c_osdp =
+			    libld_malloc(sizeof (Sym_desc))) == NULL)
+				return (S_ERROR);
+
+			cpp->c_osdp->sd_name = name;
+			cpp->c_osdp->sd_sym = nsym;
+			cpp->c_osdp->sd_shndx = shndx;
+			cpp->c_osdp->sd_file = ifl;
+			cpp->c_osdp->sd_isc = ifl->ifl_isdesc[shndx];
+			cpp->c_osdp->sd_ref = REF_REL_NEED;
+
+			/*
+			 * Save the capabilities group this symbol belongs to,
+			 * and the original symbol index.
+			 */
+			cpp->c_group = cdp->ca_groups->apl_data[0];
+			cpp->c_ndx = ndx;
+
+			/*
+			 * Replace the original symbol definition with a symbol
+			 * reference.  Make sure this reference isn't left as a
+			 * weak.
+			 */
+			if ((rsym = libld_malloc(sizeof (Sym))) == NULL)
+				return (S_ERROR);
+
+			*rsym = *nsym;
+
+			rsym->st_info = ELF_ST_INFO(STB_GLOBAL, ntype);
+			rsym->st_shndx = shndx = SHN_UNDEF;
+			rsym->st_value = 0;
+			rsym->st_size = 0;
+
+			sdflags |= FLG_SY_CAP;
+
+			nsym = rsym;
+		}
+
+		/*
 		 * If the symbol does not already exist in the internal symbol
 		 * table add it, otherwise resolve the conflict.  If the symbol
 		 * from this file is kept, retain its symbol table index for
 		 * possible use in associating a global alias.
 		 */
-		/* LINTED */
-		hash = (Word)elf_hash((const char *)name);
 		if ((sdp = ld_sym_find(name, hash, &where, ofl)) == NULL) {
 			DBG_CALL(Dbg_syms_global(ofl->ofl_lml, ndx, name));
 			if ((sdp = ld_sym_enter(name, nsym, hash, ifl, ofl, ndx,
@@ -2442,6 +2617,13 @@
 			return (S_ERROR);
 
 		/*
+		 * Now that we have a symbol descriptor, retain the descriptor
+		 * for later use by symbol capabilities processing.
+		 */
+		if (cpp)
+			cpp->c_nsdp = sdp;
+
+		/*
 		 * After we've compared a defined symbol in one shared
 		 * object, flag the symbol so we don't compare it again.
 		 */
@@ -2504,7 +2686,7 @@
 
 	/*
 	 * Associate weak (alias) symbols to their non-weak counterparts by
-	 * scaning the global symbols one more time.
+	 * scanning the global symbols one more time.
 	 *
 	 * This association is needed when processing the symbols from a shared
 	 * object dependency when a a weak definition satisfies a reference:
@@ -2650,6 +2832,155 @@
 			}
 		}
 	}
+
+	/*
+	 * Having processed all symbols, under -z symbolcap, reprocess any
+	 * symbols that are being translated from global to locals.  The symbol
+	 * pair that has been collected defines the original symbol (c_osdp),
+	 * which will become a local, and the new symbol (c_nsdp), which will
+	 * become a reference (UNDEF) for the original.
+	 *
+	 * Scan these symbol pairs looking for weak symbols, which have non-weak
+	 * aliases.  There is no need to translate both of these symbols to
+	 * locals, only the global is necessary.
+	 */
+	if (cappairs) {
+		Aliste		idx1;
+		Cap_pair	*cpp1;
+
+		for (ALIST_TRAVERSE(cappairs, idx1, cpp1)) {
+			Sym_desc	*sdp1 = cpp1->c_osdp;
+			Sym		*sym1 = sdp1->sd_sym;
+			uchar_t		bind1 = ELF_ST_BIND(sym1->st_info);
+			Aliste		idx2;
+			Cap_pair	*cpp2;
+
+			/*
+			 * If this symbol isn't weak, it's capability member is
+			 * retained for the creation of a local symbol.
+			 */
+			if (bind1 != STB_WEAK)
+				continue;
+
+			/*
+			 * If this is a weak symbol, traverse the capabilities
+			 * list again to determine if a corresponding non-weak
+			 * symbol exists.
+			 */
+			for (ALIST_TRAVERSE(cappairs, idx2, cpp2)) {
+				Sym_desc	*sdp2 = cpp2->c_osdp;
+				Sym		*sym2 = sdp2->sd_sym;
+				uchar_t		bind2 =
+				    ELF_ST_BIND(sym2->st_info);
+
+				if ((cpp1 == cpp2) ||
+				    (cpp1->c_group != cpp2->c_group) ||
+				    (sym1->st_value != sym2->st_value) ||
+				    (bind2 == STB_WEAK))
+					continue;
+
+				/*
+				 * The weak symbol (sym1) has a non-weak (sym2)
+				 * counterpart.  There's no point in translating
+				 * both of these equivalent symbols to locals.
+				 * Add this symbol capability alias to the
+				 * capabilities family information, and remove
+				 * the weak symbol.
+				 */
+				if (ld_cap_add_family(ofl, cpp2->c_nsdp,
+				    cpp1->c_nsdp, NULL, NULL) == S_ERROR)
+					return (S_ERROR);
+
+				free((void *)cpp1->c_osdp);
+				(void) alist_delete(cappairs, &idx1);
+			}
+		}
+
+		DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
+
+		/*
+		 * The capability pairs information now represents all the
+		 * global symbols that need transforming to locals.  These
+		 * local symbols are renamed using their group identifiers.
+		 */
+		for (ALIST_TRAVERSE(cappairs, idx1, cpp1)) {
+			Sym_desc	*osdp = cpp1->c_osdp;
+			Objcapset	*capset;
+			size_t		nsize, tsize;
+			const char	*oname;
+			char		*cname, *idstr;
+			Sym		*csym;
+
+			/*
+			 * If the local symbol has not yet been translated
+			 * convert it to a local symbol with a name.
+			 */
+			if ((osdp->sd_flags & FLG_SY_CAP) != 0)
+				continue;
+
+			/*
+			 * As we're converting object capabilities to symbol
+			 * capabilities, obtain the capabilities set for this
+			 * object, so as to retrieve the CA_SUNW_ID value.
+			 */
+			capset = &cpp1->c_group->cg_set;
+
+			/*
+			 * Create a new name from the existing symbol and the
+			 * capabilities group identifier.  Note, the delimiter
+			 * between the symbol name and identifier name is hard-
+			 * coded here (%), so that we establish a convention
+			 * for transformed symbol names.
+			 */
+			oname = osdp->sd_name;
+
+			idstr = capset->oc_id.cs_str;
+			nsize = strlen(oname);
+			tsize = nsize + 1 + strlen(idstr) + 1;
+			if ((cname = libld_malloc(tsize)) == 0)
+				return (S_ERROR);
+
+			(void) strcpy(cname, oname);
+			cname[nsize++] = '%';
+			(void) strcpy(&cname[nsize], idstr);
+
+			/*
+			 * Allocate a new symbol table entry, transform this
+			 * symbol to a local, and assign the new name.
+			 */
+			if ((csym = libld_malloc(sizeof (Sym))) == NULL)
+				return (S_ERROR);
+
+			*csym = *osdp->sd_sym;
+			csym->st_info = ELF_ST_INFO(STB_LOCAL,
+			    ELF_ST_TYPE(osdp->sd_sym->st_info));
+
+			osdp->sd_name = cname;
+			osdp->sd_sym = csym;
+			osdp->sd_flags = FLG_SY_CAP;
+
+			/*
+			 * Keep track of this new local symbol.  As -z symbolcap
+			 * can only be used to create a relocatable object, a
+			 * dynamic symbol table can't exist.  Ensure there is
+			 * space reserved in the string table.
+			 */
+			ofl->ofl_caploclcnt++;
+			if (st_insert(ofl->ofl_strtab, cname) == -1)
+				return (S_ERROR);
+
+			DBG_CALL(Dbg_syms_cap_local(ofl, cpp1->c_ndx,
+			    cname, csym, osdp));
+
+			/*
+			 * Establish this capability pair as a family.
+			 */
+			if (ld_cap_add_family(ofl, cpp1->c_nsdp, osdp,
+			    cpp1->c_group, &ifl->ifl_caps->ca_syms) == S_ERROR)
+				return (S_ERROR);
+		}
+	}
+
 	return (1);
 
 #undef SYM_LOC_BADADDR
@@ -2657,7 +2988,7 @@
 
 /*
  * Add an undefined symbol to the symbol table.  The reference originates from
- * the location identifed by the message id (mid).  These references can
+ * the location identified by the message id (mid).  These references can
  * originate from command line options such as -e, -u, -initarray, etc.
  * (identified with MSG_INTL(MSG_STR_COMMAND)), or from internally generated
  * TLS relocation references (identified with MSG_INTL(MSG_STR_TLSREL)).
@@ -2754,7 +3085,7 @@
  * intervenes, we will reuse the string.
  *
  * entry:
- *	isc - Input section assocated with the symbol.
+ *	isc - Input section associated with the symbol.
  *	fmt - NULL, or format string to use.
  *
  * exit:
--- a/usr/src/cmd/sgs/libld/common/update.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/update.c	Mon Mar 01 10:20:48 2010 -0800
@@ -130,7 +130,6 @@
 	}
 }
 
-
 /*
  * Build and update any output symbol tables.  Here we work on all the symbol
  * tables at once to reduce the duplication of symbol and string manipulation.
@@ -168,10 +167,9 @@
 			_dynsort_arr = NULL; \
 		} \
 		if ((_dynsort_arr != NULL) && DYNSORT_TEST_ATTR(_sdp, _sym)) \
-			_dynsort_arr[(*_dynsort_ndx)++] = _sym_ndx; \
+		    _dynsort_arr[(*_dynsort_ndx)++] = _sym_ndx; \
 	}
 
-
 	Sym_desc	*sdp;
 	Sym_avlnode	*sav;
 	Sg_desc		*sgp, *tsgp = NULL, *dsgp = NULL, *esgp = NULL;
@@ -218,7 +216,6 @@
 	Word		*hashtab;	/* hash table pointer */
 	Word		*hashbkt;	/* hash table bucket pointer */
 	Word		*hashchain;	/* hash table chain pointer */
-	Word		hashval;	/* value of hash function */
 	Wk_desc		*wkp;
 	Alist		*weak = NULL;
 	ofl_flag_t	flags = ofl->ofl_flags;
@@ -373,7 +370,7 @@
 	if (DBG_ENABLED) {
 		if ((ofl->ofl_gottable = gottable =
 		    libld_calloc(ofl->ofl_gotcnt, sizeof (Gottable))) == NULL)
-		return ((Addr)S_ERROR);
+			return ((Addr)S_ERROR);
 	}
 
 	/*
@@ -485,7 +482,7 @@
 			if ((rsdp = ofl->ofl_regsyms[ndx]) == NULL)
 				continue;
 
-			if (((rsdp->sd_flags & FLG_SY_HIDDEN) == 0) &&
+			if (!SYM_IS_HIDDEN(rsdp) &&
 			    (ELF_ST_BIND(rsdp->sd_sym->st_info) != STB_LOCAL))
 				continue;
 
@@ -630,7 +627,8 @@
 	 * assigning a new virtual address or displacement (value).
 	 */
 	for (APLIST_TRAVERSE(ofl->ofl_objs, idx1, ifl)) {
-		Xword	lndx, local = ifl->ifl_locscnt;
+		Xword		lndx, local = ifl->ifl_locscnt;
+		Cap_desc	*cdp = ifl->ifl_caps;
 
 		for (lndx = 1; lndx < local; lndx++) {
 			Gotndx		*gnp;
@@ -697,7 +695,6 @@
 			if (ifl != sdp->sd_file)
 				continue;
 
-
 			/*
 			 * Generate an output symbol to represent this input
 			 * symbol.  Even if the symbol table is to be stripped
@@ -716,6 +713,7 @@
 				if (!dynsym)
 					sdp->sd_symndx = *symndx;
 				symtab[symtab_ndx] = *sym;
+
 				/*
 				 * Provided this isn't an unnamed register
 				 * symbol, update its name.
@@ -798,7 +796,7 @@
 			 * If this isn't an UNDEF symbol (ie. an input section
 			 * is associated), update the symbols value and index.
 			 */
-			if (((isc = sdp->sd_isc) != 0) && !update_done) {
+			if (((isc = sdp->sd_isc) != NULL) && !update_done) {
 				Word	sectndx;
 
 				osp = isc->is_osdesc;
@@ -852,7 +850,53 @@
 				ldynsym_ndx++;
 			}
 		}
+
+		/*
+		 * If this input file has undergone object to symbol
+		 * capabilities conversion, supply any new capabilities symbols.
+		 * These symbols are copies of the original global symbols, and
+		 * follow the existing local symbols that are supplied from this
+		 * input file (which are identified with a preceding STT_FILE).
+		 */
+		if (symtab && cdp && cdp->ca_syms) {
+			Aliste		idx2;
+			Cap_sym		*csp;
+
+			for (APLIST_TRAVERSE(cdp->ca_syms, idx2, csp)) {
+				Is_desc	*isp;
+
+				sdp = csp->cs_sdp;
+				sym = sdp->sd_sym;
+
+				if ((isp = sdp->sd_isc) != NULL) {
+					Os_desc	*osp = isp->is_osdesc;
+
+					/*
+					 * Update the symbols value.
+					 */
+					/* LINTED */
+					sym->st_value +=
+					    (Off)_elf_getxoff(isp->is_indata);
+					if ((flags & FLG_OF_RELOBJ) == 0)
+						sym->st_value +=
+						    osp->os_shdr->sh_addr;
+
+					/*
+					 * Update the symbols section index.
+					 */
+					sdp->sd_shndx = sym->st_shndx =
+					    elf_ndxscn(osp->os_scn);
+				}
+
+				symtab[symtab_ndx] = *sym;
+				(void) st_setstring(strtab, sdp->sd_name,
+				    &stoff);
+				symtab[symtab_ndx].st_name = stoff;
+				sdp->sd_symndx = symtab_ndx++;
+			}
+		}
 	}
+
 	symtab_gbl_bndx = symtab_ndx;	/* .symtab index of 1st global entry */
 
 	/*
@@ -921,7 +965,6 @@
 		lbssndx = elf_ndxscn(osp->os_scn);
 	}
 #endif
-
 	/*
 	 * Assign .tlsbss information for use with updating COMMON symbols.
 	 */
@@ -972,7 +1015,7 @@
 		if (sdp->sd_ref == REF_DYN_SEEN)
 			continue;
 
-		if ((sdp->sd_flags & FLG_SY_HIDDEN) && (flags & FLG_OF_PROCRED))
+		if (SYM_IS_HIDDEN(sdp) && (flags & FLG_OF_PROCRED))
 			local = 1;
 		else
 			local = 0;
@@ -1082,6 +1125,52 @@
 		}
 	}
 
+	/*
+	 * If this is a dynamic object then add any local capabilities symbols.
+	 */
+	if (dynsym && ofl->ofl_capfamilies) {
+		Cap_avlnode	*cav;
+
+		for (cav = avl_first(ofl->ofl_capfamilies); cav;
+		    cav = AVL_NEXT(ofl->ofl_capfamilies, cav)) {
+			Cap_sym		*csp;
+			Aliste		idx;
+
+			for (APLIST_TRAVERSE(cav->cn_members, idx, csp)) {
+				sdp = csp->cs_sdp;
+
+				DBG_CALL(Dbg_syms_created(ofl->ofl_lml,
+				    sdp->sd_name));
+				DBG_CALL(Dbg_syms_entered(ofl, sdp->sd_sym,
+				    sdp));
+
+				dynsym[dynsym_ndx] = *sdp->sd_sym;
+
+				(void) st_setstring(dynstr, sdp->sd_name,
+				    &stoff);
+				dynsym[dynsym_ndx].st_name = stoff;
+
+				sdp->sd_sym = &dynsym[dynsym_ndx];
+				sdp->sd_symndx = dynsym_ndx;
+
+				/*
+				 * Indicate that this is a capabilities symbol.
+				 * Note, that this identification only provides
+				 * information regarding the symbol that is
+				 * visible from elfdump(1) -y.  The association
+				 * of a symbol to its capabilities is derived
+				 * from a .SUNW_capinfo entry.
+				 */
+				if (syminfo) {
+					syminfo[dynsym_ndx].si_flags |=
+					    SYMINFO_FLG_CAP;
+				}
+
+				dynsym_ndx++;
+			}
+		}
+	}
+
 	if (ofl->ofl_hashbkts) {
 		qsort(sorted_syms + ofl->ofl_scopecnt + ofl->ofl_elimcnt,
 		    ofl->ofl_globcnt, sizeof (Sym_s_list),
@@ -1131,15 +1220,13 @@
 			}
 		}
 
-
 		/*
 		 * If this symbol has been marked as being reduced to local
 		 * scope then it will have to be placed in the scoped portion
 		 * of the .symtab.  Retain the appropriate index for use in
 		 * version symbol indexing and relocation.
 		 */
-		if ((sdp->sd_flags & FLG_SY_HIDDEN) &&
-		    (flags & FLG_OF_PROCRED)) {
+		if (SYM_IS_HIDDEN(sdp) && (flags & FLG_OF_PROCRED)) {
 			local = 1;
 			if (!(sdp->sd_flags & FLG_SY_ELIM) && !dynsym)
 				sdp->sd_symndx = scopesym_ndx;
@@ -1177,12 +1264,11 @@
 			if (sdp->sd_flags & FLG_SY_MVTOCOMM) {
 				vndx = VER_NDX_GLOBAL;
 			} else if (sdp->sd_ref == REF_REL_NEED) {
-				sd_flag_t	sdflags = sdp->sd_flags;
-
 				vndx = sap->sa_overndx;
+
 				if ((vndx == 0) &&
 				    (sdp->sd_sym->st_shndx != SHN_UNDEF)) {
-					if (sdflags & FLG_SY_HIDDEN)
+					if (SYM_IS_HIDDEN(sdp))
 						vndx = VER_NDX_LOCAL;
 					else
 						vndx = VER_NDX_GLOBAL;
@@ -1293,7 +1379,7 @@
 				 * An auxiliary filter definition.  By nature,
 				 * this definition is direct, in that should the
 				 * filtee lookup fail, we'll fall back to this
-				 * object.  It may still be necesssary to
+				 * object.  It may still be necessary to
 				 * prevent external direct bindings.
 				 */
 				syminfo[ndx].si_flags |= SYMINFO_FLG_AUXILIARY;
@@ -1348,6 +1434,20 @@
 					syminfo[ndx].si_boundto =
 					    SYMINFO_BT_SELF;
 				}
+
+				/*
+				 * Indicate that this is a capabilities symbol.
+				 * Note, that this identification only provides
+				 * information regarding the symbol that is
+				 * visible from elfdump(1) -y.  The association
+				 * of a symbol to its capabilities is derived
+				 * from a .SUNW_capinfo entry.
+				 */
+				if ((sdp->sd_flags & FLG_SY_CAP) &&
+				    ofl->ofl_oscapinfo) {
+					syminfo[ndx].si_flags |=
+					    SYMINFO_FLG_CAP;
+				}
 			}
 		}
 
@@ -1397,7 +1497,7 @@
 				dynsym[dynsym_ndx].st_name = stoff;
 
 				if (stoff) {
-					Word _hashndx;
+					Word	hashval, _hashndx;
 
 					hashval =
 					    sap->sa_hash % ofl->ofl_hashbkts;
@@ -1428,6 +1528,7 @@
 			ADD_TO_DYNSORT(sdp, sym, ELF_ST_TYPE(sym->st_info),
 			    ldynsym_cnt + dynsym_ndx);
 		}
+
 		if (!enter_in_symtab && (!dynsym || (local && !dynlocal))) {
 			if (!(sdp->sd_flags & FLG_SY_UPREQD))
 				continue;
@@ -1435,7 +1536,6 @@
 		} else
 			sdp->sd_flags &= ~FLG_SY_CLEAN;
 
-
 		/*
 		 * If we have a weak data symbol for which we need the real
 		 * symbol also, save this processing until later.
@@ -1775,7 +1875,7 @@
 		 * be local, otherwise if it's from a shared object then we need
 		 * to maintain the binding of the original reference.
 		 */
-		if (sdp->sd_flags & FLG_SY_HIDDEN) {
+		if (SYM_IS_HIDDEN(sdp)) {
 			if (flags & FLG_OF_PROCRED)
 				bind = STB_LOCAL;
 			else
@@ -2357,14 +2457,14 @@
 		if (ofl->ofl_osmove) {
 			shdr = ofl->ofl_osmove->os_shdr;
 
-			dyn->d_tag = DT_MOVEENT;
-			dyn->d_un.d_val = shdr->sh_entsize;
+			dyn->d_tag = DT_MOVETAB;
+			dyn->d_un.d_val = shdr->sh_addr;
 			dyn++;
 			dyn->d_tag = DT_MOVESZ;
 			dyn->d_un.d_val = shdr->sh_size;
 			dyn++;
-			dyn->d_tag = DT_MOVETAB;
-			dyn->d_un.d_val = shdr->sh_addr;
+			dyn->d_tag = DT_MOVEENT;
+			dyn->d_un.d_val = shdr->sh_entsize;
 			dyn++;
 		}
 		if (ofl->ofl_regsymcnt) {
@@ -2407,7 +2507,24 @@
 			dyn->d_un.d_val = ofl->ofl_oscap->os_shdr->sh_addr;
 			dyn++;
 		}
-
+		if (ofl->ofl_oscapinfo) {
+			dyn->d_tag = DT_SUNW_CAPINFO;
+			dyn->d_un.d_val = ofl->ofl_oscapinfo->os_shdr->sh_addr;
+			dyn++;
+		}
+		if (ofl->ofl_oscapchain) {
+			shdr = ofl->ofl_oscapchain->os_shdr;
+
+			dyn->d_tag = DT_SUNW_CAPCHAIN;
+			dyn->d_un.d_val = shdr->sh_addr;
+			dyn++;
+			dyn->d_tag = DT_SUNW_CAPCHAINSZ;
+			dyn->d_un.d_val = shdr->sh_size;
+			dyn++;
+			dyn->d_tag = DT_SUNW_CAPCHAINENT;
+			dyn->d_un.d_val = shdr->sh_entsize;
+			dyn++;
+		}
 		if (flags & FLG_OF_SYMBOLIC) {
 			dyn->d_tag = DT_SYMBOLIC;
 			dyn->d_un.d_val = 0;
@@ -3118,6 +3235,281 @@
 }
 
 /*
+ * Update capabilities information.
+ *
+ * If string table capabilities exist, then the associated string must be
+ * translated into an offset into the string table.
+ */
+static void
+update_oscap(Ofl_desc *ofl)
+{
+	Os_desc		*strosp, *cosp;
+	Cap		*cap;
+	Str_tbl		*strtbl;
+	Capstr		*capstr;
+	size_t		stoff;
+	Aliste		idx1;
+
+	/*
+	 * Determine which symbol table or string table is appropriate.
+	 */
+	if (OFL_IS_STATIC_OBJ(ofl)) {
+		strosp = ofl->ofl_osstrtab;
+		strtbl = ofl->ofl_strtab;
+	} else {
+		strosp = ofl->ofl_osdynstr;
+		strtbl = ofl->ofl_dynstrtab;
+	}
+
+	/*
+	 * If symbol capabilities exist, set the sh_link field of the .SUNW_cap
+	 * section to the .SUNW_capinfo section.
+	 */
+	if (ofl->ofl_oscapinfo) {
+		cosp = ofl->ofl_oscap;
+		cosp->os_shdr->sh_link =
+		    (Word)elf_ndxscn(ofl->ofl_oscapinfo->os_scn);
+	}
+
+	/*
+	 * If there are capability strings to process, set the sh_info
+	 * field of the .SUNW_cap section to the associated string table, and
+	 * proceed to process any CA_SUNW_PLAT entries.
+	 */
+	if ((ofl->ofl_flags & FLG_OF_CAPSTRS) == 0)
+		return;
+
+	cosp = ofl->ofl_oscap;
+	cosp->os_shdr->sh_info = (Word)elf_ndxscn(strosp->os_scn);
+
+	cap = ofl->ofl_oscap->os_outdata->d_buf;
+
+	/*
+	 * Determine whether an object capability identifier, or object
+	 * machine/platform capabilities exists.
+	 */
+	capstr = &ofl->ofl_ocapset.oc_id;
+	if (capstr->cs_str) {
+		(void) st_setstring(strtbl, capstr->cs_str, &stoff);
+		cap[capstr->cs_ndx].c_un.c_ptr = stoff;
+	}
+	for (ALIST_TRAVERSE(ofl->ofl_ocapset.oc_plat.cl_val, idx1, capstr)) {
+		(void) st_setstring(strtbl, capstr->cs_str, &stoff);
+		cap[capstr->cs_ndx].c_un.c_ptr = stoff;
+	}
+	for (ALIST_TRAVERSE(ofl->ofl_ocapset.oc_mach.cl_val, idx1, capstr)) {
+		(void) st_setstring(strtbl, capstr->cs_str, &stoff);
+		cap[capstr->cs_ndx].c_un.c_ptr = stoff;
+	}
+
+	/*
+	 * Determine any symbol capability identifiers, or machine/platform
+	 * capabilities.
+	 */
+	if (ofl->ofl_capgroups) {
+		Cap_group	*cgp;
+
+		for (APLIST_TRAVERSE(ofl->ofl_capgroups, idx1, cgp)) {
+			Objcapset	*ocapset = &cgp->cg_set;
+			Aliste		idx2;
+
+			capstr = &ocapset->oc_id;
+			if (capstr->cs_str) {
+				(void) st_setstring(strtbl, capstr->cs_str,
+				    &stoff);
+				cap[capstr->cs_ndx].c_un.c_ptr = stoff;
+			}
+			for (ALIST_TRAVERSE(ocapset->oc_plat.cl_val, idx2,
+			    capstr)) {
+				(void) st_setstring(strtbl, capstr->cs_str,
+				    &stoff);
+				cap[capstr->cs_ndx].c_un.c_ptr = stoff;
+			}
+			for (ALIST_TRAVERSE(ocapset->oc_mach.cl_val, idx2,
+			    capstr)) {
+				(void) st_setstring(strtbl, capstr->cs_str,
+				    &stoff);
+				cap[capstr->cs_ndx].c_un.c_ptr = stoff;
+			}
+		}
+	}
+}
+
+/*
+ * Update the .SUNW_capinfo, and possibly the .SUNW_capchain sections.
+ */
+static void
+update_oscapinfo(Ofl_desc *ofl)
+{
+	Os_desc		*symosp, *ciosp, *ccosp = NULL;
+	Capinfo		*ocapinfo;
+	Capchain	*ocapchain;
+	Cap_avlnode	*cav;
+	Word		chainndx = 0;
+
+	/*
+	 * Determine which symbol table is appropriate.
+	 */
+	if (OFL_IS_STATIC_OBJ(ofl))
+		symosp = ofl->ofl_ossymtab;
+	else
+		symosp = ofl->ofl_osdynsym;
+
+	/*
+	 * Update the .SUNW_capinfo sh_link to point to the appropriate symbol
+	 * table section.  If we're creating a dynamic object, the
+	 * .SUNW_capinfo sh_info is updated to point to the .SUNW_capchain
+	 * section.
+	 */
+	ciosp = ofl->ofl_oscapinfo;
+	ciosp->os_shdr->sh_link = (Word)elf_ndxscn(symosp->os_scn);
+
+	if (OFL_IS_STATIC_OBJ(ofl) == 0) {
+		ccosp = ofl->ofl_oscapchain;
+		ciosp->os_shdr->sh_info = (Word)elf_ndxscn(ccosp->os_scn);
+	}
+
+	/*
+	 * Establish the data for each section.  The first element of each
+	 * section defines the section's version number.
+	 */
+	ocapinfo = ciosp->os_outdata->d_buf;
+	ocapinfo[0] = CAPINFO_CURRENT;
+	if (ccosp) {
+		ocapchain = ccosp->os_outdata->d_buf;
+		ocapchain[chainndx++] = CAPCHAIN_CURRENT;
+	}
+
+	/*
+	 * Traverse all capabilities families.  Each member has a .SUNW_capinfo
+	 * assignment.  The .SUNW_capinfo entry differs for relocatable objects
+	 * and dynamic objects.
+	 *
+	 * Relocatable objects:
+	 *			ELF_C_GROUP		ELF_C_SYM
+	 *
+	 * Family lead:		CAPINFO_SUNW_GLOB	lead symbol index
+	 * Family lead alias:	CAPINFO_SUNW_GLOB	lead symbol index
+	 * Family member:	.SUNW_cap index		lead symbol index
+	 *
+	 * Dynamic objects:
+	 *			ELF_C_GROUP		ELF_C_SYM
+	 *
+	 * Family lead:		CAPINFO_SUNW_GLOB	.SUNW_capchain index
+	 * Family lead alias:	CAPINFO_SUNW_GLOB	.SUNW_capchain index
+	 * Family member:	.SUNW_cap index		lead symbol index
+	 *
+	 * The ELF_C_GROUP field identifies a capabilities symbol.  Lead
+	 * capability symbols, and lead capability aliases are identified by
+	 * a CAPINFO_SUNW_GLOB group identifier.  For family members, the
+	 * ELF_C_GROUP provides an index to the associate capabilities group
+	 * (i.e, an index into the SUNW_cap section that defines a group).
+	 *
+	 * For relocatable objects, the ELF_C_SYM field identifies the lead
+	 * capability symbol.  For the lead symbol itself, the .SUNW_capinfo
+	 * index is the same as the ELF_C_SYM value.  For lead alias symbols,
+	 * the .SUNW_capinfo index differs from the ELF_C_SYM value.  This
+	 * differentiation of CAPINFO_SUNW_GLOB symbols allows ld(1) to
+	 * identify, and propagate lead alias symbols.  For example, the lead
+	 * capability symbol memcpy() would have the ELF_C_SYM for memcpy(),
+	 * and the lead alias _memcpy() would also have the ELF_C_SYM for
+	 * memcpy().
+	 *
+	 * For dynamic objects, both a lead capability symbol, and alias symbol
+	 * would have a ELF_C_SYM value that represents the same capability
+	 * chain index.  The capability chain allows ld.so.1 to traverse a
+	 * family chain for a given lead symbol, and select the most appropriate
+	 * family member.  The .SUNW_capchain array contains a series of symbol
+	 * indexes for each family member:
+	 *
+	 *    chaincap[n]  chaincap[n + 1]  chaincap[n + 2]  chaincap[n + x]
+	 *	foo() ndx    foo%x() ndx	foo%y() ndx	0
+	 *
+	 * For family members, the ELF_C_SYM value associates the capability
+	 * members with their family lead symbol.  This association, although
+	 * unused within a dynamic object, allows ld(1) to identify, and
+	 * propagate family members when processing relocatable objects.
+	 */
+	for (cav = avl_first(ofl->ofl_capfamilies); cav;
+	    cav = AVL_NEXT(ofl->ofl_capfamilies, cav)) {
+		Cap_sym		*csp;
+		Aliste		idx;
+		Sym_desc	*asdp, *lsdp = cav->cn_symavlnode.sav_sdp;
+
+		if (ccosp) {
+			/*
+			 * For a dynamic object, identify this lead symbol, and
+			 * point it to the head of a capability chain.  Set the
+			 * head of the capability chain to the same lead symbol.
+			 */
+			ocapinfo[lsdp->sd_symndx] =
+			    ELF_C_INFO(chainndx, CAPINFO_SUNW_GLOB);
+			ocapchain[chainndx] = lsdp->sd_symndx;
+		} else {
+			/*
+			 * For a relocatable object, identify this lead symbol,
+			 * and set the lead symbol index to itself.
+			 */
+			ocapinfo[lsdp->sd_symndx] =
+			    ELF_C_INFO(lsdp->sd_symndx, CAPINFO_SUNW_GLOB);
+		}
+
+		/*
+		 * Gather any lead symbol aliases.
+		 */
+		for (APLIST_TRAVERSE(cav->cn_aliases, idx, asdp)) {
+			if (ccosp) {
+				/*
+				 * For a dynamic object, identify this lead
+				 * alias symbol, and point it to the same
+				 * capability chain index as the lead symbol.
+				 */
+				ocapinfo[asdp->sd_symndx] =
+				    ELF_C_INFO(chainndx, CAPINFO_SUNW_GLOB);
+			} else {
+				/*
+				 * For a relocatable object, identify this lead
+				 * alias symbol, and set the lead symbol index
+				 * to the lead symbol.
+				 */
+				ocapinfo[asdp->sd_symndx] =
+				    ELF_C_INFO(lsdp->sd_symndx,
+				    CAPINFO_SUNW_GLOB);
+			}
+		}
+
+		chainndx++;
+
+		/*
+		 * Gather the family members.
+		 */
+		for (APLIST_TRAVERSE(cav->cn_members, idx, csp)) {
+			Sym_desc	*msdp = csp->cs_sdp;
+
+			/*
+			 * Identify the members capability group, and the lead
+			 * symbol of the family this symbol is a member of.
+			 */
+			ocapinfo[msdp->sd_symndx] =
+			    ELF_C_INFO(lsdp->sd_symndx, csp->cs_group->cg_ndx);
+			if (ccosp) {
+				/*
+				 * For a dynamic object, set the next capability
+				 * chain to point to this family member.
+				 */
+				ocapchain[chainndx++] = msdp->sd_symndx;
+			}
+		}
+
+		/*
+		 * Any chain of family members is terminated with a 0 element.
+		 */
+		if (ccosp)
+			ocapchain[chainndx++] = 0;
+	}
+}
+
+/*
  * Translate the shdr->sh_{link, info} from its input section value to that
  * of the corresponding shdr->sh_{link, info} output section value.
  */
@@ -3215,7 +3607,7 @@
 	 */
 	if (ofl->ofl_flags & FLG_OF_EXEC) {
 #if	defined(_ELF64)
-		if (ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_ADDR32)
+		if (ofl->ofl_ocapset.oc_sf_1.cm_val & SF1_SUNW_ADDR32)
 			vaddr = ld_targ.t_m.m_segm_aorigin;
 		else
 #endif
@@ -3287,7 +3679,8 @@
 		 * virtual address.  This is updated later.
 		 */
 		if (phdr->p_type == PT_SUNWCAP) {
-			if (ofl->ofl_oscap) {
+			if (ofl->ofl_oscap && (ofl->ofl_flags & FLG_OF_PTCAP) &&
+			    ((flags & FLG_OF_RELOBJ) == 0)) {
 				capsgp = sgp;
 				capsndx = segndx;
 				cappndx = phdrndx++;
@@ -3360,19 +3753,20 @@
 		 */
 		if (phdr->p_type == PT_TLS) {
 			Os_desc		*tlsosp;
-			Shdr		*firstshdr = NULL, *lastfileshdr = NULL;
-			Shdr		*lastshdr;
+			Shdr		*lastfileshdr = NULL;
+			Shdr		*firstshdr = NULL, *lastshdr;
 			Aliste		idx;
 
 			if (ofl->ofl_ostlsseg == NULL)
 				continue;
 
 			/*
-			 * Scan through the sections that have contributed TLS.
+			 * Scan the output sections that have contributed TLS.
 			 * Remember the first and last so as to determine the
 			 * TLS memory size requirement.  Remember the last
-			 * non-nobits section to determine the TLS data
-			 * contribution, which determines the TLS file size.
+			 * progbits section to determine the TLS data
+			 * contribution, which determines the TLS program
+			 * header filesz.
 			 */
 			for (APLIST_TRAVERSE(ofl->ofl_ostlsseg, idx, tlsosp)) {
 				Shdr	*tlsshdr = tlsosp->os_shdr;
@@ -3389,14 +3783,26 @@
 			phdr->p_offset = firstshdr->sh_offset;
 			phdr->p_align = firstshdr->sh_addralign;
 
+			/*
+			 * Determine the initialized TLS data size.  This
+			 * address range is from the start of the TLS segment
+			 * to the end of the last piece of initialized data.
+			 */
 			if (lastfileshdr)
 				phdr->p_filesz = lastfileshdr->sh_offset +
 				    lastfileshdr->sh_size - phdr->p_offset;
 			else
 				phdr->p_filesz = 0;
 
-			phdr->p_memsz = lastshdr->sh_offset +
-			    lastshdr->sh_size - phdr->p_offset;
+			/*
+			 * Determine the total TLS memory size.  This includes
+			 * all TLS data and TLS uninitialized data.  This
+			 * address range is from the start of the TLS segment
+			 * to the memory address of the last piece of
+			 * uninitialized data.
+			 */
+			phdr->p_memsz = lastshdr->sh_addr +
+			    lastshdr->sh_size - phdr->p_vaddr;
 
 			DBG_CALL(Dbg_seg_entry(ofl, segndx, sgp));
 			ofl->ofl_phdr[phdrndx] = *phdr;
@@ -3407,7 +3813,7 @@
 		/*
 		 * If this is an empty segment declaration, it will occur after
 		 * all other loadable segments.  As empty segments can be
-		 * defind with fixed addresses, make sure that no loadable
+		 * defined with fixed addresses, make sure that no loadable
 		 * segments overlap.  This might occur as the object evolves
 		 * and the loadable segments grow, thus encroaching upon an
 		 * existing segment reservation.
@@ -3737,7 +4143,8 @@
 		phdr->p_memsz = sdp->sd_sym->st_size;
 
 		/*
-		 * Take permisions of the segment the symbol is associated with.
+		 * Take permissions from the segment that the symbol is
+		 * associated with.
 		 */
 		aphdr = &sdp->sd_isc->is_osdesc->os_sgdesc->sg_phdr;
 		assert(aphdr);
@@ -3802,6 +4209,14 @@
 	}
 
 	/*
+	 * Update capabilities information if required.
+	 */
+	if (ofl->ofl_oscap)
+		update_oscap(ofl);
+	if (ofl->ofl_oscapinfo)
+		update_oscapinfo(ofl);
+
+	/*
 	 * Sanity test: the first and last data byte of a string table
 	 * must be NULL.
 	 */
--- a/usr/src/cmd/sgs/libld/common/util.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/util.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -704,3 +704,36 @@
 	else
 		return (name);
 }
+
+/*
+ * Compare a series of platform or machine hardware names.
+ */
+int
+cap_names_match(Alist *alp1, Alist *alp2)
+{
+	Capstr		*capstr1;
+	Aliste		idx1;
+	int		match = 0;
+	Word		nitems;
+
+	if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
+		return (1);
+
+	for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
+		Capstr		*capstr2;
+		Aliste 		idx2;
+
+		for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
+			if (strcmp(capstr1->cs_str, capstr2->cs_str))
+				continue;
+
+			match++;
+			break;
+		}
+	}
+
+	if (nitems == match)
+		return (0);
+
+	return (1);
+}
--- a/usr/src/cmd/sgs/libld/common/version.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/version.c	Mon Mar 01 10:20:48 2010 -0800
@@ -919,7 +919,7 @@
 	}
 
 	if (vndx == VER_NDX_GLOBAL) {
-		if ((sdp->sd_flags & FLG_SY_HIDDEN) == 0)
+		if (!SYM_IS_HIDDEN(sdp))
 			sdp->sd_flags |= (FLG_SY_DEFAULT | FLG_SY_EXPDEF);
 		if (sdp->sd_aux->sa_overndx <= VER_NDX_GLOBAL)
 			sdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
@@ -937,7 +937,7 @@
 		return;
 	}
 
-	if ((sdp->sd_flags & FLG_SY_HIDDEN) == 0)
+	if (!SYM_IS_HIDDEN(sdp))
 		sdp->sd_flags |= (FLG_SY_DEFAULT | FLG_SY_EXPDEF);
 
 	/*
--- a/usr/src/cmd/sgs/liblddbg/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,6 +18,7 @@
 #
 # CDDL HEADER END
 #
+
 #
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -59,17 +60,9 @@
 LINTFLAGS64 +=	-u -D_REENTRANT
 
 CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc $(VAR_LIBLDDBG_CPPFLAGS)
-DYNFLAGS +=	$(VERSREF) '-R$$ORIGIN'
+DYNFLAGS +=	$(VERSREF) $(CC_USE_PROTO) '-R$$ORIGIN'
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) -lc
 
-# A bug in pmake causes redundancy when '+=' is conditionally assigned, so
-# '=' is used with extra variables.
-# $(DYNLIB) :=  DYNFLAGS += $(USE_PROTO)
-#
-XXXFLAGS=
-$(DYNLIB) :=	XXXFLAGS= $(USE_PROTO)
-DYNFLAGS +=     $(XXXFLAGS)
-
 native :=	DYNFLAGS	+= $(CONVLIBDIR)
 
 BLTDEFS =	msg.h
--- a/usr/src/cmd/sgs/liblddbg/common/cap.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/cap.c	Mon Mar 01 10:20:48 2010 -0800
@@ -32,40 +32,117 @@
 #include	"_debug.h"
 
 void
-Dbg_cap_hw_candidate(Lm_list *lml, const char *name)
+Dbg_cap_candidate(Lm_list *lml, const char *name)
 {
 	if (DBG_NOTCLASS(DBG_C_CAP | DBG_C_FILES))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_CAP_HW_CANDIDATE), name);
+	dbg_print(lml, MSG_INTL(MSG_CAP_CANDIDATE), name);
 }
 
 void
-Dbg_cap_hw_filter(Lm_list *lml, const char *dir, Rt_map *flmp)
+Dbg_cap_filter(Lm_list *lml, const char *dir, Rt_map *flmp)
 {
 	if (DBG_NOTCLASS(DBG_C_CAP | DBG_C_FILES))
 		return;
 
 	Dbg_util_nl(lml, DBG_NL_STD);
 	if (flmp)
-		dbg_print(lml, MSG_INTL(MSG_CAP_HWFILTR_1), dir, NAME(flmp));
+		dbg_print(lml, MSG_INTL(MSG_CAP_FILTER_1), dir, NAME(flmp));
 	else
-		dbg_print(lml, MSG_INTL(MSG_CAP_HWFILTR_2), dir);
+		dbg_print(lml, MSG_INTL(MSG_CAP_FILTER_2), dir);
 }
 
 void
-Dbg_cap_val_hw1(Lm_list *lml, Xword val, Half mach)
+Dbg_cap_val(Lm_list *lml, Syscapset *sys, Syscapset *alt, Half mach)
 {
-	Conv_cap_val_hw1_buf_t cap_val_hw1_buf;
+	Conv_cap_val_buf_t	cap_val_buf;
+
+	if ((sys->sc_plat == NULL) && (sys->sc_mach == NULL) &&
+	    (sys->sc_hw_2 == 0) && (sys->sc_hw_1 == 0) &&
+	    (sys->sc_sf_1 == 0))
+		return;
 
 	Dbg_util_nl(lml, DBG_NL_FRC);
-	dbg_print(lml, MSG_INTL(MSG_CAP_VAL_HW1),
-	    conv_cap_val_hw1(val, mach, 0, &cap_val_hw1_buf));
+
+	/*
+	 * Print any capabilities in precedence order.
+	 */
+	if (sys->sc_plat) {
+		dbg_print(lml, MSG_INTL(MSG_CAP_SYS_PLAT), sys->sc_plat);
+	}
+	if (sys->sc_mach) {
+		dbg_print(lml, MSG_INTL(MSG_CAP_SYS_MACH), sys->sc_mach);
+	}
+	if (sys->sc_hw_2) {
+		dbg_print(lml, MSG_INTL(MSG_CAP_SYS_HW_2),
+		    conv_cap_val_hw2(sys->sc_hw_2, mach, 0,
+		    &cap_val_buf.cap_val_hw2_buf));
+	}
+	if (sys->sc_hw_1) {
+		dbg_print(lml, MSG_INTL(MSG_CAP_SYS_HW_1),
+		    conv_cap_val_hw1(sys->sc_hw_1, mach, 0,
+		    &cap_val_buf.cap_val_hw1_buf));
+	}
+	if (sys->sc_sf_1) {
+		dbg_print(lml, MSG_INTL(MSG_CAP_SYS_SF_1),
+		    conv_cap_val_sf1(sys->sc_sf_1, mach, 0,
+		    &cap_val_buf.cap_val_sf1_buf));
+	}
+
+	if (alt != sys) {
+		Dbg_util_nl(lml, DBG_NL_FRC);
+		if (alt->sc_plat != sys->sc_plat) {
+			dbg_print(lml, MSG_INTL(MSG_CAP_ALT_PLAT),
+			    alt->sc_plat);
+		}
+		if (alt->sc_mach != sys->sc_mach) {
+			dbg_print(lml, MSG_INTL(MSG_CAP_ALT_MACH),
+			    alt->sc_mach);
+		}
+		if (alt->sc_hw_2 != sys->sc_hw_2) {
+			dbg_print(lml, MSG_INTL(MSG_CAP_ALT_HW_2),
+			    conv_cap_val_hw2(alt->sc_hw_2, mach, 0,
+			    &cap_val_buf.cap_val_hw2_buf));
+		}
+		if (alt->sc_hw_1 != sys->sc_hw_1) {
+			dbg_print(lml, MSG_INTL(MSG_CAP_ALT_HW_1),
+			    conv_cap_val_hw1(alt->sc_hw_1, mach, 0,
+			    &cap_val_buf.cap_val_hw1_buf));
+		}
+		if (alt->sc_sf_1 != sys->sc_sf_1) {
+			dbg_print(lml, MSG_INTL(MSG_CAP_ALT_SF_1),
+			    conv_cap_val_sf1(alt->sc_sf_1, mach, 0,
+			    &cap_val_buf.cap_val_sf1_buf));
+		}
+	}
+
 	Dbg_util_nl(lml, DBG_NL_FRC);
 }
 
+/*
+ * This version takes a pointer to a Capmask, and will report the exclusion
+ * bits if they exist.
+ */
 void
-Dbg_cap_entry(Lm_list *lml, dbg_state_t dbg_state, Xword tag, Xword val,
+Dbg_cap_ptr_entry(Lm_list *lml, dbg_state_t dbg_state, Xword tag,
+    const char *ptr)
+{
+	Conv_inv_buf_t		inv_buf;
+
+	if (DBG_NOTCLASS(DBG_C_CAP))
+		return;
+
+	dbg_print(lml, MSG_INTL(MSG_CAP_SEC_ENTRY), Dbg_state_str(dbg_state),
+	    conv_cap_tag(tag, 0, &inv_buf), ptr);
+}
+
+/*
+ * This version takes a pointer to a CapMask, and will report the exclusion
+ * bits if they exist.
+ */
+void
+Dbg_cap_val_entry(Lm_list *lml, dbg_state_t dbg_state, Xword tag, Xword val,
     Half mach)
 {
 	Conv_inv_buf_t		inv_buf;
@@ -74,40 +151,11 @@
 	if (DBG_NOTCLASS(DBG_C_CAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY), Dbg_state_str(dbg_state),
-	    conv_cap_tag(tag, 0, &inv_buf), conv_cap_val(tag, val, mach,
+	dbg_print(lml, MSG_INTL(MSG_CAP_SEC_ENTRY), Dbg_state_str(dbg_state),
+	    conv_cap_tag(tag, 0, &inv_buf), conv_cap_val(tag, val, mach, 0,
 	    &cap_val_buf));
 }
 
-/*
- * This version takes a pointer to a CapMask, and will report the exclusion
- * bits if they exist.
- */
-void
-Dbg_cap_entry2(Lm_list *lml, dbg_state_t dbg_state, Xword tag, CapMask *cmp,
-    Half mach)
-{
-	Conv_inv_buf_t		inv_buf;
-	Conv_cap_val_buf_t	cap_val_buf1, cap_val_buf2;
-
-	if (DBG_NOTCLASS(DBG_C_CAP))
-		return;
-
-	/* If there is no exclusion mask, use the simpler format */
-	if (cmp->cm_exclude == 0) {
-		dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY),
-		    Dbg_state_str(dbg_state), conv_cap_tag(tag, 0, &inv_buf),
-		    conv_cap_val(tag, cmp->cm_value, mach, &cap_val_buf1));
-		return;
-	}
-
-
-	dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY_EXC), Dbg_state_str(dbg_state),
-	    conv_cap_tag(tag, 0, &inv_buf),
-	    conv_cap_val(tag, cmp->cm_value, mach, &cap_val_buf1),
-	    conv_cap_val(tag, cmp->cm_exclude, mach, &cap_val_buf2));
-}
-
 void
 Dbg_cap_sec_title(Lm_list *lml, const char *name)
 {
@@ -119,16 +167,6 @@
 }
 
 void
-Dbg_cap_out_title(Lm_list *lml)
-{
-	if (DBG_NOTCLASS(DBG_C_CAP))
-		return;
-
-	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_CAP_OUT_TITLE));
-}
-
-void
 Dbg_cap_mapfile_title(Lm_list *lml, Lineno lineno)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP | DBG_C_CAP))
@@ -138,20 +176,57 @@
 }
 
 void
+Dbg_cap_id(Lm_list *lml, Lineno lineno, const char *oid, const char *nid)
+{
+	Dbg_cap_mapfile_title(lml, lineno);
+	Dbg_cap_ptr_entry(lml, DBG_STATE_CURRENT, CA_SUNW_ID, oid);
+	Dbg_cap_ptr_entry(lml, DBG_STATE_NEW, CA_SUNW_ID, nid);
+	Dbg_cap_ptr_entry(lml, DBG_STATE_RESOLVED, CA_SUNW_ID, nid);
+}
+
+void
+Dbg_cap_post_title(Lm_list *lml, int *title)
+{
+	if (DBG_NOTCLASS(DBG_C_CAP))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	if ((*title)++ == 0)
+		dbg_print(lml, MSG_INTL(MSG_CAP_POST_TITLE));
+}
+
+void
 Elf_cap_title(Lm_list *lml)
 {
 	dbg_print(lml, MSG_INTL(MSG_CAP_ELF_TITLE));
 }
 
 void
-Elf_cap_entry(Lm_list *lml, Cap *cap, int ndx, Half mach)
+Elf_cap_entry(Lm_list *lml, Cap *cap, int ndx, const char *str, size_t str_size,
+    Half mach)
 {
 	Conv_inv_buf_t		inv_buf;
 	Conv_cap_val_buf_t	cap_val_buf;
 	char			index[INDEX_STR_SIZE];
 
 	(void) snprintf(index, INDEX_STR_SIZE, MSG_ORIG(MSG_FMT_INDEX), ndx);
+
+	switch (cap->c_tag) {
+	case CA_SUNW_PLAT:
+	case CA_SUNW_MACH:
+	case CA_SUNW_ID:
+		/* If offset is in range, format as a string */
+		if (str && (cap->c_un.c_ptr < str_size)) {
+			str += cap->c_un.c_ptr;
+			break;
+		}
+		/*FALLTHROUGH*/
+	default:
+		/* Format numerically */
+		str = conv_cap_val(cap->c_tag, cap->c_un.c_val, mach, 0,
+		    &cap_val_buf);
+	}
+
 	dbg_print(lml, MSG_INTL(MSG_CAP_ELF_ENTRY), index,
-	    conv_cap_tag(cap->c_tag, 0, &inv_buf),
-	    conv_cap_val(cap->c_tag, cap->c_un.c_val, mach, &cap_val_buf));
+	    conv_cap_tag(cap->c_tag, 0, &inv_buf), str);
 }
--- a/usr/src/cmd/sgs/liblddbg/common/debug.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/debug.c	Mon Mar 01 10:20:48 2010 -0800
@@ -563,8 +563,8 @@
 		MSG_STR_MOD_AFTER,	/* MSG_INTL(MSG_STR_MOD_AFTER) */
 		MSG_STR_NEW,		/* MSG_INTL(MSG_STR_NEW) */
 		MSG_STR_NEW_IMPLICIT,	/* MSG_INTL(MSG_STR_NEW_IMPLICIT) */
-		MSG_STR_OUT,		/* MSG_INTL(MSG_STR_OUT) */
 		MSG_STR_RESET,		/* MSG_INTL(MSG_STR_RESET) */
+		MSG_STR_ORIGINAL,	/* MSG_INTL(MSG_STR_ORIGINAL) */
 		MSG_STR_RESOLVED,	/* MSG_INTL(MSG_STR_RESOLVED) */
 	};
 #if DBG_STATE_NUM != (DBG_STATE_RESOLVED + 1)
--- a/usr/src/cmd/sgs/liblddbg/common/files.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/files.c	Mon Mar 01 10:20:48 2010 -0800
@@ -574,6 +574,9 @@
 	Conv_config_feat_buf_t	config_feat_buf;
 	const char		*str;
 
+	if (features == 0)
+		return;
+
 	switch (features & ~CONF_FEATMSK) {
 	case DBG_CONF_IGNORE:
 		str = MSG_INTL(MSG_FIL_CONFIG_ERR_1);
@@ -732,7 +735,12 @@
 	MSG_REJ_US3,		/* MSG_INTL(MSG_REJ_US3) */
 	MSG_REJ_STR,		/* MSG_INTL(MSG_REJ_STR) */
 	MSG_REJ_UNKFILE,	/* MSG_INTL(MSG_REJ_UNKFILE) */
+	MSG_REJ_UNKCAP,		/* MSG_INTL(MSG_REJ_UNKCAP) */
 	MSG_REJ_HWCAP_1,	/* MSG_INTL(MSG_REJ_HWCAP_1) */
+	MSG_REJ_SFCAP_1,	/* MSG_INTL(MSG_REJ_SFCAP_1) */
+	MSG_REJ_MACHCAP,	/* MSG_INTL(MSG_REJ_MACHCAP) */
+	MSG_REJ_PLATCAP,	/* MSG_INTL(MSG_REJ_PLATCAP) */
+	MSG_REJ_HWCAP_2		/* MSG_INTL(MSG_REJ_HWCAP_2) */
 };
 
 void
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -393,7 +393,7 @@
 #
 #         all              display information for all categories
 #         basic            basic trace information/warnings
-#         cap              hardware/software capabilities
+#         cap              platform/machine/hardware/software capabilities
 #         files            input file processing (files and libraries)
 #         help             this help message
 #         libs             library search paths; detail flag shows
@@ -419,7 +419,8 @@
 @ MSG_USE_R7_B	"        basic            basic trace information/warnings"
 
 # TRANSLATION_NOTE -- do not translate the first token "cap".
-@ MSG_USE_R7_C	"        cap              hardware/software capabilities"
+@ MSG_USE_R7_C	"        cap              platform/machine/hardware/software \
+					  capabilities"
 
 # TRANSLATION_NOTE -- do not translate the first token "files".
 @ MSG_USE_R7_D	"        files            input file processing (files \
@@ -745,8 +746,17 @@
 			 required"
 @ MSG_REJ_STR		"obj=%s;  rejected: %s"
 @ MSG_REJ_UNKFILE	"obj=%s;  rejected: unknown file type"
-@ MSG_REJ_HWCAP_1	"obj=%s;  rejected: hardware capability unsupported: \
-			 %s"
+@ MSG_REJ_UNKCAP	"obj=%s;  rejected: unknown capability: %d"
+@ MSG_REJ_HWCAP_1	"obj=%s;  rejected: hardware capability (CA_SUNW_HW_1) \
+			 unsupported: %s"
+@ MSG_REJ_SFCAP_1	"obj=%s;  rejected: software capability (CA_SUNW_SF_1) \
+			 unsupported: %s"
+@ MSG_REJ_MACHCAP	"obj=%s;  rejected: machine capability (CA_SUNW_MACH) \
+			 unsupported: %s"
+@ MSG_REJ_PLATCAP	"obj=%s;  rejected: platform capability (CA_SUNW_PLAT) \
+			 unsupported: %s"
+@ MSG_REJ_HWCAP_2	"obj=%s;  rejected: hardware capability (CA_SUNW_HW_2) \
+			 unsupported: %s"
 
 # Libs messages
 
@@ -797,8 +807,8 @@
 @ MSG_MAP_SORT_TITLE_O	"before:" 
 @ MSG_MAP_SORT_TITLE_S	"after:" 
 @ MSG_MAP_POST_TITLE	"mapfile post processing"
-@ MSG_MAP_ENT_ORD_TITLE	"set entrance criteria input section sort keys \
-			 (ec_ordndx); segment=%s"
+@ MSG_MAP_ENT_ORD_TITLE	"set entrance criteria input section sort keys; \
+			 segment=%s"
 
 @ MSG_MAP_ID_ADD	"%s: %lld: enter conditional expression id: %s"
 @ MSG_MAP_ID_CLEAR	"%s: %lld: delete conditional expression id: %s"
@@ -945,6 +955,8 @@
 @ MSG_SYM_REDUCED	"symbol table processing; reducing global symbols"
 @ MSG_SYM_RETAINING	"symbol table processing; retaining local symbols"
 @ MSG_SYM_VERSION	"symbol table processing; adding version symbols"
+@ MSG_SYM_CAPABILITIES	"symbol table processing; adding local capabilities \
+			 symbols"
 
 @ MSG_SYM_BASIC		"symbol[%d]=%s"
 @ MSG_SYM_ADDING	"symbol[%d]=%s  (global); adding"
@@ -962,7 +974,11 @@
 			 discarded file=%s"
 @ MSG_SYM_DISCARD_DUP	"symbol[%d]=%s;  discarded duplicate: originates from \
 			 file=%s"
-@ MSG_SYM_WRAP		"symbol[%d]=%s renamed to %s (-z wrap)"
+@ MSG_SYM_WRAP		"symbol[%d]=%s  renamed to %s (-z wrap)"
+@ MSG_SYM_CAP_ORIG	"symbol[%d]=%s  converting to symbol capability \
+			 (-z symbolcap)"
+@ MSG_SYM_CAP_LOCAL	"symbol[%d]=%s  creating local capability \
+			 (-z symbolcap)"
 
 @ MSG_SYM_AOUT		"symbol=%s;  (original AOUT name)"
 @ MSG_SYM_LOOKUP	"symbol=%s;  lookup in file=%s  [ %s ]"
@@ -970,6 +986,21 @@
 @ MSG_SYM_DLSYM_2	"symbol=%s;  dlsym() called from file=%s; starting \
 			 at file=%s %s %s"
 
+@ MSG_CAP_SYM_DEFAULT	"  symbol=%s[%u]:  capability family default"
+@ MSG_CAP_SYM_USED	"  symbol=%s[%u]:  used"
+@ MSG_CAP_SYM_CANDIDATE	"  symbol=%s[%u]:  capability candidate"
+@ MSG_CAP_SYM_REJECTED	"  symbol=%s[%u]:  capability rejected"
+@ MSG_CAP_SYM_HW_1	"  symbol=%s[%u]:  capability specific \
+			 (CA_SUNW_HW_1):  [ %s ]"
+@ MSG_CAP_SYM_SF_1	"  symbol=%s[%u]:  capability specific \
+			 (CA_SUNW_SF_1):  [ %s ]"
+@ MSG_CAP_SYM_MACH	"  symbol=%s[%u]:  capability specific \
+			 (CA_SUNW_MACH):  [ %s ]"
+@ MSG_CAP_SYM_PLAT	"  symbol=%s[%u]:  capability specific \
+			 (CA_SUNW_PLAT):  [ %s ]"
+@ MSG_CAP_SYM_HW_2	"  symbol=%s[%u]:  capability specific \
+			 (CA_SUNW_HW_2):  [ %s ]"
+
 @ MSG_SYM_LAZY_RESCAN	"rescanning for lazy dependencies for symbol: %s"
 
 @ MSG_SYM_DUPSORTADDR	"section %s: symbol '%s' and symbol '%s' have the \
@@ -1065,6 +1096,7 @@
 
 @ MSG_STR_IGNORE	"ignored"
 @ MSG_STR_ENTERED	"entered"
+@ MSG_STR_ORIGINAL	"original"
 @ MSG_STR_EXCLUDE	"exclude"
 @ MSG_STR_RESET		"reset"
 @ MSG_STR_IN		" in"
@@ -1122,20 +1154,28 @@
 @ MSG_STATS_RELOCS_OUT	"  Relocations output: records=%lld"
 @ MSG_STATS_RELOCS_IN	"  Relocations  input: records=%-10lld applied=%lld"
 
-# Hardware/Software capabilities messages
+# Capabilities messages
 
-@ MSG_CAP_VAL_HW1	"hardware capabilities - %s"
+@ MSG_CAP_SYS_HW_1	"hardware capabilities (CA_SUNW_HW_1) - %s"
+@ MSG_CAP_SYS_SF_1	"software capabilities (CA_SUNW_SF_1) - %s"
+@ MSG_CAP_SYS_MACH	"machine capability (CA_SUNW_MACH) - %s"
+@ MSG_CAP_SYS_PLAT	"platform capability (CA_SUNW_PLAT) - %s"
+@ MSG_CAP_SYS_HW_2	"hardware capabilities (CA_SUNW_HW_2) - %s"
+
+@ MSG_CAP_ALT_HW_1	"alternative hardware capabilities (CA_SUNW_HW_1) - %s"
+@ MSG_CAP_ALT_SF_1	"alternative software capabilities (CA_SUNW_SF_1) - %s"
+@ MSG_CAP_ALT_MACH	"alternative machine capability (CA_SUNW_MACH) - %s"
+@ MSG_CAP_ALT_PLAT	"alternative platform capability (CA_SUNW_PLAT) - %s"
+@ MSG_CAP_ALT_HW_2	"alternative hardware capabilities (CA_SUNW_HW_2) - %s"
 
 @ MSG_CAP_SEC_TITLE	"capabilities; input file=%s"
-@ MSG_CAP_OUT_TITLE	"output capabilities"
-@ MSG_CAP_ENTRY	"%12.12s  %-15.15s  %s"
-@ MSG_CAP_ENTRY_EXC	"%12.12s  %-15.15s  %s, exclude %s"
+@ MSG_CAP_SEC_ENTRY     "%12.12s  %-15.15s  %s"
 
-@ MSG_CAP_HW_CANDIDATE	"obj=%s;  hardware capabilities candidate"
+@ MSG_CAP_CANDIDATE	"obj=%s;  capabilities candidate"
+@ MSG_CAP_POST_TITLE	"capabilities post processing"
 
-@ MSG_CAP_HWFILTR_1	"dir=%s;  hardware capability directory filtered by %s"
-@ MSG_CAP_HWFILTR_2	"dir=%s;  no hardware capability objects found"
-
+@ MSG_CAP_FILTER_1	"dir=%s;  capability directory filtered by %s"
+@ MSG_CAP_FILTER_2	"dir=%s;  no capability objects found"
 
 @ MSG_ELF_HEADER	"ELF Header"
 
@@ -1146,7 +1186,6 @@
 @ MSG_CAP_ELF_TITLE	"     index  tag               value"
 @ MSG_CAP_ELF_ENTRY	"%10.10s  %-15.15s  %s"
 
-
 # Dynamic entries.
 # TRANSLATION_NOTE - the following two entries provide for a series of one or
 # more dynamic table entries that align with the initial title.
@@ -1154,7 +1193,6 @@
 @ MSG_DYN_TITLE		"     index  tag                value"
 @ MSG_DYN_ENTRY		"%10.10s  %-16.16s  %-#16llx    %s"
 
-
 # Symbol table entries.
 # TRANSLATION_NOTE - the following entries provide for a series of one or more
 # standard 32-bit symbol table entries that align with the initial title.
@@ -1205,6 +1243,7 @@
 			 bound to                 symbol"
 @ MSG_SYMINFO_ENTRY	"%10.10s  %-8s %7s %-24s %s"
 
+@ MSG_SYMINFO_CAP	"<symbol capabilities>"
 @ MSG_SYMINFO_SELF	"<self>"
 @ MSG_SYMINFO_PARENT	"<parent>"
 @ MSG_SYMINFO_EXTERN	"<extern>"
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Mon Mar 01 10:20:48 2010 -0800
@@ -73,28 +73,22 @@
 void	Dbg32_bind_weak(Rt_map *, Elf32_Addr, Elf32_Addr, const char *);
 void	Dbg64_bind_weak(Rt_map *, Elf64_Addr, Elf64_Addr, const char *);
 
-void	Dbg32_cap_entry(Lm_list *, uint_t, Elf32_Word, Elf32_Word,
-	    Elf32_Half);
-void	Dbg64_cap_entry(Lm_list *, uint_t, Elf64_Xword, Elf64_Xword,
-	    Elf64_Half);
-void	Dbg32_cap_entry2(Lm_list *, uint_t, Elf32_Word, CapMask *,
-	    Elf32_Half);
-void	Dbg64_cap_entry2(Lm_list *, uint_t, Elf64_Xword, CapMask *,
-	    Elf64_Half);
-void	Dbg32_cap_out_title(Lm_list *);
-void	Dbg64_cap_out_title(Lm_list *);
-void	Dbg32_cap_hw_candidate(Lm_list *, const char *);
-void	Dbg64_cap_hw_candidate(Lm_list *, const char *);
-void	Dbg32_cap_hw_filter(Lm_list *, const char *, Rt_map *);
-void	Dbg64_cap_hw_filter(Lm_list *, const char *, Rt_map *);
+void	Dbg32_cap_candidate(Lm_list *, const char *);
+void	Dbg64_cap_candidate(Lm_list *, const char *);
+void	Dbg32_cap_filter(Lm_list *, const char *, Rt_map *);
+void	Dbg64_cap_filter(Lm_list *, const char *, Rt_map *);
+void	Dbg32_cap_id(Lm_list *, Lineno, const char *, const char *);
+void	Dbg64_cap_id(Lm_list *, Lineno, const char *, const char *);
 void	Dbg32_cap_mapfile_title(Lm_list *, Lineno);
 void	Dbg64_cap_mapfile_title(Lm_list *, Lineno);
+void	Dbg32_cap_post_title(Lm_list *, int *);
+void	Dbg64_cap_post_title(Lm_list *, int *);
 void	Dbg32_cap_out_title(Lm_list *);
 void	Dbg64_cap_out_title(Lm_list *);
 void	Dbg32_cap_sec_title(Lm_list *, const char *);
 void	Dbg64_cap_sec_title(Lm_list *, const char *);
-void	Dbg32_cap_val_hw1(Lm_list *, Elf32_Word, Elf32_Half);
-void	Dbg64_cap_val_hw1(Lm_list *, Elf64_Xword, Elf64_Half);
+void	Dbg32_cap_val(Lm_list *, Syscapset *, Syscapset *, Elf32_Half);
+void	Dbg64_cap_val(Lm_list *, Syscapset *, Syscapset *, Elf64_Half);
 
 void	Dbg32_cb_iphdr_callback(Lm_list *, struct dl_phdr_info *);
 void	Dbg64_cb_iphdr_callback(Lm_list *, struct dl_phdr_info *);
@@ -394,6 +388,16 @@
 void	Dbg64_syms_ar_resolve(Lm_list *, Xword, Elf_Arsym *, const char *, int);
 void	Dbg32_syms_ar_title(Lm_list *, const char *, int);
 void	Dbg64_syms_ar_title(Lm_list *, const char *, int);
+void	Dbg32_syms_cap_convert(Ofl_desc *, Word, const char *, Sym *);
+void	Dbg64_syms_cap_convert(Ofl_desc *, Word, const char *, Sym *);
+void	Dbg32_syms_cap_local(Ofl_desc *, Word, const char *, Sym *, Sym_desc *);
+void	Dbg64_syms_cap_local(Ofl_desc *, Word, const char *, Sym *, Sym_desc *);
+void	Dbg32_syms_cap_lookup(Rt_map *, uint_t, const char *, uint_t, Half,
+	    Syscapset *);
+void	Dbg64_syms_cap_lookup(Rt_map *, uint_t, const char *, uint_t, Half,
+	    Syscapset *);
+void	Dbg32_syms_cap_title(Ofl_desc *);
+void	Dbg64_syms_cap_title(Ofl_desc *);
 void	Dbg32_syms_created(Lm_list *, const char *);
 void	Dbg64_syms_created(Lm_list *, const char *);
 void	Dbg32_syms_discarded(Lm_list *, Sym_desc *);
@@ -510,8 +514,10 @@
 void Elf_ver_line_4(Lm_list *, const char *);
 void Elf_ver_line_5(Lm_list *, const char *, const char *);
 
-void Elf64_cap_entry(Lm_list *, Elf64_Cap *, int ndx, Elf64_Half);
-void Elf32_cap_entry(Lm_list *, Elf32_Cap *, int ndx, Elf32_Half);
+void Elf64_cap_entry(Lm_list *, Elf64_Cap *, int ndx, const char *, size_t,
+    Elf64_Half);
+void Elf32_cap_entry(Lm_list *, Elf32_Cap *, int ndx, const char *, size_t,
+    Elf32_Half);
 void Elf64_cap_title(Lm_list *);
 void Elf32_cap_title(Lm_list *);
 
--- a/usr/src/cmd/sgs/liblddbg/common/map.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/map.c	Mon Mar 01 10:20:48 2010 -0800
@@ -319,7 +319,6 @@
 	dbg_print(lml, MSG_INTL(MSG_MAP_POST_TITLE));
 }
 
-
 void
 Dbg_map_hdr_noalloc(Lm_list *lml, Lineno lineno)
 {
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Mon Mar 01 10:20:48 2010 -0800
@@ -41,7 +41,7 @@
 # MAPFILE HEADER END
 #
 
-SUNWprivate_4.76 {
+SUNWprivate_4.77 {
 	global:
 		dbg_desc = NODIRECT;	# interposed - ld.so.1(1)
 		dbg_print = NODIRECT;	# interposed - ld(1) and ld.so.1(1)
@@ -83,22 +83,24 @@
 		Dbg32_bind_weak;
 		Dbg64_bind_weak;
 
-		Dbg32_cap_hw_candidate;
-		Dbg64_cap_hw_candidate;
-		Dbg32_cap_hw_filter;
-		Dbg64_cap_hw_filter;
+		Dbg32_cap_candidate;
+		Dbg64_cap_candidate;
+		Dbg32_cap_filter;
+		Dbg64_cap_filter;
+		Dbg32_cap_id;
+		Dbg64_cap_id;
 		Dbg32_cap_mapfile_title;
 		Dbg64_cap_mapfile_title;
-		Dbg32_cap_entry;
-		Dbg64_cap_entry;
-		Dbg32_cap_entry2;
-		Dbg64_cap_entry2;
-		Dbg32_cap_out_title;
-		Dbg64_cap_out_title;
+		Dbg32_cap_post_title;
+		Dbg64_cap_post_title;
+		Dbg32_cap_ptr_entry;
+		Dbg64_cap_ptr_entry;
 		Dbg32_cap_sec_title;
 		Dbg64_cap_sec_title;
-		Dbg32_cap_val_hw1;
-		Dbg64_cap_val_hw1;
+		Dbg32_cap_val;
+		Dbg64_cap_val;
+		Dbg32_cap_val_entry;
+		Dbg64_cap_val_entry;
 
 		Dbg32_cb_iphdr_callback;
 		Dbg64_cb_iphdr_callback;
@@ -377,6 +379,14 @@
 		Dbg64_syms_ar_resolve;
 		Dbg32_syms_ar_title;
 		Dbg64_syms_ar_title;
+		Dbg32_syms_cap_convert;
+		Dbg64_syms_cap_convert;
+		Dbg32_syms_cap_local;
+		Dbg64_syms_cap_local;
+		Dbg32_syms_cap_lookup;
+		Dbg64_syms_cap_lookup;
+		Dbg32_syms_cap_title;
+		Dbg64_syms_cap_title;
 		Dbg32_syms_created;
 		Dbg64_syms_created;
 		Dbg32_syms_discarded;
--- a/usr/src/cmd/sgs/liblddbg/common/syminfo.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/syminfo.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,11 +20,9 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include	<sgs.h>
 #include	<stdio.h>
 #include	<debug.h>
@@ -43,19 +41,26 @@
 Elf_syminfo_entry(Lm_list *lml, Word ndx, Syminfo *sip, const char *name,
     const char *needed)
 {
-	const char	*bndstr, *str;
+	const char	*bndstr = NULL, *str;
 	char		flagstr[FLAGSZ], sndxstr[NDXSZ], dndxstr[NDXSZ];
 	int		flgndx = 0;
 	Half		flags = sip->si_flags;
 
+	if (flags & SYMINFO_FLG_CAP) {
+		bndstr = MSG_INTL(MSG_SYMINFO_CAP);
+		flagstr[flgndx++] = 'S';
+		flags &= ~SYMINFO_FLG_CAP;
+	}
+
 	if (flags & SYMINFO_FLG_DIRECT) {
-		if (sip->si_boundto == SYMINFO_BT_SELF)
-			bndstr = MSG_INTL(MSG_SYMINFO_SELF);
-		else if (sip->si_boundto == SYMINFO_BT_PARENT)
-			bndstr = MSG_INTL(MSG_SYMINFO_PARENT);
-		else
-			bndstr = needed;
-
+		if (bndstr == NULL) {
+			if (sip->si_boundto == SYMINFO_BT_SELF)
+				bndstr = MSG_INTL(MSG_SYMINFO_SELF);
+			else if (sip->si_boundto == SYMINFO_BT_PARENT)
+				bndstr = MSG_INTL(MSG_SYMINFO_PARENT);
+			else
+				bndstr = needed;
+		}
 		flagstr[flgndx++] = 'D';
 		flags &= ~SYMINFO_FLG_DIRECT;
 
@@ -71,7 +76,7 @@
 
 	} else if (sip->si_boundto == SYMINFO_BT_EXTERN)
 		bndstr = MSG_INTL(MSG_SYMINFO_EXTERN);
-	else
+	else if (bndstr == NULL)
 		bndstr = MSG_ORIG(MSG_STR_EMPTY);
 
 	if (flags & SYMINFO_FLG_DIRECTBIND) {
--- a/usr/src/cmd/sgs/liblddbg/common/syms.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/syms.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,6 +55,54 @@
 	    NAME(lmp), type);
 }
 
+static	const Msg captype[DBG_CAP_MACH + 1] = {
+	MSG_CAP_SYM_DEFAULT,		/* MSG_INTL(MSG_CAP_SYM_DEFAULT) */
+	MSG_CAP_SYM_USED,		/* MSG_INTL(MSG_CAP_SYM_USED) */
+	MSG_CAP_SYM_CANDIDATE,		/* MSG_INTL(MSG_CAP_SYM_CANDIDATE) */
+	MSG_CAP_SYM_REJECTED,		/* MSG_INTL(MSG_CAP_SYM_REJECTED) */
+	MSG_CAP_SYM_HW_1,		/* MSG_INTL(MSG_CAP_SYM_HW_1) */
+	MSG_CAP_SYM_SF_1,		/* MSG_INTL(MSG_CAP_SYM_SF_1) */
+	MSG_CAP_SYM_HW_2,		/* MSG_INTL(MSG_CAP_SYM_HW_2) */
+	MSG_CAP_SYM_PLAT,		/* MSG_INTL(MSG_CAP_SYM_PLAT) */
+	MSG_CAP_SYM_MACH		/* MSG_INTL(MSG_CAP_SYM_MACH) */
+};
+
+void
+Dbg_syms_cap_lookup(Rt_map *lmp, uint_t type, const char *name, uint_t ndx,
+    Half mach, Syscapset *scapset)
+{
+	Lm_list			*lml = LIST(lmp);
+	const char		*str = NULL;
+	Conv_cap_val_buf_t	cap_val_buf;
+
+	if (DBG_NOTCLASS(DBG_C_CAP | DBG_C_SYMBOLS))
+		return;
+
+	switch (type) {
+	case DBG_CAP_HW_1:
+		str = conv_cap_val_hw1(scapset->sc_hw_1, mach, 0,
+		    &cap_val_buf.cap_val_hw1_buf);
+		break;
+	case DBG_CAP_SF_1:
+		str = conv_cap_val_sf1(scapset->sc_sf_1, mach, 0,
+		    &cap_val_buf.cap_val_sf1_buf);
+		break;
+	case DBG_CAP_HW_2:
+		str = conv_cap_val_hw2(scapset->sc_hw_2, mach, 0,
+		    &cap_val_buf.cap_val_hw2_buf);
+		break;
+	case DBG_CAP_MACH:
+		str = scapset->sc_mach;
+		break;
+	case DBG_CAP_PLAT:
+		str = scapset->sc_plat;
+		break;
+	}
+
+	dbg_print(lml, MSG_INTL(captype[type]), Dbg_demangle_name(name),
+	    ndx, str);
+}
+
 void
 Dbg_syms_ignore_gnuver(Rt_map *lmp, const char *name, Word symndx,
     Versym verndx)
@@ -284,6 +332,46 @@
 }
 
 void
+Dbg_syms_cap_convert(Ofl_desc *ofl, Word ndx, const char *name, Sym *sym)
+{
+	if (DBG_NOTCLASS(DBG_C_CAP | DBG_C_SYMBOLS))
+		return;
+
+	dbg_print(ofl->ofl_lml, MSG_INTL(MSG_SYM_CAP_ORIG), EC_WORD(ndx),
+	    Dbg_demangle_name(name));
+
+	if (DBG_NOTDETAIL())
+		return;
+
+	Elf_syms_table_entry(ofl->ofl_lml, ELF_DBG_LD,
+	    MSG_INTL(MSG_STR_ORIGINAL), ofl->ofl_dehdr->e_ident[EI_OSABI],
+	    ofl->ofl_dehdr->e_machine, sym, 0, 0, NULL,
+	    MSG_ORIG(MSG_STR_EMPTY));
+}
+
+void
+Dbg_syms_cap_local(Ofl_desc *ofl, Word ndx, const char *name, Sym *sym,
+    Sym_desc *sdp)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	if (DBG_NOTCLASS(DBG_C_CAP | DBG_C_SYMBOLS))
+		return;
+
+	dbg_print(ofl->ofl_lml, MSG_INTL(MSG_SYM_CAP_LOCAL), EC_WORD(ndx),
+	    Dbg_demangle_name(name));
+
+	if (DBG_NOTDETAIL())
+		return;
+
+	Elf_syms_table_entry(ofl->ofl_lml, ELF_DBG_LD,
+	    MSG_INTL(MSG_STR_ENTERED), ofl->ofl_dehdr->e_ident[EI_OSABI],
+	    ofl->ofl_dehdr->e_machine, sym,
+	    sdp->sd_aux ? sdp->sd_aux->sa_overndx : 0, 0, NULL,
+	    conv_def_tag(sdp->sd_ref, &inv_buf));
+}
+
+void
 Dbg_syms_wrap(Lm_list *lml, Word ndx, const char *orig_name, const char *name)
 {
 	if (DBG_NOTCLASS(DBG_C_SYMBOLS))
@@ -617,3 +705,18 @@
 		    sec, Elf_demangle_name(poststr));
 	}
 }
+
+void
+Dbg_syms_cap_title(Ofl_desc *ofl)
+{
+	Lm_list	*lml = ofl->ofl_lml;
+
+	if (DBG_NOTCLASS(DBG_C_SYMBOLS))
+		return;
+	if (DBG_NOTDETAIL())
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_SYM_CAPABILITIES));
+	Elf_syms_table_title(lml, ELF_DBG_LD);
+}
--- a/usr/src/cmd/sgs/libldmake/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libldmake/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,12 +18,11 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 LIBRARY=	libldmake.a
 VERS=		.1
@@ -39,7 +38,7 @@
 
 SRCDIR =	../common
 
-DYNFLAGS +=	$(USE_PROTO)
+DYNFLAGS +=	$(CC_USE_PROTO)
 
 CFLAGS +=	$(C_PICFLAGS)
 CFLAGS64 +=	$(C_PICFLAGS64)
--- a/usr/src/cmd/sgs/libldstab/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/libldstab/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,6 +18,7 @@
 #
 # CDDL HEADER END
 #
+
 #
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -40,7 +41,7 @@
 CPPFLAGS +=	-I$(ELFCAP)
 
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf -lc
-DYNFLAGS +=	$(VERSREF)
+DYNFLAGS +=	$(VERSREF) $(CC_USE_PROTO)
 
 LINTFLAGS +=	-erroff=E_NAME_DECL_NOT_USED_DEF2 \
 		-erroff=E_NAME_DEF_NOT_USED2 \
@@ -49,15 +50,6 @@
 		-erroff=E_NAME_DEF_NOT_USED2 \
 		-erroff=E_NAME_USED_NOT_DEF2
 
-
-# A bug in pmake causes redundancy when '+=' is conditionally assigned, so
-# '=' is used with extra variables.
-# $(DYNLIB) :=	DYNFLAGS += -Yl,$(SGSPROTO)
-#
-XXXFLAGS=
-$(DYNLIB) :=	XXXFLAGS= $(USE_PROTO)
-DYNFLAGS +=	$(XXXFLAGS)
-
 SRCS=		$(COMOBJS:%.o=../common/%.c)
 LINTSRCS=	$(SRCS)
 
--- a/usr/src/cmd/sgs/librtld/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/librtld/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,12 +18,11 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 LIBRARY=	librtld.a
 VERS=		.1
@@ -43,20 +42,12 @@
 CPPFLAGS +=	-I../../rtld/common -I$(SRCBASE)/lib/libc/inc \
 		-I$(SRCBASE)/uts/common/krtld -I$(SRC)/common/sgsrtcid \
 		-I$(SRCBASE)/uts/sparc
-DYNFLAGS +=	$(VERSREF) '-R$$ORIGIN'
+DYNFLAGS +=	$(VERSREF) $(CC_USE_PROTO)  '-R$$ORIGIN'
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf -lc
 
 LINTFLAGS +=	-u -erroff=E_NAME_DECL_NOT_USED_DEF2
 LINTFLAGS64 +=	-u -erroff=E_NAME_DECL_NOT_USED_DEF2
 
-# A bug in pmake causes redundancy when '+=' is conditionally assigned, so
-# '=' is used with extra variables.
-#
-XXXFLAGS=
-$(DYNLIB) :=	XXXFLAGS= $(USE_PROTO)
-DYNFLAGS +=	$(XXXFLAGS)
-
-
 BLTDEFS=	msg.h
 BLTDATA=	msg.c
 BLTMESG=	$(SGSMSGDIR)/librtld
--- a/usr/src/cmd/sgs/librtld/common/relocate.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/librtld/common/relocate.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,10 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include	<libelf.h>
 #include	<dlfcn.h>
@@ -101,6 +100,7 @@
 		int		_bound, _weak;
 		ulong_t		rsymndx = ELF_R_SYM(rel->r_info);
 		Slookup		sl;
+		Sresult		sr;
 		uint_t		binfo;
 		Sym		*_sym, *sym = (syms + rsymndx);
 
@@ -275,14 +275,19 @@
 		 * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
 		 * does this for them).
 		 *
-		 * Initialize the symbol lookup data structure.
+		 * Initialize the symbol lookup, and symbol result, data
+		 * structures.
 		 */
 		SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
 		    0, rsymndx, sym, type, LKUP_STDRELOC);
+		SRESULT_INIT(sr, name);
 
 		_bound = _weak = 0;
 		_sym = sym;
-		if ((sym = lookup_sym(&sl, &_lmp, &binfo, NULL)) != 0) {
+		if (lookup_sym(&sl, &sr, &binfo, NULL)) {
+			_lmp = sr.sr_dmap;
+			sym = sr.sr_sym;
+
 			/*
 			 * Determine from the various relocation requirements
 			 * whether this binding is appropriate.  If we're called
--- a/usr/src/cmd/sgs/link_audit/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/link_audit/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,8 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -92,7 +93,7 @@
 $(ROOTCCSLIB) :=	DIRMODE =	755
 
 CPPFLAGS +=	-D_REENTRANT
-LDFLAGS +=	$(USE_PROTO)
+LDFLAGS +=	$(CC_USE_PROTO)
 DYNFLAGS +=	$(VERSREF)
 
 LINTFLAGS +=	-uaxs $(LDLIBS)
--- a/usr/src/cmd/sgs/moe/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/moe/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -20,11 +20,9 @@
 #
 
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 PROG=		moe
 
@@ -39,7 +37,7 @@
 MAPFILE=	$(MAPFILE.NGB)
 MAPOPT=		$(MAPFILE:%=-M%)
 
-LDFLAGS +=	-Wl,$(VERSREF) $(USE_PROTO) $(MAPOPT)
+LDFLAGS +=	-Wl,$(VERSREF) $(CC_USE_PROTO) $(MAPOPT)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB)
 
 LINTFLAGS +=	-x
--- a/usr/src/cmd/sgs/moe/common/moe.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/moe/common/moe.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -120,21 +120,23 @@
 	 */
 	if ((handle = dlmopen(LM_ID_NEWLM, name,
 	    (RTLD_FIRST | RTLD_CONFGEN | RTLD_LAZY))) == 0) {
-		if (verbose)
+		if (verbose) {
 			(void) fprintf(stderr, MSG_ORIG(MSG_FMT_VERBOSE), prog,
 			    modestr, trim_msg(dlerror()));
 			(void) fflush(stderr);
+		}
 		return (1);
 	}
 	if (silent == 0) {
 		Link_map	*lmp;
 
 		if (dlinfo(handle, RTLD_DI_LINKMAP, &lmp) == -1) {
-			if (verbose)
+			if (verbose) {
 				(void) fprintf(stderr,
 				    MSG_ORIG(MSG_FMT_VERBOSE), prog, modestr,
 				    trim_msg(dlerror()));
 				(void) fflush(stderr);
+			}
 			return (1);
 		}
 
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Mon Mar 01 10:20:48 2010 -0800
@@ -829,6 +829,13 @@
 	Solaris/SunOS 5.8_sparc		patch T109147-29
 	Solaris/SunOS 5.8_x86		patch T109148-29
 --------------------------------------------------------------------------------
+All the above changes plus:
+	6850124 dlopen reports "No such file or directory" in spite of ENOMEM
+		when mmap fails in anon_map()
+are incorporated in the following patches:
+	Solaris/SunOS 5.9_sparc		patch TXXXXXX-XX
+	Solaris/SunOS 5.9_x86		patch TXXXXXX-XX
+--------------------------------------------------------------------------------
 
 ----------
 Solaris 10
@@ -1275,8 +1282,15 @@
 6786744 32-bit dbx failed with unknown rtld_db.so error on snv_104
 --------------------------------------------------------------------------------
 All the above changes are incorporated in the following patches:
-	Solaris/SunOS 5.10_sparc	patch TXXXXXX-XX
-	Solaris/SunOS 5.10_x86		patch TXXXXXX-XX
+	Solaris/SunOS 5.10_sparc	patch T141444-06
+	Solaris/SunOS 5.10_x86		patch T141445-06
+--------------------------------------------------------------------------------
+All the above changes plus:
+	6850124 dlopen reports "No such file or directory" in spite of ENOMEM
+		when mmap fails in anon_map()
+are incorporated in the following patches:
+	Solaris/SunOS 5.10_sparc	patch T143895-01
+	Solaris/SunOS 5.10_x86		patch T143896-01
 --------------------------------------------------------------------------------
 
 --------------------------------------------
@@ -1436,7 +1450,7 @@
 6724311 dldump() mishandles R_AMD64_JUMP_SLOT relocations
 6724774 elfdump -n doesn't print siginfo structure
 6728555 Fix for amd64 aw (6617475) breaks pure gcc builds
-6734598 ld(1) archive processing failure due to mismatched file descriptors
+6734598 ld(1) archive processing failure due to mismatched file descriptors (D)
 6684577 ld should propagate SHF_LINK_ORDER flag to ET_REL objects
 6735939 ld(1) discarded symbol relocations errors (Studio and GNU).
 6354160 Solaris linker includes more than one copy of code in binary when
@@ -1522,8 +1536,8 @@
 6851224 elf_getshnum() and elf_getshstrndx() incompatible with 2002 ELF gABI
 	agreement (D)
 	PSARC/2009/363 replace elf_getphnum, elf_getshnum, and elf_getshstrndx
-6853809	ld.so.1: rescan fallback optimization is invalid
-6854158	ld.so.1: interposition can be skipped because of incorrect
+6853809 ld.so.1: rescan fallback optimization is invalid
+6854158 ld.so.1: interposition can be skipped because of incorrect
 	caller/destination validation
 6862967 rd_loadobj_iter() failing for core files
 6856173 streams core dumps when compiled in 64bit with a very large static
@@ -1551,3 +1565,6 @@
 6916788 ld version 2 mapfile syntax (D)
 	PSARC/2009/688 Human readable and extensible ld mapfile syntax
 6929607 ld generates incorrect VERDEF entries for ET_REL output objects
+6924224 linker should ignore SUNW_dof when calculating the elf checksum
+6918143 symbol capabilities (D)
+6910387 .tdata and .tbss separation invalidates TLS program header information
--- a/usr/src/cmd/sgs/pvs/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/pvs/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -42,7 +42,7 @@
 CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc
 LLDFLAGS =	'-R$$ORIGIN/../lib'
 LLDFLAGS64 =	'-R$$ORIGIN/../../lib/$(MACH64)'
-LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
+LDFLAGS +=	$(VERSREF) $(CC_USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
 LDLIBS +=	$(LDDBGLIBDIR) $(LDDBG_LIB) $(ELFLIBDIR) -lelf \
 		    $(CONVLIBDIR) $(CONV_LIB)
 LINTFLAGS +=	-x
--- a/usr/src/cmd/sgs/rtld/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -18,12 +18,11 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 RTLD=		ld.so.1
 
@@ -31,10 +30,12 @@
 DTROBJ=		dtrace_data.o
 TOOLOBJS=	alist.o strhash.o
 BLTOBJ=		msg.o
+ELFCAPOBJ=	elfcap.o
 OBJECTS=	$(BLTOBJ) \
 		$(AVLOBJ) \
 		$(DTROBJ) \
 		$(TOOLOBJS) \
+		$(ELFCAPOBJ) \
 		$(P_ASOBJS)   $(P_COMOBJS)   $(P_MACHOBJS)   $(G_MACHOBJS)  \
 		$(S_ASOBJS)   $(S_COMOBJS)   $(S_MACHOBJS)   $(CP_MACHOBJS)
 
@@ -47,6 +48,7 @@
 include		$(SRC)/cmd/sgs/Makefile.com
 
 SRCDIR =	../common
+ELFCAP =	$(SRC)/common/elfcap
 PLAT =		$(VAR_PLAT_$(BASEPLAT))
 
 # DTrace needs an executable data segment.
@@ -79,6 +81,7 @@
 		-I$(SRCBASE)/uts/$(PLAT) \
 		-I$(SRCBASE)/uts/$(PLAT)/krtld \
 		-I$(SRC)/common/sgsrtcid \
+		-I$(ELFCAP) \
 		 $(CPPFEATUREMACROS)
 
 ASFLAGS=	-P -D_ASM $(CPPFLAGS)
--- a/usr/src/cmd/sgs/rtld/Makefile.targ	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/Makefile.targ	Mon Mar 01 10:20:48 2010 -0800
@@ -18,8 +18,9 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -61,8 +62,12 @@
 		$(COMPILE.c) -o $@ $<
 		$(POST_PROCESS_O)
 
+pics/elfcap.o:	$(ELFCAP)/elfcap.c
+		$(COMPILE.c) -o $@ $(ELFCAP)/elfcap.c
+		$(POST_PROCESS_O)
+
 $(RTLD):	pics $(PICS) $(CRTS)
-		$(SGSPROTO)/ld -o $@ -dy -G $(DYNFLAGS) $(CRTI) $(PICS) \
+		$(LD_USE_PROTO)ld -o $@ -dy -G $(DYNFLAGS) $(CRTI) $(PICS) \
 		    $(LDLIBS) $(CRTN)
 		$(POST_PROCESS_SO)
 
--- a/usr/src/cmd/sgs/rtld/amd64/amd64_elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/amd64/amd64_elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)amd64_elf.c	1.25	08/07/30 SMI"
-
 /*
  * amd64 machine dependent and ELF file class dependent functions.
  * Contains routines for performing function binding and symbol relocations.
@@ -219,6 +217,7 @@
 	Sym		*rsym, *nsym;
 	uint_t		binfo, sb_flags = 0, dbg_class;
 	Slookup		sl;
+	Sresult		sr;
 	int		entry, lmflags;
 	Lm_list		*lml;
 
@@ -268,19 +267,25 @@
 	llmp = lml->lm_tail;
 
 	/*
-	 * Find definition for symbol.  Initialize the symbol lookup data
-	 * structure.
+	 * Find definition for symbol.  Initialize the symbol lookup, and
+	 * symbol result, data structures.
 	 */
 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0,
 	    rsymndx, rsym, 0, LKUP_DEFT);
+	SRESULT_INIT(sr, name);
 
-	if ((nsym = lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) {
+	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
 		    demangle(name));
 		rtldexit(lml, 1);
 	}
 
+	name = (char *)sr.sr_name;
+	nlmp = sr.sr_dmap;
+	nsym = sr.sr_sym;
+
 	symval = nsym->st_value;
+
 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
 	    (nsym->st_shndx != SHN_ABS))
 		symval += ADDR(nlmp);
@@ -431,6 +436,7 @@
 	 */
 	if (plt) {
 		Slookup	sl;
+		Sresult	sr;
 
 		relbgn = pltbgn;
 		relend = pltend;
@@ -438,14 +444,17 @@
 			return (1);
 
 		/*
-		 * Initialize the symbol lookup data structure.
+		 * Initialize the symbol lookup, and symbol result, data
+		 * structures.
 		 */
 		SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_PLT), lmp, lmp, ld_entry_cnt,
 		    elf_hash(MSG_ORIG(MSG_SYM_PLT)), 0, 0, 0, LKUP_DEFT);
+		SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_PLT));
 
-		if ((symdef = elf_find_sym(&sl, &_lmp, &binfo, NULL)) == 0)
+		if (elf_find_sym(&sl, &sr, &binfo, NULL) == 0)
 			return (1);
 
+		symdef = sr.sr_sym;
 		_pltbgn = symdef->st_value;
 		if (!(FLAGS(lmp) & FLG_RT_FIXED) &&
 		    (symdef->st_shndx != SHN_ABS))
@@ -622,7 +631,7 @@
 			 */
 			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
 				value = basebgn;
-				name = (char *)0;
+				name = NULL;
 
 				/*
 				 * Special case TLS relocations.
@@ -684,11 +693,12 @@
 					}
 				} else {
 					Slookup		sl;
+					Sresult		sr;
 
 					/*
 					 * Lookup the symbol definition.
-					 * Initialize the symbol lookup data
-					 * structure.
+					 * Initialize the symbol lookup, and
+					 * symbol result, data structure.
 					 */
 					name = (char *)(STRTAB(lmp) +
 					    symref->st_name);
@@ -696,9 +706,15 @@
 					SLOOKUP_INIT(sl, name, lmp, 0,
 					    ld_entry_cnt, 0, rsymndx, symref,
 					    rtype, LKUP_STDRELOC);
+					SRESULT_INIT(sr, name);
+					symdef = NULL;
 
-					symdef = lookup_sym(&sl, &_lmp,
-					    &binfo, in_nfavl);
+					if (lookup_sym(&sl, &sr, &binfo,
+					    in_nfavl)) {
+						name = (char *)sr.sr_name;
+						_lmp = sr.sr_dmap;
+						symdef = sr.sr_sym;
+					}
 
 					/*
 					 * If the symbol is not found and the
@@ -822,7 +838,8 @@
 				value = TLSMODID(lmp);
 			} else
 				value = basebgn;
-			name = (char *)0;
+
+			name = NULL;
 		}
 
 		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
--- a/usr/src/cmd/sgs/rtld/common/_a.out.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/_a.out.h	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_A_DOT_OUT_DOT_H
@@ -44,7 +44,7 @@
  */
 extern	ulong_t	aout_bndr(caddr_t);
 extern	int	aout_get_mmap(Lm_list *, mmapobj_result_t *);
-extern	Sym	*aout_lookup_sym(Slookup *, Rt_map **, uint_t *, int *);
+extern	int	aout_lookup_sym(Slookup *, Sresult *, uint_t *, int *);
 extern	Rt_map	*aout_new_lmp(Lm_list *, Aliste, Fdesc *, Addr, size_t, void *,
 		    int *);
 extern	void	aout_plt_write(caddr_t, ulong_t);
--- a/usr/src/cmd/sgs/rtld/common/_elf.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/_elf.h	Mon Mar 01 10:20:48 2010 -0800
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	__ELF_DOT_H
@@ -31,6 +31,7 @@
 
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <sgs.h>
 #include <elf.h>
 #include <_rtld.h>
 
@@ -50,11 +51,11 @@
 #endif
 extern	int	elf_copy_reloc(char *, Sym *, Rt_map *, void *, Sym *,
 		    Rt_map *, const void *);
-extern	Sym	*elf_find_sym(Slookup *, Rt_map **, uint_t *, int *);
-extern	Sym	*elf_lazy_find_sym(Slookup *, Rt_map **, uint_t *, int *);
+extern	int	elf_find_sym(Slookup *, Sresult *, uint_t *, int *);
+extern	int	elf_lazy_find_sym(Slookup *, Sresult *, uint_t *, int *);
 extern	Rt_map	*elf_lazy_load(Rt_map *, Slookup *, uint_t, const char *,
 		    uint_t, Grp_hdl **, int *);
-extern	Sym	*elf_lookup_filtee(Slookup *, Rt_map **, uint_t *, uint_t,
+extern	int	elf_lookup_filtee(Slookup *, Sresult *, uint_t *, uint_t,
 		    int *);
 extern	int	elf_mach_flags_check(Rej_desc *, Ehdr *);
 extern	Rt_map	*elf_new_lmp(Lm_list *, Aliste, Fdesc *, Addr, size_t, void *,
@@ -126,6 +127,10 @@
 	ulong_t		e_syminent;	/* syminfo entry size */
 	void		*e_pltpad;	/* PLTpad table */
 	void		*e_pltpadend;	/* end of PLTpad table */
+	Syscapset	e_capset;	/* capabilities set */
+	Capinfo		*e_capinfo;	/* symbol capabilities information */
+	uint_t		e_capchainent;	/* size of capabilities chain entry */
+	uint_t		e_capchainsz;	/* size of capabilities chain data */
 } Rt_elfp;
 
 /*
@@ -161,6 +166,10 @@
 #define	SUNWSORTENT(X)		(((Rt_elfp *)(X)->rt_priv)->e_sunwsortent)
 #define	SUNWSYMSORT(X)		(((Rt_elfp *)(X)->rt_priv)->e_sunwsymsort)
 #define	SUNWSYMSORTSZ(X)	(((Rt_elfp *)(X)->rt_priv)->e_sunwsymsortsz)
+#define	CAPSET(X)		(((Rt_elfp *)(X)->rt_priv)->e_capset)
+#define	CAPINFO(X)		(((Rt_elfp *)(X)->rt_priv)->e_capinfo)
+#define	CAPCHAINENT(X)		(((Rt_elfp *)(X)->rt_priv)->e_capchainent)
+#define	CAPCHAINSZ(X)		(((Rt_elfp *)(X)->rt_priv)->e_capchainsz)
 
 /*
  * Most of the above macros are used from ELF specific routines, however there
--- a/usr/src/cmd/sgs/rtld/common/_rtld.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/_rtld.h	Mon Mar 01 10:20:48 2010 -0800
@@ -85,7 +85,7 @@
 	int	(*fct_needed)(Lm_list *, Aliste, Rt_map *, int *);
 
 	/* Look up a symbol for the object. */
-	Sym	*(*fct_lookup_sym)(Slookup *, Rt_map **, uint_t *, int *);
+	int	(*fct_lookup_sym)(Slookup *, Sresult *, uint_t *, int *);
 
 	/* Relocate the object. */
 	int	(*fct_reloc)(Rt_map *, uint_t, int *, APlist **);
@@ -107,8 +107,7 @@
 	void	(*fct_dladdr)(ulong_t, Rt_map *, Dl_info *, void **, int);
 
 	/* Process a dlsym(3c) request within the object. */
-	Sym	*(*fct_dlsym)(Grp_hdl *, Slookup *, Rt_map **, uint_t *,
-		    int *);
+	int	(*fct_dlsym)(Grp_hdl *, Slookup *, Sresult *, uint_t *, int *);
 };
 
 /*
@@ -157,7 +156,7 @@
 #define	AL_CNT_FILTEES	2		/* filtee path */
 #define	AL_CNT_HANDLES	1		/* hdl_list[] */
 #define	AL_CNT_FREELIST	80		/* free_alp */
-#define	AL_CNT_HWCAP	10		/* hwcap candidate */
+#define	AL_CNT_CAP	10		/* capabilities candidate */
 #define	AL_CNT_SPATH	4		/* search path */
 #define	AL_CNT_DYNLIST	2		/* dynlm_list */
 #define	AL_CNT_PENDING	2		/* pending tsort list (INITFIRST) */
@@ -237,7 +236,7 @@
 	rtld_ino_t	fd_ino;		/* file inode number */
 	uint_t		fd_flags;
 	avl_index_t	fd_avlwhere;	/* avl tree insertion index */
-	Xword		fd_hwcap;	/* hardware capabilities value */
+	Syscapset	fd_scapset;	/* capabilities */
 	mmapobj_result_t *fd_mapp;	/* mapping pointer */
 	uint_t		fd_mapn;	/* mapping number */
 };
@@ -245,6 +244,10 @@
 #define	FLG_FD_ALTER	0x0001		/* file is an alternate */
 #define	FLG_FD_SLASH	0x0002		/* file contains a "/" */
 #define	FLG_FD_RESOLVED	0x0004		/* fd_nname has been resolved */
+#define	FLG_FD_ALTCHECK	0x0008		/* alternative system capabilities */
+					/*	checked */
+#define	FLG_FD_ALTCAP	0x0010		/* alternative system capabilities */
+					/*	should be used */
 
 /*
  * File descriptor availability flag.
@@ -389,8 +392,10 @@
 #define	PD_TKN_OSNAME	0x00004000	/* $OSNAME expansion has occurred */
 #define	PD_TKN_OSREL	0x00008000	/* $OSREL expansion has occurred */
 #define	PD_TKN_ISALIST	0x00010000	/* $ISALIST expansion has occurred */
-#define	PD_TKN_HWCAP	0x00020000	/* $HWCAP expansion has occurred */
-#define	PD_TKN_RESOLVED	0x00040000	/* resolvepath() expansion has */
+#define	PD_TKN_CAP	0x00020000	/* $CAPABILITY/$HWCAP expansion has */
+					/*	occurred */
+#define	PD_TKN_MACHINE	0x00040000	/* $MACHINE expansion has occurred */
+#define	PD_TKN_RESOLVED	0x00080000	/* resolvepath() expansion has */
 					/*	occurred */
 #define	PD_MSK_EXPAND	0x000ff000	/* mask for all expansions */
 
@@ -514,8 +519,6 @@
 extern const char	*rtldname;	/* name of the dynamic linker */
 extern APlist		*hdl_alp[];	/* dlopen() handle list */
 extern size_t		syspagsz;	/* system page size */
-extern char		*platform; 	/* platform name */
-extern size_t		platform_sz; 	/* platform name string size */
 extern Isa_desc		*isa;		/* isalist descriptor */
 extern Uts_desc		*uts;		/* utsname descriptor */
 extern uint_t		rtld_flags;	/* status flags for RTLD */
@@ -573,6 +576,7 @@
 
 extern const Msg	err_reject[];	/* rejection error message tables */
 extern const Msg	ldd_reject[];
+extern const Msg	ldd_warn[];
 
 extern const char	*profile_name;	/* object being profiled */
 extern const char	*profile_out;	/* profile output file */
@@ -585,10 +589,24 @@
 					/* diagnostic error string headers */
 extern const char	*nosym_str;	/* MSG_GEN_NOSYM message cache */
 
-extern ulong_t		hwcap;		/* hardware capabilities */
-extern ulong_t		sfcap;		/* software capabilities */
+extern Syscapset	*org_scapset;	/* original system capabilities */
+extern Syscapset	*alt_scapset;	/* alternative system capabilities */
+
+extern const char	*rpl_hwcap;	/* replaceable hwcap str */
+extern const char	*rpl_sfcap;	/* replaceable sfcap str */
+extern const char	*rpl_machcap;	/* replaceable machcap str */
+extern const char	*rpl_platcap;	/* replaceable platcap str */
+extern const char	*rpl_cap_files;	/* associated files */
 
-extern avl_tree_t	*nfavl;		/* not-found AVL path name tree */
+extern const char	*prm_hwcap;	/* permanent hwcap str */
+extern const char	*prm_sfcap;	/* permanent sfcap str */
+extern const char	*prm_machcap;	/* permanent machcap str */
+extern const char	*prm_platcap;	/* permanent platcap str */
+extern const char	*prm_cap_files;	/* associated files */
+
+extern avl_tree_t	*capavl;	/* capabilities files */
+extern avl_tree_t	*nfavl;		/* not-found path names */
+extern avl_tree_t	*spavl;		/* secure path names */
 
 extern u_longlong_t	cnt_map;	/* Incr. for each object mapped */
 extern u_longlong_t	cnt_unmap;	/* Incr. for each object unmapped */
@@ -609,7 +627,12 @@
 extern Rt_map		*_caller(caddr_t, int);
 extern caddr_t		caller(void);
 extern void		*calloc(size_t, size_t);
-extern void		cap_assign(Cap *, Rt_map *);
+extern int		cap_alternative(void);
+extern int		cap_check_fdesc(Fdesc *, Cap *, char *, Rej_desc *);
+extern int		cap_check_lmp(Rt_map *, Rej_desc *);
+extern int 		cap_filtees(Alist **, Aliste, const char *, Aliste,
+			    Rt_map *, const char *, int, uint_t, int *);
+extern int		cap_match(Sresult *, uint_t, Sym *, char *);
 extern const char	*_conv_reloc_type(uint_t rel);
 extern Aliste		create_cntl(Lm_list *, int);
 extern void		defrag(void);
@@ -617,8 +640,8 @@
 extern const char	*demangle(const char *);
 extern int		dlclose_intn(Grp_hdl *, Rt_map *);
 extern int		dlclose_core(Grp_hdl *, Rt_map *, Lm_list *);
-extern Sym		*dlsym_handle(Grp_hdl *, Slookup *, Rt_map **,
-			    uint_t *, int *);
+extern int		dlsym_handle(Grp_hdl *, Slookup *, Sresult *, uint_t *,
+			    int *);
 extern void		*dlsym_intn(void *, const char *, Rt_map *, Rt_map **);
 extern Grp_hdl		*dlmopen_intn(Lm_list *, const char *, int, Rt_map *,
 			    uint_t, uint_t);
@@ -647,9 +670,8 @@
 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(Xword, Rej_desc *);
-extern int 		hwcap_filtees(Alist **, Aliste, const char *, Aliste,
-			    Rt_map *, const char *, int, uint_t, int *);
+extern int		hwcap1_check(Syscapset *, Xword, Rej_desc *);
+extern int		hwcap2_check(Syscapset *, Xword, Rej_desc *);
 extern void		is_dep_init(Rt_map *, Rt_map *);
 extern int		is_move_data(caddr_t);
 extern int		is_path_secure(char *, Rt_map *, uint_t, uint_t);
@@ -661,22 +683,27 @@
 extern void		lm_delete(Lm_list *, Rt_map *);
 extern void		lm_move(Lm_list *, Aliste, Aliste, Lm_cntl *,
 			    Lm_cntl *);
+extern Rt_map 		*load_cap(Lm_list *, Aliste, const char *, Rt_map *,
+			    uint_t, uint_t, Grp_hdl **, Rej_desc *, int *);
 extern void		load_completion(Rt_map *);
 extern Rt_map		*load_file(Lm_list *, Aliste, Fdesc *, int *);
-extern Rt_map 		*load_hwcap(Lm_list *, Aliste, const char *, Rt_map *,
-			    uint_t, uint_t, Grp_hdl **, Rej_desc *, int *);
 extern Rt_map		*load_path(Lm_list *, Aliste, Rt_map *, int, uint_t,
 			    Grp_hdl **, Fdesc *, Rej_desc *, int *);
 extern Rt_map		*load_one(Lm_list *, Aliste, Alist *, Rt_map *, int,
 			    uint_t, Grp_hdl **, int *);
 extern const char	*load_trace(Lm_list *, Pdesc *, Rt_map *, Fdesc *);
 extern void		nfavl_insert(const char *, avl_index_t);
-extern int		nfavl_recorded(const char *, uint_t, avl_index_t *);
 extern void		*nu_map(Lm_list *, caddr_t, size_t, int, int);
 extern Fct		*map_obj(Lm_list *, Fdesc *, size_t, const char *, int,
 			    Rej_desc *);
 extern void		*malloc(size_t);
+extern int		machcap_check(Syscapset *, const char *, Rej_desc *);
+extern void		machine_name(Syscapset *);
 extern int		move_data(Rt_map *, APlist **);
+extern int		platcap_check(Syscapset *, const char *, Rej_desc *);
+extern void		platform_name(Syscapset *);
+extern int		pnavl_recorded(avl_tree_t **, const char *, uint_t,
+			    avl_index_t *);
 extern void		rd_event(Lm_list *, rd_event_e, r_state_e);
 extern int		readenv_user(const char **, Word *, Word *, int);
 extern int		readenv_config(Rtc_env *, Addr, int);
@@ -718,8 +745,7 @@
 			    uid_t, uid_t, gid_t, gid_t, void *, int, uint_t);
 extern const char	*stravl_insert(const char *, uint_t, size_t, int);
 extern void		spavl_insert(const char *);
-extern int		spavl_recorded(const char *, avl_index_t *);
-extern int		sfcap_check(Xword, Rej_desc *);
+extern int		sfcap1_check(Syscapset *, Xword, Rej_desc *);
 extern int		tls_assign(Lm_list *, Rt_map *, Phdr *);
 extern void		tls_modaddrem(Rt_map *, uint_t);
 extern int		tls_statmod(Lm_list *, Rt_map *);
--- a/usr/src/cmd/sgs/rtld/common/a.out.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/a.out.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -69,15 +69,14 @@
  * Defines for local functions.
  */
 static void	aout_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int);
-static Sym	*aout_dlsym_handle(Grp_hdl *, Slookup *, Rt_map **, uint_t *,
-		    int *l);
+static int	aout_dlsym_handle(Grp_hdl *, Slookup *, Sresult *, uint_t *,
+		    int *);
 static Addr	aout_entry_point(void);
-static Sym	*aout_find_sym(Slookup *, Rt_map **, uint_t *, int *);
+static int	aout_find_sym(Slookup *, Sresult *, uint_t *, int *);
 static int	aout_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t);
 static Alist	**aout_get_def_dirs(void);
 static Alist	**aout_get_sec_dirs(void);
 static char	*aout_get_so(const char *, const char *, size_t, size_t);
-extern Sym	*aout_lookup_sym(Slookup *, Rt_map **, uint_t *, int *);
 static int	aout_needed(Lm_list *, Aliste, Rt_map *, int *);
 
 /*
@@ -441,8 +440,8 @@
  * ii.	   .bar		->	   .bar		(LKUP_LDOT)
  * iii.	    nuts	->	   .nuts
  */
-Sym *
-aout_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
+int
+aout_lookup_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
 	char	name[PATH_MAX];
 	Slookup	sl = *slp;
@@ -463,15 +462,15 @@
 	 * Call the generic lookup routine to cycle through the specified
 	 * link maps.
 	 */
-	return (lookup_sym(&sl, dlmp, binfo, in_nfavl));
+	return (lookup_sym(&sl, srp, binfo, in_nfavl));
 }
 
 /*
  * Symbol lookup for an a.out format module.
  */
 /* ARGSUSED3 */
-static Sym *
-aout_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
+static int
+aout_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
 	const char	*name = slp->sl_name;
 	Rt_map		*ilmp = slp->sl_imap;
@@ -486,14 +485,15 @@
 			 */
 			if (sp->n_type == (N_EXT + N_UNDF)) {
 				if ((sp = aout_find_com(sp, name)) == 0)
-					return (NULL);
+					return (0);
 			}
-			*dlmp = ilmp;
+			srp->sr_dmap = ilmp;
+			srp->sr_sym = aout_symconvert(sp);
 			*binfo |= DBG_BINFO_FOUND;
-			return (aout_symconvert(sp));
+			return (1);
 		}
 	}
-	return (NULL);
+	return (0);
 }
 
 /*
@@ -677,19 +677,15 @@
  * individual link-maps we don't need to supply a starting link-map to the
  * lookup routine (see lookup_sym():analyze.c).
  */
-static Sym *
-aout_dlsym_handle(Grp_hdl *ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo,
+static int
+aout_dlsym_handle(Grp_hdl *ghp, Slookup *slp, Sresult *srp, uint_t *binfo,
     int *in_nfavl)
 {
-	Sym	*sym;
 	char	buffer[PATH_MAX];
 	Slookup	sl;
 
-	buffer[0] = '_';
-	(void) strcpy(&buffer[1], slp->sl_name);
-
-	if ((sym = dlsym_handle(ghp, slp, _lmp, binfo, in_nfavl)) != 0)
-		return (sym);
+	if (dlsym_handle(ghp, slp, srp, binfo, in_nfavl))
+		return (1);
 
 	/*
 	 * Symbol not found as supplied.  However, most of our symbols will
@@ -697,10 +693,13 @@
 	 * to the symbol as it emits it.  Therefore, attempt to find the
 	 * symbol with the "_" prepend.
 	 */
+	buffer[0] = '_';
+	(void) strcpy(&buffer[1], slp->sl_name);
+
 	sl = *slp;
 	sl.sl_name = (const char *)buffer;
 
-	return (dlsym_handle(ghp, &sl, _lmp, binfo, in_nfavl));
+	return (dlsym_handle(ghp, &sl, srp, binfo, in_nfavl));
 }
 
 /*
--- a/usr/src/cmd/sgs/rtld/common/analyze.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/analyze.c	Mon Mar 01 10:20:48 2010 -0800
@@ -67,16 +67,24 @@
 		Slookup		sl;
 
 		/*
-		 * Initialize the symbol lookup data structure.
+		 * Initialize the symbol lookup data structure.  Note, no symbol
+		 * name is supplied.  This NULL name causes filters to be loaded
+		 * but no symbol to be searched for.
 		 */
 		SLOOKUP_INIT(sl, 0, lmp, lmp, ld_entry_cnt, 0, 0, 0, 0, 0);
 
 		for (cnt = 0; cnt < max; cnt++, dip++) {
+			uint_t	binfo;
+			Sresult	sr;
+
+			SRESULT_INIT(sr, NULL);
+
 			if (((dip->di_flags & MSK_DI_FILTER) == 0) ||
 			    ((dip->di_flags & FLG_DI_AUXFLTR) &&
 			    (rtld_flags & RT_FL_NOAUXFLTR)))
 				continue;
-			(void) elf_lookup_filtee(&sl, 0, 0, cnt, in_nfavl);
+			(void) elf_lookup_filtee(&sl, &sr, &binfo, cnt,
+			    in_nfavl);
 		}
 	}
 }
@@ -490,8 +498,8 @@
 	 * may be involved.  Under the first pass, RTLD_CONFGEN is set.  Under
 	 * this pass, crle() loads objects into the process address space.  No
 	 * relocation is necessary at this point, we simply need to analyze the
-	 * objects to insure any directly bound dependencies, filtees, etc.
-	 * get loaded. Although we skip the relocation, fall through to insure
+	 * objects to ensure any directly bound dependencies, filtees, etc.
+	 * get loaded.  Although we skip the relocation, fall through to ensure
 	 * any control lists are maintained appropriately.
 	 *
 	 * If objects are to be dldump(3c)'ed, crle(1) makes a second pass,
@@ -761,7 +769,7 @@
  *
  * A traversal through the callers link-map list is carried out, and from each
  * link-map, a comparison is made against all of the various names by which the
- * object has been referenced.  is_so_matched() is used to compares the link-map
+ * object has been referenced.  is_so_matched() is used to compare the link-map
  * names against the name being searched for.  Whether the search name is a full
  * path name or a simple file name, governs what comparisons are made.
  *
@@ -791,7 +799,7 @@
 		    ((FLAGS(lmp) & (FLG_RT_OBJECT | FLG_RT_DELETE)) == 0))
 			return (lmp);
 
-		if (nfavl_recorded(name, hash, 0)) {
+		if (pnavl_recorded(&nfavl, name, hash, NULL)) {
 			/*
 			 * For dlopen() and dlsym() fall backs, indicate that
 			 * a registered not-found path has indicated that this
@@ -827,7 +835,7 @@
 /*
  * Tracing is enabled by the LD_TRACE_LOADED_OPTIONS environment variable which
  * is normally set from ldd(1).  For each link map we load, print the load name
- * and the full pathname of the shared object.
+ * and the full pathname of the associated object.
  */
 /* ARGSUSED4 */
 static void
@@ -892,7 +900,6 @@
 		    reject);
 }
 
-
 /*
  * Establish a link-map mode, initializing it if it has just been loaded, or
  * potentially updating it if it already exists.
@@ -1158,14 +1165,14 @@
 			fdp->fd_lmp = nlmp;
 			return (1);
 		}
-		if (nfavl_recorded(nname, hash, &nfavlwhere)) {
+		if (pnavl_recorded(&nfavl, nname, hash, &nfavlwhere)) {
 			/*
 			 * For dlopen() and dlsym() fall backs, indicate that
 			 * a registered not-found path has indicated that this
 			 * object does not exist.  If this path has been
-			 * constructed as part of expanding a HWCAP directory,
-			 * this is a silent failure, where no rejection message
-			 * is created.
+			 * constructed as part of expanding a CAPABILITY
+			 * directory, this is a silent failure, where no
+			 * rejection message is created.
 			 */
 			if (in_nfavl)
 				(*in_nfavl)++;
@@ -1179,12 +1186,12 @@
 
 		/*
 		 * If this path has been constructed as part of expanding a
-		 * HWCAP directory, ignore any subdirectories.  As this is a
-		 * silent failure, no rejection message is created.  For any
-		 * other reference that expands to a directory, fall through
-		 * to construct a meaningful rejection message.
+		 * CAPABILITY directory, ignore any subdirectories.  As this
+		 * is a silent failure, no rejection message is created.  For
+		 * any other reference that expands to a directory, fall
+		 * through to construct a meaningful rejection message.
 		 */
-		if ((flags & FLG_RT_HWCAP) &&
+		if ((flags & FLG_RT_CAP) &&
 		    ((status.st_mode & S_IFMT) == S_IFDIR))
 			return (0);
 
@@ -1305,14 +1312,6 @@
 			if (fdp->fd_ftp != NULL) {
 				fdp->fd_dev = status.st_dev;
 				fdp->fd_ino = status.st_ino;
-
-				/*
-				 * Trace that this open has succeeded.
-				 */
-				if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
-					trace_so(clmp, 0, oname, nname,
-					    (fdp->fd_flags & FLG_FD_ALTER), 0);
-				}
 				return (1);
 			}
 		}
@@ -1977,12 +1976,12 @@
 		clmp = lml_rtld.lm_head;
 
 	/*
-	 * If this path resulted from a $HWCAP specification, then the best
-	 * hardware capability object has already been establish, and is
-	 * available in the calling file descriptor.  Perform some minor book-
-	 * keeping so that we can fall through into common code.
+	 * If this path resulted from a $CAPABILITY specification, then the
+	 * best capability object has already been establish, and is available
+	 * in the calling file descriptor.  Perform some minor book-keeping so
+	 * that we can fall through into common code.
 	 */
-	if (flags & FLG_RT_HWCAP) {
+	if (flags & FLG_RT_CAP) {
 		/*
 		 * If this object is already loaded, we're done.
 		 */
@@ -2086,12 +2085,19 @@
 	}
 
 	/*
-	 * Finish mapping the file and return the link-map descriptor.  Note,
-	 * if this request originated from a HWCAP request, re-establish the
-	 * fdesc information.  For single paged objects, such as filters, the
-	 * original mapping may have been sufficient to capture the file, thus
-	 * this mapping needs to be reset to insure it doesn't mistakenly get
-	 * unmapped as part of HWCAP cleanup.
+	 * Trace that this successfully opened file is about to be processed.
+	 * Note, as part of processing a family of hardware capabilities filtees
+	 * a number of candidates may have been opened and mapped to determine
+	 * their capability requirements.  At this point we've decided which
+	 * of the candidates to use.
+	 */
+	if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
+		trace_so(clmp, 0, fdp->fd_oname, fdp->fd_nname,
+		    (fdp->fd_flags & FLG_FD_ALTER), 0);
+	}
+
+	/*
+	 * Finish mapping the file and return the link-map descriptor.
 	 */
 	return (load_file(lml, lmco, fdp, in_nfavl));
 }
@@ -2430,7 +2436,7 @@
 		 * If this file has been found, reset the not-found load count.
 		 * Although a search for this file might have inspected a number
 		 * of non-existent path names, the file has been found so there
-		 * is no need to to accumulate a non-found count, as this may
+		 * is no need to accumulate a non-found count, as this may
 		 * trigger unnecessary fall back (retry) processing.
 		 */
 		if (in_nfavl)
@@ -2530,8 +2536,8 @@
 /*
  * Load one object from a possible list of objects.  Typically, for requests
  * such as NEEDED's, only one object is specified.  However, this object could
- * be specified using $ISALIST or $HWCAP, in which case only the first object
- * that can be loaded is used (ie. the best).
+ * be specified using $ISALIST or $CAPABILITY, in which case only the first
+ * object that can be loaded is used (ie. the best).
  */
 Rt_map *
 load_one(Lm_list *lml, Aliste lmco, Alist *palp, Rt_map *clmp, int mode,
@@ -2546,12 +2552,12 @@
 		Rt_map	*lmp = NULL;
 
 		/*
-		 * A Hardware capabilities requirement can itself expand into
-		 * a number of candidates.
+		 * A $CAPABILITY/$HWCAP requirement can expand into a number of
+		 * candidates.
 		 */
-		if (pdp->pd_flags & PD_TKN_HWCAP) {
-			lmp = load_hwcap(lml, lmco, pdp->pd_pname, clmp,
-			    mode, (flags | FLG_RT_HWCAP), hdl, &rej, in_nfavl);
+		if (pdp->pd_flags & PD_TKN_CAP) {
+			lmp = load_cap(lml, lmco, pdp->pd_pname, clmp,
+			    mode, (flags | FLG_RT_CAP), hdl, &rej, in_nfavl);
 		} else {
 			Fdesc	fd = { 0 };
 
@@ -2612,11 +2618,11 @@
  * which we've bound can be interposed upon.  In this context, copy relocations
  * are a form of interposition.
  */
-static Sym *
-lookup_sym_interpose(Slookup *slp, Rt_map **dlmp, uint_t *binfo, Sym *osym,
-    int *in_nfavl)
+static int
+lookup_sym_interpose(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
-	Rt_map		*lmp, *clmp;
+	Rt_map		*lmp, *clmp, *dlmp = srp->sr_dmap;
+	Sym		*osym = srp->sr_sym;
 	Slookup		sl;
 	Lm_list		*lml;
 
@@ -2625,17 +2631,18 @@
 	 * this binding to the original copy reference.  Fabricate an inter-
 	 * position diagnostic, as this is a legitimate form of interposition.
 	 */
-	if (osym && (FLAGS1(*dlmp) & FL1_RT_COPYTOOK)) {
+	if (osym && (FLAGS1(dlmp) & FL1_RT_COPYTOOK)) {
 		Rel_copy	*rcp;
 		Aliste		idx;
 
-		for (ALIST_TRAVERSE(COPY_R(*dlmp), idx, rcp)) {
+		for (ALIST_TRAVERSE(COPY_R(dlmp), idx, rcp)) {
 			if ((osym == rcp->r_dsym) || (osym->st_value &&
 			    (osym->st_value == rcp->r_dsym->st_value))) {
-				*dlmp = rcp->r_rlmp;
+				srp->sr_dmap = rcp->r_rlmp;
+				srp->sr_sym = rcp->r_rsym;
 				*binfo |=
 				    (DBG_BINFO_INTERPOSE | DBG_BINFO_COPYREF);
-				return (rcp->r_rsym);
+				return (1);
 			}
 		}
 	}
@@ -2646,7 +2653,7 @@
 	 * original caller.
 	 */
 	if (osym)
-		clmp = *dlmp;
+		clmp = dlmp;
 	else
 		clmp = slp->sl_cmap;
 
@@ -2676,10 +2683,16 @@
 	if (osym && ((FLAGS1(lmp) & FL1_RT_DTFLAGS) == 0) &&
 	    (FCT(lmp) == &elf_fct) &&
 	    (ELF_ST_TYPE(osym->st_info) != STT_FUNC) &&
-	    are_bits_zero(*dlmp, osym, 0)) {
-		Rt_map	*ilmp;
-		Sym	*isym;
-
+	    are_bits_zero(dlmp, osym, 0)) {
+		Sresult	sr;
+
+		/*
+		 * Initialize a local symbol result descriptor, using the
+		 * original symbol name.  Initialize a local symbol lookup
+		 * descriptor, using the original lookup information, and a
+		 * new initial link-map.
+		 */
+		SRESULT_INIT(sr, slp->sl_name);
 		sl = *slp;
 		sl.sl_imap = lmp;
 
@@ -2688,13 +2701,17 @@
 		 * executable, that the size and type of symbol are the same,
 		 * and that the symbol is also associated with .bss.
 		 */
-		if (((isym = SYMINTP(lmp)(&sl, &ilmp, binfo,
-		    in_nfavl)) != NULL) && (isym->st_size == osym->st_size) &&
-		    (isym->st_info == osym->st_info) &&
-		    are_bits_zero(lmp, isym, 1)) {
-			*dlmp = lmp;
-			*binfo |= (DBG_BINFO_INTERPOSE | DBG_BINFO_COPYREF);
-			return (isym);
+		if (SYMINTP(lmp)(&sl, &sr, binfo, in_nfavl)) {
+			Sym	*isym = sr.sr_sym;
+
+			if ((isym->st_size == osym->st_size) &&
+			    (isym->st_info == osym->st_info) &&
+			    are_bits_zero(lmp, isym, 1)) {
+				*srp = sr;
+				*binfo |=
+				    (DBG_BINFO_INTERPOSE | DBG_BINFO_COPYREF);
+				return (1);
+			}
 		}
 	}
 
@@ -2724,7 +2741,7 @@
 		 * If we had already bound to this object, there's no point in
 		 * searching it again, we're done.
 		 */
-		if (lmp == *dlmp)
+		if (lmp == dlmp)
 			break;
 
 		/*
@@ -2732,11 +2749,21 @@
 		 * the symbol within the interposer.
 		 */
 		if (callable(clmp, lmp, 0, sl.sl_flags)) {
-			Rt_map	*ilmp;
-			Sym	*isym;
-
+			Sresult		sr;
+
+			/*
+			 * Initialize a local symbol result descriptor, using
+			 * the original symbol name.  Initialize a local symbol
+			 * lookup descriptor, using the original lookup
+			 * information, and a new initial link-map.
+			 */
+			SRESULT_INIT(sr, slp->sl_name);
 			sl.sl_imap = lmp;
-			if (isym = SYMINTP(lmp)(&sl, &ilmp, binfo, in_nfavl)) {
+
+			if (SYMINTP(lmp)(&sl, &sr, binfo, in_nfavl)) {
+				Sym	*isym = sr.sr_sym;
+				Rt_map	*ilmp = sr.sr_dmap;
+
 				/*
 				 * If this object provides individual symbol
 				 * interposers, make sure that the symbol we
@@ -2750,13 +2777,13 @@
 				 * Indicate this binding has occurred to an
 				 * interposer, and return the symbol.
 				 */
+				*srp = sr;
 				*binfo |= DBG_BINFO_INTERPOSE;
-				*dlmp = ilmp;
-				return (isym);
+				return (1);
 			}
 		}
 	}
-	return (NULL);
+	return (0);
 }
 
 /*
@@ -2764,12 +2791,12 @@
  * describing where each binding was established during link-editing, and the
  * object was built -Bdirect), then look for the symbol in the specific object.
  */
-static Sym *
-lookup_sym_direct(Slookup *slp, Rt_map **dlmp, uint_t *binfo, Syminfo *sip,
+static int
+lookup_sym_direct(Slookup *slp, Sresult *srp, uint_t *binfo, Syminfo *sip,
     Rt_map *lmp, int *in_nfavl)
 {
-	Rt_map	*clmp = slp->sl_cmap;
-	Sym	*sym;
+	Rt_map	*dlmp, *clmp = slp->sl_cmap;
+	int	ret;
 	Slookup	sl;
 
 	/*
@@ -2789,11 +2816,11 @@
 	 */
 	if (((slp->sl_flags & LKUP_COPY) == 0) &&
 	    (sip->si_flags & SYMINFO_FLG_COPY)) {
-
 		slp->sl_imap = LIST(clmp)->lm_head;
-		if (sym = SYMINTP(clmp)(slp, dlmp, binfo, in_nfavl))
+
+		if (ret = SYMINTP(clmp)(slp, srp, binfo, in_nfavl))
 			*binfo |= (DBG_BINFO_DIRECT | DBG_BINFO_COPYREF);
-		return (sym);
+		return (ret);
 	}
 
 	/*
@@ -2802,7 +2829,7 @@
 	 */
 	sl = *slp;
 	sl.sl_flags |= LKUP_DIRECT;
-	sym = NULL;
+	ret = 0;
 
 	if (sip->si_boundto == SYMINFO_BT_PARENT) {
 		Aliste		idx1;
@@ -2815,8 +2842,7 @@
 		 */
 		for (APLIST_TRAVERSE(CALLERS(clmp), idx1, bdp)) {
 			sl.sl_imap = lmp = bdp->b_caller;
-			if ((sym = SYMINTP(lmp)(&sl, dlmp, binfo,
-			    in_nfavl)) != NULL)
+			if (ret = SYMINTP(lmp)(&sl, srp, binfo, in_nfavl))
 				goto found;
 		}
 
@@ -2835,8 +2861,8 @@
 				if ((gdp->gd_flags & GPD_PARENT) == 0)
 					continue;
 				sl.sl_imap = lmp = gdp->gd_depend;
-				if ((sym = SYMINTP(lmp)(&sl, dlmp,
-				    binfo, in_nfavl)) != NULL)
+				if (ret = SYMINTP(lmp)(&sl, srp, binfo,
+				    in_nfavl))
 					goto found;
 			}
 		}
@@ -2851,10 +2877,10 @@
 			sl.sl_imap = lmp;
 
 		if (lmp)
-			sym = SYMINTP(lmp)(&sl, dlmp, binfo, in_nfavl);
+			ret = SYMINTP(lmp)(&sl, srp, binfo, in_nfavl);
 	}
 found:
-	if (sym)
+	if (ret)
 		*binfo |= DBG_BINFO_DIRECT;
 
 	/*
@@ -2863,20 +2889,18 @@
 	 * a reference to a directly bound symbol is satisfied, then determine
 	 * whether that object can be interposed upon for this symbol.
 	 */
-	if ((sym == NULL) || ((LIST(*dlmp)->lm_head != *dlmp) &&
-	    (LIST(*dlmp) == LIST(clmp)))) {
-		Sym	*isym;
-
-		if ((isym = lookup_sym_interpose(slp, dlmp, binfo, sym,
-		    in_nfavl)) != 0)
-			return (isym);
+	dlmp = srp->sr_dmap;
+	if ((ret == 0) || (dlmp && (LIST(dlmp)->lm_head != dlmp) &&
+	    (LIST(dlmp) == LIST(clmp)))) {
+		if (lookup_sym_interpose(slp, srp, binfo, in_nfavl))
+			return (1);
 	}
 
-	return (sym);
+	return (ret);
 }
 
-static Sym *
-core_lookup_sym(Rt_map *ilmp, Slookup *slp, Rt_map **dlmp, uint_t *binfo,
+static int
+core_lookup_sym(Rt_map *ilmp, Slookup *slp, Sresult *srp, uint_t *binfo,
     Aliste off, int *in_nfavl)
 {
 	Rt_map	*lmp;
@@ -2892,20 +2916,18 @@
 
 	for (; lmp; lmp = NEXT_RT_MAP(lmp)) {
 		if (callable(slp->sl_cmap, lmp, 0, slp->sl_flags)) {
-			Sym	*sym;
 
 			slp->sl_imap = lmp;
-			if (((sym = SYMINTP(lmp)(slp, dlmp, binfo,
-			    in_nfavl)) != NULL) ||
+			if ((SYMINTP(lmp)(slp, srp, binfo, in_nfavl)) ||
 			    (*binfo & BINFO_MSK_TRYAGAIN))
-				return (sym);
+				return (1);
 		}
 	}
-	return (NULL);
+	return (0);
 }
 
-static Sym *
-rescan_lazy_find_sym(Rt_map *ilmp, Slookup *slp, Rt_map **dlmp, uint_t *binfo,
+static int
+rescan_lazy_find_sym(Rt_map *ilmp, Slookup *slp, Sresult *srp, uint_t *binfo,
     int *in_nfavl)
 {
 	Rt_map	*lmp;
@@ -2914,26 +2936,24 @@
 		if (LAZY(lmp) == 0)
 			continue;
 		if (callable(slp->sl_cmap, lmp, 0, slp->sl_flags)) {
-			Sym	*sym;
 
 			slp->sl_imap = lmp;
-			if ((sym = elf_lazy_find_sym(slp, dlmp, binfo,
-			    in_nfavl)) != 0)
-				return (sym);
+			if (elf_lazy_find_sym(slp, srp, binfo, in_nfavl))
+				return (1);
 		}
 	}
-	return (NULL);
+	return (0);
 }
 
-static Sym *
-_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
+static int
+_lookup_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
 	const char	*name = slp->sl_name;
 	Rt_map		*clmp = slp->sl_cmap;
 	Lm_list		*lml = LIST(clmp);
 	Rt_map		*ilmp = slp->sl_imap, *lmp;
 	ulong_t		rsymndx;
-	Sym		*sym;
+	int		ret;
 	Syminfo		*sip;
 	Slookup		sl;
 
@@ -2944,7 +2964,7 @@
 	 * the link map).
 	 */
 	if (slp->sl_flags & LKUP_FIRST)
-		return (SYMINTP(ilmp)(slp, dlmp, binfo, in_nfavl));
+		return (SYMINTP(ilmp)(slp, srp, binfo, in_nfavl));
 
 	/*
 	 * Determine whether this lookup can be satisfied by an objects direct,
@@ -3004,7 +3024,7 @@
 			    ((slp->sl_flags & LKUP_SINGLETON) == 0))) &&
 			    ((FLAGS1(clmp) & FL1_RT_DIRECT) ||
 			    (sip->si_flags & SYMINFO_FLG_DIRECTBIND))) {
-				sym = lookup_sym_direct(slp, dlmp, binfo,
+				ret = lookup_sym_direct(slp, srp, binfo,
 				    sip, lmp, in_nfavl);
 
 				/*
@@ -3023,7 +3043,7 @@
 				 */
 				if (((*binfo & BINFO_MSK_REJECTED) == 0) ||
 				    (*binfo & BINFO_MSK_TRYAGAIN))
-					return (sym);
+					return (ret);
 
 				*binfo &= ~BINFO_MSK_REJECTED;
 			}
@@ -3043,21 +3063,23 @@
 	 */
 	if ((FLAGS1(clmp) & FL1_RT_SYMBOLIC) &&
 	    ((sl.sl_flags & LKUP_SINGLETON) == 0)) {
+
 		sl.sl_imap = clmp;
-		if (sym = SYMINTP(clmp)(&sl, dlmp, binfo, in_nfavl)) {
-			ulong_t	dsymndx = (((ulong_t)sym -
-			    (ulong_t)SYMTAB(*dlmp)) / SYMENT(*dlmp));
+		if (SYMINTP(clmp)(&sl, srp, binfo, in_nfavl)) {
+			Rt_map	*dlmp = srp->sr_dmap;
+			ulong_t	dsymndx = (((ulong_t)srp->sr_sym -
+			    (ulong_t)SYMTAB(dlmp)) / SYMENT(dlmp));
 
 			/*
 			 * Make sure this symbol hasn't explicitly been defined
 			 * as nodirect.
 			 */
-			if (((sip = SYMINFO(*dlmp)) == 0) ||
+			if (((sip = SYMINFO(dlmp)) == 0) ||
 			    /* LINTED */
 			    ((sip = (Syminfo *)((char *)sip +
-			    (dsymndx * SYMINENT(*dlmp)))) == 0) ||
+			    (dsymndx * SYMINENT(dlmp)))) == 0) ||
 			    ((sip->si_flags & SYMINFO_FLG_NOEXTDIRECT) == 0))
-				return (sym);
+				return (1);
 		}
 	}
 
@@ -3073,16 +3095,16 @@
 		Aliste	off;
 		Lm_cntl	*lmc;
 
-		sym = NULL;
+		ret = 0;
 
 		for (ALIST_TRAVERSE_BY_OFFSET(lml->lm_lists, off, lmc)) {
-			if (((sym = core_lookup_sym(lmc->lc_head, &sl, dlmp,
-			    binfo, off, in_nfavl)) != NULL) ||
+			if (((ret = core_lookup_sym(lmc->lc_head, &sl, srp,
+			    binfo, off, in_nfavl)) != 0) ||
 			    (*binfo & BINFO_MSK_TRYAGAIN))
 				break;
 		}
 	} else
-		sym = core_lookup_sym(ilmp, &sl, dlmp, binfo, ALIST_OFF_DATA,
+		ret = core_lookup_sym(ilmp, &sl, srp, binfo, ALIST_OFF_DATA,
 		    in_nfavl);
 
 	/*
@@ -3090,7 +3112,7 @@
 	 * be repeated.
 	 */
 	if (*binfo & BINFO_MSK_TRYAGAIN)
-		return (sym);
+		return (0);
 
 	/*
 	 * To allow transitioning into a world of lazy loading dependencies see
@@ -3100,7 +3122,7 @@
 	 * the reference can be satisfied.  Use of dlsym(RTLD_PROBE) sets the
 	 * LKUP_NOFALLBACK flag, and this flag disables this fall back.
 	 */
-	if ((sym == NULL) && ((sl.sl_flags & LKUP_NOFALLBACK) == 0)) {
+	if ((ret == 0) && ((sl.sl_flags & LKUP_NOFALLBACK) == 0)) {
 		if ((lmp = ilmp) == 0)
 			lmp = LIST(clmp)->lm_head;
 
@@ -3116,7 +3138,7 @@
 		 * initial link-map.
 		 */
 		if (sl.sl_flags & LKUP_NEXT)
-			sym = rescan_lazy_find_sym(clmp, &sl, dlmp, binfo,
+			ret = rescan_lazy_find_sym(clmp, &sl, srp, binfo,
 			    in_nfavl);
 		else {
 			Aliste	idx;
@@ -3124,13 +3146,13 @@
 
 			for (ALIST_TRAVERSE(lml->lm_lists, idx, lmc)) {
 				sl.sl_flags |= LKUP_NOFALLBACK;
-				if ((sym = rescan_lazy_find_sym(lmc->lc_head,
-				    &sl, dlmp, binfo, in_nfavl)) != NULL)
+				if (ret = rescan_lazy_find_sym(lmc->lc_head,
+				    &sl, srp, binfo, in_nfavl))
 					break;
 			}
 		}
 	}
-	return (sym);
+	return (ret);
 }
 
 /*
@@ -3139,31 +3161,53 @@
  * pointer to the link map of the enclosing object, and information relating
  * to the type of binding.  Else return a null pointer.
  *
- * To improve elf performance, we first compute the elf hash value and pass
- * it to each find_sym() routine.  The elf function will use this value to
+ * To improve ELF performance, we first compute the ELF hash value and pass
+ * it to each _lookup_sym() routine.  The ELF function will use this value to
  * locate the symbol, the a.out function will simply ignore it.
  */
-Sym *
-lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
+int
+lookup_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
 	Rt_map		*clmp = slp->sl_cmap;
-	Sym		*rsym = slp->sl_rsym, *sym = NULL;
-	uchar_t		rtype = slp->sl_rtype;
-	int		mode;
+	Sym		*rsym = slp->sl_rsym;
+	uchar_t		rtype = slp->sl_rtype, vis;
+	int		ret, mode;
 
 	if (slp->sl_hash == 0)
 		slp->sl_hash = elf_hash(slp->sl_name);
 	*binfo = 0;
 
-	/*
-	 * Establish any state that might be associated with a symbol reference.
-	 */
 	if (rsym) {
+		vis = ELF_ST_VISIBILITY(rsym->st_other);
+
+		/*
+		 * Symbols that are defined as protected, or hidden, within an
+		 * object usually have any relocation references from within
+		 * the same object bound at link-edit time.  Therefore, ld.so.1
+		 * is not involved.  However, if a reference is to a
+		 * capabilities symbol, this reference must be resolved at
+		 * runtime.  In this case look directly within the calling
+		 * object, and only within the calling object, for these
+		 * symbols.  Note, an object may still use dlsym() to search
+		 * externally for a symbol which is defined as protected within
+		 * the same object.
+		 */
+		if ((rsym->st_shndx != SHN_UNDEF) &&
+		    ((slp->sl_flags & LKUP_DLSYM) == 0) &&
+		    ((vis == STV_PROTECTED) || (vis == STV_HIDDEN))) {
+			slp->sl_imap = clmp;
+			return (SYMINTP(clmp)(slp, srp, binfo, in_nfavl));
+		}
+
+		/*
+		 * Establish any state that might be associated with a symbol
+		 * reference.
+		 */
 		if ((slp->sl_flags & LKUP_STDRELOC) &&
 		    (ELF_ST_BIND(rsym->st_info) == STB_WEAK))
 			slp->sl_flags |= LKUP_WEAK;
 
-		if (ELF_ST_VISIBILITY(rsym->st_other) == STV_SINGLETON)
+		if (vis == STV_SINGLETON)
 			slp->sl_flags |= LKUP_SINGLETON;
 	}
 
@@ -3200,7 +3244,7 @@
 	 * Carry out an initial symbol search.  This search takes into account
 	 * all the modes of the requested search.
 	 */
-	if (((sym = _lookup_sym(slp, dlmp, binfo, in_nfavl)) == NULL) &&
+	if (((ret = _lookup_sym(slp, srp, binfo, in_nfavl)) == 0) &&
 	    (*binfo & BINFO_MSK_TRYAGAIN)) {
 		Slookup	sl = *slp;
 
@@ -3226,7 +3270,7 @@
 		}
 		*binfo &= ~BINFO_MSK_REJECTED;
 
-		sym = _lookup_sym(&sl, dlmp, binfo, in_nfavl);
+		ret = _lookup_sym(&sl, srp, binfo, in_nfavl);
 	}
 
 	/*
@@ -3234,14 +3278,11 @@
 	 * determine if it is necessary to follow a binding from outside of
 	 * the group.
 	 */
-	if ((mode & (RTLD_GROUP | RTLD_WORLD)) == RTLD_GROUP) {
-		Sym	*isym;
-
-		if ((isym = lookup_sym_interpose(slp, dlmp, binfo, sym,
-		    in_nfavl)) != NULL)
-			return (isym);
-	}
-	return (sym);
+	if (((mode & (RTLD_GROUP | RTLD_WORLD)) == RTLD_GROUP) &&
+	    (lookup_sym_interpose(slp, srp, binfo, in_nfavl)))
+		return (1);
+
+	return (ret);
 }
 
 /*
--- a/usr/src/cmd/sgs/rtld/common/audit.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/audit.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Audit interfaces.  Auditing can be enabled in two ways:
@@ -885,22 +885,23 @@
 static Addr
 audit_symget(Audit_list *alp, int info, int *in_nfavl)
 {
-	Rt_map		*_lmp, *lmp = alp->al_lmp;
+	Rt_map		*lmp = alp->al_lmp;
 	const char	*sname = MSG_ORIG(aud_info[info].sname);
 	uint_t		alflag = aud_info[info].alflag;
 	uint_t		auflag = aud_info[info].auflag;
 	uint_t		binfo;
-	Sym		*sym;
 	Slookup		sl;
+	Sresult		sr;
 
 	/*
-	 * Initialize the symbol lookup data structure.
+	 * Initialize the symbol lookup, and symbol result, data structures.
 	 */
 	SLOOKUP_INIT(sl, sname, lml_rtld.lm_head, lmp, ld_entry_cnt,
-	    0, 0, 0, 0, LKUP_FIRST);
+	    0, 0, 0, 0, (LKUP_FIRST | LKUP_DLSYM));
+	SRESULT_INIT(sr, sname);
 
-	if (sym = LM_LOOKUP_SYM(lmp)(&sl, &_lmp, &binfo, in_nfavl)) {
-		Addr	addr = sym->st_value;
+	if (LM_LOOKUP_SYM(lmp)(&sl, &sr, &binfo, in_nfavl)) {
+		Addr	addr = sr.sr_sym->st_value;
 
 		if (!(FLAGS(lmp) & FLG_RT_FIXED))
 			addr += ADDR(lmp);
@@ -911,10 +912,10 @@
 			audit_flags |= auflag;
 
 		DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp),
-		    alp->al_libname, sname));
+		    alp->al_libname, sr.sr_name));
 		return (addr);
-	} else
-		return (0);
+	}
+	return (0);
 }
 
 /*
--- a/usr/src/cmd/sgs/rtld/common/cap.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/cap.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,49 +33,112 @@
 #include	<limits.h>
 #include	<debug.h>
 #include	<conv.h>
+#include	<elfcap.h>
 #include	"_rtld.h"
+#include	"_elf.h"
 #include	"_audit.h"
 #include	"msg.h"
 
 /*
- * qsort(3c) comparison function.
+ * qsort(3c) capability comparison function.
  */
 static int
-compare(const void *fdesc1, const void *fdesc2)
+compare(const void *fdp_a, const void *fdp_b)
 {
-	Xword	hwcap1 = ((Fdesc *)fdesc1)->fd_hwcap;
-	Xword	hwcap2 = ((Fdesc *)fdesc2)->fd_hwcap;
+	char	*strcap_a, *strcap_b;
+	Xword	hwcap_a, hwcap_b;
+
+	/*
+	 * First, investigate any platform capability.
+	 */
+	strcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_plat;
+	strcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_plat;
 
-	if (hwcap1 && (hwcap2 == 0))
+	if (strcap_a && (strcap_b == NULL))
+		return (-1);
+	if (strcap_b && (strcap_a == NULL))
+		return (1);
+
+	/*
+	 * Second, investigate any machine capability.
+	 */
+	strcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_mach;
+	strcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_mach;
+
+	if (strcap_a && (strcap_b == NULL))
 		return (-1);
-	if ((hwcap1 == 0) && hwcap2)
+	if (strcap_b && (strcap_a == NULL))
 		return (1);
-	if ((hwcap1 == 0) && (hwcap2 == 0))
-		return (0);
+
+	/*
+	 * Third, investigate any CA_SUNW_HW_2 hardware capabilities.
+	 */
+	hwcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_hw_2;
+	hwcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_hw_2;
 
-	if (hwcap1 > hwcap2)
+	if (hwcap_a > hwcap_b)
 		return (-1);
-	if (hwcap1 < hwcap2)
+	if (hwcap_a < hwcap_b)
 		return (1);
+
+	/*
+	 * Finally, investigate any CA_SUNW_HW_1 hardware capabilities.
+	 */
+	hwcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_hw_1;
+	hwcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_hw_1;
+
+	if (hwcap_a > hwcap_b)
+		return (-1);
+	if (hwcap_a < hwcap_b)
+		return (1);
+
 	return (0);
 }
 
 /*
- * Process any hardware capabilities.
+ * Determine whether HWCAP1 capabilities value is supported.
  */
 int
-hwcap_check(Xword val, Rej_desc *rej)
+hwcap1_check(Syscapset *scapset, Xword val, Rej_desc *rej)
 {
 	Xword	mval;
 
 	/*
 	 * Ensure that the kernel can cope with the required capabilities.
 	 */
-	if ((rtld_flags2 & RT_FL2_HWCAP) && ((mval = (val & ~hwcap)) != 0)) {
-		static Conv_cap_val_hw1_buf_t	cap_buf;
+	if ((rtld_flags2 & RT_FL2_HWCAP) &&
+	    ((mval = (val & ~scapset->sc_hw_1)) != 0)) {
+		if (rej) {
+			static Conv_cap_val_hw1_buf_t	cap_buf;
+
+			rej->rej_type = SGS_REJ_HWCAP_1;
+			rej->rej_str = conv_cap_val_hw1(mval,
+			    M_MACH, 0, &cap_buf);
+		}
+		return (0);
+	}
+	return (1);
+}
 
-		rej->rej_type = SGS_REJ_HWCAP_1;
-		rej->rej_str = conv_cap_val_hw1(mval, M_MACH, 0, &cap_buf);
+/*
+ * Determine whether HWCAP2 capabilities value is supported.
+ */
+int
+hwcap2_check(Syscapset *scapset, Xword val, Rej_desc *rej)
+{
+	Xword	mval;
+
+	/*
+	 * Ensure that the kernel can cope with the required capabilities.
+	 */
+	if ((mval = (val & ~scapset->sc_hw_2)) != 0) {
+		if (rej) {
+			static Conv_cap_val_hw2_buf_t	cap_buf;
+
+			rej->rej_type = SGS_REJ_HWCAP_2;
+			rej->rej_str = conv_cap_val_hw2(mval,
+			    M_MACH, 0, &cap_buf);
+		}
 		return (0);
 	}
 	return (1);
@@ -86,7 +149,7 @@
  */
 /* ARGSUSED0 */
 int
-sfcap_check(Xword val, Rej_desc *rej)
+sfcap1_check(Syscapset *scapset, Xword val, Rej_desc *rej)
 {
 #if	defined(_ELF64)
 	/*
@@ -96,11 +159,13 @@
 	 * established this requirement.
 	 */
 	if ((val & SF1_SUNW_ADDR32) && ((rtld_flags2 & RT_FL2_ADDR32) == 0)) {
-		static Conv_cap_val_sf1_buf_t	cap_buf;
+		if (rej) {
+			static Conv_cap_val_sf1_buf_t	cap_buf;
 
-		rej->rej_type = SGS_REJ_SFCAP_1;
-		rej->rej_str =
-		    conv_cap_val_sf1(SF1_SUNW_ADDR32, M_MACH, 0, &cap_buf);
+			rej->rej_type = SGS_REJ_SFCAP_1;
+			rej->rej_str = conv_cap_val_sf1(SF1_SUNW_ADDR32,
+			    M_MACH, 0, &cap_buf);
+		}
 		return (0);
 	}
 #endif
@@ -108,11 +173,324 @@
 }
 
 /*
- * When $HWCAP is used to represent dependencies, take the associated directory
- * and analyze all the files it contains.
+ * Process any platform capability.
+ */
+int
+platcap_check(Syscapset *scapset, const char *str, Rej_desc *rej)
+{
+	/*
+	 * If the platform name hasn't been set, try and obtain it.
+	 */
+	if ((scapset->sc_plat == NULL) &&
+	    (scapset->sc_platsz == 0))
+		platform_name(scapset);
+
+	if ((scapset->sc_plat == NULL) ||
+	    (str && strcmp(scapset->sc_plat, str))) {
+		if (rej) {
+			/*
+			 * Note, the platform name points to a string within an
+			 * objects string table, and if that object can't be
+			 * loaded, it will be unloaded and thus invalidate the
+			 * string.  Duplicate the string here for rejection
+			 * message inheritance.
+			 */
+			rej->rej_type = SGS_REJ_PLATCAP;
+			rej->rej_str = stravl_insert(str, 0, 0, 0);
+		}
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Process any machine capability.
+ */
+int
+machcap_check(Syscapset *scapset, const char *str, Rej_desc *rej)
+{
+	/*
+	 * If the machine name hasn't been set, try and obtain it.
+	 */
+	if ((scapset->sc_mach == NULL) &&
+	    (scapset->sc_machsz == 0))
+		machine_name(scapset);
+
+	if ((scapset->sc_mach == NULL) ||
+	    (str && strcmp(scapset->sc_mach, str))) {
+		if (rej) {
+			/*
+			 * Note, the machine name points to a string within an
+			 * objects string table, and if that object can't be
+			 * loaded, it will be unloaded and thus invalidate the
+			 * string.  Duplicate the string here for rejection
+			 * message inheritance.
+			 */
+			rej->rej_type = SGS_REJ_MACHCAP;
+			rej->rej_str = stravl_insert(str, 0, 0, 0);
+		}
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Generic front-end to capabilities validation.
  */
 static int
-hwcap_dir(Alist **fdalpp, Lm_list *lml, const char *dname, Rt_map *clmp,
+cap_check(Cap *cptr, char *strs, int alt, Fdesc *fdp, Rej_desc *rej)
+{
+	Syscapset	*scapset;
+	int		totplat, ivlplat, totmach, ivlmach;
+
+	/*
+	 * If the caller has no capabilities, then the object is valid.
+	 */
+	if (cptr == NULL)
+		return (1);
+
+	if (alt)
+		scapset = alt_scapset;
+	else
+		scapset = org_scapset;
+
+	totplat = ivlplat = totmach = ivlmach = 0;
+
+	while (cptr->c_tag != CA_SUNW_NULL) {
+		Xword	val = cptr->c_un.c_val;
+		char	*str;
+
+		switch (cptr->c_tag) {
+		case CA_SUNW_HW_1:
+			if (hwcap1_check(scapset, val, rej) == 0)
+				return (0);
+			if (fdp)
+				fdp->fd_scapset.sc_hw_1 = val;
+			break;
+		case CA_SUNW_SF_1:
+			if (sfcap1_check(scapset, val, rej) == 0)
+				return (0);
+			if (fdp)
+				fdp->fd_scapset.sc_sf_1 = val;
+			break;
+		case CA_SUNW_HW_2:
+			if (hwcap2_check(scapset, val, rej) == 0)
+				return (0);
+			if (fdp)
+				fdp->fd_scapset.sc_hw_2 = val;
+			break;
+		case CA_SUNW_PLAT:
+			/*
+			 * A capabilities group can define multiple platform
+			 * names that are appropriate.  Only if all the names
+			 * are deemed invalid is the group determined
+			 * inappropriate.
+			 */
+			if (totplat == ivlplat) {
+				totplat++;
+
+				str = strs + val;
+
+				if (platcap_check(scapset, str, rej) == 0)
+					ivlplat++;
+				else if (fdp)
+					fdp->fd_scapset.sc_plat = str;
+			}
+			break;
+		case CA_SUNW_MACH:
+			/*
+			 * A capabilities group can define multiple machine
+			 * names that are appropriate.  Only if all the names
+			 * are deemed invalid is the group determined
+			 * inappropriate.
+			 */
+			if (totmach == ivlmach) {
+				totmach++;
+
+				str = strs + val;
+
+				if (machcap_check(scapset, str, rej) == 0)
+					ivlmach++;
+				else if (fdp)
+					fdp->fd_scapset.sc_mach = str;
+			}
+			break;
+		case CA_SUNW_ID:
+			/*
+			 * Capabilities identifiers provide for diagnostics,
+			 * but are not attributes that must be compared with
+			 * the system.  They are ignored.
+			 */
+			break;
+		default:
+			rej->rej_type = SGS_REJ_UNKCAP;
+			rej->rej_info = cptr->c_tag;
+			return (0);
+		}
+		cptr++;
+	}
+
+	/*
+	 * If any platform names, or machine names were found, and all were
+	 * invalid, indicate that the object is inappropriate.
+	 */
+	if ((totplat && (totplat == ivlplat)) ||
+	    (totmach && (totmach == ivlmach)))
+		return (0);
+
+	return (1);
+}
+
+#define	HWAVL_RECORDED(n)	pnavl_recorded(&capavl, n, NULL, NULL)
+
+/*
+ * Determine whether a link-map should use alternative system capabilities.
+ */
+static void
+cap_check_lmp_init(Rt_map *lmp)
+{
+	int	alt = 0;
+
+	/*
+	 * If an alternative set of system capabilities have been established,
+	 * and only specific files should use these alternative system
+	 * capabilities, determine whether this file is one of those specified.
+	 */
+	if (capavl) {
+		const char	*file;
+
+		/*
+		 * The simplest way to reference a file is to use its file name
+		 * (soname), however try all of the names that this file is
+		 * known by.
+		 */
+		if ((file = strrchr(NAME(lmp), '/')) != NULL)
+			file++;
+		else
+			file = NULL;
+
+		if ((file && (HWAVL_RECORDED(file) != 0)) ||
+		    (HWAVL_RECORDED(NAME(lmp)) != 0) ||
+		    ((PATHNAME(lmp) != NAME(lmp)) &&
+		    (HWAVL_RECORDED(PATHNAME(lmp)) != 0)))
+			alt = 1;
+
+		if (alt == 0) {
+			Aliste		idx;
+			const char	*cp;
+
+			for (APLIST_TRAVERSE(ALIAS(lmp), idx, cp)) {
+				if ((alt = HWAVL_RECORDED(cp)) != 0)
+					break;
+			}
+		}
+	}
+
+	/*
+	 * Indicate if this link-map should use alternative system capabilities,
+	 * and that the alternative system capabilities check has been carried
+	 * out.
+	 */
+	if ((org_scapset != alt_scapset) && ((capavl == NULL) || alt))
+		FLAGS1(lmp) |= FL1_RT_ALTCAP;
+	FLAGS1(lmp) |= FL1_RT_ALTCHECK;
+}
+
+/*
+ * Validate the capabilities requirements of a link-map.
+ *
+ * This routine is called for main, where a link-map is constructed from the
+ * mappings returned from exec(), and for any symbol capabilities comparisons.
+ */
+int
+cap_check_lmp(Rt_map *lmp, Rej_desc *rej)
+{
+	if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0)
+		cap_check_lmp_init(lmp);
+
+	return (cap_check(CAP(lmp), STRTAB(lmp),
+	    (FLAGS1(lmp) & FL1_RT_ALTCAP), NULL, rej));
+}
+
+/*
+ * Validate the capabilities requirements of a file under inspection.
+ * This file is still under the early stages of loading, and has no link-map
+ * yet.  The file must have an object capabilities definition (PT_SUNWCAP), to
+ * have gotten us here.  The logic here is the same as cap_check_lmp().
+ */
+int
+cap_check_fdesc(Fdesc *fdp, Cap *cptr, char *strs, Rej_desc *rej)
+{
+	int	alt = 0;
+
+	/*
+	 * If an alternative set of system capabilities have been established,
+	 * and only specific files should use these alternative system
+	 * capabilities, determine whether this file is one of those specified.
+	 */
+	if (capavl) {
+		const char	*file;
+
+		/*
+		 * The simplest way to reference a file is to use its file name
+		 * (soname), however try all of the names that this file is
+		 * known by.
+		 */
+		if ((file = strrchr(fdp->fd_oname, '/')) != NULL)
+			file++;
+		else
+			file = NULL;
+
+		if ((file && (HWAVL_RECORDED(file) != 0)) ||
+		    (fdp->fd_oname && (HWAVL_RECORDED(fdp->fd_oname) != 0)) ||
+		    (fdp->fd_nname && (HWAVL_RECORDED(fdp->fd_nname) != 0)) ||
+		    (fdp->fd_pname && (fdp->fd_pname != fdp->fd_nname) &&
+		    (HWAVL_RECORDED(fdp->fd_pname) != 0)))
+			alt = 1;
+	}
+
+	/*
+	 * Indicate if this file descriptor should use alternative system
+	 * capabilities, and that the alternative system capabilities check has
+	 * been carried out.
+	 */
+	if ((org_scapset != alt_scapset) && ((capavl == NULL) || alt))
+		fdp->fd_flags |= FLG_FD_ALTCAP;
+	fdp->fd_flags |= FLG_FD_ALTCHECK;
+
+	/*
+	 * Verify that the required capabilities are supported by the reference.
+	 */
+	return (cap_check(cptr, strs, (fdp->fd_flags & FLG_FD_ALTCAP),
+	    fdp, rej));
+}
+
+/*
+ * Free a file descriptor list.  As part of building this list, the original
+ * names for each capabilities candidate were duplicated for use in later
+ * diagnostics.  These names need to be freed.
+ */
+void
+free_fd(Alist *fdalp)
+{
+	if (fdalp) {
+		Aliste	idx;
+		Fdesc	*fdp;
+
+		for (ALIST_TRAVERSE(fdalp, idx, fdp)) {
+			if (fdp->fd_oname)
+				free((void *)fdp->fd_oname);
+		}
+		free(fdalp);
+	}
+}
+
+/*
+ * When $CAPABILITY (or $HWCAP) is used to represent dependencies, take the
+ * associated directory and analyze all the files it contains.
+ */
+static int
+cap_dir(Alist **fdalpp, Lm_list *lml, const char *dname, Rt_map *clmp,
     uint_t flags, Rej_desc *rej, int *in_nfavl)
 {
 	char		path[PATH_MAX], *dst;
@@ -187,18 +565,24 @@
 			continue;
 		}
 
-		DBG_CALL(Dbg_cap_hw_candidate(lml, fd.fd_nname));
+		DBG_CALL(Dbg_cap_candidate(lml, fd.fd_nname));
 
 		/*
-		 * If this object has already been loaded, obtain the hardware
-		 * capabilities for later sorting.  Otherwise we have a new
-		 * candidate.
+		 * If this object has already been loaded, save the capabilities
+		 * for later sorting.  Otherwise we have a new candidate.
 		 */
 		if (fd.fd_lmp)
-			fd.fd_hwcap = HWCAP(fd.fd_lmp);
+			fd.fd_scapset = CAPSET(fd.fd_lmp);
 
-		if (alist_append(&fdalp, &fd, sizeof (Fdesc),
-		    AL_CNT_HWCAP) == NULL) {
+		/*
+		 * Duplicate the original name, as this may be required for
+		 * later diagnostics.  Keep a copy of the file descriptor for
+		 * analysis once all capabilities candidates have been
+		 * determined.
+		 */
+		if (((fd.fd_oname = strdup(fd.fd_oname)) == NULL) ||
+		    (alist_append(&fdalp, &fd, sizeof (Fdesc),
+		    AL_CNT_CAP) == NULL)) {
 			error = 1;
 			break;
 		}
@@ -212,7 +596,7 @@
 	 */
 	if ((fdalp == NULL) || error) {
 		if (fdalp)
-			free(fdalp);
+			free_fd(fdalp);
 		return (0);
 	}
 
@@ -227,7 +611,7 @@
 }
 
 int
-hwcap_filtees(Alist **alpp, Aliste oidx, const char *dir, Aliste nlmco,
+cap_filtees(Alist **alpp, Aliste oidx, const char *dir, Aliste nlmco,
     Rt_map *flmp, const char *ref, int mode, uint_t flags, int *in_nfavl)
 {
 	Alist		*fdalp = NULL;
@@ -237,7 +621,7 @@
 	int		unused = 0;
 	Rej_desc	rej = { 0 };
 
-	if (hwcap_dir(&fdalp, lml, dir, flmp, flags, &rej, in_nfavl) == 0)
+	if (cap_dir(&fdalp, lml, dir, flmp, flags, &rej, in_nfavl) == 0)
 		return (0);
 
 	/*
@@ -348,15 +732,15 @@
 		}
 	}
 
-	free(fdalp);
+	free_fd(fdalp);
 	return (1);
 }
 
 /*
- * Load an individual hardware capabilities object.
+ * Load an individual capabilities object.
  */
 Rt_map *
-load_hwcap(Lm_list *lml, Aliste lmco, const char *dir, Rt_map *clmp,
+load_cap(Lm_list *lml, Aliste lmco, const char *dir, Rt_map *clmp,
     uint_t mode, uint_t flags, Grp_hdl **hdl, Rej_desc *rej, int *in_nfavl)
 {
 	Alist	*fdalp = NULL;
@@ -368,7 +752,7 @@
 	/*
 	 * Obtain the sorted list of hardware capabilities objects available.
 	 */
-	if (hwcap_dir(&fdalp, lml, dir, clmp, flags, rej, in_nfavl) == 0)
+	if (cap_dir(&fdalp, lml, dir, clmp, flags, rej, in_nfavl) == 0)
 		return (NULL);
 
 	/*
@@ -383,6 +767,605 @@
 			found++;
 	}
 
-	free(fdalp);
+	free_fd(fdalp);
 	return (lmp);
 }
+
+/*
+ * Use a case insensitive string match when looking up capability mask
+ * values by name, and omit the AV_ prefix.
+ */
+#define	ELFCAP_STYLE	ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
+
+/*
+ * To aid in the development and testing of capabilities, an alternative system
+ * capabilities group can be specified.  This alternative set is initialized
+ * from the system capabilities that are normally used to validate all object
+ * loading.  However, the user can disable, enable or override flags within
+ * this alternative set, and thus affect object loading.
+ *
+ * This technique is usually combined with defining the family of objects
+ * that should be compared against this alternative set.  Without defining the
+ * family of objects, all objects loaded by ld.so.1 are validated against the
+ * alternative set.  This can prevent the loading of critical system objects
+ * like libc, and thus prevent process execution.
+ */
+typedef enum {
+	CAP_OVERRIDE =	0,		/* override existing capabilities */
+	CAP_ENABLE =	1,		/* enable capabilities */
+	CAP_DISABLE =	2		/* disable capabilities */
+} cap_mode;
+
+static struct {
+	elfcap_mask_t	cs_val[3];	/* value settings, and indicator for */
+	int		cs_set[3];	/*	OVERRIDE, ENABLE and DISABLE */
+	elfcap_mask_t	*cs_aval;	/* alternative variable for final */
+					/*	update */
+} cap_settings[3] = {
+	{ { 0, 0, 0 }, { 0, 0, 0 }, NULL },		/* CA_SUNW_HW_1 */
+	{ { 0, 0, 0 }, { 0, 0, 0 }, NULL },		/* CA_SUNW_SF_1 */
+	{ { 0, 0, 0 }, { 0, 0, 0 }, NULL }		/* CA_SUNW_HW_2 */
+};
+
+static int
+cap_modify(Xword tag, const char *str)
+{
+	char		*caps, *ptr, *next;
+	cap_mode	mode = CAP_OVERRIDE;
+	Xword		ndx;
+
+	if ((caps = strdup(str)) == NULL)
+		return (0);
+
+	ptr = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next);
+	do {
+		Xword		val = 0;
+
+		/*
+		 * Determine whether this token should be enabled (+),
+		 * disabled (-), or override any existing settings.
+		 */
+		if (*ptr == '+') {
+			mode = CAP_ENABLE;
+			ptr++;
+		} else if (*ptr == '-') {
+			mode = CAP_DISABLE;
+			ptr++;
+		}
+
+		/*
+		 * Process the capabilities as directed by the calling tag.
+		 */
+		switch (tag) {
+		case CA_SUNW_HW_1:
+			/*
+			 * Determine whether the capabilities string matches
+			 * a known hardware capability mask.  Note, the caller
+			 * indicates that these are hardware capabilities by
+			 * passing in the CA_SUNW_HW_1 tag.  However, the
+			 * tokens could be CA_SUNW_HW_1 or CA_SUNW_HW_2.
+			 */
+			if ((val = (Xword)elfcap_hw2_from_str(ELFCAP_STYLE,
+			    ptr, M_MACH)) != 0) {
+				ndx = CA_SUNW_HW_2;
+				break;
+			}
+			if ((val = (Xword)elfcap_hw1_from_str(ELFCAP_STYLE,
+			    ptr, M_MACH)) != 0)
+				ndx = CA_SUNW_HW_1;
+			break;
+		case CA_SUNW_SF_1:
+			/*
+			 * Determine whether the capabilities string matches a
+			 * known software capability mask.  Note, the callers
+			 * indication of what capabilities to process are
+			 * triggered by a tag of CA_SUNW_SF_1, but the tokens
+			 * processed could be CA_SUNW_SF_1, CA_SUNW_SF_2, etc.
+			 */
+			if ((val = (Xword)elfcap_sf1_from_str(ELFCAP_STYLE,
+			    ptr, M_MACH)) != 0)
+				ndx = CA_SUNW_SF_1;
+			break;
+		}
+
+		/*
+		 * If a capabilities token has not been matched, interpret the
+		 * string as a number.  To provide for setting the various
+		 * families (CA_SUNW_HW_1, CA_SUNW_HW_2), the number can be
+		 * prefixed with the (bracketed) family index.
+		 *
+		 *	LD_HWCAP=[1]0x40    sets CA_SUNW_HW_1 with 0x40
+		 *	LD_HWCAP=[2]0x80    sets CA_SUNW_HW_2 with 0x80
+		 *
+		 * Invalid indexes are ignored.
+		 */
+		if (val == 0) {
+			if ((*ptr == '[') && (*(ptr + 2) == ']')) {
+				if (*(ptr + 1) == '1') {
+					ndx = tag;
+					ptr += 3;
+				} else if (*(ptr + 1) == '2') {
+					if (tag == CA_SUNW_HW_1) {
+						ndx = CA_SUNW_HW_2;
+						ptr += 3;
+					} else {
+						/* invalid index */
+						continue;
+					}
+				} else {
+					/* invalid index */
+					continue;
+				}
+			} else
+				ndx = tag;
+
+			errno = 0;
+			if (((val = strtol(ptr, NULL, 16)) == 0) && errno)
+				continue;
+		}
+		cap_settings[ndx - 1].cs_val[mode] |= val;
+		cap_settings[ndx - 1].cs_set[mode]++;
+
+	} while ((ptr = strtok_r(NULL,
+	    MSG_ORIG(MSG_CAP_DELIMIT), &next)) != NULL);
+
+	/*
+	 * If the "override" token was supplied, set the alternative
+	 * system capabilities, then enable or disable others.
+	 */
+	for (ndx = 0; ndx < CA_SUNW_HW_2; ndx++) {
+		if (cap_settings[ndx].cs_set[CAP_OVERRIDE])
+			*(cap_settings[ndx].cs_aval) =
+			    cap_settings[ndx].cs_val[CAP_OVERRIDE];
+		if (cap_settings[ndx].cs_set[CAP_ENABLE])
+			*(cap_settings[ndx].cs_aval) |=
+			    cap_settings[ndx].cs_val[CAP_ENABLE];
+		if (cap_settings[ndx].cs_set[CAP_DISABLE])
+			*(cap_settings[ndx].cs_aval) &=
+			    ~cap_settings[ndx].cs_val[CAP_DISABLE];
+	}
+	free(caps);
+	return (1);
+}
+#undef	ELFCAP_STYLE
+
+/*
+ * Create an AVL tree of objects that are to be validated against an alternative
+ * system capabilities value.
+ */
+static int
+cap_files(const char *str)
+{
+	char	*caps, *name, *next;
+
+	if ((caps = strdup(str)) == NULL)
+		return (0);
+
+	name = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next);
+	do {
+		avl_index_t	where;
+		PathNode	*pnp;
+		uint_t		hash = sgs_str_hash(name);
+
+		/*
+		 * Determine whether this pathname has already been recorded.
+		 */
+		if (pnavl_recorded(&capavl, name, hash, &where))
+			continue;
+
+		if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) {
+			pnp->pn_name = name;
+			pnp->pn_hash = hash;
+			avl_insert(capavl, pnp, where);
+		}
+	} while ((name = strtok_r(NULL,
+	    MSG_ORIG(MSG_CAP_DELIMIT), &next)) != NULL);
+
+	return (1);
+}
+
+/*
+ * Set alternative system capabilities.  A user can establish alternative system
+ * capabilities from the environment, or from a configuration file.  This
+ * routine is called in each instance.  Environment variables only set the
+ * replaceable (rpl) variables.  Configuration files can set both replaceable
+ * (rpl) and permanent (prm) variables.
+ */
+int
+cap_alternative(void)
+{
+	/*
+	 * If no capabilities have been set, we're done.
+	 */
+	if ((rpl_hwcap == NULL) && (rpl_sfcap == NULL) &&
+	    (rpl_machcap == NULL) && (rpl_platcap == NULL) &&
+	    (prm_hwcap == NULL) && (prm_sfcap == NULL) &&
+	    (prm_machcap == NULL) && (prm_platcap == NULL))
+		return (1);
+
+	/*
+	 * If the user has requested to modify any capabilities, establish a
+	 * unique set from the present system capabilities.
+	 */
+	if ((alt_scapset = malloc(sizeof (Syscapset))) == NULL)
+		return (0);
+	*alt_scapset = *org_scapset;
+
+	cap_settings[CA_SUNW_HW_1 - 1].cs_aval = &alt_scapset->sc_hw_1;
+	cap_settings[CA_SUNW_SF_1 - 1].cs_aval = &alt_scapset->sc_sf_1;
+	cap_settings[CA_SUNW_HW_2 - 1].cs_aval = &alt_scapset->sc_hw_2;
+
+	/*
+	 * Process any replaceable variables.
+	 */
+	if (rpl_hwcap && (cap_modify(CA_SUNW_HW_1, rpl_hwcap) == 0))
+		return (0);
+	if (rpl_sfcap && (cap_modify(CA_SUNW_SF_1, rpl_sfcap) == 0))
+		return (0);
+
+	if (rpl_platcap) {
+		alt_scapset->sc_plat = (char *)rpl_platcap;
+		alt_scapset->sc_platsz = strlen(rpl_platcap);
+	}
+	if (rpl_machcap) {
+		alt_scapset->sc_mach = (char *)rpl_machcap;
+		alt_scapset->sc_machsz = strlen(rpl_machcap);
+	}
+
+	if (rpl_cap_files && (cap_files(rpl_cap_files) == 0))
+		return (0);
+
+	/*
+	 * Process any permanent variables.
+	 */
+	if (prm_hwcap && (cap_modify(CA_SUNW_HW_1, prm_hwcap) == 0))
+		return (0);
+	if (prm_sfcap && (cap_modify(CA_SUNW_SF_1, prm_sfcap) == 0))
+		return (0);
+
+	if (prm_platcap) {
+		alt_scapset->sc_plat = (char *)prm_platcap;
+		alt_scapset->sc_platsz = strlen(prm_platcap);
+	}
+	if (prm_machcap) {
+		alt_scapset->sc_mach = (char *)prm_machcap;
+		alt_scapset->sc_machsz = strlen(prm_machcap);
+	}
+
+	if (prm_cap_files && (cap_files(prm_cap_files) == 0))
+		return (0);
+
+	/*
+	 * Reset the replaceable variables.  If this is the environment variable
+	 * processing, these variables are now available for configuration file
+	 * initialization.
+	 */
+	rpl_hwcap = rpl_sfcap = rpl_machcap = rpl_platcap =
+	    rpl_cap_files = NULL;
+
+	return (1);
+}
+
+/*
+ * Take the index from a Capinfo entry and determine the associated capabilities
+ * set.  Verify that the capabilities are available for this system.
+ */
+static int
+sym_cap_check(Cap *cptr, uint_t cndx, Syscapset *bestcapset, Rt_map *lmp,
+    const char *name, uint_t ndx)
+{
+	Syscapset	*scapset;
+	int		totplat, ivlplat, totmach, ivlmach, capfail = 0;
+
+	/*
+	 * Determine whether this file requires validation against alternative
+	 * system capabilities.
+	 */
+	if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0)
+		cap_check_lmp_init(lmp);
+
+	if (FLAGS1(lmp) & FL1_RT_ALTCAP)
+		scapset = alt_scapset;
+	else
+		scapset = org_scapset;
+
+	totplat = ivlplat = totmach = ivlmach = 0;
+
+	/*
+	 * A capabilities index points to a capabilities group that can consist
+	 * of one or more capabilities, terminated with a CA_SUNW_NULL entry.
+	 */
+	for (cptr += cndx; cptr->c_tag != CA_SUNW_NULL; cptr++) {
+		Xword	val = cptr->c_un.c_val;
+		char	*str;
+
+		switch (cptr->c_tag) {
+		case CA_SUNW_HW_1:
+			bestcapset->sc_hw_1 = val;
+			DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_1,
+			    name, ndx, M_MACH, bestcapset));
+
+			if (hwcap1_check(scapset, val, NULL) == 0)
+				capfail++;
+			break;
+		case CA_SUNW_SF_1:
+			bestcapset->sc_sf_1 = val;
+			DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_SF_1,
+			    name, ndx, M_MACH, bestcapset));
+
+			if (sfcap1_check(scapset, val, NULL) == 0)
+				capfail++;
+			break;
+		case CA_SUNW_HW_2:
+			bestcapset->sc_hw_2 = val;
+			DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_2,
+			    name, ndx, M_MACH, bestcapset));
+
+			if (hwcap2_check(scapset, val, NULL) == 0)
+				capfail++;
+			break;
+		case CA_SUNW_PLAT:
+			/*
+			 * A capabilities set can define multiple platform names
+			 * that are appropriate.  Only if all the names are
+			 * deemed invalid is the group determined inappropriate.
+			 */
+			if (totplat == ivlplat) {
+				totplat++;
+
+				str = STRTAB(lmp) + val;
+				bestcapset->sc_plat = str;
+
+				DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_PLAT,
+				    name, ndx, M_MACH, bestcapset));
+
+				if (platcap_check(scapset, str, NULL) == 0)
+					ivlplat++;
+			}
+			break;
+		case CA_SUNW_MACH:
+			/*
+			 * A capabilities set can define multiple machine names
+			 * that are appropriate.  Only if all the names are
+			 * deemed invalid is the group determined inappropriate.
+			 */
+			if (totmach == ivlmach) {
+				totmach++;
+
+				str = STRTAB(lmp) + val;
+				bestcapset->sc_mach = str;
+
+				DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_MACH,
+				    name, ndx, M_MACH, bestcapset));
+
+				if (machcap_check(scapset, str, NULL) == 0)
+					ivlmach++;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * If any platform definitions, or machine definitions were found, and
+	 * all were invalid, indicate that the object is inappropriate.
+	 */
+	if (capfail || (totplat && (totplat == ivlplat)) ||
+	    (totmach && (totmach == ivlmach))) {
+		DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_REJECTED, name, ndx,
+		    M_MACH, NULL));
+		return (0);
+	}
+
+	DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_CANDIDATE, name, ndx,
+	    M_MACH, NULL));
+	return (1);
+}
+
+/*
+ * Determine whether a symbols capabilities are more significant than any that
+ * have already been validated.  The precedence of capabilities are:
+ *
+ *   PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1
+ *
+ *
+ * Presently we make no comparisons of software capabilities.  However, should
+ * this symbol capability have required the SF1_SUNW_ADDR32 attribute, then
+ * this would have been validated as appropriate or not.
+ *
+ * bestcapset is the presently available 'best' capabilities group, and
+ * symcapset is the present capabilities group under investigation.  Return 0
+ * if the bestcapset should remain in affect, or 1 if the symcapset is better.
+ */
+inline static int
+is_sym_the_best(Syscapset *bestcapset, Syscapset *symcapset)
+{
+	/*
+	 * Check any platform capability.  If the new symbol isn't associated
+	 * with a CA_SUNW_PLAT capability, and the best symbol is, then retain
+	 * the best capabilities group.  If the new symbol is associated with a
+	 * CA_SUNW_PLAT capability, and the best symbol isn't, then the new
+	 * symbol needs to be taken.
+	 */
+	if (bestcapset->sc_plat && (symcapset->sc_plat == NULL))
+		return (0);
+
+	if ((bestcapset->sc_plat == NULL) && symcapset->sc_plat)
+		return (1);
+
+	/*
+	 * Check any machine name capability.  If the new symbol isn't
+	 * associated with a CA_SUNW_MACH capability, and the best symbol is,
+	 * then retain the best capabilities group.  If the new symbol is
+	 * associated with a CA_SUNW_MACH capability, and the best symbol isn't,
+	 * then the new symbol needs to be taken.
+	 */
+	if (bestcapset->sc_mach && (symcapset->sc_mach == NULL))
+		return (0);
+
+	if ((bestcapset->sc_mach == NULL) && symcapset->sc_mach)
+		return (1);
+
+	/*
+	 * Check the hardware capabilities.  If the best symbols CA_SUNW_HW_2
+	 * capabilities are greater than the new symbols capabilities, then
+	 * retain the best capabilities group.  If the new symbols CA_SUNW_HW_2
+	 * capabilities are greater than the best symbol, then the new symbol
+	 * needs to be taken.
+	 */
+	if (bestcapset->sc_hw_2 > symcapset->sc_hw_2)
+		return (0);
+
+	if (bestcapset->sc_hw_2 < symcapset->sc_hw_2)
+		return (1);
+
+	/*
+	 * Check the remaining hardware capabilities.  If the best symbols
+	 * CA_SUNW_HW_1 capabilities are greater than the new symbols
+	 * capabilities, then retain the best capabilities group.  If the new
+	 * symbols CA_SUNW_HW_1 capabilities are greater than the best symbol,
+	 * then the new symbol needs to be taken.
+	 */
+	if (bestcapset->sc_hw_1 > symcapset->sc_hw_1)
+		return (0);
+
+	if (bestcapset->sc_hw_1 < symcapset->sc_hw_1)
+		return (1);
+
+	/*
+	 * Both capabilities are the same.  Retain the best on a first-come
+	 * first-served basis.
+	 */
+	return (0);
+}
+
+/*
+ * Initiate symbol capabilities processing.  If an initial symbol lookup
+ * results in binding to a symbol that has an associated SUNW_capinfo entry,
+ * we arrive here.
+ *
+ * The standard model is that this initial symbol is the lead capabilities
+ * symbol (defined as CAPINFO_SUNW_GLOB) of a capabilities family.  This lead
+ * symbol's SUNW_capinfo information points to the SUNW_capchain entry that
+ * provides the family symbol indexes.  We traverse this chain, looking at
+ * each family member, to discover the best capabilities instance.  This
+ * instance name and symbol information is returned to establish the final
+ * symbol binding.
+ *
+ * If the symbol that got us here is not CAPINFO_SUNW_GLOB, then we've bound
+ * directly to a capabilities symbol which must be verified.  This is not the
+ * model created by ld(1) using -z symbolcap, but might be created directly
+ * within a relocatable object by the compilation system.
+ */
+int
+cap_match(Sresult *srp, uint_t symndx, Sym *symtabptr, char *strtabptr)
+{
+	Rt_map		*ilmp = srp->sr_dmap;
+	Sym		*bsym = NULL;
+	const char	*bname;
+	Syscapset	bestcapset = { 0 };
+	Cap		*cap;
+	Capchain	*capchain;
+	uchar_t		grpndx;
+	uint_t		ochainndx, nchainndx, bndx;
+
+	cap = CAP(ilmp);
+	capchain = CAPCHAIN(ilmp);
+
+	grpndx = (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx]);
+
+	/*
+	 * If this symbols capability group is not a lead symbol, then simply
+	 * verify the symbol.
+	 */
+	if (grpndx != CAPINFO_SUNW_GLOB) {
+		Syscapset	symcapset = { 0 };
+
+		return (sym_cap_check(cap, grpndx, &symcapset, ilmp,
+		    srp->sr_name, symndx));
+	}
+
+	/*
+	 * If there is no capabilities chain, return the lead symbol.
+	 */
+	if (capchain == NULL)
+		return (1);
+
+	ochainndx = (uint_t)ELF_C_SYM(CAPINFO(ilmp)[symndx]);
+
+	/*
+	 * If there is only one member for this family, take it.  Once a family
+	 * has been processed, the best family instance is written to the head
+	 * of the chain followed by a null entry.  This caching ensures that the
+	 * same family comparison doesn't have to be undertaken more than once.
+	 */
+	if (capchain[ochainndx] && (capchain[ochainndx + 1] == 0)) {
+		Sym		*fsym = symtabptr + capchain[ochainndx];
+		const char	*fname = strtabptr + fsym->st_name;
+
+		DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, fname,
+		    capchain[ochainndx], M_MACH, NULL));
+
+		srp->sr_sym = fsym;
+		srp->sr_name = fname;
+		return (1);
+	}
+
+	/*
+	 * As this symbol is the lead symbol of a capabilities family, it is
+	 * considered the generic member, and therefore forms the basic
+	 * fall-back for the capabilities family.
+	 */
+	DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_DEFAULT, srp->sr_name,
+	    symndx, M_MACH, NULL));
+	bsym = srp->sr_sym;
+	bname = srp->sr_name;
+	bndx = symndx;
+
+	/*
+	 * Traverse the capabilities chain analyzing each family member.
+	 */
+	for (nchainndx = ochainndx + 1, symndx = capchain[nchainndx]; symndx;
+	    nchainndx++, symndx = capchain[nchainndx]) {
+		Sym		*nsym = symtabptr + symndx;
+		const char	*nname = strtabptr + nsym->st_name;
+		Syscapset	symcapset = { 0 };
+
+		if ((grpndx =
+		    (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx])) == 0)
+			continue;
+
+		if (sym_cap_check(cap, grpndx, &symcapset, ilmp,
+		    nname, symndx) == 0)
+			continue;
+
+		/*
+		 * Determine whether a symbol's capabilities are more
+		 * significant than any that have already been validated.
+		 */
+		if (is_sym_the_best(&bestcapset, &symcapset)) {
+			bestcapset = symcapset;
+			bsym = nsym;
+			bname = nname;
+			bndx = symndx;
+		}
+	}
+
+	DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, bname, bndx,
+	    M_MACH, NULL));
+
+	/*
+	 * Having found the best symbol, cache the results by overriding the
+	 * first element of the associated chain.
+	 */
+	capchain[ochainndx] = bndx;
+	capchain[ochainndx + 1] = 0;
+
+	/*
+	 * Update the symbol result information for return to the user.
+	 */
+	srp->sr_sym = bsym;
+	srp->sr_name = bname;
+	return (1);
+}
--- a/usr/src/cmd/sgs/rtld/common/config_elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/config_elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -230,7 +230,7 @@
 		 * Expand any configuration string.
 		 */
 		if ((tkns = expand(&estr, &size, 0, 0,
-		    (PD_TKN_ISALIST | PD_TKN_HWCAP), lmp)) == 0)
+		    (PD_TKN_ISALIST | PD_TKN_CAP), lmp)) == 0)
 			return (0);
 
 		/*
@@ -332,7 +332,7 @@
 		}
 #endif
 		if (expand_paths(lmp, str, &elf_def_dirs, AL_CNT_SEARCH,
-		    (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_HWCAP) != NULL)
+		    (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
 			features |= CONF_EDLIBPATH;
 	}
 	if (head->ch_eslibpath) {
@@ -350,20 +350,20 @@
 		}
 #endif
 		if (expand_paths(lmp, str, &elf_sec_dirs, AL_CNT_SEARCH,
-		    (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_HWCAP) != NULL)
+		    (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
 			features |= CONF_ESLIBPATH;
 	}
 #if	defined(__sparc) && !defined(_ELF64)
 	if (head->ch_adlibpath) {
 		str = (const char *)(head->ch_adlibpath + addr);
 		if (expand_paths(lmp, str, &aout_def_dirs, AL_CNT_SEARCH,
-		    (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_HWCAP) != NULL)
+		    (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
 			features |= CONF_ADLIBPATH;
 	}
 	if (head->ch_aslibpath) {
 		str = (const char *)(head->ch_aslibpath + addr);
 		if (expand_paths(lmp, str, &aout_sec_dirs, AL_CNT_SEARCH,
-		    (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_HWCAP) != NULL)
+		    (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
 			features |= CONF_ASLIBPATH;
 	}
 #endif
--- a/usr/src/cmd/sgs/rtld/common/dlfcns.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c	Mon Mar 01 10:20:48 2010 -0800
@@ -1035,17 +1035,16 @@
 /*
  * Handle processing for dlsym.
  */
-Sym *
-dlsym_handle(Grp_hdl *ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo,
+int
+dlsym_handle(Grp_hdl *ghp, Slookup *slp, Sresult *srp, uint_t *binfo,
     int *in_nfavl)
 {
 	Rt_map		*nlmp, * lmp = ghp->gh_ownlmp;
 	Rt_map		*clmp = slp->sl_cmap;
 	const char	*name = slp->sl_name;
-	Sym		*sym = NULL;
 	Slookup		sl = *slp;
 
-	sl.sl_flags = (LKUP_FIRST | LKUP_SPEC);
+	sl.sl_flags = (LKUP_FIRST | LKUP_DLSYM | LKUP_SPEC);
 
 	/*
 	 * Continue processing a dlsym request.  Lookup the required symbol in
@@ -1077,7 +1076,7 @@
 			 * first object check whether we're done.
 			 */
 			if ((nlmp != lmp) && (ghp->gh_flags & GPH_FIRST))
-				return (NULL);
+				return (0);
 
 			if (!(MODE(nlmp) & RTLD_GLOBAL))
 				continue;
@@ -1086,9 +1085,8 @@
 				continue;
 
 			sl.sl_imap = nlmp;
-			if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo,
-			    in_nfavl))
-				return (sym);
+			if (LM_LOOKUP_SYM(clmp)(&sl, srp, binfo, in_nfavl))
+				return (1);
 
 			/*
 			 * Keep track of any global pending lazy loads.
@@ -1118,9 +1116,9 @@
 					continue;
 
 				sl.sl_imap = nlmp;
-				if (sym = elf_lazy_find_sym(&sl, _lmp, binfo,
+				if (elf_lazy_find_sym(&sl, srp, binfo,
 				    in_nfavl))
-					return (sym);
+					return (1);
 			}
 		}
 	} else {
@@ -1139,12 +1137,11 @@
 				continue;
 
 			sl.sl_imap = nlmp;
-			if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo,
-			    in_nfavl))
-				return (sym);
+			if (LM_LOOKUP_SYM(clmp)(&sl, srp, binfo, in_nfavl))
+				return (1);
 
 			if (ghp->gh_flags & GPH_FIRST)
-				return (NULL);
+				return (0);
 
 			/*
 			 * Keep track of any pending lazy loads associated
@@ -1169,25 +1166,27 @@
 					continue;
 
 				sl.sl_imap = nlmp;
-				if (sym = elf_lazy_find_sym(&sl, _lmp,
-				    binfo, in_nfavl))
-					return (sym);
+				if (elf_lazy_find_sym(&sl, srp, binfo,
+				    in_nfavl))
+					return (1);
 			}
 		}
 	}
-	return (NULL);
+	return (0);
 }
 
 /*
  * Core dlsym activity.  Selects symbol lookup method from handle.
  */
-void *
+static void *
 dlsym_core(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp,
     int *in_nfavl)
 {
 	Sym		*sym = NULL;
+	int		ret = 0;
 	Syminfo		*sip;
 	Slookup		sl;
+	Sresult		sr;
 	uint_t		binfo;
 
 	/*
@@ -1207,14 +1206,18 @@
 	 */
 	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) &&
-	    ((sym = SYMINTP(clmp)(&sl, 0, 0, NULL)) != NULL)) {
+	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;
 	}
 
+	SRESULT_INIT(sr, name);
+
 	if (sym && (ELF_ST_VISIBILITY(sym->st_other) == STV_SINGLETON)) {
 		Rt_map	*hlmp = LIST(clmp)->lm_head;
 
@@ -1230,7 +1233,7 @@
 		sl.sl_flags = LKUP_SPEC;
 		if (handle == RTLD_PROBE)
 			sl.sl_flags |= LKUP_NOFALLBACK;
-		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
+		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else if (handle == RTLD_NEXT) {
 		Rt_map	*nlmp;
@@ -1277,7 +1280,7 @@
 			return (0);
 
 		sl.sl_flags = LKUP_NEXT;
-		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
+		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else if (handle == RTLD_SELF) {
 		/*
@@ -1288,7 +1291,7 @@
 
 		sl.sl_imap = clmp;
 		sl.sl_flags = (LKUP_SPEC | LKUP_SELF);
-		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
+		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else if (handle == RTLD_DEFAULT) {
 		Rt_map	*hlmp = LIST(clmp)->lm_head;
@@ -1302,7 +1305,7 @@
 
 		sl.sl_imap = hlmp;
 		sl.sl_flags = LKUP_SPEC;
-		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
+		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else if (handle == RTLD_PROBE) {
 		Rt_map	*hlmp = LIST(clmp)->lm_head;
@@ -1321,7 +1324,7 @@
 
 		sl.sl_imap = hlmp;
 		sl.sl_flags = (LKUP_SPEC | LKUP_NOFALLBACK);
-		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
+		ret = LM_LOOKUP_SYM(clmp)(&sl, &sr, &binfo, in_nfavl);
 
 	} else {
 		Grp_hdl *ghp = (Grp_hdl *)handle;
@@ -1333,13 +1336,14 @@
 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl,
 		    NAME(ghp->gh_ownlmp), DBG_DLSYM_DEF));
 
-		sym = LM_DLSYM(clmp)(ghp, &sl, dlmp, &binfo, in_nfavl);
+		ret = LM_DLSYM(clmp)(ghp, &sl, &sr, &binfo, in_nfavl);
 	}
 
-	if (sym) {
+	if (ret && ((sym = sr.sr_sym) != NULL)) {
 		Lm_list	*lml = LIST(clmp);
 		Addr	addr = sym->st_value;
 
+		*dlmp = sr.sr_dmap;
 		if (!(FLAGS(*dlmp) & FLG_RT_FIXED))
 			addr += ADDR(*dlmp);
 
@@ -1350,7 +1354,7 @@
 			FLAGS1(*dlmp) |= FL1_RT_USED;
 
 		DBG_CALL(Dbg_bind_global(clmp, 0, 0, (Xword)-1, PLT_T_NONE,
-		    *dlmp, addr, sym->st_value, name, binfo));
+		    *dlmp, addr, sym->st_value, sr.sr_name, binfo));
 
 		if ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_SYMBIND) {
 			uint_t	sb_flags = LA_SYMB_DLSYM;
@@ -1361,8 +1365,9 @@
 			    &sb_flags);
 		}
 		return ((void *)addr);
-	} else
-		return (0);
+	}
+
+	return (NULL);
 }
 
 /*
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -163,50 +163,62 @@
 }
 
 /*
- * Determine whether this object requires any hardware or software capabilities.
+ * Determine whether this object requires capabilities.
  */
-static int
+inline static int
 elf_cap_check(Fdesc *fdp, Ehdr *ehdr, Rej_desc *rej)
 {
 	Phdr	*phdr;
+	Cap	*cap = NULL;
+	Dyn	*dyn = NULL;
+	char	*str = NULL;
+	Addr	base;
 	int	cnt;
 
+	/*
+	 * If this is a shared object, the base address of the shared object is
+	 * added to all address values defined within the object.  Otherwise, if
+	 * this is an executable, all object addresses are used as is.
+	 */
+	if (ehdr->e_type == ET_EXEC)
+		base = 0;
+	else
+		base = (Addr)ehdr;
+
 	/* LINTED */
 	phdr = (Phdr *)((char *)ehdr + ehdr->e_phoff);
 	for (cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) {
-		Cap	*cptr;
-
-		if (phdr->p_type != PT_SUNWCAP)
-			continue;
-
-		/* LINTED */
-		cptr = (Cap *)((char *)ehdr + phdr->p_offset);
-		while (cptr->c_tag != CA_SUNW_NULL) {
-			if (cptr->c_tag == CA_SUNW_HW_1) {
-				/*
-				 * Verify the hardware capabilities.
-				 */
-				if (hwcap_check(cptr->c_un.c_val, rej) == 0)
-					return (0);
-
-				/*
-				 * Retain this hardware capabilities value for
-				 * possible later inspection should this object
-				 * be processed as a filtee.
-				 */
-				fdp->fd_hwcap = cptr->c_un.c_val;
-			}
-			if (cptr->c_tag == CA_SUNW_SF_1) {
-				/*
-				 * Verify the software capabilities.
-				 */
-				if (sfcap_check(cptr->c_un.c_val, rej) == 0)
-					return (0);
-			}
-			cptr++;
+		if (phdr->p_type == PT_DYNAMIC) {
+			/* LINTED */
+			dyn = (Dyn *)((uintptr_t)phdr->p_vaddr + base);
+		} else if (phdr->p_type == PT_SUNWCAP) {
+			/* LINTED */
+			cap = (Cap *)((uintptr_t)phdr->p_vaddr + base);
 		}
 	}
-	return (1);
+
+	if (cap) {
+		/*
+		 * From the .dynamic section, determine the associated string
+		 * table.  Required for CA_SUNW_MACH and CA_SUNW_PLAT
+		 * processing.
+		 */
+		while (dyn) {
+			if (dyn->d_tag == DT_NULL) {
+				break;
+			} else if (dyn->d_tag == DT_STRTAB) {
+				str = (char *)(dyn->d_un.d_ptr + base);
+				break;
+			}
+			dyn++;
+		}
+	}
+
+	/*
+	 * Establish any alternative capabilities, and validate this object
+	 * if it defines it's own capabilities information.
+	 */
+	return (cap_check_fdesc(fdp, cap, str, rej));
 }
 
 /*
@@ -272,23 +284,19 @@
 		return (NULL);
 
 	/*
-	 * Verify any hardware/software capability requirements.  Note, if this
-	 * object is an explicitly defined shared object under inspection by
-	 * ldd(1), and contains an incompatible hardware capabilities
-	 * requirement, then inform the user, but continue processing.
+	 * Verify any capability requirements.  Note, if this object is a shared
+	 * object that is explicitly defined on the ldd(1) command line, and it
+	 * contains an incompatible capabilities requirement, then inform the
+	 * user, but continue processing.
 	 */
 	if (elf_cap_check(fdp, ehdr, rej) == 0) {
 		Rt_map	*lmp = lml_main.lm_head;
 
 		if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
 		    (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
-			const char	*fmt;
-
-			if (rej->rej_type == SGS_REJ_HWCAP_1)
-				fmt = MSG_INTL(MSG_LDD_GEN_HWCAP_1);
-			else
-				fmt = MSG_INTL(MSG_LDD_GEN_SFCAP_1);
-			(void) printf(fmt, name, rej->rej_str);
+			/* LINTED */
+			(void) printf(MSG_INTL(ldd_warn[rej->rej_type]), name,
+			    rej->rej_str);
 			return (&elf_fct);
 		}
 		return (NULL);
@@ -542,7 +550,7 @@
 			 *
 			 * Such versions are recorded in the object for the
 			 * benefit of VERSYM entries that refer to them. This
-			 * provides a purely diagnositic benefit.
+			 * provides a purely diagnostic benefit.
 			 */
 			if (vnap->vna_flags & VER_FLG_INFO)
 				continue;
@@ -783,10 +791,10 @@
  * A null symbol interpretor.  Used if a filter has no associated filtees.
  */
 /* ARGSUSED0 */
-static Sym *
-elf_null_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
+static int
+elf_null_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
-	return (NULL);
+	return (0);
 }
 
 /*
@@ -833,8 +841,8 @@
  *
  * A symbol name of 0 is used to trigger filtee loading.
  */
-static Sym *
-_elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx,
+static int
+_elf_lookup_filtee(Slookup *slp, Sresult *srp, uint_t *binfo, uint_t ndx,
     int *in_nfavl)
 {
 	const char	*name = slp->sl_name, *filtees;
@@ -883,10 +891,10 @@
 	 */
 	filtees = (char *)STRTAB(ilmp) + DYN(ilmp)[ndx].d_un.d_val;
 	if (dip->di_info == NULL) {
-		if (rtld_flags2 & RT_FL2_FLTCFG)
+		if (rtld_flags2 & RT_FL2_FLTCFG) {
 			elf_config_flt(lml, PATHNAME(ilmp), filtees,
 			    (Alist **)&dip->di_info, AL_CNT_FILTEES);
-
+		}
 		if (dip->di_info == NULL) {
 			DBG_CALL(Dbg_file_filter(lml, NAME(ilmp), filtees, 0));
 			if ((lml->lm_flags &
@@ -898,7 +906,7 @@
 			if (expand_paths(ilmp, filtees, (Alist **)&dip->di_info,
 			    AL_CNT_FILTEES, 0, 0) == 0) {
 				elf_disable_filtee(ilmp, dip);
-				return (NULL);
+				return (0);
 			}
 		}
 	}
@@ -934,11 +942,10 @@
 			mode |= RTLD_PARENT;
 
 		/*
-		 * Process any hardware capability directory.  Establish a new
-		 * link-map control list from which to analyze any newly added
-		 * objects.
+		 * Process any capability directory.  Establish a new link-map
+		 * control list from which to analyze any newly added objects.
 		 */
-		if ((pdp->pd_info == NULL) && (pdp->pd_flags & PD_TKN_HWCAP)) {
+		if ((pdp->pd_info == NULL) && (pdp->pd_flags & PD_TKN_CAP)) {
 			const char	*dir = pdp->pd_pname;
 			Aliste		lmco;
 
@@ -949,40 +956,38 @@
 				return (NULL);
 
 			/*
-			 * Determine the hardware capability filtees.  If none
-			 * can be found, provide suitable diagnostics.
+			 * Determine the capability filtees.  If none can be
+			 * found, provide suitable diagnostics.
 			 */
-			DBG_CALL(Dbg_cap_hw_filter(lml, dir, ilmp));
-			if (hwcap_filtees((Alist **)&dip->di_info, idx, dir,
+			DBG_CALL(Dbg_cap_filter(lml, dir, ilmp));
+			if (cap_filtees((Alist **)&dip->di_info, idx, dir,
 			    lmco, ilmp, filtees, mode,
-			    (FLG_RT_PUBHDL | FLG_RT_HWCAP), in_nfavl) == 0) {
+			    (FLG_RT_PUBHDL | FLG_RT_CAP), in_nfavl) == 0) {
 				if ((lml->lm_flags & LML_FLG_TRC_ENABLE) &&
 				    (dip->di_flags & FLG_DI_AUXFLTR) &&
 				    (rtld_flags & RT_FL_WARNFLTR)) {
 					(void) printf(
-					    MSG_INTL(MSG_LDD_HWCAP_NFOUND),
-					    dir);
+					    MSG_INTL(MSG_LDD_CAP_NFOUND), dir);
 				}
-				DBG_CALL(Dbg_cap_hw_filter(lml, dir, 0));
+				DBG_CALL(Dbg_cap_filter(lml, dir, 0));
 			}
 
 			/*
-			 * Re-establish the originating path name descriptor, as
-			 * the expansion of hardware capabilities filtees may
-			 * have re-allocated the controlling Alist.  Mark this
+			 * Re-establish the originating path name descriptor,
+			 * as the expansion of capabilities filtees may have
+			 * re-allocated the controlling Alist.  Mark this
 			 * original pathname descriptor as unused so that the
 			 * descriptor isn't revisited for processing.  Any real
-			 * hardware capabilities filtees have been added as new
-			 * pathname descriptors following this descriptor.
+			 * capabilities filtees have been added as new pathname
+			 * descriptors following this descriptor.
 			 */
 			pdp = alist_item((Alist *)dip->di_info, idx);
-			pdp->pd_flags &= ~PD_TKN_HWCAP;
+			pdp->pd_flags &= ~PD_TKN_CAP;
 			pdp->pd_plen = 0;
 
 			/*
-			 * Now that any hardware capability objects have been
-			 * processed, remove any temporary link-map control
-			 * list.
+			 * Now that any capability objects have been processed,
+			 * remove any temporary link-map control list.
 			 */
 			if (lmco != ALIST_OFF_DATA)
 				remove_cntl(lml, lmco);
@@ -1199,16 +1204,17 @@
 		ghp = (Grp_hdl *)pdp->pd_info;
 
 		/*
-		 * If we're just here to trigger filtee loading skip the symbol
-		 * lookup so we'll continue looking for additional filtees.
+		 * If name is NULL, we're here to trigger filtee loading.
+		 * Skip the symbol lookup so that we'll continue looking for
+		 * additional filtees.
 		 */
 		if (name) {
 			Grp_desc	*gdp;
-			Sym		*sym = NULL;
+			int		ret = 0;
 			Aliste		idx;
 			Slookup		sl = *slp;
 
-			sl.sl_flags |= LKUP_FIRST;
+			sl.sl_flags |= (LKUP_FIRST | LKUP_DLSYM);
 			any++;
 
 			/*
@@ -1231,8 +1237,8 @@
 				if ((sl.sl_imap = gdp->gd_depend) == ilmp)
 					continue;
 
-				if (((sym = SYMINTP(sl.sl_imap)(&sl, dlmp,
-				    binfo, in_nfavl)) != NULL) ||
+				if (((ret = SYMINTP(sl.sl_imap)(&sl, srp, binfo,
+				    in_nfavl)) != 0) ||
 				    (ghp->gh_flags & GPH_FIRST))
 					break;
 			}
@@ -1241,9 +1247,9 @@
 			 * If a symbol has been found, indicate the binding
 			 * and return the symbol.
 			 */
-			if (sym) {
+			if (ret) {
 				*binfo |= DBG_BINFO_FILTEE;
-				return (sym);
+				return (1);
 			}
 		}
 
@@ -1259,7 +1265,7 @@
 	 * If we're just here to trigger filtee loading then we're done.
 	 */
 	if (name == NULL)
-		return (NULL);
+		return (0);
 
 	/*
 	 * If no filtees have been found for a filter, clean up any path name
@@ -1271,10 +1277,9 @@
 	if (any == 0) {
 		remove_plist((Alist **)&(dip->di_info), 1);
 		elf_disable_filtee(ilmp, dip);
-		return (NULL);
 	}
 
-	return (NULL);
+	return (0);
 }
 
 /*
@@ -1282,8 +1287,8 @@
  * auxiliary filter allows for filtee use, but provides a fallback should a
  * filtee not exist (or fail to load), any errors generated as a consequence of
  * trying to load the filtees are typically suppressed.  Setting RT_FL_SILENCERR
- * suppresses errors generated by eprint(), but insures a debug diagnostic is
- * produced.  ldd(1) employs printf(), and here, the selection of whether to
+ * suppresses errors generated by eprintf(), but ensures a debug diagnostic is
+ * produced.  ldd(1) employs printf(), and here the selection of whether to
  * print a diagnostic in regards to auxiliary filters is a little more complex.
  *
  *   -	The determination of whether to produce an ldd message, or a fatal
@@ -1291,21 +1296,18 @@
  *   -	More detailed ldd messages may also be driven off of LML_FLG_TRC_WARN,
  *	(ldd -d/-r), LML_FLG_TRC_VERBOSE (ldd -v), LML_FLG_TRC_SEARCH (ldd -s),
  *	and LML_FLG_TRC_UNREF/LML_FLG_TRC_UNUSED (ldd -U/-u).
- *
  *   -	If the calling object is lddstub, then several classes of message are
  *	suppressed.  The user isn't trying to diagnose lddstub, this is simply
  *	a stub executable employed to preload a user specified library against.
- *
  *   -	If RT_FL_SILENCERR is in effect then any generic ldd() messages should
  *	be suppressed.  All detailed ldd messages should still be produced.
  */
-Sym *
-elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx,
+int
+elf_lookup_filtee(Slookup *slp, Sresult *srp, uint_t *binfo, uint_t ndx,
     int *in_nfavl)
 {
-	Sym	*sym;
 	Dyninfo	*dip = &DYNINFO(slp->sl_imap)[ndx];
-	int	silent = 0;
+	int	ret, silent = 0;
 
 	/*
 	 * Make sure this entry is still acting as a filter.  We may have tried
@@ -1314,7 +1316,7 @@
 	 * that are yet to be completed.
 	 */
 	if (dip->di_flags == 0)
-		return (NULL);
+		return (0);
 
 	/*
 	 * Indicate whether an error message is required should this filtee not
@@ -1326,12 +1328,12 @@
 		silent = 1;
 	}
 
-	sym = _elf_lookup_filtee(slp, dlmp, binfo, ndx, in_nfavl);
+	ret = _elf_lookup_filtee(slp, srp, binfo, ndx, in_nfavl);
 
 	if (silent)
 		rtld_flags &= ~RT_FL_SILENCERR;
 
-	return (sym);
+	return (ret);
 }
 
 /*
@@ -1364,20 +1366,17 @@
 }
 
 /*
- * If flag argument has LKUP_SPEC set, we treat undefined symbols of type
- * function specially in the executable - if they have a value, even though
- * undefined, we use that value.  This allows us to associate all references
- * to a function's address to a single place in the process: the plt entry
- * for that function in the executable.  Calls to lookup from plt binding
- * routines do NOT set LKUP_SPEC in the flag.
+ * Look up a symbol.  The callers lookup information is passed in the Slookup
+ * structure, and any resultant binding information is returned in the Sresult
+ * structure.
  */
-Sym *
-elf_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
+int
+elf_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
 	const char	*name = slp->sl_name;
 	Rt_map		*ilmp = slp->sl_imap;
 	ulong_t		hash = slp->sl_hash;
-	uint_t		ndx, htmp, buckets, *chainptr;
+	uint_t		ndx, hashoff, buckets, *chainptr;
 	Sym		*sym, *symtabptr;
 	char		*strtabptr, *strtabname;
 	uint_t		flags1;
@@ -1391,18 +1390,18 @@
 		DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_ELF)));
 
 	if (HASH(ilmp) == NULL)
-		return (NULL);
+		return (0);
 
 	buckets = HASH(ilmp)[0];
 	/* LINTED */
-	htmp = (uint_t)hash % buckets;
+	hashoff = ((uint_t)hash % buckets) + 2;
 
 	/*
-	 * Get the first symbol on hash chain and initialize the string
+	 * Get the first symbol from the hash chain and initialize the string
 	 * and symbol table pointers.
 	 */
-	if ((ndx = HASH(ilmp)[htmp + 2]) == 0)
-		return (NULL);
+	if ((ndx = HASH(ilmp)[hashoff]) == 0)
+		return (0);
 
 	chainptr = HASH(ilmp) + 2 + buckets;
 	strtabptr = STRTAB(ilmp);
@@ -1417,12 +1416,26 @@
 		 * names don't match continue with the next hash entry.
 		 */
 		if ((*strtabname++ != *name) || strcmp(strtabname, &name[1])) {
+			hashoff = ndx + buckets + 2;
 			if ((ndx = chainptr[ndx]) != 0)
 				continue;
-			return (NULL);
+			return (0);
 		}
 
 		/*
+		 * Symbols that are defined as hidden within an object usually
+		 * have any references from within the same object bound at
+		 * link-edit time, thus ld.so.1 is not involved.  However, if
+		 * these are capabilities symbols, then references to them must
+		 * be resolved at runtime.  A hidden symbol can only be bound
+		 * to by the object that defines the symbol.
+		 */
+		if ((sym->st_shndx != SHN_UNDEF) &&
+		    (ELF_ST_VISIBILITY(sym->st_other) == STV_HIDDEN) &&
+		    (slp->sl_cmap != ilmp))
+			return (0);
+
+		/*
 		 * The Solaris ld does not put DT_VERSYM in the dynamic
 		 * section, but the GNU ld does. The GNU runtime linker
 		 * interprets the top bit of the 16-bit Versym value
@@ -1436,28 +1449,30 @@
 		 * it allows, but we honor the hidden bit in GNU ld
 		 * produced objects in order to interoperate with them.
 		 */
-		if ((VERSYM(ilmp) != NULL) &&
-		    ((VERSYM(ilmp)[ndx] & 0x8000) != 0)) {
+		if (VERSYM(ilmp) && (VERSYM(ilmp)[ndx] & 0x8000)) {
 			DBG_CALL(Dbg_syms_ignore_gnuver(ilmp, name,
 			    ndx, VERSYM(ilmp)[ndx]));
-			if ((ndx = chainptr[ndx]) != 0)
-				continue;
-			return (NULL);
+			return (0);
 		}
 
 		/*
-		 * If we're only here to establish a symbols index, we're done.
+		 * If we're only here to establish a symbol's index, we're done.
 		 */
-		if (slp->sl_flags & LKUP_SYMNDX)
-			return (sym);
+		if (slp->sl_flags & LKUP_SYMNDX) {
+			srp->sr_dmap = ilmp;
+			srp->sr_sym = sym;
+			return (1);
+		}
 
 		/*
-		 * If we find a match and the symbol is defined, return the
+		 * If we find a match and the symbol is defined, capture the
 		 * symbol pointer and the link map in which it was found.
 		 */
 		if (sym->st_shndx != SHN_UNDEF) {
-			*dlmp = ilmp;
+			srp->sr_dmap = ilmp;
+			srp->sr_sym = sym;
 			*binfo |= DBG_BINFO_FOUND;
+
 			if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) ||
 			    ((FLAGS(ilmp) & FLG_RT_SYMINTPO) &&
 			    is_sym_interposer(ilmp, sym)))
@@ -1475,19 +1490,21 @@
 		} else if ((slp->sl_flags & LKUP_SPEC) &&
 		    (FLAGS(ilmp) & FLG_RT_ISMAIN) && (sym->st_value != 0) &&
 		    (ELF_ST_TYPE(sym->st_info) == STT_FUNC)) {
-			*dlmp = ilmp;
+			srp->sr_dmap = ilmp;
+			srp->sr_sym = sym;
 			*binfo |= (DBG_BINFO_FOUND | DBG_BINFO_PLTADDR);
+
 			if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) ||
 			    ((FLAGS(ilmp) & FLG_RT_SYMINTPO) &&
 			    is_sym_interposer(ilmp, sym)))
 				*binfo |= DBG_BINFO_INTERPOSE;
-			return (sym);
+			return (1);
 		}
 
 		/*
 		 * Undefined symbol.
 		 */
-		return (NULL);
+		return (0);
 	}
 
 	/*
@@ -1512,7 +1529,7 @@
 		    DBG_BNDREJ_SINGLE));
 		*binfo |= BINFO_REJSINGLE;
 		*binfo &= ~DBG_BINFO_MSK;
-		return (NULL);
+		return (0);
 	}
 
 	/*
@@ -1528,7 +1545,7 @@
 		    DBG_BNDREJ_DIRECT));
 		*binfo |= BINFO_REJDIRECT;
 		*binfo &= ~DBG_BINFO_MSK;
-		return (NULL);
+		return (0);
 	}
 
 	/*
@@ -1557,14 +1574,24 @@
 		    DBG_BNDREJ_GROUP));
 		*binfo |= BINFO_REJGROUP;
 		*binfo &= ~DBG_BINFO_MSK;
-		return (NULL);
+		return (0);
 	}
 
 	/*
+	 * If this symbol is associated with capabilities, then each of the
+	 * capabilities instances needs to be compared against the system
+	 * capabilities.  The best instance will be chosen to satisfy this
+	 * binding.
+	 */
+	if (CAP(ilmp) && CAPINFO(ilmp) && ELF_C_GROUP(CAPINFO(ilmp)[ndx]) &&
+	    (cap_match(srp, ndx, symtabptr, strtabptr) == 0))
+		return (0);
+
+	/*
 	 * Determine whether this object is acting as a filter.
 	 */
 	if (((flags1 = FLAGS1(ilmp)) & MSK_RT_FILTER) == 0)
-		return (sym);
+		return (1);
 
 	/*
 	 * Determine if this object offers per-symbol filtering, and if so,
@@ -1579,12 +1606,18 @@
 		 */
 		if ((sip->si_flags & SYMINFO_FLG_FILTER) &&
 		    (SYMSFLTRCNT(ilmp) == 0))
-			return (NULL);
+			return (0);
 
 		if ((sip->si_flags & SYMINFO_FLG_FILTER) ||
 		    ((sip->si_flags & SYMINFO_FLG_AUXILIARY) &&
 		    SYMAFLTRCNT(ilmp))) {
-			Sym	*fsym;
+			Sresult	sr;
+
+			/*
+			 * Initialize a local symbol result descriptor, using
+			 * the original symbol name.
+			 */
+			SRESULT_INIT(sr, slp->sl_name);
 
 			/*
 			 * This symbol has an associated filtee.  Lookup the
@@ -1593,11 +1626,13 @@
 			 * filter, return an error, otherwise fall through to
 			 * catch any object filtering that may be available.
 			 */
-			if ((fsym = elf_lookup_filtee(slp, dlmp, binfo,
-			    sip->si_boundto, in_nfavl)) != NULL)
-				return (fsym);
+			if (elf_lookup_filtee(slp, &sr, binfo, sip->si_boundto,
+			    in_nfavl)) {
+				*srp = sr;
+				return (1);
+			}
 			if (sip->si_flags & SYMINFO_FLG_FILTER)
-				return (NULL);
+				return (0);
 		}
 	}
 
@@ -1605,9 +1640,15 @@
 	 * Determine if this object provides global filtering.
 	 */
 	if (flags1 & (FL1_RT_OBJSFLTR | FL1_RT_OBJAFLTR)) {
-		Sym	*fsym;
+		if (OBJFLTRNDX(ilmp) != FLTR_DISABLED) {
+			Sresult	sr;
 
-		if (OBJFLTRNDX(ilmp) != FLTR_DISABLED) {
+			/*
+			 * Initialize a local symbol result descriptor, using
+			 * the original symbol name.
+			 */
+			SRESULT_INIT(sr, slp->sl_name);
+
 			/*
 			 * This object has an associated filtee.  Lookup the
 			 * symbol in the filtee, and if it is found return it.
@@ -1615,15 +1656,17 @@
 			 * filter, return and error, otherwise return the symbol
 			 * within the filter itself.
 			 */
-			if ((fsym = elf_lookup_filtee(slp, dlmp, binfo,
-			    OBJFLTRNDX(ilmp), in_nfavl)) != NULL)
-				return (fsym);
+			if (elf_lookup_filtee(slp, &sr, binfo, OBJFLTRNDX(ilmp),
+			    in_nfavl)) {
+				*srp = sr;
+				return (1);
+			}
 		}
 
 		if (flags1 & FL1_RT_OBJSFLTR)
-			return (NULL);
+			return (0);
 	}
-	return (sym);
+	return (1);
 }
 
 /*
@@ -1983,7 +2026,7 @@
 				 * Global auditing is only meaningful when
 				 * specified by the initiating object of the
 				 * process - typically the dynamic executable.
-				 * If this is the initiaiting object, its link-
+				 * If this is the initiating object, its link-
 				 * map will not yet have been added to the
 				 * link-map list, and consequently the link-map
 				 * list is empty.  (see setup()).
@@ -2064,6 +2107,22 @@
 			case M_DT_REGISTER:
 				FLAGS(lmp) |= FLG_RT_REGSYMS;
 				break;
+			case DT_SUNW_CAP:
+				CAP(lmp) = (void *)(dyn->d_un.d_ptr + base);
+				break;
+			case DT_SUNW_CAPINFO:
+				CAPINFO(lmp) = (void *)(dyn->d_un.d_ptr + base);
+				break;
+			case DT_SUNW_CAPCHAIN:
+				CAPCHAIN(lmp) = (void *)(dyn->d_un.d_ptr +
+				    base);
+				break;
+			case DT_SUNW_CAPCHAINENT:
+				CAPCHAINENT(lmp) = dyn->d_un.d_val;
+				break;
+			case DT_SUNW_CAPCHAINSZ:
+				CAPCHAINSZ(lmp) = dyn->d_un.d_val;
+				break;
 			}
 		}
 
@@ -2171,8 +2230,80 @@
 		return (NULL);
 	}
 
-	if (cap)
-		cap_assign(cap, lmp);
+	/*
+	 * A capabilities section should be identified by a DT_SUNW_CAP entry,
+	 * and if non-empty object capabilities are included, a PT_SUNWCAP
+	 * header should reference the section.  Make sure CAP() is set
+	 * regardless.
+	 */
+	if ((CAP(lmp) == NULL) && cap)
+		CAP(lmp) = cap;
+
+	/*
+	 * Make sure any capabilities information or chain can be handled.
+	 */
+	if (CAPINFO(lmp) && (CAPINFO(lmp)[0] > CAPINFO_CURRENT))
+		CAPINFO(lmp) = NULL;
+	if (CAPCHAIN(lmp) && (CAPCHAIN(lmp)[0] > CAPCHAIN_CURRENT))
+		CAPCHAIN(lmp) = NULL;
+
+	/*
+	 * As part of processing dependencies, a file descriptor is populated
+	 * with capabilities information following validation.
+	 */
+	if (fdp->fd_flags & FLG_FD_ALTCHECK) {
+		FLAGS1(lmp) |= FL1_RT_ALTCHECK;
+		CAPSET(lmp) = fdp->fd_scapset;
+
+		if (fdp->fd_flags & FLG_FD_ALTCAP)
+			FLAGS1(lmp) |= FL1_RT_ALTCAP;
+
+	} else if ((cap = CAP(lmp)) != NULL) {
+		/*
+		 * Processing of the a.out and ld.so.1 does not involve a file
+		 * descriptor as exec() did all the work, so capture the
+		 * capabilities for these cases.
+		 */
+		while (cap->c_tag != CA_SUNW_NULL) {
+			switch (cap->c_tag) {
+			case CA_SUNW_HW_1:
+				CAPSET(lmp).sc_hw_1 = cap->c_un.c_val;
+				break;
+			case CA_SUNW_SF_1:
+				CAPSET(lmp).sc_sf_1 = cap->c_un.c_val;
+				break;
+			case CA_SUNW_HW_2:
+				CAPSET(lmp).sc_hw_2 = cap->c_un.c_val;
+				break;
+			case CA_SUNW_PLAT:
+				CAPSET(lmp).sc_plat = STRTAB(lmp) +
+				    cap->c_un.c_ptr;
+				break;
+			case CA_SUNW_MACH:
+				CAPSET(lmp).sc_mach = STRTAB(lmp) +
+				    cap->c_un.c_ptr;
+				break;
+			}
+			cap++;
+		}
+	}
+
+	/*
+	 * If a capabilities chain table exists, duplicate it.  The chain table
+	 * is inspected for each initial call to a capabilities family lead
+	 * symbol.  From this chain, each family member is inspected to
+	 * determine the 'best' family member.  The chain table is then updated
+	 * so that the best member is immediately selected for any further
+	 * family searches.
+	 */
+	if (CAPCHAIN(lmp)) {
+		Capchain	*capchain;
+
+		if ((capchain = calloc(CAPCHAINSZ(lmp), 1)) == NULL)
+			return (NULL);
+		(void) memcpy(capchain, CAPCHAIN(lmp), CAPCHAINSZ(lmp));
+		CAPCHAIN(lmp) = capchain;
+	}
 
 	/*
 	 * Add the mapped object to the end of the link map list.
@@ -2191,24 +2322,6 @@
 }
 
 /*
- * Assign hardware/software capabilities.
- */
-void
-cap_assign(Cap *cap, Rt_map *lmp)
-{
-	while (cap->c_tag != CA_SUNW_NULL) {
-		switch (cap->c_tag) {
-		case CA_SUNW_HW_1:
-			HWCAP(lmp) = cap->c_un.c_val;
-			break;
-		case CA_SUNW_SF_1:
-			SFCAP(lmp) = cap->c_un.c_val;
-		}
-		cap++;
-	}
-}
-
-/*
  * Build full pathname of shared object from given directory name and filename.
  */
 static char *
@@ -2512,10 +2625,9 @@
  * pending, this routine loads the dependencies in an attempt to locate the
  * symbol.
  */
-Sym *
-elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl)
+int
+elf_lazy_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
 {
-	Sym		*sym = NULL;
 	static APlist	*alist = NULL;
 	Aliste		idx1;
 	Rt_map		*lmp1, *lmp = slp->sl_imap, *clmp = slp->sl_cmap;
@@ -2571,6 +2683,7 @@
 			Grp_desc	*gdp;
 			Rt_map		*nlmp, *llmp;
 			Slookup		sl2;
+			Sresult		sr;
 			Aliste		idx2;
 
 			if (((dip->di_flags & FLG_DI_LAZY) == 0) ||
@@ -2641,9 +2754,16 @@
 				sl1.sl_imap = NEXT_RT_MAP(llmp);
 				sl1.sl_flags &= ~LKUP_STDRELOC;
 
-				if ((sym = lookup_sym(&sl1, _lmp, binfo,
-				    in_nfavl)) != NULL)
-					return (sym);
+				/*
+				 * Initialize a local symbol result descriptor,
+				 * using the original symbol name.
+				 */
+				SRESULT_INIT(sr, slp->sl_name);
+
+				if (lookup_sym(&sl1, &sr, binfo, in_nfavl)) {
+					*srp = sr;
+					return (1);
+				}
 			}
 
 			/*
@@ -2661,9 +2781,18 @@
 					sl2.sl_imap = gdp->gd_depend;
 					sl2.sl_flags |= LKUP_FIRST;
 
-					if ((sym = lookup_sym(&sl2, _lmp, binfo,
-					    in_nfavl)) != NULL)
-						return (sym);
+					/*
+					 * Initialize a local symbol result
+					 * descriptor, using the original
+					 * symbol name.
+					 */
+					SRESULT_INIT(sr, slp->sl_name);
+
+					if (lookup_sym(&sl2, &sr, binfo,
+					    in_nfavl)) {
+						*srp = sr;
+						return (1);
+					}
 				}
 			}
 
@@ -2676,11 +2805,11 @@
 				continue;
 
 			if (aplist_test(&alist, nlmp, AL_CNT_LAZYFIND) == NULL)
-				return (NULL);
+				return (0);
 		}
 	}
 
-	return (NULL);
+	return (0);
 }
 
 /*
--- a/usr/src/cmd/sgs/rtld/common/globals.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/globals.c	Mon Mar 01 10:20:48 2010 -0800
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -81,10 +81,7 @@
  * END: Exposed to rtld_db
  */
 
-Reglist		*reglist = NULL;		/* list of register symbols */
-
-ulong_t		hwcap = 0;			/* hardware capabilities */
-ulong_t		sfcap = 0;			/* software capabilities */
+Reglist		*reglist = NULL;	/* list of register symbols */
 
 /*
  * Set of integers to track how many of what type of PLT's have been bound.
@@ -98,9 +95,11 @@
 uint32_t	pltcntfar = 0;
 
 /*
- * Provide for recording not-found path names.
+ * AVL tree pointers.
  */
-avl_tree_t	*nfavl = NULL;
+avl_tree_t	*capavl = NULL;		/* capabilities files */
+avl_tree_t	*nfavl = NULL;		/* not-found path names */
+avl_tree_t	*spavl = NULL;		/* secure path names */
 
 /*
  * Various other global data.
@@ -119,8 +118,6 @@
 APlist		*hdl_alp[HDLIST_SZ+2];	/* dlopen() handle list */
 size_t		syspagsz = 0;		/* system page size */
 ulong_t		at_flags = 0;		/* machine specific file flags */
-char		*platform = NULL;	/* platform name from AT_SUN_PLATFORM */
-size_t		platform_sz = 0;	/* platform string length */
 Uts_desc	*uts = NULL; 		/* utsname descriptor */
 Isa_desc	*isa = NULL;		/* isalist descriptor */
 
@@ -148,6 +145,30 @@
 APlist		*free_alp = NULL;	/* defragmentation list */
 
 /*
+ * Capabilities are provided by the system.  However, users can define an
+ * alternative set of system capabilities, where they can add, subtract, or
+ * override the system capabilities for testing purposes.  Furthermore, these
+ * alternative capabilities can be specified such that they only apply to
+ * specified files rather than to all objects.
+ */
+static Syscapset	scapset = { 0 };
+Syscapset	*org_scapset = &scapset;	/* original system and */
+Syscapset	*alt_scapset = &scapset;	/* alternative system */
+						/*	capabilities */
+
+const char	*rpl_hwcap = NULL;	/* replaceable hwcap str */
+const char	*rpl_sfcap = NULL;	/* replaceable sfcap str */
+const char	*rpl_machcap = NULL;	/* replaceable machcap str */
+const char	*rpl_platcap = NULL;	/* replaceable platcap str */
+const char	*rpl_cap_files = NULL;	/* associated files */
+
+const char	*prm_hwcap = NULL;	/* permanent hwcap str */
+const char	*prm_sfcap = NULL;	/* permanent sfcap str */
+const char	*prm_machcap = NULL;	/* permanent machcap str */
+const char	*prm_platcap = NULL;	/* permanent platcap str */
+const char	*prm_cap_files = NULL;	/* associated files */
+
+/*
  * Note, the debugging descriptor interposes on the default definition provided
  * by liblddbg.  This is required as ld.so.1 must only have outstanding relative
  * relocations.
@@ -200,8 +221,12 @@
 		MSG_LDD_REJ_US3,	/* MSG_INTL(MSG_LDD_REJ_US3) */
 		MSG_LDD_REJ_STR,	/* MSG_INTL(MSG_LDD_REJ_STR) */
 		MSG_LDD_REJ_UNKFILE,	/* MSG_INTL(MSG_LDD_REJ_UNKFILE) */
+		MSG_LDD_REJ_UNKCAP,	/* MSG_INTL(MSG_LDD_REJ_UNKCAP) */
 		MSG_LDD_REJ_HWCAP_1,	/* MSG_INTL(MSG_LDD_REJ_HWCAP_1) */
 		MSG_LDD_REJ_SFCAP_1,	/* MSG_INTL(MSG_LDD_REJ_SFCAP_1) */
+		MSG_LDD_REJ_MACHCAP,	/* MSG_INTL(MSG_LDD_REJ_MACHCAP) */
+		MSG_LDD_REJ_PLATCAP,	/* MSG_INTL(MSG_LDD_REJ_PLATCAP) */
+		MSG_LDD_REJ_HWCAP_2	/* MSG_INTL(MSG_LDD_REJ_HWCAP_2) */
 	};
 
 const Msg
@@ -218,6 +243,32 @@
 		MSG_ERR_REJ_US3,	/* MSG_INTL(MSG_ERR_REJ_US3) */
 		MSG_ERR_REJ_STR,	/* MSG_INTL(MSG_ERR_REJ_STR) */
 		MSG_ERR_REJ_UNKFILE,	/* MSG_INTL(MSG_ERR_REJ_UNKFILE) */
+		MSG_ERR_REJ_UNKCAP,	/* MSG_INTL(MSG_ERR_REJ_UNKCAP) */
 		MSG_ERR_REJ_HWCAP_1,	/* MSG_INTL(MSG_ERR_REJ_HWCAP_1) */
 		MSG_ERR_REJ_SFCAP_1,	/* MSG_INTL(MSG_ERR_REJ_SFCAP_1) */
+		MSG_ERR_REJ_MACHCAP,	/* MSG_INTL(MSG_ERR_REJ_MACHCAP) */
+		MSG_ERR_REJ_PLATCAP,	/* MSG_INTL(MSG_ERR_REJ_PLATCAP) */
+		MSG_ERR_REJ_HWCAP_2	/* MSG_INTL(MSG_ERR_REJ_HWCAP_2) */
 	};
+
+const Msg
+ldd_warn[] = {
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_STR_EMPTY,
+		MSG_LDD_WARN_UNKCAP,	/* MSG_INTL(MSG_LDD_WARN_UNKCAP) */
+		MSG_LDD_WARN_HWCAP_1,	/* MSG_INTL(MSG_LDD_WARN_HWCAP_1) */
+		MSG_LDD_WARN_SFCAP_1,	/* MSG_INTL(MSG_LDD_WARN_SFCAP_1) */
+		MSG_LDD_WARN_MACHCAP,	/* MSG_INTL(MSG_LDD_WARN_MACHCAP) */
+		MSG_LDD_WARN_PLATCAP,	/* MSG_INTL(MSG_LDD_WARN_PLATCAP) */
+		MSG_LDD_WARN_HWCAP_2	/* MSG_INTL(MSG_LDD_WARN_HWCAP_2) */
+	};
--- a/usr/src/cmd/sgs/rtld/common/object.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/object.c	Mon Mar 01 10:20:48 2010 -0800
@@ -197,6 +197,35 @@
 }
 
 /*
+ * Ensure any platform or machine capability names are valid.
+ */
+inline static int
+check_plat_names(Syscapset *scapset, Alist *caps, Rej_desc *rej)
+{
+	Capstr	*capstr;
+	Aliste	idx;
+
+	for (ALIST_TRAVERSE(caps, idx, capstr)) {
+		if (platcap_check(scapset, capstr->cs_str, rej) == 1)
+			return (1);
+	}
+	return (0);
+}
+
+inline static int
+check_mach_names(Syscapset *scapset, Alist *caps, Rej_desc *rej)
+{
+	Capstr	*capstr;
+	Aliste	idx;
+
+	for (ALIST_TRAVERSE(caps, idx, capstr)) {
+		if (machcap_check(scapset, capstr->cs_str, rej) == 1)
+			return (1);
+	}
+	return (0);
+}
+
+/*
  * Finish relocatable object processing.  Having already initially processed one
  * or more objects, complete the generation of a shared object image by calling
  * the appropriate link-edit functionality (refer to sgs/ld/common/main.c).
@@ -217,7 +246,9 @@
 	Fdesc			fd = { 0 };
 	Grp_hdl			*ghp;
 	Rej_desc		rej = { 0 };
-	elfcap_mask_t		cap_value;
+	Syscapset		*scapset;
+	elfcap_mask_t		omsk;
+	Alist			*oalp;
 
 	DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
 
@@ -228,24 +259,28 @@
 
 	/*
 	 * At this point, all input section processing is complete.  If any
-	 * hardware or software capabilities have been established, ensure that
-	 * they are appropriate for this platform.
+	 * capabilities have been established, ensure that they are appropriate
+	 * for this system.
 	 */
-	cap_value = CAPMASK_VALUE(&ofl->ofl_ocapset.c_hw_1);
-	if (cap_value && (hwcap_check(cap_value, &rej) == 0)) {
+	if (pnavl_recorded(&capavl, ofl->ofl_name, NULL, NULL))
+		scapset = alt_scapset;
+	else
+		scapset = org_scapset;
+
+	if ((((omsk = ofl->ofl_ocapset.oc_hw_1.cm_val) != 0) &&
+	    (hwcap1_check(scapset, omsk, &rej) == 0)) ||
+	    (((omsk = ofl->ofl_ocapset.oc_sf_1.cm_val) != 0) &&
+	    (sfcap1_check(scapset, omsk, &rej) == 0)) ||
+	    (((omsk = ofl->ofl_ocapset.oc_hw_2.cm_val) != 0) &&
+	    (hwcap2_check(scapset, omsk, &rej) == 0)) ||
+	    (((oalp = ofl->ofl_ocapset.oc_plat.cl_val) != NULL) &&
+	    (check_plat_names(scapset, oalp, &rej) == 0)) ||
+	    (((oalp = ofl->ofl_ocapset.oc_mach.cl_val) != NULL) &&
+	    (check_mach_names(scapset, oalp, &rej) == 0))) {
 		if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
 		    (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
-			(void) printf(MSG_INTL(MSG_LDD_GEN_HWCAP_1),
-			    ofl->ofl_name, rej.rej_str);
-		}
-		return (NULL);
-	}
-
-	cap_value = CAPMASK_VALUE(&ofl->ofl_ocapset.c_sf_1);
-	if (cap_value && (sfcap_check(cap_value, &rej) == 0)) {
-		if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
-		    (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
-			(void) printf(MSG_INTL(MSG_LDD_GEN_SFCAP_1),
+			/* LINTED */
+			(void) printf(MSG_INTL(ldd_reject[rej.rej_type]),
 			    ofl->ofl_name, rej.rej_str);
 		}
 		return (NULL);
--- a/usr/src/cmd/sgs/rtld/common/paths.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/paths.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,7 +38,6 @@
 #include	<limits.h>
 #include	<fcntl.h>
 #include	<string.h>
-#include	<sys/systeminfo.h>
 #include	<debug.h>
 #include	<conv.h>
 #include	"_rtld.h"
@@ -173,7 +172,7 @@
 				 */
 				(void) expand_paths(lmp, rpl_libpath,
 				    &rpl_libdirs, AL_CNT_SEARCH, mode,
-				    PD_TKN_HWCAP);
+				    PD_TKN_CAP);
 			}
 			dalpp = &rpl_libdirs;
 		}
@@ -214,7 +213,7 @@
 				 */
 				(void) expand_paths(lmp, prm_libpath,
 				    &prm_libdirs, AL_CNT_SEARCH, mode,
-				    PD_TKN_HWCAP);
+				    PD_TKN_CAP);
 			}
 			dalpp = &prm_libdirs;
 		}
@@ -251,7 +250,7 @@
 				 */
 				(void) expand_paths(lmp, RPATH(lmp),
 				    &RLIST(lmp), AL_CNT_SEARCH, LA_SER_RUNPATH,
-				    PD_TKN_HWCAP);
+				    PD_TKN_CAP);
 			}
 			dalpp = &RLIST(lmp);
 		}
@@ -278,7 +277,7 @@
 }
 
 /*
- * Get the next directory in the search rules path.  The seach path "cookie"
+ * Get the next directory in the search rules path.  The search path "cookie"
  * provided by the caller (sdp) maintains the state of a search in progress.
  *
  * Typically, a search consists of a series of rules that govern the order of
@@ -418,31 +417,30 @@
 
 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_PLATFORM),
 		    MSG_TKN_PLATFORM_SIZE) == 0) {
+			Syscapset	*scapset;
+
+			if (FLAGS1(lmp) & FL1_RT_ALTCAP)
+				scapset = alt_scapset;
+			else
+				scapset = org_scapset;
+
 			token = (char *)MSG_ORIG(MSG_TKN_PLATFORM);
 
 			/*
-			 * $PLATFORM expansion required.  This would have been
-			 * established from the AT_SUN_PLATFORM aux vector, but
-			 * if not attempt to get it from sysconf().
+			 * $PLATFORM expansion required.
 			 */
 			if (((omit & PD_TKN_PLATFORM) == 0) &&
-			    ((platform == 0) && (platform_sz == 0))) {
-				char	_info[SYS_NMLN];
-				long	_size;
+			    ((scapset->sc_plat == NULL) &&
+			    (scapset->sc_platsz == 0)))
+				platform_name(scapset);
 
-				_size = sysinfo(SI_PLATFORM, _info, SYS_NMLN);
-				if ((_size != -1) && ((platform =
-				    malloc((size_t)_size)) != NULL)) {
-					(void) strcpy(platform, _info);
-					platform_sz = (size_t)_size - 1;
-				}
-			}
 			if (((omit & PD_TKN_PLATFORM) == 0) &&
-			    (platform != 0)) {
-				if ((nlen += platform_sz) < PATH_MAX) {
-					(void) strncpy(nptr, platform,
-					    platform_sz);
-					nptr = nptr + platform_sz;
+			    scapset->sc_plat) {
+				nlen += scapset->sc_platsz;
+				if (nlen < PATH_MAX) {
+					(void) strncpy(nptr, scapset->sc_plat,
+					    scapset->sc_platsz);
+					nptr = nptr + scapset->sc_platsz;
 					olen += MSG_TKN_PLATFORM_SIZE;
 					optr += MSG_TKN_PLATFORM_SIZE;
 					_flags |= PD_TKN_PLATFORM;
@@ -454,6 +452,43 @@
 				}
 			}
 
+		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_MACHINE),
+		    MSG_TKN_MACHINE_SIZE) == 0) {
+			Syscapset	*scapset;
+
+			if (FLAGS1(lmp) & FL1_RT_ALTCAP)
+				scapset = alt_scapset;
+			else
+				scapset = org_scapset;
+
+			token = (char *)MSG_ORIG(MSG_TKN_MACHINE);
+
+			/*
+			 * $MACHINE expansion required.
+			 */
+			if (((omit & PD_TKN_MACHINE) == 0) &&
+			    ((scapset->sc_mach == NULL) &&
+			    (scapset->sc_machsz == 0)))
+				machine_name(scapset);
+
+			if (((omit & PD_TKN_MACHINE) == 0) &&
+			    scapset->sc_mach) {
+				nlen += scapset->sc_machsz;
+				if (nlen < PATH_MAX) {
+					(void) strncpy(nptr, scapset->sc_mach,
+					    scapset->sc_machsz);
+					nptr = nptr + scapset->sc_machsz;
+					olen += MSG_TKN_MACHINE_SIZE;
+					optr += MSG_TKN_MACHINE_SIZE;
+					_flags |= PD_TKN_MACHINE;
+				} else {
+					eprintf(lml, ERR_FATAL,
+					    MSG_INTL(MSG_ERR_EXPAND1),
+					    NAME(lmp), oname);
+					return (0);
+				}
+			}
+
 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSNAME),
 		    MSG_TKN_OSNAME_SIZE) == 0) {
 			token = (char *)MSG_ORIG(MSG_TKN_OSNAME);
@@ -581,6 +616,32 @@
 				}
 			}
 
+		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_CAPABILITY),
+		    MSG_TKN_CAPABILITY_SIZE) == 0) {
+			char	*bptr = nptr - 1;
+			char	*eptr = optr + MSG_TKN_CAPABILITY_SIZE;
+			token = (char *)MSG_ORIG(MSG_TKN_CAPABILITY);
+
+			/*
+			 * $CAPABILITY expansion required.  Expansion is only
+			 * allowed for non-simple path names (must contain a
+			 * '/'), with the token itself being the last element
+			 * of the path.  Therefore, all we need do is test the
+			 * existence of the string "/$CAPABILITY\0".
+			 */
+			if (((omit & PD_TKN_CAP) == 0) &&
+			    ((bptr > _name) && (*bptr == '/') &&
+			    ((*eptr == '\0') || (*eptr == ':')))) {
+				/*
+				 * Decrement the present pointer so that the
+				 * directories trailing "/" gets nuked later.
+				 */
+				nptr--, nlen--;
+				olen += MSG_TKN_CAPABILITY_SIZE;
+				optr += MSG_TKN_CAPABILITY_SIZE;
+				_flags |= PD_TKN_CAP;
+			}
+
 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_HWCAP),
 		    MSG_TKN_HWCAP_SIZE) == 0) {
 			char	*bptr = nptr - 1;
@@ -588,7 +649,8 @@
 			token = (char *)MSG_ORIG(MSG_TKN_HWCAP);
 
 			/*
-			 * $HWCAP expansion required.  For compatibility with
+			 * $HWCAP expansion required.  This token has been
+			 * superseeded by $CAPABILITY.  For compatibility with
 			 * older environments, only expand this token when hard-
 			 * ware capability information is available.   This
 			 * expansion is only allowed for non-simple path names
@@ -596,7 +658,7 @@
 			 * last element of the path.  Therefore, all we need do
 			 * is test the existence of the string "/$HWCAP\0".
 			 */
-			if (((omit & PD_TKN_HWCAP) == 0) &&
+			if (((omit & PD_TKN_CAP) == 0) &&
 			    (rtld_flags2 & RT_FL2_HWCAP) &&
 			    ((bptr > _name) && (*bptr == '/') &&
 			    ((*eptr == '\0') || (*eptr == ':')))) {
@@ -607,7 +669,7 @@
 				nptr--, nlen--;
 				olen += MSG_TKN_HWCAP_SIZE;
 				optr += MSG_TKN_HWCAP_SIZE;
-				_flags |= PD_TKN_HWCAP;
+				_flags |= PD_TKN_CAP;
 			}
 
 		} else {
@@ -820,7 +882,7 @@
 			 * other dependencies, to be used.
 			 */
 			if ((flags & PD_TKN_ORIGIN) &&
-			    spavl_recorded(npath, 0)) {
+			    pnavl_recorded(&spavl, npath, 0, NULL)) {
 				DBG_CALL(Dbg_libs_insecure(lml, npath, 1));
 				return (1);
 			}
@@ -850,7 +912,7 @@
 			if ((lml->lm_flags & LML_FLG_RTLDLM) &&
 			    is_rtld_setuid())
 				return (1);
-			else if (spavl_recorded(opath, 0)) {
+			else if (pnavl_recorded(&spavl, opath, 0, NULL)) {
 				DBG_CALL(Dbg_libs_insecure(lml, opath, 1));
 				return (1);
 			}
--- a/usr/src/cmd/sgs/rtld/common/remove.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/remove.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -221,7 +221,7 @@
 void
 remove_so(Lm_list *lml, Rt_map *lmp)
 {
-	Dyninfo *dip;
+	Dyninfo	*dip;
 
 	if (lmp == NULL)
 		return;
@@ -377,6 +377,9 @@
 	if (FLAGS(lmp) & FLG_RT_IMGALLOC)
 		free((void *)ADDR(lmp));
 
+	if (CAPCHAIN(lmp))
+		free((void *)CAPCHAIN(lmp));
+
 	if (MMAPS(lmp)) {
 		if ((FLAGS(lmp) & FLG_RT_IMGALLOC) == 0)
 			unmap_obj(MMAPS(lmp), MMAPCNT(lmp));
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -72,9 +72,6 @@
 @ MSG_GEN_ALTER		"%s: alternate file in use"
 @ MSG_GEN_NOSYM		"%s: can't find symbol"
 @ MSG_GEN_NODUMP	"%s: DF_1_NODUMP tagged object may not be dldump()'ed"
-@ MSG_GEN_BADHWCAP_1	"hardware capability unsupported: %s"
-@ MSG_GEN_BADSFCAP_1	"software capability unsupported: %s"
-
 
 # Move related messages
 
@@ -151,7 +148,7 @@
 @ MSG_LDD_FIL_ILLEGAL	"\t%s =>\t (illegal insecure pathname)\n"
 @ MSG_LDD_FIL_ALTER	"  (alternate)"
 
-@ MSG_LDD_HWCAP_NFOUND	"\t%s =>\t (no hardware capability objects found)\n"
+@ MSG_LDD_CAP_NFOUND	"\t%s =>\t (no capability objects found)\n"
 
 @ MSG_LDD_SEC_NFOUND	"\t%s =>\t (file not found in secure directories)\n"
 
@@ -191,11 +188,24 @@
 @ MSG_LDD_REJ_US3	"  - Sun UltraSPARC III extensions required"
 @ MSG_LDD_REJ_STR	"  - %s"
 @ MSG_LDD_REJ_UNKFILE	"  - unknown file type"
-@ MSG_LDD_REJ_HWCAP_1	"  - hardware capability unsupported: %s"
-@ MSG_LDD_REJ_SFCAP_1	"  - software capability unsupported: %s"
+@ MSG_LDD_REJ_UNKCAP	"  - unknown capability: %d"
+@ MSG_LDD_REJ_HWCAP_1	"  - hardware capability (CA_SUNW_HW_1) unsupported: %s"
+@ MSG_LDD_REJ_SFCAP_1	"  - software capability (CA_SUNW_SF_1) unsupported: %s"
+@ MSG_LDD_REJ_MACHCAP	"  - machine capability (CA_SUNW_MACH) unsupported: %s"
+@ MSG_LDD_REJ_PLATCAP	"  - platform capability (CA_SUNW_PLAT) unsupported: %s"
+@ MSG_LDD_REJ_HWCAP_2	"  - hardware capability (CA_SUNW_HW_2) unsupported: %s"
 
-@ MSG_LDD_GEN_HWCAP_1	"%s: warning: hardware capability unsupported: %s\n"
-@ MSG_LDD_GEN_SFCAP_1	"%s: warning: hardware capability unsupported: %s\n"
+@ MSG_LDD_WARN_UNKCAP	"%s: unknown capability: %d"
+@ MSG_LDD_WARN_HWCAP_1	"%s: warning: hardware capability (CA_SUNW_HW_1) \
+			 unsupported: %s\n"
+@ MSG_LDD_WARN_SFCAP_1	"%s: warning: software capability (CA_SUNW_SF_1) \
+			 unsupported: %s\n"
+@ MSG_LDD_WARN_MACHCAP	"%s: warning: machine capability (CA_SUNW_MACH) \
+			 unsupported: %s\n"
+@ MSG_LDD_WARN_PLATCAP	"%s: warning: platform capability (CA_SUNW_PLAT) \
+			 unsupported: %s\n"
+@ MSG_LDD_WARN_HWCAP_2	"%s: warning: hardware capability (CA_SUNW_HW_2) \
+			 unsupported: %s\n"
 
 # Error rejection messages.
 
@@ -210,8 +220,12 @@
 @ MSG_ERR_REJ_US3	"%s: Sun UltraSPARC III extensions required"
 @ MSG_ERR_REJ_STR	"%s: %s"
 @ MSG_ERR_REJ_UNKFILE	"%s: unknown file type"
-@ MSG_ERR_REJ_HWCAP_1	"%s: hardware capability unsupported: %s"
-@ MSG_ERR_REJ_SFCAP_1	"%s: software capability unsupported: %s"
+@ MSG_ERR_REJ_UNKCAP	"%s: unknown capability: %d"
+@ MSG_ERR_REJ_HWCAP_1	"%s: hardware capability (CA_SUNW_HW_1) unsupported: %s"
+@ MSG_ERR_REJ_SFCAP_1	"%s: software capability (CA_SUNW_SF_1) unsupported: %s"
+@ MSG_ERR_REJ_MACHCAP	"%s: machine capability (CA_SUNW_MACH) unsupported: %s"
+@ MSG_ERR_REJ_PLATCAP	"%s: platform capability (CA_SUNW_PLAT) unsupported: %s"
+@ MSG_ERR_REJ_HWCAP_2	"%s: hardware capability (CA_SUNW_HW_2) unsupported: %s"
 
 # Error TLS failures
 
@@ -253,6 +267,10 @@
 
 @ _END_
 
+# The following strings represent reserved words, files, pathnames and symbols.
+# Reference to this strings is via the MSG_ORIG() macro, and thus no message
+# translation is required.
+
 @ MSG_LDD_FIL_PATH	"\t%s%s%s\n"
 @ MSG_LDD_FIL_EQUIV	"\t%s =>\t %s%s%s\n"
 @ MSG_LDD_FMT_PATH1	"%s"
@@ -260,11 +278,6 @@
 @ MSG_LDD_INIT_FMT_FILE	"\t%s\n"
 @ MSG_LDD_VER_FOUND	"\t%s (%s) =>\t %s\n"
 
-
-# The following strings represent reserved words, files, pathnames and symbols.
-# Reference to this strings is via the MSG_ORIG() macro, and thus no message
-# translation is required.
-
 @ MSG_STR_EMPTY		""
 @ MSG_STR_NEGATE	"-"
 @ MSG_STR_ZERO		"0"
@@ -277,9 +290,13 @@
 @ MSG_STR_SLASH		"/"
 @ MSG_STR_DELIMIT	": "
 
+@ MSG_CAP_DELIMIT	","
+
 @ MSG_SUNW_OST_SGS	"SUNW_OST_SGS"
 @ MSG_SUNW_OST_OSLIB	"SUNW_OST_OSLIB"
 
+@ MSG_TKN_CAPABILITY	"CAPABILITY"
+@ MSG_TKN_MACHINE	"MACHINE"
 @ MSG_TKN_PLATFORM	"PLATFORM"
 @ MSG_TKN_ORIGIN	"ORIGIN"
 @ MSG_TKN_ISALIST	"ISALIST"
@@ -335,15 +352,18 @@
 @ MSG_LD_BIND_NOT	"BIND_NOT"
 @ MSG_LD_BINDINGS	"BINDINGS"
 @ MSG_LD_CONFGEN	"CONFGEN"
+@ MSG_LD_CAP_FILES	"CAP_FILES"
 @ MSG_LD_CONFIG		"CONFIG"
 @ MSG_LD_DEBUG		"DEBUG"
 @ MSG_LD_DEBUG_OUTPUT	"DEBUG_OUTPUT"
 @ MSG_LD_DEMANGLE	"DEMANGLE"
 @ MSG_LD_FLAGS		"FLAGS"
+@ MSG_LD_HWCAP		"HWCAP"
 @ MSG_LD_INIT		"INIT"
 @ MSG_LD_LIBPATH	"LIBRARY_PATH"
 @ MSG_LD_LOADAVAIL	"LOADAVAIL"
 @ MSG_LD_LOADFLTR	"LOADFLTR"
+@ MSG_LD_MACHCAP	"MACHCAP"
 @ MSG_LD_NOAUDIT	"NOAUDIT"
 @ MSG_LD_NOAUXFLTR	"NOAUXFLTR"
 @ MSG_LD_NOBAPLT	"NOBAPLT"
@@ -357,9 +377,11 @@
 @ MSG_LD_NOPAREXT	"NOPAREXT"
 @ MSG_LD_NOUNRESWEAK	"NOUNRESWEAK"
 @ MSG_LD_NOVERSION	"NOVERSION"
+@ MSG_LD_PLATCAP	"PLATCAP"
 @ MSG_LD_PRELOAD	"PRELOAD"
 @ MSG_LD_PROFILE	"PROFILE"
 @ MSG_LD_PROFILE_OUTPUT	"PROFILE_OUTPUT"
+@ MSG_LD_SFCAP		"SFCAP"
 @ MSG_LD_SIGNAL		"SIGNAL"
 @ MSG_LD_TRACE_OBJS	"TRACE_LOADED_OBJECTS"
 @ MSG_LD_TRACE_OBJS_E	"TRACE_LOADED_OBJECTS_E"
--- a/usr/src/cmd/sgs/rtld/common/setup.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/setup.c	Mon Mar 01 10:20:48 2010 -0800
@@ -42,7 +42,6 @@
 #include	<sys/stat.h>
 #include	<sys/mman.h>
 #include	<string.h>
-#include	<stdio.h>
 #include	<unistd.h>
 #include	<dlfcn.h>
 #include	<sys/sysconfig.h>
@@ -291,7 +290,14 @@
 	 * Initialize any global variables.
 	 */
 	at_flags = _flags;
-	platform = _platform;
+
+	if ((org_scapset->sc_plat = _platform) != NULL)
+		org_scapset->sc_platsz = strlen(_platform);
+
+	if (org_scapset->sc_plat == NULL)
+		platform_name(org_scapset);
+	if (org_scapset->sc_mach == NULL)
+		machine_name(org_scapset);
 
 	/*
 	 * If pagesize is unspecified find its value.
@@ -338,15 +344,6 @@
 	security(uid, euid, gid, egid, auxflags);
 
 	/*
-	 * Initialize a hardware capability descriptor for use in comparing
-	 * each loaded object.
-	 */
-	if (auxflags & AF_SUN_HWCAPVERIFY) {
-		rtld_flags2 |= RT_FL2_HWCAP;
-		hwcap = (ulong_t)hwcap_1;
-	}
-
-	/*
 	 * Look for environment strings (allows things like LD_NOAUDIT to be
 	 * established, although debugging isn't enabled until later).
 	 */
@@ -355,6 +352,19 @@
 		return (0);
 
 	/*
+	 * Initialize a hardware capability descriptor for use in comparing
+	 * each loaded object.  The aux vector must provide AF_SUN_HWCAPVERIFY,
+	 * as prior to this setting any hardware capabilities that were found
+	 * could not be relied upon.  Set any alternative system capabilities.
+	 */
+	if (auxflags & AF_SUN_HWCAPVERIFY) {
+		rtld_flags2 |= RT_FL2_HWCAP;
+		org_scapset->sc_hw_1 = (Xword)hwcap_1;
+	}
+	if (cap_alternative() == 0)
+		return (0);
+
+	/*
 	 * Create a mapping descriptor for ld.so.1.  We can determine our
 	 * two segments information from known symbols.
 	 */
@@ -676,7 +686,7 @@
 		size_t	len = strlen(interp->i_name);
 
 		if (expand(&interp->i_name, &len, 0, 0,
-		    (PD_TKN_ISALIST | PD_TKN_HWCAP), rlmp) & PD_TKN_RESOLVED)
+		    (PD_TKN_ISALIST | PD_TKN_CAP), rlmp) & PD_TKN_RESOLVED)
 			fdr.fd_flags |= FLG_FD_RESOLVED;
 	}
 	fdr.fd_pname = interp->i_name;
@@ -721,36 +731,23 @@
 	 * that are restricted to a 32-bit address space can only be loaded if
 	 * the executable has established this requirement.
 	 */
-	if (SFCAP(mlmp) & SF1_SUNW_ADDR32)
+	if (CAPSET(mlmp).sc_sf_1 & SF1_SUNW_ADDR32)
 		rtld_flags2 |= RT_FL2_ADDR32;
 #endif
 	/*
-	 * Validate any hardware capabilities information.
+	 * Establish any alternative capabilities, and validate this object
+	 * if it defines it's own capabilities information.
 	 */
-	if (HWCAP(mlmp) && (hwcap_check(HWCAP(mlmp), &rej) == 0)) {
+	if (cap_check_lmp(mlmp, &rej) == 0) {
 		if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) {
-			(void) printf(MSG_INTL(MSG_LDD_GEN_HWCAP_1),
+			/* LINTED */
+			(void) printf(MSG_INTL(ldd_warn[rej.rej_type]),
 			    NAME(mlmp), rej.rej_str);
 		} else {
+			/* LINTED */
 			eprintf(&lml_main, ERR_FATAL,
-			    MSG_INTL(MSG_GEN_BADHWCAP_1), rej.rej_str);
-			return (0);
-		}
-	}
-
-	/*
-	 * Validate any software capabilities information, other than
-	 * SF1_SUNW_ADDR32.  Only dependencies need check their SF1_SUNW_ADDR32
-	 * use against the application enabling a 32-bit address space.
-	 */
-	if ((SFCAP(mlmp) & ~SF1_SUNW_ADDR32) &&
-	    (sfcap_check(SFCAP(mlmp), &rej) == 0)) {
-		if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) {
-			(void) printf(MSG_INTL(MSG_LDD_GEN_SFCAP_1),
+			    MSG_INTL(err_reject[rej.rej_type]),
 			    NAME(mlmp), rej.rej_str);
-		} else {
-			eprintf(&lml_main, ERR_FATAL,
-			    MSG_INTL(MSG_GEN_BADSFCAP_1), rej.rej_str);
 			return (0);
 		}
 	}
@@ -813,9 +810,6 @@
 	r_debug.rtd_rdebug.r_ldbase = r_debug.rtd_rdebug.r_ldsomap->l_addr;
 	r_debug.rtd_dynlmlst = &dynlm_list;
 
-	if (platform)
-		platform_sz = strlen(platform);
-
 	/*
 	 * Determine the dev/inode information for the executable to complete
 	 * load_so() checking for those who might dlopen(a.out).
@@ -831,6 +825,9 @@
 	if (!(rtld_flags & RT_FL_NOCFG)) {
 		if ((features = elf_config(mlmp, (aoutdyn != 0))) == -1)
 			return (0);
+
+		if (cap_alternative() == 0)
+			return (0);
 	}
 
 	/*
@@ -900,13 +897,12 @@
 	 * Now that debugging is enabled generate any diagnostics from any
 	 * previous events.
 	 */
-	if (hwcap)
-		DBG_CALL(Dbg_cap_val_hw1(&lml_main, hwcap, M_MACH));
-	if (features)
+	if (DBG_ENABLED) {
+		DBG_CALL(Dbg_cap_val(&lml_main, org_scapset, alt_scapset,
+		    M_MACH));
 		DBG_CALL(Dbg_file_config_dis(&lml_main, config->c_name,
 		    features));
 
-	if (DBG_ENABLED) {
 		DBG_CALL(Dbg_file_ldso(rlmp, envp, auxv,
 		    LIST(rlmp)->lm_lmidstr, ALIST_OFF_DATA));
 
@@ -1137,14 +1133,14 @@
 	 * Without this flag we only support one copy of the linker in a
 	 * process because by default the linker will always try to
 	 * initialize at one primary link map  The copy of libc which is
-	 * initialized on a primary link map will initalize global TLS
+	 * initialized on a primary link map will initialize global TLS
 	 * data which can be shared with other copies of libc in the
 	 * process.  The problem is that if there is more than one copy
 	 * of the linker, only one copy should link libc onto a primary
 	 * link map, otherwise libc will attempt to re-initialize global
 	 * TLS data.  So when a copy of the linker is loaded with this
 	 * flag set, it will not initialize any primary link maps since
-	 * persumably another copy of the linker will do this.
+	 * presumably another copy of the linker will do this.
 	 *
 	 * Note that this flag only allows multiple copies of the -same-
 	 * -version- of the linker (and libc) to coexist.  This approach
--- a/usr/src/cmd/sgs/rtld/common/util.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/util.c	Mon Mar 01 10:20:48 2010 -0800
@@ -33,6 +33,7 @@
  * Utility routines for run-time linker.  some are duplicated here from libc
  * (with different names) to avoid name space collisions.
  */
+#include	<sys/systeminfo.h>
 #include	<stdio.h>
 #include	<sys/time.h>
 #include	<sys/types.h>
@@ -382,6 +383,32 @@
 }
 
 /*
+ * Determine whether a PathNode is recorded.
+ */
+int
+pnavl_recorded(avl_tree_t **pnavl, const char *name, uint_t hash,
+    avl_index_t *where)
+{
+	PathNode	pn;
+
+	/*
+	 * Create the avl tree if required.
+	 */
+	if ((*pnavl == NULL) &&
+	    ((*pnavl = pnavl_create(sizeof (PathNode))) == NULL))
+		return (0);
+
+	pn.pn_name = name;
+	if ((pn.pn_hash = hash) == 0)
+		pn.pn_hash = sgs_str_hash(name);
+
+	if (avl_find(*pnavl, &pn, where) == NULL)
+		return (0);
+
+	return (1);
+}
+
+/*
  * Determine if a pathname has already been recorded on the full path name
  * AVL tree.  This tree maintains a node for each path name that ld.so.1 has
  * successfully loaded.  If the path name does not exist in this AVL tree, then
@@ -473,38 +500,14 @@
 }
 
 /*
- * Determine if a pathname has already been recorded on the not-found AVL tree.
+ * Insert a path name into the not-found AVL tree.
+ *
  * This tree maintains a node for each path name that ld.so.1 has explicitly
  * inspected, but has failed to load during a single ld.so.1 operation.  If the
  * path name does not exist in this AVL tree, then the next insertion point is
  * deposited in "where".  This value can be used by nfavl_insert() to expedite
  * the insertion.
  */
-int
-nfavl_recorded(const char *name, uint_t hash, avl_index_t *where)
-{
-	PathNode	pn;
-
-	/*
-	 * Create the avl tree if required.
-	 */
-	if ((nfavl == NULL) &&
-	    ((nfavl = pnavl_create(sizeof (PathNode))) == NULL))
-		return (NULL);
-
-	pn.pn_name = name;
-	if ((pn.pn_hash = hash) == 0)
-		pn.pn_hash = sgs_str_hash(name);
-
-	if (avl_find(nfavl, &pn, where) == NULL)
-		return (0);
-
-	return (1);
-}
-
-/*
- * Insert a name into the not-found AVL tree.
- */
 void
 nfavl_insert(const char *name, avl_index_t where)
 {
@@ -513,7 +516,7 @@
 
 	if (where == 0) {
 		/* LINTED */
-		int	in_nfavl = nfavl_recorded(name, hash, &where);
+		int	in_nfavl = pnavl_recorded(&nfavl, name, hash, &where);
 
 		/*
 		 * We better not get a hit now, we do not want duplicates in
@@ -532,39 +535,14 @@
 	}
 }
 
-static avl_tree_t	*spavl = NULL;
-
 /*
- * Search for a path name within the secure path AVL tree.  This tree is used
- * to maintain a list of directories in which the dependencies of a secure
- * process have been found.  This list provides a fall-back in the case that a
- * $ORIGIN expansion is deemed insecure, when the expansion results in a path
- * name that has already provided dependencies.
- */
-int
-spavl_recorded(const char *name, avl_index_t *where)
-{
-	PathNode	pn;
-
-	/*
-	 * Create the avl tree if required.
-	 */
-	if ((spavl == NULL) &&
-	    ((spavl = pnavl_create(sizeof (PathNode))) == NULL))
-		return (0);
-
-	pn.pn_name = name;
-	pn.pn_hash = sgs_str_hash(name);
-
-	if (avl_find(spavl, &pn, where) == NULL)
-		return (0);
-
-	return (1);
-}
-
-/*
- * Insert the directory name, of a full path name,  into the secure path AVL
+ * Insert the directory name, of a full path name, into the secure path AVL
  * tree.
+ *
+ * This tree is used to maintain a list of directories in which the dependencies
+ * of a secure process have been found.  This list provides a fall-back in the
+ * case that a $ORIGIN expansion is deemed insecure, when the expansion results
+ * in a path name that has already provided dependencies.
  */
 void
 spavl_insert(const char *name)
@@ -573,6 +551,7 @@
 	size_t		size;
 	avl_index_t	where;
 	PathNode	*pnp;
+	uint_t		hash;
 
 	/*
 	 * Separate the directory name from the path name.
@@ -584,12 +563,13 @@
 
 	(void) strncpy(buffer, name, size);
 	buffer[size] = '\0';
+	hash = sgs_str_hash(buffer);
 
 	/*
 	 * Determine whether this directory name is already recorded, or if
 	 * not, 'where" will provide the insertion point for the new string.
 	 */
-	if (spavl_recorded(buffer, &where))
+	if (pnavl_recorded(&spavl, buffer, hash, &where))
 		return;
 
 	/*
@@ -597,7 +577,7 @@
 	 */
 	if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) {
 		pnp->pn_name = strdup(buffer);
-		pnp->pn_hash = sgs_str_hash(buffer);
+		pnp->pn_hash = hash;
 		avl_insert(spavl, pnp, where);
 	}
 }
@@ -1444,46 +1424,50 @@
 /*
  * Identify all environment variables.
  */
-#define	ENV_FLG_AUDIT		0x0000000001ULL
-#define	ENV_FLG_AUDIT_ARGS	0x0000000002ULL
-#define	ENV_FLG_BIND_NOW	0x0000000004ULL
-#define	ENV_FLG_BIND_NOT	0x0000000008ULL
-#define	ENV_FLG_BINDINGS	0x0000000010ULL
-
-#define	ENV_FLG_CONFGEN		0x0000000040ULL
-#define	ENV_FLG_CONFIG		0x0000000080ULL
-#define	ENV_FLG_DEBUG		0x0000000100ULL
-#define	ENV_FLG_DEBUG_OUTPUT	0x0000000200ULL
-#define	ENV_FLG_DEMANGLE	0x0000000400ULL
-#define	ENV_FLG_FLAGS		0x0000000800ULL
-#define	ENV_FLG_INIT		0x0000001000ULL
-#define	ENV_FLG_LIBPATH		0x0000002000ULL
-#define	ENV_FLG_LOADAVAIL	0x0000004000ULL
-#define	ENV_FLG_LOADFLTR	0x0000008000ULL
-#define	ENV_FLG_NOAUDIT		0x0000010000ULL
-#define	ENV_FLG_NOAUXFLTR	0x0000020000ULL
-#define	ENV_FLG_NOBAPLT		0x0000040000ULL
-#define	ENV_FLG_NOCONFIG	0x0000080000ULL
-#define	ENV_FLG_NODIRCONFIG	0x0000100000ULL
-#define	ENV_FLG_NODIRECT	0x0000200000ULL
-#define	ENV_FLG_NOENVCONFIG	0x0000400000ULL
-#define	ENV_FLG_NOLAZY		0x0000800000ULL
-#define	ENV_FLG_NOOBJALTER	0x0001000000ULL
-#define	ENV_FLG_NOVERSION	0x0002000000ULL
-#define	ENV_FLG_PRELOAD		0x0004000000ULL
-#define	ENV_FLG_PROFILE		0x0008000000ULL
-#define	ENV_FLG_PROFILE_OUTPUT	0x0010000000ULL
-#define	ENV_FLG_SIGNAL		0x0020000000ULL
-#define	ENV_FLG_TRACE_OBJS	0x0040000000ULL
-#define	ENV_FLG_TRACE_PTHS	0x0080000000ULL
-#define	ENV_FLG_UNREF		0x0100000000ULL
-#define	ENV_FLG_UNUSED		0x0200000000ULL
-#define	ENV_FLG_VERBOSE		0x0400000000ULL
-#define	ENV_FLG_WARN		0x0800000000ULL
-#define	ENV_FLG_NOFLTCONFIG	0x1000000000ULL
-#define	ENV_FLG_BIND_LAZY	0x2000000000ULL
-#define	ENV_FLG_NOUNRESWEAK	0x4000000000ULL
-#define	ENV_FLG_NOPAREXT	0x8000000000ULL
+#define	ENV_FLG_AUDIT		0x0000000000001ULL
+#define	ENV_FLG_AUDIT_ARGS	0x0000000000002ULL
+#define	ENV_FLG_BIND_NOW	0x0000000000004ULL
+#define	ENV_FLG_BIND_NOT	0x0000000000008ULL
+#define	ENV_FLG_BINDINGS	0x0000000000010ULL
+#define	ENV_FLG_CONFGEN		0x0000000000020ULL
+#define	ENV_FLG_CONFIG		0x0000000000040ULL
+#define	ENV_FLG_DEBUG		0x0000000000080ULL
+#define	ENV_FLG_DEBUG_OUTPUT	0x0000000000100ULL
+#define	ENV_FLG_DEMANGLE	0x0000000000200ULL
+#define	ENV_FLG_FLAGS		0x0000000000400ULL
+#define	ENV_FLG_INIT		0x0000000000800ULL
+#define	ENV_FLG_LIBPATH		0x0000000001000ULL
+#define	ENV_FLG_LOADAVAIL	0x0000000002000ULL
+#define	ENV_FLG_LOADFLTR	0x0000000004000ULL
+#define	ENV_FLG_NOAUDIT		0x0000000008000ULL
+#define	ENV_FLG_NOAUXFLTR	0x0000000010000ULL
+#define	ENV_FLG_NOBAPLT		0x0000000020000ULL
+#define	ENV_FLG_NOCONFIG	0x0000000040000ULL
+#define	ENV_FLG_NODIRCONFIG	0x0000000080000ULL
+#define	ENV_FLG_NODIRECT	0x0000000100000ULL
+#define	ENV_FLG_NOENVCONFIG	0x0000000200000ULL
+#define	ENV_FLG_NOLAZY		0x0000000400000ULL
+#define	ENV_FLG_NOOBJALTER	0x0000000800000ULL
+#define	ENV_FLG_NOVERSION	0x0000001000000ULL
+#define	ENV_FLG_PRELOAD		0x0000002000000ULL
+#define	ENV_FLG_PROFILE		0x0000004000000ULL
+#define	ENV_FLG_PROFILE_OUTPUT	0x0000008000000ULL
+#define	ENV_FLG_SIGNAL		0x0000010000000ULL
+#define	ENV_FLG_TRACE_OBJS	0x0000020000000ULL
+#define	ENV_FLG_TRACE_PTHS	0x0000040000000ULL
+#define	ENV_FLG_UNREF		0x0000080000000ULL
+#define	ENV_FLG_UNUSED		0x0000100000000ULL
+#define	ENV_FLG_VERBOSE		0x0000200000000ULL
+#define	ENV_FLG_WARN		0x0000400000000ULL
+#define	ENV_FLG_NOFLTCONFIG	0x0000800000000ULL
+#define	ENV_FLG_BIND_LAZY	0x0001000000000ULL
+#define	ENV_FLG_NOUNRESWEAK	0x0002000000000ULL
+#define	ENV_FLG_NOPAREXT	0x0004000000000ULL
+#define	ENV_FLG_HWCAP		0x0008000000000ULL
+#define	ENV_FLG_SFCAP		0x0010000000000ULL
+#define	ENV_FLG_MACHCAP		0x0020000000000ULL
+#define	ENV_FLG_PLATCAP		0x0040000000000ULL
+#define	ENV_FLG_CAP_FILES	0x0080000000000ULL
 
 #define	SEL_REPLACE		0x0001
 #define	SEL_PERMANT		0x0002
@@ -1585,10 +1569,16 @@
 		}
 	}
 	/*
-	 * LD_CONFIG family.
+	 * LD_CAP_FILES and LD_CONFIG family.
 	 */
 	else if (*s1 == 'C') {
-		if ((len == MSG_LD_CONFGEN_SIZE) && (strncmp(s1,
+		if ((len == MSG_LD_CAP_FILES_SIZE) && (strncmp(s1,
+		    MSG_ORIG(MSG_LD_CAP_FILES), MSG_LD_CAP_FILES_SIZE) == 0)) {
+			select |= SEL_ACT_STR;
+			str = (select & SEL_REPLACE) ?
+			    &rpl_cap_files : &prm_cap_files;
+			variable = ENV_FLG_CAP_FILES;
+		} else if ((len == MSG_LD_CONFGEN_SIZE) && (strncmp(s1,
 		    MSG_ORIG(MSG_LD_CONFGEN), MSG_LD_CONFGEN_SIZE) == 0)) {
 			/*
 			 * Set by crle(1) to indicate it's building a
@@ -1649,6 +1639,18 @@
 		}
 	}
 	/*
+	 * LD_HWCAP.
+	 */
+	else if (*s1 == 'H') {
+		if ((len == MSG_LD_HWCAP_SIZE) && (strncmp(s1,
+		    MSG_ORIG(MSG_LD_HWCAP), MSG_LD_HWCAP_SIZE) == 0)) {
+			select |= SEL_ACT_STR;
+			str = (select & SEL_REPLACE) ?
+			    &rpl_hwcap : &prm_hwcap;
+			variable = ENV_FLG_HWCAP;
+		}
+	}
+	/*
 	 * LD_INIT (internal, used by ldd(1)).
 	 */
 	else if (*s1 == 'I') {
@@ -1685,6 +1687,18 @@
 		}
 	}
 	/*
+	 * LD_MACHCAP.
+	 */
+	else if (*s1 == 'M') {
+		if ((len == MSG_LD_MACHCAP_SIZE) && (strncmp(s1,
+		    MSG_ORIG(MSG_LD_MACHCAP), MSG_LD_MACHCAP_SIZE) == 0)) {
+			select |= SEL_ACT_STR;
+			str = (select & SEL_REPLACE) ?
+			    &rpl_machcap : &prm_machcap;
+			variable = ENV_FLG_MACHCAP;
+		}
+	}
+	/*
 	 * The LD_NO family.
 	 */
 	else if (*s1 == 'N') {
@@ -1764,10 +1778,16 @@
 		}
 	}
 	/*
-	 * LD_PRELOAD and LD_PROFILE family.
+	 * LD_PLATCAP, LD_PRELOAD and LD_PROFILE family.
 	 */
 	else if (*s1 == 'P') {
-		if ((len == MSG_LD_PRELOAD_SIZE) && (strncmp(s1,
+		if ((len == MSG_LD_PLATCAP_SIZE) && (strncmp(s1,
+		    MSG_ORIG(MSG_LD_PLATCAP), MSG_LD_PLATCAP_SIZE) == 0)) {
+			select |= SEL_ACT_STR;
+			str = (select & SEL_REPLACE) ?
+			    &rpl_platcap : &prm_platcap;
+			variable = ENV_FLG_PLATCAP;
+		} else if ((len == MSG_LD_PRELOAD_SIZE) && (strncmp(s1,
 		    MSG_ORIG(MSG_LD_PRELOAD), MSG_LD_PRELOAD_SIZE) == 0)) {
 			select |= SEL_ACT_STR;
 			str = (select & SEL_REPLACE) ? &rpl_preload :
@@ -1792,14 +1812,19 @@
 		}
 	}
 	/*
-	 * LD_SIGNAL.
+	 * LD_SFCAP and LD_SIGNAL.
 	 */
 	else if (*s1 == 'S') {
-		if (rtld_flags & RT_FL_SECURE)
-			return;
-		if ((len == MSG_LD_SIGNAL_SIZE) &&
+		if ((len == MSG_LD_SFCAP_SIZE) && (strncmp(s1,
+		    MSG_ORIG(MSG_LD_SFCAP), MSG_LD_SFCAP_SIZE) == 0)) {
+			select |= SEL_ACT_STR;
+			str = (select & SEL_REPLACE) ?
+			    &rpl_sfcap : &prm_sfcap;
+			variable = ENV_FLG_SFCAP;
+		} else if ((len == MSG_LD_SIGNAL_SIZE) &&
 		    (strncmp(s1, MSG_ORIG(MSG_LD_SIGNAL),
-		    MSG_LD_SIGNAL_SIZE) == 0)) {
+		    MSG_LD_SIGNAL_SIZE) == 0) &&
+		    ((rtld_flags & RT_FL_SECURE) == 0)) {
 			select |= SEL_ACT_SPEC_2;
 			variable = ENV_FLG_SIGNAL;
 		}
@@ -3420,19 +3445,21 @@
 void
 set_environ(Lm_list *lml)
 {
-	Rt_map		*dlmp;
-	Sym		*sym;
 	Slookup		sl;
+	Sresult		sr;
 	uint_t		binfo;
 
 	/*
-	 * Initialize the symbol lookup data structure.
+	 * Initialize the symbol lookup, and symbol result, data structures.
 	 */
 	SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_ENVIRON), lml->lm_head, lml->lm_head,
 	    ld_entry_cnt, 0, 0, 0, 0, LKUP_WEAK);
-
-	if (sym = LM_LOOKUP_SYM(lml->lm_head)(&sl, &dlmp, &binfo, 0)) {
-		lml->lm_environ = (char ***)sym->st_value;
+	SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_ENVIRON));
+
+	if (LM_LOOKUP_SYM(lml->lm_head)(&sl, &sr, &binfo, 0)) {
+		Rt_map	*dlmp = sr.sr_dmap;
+
+		lml->lm_environ = (char ***)sr.sr_sym->st_value;
 
 		if (!(FLAGS(dlmp) & FLG_RT_FIXED))
 			lml->lm_environ =
@@ -3502,6 +3529,50 @@
 }
 
 /*
+ * Determine that systems platform name.  Normally, this name is provided from
+ * the AT_SUN_PLATFORM aux vector from the kernel.  This routine provides a
+ * fall back.
+ */
+void
+platform_name(Syscapset *scapset)
+{
+	char	info[SYS_NMLN];
+	size_t	size;
+
+	if ((scapset->sc_platsz = size =
+	    sysinfo(SI_PLATFORM, info, SYS_NMLN)) == (size_t)-1)
+		return;
+
+	if ((scapset->sc_plat = malloc(size)) == NULL) {
+		scapset->sc_platsz = (size_t)-1;
+		return;
+	}
+	(void) strcpy(scapset->sc_plat, info);
+}
+
+/*
+ * Determine that systems machine name.  Normally, this name is provided from
+ * the AT_SUN_MACHINE aux vector from the kernel.  This routine provides a
+ * fall back.
+ */
+void
+machine_name(Syscapset *scapset)
+{
+	char	info[SYS_NMLN];
+	size_t	size;
+
+	if ((scapset->sc_machsz = size =
+	    sysinfo(SI_MACHINE, info, SYS_NMLN)) == (size_t)-1)
+		return;
+
+	if ((scapset->sc_mach = malloc(size)) == NULL) {
+		scapset->sc_machsz = (size_t)-1;
+		return;
+	}
+	(void) strcpy(scapset->sc_mach, info);
+}
+
+/*
  * _REENTRANT code gets errno redefined to a function so provide for return
  * of the thread errno if applicable.  This has no meaning in ld.so.1 which
  * is basically singled threaded.  Provide the interface for our dependencies.
--- a/usr/src/cmd/sgs/rtld/i386/i386_elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/i386/i386_elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -200,6 +200,7 @@
 	Sym		*rsym, *nsym;
 	uint_t		binfo, sb_flags = 0, dbg_class;
 	Slookup		sl;
+	Sresult		sr;
 	int		entry, lmflags;
 	Lm_list		*lml;
 
@@ -247,19 +248,25 @@
 	llmp = lml->lm_tail;
 
 	/*
-	 * Find definition for symbol.  Initialize the symbol lookup data
-	 * structure.
+	 * Find definition for symbol.  Initialize the symbol lookup, and
+	 * symbol result, data structures.
 	 */
 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0,
 	    rsymndx, rsym, 0, LKUP_DEFT);
+	SRESULT_INIT(sr, name);
 
-	if ((nsym = lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) {
+	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
 		    demangle(name));
 		rtldexit(lml, 1);
 	}
 
+	name = (char *)sr.sr_name;
+	nlmp = sr.sr_dmap;
+	nsym = sr.sr_sym;
+
 	symval = nsym->st_value;
+
 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
 	    (nsym->st_shndx != SHN_ABS))
 		symval += ADDR(nlmp);
@@ -408,6 +415,7 @@
 	 */
 	if (plt) {
 		Slookup	sl;
+		Sresult	sr;
 
 		relbgn = pltbgn;
 		relend = pltend;
@@ -415,14 +423,17 @@
 			return (1);
 
 		/*
-		 * Initialize the symbol lookup data structure.
+		 * Initialize the symbol lookup, and symbol result, data
+		 * structures.
 		 */
 		SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_PLT), lmp, lmp, ld_entry_cnt,
 		    elf_hash(MSG_ORIG(MSG_SYM_PLT)), 0, 0, 0, LKUP_DEFT);
+		SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_PLT));
 
-		if ((symdef = elf_find_sym(&sl, &_lmp, &binfo, NULL)) == 0)
+		if (elf_find_sym(&sl, &sr, &binfo, NULL) == 0)
 			return (1);
 
+		symdef = sr.sr_sym;
 		_pltbgn = symdef->st_value;
 		if (!(FLAGS(lmp) & FLG_RT_FIXED) &&
 		    (symdef->st_shndx != SHN_ABS))
@@ -581,7 +592,7 @@
 			 */
 			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
 				value = basebgn;
-				name = (char *)0;
+				name = NULL;
 
 				/*
 				 * Special case TLS relocations.
@@ -642,11 +653,12 @@
 					}
 				} else {
 					Slookup		sl;
+					Sresult		sr;
 
 					/*
 					 * Lookup the symbol definition.
-					 * Initialize the symbol lookup data
-					 * structure.
+					 * Initialize the symbol lookup, and
+					 * symbol result, data structures.
 					 */
 					name = (char *)(STRTAB(lmp) +
 					    symref->st_name);
@@ -654,9 +666,15 @@
 					SLOOKUP_INIT(sl, name, lmp, 0,
 					    ld_entry_cnt, 0, rsymndx, symref,
 					    rtype, LKUP_STDRELOC);
+					SRESULT_INIT(sr, name);
+					symdef = NULL;
 
-					symdef = lookup_sym(&sl, &_lmp,
-					    &binfo, in_nfavl);
+					if (lookup_sym(&sl, &sr, &binfo,
+					    in_nfavl)) {
+						name = (char *)sr.sr_name;
+						_lmp = sr.sr_dmap;
+						symdef = sr.sr_sym;
+					}
 
 					/*
 					 * If the symbol is not found and the
@@ -779,7 +797,8 @@
 				value = TLSMODID(lmp);
 			} else
 				value = basebgn;
-			name = (char *)0;
+
+			name = NULL;
 		}
 
 		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
@@ -892,26 +911,34 @@
 	Rt_map		*_lmp;
 	Rel		rel;
 	Slookup		sl;
+	Sresult		sr;
 	uint_t		binfo;
 
 	/*
 	 * Determine if the special symbol exists as a reference in the dynamic
 	 * executable, and that an associated definition exists in libc.so.1.
 	 *
-	 * Initialize the symbol lookup data structure.
+	 * Initialize the symbol lookup, and symbol result, data structures.
 	 */
 	SLOOKUP_INIT(sl, name, rlmp, rlmp, ld_entry_cnt, 0, 0, 0, 0,
 	    LKUP_FIRST);
+	SRESULT_INIT(sr, name);
 
-	if ((symref = lookup_sym(&sl, &_lmp, &binfo, NULL)) == 0)
+	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0)
+		return (1);
+	symref = sr.sr_sym;
+
+	SLOOKUP_INIT(sl, name, rlmp, dlmp, ld_entry_cnt, 0, 0, 0, 0,
+	    LKUP_DEFT);
+	SRESULT_INIT(sr, name);
+
+	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0)
 		return (1);
 
-	sl.sl_imap = dlmp;
-	sl.sl_flags = LKUP_DEFT;
+	_lmp = sr.sr_dmap;
+	symdef = sr.sr_sym;
 
-	if ((symdef = lookup_sym(&sl, &_lmp, &binfo, NULL)) == 0)
-		return (1);
-	if (strcmp(NAME(_lmp), MSG_ORIG(MSG_PTH_LIBC)))
+	if (strcmp(NAME(sr.sr_dmap), MSG_ORIG(MSG_PTH_LIBC)))
 		return (1);
 
 	/*
@@ -921,7 +948,7 @@
 	if (!(FLAGS(rlmp) & FLG_RT_FIXED))
 		ref += ADDR(rlmp);
 	def = (void *)(symdef->st_value);
-	if (!(FLAGS(_lmp) & FLG_RT_FIXED))
+	if (!(FLAGS(sr.sr_dmap) & FLG_RT_FIXED))
 		def += ADDR(_lmp);
 
 	/*
--- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -49,7 +49,7 @@
 	{ MSG_ORIG(MSG_FLG_IMGALLOC), FLG_RT_IMGALLOC, FLG_RT_IMGALLOC},
 	{ MSG_ORIG(MSG_FLG_RELOCED), FLG_RT_RELOCED, FLG_RT_RELOCED},
 	{ MSG_ORIG(MSG_FLG_SETGROUP), FLG_RT_SETGROUP, FLG_RT_SETGROUP},
-	{ MSG_ORIG(MSG_FLG_HWCAP), FLG_RT_HWCAP, FLG_RT_HWCAP},
+	{ MSG_ORIG(MSG_FLG_CAP), FLG_RT_CAP, FLG_RT_CAP},
 	{ MSG_ORIG(MSG_FLG_OBJECT), FLG_RT_OBJECT, FLG_RT_OBJECT},
 	{ MSG_ORIG(MSG_FLG_NEWLOAD), FLG_RT_NEWLOAD, FLG_RT_NEWLOAD},
 	{ MSG_ORIG(MSG_FLG_NODUMP), FLG_RT_NODUMP, FLG_RT_NODUMP},
@@ -81,6 +81,8 @@
 
 static const mdb_bitmask_t rtflags1_bits[] = {
 	{ MSG_ORIG(MSG_FL1_COPYTOOK), FL1_RT_COPYTOOK, FL1_RT_COPYTOOK},
+	{ MSG_ORIG(MSG_FL1_ALTCHECK), FL1_RT_ALTCHECK, FL1_RT_ALTCHECK},
+	{ MSG_ORIG(MSG_FL1_ALTCAP), FL1_RT_ALTCAP, FL1_RT_ALTCAP},
 	{ MSG_ORIG(MSG_FL1_CONFSET), FL1_RT_CONFSET, FL1_RT_CONFSET },
 	{ MSG_ORIG(MSG_FL1_NODEFLIB), FL1_RT_NODEFLIB, FL1_RT_NODEFLIB },
 	{ MSG_ORIG(MSG_FL1_ENDFILTE), FL1_RT_ENDFILTE, FL1_RT_ENDFILTE },
--- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -64,7 +64,7 @@
 @ MSG_FLG_IMGALLOC	"IMAGE-ALLOCATED"
 @ MSG_FLG_RELOCED	"RELOCED"
 @ MSG_FLG_SETGROUP	"SET-GROUP"
-@ MSG_FLG_HWCAP		"HWCAP"
+@ MSG_FLG_CAP		"CAP"
 @ MSG_FLG_OBJECT	"OBJECT"
 @ MSG_FLG_NEWLOAD	"NEWLOAD"
 @ MSG_FLG_NODUMP	"NODUMP"
@@ -93,6 +93,8 @@
 @ MSG_FLG_PRIHDL	"PRIVATE-HANDLE"
 
 @ MSG_FL1_COPYTOOK	"COPYTOOK"
+@ MSG_FL1_ALTCHECK	"ALT-CAP-CHECKED"
+@ MSG_FL1_ALTCAP	"ALT-CAP-REQUIRED"
 @ MSG_FL1_CONFSET	"CONFSET"
 @ MSG_FL1_NODEFLIB	"NO-DEFAULT-LIBPATH"
 @ MSG_FL1_ENDFILTE	"END-FILTEE"
--- a/usr/src/cmd/sgs/rtld/sparc/sparc_a.out.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/sparc/sparc_a.out.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -74,6 +74,7 @@
 	int 		rndx, entry;
 	ulong_t		symval;
 	Slookup		sl;
+	Sresult		sr;
 	uint_t		binfo;
 	Lm_list		*lml;
 
@@ -116,14 +117,20 @@
 	 */
 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, 0, 0, 0,
 	    LKUP_DEFT);
+	SRESULT_INIT(sr, name);
 
-	if ((sym = aout_lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) {
+	if (aout_lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
 		    demangle(name));
 		rtldexit(lml, 1);
 	}
 
+	name = (char *)sr.sr_name;
+	nlmp = sr.sr_dmap;
+	sym = sr.sr_sym;
+
 	symval = sym->st_value;
+
 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
 	    (sym->st_shndx != SHN_ABS))
 		symval += (int)(ADDR(nlmp));
@@ -259,10 +266,11 @@
 		 * Perform the relocation.
 		 */
 		if (rp->r_extern == 0) {
-			name = (char *)0;
+			name = NULL;
 			value = ADDR(lmp);
 		} else {
 			Slookup		sl;
+			Sresult		sr;
 			uint_t		binfo;
 
 			if (rp->r_type == RELOC_JMP_SLOT)
@@ -276,9 +284,9 @@
 			 */
 			SLOOKUP_INIT(sl, name, lmp, 0, ld_entry_cnt,
 			    0, 0, 0, 0, LKUP_STDRELOC);
+			SRESULT_INIT(sr, name);
 
-			if ((sym = aout_lookup_sym(&sl, &_lmp,
-			    &binfo, in_nfavl)) == 0) {
+			if (aout_lookup_sym(&sl, &sr, &binfo, in_nfavl) == 0) {
 				if (lml->lm_flags & LML_FLG_TRC_WARN) {
 					(void)
 					    printf(MSG_INTL(MSG_LDD_SYM_NFOUND),
@@ -297,6 +305,10 @@
 			 * If symbol was found in an object other than the
 			 * referencing object then record the binding.
 			 */
+			name = (char *)sr.sr_name;
+			_lmp = sr.sr_dmap;
+			sym = sr.sr_sym;
+
 			if ((lmp != _lmp) &&
 			    ((FLAGS1(_lmp) & FL1_RT_NOINIFIN) == 0)) {
 				if (aplist_test(&bound, _lmp,
--- a/usr/src/cmd/sgs/rtld/sparc/sparc_elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/sparc/sparc_elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -358,6 +358,7 @@
 	Xword		pltndx;
 	uint_t		binfo, sb_flags = 0, dbg_class;
 	Slookup		sl;
+	Sresult		sr;
 	Pltbindtype	pbtype;
 	int		entry, lmflags;
 	Lm_list		*lml;
@@ -419,19 +420,25 @@
 	llmp = lml->lm_tail;
 
 	/*
-	 * Find definition for symbol.  Initialize the symbol lookup data
-	 * structure.
+	 * Find definition for symbol.  Initialize the symbol lookup, and
+	 * symbol result, data structures.
 	 */
 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0,
 	    rsymndx, rsym, 0, LKUP_DEFT);
+	SRESULT_INIT(sr, name);
 
-	if ((nsym = lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) {
+	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
 		    demangle(name));
 		rtldexit(lml, 1);
 	}
 
+	name = (char *)sr.sr_name;
+	nlmp = sr.sr_dmap;
+	nsym = sr.sr_sym;
+
 	symval = nsym->st_value;
+
 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
 	    (nsym->st_shndx != SHN_ABS))
 		symval += ADDR(nlmp);
@@ -590,11 +597,11 @@
 		 * of this table.  There are two different interpretations of
 		 * the ABI at this point:
 		 *
-		 *   o	The REL table and its associated RELSZ indicate the
+		 *  -	The REL table and its associated RELSZ indicate the
 		 *	concatenation of *all* relocation sections (this is the
 		 *	model our link-editor constructs).
 		 *
-		 *   o	The REL table and its associated RELSZ indicate the
+		 *  -	The REL table and its associated RELSZ indicate the
 		 *	concatenation of all *but* the .plt relocations.  These
 		 *	relocations are specified individually by the JMPREL and
 		 *	PLTRELSZ entries.
@@ -741,7 +748,7 @@
 			 */
 			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
 				value = basebgn;
-				name = (char *)0;
+				name = NULL;
 
 				/*
 				 * Special case TLS relocations.
@@ -801,11 +808,12 @@
 					}
 				} else {
 					Slookup		sl;
+					Sresult		sr;
 
 					/*
 					 * Lookup the symbol definition.
-					 * Initialize the symbol lookup data
-					 * structure.
+					 * Initialize the symbol lookup, and
+					 * symbol result, data structures.
 					 */
 					name = (char *)(STRTAB(lmp) +
 					    symref->st_name);
@@ -813,9 +821,15 @@
 					SLOOKUP_INIT(sl, name, lmp, 0,
 					    ld_entry_cnt, 0, rsymndx, symref,
 					    rtype, LKUP_STDRELOC);
+					SRESULT_INIT(sr, name);
+					symdef = NULL;
 
-					symdef = lookup_sym(&sl, &_lmp,
-					    &binfo, in_nfavl);
+					if (lookup_sym(&sl, &sr, &binfo,
+					    in_nfavl)) {
+						name = (char *)sr.sr_name;
+						_lmp = sr.sr_dmap;
+						symdef = sr.sr_sym;
+					}
 
 					/*
 					 * If the symbol is not found and the
@@ -947,7 +961,8 @@
 				value = TLSMODID(lmp);
 			} else
 				value = basebgn;
-			name = (char *)0;
+
+			name = NULL;
 		}
 
 		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
--- a/usr/src/cmd/sgs/rtld/sparcv9/sparc_elf.c	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/sparcv9/sparc_elf.c	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -484,6 +484,7 @@
 	uint_t		binfo, sb_flags = 0, dbg_class;
 	ulong_t		rsymndx;
 	Slookup		sl;
+	Sresult		sr;
 	Pltbindtype	pbtype;
 	int		entry, lmflags, farplt = 0;
 	Lm_list		*lml;
@@ -558,19 +559,25 @@
 	llmp = lml->lm_tail;
 
 	/*
-	 * Find definition for symbol.  Initialize the symbol lookup data
-	 * structure.
+	 * Find definition for symbol.  Initialize the symbol lookup, and symbol
+	 * result, data structures.
 	 */
 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0,
 	    rsymndx, rsym, 0, LKUP_DEFT);
+	SRESULT_INIT(sr, name);
 
-	if ((nsym = lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) {
+	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
 		    demangle(name));
 		rtldexit(lml, 1);
 	}
 
+	name = (char *)sr.sr_name;
+	nlmp = sr.sr_dmap;
+	nsym = sr.sr_sym;
+
 	symval = nsym->st_value;
+
 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
 	    (nsym->st_shndx != SHN_ABS))
 		symval += ADDR(nlmp);
@@ -967,7 +974,7 @@
 			 */
 			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
 				value = basebgn;
-				name = (char *)0;
+				name = NULL;
 
 				/*
 				 * Special case TLS relocations.
@@ -1029,11 +1036,12 @@
 					}
 				} else {
 					Slookup		sl;
+					Sresult		sr;
 
 					/*
 					 * Lookup the symbol definition.
-					 * Initialize the symbol lookup data
-					 * structure.
+					 * Initialize the symbol lookup, and
+					 * symbol result, data structures.
 					 */
 					name = (char *)(STRTAB(lmp) +
 					    symref->st_name);
@@ -1041,9 +1049,15 @@
 					SLOOKUP_INIT(sl, name, lmp, 0,
 					    ld_entry_cnt, 0, rsymndx, symref,
 					    rtype, LKUP_STDRELOC);
+					SRESULT_INIT(sr, name);
+					symdef = NULL;
 
-					symdef = lookup_sym(&sl, &_lmp,
-					    &binfo, in_nfavl);
+					if (lookup_sym(&sl, &sr, &binfo,
+					    in_nfavl)) {
+						name = (char *)sr.sr_name;
+						_lmp = sr.sr_dmap;
+						symdef = sr.sr_sym;
+					}
 
 					/*
 					 * If the symbol is not found and the
@@ -1179,7 +1193,8 @@
 				value = TLSMODID(lmp);
 			} else
 				value = basebgn;
-			name = (char *)0;
+
+			name = NULL;
 		}
 
 		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
--- a/usr/src/cmd/sgs/tools/Makefile.com	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/cmd/sgs/tools/Makefile.com	Mon Mar 01 10:20:48 2010 -0800
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,12 +18,13 @@
 #
 # CDDL HEADER END
 #
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
+
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+
+#
 # Makefile to support tools used for linker development:
 #
 #  o	sgsmsg creates message headers/arrays/catalogs (a native tool).
@@ -59,7 +59,7 @@
 SRCS=		$(COMOBJS:%.o=../common/%.c)  $(NATOBJS:%.o=../common/%.c)
 
 CPPFLAGS +=	$(VAR_TOOLS_CPPFLAGS)
-LDFLAGS +=	$(USE_PROTO)
+LDFLAGS +=	$(CC_USE_PROTO)
 CLEANFILES +=	$(LINTOUT) $(SGSMSG_OBJS)
 LINTFLAGS=	-ax
 
--- a/usr/src/head/link.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/head/link.h	Mon Mar 01 10:20:48 2010 -0800
@@ -264,7 +264,7 @@
 #endif /* _LP64 */
 #endif /* __STDC__ */
 
-
+#ifdef	__STDC__
 /*
  * The ElfW() macro is a GNU/Linux feature, provided as support for
  * the dl_phdr_info structure used by dl_phdr_iterate(), which also
@@ -318,6 +318,7 @@
 
 extern  int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *),
 	    void *);
+#endif /* __STDC__ */
 
 #endif	/* _ASM */
 #endif /* _KERNEL */
--- a/usr/src/uts/common/sys/elf.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/uts/common/sys/elf.h	Mon Mar 01 10:20:48 2010 -0800
@@ -421,7 +421,9 @@
 
 /* Solaris ABI specific values */
 #define	SHT_LOOS		0x60000000	/* OS specific range */
-#define	SHT_LOSUNW		0x6ffffff1
+#define	SHT_LOSUNW		0x6fffffef
+#define	SHT_SUNW_capchain	0x6fffffef
+#define	SHT_SUNW_capinfo	0x6ffffff0
 #define	SHT_SUNW_symsort	0x6ffffff1
 #define	SHT_SUNW_tlssort	0x6ffffff2
 #define	SHT_SUNW_LDYNSYM	0x6ffffff3
@@ -519,7 +521,7 @@
 #define	STN_UNDEF	0
 
 /*
- *	The macros compose and decompose values for S.st_info
+ *	Macros to compose and decompose values for S.st_info
  *
  *	bind = ELF32_ST_BIND(S.st_info)
  *	type = ELF32_ST_TYPE(S.st_info)
@@ -557,7 +559,7 @@
 #define	STT_HIPROC	15
 
 /*
- *	The macros decompose values for S.st_other
+ *	Macros to decompose values for S.st_other
  *
  *	visibility = ELF32_ST_VISIBILITY(S.st_other)
  */
@@ -604,7 +606,7 @@
 
 
 /*
- *	The macros compose and decompose values for Rel.r_info, Rela.f_info
+ *	Macros to compose and decompose values for Rel.r_info, Rela.f_info
  *
  *	sym = ELF32_R_SYM(R.r_info)
  *	type = ELF32_R_TYPE(R.r_info)
@@ -670,7 +672,7 @@
 } Elf32_Move;
 
 /*
- *	The macros compose and decompose values for Move.r_info
+ *	Macros to compose and decompose values for Move.r_info
  *
  *	sym = ELF32_M_SYM(M.m_info)
  *	size = ELF32_M_SIZE(M.m_info)
@@ -695,7 +697,7 @@
 
 
 /*
- *	Hardware/Software capabilities entry
+ *	Capabilities entry, Capabilities info and Capabilities chain.
  */
 #ifndef	_ASM
 typedef struct {
@@ -706,6 +708,21 @@
 	} c_un;
 } Elf32_Cap;
 
+typedef	Elf32_Word	Elf32_Capinfo;
+typedef	Elf32_Word	Elf32_Capchain;
+
+/*
+ *	Macros to compose and decompose values for capabilities info.
+ *
+ *	sym = ELF32_C_SYM(info)
+ *	grp = ELF32_C_GROUP(info)
+ *	info = ELF32_C_INFO(sym, grp)
+ */
+#define	ELF32_C_SYM(info)	((info)>>8)
+#define	ELF32_C_GROUP(info)	((unsigned char)(info))
+#define	ELF32_C_INFO(sym, grp)	(((sym)<<8)+(unsigned char)(grp))
+
+
 #if defined(_LP64) || defined(_LONGLONG_TYPE)
 typedef struct {
 	Elf64_Xword	c_tag;		/* how to interpret value */
@@ -714,14 +731,55 @@
 		Elf64_Addr	c_ptr;
 	} c_un;
 } Elf64_Cap;
+
+typedef	Elf64_Xword	Elf64_Capinfo;
+typedef	Elf64_Word	Elf64_Capchain;
+
+/*
+ *	Macros to compose and decompose values for capabilities info.
+ *
+ *	sym = ELF64_C_SYM(info)
+ *	grp = ELF64_C_GROUP(info)
+ *	info = ELF64_C_INFO(sym, grp)
+ */
+#define	ELF64_C_SYM(info)	((info)>>32)
+#define	ELF64_C_GROUP(info)    	((Elf64_Word)(info))
+#define	ELF64_C_INFO(sym, grp)	(((Elf64_Xword)(sym)<<32)+(Elf64_Xword)(grp))
+
 #endif	/* defined(_LP64) || defined(_LONGLONG_TYPE) */
 #endif
 
+/*
+ * Version numbers for SHT_SUNW_capinfo and SHT_SUNW_capchain.
+ */
+#define	CAPINFO_NONE		0
+#define	CAPINFO_CURRENT		1
+#define	CAPINFO_NUM		2
+
+#define	CAPCHAIN_NONE		0
+#define	CAPCHAIN_CURRENT	1
+#define	CAPCHAIN_NUM		2
+
+/*
+ * A SHT_SUNW_capinfo table mirrors a symbol table.  A capabilities symbol has
+ * a SHT_SUNW_capinfo table entry that provides an index into the associated
+ * SHT_SUNW_cap capabilities group, and the symbol index of the associated lead
+ * symbol.  A capabilities symbol is a local symbol.  A global lead capabilities
+ * symbol is tagged with a group CAPINFO_SUNW_GLOB.
+ */
+#define	CAPINFO_SUNW_GLOB	0xff
+
+/*
+ * Capabilities values.
+ */
 #define	CA_SUNW_NULL	0
 #define	CA_SUNW_HW_1	1		/* first hardware capabilities entry */
 #define	CA_SUNW_SF_1	2		/* first software capabilities entry */
 #define	CA_SUNW_HW_2	3		/* second hardware capabilities entry */
-#define	CA_SUNW_NUM	4
+#define	CA_SUNW_PLAT	4		/* platform capability entry */
+#define	CA_SUNW_MACH	5		/* machine capability entry */
+#define	CA_SUNW_ID	6		/* capability identifier */
+#define	CA_SUNW_NUM	7
 
 /*
  * Define software capabilities (CA_SUNW_SF_1 values).  Note, hardware
@@ -735,7 +793,6 @@
 /*
  *	Known values for note entry types (e_type == ET_CORE)
  */
-
 #define	NT_PRSTATUS	1	/* prstatus_t	<sys/old_procfs.h>	*/
 #define	NT_PRFPREG	2	/* prfpregset_t	<sys/old_procfs.h>	*/
 #define	NT_PRPSINFO	3	/* prpsinfo_t	<sys/old_procfs.h>	*/
--- a/usr/src/uts/common/sys/link.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/uts/common/sys/link.h	Mon Mar 01 10:20:48 2010 -0800
@@ -150,11 +150,14 @@
 #define	DT_SUNW_SYMSORTSZ	0x60000015	/* size of SUNW_SYMSORT */
 #define	DT_SUNW_TLSSORT		0x60000016	/* tls sym ndx sort by offset */
 #define	DT_SUNW_TLSSORTSZ	0x60000017	/* size of SUNW_TLSSORT */
-
+#define	DT_SUNW_CAPINFO		0x60000018	/* capabilities symbols */
 #define	DT_SUNW_STRPAD		0x60000019	/* # of unused bytes at the */
 						/*	end of dynstr */
+#define	DT_SUNW_CAPCHAIN	0x6000001a	/* capabilities chain info */
 #define	DT_SUNW_LDMACH		0x6000001b	/* EM_ machine code of linker */
 						/*	that produced object */
+#define	DT_SUNW_CAPCHAINENT	0x6000001d	/* capabilities chain entry */
+#define	DT_SUNW_CAPCHAINSZ	0x6000001f	/* capabilities chain size */
 
 /*
  * DT_* encoding rules do not apply between DT_HIOS and DT_LOPROC
@@ -468,6 +471,7 @@
 #define	SYMINFO_FLG_AUXILIARY	0x0040	/* symbol ref is associated to a */
 					/* 	auxiliary filter */
 #define	SYMINFO_FLG_INTERPOSE	0x0080	/* symbol defines an interposer */
+#define	SYMINFO_FLG_CAP		0x0100	/* symbol is capabilities specific */
 
 /*
  * Syminfo.si_boundto values.
--- a/usr/src/uts/common/sys/machelf.h	Thu Feb 25 18:07:30 2010 -0800
+++ b/usr/src/uts/common/sys/machelf.h	Mon Mar 01 10:20:48 2010 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -90,6 +90,8 @@
 typedef	Elf64_Versym	Versym;
 typedef	Elf64_Move	Move;
 typedef	Elf64_Cap	Cap;
+typedef	Elf64_Capinfo	Capinfo;
+typedef	Elf64_Capchain	Capchain;
 #endif	/* _ASM */
 
 #else	/* _ILP32 */
@@ -135,6 +137,8 @@
 typedef	Elf32_Versym	Versym;
 typedef	Elf32_Move	Move;
 typedef	Elf32_Cap	Cap;
+typedef	Elf32_Capinfo	Capinfo;
+typedef	Elf32_Capchain	Capchain;
 #endif	/* _ASM */
 
 #endif	/* _ILP32 */