From nobody@FreeBSD.org  Mon Nov 19 16:50:45 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 829861BA
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 19 Nov 2012 16:50:45 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 69CE08FC08
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 19 Nov 2012 16:50:45 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.5/8.14.5) with ESMTP id qAJGojix019261
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 19 Nov 2012 16:50:45 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.5/8.14.5/Submit) id qAJGojuv019260;
	Mon, 19 Nov 2012 16:50:45 GMT
	(envelope-from nobody)
Message-Id: <201211191650.qAJGojuv019260@red.freebsd.org>
Date: Mon, 19 Nov 2012 16:50:45 GMT
From: John Baldwin <jhb@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Add file descriptor information to process core dumps
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         173723
>Category:       kern
>Synopsis:       Add file descriptor information to process core dumps
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    trociny
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 19 17:00:00 UTC 2012
>Closed-Date:    Mon May 27 18:05:50 UTC 2013
>Last-Modified:  Mon May 27 18:05:50 UTC 2013
>Originator:     John Baldwin
>Release:        
>Organization:
>Environment:
>Description:
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.
>How-To-Repeat:

>Fix:


>Release-Note:
>Audit-Trail:

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/173723: commit references a PR
Date: Tue, 16 Apr 2013 19:19:29 +0000 (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"
 
Responsible-Changed-From-To: freebsd-bugs->trociny 
Responsible-Changed-By: trociny 
Responsible-Changed-When: Tue Apr 16 19:39:52 UTC 2013 
Responsible-Changed-Why:  
Working on it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=173723 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/173723: commit references a PR
Date: Sat, 20 Apr 2013 07:47:42 +0000 (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"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/173723: commit references a PR
Date: Sat, 20 Apr 2013 08:22:22 +0000 (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"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/173723: commit references a PR
Date: Fri, 17 May 2013 20:13:17 +0000 (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"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/173723: commit references a PR
Date: Tue, 21 May 2013 19:05:45 +0000 (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"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/173723: commit references a PR
Date: Tue, 21 May 2013 19:04:34 +0000 (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"
 
State-Changed-From-To: open->closed 
State-Changed-By: trociny 
State-Changed-When: Mon May 27 18:04:40 UTC 2013 
State-Changed-Why:  
Implemented and merged to stable/9. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=173723 
>Unformatted:
