changeset 12889:69001e4756ae

6956152 dlclose() from an auditor can be fatal. Preinit/activity events should be more flexible.
author Rod Evans <Rod.Evans@Sun.COM>
date Tue, 20 Jul 2010 16:29:51 -0700
parents a534e180a8e7
children 77865d4311a1
files usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/rtld.h usr/src/cmd/sgs/ldprof/common/profile.c usr/src/cmd/sgs/libconv/Makefile.com usr/src/cmd/sgs/libconv/common/audit.c usr/src/cmd/sgs/libconv/common/audit.msg usr/src/cmd/sgs/libconv/common/lintsup.c usr/src/cmd/sgs/libconv/common/llib-lconv usr/src/cmd/sgs/liblddbg/common/audit.c usr/src/cmd/sgs/liblddbg/common/files.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/liblddbg/common/libs.c usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/liblddbg/common/mapfile-vers usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/rtld/common/_a.out.h usr/src/cmd/sgs/rtld/common/_audit.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/dlfcns.c usr/src/cmd/sgs/rtld/common/elf.c usr/src/cmd/sgs/rtld/common/external.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/tsort.c usr/src/cmd/sgs/rtld/common/util.c usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg usr/src/head/link.h
diffstat 38 files changed, 1582 insertions(+), 591 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/include/conv.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/include/conv.h	Tue Jul 20 16:29:51 2010 -0700
@@ -126,6 +126,33 @@
 } Conv_reject_desc_buf_t;
 
 /*
+ * conv_la_bind()
+ */
+#define	CONV_LA_BIND_BUFSIZE		56
+typedef union {
+	Conv_inv_buf_t			inv_buf;
+	char				buf[CONV_LA_BIND_BUFSIZE];
+} Conv_la_bind_buf_t;
+
+/*
+ * conv_la_search()
+ */
+#define	CONV_LA_SEARCH_BUFSIZE		111
+typedef union {
+	Conv_inv_buf_t			inv_buf;
+	char				buf[CONV_LA_SEARCH_BUFSIZE];
+} Conv_la_search_buf_t;
+
+/*
+ * conv_la_symbind()
+ */
+#define	CONV_LA_SYMBIND_BUFSIZE		113
+typedef union {
+	Conv_inv_buf_t			inv_buf;
+	char				buf[CONV_LA_SYMBIND_BUFSIZE];
+} Conv_la_symbind_buf_t;
+
+/*
  * conv_cap_val_hw/sf()
  *
  * These sizes are based on the maximum number of capabilities that exist.
@@ -843,6 +870,11 @@
 extern	const char	*conv_ent_flags(ec_flags_t, Conv_ent_flags_buf_t *);
 extern	const char	*conv_ent_files_flags(Word,  Conv_fmt_flags_t fmt_flags,
 			    Conv_ent_files_flags_buf_t *);
+extern	const char	*conv_la_activity(uint_t, Conv_fmt_flags_t,
+			    Conv_inv_buf_t *);
+extern	const char	*conv_la_bind(uint_t, Conv_la_bind_buf_t *);
+extern	const char	*conv_la_search(uint_t, Conv_la_search_buf_t *);
+extern	const char	*conv_la_symbind(uint_t, Conv_la_symbind_buf_t *);
 extern	const char	*conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *);
 extern	const char	*conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *);
 extern	Isa_desc	*conv_isalist(void);
--- a/usr/src/cmd/sgs/include/debug.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/include/debug.h	Tue Jul 20 16:29:51 2010 -0700
@@ -93,6 +93,13 @@
 #define	DBG_SYM_REDUCE_GLOBAL	1	/* reporting global symbols to local */
 #define	DBG_SYM_REDUCE_RETAIN	2	/* reporting non reduced local syms */
 
+#define	DBG_AUD_CALL		1	/* original call to auditor */
+#define	DBG_AUD_RET		2	/* return from auditor diagnostic */
+
+#define	DBG_AUD_LOCAL		0	/* auditor is local */
+#define	DBG_AUD_GLOBAL		1	/* auditor is global */
+#define	DBG_AUD_PRELOAD		2	/* auditor is preloaded */
+
 /*
  * Group handle operations - passed to Dbg_file_hdl_title().  Indicate why
  * handle dependencies are being manipulated.
@@ -759,15 +766,27 @@
 extern	void	Dbg_args_option(Lm_list *, int, int, char *);
 extern	void	Dbg_args_str2chr(Lm_list *, int, const char *, int);
 extern	void	Dbg_args_Wldel(Lm_list *, int, const char *);
+extern	void	Dbg_audit_activity(Lm_list *, const char *, const char *,
+		    uint_t);
 extern	void	Dbg_audit_ignore(Rt_map *);
 extern	void	Dbg_audit_interface(Lm_list *, const char *, const char *);
-extern	void	Dbg_audit_lib(Lm_list *, const char *);
-extern	void	Dbg_audit_object(Lm_list *, const char *, const char *);
-extern	void	Dbg_audit_symval(Lm_list *, const char *, const char *,
-		    const char *, Addr, Addr);
+extern	void	Dbg_audit_lib(Rt_map *, const char *, int);
+extern	void	Dbg_audit_objclose(Lm_list *, const char *, const char *);
+extern	void	Dbg_audit_objopen(Lm_list *, int, const char *, const char *,
+		    uint_t, Boolean);
+extern	void	Dbg_audit_objfilter(Lm_list *, int, const char *, const char *,
+		    const char *, const char *);
+extern	void	Dbg_audit_objsearch(Lm_list *, int, const char *, const char *,
+		    uint_t, const char *);
+extern	void	Dbg_audit_pltenter(Lm_list *, int, const char *, const char *,
+		    Addr);
+extern	void	Dbg_audit_pltexit(Lm_list *, const char *, const char *);
+extern	void	Dbg_audit_preinit(Lm_list *, const char *, const char *);
+extern	void	Dbg_audit_symbind(Lm_list *, int, const char *, const char *,
+		    Addr, uint_t);
 extern	void	Dbg_audit_skip(Lm_list *, const char *, const char *);
 extern	void	Dbg_audit_terminate(Lm_list *, const char *);
-extern	void	Dbg_audit_version(Lm_list *, const char *, ulong_t);
+extern	void	Dbg_audit_version(Lm_list *, const char *, uint_t, uint_t);
 
 extern	void	Dbg_basic_collect(Lm_list *);
 extern	void	Dbg_basic_create(Lm_list *);
--- a/usr/src/cmd/sgs/include/rtld.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/include/rtld.h	Tue Jul 20 16:29:51 2010 -0700
@@ -303,7 +303,7 @@
 	uint_t		lm_tls;		/* new obj that require TLS */
 	uint_t		lm_lmid;	/* unique link-map list identifier, */
 	char		*lm_lmidstr;	/* and associated diagnostic string */
-	APlist		*lm_actaudit;	/* list of pending audit activity */
+	Alist		*lm_aud_cookies; /* local auditor cookies */
 	Lc_desc		lm_lcs[CI_MAX];	/* external libc functions */
 };
 
@@ -330,7 +330,7 @@
 	uint_t		lm_tls;
 	uint_t		lm_lmid;
 	Elf32_Addr	lm_lmidstr;
-	Elf32_Addr	lm_actaudit;
+	Elf32_Addr	lm_aud_cookies;
 	Elf32_Addr	lm_lcs[CI_MAX];
 };
 #endif /* _SYSCALL32 */
@@ -346,28 +346,27 @@
 /*
  * END: Exposed to rtld_db - don't move, don't delete
  */
-#define	LML_FLG_NOAUDIT		0x00000004	/* symbol auditing disabled */
+#define	LML_FLG_ACTAUDIT	0x00000004	/* audit activity posted */
 #define	LML_FLG_PLTREL		0x00000008	/* deferred plt relocation */
-						/* 	initialization */
-						/*	(ld.so.1 only) */
+						/*    initialization (ld.so.1 */
+						/*    only) */
 #define	LML_FLG_HOLDLOCK	0x00000010	/* hold the rtld mutex lock */
 #define	LML_FLG_ENVIRON		0x00000020	/* environ var initialized */
 #define	LML_FLG_INTRPOSE	0x00000040	/* interposing objs on list */
 #define	LML_FLG_LOCAUDIT	0x00000080	/* local auditors exists for */
-						/*	this link-map list */
+						/*    this link-map list */
 #define	LML_FLG_LOADAVAIL	0x00000100	/* load anything available */
 #define	LML_FLG_IGNRELERR	0x00000200	/* ignore relocation errors - */
-						/*	internal for crle(1) */
-#define	LML_FLG_DBNOTIF		0x00000400	/* binding activity going on */
-#define	LML_FLG_STARTREL	0x00000800	/* relocation started */
-#define	LML_FLG_ATEXIT		0x00001000	/* atexit processing */
-#define	LML_FLG_OBJADDED	0x00002000	/* object(s) added */
-#define	LML_FLG_OBJDELETED	0x00004000	/* object(s) deleted */
-#define	LML_FLG_OBJREEVAL	0x00008000	/* existing object(s) needs */
-						/*	tsort reevaluation */
-#define	LML_FLG_INTRPOSETSORT	0x00020000	/* interpose tsorting done */
-#define	LML_FLG_AUDITNOTIFY	0x00040000	/* audit consistent required */
-#define	LML_FLG_GROUPSEXIST	0x00080000	/* local groups exist */
+						/*    internal for crle(1) */
+#define	LML_FLG_STARTREL	0x00000400	/* relocation started */
+#define	LML_FLG_ATEXIT		0x00000800	/* atexit processing */
+#define	LML_FLG_OBJADDED	0x00001000	/* object(s) added */
+#define	LML_FLG_OBJDELETED	0x00002000	/* object(s) deleted */
+#define	LML_FLG_OBJREEVAL	0x00004000	/* existing object(s) needs */
+						/*    tsort reevaluation */
+#define	LML_FLG_INTRPOSETSORT	0x00008000	/* interpose tsorting done */
+#define	LML_FLG_AUDITNOTIFY	0x00010000	/* audit consistent required */
+#define	LML_FLG_GROUPSEXIST	0x00020000	/* local groups exist */
 
 #define	LML_FLG_TRC_LDDSTUB	0x00100000	/* identify lddstub */
 #define	LML_FLG_TRC_ENABLE	0x00200000	/* tracing enabled (ldd) */
@@ -375,14 +374,14 @@
 #define	LML_FLG_TRC_VERBOSE	0x00800000	/* verbose (versioning) trace */
 #define	LML_FLG_TRC_SEARCH	0x01000000	/* trace search paths */
 #define	LML_FLG_TRC_UNREF	0x02000000	/* trace unreferenced */
-						/*	dependencies */
+						/*    dependencies */
 #define	LML_FLG_TRC_UNUSED	0x04000000	/* trace unused dependencies */
 #define	LML_FLG_TRC_INIT	0x08000000	/* print .init order */
 #define	LML_FLG_TRC_NOUNRESWEAK	0x10000000	/* unresolved weak references */
-						/*	are not allowed */
+						/*    are not allowed */
 #define	LML_FLG_TRC_NOPAREXT	0x20000000	/* unresolved PARENT/EXTERN */
-						/*	references are not */
-						/*	allowed */
+						/*    references are not */
+						/*    allowed */
 #define	LML_MSK_TRC		0xfff00000	/* tracing mask */
 
 /*
@@ -391,7 +390,7 @@
  */
 #define	LML_TFLG_NOLAZYLD	0x00000001	/* lazy loading disabled */
 #define	LML_TFLG_NODIRECT	0x00000002	/* direct bindings disabled */
-
+#define	LML_TFLG_NOAUDIT	0x00000004	/* auditing disabled */
 #define	LML_TFLG_LOADFLTR	0x00000008	/* trigger filtee loading */
 
 #define	LML_TFLG_AUD_PREINIT	0x00001000	/* preinit (audit) exists */
--- a/usr/src/cmd/sgs/ldprof/common/profile.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/ldprof/common/profile.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -405,7 +404,7 @@
 	 * Don't even try to profile an object that does not have
 	 * auditing enabled on it's link-map.  This catches 'ld.so.1'.
 	 */
-	if (LIST(LINKMAP_TO_RTMAP(lmp))->lm_flags & LML_FLG_NOAUDIT)
+	if (LIST(LINKMAP_TO_RTMAP(lmp))->lm_tflags & LML_TFLG_NOAUDIT)
 		return (LA_FLG_BINDFROM);
 
 	if (profile_open(pname, lmp) == 0)
--- a/usr/src/cmd/sgs/libconv/Makefile.com	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/libconv/Makefile.com	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 LIBRARY =	libconv.a
@@ -34,7 +33,8 @@
 		globals_machelf64.o	sections_machelf64.o \
 		symbols_machelf64.o	symbols_sparc_machelf64.o
 
-COMOBJS=	arch.o			c_literal.o \
+COMOBJS=	arch.o			audit.o \
+		c_literal.o \
 		cap.o			config.o \
 		corenote.o 		data.o \
 		deftag.o 		demangle.o \
@@ -55,7 +55,8 @@
 
 ASOBJS=		vernote.o
 
-BLTOBJS=	arch_msg.o		c_literal_msg.o \
+BLTOBJS=	arch_msg.o		audit_msg.o \
+		c_literal_msg.o \
 		cap_msg.o		config_msg.o \
 		corenote_msg.o		data_msg.o \
 		deftag_msg.o		demangle_msg.o \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/audit.c	Tue Jul 20 16:29:51 2010 -0700
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include	<string.h>
+#include	<link.h>
+#include	"_conv.h"
+#include	"audit_msg.h"
+
+#define	BINDSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+		MSG_LA_FLG_BINDTO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_FLG_BINDFROM_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_la_bind_buf_t is large enough:
+ *
+ * BINDSZ is the real minimum size of the buffer required by conv_la_bind().
+ * However, Conv_la_bind_buf_t uses CONV_LA_BIND_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of BINDSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_LA_BIND_BUFSIZE != BINDSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE BINDSZ
+#include "report_bufsize.h"
+#error "CONV_LA_BIND_BUFSIZE does not match BINDSZ"
+#endif
+
+/*
+ * String conversion routine for la_objopen() return flags.
+ */
+const char *
+conv_la_bind(uint_t bind, Conv_la_bind_buf_t *la_bind_buf)
+{
+	static const Val_desc vda[] = {
+		{ LA_FLG_BINDTO,	MSG_LA_FLG_BINDTO },
+		{ LA_FLG_BINDFROM,	MSG_LA_FLG_BINDFROM },
+		{ 0,			0 }
+	};
+	static CONV_EXPN_FIELD_ARG conv_arg = {
+	    NULL, sizeof (la_bind_buf->buf), NULL };
+
+	if (bind == 0)
+		return (MSG_ORIG(MSG_GBL_ZERO));
+
+	conv_arg.buf = la_bind_buf->buf;
+	conv_arg.oflags = conv_arg.rflags = bind;
+
+	(void) conv_expn_field(&conv_arg, vda, 0);
+
+	return ((const char *)la_bind_buf->buf);
+}
+
+#define	SEARCHSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+		MSG_LA_SER_ORIG_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SER_LIBPATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SER_RUNPATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SER_DEFAULT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SER_CONFIG_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SER_SECURE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_la_search_buf_t is large enough:
+ *
+ * SEARCHSZ is the real minimum size of the buffer required by conv_la_search().
+ * However, Conv_la_search_buf_t uses CONV_LA_SEARCH_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of SEARCHSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_LA_SEARCH_BUFSIZE != SEARCHSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE SEARCHSZ
+#include "report_bufsize.h"
+#error "CONV_LA_SEARCH_BUFSIZE does not match SEARCHSZ"
+#endif
+
+/*
+ * String conversion routine for la_objsearch() flags.
+ */
+const char *
+conv_la_search(uint_t search, Conv_la_search_buf_t *la_search_buf)
+{
+	static const Val_desc vda[] = {
+		{ LA_SER_ORIG,		MSG_LA_SER_ORIG },
+		{ LA_SER_LIBPATH,	MSG_LA_SER_LIBPATH },
+		{ LA_SER_RUNPATH,	MSG_LA_SER_RUNPATH },
+		{ LA_SER_DEFAULT,	MSG_LA_SER_DEFAULT },
+		{ LA_SER_CONFIG,	MSG_LA_SER_CONFIG },
+		{ LA_SER_SECURE,	MSG_LA_SER_SECURE },
+		{ 0,			0 }
+	};
+	static CONV_EXPN_FIELD_ARG conv_arg = {
+	    NULL, sizeof (la_search_buf->buf), NULL };
+
+	if (search == 0)
+		return (MSG_ORIG(MSG_GBL_NULL));
+
+	conv_arg.buf = la_search_buf->buf;
+	conv_arg.oflags = conv_arg.rflags = search;
+
+	(void) conv_expn_field(&conv_arg, vda, 0);
+
+	return ((const char *)la_search_buf->buf);
+}
+
+/*
+ * String conversion routine for la_objopen() return flags.
+ */
+
+/*
+ * String conversion routine for la_activity() flags.
+ */
+const char *
+conv_la_activity(uint_t request, Conv_fmt_flags_t fmt_flags,
+    Conv_inv_buf_t *inv_buf)
+{
+	static const Msg	requests[LA_ACT_MAX] = {
+		MSG_LA_ACT_CONSISTENT,	/* MSG_ORIG(MSG_LA_ACT_CONSISTENT) */
+		MSG_LA_ACT_ADD,		/* MSG_ORIG(MSG_LA_ACT_ADD) */
+		MSG_LA_ACT_DELETE	/* MSG_ORIG(MSG_LA_ACT_DELETE) */
+	};
+	static const conv_ds_msg_t ds_requests = {
+	    CONV_DS_MSG_INIT(LA_ACT_CONSISTENT, requests) };
+
+	static const conv_ds_t	*ds[] = { CONV_DS_ADDR(ds_requests), NULL };
+
+	return (conv_map_ds(ELFOSABI_NONE, EM_NONE, request, ds, fmt_flags,
+	    inv_buf));
+}
+
+#define	SYMBSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+		MSG_LA_SYMB_NOPLTENTER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SYMB_NOPLTEXIT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SYMB_STRUCTCALL_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SYMB_DLSYM_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_LA_SYMB_ALTVALUE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_la_symbind_buf_t is large enough:
+ *
+ * SYMBSZ is the real minimum size of the buffer required by conv_la_symbind().
+ * However, Conv_la_symbind_buf_t uses CONV_LA_SYMB_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of SYMBSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_LA_SYMBIND_BUFSIZE != SYMBSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE SYMBSZ
+#include "report_bufsize.h"
+#error "CONV_LA_SYMBIND_BUFSIZE does not match SYMBSZ"
+#endif
+
+/*
+ * String conversion routine for la_symbind() flags.
+ */
+const char *
+conv_la_symbind(uint_t symbind, Conv_la_symbind_buf_t *la_symbind_buf)
+{
+	static const Val_desc vda[] = {
+		{ LA_SYMB_NOPLTENTER,	MSG_LA_SYMB_NOPLTENTER },
+		{ LA_SYMB_NOPLTEXIT,	MSG_LA_SYMB_NOPLTEXIT },
+		{ LA_SYMB_STRUCTCALL,	MSG_LA_SYMB_STRUCTCALL },
+		{ LA_SYMB_DLSYM,	MSG_LA_SYMB_DLSYM },
+		{ LA_SYMB_ALTVALUE,	MSG_LA_SYMB_ALTVALUE },
+		{ 0,			0 }
+	};
+	static CONV_EXPN_FIELD_ARG conv_arg = {
+	    NULL, sizeof (la_symbind_buf->buf), NULL };
+
+	if (symbind == 0)
+		return (MSG_ORIG(MSG_GBL_NULL));
+
+	conv_arg.buf = la_symbind_buf->buf;
+	conv_arg.oflags = conv_arg.rflags = symbind;
+
+	(void) conv_expn_field(&conv_arg, vda, 0);
+
+	return ((const char *)la_symbind_buf->buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/audit.msg	Tue Jul 20 16:29:51 2010 -0700
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# 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.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Message file for cmd/sgs/libconv/common/audit.c
+
+@ MSG_LA_FLG_BINDTO	"LA_FLG_BINDTO"
+@ MSG_LA_FLG_BINDFROM	"LA_FLG_BINDFROM"
+
+@ MSG_LA_ACT_CONSISTENT	"[ LA_ACT_CONSISTENT ]"
+@ MSG_LA_ACT_ADD	"[ LA_ACT_ADD ]"
+@ MSG_LA_ACT_DELETE	"[ LA_ACT_DELETE ]"
+
+@ MSG_LA_SER_ORIG	"LA_SER_ORIG"
+@ MSG_LA_SER_LIBPATH	"LA_SER_LIBPATH"
+@ MSG_LA_SER_RUNPATH	"LA_SER_RUNPATH"
+@ MSG_LA_SER_DEFAULT	"LA_SER_DEFAULT"
+@ MSG_LA_SER_CONFIG	"LA_SER_CONFIG"
+@ MSG_LA_SER_SECURE	"LA_SER_SECURE"
+
+@ MSG_LA_SYMB_NOPLTENTER	"LA_SYMB_NOPLTENTER"
+@ MSG_LA_SYMB_NOPLTEXIT		"LA_SYMB_NOPLTEXIT"
+@ MSG_LA_SYMB_STRUCTCALL	"LA_SYMB_STRUCTCALL"
+@ MSG_LA_SYMB_DLSYM		"LA_SYMB_DLSYM"
+@ MSG_LA_SYMB_ALTVALUE		"LA_SYMB_ALTVALUE"
+
+@ MSG_GBL_ZERO		"0"
+@ MSG_GBL_NULL		""
--- a/usr/src/cmd/sgs/libconv/common/lintsup.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/libconv/common/lintsup.c	Tue Jul 20 16:29:51 2010 -0700
@@ -18,16 +18,15 @@
  *
  * CDDL HEADER END
  */
+
+/*
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
 /* LINTLIBRARY */
 /* PROTOLIB1 */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Supplimental definitions for lint that help us avoid
+ * Supplemental definitions for lint that help us avoid
  * options like `-x' that filter out things we want to
  * know about as well as things we don't.
  */
@@ -54,6 +53,7 @@
  */
 #define	LINTSUP_SUPPRESS_STRINGS
 #include "arch_msg.h"
+#include "audit_msg.h"
 #include "c_literal_msg.h"
 #include "cap_msg.h"
 #include "config_msg.h"
@@ -89,6 +89,7 @@
 #define	USE(name) (void) name((Msg)&_ ## name[0])
 
 	USE(_sgs_msg_libconv_arch);
+	USE(_sgs_msg_libconv_audit);
 	USE(_sgs_msg_libconv_c_literal);
 	USE(_sgs_msg_libconv_cap);
 	USE(_sgs_msg_libconv_config);
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/libconv/common/llib-lconv	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 /* LINTLIBRARY */
 /* PROTOLIB1 */
@@ -141,6 +140,10 @@
 const char	*conv_ent_filcmp(Word, Conv_fmt_flags_t, Conv_inv_buf_t *);
 const char	*conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *);
 const char	*conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *);
+const char	*conv_la_activity(uint_t, Conv_fmt_flags_t, Conv_inv_buf_t *);
+const char	*conv_la_bind(uint_t, Conv_la_bind_buf_t *);
+const char	*conv_la_search(uint_t, Conv_la_search_buf_t *);
+const char	*conv_la_symbind(uint_t, Conv_la_symbind_buf_t *);
 Isa_desc	*conv_isalist(void);
 const char	*conv_mapfile_version(Word, Conv_fmt_flags_t,
 		    Conv_inv_buf_t *);
--- a/usr/src/cmd/sgs/liblddbg/common/audit.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/liblddbg/common/audit.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,10 +20,8 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include	<dlfcn.h>
 #include	<stdio.h>
@@ -32,23 +30,29 @@
 #include	"libld.h"
 
 void
-Dbg_audit_version(Lm_list *lml, const char *lib, ulong_t version)
+Dbg_audit_lib(Rt_map *clmp, const char *lib, int type)
 {
+	Lm_list		*clml = LIST(clmp);
+	const char	*str;
+
 	if (DBG_NOTCLASS(DBG_C_AUDITING))
 		return;
 
-	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_AUD_VERSION), lib, (int)version);
-}
+	Dbg_util_nl(clml, DBG_NL_STD);
+	switch (type) {
+	case DBG_AUD_PRELOAD:
+		str = MSG_ORIG(MSG_AUD_PRELOAD);
+		break;
+	case DBG_AUD_GLOBAL:
+		str = MSG_ORIG(MSG_AUD_GLOBAL);
+		break;
+	case DBG_AUD_LOCAL:
+		/* FALLTHROUGH */
+	default:
+		str = MSG_ORIG(MSG_STR_EMPTY);
+	}
 
-void
-Dbg_audit_lib(Lm_list *lml, const char *lib)
-{
-	if (DBG_NOTCLASS(DBG_C_AUDITING))
-		return;
-
-	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_AUD_INIT), lib);
+	dbg_print(clml, MSG_INTL(MSG_AUD_LIB), lib, NAME(clmp), str);
 }
 
 void
@@ -57,38 +61,154 @@
 	if (DBG_NOTCLASS(DBG_C_AUDITING))
 		return;
 
-	Dbg_util_nl(lml, DBG_NL_STD);
 	dbg_print(lml, MSG_INTL(MSG_AUD_INTERFACE), lib, interface);
 }
 
 void
-Dbg_audit_object(Lm_list *lml, const char *lib, const char *obj)
+Dbg_audit_version(Lm_list *lml, const char *lib, uint_t overs, uint_t nvers)
+{
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
+
+	dbg_print(lml, MSG_INTL(MSG_AUD_VERSION), lib, overs, nvers);
+}
+
+void
+Dbg_audit_activity(Lm_list *lml, const char *lib, const char *obj, uint_t flags)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_AUD_ACTIVITY), lib, obj,
+	    conv_la_activity(flags, CONV_FMT_ALT_DEFAULT, &inv_buf));
+}
+
+void
+Dbg_audit_preinit(Lm_list *lml, const char *lib, const char *obj)
 {
 	if (DBG_NOTCLASS(DBG_C_AUDITING))
 		return;
 
 	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_AUD_OBJECT), lib, obj);
+	dbg_print(lml, MSG_INTL(MSG_AUD_PREINIT), lib, obj);
 }
 
 void
-Dbg_audit_symval(Lm_list *lml, const char *lib, const char *func,
-    const char *sym, Addr pval, Addr nval)
+Dbg_audit_objsearch(Lm_list *lml, int call, const char *lib,
+    const char *oobj, uint_t flags, const char *nobj)
 {
-	char	mesg[100];
+	Conv_la_search_buf_t	la_search_buf;
+
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
+
+	if (call == DBG_AUD_CALL) {
+		Dbg_util_nl(lml, DBG_NL_STD);
+		dbg_print(lml, MSG_INTL(MSG_AUD_OBJSEARCH), lib, oobj,
+		    conv_la_search(flags, &la_search_buf));
+	} else {
+		if (nobj)
+			dbg_print(lml, MSG_INTL(MSG_AUD_OBJSEARCH_R), lib,
+			    oobj, nobj);
+		else
+			dbg_print(lml, MSG_INTL(MSG_AUD_OBJSEARCH_S), lib,
+			    oobj);
+	}
+}
+
+void
+Dbg_audit_objfilter(Lm_list *lml, int call, const char *lib,
+    const char *filter, const char *filtee, const char *ref)
+{
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
+
+	if (call == DBG_AUD_CALL) {
+		Dbg_util_nl(lml, DBG_NL_STD);
+		dbg_print(lml, MSG_INTL(MSG_AUD_OBJFILTER), lib, filter,
+		    filtee, ref);
+	} else
+		dbg_print(lml, MSG_INTL(MSG_AUD_OBJFILTER_R), lib, filter);
+}
+
+void
+Dbg_audit_objopen(Lm_list *lml, int call, const char *lib, const char *obj,
+    uint_t flags, Boolean ignore)
+{
+	Conv_la_bind_buf_t	la_bind_buf;
 
 	if (DBG_NOTCLASS(DBG_C_AUDITING))
 		return;
-	if (DBG_NOTDETAIL())
+
+	if (call == DBG_AUD_CALL) {
+		Dbg_util_nl(lml, DBG_NL_STD);
+		dbg_print(lml, MSG_INTL(MSG_AUD_OBJOPEN), lib, obj);
+	} else {
+		if (ignore)
+			dbg_print(lml, MSG_INTL(MSG_AUD_OBJOPEN_RI), lib, obj,
+			    conv_la_bind(flags, &la_bind_buf));
+		else
+			dbg_print(lml, MSG_INTL(MSG_AUD_OBJOPEN_R), lib, obj,
+			    conv_la_bind(flags, &la_bind_buf));
+	}
+}
+
+void
+Dbg_audit_objclose(Lm_list *lml, const char *lib, const char *obj)
+{
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_AUD_OBJCLOSE), lib, obj);
+}
+
+void
+Dbg_audit_symbind(Lm_list *lml, int call, const char *lib, const char *name,
+    Addr value, uint_t flags)
+{
+	Conv_la_symbind_buf_t	la_symbind_buf;
+
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
 		return;
 
-	if (pval == nval)
-		mesg[0] = '\0';
-	else
-		(void) sprintf(mesg, MSG_INTL(MSG_AUD_SYMNEW), EC_XWORD(nval));
+	if (call == DBG_AUD_CALL) {
+		Dbg_util_nl(lml, DBG_NL_STD);
+		dbg_print(lml, MSG_INTL(MSG_AUD_SYMBIND), lib, name,
+		    EC_XWORD(value), conv_la_symbind(flags, &la_symbind_buf));
+	} else {
+		dbg_print(lml, MSG_INTL(MSG_AUD_SYMBIND_R), lib, name,
+		    EC_XWORD(value), conv_la_symbind(flags, &la_symbind_buf));
+	}
+}
+
+void
+Dbg_audit_pltenter(Lm_list *lml, int call, const char *lib, const char *name,
+    Addr value)
+{
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
 
-	dbg_print(lml, MSG_INTL(MSG_AUD_SYM), lib, func, Dbg_demangle_name(sym),
-	    EC_XWORD(pval), mesg);
+	if (call == DBG_AUD_CALL) {
+		Dbg_util_nl(lml, DBG_NL_STD);
+		dbg_print(lml, MSG_INTL(MSG_AUD_PLTENTER), lib, name,
+		    EC_XWORD(value));
+	} else {
+		dbg_print(lml, MSG_INTL(MSG_AUD_PLTENTER_R), lib, name,
+		    EC_XWORD(value));
+	}
+}
+
+void
+Dbg_audit_pltexit(Lm_list *lml, const char *lib, const char *name)
+{
+	if (DBG_NOTCLASS(DBG_C_AUDITING))
+		return;
+
+	dbg_print(lml, MSG_INTL(MSG_AUD_PLTEXIT), lib, name);
 }
 
 void
@@ -103,7 +223,7 @@
 void
 Dbg_audit_terminate(Lm_list *lml, const char *name)
 {
-	if (DBG_NOTCLASS(DBG_C_AUDITING | DBG_C_FILES))
+	if (DBG_NOTCLASS(DBG_C_FILES))
 		return;
 
 	dbg_print(lml, MSG_INTL(MSG_AUD_TERM), name);
--- a/usr/src/cmd/sgs/liblddbg/common/files.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/liblddbg/common/files.c	Tue Jul 20 16:29:51 2010 -0700
@@ -441,23 +441,17 @@
 void
 Dbg_file_filtee(Lm_list *lml, const char *filter, const char *filtee, int audit)
 {
-	if (audit) {
-		if (DBG_NOTCLASS(DBG_C_AUDITING | DBG_C_FILES))
-			return;
+	if (DBG_NOTCLASS(DBG_C_FILES))
+		return;
 
-		Dbg_util_nl(lml, DBG_NL_STD);
+	Dbg_util_nl(lml, DBG_NL_STD);
+
+	if (audit)
 		dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_3), filtee);
-	} else {
-		if (DBG_NOTCLASS(DBG_C_FILES))
-			return;
-
-		Dbg_util_nl(lml, DBG_NL_STD);
-		if (filter)
-			dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_1), filtee,
-			    filter);
-		else
-			dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_2), filtee);
-	}
+	else if (filter)
+		dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_1), filtee, filter);
+	else
+		dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_2), filtee);
 }
 
 void
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Tue Jul 20 16:29:51 2010 -0700
@@ -660,7 +660,7 @@
 @ MSG_FIL_FILTER_1	"file=%s;  filter for %s  (configuration definition)"
 @ MSG_FIL_FILTER_2	"file=%s;  filter for %s"
 @ MSG_FIL_FILTEE_2	"file=%s;  filtee processing failed"
-@ MSG_FIL_FILTEE_3	"file=%s;  filtee skipped  (auditing directed)"
+@ MSG_FIL_FILTEE_3	"file=%s;  filtee skipped  (auditor directed)"
 @ MSG_FIL_FIXNAME	"file=%s;  required name=%s"
 @ MSG_FIL_PROMOTE	"file=%s;  promoting mode to %s"
 @ MSG_FIL_DEFERRED	"file=%s;  deferred dependency exchanged for file=%s"
@@ -772,8 +772,8 @@
 
 @ MSG_LIB_FIND		"find object=%s; searching"
 @ MSG_LIB_TRYING	" trying path=%s%s"
-@ MSG_LIB_ALTER		" trying path=%s  (auditing supplied alternative)"
-@ MSG_LIB_SKIP		"   skip path=%s  (auditing directed)"
+@ MSG_LIB_ALTER		" trying path=%s  (auditor returned alternative)"
+@ MSG_LIB_SKIP		"   skip path=%s  (auditor directed)"
 @ MSG_LIB_IGNORE	" ignore path=%s  (insecure directory name)"
 @ MSG_LIB_INUSE		"    use path=%s  (implicitly secure, as directory \
 			 has already provided dependencies)"
@@ -1043,17 +1043,36 @@
 
 # Link-Auditing Messages
 
-@ MSG_AUD_INIT		"audit library %s: processing"
-@ MSG_AUD_VERSION	"audit library %s: running at version: %d"
-@ MSG_AUD_INTERFACE	"audit library %s: provides interface: %s"
-@ MSG_AUD_OBJECT	"audit library %s: offered object: %s"
-@ MSG_AUD_SYM		"audit library %s: %s: symbol: %s: value: 0x%llx %s"
-@ MSG_AUD_SYMNEW	"modified to: 0x%llx"
+@ MSG_AUD_LIB		"auditor %s: required by: %s  %s"
+@ MSG_AUD_INTERFACE	"auditor %s: provides interface: %s"
+
+@ MSG_AUD_VERSION	"auditor %s: la_version(): %d: returned %d"
+@ MSG_AUD_ACTIVITY	"auditor %s: la_activity(): %s  %s"
+@ MSG_AUD_PREINIT	"auditor %s: la_preinit(): %s"
+@ MSG_AUD_OBJFILTER	"auditor %s: la_objfilter(): %s: filtee=%s  [ %s ]"
+@ MSG_AUD_OBJFILTER_R	"auditor %s: la_objfilter(): %s: returned 0  (filtee \
+			 ignored)"
+@ MSG_AUD_OBJOPEN	"auditor %s: la_objopen(): %s"
+@ MSG_AUD_OBJOPEN_R	"auditor %s: la_objopen(): %s: returned %s"
+@ MSG_AUD_OBJOPEN_RI	"auditor %s: la_objopen(): %s: returned %s  (flags \
+			 ignored)"
+@ MSG_AUD_OBJSEARCH	"auditor %s: la_objsearch(): %s  %s"
+@ MSG_AUD_OBJSEARCH_R	"auditor %s: la_objsearch(): %s: alternative path \
+			 returned: %s"
+@ MSG_AUD_OBJSEARCH_S	"auditor %s: la_objsearch(): %s: alternative path \
+			 returned: 0  (path skipped)"
+@ MSG_AUD_OBJCLOSE	"auditor %s: la_objclose(): %s"
+@ MSG_AUD_SYMBIND	"auditor %s: la_symbind(): %s: value: 0x%llx  %s"
+@ MSG_AUD_SYMBIND_R	"auditor %s: la_symbind(): %s: returned value: \
+			 0x%llx  %s"
+@ MSG_AUD_PLTENTER	"auditor %s: la_pltenter(): %s: value: 0x%llx"
+@ MSG_AUD_PLTENTER_R	"auditor %s: la_pltenter(): %s: returned value: 0x%llx"
+@ MSG_AUD_PLTEXIT	"auditor %s: la_pltexit(): %s"
 
 @ MSG_AUD_IGNORE	"file=%s;  global auditing request ignored: object \
 			 did not initiate process" 
 @ MSG_AUD_SKIP		"file=%s;  skipped: using auditor from %s"
-@ MSG_AUD_TERM		"file=%s;  auditing terminated search"
+@ MSG_AUD_TERM		"file=%s;  auditor has indicated path should be skipped"
 
 # GOT Messages
 
@@ -1744,3 +1763,8 @@
 @ MSG_MR_PADDING	"[ PADDING ]"
 @ MSG_MR_HDR_ELF	"[ HDR_ELF ]"
 @ MSG_MR_HDR_AOUT	"[ HDR_AOUT ]"
+
+# audit originator
+
+@ MSG_AUD_PRELOAD	"[ LD_AUDIT ]"
+@ MSG_AUD_GLOBAL	"[ GLOBAL AUDIT ]"
--- a/usr/src/cmd/sgs/liblddbg/common/libs.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/liblddbg/common/libs.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 #include	"msg.h"
 #include	"_debug.h"
@@ -30,12 +29,13 @@
 void
 Dbg_libs_audit(Lm_list *lml, const char *opath, const char *npath)
 {
-	if (DBG_NOTCLASS(DBG_C_LIBS | DBG_C_AUDITING))
+	if (DBG_NOTCLASS(DBG_C_LIBS))
 		return;
 
 	if (npath == opath)
 		return;
-	else if (npath == 0)
+
+	if (npath == NULL)
 		dbg_print(lml, MSG_INTL(MSG_LIB_SKIP), opath);
 	else
 		dbg_print(lml, MSG_INTL(MSG_LIB_ALTER), npath);
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Jul 20 16:29:51 2010 -0700
@@ -15,7 +15,7 @@
  * If applicable, add the following below this CDDL HEADER, with the
  * fields enclosed by brackets "[]" replaced with your own identifying
  * information: Portions Copyright [yyyy] [name of copyright owner]
-
+ *
  * CDDL HEADER END
  */
 /* LINTLIBRARY */
@@ -39,15 +39,25 @@
 void	Dbg_args_option(Lm_list *, int, int, char *);
 void	Dbg_args_str2chr(Lm_list *, int, const char *, int);
 void	Dbg_args_Wldel(Lm_list *, int, const char *);
+void	Dbg_audit_activity(Lm_list *, const char *, const char *, uint_t);
 void	Dbg_audit_ignore(Rt_map *);
 void	Dbg_audit_interface(Lm_list *, const char *, const char *);
-void	Dbg_audit_lib(Lm_list *, const char *);
-void	Dbg_audit_object(Lm_list *, const char *, const char *);
-void	Dbg_audit_symval(Lm_list *, const char *, const char *, const char *,
-	    Addr, Addr);
+void	Dbg_audit_lib(Rt_map *, const char *, int);
+void	Dbg_audit_objclose(Lm_list *, const char *, const char *);
+void	Dbg_audit_objfilter(Lm_list *, int, const char *, const char *,
+	    const char *, const char *);
+void	Dbg_audit_objopen(Lm_list *, int, const char *, const char *, uint_t,
+	    Boolean);
+void	Dbg_audit_objsearch(Lm_list *, int, const char *, const char *, uint_t,
+	    const char *);
+void	Dbg_audit_pltenter(Lm_list *, int, const char *, const char *, Addr);
+void	Dbg_audit_pltexit(Lm_list *, const char *, const char *);
+void	Dbg_audit_preinit(Lm_list *, const char *, const char *);
+void	Dbg_audit_symbind(Lm_list *, int, const char *, const char *,
+	    Addr, uint_t);
 void	Dbg_audit_skip(Lm_list *, const char *, const char *);
 void	Dbg_audit_terminate(Lm_list *, const char *);
-void	Dbg_audit_version(Lm_list *, const char *, ulong_t);
+void	Dbg_audit_version(Lm_list *, const char *, uint_t, uint_t);
 
 void	Dbg_basic_collect(Lm_list *);
 void	Dbg_basic_create(Lm_list *);
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Tue Jul 20 16:29:51 2010 -0700
@@ -42,7 +42,7 @@
 
 $mapfile_version 2
 
-SYMBOL_VERSION SUNWprivate_4.81 {
+SYMBOL_VERSION SUNWprivate_4.82 {
 	global:
 		dbg_desc {	# interposed - ld.so.1(1)
 			FLAGS = NODIRECT;
@@ -55,11 +55,18 @@
 		Dbg_args_option;
 		Dbg_args_str2chr;
 		Dbg_args_Wldel;
+		Dbg_audit_activity;
 		Dbg_audit_ignore;
 		Dbg_audit_interface;
 		Dbg_audit_lib;
-		Dbg_audit_object;
-		Dbg_audit_symval;
+		Dbg_audit_objclose;
+		Dbg_audit_objfilter;
+		Dbg_audit_objopen;
+		Dbg_audit_objsearch;
+		Dbg_audit_pltenter;
+		Dbg_audit_pltexit;
+		Dbg_audit_preinit;
+		Dbg_audit_symbind;
 		Dbg_audit_skip;
 		Dbg_audit_terminate;
 		Dbg_audit_version;
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Jul 20 16:29:51 2010 -0700
@@ -1286,9 +1286,9 @@
 	Solaris/SunOS 5.10_x86		patch T141445-06
 --------------------------------------------------------------------------------
 
--------------------------------------
-Solaris 10 XXXX (9th Q-update - s10u9)
--------------------------------------
+--------------------------------------
+Solaris 10 1005 (9th Q-update - s10u9)
+--------------------------------------
 Bugid   Risk Synopsis
 ================================================================================
 6850124 dlopen reports "No such file or directory" in spite of ENOMEM
@@ -1303,6 +1303,19 @@
 	Solaris/SunOS 5.10_x86		patch T143896-01
 --------------------------------------------------------------------------------
 
+----------------------------------------
+Solaris 10 XXXX (10th Q-update - s10u10)
+----------------------------------------
+Bugid   Risk Synopsis
+================================================================================
+6478684 isainfo/cpuid reports pause instruction not supported on amd64
+	PSARC/2010/089 Removal of AV_386_PAUSE and AV_386_MON
+--------------------------------------------------------------------------------
+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 Nevada (OpenSolaris 2008.05, snv_86)
 --------------------------------------------
@@ -1575,8 +1588,6 @@
 6918143 symbol capabilities (D)
 	PSARC/2010/022 Linker-editors: Symbol Capabilities
 6910387 .tdata and .tbss separation invalidates TLS program header information
-6478684 isainfo/cpuid reports pause instruction not supported on amd64
-	PSARC/2010/089 Removal of AV_386_PAUSE and AV_386_MON
 6934123 elfdump -d coredumps on PA-RISC elf
 6931044 ld should not allow SHT_PROGBITS .eh_frame sections on amd64 (D)
 6931056 pvs -r output can include empty versions in output
@@ -1603,3 +1614,5 @@
 	capabilities - gcc failure (link-editor components only)
 6952219 ld support for archives larger than 2 GB (D, P)
 	PSARC/2010/224 Support for archives larger than 2 GB
+6956152 dlclose() from an auditor can be fatal. Preinit/activity events should
+	be more flexible. (D)
--- a/usr/src/cmd/sgs/rtld/common/_a.out.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/_a.out.h	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 #ifndef	_A_DOT_OUT_DOT_H
 #define	_A_DOT_OUT_DOT_H
@@ -46,7 +45,7 @@
 extern	int	aout_get_mmap(Lm_list *, mmapobj_result_t *);
 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 *);
+		    Rt_map *, int *);
 extern	void	aout_plt_write(caddr_t, ulong_t);
 extern	int	aout_reloc(Rt_map *, uint_t, int *, APlist **);
 extern	void	aout_rtbndr(caddr_t);
--- a/usr/src/cmd/sgs/rtld/common/_audit.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/_audit.h	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	__AUDIT_DOT_H
@@ -39,13 +38,28 @@
 /*
  * Define all auditing structures.
  *
- * A shared object may be a client of an audit library, in which case the
- * identify of the shared object is passed to the auditor using a cookie.
+ * A shared object may be a client of one or more audit libraries.  Calls to an
+ * auditor are accompanied with cookies that identify an object being audited.
+ * These cookies are initialized to the link-map pointers of the object being
+ * audited, however the auditor is free to re-allocate these cookies, and thus
+ * associate their own data with each object being audited.
+ *
+ * With auditing version LAV_VERSION5, local auditors can provide la_preinit()
+ * and la_activity() routines, each of which should be passed a cookie that
+ * represents the link-map of the head of the associated link-map list.  These
+ * cookies are maintained on the associated link-map list, using the lm_cookies
+ * alist.  These cookies are created by _audit_add_head(), and dynamically
+ * retrieved by the _audit_preinit() and _audit_activity() routines.
+ *
+ * Having these cookies kept on the link-map list decouples these cookies from
+ * the Audit_client structure of the object being locally audited.  In addition,
+ * this model ensures that multiple objects, undergoing local auditing from the
+ * same auditor, receive the same head link-map cookie.
  */
 typedef struct {
 	Rt_map		*ac_lmp;	/* audit library identifier */
 	uintptr_t	ac_cookie;	/* cookie assigned to audit library */
-	Word		ac_flags;	/*	and its associated flags */
+	Word		ac_flags;	/*    and its associated flags */
 } Audit_client;
 
 #define	FLG_AC_BINDTO	0x00001
@@ -70,7 +84,8 @@
 	char		*ad_name;	/* originating audit names */
 	APlist		*ad_list;	/* audit objs Audit Interface list */
 	uint_t		ad_cnt;		/* no. of audit objs in this desc. */
-	uint_t		ad_flags;	/* audit capabilities found */
+	uint_t		ad_flags;	/* audit capabilities found.  See */
+					/*    LML_TFLG_AUD_* flags */
 };
 
 /*
--- a/usr/src/cmd/sgs/rtld/common/_elf.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/_elf.h	Tue Jul 20 16:29:51 2010 -0700
@@ -58,10 +58,10 @@
 		    int *);
 extern	int	elf_mach_flags_check(Rej_desc *, Ehdr *);
 extern	Rt_map	*elf_new_lmp(Lm_list *, Aliste, Fdesc *, Addr, size_t, void *,
-		    int *);
-extern	Rt_map	*elf_obj_file(Lm_list *, Aliste, const char *,
+		    Rt_map *, int *);
+extern	Rt_map	*elf_obj_file(Lm_list *, Aliste, Rt_map *, const char *,
 		    mmapobj_result_t *, mmapobj_result_t *, uint_t);
-extern	Rt_map	*elf_obj_fini(Lm_list *, Rt_map *, int *);
+extern	Rt_map	*elf_obj_fini(Lm_list *, Rt_map *, Rt_map *, int *);
 extern	void	elf_plt_init(void *, caddr_t);
 #if	defined(__sparcv9)
 extern	void	elf_plt2_init(uint_t *, Rt_map *);
--- a/usr/src/cmd/sgs/rtld/common/_rtld.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/_rtld.h	Tue Jul 20 16:29:51 2010 -0700
@@ -75,7 +75,7 @@
 
 	/* Generate a link-map to describe the loaded object. */
 	Rt_map	*(*fct_new_lmp)(Lm_list *, Aliste, Fdesc *, Addr, size_t,
-	    void *, int *);
+	    void *, Rt_map *, int *);
 
 	/* Retrieve the entry point of the object. */
 	Addr	(*fct_entry_pt)(void);
@@ -162,6 +162,7 @@
 #define	AL_CNT_PLTPAD	10		/* plt padding */
 #define	AL_CNT_AUDITORS	2		/* auditing list */
 #define	AL_CNT_ENVIRON	20		/* environment list (enough for ldd) */
+#define	AL_CNT_COOKIES	2		/* head link-map list cookies */
 
 /*
  * Size of buffer for building error messages.
@@ -276,7 +277,7 @@
 #define	RT_FL_NOBIND	0x00000010	/* don't carry out plt binding */
 #define	RT_FL_NOVERSION	0x00000020	/* disable version checking */
 #define	RT_FL_SECURE	0x00000040	/* setuid/segid flag */
-#define	RT_FL_APPLIC	0x00000080	/* are we executing user code */
+#define	RT_FL_APPLIC	0x00000080	/* executing application code */
 #define	RT_FL_NOENVIRON	0x00000100	/* don't process environment */
 					/*	variables (ld.so.1 -e) */
 #define	RT_FL_CONFGEN	0x00000200	/* don't relocate initiating object */
@@ -519,6 +520,24 @@
 #endif
 
 /*
+ * Error messages generated by ld.so.1 can be written to two different places.
+ * During initial startup, messages are flushed to the stderr.  Once ld.so.1
+ * has jumped to the application, messages are stored in an internal buffer for
+ * retrieval by dlerror().  Between these two conditions, events such as libc's
+ * callbacks, and calls to auditors, are effectively jumping to application
+ * code.  These transitions from application code to ld.so.1 code are guarded by
+ * the following macros to ensure any error messages are directed to the
+ * appropriate output.  The single argument, "f", is a local variable that
+ * can retain, and reinstate, the RT_FL_APPLIC flag of the global rtld_flags
+ * variable.
+ */
+#define	APPLICATION_ENTER(f) \
+	f = (rtld_flags & RT_FL_APPLIC) ? 0 : RT_FL_APPLIC; \
+	rtld_flags |= f;
+#define	APPLICATION_RETURN(f) \
+	rtld_flags &= ~f;
+
+/*
  * Data declarations.
  */
 extern Lc_desc		glcs[];		/* global external interfaces */
@@ -587,6 +606,8 @@
 
 extern uint_t		audit_argcnt;	/* no. of stack args to copy */
 extern Audit_desc	*auditors;	/* global auditors */
+extern APlist		*aud_preinit;	/* list of objects defining local */
+extern APlist		*aud_activity;	/*    preinit and activity auditors */
 
 extern char		**_environ;	/* environ reference for libc */
 
@@ -636,12 +657,13 @@
  */
 extern void		addfree(void *, size_t);
 extern int		append_alias(Rt_map *, const char *, int *);
-extern Rt_map		*analyze_lmc(Lm_list *, Aliste, Rt_map *, int *);
+extern Rt_map		*analyze_lmc(Lm_list *, Aliste, Rt_map *, Rt_map *,
+			    int *);
 extern void		atexit_fini(void);
 extern int		bind_one(Rt_map *, Rt_map *, uint_t);
 extern int		bufprint(Prfbuf *, const char *, ...);
 extern void		call_array(Addr *, uint_t, Rt_map *, Word);
-extern void		call_fini(Lm_list *, Rt_map **);
+extern void		call_fini(Lm_list *, Rt_map **, Rt_map *);
 extern void		call_init(Rt_map **, int);
 extern int		callable(Rt_map *, Rt_map *, Grp_hdl *, uint_t);
 extern Rt_map		*_caller(caddr_t, int);
@@ -651,7 +673,8 @@
 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 *);
+			    Rt_map *, 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);
@@ -700,13 +723,13 @@
 extern void		ldso_plt_init(Rt_map *);
 extern void		leave(Lm_list *, int);
 extern void		lm_append(Lm_list *, Aliste, Rt_map *);
-extern void		lm_delete(Lm_list *, Rt_map *);
+extern void		lm_delete(Lm_list *, Rt_map *, 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_file(Lm_list *, Aliste, Rt_map *, Fdesc *, 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,
@@ -732,12 +755,12 @@
 extern int		relocate_lmc(Lm_list *, Aliste, Rt_map *, Rt_map *,
 			    int *);
 extern int		relocate_finish(Rt_map *, APlist *, int);
+extern void		remove_alist(Alist **, int);
 extern void		remove_cntl(Lm_list *, Aliste);
 extern int		remove_hdl(Grp_hdl *, Rt_map *, int *);
 extern void		remove_lmc(Lm_list *, Rt_map *, Aliste, const char *);
 extern void		remove_lml(Lm_list *);
-extern void		remove_plist(Alist **, int);
-extern void		remove_so(Lm_list *, Rt_map *);
+extern void		remove_so(Lm_list *, Rt_map *, Rt_map *);
 extern int		rt_cond_wait(Rt_cond *, Rt_lock *);
 extern int		rt_critical(void);
 extern int		rt_bind_guard(int);
--- a/usr/src/cmd/sgs/rtld/common/a.out.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/a.out.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -282,7 +281,7 @@
 
 		nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp), 0, 0,
 		    in_nfavl);
-		remove_plist(&palp, 1);
+		remove_alist(&palp, 1);
 		if (((nlmp == 0) || (bind_one(clmp, nlmp, BND_NEEDED) == 0)) &&
 		    ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0))
 			return (0);
@@ -503,7 +502,7 @@
 /* ARGSUSED6 */
 Rt_map *
 aout_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize,
-    void *odyn, int *in_nfavl)
+    void *odyn, Rt_map *clmp, int *in_nfavl)
 {
 	const char	*name = fdp->fd_nname;
 	Rt_map		*lmp;
--- a/usr/src/cmd/sgs/rtld/common/analyze.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/analyze.c	Tue Jul 20 16:29:51 2010 -0700
@@ -102,7 +102,8 @@
  * Return the initial link-map from which analysis starts for relocate_lmc().
  */
 Rt_map *
-analyze_lmc(Lm_list *lml, Aliste nlmco, Rt_map *nlmp, int *in_nfavl)
+analyze_lmc(Lm_list *lml, Aliste nlmco, Rt_map *nlmp, Rt_map *clmp,
+    int *in_nfavl)
 {
 	Rt_map	*lmp;
 	Lm_cntl	*nlmc;
@@ -148,7 +149,8 @@
 		if (FLAGS(lmp) & FLG_RT_OBJECT) {
 			Rt_map	*olmp;
 
-			if ((olmp = elf_obj_fini(lml, lmp, in_nfavl)) == NULL) {
+			if ((olmp = elf_obj_fini(lml, lmp, clmp,
+			    in_nfavl)) == NULL) {
 				if (lml->lm_flags & LML_FLG_TRC_ENABLE)
 					continue;
 				nlmp = NULL;
@@ -1759,7 +1761,7 @@
  * process the various names by which it can be referenced.
  */
 Rt_map *
-load_file(Lm_list *lml, Aliste lmco, Fdesc *fdp, int *in_nfavl)
+load_file(Lm_list *lml, Aliste lmco, Rt_map *clmp, Fdesc *fdp, int *in_nfavl)
 {
 	mmapobj_result_t	*fpmpp = NULL, *fmpp = NULL, *lpmpp, *lmpp;
 	mmapobj_result_t	*hmpp, *mpp, *ompp = fdp->fd_mapp;
@@ -1809,7 +1811,7 @@
 	 * processing is finished with elf_obj_fini().
 	 */
 	if (ehdr && (ehdr->e_type == ET_REL)) {
-		if ((nlmp = elf_obj_file(lml, lmco, nname, hmpp, ompp,
+		if ((nlmp = elf_obj_file(lml, lmco, clmp, nname, hmpp, ompp,
 		    omapnum)) == NULL)
 			return (nlmp);
 	} else {
@@ -1829,7 +1831,7 @@
 		msize = lmpp->mr_addr + lmpp->mr_msize - fmpp->mr_addr;
 
 		if ((nlmp = ((fdp->fd_ftp)->fct_new_lmp)(lml, lmco, fdp, addr,
-		    msize, NULL, in_nfavl)) == NULL)
+		    msize, NULL, clmp, in_nfavl)) == NULL)
 			return (NULL);
 
 		/*
@@ -1864,12 +1866,12 @@
 
 	if ((NAME(nlmp)[0] == '/') && (fpavl_insert(lml, nlmp, NAME(nlmp),
 	    fdp->fd_avlwhere) == 0)) {
-		remove_so(lml, nlmp);
+		remove_so(lml, nlmp, clmp);
 		return (NULL);
 	}
 	if (((NAME(nlmp)[0] != '/') || (NAME(nlmp) != PATHNAME(nlmp))) &&
 	    (fpavl_insert(lml, nlmp, PATHNAME(nlmp), 0) == 0)) {
-		remove_so(lml, nlmp);
+		remove_so(lml, nlmp, clmp);
 		return (NULL);
 	}
 
@@ -1916,7 +1918,7 @@
 			olen = strlen(odir) + 1;
 		}
 		if ((ndir = stravl_insert(odir, 0, olen, 1)) == NULL) {
-			remove_so(lml, nlmp);
+			remove_so(lml, nlmp, clmp);
 			return (NULL);
 		}
 		ORIGNAME(nlmp) = ndir;
@@ -2016,8 +2018,6 @@
 		Word		strhash = 0;
 		int		found = 0;
 
-		DBG_CALL(Dbg_libs_find(lml, oname));
-
 		/*
 		 * Traverse the search path lists, creating full pathnames and
 		 * attempt to load each path.
@@ -2098,7 +2098,7 @@
 	/*
 	 * Finish mapping the file and return the link-map descriptor.
 	 */
-	return (load_file(lml, lmco, fdp, in_nfavl));
+	return (load_file(lml, lmco, clmp, fdp, in_nfavl));
 }
 
 /*
@@ -2109,6 +2109,8 @@
 {
 	const char	*name = pdp->pd_pname;
 
+	DBG_CALL(Dbg_libs_find(lml, name));
+
 	/*
 	 * First generate any ldd(1) diagnostics.
 	 */
@@ -2123,11 +2125,11 @@
 		fdp->fd_flags |= FLG_FD_SLASH;
 
 	/*
-	 * If we're being audited tell the audit library of the file we're
+	 * If we're being audited tell any audit libraries of the file we're
 	 * about to go search for.
 	 */
-	if (((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_ACTIVITY) &&
-	    (lml == LIST(clmp)))
+	if (aud_activity ||
+	    ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_ACTIVITY))
 		audit_activity(clmp, LA_ACT_ADD);
 
 	if ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_OBJSEARCH) {
@@ -2406,7 +2408,7 @@
 
 /*
  * The central routine for loading shared objects.  Insures ldd() diagnostics,
- * handles and any other related additions are all done in one place.
+ * handle creation, and any other related additions are all done in one place.
  */
 Rt_map *
 load_path(Lm_list *lml, Aliste lmco, Rt_map *clmp, int nmode, uint_t flags,
@@ -2457,7 +2459,7 @@
 			_rej.rej_str = MSG_INTL(MSG_GEN_NOOPEN);
 			DBG_CALL(Dbg_file_rejected(lml, &_rej, M_MACH));
 			rejection_inherit(rej, &_rej);
-			remove_so(lml, nlmp);
+			remove_so(lml, nlmp, clmp);
 			return (NULL);
 		}
 	} else {
@@ -2507,24 +2509,23 @@
 		 * torn down.
 		 */
 		if ((FLAGS(nlmp) & FLG_RT_ANALYZED) == 0)
-			remove_so(lml, nlmp);
+			remove_so(lml, nlmp, clmp);
 		return (NULL);
 	}
 
 	/*
 	 * If this object is new, and we're being audited, tell the audit
-	 * library of the file we've just opened.  Note, if the new link-map
+	 * libraries of the file we've just opened.  Note, if the new link-map
 	 * requires local auditing of its dependencies we also register its
 	 * opening.
 	 */
 	if (FLAGS(nlmp) & FLG_RT_NEWLOAD) {
 		FLAGS(nlmp) &= ~FLG_RT_NEWLOAD;
 
-		if (((lml->lm_tflags | AFLAGS(clmp) | AFLAGS(nlmp)) &
-		    LML_TFLG_AUD_MASK) && (((lml->lm_flags |
-		    LIST(clmp)->lm_flags) & LML_FLG_NOAUDIT) == 0)) {
+		if ((lml->lm_tflags | AFLAGS(clmp) | AFLAGS(nlmp)) &
+		    LML_TFLG_AUD_MASK) {
 			if (audit_objopen(clmp, nlmp) == 0) {
-				remove_so(lml, nlmp);
+				remove_so(lml, nlmp, clmp);
 				return (NULL);
 			}
 		}
--- a/usr/src/cmd/sgs/rtld/common/audit.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/audit.c	Tue Jul 20 16:29:51 2010 -0700
@@ -24,9 +24,9 @@
  *
  * Audit interfaces.  Auditing can be enabled in two ways:
  *
- *	o	Using the LD_AUDIT environment variable
+ *  -	Using the LD_AUDIT environment variable
  *
- *	o	From individual objects containing a DT_DEPAUDIT entry
+ *  -	From individual objects containing a DT_DEPAUDIT entry
  *		(see ld(1) -P/-p options).
  *
  * The former establishes a global set of audit libraries which can inspect all
@@ -39,11 +39,61 @@
  * flags can occur in different data items they are defined as one to simplify
  * audit interface requirements.  The basic test for all audit interfaces is:
  *
- *    if (((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK) &&
- *	(lml == LIST(lmp)))
+ *    if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK)
+ *
+ * Note.  Auditors themselves are identified with the LML_TFLG_NOAUDIT link-map
+ * list flag, and no LML_TFLG_AUD_MASK flags.  These flags get propagated from
+ * a callers link-map list to any new link-map lists created.  Thus, standard
+ * link-maps lists have the LML_TFLG_AUD_MASK flags propagated, and should a
+ * new link-map list be created by an auditor, that list gets tagged as
+ * LML_TFLG_NOAUDIT.
  *
  * The latter link-map list equivalence test insures that auditors themselves
  * (invoked through DT_DEPAUDIT) are not audited.
+ *
+ * The history of version changes:
+ *
+ * LAV_VERSION1 (Solaris 2.6)
+ *	Auditing implementation added.
+ *
+ * LAV_VERSION2 (Solaris 2.6)
+ *	LA_SYMB_ALTVALUE support added.
+ *
+ * LAV_VERSION3 (Solaris 9 update 7)
+ *	ld_objfilter() added.
+ *
+ * LAV_VERSION4 (Solaris 10 update 5)
+ *	Correction of activity calls for local auditors, and introduction of
+ *	-z globalaudit concept.
+ *
+ * LAV_VERSION5 (Solaris 11)
+ *	Under this version, preinit and activity events are enabled from local
+ *	auditors.  The la_preinit and la_activity interfaces require a cookie
+ *	that represents the head of the link-map list being audited.  If a
+ *	local preinit or activity interface is detected, the local auditors
+ *	la_objopen() routine is called with a cookie that represents the object
+ *	that heads the link-map list of the object being audited.
+ *
+ *	A local auditor is loaded through adding a new dependency that requests
+ *	auditing, and therefore an la_activity(ADD) event is already in effect.
+ *	Regardless, the local auditors la_activity() routine is called with the
+ *	cookie that represents the object that heads the link-map list of the
+ *	object being audited.
+ *
+ *	A local auditor can be loaded prior to the preinit event.  In this case,
+ *	the local auditors la_preinit() routine is called with the cookie that
+ *	represents the object that heads the link-map list of the object being
+ *	audited.  After the preinit event, any la_preinit() routine within a
+ *	local auditor will not be called.
+ *
+ *	These events are intended to follow the expected sequence of events
+ *	received by global auditors, ie:
+ *
+ *	  -	la_objopen(main)
+ *	  -	la_activity(ADD)
+ *	  -	la_objopen(dependency)
+ *	  -	la_activity(CONSISTENT)
+ *	  -	la_preinit(main)
  */
 
 #include	<stdio.h>
@@ -62,6 +112,63 @@
 uint_t	audit_flags = 0;		/* Copy of specific audit flags to */
 					/* simplify boot_elf.s access. */
 
+/*
+ * Obtain a head link-map cookie.  Local auditors can provide la_preinit() and
+ * la_activity() routines, and these routines require a cookie that represents
+ * the object that heads the link-map of the object being audited.  A list of
+ * these cookies is maintained on the link-map list.  This list allows multiple
+ * local objects to specify the same auditor, and to obtain the same cookie
+ * for the link-map that heads the link-map list.
+ *
+ * The initial cookie is created by _audit_create_head_client() which is called
+ * from _audit_add_head().  This cookies address is then passed to the local
+ * auditors ld_objopen() and la_activity() routines.  Subsequent preinit and
+ * activity events use _audit_get_head_client() to dynamically retrieve the
+ * cookies address.
+ */
+static Audit_client *
+_audit_get_head_client(Rt_map *hlmp, Rt_map *almp)
+{
+	Audit_client	*acp;
+	Aliste		idx;
+	Lm_list		*hlml = LIST(hlmp);
+
+	for (ALIST_TRAVERSE(hlml->lm_aud_cookies, idx, acp)) {
+		if (acp->ac_lmp == almp)
+			return (acp);
+	}
+	return (NULL);
+}
+
+static Audit_client *
+_audit_create_head_client(Rt_map *hlmp, Rt_map *almp)
+{
+	Audit_client	ac, *acp;
+	Lm_list		*hlml = LIST(hlmp);
+
+	ac.ac_lmp = almp;
+	ac.ac_cookie = (uintptr_t)hlmp;
+	ac.ac_flags = 0;
+
+	if ((acp = alist_append(&(hlml->lm_aud_cookies), &ac,
+	    sizeof (Audit_client), AL_CNT_COOKIES)) == NULL)
+		return (NULL);
+
+	return (acp);
+}
+
+/*
+ * Determine the appropriate client.  Each client structure identifies the
+ * link-map of the auditor it is associated with.  From the client structure,
+ * the address of the associated cookie, that represents the object being
+ * audited, is retrieved so that the address can be passed to any audit call.
+ *
+ * Note, objects that are being locally audited, can provide la_preinit() and
+ * la_activity() routines.  These routines must be passed cookies that represent
+ * the object that heads the link-map list of the object being audited.  These
+ * cookies are not maintained on this objects Audit_client structure, but are
+ * obtained from the associated link-map lists lm_cookies alist.
+ */
 static Audit_client *
 _audit_client(Audit_info *aip, Rt_map *almp)
 {
@@ -88,26 +195,34 @@
 {
 	Audit_list	*alp;
 	Aliste		idx;
+	Lm_list		*frlml = LIST(frlmp);
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*fracp, *feacp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
 		int		ret;
 
 		if (alp->al_objfilter == NULL)
 			continue;
-		if ((fracp = _audit_client(AUDINFO(frlmp),
-		    alp->al_lmp)) == NULL)
+		if ((fracp = _audit_client(AUDINFO(frlmp), almp)) == NULL)
 			continue;
-		if ((feacp = _audit_client(AUDINFO(felmp),
-		    alp->al_lmp)) == NULL)
+		if ((feacp = _audit_client(AUDINFO(felmp), almp)) == NULL)
 			continue;
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		DBG_CALL(Dbg_audit_objfilter(frlml, DBG_AUD_CALL,
+		    alp->al_libname, NAME(frlmp), NAME(felmp), ref));
+
+		leave(alml, thr_flg_reenter);
 		ret = (*alp->al_objfilter)(&(fracp->ac_cookie), ref,
 		    &(feacp->ac_cookie), flags);
 		(void) enter(thr_flg_reenter);
-		if (ret == 0)
+
+		if (ret == 0) {
+			DBG_CALL(Dbg_audit_objfilter(frlml, DBG_AUD_RET,
+			    alp->al_libname, NAME(frlmp), NULL, NULL));
 			return (0);
+		}
 	}
 	return (1);
 }
@@ -115,13 +230,13 @@
 int
 audit_objfilter(Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags)
 {
-	int	appl = 0, respond = 1;
+	uint_t	rtldflags;
+	int	respond = 1;
 
 	if (rt_critical())
 		return (respond);
 
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJFILTER))
 		respond = _audit_objfilter(auditors->ad_list, frlmp,
@@ -131,8 +246,7 @@
 		respond = _audit_objfilter(AUDITORS(frlmp)->ad_list, frlmp,
 		    ref, felmp, flags);
 
-	if (appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	APPLICATION_RETURN(rtldflags);
 
 	return (respond);
 }
@@ -146,40 +260,57 @@
  * terminates the search.
  */
 static char *
-_audit_objsearch(APlist *list, char *name, Rt_map *clmp, uint_t flags)
+_audit_objsearch(APlist *list, char *oname, Rt_map *clmp, uint_t flags)
 {
 	Audit_list	*alp;
 	Aliste		idx;
-	char		*nname = (char *)name;
+	Lm_list		*clml = LIST(clmp);
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*acp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
+		char		*nname = oname;
 
 		if (alp->al_objsearch == NULL)
 			continue;
-		if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == NULL)
+		if ((acp = _audit_client(AUDINFO(clmp), almp)) == NULL)
 			continue;
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		DBG_CALL(Dbg_audit_objsearch(clml, DBG_AUD_CALL,
+		    alp->al_libname, nname, flags, NULL));
+
+		leave(alml, thr_flg_reenter);
 		nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags);
 		(void) enter(thr_flg_reenter);
-		if (nname == NULL)
+
+		/*
+		 * Diagnose any return name that differs from the original name
+		 * passed to the auditor.
+		 */
+		if (nname && (nname[0] == '\0'))
+			nname = NULL;
+		if ((nname != oname) || strcmp(nname, oname))
+			DBG_CALL(Dbg_audit_objsearch(clml, DBG_AUD_RET,
+			    alp->al_libname, oname, flags, nname));
+
+		if ((oname = nname) == NULL)
 			break;
+
 	}
-	return (nname);
+	return (oname);
 }
 
 char *
 audit_objsearch(Rt_map *clmp, const char *name, uint_t flags)
 {
 	char	*nname = (char *)name;
-	int	appl = 0;
+	uint_t	rtldflags;
 
 	if (rt_critical())
 		return (nname);
 
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJSEARCH))
 		nname = _audit_objsearch(auditors->ad_list, nname,
@@ -189,8 +320,7 @@
 		nname = _audit_objsearch(AUDITORS(clmp)->ad_list, nname,
 		    clmp, flags);
 
-	if (appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	APPLICATION_RETURN(rtldflags);
 
 	DBG_CALL(Dbg_libs_audit(LIST(clmp), name, nname));
 	return (nname);
@@ -201,7 +331,7 @@
  * la_activity() entry points found.
  */
 static void
-_audit_activity(APlist *list, Rt_map *clmp, uint_t flags)
+_audit_activity(APlist *list, Rt_map *clmp, uint_t flags, Boolean client)
 {
 	Audit_list	*alp;
 	Aliste		idx;
@@ -211,11 +341,25 @@
 		Audit_client	*acp;
 		Rt_map		*almp = alp->al_lmp;
 		Lm_list		*alml = LIST(almp);
+		uintptr_t	*cookie;
 
 		if (alp->al_activity == 0)
 			continue;
-		if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == NULL)
+
+		/*
+		 * Determine what cookie is required.  Any auditing that
+		 * originates from the object that heads the link-map list has
+		 * its own cookie.  Local auditors must obtain the cookie that
+		 * represents the object that heads the link-map list.
+		 */
+		if (client)
+			acp = _audit_client(AUDINFO(clmp), almp);
+		else
+			acp = _audit_get_head_client(clml->lm_head, almp);
+
+		if (acp == NULL)
 			continue;
+		cookie = &(acp->ac_cookie);
 
 		/*
 		 * Make sure the audit library only sees one addition/deletion
@@ -226,16 +370,11 @@
 		 * ld.so.1.
 		 */
 		if ((flags == LA_ACT_ADD) || (flags == LA_ACT_DELETE)) {
-
 			if (alml->lm_flags & LML_FLG_AUDITNOTIFY)
 				continue;
 
-			if (aplist_append(&clml->lm_actaudit, clmp,
-			    AL_CNT_ACTAUDIT) == NULL)
-				return;
-
 			alml->lm_flags |= LML_FLG_AUDITNOTIFY;
-
+			clml->lm_flags |= LML_FLG_ACTAUDIT;
 		} else {
 			if ((alml->lm_flags & LML_FLG_AUDITNOTIFY) == 0)
 				continue;
@@ -243,8 +382,11 @@
 			alml->lm_flags &= ~LML_FLG_AUDITNOTIFY;
 		}
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
-		(*alp->al_activity)(&(acp->ac_cookie), flags);
+		DBG_CALL(Dbg_audit_activity(clml, alp->al_libname,
+		    NAME(clml->lm_head), flags));
+
+		leave(alml, thr_flg_reenter);
+		(*alp->al_activity)(cookie, flags);
 		(void) enter(thr_flg_reenter);
 	}
 }
@@ -252,41 +394,180 @@
 void
 audit_activity(Rt_map *clmp, uint_t flags)
 {
-	int	appl = 0;
+	Rt_map	*lmp;
+	Aliste	idx;
+	uint_t	rtldflags;
 
 	if (rt_critical())
 		return;
 
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_ACTIVITY))
-		_audit_activity(auditors->ad_list, clmp, flags);
+		_audit_activity(auditors->ad_list, clmp, flags, TRUE);
 	if (AUDITORS(clmp) &&
 	    (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_ACTIVITY))
-		_audit_activity(AUDITORS(clmp)->ad_list, clmp, flags);
+		_audit_activity(AUDITORS(clmp)->ad_list, clmp, flags, TRUE);
+
+	for (APLIST_TRAVERSE(aud_activity, idx, lmp)) {
+		if ((clmp != lmp) && AUDITORS(lmp) &&
+		    (AUDITORS(lmp)->ad_flags & LML_TFLG_AUD_ACTIVITY)) {
+			_audit_activity(AUDITORS(lmp)->ad_list, lmp, flags,
+			    FALSE);
+		}
+	}
+
+	APPLICATION_RETURN(rtldflags);
+}
+
+/*
+ * Determine whether an auditor is in use by the head link-map object.
+ */
+static int
+_audit_used_by_head(Rt_map *hlmp, Rt_map *almp)
+{
+	Audit_list	*alp;
+	Aliste		idx;
+
+	for (APLIST_TRAVERSE(AUDITORS(hlmp)->ad_list, idx, alp)) {
+		if (alp->al_lmp == almp)
+			return (1);
+	}
+	return (0);
+}
+
+/*
+ * la_objopen() caller for the head link-map.  Global auditors, or an auditor
+ * started from the object that heads a link-map list (typically the dynamic
+ * executable), are passed to la_objopen().  However, local auditors can
+ * provide activity and preinit events, and for these events, a cookie
+ * representing the head link-map list object is expected.  This routine obtains
+ * these cookies from the link-map list lm_cookies element.  This element
+ * ensures all clients of the same auditor use the same cookie.
+ *
+ * Although a local auditor will get an la_objopen() call for the object that
+ * heads the link-map list of the object being audited, the auditor is not
+ * permitted to request binding information for this head object.  The head
+ * object has already been in existence, and bindings may have been resolved
+ * with it.  This local auditor is coming into existence too late, and thus we
+ * don't allow any bindings to be caught at all.
+ */
+static int
+_audit_add_head(Rt_map *clmp, Rt_map *hlmp, int preinit, int activity)
+{
+	Lm_list		*clml = LIST(clmp);
+	Lmid_t		lmid = get_linkmap_id(clml);
+	Audit_list	*alp;
+	Aliste		idx;
+	int		save = 0;
+
+	for (APLIST_TRAVERSE(AUDITORS(clmp)->ad_list, idx, alp)) {
+		Audit_client	*acp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
+		uintptr_t	*cookie;
+		uint_t		rtldflags;
+
+		/*
+		 * Ensure this local auditor isn't already in existence as an
+		 * auditor for the head of the link-map list.  If it is, then
+		 * this auditor will have already receive preinit and activity
+		 * events.
+		 */
+		if (AUDITORS(hlmp) && _audit_used_by_head(hlmp, almp))
+			continue;
 
-	if (appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+		/*
+		 * Create a cookie that represents the object that heads the
+		 * link-map list.  If the cookie already exists, then this
+		 * auditor has already been established for another objects
+		 * local auditing.  In this case, do not issue a la_objopen()
+		 * or la_activity() event, as these will have already occurred.
+		 */
+		if ((acp = _audit_get_head_client(clml->lm_head, almp)) != NULL)
+			continue;
+		if ((acp =
+		    _audit_create_head_client(clml->lm_head, almp)) == NULL)
+			return (0);
+
+		cookie = &(acp->ac_cookie);
+		save++;
+
+		/*
+		 * Call the la_objopen() if available.
+		 */
+		if (alp->al_objopen) {
+			uint_t	flags;
+
+			DBG_CALL(Dbg_audit_objopen(clml, DBG_AUD_CALL,
+			    alp->al_libname, NAME(hlmp), 0, FALSE));
+
+			APPLICATION_ENTER(rtldflags);
+			leave(alml, thr_flg_reenter);
+			flags = (*alp->al_objopen)((Link_map *)hlmp, lmid,
+			    cookie);
+			(void) enter(thr_flg_reenter);
+			APPLICATION_RETURN(rtldflags);
+
+			if (flags) {
+				DBG_CALL(Dbg_audit_objopen(clml, DBG_AUD_RET,
+				    alp->al_libname, NAME(hlmp), flags, TRUE));
+			}
+		}
+
+		/*
+		 * Call the la_activity() if available.
+		 */
+		if (alp->al_activity) {
+			alml->lm_flags |= LML_FLG_AUDITNOTIFY;
+			clml->lm_flags |= LML_FLG_ACTAUDIT;
+
+			DBG_CALL(Dbg_audit_activity(clml, alp->al_libname,
+			    NAME(clml->lm_head), LA_ACT_ADD));
+
+			APPLICATION_ENTER(rtldflags);
+			leave(alml, thr_flg_reenter);
+			(*alp->al_activity)(cookie, LA_ACT_ADD);
+			(void) enter(thr_flg_reenter);
+			APPLICATION_RETURN(rtldflags);
+		}
+	}
+
+	/*
+	 * If new head link-map cookies have been generated, then maintain
+	 * any preinit and/or activity requirements.
+	 */
+	if (save) {
+		if (preinit && (aplist_append(&aud_preinit, clmp,
+		    AL_CNT_AUDITORS) == NULL))
+			return (0);
+		if (activity && (aplist_append(&aud_activity, clmp,
+		    AL_CNT_AUDITORS) == NULL))
+			return (0);
+	}
+	return (1);
 }
 
 /*
  * la_objopen() caller.  Create an audit information structure for the indicated
  * link-map, regardless of an la_objopen() entry point.  This structure is used
  * to supply information to various audit interfaces (see LML_MSK_AUDINFO).
- * Traverse through all audit library and call any la_objopen() entry points
+ * Traverse through all audit libraries and call any la_objopen() entry points
  * found.
  */
 static int
 _audit_objopen(APlist *list, Rt_map *nlmp, Lmid_t lmid, Audit_info *aip,
     int *ndx)
 {
+	Lm_list		*nlml = LIST(nlmp);
 	Audit_list	*alp;
 	Aliste		idx;
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		uint_t		flags;
 		Audit_client	*acp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
 
 		/*
 		 * Associate a cookie with the audit library, and assign the
@@ -299,14 +580,22 @@
 		if (alp->al_objopen == NULL)
 			continue;
 
-		DBG_CALL(Dbg_audit_object(LIST(alp->al_lmp), alp->al_libname,
-		    NAME(nlmp)));
+		DBG_CALL(Dbg_audit_objopen(nlml, DBG_AUD_CALL, alp->al_libname,
+		    NAME(nlmp), 0, FALSE));
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		leave(alml, thr_flg_reenter);
 		flags = (*alp->al_objopen)((Link_map *)nlmp, lmid,
 		    &(acp->ac_cookie));
 		(void) enter(thr_flg_reenter);
 
+		/*
+		 * Diagnose any flags returned by the auditor.
+		 */
+		if (flags) {
+			DBG_CALL(Dbg_audit_objopen(nlml, DBG_AUD_RET,
+			    alp->al_libname, NAME(nlmp), flags, FALSE));
+		}
+
 		if (flags & LA_FLG_BINDTO)
 			acp->ac_flags |= FLG_AC_BINDTO;
 
@@ -341,7 +630,8 @@
 audit_objopen(Rt_map *clmp, Rt_map *nlmp)
 {
 	Lmid_t		lmid = get_linkmap_id(LIST(nlmp));
-	int		appl = 0, respond = 1, ndx = 0;
+	int		respond = 1, ndx = 0;
+	uint_t		rtldflags;
 	uint_t		clients = 0;
 	Audit_info	*aip;
 
@@ -349,8 +639,9 @@
 		return (respond);
 
 	/*
-	 * Determine the total number of audit libraries in use.  This provides
-	 * the number of client structures required for this object.
+	 * Determine the number of auditors that can receive information
+	 * regarding this object.  This provides the number of client
+	 * structures required for this object.
 	 */
 	if (auditors)
 		clients = auditors->ad_cnt;
@@ -360,8 +651,13 @@
 		clients += AUDITORS(nlmp)->ad_cnt;
 
 	/*
-	 * The initial allocation of the audit information structure includes
-	 * an array of audit clients, 1 per audit library presently available.
+	 * Allocate an audit information structure.  Each audited object
+	 * maintains a AUDINFO() structure.  As this structure can only be
+	 * created once all auditors are loaded, a client count can now be
+	 * computed.
+	 *
+	 * The allocation of the audit information structure includes an array
+	 * of audit clients, 1 per audit library that has been loaded.
 	 *
 	 *			 ---------------
 	 *			| ai_cnt	|
@@ -381,8 +677,7 @@
 	aip->ai_clients = (Audit_client *)((uintptr_t)aip +
 	    sizeof (Audit_info));
 
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors)
 		respond = _audit_objopen(auditors->ad_list, nlmp,
@@ -394,14 +689,13 @@
 		respond = _audit_objopen(AUDITORS(nlmp)->ad_list, nlmp,
 		    lmid, aip, &ndx);
 
-	if (appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	APPLICATION_RETURN(rtldflags);
 
 	return (respond);
 }
 
 /*
- * la_objclose() caller.  Traverse through all audit library and call any
+ * la_objclose() caller.  Traverse through all audit libraries and call any
  * la_objclose() entry points found.
  */
 void
@@ -409,44 +703,94 @@
 {
 	Audit_list	*alp;
 	Aliste		idx;
+	Lm_list		*lml = LIST(lmp);
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*acp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
 
 		if (alp->al_objclose == NULL)
 			continue;
-		if ((acp = _audit_client(AUDINFO(lmp), alp->al_lmp)) == NULL)
+		if ((acp = _audit_client(AUDINFO(lmp), almp)) == NULL)
 			continue;
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		DBG_CALL(Dbg_audit_objclose(lml, alp->al_libname, NAME(lmp)));
+
+		leave(alml, thr_flg_reenter);
 		(*alp->al_objclose)(&(acp->ac_cookie));
 		(void) enter(thr_flg_reenter);
 	}
 }
 
+/*
+ * Determine any la_objclose() requirements.  An object that is about to be
+ * deleted needs to trigger an la_objclose() event to any associated auditors.
+ * In the case of local auditing, a deleted object may have a number of callers,
+ * and each of these callers may have their own auditing requirements.  To
+ * ensure only one la_objclose() event is sent to each auditor, collect the
+ * auditors from any callers and make sure there's no duplication.
+ */
+inline static void
+add_objclose_list(Rt_map *lmp, APlist **alpp)
+{
+	if (AFLAGS(lmp) & LML_TFLG_AUD_OBJCLOSE) {
+		Audit_list	*alp;
+		Aliste		idx;
+
+		for (APLIST_TRAVERSE(AUDITORS(lmp)->ad_list, idx, alp)) {
+			if (aplist_test(alpp, alp, AL_CNT_AUDITORS) == 0)
+				return;
+		}
+	}
+}
+
 void
-audit_objclose(Rt_map *clmp, Rt_map *lmp)
+audit_objclose(Rt_map *lmp, Rt_map *clmp)
 {
-	int	appl = 0;
+	APlist		*alp = NULL;
+	uint_t		rtldflags;
 
 	if (rt_critical())
 		return;
 
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJCLOSE))
 		_audit_objclose(auditors->ad_list, lmp);
-	if (AUDITORS(clmp) &&
-	    (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJCLOSE))
-		_audit_objclose(AUDITORS(clmp)->ad_list, lmp);
+
+	/*
+	 * If this link-map list contains local auditors, determine if this
+	 * object, or any of this objects CALLERS have instantiated auditors
+	 * that need to know of la_objclose() events.
+	 */
+	if (LIST(lmp)->lm_flags & LML_FLG_LOCAUDIT) {
+		Bnd_desc	*bdp;
+		Aliste		idx;
+
+		add_objclose_list(lmp, &alp);
 
-	if (appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+		for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp))
+			add_objclose_list(bdp->b_caller, &alp);
+	}
+
+	/*
+	 * If this close originated from dlclose(), determine whether the caller
+	 * requires a la_objclose() event.
+	 */
+	if (clmp)
+		add_objclose_list(clmp, &alp);
+
+	if (alp) {
+		_audit_objclose(alp, lmp);
+		free((void *)alp);
+	}
+
+	APPLICATION_RETURN(rtldflags);
 }
 
 /*
- * la_pltenter() caller.  Traverse through all audit library and call any
+ * la_pltenter() caller.  Traverse through all audit libraries and call any
  * la_pltenter() entry points found.  NOTE: this routine is called via the
  * glue code established in elf_plt_trace_write(), the symbol descriptor is
  * created as part of the glue and for 32bit environments the st_name is a
@@ -461,6 +805,7 @@
 {
 	Audit_list	*alp;
 	Aliste		idx;
+	Lm_list		*rlml = LIST(rlmp);
 #if	defined(_ELF64)
 	const char	*name = (const char *)(sym->st_name + STRTAB(dlmp));
 #else
@@ -469,19 +814,24 @@
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*racp, *dacp;
-		Addr		prev = sym->st_value;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
+		Addr		ovalue = sym->st_value;
 
 		if (alp->al_pltenter == 0)
 			continue;
-		if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == NULL)
+		if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
 			continue;
-		if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == NULL)
+		if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
 			continue;
 		if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
 		    ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
 			continue;
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		DBG_CALL(Dbg_audit_pltenter(rlml, DBG_AUD_CALL,
+		    alp->al_libname, name, ovalue));
+
+		leave(alml, thr_flg_reenter);
 		sym->st_value = (Addr)(*alp->al_pltenter)(sym, ndx,
 		    &(racp->ac_cookie), &(dacp->ac_cookie), regs,
 		/* BEGIN CSTYLED */
@@ -493,8 +843,10 @@
 		/* END CSTYLED */
 		(void) enter(thr_flg_reenter);
 
-		DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname,
-		    MSG_ORIG(MSG_AUD_PLTENTER), name, prev, sym->st_name));
+		if (ovalue != sym->st_value) {
+			DBG_CALL(Dbg_audit_pltenter(rlml, DBG_AUD_RET,
+			    alp->al_libname, name, sym->st_value));
+		}
 	}
 }
 
@@ -502,36 +854,34 @@
 audit_pltenter(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
     void *regs, uint_t *flags)
 {
-	Sym	_sym = *sym;
-	int	_appl = 0;
+	Sym	nsym = *sym;
+	uint_t	rtldflags;
 
 	if (rt_critical())
-		return (_sym.st_value);
+		return (nsym.st_value);
 
 	/*
 	 * We're effectively entering ld.so.1 from user (glue) code.
 	 */
 	(void) enter(0);
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		_appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTENTER))
-		_audit_pltenter(auditors->ad_list, rlmp, dlmp, &_sym,
+		_audit_pltenter(auditors->ad_list, rlmp, dlmp, &nsym,
 		    ndx, regs, flags);
 	if (AUDITORS(rlmp) &&
 	    (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTENTER))
-		_audit_pltenter(AUDITORS(rlmp)->ad_list, rlmp, dlmp, &_sym,
+		_audit_pltenter(AUDITORS(rlmp)->ad_list, rlmp, dlmp, &nsym,
 		    ndx, regs, flags);
 
-	if (_appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	APPLICATION_RETURN(rtldflags);
 	leave(LIST(rlmp), 0);
 
-	return (_sym.st_value);
+	return (nsym.st_value);
 }
 
 /*
- * la_pltexit() caller.  Traverse through all audit library and call any
+ * la_pltexit() caller.  Traverse through all audit libraries and call any
  * la_pltexit() entry points found.  See notes above (_audit_pltenter) for
  * discussion on st_name.
  */
@@ -543,22 +893,29 @@
 	Aliste		idx;
 #if	defined(_ELF64)
 	const char	*name = (const char *)(sym->st_name + STRTAB(dlmp));
+#else
+	const char	*name = (const char *)(sym->st_name);
 #endif
+	Lm_list		*rlml = LIST(rlmp);
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*racp, *dacp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
 
 		if (alp->al_pltexit == 0)
 			continue;
-		if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == NULL)
+		if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
 			continue;
-		if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == NULL)
+		if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
 			continue;
 		if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
 		    ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
 			continue;
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		DBG_CALL(Dbg_audit_pltexit(rlml, alp->al_libname, name));
+
+		leave(alml, thr_flg_reenter);
 		retval = (*alp->al_pltexit)(sym, ndx,
 		    &(racp->ac_cookie), &(dacp->ac_cookie),
 		/* BEGIN CSTYLED */
@@ -578,7 +935,7 @@
     uint_t ndx)
 {
 	uintptr_t	_retval = retval;
-	int		_appl = 0;
+	uint_t		rtldflags;
 
 	if (rt_critical())
 		return (_retval);
@@ -587,8 +944,7 @@
 	 * We're effectively entering ld.so.1 from user (glue) code.
 	 */
 	(void) enter(0);
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		_appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTEXIT))
 		_retval = _audit_pltexit(auditors->ad_list, _retval,
@@ -597,8 +953,7 @@
 		_retval = _audit_pltexit(AUDITORS(rlmp)->ad_list, _retval,
 		    rlmp, dlmp, sym, ndx);
 
-	if (_appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	APPLICATION_RETURN(rtldflags);
 	leave(LIST(rlmp), 0);
 
 	return (_retval);
@@ -606,7 +961,7 @@
 
 
 /*
- * la_symbind() caller.  Traverse through all audit library and call any
+ * la_symbind() caller.  Traverse through all audit libraries and call any
  * la_symbind() entry points found.
  */
 static Addr
@@ -615,6 +970,7 @@
 {
 	Audit_list	*alp;
 	Aliste		idx;
+	Lm_list		*rlml = LIST(rlmp);
 #if	defined(_ELF64)
 	const char	*name = (const char *)(sym->st_name + STRTAB(dlmp));
 #else
@@ -623,14 +979,16 @@
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*racp, *dacp;
-		Addr		prev = sym->st_value;
-		uint_t		lflags;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
+		Addr		ovalue = sym->st_value;
+		uint_t		lflags, oflags = *flags;
 
 		if (alp->al_symbind == 0)
 			continue;
-		if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == NULL)
+		if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
 			continue;
-		if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == NULL)
+		if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
 			continue;
 		if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
 		    ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
@@ -642,10 +1000,13 @@
 		 * object has been identified as BINDTO.  Use a local version of
 		 * the flags, so that any user update can be collected.
 		 */
-		called++;
-		lflags = (*flags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
+		(*called)++;
+		lflags = (oflags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
+		DBG_CALL(Dbg_audit_symbind(rlml, DBG_AUD_CALL,
+		    alp->al_libname, name, ovalue, oflags));
+
+		leave(alml, thr_flg_reenter);
 		sym->st_value = (*alp->al_symbind)(sym, ndx,
 		    &(racp->ac_cookie), &(dacp->ac_cookie),
 		/* BEGIN CSTYLED */
@@ -664,11 +1025,14 @@
 		 * has been supplied.
 		 */
 		*flags |= (lflags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
-		if ((prev != sym->st_value) && (alp->al_vernum >= LAV_VERSION2))
+		if ((ovalue != sym->st_value) &&
+		    (alp->al_vernum >= LAV_VERSION2))
 			*flags |= LA_SYMB_ALTVALUE;
 
-		DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname,
-		    MSG_ORIG(MSG_AUD_SYMBIND), name, prev, sym->st_value));
+		if ((ovalue != sym->st_value) || (oflags != *flags)) {
+			DBG_CALL(Dbg_audit_symbind(rlml, DBG_AUD_RET,
+			    alp->al_libname, name, sym->st_value, *flags));
+		}
 	}
 	return (sym->st_value);
 }
@@ -677,8 +1041,9 @@
 audit_symbind(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, Addr value,
     uint_t *flags)
 {
-	Sym	_sym;
-	int	_appl = 0, called = 0;
+	Sym	nsym;
+	int	called = 0;
+	uint_t	rtldflags;
 
 	/*
 	 * Construct a new symbol from that supplied but with the real address.
@@ -686,37 +1051,35 @@
 	 * big enough to hold a character pointer. We pass this pointer as a
 	 * separate parameter for 64-bit audit libraries.
 	 */
-	_sym = *sym;
-	_sym.st_value = value;
+	nsym = *sym;
+	nsym.st_value = value;
 
 	if (rt_critical())
-		return (_sym.st_value);
+		return (nsym.st_value);
 
 #if	!defined(_ELF64)
-	_sym.st_name += (Word)STRTAB(dlmp);
+	nsym.st_name += (Word)STRTAB(dlmp);
 #endif
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		_appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_SYMBIND))
-		_sym.st_value = _audit_symbind(auditors->ad_list,
-		    rlmp, dlmp, &_sym, ndx, flags, &called);
+		nsym.st_value = _audit_symbind(auditors->ad_list,
+		    rlmp, dlmp, &nsym, ndx, flags, &called);
 	if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_SYMBIND))
-		_sym.st_value = _audit_symbind(AUDITORS(rlmp)->ad_list,
-		    rlmp, dlmp, &_sym, ndx, flags, &called);
+		nsym.st_value = _audit_symbind(AUDITORS(rlmp)->ad_list,
+		    rlmp, dlmp, &nsym, ndx, flags, &called);
 
 	/*
 	 * If no la_symbind() was called for this interface, fabricate that no
 	 * la_pltenter, or la_pltexit is required.  This helps reduce the glue
 	 * code created for further auditing.
 	 */
-	if (caller == 0)
+	if (called == 0)
 		*flags |= (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
 
-	if (_appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	APPLICATION_RETURN(rtldflags);
 
-	return (_sym.st_value);
+	return (nsym.st_value);
 }
 
 /*
@@ -724,43 +1087,70 @@
  * la_preinit() entry points found.
  */
 static void
-_audit_preinit(APlist *list, Rt_map *clmp)
+_audit_preinit(APlist *list, Rt_map *clmp, Boolean client)
 {
 	Audit_list	*alp;
 	Aliste		idx;
+	Lm_list		*clml = LIST(clmp);
 
 	for (APLIST_TRAVERSE(list, idx, alp)) {
 		Audit_client	*acp;
+		Rt_map		*almp = alp->al_lmp;
+		Lm_list		*alml = LIST(almp);
+		uintptr_t	*cookie;
 
 		if (alp->al_preinit == 0)
 			continue;
-		if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == NULL)
-			continue;
 
-		leave(LIST(alp->al_lmp), thr_flg_reenter);
-		(*alp->al_preinit)(&(acp->ac_cookie));
+		/*
+		 * Determine what cookie is required.  Any auditing that
+		 * originates from the object that heads the link-map list has
+		 * its own cookie.  Local auditors must obtain the cookie that
+		 * represents the object that heads the link-map list.
+		 */
+		if (client)
+			acp = _audit_client(AUDINFO(clmp), almp);
+		else
+			acp = _audit_get_head_client(clml->lm_head, almp);
+
+		if (acp == NULL)
+			continue;
+		cookie = &(acp->ac_cookie);
+
+		DBG_CALL(Dbg_audit_preinit(clml, alp->al_libname,
+		    NAME(clml->lm_head)));
+
+		leave(alml, thr_flg_reenter);
+		(*alp->al_preinit)(cookie);
 		(void) enter(thr_flg_reenter);
 	}
 }
 
 void
-audit_preinit(Rt_map *clmp)
+audit_preinit(Rt_map *mlmp)
 {
-	int	appl = 0;
+	Rt_map	*clmp;
+	Aliste	idx;
+	uint_t	rtldflags;
 
 	if (rt_critical())
 		return;
 
-	if ((rtld_flags & RT_FL_APPLIC) == 0)
-		appl = rtld_flags |= RT_FL_APPLIC;
+	APPLICATION_ENTER(rtldflags);
 
 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PREINIT))
-		_audit_preinit(auditors->ad_list, clmp);
-	if (AUDITORS(clmp) && (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_PREINIT))
-		_audit_preinit(AUDITORS(clmp)->ad_list, clmp);
+		_audit_preinit(auditors->ad_list, mlmp, TRUE);
+
+	if (AUDITORS(mlmp) && (AUDITORS(mlmp)->ad_flags & LML_TFLG_AUD_PREINIT))
+		_audit_preinit(AUDITORS(mlmp)->ad_list, mlmp, TRUE);
 
-	if (appl)
-		rtld_flags &= ~RT_FL_APPLIC;
+	for (APLIST_TRAVERSE(aud_preinit, idx, clmp)) {
+		if (AUDITORS(clmp) &&
+		    (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_PREINIT))
+			_audit_preinit(AUDITORS(clmp)->ad_list, clmp, FALSE);
+	}
+
+	APPLICATION_RETURN(rtldflags);
 }
 
 /*
@@ -768,7 +1158,7 @@
  * and then close each one down.  This is done rather than using the handles
  * directly from the auditors, as the audit list can be torn down as a result
  * of the dlclose.  In other words, what you're pointing at can be removed
- * while your still pointing at it.
+ * while you're still pointing at it.
  */
 void
 audit_desc_cleanup(Rt_map *clmp)
@@ -790,7 +1180,12 @@
 	adp->ad_list = NULL;
 
 	free(adp);
+
+	/*
+	 * Indicate that the caller is no longer being audited.
+	 */
 	AUDITORS(clmp) = NULL;
+	AFLAGS(clmp) &= ~LML_TFLG_AUD_MASK;
 
 	if (ghalp) {
 		Grp_hdl		*ghp;
@@ -804,6 +1199,24 @@
 }
 
 /*
+ * Objects that establish local auditors may have been added to preinit or
+ * activity lists.  Remove the object from this list if it is present.
+ */
+static void
+remove_auditor(APlist *alp, Rt_map *clmp)
+{
+	Rt_map	*lmp;
+	Aliste	idx;
+
+	for (APLIST_TRAVERSE(alp, idx, lmp)) {
+		if (lmp == clmp) {
+			aplist_delete(alp, &idx);
+			return;
+		}
+	}
+}
+
+/*
  * Clean up (free) an audit information structure.
  */
 void
@@ -816,6 +1229,12 @@
 
 	if (aip->ai_dynplts)
 		free(aip->ai_dynplts);
+
+	if (aud_preinit)
+		remove_auditor(aud_preinit, clmp);
+	if (aud_activity)
+		remove_auditor(aud_activity, clmp);
+
 	free(aip);
 }
 
@@ -830,7 +1249,7 @@
 } Aud_info;
 
 static const Aud_info aud_info[] = {
-	{ MSG_SYM_LAVERSION,	0 },	/* MSG_ORIG(MSG_SYM_LAVERSION) */
+	{ MSG_SYM_LAVERSION, 0, 0 },	/* MSG_ORIG(MSG_SYM_LAVERSION) */
 	{ MSG_SYM_LAPREINIT,		/* MSG_ORIG(MSG_SYM_LAPREINIT) */
 	    LML_TFLG_AUD_PREINIT, 0 },
 	{ MSG_SYM_LAOBJSEARCH,		/* MSG_ORIG(MSG_SYM_LAOBJSEARCH) */
@@ -912,6 +1331,12 @@
 		if (auflag)
 			audit_flags |= auflag;
 
+		/*
+		 * Note, unlike most other diagnostics, where we wish to
+		 * identify the lmid of the caller, here we use the lmid of
+		 * the auditor itself to show the association of the auditor
+		 * and the interfaces it provides.
+		 */
 		DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp),
 		    alp->al_libname, sr.sr_name));
 		return (addr);
@@ -941,11 +1366,27 @@
 int
 audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig, int *in_nfavl)
 {
-	char	*ptr, *next;
-	Lm_list	*clml = LIST(clmp);
-	int	error = 1;
+	char		*ptr, *next;
+	Lm_list		*clml = LIST(clmp);
+	Rt_map		*hlmp;
+	int		error = 1, activity = 0, preinit = 0;
+	uint_t		rtldflags;
 
-	DBG_CALL(Dbg_audit_lib(clml, adp->ad_name));
+	/*
+	 * Determine the type of auditing for diagnostics.
+	 */
+	if (DBG_ENABLED) {
+		int	type;
+
+		if (orig & PD_FLG_EXTLOAD)
+			type = DBG_AUD_PRELOAD;
+		else if (FLAGS1(clmp) & FL1_RT_GLOBAUD)
+			type = DBG_AUD_GLOBAL;
+		else
+			type = DBG_AUD_LOCAL;
+
+		DBG_CALL(Dbg_audit_lib(clmp, adp->ad_name, type));
+	}
 
 	/*
 	 * Mark that we have at least one auditing link map
@@ -960,9 +1401,12 @@
 	    ptr; ptr = strtok_r(NULL,  MSG_ORIG(MSG_STR_DELIMIT), &next)) {
 		Grp_hdl		*ghp;
 		Rt_map		*lmp;
+		Lm_list		*lml;
 		Rt_map		**tobj;
 		Audit_list	*alp;
 
+		DBG_CALL(Dbg_util_nl(clml, DBG_NL_STD));
+
 		/*
 		 * Open the audit library on its own link-map.
 		 */
@@ -973,19 +1417,31 @@
 			continue;
 		}
 		lmp = ghp->gh_ownlmp;
+		lml = LIST(lmp);
 
 		/*
 		 * If this auditor has already been loaded, reuse it.
 		 */
-		if ((alp = LIST(lmp)->lm_alp) != NULL) {
+		if ((alp = lml->lm_alp) != NULL) {
 			if (aplist_append(&(adp->ad_list), alp,
 			    AL_CNT_AUDITORS) == NULL)
 				return (audit_disable(ptr, clmp, ghp, alp));
 
 			adp->ad_cnt++;
-			DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
-			    alp->al_vernum));
 			adp->ad_flags |= alp->al_flags;
+
+			/*
+			 * If this existing auditor provides preinit or
+			 * activity routines, track their existence.  The
+			 * instantiation of a local auditor requires a cookie
+			 * be created that represents the object that heads
+			 * the link-map list of the object being audited.
+			 */
+			if (alp->al_preinit)
+				preinit++;
+			if (alp->al_activity)
+				activity++;
+
 			continue;
 		}
 
@@ -998,7 +1454,7 @@
 		 * Refer to external.c:get_lcinterface().
 		 */
 		if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0)
-			LIST(lmp)->lm_flags |= LML_FLG_HOLDLOCK;
+			lml->lm_flags |= LML_FLG_HOLDLOCK;
 
 		/*
 		 * Allocate an audit list descriptor for this object and
@@ -1018,26 +1474,31 @@
 		 */
 		if ((alp->al_version = (uint_t(*)())audit_symget(alp,
 		    AI_LAVERSION, in_nfavl)) == 0) {
-			eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM),
+			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM),
 			    MSG_ORIG(MSG_SYM_LAVERSION));
 			error = audit_disable(ptr, clmp, ghp, alp);
 			continue;
 		}
 
-		if ((tobj = tsort(lmp, LIST(lmp)->lm_init, RT_SORT_REV)) ==
+		if ((tobj = tsort(lmp, lml->lm_init, RT_SORT_REV)) ==
 		    (Rt_map **)S_ERROR)
 			return (audit_disable(ptr, clmp, ghp, alp));
 
-		rtld_flags |= RT_FL_APPLIC;
-		if (tobj != (Rt_map **)NULL)
+		if (tobj)
 			call_init(tobj, DBG_INIT_SORT);
 
-		alp->al_vernum = alp->al_version(LAV_CURRENT);
-		rtld_flags &= ~RT_FL_APPLIC;
+		APPLICATION_ENTER(rtldflags);
+		leave(lml, thr_flg_reenter);
+		alp->al_vernum = (*alp->al_version)(LAV_CURRENT);
+		(void) enter(thr_flg_reenter);
+		APPLICATION_RETURN(rtldflags);
+
+		DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
+		    LAV_CURRENT, alp->al_vernum));
 
 		if ((alp->al_vernum < LAV_VERSION1) ||
 		    (alp->al_vernum > LAV_CURRENT)) {
-			eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS),
+			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS),
 			    LAV_CURRENT, alp->al_vernum);
 			error = audit_disable(ptr, clmp, ghp, alp);
 			continue;
@@ -1048,14 +1509,10 @@
 			return (audit_disable(ptr, clmp, ghp, alp));
 
 		adp->ad_cnt++;
-		DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
-		    alp->al_vernum));
 
 		/*
 		 * Collect any remaining entry points.
 		 */
-		alp->al_preinit = (void(*)())audit_symget(alp,
-		    AI_LAPREINIT, in_nfavl);
 		alp->al_objsearch = (char *(*)())audit_symget(alp,
 		    AI_LAOBJSEARCH, in_nfavl);
 		alp->al_objopen = (uint_t(*)())audit_symget(alp,
@@ -1064,8 +1521,6 @@
 		    AI_LAOBJFILTER, in_nfavl);
 		alp->al_objclose = (uint_t(*)())audit_symget(alp,
 		    AI_LAOBJCLOSE, in_nfavl);
-		alp->al_activity = (void (*)())audit_symget(alp,
-		    AI_LAACTIVITY, in_nfavl);
 		alp->al_symbind = (uintptr_t(*)())audit_symget(alp,
 		    AI_LASYMBIND, in_nfavl);
 		alp->al_pltenter = (uintptr_t(*)())audit_symget(alp,
@@ -1073,15 +1528,37 @@
 		alp->al_pltexit = (uintptr_t(*)())audit_symget(alp,
 		    AI_LAPLTEXIT, in_nfavl);
 
+		if ((alp->al_preinit = (void(*)())audit_symget(alp,
+		    AI_LAPREINIT, in_nfavl)) != NULL)
+			preinit++;
+		if ((alp->al_activity = (void(*)())audit_symget(alp,
+		    AI_LAACTIVITY, in_nfavl)) != NULL)
+			activity++;
+
 		/*
 		 * Collect the individual object flags, and assign this audit
 		 * list descriptor to its associated link-map list.
 		 */
 		adp->ad_flags |= alp->al_flags;
-		LIST(lmp)->lm_alp = alp;
+		lml->lm_alp = alp;
 	}
 
 	/*
+	 * If the caller isn't the head of its own link-map list, then any
+	 * preinit or activity entry points need to be tracked separately.
+	 * These "events" are not associated with a particular link-map, and
+	 * thus a traversal of any existing preinit and activity clients is
+	 * required.
+	 *
+	 * If either of these events are required, establish a cookie for the
+	 * object at the head of the link-map list, and make an initial ADD
+	 * activity for these local auditors.
+	 */
+	if ((preinit || activity) && ((hlmp = clml->lm_head) != clmp) &&
+	    (_audit_add_head(clmp, hlmp, preinit, activity) == 0))
+		return (0);
+
+	/*
 	 * Free the original audit string, as this descriptor may be used again
 	 * to add additional auditing.
 	 */
--- a/usr/src/cmd/sgs/rtld/common/cap.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/cap.c	Tue Jul 20 16:29:51 2010 -0700
@@ -652,7 +652,8 @@
 
 int
 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)
+    Rt_map *flmp, Rt_map *clmp, const char *ref, int mode, uint_t flags,
+    int *in_nfavl)
 {
 	Alist		*fdalp = NULL;
 	Aliste		idx;
@@ -729,7 +730,7 @@
 		 * Finish processing the objects associated with this request.
 		 */
 		if (nlmp && ghp && (((nlmp = analyze_lmc(lml, nlmco, nlmp,
-		    in_nfavl)) == NULL) ||
+		    clmp, in_nfavl)) == NULL) ||
 		    (relocate_lmc(lml, nlmco, flmp, nlmp, in_nfavl) == 0)))
 			nlmp = NULL;
 
--- a/usr/src/cmd/sgs/rtld/common/dlfcns.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c	Tue Jul 20 16:29:51 2010 -0700
@@ -456,6 +456,7 @@
 dlclose_core(Grp_hdl *ghp, Rt_map *clmp, Lm_list *lml)
 {
 	int	error;
+	Rt_map	*lmp;
 
 	/*
 	 * If we're already at atexit() there's no point processing further,
@@ -489,6 +490,21 @@
 		return (0);
 
 	/*
+	 * If this handle is associated with an object that is not on the base
+	 * link-map control list, or it has not yet been relocated, then this
+	 * handle must have originated from an auditors interaction.  User code
+	 * can only execute and bind to relocated objects on the base link-map
+	 * control list.  A non-relocated object, or an object on a non-base
+	 * link-map control list, is in the process of being loaded, and
+	 * therefore we do not attempt to remove the handle, as we might
+	 * mistakenly delete the object thinking that its loading has failed.
+	 */
+	if (((lmp = ghp->gh_ownlmp) != NULL) &&
+	    ((CNTL(lmp) != ALIST_OFF_DATA) ||
+	    ((FLAGS(lmp) & FLG_RT_RELOCED) == 0)))
+		return (0);
+
+	/*
 	 * This handle is no longer being referenced, remove it.  If this handle
 	 * is part of an alternative link-map list, determine if the whole list
 	 * can be removed also.
@@ -730,7 +746,7 @@
 		return (NULL);
 
 	if ((palp->al_arritems > 1) && ((mode & RTLD_FIRST) == 0)) {
-		remove_plist(&palp, 1);
+		remove_alist(&palp, 1);
 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_5));
 		return (NULL);
 	}
@@ -740,7 +756,7 @@
 	 * associated object.
 	 */
 	if ((nlmco = create_cntl(lml, 1)) == NULL) {
-		remove_plist(&palp, 1);
+		remove_alist(&palp, 1);
 		return (NULL);
 	}
 	olmco = nlmco;
@@ -752,7 +768,7 @@
 	 * Remove any expanded pathname infrastructure, and if the dependency
 	 * couldn't be loaded, cleanup.
 	 */
-	remove_plist(&palp, 1);
+	remove_alist(&palp, 1);
 	if (nlmp == NULL) {
 		remove_cntl(lml, olmco);
 		return (NULL);
@@ -776,7 +792,7 @@
 	/*
 	 * Finish processing the objects associated with this request.
 	 */
-	if (((nlmp = analyze_lmc(lml, nlmco, nlmp, in_nfavl)) == NULL) ||
+	if (((nlmp = analyze_lmc(lml, nlmco, nlmp, clmp, in_nfavl)) == NULL) ||
 	    (relocate_lmc(lml, nlmco, clmp, nlmp, in_nfavl) == 0)) {
 		ghp = NULL;
 		nlmp = NULL;
@@ -864,9 +880,8 @@
 			 * audited.  Insure all audit dependencies are loaded.
 			 */
 			lml->lm_tflags &= ~LML_TFLG_AUD_MASK;
-			lml->lm_tflags |=
-			    (LML_TFLG_NOLAZYLD | LML_TFLG_LOADFLTR);
-			lml->lm_flags |= LML_FLG_NOAUDIT;
+			lml->lm_tflags |= (LML_TFLG_NOLAZYLD |
+			    LML_TFLG_LOADFLTR | LML_TFLG_NOAUDIT);
 		}
 
 		if (aplist_append(&dynlm_list, lml, AL_CNT_DYNLIST) == NULL) {
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Tue Jul 20 16:29:51 2010 -0700
@@ -420,7 +420,7 @@
 	 * Establish a link-map control list for this request.
 	 */
 	if ((lmco = create_cntl(lml, 0)) == NULL) {
-		remove_plist(&palp, 1);
+		remove_alist(&palp, 1);
 		return (NULL);
 	}
 
@@ -435,7 +435,7 @@
 	 * dependency count of the caller, together with the link-map lists
 	 * count of objects that still have lazy dependencies pending.
 	 */
-	remove_plist(&palp, 1);
+	remove_alist(&palp, 1);
 	if (--LAZY(clmp) == 0)
 		LIST(clmp)->lm_lazy--;
 
@@ -444,7 +444,7 @@
 	 * create an association between the caller and this dependency.
 	 */
 	if (nlmp && ((bind_one(clmp, nlmp, BND_NEEDED) == 0) ||
-	    ((nlmp = analyze_lmc(lml, lmco, nlmp, in_nfavl)) == NULL) ||
+	    ((nlmp = analyze_lmc(lml, lmco, nlmp, clmp, in_nfavl)) == NULL) ||
 	    (relocate_lmc(lml, lmco, clmp, nlmp, in_nfavl) == 0)))
 		dip->di_info = nlmp = NULL;
 
@@ -729,7 +729,7 @@
 		 * error suppression state, if it had been previously set in
 		 * this routine.
 		 */
-		remove_plist(&palp, 0);
+		remove_alist(&palp, 0);
 
 		if (silent)
 			rtld_flags &= ~RT_FL_SILENCERR;
@@ -743,7 +743,7 @@
 			    (LML_FLG_LOADAVAIL | LML_FLG_TRC_ENABLE)))
 				continue;
 			else {
-				remove_plist(&palp, 1);
+				remove_alist(&palp, 1);
 				return (0);
 			}
 		}
@@ -752,7 +752,7 @@
 	if (LAZY(clmp))
 		lml->lm_lazy++;
 
-	remove_plist(&palp, 1);
+	remove_alist(&palp, 1);
 	return (1);
 }
 
@@ -930,7 +930,7 @@
 			 */
 			DBG_CALL(Dbg_cap_filter(lml, dir, ilmp));
 			if (cap_filtees((Alist **)&dip->di_info, idx, dir,
-			    lmco, ilmp, filtees, mode,
+			    lmco, ilmp, clmp, filtees, mode,
 			    (FLG_RT_PUBHDL | FLG_RT_CAP), in_nfavl) == 0) {
 				if ((lml->lm_flags & LML_FLG_TRC_ENABLE) &&
 				    (dip->di_flags & FLG_DI_AUXFLTR) &&
@@ -1114,7 +1114,7 @@
 				 * this filtee if necessary.
 				 */
 				if (nlmp && ghp && (((nlmp = analyze_lmc(lml,
-				    lmco, nlmp, in_nfavl)) == NULL) ||
+				    lmco, nlmp, clmp, in_nfavl)) == NULL) ||
 				    (relocate_lmc(lml, lmco, ilmp, nlmp,
 				    in_nfavl) == 0)))
 					nlmp = NULL;
@@ -1244,7 +1244,7 @@
 	 * use the null symbol routine.
 	 */
 	if (any == 0) {
-		remove_plist((Alist **)&(dip->di_info), 1);
+		remove_alist((Alist **)&(dip->di_info), 1);
 		elf_disable_filtee(ilmp, dip);
 	}
 
@@ -1644,7 +1644,7 @@
  */
 Rt_map *
 elf_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize,
-    void *odyn, int *in_nfavl)
+    void *odyn, Rt_map *clmp, int *in_nfavl)
 {
 	const char	*name = fdp->fd_nname;
 	Rt_map		*lmp;
@@ -2115,7 +2115,7 @@
 				if ((rti = alist_append(&lml->lm_rti, NULL,
 				    sizeof (Rti_desc),
 				    AL_CNT_RTLDINFO)) == NULL) {
-					remove_so(0, lmp);
+					remove_so(0, lmp, clmp);
 					return (NULL);
 				}
 				rti->rti_lmp = lmp;
@@ -2262,13 +2262,13 @@
 			if (((AUDITORS(lmp) =
 			    calloc(1, sizeof (Audit_desc))) == NULL) ||
 			    ((AUDITORS(lmp)->ad_name = strdup(cp)) == NULL)) {
-				remove_so(0, lmp);
+				remove_so(0, lmp, clmp);
 				return (NULL);
 			}
 			if (lml_main.lm_head) {
 				if (audit_setup(lmp, AUDITORS(lmp), 0,
 				    in_nfavl) == 0) {
-					remove_so(0, lmp);
+					remove_so(0, lmp, clmp);
 					return (NULL);
 				}
 				AFLAGS(lmp) |= AUDITORS(lmp)->ad_flags;
@@ -2278,7 +2278,7 @@
 	}
 
 	if (tphdr && (tls_assign(lml, lmp, tphdr) == 0)) {
-		remove_so(0, lmp);
+		remove_so(0, lmp, clmp);
 		return (NULL);
 	}
 
--- a/usr/src/cmd/sgs/rtld/common/external.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/external.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -478,7 +477,8 @@
 	if ((fptr =
 	    (void (*)())lml->lm_lcs[CI_THRINIT].lc_un.lc_func) != NULL) {
 		lml->lm_lcs[CI_THRINIT].lc_un.lc_func = NULL;
-		leave(NULL, thr_flg_reenter);
+
+		leave(lml, thr_flg_reenter);
 		(*fptr)();
 		(void) enter(thr_flg_reenter);
 
@@ -578,11 +578,7 @@
 size_t
 thr_min_stack()
 {
-#ifdef _LP64
-	return (8 * 1024);
-#else
-	return (4 * 1024);
-#endif
+	return (sizeof (uintptr_t) * 1024);
 }
 
 /*
@@ -592,7 +588,6 @@
  * the dynamic linker, so we redefine these to call the primitive,
  * non-cancellation interfaces.
  */
-
 int
 close(int fildes)
 {
--- a/usr/src/cmd/sgs/rtld/common/globals.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/globals.c	Tue Jul 20 16:29:51 2010 -0700
@@ -112,7 +112,7 @@
 const char	*rtldname = MSG_ORIG(MSG_FIL_RTLD);
 
 char		*lasterr = NULL;	/* string describing last error */
-					/*	cleared by each dlerror() */
+					/*    cleared by each dlerror() */
 Interp		*interp = NULL;		/* ELF interpreter info */
 APlist		*hdl_alp[HDLIST_SZ+2];	/* dlopen() handle list */
 size_t		syspagsz = 0;		/* system page size */
@@ -121,25 +121,27 @@
 Isa_desc	*isa = NULL;		/* isalist descriptor */
 
 uint_t		audit_argcnt = 64;	/* no. of stack args to copy (default */
-					/*	is all) */
+					/*    is all) */
 Audit_desc	*auditors = NULL;	/* global auditors (LD_AUDIT) */
+APlist		*aud_preinit = NULL;	/* list of objects defining local */
+APlist		*aud_activity = NULL;	/*    preinit and activity auditors */
 
 const char	*rpl_audit = NULL;	/* replaceable LD_AUDIT string */
 const char	*rpl_debug = NULL;	/* replaceable LD_DEBUG string */
 const char	*rpl_ldflags = NULL;	/* replaceable LD_FLAGS string */
 const char	*rpl_libpath = NULL;	/* replaceable LD_LIBRARY_PATH string */
-Alist		*rpl_libdirs = NULL;	/*	and associated Pdesc list */
+Alist		*rpl_libdirs = NULL;	/*    and associated Pdesc list */
 const char	*rpl_preload = NULL;	/* replaceable LD_PRELOAD string */
 
 const char	*prm_audit = NULL;	/* permanent LD_AUDIT string */
 const char	*prm_debug = NULL;	/* permanent LD_DEBUG string */
 const char	*prm_ldflags = NULL;	/* permanent LD_FLAGS string */
 const char	*prm_libpath = NULL;	/* permanent LD_LIBRARY_PATH string */
-Alist		*prm_libdirs = NULL;	/*	and associated Pdesc list */
+Alist		*prm_libdirs = NULL;	/*    and associated Pdesc list */
 const char	*prm_preload = NULL;	/* permanent LD_PRELOAD string */
 
 uint_t		env_info = 0;		/* information regarding environment */
-					/*	variables */
+					/*    variables */
 int		killsig = SIGKILL;	/* signal sent on fatal exit */
 APlist		*free_alp = NULL;	/* defragmentation list */
 
--- a/usr/src/cmd/sgs/rtld/common/object.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/object.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -156,7 +155,7 @@
  * sections).
  */
 Rt_map *
-elf_obj_file(Lm_list *lml, Aliste lmco, const char *name,
+elf_obj_file(Lm_list *lml, Aliste lmco, Rt_map *clmp, const char *name,
     mmapobj_result_t *hmpp, mmapobj_result_t *mpp, uint_t mnum)
 {
 	Rej_desc	rej;
@@ -179,7 +178,7 @@
 	md.md_mnum = mnum;
 	if (alist_append(&mpalp, &md, sizeof (Mmap_desc),
 	    AL_CNT_MPOBJS) == NULL) {
-		remove_so(lml, olmp);
+		remove_so(lml, olmp, clmp);
 		return (NULL);
 	}
 
@@ -189,7 +188,7 @@
 	 */
 	if (ld_process_mem(name, name, hmpp->mr_addr, hmpp->mr_msize,
 	    (Ofl_desc *)ELFPRV(olmp), &rej) == (Ifl_desc *)S_ERROR) {
-		remove_so(lml, olmp);
+		remove_so(lml, olmp, clmp);
 		return (NULL);
 	}
 
@@ -231,7 +230,7 @@
  * the appropriate link-edit functionality (refer to sgs/ld/common/main.c).
  */
 Rt_map *
-elf_obj_fini(Lm_list *lml, Rt_map *lmp, int *in_nfavl)
+elf_obj_fini(Lm_list *lml, Rt_map *lmp, Rt_map *clmp, int *in_nfavl)
 {
 	Ofl_desc		*ofl = (Ofl_desc *)ELFPRV(lmp);
 	Rt_map			*nlmp, *tlmp;
@@ -331,7 +330,7 @@
 	 */
 	fd.fd_nname = ofl->ofl_name;
 	if ((nlmp = elf_new_lmp(lml, CNTL(olmp), &fd, (Addr)hmpp->mr_addr,
-	    ofl->ofl_size, 0, in_nfavl)) == NULL)
+	    ofl->ofl_size, NULL, clmp, in_nfavl)) == NULL)
 		return (NULL);
 
 	MMAPS(nlmp) = hmpp;
@@ -426,7 +425,7 @@
 	 * opened.
 	 */
 	if ((lml->lm_tflags | AFLAGS(nlmp)) & LML_TFLG_AUD_MASK) {
-		if (audit_objopen(lmp, lmp) == 0)
+		if (audit_objopen(nlmp, nlmp) == 0)
 			return (NULL);
 	}
 	return (nlmp);
--- a/usr/src/cmd/sgs/rtld/common/paths.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/paths.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -163,7 +162,7 @@
 			}
 			if (rpl_libdirs && (rtld_flags & RT_FL_SECURE) &&
 			    (search || DBG_ENABLED))
-				remove_plist(&rpl_libdirs, 1);
+				remove_alist(&rpl_libdirs, 1);
 
 			if (rpl_libdirs == NULL) {
 				/*
@@ -204,7 +203,7 @@
 				    prm_libpath, config->c_name);
 			if (prm_libdirs && (rtld_flags & RT_FL_SECURE) &&
 			    (search || DBG_ENABLED))
-				remove_plist(&prm_libdirs, 1);
+				remove_alist(&prm_libdirs, 1);
 
 			if (prm_libdirs == NULL) {
 				/*
@@ -241,7 +240,7 @@
 				    RPATH(lmp), NAME(lmp));
 			if (RLIST(lmp) && (rtld_flags & RT_FL_SECURE) &&
 			    (search || DBG_ENABLED))
-				remove_plist(&RLIST(lmp), 1);
+				remove_alist(&RLIST(lmp), 1);
 
 			if (RLIST(lmp) == NULL) {
 				/*
--- a/usr/src/cmd/sgs/rtld/common/remove.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/remove.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -140,10 +139,11 @@
 
 /*
  * Break down an Alist containing pathname descriptors.  In most instances, the
- * Alist is cleaned of all entries, but retained for later use.
+ * Alist is removed completely.  However, in some instances the alist is cleaned
+ * of all entries, but retained for later use.
  */
 void
-remove_plist(Alist **alpp, int complete)
+remove_alist(Alist **alpp, int complete)
 {
 	Alist	*alp = *alpp;
 
@@ -152,8 +152,7 @@
 			free((void *)alp);
 			*alpp = NULL;
 		} else {
-			alp->al_nitems = 0;
-			alp->al_next = ALIST_OFF_DATA;
+			alist_reset(alp);
 		}
 	}
 }
@@ -170,23 +169,14 @@
 remove_lml(Lm_list *lml)
 {
 	if (lml && (lml->lm_head == NULL)) {
-		/*
-		 * As a whole link-map list is being removed, the debuggers
-		 * would have been alerted of this deletion (or an addition
-		 * in the case we're here to clean up from a failure).  Set
-		 * the main link-map list so that a consistent registration
-		 * can be signaled to the debuggers when we leave ld.so.1.
-		 */
-		lml_main.lm_flags |= LML_FLG_DBNOTIF;
-
 		if (lml->lm_lmidstr)
 			free(lml->lm_lmidstr);
 		if (lml->lm_alp)
 			free(lml->lm_alp);
 		if (lml->lm_lists)
 			free(lml->lm_lists);
-		if (lml->lm_actaudit)
-			free(lml->lm_actaudit);
+		if (lml->lm_aud_cookies)
+			free(lml->lm_aud_cookies);
 
 		/*
 		 * Cleanup any pending RTLDINFO in the case where it was
@@ -219,7 +209,7 @@
  * link-map creation failure.
  */
 void
-remove_so(Lm_list *lml, Rt_map *lmp)
+remove_so(Lm_list *lml, Rt_map *lmp, Rt_map *clmp)
 {
 	Dyninfo	*dip;
 
@@ -230,7 +220,7 @@
 	 * Unlink the link map from the link-map list.
 	 */
 	if (lml && lmp)
-		lm_delete(lml, lmp);
+		lm_delete(lml, lmp, clmp);
 
 	/*
 	 * If this object contributed any local external vectors for the current
@@ -257,6 +247,33 @@
 	DBG_CALL(Dbg_file_delete(lmp));
 
 	/*
+	 * If this object is an auditor, determine whether any link-map lists
+	 * are maintaining cookies to represent this auditor.  These cookies
+	 * are established for local auditing preinit and activity events.
+	 */
+	if (FLAGS(lmp) & FLG_RT_AUDIT) {
+		Lm_list	*nlml;
+		Aliste	idx1;
+
+		for (APLIST_TRAVERSE(dynlm_list, idx1, nlml)) {
+			Rt_map  	*hlmp = nlml->lm_head;
+			Audit_client	*acp;
+			Aliste		idx2;
+
+			if ((hlmp == NULL) || (FLAGS(hlmp) & FLG_RT_AUDIT))
+				continue;
+
+			for (ALIST_TRAVERSE(nlml->lm_aud_cookies, idx2, acp)) {
+				if (acp->ac_lmp != lmp) {
+					alist_delete(nlml->lm_aud_cookies,
+					    &idx2);
+					break;
+				}
+			}
+		}
+	}
+
+	/*
 	 * If this is a temporary link-map, put in place to facilitate the
 	 * link-edit or a relocatable object, then the link-map contains no
 	 * information that needs to be cleaned up.
@@ -288,7 +305,7 @@
 			    ((dip->di_flags & MSK_DI_FILTER) == 0))
 				continue;
 
-			remove_plist((Alist **)&(dip->di_info), 1);
+			remove_alist((Alist **)&(dip->di_info), 1);
 		}
 	}
 
@@ -296,7 +313,7 @@
 	 * Deallocate any remaining cruft and free the link-map.
 	 */
 	if (RLIST(lmp))
-		remove_plist(&RLIST(lmp), 1);
+		remove_alist(&RLIST(lmp), 1);
 
 	if (AUDITORS(lmp))
 		audit_desc_cleanup(lmp);
@@ -488,7 +505,7 @@
  * that are apart of this link-map control list.
  */
 static void
-remove_incomplete(Lm_list *lml, Aliste lmco)
+remove_incomplete(Lm_list *lml, Aliste lmco, Rt_map *clmp)
 {
 	Rt_map	*lmp;
 	Lm_cntl	*lmc;
@@ -497,7 +514,20 @@
 	lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
 
 	/*
-	 * First, remove any lists that may point between objects.
+	 * If auditing is in effect, the loading of these objects might have
+	 * resulted in la_objopen() events being posted.  Normally, an
+	 * la_objclose() event is posted after an object's .fini is executed,
+	 * just before the objects are unloaded.  These failed objects do not
+	 * have their .fini's executed, but an la_objclose() event should still
+	 * be posted to any auditors.
+	 */
+	if ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_OBJCLOSE) {
+		for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp))
+			audit_objclose(lmp, clmp);
+	}
+
+	/*
+	 * Remove any lists that may point between objects.
 	 */
 	for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp))
 		remove_lists(lmp, 1);
@@ -508,7 +538,7 @@
 	 * next link-map.
 	 */
 	while ((lmp = lmc->lc_head) != NULL)
-		remove_so(lml, lmp);
+		remove_so(lml, lmp, clmp);
 
 	lmc->lc_head = lmc->lc_tail = NULL;
 }
@@ -541,7 +571,7 @@
 	 * this parent will have callers that are not apart of this dlclose()
 	 * family, and thus would be caught by the CALLERS test below.  However,
 	 * if the caller had itself been dlopen'ed, it may not have any explicit
-	 * callers registered for itself.  Thus, but looking for objects with
+	 * callers registered for itself.  Thus, by looking for objects with
 	 * handles we can ferret out these outsiders.
 	 */
 	for (APLIST_TRAVERSE(HANDLES(lmp), idx, ghp)) {
@@ -869,7 +899,7 @@
 	 * list, and any handle that may have been created.
 	 */
 	if ((lmc->lc_flags & LMC_FLG_RELOCATING) == 0) {
-		remove_incomplete(lml, lmco);
+		remove_incomplete(lml, lmco, clmp);
 
 		if (ghp) {
 			ghp->gh_refcnt = 1;
@@ -981,7 +1011,7 @@
  *  -	Remove the handle descriptors for each deleted object, and hopefully
  *	the whole handle.
  *
- * An handle that can't be deleted is added to an orphans list.  This list is
+ * A handle that can't be deleted is added to an orphans list.  This list is
  * revisited any time another dlclose() request results in handle descriptors
  * being deleted.  These deleted descriptors can be sufficient to allow the
  * final deletion of the orphaned handles.
@@ -1294,14 +1324,6 @@
 		Rt_map	**tobj;
 
 		/*
-		 * If we're being audited tell the audit library that we're
-		 * about to go deleting dependencies.
-		 */
-		if (clmp && ((LIST(clmp)->lm_tflags | AFLAGS(clmp)) &
-		    LML_TFLG_AUD_ACTIVITY))
-			audit_activity(clmp, LA_ACT_DELETE);
-
-		/*
 		 * Sort and fire all fini's of the objects selected for
 		 * deletion.  Note that we have to start our search from the
 		 * link-map head - there's no telling whether this object has
@@ -1317,23 +1339,7 @@
 		    (RT_SORT_DELETE | RT_SORT_FWD))) != NULL) &&
 		    (tobj != (Rt_map **)S_ERROR)) {
 			error = purge_exit_handlers(lml, tobj);
-			call_fini(lml, tobj);
-		}
-
-		/*
-		 * Audit the closure of the dlopen'ed object to any local
-		 * auditors.  Any global auditors would have been caught by
-		 * call_fini(), but as the link-maps CALLERS was removed
-		 * already we do the local auditors explicitly.
-		 */
-		for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
-			Grp_hdl	*ghp = ghp2;
-			Rt_map	*dlmp = ghp->gh_ownlmp;
-
-			if (clmp && dlmp &&
-			    ((LIST(dlmp)->lm_flags & LML_FLG_NOAUDIT) == 0) &&
-			    (AFLAGS(clmp) & LML_TFLG_AUD_OBJCLOSE))
-				_audit_objclose(AUDITORS(clmp)->ad_list, dlmp);
+			call_fini(lml, tobj, clmp);
 		}
 	}
 
@@ -1466,7 +1472,7 @@
 			if ((FLAGS(lmp) & FLG_RT_DELETE) &&
 			    ((flags & GPD_PARENT) == 0)) {
 				tls_modaddrem(lmp, TM_FLG_MODREM);
-				remove_so(LIST(lmp), lmp);
+				remove_so(LIST(lmp), lmp, clmp);
 			}
 		}
 
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg	Tue Jul 20 16:29:51 2010 -0700
@@ -422,6 +422,3 @@
 
 @ MSG_LMID_FMT		"%s%d"
 @ MSG_LMID_MAXED	"ALTMAXEDOUT"
-
-@ MSG_AUD_PLTENTER	"la_pltenter"
-@ MSG_AUD_SYMBIND	"la_symbind"
--- a/usr/src/cmd/sgs/rtld/common/setup.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/setup.c	Tue Jul 20 16:29:51 2010 -0700
@@ -133,7 +133,7 @@
 		    PD_FLG_EXTLOAD, 0) != 0)
 			nlmp = load_one(&lml_main, ALIST_OFF_DATA, palp, *clmp,
 			    MODE(mlmp), flags, 0, NULL);
-		remove_plist(&palp, 0);
+		remove_alist(&palp, 0);
 		if (rtld_flags & RT_FL_SECURE)
 			rtld_flags2 &= ~RT_FL2_FTL2WARN;
 		if (nlmp && (bind_one(*clmp, nlmp, BND_NEEDED) == 0))
@@ -333,8 +333,8 @@
 	if (alist_append(&lml_rtld.lm_lists, NULL, sizeof (Lm_cntl),
 	    AL_CNT_LMLISTS) == NULL)
 		return (0);
-	lml_rtld.lm_flags |= (LML_FLG_RTLDLM | LML_FLG_NOAUDIT |
-	    LML_FLG_HOLDLOCK);
+	lml_rtld.lm_flags |= (LML_FLG_RTLDLM | LML_FLG_HOLDLOCK);
+	lml_rtld.lm_tflags |= LML_TFLG_NOAUDIT;
 	lml_rtld.lm_lmid = LM_ID_LDSO;
 	lml_rtld.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_LDSO);
 
@@ -427,7 +427,7 @@
 		return (0);
 	if ((rlmp = elf_new_lmp(&lml_rtld, ALIST_OFF_DATA, &fdr,
 	    (Addr)mpp->mr_addr, (size_t)((uintptr_t)eaddr - (uintptr_t)ld_base),
-	    NULL, NULL)) == NULL)
+	    NULL, NULL, NULL)) == NULL)
 		return (0);
 
 	MMAPS(rlmp) = mpp;
@@ -481,7 +481,7 @@
 		fdm.fd_dev = status.st_dev;
 		fdm.fd_ino = status.st_ino;
 
-		if ((mlmp = load_file(&lml_main, ALIST_OFF_DATA, &fdm,
+		if ((mlmp = load_file(&lml_main, ALIST_OFF_DATA, NULL, &fdm,
 		    NULL)) == NULL)
 			return (0);
 
@@ -545,7 +545,7 @@
 			    stravl_insert(execname, 0, 0, 0)) == NULL)
 				return (0);
 			if ((mlmp = aout_new_lmp(&lml_main, ALIST_OFF_DATA,
-			    &fdm, 0, 0, aoutdyn, NULL)) == NULL)
+			    &fdm, 0, 0, aoutdyn, NULL, NULL)) == NULL)
 				return (0);
 
 			/*
@@ -678,8 +678,9 @@
 			if ((fdm.fd_nname =
 			    stravl_insert(execname, 0, 0, 0)) == NULL)
 				return (0);
-			if ((mlmp = elf_new_lmp(&lml_main, ALIST_OFF_DATA, &fdm,
-			    (Addr)hmpp->mr_addr, msize, NULL, NULL)) == NULL)
+			if ((mlmp = elf_new_lmp(&lml_main, ALIST_OFF_DATA,
+			    &fdm, (Addr)hmpp->mr_addr, msize,
+			    NULL, NULL, NULL)) == NULL)
 				return (0);
 
 			MMAPS(mlmp) = fmpp;
@@ -1033,7 +1034,7 @@
 	/*
 	 * Load all dependent (needed) objects.
 	 */
-	if (analyze_lmc(&lml_main, ALIST_OFF_DATA, mlmp, NULL) == NULL)
+	if (analyze_lmc(&lml_main, ALIST_OFF_DATA, mlmp, mlmp, NULL) == NULL)
 		return (0);
 
 	/*
@@ -1102,9 +1103,11 @@
 	 */
 	rd_event(&lml_main, RD_PREINIT, 0);
 
-	if ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_ACTIVITY)
+	if (aud_activity ||
+	    ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_ACTIVITY))
 		audit_activity(mlmp, LA_ACT_CONSISTENT);
-	if ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_PREINIT)
+	if (aud_preinit ||
+	    ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_PREINIT))
 		audit_preinit(mlmp);
 
 	/*
@@ -1194,8 +1197,6 @@
 		rt_thr_init(&lml_main);
 	}
 
-	rtld_flags |= RT_FL_APPLIC;
-
 	/*
 	 * Fire all dependencies .init sections.  Identify any unused
 	 * dependencies, and leave the runtime linker - effectively calling
@@ -1213,7 +1214,8 @@
 
 	DBG_CALL(Dbg_util_call_main(mlmp));
 
-	rtld_flags |= RT_FL_OPERATION;
+	rtld_flags |= (RT_FL_OPERATION | RT_FL_APPLIC);
+
 	leave(LIST(mlmp), 0);
 
 	return (mlmp);
--- a/usr/src/cmd/sgs/rtld/common/tsort.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/tsort.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -155,9 +154,9 @@
 	 * each object a group identifier so that cyclic dependent callers can
 	 * be better traced (see trace_sort()), or analyzed for non-use.
 	 */
-	if (((init = (lmflags & LML_FLG_TRC_INIT)) == 0) &&
-	    ((unref = (lmflags & LML_FLG_TRC_UNREF)) == 0) &&
-	    (DBG_ENABLED == 0))
+	init = lmflags & LML_FLG_TRC_INIT;
+	unref = lmflags & LML_FLG_TRC_UNREF;
+	if ((init == 0) && (unref == 0) && (DBG_ENABLED == 0))
 		return (1);
 
 	if (init) {
--- a/usr/src/cmd/sgs/rtld/common/util.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/common/util.c	Tue Jul 20 16:29:51 2010 -0700
@@ -98,26 +98,18 @@
  * We also don't want to trigger multiple RD_ADD/RD_DELETE events any time we
  * enter ld.so.1.
  *
- * With auditors, we may be in the process of relocating a collection of
- * objects, and will leave() ld.so.1 to call the auditor.  At this point we
- * must indicate an RD_CONSISTENT event, but librtld_db will not report an
- * object to the debuggers until relocation processing has been completed on it.
- * To allow for the collection of these objects that are pending relocation, an
- * RD_ADD event is set after completing a series of relocations on the primary
- * link-map control list.
+ * Set an RD_ADD/RD_DELETE event and indicate that an RD_CONSISTENT event is
+ * required later (RT_FL_DBNOTIF):
  *
- * Set an RD_ADD/RD_DELETE event and indicate that an RD_CONSISTENT event is
- * required later (LML_FLG_DBNOTIF):
- *
- *  i	the first time we add or delete an object to the primary link-map
+ *  i.	the first time we add or delete an object to the primary link-map
  *	control list.
- *  ii	the first time we move a secondary link-map control list to the primary
+ *  ii.	the first time we move a secondary link-map control list to the primary
  *	link-map control list (effectively, this is like adding a group of
  *	objects to the primary link-map control list).
  *
- * Set an RD_CONSISTENT event when it is required (LML_FLG_DBNOTIF is set) and
+ * Set an RD_CONSISTENT event when it is required (RT_FL_DBNOTIF is set):
  *
- *  i	each time we leave the runtime linker.
+ *  i.	each time we leave the runtime linker.
  */
 void
 rd_event(Lm_list *lml, rd_event_e event, r_state_e state)
@@ -134,8 +126,6 @@
 	case RD_DLACTIVITY:
 		switch (state) {
 		case RT_CONSISTENT:
-			lml->lm_flags &= ~LML_FLG_DBNOTIF;
-
 			/*
 			 * Do we need to send a notification?
 			 */
@@ -145,8 +135,6 @@
 			break;
 		case RT_ADD:
 		case RT_DELETE:
-			lml->lm_flags |= LML_FLG_DBNOTIF;
-
 			/*
 			 * If we are already in an inconsistent state, no
 			 * notification is required.
@@ -628,8 +616,8 @@
 	 * If the caller is an auditor, and the destination isn't, then don't
 	 * run any .inits (see comments in load_completion()).
 	 */
-	if ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) &&
-	    (LIST(clmp) != LIST(dlmp)))
+	if ((LIST(clmp)->lm_tflags & LML_TFLG_NOAUDIT) &&
+	    ((LIST(dlmp)->lm_tflags & LML_TFLG_NOAUDIT) == 0))
 		return;
 
 	if ((dlmp == clmp) || (rtld_flags & RT_FL_INITFIRST))
@@ -680,13 +668,16 @@
 	 * Call the .*array[] entries
 	 */
 	for (ndx = start; ndx != stop; ndx += incr) {
-		void (*fptr)(void) = (void(*)())array[ndx];
+		uint_t	rtldflags;
+		void	(*fptr)(void) = (void(*)())array[ndx];
 
 		DBG_CALL(Dbg_util_call_array(lmp, (void *)fptr, ndx, shtype));
 
+		APPLICATION_ENTER(rtldflags);
 		leave(LIST(lmp), 0);
 		(*fptr)();
 		(void) enter(0);
+		APPLICATION_RETURN(rtldflags);
 	}
 }
 
@@ -717,7 +708,6 @@
 	for (_tobj = _nobj = tobj, _nobj++; *_tobj != NULL; _tobj++, _nobj++) {
 		Rt_map	*lmp = *_tobj;
 		void	(*iptr)() = INIT(lmp);
-		uint_t	rtldflags;
 
 		if (FLAGS(lmp) & FLG_RT_INITCALL)
 			continue;
@@ -725,17 +715,6 @@
 		FLAGS(lmp) |= FLG_RT_INITCALL;
 
 		/*
-		 * It is possible, that during the initial handshake with libc,
-		 * an interposition object has resolved a symbol binding, and
-		 * that this objects .init must be fired.  As we're about to
-		 * run user code, make sure any dynamic linking errors remain
-		 * internal (ie., only obtainable from dlerror()), and are not
-		 * flushed to stderr.
-		 */
-		rtldflags = (rtld_flags & RT_FL_APPLIC) ? 0 : RT_FL_APPLIC;
-		rtld_flags |= rtldflags;
-
-		/*
 		 * Establish an initfirst state if necessary - no other inits
 		 * will be fired (because of additional relocation bindings)
 		 * when in this state.
@@ -747,9 +726,13 @@
 			DBG_CALL(Dbg_util_call_init(lmp, flag));
 
 		if (iptr) {
+			uint_t	rtldflags;
+
+			APPLICATION_ENTER(rtldflags);
 			leave(LIST(lmp), 0);
 			(*iptr)();
 			(void) enter(0);
+			APPLICATION_RETURN(rtldflags);
 		}
 
 		call_array(INITARRAY(lmp), INITARRAYSZ(lmp), lmp,
@@ -759,11 +742,6 @@
 			DBG_CALL(Dbg_util_call_init(lmp, DBG_INIT_DONE));
 
 		/*
-		 * Return to a non-application setting if necessary.
-		 */
-		rtld_flags &= ~rtldflags;
-
-		/*
 		 * Set the initdone flag regardless of whether this object
 		 * actually contains an .init section.  This flag prevents us
 		 * from processing this section again for an .init and also
@@ -796,20 +774,18 @@
 }
 
 /*
- * Function called by atexit(3C).  Calls all .fini sections related with the
- * mains dependent shared libraries in the order in which the shared libraries
- * have been loaded.  Skip any .fini defined in the main executable, as this
- * will be called by crt0 (main was never marked as initdone).
+ * Call .fini sections for the topologically sorted list of objects.  This
+ * routine is called from remove_hdl() for any objects being torn down as part
+ * of a dlclose() operation, and from atexit() processing for all the remaining
+ * objects within the process.
  */
 void
-call_fini(Lm_list * lml, Rt_map ** tobj)
+call_fini(Lm_list *lml, Rt_map **tobj, Rt_map *clmp)
 {
 	Rt_map **_tobj;
 
 	for (_tobj = tobj; *_tobj != NULL; _tobj++) {
-		Rt_map		*clmp, * lmp = *_tobj;
-		Aliste		idx;
-		Bnd_desc	*bdp;
+		Rt_map		*lmp = *_tobj;
 
 		/*
 		 * Only fire a .fini if the objects corresponding .init has
@@ -827,9 +803,13 @@
 			    SHT_FINI_ARRAY);
 
 			if (fptr) {
-				leave(LIST(lmp), 0);
+				uint_t	rtldflags;
+
+				APPLICATION_ENTER(rtldflags);
+				leave(lml, 0);
 				(*fptr)();
 				(void) enter(0);
+				APPLICATION_RETURN(rtldflags);
 			}
 		}
 
@@ -840,40 +820,25 @@
 			continue;
 
 		/*
-		 * Audit `close' operations at this point.  The library has
-		 * exercised its last instructions (regardless of whether it
-		 * will be unmapped or not).
-		 *
-		 * First call any global auditing.
-		 */
-		if (lml->lm_tflags & LML_TFLG_AUD_OBJCLOSE)
-			_audit_objclose(auditors->ad_list, lmp);
-
-		/*
-		 * Finally determine whether this object has local auditing
-		 * requirements by inspecting itself and then its dependencies.
+		 * This object has exercised its last instructions (regardless
+		 * of whether it will be unmapped or not).  Audit this closure.
 		 */
-		if ((lml->lm_flags & LML_FLG_LOCAUDIT) == 0)
-			continue;
-
-		if (AFLAGS(lmp) & LML_TFLG_AUD_OBJCLOSE)
-			_audit_objclose(AUDITORS(lmp)->ad_list, lmp);
-
-		for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp)) {
-			clmp = bdp->b_caller;
-
-			if (AFLAGS(clmp) & LML_TFLG_AUD_OBJCLOSE) {
-				_audit_objclose(AUDITORS(clmp)->ad_list, lmp);
-				break;
-			}
-		}
+		if ((lml->lm_tflags & LML_TFLG_NOAUDIT) == 0)
+			audit_objclose(lmp, clmp);
 	}
+
 	DBG_CALL(Dbg_bind_plt_summary(lml, M_MACH, pltcnt21d, pltcnt24d,
 	    pltcntu32, pltcntu44, pltcntfull, pltcntfar));
 
 	free(tobj);
 }
 
+/*
+ * Function called by atexit(3C).  Calls all .fini sections within the objects
+ * that make up the process.  As .fini processing is the last opportunity for
+ * any new bindings to be established, this is also a convenient location to
+ * check for unused objects.
+ */
 void
 atexit_fini()
 {
@@ -895,19 +860,7 @@
 	 */
 	if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
 	    (tobj != (Rt_map **)S_ERROR))
-		call_fini(lml, tobj);
-
-	/*
-	 * Add an explicit close to main and ld.so.1.  Although main's .fini is
-	 * collected in call_fini() to provide for FINITARRAY processing, its
-	 * audit_objclose is explicitly skipped.  This provides for it to be
-	 * called last, here.  This is the reverse of the explicit calls to
-	 * audit_objopen() made in setup().
-	 */
-	if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK) {
-		audit_objclose(lmp, (Rt_map *)lml_rtld.lm_head);
-		audit_objclose(lmp, lmp);
-	}
+		call_fini(lml, tobj, NULL);
 
 	/*
 	 * Now that all .fini code has been run, see what unreferenced objects
@@ -916,18 +869,17 @@
 	unused(lml);
 
 	/*
-	 * Traverse any alternative link-map lists.
+	 * Traverse any alternative link-map lists, looking for non-auditors.
 	 */
 	for (APLIST_TRAVERSE(dynlm_list, idx, lml)) {
 		/*
 		 * Ignore the base-link-map list, which has already been
-		 * processed, and the runtime linkers link-map list, which is
-		 * typically processed last.
+		 * processed, the runtime linkers link-map list, which is
+		 * processed last, and any auditors.
 		 */
-		if (lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM))
-			continue;
-
-		if ((lmp = (Rt_map *)lml->lm_head) == NULL)
+		if ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) ||
+		    (lml->lm_tflags & LML_TFLG_AUD_MASK) ||
+		    ((lmp = (Rt_map *)lml->lm_head) == NULL))
 			continue;
 
 		lml->lm_flags |= LML_FLG_ATEXIT;
@@ -938,7 +890,49 @@
 		 */
 		if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
 		    (tobj != (Rt_map **)S_ERROR))
-			call_fini(lml, tobj);
+			call_fini(lml, tobj, NULL);
+
+		unused(lml);
+	}
+
+	/*
+	 * Add an explicit close to main and ld.so.1.  Although main's .fini is
+	 * collected in call_fini() to provide for FINITARRAY processing, its
+	 * audit_objclose is explicitly skipped.  This provides for it to be
+	 * called last, here.  This is the reverse of the explicit calls to
+	 * audit_objopen() made in setup().
+	 */
+	lml = &lml_main;
+	lmp = (Rt_map *)lml->lm_head;
+
+	if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK) {
+		audit_objclose((Rt_map *)lml_rtld.lm_head, lmp);
+		audit_objclose(lmp, lmp);
+	}
+
+	/*
+	 * Traverse any alternative link-map lists, looking for non-auditors.
+	 */
+	for (APLIST_TRAVERSE(dynlm_list, idx, lml)) {
+		/*
+		 * Ignore the base-link-map list, which has already been
+		 * processed, the runtime linkers link-map list, which is
+		 * processed last, and any non-auditors.
+		 */
+		if ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) ||
+		    ((lml->lm_tflags & LML_TFLG_AUD_MASK) == 0) ||
+		    ((lmp = (Rt_map *)lml->lm_head) == NULL))
+			continue;
+
+		lml->lm_flags |= LML_FLG_ATEXIT;
+		lml->lm_flags &= ~LML_FLG_INTRPOSETSORT;
+
+		/*
+		 * Reverse topologically sort the link-map for .fini execution.
+		 */
+		if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
+		    (tobj != (Rt_map **)S_ERROR))
+			call_fini(lml, tobj, NULL);
 
 		unused(lml);
 	}
@@ -954,7 +948,7 @@
 
 	if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != NULL) &&
 	    (tobj != (Rt_map **)S_ERROR))
-		call_fini(lml, tobj);
+		call_fini(lml, tobj, NULL);
 
 	leave(&lml_main, 0);
 }
@@ -1046,15 +1040,15 @@
 	(lml->lm_obj)++;
 
 	/*
-	 * If we're about to add a new object to the main link-map control list,
-	 * alert the debuggers that we are about to mess with this list.
-	 * Additions of individual objects to the main link-map control list
-	 * occur during initial setup as the applications immediate dependencies
-	 * are loaded.  Individual objects are also loaded on the main link-map
-	 * control list of new alternative link-map control lists.
+	 * If we're about to add a new object to the main link-map control
+	 * list, alert the debuggers.  Additions of individual objects to the
+	 * main link-map control list occur during initial setup as the
+	 * applications immediate dependencies are loaded.  Additional objects
+	 * are loaded on the main link-map control list after they have been
+	 * fully initialized on an alternative link-map control list.  See
+	 * lm_move().
 	 */
-	if ((lmco == ALIST_OFF_DATA) &&
-	    ((lml->lm_flags & LML_FLG_DBNOTIF) == 0))
+	if (lmco == ALIST_OFF_DATA)
 		rd_event(lml, RD_DLACTIVITY, RT_ADD);
 
 	/* LINTED */
@@ -1162,7 +1156,7 @@
  * Delete an item from the specified link map control list.
  */
 void
-lm_delete(Lm_list *lml, Rt_map *lmp)
+lm_delete(Lm_list *lml, Rt_map *lmp, Rt_map *clmp)
 {
 	Lm_cntl	*lmc;
 
@@ -1175,12 +1169,19 @@
 
 	/*
 	 * If we're about to delete an object from the main link-map control
-	 * list, alert the debuggers that we are about to mess with this list.
+	 * list, alert the debuggers.
 	 */
-	if ((CNTL(lmp) == ALIST_OFF_DATA) &&
-	    ((lml->lm_flags & LML_FLG_DBNOTIF) == 0))
+	if (CNTL(lmp) == ALIST_OFF_DATA)
 		rd_event(lml, RD_DLACTIVITY, RT_DELETE);
 
+	/*
+	 * If we're being audited tell the audit library that we're
+	 * about to go deleting dependencies.
+	 */
+	if (clmp && (aud_activity ||
+	    ((LIST(clmp)->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_ACTIVITY)))
+		audit_activity(clmp, LA_ACT_DELETE);
+
 	/* LINTED */
 	lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, CNTL(lmp));
 
@@ -1222,12 +1223,11 @@
 
 	/*
 	 * If we're about to add a new family of objects to the main link-map
-	 * control list, alert the debuggers that we are about to mess with this
-	 * list.  Additions of object families to the main link-map control
-	 * list occur during lazy loading, filtering and dlopen().
+	 * control list, alert the debuggers.  Additions of object families to
+	 * the main link-map control list occur during lazy loading, filtering
+	 * and dlopen().
 	 */
-	if ((plmco == ALIST_OFF_DATA) &&
-	    ((lml->lm_flags & LML_FLG_DBNOTIF) == 0))
+	if (plmco == ALIST_OFF_DATA)
 		rd_event(lml, RD_DLACTIVITY, RT_ADD);
 
 	DBG_CALL(Dbg_file_cntl(lml, nlmco, plmco));
@@ -1526,8 +1526,10 @@
 		} 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
-			 * configuration file, not documented for general use.
+			 * This variable is not documented for general use.
+			 * Although originaly designed for internal use with
+			 * crle(1), this variable is in use by the Studio
+			 * auditing tools.  Hence, it can't be removed.
 			 */
 			select |= SEL_ACT_SPEC_2;
 			variable = ENV_FLG_CONFGEN;
@@ -1625,8 +1627,10 @@
 		} else if ((len == MSG_LD_LOADAVAIL_SIZE) && (strncmp(s1,
 		    MSG_ORIG(MSG_LD_LOADAVAIL), MSG_LD_LOADAVAIL_SIZE) == 0)) {
 			/*
-			 * Internal use by crle(1), not documented for general
-			 * use.
+			 * This variable is not documented for general use.
+			 * Although originaly designed for internal use with
+			 * crle(1), this variable is in use by the Studio
+			 * auditing tools.  Hence, it can't be removed.
 			 */
 			select |= SEL_ACT_LML;
 			val = LML_FLG_LOADAVAIL;
@@ -2892,7 +2896,7 @@
 	prf.pr_buf = prf.pr_cur = nextptr;
 	prf.pr_len = ERRSIZE - (nextptr - errbuf);
 
-	if (!(rtld_flags & RT_FL_APPLIC))
+	if ((rtld_flags & RT_FL_APPLIC) == 0)
 		prf.pr_fd = 2;
 	else
 		prf.pr_fd = -1;
@@ -3348,33 +3352,23 @@
 
 /*
  * Generic cleanup routine called prior to returning control to the user.
- * Insures that any ld.so.1 specific file descriptors or temporary mapping are
+ * Ensures that any ld.so.1 specific file descriptors or temporary mapping are
  * released, and any locks dropped.
  */
 void
 leave(Lm_list *lml, int flags)
 {
-	Lm_list		*elml = lml;
-	Rt_map		*clmp;
-	Aliste		idx;
-
 	/*
-	 * Alert the debuggers that the link-maps are consistent.  Note, in the
-	 * case of tearing down a whole link-map list, lml will be null.  In
-	 * this case use the main link-map list to test for a notification.
+	 * Alert the debuggers that the link-maps are consistent.
 	 */
-	if (elml == NULL)
-		elml = &lml_main;
-	if (elml->lm_flags & LML_FLG_DBNOTIF)
-		rd_event(elml, RD_DLACTIVITY, RT_CONSISTENT);
+	rd_event(lml, RD_DLACTIVITY, RT_CONSISTENT);
 
 	/*
 	 * Alert any auditors that the link-maps are consistent.
 	 */
-	for (APLIST_TRAVERSE(elml->lm_actaudit, idx, clmp)) {
-		audit_activity(clmp, LA_ACT_CONSISTENT);
-
-		aplist_delete(elml->lm_actaudit, &idx);
+	if (lml->lm_flags & LML_FLG_ACTAUDIT) {
+		audit_activity(lml->lm_head, LA_ACT_CONSISTENT);
+		lml->lm_flags &= ~LML_FLG_ACTAUDIT;
 	}
 
 	if (nu_fd != FD_UNAVAIL) {
@@ -3402,7 +3396,7 @@
 	 *  -	 The ld.so.1's link-map list.
 	 *  -	 The auditor's link-map if the environment is pre-UPM.
 	 */
-	if (lml && (lml->lm_flags & LML_FLG_HOLDLOCK))
+	if (lml->lm_flags & LML_FLG_HOLDLOCK)
 		return;
 
 	if (rt_bind_clear(0) & THR_FLG_RTLD) {
--- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <msg.h>
@@ -708,7 +707,6 @@
 static const mdb_bitmask_t lml_flags_bit[] = {
 	{ MSG_ORIG(MSG_LFL_BASELM), LML_FLG_BASELM, LML_FLG_BASELM },
 	{ MSG_ORIG(MSG_LFL_RTLDLM), LML_FLG_RTLDLM, LML_FLG_RTLDLM },
-	{ MSG_ORIG(MSG_LFL_NOAUDIT), LML_FLG_NOAUDIT, LML_FLG_NOAUDIT },
 	{ MSG_ORIG(MSG_LFL_PLTREL), LML_FLG_PLTREL, LML_FLG_PLTREL },
 	{ MSG_ORIG(MSG_LFL_HOLDLOCK), LML_FLG_HOLDLOCK, LML_FLG_HOLDLOCK },
 	{ MSG_ORIG(MSG_LFL_ENVIRON), LML_FLG_ENVIRON, LML_FLG_ENVIRON },
@@ -716,7 +714,6 @@
 	{ MSG_ORIG(MSG_LFL_LOCAUDIT), LML_FLG_LOCAUDIT, LML_FLG_LOCAUDIT },
 	{ MSG_ORIG(MSG_LFL_LOADAVAIL), LML_FLG_LOADAVAIL, LML_FLG_LOADAVAIL },
 	{ MSG_ORIG(MSG_LFL_IGNRELERR), LML_FLG_IGNRELERR, LML_FLG_IGNRELERR },
-	{ MSG_ORIG(MSG_LFL_DBNOTIF), LML_FLG_DBNOTIF, LML_FLG_DBNOTIF },
 	{ MSG_ORIG(MSG_LFL_STARTREL), LML_FLG_STARTREL, LML_FLG_STARTREL },
 	{ MSG_ORIG(MSG_LFL_ATEXIT), LML_FLG_ATEXIT, LML_FLG_ATEXIT },
 	{ MSG_ORIG(MSG_LFL_OBJADDED), LML_FLG_OBJADDED, LML_FLG_OBJADDED },
@@ -753,6 +750,7 @@
 static const mdb_bitmask_t lml_tflags_bit[] = {
 	{ MSG_ORIG(MSG_LTFL_NOLAZYLD), LML_TFLG_NOLAZYLD, LML_TFLG_NOLAZYLD },
 	{ MSG_ORIG(MSG_LTFL_NODIRECT), LML_TFLG_NODIRECT, LML_TFLG_NODIRECT },
+	{ MSG_ORIG(MSG_LTFL_NOAUDIT), LML_TFLG_NOAUDIT, LML_TFLG_NOAUDIT },
 	{ MSG_ORIG(MSG_LTFL_LOADFLTR), LML_TFLG_LOADFLTR, LML_TFLG_LOADFLTR },
 
 	{ MSG_ORIG(MSG_LTFL_AUD_PREINIT), LML_TFLG_AUD_PREINIT,
--- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg	Tue Jul 20 16:29:51 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 @ _START_
@@ -145,7 +144,6 @@
 
 @ MSG_LFL_BASELM		"BASELM"
 @ MSG_LFL_RTLDLM		"RTLDLM"
-@ MSG_LFL_NOAUDIT		"NO-AUDIT"
 @ MSG_LFL_PLTREL		"DEFERRED-PLT-RELOCATION"
 @ MSG_LFL_HOLDLOCK		"HOLD-LOCK"
 @ MSG_LFL_ENVIRON		"ENVIRON"
@@ -153,7 +151,6 @@
 @ MSG_LFL_LOCAUDIT		"LOCAL-AUDIT"
 @ MSG_LFL_LOADAVAIL		"LOAD-AVAILABLE"
 @ MSG_LFL_IGNRELERR		"IGNORE-RELOCATION-ERROR"
-@ MSG_LFL_DBNOTIF		"DBG-NOTIFY"
 @ MSG_LFL_STARTREL		"START-RELOCATION"
 @ MSG_LFL_ATEXIT		"ATEXIT"
 @ MSG_LFL_OBJADDED		"OBJECT-ADDED"
@@ -176,6 +173,7 @@
 
 @ MSG_LTFL_NOLAZYLD		"NO-LAZY-LOADING"
 @ MSG_LTFL_NODIRECT		"NO-DIRECT"
+@ MSG_LTFL_NOAUDIT		"NO-AUDIT"
 @ MSG_LTFL_LOADFLTR		"LOAD-FILTER"
 
 @ MSG_LTFL_AUD_PREINIT		"AUD_PREINIT"
--- a/usr/src/head/link.h	Tue Jul 20 16:38:52 2010 -0400
+++ b/usr/src/head/link.h	Tue Jul 20 16:29:51 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _LINK_H
@@ -126,8 +125,9 @@
 #define	LAV_VERSION2		2
 #define	LAV_VERSION3		3
 #define	LAV_VERSION4		4
-#define	LAV_CURRENT		LAV_VERSION4
-#define	LAV_NUM			5
+#define	LAV_VERSION5		5
+#define	LAV_CURRENT		LAV_VERSION5
+#define	LAV_NUM			6
 
 /*
  * Flags that can be or'd into the la_objopen() return code
@@ -165,6 +165,7 @@
 #define	LA_ACT_CONSISTENT	0x00	/* add/deletion of objects complete */
 #define	LA_ACT_ADD		0x01	/* objects being added */
 #define	LA_ACT_DELETE		0x02	/* objects being deleted */
+#define	LA_ACT_MAX		3
 
 
 #ifndef	_KERNEL