*BSD News Article 14171


Return to BSD News archive

Newsgroups: comp.os.386bsd.development
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!haven.umd.edu!uunet!mcsun!sun4nl!eur.nl!pk
From: pk@cs.few.eur.nl (Paul Kranenburg)
Subject: Command line arguments for ps(1) and w(1)
Message-ID: <1993Apr7.160932.16923@cs.few.eur.nl>
Keywords: Process status, KVM
Sender: news@cs.few.eur.nl
Reply-To: pk@cs.few.eur.nl
Organization: Erasmus University Rotterdam
Date: Wed, 7 Apr 1993 16:09:32 GMT
Lines: 594

Below is a patch (believed to be relative to kvm.c.pl2) to
`lib/libutil/kvm.c' which allows ps(1) and w(1) to lay
their hands on process command line arguments.

Thanks to David Greenman who taught me about VM shadow objects.

-pk

------------------------------------------------------------------------
*** kvm.c.orig	Wed Apr  7 16:08:05 1993
--- kvm.c	Wed Apr  7 17:30:34 1993
***************
*** 74,79 ****
--- 74,81 ----
  #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,113 ****
--- 110,122 ----
  	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,125 ****
--- 129,135 ----
  static	int	pcbpf;
  static	int	argaddr0;	/* XXX */
  static	int	argaddr1;
+ static	int	swaddr;
  static	int	nswap;
  static	char	*tmp;
  #if defined(hp300)
***************
*** 156,176 ****
  #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)
--- 166,192 ----
  #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	8
  #define	X_DEADKERNEL	X_SYSMAP
  	{ "_Syssize" },
! #define	X_SYSSIZE	9
  	{ "_allproc" },
! #define X_ALLPROC	10
  	{ "_zombproc" },
! #define X_ZOMBPROC	11
  	{ "_nproc" },
! #define	X_NPROC		12
! #define	X_LAST		12
  #if defined(hp300)
  	{ "_Sysseg" },
  #define	X_SYSSEG	(X_LAST+1)
***************
*** 187,192 ****
--- 203,212 ----
  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,401 ****
--- 416,423 ----
  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,416 ****
  			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");
--- 428,440 ----
  			return (-1);
  		}
  		copysize = ret;
! 		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,667 ****
--- 686,693 ----
  	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,680 ****
  		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;
--- 695,744 ----
  		seterr("zombie process");
  		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
  	 */
  	up = (char *) p->p_addr;
***************
*** 691,697 ****
  	/*
  	 * 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];
--- 755,760 ----
***************
*** 706,746 ****
  			argaddr1 = ctob(pftoc(pte[CLSIZE*1].pg_pfnum));
  		}
  	}
! #endif							/* 08 Sep 92*/
  	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 = 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);
  			}
  		}
  	}
! #endif
  	return(&user.user);
  }
  #else
--- 769,816 ----
  			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 */
  
+ 	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;
  
  		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;
  
! 			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	/* i386 */
! 
! hard:
! 	if (vatosw(p, vaddr, &argaddr1, &swb)) {
! 		if (argaddr1 == 0 && swb.size >= ARGSIZE)
! 			swaddr = swb.offset;
! 	}
! 
  	return(&user.user);
  }
  #else
***************
*** 849,856 ****
  		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);
--- 919,942 ----
  		goto retucomm;
  	if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) {
  #ifdef NEWVM
! 		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;
  		vstodb(0, CLSIZE, &up->u_smap, &db, 1);
***************
*** 882,891 ****
  #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)];
--- 968,978 ----
  #endif
  		file = (char *) memf;
  	}
+ 
+ 	nbad = 0;
  #ifdef i386
  	ip = &argspac.argi[(ARGSIZE-ARG_MAX)/sizeof (int)];
  
  	for (cp = (char *)ip; cp < &argspac.argc[ARGSIZE-stkoff]; cp++) {
  #else
  	ip = &argspac.argi[CLBYTES*2/sizeof (int)];
***************
*** 897,903 ****
  	}
  	*(char *)ip = ' ';
  	ip++;
- 	nbad = 0;
  
  	for (cp = (char *)ip; cp < &argspac.argc[CLBYTES*2-stkoff]; cp++) {
  #endif
--- 984,989 ----
***************
*** 1190,1195 ****
--- 1276,1457 ----
  }
  #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,1208 ****
--- 1465,1473 ----
  	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);
  }