Return to BSD News archive
Xref: sserve comp.unix.bsd:4004 comp.bugs.4bsd:1894 Path: sserve!manuel!munnari.oz.au!network.ucsd.edu!usc!sol.ctr.columbia.edu!destroyer!uunet!zephyr.ens.tek.com!psgrain!m2xenix!agora!davidg From: davidg@agora.rain.com (David Greenman) Newsgroups: comp.unix.bsd,comp.bugs.4bsd Subject: Fixes for ps's many problems (386BSD) Message-ID: <1992Aug20.131718.28995@agora.uucp> Date: 20 Aug 92 13:17:18 GMT Sender: davidg@agora.uucp (David Greenman) Organization: Open Communications Forum Lines: 1281 I've been asked by several people to post all the patches necessary to fix the 'ps' command. If you have already installed these fixes, please note fix 2 which was not in my previous 'ps' patches. What follows are patches to ps.c and ps/nlist.c (for ps), a patch to kvm_mkdb/nlist.c, and a replacement kvm.c (patches are too large). These fix: (ps.c) 1) The Floating Exception bug when sorting by %CPU (implied with ps aux). (ps/nlist.c, kvm.c) 2) Resident memory size (RSS) and %MEM are now correct. (kvm.c) 3) Command+arguments are now properly returned if the information is available (not paged out). (kvm.c, kvm_mkdb/nlist.c) 4) Kernel namelist caching will now work as long as vers.o is the first object linked in the kernel (cgd's new Makefile.i386 will do this) This speeds up 'ps' & 'w' by about a factor of 3. --- David Greenman davidg%implode@percy.rain.com ------------------------------------------------------------------------ *** /usr/src/bin/ps/ps.c.01orig Mon Jul 1 17:54:45 1991 --- /usr/src/bin/ps/ps.c Sun Aug 9 06:45:30 1992 *************** *** 78,83 **** --- 78,84 ---- uid_t getuid(); char *ttyname(); + double getpcpu(); char dfmt[] = "pid tt state time command"; char jfmt[] = "user pid ppid pgid sess jobc state tt time command"; *** /usr/src/bin/ps/nlist.c.01orig Mon Jul 1 18:00:23 1991 --- /usr/src/bin/ps/nlist.c Fri Aug 14 10:14:51 1992 *************** *** 101,106 **** --- 101,107 ---- eval = rval = 1; } mempages -= tmp; + mempages = mempages / NBPG; #else if (kread(X_ECMX, mempages)) { (void)fprintf(stderr, "ps: ecmx: %s\n", kvm_geterr()); *** /usr/src/usr.sbin/kvm_mkdb/nlist.c.01orig Sat Apr 27 16:23:58 1991 --- /usr/src/usr.sbin/kvm_mkdb/nlist.c Wed Aug 5 03:39:37 1992 *************** *** 138,143 **** --- 138,146 ---- #ifdef vax rel_off = nbuf.n_value & ~KERNBASE; #endif + #ifdef i386 + rel_off = ((nbuf.n_value & ~KERNBASE) + CLBYTES); + #endif /* * When loaded, data is rounded to next page cluster * after text, but not in file. ------------------------------------------------------------------------ /*- * 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. */ /* * Updated for 386BSD 0.1 by David Greenman (davidg%implode@percy.rain.com) * and Paul Kranenburg (pk@cs.few.eur.nl) * 20-Aug-1992 */ #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); 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); 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; 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, ©size, 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 i386 /* See also ./sys/kern/kern_execve.c */ #define ARGSIZE (roundup(ARG_MAX, NBPG)) #endif #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)); } } #endif kp->kp_eproc.e_vm.vm_rssize = kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */ #ifdef i386 if (kp->kp_eproc.e_vm.vm_pmap.pm_pdir) { struct pde pde; u_int vaddr = (u_int)kp->kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ - ARGSIZE; klseek(kmem, (long)(&kp->kp_eproc.e_vm.vm_pmap.pm_pdir[pdei(vaddr)]), 0); if (read(kmem, (char *)&pde, sizeof pde) == sizeof pde && pde.pd_v) { struct pte pte; lseek(mem, (long)ctob(pde.pd_pfnum) + (ptei(vaddr) * sizeof pte), 0); if (read(mem, (char *)&pte, sizeof pte) == sizeof pte && 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; { #ifdef i386 /* See also ./sys/kern/kern_execve.c */ static char cmdbuf[ARGSIZE]; static union { char argc[ARGSIZE]; int argi[ARGSIZE/sizeof (int)]; } argspac; #else static char cmdbuf[CLBYTES*2]; static union { char argc[CLBYTES*2]; int argi[CLBYTES*2/sizeof (int)]; } argspac; #endif 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 { #ifdef i386 lseek(mem, (long)argaddr1, 0); if (read(mem, &argspac.argc[0], ARGSIZE) != ARGSIZE) goto bad; #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; #endif file = (char *) memf; } #ifdef i386 ip = &argspac.argi[(ARGSIZE-ARG_MAX)/sizeof (int)]; nbad = 0; for (cp = (char *)ip; cp < &argspac.argc[ARGSIZE-stkoff]; cp++) { #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; for (cp = (char *)ip; cp < &argspac.argc[CLBYTES*2-stkoff]; cp++) { #endif c = *cp; if (c == 0) { /* convert null between arguments to space */ *cp = ' '; if (*(cp+1) == 0) break; /* if null argument follows then no more args */ } else if (c < ' ' || c > 0176) { if (++nbad >= 5*(0+1)) { /* eflg -> 0 XXX */ /* limit number of bad chars to 5 */ *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) strcpy(cmdbuf, 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); }