kvm_proc.c revision 76176
152942Sbrian/*-
252942Sbrian * Copyright (c) 1989, 1992, 1993
352942Sbrian *	The Regents of the University of California.  All rights reserved.
452942Sbrian *
552942Sbrian * This code is derived from software developed by the Computer Systems
652942Sbrian * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
752942Sbrian * BG 91-66 and contributed to Berkeley.
852942Sbrian *
952942Sbrian * Redistribution and use in source and binary forms, with or without
1052942Sbrian * modification, are permitted provided that the following conditions
1152942Sbrian * are met:
1252942Sbrian * 1. Redistributions of source code must retain the above copyright
1352942Sbrian *    notice, this list of conditions and the following disclaimer.
1452942Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1552942Sbrian *    notice, this list of conditions and the following disclaimer in the
1652942Sbrian *    documentation and/or other materials provided with the distribution.
1752942Sbrian * 3. All advertising materials mentioning features or use of this software
1852942Sbrian *    must display the following acknowledgement:
1952942Sbrian *	This product includes software developed by the University of
2052942Sbrian *	California, Berkeley and its contributors.
2152942Sbrian * 4. Neither the name of the University nor the names of its contributors
2252942Sbrian *    may be used to endorse or promote products derived from this software
2352942Sbrian *    without specific prior written permission.
2452942Sbrian *
2552942Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2652942Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2752942Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2852942Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2952942Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3052942Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3152942Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3252942Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3352942Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3452942Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3552942Sbrian * SUCH DAMAGE.
3652942Sbrian *
3774916Sbrian * $FreeBSD: head/lib/libkvm/kvm_proc.c 76176 2001-05-01 09:24:15Z markm $
3874916Sbrian */
3952942Sbrian
4052942Sbrian#if defined(LIBC_SCCS) && !defined(lint)
4152942Sbrianstatic char sccsid[] = "@(#)kvm_proc.c	8.3 (Berkeley) 9/23/93";
4252942Sbrian#endif /* LIBC_SCCS and not lint */
4352942Sbrian
4452942Sbrian/*
4552942Sbrian * Proc traversal interface for kvm.  ps and w are (probably) the exclusive
4652942Sbrian * users of this code, so we've factored it out into a separate module.
4752942Sbrian * Thus, we keep this grunge out of the other kvm applications (i.e.,
4852942Sbrian * most other applications are interested only in open/close/read/nlist).
4952942Sbrian */
5052942Sbrian
5152942Sbrian#include <sys/param.h>
5271006Sbrian#include <sys/lock.h>
5352942Sbrian#include <sys/mutex.h>
5452942Sbrian#include <sys/user.h>
5552942Sbrian#include <sys/proc.h>
5696582Sbrian#include <sys/exec.h>
5752942Sbrian#include <sys/stat.h>
5852942Sbrian#include <sys/ioctl.h>
5952942Sbrian#include <sys/tty.h>
6052942Sbrian#include <sys/file.h>
6152942Sbrian#include <stdio.h>
6252942Sbrian#include <stdlib.h>
6352942Sbrian#include <unistd.h>
6452942Sbrian#include <nlist.h>
6552942Sbrian#include <kvm.h>
6652942Sbrian
6752942Sbrian#include <vm/vm.h>
6852942Sbrian#include <vm/vm_param.h>
6952942Sbrian#include <vm/swap_pager.h>
7052942Sbrian
7152942Sbrian#include <sys/sysctl.h>
7252942Sbrian
7352942Sbrian#include <limits.h>
7452942Sbrian#include <memory.h>
7552942Sbrian#include <paths.h>
7652942Sbrian
7752942Sbrian#include "kvm_private.h"
7852942Sbrian
7952942Sbrian#if used
8052942Sbrianstatic char *
8152942Sbriankvm_readswap(kd, p, va, cnt)
8252942Sbrian	kvm_t *kd;
8381634Sbrian	const struct proc *p;
8481634Sbrian	u_long va;
8552942Sbrian	u_long *cnt;
8652942Sbrian{
8752942Sbrian#ifdef __FreeBSD__
8852942Sbrian	/* XXX Stubbed out, our vm system is differnet */
8952942Sbrian	_kvm_err(kd, kd->program, "kvm_readswap not implemented");
9081634Sbrian	return(0);
9181634Sbrian#endif	/* __FreeBSD__ */
9252942Sbrian}
9352942Sbrian#endif
9474916Sbrian
9596582Sbrian#define KREAD(kd, addr, obj) \
9652942Sbrian	(kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
9752942Sbrian
9852942Sbrian/*
9952942Sbrian * Read proc's from memory file into buffer bp, which has space to hold
10052942Sbrian * at most maxcnt procs.
10152942Sbrian */
10252942Sbrianstatic int
10352942Sbriankvm_proclist(kd, what, arg, p, bp, maxcnt)
10452942Sbrian	kvm_t *kd;
10552942Sbrian	int what, arg;
10652942Sbrian	struct proc *p;
10796582Sbrian	struct kinfo_proc *bp;
10852942Sbrian	int maxcnt;
10952942Sbrian{
11052942Sbrian	register int cnt = 0;
11152942Sbrian	struct kinfo_proc kinfo_proc, *kp;
11252942Sbrian	struct pgrp pgrp;
11352942Sbrian	struct session sess;
11452942Sbrian	struct tty tty;
11552942Sbrian	struct vmspace vmspace;
11652942Sbrian	struct procsig procsig;
11752942Sbrian	struct pcred pcred;
11852942Sbrian	struct pstats pstats;
11952942Sbrian	struct ucred ucred;
12052942Sbrian	struct proc proc;
12152942Sbrian	struct proc pproc;
12252942Sbrian
12352942Sbrian	kp = &kinfo_proc;
12452942Sbrian	kp->ki_structsize = sizeof(kinfo_proc);
12552942Sbrian	for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) {
12652942Sbrian		if (KREAD(kd, (u_long)p, &proc)) {
12752942Sbrian			_kvm_err(kd, kd->program, "can't read proc at %x", p);
12852942Sbrian			return (-1);
12952942Sbrian		}
13052942Sbrian		if (KREAD(kd, (u_long)proc.p_cred, &pcred) == 0) {
13152942Sbrian			kp->ki_ruid = pcred.p_ruid;
13252942Sbrian			kp->ki_svuid = pcred.p_svuid;
13352942Sbrian			kp->ki_rgid = pcred.p_rgid;
13452942Sbrian			kp->ki_svgid = pcred.p_svgid;
13552942Sbrian			(void)(KREAD(kd, (u_long)pcred.pc_ucred, &ucred));
13652942Sbrian			kp->ki_ngroups = ucred.cr_ngroups;
13752942Sbrian			bcopy(ucred.cr_groups, kp->ki_groups,
13852942Sbrian			    NGROUPS * sizeof(gid_t));
13952942Sbrian			kp->ki_uid = ucred.cr_uid;
14052942Sbrian		}
14152942Sbrian
14252942Sbrian		switch(what) {
14352942Sbrian
14452942Sbrian		case KERN_PROC_PID:
14552942Sbrian			if (proc.p_pid != (pid_t)arg)
14652942Sbrian				continue;
14752942Sbrian			break;
14852942Sbrian
14952942Sbrian		case KERN_PROC_UID:
15052942Sbrian			if (kp->ki_uid != (uid_t)arg)
15152942Sbrian				continue;
15252942Sbrian			break;
15352942Sbrian
15452942Sbrian		case KERN_PROC_RUID:
15552942Sbrian			if (kp->ki_ruid != (uid_t)arg)
15652942Sbrian				continue;
15752942Sbrian			break;
15852942Sbrian		}
15952942Sbrian		/*
16052942Sbrian		 * We're going to add another proc to the set.  If this
16152942Sbrian		 * will overflow the buffer, assume the reason is because
16252942Sbrian		 * nprocs (or the proc list) is corrupt and declare an error.
16352942Sbrian		 */
16452942Sbrian		if (cnt >= maxcnt) {
16552942Sbrian			_kvm_err(kd, kd->program, "nprocs corrupt");
16652942Sbrian			return (-1);
16752942Sbrian		}
16852942Sbrian		/*
16952942Sbrian		 * gather kinfo_proc
17052942Sbrian		 */
17152942Sbrian		kp->ki_paddr = p;
17252942Sbrian		kp->ki_addr = proc.p_addr;
17352942Sbrian		kp->ki_args = proc.p_args;
17452942Sbrian		kp->ki_tracep = proc.p_tracep;
17552942Sbrian		kp->ki_textvp = proc.p_textvp;
17652942Sbrian		kp->ki_fd = proc.p_fd;
17752942Sbrian		kp->ki_vmspace = proc.p_vmspace;
17852942Sbrian		if (proc.p_procsig != NULL) {
17952942Sbrian			if (KREAD(kd, (u_long)proc.p_procsig, &procsig)) {
18052942Sbrian				_kvm_err(kd, kd->program,
18152942Sbrian				    "can't read procsig at %x", proc.p_procsig);
18252942Sbrian				return (-1);
18396582Sbrian			}
18496582Sbrian			kp->ki_sigignore = procsig.ps_sigignore;
18596582Sbrian			kp->ki_sigcatch = procsig.ps_sigcatch;
18696582Sbrian		}
18796582Sbrian		if ((proc.p_sflag & PS_INMEM) && proc.p_stats != NULL) {
18896582Sbrian			if (KREAD(kd, (u_long)proc.p_stats, &pstats)) {
18996582Sbrian				_kvm_err(kd, kd->program,
19096582Sbrian				    "can't read stats at %x", proc.p_stats);
19196582Sbrian				return (-1);
19252942Sbrian			}
19352942Sbrian			kp->ki_start = pstats.p_start;
19453684Sbrian			kp->ki_rusage = pstats.p_ru;
19552942Sbrian			kp->ki_childtime.tv_sec = pstats.p_cru.ru_utime.tv_sec +
19652942Sbrian			    pstats.p_cru.ru_stime.tv_sec;
19752942Sbrian			kp->ki_childtime.tv_usec =
19852942Sbrian			    pstats.p_cru.ru_utime.tv_usec +
19952942Sbrian			    pstats.p_cru.ru_stime.tv_usec;
20052942Sbrian		}
20152942Sbrian		if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) {
20252942Sbrian			_kvm_err(kd, kd->program, "can't read pgrp at %x",
20352942Sbrian				 proc.p_pgrp);
20452942Sbrian			return (-1);
20552942Sbrian		}
20652942Sbrian		if (proc.p_oppid)
20752942Sbrian			kp->ki_ppid = proc.p_oppid;
20852942Sbrian		else if (proc.p_pptr) {
20952942Sbrian			if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) {
21052942Sbrian				_kvm_err(kd, kd->program,
21152942Sbrian				    "can't read pproc at %x", proc.p_pptr);
21252942Sbrian				return (-1);
21352942Sbrian			}
21452942Sbrian			kp->ki_ppid = pproc.p_pid;
21552942Sbrian		} else
21652942Sbrian			kp->ki_ppid = 0;
21752942Sbrian		kp->ki_pgid = pgrp.pg_id;
21852942Sbrian		kp->ki_jobc = pgrp.pg_jobc;
21996582Sbrian		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
22052942Sbrian			_kvm_err(kd, kd->program, "can't read session at %x",
22152942Sbrian				pgrp.pg_session);
22266898Sbrian			return (-1);
22396582Sbrian		}
22498638Sbrian		kp->ki_sid = sess.s_sid;
22552942Sbrian		(void)memcpy(kp->ki_login, sess.s_login,
22652942Sbrian						sizeof(kp->ki_login));
22752942Sbrian		kp->ki_kiflag = sess.s_ttyvp ? KI_CTTY : 0;
22852942Sbrian		if (sess.s_leader == p)
22966898Sbrian			kp->ki_kiflag |= KI_SLEADER;
23066898Sbrian		if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) {
23166898Sbrian			if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
23266898Sbrian				_kvm_err(kd, kd->program,
23366898Sbrian					 "can't read tty at %x", sess.s_ttyp);
23499086Sbrian				return (-1);
23599086Sbrian			}
23699086Sbrian			kp->ki_tdev = tty.t_dev;
23799086Sbrian			if (tty.t_pgrp != NULL) {
23899086Sbrian				if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
23952942Sbrian					_kvm_err(kd, kd->program,
24099086Sbrian						 "can't read tpgrp at &x",
24199086Sbrian						tty.t_pgrp);
24252942Sbrian					return (-1);
24399086Sbrian				}
24499086Sbrian				kp->ki_tpgid = pgrp.pg_id;
24552942Sbrian			} else
24699086Sbrian				kp->ki_tpgid = -1;
24799086Sbrian			if (tty.t_session != NULL) {
24899086Sbrian				if (KREAD(kd, (u_long)tty.t_session, &sess)) {
24999086Sbrian					_kvm_err(kd, kd->program,
25099086Sbrian					    "can't read session at %x",
25152942Sbrian					    tty.t_session);
25299086Sbrian					return (-1);
25399086Sbrian				}
25499086Sbrian				kp->ki_tsid = sess.s_sid;
25590975Sbrian			}
25699086Sbrian		} else
25752942Sbrian			kp->ki_tdev = NODEV;
25899086Sbrian		if (proc.p_wmesg)
25999086Sbrian			(void)kvm_read(kd, (u_long)proc.p_wmesg,
26099086Sbrian			    kp->ki_wmesg, WMESGLEN);
26199086Sbrian
26299086Sbrian#ifdef sparc
26399086Sbrian		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_rssize,
26499086Sbrian		    (char *)&kp->ki_rssize,
26599086Sbrian		    sizeof(kp->ki_rssize));
26699086Sbrian		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_tsize,
26799086Sbrian		    (char *)&kp->ki_tsize,
26899086Sbrian		    3 * sizeof(kp->ki_rssize));	/* XXX */
26999086Sbrian#else
27099086Sbrian		(void)kvm_read(kd, (u_long)proc.p_vmspace,
27199086Sbrian		    (char *)&vmspace, sizeof(vmspace));
27299086Sbrian		kp->ki_size = vmspace.vm_map.size;
27399086Sbrian		kp->ki_rssize = vmspace.vm_swrss; /* XXX */
27499086Sbrian		kp->ki_swrss = vmspace.vm_swrss;
27599086Sbrian		kp->ki_tsize = vmspace.vm_tsize;
27699086Sbrian		kp->ki_dsize = vmspace.vm_dsize;
27799086Sbrian		kp->ki_ssize = vmspace.vm_ssize;
27899086Sbrian#endif
27999086Sbrian
28099086Sbrian		switch (what) {
28199086Sbrian
28299086Sbrian		case KERN_PROC_PGRP:
28399086Sbrian			if (kp->ki_pgid != (pid_t)arg)
28499086Sbrian				continue;
28599086Sbrian			break;
28699086Sbrian
28799086Sbrian		case KERN_PROC_TTY:
28899086Sbrian			if ((proc.p_flag & P_CONTROLT) == 0 ||
28999086Sbrian			     kp->ki_tdev != (dev_t)arg)
29052942Sbrian				continue;
29199086Sbrian			break;
29299086Sbrian		}
29399086Sbrian		if (proc.p_comm[0] != 0) {
29499086Sbrian			strncpy(kp->ki_comm, proc.p_comm, MAXCOMLEN);
29599086Sbrian			kp->ki_comm[MAXCOMLEN] = 0;
29699086Sbrian		}
29799086Sbrian		if (proc.p_blocked != 0) {
29899086Sbrian			kp->ki_kiflag |= KI_MTXBLOCK;
29999086Sbrian			if (proc.p_mtxname)
30099086Sbrian				(void)kvm_read(kd, (u_long)proc.p_mtxname,
30199086Sbrian				    kp->ki_mtxname, MTXNAMELEN);
30299086Sbrian			kp->ki_mtxname[MTXNAMELEN] = 0;
30399086Sbrian		}
30499086Sbrian		kp->ki_runtime = proc.p_runtime;
30599086Sbrian		kp->ki_pid = proc.p_pid;
30652942Sbrian		kp->ki_siglist = proc.p_siglist;
30799086Sbrian		kp->ki_sigmask = proc.p_sigmask;
30852942Sbrian		kp->ki_xstat = proc.p_xstat;
30952942Sbrian		kp->ki_acflag = proc.p_acflag;
31052942Sbrian		kp->ki_pctcpu = proc.p_pctcpu;
31152942Sbrian		kp->ki_estcpu = proc.p_estcpu;
31252942Sbrian		kp->ki_slptime = proc.p_slptime;
31352942Sbrian		kp->ki_swtime = proc.p_swtime;
31452942Sbrian		kp->ki_flag = proc.p_flag;
31553071Sbrian		kp->ki_sflag = proc.p_sflag;
31652942Sbrian		kp->ki_wchan = proc.p_wchan;
31752942Sbrian		kp->ki_traceflag = proc.p_traceflag;
31852942Sbrian		kp->ki_stat = proc.p_stat;
31952942Sbrian		kp->ki_pri = proc.p_pri;
32052942Sbrian		kp->ki_nice = proc.p_nice;
32152942Sbrian		kp->ki_lock = proc.p_lock;
32252942Sbrian		kp->ki_rqindex = proc.p_rqindex;
32352942Sbrian		kp->ki_oncpu = proc.p_oncpu;
32452942Sbrian		kp->ki_lastcpu = proc.p_lastcpu;
32552942Sbrian		bcopy(&kinfo_proc, bp, sizeof(kinfo_proc));
32678410Sbrian		++bp;
32753733Sbrian		++cnt;
32852942Sbrian	}
32952942Sbrian	return (cnt);
33052942Sbrian}
33152942Sbrian
33252942Sbrian/*
33352942Sbrian * Build proc info array by reading in proc list from a crash dump.
33493418Sbrian * Return number of procs read.  maxcnt is the max we will read.
33552942Sbrian */
33652942Sbrianstatic int
33752942Sbriankvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt)
33852942Sbrian	kvm_t *kd;
33952942Sbrian	int what, arg;
34096582Sbrian	u_long a_allproc;
34196582Sbrian	u_long a_zombproc;
34252942Sbrian	int maxcnt;
34352942Sbrian{
34452942Sbrian	register struct kinfo_proc *bp = kd->procbase;
34552942Sbrian	register int acnt, zcnt;
34652942Sbrian	struct proc *p;
34752942Sbrian
34852942Sbrian	if (KREAD(kd, a_allproc, &p)) {
34952942Sbrian		_kvm_err(kd, kd->program, "cannot read allproc");
35052942Sbrian		return (-1);
35152942Sbrian	}
35252942Sbrian	acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt);
35352942Sbrian	if (acnt < 0)
35452942Sbrian		return (acnt);
35552942Sbrian
35652942Sbrian	if (KREAD(kd, a_zombproc, &p)) {
35752942Sbrian		_kvm_err(kd, kd->program, "cannot read zombproc");
35852942Sbrian		return (-1);
35952942Sbrian	}
36052942Sbrian	zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt);
36152942Sbrian	if (zcnt < 0)
36252942Sbrian		zcnt = 0;
36352942Sbrian
36452942Sbrian	return (acnt + zcnt);
36552942Sbrian}
36652942Sbrian
36752942Sbrianstruct kinfo_proc *
36852942Sbriankvm_getprocs(kd, op, arg, cnt)
36952942Sbrian	kvm_t *kd;
37052942Sbrian	int op, arg;
37152942Sbrian	int *cnt;
37252942Sbrian{
37352942Sbrian	int mib[4], st, nprocs;
37452942Sbrian	size_t size;
37558028Sbrian
37652942Sbrian	if (kd->procbase != 0) {
37752942Sbrian		free((void *)kd->procbase);
37852942Sbrian		/*
37952942Sbrian		 * Clear this pointer in case this call fails.  Otherwise,
38052942Sbrian		 * kvm_close() will free it again.
38152942Sbrian		 */
38252942Sbrian		kd->procbase = 0;
38352942Sbrian	}
38452942Sbrian	if (ISALIVE(kd)) {
38552942Sbrian		size = 0;
38652942Sbrian		mib[0] = CTL_KERN;
38752942Sbrian		mib[1] = KERN_PROC;
38852942Sbrian		mib[2] = op;
38952942Sbrian		mib[3] = arg;
39052942Sbrian		st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, NULL, &size, NULL, 0);
39152942Sbrian		if (st == -1) {
39252942Sbrian			_kvm_syserr(kd, kd->program, "kvm_getprocs");
39352942Sbrian			return (0);
39458028Sbrian		}
39552942Sbrian		do {
39652942Sbrian			size += size / 10;
39752942Sbrian			kd->procbase = (struct kinfo_proc *)
39852942Sbrian			    _kvm_realloc(kd, kd->procbase, size);
39952942Sbrian			if (kd->procbase == 0)
40052942Sbrian				return (0);
40152942Sbrian			st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4,
40252942Sbrian			    kd->procbase, &size, NULL, 0);
40352942Sbrian		} while (st == -1 && errno == ENOMEM);
40452942Sbrian		if (st == -1) {
40552942Sbrian			_kvm_syserr(kd, kd->program, "kvm_getprocs");
40652942Sbrian			return (0);
40758028Sbrian		}
40852942Sbrian		if (kd->procbase->ki_structsize != sizeof(struct kinfo_proc)) {
40952942Sbrian			_kvm_err(kd, kd->program,
41052942Sbrian			    "kinfo_proc size mismatch (expected %d, got %d)",
41152942Sbrian			    sizeof(struct kinfo_proc),
41252942Sbrian			    kd->procbase->ki_structsize);
41352942Sbrian			return (0);
41452942Sbrian		}
41552942Sbrian		nprocs = size / kd->procbase->ki_structsize;
41652942Sbrian	} else {
41752942Sbrian		struct nlist nl[4], *p;
41852942Sbrian
41952942Sbrian		nl[0].n_name = "_nprocs";
42052942Sbrian		nl[1].n_name = "_allproc";
42152942Sbrian		nl[2].n_name = "_zombproc";
42252942Sbrian		nl[3].n_name = 0;
42352942Sbrian
42452942Sbrian		if (kvm_nlist(kd, nl) != 0) {
42552942Sbrian			for (p = nl; p->n_type != 0; ++p)
42652942Sbrian				;
42752942Sbrian			_kvm_err(kd, kd->program,
42852942Sbrian				 "%s: no such symbol", p->n_name);
42952942Sbrian			return (0);
43052942Sbrian		}
43152942Sbrian		if (KREAD(kd, nl[0].n_value, &nprocs)) {
43252942Sbrian			_kvm_err(kd, kd->program, "can't read nprocs");
43352942Sbrian			return (0);
43452942Sbrian		}
43552942Sbrian		size = nprocs * sizeof(struct kinfo_proc);
43652942Sbrian		kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size);
43752942Sbrian		if (kd->procbase == 0)
43852942Sbrian			return (0);
43952942Sbrian
44052942Sbrian		nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value,
44152942Sbrian				      nl[2].n_value, nprocs);
44252942Sbrian#ifdef notdef
44352942Sbrian		size = nprocs * sizeof(struct kinfo_proc);
44452942Sbrian		(void)realloc(kd->procbase, size);
44552942Sbrian#endif
44696582Sbrian	}
44774916Sbrian	*cnt = nprocs;
44852942Sbrian	return (kd->procbase);
44952942Sbrian}
45074916Sbrian
45174916Sbrianvoid
45252942Sbrian_kvm_freeprocs(kd)
45352942Sbrian	kvm_t *kd;
45452942Sbrian{
45552942Sbrian	if (kd->procbase) {
45652942Sbrian		free(kd->procbase);
45752942Sbrian		kd->procbase = 0;
45852942Sbrian	}
45952942Sbrian}
46074916Sbrian
46174916Sbrianvoid *
46252942Sbrian_kvm_realloc(kd, p, n)
46352942Sbrian	kvm_t *kd;
46452942Sbrian	void *p;
46552942Sbrian	size_t n;
46693418Sbrian{
46793418Sbrian	void *np = (void *)realloc(p, n);
46852942Sbrian
46952942Sbrian	if (np == 0) {
47052942Sbrian		free(p);
47152942Sbrian		_kvm_err(kd, kd->program, "out of memory");
47252942Sbrian	}
47352942Sbrian	return (np);
47452942Sbrian}
47552942Sbrian
47652942Sbrian#ifndef MAX
47752942Sbrian#define MAX(a, b) ((a) > (b) ? (a) : (b))
47852942Sbrian#endif
47952942Sbrian
48052942Sbrian/*
48152942Sbrian * Read in an argument vector from the user address space of process kp.
48252942Sbrian * addr if the user-space base address of narg null-terminated contiguous
48352942Sbrian * strings.  This is used to read in both the command arguments and
48452942Sbrian * environment strings.  Read at most maxcnt characters of strings.
48552942Sbrian */
48652942Sbrianstatic char **
48752942Sbriankvm_argv(kd, kp, addr, narg, maxcnt)
48852942Sbrian	kvm_t *kd;
48952942Sbrian	struct kinfo_proc *kp;
49052942Sbrian	register u_long addr;
49152942Sbrian	register int narg;
49252942Sbrian	register int maxcnt;
49352942Sbrian{
49452942Sbrian	register char *np, *cp, *ep, *ap;
49552942Sbrian	register u_long oaddr = -1;
49652942Sbrian	register int len, cc;
49752942Sbrian	register char **argv;
49852942Sbrian
49952942Sbrian	/*
50052942Sbrian	 * Check that there aren't an unreasonable number of agruments,
50152942Sbrian	 * and that the address is in user space.
50252942Sbrian	 */
50352942Sbrian	if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS)
50452942Sbrian		return (0);
50552942Sbrian
50652942Sbrian	/*
50753535Sbrian	 * kd->argv : work space for fetching the strings from the target
50852942Sbrian	 *            process's space, and is converted for returning to caller
50952942Sbrian	 */
51052942Sbrian	if (kd->argv == 0) {
51193418Sbrian		/*
51252942Sbrian		 * Try to avoid reallocs.
51352942Sbrian		 */
51452942Sbrian		kd->argc = MAX(narg + 1, 32);
51552942Sbrian		kd->argv = (char **)_kvm_malloc(kd, kd->argc *
51652942Sbrian						sizeof(*kd->argv));
51752942Sbrian		if (kd->argv == 0)
51852942Sbrian			return (0);
51952942Sbrian	} else if (narg + 1 > kd->argc) {
52052942Sbrian		kd->argc = MAX(2 * kd->argc, narg + 1);
52152942Sbrian		kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc *
52252942Sbrian						sizeof(*kd->argv));
52352942Sbrian		if (kd->argv == 0)
52452942Sbrian			return (0);
52552942Sbrian	}
52652942Sbrian	/*
52752942Sbrian	 * kd->argspc : returned to user, this is where the kd->argv
52852942Sbrian	 *              arrays are left pointing to the collected strings.
52952942Sbrian	 */
53082277Sbrian	if (kd->argspc == 0) {
53152942Sbrian		kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE);
53252942Sbrian		if (kd->argspc == 0)
53352942Sbrian			return (0);
53452942Sbrian		kd->arglen = PAGE_SIZE;
53552942Sbrian	}
53652942Sbrian	/*
53752942Sbrian	 * kd->argbuf : used to pull in pages from the target process.
53852942Sbrian	 *              the strings are copied out of here.
53952942Sbrian	 */
54052942Sbrian	if (kd->argbuf == 0) {
54152942Sbrian		kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE);
54252942Sbrian		if (kd->argbuf == 0)
54352942Sbrian			return (0);
54452942Sbrian	}
54552942Sbrian
54652942Sbrian	/* Pull in the target process'es argv vector */
54752963Sbrian	cc = sizeof(char *) * narg;
54852942Sbrian	if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc)
54952942Sbrian		return (0);
55052942Sbrian	/*
55152942Sbrian	 * ap : saved start address of string we're working on in kd->argspc
55252942Sbrian	 * np : pointer to next place to write in kd->argspc
55352942Sbrian	 * len: length of data in kd->argspc
55452942Sbrian	 * argv: pointer to the argv vector that we are hunting around the
55552942Sbrian	 *       target process space for, and converting to addresses in
55652942Sbrian	 *       our address space (kd->argspc).
55752942Sbrian	 */
55852942Sbrian	ap = np = kd->argspc;
55952942Sbrian	argv = kd->argv;
56052942Sbrian	len = 0;
56152942Sbrian	/*
56252942Sbrian	 * Loop over pages, filling in the argument vector.
56352942Sbrian	 * Note that the argv strings could be pointing *anywhere* in
56452942Sbrian	 * the user address space and are no longer contiguous.
56552942Sbrian	 * Note that *argv is modified when we are going to fetch a string
56652963Sbrian	 * that crosses a page boundary.  We copy the next part of the string
56752942Sbrian	 * into to "np" and eventually convert the pointer.
56852942Sbrian	 */
56952942Sbrian	while (argv < kd->argv + narg && *argv != 0) {
57052942Sbrian
57152942Sbrian		/* get the address that the current argv string is on */
57252942Sbrian		addr = (u_long)*argv & ~(PAGE_SIZE - 1);
57352942Sbrian
57452942Sbrian		/* is it the same page as the last one? */
57552942Sbrian		if (addr != oaddr) {
57652942Sbrian			if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) !=
57752942Sbrian			    PAGE_SIZE)
57852942Sbrian				return (0);
57993418Sbrian			oaddr = addr;
58052942Sbrian		}
58152942Sbrian
58252942Sbrian		/* offset within the page... kd->argbuf */
58352942Sbrian		addr = (u_long)*argv & (PAGE_SIZE - 1);
58452963Sbrian
58552942Sbrian		/* cp = start of string, cc = count of chars in this chunk */
58652942Sbrian		cp = kd->argbuf + addr;
58752942Sbrian		cc = PAGE_SIZE - addr;
58852942Sbrian
58952942Sbrian		/* dont get more than asked for by user process */
59052942Sbrian		if (maxcnt > 0 && cc > maxcnt - len)
59152942Sbrian			cc = maxcnt - len;
59252942Sbrian
59352942Sbrian		/* pointer to end of string if we found it in this page */
59452942Sbrian		ep = memchr(cp, '\0', cc);
59552942Sbrian		if (ep != 0)
59652942Sbrian			cc = ep - cp + 1;
59752942Sbrian		/*
59852942Sbrian		 * at this point, cc is the count of the chars that we are
59952942Sbrian		 * going to retrieve this time. we may or may not have found
60052942Sbrian		 * the end of it.  (ep points to the null if the end is known)
60152942Sbrian		 */
60252942Sbrian
60352942Sbrian		/* will we exceed the malloc/realloced buffer? */
60452942Sbrian		if (len + cc > kd->arglen) {
60552942Sbrian			register int off;
60652942Sbrian			register char **pp;
60752942Sbrian			register char *op = kd->argspc;
60852942Sbrian
60952942Sbrian			kd->arglen *= 2;
61052942Sbrian			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc,
61152942Sbrian							  kd->arglen);
61252942Sbrian			if (kd->argspc == 0)
61352942Sbrian				return (0);
61452942Sbrian			/*
61552942Sbrian			 * Adjust argv pointers in case realloc moved
61652942Sbrian			 * the string space.
61752942Sbrian			 */
61879854Sbrian			off = kd->argspc - op;
61979854Sbrian			for (pp = kd->argv; pp < argv; pp++)
62079854Sbrian				*pp += off;
62179854Sbrian			ap += off;
62279854Sbrian			np += off;
62379854Sbrian		}
62452942Sbrian		/* np = where to put the next part of the string in kd->argspc*/
62552942Sbrian		/* np is kinda redundant.. could use "kd->argspc + len" */
62668032Sbrian		memcpy(np, cp, cc);
62752942Sbrian		np += cc;	/* inc counters */
62868846Sbrian		len += cc;
62968846Sbrian
63052942Sbrian		/*
63152942Sbrian		 * if end of string found, set the *argv pointer to the
63252942Sbrian		 * saved beginning of string, and advance. argv points to
63352942Sbrian		 * somewhere in kd->argv..  This is initially relative
63452942Sbrian		 * to the target process, but when we close it off, we set
63552942Sbrian		 * it to point in our address space.
63652942Sbrian		 */
63752942Sbrian		if (ep != 0) {
63852942Sbrian			*argv++ = ap;
63952942Sbrian			ap = np;
64053062Sbrian		} else {
64153062Sbrian			/* update the address relative to the target process */
64253062Sbrian			*argv += cc;
64353062Sbrian		}
64453733Sbrian
64553733Sbrian		if (maxcnt > 0 && len >= maxcnt) {
64653733Sbrian			/*
64753733Sbrian			 * We're stopping prematurely.  Terminate the
64853733Sbrian			 * current string.
64953733Sbrian			 */
65053733Sbrian			if (ep == 0) {
65153733Sbrian				*np = '\0';
65253733Sbrian				*argv++ = ap;
65353733Sbrian			}
65453733Sbrian			break;
65553733Sbrian		}
65653733Sbrian	}
65753733Sbrian	/* Make sure argv is terminated. */
65853733Sbrian	*argv = 0;
65953733Sbrian	return (kd->argv);
66053733Sbrian}
66153733Sbrian
66296582Sbrianstatic void
66396582Sbrianps_str_a(p, addr, n)
66452942Sbrian	struct ps_strings *p;
66552942Sbrian	u_long *addr;
66671006Sbrian	int *n;
66752942Sbrian{
66871006Sbrian	*addr = (u_long)p->ps_argvstr;
66971006Sbrian	*n = p->ps_nargvstr;
67071006Sbrian}
67171006Sbrian
67252942Sbrianstatic void
67371006Sbrianps_str_e(p, addr, n)
67471006Sbrian	struct ps_strings *p;
67571006Sbrian	u_long *addr;
67671006Sbrian	int *n;
67771006Sbrian{
67852942Sbrian	*addr = (u_long)p->ps_envstr;
67952942Sbrian	*n = p->ps_nenvstr;
68052942Sbrian}
68171006Sbrian
68271006Sbrian/*
68371006Sbrian * Determine if the proc indicated by p is still active.
68471006Sbrian * This test is not 100% foolproof in theory, but chances of
68571006Sbrian * being wrong are very low.
68671006Sbrian */
68771006Sbrianstatic int
68871006Sbrianproc_verify(curkp)
68971006Sbrian	struct kinfo_proc *curkp;
69071006Sbrian{
69171006Sbrian	struct kinfo_proc newkp;
69271006Sbrian	int mib[4];
69371006Sbrian	size_t len;
69471006Sbrian
69571006Sbrian	mib[0] = CTL_KERN;
69671006Sbrian	mib[1] = KERN_PROC;
69771006Sbrian	mib[2] = KERN_PROC_PID;
69871006Sbrian	mib[3] = curkp->ki_pid;
69996582Sbrian	len = sizeof(newkp);
70096582Sbrian	if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1)
70196582Sbrian		return (0);
70296582Sbrian	return (curkp->ki_pid == newkp.ki_pid &&
70396582Sbrian	    (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB));
70496582Sbrian}
70596582Sbrian
70696582Sbrianstatic char **
70796582Sbriankvm_doargv(kd, kp, nchr, info)
70896582Sbrian	kvm_t *kd;
70996582Sbrian	struct kinfo_proc *kp;
71096582Sbrian	int nchr;
71196582Sbrian	void (*info)(struct ps_strings *, u_long *, int *);
71271006Sbrian{
71352942Sbrian	char **ap;
71452942Sbrian	u_long addr;
71552942Sbrian	int cnt;
71652942Sbrian	static struct ps_strings arginfo;
71752942Sbrian	static u_long ps_strings;
71852942Sbrian	size_t len;
71952942Sbrian
72052942Sbrian	if (ps_strings == NULL) {
72152942Sbrian		len = sizeof(ps_strings);
72252942Sbrian		if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL,
723		    0) == -1)
724			ps_strings = PS_STRINGS;
725	}
726
727	/*
728	 * Pointers are stored at the top of the user stack.
729	 */
730	if (kp->ki_stat == SZOMB ||
731	    kvm_uread(kd, kp, ps_strings, (char *)&arginfo,
732		      sizeof(arginfo)) != sizeof(arginfo))
733		return (0);
734
735	(*info)(&arginfo, &addr, &cnt);
736	if (cnt == 0)
737		return (0);
738	ap = kvm_argv(kd, kp, addr, cnt, nchr);
739	/*
740	 * For live kernels, make sure this process didn't go away.
741	 */
742	if (ap != 0 && ISALIVE(kd) && !proc_verify(kp))
743		ap = 0;
744	return (ap);
745}
746
747/*
748 * Get the command args.  This code is now machine independent.
749 */
750char **
751kvm_getargv(kd, kp, nchr)
752	kvm_t *kd;
753	const struct kinfo_proc *kp;
754	int nchr;
755{
756	int oid[4];
757	int i;
758	size_t bufsz;
759	static int buflen;
760	static char *buf, *p;
761	static char **bufp;
762	static int argc;
763
764	if (!ISALIVE(kd)) {
765		_kvm_err(kd, kd->program,
766		    "cannot read user space from dead kernel");
767		return (0);
768	}
769
770	if (!buflen) {
771		bufsz = sizeof(buflen);
772		i = sysctlbyname("kern.ps_arg_cache_limit",
773		    &buflen, &bufsz, NULL, 0);
774		if (i == -1) {
775			buflen = 0;
776		} else {
777			buf = malloc(buflen);
778			if (buf == NULL)
779				buflen = 0;
780			argc = 32;
781			bufp = malloc(sizeof(char *) * argc);
782		}
783	}
784	if (buf != NULL) {
785		oid[0] = CTL_KERN;
786		oid[1] = KERN_PROC;
787		oid[2] = KERN_PROC_ARGS;
788		oid[3] = kp->ki_pid;
789		bufsz = buflen;
790		i = sysctl(oid, 4, buf, &bufsz, 0, 0);
791		if (i == 0 && bufsz > 0) {
792			i = 0;
793			p = buf;
794			do {
795				bufp[i++] = p;
796				p += strlen(p) + 1;
797				if (i >= argc) {
798					argc += argc;
799					bufp = realloc(bufp,
800					    sizeof(char *) * argc);
801				}
802			} while (p < buf + bufsz);
803			bufp[i++] = 0;
804			return (bufp);
805		}
806	}
807	if (kp->ki_flag & P_SYSTEM)
808		return (NULL);
809	return (kvm_doargv(kd, kp, nchr, ps_str_a));
810}
811
812char **
813kvm_getenvv(kd, kp, nchr)
814	kvm_t *kd;
815	const struct kinfo_proc *kp;
816	int nchr;
817{
818	return (kvm_doargv(kd, kp, nchr, ps_str_e));
819}
820
821/*
822 * Read from user space.  The user context is given by p.
823 */
824ssize_t
825kvm_uread(kd, kp, uva, buf, len)
826	kvm_t *kd;
827	struct kinfo_proc *kp;
828	register u_long uva;
829	register char *buf;
830	register size_t len;
831{
832	register char *cp;
833	char procfile[MAXPATHLEN];
834	ssize_t amount;
835	int fd;
836
837	if (!ISALIVE(kd)) {
838		_kvm_err(kd, kd->program,
839		    "cannot read user space from dead kernel");
840		return (0);
841	}
842
843	sprintf(procfile, "/proc/%d/mem", kp->ki_pid);
844	fd = open(procfile, O_RDONLY, 0);
845	if (fd < 0) {
846		_kvm_err(kd, kd->program, "cannot open %s", procfile);
847		close(fd);
848		return (0);
849	}
850
851	cp = buf;
852	while (len > 0) {
853		errno = 0;
854		if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) {
855			_kvm_err(kd, kd->program, "invalid address (%x) in %s",
856			    uva, procfile);
857			break;
858		}
859		amount = read(fd, cp, len);
860		if (amount < 0) {
861			_kvm_syserr(kd, kd->program, "error reading %s",
862			    procfile);
863			break;
864		}
865		if (amount == 0) {
866			_kvm_err(kd, kd->program, "EOF reading %s", procfile);
867			break;
868		}
869		cp += amount;
870		uva += amount;
871		len -= amount;
872	}
873
874	close(fd);
875	return ((ssize_t)(cp - buf));
876}
877