svn commit: r250870 - in stable/9: . lib/libprocstat

Mikolaj Golub trociny at FreeBSD.org
Tue May 21 19:04:18 UTC 2013


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 ***


More information about the svn-src-all mailing list