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-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to