Bug 173723

Summary: Add file descriptor information to process core dumps
Product: Base System Reporter: John Baldwin <jhb>
Component: kernAssignee: Mikolaj Golub <trociny>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 1.0-CURRENT   
Hardware: Any   
OS: Any   

Description John Baldwin freebsd_committer freebsd_triage 2012-11-19 17:00:00 UTC
ELF core files already include metadata about processes including notes with the context of each running thread.  Occasionally I have wanted to examine the open fd's associated with a process while debugging.  With the advent of 'procstat -f' we now have a useful structure that holds file descriptor info in a somewhat abstract manner.  It seems possible that we could add a new set of notes to a core dump listing the various file descriptors associated with the process at the time of exit storing 'kinfo_file' objects in the relevant notes.  It is probably worth including additional notes for other "files" such as the working directory, etc. as show in 'procstat -f' output of a running process.

Once this is present there should be ways to extract the information from a core. One would be to teach libprocstat how to look for data from a core file (and thus procstat).  Another useful thing to do would be to add a new custom command to gdb to dump this table from within gdb.  Said command could use libprocstat to work against both coredumps and running processes.
Comment 1 dfilter service freebsd_committer freebsd_triage 2013-04-16 20:19:29 UTC
Author: trociny
Date: Tue Apr 16 19:19:14 2013
New Revision: 249558
URL: http://svnweb.freebsd.org/changeset/base/249558

Log:
  Add a new set of notes to a process core dump to store procstat data.
  
  The notes format is a header of sizeof(int), which stores the size of
  the corresponding data structure to provide some versioning, and data
  in the format as it is returned by a related sysctl call.
  
  The userland tools (procstat(1)) will be taught to extract this data,
  providing additional info for postmortem analysis.
  
  PR:		kern/173723
  Suggested by:	jhb
  Discussed with:	jhb, kib
  Reviewed by:	jhb (initial version), kib
  MFC after:	1 month

Modified:
  head/sys/kern/imgact_elf.c
  head/sys/sys/elf_common.h

Modified: head/sys/kern/imgact_elf.c
==============================================================================
--- head/sys/kern/imgact_elf.c	Tue Apr 16 17:50:20 2013	(r249557)
+++ head/sys/kern/imgact_elf.c	Tue Apr 16 19:19:14 2013	(r249558)
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/vnode.h>
 #include <sys/syslog.h>
 #include <sys/eventhandler.h>
+#include <sys/user.h>
 
 #include <net/zlib.h>
 
@@ -1062,12 +1063,22 @@ static void __elfN(puthdr)(struct thread
 static void __elfN(putnote)(struct note_info *, struct sbuf *);
 static size_t register_note(struct note_info_list *, int, outfunc_t, void *);
 static int sbuf_drain_core_output(void *, const char *, int);
+static int sbuf_drain_count(void *arg, const char *data, int len);
 
 static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *);
 static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *);
 static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *);
 static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *);
 static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *);
+static void note_procstat_files(void *, struct sbuf *, size_t *);
+static void note_procstat_groups(void *, struct sbuf *, size_t *);
+static void note_procstat_osrel(void *, struct sbuf *, size_t *);
+static void note_procstat_rlimit(void *, struct sbuf *, size_t *);
+static void note_procstat_umask(void *, struct sbuf *, size_t *);
+static void note_procstat_vmmap(void *, struct sbuf *, size_t *);
 
 #ifdef COMPRESS_USER_CORES
 extern int compress_user_cores;
@@ -1113,9 +1124,21 @@ static int
 sbuf_drain_core_output(void *arg, const char *data, int len)
 {
 	struct sbuf_drain_core_params *p;
-	int error;
+	int error, locked;
 
 	p = (struct sbuf_drain_core_params *)arg;
+
+	/*
+	 * Some kern_proc out routines that print to this sbuf may
+	 * call us with the process lock held. Draining with the
+	 * non-sleepable lock held is unsafe. The lock is needed for
+	 * those routines when dumping a live process. In our case we
+	 * can safely release the lock before draining and acquire
+	 * again after.
+	 */
+	locked = PROC_LOCKED(p->td->td_proc);
+	if (locked)
+		PROC_UNLOCK(p->td->td_proc);
 #ifdef COMPRESS_USER_CORES
 	if (p->gzfile != Z_NULL)
 		error = compress_core(p->gzfile, NULL, __DECONST(char *, data),
@@ -1126,12 +1149,27 @@ sbuf_drain_core_output(void *arg, const 
 		    __DECONST(void *, data), len, p->offset, UIO_SYSSPACE,
 		    IO_UNIT | IO_DIRECT, p->active_cred, p->file_cred, NULL,
 		    p->td);
+	if (locked)
+		PROC_LOCK(p->td->td_proc);
 	if (error != 0)
 		return (-error);
 	p->offset += len;
 	return (len);
 }
 
+/*
+ * Drain into a counter.
+ */
+static int
+sbuf_drain_count(void *arg, const char *data __unused, int len)
+{
+	size_t *sizep;
+
+	sizep = (size_t *)arg;
+	*sizep += len;
+	return (len);
+}
+
 int
 __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 {
@@ -1436,6 +1474,25 @@ __elfN(prepare_notes)(struct thread *td,
 			thr = TAILQ_NEXT(thr, td_plist);
 	}
 
+	size += register_note(list, NT_PROCSTAT_PROC,
+	    __elfN(note_procstat_proc), p);
+	size += register_note(list, NT_PROCSTAT_FILES,
+	    note_procstat_files, p);
+	size += register_note(list, NT_PROCSTAT_VMMAP,
+	    note_procstat_vmmap, p);
+	size += register_note(list, NT_PROCSTAT_GROUPS,
+	    note_procstat_groups, p);
+	size += register_note(list, NT_PROCSTAT_UMASK,
+	    note_procstat_umask, p);
+	size += register_note(list, NT_PROCSTAT_RLIMIT,
+	    note_procstat_rlimit, p);
+	size += register_note(list, NT_PROCSTAT_OSREL,
+	    note_procstat_osrel, p);
+	size += register_note(list, NT_PROCSTAT_PSSTRINGS,
+	    __elfN(note_procstat_psstrings), p);
+	size += register_note(list, NT_PROCSTAT_AUXV,
+	    __elfN(note_procstat_auxv), p);
+
 	*sizep = size;
 }
 
@@ -1562,6 +1619,9 @@ typedef struct fpreg32 elf_prfpregset_t;
 typedef struct fpreg32 elf_fpregset_t;
 typedef struct reg32 elf_gregset_t;
 typedef struct thrmisc32 elf_thrmisc_t;
+#define ELF_KERN_PROC_MASK	KERN_PROC_MASK32
+typedef struct kinfo_proc32 elf_kinfo_proc_t;
+typedef uint32_t elf_ps_strings_t;
 #else
 typedef prstatus_t elf_prstatus_t;
 typedef prpsinfo_t elf_prpsinfo_t;
@@ -1569,6 +1629,9 @@ typedef prfpregset_t elf_prfpregset_t;
 typedef prfpregset_t elf_fpregset_t;
 typedef gregset_t elf_gregset_t;
 typedef thrmisc_t elf_thrmisc_t;
+#define ELF_KERN_PROC_MASK	0
+typedef struct kinfo_proc elf_kinfo_proc_t;
+typedef vm_offset_t elf_ps_strings_t;
 #endif
 
 static void
@@ -1686,6 +1749,221 @@ __elfN(note_threadmd)(void *arg, struct 
 	*sizep = size;
 }
 
+#ifdef KINFO_PROC_SIZE
+CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE);
+#endif
+
+static void
+__elfN(note_procstat_proc)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + p->p_numthreads *
+	    sizeof(elf_kinfo_proc_t);
+
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(elf_kinfo_proc_t);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_out(p, sb, ELF_KERN_PROC_MASK);
+	}
+	*sizep = size;
+}
+
+#ifdef KINFO_FILE_SIZE
+CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE);
+#endif
+
+static void
+note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_drain_count, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_filedesc_out(p, sb, -1);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		structsize = sizeof(struct kinfo_file);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_filedesc_out(p, sb, -1);
+	}
+}
+
+#ifdef KINFO_VMENTRY_SIZE
+CTASSERT(sizeof(struct kinfo_vmentry) == KINFO_VMENTRY_SIZE);
+#endif
+
+static void
+note_procstat_vmmap(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_drain_count, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_vmmap_out(p, sb);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		structsize = sizeof(struct kinfo_vmentry);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_vmmap_out(p, sb);
+	}
+}
+
+static void
+note_procstat_groups(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + p->p_ucred->cr_ngroups * sizeof(gid_t);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(gid_t);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, p->p_ucred->cr_groups, p->p_ucred->cr_ngroups *
+		    sizeof(gid_t));
+	}
+	*sizep = size;
+}
+
+static void
+note_procstat_umask(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(p->p_fd->fd_cmask);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(p->p_fd->fd_cmask);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, &p->p_fd->fd_cmask, sizeof(p->p_fd->fd_cmask));
+	}
+	*sizep = size;
+}
+
+static void
+note_procstat_rlimit(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	struct rlimit rlim[RLIM_NLIMITS];
+	size_t size;
+	int structsize, i;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(rlim);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(rlim);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		for (i = 0; i < RLIM_NLIMITS; i++)
+			lim_rlimit(p, i, &rlim[i]);
+		PROC_UNLOCK(p);
+		sbuf_bcat(sb, rlim, sizeof(rlim));
+	}
+	*sizep = size;
+}
+
+static void
+note_procstat_osrel(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(p->p_osrel);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(p->p_osrel);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, &p->p_osrel, sizeof(p->p_osrel));
+	}
+	*sizep = size;
+}
+
+static void
+__elfN(note_procstat_psstrings)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	elf_ps_strings_t ps_strings;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(ps_strings);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(ps_strings);
+#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
+		ps_strings = PTROUT(p->p_sysent->sv_psstrings);
+#else
+		ps_strings = p->p_sysent->sv_psstrings;
+#endif
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, &ps_strings, sizeof(ps_strings));
+	}
+	*sizep = size;
+}
+
+static void
+__elfN(note_procstat_auxv)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_drain_count, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PHOLD(p);
+		proc_getauxv(curthread, p, sb);
+		PRELE(p);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		structsize = sizeof(Elf_Auxinfo);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PHOLD(p);
+		proc_getauxv(curthread, p, sb);
+		PRELE(p);
+	}
+}
+
 static boolean_t
 __elfN(parse_notes)(struct image_params *imgp, Elf_Brandnote *checknote,
     int32_t *osrel, const Elf_Phdr *pnote)

Modified: head/sys/sys/elf_common.h
==============================================================================
--- head/sys/sys/elf_common.h	Tue Apr 16 17:50:20 2013	(r249557)
+++ head/sys/sys/elf_common.h	Tue Apr 16 19:19:14 2013	(r249558)
@@ -487,6 +487,15 @@ typedef struct {
 #define	NT_FPREGSET	2	/* Floating point registers. */
 #define	NT_PRPSINFO	3	/* Process state info. */
 #define	NT_THRMISC	7	/* Thread miscellaneous info. */
+#define	NT_PROCSTAT_PROC	8	/* Procstat proc data. */
+#define	NT_PROCSTAT_FILES	9	/* Procstat files data. */
+#define	NT_PROCSTAT_VMMAP	10	/* Procstat vmmap data. */
+#define	NT_PROCSTAT_GROUPS	11	/* Procstat groups data. */
+#define	NT_PROCSTAT_UMASK	12	/* Procstat umask data. */
+#define	NT_PROCSTAT_RLIMIT	13	/* Procstat rlimit data. */
+#define	NT_PROCSTAT_OSREL	14	/* Procstat osreldate data. */
+#define	NT_PROCSTAT_PSSTRINGS	15	/* Procstat ps_strings data. */
+#define	NT_PROCSTAT_AUXV	16	/* Procstat auxv data. */
 
 /* Symbol Binding - ELFNN_ST_BIND - st_info */
 #define	STB_LOCAL	0	/* Local symbol */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 2 Mikolaj Golub freebsd_committer freebsd_triage 2013-04-16 20:39:52 UTC
Responsible Changed
From-To: freebsd-bugs->trociny

Working on it.
Comment 3 dfilter service freebsd_committer freebsd_triage 2013-04-20 08:47:42 UTC
Author: trociny
Date: Sat Apr 20 07:47:26 2013
New Revision: 249666
URL: http://svnweb.freebsd.org/changeset/base/249666

Log:
  Make libprocstat(3) extract procstat notes from a process core file.
  
  PR:		kern/173723
  Suggested by:	jhb
  Glanced by:	kib
  MFC after:	1 month

Added:
  head/lib/libprocstat/core.c   (contents, props changed)
  head/lib/libprocstat/core.h   (contents, props changed)
Modified:
  head/lib/libprocstat/Makefile
  head/lib/libprocstat/Symbol.map
  head/lib/libprocstat/libprocstat.3
  head/lib/libprocstat/libprocstat.c
  head/lib/libprocstat/libprocstat.h
  head/lib/libprocstat/libprocstat_internal.h

Modified: head/lib/libprocstat/Makefile
==============================================================================
--- head/lib/libprocstat/Makefile	Sat Apr 20 01:12:23 2013	(r249665)
+++ head/lib/libprocstat/Makefile	Sat Apr 20 07:47:26 2013	(r249666)
@@ -6,6 +6,7 @@ LIB=	procstat
 
 SRCS=	cd9660.c	\
 	common_kvm.c	\
+	core.c		\
 	libprocstat.c	\
         msdosfs.c	\
 	udf.c
@@ -17,8 +18,8 @@ INCS=		libprocstat.h
 CFLAGS+=	-I. -I${.CURDIR} -D_KVM_VNODE
 SHLIB_MAJOR=	1
 
-DPADD=		${LIBKVM} ${LIBUTIL}
-LDADD=		-lkvm -lutil
+DPADD=		${LIBELF} ${LIBKVM} ${LIBUTIL}
+LDADD=		-lelf -lkvm -lutil
 
 MAN=		libprocstat.3
 

Modified: head/lib/libprocstat/Symbol.map
==============================================================================
--- head/lib/libprocstat/Symbol.map	Sat Apr 20 01:12:23 2013	(r249665)
+++ head/lib/libprocstat/Symbol.map	Sat Apr 20 07:47:26 2013	(r249666)
@@ -17,4 +17,5 @@ FBSD_1.2 {
 
 FBSD_1.3 {
 	procstat_get_shm_info;
+	procstat_open_core;
 };

Added: head/lib/libprocstat/core.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libprocstat/core.c	Sat Apr 20 07:47:26 2013	(r249666)
@@ -0,0 +1,262 @@
+/*-
+ * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/elf.h>
+#include <sys/user.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "core.h"
+
+#define PROCSTAT_CORE_MAGIC	0x012DADB8
+struct procstat_core
+{
+	int		pc_magic;
+	int		pc_fd;
+	Elf		*pc_elf;
+	GElf_Ehdr	pc_ehdr;
+	GElf_Phdr	pc_phdr;
+};
+
+static bool	core_offset(struct procstat_core *core, off_t offset);
+static bool	core_read(struct procstat_core *core, void *buf, size_t len);
+
+struct procstat_core *
+procstat_core_open(const char *filename)
+{
+	struct procstat_core *core;
+	Elf *e;
+	GElf_Ehdr ehdr;
+	GElf_Phdr phdr;
+	size_t nph;
+	int fd, i;
+
+	if (elf_version(EV_CURRENT) == EV_NONE) {
+		warnx("ELF library too old");
+		return (NULL);
+	}
+	fd = open(filename, O_RDONLY, 0);
+	if (fd == -1) {
+		warn("open(%s)", filename);
+		return (NULL);
+	}
+	e = elf_begin(fd, ELF_C_READ, NULL);
+	if (e == NULL) {
+		warnx("elf_begin: %s", elf_errmsg(-1));
+		goto fail;
+	}
+	if (elf_kind(e) != ELF_K_ELF) {
+		warnx("%s is not an ELF object", filename);
+		goto fail;
+	}
+	if (gelf_getehdr(e, &ehdr) == NULL) {
+		warnx("gelf_getehdr: %s", elf_errmsg(-1));
+		goto fail;
+	}
+	if (ehdr.e_type != ET_CORE) {
+		warnx("%s is not a CORE file", filename);
+		goto fail;
+	}
+	if (elf_getphnum(e, &nph) == 0) {
+		warnx("program headers not found");
+		goto fail;
+	}
+	for (i = 0; i < ehdr.e_phnum; i++) {
+		if (gelf_getphdr(e, i, &phdr) != &phdr) {
+			warnx("gelf_getphdr: %s", elf_errmsg(-1));
+			goto fail;
+		}
+		if (phdr.p_type == PT_NOTE)
+			break;
+	}
+	if (i == ehdr.e_phnum) {
+		warnx("NOTE program header not found");
+		goto fail;
+	}
+	core = malloc(sizeof(struct procstat_core));
+	if (core == NULL) {
+		warn("malloc(%zu)", sizeof(struct procstat_core));
+		goto fail;
+	}
+	core->pc_magic = PROCSTAT_CORE_MAGIC;
+	core->pc_fd = fd;
+	core->pc_elf = e;
+	core->pc_ehdr = ehdr;
+	core->pc_phdr = phdr;
+
+	return (core);
+fail:
+	if (e != NULL)
+		elf_end(e);
+	close(fd);
+
+	return (NULL);
+}
+
+void
+procstat_core_close(struct procstat_core *core)
+{
+
+	assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
+
+	elf_end(core->pc_elf);
+	close(core->pc_fd);
+	free(core);
+}
+
+void *
+procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf,
+    size_t *lenp)
+{
+	Elf_Note nhdr;
+	off_t offset, eoffset;
+	void *freebuf;
+	size_t len;
+	u_int32_t n_type;
+	int cstructsize, structsize;
+	char nbuf[8];
+
+	assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
+
+	switch(type) {
+	case PSC_TYPE_PROC:
+		n_type = NT_PROCSTAT_PROC;
+		structsize = sizeof(struct kinfo_proc);
+		break;
+	case PSC_TYPE_FILES:
+		n_type = NT_PROCSTAT_FILES;
+		structsize = sizeof(struct kinfo_file);
+		break;
+	case PSC_TYPE_VMMAP:
+		n_type = NT_PROCSTAT_VMMAP;
+		structsize = sizeof(struct kinfo_vmentry);
+		break;
+	default:
+		warnx("unknown core stat type: %d", type);
+		return (NULL);
+	}
+
+	offset = core->pc_phdr.p_offset;
+	eoffset = offset + core->pc_phdr.p_filesz;
+
+	while (offset < eoffset) {
+		if (!core_offset(core, offset))
+			return (NULL);
+		if (!core_read(core, &nhdr, sizeof(nhdr)))
+			return (NULL);
+
+		offset += sizeof(nhdr) +
+		    roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) +
+		    roundup2(nhdr.n_descsz, sizeof(Elf32_Size));
+
+		if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0)
+			break;
+		if (nhdr.n_type != n_type)
+			continue;
+		if (nhdr.n_namesz != 8)
+			continue;
+		if (!core_read(core, nbuf, sizeof(nbuf)))
+			return (NULL);
+		if (strcmp(nbuf, "FreeBSD") != 0)
+			continue;
+		if (nhdr.n_descsz < sizeof(cstructsize)) {
+			warnx("corrupted core file");
+			return (NULL);
+		}
+		if (!core_read(core, &cstructsize, sizeof(cstructsize)))
+			return (NULL);
+		if (cstructsize != structsize) {
+			warnx("version mismatch");
+			return (NULL);
+		}
+		len = nhdr.n_descsz - sizeof(cstructsize);
+		if (len == 0)
+			return (NULL);
+		if (buf != NULL) {
+			len = MIN(len, *lenp);
+			freebuf = NULL;
+		} else {
+			freebuf = buf = malloc(len);
+			if (buf == NULL) {
+				warn("malloc(%zu)", len);
+				return (NULL);
+			}
+		}
+		if (!core_read(core, buf, len)) {
+			free(freebuf);
+			return (NULL);
+		}
+		*lenp = len;
+		return (buf);
+        }
+
+	return (NULL);
+}
+
+static bool
+core_offset(struct procstat_core *core, off_t offset)
+{
+
+	assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
+
+	if (lseek(core->pc_fd, offset, SEEK_SET) == -1) {
+		warn("core: lseek(%jd)", (intmax_t)offset);
+		return (false);
+	}
+	return (true);
+}
+
+static bool
+core_read(struct procstat_core *core, void *buf, size_t len)
+{
+	ssize_t n;
+
+	assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
+
+	n = read(core->pc_fd, buf, len);
+	if (n == -1) {
+		warn("core: read");
+		return (false);
+	}
+	if (n < (ssize_t)len) {
+		warnx("core: short read");
+		return (false);
+	}
+	return (true);
+}

Added: head/lib/libprocstat/core.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libprocstat/core.h	Sat Apr 20 07:47:26 2013	(r249666)
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CORE_H
+#define _CORE_H
+
+enum psc_type {
+	PSC_TYPE_PROC,
+	PSC_TYPE_FILES,
+	PSC_TYPE_VMMAP,
+};
+
+struct procstat_core;
+
+void procstat_core_close(struct procstat_core *core);
+void *procstat_core_get(struct procstat_core *core, enum psc_type type,
+    void * buf, size_t *lenp);
+struct procstat_core *procstat_core_open(const char *filename);
+
+#endif 	/* !_CORE_H_ */

Modified: head/lib/libprocstat/libprocstat.3
==============================================================================
--- head/lib/libprocstat/libprocstat.3	Sat Apr 20 01:12:23 2013	(r249665)
+++ head/lib/libprocstat/libprocstat.3	Sat Apr 20 07:47:26 2013	(r249666)
@@ -28,6 +28,7 @@
 .Dt LIBPROCSTAT 3
 .Os
 .Sh NAME
+.Nm procstat_open_core ,
 .Nm procstat_open_kvm ,
 .Nm procstat_open_sysctl ,
 .Nm procstat_close ,
@@ -105,6 +106,8 @@
 .Fa "unsigned int *count"
 .Fc
 .Ft "struct procstat *"
+.Fn procstat_open_core "const char *filename"
+.Ft "struct procstat *"
 .Fn procstat_open_kvm "const char *nlistf" "const char *memf"
 .Ft "struct procstat *"
 .Fn procstat_open_sysctl void
@@ -116,7 +119,11 @@ retrieval from the running kernel via th
 .Xr sysctl 3
 library backend, and for post-mortem analysis via the
 .Xr kvm 3
-library backend.
+library backend, or from the process
+.Xr core 5
+file, searching for statistics in special
+.Xr elf 3
+note sections.
 .Pp
 The
 .Fn procstat_open_kvm
@@ -129,6 +136,16 @@ or
 library routines, respectively, to access kernel state information
 used to retrieve processes and files states.
 The
+.Fn procstat_open_core
+uses
+.Xr elf 3
+routines to access statistics stored as a set of notes in a process
+.Xr core 5
+file, written by the kernel at the moment of the process abnormal termination.
+The
+.Fa filename
+argument is the process core file name.
+The
 .Fa nlistf
 argument is the executable image of the kernel being examined.
 If this argument is
@@ -145,7 +162,7 @@ is assumed.
 See
 .Xr kvm_open 3
 for more details.
-Both functions dynamically allocate and return a
+The functions dynamically allocate and return a
 .Vt procstat
 structure pointer used in the rest of the
 .Nm libprocstat
@@ -250,10 +267,12 @@ argument indicates an actual error messa
 .Xr pipe 2 ,
 .Xr shm_open 2 ,
 .Xr socket 2 ,
+.Xr elf 3 ,
 .Xr kvm 3 ,
 .Xr queue 3 ,
 .Xr sysctl 3 ,
 .Xr pts 4 ,
+.Xr core 5 ,
 .Xr vnode 9
 .Sh HISTORY
 The

Modified: head/lib/libprocstat/libprocstat.c
==============================================================================
--- head/lib/libprocstat/libprocstat.c	Sat Apr 20 01:12:23 2013	(r249665)
+++ head/lib/libprocstat/libprocstat.c	Sat Apr 20 07:47:26 2013	(r249666)
@@ -96,11 +96,13 @@ __FBSDID("$FreeBSD$");
 #include <libprocstat.h>
 #include "libprocstat_internal.h"
 #include "common_kvm.h"
+#include "core.h"
 
 int     statfs(const char *, struct statfs *);	/* XXX */
 
 #define	PROCSTAT_KVM	1
 #define	PROCSTAT_SYSCTL	2
+#define	PROCSTAT_CORE	3
 
 static char	*getmnton(kvm_t *kd, struct mount *m);
 static struct filestat_list	*procstat_getfiles_kvm(
@@ -137,6 +139,8 @@ procstat_close(struct procstat *procstat
 	assert(procstat);
 	if (procstat->type == PROCSTAT_KVM)
 		kvm_close(procstat->kd);
+	else if (procstat->type == PROCSTAT_CORE)
+		procstat_core_close(procstat->core);
 	free(procstat);
 }
 
@@ -177,6 +181,27 @@ procstat_open_kvm(const char *nlistf, co
 	return (procstat);
 }
 
+struct procstat *
+procstat_open_core(const char *filename)
+{
+	struct procstat *procstat;
+	struct procstat_core *core;
+
+	procstat = calloc(1, sizeof(*procstat));
+	if (procstat == NULL) {
+		warn("malloc()");
+		return (NULL);
+	}
+	core = procstat_core_open(filename);
+	if (core == NULL) {
+		free(procstat);
+		return (NULL);
+	}
+	procstat->type = PROCSTAT_CORE;
+	procstat->core = core;
+	return (procstat);
+}
+
 struct kinfo_proc *
 procstat_getprocs(struct procstat *procstat, int what, int arg,
     unsigned int *count)
@@ -231,6 +256,15 @@ procstat_getprocs(struct procstat *procs
 		}
 		/* Perform simple consistency checks. */
 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
+			warnx("kinfo_proc structure size mismatch (len = %zu)", len);
+			goto fail;
+		}
+		*count = len / sizeof(*p);
+		return (p);
+	} else if (procstat->type == PROCSTAT_CORE) {
+		p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
+		    &len);
+		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
 			warnx("kinfo_proc structure size mismatch");
 			goto fail;
 		}
@@ -258,13 +292,17 @@ procstat_freeprocs(struct procstat *proc
 struct filestat_list *
 procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
 {
-	
-	if (procstat->type == PROCSTAT_SYSCTL)
-		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
-	else if (procstat->type == PROCSTAT_KVM)
+
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
 		return (procstat_getfiles_kvm(procstat, kp, mmapped));
-	else
+	case PROCSTAT_SYSCTL:
+	case PROCSTAT_CORE:
+		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
+	default:
+		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
+	}
 }
 
 void
@@ -646,8 +684,62 @@ kinfo_uflags2fst(int fd)
 	return (0);
 }
 
+static struct kinfo_file *
+kinfo_getfile_core(struct procstat_core *core, int *cntp)
+{
+	int cnt;
+	size_t len;
+	char *buf, *bp, *eb;
+	struct kinfo_file *kif, *kp, *kf;
+
+	buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len);
+	if (buf == NULL)
+		return (NULL);
+	/*
+	 * XXXMG: The code below is just copy&past from libutil.
+	 * The code duplication can be avoided if libutil
+	 * is extended to provide something like:
+	 *   struct kinfo_file *kinfo_getfile_from_buf(const char *buf,
+	 *       size_t len, int *cntp);
+	 */
+
+	/* Pass 1: count items */
+	cnt = 0;
+	bp = buf;
+	eb = buf + len;
+	while (bp < eb) {
+		kf = (struct kinfo_file *)(uintptr_t)bp;
+		bp += kf->kf_structsize;
+		cnt++;
+	}
+
+	kif = calloc(cnt, sizeof(*kif));
+	if (kif == NULL) {
+		free(buf);
+		return (NULL);
+	}
+	bp = buf;
+	eb = buf + len;
+	kp = kif;
+	/* Pass 2: unpack */
+	while (bp < eb) {
+		kf = (struct kinfo_file *)(uintptr_t)bp;
+		/* Copy/expand into pre-zeroed buffer */
+		memcpy(kp, kf, kf->kf_structsize);
+		/* Advance to next packed record */
+		bp += kf->kf_structsize;
+		/* Set field size to fixed length, advance */
+		kp->kf_structsize = sizeof(*kp);
+		kp++;
+	}
+	free(buf);
+	*cntp = cnt;
+	return (kif);	/* Caller must free() return value */
+}
+
 static struct filestat_list *
-procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
+procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
+    int mmapped)
 {
 	struct kinfo_file *kif, *files;
 	struct kinfo_vmentry *kve, *vmentries;
@@ -663,8 +755,16 @@ procstat_getfiles_sysctl(struct procstat
 	assert(kp);
 	if (kp->ki_fd == NULL)
 		return (NULL);
-
-	files = kinfo_getfile(kp->ki_pid, &cnt);
+	switch(procstat->type) {
+	case PROCSTAT_SYSCTL:
+		files = kinfo_getfile(kp->ki_pid, &cnt);
+		break;
+	case PROCSTAT_CORE:
+		files = kinfo_getfile_core(procstat->core, &cnt);
+		break;
+	default:
+		assert(!"invalid type");
+	}
 	if (files == NULL && errno != EPERM) {
 		warn("kinfo_getfile()");
 		return (NULL);
@@ -742,7 +842,8 @@ procstat_get_pipe_info(struct procstat *
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -806,7 +907,8 @@ procstat_get_pts_info(struct procstat *p
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -868,7 +970,8 @@ procstat_get_shm_info(struct procstat *p
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+	    procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -948,7 +1051,8 @@ procstat_get_vnode_info(struct procstat 
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -1150,7 +1254,8 @@ procstat_get_socket_info(struct procstat
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -1401,3 +1506,4 @@ getmnton(kvm_t *kd, struct mount *m)
 	mhead = mt;
 	return (mt->mntonname);
 }
+

Modified: head/lib/libprocstat/libprocstat.h
==============================================================================
--- head/lib/libprocstat/libprocstat.h	Sat Apr 20 01:12:23 2013	(r249665)
+++ head/lib/libprocstat/libprocstat.h	Sat Apr 20 07:47:26 2013	(r249666)
@@ -162,6 +162,7 @@ int	procstat_get_socket_info(struct proc
     struct sockstat *sock, char *errbuf);
 int	procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
     struct vnstat *vn, char *errbuf);
+struct procstat	*procstat_open_core(const char *filename);
 struct procstat	*procstat_open_sysctl(void);
 struct procstat	*procstat_open_kvm(const char *nlistf, const char *memf);
 __END_DECLS

Modified: head/lib/libprocstat/libprocstat_internal.h
==============================================================================
--- head/lib/libprocstat/libprocstat_internal.h	Sat Apr 20 01:12:23 2013	(r249665)
+++ head/lib/libprocstat/libprocstat_internal.h	Sat Apr 20 07:47:26 2013	(r249666)
@@ -34,6 +34,7 @@ struct procstat {
 	kvm_t	*kd;
 	void	*vmentries;
 	void	*files;
+	struct procstat_core *core;
 };
 
 #endif	/* !_LIBPROCSTAT_INTERNAL_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 4 dfilter service freebsd_committer freebsd_triage 2013-04-20 09:22:22 UTC
Author: trociny
Date: Sat Apr 20 08:22:09 2013
New Revision: 249686
URL: http://svnweb.freebsd.org/changeset/base/249686

Log:
  Make use of newly added libprocstat(3) ability to extract procstat
  info from a process core file.
  
  So now one can run procstat(1) on a process core e.g. to get a list of
  files opened by a process when it crashed:
  
  root@lisa:/ # procstat -f /root/vi.core
    PID COMM               FD T V FLAGS     REF  OFFSET PRO NAME
    658 vi               text v r r--------   -       - -   /usr/bin/vi
    658 vi               ctty v c rw-------   -       - -   /dev/pts/0
    658 vi                cwd v d r--------   -       - -   /root
    658 vi               root v d r--------   -       - -   /
    658 vi                  0 v c rw-------  11    3208 -   /dev/pts/0
    658 vi                  1 v c rw-------  11    3208 -   /dev/pts/0
    658 vi                  2 v c rw-------  11    3208 -   /dev/pts/0
    658 vi                  3 v r r----n-l-   1       0 -   /tmp/vi.0AYKz3Lps7
    658 vi                  4 v r rw-------   1       0 -   /var/tmp/vi.recover/vi.GaGYsz
    658 vi                  5 v r rw-------   1       0 -   -
  
  PR:		kern/173723
  Suggested by:	jhb
  MFC after:	1 month

Modified:
  head/usr.bin/procstat/procstat.1
  head/usr.bin/procstat/procstat.c

Modified: head/usr.bin/procstat/procstat.1
==============================================================================
--- head/usr.bin/procstat/procstat.1	Sat Apr 20 08:19:06 2013	(r249685)
+++ head/usr.bin/procstat/procstat.1	Sat Apr 20 08:22:09 2013	(r249686)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 11, 2012
+.Dd April 20, 2013
 .Dt PROCSTAT 1
 .Os
 .Sh NAME
@@ -38,7 +38,7 @@
 .Op Fl C
 .Op Fl w Ar interval
 .Op Fl b | c | e | f | i | j | k | l | s | t | v | x
-.Op Fl a | Ar pid ...
+.Op Fl a | Ar pid | Ar core ...
 .Sh DESCRIPTION
 The
 .Nm
@@ -47,6 +47,8 @@ utility displays detailed information ab
 arguments, or if the
 .Fl a
 flag is used, all processes.
+It can also display information extracted from a process core file, if
+the core file is specified as the argument.
 .Pp
 By default, basic process statistics are printed; one of the following
 options may be specified in order to select more detailed process information

Modified: head/usr.bin/procstat/procstat.c
==============================================================================
--- head/usr.bin/procstat/procstat.c	Sat Apr 20 08:19:06 2013	(r249685)
+++ head/usr.bin/procstat/procstat.c	Sat Apr 20 08:22:09 2013	(r249686)
@@ -50,7 +50,7 @@ usage(void)
 	fprintf(stderr, "usage: procstat [-h] [-C] [-M core] [-N system] "
 	    "[-w interval] \n");
 	fprintf(stderr, "                [-b | -c | -e | -f | -i | -j | -k | "
-	    "-l | -s | -t | -v | -x] [-a | pid ...]\n");
+	    "-l | -s | -t | -v | -x] [-a | pid | core ...]\n");
 	exit(EX_USAGE);
 }
 
@@ -116,7 +116,7 @@ main(int argc, char *argv[])
 	int ch, interval, tmp;
 	int i;
 	struct kinfo_proc *p;
-	struct procstat *prstat;
+	struct procstat *prstat, *cprstat;
 	long l;
 	pid_t pid;
 	char *dummy;
@@ -255,19 +255,32 @@ main(int argc, char *argv[])
 		}
 		for (i = 0; i < argc; i++) {
 			l = strtol(argv[i], &dummy, 10);
-			if (*dummy != '\0')
-				usage();
-			if (l < 0)
-				usage();
-			pid = l;
-
-			p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt);
-			if (p == NULL)
-				errx(1, "procstat_getprocs()");
-			if (cnt != 0)
-				procstat(prstat, p);
-			procstat_freeprocs(prstat, p);
-
+			if (*dummy == '\0') {
+				if (l < 0)
+					usage();
+				pid = l;
+
+				p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt);
+				if (p == NULL)
+					errx(1, "procstat_getprocs()");
+				if (cnt != 0)
+					procstat(prstat, p);
+				procstat_freeprocs(prstat, p);
+			} else {
+				cprstat = procstat_open_core(argv[i]);
+				if (cprstat == NULL) {
+					warnx("procstat_open()");
+					continue;
+				}
+				p = procstat_getprocs(cprstat, KERN_PROC_PID,
+				    -1, &cnt);
+				if (p == NULL)
+					errx(1, "procstat_getprocs()");
+				if (cnt != 0)
+					procstat(cprstat, p);
+				procstat_freeprocs(cprstat, p);
+				procstat_close(cprstat);
+			}
 			/* Suppress header after first process. */
 			hflag = 1;
 		}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 5 dfilter service freebsd_committer freebsd_triage 2013-05-17 21:13:17 UTC
Author: trociny
Date: Fri May 17 20:12:56 2013
New Revision: 250752
URL: http://svnweb.freebsd.org/changeset/base/250752

Log:
  MFC r249558, r250145:
  
  r249558:
  
  Add a new set of notes to a process core dump to store procstat data.
  
  The notes format is a header of sizeof(int), which stores the size of
  the corresponding data structure to provide some versioning, and data
  in the format as it is returned by a related sysctl call.
  
  The userland tools (procstat(1)) will be taught to extract this data,
  providing additional info for postmortem analysis.
  
  PR:		kern/173723
  Suggested by:	jhb
  Discussed with:	jhb, kib
  Reviewed by:	jhb (initial version), kib
  
  r250145:
  
  Introduce a constant, ELF_NOTE_ROUNDSIZE, which evidently declares our
  intention to use 4-byte padding for elf notes.

Modified:
  stable/9/sys/kern/imgact_elf.c
  stable/9/sys/sys/elf_common.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/sys/   (props changed)

Modified: stable/9/sys/kern/imgact_elf.c
==============================================================================
--- stable/9/sys/kern/imgact_elf.c	Fri May 17 20:03:55 2013	(r250751)
+++ stable/9/sys/kern/imgact_elf.c	Fri May 17 20:12:56 2013	(r250752)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/capability.h>
 #include <sys/exec.h>
 #include <sys/fcntl.h>
+#include <sys/filedesc.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 #include <sys/kernel.h>
@@ -66,6 +67,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/vnode.h>
 #include <sys/syslog.h>
 #include <sys/eventhandler.h>
+#include <sys/user.h>
 
 #include <net/zlib.h>
 
@@ -80,6 +82,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/elf.h>
 #include <machine/md_var.h>
 
+#define ELF_NOTE_ROUNDSIZE	4
 #define OLD_EI_BRAND	8
 
 static int __elfN(check_header)(const Elf_Ehdr *hdr);
@@ -160,7 +163,7 @@ __elfN(freebsd_trans_osrel)(const Elf_No
 	uintptr_t p;
 
 	p = (uintptr_t)(note + 1);
-	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
+	p += roundup2(note->n_namesz, ELF_NOTE_ROUNDSIZE);
 	*osrel = *(const int32_t *)(p);
 
 	return (TRUE);
@@ -185,7 +188,7 @@ kfreebsd_trans_osrel(const Elf_Note *not
 	uintptr_t p;
 
 	p = (uintptr_t)(note + 1);
-	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
+	p += roundup2(note->n_namesz, ELF_NOTE_ROUNDSIZE);
 
 	desc = (const Elf32_Word *)p;
 	if (desc[0] != GNU_KFREEBSD_ABI_DESC)
@@ -1064,12 +1067,22 @@ static void __elfN(puthdr)(struct thread
 static void __elfN(putnote)(struct note_info *, struct sbuf *);
 static size_t register_note(struct note_info_list *, int, outfunc_t, void *);
 static int sbuf_drain_core_output(void *, const char *, int);
+static int sbuf_drain_count(void *arg, const char *data, int len);
 
 static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *);
 static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *);
 static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *);
 static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *);
 static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *);
+static void note_procstat_files(void *, struct sbuf *, size_t *);
+static void note_procstat_groups(void *, struct sbuf *, size_t *);
+static void note_procstat_osrel(void *, struct sbuf *, size_t *);
+static void note_procstat_rlimit(void *, struct sbuf *, size_t *);
+static void note_procstat_umask(void *, struct sbuf *, size_t *);
+static void note_procstat_vmmap(void *, struct sbuf *, size_t *);
 
 #ifdef COMPRESS_USER_CORES
 extern int compress_user_cores;
@@ -1115,9 +1128,21 @@ static int
 sbuf_drain_core_output(void *arg, const char *data, int len)
 {
 	struct sbuf_drain_core_params *p;
-	int error;
+	int error, locked;
 
 	p = (struct sbuf_drain_core_params *)arg;
+
+	/*
+	 * Some kern_proc out routines that print to this sbuf may
+	 * call us with the process lock held. Draining with the
+	 * non-sleepable lock held is unsafe. The lock is needed for
+	 * those routines when dumping a live process. In our case we
+	 * can safely release the lock before draining and acquire
+	 * again after.
+	 */
+	locked = PROC_LOCKED(p->td->td_proc);
+	if (locked)
+		PROC_UNLOCK(p->td->td_proc);
 #ifdef COMPRESS_USER_CORES
 	if (p->gzfile != Z_NULL)
 		error = compress_core(p->gzfile, NULL, __DECONST(char *, data),
@@ -1128,12 +1153,27 @@ sbuf_drain_core_output(void *arg, const 
 		    __DECONST(void *, data), len, p->offset, UIO_SYSSPACE,
 		    IO_UNIT | IO_DIRECT, p->active_cred, p->file_cred, NULL,
 		    p->td);
+	if (locked)
+		PROC_LOCK(p->td->td_proc);
 	if (error != 0)
 		return (-error);
 	p->offset += len;
 	return (len);
 }
 
+/*
+ * Drain into a counter.
+ */
+static int
+sbuf_drain_count(void *arg, const char *data __unused, int len)
+{
+	size_t *sizep;
+
+	sizep = (size_t *)arg;
+	*sizep += len;
+	return (len);
+}
+
 int
 __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 {
@@ -1438,6 +1478,25 @@ __elfN(prepare_notes)(struct thread *td,
 			thr = TAILQ_NEXT(thr, td_plist);
 	}
 
+	size += register_note(list, NT_PROCSTAT_PROC,
+	    __elfN(note_procstat_proc), p);
+	size += register_note(list, NT_PROCSTAT_FILES,
+	    note_procstat_files, p);
+	size += register_note(list, NT_PROCSTAT_VMMAP,
+	    note_procstat_vmmap, p);
+	size += register_note(list, NT_PROCSTAT_GROUPS,
+	    note_procstat_groups, p);
+	size += register_note(list, NT_PROCSTAT_UMASK,
+	    note_procstat_umask, p);
+	size += register_note(list, NT_PROCSTAT_RLIMIT,
+	    note_procstat_rlimit, p);
+	size += register_note(list, NT_PROCSTAT_OSREL,
+	    note_procstat_osrel, p);
+	size += register_note(list, NT_PROCSTAT_PSSTRINGS,
+	    __elfN(note_procstat_psstrings), p);
+	size += register_note(list, NT_PROCSTAT_AUXV,
+	    __elfN(note_procstat_auxv), p);
+
 	*sizep = size;
 }
 
@@ -1491,7 +1550,7 @@ __elfN(puthdr)(struct thread *td, void *
 	phdr->p_filesz = notesz;
 	phdr->p_memsz = 0;
 	phdr->p_flags = PF_R;
-	phdr->p_align = sizeof(Elf32_Size);
+	phdr->p_align = ELF_NOTE_ROUNDSIZE;
 	phdr++;
 
 	/* All the writable segments from the program. */
@@ -1519,8 +1578,8 @@ register_note(struct note_info_list *lis
 		return (size);
 
 	notesize = sizeof(Elf_Note) +		/* note header */
-	    roundup2(8, sizeof(Elf32_Size)) +	/* note name ("FreeBSD") */
-	    roundup2(size, sizeof(Elf32_Size));	/* note description */
+	    roundup2(8, ELF_NOTE_ROUNDSIZE) +	/* note name ("FreeBSD") */
+	    roundup2(size, ELF_NOTE_ROUNDSIZE);	/* note description */
 
 	return (notesize);
 }
@@ -1543,12 +1602,12 @@ __elfN(putnote)(struct note_info *ninfo,
 	sbuf_bcat(sb, &note, sizeof(note));
 	sbuf_start_section(sb, &old_len);
 	sbuf_bcat(sb, "FreeBSD", note.n_namesz);
-	sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
+	sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0);
 	if (note.n_descsz == 0)
 		return;
 	sbuf_start_section(sb, &old_len);
 	ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
-	sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
+	sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0);
 }
 
 /*
@@ -1564,6 +1623,9 @@ typedef struct fpreg32 elf_prfpregset_t;
 typedef struct fpreg32 elf_fpregset_t;
 typedef struct reg32 elf_gregset_t;
 typedef struct thrmisc32 elf_thrmisc_t;
+#define ELF_KERN_PROC_MASK	KERN_PROC_MASK32
+typedef struct kinfo_proc32 elf_kinfo_proc_t;
+typedef uint32_t elf_ps_strings_t;
 #else
 typedef prstatus_t elf_prstatus_t;
 typedef prpsinfo_t elf_prpsinfo_t;
@@ -1571,6 +1633,9 @@ typedef prfpregset_t elf_prfpregset_t;
 typedef prfpregset_t elf_fpregset_t;
 typedef gregset_t elf_gregset_t;
 typedef thrmisc_t elf_thrmisc_t;
+#define ELF_KERN_PROC_MASK	0
+typedef struct kinfo_proc elf_kinfo_proc_t;
+typedef vm_offset_t elf_ps_strings_t;
 #endif
 
 static void
@@ -1688,6 +1753,221 @@ __elfN(note_threadmd)(void *arg, struct 
 	*sizep = size;
 }
 
+#ifdef KINFO_PROC_SIZE
+CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE);
+#endif
+
+static void
+__elfN(note_procstat_proc)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + p->p_numthreads *
+	    sizeof(elf_kinfo_proc_t);
+
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(elf_kinfo_proc_t);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_out(p, sb, ELF_KERN_PROC_MASK);
+	}
+	*sizep = size;
+}
+
+#ifdef KINFO_FILE_SIZE
+CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE);
+#endif
+
+static void
+note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_drain_count, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_filedesc_out(p, sb, -1);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		structsize = sizeof(struct kinfo_file);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_filedesc_out(p, sb, -1);
+	}
+}
+
+#ifdef KINFO_VMENTRY_SIZE
+CTASSERT(sizeof(struct kinfo_vmentry) == KINFO_VMENTRY_SIZE);
+#endif
+
+static void
+note_procstat_vmmap(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_drain_count, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_vmmap_out(p, sb);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		structsize = sizeof(struct kinfo_vmentry);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		kern_proc_vmmap_out(p, sb);
+	}
+}
+
+static void
+note_procstat_groups(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + p->p_ucred->cr_ngroups * sizeof(gid_t);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(gid_t);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, p->p_ucred->cr_groups, p->p_ucred->cr_ngroups *
+		    sizeof(gid_t));
+	}
+	*sizep = size;
+}
+
+static void
+note_procstat_umask(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(p->p_fd->fd_cmask);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(p->p_fd->fd_cmask);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, &p->p_fd->fd_cmask, sizeof(p->p_fd->fd_cmask));
+	}
+	*sizep = size;
+}
+
+static void
+note_procstat_rlimit(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	struct rlimit rlim[RLIM_NLIMITS];
+	size_t size;
+	int structsize, i;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(rlim);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(rlim);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PROC_LOCK(p);
+		for (i = 0; i < RLIM_NLIMITS; i++)
+			lim_rlimit(p, i, &rlim[i]);
+		PROC_UNLOCK(p);
+		sbuf_bcat(sb, rlim, sizeof(rlim));
+	}
+	*sizep = size;
+}
+
+static void
+note_procstat_osrel(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(p->p_osrel);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(p->p_osrel);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, &p->p_osrel, sizeof(p->p_osrel));
+	}
+	*sizep = size;
+}
+
+static void
+__elfN(note_procstat_psstrings)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	elf_ps_strings_t ps_strings;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	size = sizeof(structsize) + sizeof(ps_strings);
+	if (sb != NULL) {
+		KASSERT(*sizep == size, ("invalid size"));
+		structsize = sizeof(ps_strings);
+#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
+		ps_strings = PTROUT(p->p_sysent->sv_psstrings);
+#else
+		ps_strings = p->p_sysent->sv_psstrings;
+#endif
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		sbuf_bcat(sb, &ps_strings, sizeof(ps_strings));
+	}
+	*sizep = size;
+}
+
+static void
+__elfN(note_procstat_auxv)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size;
+	int structsize;
+
+	p = (struct proc *)arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_drain_count, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PHOLD(p);
+		proc_getauxv(curthread, p, sb);
+		PRELE(p);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		structsize = sizeof(Elf_Auxinfo);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		PHOLD(p);
+		proc_getauxv(curthread, p, sb);
+		PRELE(p);
+	}
+}
+
 static boolean_t
 __elfN(parse_notes)(struct image_params *imgp, Elf_Brandnote *checknote,
     int32_t *osrel, const Elf_Phdr *pnote)
@@ -1728,8 +2008,8 @@ __elfN(parse_notes)(struct image_params 
 
 nextnote:
 		note = (const Elf_Note *)((const char *)(note + 1) +
-		    roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
-		    roundup2(note->n_descsz, sizeof(Elf32_Addr)));
+		    roundup2(note->n_namesz, ELF_NOTE_ROUNDSIZE) +
+		    roundup2(note->n_descsz, ELF_NOTE_ROUNDSIZE));
 	}
 
 	return (FALSE);

Modified: stable/9/sys/sys/elf_common.h
==============================================================================
--- stable/9/sys/sys/elf_common.h	Fri May 17 20:03:55 2013	(r250751)
+++ stable/9/sys/sys/elf_common.h	Fri May 17 20:12:56 2013	(r250752)
@@ -485,6 +485,15 @@ typedef struct {
 #define	NT_FPREGSET	2	/* Floating point registers. */
 #define	NT_PRPSINFO	3	/* Process state info. */
 #define	NT_THRMISC	7	/* Thread miscellaneous info. */
+#define	NT_PROCSTAT_PROC	8	/* Procstat proc data. */
+#define	NT_PROCSTAT_FILES	9	/* Procstat files data. */
+#define	NT_PROCSTAT_VMMAP	10	/* Procstat vmmap data. */
+#define	NT_PROCSTAT_GROUPS	11	/* Procstat groups data. */
+#define	NT_PROCSTAT_UMASK	12	/* Procstat umask data. */
+#define	NT_PROCSTAT_RLIMIT	13	/* Procstat rlimit data. */
+#define	NT_PROCSTAT_OSREL	14	/* Procstat osreldate data. */
+#define	NT_PROCSTAT_PSSTRINGS	15	/* Procstat ps_strings data. */
+#define	NT_PROCSTAT_AUXV	16	/* Procstat auxv data. */
 
 /* Symbol Binding - ELFNN_ST_BIND - st_info */
 #define	STB_LOCAL	0	/* Local symbol */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 6 dfilter service freebsd_committer freebsd_triage 2013-05-21 20:04:34 UTC
Author: trociny
Date: Tue May 21 19:04:16 2013
New Revision: 250870
URL: http://svnweb.freebsd.org/changeset/base/250870

Log:
  MFC r249666, r249667, r249670, r249672, r249674, r249676, r249677, r249679,
      r249681, r249684, r249688, r249711, r249731, r250146
  
  r249666, r249682:
  
  Make libprocstat(3) extract procstat notes from a process core file.
  
  PR:		kern/173723
  Suggested by:	jhb
  Glanced by:	kib
  
  r249667:
  
  Add procstat_getvmmap function to get VM layout of a process.
  
  r249670:
  
  Add procstat_getgroups function to retrieve process groups.
  
  r249672:
  
  Add procstat_getumask function to retrieve a process umask.
  
  r249674:
  
  Add procstat_getrlimit function to retrieve a process resource limits info.
  
  r249676:
  
  Add procstat_getpathname function to retrieve a process executable.
  
  r249677:
  
  Add procstat_getosrel function to retrieve a process osrel info.
  
  r249679:
  
  Extend libprocstat with functions to retrieve process command line
  arguments and environment variables.
  
  Suggested by:	stas
  Reviewed by:	jhb and stas (initial version)
  
  r249681:
  
  Add procstat_getauxv function to retrieve a process auxiliary vector.
  
  r249684:
  
  Add procstat_getkstack function to dump kernel stacks of a process.
  
  r249688:
  
  Bump date.
  
  r249711 (joel):
  
  mdoc: end function context properly.
  
  r249731:
  
  Embed revision id in the library.
  
  r250146:
  
  KVM method support for procstat_getgroups, procstat_getumask,
  procstat_getrlimit, and procstat_getosrel.

Added:
  stable/9/lib/libprocstat/core.c
     - copied, changed from r249666, head/lib/libprocstat/core.c
  stable/9/lib/libprocstat/core.h
     - copied, changed from r249666, head/lib/libprocstat/core.h
Modified:
  stable/9/Makefile.inc1   (contents, props changed)
  stable/9/lib/libprocstat/Makefile
  stable/9/lib/libprocstat/Symbol.map
  stable/9/lib/libprocstat/libprocstat.3
  stable/9/lib/libprocstat/libprocstat.c
  stable/9/lib/libprocstat/libprocstat.h
  stable/9/lib/libprocstat/libprocstat_internal.h
Directory Properties:
  stable/9/lib/libprocstat/   (props changed)

Modified: stable/9/Makefile.inc1
==============================================================================
--- stable/9/Makefile.inc1	Tue May 21 18:52:37 2013	(r250869)
+++ stable/9/Makefile.inc1	Tue May 21 19:04:16 2013	(r250870)
@@ -1371,7 +1371,7 @@ _prebuild_libs=	${_kerberos5_lib_libasn1
 		${_kerberos5_lib_libhx509} ${_kerberos5_lib_libkrb5} \
 		${_kerberos5_lib_libroken} \
 		lib/libbz2 lib/libcom_err lib/libcrypt \
-		lib/libexpat \
+		lib/libelf lib/libexpat \
 		${_lib_libgssapi} ${_lib_libipx} \
 		lib/libkiconv lib/libkvm lib/liblzma lib/libmd \
 		lib/ncurses/ncurses lib/ncurses/ncursesw \

Modified: stable/9/lib/libprocstat/Makefile
==============================================================================
--- stable/9/lib/libprocstat/Makefile	Tue May 21 18:52:37 2013	(r250869)
+++ stable/9/lib/libprocstat/Makefile	Tue May 21 19:04:16 2013	(r250870)
@@ -6,6 +6,7 @@ LIB=	procstat
 
 SRCS=	cd9660.c	\
 	common_kvm.c	\
+	core.c		\
 	libprocstat.c	\
         msdosfs.c	\
 	ntfs.c		\
@@ -19,8 +20,8 @@ INCS=		libprocstat.h
 CFLAGS+=	-I. -I${.CURDIR} -D_KVM_VNODE
 SHLIB_MAJOR=	1
 
-DPADD=		${LIBKVM} ${LIBUTIL}
-LDADD=		-lkvm -lutil
+DPADD=		${LIBELF} ${LIBKVM} ${LIBUTIL}
+LDADD=		-lelf -lkvm -lutil
 
 MAN=		libprocstat.3
 

Modified: stable/9/lib/libprocstat/Symbol.map
==============================================================================
--- stable/9/lib/libprocstat/Symbol.map	Tue May 21 18:52:37 2013	(r250869)
+++ stable/9/lib/libprocstat/Symbol.map	Tue May 21 19:04:16 2013	(r250870)
@@ -16,5 +16,22 @@ FBSD_1.2 {
 };
 
 FBSD_1.3 {
+	procstat_freeargv;
+	procstat_freeauxv;
+	procstat_freeenvv;
+	procstat_freegroups;
+	procstat_freekstack;
+	procstat_freevmmap;
 	procstat_get_shm_info;
+	procstat_getargv;
+	procstat_getauxv;
+	procstat_getenvv;
+	procstat_getgroups;
+	procstat_getkstack;
+	procstat_getosrel;
+	procstat_getpathname;
+	procstat_getrlimit;
+	procstat_getumask;
+	procstat_getvmmap;
+	procstat_open_core;
 };

Copied and modified: stable/9/lib/libprocstat/core.c (from r249666, head/lib/libprocstat/core.c)
==============================================================================
--- head/lib/libprocstat/core.c	Sat Apr 20 07:47:26 2013	(r249666, copy source)
+++ stable/9/lib/libprocstat/core.c	Tue May 21 19:04:16 2013	(r250870)
@@ -22,12 +22,14 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
 #include <sys/param.h>
 #include <sys/elf.h>
+#include <sys/exec.h>
 #include <sys/user.h>
 
 #include <assert.h>
@@ -56,6 +58,10 @@ struct procstat_core
 
 static bool	core_offset(struct procstat_core *core, off_t offset);
 static bool	core_read(struct procstat_core *core, void *buf, size_t len);
+static ssize_t	core_read_mem(struct procstat_core *core, void *buf,
+    size_t len, vm_offset_t addr, bool readall);
+static void	*get_args(struct procstat_core *core, vm_offset_t psstrings,
+    enum psc_type type, void *buf, size_t *lenp);
 
 struct procstat_core *
 procstat_core_open(const char *filename)
@@ -146,6 +152,7 @@ procstat_core_get(struct procstat_core *
 {
 	Elf_Note nhdr;
 	off_t offset, eoffset;
+	vm_offset_t psstrings;
 	void *freebuf;
 	size_t len;
 	u_int32_t n_type;
@@ -167,6 +174,32 @@ procstat_core_get(struct procstat_core *
 		n_type = NT_PROCSTAT_VMMAP;
 		structsize = sizeof(struct kinfo_vmentry);
 		break;
+	case PSC_TYPE_GROUPS:
+		n_type = NT_PROCSTAT_GROUPS;
+		structsize = sizeof(gid_t);
+		break;
+	case PSC_TYPE_UMASK:
+		n_type = NT_PROCSTAT_UMASK;
+		structsize = sizeof(u_short);
+		break;
+	case PSC_TYPE_RLIMIT:
+		n_type = NT_PROCSTAT_RLIMIT;
+		structsize = sizeof(struct rlimit) * RLIM_NLIMITS;
+		break;
+	case PSC_TYPE_OSREL:
+		n_type = NT_PROCSTAT_OSREL;
+		structsize = sizeof(int);
+		break;
+	case PSC_TYPE_PSSTRINGS:
+	case PSC_TYPE_ARGV:
+	case PSC_TYPE_ENVV:
+		n_type = NT_PROCSTAT_PSSTRINGS;
+		structsize = sizeof(vm_offset_t);
+		break;
+	case PSC_TYPE_AUXV:
+		n_type = NT_PROCSTAT_AUXV;
+		structsize = sizeof(Elf_Auxinfo);
+		break;
 	default:
 		warnx("unknown core stat type: %d", type);
 		return (NULL);
@@ -222,6 +255,19 @@ procstat_core_get(struct procstat_core *
 			free(freebuf);
 			return (NULL);
 		}
+		if (type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV) {
+			if (len < sizeof(psstrings)) {
+				free(freebuf);
+				return (NULL);
+			}
+			psstrings = *(vm_offset_t *)buf;
+			if (freebuf == NULL)
+				len = *lenp;
+			else
+				buf = NULL;
+			free(freebuf);
+			buf = get_args(core, psstrings, type, buf, &len);
+		}
 		*lenp = len;
 		return (buf);
         }
@@ -260,3 +306,128 @@ core_read(struct procstat_core *core, vo
 	}
 	return (true);
 }
+
+static ssize_t
+core_read_mem(struct procstat_core *core, void *buf, size_t len,
+    vm_offset_t addr, bool readall)
+{
+	GElf_Phdr phdr;
+	off_t offset;
+	int i;
+
+	assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
+
+	for (i = 0; i < core->pc_ehdr.e_phnum; i++) {
+		if (gelf_getphdr(core->pc_elf, i, &phdr) != &phdr) {
+			warnx("gelf_getphdr: %s", elf_errmsg(-1));
+			return (-1);
+		}
+		if (phdr.p_type != PT_LOAD)
+			continue;
+		if (addr < phdr.p_vaddr || addr > phdr.p_vaddr + phdr.p_memsz)
+			continue;
+		offset = phdr.p_offset + (addr - phdr.p_vaddr);
+		if ((phdr.p_vaddr + phdr.p_memsz) - addr < len) {
+			if (readall) {
+				warnx("format error: "
+				    "attempt to read out of segment");
+				return (-1);
+			}
+			len = (phdr.p_vaddr + phdr.p_memsz) - addr;
+		}
+		if (!core_offset(core, offset))
+			return (-1);
+		if (!core_read(core, buf, len))
+			return (-1);
+		return (len);
+	}
+	warnx("format error: address %ju not found", (uintmax_t)addr);
+	return (-1);
+}
+
+#define ARGS_CHUNK_SZ	256	/* Chunk size (bytes) for get_args operations. */
+
+static void *
+get_args(struct procstat_core *core, vm_offset_t psstrings, enum psc_type type,
+     void *args, size_t *lenp)
+{
+	struct ps_strings pss;
+	void *freeargs;
+	vm_offset_t addr;
+	char **argv, *p;
+	size_t chunksz, done, len, nchr, size;
+	ssize_t n;
+	u_int i, nstr;
+
+	assert(type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV);
+
+	if (core_read_mem(core, &pss, sizeof(pss), psstrings, true) == -1)
+		return (NULL);
+	if (type == PSC_TYPE_ARGV) {
+		addr = (vm_offset_t)pss.ps_argvstr;
+		nstr = pss.ps_nargvstr;
+	} else /* type == PSC_TYPE_ENVV */ {
+		addr = (vm_offset_t)pss.ps_envstr;
+		nstr = pss.ps_nenvstr;
+	}
+	if (addr == 0 || nstr == 0)
+		return (NULL);
+	if (nstr > ARG_MAX) {
+		warnx("format error");
+		return (NULL);
+	}
+	size = nstr * sizeof(char *);
+	argv = malloc(size);
+	if (argv == NULL) {
+		warn("malloc(%zu)", size);
+		return (NULL);
+	}
+	done = 0;
+	freeargs = NULL;
+	if (core_read_mem(core, argv, size, addr, true) == -1)
+		goto fail;
+	if (args != NULL) {
+		nchr = MIN(ARG_MAX, *lenp);
+	} else {
+		nchr = ARG_MAX;
+		freeargs = args = malloc(nchr);
+		if (args == NULL) {
+			warn("malloc(%zu)", nchr);
+			goto fail;
+		}
+	}
+	p = args;
+	for (i = 0; ; i++) {
+		if (i == nstr)
+			goto done;
+		/*
+		 * The program may have scribbled into its argv array, e.g. to
+		 * remove some arguments.  If that has happened, break out
+		 * before trying to read from NULL.
+		 */
+		if (argv[i] == NULL)
+			goto done;
+		for (addr = (vm_offset_t)argv[i]; ; addr += chunksz) {
+			chunksz = MIN(ARGS_CHUNK_SZ, nchr - 1 - done);
+			if (chunksz <= 0)
+				goto done;
+			n = core_read_mem(core, p, chunksz, addr, false);
+			if (n == -1)
+				goto fail;
+			len = strnlen(p, chunksz);
+			p += len;
+			done += len;
+			if (len != chunksz)
+				break;
+		}
+		*p++ = '\0';
+		done++;
+	}
+fail:
+	free(freeargs);
+	args = NULL;
+done:
+	*lenp = done;
+	free(argv);
+	return (args);
+}

Copied and modified: stable/9/lib/libprocstat/core.h (from r249666, head/lib/libprocstat/core.h)
==============================================================================
--- head/lib/libprocstat/core.h	Sat Apr 20 07:47:26 2013	(r249666, copy source)
+++ stable/9/lib/libprocstat/core.h	Tue May 21 19:04:16 2013	(r250870)
@@ -33,6 +33,14 @@ enum psc_type {
 	PSC_TYPE_PROC,
 	PSC_TYPE_FILES,
 	PSC_TYPE_VMMAP,
+	PSC_TYPE_GROUPS,
+	PSC_TYPE_UMASK,
+	PSC_TYPE_RLIMIT,
+	PSC_TYPE_OSREL,
+	PSC_TYPE_PSSTRINGS,
+	PSC_TYPE_ARGV,
+	PSC_TYPE_ENVV,
+	PSC_TYPE_AUXV,
 };
 
 struct procstat_core;

Modified: stable/9/lib/libprocstat/libprocstat.3
==============================================================================
--- stable/9/lib/libprocstat/libprocstat.3	Tue May 21 18:52:37 2013	(r250869)
+++ stable/9/lib/libprocstat/libprocstat.3	Tue May 21 19:04:16 2013	(r250870)
@@ -24,17 +24,33 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 1, 2012
+.Dd April 20, 2013
 .Dt LIBPROCSTAT 3
 .Os
 .Sh NAME
+.Nm procstat_open_core ,
 .Nm procstat_open_kvm ,
 .Nm procstat_open_sysctl ,
 .Nm procstat_close ,
+.Nm procstat_getargv ,
+.Nm procstat_getauxv ,
+.Nm procstat_getenvv ,
 .Nm procstat_getfiles ,
+.Nm procstat_getgroups ,
+.Nm procstat_getkstack ,
+.Nm procstat_getosrel ,
+.Nm procstat_getpathname ,
 .Nm procstat_getprocs ,
+.Nm procstat_getumask ,
+.Nm procstat_getvmmap ,
+.Nm procstat_freeargv ,
+.Nm procstat_freeauxv ,
+.Nm procstat_freeenvv ,
 .Nm procstat_freefiles ,
+.Nm procstat_freegroups ,
+.Nm procstat_freekstack ,
 .Nm procstat_freeprocs ,
+.Nm procstat_freevmmap ,
 .Nm procstat_get_pipe_info ,
 .Nm procstat_get_pts_info ,
 .Nm procstat_get_shm_info ,
@@ -50,12 +66,40 @@
 .Ft void
 .Fn procstat_close "struct procstat *procstat"
 .Ft void
+.Fo procstat_freeargv
+.Fa "struct procstat *procstat"
+.Fc
+.Ft void
+.Fo procstat_freeauxv
+.Fa "struct procstat *procstat"
+.Fa "Elf_Auxinfo *auxv"
+.Fc
+.Ft void
+.Fo procstat_freeenvv
+.Fa "struct procstat *procstat"
+.Fc
+.Ft void
 .Fo procstat_freefiles
 .Fa "struct procstat *procstat"
 .Fa "struct filestat_list *head"
 .Fc
 .Ft void
+.Fo procstat_freegroups
+.Fa "struct procstat *procstat"
+.Fa "gid_t *groups"
+.Fc
+.Ft void
+.Fo procstat_freekstack
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_kstack *kkstp"
+.Fc
+.Ft void
 .Fn procstat_freeprocs "struct procstat *procstat" "struct kinfo_proc *p"
+.Ft void
+.Fo procstat_freevmmap
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_vmentry *vmmap"
+.Fc
 .Ft int
 .Fo procstat_get_pipe_info
 .Fa "struct procstat *procstat"
@@ -91,12 +135,50 @@
 .Fa "struct vnstat *vn"
 .Fa "char *errbuf"
 .Fc
+.Ft "char **"
+.Fo procstat_getargv
+.Fa "struct procstat *procstat"
+.Fa "const struct kinfo_proc *kp"
+.Fa "size_t nchr"
+.Fa "char *errbuf"
+.Fc
+.Ft "Elf_Auxinfo *"
+.Fo procstat_getauxv
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
+.Ft "char **"
+.Fo procstat_getenvv
+.Fa "struct procstat *procstat"
+.Fa "const struct kinfo_proc *kp"
+.Fa "size_t nchr"
+.Fa "char *errbuf"
+.Fc
 .Ft "struct filestat_list *"
 .Fo procstat_getfiles
 .Fa "struct procstat *procstat"
 .Fa "struct kinfo_proc *kp"
 .Fa "int mmapped"
 .Fc
+.Ft "gid_t *"
+.Fo procstat_getgroups
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
+.Ft int
+.Fo procstat_getosrel
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "int *osrelp"
+.Fc
+.Ft "struct kinfo_kstack *"
+.Fo procstat_getkstack
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
 .Ft "struct kinfo_proc *"
 .Fo procstat_getprocs
 .Fa "struct procstat *procstat"
@@ -104,6 +186,34 @@
 .Fa "int arg"
 .Fa "unsigned int *count"
 .Fc
+.Ft "int"
+.Fo procstat_getpathname
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "char *pathname"
+.Fa "size_t maxlen"
+.Fc
+.Ft "int"
+.Fo procstat_getrlimit
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "int which"
+.Fa "struct rlimit* rlimit"
+.Fc
+.Ft "int"
+.Fo procstat_getumask
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned short *maskp"
+.Fc
+.Ft "struct kinfo_vmentry *"
+.Fo procstat_getvmmap
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
+.Ft "struct procstat *"
+.Fn procstat_open_core "const char *filename"
 .Ft "struct procstat *"
 .Fn procstat_open_kvm "const char *nlistf" "const char *memf"
 .Ft "struct procstat *"
@@ -116,7 +226,11 @@ retrieval from the running kernel via th
 .Xr sysctl 3
 library backend, and for post-mortem analysis via the
 .Xr kvm 3
-library backend.
+library backend, or from the process
+.Xr core 5
+file, searching for statistics in special
+.Xr elf 3
+note sections.
 .Pp
 The
 .Fn procstat_open_kvm
@@ -129,6 +243,16 @@ or
 library routines, respectively, to access kernel state information
 used to retrieve processes and files states.
 The
+.Fn procstat_open_core
+uses
+.Xr elf 3
+routines to access statistics stored as a set of notes in a process
+.Xr core 5
+file, written by the kernel at the moment of the process abnormal termination.
+The
+.Fa filename
+argument is the process core file name.
+The
 .Fa nlistf
 argument is the executable image of the kernel being examined.
 If this argument is
@@ -145,7 +269,7 @@ is assumed.
 See
 .Xr kvm_open 3
 for more details.
-Both functions dynamically allocate and return a
+The functions dynamically allocate and return a
 .Vt procstat
 structure pointer used in the rest of the
 .Nm libprocstat
@@ -179,6 +303,63 @@ The caller is responsible to free the al
 function call.
 .Pp
 The
+.Fn procstat_getargv
+function gets a pointer to the
+.Vt procstat
+structure from one of the
+.Fn procstat_open_*
+functions, a pointer to
+.Vt kinfo_proc
+structure from the array obtained from the
+.Fn kvm_getprocs
+function, and returns a null-terminated argument vector that corresponds to
+the command line arguments passed to the process.
+The
+.Fa nchr
+argument indicates the maximum number of characters, including null bytes,
+to use in building the strings.
+If this amount is exceeded, the string causing the overflow is truncated and
+the partial result is returned.
+This is handy for programs that print only a one line summary of a
+command and should not copy out large amounts of text only to ignore it.
+If
+.Fa nchr
+is zero, no limit is imposed and all argument strings are returned.
+The values of the returned argument vector refer the strings stored
+in the
+.Vt procstat
+internal buffer.
+A subsequent call of the function with the same
+.Vt procstat
+argument will reuse the buffer.
+To free the allocated memory
+.Fn procstat_freeargv
+function call can be used, or it will be released on
+.Fn procstat_close .
+.Pp
+The
+.Fn procstat_getenvv
+function is similar to
+.Fn procstat_getargv
+but returns the vector of environment strings.
+The caller may free the allocated memory with a subsequent
+.Fn procstat_freeenv
+function call.
+.Pp
+The
+.Fn procstat_getauxv
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the auxiliary vector as a dynamically allocated array of
+.Vt Elf_Auxinfo
+elements.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freeauxv
+function call.
+.Pp
+The
 .Fn procstat_getfiles
 function gets a pointer to the
 .Vt procstat
@@ -197,6 +378,89 @@ The caller is responsible to free the al
 function call.
 .Pp
 The
+.Fn procstat_getgroups
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the process groups as a dynamically allocated array of
+.Vt gid_t
+elements.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freegroups
+function call.
+.Pp
+The
+.Fn procstat_getkstack
+function gets a pointer to the
+.Vt procstat
+structure initialized with one of the
+.Fn procstat_open_*
+functions, a pointer to
+.Vt kinfo_proc
+structure, and returns kernel stacks of the process as a dynamically allocated
+array of
+.Vt kinfo_kstack
+structures.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freekstack
+function call.
+.Pp
+The
+.Fn procstat_getosrel
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns osrel date in the 3rd reference parameter.
+.Pp
+The
+.Fn procstat_getpathname
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and copies the path of the process executable to
+.Fa pathname
+buffer, limiting to
+.Fa maxlen
+characters.
+.Pp
+The
+.Fn procstat_getrlimit
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, resource index
+.Fa which ,
+and returns the actual resource limit in the 4th reference parameter.
+.Pp
+The
+.Fn procstat_getumask
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the process umask in the 3rd reference parameter.
+.Pp
+The
+.Fn procstat_getvmmap
+function gets a pointer to the
+.Vt procstat
+structure initialized with one of the
+.Fn procstat_open_*
+functions, a pointer to
+.Vt kinfo_proc
+structure, and returns VM layout of the process as a dynamically allocated
+array of
+.Vt kinfo_vmentry
+structures.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freevmmap
+function call.
+.Pp
+The
 .Fn procstat_get_pipe_info ,
 .Fn procstat_get_pts_info ,
 .Fn procstat_get_shm_info ,
@@ -250,10 +514,12 @@ argument indicates an actual error messa
 .Xr pipe 2 ,
 .Xr shm_open 2 ,
 .Xr socket 2 ,
+.Xr elf 3 ,
 .Xr kvm 3 ,
 .Xr queue 3 ,
 .Xr sysctl 3 ,
 .Xr pts 4 ,
+.Xr core 5 ,
 .Xr vnode 9
 .Sh HISTORY
 The

Modified: stable/9/lib/libprocstat/libprocstat.c
==============================================================================
--- stable/9/lib/libprocstat/libprocstat.c	Tue May 21 18:52:37 2013	(r250869)
+++ stable/9/lib/libprocstat/libprocstat.c	Tue May 21 19:04:16 2013	(r250870)
@@ -36,7 +36,12 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/elf.h>
 #include <sys/time.h>
+#include <sys/resourcevar.h>
+#define	_WANT_UCRED
+#include <sys/ucred.h>
+#undef _WANT_UCRED
 #include <sys/proc.h>
 #include <sys/user.h>
 #include <sys/stat.h>
@@ -96,13 +101,22 @@ __FBSDID("$FreeBSD$");
 #include <libprocstat.h>
 #include "libprocstat_internal.h"
 #include "common_kvm.h"
+#include "core.h"
 
 int     statfs(const char *, struct statfs *);	/* XXX */
 
 #define	PROCSTAT_KVM	1
 #define	PROCSTAT_SYSCTL	2
+#define	PROCSTAT_CORE	3
 
+static char	**getargv(struct procstat *procstat, struct kinfo_proc *kp,
+    size_t nchr, int env);
 static char	*getmnton(kvm_t *kd, struct mount *m);
+static struct kinfo_vmentry *	kinfo_getvmmap_core(struct procstat_core *core,
+    int *cntp);
+static Elf_Auxinfo	*procstat_getauxv_core(struct procstat_core *core,
+    unsigned int *cntp);
+static Elf_Auxinfo	*procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp);
 static struct filestat_list	*procstat_getfiles_kvm(
     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
 static struct filestat_list	*procstat_getfiles_sysctl(
@@ -128,6 +142,33 @@ static int	procstat_get_vnode_info_kvm(k
     struct vnstat *vn, char *errbuf);
 static int	procstat_get_vnode_info_sysctl(struct filestat *fst,
     struct vnstat *vn, char *errbuf);
+static gid_t	*procstat_getgroups_core(struct procstat_core *core,
+    unsigned int *count);
+static gid_t *	procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp,
+    unsigned int *count);
+static gid_t	*procstat_getgroups_sysctl(pid_t pid, unsigned int *count);
+static struct kinfo_kstack	*procstat_getkstack_sysctl(pid_t pid,
+    int *cntp);
+static int	procstat_getosrel_core(struct procstat_core *core,
+    int *osrelp);
+static int	procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp,
+    int *osrelp);
+static int	procstat_getosrel_sysctl(pid_t pid, int *osrelp);
+static int	procstat_getpathname_core(struct procstat_core *core,
+    char *pathname, size_t maxlen);
+static int	procstat_getpathname_sysctl(pid_t pid, char *pathname,
+    size_t maxlen);
+static int	procstat_getrlimit_core(struct procstat_core *core, int which,
+    struct rlimit* rlimit);
+static int	procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp,
+    int which, struct rlimit* rlimit);
+static int	procstat_getrlimit_sysctl(pid_t pid, int which,
+    struct rlimit* rlimit);
+static int	procstat_getumask_core(struct procstat_core *core,
+    unsigned short *maskp);
+static int	procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp,
+    unsigned short *maskp);
+static int	procstat_getumask_sysctl(pid_t pid, unsigned short *maskp);
 static int	vntype2psfsttype(int type);
 
 void
@@ -137,6 +178,10 @@ procstat_close(struct procstat *procstat
 	assert(procstat);
 	if (procstat->type == PROCSTAT_KVM)
 		kvm_close(procstat->kd);
+	else if (procstat->type == PROCSTAT_CORE)
+		procstat_core_close(procstat->core);
+	procstat_freeargv(procstat);
+	procstat_freeenvv(procstat);
 	free(procstat);
 }
 
@@ -177,6 +222,27 @@ procstat_open_kvm(const char *nlistf, co
 	return (procstat);
 }
 
+struct procstat *
+procstat_open_core(const char *filename)
+{
+	struct procstat *procstat;
+	struct procstat_core *core;
+
+	procstat = calloc(1, sizeof(*procstat));
+	if (procstat == NULL) {
+		warn("malloc()");
+		return (NULL);
+	}
+	core = procstat_core_open(filename);
+	if (core == NULL) {
+		free(procstat);
+		return (NULL);
+	}
+	procstat->type = PROCSTAT_CORE;
+	procstat->core = core;
+	return (procstat);
+}
+
 struct kinfo_proc *
 procstat_getprocs(struct procstat *procstat, int what, int arg,
     unsigned int *count)
@@ -231,6 +297,15 @@ procstat_getprocs(struct procstat *procs
 		}
 		/* Perform simple consistency checks. */
 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
+			warnx("kinfo_proc structure size mismatch (len = %zu)", len);
+			goto fail;
+		}
+		*count = len / sizeof(*p);
+		return (p);
+	} else if (procstat->type == PROCSTAT_CORE) {
+		p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
+		    &len);
+		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
 			warnx("kinfo_proc structure size mismatch");
 			goto fail;
 		}
@@ -258,13 +333,17 @@ procstat_freeprocs(struct procstat *proc
 struct filestat_list *
 procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
 {
-	
-	if (procstat->type == PROCSTAT_SYSCTL)
-		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
-	else if (procstat->type == PROCSTAT_KVM)
+
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
 		return (procstat_getfiles_kvm(procstat, kp, mmapped));
-	else
+	case PROCSTAT_SYSCTL:
+	case PROCSTAT_CORE:
+		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
+	default:
+		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
+	}
 }
 
 void
@@ -647,8 +726,62 @@ kinfo_uflags2fst(int fd)
 	return (0);
 }
 
+static struct kinfo_file *
+kinfo_getfile_core(struct procstat_core *core, int *cntp)
+{
+	int cnt;
+	size_t len;
+	char *buf, *bp, *eb;
+	struct kinfo_file *kif, *kp, *kf;
+
+	buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len);
+	if (buf == NULL)
+		return (NULL);
+	/*
+	 * XXXMG: The code below is just copy&past from libutil.
+	 * The code duplication can be avoided if libutil
+	 * is extended to provide something like:
+	 *   struct kinfo_file *kinfo_getfile_from_buf(const char *buf,
+	 *       size_t len, int *cntp);
+	 */
+
+	/* Pass 1: count items */
+	cnt = 0;
+	bp = buf;
+	eb = buf + len;
+	while (bp < eb) {
+		kf = (struct kinfo_file *)(uintptr_t)bp;
+		bp += kf->kf_structsize;
+		cnt++;
+	}
+
+	kif = calloc(cnt, sizeof(*kif));
+	if (kif == NULL) {
+		free(buf);
+		return (NULL);
+	}
+	bp = buf;
+	eb = buf + len;
+	kp = kif;
+	/* Pass 2: unpack */
+	while (bp < eb) {
+		kf = (struct kinfo_file *)(uintptr_t)bp;
+		/* Copy/expand into pre-zeroed buffer */
+		memcpy(kp, kf, kf->kf_structsize);
+		/* Advance to next packed record */
+		bp += kf->kf_structsize;
+		/* Set field size to fixed length, advance */
+		kp->kf_structsize = sizeof(*kp);
+		kp++;
+	}
+	free(buf);
+	*cntp = cnt;
+	return (kif);	/* Caller must free() return value */
+}
+
 static struct filestat_list *
-procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
+procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
+    int mmapped)
 {
 	struct kinfo_file *kif, *files;
 	struct kinfo_vmentry *kve, *vmentries;
@@ -664,8 +797,16 @@ procstat_getfiles_sysctl(struct procstat
 	assert(kp);
 	if (kp->ki_fd == NULL)
 		return (NULL);
-
-	files = kinfo_getfile(kp->ki_pid, &cnt);
+	switch(procstat->type) {
+	case PROCSTAT_SYSCTL:
+		files = kinfo_getfile(kp->ki_pid, &cnt);
+		break;
+	case PROCSTAT_CORE:
+		files = kinfo_getfile_core(procstat->core, &cnt);
+		break;
+	default:
+		assert(!"invalid type");
+	}
 	if (files == NULL && errno != EPERM) {
 		warn("kinfo_getfile()");
 		return (NULL);
@@ -703,7 +844,7 @@ procstat_getfiles_sysctl(struct procstat
 			STAILQ_INSERT_TAIL(head, entry, next);
 	}
 	if (mmapped != 0) {
-		vmentries = kinfo_getvmmap(kp->ki_pid, &cnt);
+		vmentries = procstat_getvmmap(procstat, kp, &cnt);
 		procstat->vmentries = vmentries;
 		if (vmentries == NULL || cnt == 0)
 			goto fail;
@@ -743,7 +884,8 @@ procstat_get_pipe_info(struct procstat *
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -807,7 +949,8 @@ procstat_get_pts_info(struct procstat *p
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -869,7 +1012,8 @@ procstat_get_shm_info(struct procstat *p
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+	    procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -949,7 +1093,8 @@ procstat_get_vnode_info(struct procstat 
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -1156,7 +1301,8 @@ procstat_get_socket_info(struct procstat
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
 		    errbuf));
-	} else if (procstat->type == PROCSTAT_SYSCTL) {
+	} else if (procstat->type == PROCSTAT_SYSCTL ||
+		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
@@ -1407,3 +1553,866 @@ getmnton(kvm_t *kd, struct mount *m)
 	mhead = mt;
 	return (mt->mntonname);
 }
+
+/*
+ * Auxiliary structures and functions to get process environment or
+ * command line arguments.
+ */
+struct argvec {
+	char	*buf;
+	size_t	bufsize;
+	char	**argv;
+	size_t	argc;
+};
+
+static struct argvec *
+argvec_alloc(size_t bufsize)
+{
+	struct argvec *av;
+
+	av = malloc(sizeof(*av));
+	if (av == NULL)
+		return (NULL);
+	av->bufsize = bufsize;
+	av->buf = malloc(av->bufsize);
+	if (av->buf == NULL) {
+		free(av);
+		return (NULL);
+	}
+	av->argc = 32;
+	av->argv = malloc(sizeof(char *) * av->argc);
+	if (av->argv == NULL) {
+		free(av->buf);
+		free(av);
+		return (NULL);
+	}
+	return av;
+}
+
+static void
+argvec_free(struct argvec * av)
+{
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 7 dfilter service freebsd_committer freebsd_triage 2013-05-21 20:05:45 UTC
Author: trociny
Date: Tue May 21 19:05:27 2013
New Revision: 250871
URL: http://svnweb.freebsd.org/changeset/base/250871

Log:
  MFC r249668, r249669, r249671, r249673, r249675, r249678, r249680, r249683,
      r249685, r249686:
  
  r249668:
  
  Use procstat_getprocs(3) for retrieving thread information instead of
  direct sysctl calls.
  
  r249669:
  
  Use more generic procstat_getvmmap(3) for retrieving VM layout of a process.
  
  r249671:
  
  Use procstat_getgroups(3) for retrieving groups information instead of
  direct sysctl.
  
  r249673:
  
  Use procstat_getumask(3) for retrieving umaks information instead of
  direct sysctl.
  
  r249675:
  
  Use procstat_getrlimit(3) for retrieving rlimit information instead of
  direct sysctl calls.
  
  r249678:
  
  Use libprocstat(3) when retrieving binary information for a process.
  
  r249680:
  
  Use libprocstat(3) to retrieve process command line arguments and
  environment variables.
  
  r249683:
  
  Use libprocstat(3) to retrieve ELF auxiliary vector.
  
  r249685:
  
  Use procstat_getkstack(3) for retrieving process kernel stacks
  instead of direct sysctl calls.
  
  r249686:
  
  Make use of newly added libprocstat(3) ability to extract procstat
  info from a process core file.
  
  So now one can run procstat(1) on a process core e.g. to get a list of
  files opened by a process when it crashed:
  
  root@lisa:/ # procstat -f /root/vi.core
    PID COMM               FD T V FLAGS     REF  OFFSET PRO NAME
    658 vi               text v r r--------   -       - -   /usr/bin/vi
    658 vi               ctty v c rw-------   -       - -   /dev/pts/0
    658 vi                cwd v d r--------   -       - -   /root
    658 vi               root v d r--------   -       - -   /
    658 vi                  0 v c rw-------  11    3208 -   /dev/pts/0
    658 vi                  1 v c rw-------  11    3208 -   /dev/pts/0
    658 vi                  2 v c rw-------  11    3208 -   /dev/pts/0
    658 vi                  3 v r r----n-l-   1       0 -   /tmp/vi.0AYKz3Lps7
    658 vi                  4 v r rw-------   1       0 -   /var/tmp/vi.recover/vi.GaGYsz
    658 vi                  5 v r rw-------   1       0 -   -
  
  PR:		kern/173723
  Suggested by:	jhb

Modified:
  stable/9/usr.bin/procstat/procstat.1
  stable/9/usr.bin/procstat/procstat.c
  stable/9/usr.bin/procstat/procstat.h
  stable/9/usr.bin/procstat/procstat_args.c
  stable/9/usr.bin/procstat/procstat_auxv.c
  stable/9/usr.bin/procstat/procstat_bin.c
  stable/9/usr.bin/procstat/procstat_cred.c
  stable/9/usr.bin/procstat/procstat_kstack.c
  stable/9/usr.bin/procstat/procstat_rlimit.c
  stable/9/usr.bin/procstat/procstat_sigs.c
  stable/9/usr.bin/procstat/procstat_threads.c
  stable/9/usr.bin/procstat/procstat_vm.c
Directory Properties:
  stable/9/usr.bin/procstat/   (props changed)

Modified: stable/9/usr.bin/procstat/procstat.1
==============================================================================
--- stable/9/usr.bin/procstat/procstat.1	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat.1	Tue May 21 19:05:27 2013	(r250871)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 11, 2012
+.Dd April 20, 2013
 .Dt PROCSTAT 1
 .Os
 .Sh NAME
@@ -38,7 +38,7 @@
 .Op Fl C
 .Op Fl w Ar interval
 .Op Fl b | c | e | f | i | j | k | l | s | t | v | x
-.Op Fl a | Ar pid ...
+.Op Fl a | Ar pid | Ar core ...
 .Sh DESCRIPTION
 The
 .Nm
@@ -47,6 +47,8 @@ utility displays detailed information ab
 arguments, or if the
 .Fl a
 flag is used, all processes.
+It can also display information extracted from a process core file, if
+the core file is specified as the argument.
 .Pp
 By default, basic process statistics are printed; one of the following
 options may be specified in order to select more detailed process information

Modified: stable/9/usr.bin/procstat/procstat.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat.c	Tue May 21 19:05:27 2013	(r250871)
@@ -50,7 +50,7 @@ usage(void)
 	fprintf(stderr, "usage: procstat [-h] [-C] [-M core] [-N system] "
 	    "[-w interval] \n");
 	fprintf(stderr, "                [-b | -c | -e | -f | -i | -j | -k | "
-	    "-l | -s | -t | -v | -x] [-a | pid ...]\n");
+	    "-l | -s | -t | -v | -x] [-a | pid | core ...]\n");
 	exit(EX_USAGE);
 }
 
@@ -59,11 +59,11 @@ procstat(struct procstat *prstat, struct
 {
 
 	if (bflag)
-		procstat_bin(kipp);
+		procstat_bin(prstat, kipp);
 	else if (cflag)
-		procstat_args(kipp);
+		procstat_args(prstat, kipp);
 	else if (eflag)
-		procstat_env(kipp);
+		procstat_env(prstat, kipp);
 	else if (fflag)
 		procstat_files(prstat, kipp);
 	else if (iflag)
@@ -71,17 +71,17 @@ procstat(struct procstat *prstat, struct
 	else if (jflag)
 		procstat_threads_sigs(prstat, kipp);
 	else if (kflag)
-		procstat_kstack(kipp, kflag);
+		procstat_kstack(prstat, kipp, kflag);
 	else if (lflag)
-		procstat_rlimit(kipp);
+		procstat_rlimit(prstat, kipp);
 	else if (sflag)
-		procstat_cred(kipp);
+		procstat_cred(prstat, kipp);
 	else if (tflag)
-		procstat_threads(kipp);
+		procstat_threads(prstat, kipp);
 	else if (vflag)
-		procstat_vm(kipp);
+		procstat_vm(prstat, kipp);
 	else if (xflag)
-		procstat_auxv(kipp);
+		procstat_auxv(prstat, kipp);
 	else
 		procstat_basic(kipp);
 }
@@ -116,7 +116,7 @@ main(int argc, char *argv[])
 	int ch, interval, tmp;
 	int i;
 	struct kinfo_proc *p;
-	struct procstat *prstat;
+	struct procstat *prstat, *cprstat;
 	long l;
 	pid_t pid;
 	char *dummy;
@@ -255,19 +255,32 @@ main(int argc, char *argv[])
 		}
 		for (i = 0; i < argc; i++) {
 			l = strtol(argv[i], &dummy, 10);
-			if (*dummy != '\0')
-				usage();
-			if (l < 0)
-				usage();
-			pid = l;
-
-			p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt);
-			if (p == NULL)
-				errx(1, "procstat_getprocs()");
-			if (cnt != 0)
-				procstat(prstat, p);
-			procstat_freeprocs(prstat, p);
-
+			if (*dummy == '\0') {
+				if (l < 0)
+					usage();
+				pid = l;
+
+				p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt);
+				if (p == NULL)
+					errx(1, "procstat_getprocs()");
+				if (cnt != 0)
+					procstat(prstat, p);
+				procstat_freeprocs(prstat, p);
+			} else {
+				cprstat = procstat_open_core(argv[i]);
+				if (cprstat == NULL) {
+					warnx("procstat_open()");
+					continue;
+				}
+				p = procstat_getprocs(cprstat, KERN_PROC_PID,
+				    -1, &cnt);
+				if (p == NULL)
+					errx(1, "procstat_getprocs()");
+				if (cnt != 0)
+					procstat(cprstat, p);
+				procstat_freeprocs(cprstat, p);
+				procstat_close(cprstat);
+			}
 			/* Suppress header after first process. */
 			hflag = 1;
 		}

Modified: stable/9/usr.bin/procstat/procstat.h
==============================================================================
--- stable/9/usr.bin/procstat/procstat.h	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat.h	Tue May 21 19:05:27 2013	(r250871)
@@ -34,18 +34,19 @@ extern int	hflag, nflag, Cflag;
 struct kinfo_proc;
 void	kinfo_proc_sort(struct kinfo_proc *kipp, int count);
 
-void	procstat_args(struct kinfo_proc *kipp);
-void	procstat_auxv(struct kinfo_proc *kipp);
+void	procstat_args(struct procstat *prstat, struct kinfo_proc *kipp);
+void	procstat_auxv(struct procstat *prstat, struct kinfo_proc *kipp);
 void	procstat_basic(struct kinfo_proc *kipp);
-void	procstat_bin(struct kinfo_proc *kipp);
-void	procstat_cred(struct kinfo_proc *kipp);
-void	procstat_env(struct kinfo_proc *kipp);
+void	procstat_bin(struct procstat *prstat, struct kinfo_proc *kipp);
+void	procstat_cred(struct procstat *prstat, struct kinfo_proc *kipp);
+void	procstat_env(struct procstat *prstat, struct kinfo_proc *kipp);
 void	procstat_files(struct procstat *prstat, struct kinfo_proc *kipp);
-void	procstat_kstack(struct kinfo_proc *kipp, int kflag);
-void	procstat_rlimit(struct kinfo_proc *kipp);
+void	procstat_kstack(struct procstat *prstat, struct kinfo_proc *kipp,
+    int kflag);
+void	procstat_rlimit(struct procstat *prstat, struct kinfo_proc *kipp);
 void	procstat_sigs(struct procstat *prstat, struct kinfo_proc *kipp);
-void	procstat_threads(struct kinfo_proc *kipp);
+void	procstat_threads(struct procstat *prstat, struct kinfo_proc *kipp);
 void	procstat_threads_sigs(struct procstat *prstat, struct kinfo_proc *kipp);
-void	procstat_vm(struct kinfo_proc *kipp);
+void	procstat_vm(struct procstat *prstat, struct kinfo_proc *kipp);
 
 #endif /* !PROCSTAT_H */

Modified: stable/9/usr.bin/procstat/procstat_args.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_args.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_args.c	Tue May 21 19:05:27 2013	(r250871)
@@ -40,52 +40,40 @@
 
 #include "procstat.h"
 
-static char args[ARG_MAX];
-
 static void
-do_args(struct kinfo_proc *kipp, int env)
+do_args(struct procstat *procstat, struct kinfo_proc *kipp, int env)
 {
-	int error, name[4];
-	size_t len;
-	char *cp;
+	int i;
+	char **args;
 
-	if (!hflag)
+	if (!hflag) {
 		printf("%5s %-16s %-53s\n", "PID", "COMM",
 		    env ? "ENVIRONMENT" : "ARGS");
-
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
-	name[3] = kipp->ki_pid;
-	len = sizeof(args);
-	error = sysctl(name, 4, args, &len, NULL, 0);
-	if (error < 0 && errno != ESRCH && errno != EPERM) {
-		warn("sysctl: kern.proc.%s: %d: %d", env ? "env" : "args",
-		    kipp->ki_pid, errno);
-		return;
 	}
-	if (error < 0)
+
+	args = env ? procstat_getenvv(procstat, kipp, 0) :
+	    procstat_getargv(procstat, kipp, 0);
+
+	printf("%5d %-16s", kipp->ki_pid, kipp->ki_comm);
+
+	if (args == NULL) {
+		printf(" -\n");
 		return;
-	if (len == 0 || strlen(args) == 0) {
-		strcpy(args, "-");
-		len = strlen(args) + 1;
 	}
 
-	printf("%5d ", kipp->ki_pid);
-	printf("%-16s ", kipp->ki_comm);
-	for (cp = args; cp < args + len; cp += strlen(cp) + 1)
-		printf("%s%s", cp != args ? " " : "", cp);
+	for (i = 0; args[i] != NULL; i++)
+		printf(" %s", args[i]);
 	printf("\n");
 }
 
 void
-procstat_args(struct kinfo_proc *kipp)
+procstat_args(struct procstat *procstat, struct kinfo_proc *kipp)
 {
-	do_args(kipp, 0);
+	do_args(procstat, kipp, 0);
 }
 
 void
-procstat_env(struct kinfo_proc *kipp)
+procstat_env(struct procstat *procstat, struct kinfo_proc *kipp)
 {
-	do_args(kipp, 1);
+	do_args(procstat, kipp, 1);
 }

Modified: stable/9/usr.bin/procstat/procstat_auxv.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_auxv.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_auxv.c	Tue May 21 19:05:27 2013	(r250871)
@@ -43,113 +43,26 @@
 
 #include "procstat.h"
 
-#define PROC_AUXV_MAX	256
-
-static Elf_Auxinfo auxv[PROC_AUXV_MAX];
-static char prefix[256];
-
-#if __ELF_WORD_SIZE == 64
-static Elf32_Auxinfo auxv32[PROC_AUXV_MAX];
-
-static const char *elf32_sv_names[] = {
-	"Linux ELF32",
-	"FreeBSD ELF32",
-};
-
-static int
-is_elf32(pid_t pid)
-{
-	int error, name[4];
-	size_t len, i;
-	static char sv_name[256];
-
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_SV_NAME;
-	name[3] = pid;
-	len = sizeof(sv_name);
-	error = sysctl(name, 4, sv_name, &len, NULL, 0);
-	if (error != 0 || len == 0)
-		return (0);
-	for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) {
-		if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0)
-			return (1);
-	}
-	return (0);
-}
-
-static size_t
-retrieve_auxv32(pid_t pid)
-{
-	int name[4];
-	size_t len, i;
-	void *ptr;
-
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_AUXV;
-	name[3] = pid;
-	len = sizeof(auxv32);
-	if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) {
-		if (errno != ESRCH && errno != EPERM)
-			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
-		return (0);
-	}
-	for (i = 0; i < len; i++) {
-		/*
-		 * XXX: We expect that values for a_type on a 32-bit platform
-		 * are directly mapped to those on 64-bit one, which is not
-		 * necessarily true.
-		 */
-		auxv[i].a_type = auxv32[i].a_type;
-		ptr = &auxv32[i].a_un;
-		auxv[i].a_un.a_val = *((uint32_t *)ptr);
-	}
-	return (len);
-}
-#endif /* __ELF_WORD_SIZE == 64 */
-
 #define	PRINT(name, spec, val)		\
 	printf("%s %-16s " #spec "\n", prefix, #name, (val))
 #define	PRINT_UNKNOWN(type, val)	\
 	printf("%s %16ld %#lx\n", prefix, (long)type, (u_long)(val))
 
-static size_t
-retrieve_auxv(pid_t pid)
-{
-	int name[4];
-	size_t len;
-
-#if __ELF_WORD_SIZE == 64
-	if (is_elf32(pid))
-		return (retrieve_auxv32(pid));
-#endif
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_AUXV;
-	name[3] = pid;
-	len = sizeof(auxv);
-	if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) {
-		if (errno != ESRCH && errno != EPERM)
-			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
-		return (0);
-	}
-	return (len);
-}
-
 void
-procstat_auxv(struct kinfo_proc *kipp)
+procstat_auxv(struct procstat *procstat, struct kinfo_proc *kipp)
 {
-	size_t len, i;
+	Elf_Auxinfo *auxv;
+	u_int count, i;
+	static char prefix[256];
 
 	if (!hflag)
 		printf("%5s %-16s %-16s %-16s\n", "PID", "COMM", "AUXV", "VALUE");
-	len = retrieve_auxv(kipp->ki_pid);
-	if (len == 0)
+	auxv = procstat_getauxv(procstat, kipp, &count);
+	if (auxv == NULL)
 		return;
 	snprintf(prefix, sizeof(prefix), "%5d %-16s", kipp->ki_pid,
 	    kipp->ki_comm);
-	for (i = 0; i < len; i++) {
+	for (i = 0; i < count; i++) {
 		switch(auxv[i].a_type) {
 		case AT_NULL:
 			return;
@@ -242,5 +155,6 @@ procstat_auxv(struct kinfo_proc *kipp)
 		}
 	}
 	printf("\n");
+	procstat_freeauxv(procstat, auxv);
 }
 

Modified: stable/9/usr.bin/procstat/procstat_bin.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_bin.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_bin.c	Tue May 21 19:05:27 2013	(r250871)
@@ -40,40 +40,19 @@
 #include "procstat.h"
 
 void
-procstat_bin(struct kinfo_proc *kipp)
+procstat_bin(struct procstat *prstat, struct kinfo_proc *kipp)
 {
-	char pathname[PATH_MAX];
-	int error, osrel, name[4];
-	size_t len;
+	int osrel;
+	static char pathname[PATH_MAX];
 
 	if (!hflag)
 		printf("%5s %-16s %8s %s\n", "PID", "COMM", "OSREL", "PATH");
 
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_PATHNAME;
-	name[3] = kipp->ki_pid;
-
-	len = sizeof(pathname);
-	error = sysctl(name, 4, pathname, &len, NULL, 0);
-	if (error < 0 && errno != ESRCH) {
-		warn("sysctl: kern.proc.pathname: %d", kipp->ki_pid);
-		return;
-	}
-	if (error < 0)
+	if (procstat_getpathname(prstat, kipp, pathname, sizeof(pathname)) != 0)
 		return;
-	if (len == 0 || strlen(pathname) == 0)
+	if (strlen(pathname) == 0)
 		strcpy(pathname, "-");
-
-	name[2] = KERN_PROC_OSREL;
-
-	len = sizeof(osrel);
-	error = sysctl(name, 4, &osrel, &len, NULL, 0);
-	if (error < 0 && errno != ESRCH) {
-		warn("sysctl: kern.proc.osrel: %d", kipp->ki_pid);
-		return;
-	}
-	if (error < 0)
+	if (procstat_getosrel(prstat, kipp, &osrel) != 0)
 		return;
 
 	printf("%5d ", kipp->ki_pid);

Modified: stable/9/usr.bin/procstat/procstat_cred.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_cred.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_cred.c	Tue May 21 19:05:27 2013	(r250871)
@@ -38,16 +38,14 @@
 
 #include "procstat.h"
 
-static const char *get_umask(struct kinfo_proc *kipp);
+static const char *get_umask(struct procstat *procstat,
+    struct kinfo_proc *kipp);
 
 void
-procstat_cred(struct kinfo_proc *kipp)
+procstat_cred(struct procstat *procstat, struct kinfo_proc *kipp)
 {
-	int i;
-	int mib[4];
-	int ngroups;
-	size_t len;
-	gid_t *groups = NULL;
+	unsigned int i, ngroups;
+	gid_t *groups;
 
 	if (!hflag)
 		printf("%5s %-16s %5s %5s %5s %5s %5s %5s %5s %5s %-15s\n",
@@ -62,34 +60,18 @@ procstat_cred(struct kinfo_proc *kipp)
 	printf("%5d ", kipp->ki_groups[0]);
 	printf("%5d ", kipp->ki_rgid);
 	printf("%5d ", kipp->ki_svgid);
-	printf("%5s ", get_umask(kipp));
+	printf("%5s ", get_umask(procstat, kipp));
 	printf("%s", kipp->ki_cr_flags & CRED_FLAG_CAPMODE ? "C" : "-");
 	printf("     ");
 
+	groups = NULL;
 	/*
 	 * We may have too many groups to fit in kinfo_proc's statically
-	 * sized storage.  If that occurs, attempt to retrieve them via
-	 * sysctl.
+	 * sized storage.  If that occurs, attempt to retrieve them using
+	 * libprocstat.
 	 */
-	if (kipp->ki_cr_flags & KI_CRF_GRP_OVERFLOW) {
-		mib[0] = CTL_KERN;
-		mib[1] = KERN_PROC;
-		mib[2] = KERN_PROC_GROUPS;
-		mib[3] = kipp->ki_pid;
-
-		ngroups = sysconf(_SC_NGROUPS_MAX) + 1;
-		len = ngroups * sizeof(gid_t);
-		if((groups = malloc(len)) == NULL)
-			err(-1, "malloc");
-
-		if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) {
-			warn("sysctl: kern.proc.groups: %d "
-			    "group list truncated", kipp->ki_pid);
-			free(groups);
-			groups = NULL;
-		}
-		ngroups = len / sizeof(gid_t);
-	}
+	if (kipp->ki_cr_flags & KI_CRF_GRP_OVERFLOW)
+		groups = procstat_getgroups(procstat, kipp, &ngroups);
 	if (groups == NULL) {
 		ngroups = kipp->ki_ngroups;
 		groups = kipp->ki_groups;
@@ -97,27 +79,18 @@ procstat_cred(struct kinfo_proc *kipp)
 	for (i = 0; i < ngroups; i++)
 		printf("%s%d", (i > 0) ? "," : "", groups[i]);
 	if (groups != kipp->ki_groups)
-		free(groups);
+		procstat_freegroups(procstat, groups);
 
 	printf("\n");
 }
 
 static const char *
-get_umask(struct kinfo_proc *kipp)
+get_umask(struct procstat *procstat, struct kinfo_proc *kipp)
 {
-	int error;
-	int mib[4];
-	size_t len;
 	u_short fd_cmask;
 	static char umask[4];
 
-	mib[0] = CTL_KERN;
-	mib[1] = KERN_PROC;
-	mib[2] = KERN_PROC_UMASK;
-	mib[3] = kipp->ki_pid;
-	len = sizeof(fd_cmask);
-	error = sysctl(mib, 4, &fd_cmask, &len, NULL, 0);
-	if (error == 0) {
+	if (procstat_getumask(procstat, kipp, &fd_cmask) == 0) {
 		snprintf(umask, 4, "%03o", fd_cmask);
 		return (umask);
 	} else {

Modified: stable/9/usr.bin/procstat/procstat_kstack.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_kstack.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_kstack.c	Tue May 21 19:05:27 2013	(r250871)
@@ -125,76 +125,35 @@ kinfo_kstack_sort(struct kinfo_kstack *k
 
 
 void
-procstat_kstack(struct kinfo_proc *kipp, int kflag)
+procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag)
 {
 	struct kinfo_kstack *kkstp, *kkstp_free;
 	struct kinfo_proc *kip, *kip_free;
 	char trace[KKST_MAXLEN];
-	int error, name[4];
 	unsigned int i, j;
-	size_t kip_len, kstk_len;
+	unsigned int kip_count, kstk_count;
 
 	if (!hflag)
 		printf("%5s %6s %-16s %-16s %-29s\n", "PID", "TID", "COMM",
 		    "TDNAME", "KSTACK");
 
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_KSTACK;
-	name[3] = kipp->ki_pid;
-
-	kstk_len = 0;
-	error = sysctl(name, 4, NULL, &kstk_len, NULL, 0);
-	if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
-		warn("sysctl: kern.proc.kstack: %d", kipp->ki_pid);
-		return;
-	}
-	if (error < 0 && errno == ENOENT) {
-		warnx("sysctl: kern.proc.kstack unavailable");
-		errx(-1, "options DDB or options STACK required in kernel");
-	}
-	if (error < 0)
-		return;
-
-	kkstp = kkstp_free = malloc(kstk_len);
+	kkstp = kkstp_free = procstat_getkstack(procstat, kipp, &kstk_count);
 	if (kkstp == NULL)
-		err(-1, "malloc");
-
-	if (sysctl(name, 4, kkstp, &kstk_len, NULL, 0) < 0) {
-		warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
-		free(kkstp);
 		return;
-	}
 
 	/*
 	 * We need to re-query for thread information, so don't use *kipp.
 	 */
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
-	name[3] = kipp->ki_pid;
-
-	kip_len = 0;
-	error = sysctl(name, 4, NULL, &kip_len, NULL, 0);
-	if (error < 0 && errno != ESRCH) {
-		warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
-		return;
-	}
-	if (error < 0)
-		return;
+	kip = kip_free = procstat_getprocs(procstat,
+	    KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &kip_count);
 
-	kip = kip_free = malloc(kip_len);
-	if (kip == NULL)
-		err(-1, "malloc");
-
-	if (sysctl(name, 4, kip, &kip_len, NULL, 0) < 0) {
-		warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
-		free(kip);
+	if (kip == NULL) {
+		procstat_freekstack(procstat, kkstp_free);
 		return;
 	}
 
-	kinfo_kstack_sort(kkstp, kstk_len / sizeof(*kkstp));
-	for (i = 0; i < kstk_len / sizeof(*kkstp); i++) {
+	kinfo_kstack_sort(kkstp, kstk_count);
+	for (i = 0; i < kstk_count; i++) {
 		kkstp = &kkstp_free[i];
 
 		/*
@@ -202,7 +161,7 @@ procstat_kstack(struct kinfo_proc *kipp,
 		 * display the per-thread command line.
 		 */
 		kipp = NULL;
-		for (j = 0; j < kip_len / sizeof(*kipp); j++) {
+		for (j = 0; j < kip_count; j++) {
 			kipp = &kip_free[j];
 			if (kkstp->kkst_tid == kipp->ki_tid)
 				break;
@@ -242,6 +201,6 @@ procstat_kstack(struct kinfo_proc *kipp,
 		kstack_cleanup(kkstp->kkst_trace, trace, kflag);
 		printf("%-29s\n", trace);
 	}
-	free(kip_free);
-	free(kkstp_free);
+	procstat_freekstack(procstat, kkstp_free);
+	procstat_freeprocs(procstat, kip_free);
 }

Modified: stable/9/usr.bin/procstat/procstat_rlimit.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_rlimit.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_rlimit.c	Tue May 21 19:05:27 2013	(r250871)
@@ -86,31 +86,18 @@ humanize_rlimit(int indx, rlim_t limit)
 }
 
 void
-procstat_rlimit(struct kinfo_proc *kipp)
+procstat_rlimit(struct procstat *prstat, struct kinfo_proc *kipp)
 {
 	struct rlimit rlimit;
-	int error, i, name[5];
-	size_t len;
+	int i;
 
 	if (!hflag) {
 		printf("%5s %-16s %-16s %16s %16s\n",
 		    "PID", "COMM", "RLIMIT", "SOFT     ", "HARD     ");
 	}
-	len = sizeof(struct rlimit);
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_RLIMIT;
-	name[3] = kipp->ki_pid;
 	for (i = 0; i < RLIM_NLIMITS; i++) {
-		name[4] = i;
-		error = sysctl(name, 5, &rlimit, &len, NULL, 0);
-		if (error < 0 && errno != ESRCH) {
-			warn("sysctl: kern.proc.rlimit: %d", kipp->ki_pid);
+		if (procstat_getrlimit(prstat, kipp, i, &rlimit) == -1)
 			return;
-		}
-		if (error < 0 || len != sizeof(struct rlimit))
-			return;
-
 		printf("%5d %-16s %-16s ", kipp->ki_pid, kipp->ki_comm,
 		    rlimit_param[i].name);
 		printf("%16s ", humanize_rlimit(i, rlimit.rlim_cur));

Modified: stable/9/usr.bin/procstat/procstat_sigs.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_sigs.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_sigs.c	Tue May 21 19:05:27 2013	(r250871)
@@ -86,48 +86,24 @@ procstat_sigs(struct procstat *prstat __
 }
 
 void
-procstat_threads_sigs(struct procstat *prstat __unused, struct kinfo_proc *kipp)
+procstat_threads_sigs(struct procstat *procstat, struct kinfo_proc *kipp)
 {
 	struct kinfo_proc *kip;
 	pid_t pid;
-	int error, name[4], j;
-	unsigned int i;
-	size_t len;
+	int j;
+	unsigned int count, i;
 
 	pid = kipp->ki_pid;
 	if (!hflag)
 		printf("%5s %6s %-16s %-7s %4s\n", "PID", "TID", "COMM",
 		     "SIG", "FLAGS");
 
-	/*
-	 * We need to re-query for thread information, so don't use *kipp.
-	 */
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
-	name[3] = pid;
-
-	len = 0;
-	error = sysctl(name, 4, NULL, &len, NULL, 0);
-	if (error < 0 && errno != ESRCH) {
-		warn("sysctl: kern.proc.pid: %d", pid);
-		return;
-	}
-	if (error < 0)
-		return;
-
-	kip = malloc(len);
+	kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+	    pid, &count);
 	if (kip == NULL)
-		err(-1, "malloc");
-
-	if (sysctl(name, 4, kip, &len, NULL, 0) < 0) {
-		warn("sysctl: kern.proc.pid: %d", pid);
-		free(kip);
 		return;
-	}
-
-	kinfo_proc_sort(kip, len / sizeof(*kipp));
-	for (i = 0; i < len / sizeof(*kipp); i++) {
+	kinfo_proc_sort(kip, count);
+	for (i = 0; i < count; i++) {
 		kipp = &kip[i];
 		for (j = 1; j <= _SIG_MAXSIG; j++) {
 			printf("%5d ", pid);
@@ -140,5 +116,5 @@ procstat_threads_sigs(struct procstat *p
 			printf("\n");
 		}
 	}
-	free(kip);
+	procstat_freeprocs(procstat, kip);
 }

Modified: stable/9/usr.bin/procstat/procstat_threads.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_threads.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_threads.c	Tue May 21 19:05:27 2013	(r250871)
@@ -40,47 +40,22 @@
 #include "procstat.h"
 
 void
-procstat_threads(struct kinfo_proc *kipp)
+procstat_threads(struct procstat *procstat, struct kinfo_proc *kipp)
 {
 	struct kinfo_proc *kip;
-	int error, name[4];
-	unsigned int i;
+	unsigned int count, i;
 	const char *str;
-	size_t len;
 
 	if (!hflag)
 		printf("%5s %6s %-16s %-16s %2s %4s %-7s %-9s\n", "PID",
 		    "TID", "COMM", "TDNAME", "CPU", "PRI", "STATE", "WCHAN");
 
-	/*
-	 * We need to re-query for thread information, so don't use *kipp.
-	 */
-	name[0] = CTL_KERN;
-	name[1] = KERN_PROC;
-	name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
-	name[3] = kipp->ki_pid;
-
-	len = 0;
-	error = sysctl(name, 4, NULL, &len, NULL, 0);
-	if (error < 0 && errno != ESRCH) {
-		warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
-		return;
-	}
-	if (error < 0)
-		return;
-
-	kip = malloc(len);
+	kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+	    kipp->ki_pid, &count);
 	if (kip == NULL)
-		err(-1, "malloc");
-
-	if (sysctl(name, 4, kip, &len, NULL, 0) < 0) {
-		warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
-		free(kip);
 		return;
-	}
-
-	kinfo_proc_sort(kip, len / sizeof(*kipp));
-	for (i = 0; i < len / sizeof(*kipp); i++) {
+	kinfo_proc_sort(kip, count);
+	for (i = 0; i < count; i++) {
 		kipp = &kip[i];
 		printf("%5d ", kipp->ki_pid);
 		printf("%6d ", kipp->ki_tid);
@@ -139,5 +114,5 @@ procstat_threads(struct kinfo_proc *kipp
 		}
 		printf("\n");
 	}
-	free(kip);
+	procstat_freeprocs(procstat, kip);
 }

Modified: stable/9/usr.bin/procstat/procstat_vm.c
==============================================================================
--- stable/9/usr.bin/procstat/procstat_vm.c	Tue May 21 19:04:16 2013	(r250870)
+++ stable/9/usr.bin/procstat/procstat_vm.c	Tue May 21 19:05:27 2013	(r250871)
@@ -41,7 +41,7 @@
 #include "procstat.h"
 
 void
-procstat_vm(struct kinfo_proc *kipp)
+procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp)
 {
 	struct kinfo_vmentry *freep, *kve;
 	int ptrwidth;
@@ -54,7 +54,7 @@ procstat_vm(struct kinfo_proc *kipp)
 		    "PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
 		    "PRES", "REF", "SHD", "FL", "TP", "PATH");
 
-	freep = kinfo_getvmmap(kipp->ki_pid, &cnt);
+	freep = procstat_getvmmap(procstat, kipp, &cnt);
 	if (freep == NULL)
 		return;
 	for (i = 0; i < cnt; i++) {
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 8 Mikolaj Golub freebsd_committer freebsd_triage 2013-05-27 19:04:40 UTC
State Changed
From-To: open->closed

Implemented and merged to stable/9.