changeset 13875:f128a109e6d2

3294 pfiles postmortem support Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Approved by: Eric Schrock <eric.schrock@delphix.com>
author Garrett D'Amore <garrett@damore.org>
date Fri, 02 Nov 2012 09:48:42 -0700
parents cab67b95c26b
children 54f26394c8b0
files usr/src/cmd/ptools/pfiles/pfiles.c usr/src/cmd/sgs/elfdump/common/corenote.c usr/src/cmd/sgs/elfdump/common/elfdump.msg usr/src/cmd/sgs/elfdump/common/struct_layout.h usr/src/cmd/sgs/elfdump/common/struct_layout_amd64.c usr/src/cmd/sgs/elfdump/common/struct_layout_i386.c usr/src/cmd/sgs/elfdump/common/struct_layout_sparc.c usr/src/cmd/sgs/elfdump/common/struct_layout_sparcv9.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/lib/libproc/Makefile.com usr/src/lib/libproc/common/Pcontrol.c usr/src/lib/libproc/common/Pcontrol.h usr/src/lib/libproc/common/Pcore.c usr/src/lib/libproc/common/Pfdinfo.c usr/src/lib/libproc/common/Pgcore.c usr/src/lib/libproc/common/libproc.h usr/src/lib/libproc/common/mapfile-vers usr/src/man/man1/proc.1 usr/src/man/man4/core.4 usr/src/uts/common/exec/elf/elf_notes.c usr/src/uts/common/sys/elf.h usr/src/uts/common/sys/procfs.h
diffstat 24 files changed, 928 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/ptools/pfiles/pfiles.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/ptools/pfiles/pfiles.c	Fri Nov 02 09:48:42 2012 -0700
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  */
 
 #include <stdio.h>
@@ -61,7 +62,7 @@
 static boolean_t nflag = B_FALSE;
 
 static	void	intr(int);
-static	void	dofcntl(struct ps_prochandle *, int, int, int);
+static	void	dofcntl(struct ps_prochandle *, prfdinfo_t *, int, int);
 static	void	dosocket(struct ps_prochandle *, int);
 static	void	dofifo(struct ps_prochandle *, int);
 static	void	dotli(struct ps_prochandle *, int);
@@ -102,7 +103,7 @@
 	argv += optind;
 
 	if (errflg || argc <= 0) {
-		(void) fprintf(stderr, "usage:\t%s [-F] pid ...\n",
+		(void) fprintf(stderr, "usage:\t%s [-F] { pid | core } ...\n",
 		    command);
 		(void) fprintf(stderr,
 		    "  (report open files of each process)\n");
@@ -132,12 +133,35 @@
 
 		(void) proc_flushstdio();
 
+		arg = *argv++;
+
 		/* get the specified pid and the psinfo struct */
-		if ((pid = proc_arg_psinfo(arg = *argv++, PR_ARG_PIDS,
+		if ((pid = proc_arg_psinfo(arg, PR_ARG_PIDS,
 		    &psinfo, &gret)) == -1) {
-			(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
-			    command, arg, Pgrab_error(gret));
-			retc++;
+
+			if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_CORES,
+			    Fflag, &gret, NULL)) == NULL) {
+				(void) fprintf(stderr,
+				    "%s: cannot examine %s: %s\n",
+				    command, arg, Pgrab_error(gret));
+				retc++;
+				continue;
+			}
+			if (proc_arg_psinfo(arg, PR_ARG_ANY, &psinfo,
+			    &gret) < 0) {
+				(void) fprintf(stderr,
+				    "%s: cannot examine %s: %s\n",
+				    command, arg, Pgrab_error(gret));
+				retc++;
+				Prelease(Pr, 0);
+				continue;
+			}
+			(void) printf("core '%s' of %d:\t%.70s\n",
+			    arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
+
+			show_files(Pr);
+			Prelease(Pr, 0);
+
 		} else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
 			if (Pcreate_agent(Pr) == 0) {
 				proc_unctrl_psinfo(&psinfo);
@@ -190,20 +214,109 @@
 
 /* ------ begin specific code ------ */
 
+static int
+show_file(void *data, prfdinfo_t *info)
+{
+	struct ps_prochandle *Pr = data;
+	char unknown[12];
+	char *s;
+	mode_t mode;
+
+	if (interrupt)
+		return (1);
+
+	mode = info->pr_mode;
+
+	switch (mode & S_IFMT) {
+	case S_IFCHR: s = "S_IFCHR"; break;
+	case S_IFBLK: s = "S_IFBLK"; break;
+	case S_IFIFO: s = "S_IFIFO"; break;
+	case S_IFDIR: s = "S_IFDIR"; break;
+	case S_IFREG: s = "S_IFREG"; break;
+	case S_IFLNK: s = "S_IFLNK"; break;
+	case S_IFSOCK: s = "S_IFSOCK"; break;
+	case S_IFDOOR: s = "S_IFDOOR"; break;
+	case S_IFPORT: s = "S_IFPORT"; break;
+	default:
+		s = unknown;
+		(void) sprintf(s, "0x%.4x ", (int)mode & S_IFMT);
+		break;
+	}
+
+	(void) printf("%4d: %s mode:0%.3o", info->pr_fd, s,
+	    (int)mode & ~S_IFMT);
+
+	(void) printf(" dev:%u,%u",
+	    (unsigned)info->pr_major, (unsigned)info->pr_minor);
+
+	if ((mode & S_IFMT) == S_IFPORT) {
+		(void) printf(" uid:%d gid:%d",
+		    (int)info->pr_uid, (int)info->pr_gid);
+		(void) printf(" size:%lld\n", (longlong_t)info->pr_size);
+		return (0);
+	}
+
+	(void) printf(" ino:%llu uid:%d gid:%d",
+	    (u_longlong_t)info->pr_ino, (int)info->pr_uid, (int)info->pr_gid);
+
+	if ((info->pr_rmajor == (major_t)NODEV) &&
+	    (info->pr_rminor == (minor_t)NODEV))
+		(void) printf(" size:%lld\n", (longlong_t)info->pr_size);
+	else
+		(void) printf(" rdev:%u,%u\n",
+		    (unsigned)info->pr_rmajor, (unsigned)info->pr_rminor);
+
+	if (!nflag) {
+		dofcntl(Pr, info,
+		    (mode & (S_IFMT|S_ENFMT|S_IXGRP)) == (S_IFREG|S_ENFMT),
+		    (mode & S_IFMT) == S_IFDOOR);
+
+		if (Pstate(Pr) != PS_DEAD) {
+			char *dev;
+
+			if ((mode & S_IFMT) == S_IFSOCK)
+				dosocket(Pr, info->pr_fd);
+			else if ((mode & S_IFMT) == S_IFIFO)
+				dofifo(Pr, info->pr_fd);
+
+			if ((mode & S_IFMT) == S_IFCHR &&
+			    (dev = strrchr(info->pr_path, ':')) != NULL) {
+				/*
+				 * There's no elegant way to determine
+				 * if a character device supports TLI,
+				 * so we lame out and just check a
+				 * hardcoded list of known TLI devices.
+				 */
+				int i;
+				const char *tlidevs[] = {
+				    "tcp", "tcp6", "udp", "udp6", NULL
+				};
+
+				dev++; /* skip past the `:' */
+				for (i = 0; tlidevs[i] != NULL; i++) {
+					if (strcmp(dev, tlidevs[i]) == 0) {
+						dotli(Pr, info->pr_fd);
+						break;
+					}
+				}
+			}
+		}
+
+		if (info->pr_path[0] != '\0')
+			(void) printf("      %s\n", info->pr_path);
+
+		if (info->pr_offset != -1) {
+			(void) printf("      offset:%lld\n",
+			    (long long)info->pr_offset);
+		}
+	}
+	return (0);
+}
+
 static void
 show_files(struct ps_prochandle *Pr)
 {
-	DIR *dirp;
-	struct dirent *dentp;
-	const char *dev;
-	char pname[100];
-	char fname[PATH_MAX];
-	struct stat64 statb;
 	struct rlimit rlim;
-	pid_t pid;
-	int fd;
-	char *s;
-	int ret;
 
 	if (pr_getrlimit(Pr, RLIMIT_NOFILE, &rlim) == 0) {
 		ulong_t nfd = rlim.rlim_cur;
@@ -215,135 +328,7 @@
 			    "  Current rlimit: %lu file descriptors\n", nfd);
 	}
 
-	/* in case we are doing this to ourself */
-	pid = (Pr == NULL)? getpid() : Pstatus(Pr)->pr_pid;
-
-	(void) sprintf(pname, "/proc/%d/fd", (int)pid);
-	if ((dirp = opendir(pname)) == NULL) {
-		(void) fprintf(stderr, "%s: cannot open directory %s\n",
-		    command, pname);
-		return;
-	}
-
-	/* for each open file --- */
-	while ((dentp = readdir(dirp)) != NULL && !interrupt) {
-		char unknown[12];
-		dev_t rdev;
-
-		/* skip '.' and '..' */
-		if (!isdigit(dentp->d_name[0]))
-			continue;
-
-		fd = atoi(dentp->d_name);
-		if (pr_fstat64(Pr, fd, &statb) == -1) {
-			s = unknown;
-			(void) sprintf(s, "%4d", fd);
-			perror(s);
-			continue;
-		}
-
-		rdev = NODEV;
-		switch (statb.st_mode & S_IFMT) {
-		case S_IFCHR: s = "S_IFCHR"; rdev = statb.st_rdev; break;
-		case S_IFBLK: s = "S_IFBLK"; rdev = statb.st_rdev; break;
-		case S_IFIFO: s = "S_IFIFO"; break;
-		case S_IFDIR: s = "S_IFDIR"; break;
-		case S_IFREG: s = "S_IFREG"; break;
-		case S_IFLNK: s = "S_IFLNK"; break;
-		case S_IFSOCK: s = "S_IFSOCK"; break;
-		case S_IFDOOR: s = "S_IFDOOR"; break;
-		case S_IFPORT: s = "S_IFPORT"; break;
-		default:
-			s = unknown;
-			(void) sprintf(s, "0x%.4x ",
-			    (int)statb.st_mode & S_IFMT);
-			break;
-		}
-
-		(void) printf("%4d: %s mode:0%.3o", fd, s,
-		    (int)statb.st_mode & ~S_IFMT);
-
-		if (major(statb.st_dev) != (major_t)NODEV &&
-		    minor(statb.st_dev) != (minor_t)NODEV)
-			(void) printf(" dev:%lu,%lu",
-			    (ulong_t)major(statb.st_dev),
-			    (ulong_t)minor(statb.st_dev));
-		else
-			(void) printf(" dev:0x%.8lX", (long)statb.st_dev);
-
-		if ((statb.st_mode & S_IFMT) == S_IFPORT) {
-			(void) printf(" uid:%d gid:%d",
-			    (int)statb.st_uid,
-			    (int)statb.st_gid);
-			(void) printf(" size:%lld\n",
-			    (longlong_t)statb.st_size);
-			continue;
-		}
-
-		(void) printf(" ino:%llu uid:%d gid:%d",
-		    (u_longlong_t)statb.st_ino,
-		    (int)statb.st_uid, (int)statb.st_gid);
-
-		if (rdev == NODEV)
-			(void) printf(" size:%lld\n",
-			    (longlong_t)statb.st_size);
-		else if (major(rdev) != (major_t)NODEV &&
-		    minor(rdev) != (minor_t)NODEV)
-			(void) printf(" rdev:%lu,%lu\n",
-			    (ulong_t)major(rdev), (ulong_t)minor(rdev));
-		else
-			(void) printf(" rdev:0x%.8lX\n", (long)rdev);
-
-		if (!nflag) {
-			off_t offset;
-
-			dofcntl(Pr, fd,
-			    (statb.st_mode & (S_IFMT|S_ENFMT|S_IXGRP))
-			    == (S_IFREG|S_ENFMT),
-			    (statb.st_mode & S_IFMT) == S_IFDOOR);
-
-			if ((statb.st_mode & S_IFMT) == S_IFSOCK)
-				dosocket(Pr, fd);
-			else if ((statb.st_mode & S_IFMT) == S_IFIFO)
-				dofifo(Pr, fd);
-
-			(void) sprintf(pname, "/proc/%d/path/%d", (int)pid, fd);
-
-			if ((ret = readlink(pname, fname, PATH_MAX - 1)) <= 0)
-				continue;
-
-			fname[ret] = '\0';
-
-			if ((statb.st_mode & S_IFMT) == S_IFCHR &&
-			    (dev = strrchr(fname, ':')) != NULL) {
-				/*
-				 * There's no elegant way to determine if a
-				 * character device supports TLI, so we lame
-				 * out and just check a hardcoded list of
-				 * known TLI devices.
-				 */
-				int i;
-				const char *tlidevs[] =
-				    { "tcp", "tcp6", "udp", "udp6", NULL };
-
-				dev++; /* skip past the `:' */
-				for (i = 0; tlidevs[i] != NULL; i++) {
-					if (strcmp(dev, tlidevs[i]) == 0) {
-						dotli(Pr, fd);
-						break;
-					}
-				}
-			}
-			(void) printf("      %s\n", fname);
-
-			offset = pr_lseek(Pr, fd, 0, SEEK_CUR);
-			if (offset != -1) {
-				(void) printf("      offset:%ld\n", offset);
-			}
-
-		}
-	}
-	(void) closedir(dirp);
+	(void) Pfdinfo_iter(Pr, show_file, Pr);
 }
 
 
@@ -371,14 +356,17 @@
 
 /* examine open file with fcntl() */
 static void
-dofcntl(struct ps_prochandle *Pr, int fd, int mandatory, int isdoor)
+dofcntl(struct ps_prochandle *Pr, prfdinfo_t *info, int mandatory, int isdoor)
 {
 	struct flock flock;
 	int fileflags;
 	int fdflags;
+	int fd;
 
-	fileflags = pr_fcntl(Pr, fd, F_GETXFL, 0);
-	fdflags = pr_fcntl(Pr, fd, F_GETFD, 0);
+	fd = info->pr_fd;
+
+	fileflags = info->pr_fileflags;
+	fdflags = info->pr_fdflags;
 
 	if (fileflags != -1 || fdflags != -1) {
 		(void) printf("      ");
@@ -386,10 +374,10 @@
 			show_fileflags(fileflags);
 		if (fdflags != -1 && (fdflags & FD_CLOEXEC))
 			(void) printf(" FD_CLOEXEC");
-		if (isdoor)
+		if (isdoor && (Pstate(Pr) != PS_DEAD))
 			show_door(Pr, fd);
 		(void) fputc('\n', stdout);
-	} else if (isdoor) {
+	} else if (isdoor && (Pstate(Pr) != PS_DEAD)) {
 		(void) printf("    ");
 		show_door(Pr, fd);
 		(void) fputc('\n', stdout);
@@ -401,7 +389,7 @@
 	flock.l_len = 0;
 	flock.l_sysid = 0;
 	flock.l_pid = 0;
-	if (getflock(Pr, fd, &flock) != -1) {
+	if ((Pstate(Pr) != PS_DEAD) && (getflock(Pr, fd, &flock) != -1)) {
 		if (flock.l_type != F_UNLCK && (flock.l_sysid || flock.l_pid)) {
 			unsigned long sysid = flock.l_sysid;
 
--- a/usr/src/cmd/sgs/elfdump/common/corenote.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/corenote.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,7 +23,9 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -1545,6 +1547,45 @@
 	indent_exit(state);
 }
 
+static void
+dump_prfdinfo(note_state_t *state, const char *title)
+{
+	const sl_prfdinfo_layout_t *layout = state->ns_arch->prfdinfo;
+	char buf[1024];
+	uint32_t fileflags, mode;
+
+	indent_enter(state, title, &layout->pr_fd);
+
+	PRINT_DEC(MSG_ORIG(MSG_CNOTE_T_PR_FD), pr_fd);
+	mode = extract_as_word(state, &layout->pr_mode);
+
+	print_str(state, MSG_ORIG(MSG_CNOTE_T_PR_MODE),
+	    conv_cnote_filemode(mode, 0, buf, sizeof (buf)));
+
+	PRINT_DEC_2UP(MSG_ORIG(MSG_CNOTE_T_PR_UID), pr_uid,
+	    MSG_ORIG(MSG_CNOTE_T_PR_GID), pr_gid);
+
+	PRINT_DEC_2UP(MSG_ORIG(MSG_CNOTE_T_PR_MAJOR), pr_major,
+	    MSG_ORIG(MSG_CNOTE_T_PR_MINOR), pr_minor);
+	PRINT_DEC_2UP(MSG_ORIG(MSG_CNOTE_T_PR_RMAJOR), pr_rmajor,
+	    MSG_ORIG(MSG_CNOTE_T_PR_RMINOR), pr_rminor);
+
+	PRINT_DEC(MSG_ORIG(MSG_CNOTE_T_PR_INO), pr_ino);
+
+	PRINT_DEC_2UP(MSG_ORIG(MSG_CNOTE_T_PR_SIZE), pr_size,
+	    MSG_ORIG(MSG_CNOTE_T_PR_OFFSET), pr_offset);
+
+	fileflags = extract_as_word(state, &layout->pr_fileflags);
+
+	print_str(state, MSG_ORIG(MSG_CNOTE_T_PR_FILEFLAGS),
+	    conv_cnote_fileflags(fileflags, 0, buf, sizeof (buf)));
+
+	PRINT_DEC(MSG_ORIG(MSG_CNOTE_T_PR_FDFLAGS), pr_fdflags);
+
+	PRINT_STRBUF(MSG_ORIG(MSG_CNOTE_T_PR_PATH), pr_path);
+
+	indent_exit(state);
+}
 
 /*
  * Output information from priv_impl_info_t structure.
@@ -1777,6 +1818,14 @@
 		dbg_print(0, MSG_ORIG(MSG_NOTE_DESC));
 		dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), safe_str(desc, descsz));
 		return (CORENOTE_R_OK);
+
+
+	case NT_FDINFO:
+		state.ns_vcol = 22;
+		state.ns_t2col = 41;
+		state.ns_v2col = 54;
+		dump_prfdinfo(&state, MSG_ORIG(MSG_CNOTE_DESC_PRFDINFO_T));
+		return (CORENOTE_R_OK);
 	}
 
 	return (CORENOTE_R_BADTYPE);
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Fri Nov 02 09:48:42 2012 -0700
@@ -21,6 +21,7 @@
 
 #
 # Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
 #
 
 @ _START_
@@ -457,6 +458,7 @@
 @ MSG_CNOTE_DESC_PSINFO_T		"desc: (psinfo_t)"
 @ MSG_CNOTE_DESC_PSTATUS_T		"desc: (pstatus_t)"
 @ MSG_CNOTE_DESC_STRUCT_UTSNAME		"desc: (struct utsname)"
+@ MSG_CNOTE_DESC_PRFDINFO_T		"desc: (prfdinfo_t)"
 
 
 @ MSG_CNOTE_FMT_LINE		"%*s%-*s%s"
@@ -615,6 +617,17 @@
 @ MSG_CNOTE_T_UTS_RELEASE		"release:"
 @ MSG_CNOTE_T_UTS_SYSNAME		"sysname:"
 @ MSG_CNOTE_T_UTS_VERSION		"version:"
+@ MSG_CNOTE_T_PR_FD			"pr_fd:"
+@ MSG_CNOTE_T_PR_MODE			"pr_mode:"
+@ MSG_CNOTE_T_PR_PATH			"pr_path:"
+@ MSG_CNOTE_T_PR_MAJOR			"pr_major:"
+@ MSG_CNOTE_T_PR_MINOR			"pr_minor:"
+@ MSG_CNOTE_T_PR_RMAJOR			"pr_rmajor:"
+@ MSG_CNOTE_T_PR_RMINOR			"pr_rminor:"
+@ MSG_CNOTE_T_PR_OFFSET			"pr_offset:"
+@ MSG_CNOTE_T_PR_INO			"pr_ino:"
+@ MSG_CNOTE_T_PR_FILEFLAGS		"pr_fileflags:"
+@ MSG_CNOTE_T_PR_FDFLAGS		"pr_fdflags:"
 
 
 # Names of fake sections generated from program header data
--- a/usr/src/cmd/sgs/elfdump/common/struct_layout.h	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/struct_layout.h	Fri Nov 02 09:48:42 2012 -0700
@@ -24,6 +24,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
+
 #ifndef	_STRUCT_LAYOUT_H
 #define	_STRUCT_LAYOUT_H
 
@@ -88,7 +92,7 @@
 } sl_field_t;
 
 /*
- * This type is used to extract and manipuate data described by
+ * This type is used to extract and manipulate data described by
  * sl_field_t. We rely on the C guarantee that all the fields in
  * a union have offset 0.
  */
@@ -502,6 +506,27 @@
 } sl_utsname_layout_t;
 
 /*
+ * Layout description of prdinfo_t, from <sys/procfs.h>.
+ */
+typedef struct {
+	sl_field_t		sizeof_struct;
+	sl_field_t		pr_fd;
+	sl_field_t		pr_mode;
+	sl_field_t		pr_uid;
+	sl_field_t		pr_gid;
+	sl_field_t		pr_major;
+	sl_field_t		pr_minor;
+	sl_field_t		pr_rmajor;
+	sl_field_t		pr_rminor;
+	sl_field_t		pr_ino;
+	sl_field_t		pr_offset;
+	sl_field_t		pr_size;
+	sl_field_t		pr_fileflags;
+	sl_field_t		pr_fdflags;
+	sl_field_t		pr_path;
+} sl_prfdinfo_layout_t;
+
+/*
  * This type collects all of the layout definitions for
  * a given architecture.
  */
@@ -525,6 +550,7 @@
 	const sl_sysset_layout_t	*sysset;	/* sysset_t */
 	const sl_timestruc_layout_t	*timestruc;	/* timestruc_t */
 	const sl_utsname_layout_t	*utsname;	/* struct utsname */
+	const sl_prfdinfo_layout_t	*prfdinfo;	/* prdinfo_t */
 } sl_arch_layout_t;
 
 
--- a/usr/src/cmd/sgs/elfdump/common/struct_layout_amd64.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/struct_layout_amd64.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,7 +23,9 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #include <struct_layout.h>
 
@@ -356,6 +358,23 @@
 };
 
 
+static const sl_prfdinfo_layout_t prfdinfo_layout = {
+	{ 0,	1088,	0,	0 },		/* sizeof (prfdinfo_t) */
+	{ 0,	4,	0,	0 },		/* pr_fd */
+	{ 4,	4,	0,	0 },		/* pr_mode */
+	{ 8,	4,	0,	0 },		/* pr_uid */
+	{ 12,	4,	0,	0 },		/* pr_gid */
+	{ 16,	4,	0,	0 },		/* pr_major */
+	{ 20,	4,	0,	0 },		/* pr_minor */
+	{ 24,	4,	0,	0 },		/* pr_rmajor */
+	{ 28,	4,	0,	0 },		/* pr_rminor */
+	{ 32,	8,	0,	0 },		/* pr_ino */
+	{ 40,	8,	0,	0 },		/* pr_offset */
+	{ 48,	8,	0,	0 },		/* pr_size */
+	{ 56,	4,	0,	0 },		/* pr_filefags */
+	{ 60,	4,	0,	0 },		/* pr_fdflags */
+	{ 64,	1,	1024,	0 },		/* pr_path */
+};
 
 
 static const sl_arch_layout_t layout_amd64 = {
@@ -378,6 +397,7 @@
 	&sysset_layout,
 	&timestruc_layout,
 	&utsname_layout,
+	&prfdinfo_layout,
 };
 
 
--- a/usr/src/cmd/sgs/elfdump/common/struct_layout_i386.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/struct_layout_i386.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,7 +23,9 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #include <struct_layout.h>
 
@@ -356,6 +358,23 @@
 };
 
 
+static const sl_prfdinfo_layout_t prfdinfo_layout = {
+	{ 0,	1088,	0,	0 },	/* sizeof (prfdinfo_t) */
+	{ 0,	4,	0,	0 },	/* pr_fd */
+	{ 4,	4,	0,	0 },	/* pr_mode */
+	{ 8,	4,	0,	0 },	/* pr_uid */
+	{ 12,	4,	0,	0 },	/* pr_gid */
+	{ 16,	4,	0,	0 },	/* pr_major */
+	{ 20,	4,	0,	0 },	/* pr_minor */
+	{ 24,	4,	0,	0 },	/* pr_rmajor */
+	{ 28,	4,	0,	0 },	/* pr_rminor */
+	{ 32,	8,	0,	0 },	/* pr_ino */
+	{ 40,	8,	0,	0 },	/* pr_offset */
+	{ 48,	8,	0,	0 },	/* pr_size */
+	{ 56,	4,	0,	0 },	/* pr_filefags */
+	{ 60,	4,	0,	0 },	/* pr_fdflags */
+	{ 64,	1,	1024,	0 },	/* pr_path */
+};
 
 
 static const sl_arch_layout_t layout_i386 = {
@@ -378,6 +397,7 @@
 	&sysset_layout,
 	&timestruc_layout,
 	&utsname_layout,
+	&prfdinfo_layout,
 };
 
 
--- a/usr/src/cmd/sgs/elfdump/common/struct_layout_sparc.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/struct_layout_sparc.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,8 +23,9 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 #include <struct_layout.h>
 
 
@@ -356,6 +357,23 @@
 };
 
 
+static const sl_prfdinfo_layout_t prfdinfo_layout = {
+	{ 0,	1088,	0,	0 },		/* sizeof (prfdinfo_t) */
+	{ 0,	4,	0,	0 },		/* pr_fd */
+	{ 4,	4,	0,	0 },		/* pr_mode */
+	{ 8,	4,	0,	0 },		/* pr_uid */
+	{ 12,	4,	0,	0 },		/* pr_gid */
+	{ 16,	4,	0,	0 },		/* pr_major */
+	{ 20,	4,	0,	0 },		/* pr_minor */
+	{ 24,	4,	0,	0 },		/* pr_rmajor */
+	{ 28,	4,	0,	0 },		/* pr_rminor */
+	{ 32,	8,	0,	0 },		/* pr_ino */
+	{ 40,	8,	0,	0 },		/* pr_offset */
+	{ 48,	8,	0,	0 },		/* pr_size */
+	{ 56,	4,	0,	0 },		/* pr_filefags */
+	{ 60,	4,	0,	0 },		/* pr_fdflags */
+	{ 64,	1,	1024,	0 },		/* pr_path */
+};
 
 
 static const sl_arch_layout_t layout_sparc = {
@@ -378,6 +396,7 @@
 	&sysset_layout,
 	&timestruc_layout,
 	&utsname_layout,
+	&prfdinfo_layout,
 };
 
 
--- a/usr/src/cmd/sgs/elfdump/common/struct_layout_sparcv9.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/elfdump/common/struct_layout_sparcv9.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,7 +23,9 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #include <struct_layout.h>
 
@@ -356,6 +358,23 @@
 };
 
 
+static const sl_prfdinfo_layout_t prfdinfo_layout = {
+	{ 0,	1088,	0,	0 },		/* sizeof (prfdinfo_t) */
+	{ 0,	4,	0,	0 },		/* pr_fd */
+	{ 4,	4,	0,	0 },		/* pr_mode */
+	{ 8,	4,	0,	0 },		/* pr_uid */
+	{ 12,	4,	0,	0 },		/* pr_gid */
+	{ 16,	4,	0,	0 },		/* pr_major */
+	{ 20,	4,	0,	0 },		/* pr_minor */
+	{ 24,	4,	0,	0 },		/* pr_rmajor */
+	{ 28,	4,	0,	0 },		/* pr_rminor */
+	{ 32,	8,	0,	0 },		/* pr_ino */
+	{ 40,	8,	0,	0 },		/* pr_offset */
+	{ 48,	8,	0,	0 },		/* pr_size */
+	{ 56,	4,	0,	0 },		/* pr_filefags */
+	{ 60,	4,	0,	0 },		/* pr_fdflags */
+	{ 64,	1,	1024,	0 },		/* pr_path */
+};
 
 
 static const sl_arch_layout_t layout_sparcv9 = {
@@ -378,6 +397,7 @@
 	&sysset_layout,
 	&timestruc_layout,
 	&utsname_layout,
+	&prfdinfo_layout,
 };
 
 
--- a/usr/src/cmd/sgs/include/conv.h	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/include/conv.h	Fri Nov 02 09:48:42 2012 -0700
@@ -24,6 +24,7 @@
  *	  All Rights Reserved
  *
  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  */
 
 #ifndef	_CONV_H
@@ -837,6 +838,10 @@
 			    Conv_inv_buf_t *);
 extern	const char	*conv_cnote_sysset(uint32_t *, int,
 			    Conv_fmt_flags_t, Conv_cnote_sysset_buf_t *);
+extern	const char	*conv_cnote_fileflags(uint32_t, Conv_fmt_flags_t,
+			    char *, size_t);
+extern	const char	*conv_cnote_filemode(uint32_t, Conv_fmt_flags_t,
+			    char *, size_t);
 extern	const char	*conv_cnote_type(Word, Conv_fmt_flags_t,
 			    Conv_inv_buf_t *);
 extern	const char	*conv_def_tag(Symref, Conv_inv_buf_t *);
--- a/usr/src/cmd/sgs/libconv/common/corenote.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/libconv/common/corenote.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,6 +23,9 @@
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 /*
  * String conversion routines the system structs found in
@@ -52,9 +55,9 @@
 		MSG_NT_UTSNAME,		MSG_NT_LWPSTATUS,
 		MSG_NT_LWPSINFO,	MSG_NT_PRPRIV,
 		MSG_NT_PRPRIVINFO,	MSG_NT_CONTENT,
-		MSG_NT_ZONENAME
+		MSG_NT_ZONENAME,	MSG_NT_FDINFO
 	};
-#if NT_NUM != NT_ZONENAME
+#if NT_NUM != NT_FDINFO
 #error "NT_NUM has grown. Update core note types[]"
 #endif
 	static const conv_ds_msg_t ds_types = {
@@ -2442,3 +2445,138 @@
 
 #undef N_MASK
 }
+
+const char *
+conv_cnote_fileflags(uint32_t fileflags, Conv_fmt_flags_t fmt_flags,
+    char *buf, size_t bufsize)
+{
+	CONV_EXPN_FIELD_ARG arg = { 0 };
+
+	Val_desc vda[] = {
+		{ 0x0001,	MSG_PR_O_WRONLY },
+		{ 0x0002,	MSG_PR_O_RDONLY },
+		{ 0x200000,	MSG_PR_O_SEARCH },
+		{ 0x400000,	MSG_PR_O_EXEC },
+		{ 0x0004,	MSG_PR_O_NDELAY },
+		{ 0x0008,	MSG_PR_O_APPEND },
+		{ 0x0010,	MSG_PR_O_SYNC },
+		{ 0x0040,	MSG_PR_O_DSYNC },
+		{ 0x0080,	MSG_PR_O_NONBLOCK },
+		{ 0x0100,	MSG_PR_O_CREAT },
+		{ 0x0200,	MSG_PR_O_TRUNC },
+		{ 0x0400,	MSG_PR_O_EXCL },
+		{ 0x0800,	MSG_PR_O_NOCTTY },
+		{ 0x4000,	MSG_PR_O_XATTR },
+		{ 0x8000,	MSG_PR_O_RSYNC },
+		{ 0x2000,	MSG_PR_O_LARGEFILE },
+		{ 0x20000,	MSG_PR_O_NOFOLLOW },
+		{ 0x40000,	MSG_PR_O_NOLINKS },
+		{ 0, NULL },
+	};
+
+	arg.oflags = arg.rflags = fileflags;
+	arg.buf = buf;
+	arg.bufsize = bufsize;
+
+	switch (fileflags & (0x600003)) {
+	case 0:	/* RDONLY */
+		vda[0].v_msg = MSG_PR_O_RDONLY;
+		arg.oflags |= 1;
+		arg.rflags |= 1;
+		break;
+	case 1:	/* WRONLY */
+	case 2:	/* RDWR */
+	case 0x200000:	/* SEARCH */
+	case 0x400000:
+		/* In isolate, treat these as normal bits */
+		break;
+	default:
+		/* More than one bit set in this group, emit numerically */
+		arg.oflags &= ~(fileflags & 0x600003);
+	}
+
+	if (fileflags == 0)
+		return (MSG_ORIG(MSG_GBL_ZERO));
+
+	(void) conv_expn_field(&arg, vda, fmt_flags);
+	return (buf);
+}
+
+const char *
+conv_cnote_filemode(uint32_t mode, Conv_fmt_flags_t fmt_flags,
+    char *buf, size_t bufsize)
+{
+	CONV_EXPN_FIELD_ARG arg = { 0 };
+	Msg s;
+
+	Val_desc vda[] = {
+		{ 0x1000,	MSG_S_IFIFO },
+		{ 0x800,	MSG_S_ISUID },
+		{ 0x400,	MSG_S_ISGID },
+		{ 0x200,	MSG_S_ISVTX },
+		{ 0400,		MSG_S_IRUSR },
+		{ 0200,		MSG_S_IWUSR },
+		{ 0100,		MSG_S_IXUSR },
+		{ 0040,		MSG_S_IRGRP },
+		{ 0020,		MSG_S_IWGRP },
+		{ 0010,		MSG_S_IXGRP },
+		{ 0004,		MSG_S_IROTH },
+		{ 0002,		MSG_S_IWOTH },
+		{ 0001,		MSG_S_IXOTH },
+		{ 0, NULL },
+	};
+
+	arg.oflags = arg.rflags = mode & ~(0xf000);
+	arg.buf = buf;
+	arg.bufsize = bufsize;
+
+	switch (mode & (0xf000)) {
+	case 0x1000:
+		s = MSG_S_IFIFO;
+		break;
+	case 0x2000:
+		s = MSG_S_IFCHR;
+		break;
+	case 0x4000:
+		s = MSG_S_IFDIR;
+		break;
+	case 0x5000:
+		s = MSG_S_IFNAM;
+		break;
+	case 0x6000:
+		s = MSG_S_IFBLK;
+		break;
+	case 0x8000:
+		s = MSG_S_IFREG;
+		break;
+	case 0xA000:
+		s = MSG_S_IFLNK;
+		break;
+	case 0xc000:
+		s = MSG_S_IFSOCK;
+		break;
+	case 0xd000:
+		s = MSG_S_IFDOOR;
+		break;
+	case 0xe000:
+		s = MSG_S_IFPORT;
+		break;
+	default:
+		s = NULL;
+		break;
+	}
+
+	if (s) {
+		arg.oflags |= 0x1000;
+		arg.rflags |= 0x1000;
+		vda[0].v_msg = s;
+	} else {
+		arg.rflags = mode;
+	}
+
+	if (mode == 0)
+		return (MSG_ORIG(MSG_GBL_ZERO));
+
+	(void) conv_expn_field(&arg, vda, fmt_flags);
+	return (buf);
+}
--- a/usr/src/cmd/sgs/libconv/common/corenote.msg	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/cmd/sgs/libconv/common/corenote.msg	Fri Nov 02 09:48:42 2012 -0700
@@ -23,6 +23,8 @@
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+#
 
 @ MSG_NT_PRSTATUS		"[ NT_PRSTATUS ]"
 @ MSG_NT_PRFPREG		"[ NT_PRFPREG ]"
@@ -43,6 +45,7 @@
 @ MSG_NT_PRPRIVINFO		"[ NT_PRPRIVINFO ]"
 @ MSG_NT_CONTENT		"[ NT_CONTENT ]"
 @ MSG_NT_ZONENAME		"[ NT_ZONENAME ]"
+@ MSG_NT_FDINFO			"[ NT_FDINFO ]"
 
 
 @ MSG_AUXV_AF_SUN_SETUGID		"AF_SUN_SETUGID"
@@ -1067,6 +1070,48 @@
 @ MSG_SYS_UMOUNT2			"[ umount2 ]"			# 255
 @ MSG_SYS_UMOUNT2_ALT			"umount2"
 
+@ MSG_PR_O_RDONLY			"O_RDONLY"
+@ MSG_PR_O_WRONLY			"O_WRONLY"
+@ MSG_PR_O_RDWR				"O_RDWR"
+@ MSG_PR_O_SEARCH			"O_SEARCH"
+@ MSG_PR_O_EXEC				"O_EXEC"
+@ MSG_PR_O_NDELAY			"O_NDELAY"
+@ MSG_PR_O_NONBLOCK			"O_NONBLOCK"
+@ MSG_PR_O_APPEND			"O_APPEND"
+@ MSG_PR_O_SYNC				"O_SYNC"
+@ MSG_PR_O_DSYNC			"O_DSYNC"
+@ MSG_PR_O_RSYNC			"O_RSYNC"
+@ MSG_PR_O_CREAT			"O_CREAT"
+@ MSG_PR_O_TRUNC			"O_TRUNC"
+@ MSG_PR_O_EXCL				"O_EXCL"
+@ MSG_PR_O_NOCTTY			"O_NOCTTY"
+@ MSG_PR_O_LARGEFILE			"O_LARGEFILE"
+@ MSG_PR_O_XATTR			"O_XATTR"
+@ MSG_PR_O_NOFOLLOW			"O_NOFOLLOW"
+@ MSG_PR_O_NOLINKS			"O_NOLINKS"
+
+@ MSG_S_IFIFO				"S_IFIFO"
+@ MSG_S_IFCHR				"S_IFCHR"
+@ MSG_S_IFDIR				"S_IFDIR"
+@ MSG_S_IFNAM				"S_IFNAM"
+@ MSG_S_IFBLK				"S_IFBLK"
+@ MSG_S_IFREG				"S_IFREG"
+@ MSG_S_IFLNK				"S_IFLNK"
+@ MSG_S_IFSOCK				"S_IFSOCK"
+@ MSG_S_IFDOOR				"S_IFDOOR"
+@ MSG_S_IFPORT				"S_IFPORT"
+@ MSG_S_ISUID				"S_ISUID"
+@ MSG_S_ISGID				"S_ISGID"
+@ MSG_S_ISVTX				"S_ISVTX"
+@ MSG_S_IRUSR				"S_IRUSR"
+@ MSG_S_IWUSR				"S_IWUSR"
+@ MSG_S_IXUSR				"S_IXUSR"
+@ MSG_S_IRGRP				"S_IRGRP"
+@ MSG_S_IWGRP				"S_IWGRP"
+@ MSG_S_IXGRP				"S_IXGRP"
+@ MSG_S_IROTH				"S_IROTH"
+@ MSG_S_IWOTH				"S_IWOTH"
+@ MSG_S_IXOTH				"S_IXOTH"
 
 @ MSG_GBL_ZERO		"0"
 
--- a/usr/src/lib/libproc/Makefile.com	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/Makefile.com	Fri Nov 02 09:48:42 2012 -0700
@@ -20,6 +20,7 @@
 #
 #
 # Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
 #
 
 LIBRARY = libproc.a
@@ -30,6 +31,7 @@
 	Pcontrol.o	\
 	Pcore.o		\
 	Pexecname.o	\
+	Pfdinfo.o	\
 	Pgcore.o	\
 	Pidle.o		\
 	Pisprocdir.o	\
--- a/usr/src/lib/libproc/common/Pcontrol.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/common/Pcontrol.c	Fri Nov 02 09:48:42 2012 -0700
@@ -24,6 +24,7 @@
  * Use is subject to license terms.
  *
  * Portions Copyright 2007 Chad Mynhier
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  */
 
 #include <assert.h>
@@ -986,6 +987,13 @@
 		}
 		free(P->hashtab);
 	}
+
+	while (P->num_fd > 0) {
+		fd_info_t *fip = list_next(&P->fd_head);
+		list_unlink(fip);
+		free(fip);
+		P->num_fd--;
+	}
 	(void) mutex_unlock(&P->proc_lock);
 	(void) mutex_destroy(&P->proc_lock);
 
--- a/usr/src/lib/libproc/common/Pcontrol.h	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/common/Pcontrol.h	Fri Nov 02 09:48:42 2012 -0700
@@ -22,6 +22,9 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #ifndef	_PCONTROL_H
 #define	_PCONTROL_H
@@ -136,6 +139,11 @@
 #endif
 } lwp_info_t;
 
+typedef struct fd_info {
+	plist_t	fd_list;	/* linked list */
+	prfdinfo_t fd_info;	/* fd info */
+} fd_info_t;
+
 typedef struct core_info {	/* information specific to core files */
 	char core_dmodel;	/* data model for core file */
 	int core_errno;		/* error during initialization if != 0 */
@@ -223,6 +231,8 @@
 	uintptr_t *ucaddrs;	/* ucontext-list addresses */
 	uint_t	ucnelems;	/* number of elements in the ucaddrs list */
 	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 */
 };
 
 /* flags */
@@ -269,6 +279,8 @@
 extern	char	*Pzoneroot(struct ps_prochandle *, char *, size_t);
 extern	char	*Pzonepath(struct ps_prochandle *, const char *, char *,
 	size_t);
+extern	fd_info_t *Pfd2info(struct ps_prochandle *, int);
+
 extern	char	*Pfindmap(struct ps_prochandle *, map_info_t *, char *,
 	size_t);
 
--- a/usr/src/lib/libproc/common/Pcore.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/common/Pcore.c	Fri Nov 02 09:48:42 2012 -0700
@@ -22,6 +22,9 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -300,6 +303,26 @@
 }
 
 static int
+note_fdinfo(struct ps_prochandle *P, size_t nbytes)
+{
+	prfdinfo_t prfd;
+	fd_info_t *fip;
+
+	if ((nbytes < sizeof (prfd)) ||
+	    (read(P->asfd, &prfd, sizeof (prfd)) != sizeof (prfd))) {
+		dprintf("Pgrab_core: failed to read NT_FDINFO\n");
+		return (-1);
+	}
+
+	if ((fip = Pfd2info(P, prfd.pr_fd)) == NULL) {
+		dprintf("Pgrab_core: failed to add NT_FDINFO\n");
+		return (-1);
+	}
+	(void) memcpy(&fip->fd_info, &prfd, sizeof (prfd));
+	return (0);
+}
+
+static int
 note_platform(struct ps_prochandle *P, size_t nbytes)
 {
 	char *plat;
@@ -701,6 +724,7 @@
 	note_priv_info,		/* 19	NT_PRPRIVINFO		*/
 	note_content,		/* 20	NT_CONTENT		*/
 	note_zonename,		/* 21	NT_ZONENAME		*/
+	note_fdinfo,		/* 22	NT_FDINFO		*/
 };
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libproc/common/Pfdinfo.c	Fri Nov 02 09:48:42 2012 -0700
@@ -0,0 +1,168 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/mkdev.h>
+
+#include "libproc.h"
+#include "Pcontrol.h"
+
+/*
+ * Pfdinfo.c - obtain open file information.
+ */
+
+/*
+ * Allocate an fd_info structure and stick it on the list.
+ * (Unless one already exists.)  The list is sorted in
+ * reverse order.  We will traverse it in that order later.
+ * This makes the usual ordered insert *fast*.
+ */
+fd_info_t *
+Pfd2info(struct ps_prochandle *P, int fd)
+{
+	fd_info_t	*fip = list_next(&P->fd_head);
+	fd_info_t	*next;
+	int i;
+
+	if (fip == NULL) {
+		list_link(&P->fd_head, NULL);
+		fip = list_next(&P->fd_head);
+	}
+
+	for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) {
+		if (fip->fd_info.pr_fd == fd) {
+			return (fip);
+		}
+		if (fip->fd_info.pr_fd < fd) {
+			break;
+		}
+	}
+
+	next = fip;
+	if ((fip = calloc(1, sizeof (*fip))) == NULL)
+		return (NULL);
+
+	fip->fd_info.pr_fd = fd;
+	list_link(fip, next ? next : (void *)&(P->fd_head));
+	P->num_fd++;
+	return (fip);
+}
+
+/*
+ * Attempt to load the open file information from a live process.
+ */
+static void
+load_fdinfo(struct ps_prochandle *P)
+{
+	/*
+	 * In the unlikely case there are *no* file descriptors open,
+	 * we will keep rescanning the proc directory, which will be empty.
+	 * This is an edge case it isn't worth adding additional state to
+	 * to eliminate.
+	 */
+	if (P->num_fd > 0) {
+		return;
+	}
+
+	if (P->state != PS_DEAD && P->state != PS_IDLE) {
+		char dir_name[PATH_MAX];
+		char path[PATH_MAX];
+		struct dirent *ent;
+		DIR	*dirp;
+		int	fd;
+
+		/*
+		 * Try to get the path information first.
+		 */
+		(void) snprintf(dir_name, sizeof (dir_name),
+		    "%s/%d/path", procfs_path, (int)P->pid);
+		dirp = opendir(dir_name);
+		if (dirp == NULL) {
+			return;
+		}
+		ent = NULL;
+		while ((ent = readdir(dirp)) != NULL) {
+			fd_info_t	*fip;
+			prfdinfo_t	*info;
+			int		len;
+			struct stat64	stat;
+
+			if (!isdigit(ent->d_name[0]))
+				continue;
+
+			fd = atoi(ent->d_name);
+
+			fip = Pfd2info(P, fd);
+			info = &fip->fd_info;
+			info->pr_fd = fd;
+
+			if (pr_fstat64(P, fd, &stat) == 0) {
+				info->pr_mode = stat.st_mode;
+				info->pr_uid = stat.st_uid;
+				info->pr_gid = stat.st_gid;
+				info->pr_major = major(stat.st_dev);
+				info->pr_minor = minor(stat.st_dev);
+				info->pr_rmajor = major(stat.st_rdev);
+				info->pr_rminor = minor(stat.st_rdev);
+				info->pr_size = stat.st_size;
+				info->pr_ino = stat.st_ino;
+			}
+
+			info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0);
+			info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0);
+			info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR);
+
+			/* attempt to determine the path to it */
+			(void) snprintf(path, sizeof (path),
+			    "%s/%d/path/%d", procfs_path, (int)P->pid, fd);
+			len = readlink(path, info->pr_path,
+			    sizeof (info->pr_path) - 1);
+
+			if (len < 0) {
+				info->pr_path[0] = 0;
+			} else {
+				info->pr_path[len] = 0;
+			}
+		}
+		(void) closedir(dirp);
+
+	}
+}
+
+int
+Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd)
+{
+	fd_info_t *fip;
+	int rv;
+
+	/* Make sure we have live data, if appropriate */
+	load_fdinfo(P);
+
+	/* NB: We walk the list backwards. */
+
+	for (fip = list_prev(&P->fd_head);
+	    fip != (void *)&P->fd_head;
+	    fip = list_prev(fip)) {
+		if ((rv = func(cd, &fip->fd_info)) != 0)
+			return (rv);
+	}
+	return (0);
+}
--- a/usr/src/lib/libproc/common/Pgcore.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/common/Pgcore.c	Fri Nov 02 09:48:42 2012 -0700
@@ -23,6 +23,9 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #define	_STRUCTURED_PROC	1
 
@@ -84,6 +87,11 @@
 	shstrtab_t	pgc_shstrtab;
 } pgcore_t;
 
+typedef struct {
+	int		fd_fd;
+	off64_t		*fd_doff;
+} fditer_t;
+
 static void
 shstrtab_init(shstrtab_t *s)
 {
@@ -543,6 +551,17 @@
 	return (0);
 }
 
+static int
+iter_fd(void *data, prfdinfo_t *fdinfo)
+{
+	fditer_t *iter = data;
+
+	if (write_note(iter->fd_fd, NT_FDINFO, fdinfo,
+	    sizeof (*fdinfo), iter->fd_doff) != 0)
+		return (1);
+	return (0);
+}
+
 static uint_t
 count_sections(pgcore_t *pgc)
 {
@@ -1341,6 +1360,15 @@
 	    &doff) != 0)
 		goto err;
 
+	{
+		fditer_t iter;
+		iter.fd_fd = fd;
+		iter.fd_doff = &doff;
+
+		if (Pfdinfo_iter(P, iter_fd, &iter) != 0)
+			goto err;
+	}
+
 #if defined(__i386) || defined(__amd64)
 	/* CSTYLED */
 	{
--- a/usr/src/lib/libproc/common/libproc.h	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/common/libproc.h	Fri Nov 02 09:48:42 2012 -0700
@@ -24,6 +24,7 @@
  * Use is subject to license terms.
  *
  * Portions Copyright 2007 Chad Mynhier
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -713,6 +714,12 @@
 extern int proc_flushstdio(void);
 extern int proc_finistdio(void);
 
+/*
+ * Iterate over all open files.
+ */
+typedef int proc_fdinfo_f(void *, prfdinfo_t *);
+extern int Pfdinfo_iter(struct ps_prochandle *, proc_fdinfo_f *, void *);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/libproc/common/mapfile-vers	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/lib/libproc/common/mapfile-vers	Fri Nov 02 09:48:42 2012 -0700
@@ -20,6 +20,7 @@
 #
 #
 # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
 #
 
 #
@@ -298,6 +299,7 @@
 	Pzonename;
 	Pzonepath;
 	Pzoneroot;
+	Pfdinfo_iter;
 
 $if _x86 && _ELF32
 	Pldt;
--- a/usr/src/man/man1/proc.1	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/man/man1/proc.1	Fri Nov 02 09:48:42 2012 -0700
@@ -1,10 +1,11 @@
 '\" te
 .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
 .\" Portions Copyright 2008 Chad Mynhier
+.\" Copyright 2012 DEY Storage Systems, 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 1 "Dec 10, 2008"
+.TH PROC 1 "Oct 23, 2012"
 .SH NAME
 proc, pflags, pcred, pldd, psig, pstack, pfiles, pwdx, pstop, prun, pwait,
 ptime \- proc tools
@@ -46,7 +47,7 @@
 
 .LP
 .nf
-\fB/usr/bin/pfiles\fR [\fB-Fn\fR] \fIpid\fR...
+\fB/usr/bin/pfiles\fR [\fB-Fn\fR] \fIpid\fR | \fIcore\fR...
 .fi
 
 .LP
--- a/usr/src/man/man4/core.4	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/man/man4/core.4	Fri Nov 02 09:48:42 2012 -0700
@@ -1,10 +1,11 @@
 '\" te
 .\" Copyright (C) 2008, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2012 DEY Storage Systems, 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 "May 13, 2008"
+.TH CORE 4 "Oct 23, 2012"
 .SH NAME
 core \- process core file
 .SH DESCRIPTION
@@ -307,7 +308,7 @@
 .RS 20n
 \fBn_type\fR: \fBNT_PRCRED\fR. This structure contains the process credentials,
 including the real, saved, and effective user and group IDs. The \fBprcred_t\fR
-structure is defined in <\fBaasys/procfs.h\fR>. Following the structure is an
+structure is defined in <\fBsys/procfs.h\fR>. Following the structure is an
 optional array of supplementary group IDs. The total number of supplementary
 group IDs is given by the \fBpr_ngroups\fR member of the \fBprcred_t\fR
 structure, and the structure includes space for one supplementary group. If
@@ -330,6 +331,18 @@
 .sp
 .ne 2
 .na
+\fB\fBprfdinfo_t\fR\fR
+.ad
+.RS 20n
+\fBn_type\fR: \fBNT_FDINFO\fR. This structure contains information about
+any open file descriptors, including the path, flags, and
+\fBstat\fR(2) information.  The \fBprfdinfo_t\fR structure is defined in
+<\fBsys/procfs.h\fR>.
+.RE
+
+.sp
+.ne 2
+.na
 \fB\fBstruct ssd\fR array\fR
 .ad
 .RS 20n
--- a/usr/src/uts/common/exec/elf/elf_notes.c	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/uts/common/exec/elf/elf_notes.c	Fri Nov 02 09:48:42 2012 -0700
@@ -24,7 +24,9 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -34,8 +36,11 @@
 #include <sys/cred.h>
 #include <sys/priv.h>
 #include <sys/user.h>
+#include <sys/file.h>
 #include <sys/errno.h>
 #include <sys/vnode.h>
+#include <sys/mode.h>
+#include <sys/vfs.h>
 #include <sys/mman.h>
 #include <sys/kmem.h>
 #include <sys/proc.h>
@@ -57,6 +62,7 @@
 #include <sys/modctl.h>
 #include <sys/systeminfo.h>
 #include <sys/machelf.h>
+#include <sys/sunddi.h>
 #include "elf_impl.h"
 #if defined(__i386) || defined(__i386_COMPAT)
 #include <sys/sysi86.h>
@@ -67,12 +73,27 @@
 {
 	int nlwp = p->p_lwpcnt;
 	int nzomb = p->p_zombcnt;
+	int nfd;
 	size_t size;
 	prcred_t *pcrp;
+	uf_info_t *fip;
+	uf_entry_t *ufp;
+	int fd;
+
+	fip = P_FINFO(p);
+	nfd = 0;
+	mutex_enter(&fip->fi_lock);
+	for (fd = 0; fd < fip->fi_nfiles; fd++) {
+		UF_ENTER(ufp, fip, fd);
+		if ((ufp->uf_file != NULL) && (ufp->uf_file->f_count > 0))
+			nfd++;
+		UF_EXIT(ufp);
+	}
+	mutex_exit(&fip->fi_lock);
 
 	v[0].p_type = PT_NOTE;
 	v[0].p_flags = PF_R;
-	v[0].p_filesz = (sizeof (Note) * (9 + 2 * nlwp + nzomb))
+	v[0].p_filesz = (sizeof (Note) * (9 + 2 * nlwp + nzomb + nfd))
 	    + roundup(sizeof (psinfo_t), sizeof (Word))
 	    + roundup(sizeof (pstatus_t), sizeof (Word))
 	    + roundup(prgetprivsize(), sizeof (Word))
@@ -83,7 +104,8 @@
 	    + roundup(sizeof (utsname), sizeof (Word))
 	    + roundup(sizeof (core_content_t), sizeof (Word))
 	    + (nlwp + nzomb) * roundup(sizeof (lwpsinfo_t), sizeof (Word))
-	    + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word));
+	    + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word))
+	    + nfd * roundup(sizeof (prfdinfo_t), sizeof (Word));
 
 	size = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1);
 	pcrp = kmem_alloc(size, KM_SLEEP);
@@ -97,6 +119,7 @@
 	}
 	kmem_free(pcrp, size);
 
+
 #if defined(__i386) || defined(__i386_COMPAT)
 	mutex_enter(&p->p_ldtlock);
 	size = prnldt(p) * sizeof (struct ssd);
@@ -159,7 +182,7 @@
 	size_t crsize = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1);
 	size_t psize = prgetprivsize();
 	size_t bigsize = MAX(psize, MAX(sizeof (*bigwad),
-					MAX(xregsize, crsize)));
+	    MAX(xregsize, crsize)));
 
 	priv_impl_info_t *prii;
 
@@ -173,6 +196,10 @@
 	int nzomb;
 	int error;
 	uchar_t oldsig;
+	uf_info_t *fip;
+	int fd;
+	vnode_t *vroot;
+
 #if defined(__i386) || defined(__i386_COMPAT)
 	struct ssd *ssd;
 	size_t ssdsize;
@@ -293,6 +320,89 @@
 	if (error)
 		goto done;
 
+
+	/* open file table */
+	vroot = PTOU(p)->u_rdir;
+	if (vroot == NULL)
+		vroot = rootdir;
+
+	VN_HOLD(vroot);
+
+	fip = P_FINFO(p);
+
+	for (fd = 0; fd < fip->fi_nfiles; fd++) {
+		uf_entry_t *ufp;
+		vnode_t *fvp;
+		struct file *fp;
+		vattr_t vattr;
+		prfdinfo_t fdinfo;
+
+		bzero(&fdinfo, sizeof (fdinfo));
+
+		mutex_enter(&fip->fi_lock);
+		UF_ENTER(ufp, fip, fd);
+		if (((fp = ufp->uf_file) == NULL) || (fp->f_count < 1)) {
+			UF_EXIT(ufp);
+			mutex_exit(&fip->fi_lock);
+			continue;
+		}
+
+		fdinfo.pr_fd = fd;
+		fdinfo.pr_fdflags = ufp->uf_flag;
+		fdinfo.pr_fileflags = fp->f_flag2;
+		fdinfo.pr_fileflags <<= 16;
+		fdinfo.pr_fileflags |= fp->f_flag;
+		if ((fdinfo.pr_fileflags & (FSEARCH | FEXEC)) == 0)
+			fdinfo.pr_fileflags += FOPEN;
+		fdinfo.pr_offset = fp->f_offset;
+
+
+		fvp = fp->f_vnode;
+		VN_HOLD(fvp);
+		UF_EXIT(ufp);
+		mutex_exit(&fip->fi_lock);
+
+		/*
+		 * There are some vnodes that have no corresponding
+		 * path.  Its reasonable for this to fail, in which
+		 * case the path will remain an empty string.
+		 */
+		(void) vnodetopath(vroot, fvp, fdinfo.pr_path,
+		    sizeof (fdinfo.pr_path), credp);
+
+		error = VOP_GETATTR(fvp, &vattr, 0, credp, NULL);
+		if (error != 0) {
+			VN_RELE(fvp);
+			VN_RELE(vroot);
+			goto done;
+		}
+
+		if (fvp->v_type == VSOCK)
+			fdinfo.pr_fileflags |= sock_getfasync(fvp);
+
+		VN_RELE(fvp);
+
+		/*
+		 * This logic mirrors fstat(), which we cannot use
+		 * directly, as it calls copyout().
+		 */
+		fdinfo.pr_major = getmajor(vattr.va_fsid);
+		fdinfo.pr_minor = getminor(vattr.va_fsid);
+		fdinfo.pr_ino = (ino64_t)vattr.va_nodeid;
+		fdinfo.pr_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
+		fdinfo.pr_uid = vattr.va_uid;
+		fdinfo.pr_gid = vattr.va_gid;
+		fdinfo.pr_rmajor = getmajor(vattr.va_rdev);
+		fdinfo.pr_rminor = getminor(vattr.va_rdev);
+		fdinfo.pr_size = (off64_t)vattr.va_size;
+
+		error = elfnote(vp, &offset, NT_FDINFO,
+		    sizeof (fdinfo), &fdinfo, rlimit, credp);
+		if (error) {
+			goto done;
+		}
+	}
+
 #if defined(__i386) || defined(__i386_COMPAT)
 	mutex_enter(&p->p_ldtlock);
 	ssdsize = prnldt(p) * sizeof (struct ssd);
--- a/usr/src/uts/common/sys/elf.h	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/uts/common/sys/elf.h	Fri Nov 02 09:48:42 2012 -0700
@@ -19,6 +19,9 @@
  * CDDL HEADER END
  */
 /*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
+/*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -812,7 +815,8 @@
 #define	NT_PRPRIVINFO	19	/* priv_impl_info_t <sys/priv.h>	*/
 #define	NT_CONTENT	20	/* core_content_t <sys/corectl.h>	*/
 #define	NT_ZONENAME	21	/* string from getzonenamebyid(3C)	*/
-#define	NT_NUM		21
+#define	NT_FDINFO	22	/* open fd info 			*/
+#define	NT_NUM		22
 
 
 #ifdef _KERNEL
--- a/usr/src/uts/common/sys/procfs.h	Tue Oct 23 12:58:35 2012 -0400
+++ b/usr/src/uts/common/sys/procfs.h	Fri Nov 02 09:48:42 2012 -0700
@@ -23,12 +23,13 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
+ */
 
 #ifndef _SYS_PROCFS_H
 #define	_SYS_PROCFS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -61,6 +62,8 @@
 #include <sys/pset.h>
 #include <sys/procfs_isa.h>
 #include <sys/priv.h>
+#include <sys/stat.h>
+#include <sys/param.h>
 
 #if !defined(_LP64) && _FILE_OFFSET_BITS == 64
 #error	"Cannot use procfs in the large file compilation environment"
@@ -492,6 +495,38 @@
 #define	PG_HWMAPPED	0x04		/* page is present and mapped */
 
 /*
+ * Open files.  Only in core files (for now).  Note that we'd like to use
+ * the stat or stat64 structure, but both of these structures are unfortunately
+ * not consistent between 32 and 64 bit modes.  To keep our lives simpler, we
+ * just define our own structure with types that are not sensitive to this
+ * difference.  Also, it turns out that pfiles omits a lot of info from the
+ * struct stat (e.g. times, device sizes, etc.) so we don't bother adding those
+ * here.
+ */
+typedef struct prfdinfo {
+	int		pr_fd;
+	mode_t		pr_mode;
+
+	uid_t		pr_uid;
+	gid_t		pr_gid;
+
+	major_t		pr_major;	/* think stat.st_dev */
+	minor_t		pr_minor;
+
+	major_t		pr_rmajor;	/* think stat.st_rdev */
+	minor_t		pr_rminor;
+
+	ino64_t		pr_ino;
+	off64_t		pr_offset;
+	off64_t		pr_size;
+
+	int		pr_fileflags;	/* fcntl(F_GETXFL), etc */
+	int		pr_fdflags;	/* fcntl(F_GETFD), etc. */
+
+	char		pr_path[MAXPATHLEN];
+} prfdinfo_t;
+
+/*
  * Header for /proc/<pid>/lstatus /proc/<pid>/lpsinfo /proc/<pid>/lusage
  */
 typedef struct prheader {