386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 13 Jul 1992 09:20:51 +0000 (01:20 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 13 Jul 1992 09:20:51 +0000 (01:20 -0800)
Work on file usr/src/lib/libutil/kvm.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/lib/libutil/kvm.c [new file with mode: 0644]

diff --git a/usr/src/lib/libutil/kvm.c b/usr/src/lib/libutil/kvm.c
new file mode 100644 (file)
index 0000000..01d075b
--- /dev/null
@@ -0,0 +1,1176 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)kvm.c      5.18 (Berkeley) 5/7/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/ioctl.h>
+#include <sys/kinfo.h>
+#include <sys/tty.h>
+#include <machine/vmparam.h>
+#include <fcntl.h>
+#include <nlist.h>
+#include <kvm.h>
+#include <ndbm.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef SPPWAIT
+#define NEWVM
+#endif
+
+#ifdef NEWVM
+#define        btop(x)         (((unsigned)(x)) >> PGSHIFT)    /* XXX */
+#define        ptob(x)         ((caddr_t)((x) << PGSHIFT))     /* XXX */
+#include <vm/vm.h>     /* ??? kinfo_proc currently includes this*/
+#include <sys/kinfo_proc.h>
+#ifdef hp300
+#include <hp300/hp300/pte.h>
+#endif
+#else /* NEWVM */
+#include <machine/pte.h>
+#include <sys/vmmac.h>
+#include <sys/text.h>
+#endif /* NEWVM */
+
+/*
+ * files
+ */
+static const char *unixf, *memf, *kmemf, *swapf;
+static int unixx, mem, kmem, swap;
+static DBM *db;
+/*
+ * flags
+ */
+static int deadkernel;
+static int kvminit = 0;
+static int kvmfilesopen = 0;
+/*
+ * state
+ */
+static struct kinfo_proc *kvmprocbase, *kvmprocptr;
+static int kvmnprocs;
+/*
+ * u. buffer
+ */
+static union {
+       struct  user user;
+       char    upages[UPAGES][NBPG];
+} user;
+/*
+ * random other stuff
+ */
+#ifndef NEWVM
+static struct pte *Usrptmap, *usrpt;
+static struct  pte *Sysmap;
+static int     Syssize;
+#endif
+static int     dmmin, dmmax;
+static int     pcbpf;
+static int     argaddr0;       /* XXX */
+static int     argaddr1;
+static int     nswap;
+static char    *tmp;
+#if defined(hp300)
+static int     lowram;
+static struct ste *Sysseg;
+#endif
+#if defined(i386)
+static struct pde *PTD;
+#endif
+
+#define basename(cp)   ((tmp=rindex((cp), '/')) ? tmp+1 : (cp))
+#define        MAXSYMSIZE      256
+
+#if defined(hp300)
+#define pftoc(f)       ((f) - lowram)
+#define iskva(v)       (1)
+#endif
+
+#ifndef pftoc
+#define pftoc(f)       (f)
+#endif
+#ifndef iskva
+#define iskva(v)       ((u_long)(v) & KERNBASE)
+#endif
+
+static struct nlist nl[] = {
+       { "_Usrptmap" },
+#define        X_USRPTMAP      0
+       { "_usrpt" },
+#define        X_USRPT         1
+       { "_nswap" },
+#define        X_NSWAP         2
+       { "_dmmin" },
+#define        X_DMMIN         3
+       { "_dmmax" },
+#define        X_DMMAX         4
+       /*
+        * everything here and down, only if a dead kernel
+        */
+       { "_Sysmap" },
+#define        X_SYSMAP        5
+#define        X_DEADKERNEL    X_SYSMAP
+       { "_Syssize" },
+#define        X_SYSSIZE       6
+       { "_allproc" },
+#define X_ALLPROC      7
+       { "_zombproc" },
+#define X_ZOMBPROC     8
+       { "_nproc" },
+#define        X_NPROC         9
+#define        X_LAST          9
+#if defined(hp300)
+       { "_Sysseg" },
+#define        X_SYSSEG        (X_LAST+1)
+       { "_lowram" },
+#define        X_LOWRAM        (X_LAST+2)
+#endif
+#if defined(i386)
+       { "_IdlePTD" },
+#define        X_IdlePTD       (X_LAST+1)
+#endif
+       { "" },
+};
+
+static off_t Vtophys();
+static void klseek(), seterr(), setsyserr(), vstodb();
+static int getkvars(), kvm_doprocs(), kvm_init();
+
+/*
+ * returns     0 if files were opened now,
+ *             1 if files were already opened,
+ *             -1 if files could not be opened.
+ */
+kvm_openfiles(uf, mf, sf)
+       const char *uf, *mf, *sf; 
+{
+       if (kvmfilesopen)
+               return (1);
+       unixx = mem = kmem = swap = -1;
+       unixf = (uf == NULL) ? _PATH_UNIX : uf; 
+       memf = (mf == NULL) ? _PATH_MEM : mf;
+
+       if ((unixx = open(unixf, O_RDONLY, 0)) == -1) {
+               setsyserr("can't open %s", unixf);
+               goto failed;
+       }
+       if ((mem = open(memf, O_RDONLY, 0)) == -1) {
+               setsyserr("can't open %s", memf);
+               goto failed;
+       }
+       if (sf != NULL)
+               swapf = sf;
+       if (mf != NULL) {
+               deadkernel++;
+               kmemf = mf;
+               kmem = mem;
+               swap = -1;
+       } else {
+               kmemf = _PATH_KMEM;
+               if ((kmem = open(kmemf, O_RDONLY, 0)) == -1) {
+                       setsyserr("can't open %s", kmemf);
+                       goto failed;
+               }
+               swapf = (sf == NULL) ?  _PATH_DRUM : sf;
+               /*
+                * live kernel - avoid looking up nlist entries
+                * past X_DEADKERNEL.
+                */
+               nl[X_DEADKERNEL].n_name = "";
+       }
+       if (swapf != NULL && ((swap = open(swapf, O_RDONLY, 0)) == -1)) {
+               seterr("can't open %s", swapf);
+               goto failed;
+       }
+       kvmfilesopen++;
+       if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) /*XXX*/
+               return (-1);
+       return (0);
+failed:
+       kvm_close();
+       return (-1);
+}
+
+static
+kvm_init(uf, mf, sf)
+       char *uf, *mf, *sf;
+{
+       if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1)
+               return (-1);
+       if (getkvars() == -1)
+               return (-1);
+       kvminit = 1;
+
+       return (0);
+}
+
+kvm_close()
+{
+       if (unixx != -1) {
+               close(unixx);
+               unixx = -1;
+       }
+       if (kmem != -1) {
+               if (kmem != mem)
+                       close(kmem);
+               /* otherwise kmem is a copy of mem, and will be closed below */
+               kmem = -1;
+       }
+       if (mem != -1) {
+               close(mem);
+               mem = -1;
+       }
+       if (swap != -1) {
+               close(swap);
+               swap = -1;
+       }
+       if (db != NULL) {
+               dbm_close(db);
+               db = NULL;
+       }
+       kvminit = 0;
+       kvmfilesopen = 0;
+       deadkernel = 0;
+#ifndef NEWVM
+       if (Sysmap) {
+               free(Sysmap);
+               Sysmap = NULL;
+       }
+#endif
+}
+
+kvm_nlist(nl)
+       struct nlist *nl;
+{
+       datum key, data;
+       char dbname[MAXPATHLEN];
+       char dbversion[_POSIX2_LINE_MAX];
+       char kversion[_POSIX2_LINE_MAX];
+       int dbversionlen;
+       char symbuf[MAXSYMSIZE];
+       struct nlist nbuf, *n;
+       int num, did;
+
+       if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1)
+               return (-1);
+       if (deadkernel)
+               goto hard2;
+       /*
+        * initialize key datum
+        */
+       key.dptr = symbuf;
+
+       if (db != NULL)
+               goto win;       /* off to the races */
+       /*
+        * open database
+        */
+       sprintf(dbname, "%s/kvm_%s", _PATH_VARRUN, basename(unixf));
+       if ((db = dbm_open(dbname, O_RDONLY, 0)) == NULL)
+               goto hard2;
+       /*
+        * read version out of database
+        */
+       bcopy("VERSION", symbuf, sizeof ("VERSION")-1);
+       key.dsize = (sizeof ("VERSION") - 1) + 1;
+       data = dbm_fetch(db, key);
+       if (data.dptr == NULL)
+               goto hard1;
+       bcopy(data.dptr, dbversion, data.dsize);
+       dbversionlen = data.dsize;
+       /*
+        * read version string from kernel memory
+        */
+       bcopy("_version", symbuf, sizeof ("_version")-1);
+       key.dsize = (sizeof ("_version")-1) + 1;
+       data = dbm_fetch(db, key);
+       if (data.dptr == NULL)
+               goto hard1;
+       if (data.dsize != sizeof (struct nlist))
+               goto hard1;
+       bcopy(data.dptr, &nbuf, sizeof (struct nlist));
+       lseek(kmem, nbuf.n_value, 0);
+       if (read(kmem, kversion, dbversionlen) != dbversionlen)
+               goto hard1;
+       /*
+        * if they match, we win - otherwise do it the hard way
+        */
+       if (bcmp(dbversion, kversion, dbversionlen) != 0)
+               goto hard1;
+       /*
+        * getem from the database.
+        */
+win:
+       num = did = 0;
+       for (n = nl; n->n_name && n->n_name[0]; n++, num++) {
+               int len;
+               /*
+                * clear out fields from users buffer
+                */
+               n->n_type = 0;
+               n->n_other = 0;
+               n->n_desc = 0;
+               n->n_value = 0;
+               /*
+                * query db
+                */
+               if ((len = strlen(n->n_name)) > MAXSYMSIZE) {
+                       seterr("symbol too large");
+                       return (-1);
+               }
+               (void)strcpy(symbuf, n->n_name);
+               key.dsize = len + 1;
+               data = dbm_fetch(db, key);
+               if (data.dptr == NULL || data.dsize != sizeof (struct nlist))
+                       continue;
+               bcopy(data.dptr, &nbuf, sizeof (struct nlist));
+               n->n_value = nbuf.n_value;
+               n->n_type = nbuf.n_type;
+               n->n_desc = nbuf.n_desc;
+               n->n_other = nbuf.n_other;
+               did++;
+       }
+       return (num - did);
+hard1:
+       dbm_close(db);
+       db = NULL;
+hard2:
+       num = nlist(unixf, nl);
+       if (num == -1)
+               seterr("nlist (hard way) failed");
+       return (num);
+}
+
+kvm_getprocs(what, arg)
+       int what, arg;
+{
+       if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
+               return (NULL);
+       if (!deadkernel) {
+               int ret, copysize;
+
+               if ((ret = getkerninfo(what, NULL, NULL, arg)) == -1) {
+                       setsyserr("can't get estimate for kerninfo");
+                       return (-1);
+               }
+               copysize = ret;
+               if ((kvmprocbase = (struct kinfo_proc *)malloc(copysize)) 
+                    == NULL) {
+                       seterr("out of memory");
+                       return (-1);
+               }
+               if ((ret = getkerninfo(what, kvmprocbase, &copysize, 
+                    arg)) == -1) {
+                       setsyserr("can't get proc list");
+                       return (-1);
+               }
+               if (copysize % sizeof (struct kinfo_proc)) {
+                       seterr("proc size mismatch (got %d total, kinfo_proc: %d)",
+                               copysize, sizeof (struct kinfo_proc));
+                       return (-1);
+               }
+               kvmnprocs = copysize / sizeof (struct kinfo_proc);
+       } else {
+               int nproc;
+
+               if (kvm_read((void *) nl[X_NPROC].n_value, &nproc,
+                   sizeof (int)) != sizeof (int)) {
+                       seterr("can't read nproc");
+                       return (-1);
+               }
+               if ((kvmprocbase = (struct kinfo_proc *)
+                    malloc(nproc * sizeof (struct kinfo_proc))) == NULL) {
+                       seterr("out of memory (addr: %x nproc = %d)",
+                               nl[X_NPROC].n_value, nproc);
+                       return (-1);
+               }
+               kvmnprocs = kvm_doprocs(what, arg, kvmprocbase);
+               realloc(kvmprocbase, kvmnprocs * sizeof (struct kinfo_proc));
+       }
+       kvmprocptr = kvmprocbase;
+
+       return (kvmnprocs);
+}
+
+/*
+ * XXX - should NOT give up so easily - especially since the kernel
+ * may be corrupt (it died).  Should gather as much information as possible.
+ * Follows proc ptrs instead of reading table since table may go
+ * away soon.
+ */
+static
+kvm_doprocs(what, arg, buff)
+       int what, arg;
+       char *buff;
+{
+       struct proc *p, proc;
+       register char *bp = buff;
+       int i = 0;
+       int doingzomb = 0;
+       struct eproc eproc;
+       struct pgrp pgrp;
+       struct session sess;
+       struct tty tty;
+#ifndef NEWVM
+       struct text text;
+#endif
+
+       /* allproc */
+       if (kvm_read((void *) nl[X_ALLPROC].n_value, &p, 
+           sizeof (struct proc *)) != sizeof (struct proc *)) {
+               seterr("can't read allproc");
+               return (-1);
+       }
+
+again:
+       for (; p; p = proc.p_nxt) {
+               if (kvm_read(p, &proc, sizeof (struct proc)) !=
+                   sizeof (struct proc)) {
+                       seterr("can't read proc at %x", p);
+                       return (-1);
+               }
+#ifdef NEWVM
+               if (kvm_read(proc.p_cred, &eproc.e_pcred,
+                   sizeof (struct pcred)) == sizeof (struct pcred))
+                       (void) kvm_read(eproc.e_pcred.pc_ucred, &eproc.e_ucred,
+                           sizeof (struct ucred));
+               switch(ki_op(what)) {
+                       
+               case KINFO_PROC_PID:
+                       if (proc.p_pid != (pid_t)arg)
+                               continue;
+                       break;
+
+
+               case KINFO_PROC_UID:
+                       if (eproc.e_ucred.cr_uid != (uid_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_RUID:
+                       if (eproc.e_pcred.p_ruid != (uid_t)arg)
+                               continue;
+                       break;
+               }
+#else
+               switch(ki_op(what)) {
+                       
+               case KINFO_PROC_PID:
+                       if (proc.p_pid != (pid_t)arg)
+                               continue;
+                       break;
+
+
+               case KINFO_PROC_UID:
+                       if (proc.p_uid != (uid_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_RUID:
+                       if (proc.p_ruid != (uid_t)arg)
+                               continue;
+                       break;
+               }
+#endif
+               /*
+                * gather eproc
+                */
+               eproc.e_paddr = p;
+               if (kvm_read(proc.p_pgrp, &pgrp, sizeof (struct pgrp)) !=
+                   sizeof (struct pgrp)) {
+                       seterr("can't read pgrp at %x", proc.p_pgrp);
+                       return (-1);
+               }
+               eproc.e_sess = pgrp.pg_session;
+               eproc.e_pgid = pgrp.pg_id;
+               eproc.e_jobc = pgrp.pg_jobc;
+               if (kvm_read(pgrp.pg_session, &sess, sizeof (struct session))
+                  != sizeof (struct session)) {
+                       seterr("can't read session at %x", pgrp.pg_session);
+                       return (-1);
+               }
+               if ((proc.p_flag&SCTTY) && sess.s_ttyp != NULL) {
+                       if (kvm_read(sess.s_ttyp, &tty, sizeof (struct tty))
+                           != sizeof (struct tty)) {
+                               seterr("can't read tty at %x", sess.s_ttyp);
+                               return (-1);
+                       }
+                       eproc.e_tdev = tty.t_dev;
+                       eproc.e_tsess = tty.t_session;
+                       if (tty.t_pgrp != NULL) {
+                               if (kvm_read(tty.t_pgrp, &pgrp, sizeof (struct
+                                   pgrp)) != sizeof (struct pgrp)) {
+                                       seterr("can't read tpgrp at &x", 
+                                               tty.t_pgrp);
+                                       return (-1);
+                               }
+                               eproc.e_tpgid = pgrp.pg_id;
+                       } else
+                               eproc.e_tpgid = -1;
+               } else
+                       eproc.e_tdev = NODEV;
+               if (proc.p_wmesg)
+                       kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN);
+#ifdef NEWVM
+               (void) kvm_read(proc.p_vmspace, &eproc.e_vm,
+                   sizeof (struct vmspace));
+               eproc.e_xsize = eproc.e_xrssize =
+                       eproc.e_xccount = eproc.e_xswrss = 0;
+#else
+               if (proc.p_textp) {
+                       kvm_read(proc.p_textp, &text, sizeof (text));
+                       eproc.e_xsize = text.x_size;
+                       eproc.e_xrssize = text.x_rssize;
+                       eproc.e_xccount = text.x_ccount;
+                       eproc.e_xswrss = text.x_swrss;
+               } else {
+                       eproc.e_xsize = eproc.e_xrssize =
+                         eproc.e_xccount = eproc.e_xswrss = 0;
+               }
+#endif
+
+               switch(ki_op(what)) {
+
+               case KINFO_PROC_PGRP:
+                       if (eproc.e_pgid != (pid_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_TTY:
+                       if ((proc.p_flag&SCTTY) == 0 || 
+                            eproc.e_tdev != (dev_t)arg)
+                               continue;
+                       break;
+               }
+
+               i++;
+               bcopy(&proc, bp, sizeof (struct proc));
+               bp += sizeof (struct proc);
+               bcopy(&eproc, bp, sizeof (struct eproc));
+               bp+= sizeof (struct eproc);
+       }
+       if (!doingzomb) {
+               /* zombproc */
+               if (kvm_read((void *) nl[X_ZOMBPROC].n_value, &p, 
+                   sizeof (struct proc *)) != sizeof (struct proc *)) {
+                       seterr("can't read zombproc");
+                       return (-1);
+               }
+               doingzomb = 1;
+               goto again;
+       }
+
+       return (i);
+}
+
+struct proc *
+kvm_nextproc()
+{
+
+       if (!kvmprocbase && kvm_getprocs(0, 0) == -1)
+               return (NULL);
+       if (kvmprocptr >= (kvmprocbase + kvmnprocs)) {
+               seterr("end of proc list");
+               return (NULL);
+       }
+       return((struct proc *)(kvmprocptr++));
+}
+
+struct eproc *
+kvm_geteproc(p)
+       const struct proc *p;
+{
+       return ((struct eproc *)(((char *)p) + sizeof (struct proc)));
+}
+
+kvm_setproc()
+{
+       kvmprocptr = kvmprocbase;
+}
+
+kvm_freeprocs()
+{
+
+       if (kvmprocbase) {
+               free(kvmprocbase);
+               kvmprocbase = NULL;
+       }
+}
+
+#ifdef NEWVM
+struct user *
+kvm_getu(p)
+       const struct proc *p;
+{
+       register struct kinfo_proc *kp = (struct kinfo_proc *)p;
+       register int i;
+       register char *up;
+
+       if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
+               return (NULL);
+       if (p->p_stat == SZOMB) {
+               seterr("zombie process");
+               return (NULL);
+       }
+       /*
+        * Reading from swap is too complicated right now.
+        */
+       if ((p->p_flag & SLOAD) == 0)
+               return(NULL);
+       /*
+        * Read u-area one page at a time for the benefit of post-mortems
+        */
+       up = (char *) p->p_addr;
+       for (i = 0; i < UPAGES; i++) {
+               klseek(kmem, (long)up, 0);
+               if (read(kmem, user.upages[i], CLBYTES) != CLBYTES) {
+                       seterr("cant read page %x of u of pid %d from %s",
+                           up, p->p_pid, kmemf);
+                       return(NULL);
+               }
+               up += CLBYTES;
+       }
+       pcbpf = (int) btop(p->p_addr);  /* what should this be really? */
+       /*
+        * Conjure up a physical address for the arguments.
+        */
+       argaddr0 = argaddr1 = 0;
+#ifdef hp300
+       if (kp->kp_eproc.e_vm.vm_pmap.pm_ptab) {
+               struct pte pte[CLSIZE*2];
+
+               klseek(kmem,
+                   (long)&kp->kp_eproc.e_vm.vm_pmap.pm_ptab
+                   [btoc(USRSTACK-CLBYTES*2)], 0);
+               if (read(kmem, (char *)&pte, sizeof(pte)) == sizeof(pte)) {
+#if CLBYTES < 2048
+                       argaddr0 = ctob(pftoc(pte[CLSIZE*0].pg_pfnum));
+#endif
+                       argaddr1 = ctob(pftoc(pte[CLSIZE*1].pg_pfnum));
+               }
+       }
+       kp->kp_eproc.e_vm.vm_rssize =
+           kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */
+#endif
+
+#ifdef i386
+      if (kp->kp_eproc.e_vm.vm_pmap.pm_pdir) {
+              struct pde pde;
+
+              klseek(kmem,
+                      (long)(kp->kp_eproc.e_vm.vm_pmap.pm_pdir + UPTDI), 0);
+              if (read(kmem, (char *)&pde, sizeof pde) == sizeof pde &&
+                      pde.pd_v) {
+
+                      struct pte pte;
+
+                      lseek(mem, (long)ctob(pde.pd_pfnum) +
+                              (ptei(USRSTACK-CLBYTES) * sizeof pte), 0);
+                      if (read(mem, (char *)&pte, sizeof pte) == sizeof pte && \b+                               pte.pg_v) {
+                              argaddr1 = (long)ctob(pte.pg_pfnum);
+                      }
+              }
+      }
+#endif
+       return(&user.user);
+}
+#else
+struct user *
+kvm_getu(p)
+       const struct proc *p;
+{
+       struct pte *pteaddr, apte;
+       struct pte arguutl[HIGHPAGES+(CLSIZE*2)];
+       register int i;
+       int ncl;
+
+       if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
+               return (NULL);
+       if (p->p_stat == SZOMB) {
+               seterr("zombie process");
+               return (NULL);
+       }
+       if ((p->p_flag & SLOAD) == 0) {
+               if (swap < 0) {
+                       seterr("no swap");
+                       return (NULL);
+               }
+               (void) lseek(swap, (long)dtob(p->p_swaddr), 0);
+               if (read(swap, (char *)&user.user, sizeof (struct user)) != 
+                   sizeof (struct user)) {
+                       seterr("can't read u for pid %d from %s",
+                           p->p_pid, swapf);
+                       return (NULL);
+               }
+               pcbpf = 0;
+               argaddr0 = 0;
+               argaddr1 = 0;
+               return (&user.user);
+       }
+       pteaddr = &Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1];
+       klseek(kmem, (long)pteaddr, 0);
+       if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
+               seterr("can't read indir pte to get u for pid %d from %s",
+                   p->p_pid, kmemf);
+               return (NULL);
+       }
+       lseek(mem, (long)ctob(pftoc(apte.pg_pfnum+1)) - sizeof(arguutl), 0);
+       if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
+               seterr("can't read page table for u of pid %d from %s",
+                   p->p_pid, memf);
+               return (NULL);
+       }
+       if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
+               argaddr0 = ctob(pftoc(arguutl[0].pg_pfnum));
+       else
+               argaddr0 = 0;
+       if (arguutl[CLSIZE*1].pg_fod == 0 && arguutl[CLSIZE*1].pg_pfnum)
+               argaddr1 = ctob(pftoc(arguutl[CLSIZE*1].pg_pfnum));
+       else
+               argaddr1 = 0;
+       pcbpf = arguutl[CLSIZE*2].pg_pfnum;
+       ncl = (sizeof (struct user) + CLBYTES - 1) / CLBYTES;
+       while (--ncl >= 0) {
+               i = ncl * CLSIZE;
+               lseek(mem,
+                     (long)ctob(pftoc(arguutl[(CLSIZE*2)+i].pg_pfnum)), 0);
+               if (read(mem, user.upages[i], CLBYTES) != CLBYTES) {
+                       seterr("can't read page %d of u of pid %d from %s",
+                           arguutl[(CLSIZE*2)+i].pg_pfnum, p->p_pid, memf);
+                       return(NULL);
+               }
+       }
+       return (&user.user);
+}
+#endif
+
+char *
+kvm_getargs(p, up)
+       const struct proc *p;
+       const struct user *up;
+{
+       static char cmdbuf[CLBYTES*2];
+       static union {
+               char    argc[CLBYTES*2];
+               int     argi[CLBYTES*2/sizeof (int)];
+       } argspac;
+       register char *cp;
+       register int *ip;
+       char c;
+       int nbad;
+#ifndef NEWVM
+       struct dblock db;
+#endif
+       const char *file;
+       int stkoff = 0;
+
+#if defined(NEWVM) && defined(hp300)
+       stkoff = 20;                    /* XXX for sigcode */
+#endif
+       if (up == NULL || p->p_pid == 0 || p->p_pid == 2)
+               goto retucomm;
+       if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) {
+#ifdef NEWVM
+               goto retucomm;  /* XXX for now */
+#else
+               if (swap < 0 || p->p_ssize == 0)
+                       goto retucomm;
+               vstodb(0, CLSIZE, &up->u_smap, &db, 1);
+               (void) lseek(swap, (long)dtob(db.db_base), 0);
+               if (read(swap, (char *)&argspac.argc[CLBYTES], CLBYTES)
+                       != CLBYTES)
+                       goto bad;
+               vstodb(1, CLSIZE, &up->u_smap, &db, 1);
+               (void) lseek(swap, (long)dtob(db.db_base), 0);
+               if (read(swap, (char *)&argspac.argc[0], CLBYTES) != CLBYTES)
+                       goto bad;
+               file = swapf;
+#endif
+       } else {
+               if (argaddr0) {
+                       lseek(mem, (long)argaddr0, 0);
+                       if (read(mem, (char *)&argspac, CLBYTES) != CLBYTES)
+                               goto bad;
+               } else
+                       bzero(&argspac, CLBYTES);
+               lseek(mem, (long)argaddr1, 0);
+               if (read(mem, &argspac.argc[CLBYTES], CLBYTES) != CLBYTES)
+                       goto bad;
+               file = (char *) memf;
+       }
+#ifdef i386
+       ip = &argspac.argi[(CLBYTES + CLBYTES/2)/sizeof (int)];
+#else
+       ip = &argspac.argi[CLBYTES*2/sizeof (int)];
+       ip -= 2;                /* last arg word and .long 0 */
+       ip -= stkoff / sizeof (int);
+       while (*--ip) {
+               if (ip == argspac.argi)
+                       goto retucomm;
+       }
+       *(char *)ip = ' ';
+       ip++;
+       nbad = 0;
+#endif
+       for (cp = (char *)ip; cp < &argspac.argc[CLBYTES*2-stkoff]; cp++) {
+               c = *cp & 0177;
+               if (c == 0)
+                       *cp = ' ';
+               else if (c < ' ' || c > 0176) {
+                       if (++nbad >= 5*(0+1)) {        /* eflg -> 0 XXX */
+                               *cp++ = ' ';
+                               break;
+                       }
+                       *cp = '?';
+               } else if (0 == 0 && c == '=') {        /* eflg -> 0 XXX */
+                       while (*--cp != ' ')
+                               if (cp <= (char *)ip)
+                                       break;
+                       break;
+               }
+       }
+       *cp = 0;
+       while (*--cp == ' ')
+               *cp = 0;
+       cp = (char *)ip;
+       (void) strncpy(cmdbuf, cp, &argspac.argc[CLBYTES*2] - cp);
+       if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
+               (void) strcat(cmdbuf, " (");
+               (void) strncat(cmdbuf, p->p_comm, sizeof(p->p_comm));
+               (void) strcat(cmdbuf, ")");
+       }
+       return (cmdbuf);
+
+bad:
+       seterr("error locating command name for pid %d from %s",
+           p->p_pid, file);
+retucomm:
+       (void) strcpy(cmdbuf, " (");
+       (void) strncat(cmdbuf, p->p_comm, sizeof (p->p_comm));
+       (void) strcat(cmdbuf, ")");
+       return (cmdbuf);
+}
+
+
+static
+getkvars()
+{
+       if (kvm_nlist(nl) == -1)
+               return (-1);
+       if (deadkernel) {
+               /* We must do the sys map first because klseek uses it */
+               long    addr;
+
+#ifndef NEWVM
+               Syssize = nl[X_SYSSIZE].n_value;
+               Sysmap = (struct pte *)
+                       calloc((unsigned) Syssize, sizeof (struct pte));
+               if (Sysmap == NULL) {
+                       seterr("out of space for Sysmap");
+                       return (-1);
+               }
+               addr = (long) nl[X_SYSMAP].n_value;
+               addr &= ~KERNBASE;
+               (void) lseek(kmem, addr, 0);
+               if (read(kmem, (char *) Sysmap, Syssize * sizeof (struct pte))
+                   != Syssize * sizeof (struct pte)) {
+                       seterr("can't read Sysmap");
+                       return (-1);
+               }
+#endif
+#if defined(hp300)
+               addr = (long) nl[X_LOWRAM].n_value;
+               (void) lseek(kmem, addr, 0);
+               if (read(kmem, (char *) &lowram, sizeof (lowram))
+                   != sizeof (lowram)) {
+                       seterr("can't read lowram");
+                       return (-1);
+               }
+               lowram = btop(lowram);
+               Sysseg = (struct ste *) malloc(NBPG);
+               if (Sysseg == NULL) {
+                       seterr("out of space for Sysseg");
+                       return (-1);
+               }
+               addr = (long) nl[X_SYSSEG].n_value;
+               (void) lseek(kmem, addr, 0);
+               read(kmem, (char *)&addr, sizeof(addr));
+               (void) lseek(kmem, (long)addr, 0);
+               if (read(kmem, (char *) Sysseg, NBPG) != NBPG) {
+                       seterr("can't read Sysseg");
+                       return (-1);
+               }
+#endif
+#if defined(i386)
+               PTD = (struct pde *) malloc(NBPG);
+               if (PTD == NULL) {
+                       seterr("out of space for PTD");
+                       return (-1);
+               }
+               addr = (long) nl[X_IdlePTD].n_value;
+               (void) lseek(kmem, addr, 0);
+               read(kmem, (char *)&addr, sizeof(addr));
+               (void) lseek(kmem, (long)addr, 0);
+               if (read(kmem, (char *) PTD, NBPG) != NBPG) {
+                       seterr("can't read PTD");
+                       return (-1);
+               }
+#endif
+       }
+#ifndef NEWVM
+       usrpt = (struct pte *)nl[X_USRPT].n_value;
+       Usrptmap = (struct pte *)nl[X_USRPTMAP].n_value;
+#endif
+       if (kvm_read((void *) nl[X_NSWAP].n_value, &nswap, sizeof (long)) !=
+           sizeof (long)) {
+               seterr("can't read nswap");
+               return (-1);
+       }
+       if (kvm_read((void *) nl[X_DMMIN].n_value, &dmmin, sizeof (long)) !=
+           sizeof (long)) {
+               seterr("can't read dmmin");
+               return (-1);
+       }
+       if (kvm_read((void *) nl[X_DMMAX].n_value, &dmmax, sizeof (long)) !=
+           sizeof (long)) {
+               seterr("can't read dmmax");
+               return (-1);
+       }
+       return (0);
+}
+
+kvm_read(loc, buf, len)
+       void *loc;
+       void *buf;
+{
+       if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1)
+               return (-1);
+       if (iskva(loc)) {
+               klseek(kmem, (off_t) loc, 0);
+               if (read(kmem, buf, len) != len) {
+                       seterr("error reading kmem at %x", loc);
+                       return (-1);
+               }
+       } else {
+               lseek(mem, (off_t) loc, 0);
+               if (read(mem, buf, len) != len) {
+                       seterr("error reading mem at %x", loc);
+                       return (-1);
+               }
+       }
+       return (len);
+}
+
+static void
+klseek(fd, loc, off)
+       int fd;
+       off_t loc;
+       int off;
+{
+
+       if (deadkernel) {
+               if ((loc = Vtophys(loc)) == -1)
+                       return;
+       }
+       (void) lseek(fd, (off_t)loc, off);
+}
+
+#ifndef NEWVM
+/*
+ * Given a base/size pair in virtual swap area,
+ * return a physical base/size pair which is the
+ * (largest) initial, physically contiguous block.
+ */
+static void
+vstodb(vsbase, vssize, dmp, dbp, rev)
+       register int vsbase;
+       int vssize;
+       struct dmap *dmp;
+       register struct dblock *dbp;
+{
+       register int blk = dmmin;
+       register swblk_t *ip = dmp->dm_map;
+
+       vsbase = ctod(vsbase);
+       vssize = ctod(vssize);
+       if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
+               /*panic("vstodb")*/;
+       while (vsbase >= blk) {
+               vsbase -= blk;
+               if (blk < dmmax)
+                       blk *= 2;
+               ip++;
+       }
+       if (*ip <= 0 || *ip + blk > nswap)
+               /*panic("vstodb")*/;
+       dbp->db_size = MIN(vssize, blk - vsbase);
+       dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
+}
+#endif
+
+#ifdef NEWVM
+static off_t
+Vtophys(loc)
+       u_long  loc;
+{
+       off_t newloc = (off_t) -1;
+#ifdef hp300
+       int p, ste, pte;
+
+       ste = *(int *)&Sysseg[loc >> SG_ISHIFT];
+       if ((ste & SG_V) == 0) {
+               seterr("vtophys: segment not valid");
+               return((off_t) -1);
+       }
+       p = btop(loc & SG_PMASK);
+       newloc = (ste & SG_FRAME) + (p * sizeof(struct pte));
+       (void) lseek(kmem, (long)(newloc-(off_t)ptob(lowram)), 0);
+       if (read(kmem, (char *)&pte, sizeof pte) != sizeof pte) {
+               seterr("vtophys: cannot locate pte");
+               return((off_t) -1);
+       }
+       newloc = pte & PG_FRAME;
+       if (pte == PG_NV || newloc < (off_t)ptob(lowram)) {
+               seterr("vtophys: page not valid");
+               return((off_t) -1);
+       }
+       newloc = (newloc - (off_t)ptob(lowram)) + (loc & PGOFSET);
+#endif
+#ifdef i386
+       struct pde pde;
+       struct pte pte;
+       int p;
+
+       pde = PTD[loc >> PD_SHIFT];
+       if (pde.pd_v == 0) {
+               seterr("vtophys: page directory entry not valid");
+               return((off_t) -1);
+       }
+       p = btop(loc & PT_MASK);
+       newloc = pde.pd_pfnum + (p * sizeof(struct pte));
+       (void) lseek(kmem, (long)newloc, 0);
+       if (read(kmem, (char *)&pte, sizeof pte) != sizeof pte) {
+               seterr("vtophys: cannot obtain desired pte");
+               return((off_t) -1);
+       }
+       newloc = pte.pg_pfnum;
+       if (pte.pg_v == 0) {
+               seterr("vtophys: page table entry not valid");
+               return((off_t) -1);
+       }
+       newloc += (loc & PGOFSET);
+#endif
+       return((off_t) newloc);
+}
+#else
+static off_t
+vtophys(loc)
+       long loc;
+{
+       int p;
+       off_t newloc;
+       register struct pte *pte;
+
+       newloc = loc & ~KERNBASE;
+       p = btop(newloc);
+#if defined(vax) || defined(tahoe)
+       if ((loc & KERNBASE) == 0) {
+               seterr("vtophys: translating non-kernel address");
+               return((off_t) -1);
+       }
+#endif
+       if (p >= Syssize) {
+               seterr("vtophys: page out of bound (%d>=%d)", p, Syssize);
+               return((off_t) -1);
+       }
+       pte = &Sysmap[p];
+       if (pte->pg_v == 0 && (pte->pg_fod || pte->pg_pfnum == 0)) {
+               seterr("vtophys: page not valid");
+               return((off_t) -1);
+       }
+#if defined(hp300)
+       if (pte->pg_pfnum < lowram) {
+               seterr("vtophys: non-RAM page (%d<%d)", pte->pg_pfnum, lowram);
+               return((off_t) -1);
+       }
+#endif
+       loc = (long) (ptob(pftoc(pte->pg_pfnum)) + (loc & PGOFSET));
+       return(loc);
+}
+#endif
+
+#include <varargs.h>
+static char errbuf[_POSIX2_LINE_MAX];
+
+static void
+seterr(va_alist)
+       va_dcl
+{
+       char *fmt;
+       va_list ap;
+
+       va_start(ap);
+       fmt = va_arg(ap, char *);
+       (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap);
+       va_end(ap);
+}
+
+static void
+setsyserr(va_alist)
+       va_dcl
+{
+       char *fmt, *cp;
+       va_list ap;
+       extern int errno;
+
+       va_start(ap);
+       fmt = va_arg(ap, char *);
+       (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap);
+       for (cp=errbuf; *cp; cp++)
+               ;
+       snprintf(cp, _POSIX2_LINE_MAX - (cp - errbuf), ": %s", strerror(errno));
+       va_end(ap);
+}
+
+char *
+kvm_geterr()
+{
+       return (errbuf);
+}