summaryrefslogtreecommitdiff
path: root/lib/libutil
diff options
context:
space:
mode:
authorcgd <cgd@NetBSD.org>1993-04-10 15:02:41 +0000
committercgd <cgd@NetBSD.org>1993-04-10 15:02:41 +0000
commitea0119db7175e2c2cbc3e64ec039b27cc6bfc723 (patch)
tree2e02db615785df41522348cdf17dadefbc77e5bc /lib/libutil
parenta3a1e40463fd1c63c2d49beb80d2a2aa78baedc5 (diff)
From: pk@cs.few.eur.nl (Paul Kranenburg)
patch which allows ps(1) and w(1) to lay their hands on process command line arguments.
Diffstat (limited to 'lib/libutil')
-rw-r--r--lib/libutil/kvm.c335
1 files changed, 300 insertions, 35 deletions
diff --git a/lib/libutil/kvm.c b/lib/libutil/kvm.c
index f3c793f6166..be4da345960 100644
--- a/lib/libutil/kvm.c
+++ b/lib/libutil/kvm.c
@@ -74,6 +74,8 @@ static char sccsid[] = "@(#)kvm.c 5.18 (Berkeley) 5/7/91";
#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 <vm/vm_page.h>
+#include <vm/swap_pager.h>
#include <sys/kinfo_proc.h>
#ifdef hp300
#include <hp300/hp300/pte.h>
@@ -108,6 +110,13 @@ static union {
struct user user;
char upages[UPAGES][NBPG];
} user;
+
+#ifdef NEWVM
+struct swapblk {
+ long offset; /* offset in swap device */
+ long size; /* remaining size of block in swap device */
+};
+#endif
/*
* random other stuff
*/
@@ -120,6 +129,7 @@ static int dmmin, dmmax;
static int pcbpf;
static int argaddr0; /* XXX */
static int argaddr1;
+static int swaddr;
static int nswap;
static char *tmp;
#if defined(hp300)
@@ -156,21 +166,27 @@ static struct nlist nl[] = {
#define X_DMMIN 3
{ "_dmmax" },
#define X_DMMAX 4
+ { "_vm_page_buckets" },
+#define X_VM_PAGE_BUCKETS 5
+ { "_vm_page_hash_mask" },
+#define X_VM_PAGE_HASH_MASK 6
+ { "_page_shift" },
+#define X_PAGE_SHIFT 7
/*
* everything here and down, only if a dead kernel
*/
{ "_Sysmap" },
-#define X_SYSMAP 5
+#define X_SYSMAP 8
#define X_DEADKERNEL X_SYSMAP
{ "_Syssize" },
-#define X_SYSSIZE 6
+#define X_SYSSIZE 9
{ "_allproc" },
-#define X_ALLPROC 7
+#define X_ALLPROC 10
{ "_zombproc" },
-#define X_ZOMBPROC 8
+#define X_ZOMBPROC 11
{ "_nproc" },
-#define X_NPROC 9
-#define X_LAST 9
+#define X_NPROC 12
+#define X_LAST 12
#if defined(hp300)
{ "_Sysseg" },
#define X_SYSSEG (X_LAST+1)
@@ -187,6 +203,10 @@ static struct nlist nl[] = {
static off_t Vtophys();
static void klseek(), seterr(), setsyserr(), vstodb();
static int getkvars(), kvm_doprocs(), kvm_init();
+#ifdef NEWVM
+static int vatosw();
+static int findpage();
+#endif
/*
* returns 0 if files were opened now,
@@ -396,6 +416,8 @@ hard2:
kvm_getprocs(what, arg)
int what, arg;
{
+ static int ocopysize = -1;
+
if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
return (NULL);
if (!deadkernel) {
@@ -406,11 +428,13 @@ kvm_getprocs(what, arg)
return (-1);
}
copysize = ret;
- if ((kvmprocbase = (struct kinfo_proc *)malloc(copysize))
- == NULL) {
+ if (copysize > ocopysize &&
+ (kvmprocbase = (struct kinfo_proc *)malloc(copysize))
+ == NULL) {
seterr("out of memory");
return (-1);
}
+ ocopysize = copysize;
if ((ret = getkerninfo(what, kvmprocbase, &copysize,
arg)) == -1) {
setsyserr("can't get proc list");
@@ -662,6 +686,8 @@ kvm_getu(p)
register struct kinfo_proc *kp = (struct kinfo_proc *)p;
register int i;
register char *up;
+ u_int vaddr;
+ struct swapblk swb;
if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
return (NULL);
@@ -669,11 +695,49 @@ kvm_getu(p)
seterr("zombie process");
return (NULL);
}
- /*
- * Reading from swap is too complicated right now.
- */
- if ((p->p_flag & SLOAD) == 0)
- return(NULL);
+
+ argaddr0 = argaddr1 = swaddr = 0;
+ if ((p->p_flag & SLOAD) == 0) {
+ vm_offset_t maddr;
+
+ if (swap < 0) {
+ seterr("no swap");
+ return (NULL);
+ }
+ /*
+ * Costly operation, better set enable_swap to zero
+ * in vm/vm_glue.c, since paging of user pages isn't
+ * done yet anyway.
+ */
+ if (vatosw(p, USRSTACK + i * NBPG, &maddr, &swb) == 0)
+ return NULL;
+
+ if (maddr == 0 && swb.size < UPAGES * NBPG)
+ return NULL;
+
+ for (i = 0; i < UPAGES; i++) {
+ if (maddr) {
+ (void) lseek(mem, maddr + i * NBPG, 0);
+ if (read(mem,
+ (char *)user.upages[i], NBPG) != NBPG) {
+ seterr(
+ "can't read u for pid %d from %s",
+ p->p_pid, swapf);
+ return NULL;
+ }
+ } else {
+ (void) lseek(swap, swb.offset + i * NBPG, 0);
+ if (read(swap,
+ (char *)user.upages[i], NBPG) != NBPG) {
+ seterr(
+ "can't read u for pid %d from %s",
+ p->p_pid, swapf);
+ return NULL;
+ }
+ }
+ }
+ return(&user.user);
+ }
/*
* Read u-area one page at a time for the benefit of post-mortems
*/
@@ -691,7 +755,6 @@ kvm_getu(p)
/*
* 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];
@@ -706,41 +769,48 @@ kvm_getu(p)
argaddr1 = ctob(pftoc(pte[CLSIZE*1].pg_pfnum));
}
}
-#endif /* 08 Sep 92*/
+#endif
kp->kp_eproc.e_vm.vm_rssize =
kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */
+ vaddr = (u_int)kp->kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ - ARGSIZE;
+
#ifdef i386
if (kp->kp_eproc.e_vm.vm_pmap.pm_pdir) {
struct pde pde;
- /* u_int vaddr = USRSTACK-ARGSIZE;*/
-/* 08 Sep 92*/ u_int vaddr = (u_int)kp->kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ - ARGSIZE;
- /* 08 Sep 92 ---------
- if ((u_int)kp->kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ < USRSTACK)
- vaddr -= MAXSSIZ;
- */
-#if 0
- klseek(kmem,
- (long)(kp->kp_eproc.e_vm.vm_pmap.pm_pdir + UPTDI), 0);
-#else
klseek(kmem,
(long)(&kp->kp_eproc.e_vm.vm_pmap.pm_pdir[pdei(vaddr)]), 0);
-#endif
+
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);
+ if (lseek(mem, (long)ctob(pde.pd_pfnum) +
+ (ptei(vaddr) * sizeof pte), 0) == -1)
+ seterr("kvm_getu: lseek");
+ if (read(mem, (char *)&pte, sizeof pte) == sizeof pte) {
+ if (pte.pg_v) {
+ argaddr1 = (long)ctob(pte.pg_pfnum);
+ } else {
+ goto hard;
+ }
+ } else {
+ seterr("kvm_getu: read");
}
+ } else {
+ goto hard;
}
}
-#endif
+#endif /* i386 */
+
+hard:
+ if (vatosw(p, vaddr, &argaddr1, &swb)) {
+ if (argaddr1 == 0 && swb.size >= ARGSIZE)
+ swaddr = swb.offset;
+ }
+
return(&user.user);
}
#else
@@ -849,7 +919,23 @@ kvm_getargs(p, up)
goto retucomm;
if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) {
#ifdef NEWVM
- goto retucomm; /* XXX for now */
+ if (swaddr == 0)
+ goto retucomm; /* XXX for now */
+#ifdef i386
+ (void) lseek(swap, swaddr, 0);
+ if (read(swap, &argspac.argc[0], ARGSIZE) != ARGSIZE)
+ goto bad;
+#else
+ if (argaddr0) {
+ lseek(swap, (long)argaddr0, 0);
+ if (read(swap, (char *)&argspac, CLBYTES) != CLBYTES)
+ goto bad;
+ } else
+ bzero(&argspac, CLBYTES);
+ lseek(swap, (long)argaddr1, 0);
+ if (read(swap, &argspac.argc[CLBYTES], CLBYTES) != CLBYTES)
+ goto bad;
+#endif
#else
if (swap < 0 || p->p_ssize == 0)
goto retucomm;
@@ -882,10 +968,11 @@ kvm_getargs(p, up)
#endif
file = (char *) memf;
}
+
+ nbad = 0;
#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)];
@@ -897,7 +984,6 @@ kvm_getargs(p, up)
}
*(char *)ip = ' ';
ip++;
- nbad = 0;
for (cp = (char *)ip; cp < &argspac.argc[CLBYTES*2-stkoff]; cp++) {
#endif
@@ -1190,6 +1276,182 @@ vtophys(loc)
}
#endif
+
+#ifdef NEWVM
+/*
+ * locate address of unwired or swapped page
+ */
+
+#define DEBUG 0
+
+#define KREAD(off, addr, len) \
+ (kvm_read((void *)(off), (char *)(addr), (len)) == (len))
+
+
+static int
+vatosw(p, vaddr, maddr, swb)
+struct proc *p ;
+vm_offset_t vaddr;
+vm_offset_t *maddr;
+struct swapblk *swb;
+{
+ register struct kinfo_proc *kp = (struct kinfo_proc *)p;
+ vm_map_t mp = &kp->kp_eproc.e_vm.vm_map;
+ struct vm_object vm_object;
+ struct vm_map_entry vm_entry;
+ struct pager_struct pager;
+ struct swpager swpager;
+ struct swblock swblock;
+ long addr, off;
+ int i;
+
+ if (p->p_pid == 0 || p->p_pid == 2)
+ return 0;
+
+ addr = (long)mp->header.next;
+ for (i = 0; i < mp->nentries; i++) {
+ /* Weed through map entries until vaddr in range */
+ if (!KREAD(addr, &vm_entry, sizeof(vm_entry))) {
+ setsyserr("vatosw: read vm_map_entry");
+ return 0;
+ }
+ if ((vaddr >= vm_entry.start) && (vaddr <= vm_entry.end) &&
+ (vm_entry.object.vm_object != 0))
+ break;
+
+ addr = (long)vm_entry.next;
+ }
+ if (i == mp->nentries) {
+ seterr("%u: map not found\n", p->p_pid);
+ return 0;
+ }
+
+ if (vm_entry.is_a_map || vm_entry.is_sub_map) {
+ seterr("%u: Is a map\n", p->p_pid);
+ return 0;
+ }
+
+ /* Locate memory object */
+ off = (vaddr - vm_entry.start) + vm_entry.offset;
+ addr = (long)vm_entry.object.vm_object;
+ while (1) {
+ if (!KREAD(addr, &vm_object, sizeof vm_object)) {
+ setsyserr("vatosw: read vm_object");
+ return 0;
+ }
+
+#if DEBUG
+ fprintf(stderr, "%u: find page: object %#x offset %x\n",
+ p->p_pid, addr, off);
+#endif
+
+ /* Lookup in page queue */
+ if (findpage(addr, off, maddr))
+ return 1;
+
+ if (vm_object.shadow == 0)
+ break;
+
+#if DEBUG
+ fprintf(stderr, "%u: shadow obj at %x: offset %x+%x\n",
+ p->p_pid, addr, off, vm_object.shadow_offset);
+#endif
+
+ addr = (long)vm_object.shadow;
+ off += vm_object.shadow_offset;
+ }
+
+ if (!vm_object.pager) {
+ seterr("%u: no pager\n", p->p_pid);
+ return 0;
+ }
+
+ /* Find address in swap space */
+ if (!KREAD(vm_object.pager, &pager, sizeof pager)) {
+ setsyserr("vatosw: read pager");
+ return 0;
+ }
+ if (pager.pg_type != PG_SWAP) {
+ seterr("%u: weird pager\n", p->p_pid);
+ return 0;
+ }
+
+ /* Get swap pager data */
+ if (!KREAD(pager.pg_data, &swpager, sizeof swpager)) {
+ setsyserr("vatosw: read swpager");
+ return 0;
+ }
+
+ off += vm_object.paging_offset;
+
+ /* Read swap block array */
+ if (!KREAD((long)swpager.sw_blocks +
+ (off/dbtob(swpager.sw_bsize)) * sizeof swblock,
+ &swblock, sizeof swblock)) {
+ setsyserr("vatosw: read swblock");
+ return 0;
+ }
+ swb->offset = dbtob(swblock.swb_block)+ (off % dbtob(swpager.sw_bsize));
+ swb->size = dbtob(swpager.sw_bsize) - (off % dbtob(swpager.sw_bsize));
+ return 1;
+}
+
+
+#define atop(x) (((unsigned)(x)) >> page_shift)
+#define vm_page_hash(object, offset) \
+ (((unsigned)object+(unsigned)atop(offset))&vm_page_hash_mask)
+
+static int
+findpage(object, offset, maddr)
+long object;
+long offset;
+vm_offset_t *maddr;
+{
+static long vm_page_hash_mask;
+static long vm_page_buckets;
+static long page_shift;
+ queue_head_t bucket;
+ struct vm_page mem;
+ long addr, baddr;
+
+ if (vm_page_hash_mask == 0 && !KREAD(nl[X_VM_PAGE_HASH_MASK].n_value,
+ &vm_page_hash_mask, sizeof (long))) {
+ seterr("can't read vm_page_hash_mask");
+ return 0;
+ }
+ if (page_shift == 0 && !KREAD(nl[X_PAGE_SHIFT].n_value,
+ &page_shift, sizeof (long))) {
+ seterr("can't read page_shift");
+ return 0;
+ }
+ if (vm_page_buckets == 0 && !KREAD(nl[X_VM_PAGE_BUCKETS].n_value,
+ &vm_page_buckets, sizeof (long))) {
+ seterr("can't read vm_page_buckets");
+ return 0;
+ }
+
+ baddr = vm_page_buckets + vm_page_hash(object,offset) * sizeof(queue_head_t);
+ if (!KREAD(baddr, &bucket, sizeof (bucket))) {
+ seterr("can't read vm_page_bucket");
+ return 0;
+ }
+
+ addr = (long)bucket.next;
+ while (addr != baddr) {
+ if (!KREAD(addr, &mem, sizeof (mem))) {
+ seterr("can't read vm_page");
+ return 0;
+ }
+ if ((long)mem.object == object && mem.offset == offset) {
+ *maddr = (long)mem.phys_addr;
+ return 1;
+ }
+ addr = (long)mem.hashq.next;
+ }
+ return 0;
+}
+#endif /* NEWVM */
+
#include <varargs.h>
static char errbuf[_POSIX2_LINE_MAX];
@@ -1203,6 +1465,9 @@ seterr(va_alist)
va_start(ap);
fmt = va_arg(ap, char *);
(void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap);
+#if DEBUG
+ (void) vfprintf(stderr, fmt, ap);
+#endif
va_end(ap);
}