changeset 14012:c1f1ea4feeb1

3673 core dumping is abysmally slow 3671 left behind enemy lines, agent LWP can go rogue 3670 add visibility into agent LWP's spymaster Reviewed by: Keith M Wesolowski <keith.wesolowski@joyent.com> Reviewed by: Joshua M. Clulow <jmc@joyent.com> Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Bryan Cantrill <bryan@joyent.com>
date Tue, 02 Apr 2013 13:52:19 -0700
parents 779e63d911a5
children 1a1202688ff3
files usr/src/cmd/ptools/pflags/pflags.c usr/src/cmd/sgs/elfdump/common/corenote.c usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/libconv/common/corenote.c usr/src/cmd/sgs/libconv/common/corenote.msg usr/src/cmd/sgs/libconv/common/phdr.c usr/src/cmd/sgs/libconv/common/phdr.msg usr/src/lib/libproc/common/Pcontrol.h usr/src/lib/libproc/common/Pcore.c usr/src/lib/libproc/common/Pgcore.c usr/src/lib/libproc/common/Plwpregs.c usr/src/lib/libproc/common/Psyscall.c usr/src/lib/libproc/common/libproc.h usr/src/lib/libproc/common/mapfile-vers usr/src/man/man4/core.4 usr/src/man/man4/proc.4 usr/src/uts/common/exec/elf/elf.c usr/src/uts/common/exec/elf/elf_notes.c usr/src/uts/common/fs/proc/prcontrol.c usr/src/uts/common/fs/proc/prdata.h usr/src/uts/common/fs/proc/prsubr.c usr/src/uts/common/fs/proc/prvnops.c usr/src/uts/common/os/core.c usr/src/uts/common/os/lwp.c usr/src/uts/common/sys/elf.h usr/src/uts/common/sys/klwp.h usr/src/uts/common/sys/proc.h usr/src/uts/common/sys/prsystm.h usr/src/uts/intel/ia32/ml/modstubs.s usr/src/uts/sparc/ml/modstubs.s
diffstat 30 files changed, 631 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/ptools/pflags/pflags.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/ptools/pflags/pflags.c	Tue Apr 02 13:52:19 2013 -0700
@@ -24,6 +24,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
 #include <stdio.h>
 #include <stdio_ext.h>
 #include <stdlib.h>
@@ -258,6 +262,7 @@
 	int flags;
 	uint32_t sighold, sighold1, sighold2;
 	uint32_t sigpend, sigpend1, sigpend2;
+	psinfo_t ps;
 	int cursig;
 	char buf[32];
 
@@ -331,6 +336,17 @@
 		(void) printf("\tcursig = %s\n",
 		    proc_signame(cursig, buf, sizeof (buf)));
 
+	if ((flags & PR_AGENT) &&
+	    Plwp_getspymaster(Pr, pip->pr_lwpid, &ps) == 0) {
+		time_t time = ps.pr_time.tv_sec;
+		char t[64];
+
+		(void) strftime(t, sizeof (t), "%F:%H.%M.%S", localtime(&time));
+
+		(void) printf("\tspymaster = pid %d, \"%s\" at %s\n",
+		    (int)ps.pr_pid, ps.pr_psargs, t);
+	}
+
 	if (rflag) {
 		if (Pstate(Pr) == PS_DEAD || (arg->pflags & PR_STOPPED)) {
 #if defined(__sparc) && defined(_ILP32)
--- a/usr/src/cmd/sgs/elfdump/common/corenote.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/corenote.c	Tue Apr 02 13:52:19 2013 -0700
@@ -25,6 +25,7 @@
  */
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <stdlib.h>
@@ -1437,7 +1438,6 @@
 	indent_exit(state);
 }
 
-
 /*
  * Output information from prpsinfo_t structure.
  */
@@ -1849,6 +1849,13 @@
 		state.ns_v2col = 54;
 		dump_prfdinfo(&state, MSG_ORIG(MSG_CNOTE_DESC_PRFDINFO_T));
 		return (CORENOTE_R_OK);
+
+	case NT_SPYMASTER:
+		state.ns_vcol = 25;
+		state.ns_t2col = 45;
+		state.ns_v2col = 58;
+		dump_psinfo(&state, MSG_ORIG(MSG_CNOTE_DESC_PSINFO_T));
+		return (CORENOTE_R_OK);
 	}
 
 	return (CORENOTE_R_BADTYPE);
--- a/usr/src/cmd/sgs/include/conv.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/sgs/include/conv.h	Tue Apr 02 13:52:19 2013 -0700
@@ -277,7 +277,7 @@
 } Conv_bnd_obj_buf_t;
 
 /* conv_phdr_flags() */
-#define	CONV_PHDR_FLAGS_BUFSIZE		57
+#define	CONV_PHDR_FLAGS_BUFSIZE		88
 typedef union {
 	Conv_inv_buf_t			inv_buf;
 	char				buf[CONV_PHDR_FLAGS_BUFSIZE];
--- a/usr/src/cmd/sgs/libconv/common/corenote.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/sgs/libconv/common/corenote.c	Tue Apr 02 13:52:19 2013 -0700
@@ -25,6 +25,7 @@
  */
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 /*
@@ -55,9 +56,10 @@
 		MSG_NT_UTSNAME,		MSG_NT_LWPSTATUS,
 		MSG_NT_LWPSINFO,	MSG_NT_PRPRIV,
 		MSG_NT_PRPRIVINFO,	MSG_NT_CONTENT,
-		MSG_NT_ZONENAME,	MSG_NT_FDINFO
+		MSG_NT_ZONENAME,	MSG_NT_FDINFO,
+		MSG_NT_SPYMASTER
 	};
-#if NT_NUM != NT_FDINFO
+#if NT_NUM != NT_SPYMASTER
 #error "NT_NUM has grown. Update core note types[]"
 #endif
 	static const conv_ds_msg_t ds_types = {
--- a/usr/src/cmd/sgs/libconv/common/corenote.msg	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/sgs/libconv/common/corenote.msg	Tue Apr 02 13:52:19 2013 -0700
@@ -24,6 +24,7 @@
 # Use is subject to license terms.
 #
 # Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
 #
 
 @ MSG_NT_PRSTATUS		"[ NT_PRSTATUS ]"
@@ -46,6 +47,7 @@
 @ MSG_NT_CONTENT		"[ NT_CONTENT ]"
 @ MSG_NT_ZONENAME		"[ NT_ZONENAME ]"
 @ MSG_NT_FDINFO			"[ NT_FDINFO ]"
+@ MSG_NT_SPYMASTER		"[ NT_SPYMASTER ]"
 
 
 @ MSG_AUXV_AF_SUN_SETUGID		"AF_SUN_SETUGID"
--- a/usr/src/cmd/sgs/libconv/common/phdr.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/sgs/libconv/common/phdr.c	Tue Apr 02 13:52:19 2013 -0700
@@ -215,6 +215,8 @@
 		MSG_PF_W_CF_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_PF_R_CF_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_PF_SUNW_FAILURE_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_PF_SUNW_KILLED_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_PF_SUNW_SIGINFO_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
 
 	/*
@@ -241,6 +243,8 @@
 		{ PF_W,			ALL,	MSG_PF_W_CF },
 		{ PF_R,			ALL,	MSG_PF_R_CF },
 		{ PF_SUNW_FAILURE,	SOL,	MSG_PF_SUNW_FAILURE_CF },
+		{ PF_SUNW_KILLED,	SOL,	MSG_PF_SUNW_KILLED_CF },
+		{ PF_SUNW_SIGINFO,	SOL,	MSG_PF_SUNW_SIGINFO_CF },
 		{ 0 }
 	};
 	static const Val_desc2 vda_nf[] = {
@@ -248,6 +252,8 @@
 		{ PF_W,			ALL,	MSG_PF_W_NF },
 		{ PF_R,			ALL,	MSG_PF_R_NF },
 		{ PF_SUNW_FAILURE,	SOL,	MSG_PF_SUNW_FAILURE_NF },
+		{ PF_SUNW_KILLED,	SOL,	MSG_PF_SUNW_KILLED_NF },
+		{ PF_SUNW_SIGINFO,	SOL,	MSG_PF_SUNW_SIGINFO_NF },
 		{ 0 }
 	};
 
--- a/usr/src/cmd/sgs/libconv/common/phdr.msg	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/cmd/sgs/libconv/common/phdr.msg	Tue Apr 02 13:52:19 2013 -0700
@@ -105,5 +105,9 @@
 @ MSG_PF_R_NF				 "r"
 @ MSG_PF_SUNW_FAILURE_CF	 "PF_SUNW_FAILURE"		# 0x00100000
 @ MSG_PF_SUNW_FAILURE_NF		 "sunw_failure"
+@ MSG_PF_SUNW_KILLED_CF		 "PF_SUNW_KILLED"		# 0x00200000
+@ MSG_PF_SUNW_KILLED_NF			"sunw_killed"
+@ MSG_PF_SUNW_SIGINFO_CF	 "PF_SUNW_SIGINFO"		# 0x00400000
+@ MSG_PF_SUNW_SIGINFO_NF		"sunw_siginfo"
 
 @ MSG_GBL_ZERO		"0"
--- a/usr/src/lib/libproc/common/Pcontrol.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/Pcontrol.h	Tue Apr 02 13:52:19 2013 -0700
@@ -24,6 +24,7 @@
  */
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #ifndef	_PCONTROL_H
@@ -233,6 +234,9 @@
 	char	*zoneroot;	/* cached path to zone root */
 	plist_t	fd_head;	/* head of file desc info list */
 	int	num_fd;		/* number of file descs in list */
+	uintptr_t map_missing;	/* first missing mapping in core due to sig */
+	siginfo_t killinfo;	/* signal that interrupted core dump */
+	psinfo_t spymaster;	/* agent LWP's spymaster, if any */
 };
 
 /* flags */
--- a/usr/src/lib/libproc/common/Pcore.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/Pcore.c	Tue Apr 02 13:52:19 2013 -0700
@@ -24,11 +24,13 @@
  */
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
 #include <sys/utsname.h>
 #include <sys/sysmacros.h>
+#include <sys/proc.h>
 
 #include <alloca.h>
 #include <rtld_db.h>
@@ -40,6 +42,7 @@
 #include <errno.h>
 #include <gelf.h>
 #include <stddef.h>
+#include <signal.h>
 
 #include "libproc.h"
 #include "Pcontrol.h"
@@ -672,6 +675,35 @@
 #endif	/* __sparcv9 */
 #endif	/* __sparc */
 
+static int
+note_spymaster(struct ps_prochandle *P, size_t nbytes)
+{
+#ifdef _LP64
+	if (P->core->core_dmodel == PR_MODEL_ILP32) {
+		psinfo32_t ps32;
+
+		if (nbytes < sizeof (psinfo32_t) ||
+		    read(P->asfd, &ps32, sizeof (ps32)) != sizeof (ps32))
+			goto err;
+
+		psinfo_32_to_n(&ps32, &P->spymaster);
+	} else
+#endif
+	if (nbytes < sizeof (psinfo_t) || read(P->asfd,
+	    &P->spymaster, sizeof (psinfo_t)) != sizeof (psinfo_t))
+		goto err;
+
+	dprintf("spymaster pr_fname = <%s>\n", P->psinfo.pr_fname);
+	dprintf("spymaster pr_psargs = <%s>\n", P->psinfo.pr_psargs);
+	dprintf("spymaster pr_wstat = 0x%x\n", P->psinfo.pr_wstat);
+
+	return (0);
+
+err:
+	dprintf("Pgrab_core: failed to read NT_SPYMASTER\n");
+	return (-1);
+}
+
 /*ARGSUSED*/
 static int
 note_notsup(struct ps_prochandle *P, size_t nbytes)
@@ -725,8 +757,72 @@
 	note_content,		/* 20	NT_CONTENT		*/
 	note_zonename,		/* 21	NT_ZONENAME		*/
 	note_fdinfo,		/* 22	NT_FDINFO		*/
+	note_spymaster,		/* 23	NT_SPYMASTER		*/
 };
 
+static void
+core_report_mapping(struct ps_prochandle *P, GElf_Phdr *php)
+{
+	prkillinfo_t killinfo;
+	siginfo_t *si = &killinfo.prk_info;
+	char signame[SIG2STR_MAX], sig[64], info[64];
+	void *addr = (void *)(uintptr_t)php->p_vaddr;
+
+	const char *errfmt = "core file data for mapping at %p not saved: %s\n";
+	const char *incfmt = "core file incomplete due to %s%s\n";
+	const char *msgfmt = "mappings at and above %p are missing\n";
+
+	if (!(php->p_flags & PF_SUNW_KILLED)) {
+		int err = 0;
+
+		(void) pread64(P->asfd, &err,
+		    sizeof (err), (off64_t)php->p_offset);
+
+		Perror_printf(P, errfmt, addr, strerror(err));
+		dprintf(errfmt, addr, strerror(err));
+		return;
+	}
+
+	if (!(php->p_flags & PF_SUNW_SIGINFO))
+		return;
+
+	(void) memset(&killinfo, 0, sizeof (killinfo));
+
+	(void) pread64(P->asfd, &killinfo,
+	    sizeof (killinfo), (off64_t)php->p_offset);
+
+	/*
+	 * While there is (or at least should be) only one segment that has
+	 * PF_SUNW_SIGINFO set, the signal information there is globally
+	 * useful (even if only to those debugging libproc consumers); we hang
+	 * the signal information gleaned here off of the ps_prochandle.
+	 */
+	P->map_missing = php->p_vaddr;
+	P->killinfo = killinfo.prk_info;
+
+	if (sig2str(si->si_signo, signame) == -1) {
+		(void) snprintf(sig, sizeof (sig),
+		    "<Unknown signal: 0x%x>, ", si->si_signo);
+	} else {
+		(void) snprintf(sig, sizeof (sig), "SIG%s, ", signame);
+	}
+
+	if (si->si_code == SI_USER || si->si_code == SI_QUEUE) {
+		(void) snprintf(info, sizeof (info),
+		    "pid=%d uid=%d zone=%d ctid=%d",
+		    si->si_pid, si->si_uid, si->si_zoneid, si->si_ctid);
+	} else {
+		(void) snprintf(info, sizeof (info),
+		    "code=%d", si->si_code);
+	}
+
+	Perror_printf(P, incfmt, sig, info);
+	Perror_printf(P, msgfmt, addr);
+
+	dprintf(incfmt, sig, info);
+	dprintf(msgfmt, addr);
+}
+
 /*
  * Add information on the address space mapping described by the given
  * PT_LOAD program header.  We fill in more information on the mapping later.
@@ -734,7 +830,6 @@
 static int
 core_add_mapping(struct ps_prochandle *P, GElf_Phdr *php)
 {
-	int err = 0;
 	prmap_t pmap;
 
 	dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
@@ -749,14 +844,7 @@
 	 * PF_SUNW_FAILURE in the Phdr and try to stash away the errno for us.
 	 */
 	if (php->p_flags & PF_SUNW_FAILURE) {
-		(void) pread64(P->asfd, &err,
-		    sizeof (err), (off64_t)php->p_offset);
-
-		Perror_printf(P, "core file data for mapping at %p not saved: "
-		    "%s\n", (void *)(uintptr_t)php->p_vaddr, strerror(err));
-		dprintf("core file data for mapping at %p not saved: %s\n",
-		    (void *)(uintptr_t)php->p_vaddr, strerror(err));
-
+		core_report_mapping(P, php);
 	} else if (php->p_filesz != 0 && php->p_offset >= P->core->core_size) {
 		Perror_printf(P, "core file may be corrupt -- data for mapping "
 		    "at %p is missing\n", (void *)(uintptr_t)php->p_vaddr);
--- a/usr/src/lib/libproc/common/Pgcore.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/Pgcore.c	Tue Apr 02 13:52:19 2013 -0700
@@ -25,6 +25,7 @@
  */
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #define	_STRUCTURED_PROC	1
@@ -481,6 +482,7 @@
 {
 	pgcore_t *pgc = data;
 	struct ps_prochandle *P = pgc->P;
+	psinfo_t ps;
 
 	/*
 	 * If lsp is NULL this indicates that this is a zombie LWP in
@@ -548,6 +550,27 @@
 #endif	/* __sparcv9 */
 #endif	/* sparc */
 
+	if (!(lsp->pr_flags & PR_AGENT))
+		return (0);
+
+	if (Plwp_getspymaster(P, lsp->pr_lwpid, &ps) != 0)
+		return (0);
+
+	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+		if (write_note(pgc->pgc_fd, NT_SPYMASTER, &ps,
+		    sizeof (psinfo_t), pgc->pgc_doff) != 0)
+			return (1);
+#ifdef _LP64
+	} else {
+		psinfo32_t ps32;
+		psinfo_n_to_32(&ps, &ps32);
+		if (write_note(pgc->pgc_fd, NT_SPYMASTER, &ps32,
+		    sizeof (psinfo32_t), pgc->pgc_doff) != 0)
+			return (1);
+#endif	/* _LP64 */
+	}
+
+
 	return (0);
 }
 
--- a/usr/src/lib/libproc/common/Plwpregs.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/Plwpregs.c	Tue Apr 02 13:52:19 2013 -0700
@@ -23,7 +23,9 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/uio.h>
@@ -349,6 +351,39 @@
 }
 
 int
+Plwp_getspymaster(struct ps_prochandle *P, lwpid_t lwpid, psinfo_t *ps)
+{
+	lwpstatus_t lps;
+
+	if (P->state == PS_IDLE) {
+		errno = ENODATA;
+		return (-1);
+	}
+
+	if (getlwpstatus(P, lwpid, &lps) != 0)
+		return (-1);
+
+	if (!(lps.pr_flags & PR_AGENT)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (P->state != PS_DEAD) {
+		return (getlwpfile(P, lwpid, "spymaster",
+		    ps, sizeof (psinfo_t)));
+	}
+
+	if (P->spymaster.pr_nlwp != 0) {
+		(void) memcpy(ps, &P->spymaster, sizeof (psinfo_t));
+		return (0);
+	}
+
+	errno = ENODATA;
+
+	return (-1);
+}
+
+int
 Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
 {
 	uintptr_t addr;
--- a/usr/src/lib/libproc/common/Psyscall.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/Psyscall.c	Tue Apr 02 13:52:19 2013 -0700
@@ -22,8 +22,9 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+
 /*
- * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <stdio.h>
@@ -61,7 +62,7 @@
 	int sysnum = P->status.pr_lwp.pr_syscall;
 	int stop;
 
-	dprintf("agent LWP is asleep in syscall %d\n", sysnum);
+	dprintf("agent LWP is stopped or asleep in syscall %d\n", sysnum);
 	(void) Pstop(P, 0);
 	stop = Psysexit(P, sysnum, TRUE);
 
@@ -147,11 +148,16 @@
 	P->agentctlfd = fd;
 
 	/*
-	 * If the agent is currently asleep in a system call, attempt
-	 * to abort the system call so it's ready to serve.
+	 * If the agent is currently asleep in a system call or stopped on
+	 * system call entry, attempt to abort the system call so it's ready to
+	 * serve.
 	 */
-	if (P->status.pr_lwp.pr_flags & PR_ASLEEP) {
-		dprintf("Pcreate_agent: aborting agent syscall\n");
+	if ((P->status.pr_lwp.pr_flags & PR_ASLEEP) ||
+	    ((P->status.pr_lwp.pr_flags & PR_STOPPED) &&
+	    P->status.pr_lwp.pr_why == PR_SYSENTRY)) {
+		dprintf("Pcreate_agent: aborting agent syscall; lwp is %s\n",
+		    (P->status.pr_lwp.pr_flags & PR_ASLEEP) ?
+		    "asleep" : "stopped");
 		Pabort_agent(P);
 	}
 
--- a/usr/src/lib/libproc/common/libproc.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/libproc.h	Tue Apr 02 13:52:19 2013 -0700
@@ -25,6 +25,7 @@
  *
  * Portions Copyright 2007 Chad Mynhier
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 /*
@@ -389,6 +390,7 @@
 #endif	/* __i386 || __amd64 */
 
 extern int Plwp_getpsinfo(struct ps_prochandle *, lwpid_t, lwpsinfo_t *);
+extern int Plwp_getspymaster(struct ps_prochandle *, lwpid_t, psinfo_t *);
 
 extern int Plwp_stack(struct ps_prochandle *, lwpid_t, stack_t *);
 extern int Plwp_main_stack(struct ps_prochandle *, lwpid_t, stack_t *);
--- a/usr/src/lib/libproc/common/mapfile-vers	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/lib/libproc/common/mapfile-vers	Tue Apr 02 13:52:19 2013 -0700
@@ -21,6 +21,7 @@
 #
 # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
 #
 
 #
@@ -133,6 +134,7 @@
 	Plwp_getfpregs;
 	Plwp_getpsinfo;
 	Plwp_getregs;
+	Plwp_getspymaster;
 	Plwp_iter;
 	Plwp_iter_all;
 	Plwp_main_stack;
--- a/usr/src/man/man4/core.4	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/man/man4/core.4	Tue Apr 02 13:52:19 2013 -0700
@@ -1,11 +1,12 @@
 '\" te
 .\" Copyright (C) 2008, Sun Microsystems, Inc. All Rights Reserved.
 .\" Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+.\" Copyright (c) 2013, Joyent, Inc. All rights reserved.
 .\" Copyright 1989 AT&T
 .\" 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]
-.TH CORE 4 "Oct 23, 2012"
+.TH CORE 4 "Mar 31, 2013"
 .SH NAME
 core \- process core file
 .SH DESCRIPTION
@@ -130,9 +131,13 @@
 .sp
 .LP
 A mapping's data can be excluded due to the core file content settings (see
-\fBcoreadm\fR(1M)), or due to some failure. If the data is excluded because of
-a failure, the program header entry will have the \fBPF_SUNW_FAILURE\fR flag
-set in its \fBp_flags\fR field.
+\fBcoreadm\fR(1M)), due to a failure, or due to a signal received after
+core dump initiation but before its completion. If the data is excluded
+because of a failure, the program header entry will have the
+\fBPF_SUNW_FAILURE\fR flag
+set in its \fBp_flags\fR field; if the data is excluded because of a signal,
+the segment's \fBp_flags\fR field will have the \fBPF_SUNW_KILLED\fR
+flag set.
 .sp
 .LP
 The program headers of an \fBELF\fR core file also contain entries for two
@@ -434,6 +439,18 @@
 .RE
 
 .sp
+.ne 2
+.na
+\fB\fBpsinfo_t\fR\fR
+.ad
+.RS 15n
+\fBn_type\fR: \fBNT_SPYMASTER\fR. This entry is present only for an agent
+LWP and contains the \fBpsinfo_t\fR of the process that created the agent
+LWP. See the \fBproc\fR(4) description of the \fBspymaster\fR entry for
+more details.
+.RE
+
+.sp
 .LP
 Depending on the \fBcoreadm\fR(1M) settings, the section header of an ELF core
 file can contain entries for CTF, symbol table, and string table sections. The
--- a/usr/src/man/man4/proc.4	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/man/man4/proc.4	Tue Apr 02 13:52:19 2013 -0700
@@ -1,10 +1,11 @@
 '\" te
 .\" Copyright 1989 AT&T
 .\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2013, Joyent, Inc. All rights reserved.
 .\" 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]
-.TH PROC 4 "Nov 29, 2006"
+.TH PROC 4 "Mar 31, 2013"
 .SH NAME
 proc \- /proc, the process file system
 .SH DESCRIPTION
@@ -1481,7 +1482,7 @@
 within the process. These entries are themselves directories containing
 additional files as described below. Only the \fBlwpsinfo\fR file exists in the
 directory of a zombie lwp.
-.SH STRUCTURE OF \fB/proc/\fR\fIpid\fR\fB/lwp/\fR \fIlwpid\fR
+.SH STRUCTURE OF \fB/proc/\fR\fIpid\fR\fB/lwp/\fR\fIlwpid\fR
 .sp
 .LP
 A given directory \fB/proc/\fR\fIpid\fR\fB/lwp/\fR\fIlwpid\fR contains the
@@ -1538,6 +1539,15 @@
 values of the lwp's platform-dependent ancillary state registers. If the lwp is
 not stopped, all register values are undefined. See also the \fBPCSASRS\fR
 control operation, below.
+.SS "spymaster"
+.sp
+.LP
+For an agent lwp (see \fBPCAGENT\fR), this file contains a \fBpsinfo_t\fR
+structure that corresponds to the process that created the agent lwp at the
+time the agent was created. This structure is identical to that retrieved via
+the \fBpsinfo\fR file, with one modification: the \fBpr_time\fR field does not
+correspond to the CPU time for the process, but rather to the creation time of
+the agent lwp.
 .SS "templates"
 .sp
 .LP
@@ -2263,6 +2273,16 @@
 of the representative lwp, so that the agent lwp can use its stack.
 .sp
 .LP
+If the controlling process neglects to force the agent lwp to execute the
+\fBSYS_lwp_exit\fR system call (due to either logic error or fatal failure on
+the part of the controlling process), the agent lwp will remain in the target
+process.  For purposes of being able to debug these otherwise rogue agents,
+information as to the creator of the agent lwp is reflected in that lwp's
+\fBspymaster\fR file in \fB/proc\fR. Should the target process generate a core
+dump with the agent lwp in place, this information will be available via the
+\fBNT_SPYMASTER\fR note in the core file (see \fBcore\fR(4)).
+.sp
+.LP
 The agent lwp is not allowed to execute any variation of the \fBSYS_fork\fR or
 \fBSYS_exec\fR system call traps. Attempts to do so yield \fBENOTSUP\fR to the
 agent lwp.
@@ -2789,6 +2809,16 @@
 ancillary state registers (SPARC V9 only)
 .RE
 
+.sp
+.ne 2
+.na
+\fB\fB/proc/\fIpid\fR/lwp/\fIlwpid\fR/spymaster\fR\fR
+.ad
+.sp .6
+.RS 4n
+For an agent LWP, the controlling process
+.RE
+
 .SH SEE ALSO
 .sp
 .LP
@@ -2803,8 +2833,8 @@
 \fBreaddir\fR(3C), \fBpthread_create\fR(3C), \fBpthread_join\fR(3C),
 \fBsiginfo.h\fR(3HEAD), \fBsignal.h\fR(3HEAD), \fBthr_create\fR(3C),
 \fBthr_join\fR(3C), \fBtypes32.h\fR(3HEAD), \fBucontext.h\fR(3HEAD),
-\fBwait\fR(3C), \fBcontract\fR(4), \fBprocess\fR(4), \fBlfcompile\fR(5),
-\fBprivileges\fR(5)
+\fBwait\fR(3C), \fBcontract\fR(4), \fBcore\fR(4), \fBprocess\fR(4),
+\fBlfcompile\fR(5), \fBprivileges\fR(5)
 .SH DIAGNOSTICS
 .sp
 .LP
--- a/usr/src/uts/common/exec/elf/elf.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/exec/elf/elf.c	Tue Apr 02 13:52:19 2013 -0700
@@ -64,6 +64,7 @@
 #include <sys/brand.h>
 #include "elf_impl.h"
 #include <sys/sdt.h>
+#include <sys/siginfo.h>
 
 extern int at_flags;
 
@@ -1726,6 +1727,7 @@
 	caddr_t stkbase;
 	size_t stksize;
 	int ntries = 0;
+	klwp_t *lwp = ttolwp(curthread);
 
 top:
 	/*
@@ -1989,6 +1991,10 @@
 		goto done;
 
 	for (i = 2; i < nphdrs; i++) {
+		prkillinfo_t killinfo;
+		sigqueue_t *sq;
+		int sig, j;
+
 		if (v[i].p_filesz == 0)
 			continue;
 
@@ -2002,9 +2008,13 @@
 		 */
 		if ((error = core_seg(p, vp, v[i].p_offset,
 		    (caddr_t)(uintptr_t)v[i].p_vaddr, v[i].p_filesz,
-		    rlimit, credp)) != 0) {
+		    rlimit, credp)) == 0) {
+			continue;
+		}
 
+		if ((sig = lwp->lwp_cursig) == 0) {
 			/*
+			 * We failed due to something other than a signal.
 			 * Since the space reserved for the segment is now
 			 * unused, we stash the errno in the first four
 			 * bytes. This undocumented interface will let us
@@ -2019,7 +2029,75 @@
 			    poffset + sizeof (v[i]) * i, &v[i], sizeof (v[i]),
 			    rlimit, credp)) != 0)
 				goto done;
+
+			continue;
 		}
+
+		/*
+		 * We took a signal.  We want to abort the dump entirely, but
+		 * we also want to indicate what failed and why.  We therefore
+		 * use the space reserved for the first failing segment to
+		 * write our error (which, for purposes of compatability with
+		 * older core dump readers, we set to EINTR) followed by any
+		 * siginfo associated with the signal.
+		 */
+		bzero(&killinfo, sizeof (killinfo));
+		killinfo.prk_error = EINTR;
+
+		sq = sig == SIGKILL ? curproc->p_killsqp : lwp->lwp_curinfo;
+
+		if (sq != NULL) {
+			bcopy(&sq->sq_info, &killinfo.prk_info,
+			    sizeof (killinfo.prk_info));
+		} else {
+			killinfo.prk_info.si_signo = lwp->lwp_cursig;
+			killinfo.prk_info.si_code = SI_NOINFO;
+		}
+
+#if (defined(_SYSCALL32_IMPL) || defined(_LP64))
+		/*
+		 * If this is a 32-bit process, we need to translate from the
+		 * native siginfo to the 32-bit variant.  (Core readers must
+		 * always have the same data model as their target or must
+		 * be aware of -- and compensate for -- data model differences.)
+		 */
+		if (curproc->p_model == DATAMODEL_ILP32) {
+			siginfo32_t si32;
+
+			siginfo_kto32((k_siginfo_t *)&killinfo.prk_info, &si32);
+			bcopy(&si32, &killinfo.prk_info, sizeof (si32));
+		}
+#endif
+
+		(void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
+		    &killinfo, sizeof (killinfo), rlimit, credp);
+
+		/*
+		 * For the segment on which we took the signal, indicate that
+		 * its data now refers to a siginfo.
+		 */
+		v[i].p_filesz = 0;
+		v[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
+		    PF_SUNW_SIGINFO;
+
+		/*
+		 * And for every other segment, indicate that its absence
+		 * is due to a signal.
+		 */
+		for (j = i + 1; j < nphdrs; j++) {
+			v[j].p_filesz = 0;
+			v[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
+		}
+
+		/*
+		 * Finally, write out our modified program headers.
+		 */
+		if ((error = core_write(vp, UIO_SYSSPACE,
+		    poffset + sizeof (v[i]) * i, &v[i],
+		    sizeof (v[i]) * (nphdrs - i), rlimit, credp)) != 0)
+			goto done;
+
+		break;
 	}
 
 	if (nshdrs > 0) {
--- a/usr/src/uts/common/exec/elf/elf_notes.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/exec/elf/elf_notes.c	Tue Apr 02 13:52:19 2013 -0700
@@ -26,6 +26,7 @@
 
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -107,6 +108,11 @@
 	    + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word))
 	    + nfd * roundup(sizeof (prfdinfo_t), sizeof (Word));
 
+	if (curproc->p_agenttp != NULL) {
+		v[0].p_filesz += sizeof (Note) +
+		    roundup(sizeof (psinfo_t), sizeof (Word));
+	}
+
 	size = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1);
 	pcrp = kmem_alloc(size, KM_SLEEP);
 	prgetcred(p, pcrp);
@@ -519,6 +525,31 @@
 			if (error)
 				goto done;
 		}
+
+		if (t->t_lwp->lwp_spymaster != NULL) {
+			void *psaddr = t->t_lwp->lwp_spymaster;
+#ifdef _ELF32_COMPAT
+			/*
+			 * On a 64-bit kernel with 32-bit ELF compatibility,
+			 * this file is compiled into two different objects:
+			 * one is compiled normally, and the other is compiled
+			 * with _ELF32_COMPAT set -- and therefore with a
+			 * psinfo_t defined to be a psinfo32_t.  However, the
+			 * psinfo_t denoting our spymaster is always of the
+			 * native type; if we are in the _ELF32_COMPAT case,
+			 * we need to explicitly convert it.
+			 */
+			if (p->p_model == DATAMODEL_ILP32) {
+				psinfo_kto32(psaddr, &bigwad->psinfo);
+				psaddr = &bigwad->psinfo;
+			}
+#endif
+
+			error = elfnote(vp, &offset, NT_SPYMASTER,
+			    sizeof (psinfo_t), psaddr, rlimit, credp);
+			if (error)
+				goto done;
+		}
 	}
 	ASSERT(nlwp == 0);
 
--- a/usr/src/uts/common/fs/proc/prcontrol.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/fs/proc/prcontrol.c	Tue Apr 02 13:52:19 2013 -0700
@@ -24,6 +24,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
+
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <sys/param.h>
@@ -2008,6 +2012,23 @@
 		return (ENOMEM);
 	}
 	prsetprregs(clwp, prgregset, 1);
+
+	/*
+	 * Because abandoning the agent inside the target process leads to
+	 * a state that is essentially undebuggable, we record the psinfo of
+	 * the process creating the agent and hang that off of the lwp.
+	 */
+	clwp->lwp_spymaster = kmem_zalloc(sizeof (psinfo_t), KM_SLEEP);
+	mutex_enter(&curproc->p_lock);
+	prgetpsinfo(curproc, clwp->lwp_spymaster);
+	mutex_exit(&curproc->p_lock);
+
+	/*
+	 * We overload pr_time in the spymaster to denote the time at which the
+	 * agent was created.
+	 */
+	gethrestime(&clwp->lwp_spymaster->pr_time);
+
 retry:
 	cid = t->t_cid;
 	(void) CL_ALLOC(&bufp, cid, KM_SLEEP);
--- a/usr/src/uts/common/fs/proc/prdata.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/fs/proc/prdata.h	Tue Apr 02 13:52:19 2013 -0700
@@ -26,12 +26,13 @@
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All Rights Reserved  	*/
 
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
 
 #ifndef _SYS_PROC_PRDATA_H
 #define	_SYS_PROC_PRDATA_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/isa_defs.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
@@ -141,6 +142,7 @@
 	PR_XREGS,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
 	PR_TMPLDIR,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
 	PR_TMPL,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
+	PR_SPYMASTER,		/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
 #if defined(__sparc)
 	PR_GWINDOWS,		/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
 	PR_ASRS,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
--- a/usr/src/uts/common/fs/proc/prsubr.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/fs/proc/prsubr.c	Tue Apr 02 13:52:19 2013 -0700
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
@@ -2490,6 +2491,7 @@
 		psp->pr_envp = 0;
 	}
 }
+
 #endif	/* _SYSCALL32_IMPL */
 
 void
@@ -2628,6 +2630,100 @@
 }
 #endif	/* _SYSCALL32_IMPL */
 
+#ifdef _SYSCALL32_IMPL
+
+#define	PR_COPY_FIELD(s, d, field)	 d->field = s->field
+
+#define	PR_COPY_FIELD_ILP32(s, d, field)				\
+	if (s->pr_dmodel == PR_MODEL_ILP32) {			\
+		d->field = s->field;				\
+	}
+
+#define	PR_COPY_TIMESPEC(s, d, field)				\
+	TIMESPEC_TO_TIMESPEC32(&d->field, &s->field);
+
+#define	PR_COPY_BUF(s, d, field)	 			\
+	bcopy(s->field, d->field, sizeof (d->field));
+
+#define	PR_IGNORE_FIELD(s, d, field)
+
+void
+lwpsinfo_kto32(const struct lwpsinfo *src, struct lwpsinfo32 *dest)
+{
+	bzero(dest, sizeof (*dest));
+
+	PR_COPY_FIELD(src, dest, pr_flag);
+	PR_COPY_FIELD(src, dest, pr_lwpid);
+	PR_IGNORE_FIELD(src, dest, pr_addr);
+	PR_IGNORE_FIELD(src, dest, pr_wchan);
+	PR_COPY_FIELD(src, dest, pr_stype);
+	PR_COPY_FIELD(src, dest, pr_state);
+	PR_COPY_FIELD(src, dest, pr_sname);
+	PR_COPY_FIELD(src, dest, pr_nice);
+	PR_COPY_FIELD(src, dest, pr_syscall);
+	PR_COPY_FIELD(src, dest, pr_oldpri);
+	PR_COPY_FIELD(src, dest, pr_cpu);
+	PR_COPY_FIELD(src, dest, pr_pri);
+	PR_COPY_FIELD(src, dest, pr_pctcpu);
+	PR_COPY_TIMESPEC(src, dest, pr_start);
+	PR_COPY_BUF(src, dest, pr_clname);
+	PR_COPY_BUF(src, dest, pr_name);
+	PR_COPY_FIELD(src, dest, pr_onpro);
+	PR_COPY_FIELD(src, dest, pr_bindpro);
+	PR_COPY_FIELD(src, dest, pr_bindpset);
+	PR_COPY_FIELD(src, dest, pr_lgrp);
+}
+
+void
+psinfo_kto32(const struct psinfo *src, struct psinfo32 *dest)
+{
+	bzero(dest, sizeof (*dest));
+
+	PR_COPY_FIELD(src, dest, pr_flag);
+	PR_COPY_FIELD(src, dest, pr_nlwp);
+	PR_COPY_FIELD(src, dest, pr_pid);
+	PR_COPY_FIELD(src, dest, pr_ppid);
+	PR_COPY_FIELD(src, dest, pr_pgid);
+	PR_COPY_FIELD(src, dest, pr_sid);
+	PR_COPY_FIELD(src, dest, pr_uid);
+	PR_COPY_FIELD(src, dest, pr_euid);
+	PR_COPY_FIELD(src, dest, pr_gid);
+	PR_COPY_FIELD(src, dest, pr_egid);
+	PR_IGNORE_FIELD(src, dest, pr_addr);
+	PR_COPY_FIELD_ILP32(src, dest, pr_size);
+	PR_COPY_FIELD_ILP32(src, dest, pr_rssize);
+	PR_COPY_FIELD(src, dest, pr_ttydev);
+	PR_COPY_FIELD(src, dest, pr_pctcpu);
+	PR_COPY_FIELD(src, dest, pr_pctmem);
+	PR_COPY_TIMESPEC(src, dest, pr_start);
+	PR_COPY_TIMESPEC(src, dest, pr_time);
+	PR_COPY_TIMESPEC(src, dest, pr_ctime);
+	PR_COPY_BUF(src, dest, pr_fname);
+	PR_COPY_BUF(src, dest, pr_psargs);
+	PR_COPY_FIELD(src, dest, pr_wstat);
+	PR_COPY_FIELD(src, dest, pr_argc);
+	PR_COPY_FIELD_ILP32(src, dest, pr_argv);
+	PR_COPY_FIELD_ILP32(src, dest, pr_envp);
+	PR_COPY_FIELD(src, dest, pr_dmodel);
+	PR_COPY_FIELD(src, dest, pr_taskid);
+	PR_COPY_FIELD(src, dest, pr_projid);
+	PR_COPY_FIELD(src, dest, pr_nzomb);
+	PR_COPY_FIELD(src, dest, pr_poolid);
+	PR_COPY_FIELD(src, dest, pr_contract);
+	PR_COPY_FIELD(src, dest, pr_poolid);
+	PR_COPY_FIELD(src, dest, pr_poolid);
+
+	lwpsinfo_kto32(&src->pr_lwp, &dest->pr_lwp);
+}
+
+#undef	PR_COPY_FIELD
+#undef	PR_COPY_FIELD_ILP32
+#undef	PR_COPY_TIMESPEC
+#undef	PR_COPY_BUF
+#undef	PR_IGNORE_FIELD
+
+#endif	/* _SYSCALL32_IMPL */
+
 /*
  * This used to get called when microstate accounting was disabled but
  * microstate information was requested.  Since Microstate accounting is on
--- a/usr/src/uts/common/fs/proc/prvnops.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/fs/proc/prvnops.c	Tue Apr 02 13:52:19 2013 -0700
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 /*	Copyright (c) 1984,	 1986, 1987, 1988, 1989 AT&T	*/
@@ -189,10 +190,12 @@
 		"xregs" },
 	{ PR_TMPLDIR,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
 		"templates" },
+	{ PR_SPYMASTER,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
+		"spymaster" },
 #if defined(__sparc)
-	{ PR_GWINDOWS,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
+	{ PR_GWINDOWS,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
 		"gwindows" },
-	{ PR_ASRS,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
+	{ PR_ASRS,	11 * sizeof (prdirent_t), sizeof (prdirent_t),
 		"asrs" },
 #endif
 };
@@ -573,6 +576,7 @@
 	pr_read_usage(), pr_read_lusage(), pr_read_pagedata(),
 	pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(),
 	pr_read_lwpusage(), pr_read_xregs(), pr_read_priv(),
+	pr_read_spymaster(),
 #if defined(__sparc)
 	pr_read_gwindows(), pr_read_asrs(),
 #endif
@@ -616,6 +620,7 @@
 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
+	pr_read_spymaster,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
 #if defined(__sparc)
 	pr_read_gwindows,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
@@ -1562,6 +1567,31 @@
 #endif
 }
 
+static int
+pr_read_spymaster(prnode_t *pnp, uio_t *uiop)
+{
+	psinfo_t psinfo;
+	int error;
+	klwp_t *lwp;
+
+	ASSERT(pnp->pr_type == PR_SPYMASTER);
+
+	if ((error = prlock(pnp, ZNO)) != 0)
+		return (error);
+
+	lwp = pnp->pr_common->prc_thread->t_lwp;
+
+	if (lwp->lwp_spymaster == NULL) {
+		prunlock(pnp);
+		return (0);
+	}
+
+	bcopy(lwp->lwp_spymaster, &psinfo, sizeof (psinfo_t));
+	prunlock(pnp);
+
+	return (pr_uioread(&psinfo, sizeof (psinfo), uiop));
+}
+
 #if defined(__sparc)
 
 static int
@@ -1703,7 +1733,7 @@
 	pr_read_sigact_32(), pr_read_auxv_32(),
 	pr_read_usage_32(), pr_read_lusage_32(), pr_read_pagedata_32(),
 	pr_read_watch_32(), pr_read_lwpstatus_32(), pr_read_lwpsinfo_32(),
-	pr_read_lwpusage_32(),
+	pr_read_lwpusage_32(), pr_read_spymaster_32(),
 #if defined(__sparc)
 	pr_read_gwindows_32(),
 #endif
@@ -1747,6 +1777,7 @@
 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
+	pr_read_spymaster_32,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
 #if defined(__sparc)
 	pr_read_gwindows_32,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
@@ -2545,6 +2576,31 @@
 	return (error);
 }
 
+static int
+pr_read_spymaster_32(prnode_t *pnp, uio_t *uiop)
+{
+	psinfo32_t psinfo;
+	int error;
+	klwp_t *lwp;
+
+	ASSERT(pnp->pr_type == PR_SPYMASTER);
+
+	if ((error = prlock(pnp, ZNO)) != 0)
+		return (error);
+
+	lwp = pnp->pr_common->prc_thread->t_lwp;
+
+	if (lwp->lwp_spymaster == NULL) {
+		prunlock(pnp);
+		return (0);
+	}
+
+	psinfo_kto32(lwp->lwp_spymaster, &psinfo);
+	prunlock(pnp);
+
+	return (pr_uioread(&psinfo, sizeof (psinfo), uiop));
+}
+
 #if defined(__sparc)
 static int
 pr_read_gwindows_32(prnode_t *pnp, uio_t *uiop)
@@ -3054,6 +3110,13 @@
 		else
 			vap->va_size = 0;
 		break;
+	case PR_SPYMASTER:
+		if (pnp->pr_common->prc_thread->t_lwp->lwp_spymaster != NULL) {
+			vap->va_size = PR_OBJSIZE(psinfo32_t, psinfo_t);
+		} else {
+			vap->va_size = 0;
+		}
+		break;
 #if defined(__sparc)
 	case PR_GWINDOWS:
 	{
@@ -3254,6 +3317,7 @@
 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
 	pr_lookup_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
+	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
 #if defined(__sparc)
 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
@@ -4602,6 +4666,7 @@
 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
 	pr_readdir_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
+	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
 #if defined(__sparc)
 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
--- a/usr/src/uts/common/os/core.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/os/core.c	Tue Apr 02 13:52:19 2013 -0700
@@ -651,11 +651,11 @@
 	}
 
 	/*
-	 * Block all signals except SIGHUP, SIGINT, SIGKILL, and SIGTERM.
-	 * These signals are allowed to interrupt the core dump.
-	 * SIGQUIT is not allowed because it is supposed to make a core.
-	 * Additionally, get current limit on core file size for handling later
-	 * error reporting.
+	 * Block all signals except SIGHUP, SIGINT, SIGKILL, and SIGTERM; no
+	 * other signal may interrupt a core dump.  For each signal, we
+	 * explicitly unblock it and set it in p_siginfo to allow for some
+	 * minimal error reporting.  Additionally, we get the current limit on
+	 * core file size for handling later error reporting.
 	 */
 	mutex_enter(&p->p_lock);
 
@@ -671,6 +671,12 @@
 		sigdelset(&sighold, SIGKILL);
 	if (!sigismember(&sigmask, SIGTERM))
 		sigdelset(&sighold, SIGTERM);
+
+	sigaddset(&p->p_siginfo, SIGHUP);
+	sigaddset(&p->p_siginfo, SIGINT);
+	sigaddset(&p->p_siginfo, SIGKILL);
+	sigaddset(&p->p_siginfo, SIGTERM);
+
 	curthread->t_hold = sighold;
 
 	rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE], p->p_rctls,
@@ -789,6 +795,7 @@
 		len = eaddr - base;
 		if (as_memory(p->p_as, &base, &len) != 0)
 			return (0);
+
 		/*
 		 * Reduce len to a reasonable value so that we don't
 		 * overwhelm the VM system with a monstrously large
@@ -800,16 +807,17 @@
 		err = core_write(vp, UIO_USERSPACE,
 		    offset + (size_t)(base - addr), base, len, rlimit, credp);
 
-		if (err == 0) {
-			/*
-			 * Give pageout a chance to run.
-			 * Also allow core dumping to be interruptible.
-			 */
-			err = delay_sig(drv_usectohz(core_delay_usec));
-		}
 		if (err)
 			return (err);
+
+		/*
+		 * If we have taken a signal, return EINTR to allow the dump
+		 * to be aborted.
+		 */
+		if (issig(JUSTLOOKING) && issig(FORREAL))
+			return (EINTR);
 	}
+
 	return (0);
 }
 
--- a/usr/src/uts/common/os/lwp.c	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/os/lwp.c	Tue Apr 02 13:52:19 2013 -0700
@@ -24,6 +24,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
@@ -995,6 +999,15 @@
 		lwp->lwp_curinfo = NULL;
 	}
 
+	/*
+	 * If we have spymaster information (that is, if we're an agent LWP),
+	 * free that now.
+	 */
+	if (lwp->lwp_spymaster != NULL) {
+		kmem_free(lwp->lwp_spymaster, sizeof (psinfo_t));
+		lwp->lwp_spymaster = NULL;
+	}
+
 	thread_rele(t);
 
 	/*
--- a/usr/src/uts/common/sys/elf.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/sys/elf.h	Tue Apr 02 13:52:19 2013 -0700
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
@@ -366,6 +367,8 @@
 #define	PF_MASKPROC	0xf0000000	/* processor specific values */
 
 #define	PF_SUNW_FAILURE	0x00100000	/* mapping absent due to failure */
+#define	PF_SUNW_KILLED	0x00200000	/* signal received during dump */
+#define	PF_SUNW_SIGINFO	0x00400000	/* segment has killing sig's siginfo */
 
 #define	PN_XNUM		0xffff		/* extended program header index */
 
@@ -816,7 +819,8 @@
 #define	NT_CONTENT	20	/* core_content_t <sys/corectl.h>	*/
 #define	NT_ZONENAME	21	/* string from getzonenamebyid(3C)	*/
 #define	NT_FDINFO	22	/* open fd info 			*/
-#define	NT_NUM		22
+#define	NT_SPYMASTER	23	/* psinfo_t for agent LWP spymaster	*/
+#define	NT_NUM		23
 
 
 #ifdef _KERNEL
--- a/usr/src/uts/common/sys/klwp.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/sys/klwp.h	Tue Apr 02 13:52:19 2013 -0700
@@ -23,11 +23,13 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
 #ifndef	_SYS_KLWP_H
 #define	_SYS_KLWP_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/condvar.h>
 #include <sys/thread.h>
@@ -190,6 +192,7 @@
 	struct contract	*lwp_ct_latest[CTT_MAXTYPE]; /* last created contract */
 
 	void	*lwp_brand;		/* per-lwp brand data */
+	struct psinfo *lwp_spymaster;	/* if an agent LWP, our spymaster */
 } klwp_t;
 
 /* lwp states */
--- a/usr/src/uts/common/sys/proc.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/sys/proc.h	Tue Apr 02 13:52:19 2013 -0700
@@ -574,6 +574,12 @@
 	LWP_STAT_MSGSND
 } lwp_stat_id_t;
 
+typedef struct prkillinfo {
+	int32_t prk_error;		/* errno */
+	int32_t prk_pad;		/* pad */
+	siginfo_t prk_info;		/* siginfo of killing signal */
+} prkillinfo_t;
+
 #ifdef _KERNEL
 
 /* user profiling functions */
--- a/usr/src/uts/common/sys/prsystm.h	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/common/sys/prsystm.h	Tue Apr 02 13:52:19 2013 -0700
@@ -27,6 +27,9 @@
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All Rights Reserved  	*/
 
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
 
 #ifndef _SYS_PRSYSTM_H
 #define	_SYS_PRSYSTM_H
@@ -129,6 +132,8 @@
 extern void prgetlwpstatus32(kthread_t *, struct lwpstatus32 *, zone_t *);
 extern void prgetpsinfo32(proc_t *, struct psinfo32 *);
 extern void prgetlwpsinfo32(kthread_t *, struct lwpsinfo32 *);
+extern void lwpsinfo_kto32(const struct lwpsinfo *src, struct lwpsinfo32 *dest);
+extern void psinfo_kto32(const struct psinfo *src, struct psinfo32 *dest);
 extern void prgetprfpregs32(klwp_t *, struct prfpregset32 *);
 #if defined(__sparc)
 struct gwindows32;
--- a/usr/src/uts/intel/ia32/ml/modstubs.s	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s	Tue Apr 02 13:52:19 2013 -0700
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/asm_linkage.h>
@@ -695,6 +696,8 @@
 	NO_UNLOAD_STUB(procfs, prgetlwpsinfo32,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, oprgetstatus32,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, oprgetpsinfo32,	nomod_zero);
+	NO_UNLOAD_STUB(procfs, psinfo_kto32,	nomod_zero);
+	NO_UNLOAD_STUB(procfs, lwpsinfo_kto32,	nomod_zero);
 #endif	/* _SYSCALL32_IMPL */
 	NO_UNLOAD_STUB(procfs, prnotify,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prexecstart,	nomod_zero);
--- a/usr/src/uts/sparc/ml/modstubs.s	Tue Apr 02 17:25:01 2013 -0700
+++ b/usr/src/uts/sparc/ml/modstubs.s	Tue Apr 02 13:52:19 2013 -0700
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #if !defined(lint)
@@ -582,6 +583,8 @@
 	NO_UNLOAD_STUB(procfs, prgetlwpsinfo32,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, oprgetstatus32,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, oprgetpsinfo32,	nomod_zero);
+	NO_UNLOAD_STUB(procfs, psinfo_kto32,	nomod_zero);
+	NO_UNLOAD_STUB(procfs, lwpsinfo_kto32,	nomod_zero);
 #endif	/* _SYSCALL32_IMPL */
 	NO_UNLOAD_STUB(procfs, prnotify,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prexecstart,	nomod_zero);