diff options
| author | cgd <cgd@NetBSD.org> | 1993-04-10 15:02:41 +0000 |
|---|---|---|
| committer | cgd <cgd@NetBSD.org> | 1993-04-10 15:02:41 +0000 |
| commit | ea0119db7175e2c2cbc3e64ec039b27cc6bfc723 (patch) | |
| tree | 2e02db615785df41522348cdf17dadefbc77e5bc /lib/libutil | |
| parent | a3a1e40463fd1c63c2d49beb80d2a2aa78baedc5 (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.c | 335 |
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, ©size, 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); } |
