[Midnightbsd-cvs] src [9409] trunk/lib/libprocstat: make libprocstat(3) extract procstat notes from a process core file.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Mar 4 16:43:04 EST 2017


Revision: 9409
          http://svnweb.midnightbsd.org/src/?rev=9409
Author:   laffer1
Date:     2017-03-04 16:43:03 -0500 (Sat, 04 Mar 2017)
Log Message:
-----------
make libprocstat(3) extract procstat notes from a process core file.

Modified Paths:
--------------
    trunk/lib/libprocstat/Makefile
    trunk/lib/libprocstat/Symbol.map
    trunk/lib/libprocstat/libprocstat.3
    trunk/lib/libprocstat/libprocstat.c
    trunk/lib/libprocstat/libprocstat.h
    trunk/lib/libprocstat/libprocstat_internal.h

Modified: trunk/lib/libprocstat/Makefile
===================================================================
--- trunk/lib/libprocstat/Makefile	2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/Makefile	2017-03-04 21:43:03 UTC (rev 9409)
@@ -6,6 +6,7 @@
 
 SRCS=	cd9660.c	\
 	common_kvm.c	\
+	core.c		\
 	libprocstat.c	\
         msdosfs.c	\
 	ntfs.c		\
@@ -19,8 +20,8 @@
 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: trunk/lib/libprocstat/Symbol.map
===================================================================
--- trunk/lib/libprocstat/Symbol.map	2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/Symbol.map	2017-03-04 21:43:03 UTC (rev 9409)
@@ -16,5 +16,22 @@
 };
 
 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;
 };

Modified: trunk/lib/libprocstat/libprocstat.3
===================================================================
--- trunk/lib/libprocstat/libprocstat.3	2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat.3	2017-03-04 21:43:03 UTC (rev 9409)
@@ -24,17 +24,33 @@
 .\"
 .\" $MidnightBSD$
 .\"
-.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,6 +135,26 @@
 .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"
@@ -97,6 +161,24 @@
 .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,7 +186,35 @@
 .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 *"
 .Fn procstat_open_sysctl void
@@ -116,7 +226,11 @@
 .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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 .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: trunk/lib/libprocstat/libprocstat.c
===================================================================
--- trunk/lib/libprocstat/libprocstat.c	2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat.c	2017-03-04 21:43:03 UTC (rev 9409)
@@ -36,7 +36,12 @@
 __MBSDID("$MidnightBSD$");
 
 #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 @@
 #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 @@
     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 @@
 	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 @@
 	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 @@
 		}
 		/* 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 @@
 struct filestat_list *
 procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
 {
-	
-	if (procstat->type == PROCSTAT_SYSCTL)
+
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		return (procstat_getfiles_kvm(procstat, kp, mmapped));
+	case PROCSTAT_SYSCTL:
+	case PROCSTAT_CORE:
 		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
-	else if (procstat->type == PROCSTAT_KVM)
-		return (procstat_getfiles_kvm(procstat, kp, mmapped));
-	else
+	default:
+		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
+	}
 }
 
 void
@@ -647,8 +726,62 @@
 	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 @@
 	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 @@
 			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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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)
+{
+
+	free(av->argv);
+	free(av->buf);
+	free(av);
+}
+
+static char **
+getargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env)
+{
+	int error, name[4], argc, i;
+	struct argvec *av, **avp;
+	enum psc_type type;
+	size_t len;
+	char *p, **argv;
+
+	assert(procstat);
+	assert(kp);
+	if (procstat->type == PROCSTAT_KVM) {
+		warnx("can't use kvm access method");
+		return (NULL);
+	}
+	if (procstat->type != PROCSTAT_SYSCTL &&
+	    procstat->type != PROCSTAT_CORE) {
+		warnx("unknown access method: %d", procstat->type);
+		return (NULL);
+	}
+
+	if (nchr == 0 || nchr > ARG_MAX)
+		nchr = ARG_MAX;
+
+	avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv);
+	av = *avp;
+
+	if (av == NULL)
+	{
+		av = argvec_alloc(nchr);
+		if (av == NULL)
+		{
+			warn("malloc(%zu)", nchr);
+			return (NULL);
+		}
+		*avp = av;
+	} else if (av->bufsize < nchr) {
+		av->buf = reallocf(av->buf, nchr);
+		if (av->buf == NULL) {
+			warn("malloc(%zu)", nchr);
+			return (NULL);
+		}
+	}
+	if (procstat->type == PROCSTAT_SYSCTL) {
+		name[0] = CTL_KERN;
+		name[1] = KERN_PROC;
+		name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
+		name[3] = kp->ki_pid;
+		len = nchr;
+		error = sysctl(name, 4, av->buf, &len, NULL, 0);
+		if (error != 0 && errno != ESRCH && errno != EPERM)
+			warn("sysctl(kern.proc.%s)", env ? "env" : "args");
+		if (error != 0 || len == 0)
+			return (NULL);
+	} else /* procstat->type == PROCSTAT_CORE */ {
+		type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV;
+		len = nchr;
+		if (procstat_core_get(procstat->core, type, av->buf, &len)
+		    == NULL) {
+			return (NULL);
+		}
+	}
+
+	argv = av->argv;
+	argc = av->argc;
+	i = 0;
+	for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) {
+		argv[i++] = p;
+		if (i < argc)
+			continue;
+		/* Grow argv. */
+		argc += argc;
+		argv = realloc(argv, sizeof(char *) * argc);
+		if (argv == NULL) {
+			warn("malloc(%zu)", sizeof(char *) * argc);
+			return (NULL);
+		}
+		av->argv = argv;
+		av->argc = argc;
+	}
+	argv[i] = NULL;
+
+	return (argv);
+}
+
+/*
+ * Return process command line arguments.
+ */
+char **
+procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
+{
+
+	return (getargv(procstat, p, nchr, 0));
+}
+
+/*
+ * Free the buffer allocated by procstat_getargv().
+ */
+void
+procstat_freeargv(struct procstat *procstat)
+{
+
+	if (procstat->argv != NULL) {
+		argvec_free(procstat->argv);
+		procstat->argv = NULL;
+	}
+}
+
+/*
+ * Return process environment.
+ */
+char **
+procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
+{
+
+	return (getargv(procstat, p, nchr, 1));
+}
+
+/*
+ * Free the buffer allocated by procstat_getenvv().
+ */
+void
+procstat_freeenvv(struct procstat *procstat)
+{
+	if (procstat->envv != NULL) {
+		argvec_free(procstat->envv);
+		procstat->envv = NULL;
+	}
+}
+
+static struct kinfo_vmentry *
+kinfo_getvmmap_core(struct procstat_core *core, int *cntp)
+{
+	int cnt;
+	size_t len;
+	char *buf, *bp, *eb;
+	struct kinfo_vmentry *kiv, *kp, *kv;
+
+	buf = procstat_core_get(core, PSC_TYPE_VMMAP, 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_vmentry *kinfo_getvmmap_from_buf(const char *buf,
+	 *       size_t len, int *cntp);
+	 */
+
+	/* Pass 1: count items */
+	cnt = 0;
+	bp = buf;
+	eb = buf + len;
+	while (bp < eb) {
+		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
+		bp += kv->kve_structsize;
+		cnt++;
+	}
+
+	kiv = calloc(cnt, sizeof(*kiv));
+	if (kiv == NULL) {
+		free(buf);
+		return (NULL);
+	}
+	bp = buf;
+	eb = buf + len;
+	kp = kiv;
+	/* Pass 2: unpack */
+	while (bp < eb) {
+		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
+		/* Copy/expand into pre-zeroed buffer */
+		memcpy(kp, kv, kv->kve_structsize);
+		/* Advance to next packed record */
+		bp += kv->kve_structsize;
+		/* Set field size to fixed length, advance */
+		kp->kve_structsize = sizeof(*kp);
+		kp++;
+	}
+	free(buf);
+	*cntp = cnt;
+	return (kiv);	/* Caller must free() return value */
+}
+
+struct kinfo_vmentry *
+procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned int *cntp)
+{
+
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		warnx("kvm method is not supported");
+		return (NULL);
+	case PROCSTAT_SYSCTL:
+		return (kinfo_getvmmap(kp->ki_pid, cntp));
+	case PROCSTAT_CORE:
+		return (kinfo_getvmmap_core(procstat->core, cntp));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (NULL);
+	}
+}
+
+void
+procstat_freevmmap(struct procstat *procstat __unused,
+    struct kinfo_vmentry *vmmap)
+{
+
+	free(vmmap);
+}
+
+static gid_t *
+procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp)
+{
+	struct proc proc;
+	struct ucred ucred;
+	gid_t *groups;
+	size_t len;
+
+	assert(kd != NULL);
+	assert(kp != NULL);
+	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+	    sizeof(proc))) {
+		warnx("can't read proc struct at %p for pid %d",
+		    kp->ki_paddr, kp->ki_pid);
+		return (NULL);
+	}
+	if (proc.p_ucred == NOCRED)
+		return (NULL);
+	if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred,
+	    sizeof(ucred))) {
+		warnx("can't read ucred struct at %p for pid %d",
+		    proc.p_ucred, kp->ki_pid);
+		return (NULL);
+	}
+	len = ucred.cr_ngroups * sizeof(gid_t);
+	groups = malloc(len);
+	if (groups == NULL) {
+		warn("malloc(%zu)", len);
+		return (NULL);
+	}
+	if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) {
+		warnx("can't read groups at %p for pid %d",
+		    ucred.cr_groups, kp->ki_pid);
+		free(groups);
+		return (NULL);
+	}
+	*cntp = ucred.cr_ngroups;
+	return (groups);
+}
+
+static gid_t *
+procstat_getgroups_sysctl(pid_t pid, unsigned int *cntp)
+{
+	int mib[4];
+	size_t len;
+	gid_t *groups;
+
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_PROC;
+	mib[2] = KERN_PROC_GROUPS;
+	mib[3] = pid;
+	len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t);
+	groups = malloc(len);
+	if (groups == NULL) {
+		warn("malloc(%zu)", len);
+		return (NULL);
+	}
+	if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) {
+		warn("sysctl: kern.proc.groups: %d", pid);
+		free(groups);
+		return (NULL);
+	}
+	*cntp = len / sizeof(gid_t);
+	return (groups);
+}
+
+static gid_t *
+procstat_getgroups_core(struct procstat_core *core, unsigned int *cntp)
+{
+	size_t len;
+	gid_t *groups;
+
+	groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len);
+	if (groups == NULL)
+		return (NULL);
+	*cntp = len / sizeof(gid_t);
+	return (groups);
+}
+
+gid_t *
+procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned int *cntp)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		return (procstat_getgroups_kvm(procstat->kd, kp, cntp));
+	case PROCSTAT_SYSCTL:
+		return (procstat_getgroups_sysctl(kp->ki_pid, cntp));
+	case PROCSTAT_CORE:
+		return (procstat_getgroups_core(procstat->core, cntp));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (NULL);
+	}
+}
+
+void
+procstat_freegroups(struct procstat *procstat __unused, gid_t *groups)
+{
+
+	free(groups);
+}
+
+static int
+procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp)
+{
+	struct filedesc fd;
+
+	assert(kd != NULL);
+	assert(kp != NULL);
+	if (kp->ki_fd == NULL)
+		return (-1);
+	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) {
+		warnx("can't read filedesc at %p for pid %d", kp->ki_fd,
+		    kp->ki_pid);
+		return (-1);
+	}
+	*maskp = fd.fd_cmask;
+	return (0);
+}
+
+static int
+procstat_getumask_sysctl(pid_t pid, unsigned short *maskp)
+{
+	int error;
+	int mib[4];
+	size_t len;
+
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_PROC;
+	mib[2] = KERN_PROC_UMASK;
+	mib[3] = pid;
+	len = sizeof(*maskp);
+	error = sysctl(mib, 4, maskp, &len, NULL, 0);
+	if (error != 0 && errno != ESRCH)
+		warn("sysctl: kern.proc.umask: %d", pid);
+	return (error);
+}
+
+static int
+procstat_getumask_core(struct procstat_core *core, unsigned short *maskp)
+{
+	size_t len;
+	unsigned short *buf;
+
+	buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len);
+	if (buf == NULL)
+		return (-1);
+	if (len < sizeof(*maskp)) {
+		free(buf);
+		return (-1);
+	}
+	*maskp = *buf;
+	free(buf);
+	return (0);
+}
+
+int
+procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned short *maskp)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		return (procstat_getumask_kvm(procstat->kd, kp, maskp));
+	case PROCSTAT_SYSCTL:
+		return (procstat_getumask_sysctl(kp->ki_pid, maskp));
+	case PROCSTAT_CORE:
+		return (procstat_getumask_core(procstat->core, maskp));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (-1);
+	}
+}
+
+static int
+procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which,
+    struct rlimit* rlimit)
+{
+	struct proc proc;
+	unsigned long offset;
+
+	assert(kd != NULL);
+	assert(kp != NULL);
+	assert(which >= 0 && which < RLIM_NLIMITS);
+	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+	    sizeof(proc))) {
+		warnx("can't read proc struct at %p for pid %d",
+		    kp->ki_paddr, kp->ki_pid);
+		return (-1);
+	}
+	if (proc.p_limit == NULL)
+		return (-1);
+	offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which;
+	if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) {
+		warnx("can't read rlimit struct at %p for pid %d",
+		    (void *)offset, kp->ki_pid);
+		return (-1);
+	}
+	return (0);
+}
+
+static int
+procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit)
+{
+	int error, name[5];
+	size_t len;
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_RLIMIT;
+	name[3] = pid;
+	name[4] = which;
+	len = sizeof(struct rlimit);
+	error = sysctl(name, 5, rlimit, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH) {
+		warn("sysctl: kern.proc.rlimit: %d", pid);
+		return (-1);
+	}
+	if (error < 0 || len != sizeof(struct rlimit))
+		return (-1);
+	return (0);
+}
+
+static int
+procstat_getrlimit_core(struct procstat_core *core, int which,
+    struct rlimit* rlimit)
+{
+	size_t len;
+	struct rlimit* rlimits;
+
+	if (which < 0 || which >= RLIM_NLIMITS) {
+		errno = EINVAL;
+		warn("getrlimit: which");
+		return (-1);
+	}
+	rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len);
+	if (rlimits == NULL)
+		return (-1);
+	if (len < sizeof(struct rlimit) * RLIM_NLIMITS) {
+		free(rlimits);
+		return (-1);
+	}
+	*rlimit = rlimits[which];
+	return (0);
+}
+
+int
+procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which,
+    struct rlimit* rlimit)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		return (procstat_getrlimit_kvm(procstat->kd, kp, which,
+		    rlimit));
+	case PROCSTAT_SYSCTL:
+		return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit));
+	case PROCSTAT_CORE:
+		return (procstat_getrlimit_core(procstat->core, which, rlimit));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (-1);
+	}
+}
+
+static int
+procstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen)
+{
+	int error, name[4];
+	size_t len;
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_PATHNAME;
+	name[3] = pid;
+	len = maxlen;
+	error = sysctl(name, 4, pathname, &len, NULL, 0);
+	if (error != 0 && errno != ESRCH)
+		warn("sysctl: kern.proc.pathname: %d", pid);
+	if (len == 0)
+		pathname[0] = '\0';
+	return (error);
+}
+
+static int
+procstat_getpathname_core(struct procstat_core *core, char *pathname,
+    size_t maxlen)
+{
+	struct kinfo_file *files;
+	int cnt, i, result;
+
+	files = kinfo_getfile_core(core, &cnt);
+	if (files == NULL)
+		return (-1);
+	result = -1;
+	for (i = 0; i < cnt; i++) {
+		if (files[i].kf_fd != KF_FD_TYPE_TEXT)
+			continue;
+		strncpy(pathname, files[i].kf_path, maxlen);
+		result = 0;
+		break;
+	}
+	free(files);
+	return (result);
+}
+
+int
+procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
+    char *pathname, size_t maxlen)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		warnx("kvm method is not supported");
+		return (-1);
+	case PROCSTAT_SYSCTL:
+		return (procstat_getpathname_sysctl(kp->ki_pid, pathname,
+		    maxlen));
+	case PROCSTAT_CORE:
+		return (procstat_getpathname_core(procstat->core, pathname,
+		    maxlen));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (-1);
+	}
+}
+
+static int
+procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp)
+{
+	struct proc proc;
+
+	assert(kd != NULL);
+	assert(kp != NULL);
+	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+	    sizeof(proc))) {
+		warnx("can't read proc struct at %p for pid %d",
+		    kp->ki_paddr, kp->ki_pid);
+		return (-1);
+	}
+	*osrelp = proc.p_osrel;
+	return (0);
+}
+
+static int
+procstat_getosrel_sysctl(pid_t pid, int *osrelp)
+{
+	int error, name[4];
+	size_t len;
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_OSREL;
+	name[3] = pid;
+	len = sizeof(*osrelp);
+	error = sysctl(name, 4, osrelp, &len, NULL, 0);
+	if (error != 0 && errno != ESRCH)
+		warn("sysctl: kern.proc.osrel: %d", pid);
+	return (error);
+}
+
+static int
+procstat_getosrel_core(struct procstat_core *core, int *osrelp)
+{
+	size_t len;
+	int *buf;
+
+	buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len);
+	if (buf == NULL)
+		return (-1);
+	if (len < sizeof(*osrelp)) {
+		free(buf);
+		return (-1);
+	}
+	*osrelp = *buf;
+	free(buf);
+	return (0);
+}
+
+int
+procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		return (procstat_getosrel_kvm(procstat->kd, kp, osrelp));
+	case PROCSTAT_SYSCTL:
+		return (procstat_getosrel_sysctl(kp->ki_pid, osrelp));
+	case PROCSTAT_CORE:
+		return (procstat_getosrel_core(procstat->core, osrelp));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (-1);
+	}
+}
+
+#define PROC_AUXV_MAX	256
+
+#if __ELF_WORD_SIZE == 64
+static const char *elf32_sv_names[] = {
+	"Linux ELF32",
+	"FreeBSD ELF32",
+};
+
+static int
+is_elf32_sysctl(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 Elf_Auxinfo *
+procstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp)
+{
+	Elf_Auxinfo *auxv;
+	Elf32_Auxinfo *auxv32;
+	void *ptr;
+	size_t len;
+	unsigned int i, count;
+	int name[4];
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_AUXV;
+	name[3] = pid;
+	len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo);
+	auxv = NULL;
+	auxv32 = malloc(len);
+	if (auxv32 == NULL) {
+		warn("malloc(%zu)", len);
+		goto out;
+	}
+	if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) {
+		if (errno != ESRCH && errno != EPERM)
+			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
+		goto out;
+	}
+	count = len / sizeof(Elf_Auxinfo);
+	auxv = malloc(count  * sizeof(Elf_Auxinfo));
+	if (auxv == NULL) {
+		warn("malloc(%zu)", count * sizeof(Elf_Auxinfo));
+		goto out;
+	}
+	for (i = 0; i < count; i++) {
+		/*
+		 * XXX: We expect that values for a_type on a 32-bit platform
+		 * are directly mapped to values 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);
+	}
+	*cntp = count;
+out:
+	free(auxv32);
+	return (auxv);
+}
+#endif /* __ELF_WORD_SIZE == 64 */
+
+static Elf_Auxinfo *
+procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp)
+{
+	Elf_Auxinfo *auxv;
+	int name[4];
+	size_t len;
+
+#if __ELF_WORD_SIZE == 64
+	if (is_elf32_sysctl(pid))
+		return (procstat_getauxv32_sysctl(pid, cntp));
+#endif
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_AUXV;
+	name[3] = pid;
+	len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo);
+	auxv = malloc(len);
+	if (auxv == NULL) {
+		warn("malloc(%zu)", len);
+		return (NULL);
+	}
+	if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) {
+		if (errno != ESRCH && errno != EPERM)
+			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
+		free(auxv);
+		return (NULL);
+	}
+	*cntp = len / sizeof(Elf_Auxinfo);
+	return (auxv);
+}
+
+static Elf_Auxinfo *
+procstat_getauxv_core(struct procstat_core *core, unsigned int *cntp)
+{
+	Elf_Auxinfo *auxv;
+	size_t len;
+
+	auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len);
+	if (auxv == NULL)
+		return (NULL);
+	*cntp = len / sizeof(Elf_Auxinfo);
+	return (auxv);
+}
+
+Elf_Auxinfo *
+procstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned int *cntp)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		warnx("kvm method is not supported");
+		return (NULL);
+	case PROCSTAT_SYSCTL:
+		return (procstat_getauxv_sysctl(kp->ki_pid, cntp));
+	case PROCSTAT_CORE:
+		return (procstat_getauxv_core(procstat->core, cntp));
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (NULL);
+	}
+}
+
+void
+procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv)
+{
+
+	free(auxv);
+}
+
+static struct kinfo_kstack *
+procstat_getkstack_sysctl(pid_t pid, int *cntp)
+{
+	struct kinfo_kstack *kkstp;
+	int error, name[4];
+	size_t len;
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_KSTACK;
+	name[3] = pid;
+
+	len = 0;
+	error = sysctl(name, 4, NULL, &len, NULL, 0);
+	if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
+		warn("sysctl: kern.proc.kstack: %d", pid);
+		return (NULL);
+	}
+	if (error == -1 && errno == ENOENT) {
+		warnx("sysctl: kern.proc.kstack unavailable"
+		    " (options DDB or options STACK required in kernel)");
+		return (NULL);
+	}
+	if (error == -1)
+		return (NULL);
+	kkstp = malloc(len);
+	if (kkstp == NULL) {
+		warn("malloc(%zu)", len);
+		return (NULL);
+	}
+	if (sysctl(name, 4, kkstp, &len, NULL, 0) == -1) {
+		warn("sysctl: kern.proc.pid: %d", pid);
+		free(kkstp);
+		return (NULL);
+	}
+	*cntp = len / sizeof(*kkstp);
+
+	return (kkstp);
+}
+
+struct kinfo_kstack *
+procstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned int *cntp)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		warnx("kvm method is not supported");
+		return (NULL);
+	case PROCSTAT_SYSCTL:
+		return (procstat_getkstack_sysctl(kp->ki_pid, cntp));
+	case PROCSTAT_CORE:
+		warnx("core method is not supported");
+		return (NULL);
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (NULL);
+	}
+}
+
+void
+procstat_freekstack(struct procstat *procstat __unused,
+    struct kinfo_kstack *kkstp)
+{
+
+	free(kkstp);
+}

Modified: trunk/lib/libprocstat/libprocstat.h
===================================================================
--- trunk/lib/libprocstat/libprocstat.h	2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat.h	2017-03-04 21:43:03 UTC (rev 9409)
@@ -30,6 +30,14 @@
 #define	_LIBPROCSTAT_H_
 
 /*
+ * XXX: sys/elf.h conflicts with zfs_context.h. Workaround this by not
+ * including conflicting parts when building zfs code.
+ */
+#ifndef ZFS
+#include <sys/elf.h>
+#endif
+
+/*
  * Vnode types.
  */
 #define	PS_FST_VTYPE_VNON	1
@@ -90,7 +98,10 @@
 #define	PS_FST_FFLAG_HASLOCK	0x4000
 #define	PS_FST_FFLAG_CAPABILITY	0x8000
 
+struct kinfo_kstack;
+struct kinfo_vmentry;
 struct procstat;
+struct rlimit;
 struct filestat {
 	int	fs_type;	/* Descriptor type. */
 	int	fs_flags;	/* filestat specific flags. */
@@ -146,9 +157,19 @@
 
 __BEGIN_DECLS
 void	procstat_close(struct procstat *procstat);
+void	procstat_freeargv(struct procstat *procstat);
+#ifndef ZFS
+void	procstat_freeauxv(struct procstat *procstat, Elf_Auxinfo *auxv);
+#endif
+void	procstat_freeenvv(struct procstat *procstat);
+void	procstat_freegroups(struct procstat *procstat, gid_t *groups);
+void	procstat_freekstack(struct procstat *procstat,
+    struct kinfo_kstack *kkstp);
 void	procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p);
 void	procstat_freefiles(struct procstat *procstat,
     struct filestat_list *head);
+void	procstat_freevmmap(struct procstat *procstat,
+    struct kinfo_vmentry *vmmap);
 struct filestat_list	*procstat_getfiles(struct procstat *procstat,
     struct kinfo_proc *kp, int mmapped);
 struct kinfo_proc	*procstat_getprocs(struct procstat *procstat,
@@ -163,6 +184,29 @@
     struct sockstat *sock, char *errbuf);
 int	procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
     struct vnstat *vn, char *errbuf);
+char	**procstat_getargv(struct procstat *procstat, struct kinfo_proc *p,
+    size_t nchr);
+#ifndef ZFS
+Elf_Auxinfo	*procstat_getauxv(struct procstat *procstat,
+    struct kinfo_proc *kp, unsigned int *cntp);
+#endif
+char	**procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p,
+    size_t nchr);
+gid_t	*procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned int *count);
+struct kinfo_kstack	*procstat_getkstack(struct procstat *procstat,
+    struct kinfo_proc *kp, unsigned int *count);
+int	procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp,
+    int *osrelp);
+int	procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
+    char *pathname, size_t maxlen);
+int	procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp,
+    int which, struct rlimit* rlimit);
+int	procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
+    unsigned short* umask);
+struct kinfo_vmentry	*procstat_getvmmap(struct procstat *procstat,
+    struct kinfo_proc *kp, unsigned int *count);
+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: trunk/lib/libprocstat/libprocstat_internal.h
===================================================================
--- trunk/lib/libprocstat/libprocstat_internal.h	2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat_internal.h	2017-03-04 21:43:03 UTC (rev 9409)
@@ -34,6 +34,9 @@
 	kvm_t	*kd;
 	void	*vmentries;
 	void	*files;
+	void	*argv;
+	void	*envv;
+	struct procstat_core *core;
 };
 
 #endif	/* !_LIBPROCSTAT_INTERNAL_H_ */



More information about the Midnightbsd-cvs mailing list