kvm_proc.c revision 70525
138032Speter/*-
2111826Sgshapiro * Copyright (c) 1989, 1992, 1993
364565Sgshapiro *	The Regents of the University of California.  All rights reserved.
438032Speter *
538032Speter * This code is derived from software developed by the Computer Systems
638032Speter * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
738032Speter * BG 91-66 and contributed to Berkeley.
838032Speter *
938032Speter * Redistribution and use in source and binary forms, with or without
1038032Speter * modification, are permitted provided that the following conditions
1138032Speter * are met:
12120259Sgshapiro * 1. Redistributions of source code must retain the above copyright
1338032Speter *    notice, this list of conditions and the following disclaimer.
1438032Speter * 2. Redistributions in binary form must reproduce the above copyright
1564565Sgshapiro *    notice, this list of conditions and the following disclaimer in the
1664565Sgshapiro *    documentation and/or other materials provided with the distribution.
17141862Sgshapiro * 3. All advertising materials mentioning features or use of this software
1864565Sgshapiro *    must display the following acknowledgement:
1964565Sgshapiro *	This product includes software developed by the University of
2064565Sgshapiro *	California, Berkeley and its contributors.
2164565Sgshapiro * 4. Neither the name of the University nor the names of its contributors
2264565Sgshapiro *    may be used to endorse or promote products derived from this software
2338032Speter *    without specific prior written permission.
2438032Speter *
2564565Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2664565Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2764565Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2864565Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2964565Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3090795Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3164565Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3238032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3338032Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3438032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3538032Speter * SUCH DAMAGE.
3638032Speter *
3738032Speter * $FreeBSD: head/lib/libkvm/kvm_proc.c 70525 2000-12-30 21:52:34Z ben $
3838032Speter */
3938032Speter
4038032Speter#if defined(LIBC_SCCS) && !defined(lint)
4138032Speterstatic char sccsid[] = "@(#)kvm_proc.c	8.3 (Berkeley) 9/23/93";
4238032Speter#endif /* LIBC_SCCS and not lint */
4338032Speter
4438032Speter/*
4538032Speter * Proc traversal interface for kvm.  ps and w are (probably) the exclusive
4638032Speter * users of this code, so we've factored it out into a separate module.
4738032Speter * Thus, we keep this grunge out of the other kvm applications (i.e.,
4838032Speter * most other applications are interested only in open/close/read/nlist).
4938032Speter */
5038032Speter
5138032Speter#include <sys/param.h>
5238032Speter#include <sys/user.h>
5338032Speter#include <sys/proc.h>
5438032Speter#include <sys/exec.h>
5538032Speter#include <sys/stat.h>
5638032Speter#include <sys/ioctl.h>
5738032Speter#define _KERNEL
5838032Speter#include <sys/select.h>
5938032Speter#undef _KERNEL
6038032Speter#include <sys/tty.h>
6138032Speter#include <sys/file.h>
6238032Speter#include <stdio.h>
6364565Sgshapiro#include <stdlib.h>
6438032Speter#include <unistd.h>
6590795Sgshapiro#include <nlist.h>
6638032Speter#include <kvm.h>
6738032Speter
6838032Speter#include <vm/vm.h>
6938032Speter#include <vm/vm_param.h>
7038032Speter#include <vm/swap_pager.h>
7138032Speter
7238032Speter#include <sys/sysctl.h>
7338032Speter
7438032Speter#include <limits.h>
7538032Speter#include <memory.h>
7638032Speter#include <paths.h>
7738032Speter
7838032Speter#include "kvm_private.h"
7938032Speter
8038032Speter#if used
8138032Speterstatic char *
8238032Speterkvm_readswap(kd, p, va, cnt)
8338032Speter	kvm_t *kd;
8438032Speter	const struct proc *p;
8538032Speter	u_long va;
8638032Speter	u_long *cnt;
8738032Speter{
8838032Speter#ifdef __FreeBSD__
8938032Speter	/* XXX Stubbed out, our vm system is differnet */
9038032Speter	_kvm_err(kd, kd->program, "kvm_readswap not implemented");
9138032Speter	return(0);
9238032Speter#endif	/* __FreeBSD__ */
9338032Speter}
9438032Speter#endif
9538032Speter
9638032Speter#define KREAD(kd, addr, obj) \
9738032Speter	(kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
9838032Speter
9938032Speter/*
10038032Speter * Read proc's from memory file into buffer bp, which has space to hold
10138032Speter * at most maxcnt procs.
10238032Speter */
10338032Speterstatic int
10490795Sgshapirokvm_proclist(kd, what, arg, p, bp, maxcnt)
10538032Speter	kvm_t *kd;
10638032Speter	int what, arg;
10790795Sgshapiro	struct proc *p;
10890795Sgshapiro	struct kinfo_proc *bp;
10938032Speter	int maxcnt;
11038032Speter{
11164565Sgshapiro	register int cnt = 0;
11290795Sgshapiro	struct kinfo_proc kinfo_proc, *kp;
11390795Sgshapiro	struct pgrp pgrp;
11438032Speter	struct session sess;
11538032Speter	struct tty tty;
11638032Speter	struct vmspace vmspace;
11738032Speter	struct procsig procsig;
11890795Sgshapiro	struct pcred pcred;
11938032Speter	struct pstats pstats;
12038032Speter	struct ucred ucred;
12138032Speter	struct proc proc;
12238032Speter	struct proc pproc;
12338032Speter
12438032Speter	kp = &kinfo_proc;
12538032Speter	kp->ki_structsize = sizeof(kinfo_proc);
12638032Speter	for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) {
12738032Speter		if (KREAD(kd, (u_long)p, &proc)) {
12838032Speter			_kvm_err(kd, kd->program, "can't read proc at %x", p);
12938032Speter			return (-1);
13038032Speter		}
13138032Speter		if (KREAD(kd, (u_long)proc.p_cred, &pcred) == 0) {
13238032Speter			kp->ki_ruid = pcred.p_ruid;
13338032Speter			kp->ki_svuid = pcred.p_svuid;
13438032Speter			kp->ki_rgid = pcred.p_rgid;
13538032Speter			kp->ki_svgid = pcred.p_svgid;
13638032Speter			(void)(KREAD(kd, (u_long)pcred.pc_ucred, &ucred));
13738032Speter			kp->ki_ngroups = ucred.cr_ngroups;
13838032Speter			bcopy(ucred.cr_groups, kp->ki_groups,
13938032Speter			    NGROUPS * sizeof(gid_t));
14038032Speter			kp->ki_uid = ucred.cr_uid;
14138032Speter		}
14238032Speter
14338032Speter		switch(what) {
14438032Speter
14538032Speter		case KERN_PROC_PID:
14690795Sgshapiro			if (proc.p_pid != (pid_t)arg)
14764565Sgshapiro				continue;
14864565Sgshapiro			break;
14938032Speter
15038032Speter		case KERN_PROC_UID:
15138032Speter			if (kp->ki_uid != (uid_t)arg)
15238032Speter				continue;
15338032Speter			break;
15438032Speter
15538032Speter		case KERN_PROC_RUID:
15638032Speter			if (kp->ki_ruid != (uid_t)arg)
15738032Speter				continue;
15838032Speter			break;
15938032Speter		}
16038032Speter		/*
16194337Sgshapiro		 * We're going to add another proc to the set.  If this
16264565Sgshapiro		 * will overflow the buffer, assume the reason is because
16364565Sgshapiro		 * nprocs (or the proc list) is corrupt and declare an error.
16464565Sgshapiro		 */
16564565Sgshapiro		if (cnt >= maxcnt) {
16638032Speter			_kvm_err(kd, kd->program, "nprocs corrupt");
16764565Sgshapiro			return (-1);
16838032Speter		}
16964565Sgshapiro		/*
17064565Sgshapiro		 * gather kinfo_proc
17190795Sgshapiro		 */
17238032Speter		kp->ki_paddr = p;
17338032Speter		kp->ki_addr = proc.p_addr;
17438032Speter		kp->ki_args = proc.p_args;
17538032Speter		kp->ki_tracep = proc.p_tracep;
17638032Speter		kp->ki_textvp = proc.p_textvp;
17738032Speter		kp->ki_fd = proc.p_fd;
17838032Speter		kp->ki_vmspace = proc.p_vmspace;
17938032Speter		if (proc.p_procsig != NULL) {
18038032Speter			if (KREAD(kd, (u_long)proc.p_procsig, &procsig)) {
18190795Sgshapiro				_kvm_err(kd, kd->program,
18238032Speter				    "can't read procsig at %x", proc.p_procsig);
18338032Speter				return (-1);
18438032Speter			}
18538032Speter			kp->ki_sigignore = procsig.ps_sigignore;
18638032Speter			kp->ki_sigcatch = procsig.ps_sigcatch;
18738032Speter		}
18890795Sgshapiro		if ((proc.p_flag & P_INMEM) && proc.p_stats != NULL) {
18990795Sgshapiro			if (KREAD(kd, (u_long)proc.p_stats, &pstats)) {
19038032Speter				_kvm_err(kd, kd->program,
19138032Speter				    "can't read stats at %x", proc.p_stats);
19238032Speter				return (-1);
19338032Speter			}
19438032Speter			kp->ki_start = pstats.p_start;
19538032Speter			kp->ki_rusage = pstats.p_ru;
19664565Sgshapiro			kp->ki_childtime.tv_sec = pstats.p_cru.ru_utime.tv_sec +
19738032Speter			    pstats.p_cru.ru_stime.tv_sec;
19838032Speter			kp->ki_childtime.tv_usec =
19938032Speter			    pstats.p_cru.ru_utime.tv_usec +
20038032Speter			    pstats.p_cru.ru_stime.tv_usec;
20138032Speter		}
20238032Speter		if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) {
20338032Speter			_kvm_err(kd, kd->program, "can't read pgrp at %x",
20438032Speter				 proc.p_pgrp);
20538032Speter			return (-1);
20638032Speter		}
20738032Speter		if (proc.p_oppid)
20838032Speter			kp->ki_ppid = proc.p_oppid;
20938032Speter		else if (proc.p_pptr) {
21038032Speter			if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) {
21138032Speter				_kvm_err(kd, kd->program,
21238032Speter				    "can't read pproc at %x", proc.p_pptr);
21338032Speter				return (-1);
21490795Sgshapiro			}
21590795Sgshapiro			kp->ki_ppid = pproc.p_pid;
21690795Sgshapiro		} else
21738032Speter			kp->ki_ppid = 0;
21838032Speter		kp->ki_pgid = pgrp.pg_id;
21964565Sgshapiro		kp->ki_jobc = pgrp.pg_jobc;
22090795Sgshapiro		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
22190795Sgshapiro			_kvm_err(kd, kd->program, "can't read session at %x",
22238032Speter				pgrp.pg_session);
22364565Sgshapiro			return (-1);
22438032Speter		}
22538032Speter		kp->ki_sid = sess.s_sid;
22638032Speter		(void)memcpy(kp->ki_login, sess.s_login,
22738032Speter						sizeof(kp->ki_login));
22838032Speter		kp->ki_kiflag = sess.s_ttyvp ? KI_CTTY : 0;
22938032Speter		if (sess.s_leader == p)
23038032Speter			kp->ki_kiflag |= KI_SLEADER;
23138032Speter		if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) {
23238032Speter			if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
23390795Sgshapiro				_kvm_err(kd, kd->program,
23438032Speter					 "can't read tty at %x", sess.s_ttyp);
23590795Sgshapiro				return (-1);
23638032Speter			}
23738032Speter			kp->ki_tdev = tty.t_dev;
23838032Speter			if (tty.t_pgrp != NULL) {
23938032Speter				if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
24090795Sgshapiro					_kvm_err(kd, kd->program,
24138032Speter						 "can't read tpgrp at &x",
24290795Sgshapiro						tty.t_pgrp);
24338032Speter					return (-1);
24438032Speter				}
24538032Speter				kp->ki_tpgid = pgrp.pg_id;
24638032Speter			} else
24738032Speter				kp->ki_tpgid = -1;
24890795Sgshapiro			if (tty.t_session != NULL) {
24990795Sgshapiro				if (KREAD(kd, (u_long)tty.t_session, &sess)) {
25090795Sgshapiro					_kvm_err(kd, kd->program,
25190795Sgshapiro					    "can't read session at %x",
25290795Sgshapiro					    tty.t_session);
25390795Sgshapiro					return (-1);
25438032Speter				}
25590795Sgshapiro				kp->ki_tsid = sess.s_sid;
25690795Sgshapiro			}
25790795Sgshapiro		} else
25890795Sgshapiro			kp->ki_tdev = NODEV;
25990795Sgshapiro		if (proc.p_wmesg)
26090795Sgshapiro			(void)kvm_read(kd, (u_long)proc.p_wmesg,
26190795Sgshapiro			    kp->ki_wmesg, WMESGLEN);
26290795Sgshapiro
26390795Sgshapiro#ifdef sparc
26490795Sgshapiro		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_rssize,
26538032Speter		    (char *)&kp->ki_rssize,
26690795Sgshapiro		    sizeof(kp->ki_rssize));
26738032Speter		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_tsize,
26838032Speter		    (char *)&kp->ki_tsize,
26938032Speter		    3 * sizeof(kp->ki_rssize));	/* XXX */
27090795Sgshapiro#else
27190795Sgshapiro		(void)kvm_read(kd, (u_long)proc.p_vmspace,
27238032Speter		    (char *)&vmspace, sizeof(vmspace));
27338032Speter		kp->ki_size = vmspace.vm_map.size;
27438032Speter		kp->ki_rssize = vmspace.vm_swrss; /* XXX */
27538032Speter		kp->ki_swrss = vmspace.vm_swrss;
27638032Speter		kp->ki_tsize = vmspace.vm_tsize;
27738032Speter		kp->ki_dsize = vmspace.vm_dsize;
27838032Speter		kp->ki_ssize = vmspace.vm_ssize;
27938032Speter#endif
28038032Speter
28138032Speter		switch (what) {
28238032Speter
28338032Speter		case KERN_PROC_PGRP:
28438032Speter			if (kp->ki_pgid != (pid_t)arg)
28538032Speter				continue;
28638032Speter			break;
28738032Speter
28838032Speter		case KERN_PROC_TTY:
28971348Sgshapiro			if ((proc.p_flag & P_CONTROLT) == 0 ||
29038032Speter			     kp->ki_tdev != (dev_t)arg)
29138032Speter				continue;
29271348Sgshapiro			break;
29338032Speter		}
29490795Sgshapiro		if (proc.p_comm[0] != 0) {
29538032Speter			strncpy(kp->ki_comm, proc.p_comm, MAXCOMLEN);
29690795Sgshapiro			kp->ki_comm[MAXCOMLEN] = 0;
29790795Sgshapiro		}
29890795Sgshapiro		if (proc.p_blocked != 0) {
29990795Sgshapiro			kp->ki_kiflag |= KI_MTXBLOCK;
30090795Sgshapiro			if (proc.p_mtxname)
30190795Sgshapiro				(void)kvm_read(kd, (u_long)proc.p_mtxname,
30290795Sgshapiro				    kp->ki_mtxname, MTXNAMELEN);
30338032Speter			kp->ki_mtxname[MTXNAMELEN] = 0;
30438032Speter		}
30538032Speter		kp->ki_rtprio = proc.p_rtprio;
30638032Speter		kp->ki_runtime = proc.p_runtime;
30738032Speter		kp->ki_pid = proc.p_pid;
30838032Speter		kp->ki_siglist = proc.p_siglist;
30938032Speter		kp->ki_sigmask = proc.p_sigmask;
31038032Speter		kp->ki_xstat = proc.p_xstat;
31138032Speter		kp->ki_acflag = proc.p_acflag;
31238032Speter		kp->ki_pctcpu = proc.p_pctcpu;
31338032Speter		kp->ki_estcpu = proc.p_estcpu;
31438032Speter		kp->ki_slptime = proc.p_slptime;
31564565Sgshapiro		kp->ki_swtime = proc.p_swtime;
31638032Speter		kp->ki_flag = proc.p_flag;
31738032Speter		kp->ki_wchan = proc.p_wchan;
31838032Speter		kp->ki_traceflag = proc.p_traceflag;
31938032Speter		kp->ki_priority = proc.p_priority;
32038032Speter		kp->ki_usrpri = proc.p_usrpri;
32171348Sgshapiro		kp->ki_nativepri = proc.p_nativepri;
32264565Sgshapiro		kp->ki_stat = proc.p_stat;
32338032Speter		kp->ki_nice = proc.p_nice;
32438032Speter		kp->ki_lock = proc.p_lock;
32538032Speter		kp->ki_rqindex = proc.p_rqindex;
32690795Sgshapiro		kp->ki_oncpu = proc.p_oncpu;
32790795Sgshapiro		kp->ki_lastcpu = proc.p_lastcpu;
32890795Sgshapiro		bcopy(&kinfo_proc, bp, sizeof(kinfo_proc));
32990795Sgshapiro		++bp;
33090795Sgshapiro		++cnt;
33190795Sgshapiro	}
33290795Sgshapiro	return (cnt);
33390795Sgshapiro}
33490795Sgshapiro
33590795Sgshapiro/*
33690795Sgshapiro * Build proc info array by reading in proc list from a crash dump.
33790795Sgshapiro * Return number of procs read.  maxcnt is the max we will read.
33890795Sgshapiro */
33964565Sgshapirostatic int
34090795Sgshapirokvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt)
34164565Sgshapiro	kvm_t *kd;
34264565Sgshapiro	int what, arg;
34364565Sgshapiro	u_long a_allproc;
34464565Sgshapiro	u_long a_zombproc;
34564565Sgshapiro	int maxcnt;
34664565Sgshapiro{
34738032Speter	register struct kinfo_proc *bp = kd->procbase;
34838032Speter	register int acnt, zcnt;
34990795Sgshapiro	struct proc *p;
35064565Sgshapiro
35138032Speter	if (KREAD(kd, a_allproc, &p)) {
35238032Speter		_kvm_err(kd, kd->program, "cannot read allproc");
35338032Speter		return (-1);
35438032Speter	}
35538032Speter	acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt);
35638032Speter	if (acnt < 0)
35738032Speter		return (acnt);
35838032Speter
35990795Sgshapiro	if (KREAD(kd, a_zombproc, &p)) {
36038032Speter		_kvm_err(kd, kd->program, "cannot read zombproc");
36138032Speter		return (-1);
36238032Speter	}
36338032Speter	zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt);
36438032Speter	if (zcnt < 0)
36538032Speter		zcnt = 0;
36638032Speter
36738032Speter	return (acnt + zcnt);
36838032Speter}
36938032Speter
37038032Speterstruct kinfo_proc *
37138032Speterkvm_getprocs(kd, op, arg, cnt)
37238032Speter	kvm_t *kd;
37338032Speter	int op, arg;
37438032Speter	int *cnt;
37538032Speter{
37638032Speter	int mib[4], st, nprocs;
37738032Speter	size_t size;
37890795Sgshapiro
37938032Speter	if (kd->procbase != 0) {
38038032Speter		free((void *)kd->procbase);
38138032Speter		/*
38290795Sgshapiro		 * Clear this pointer in case this call fails.  Otherwise,
38390795Sgshapiro		 * kvm_close() will free it again.
38438032Speter		 */
38538032Speter		kd->procbase = 0;
38638032Speter	}
38738032Speter	if (ISALIVE(kd)) {
38838032Speter		size = 0;
38938032Speter		mib[0] = CTL_KERN;
39038032Speter		mib[1] = KERN_PROC;
39138032Speter		mib[2] = op;
39294337Sgshapiro		mib[3] = arg;
39338032Speter		st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, NULL, &size, NULL, 0);
39438032Speter		if (st == -1) {
39538032Speter			_kvm_syserr(kd, kd->program, "kvm_getprocs");
39638032Speter			return (0);
39738032Speter		}
39838032Speter		do {
39938032Speter			size += size / 10;
40038032Speter			kd->procbase = (struct kinfo_proc *)
40138032Speter			    _kvm_realloc(kd, kd->procbase, size);
40290795Sgshapiro			if (kd->procbase == 0)
40390795Sgshapiro				return (0);
40490795Sgshapiro			st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4,
40590795Sgshapiro			    kd->procbase, &size, NULL, 0);
40690795Sgshapiro		} while (st == -1 && errno == ENOMEM);
40790795Sgshapiro		if (st == -1) {
40890795Sgshapiro			_kvm_syserr(kd, kd->program, "kvm_getprocs");
40990795Sgshapiro			return (0);
41090795Sgshapiro		}
41190795Sgshapiro		if (kd->procbase->ki_structsize != sizeof(struct kinfo_proc)) {
41290795Sgshapiro			_kvm_err(kd, kd->program,
41390795Sgshapiro			    "kinfo_proc size mismatch (expected %d, got %d)",
41490795Sgshapiro			    sizeof(struct kinfo_proc),
41590795Sgshapiro			    kd->procbase->ki_structsize);
41690795Sgshapiro			return (0);
41790795Sgshapiro		}
41890795Sgshapiro		nprocs = size / kd->procbase->ki_structsize;
41990795Sgshapiro	} else {
42090795Sgshapiro		struct nlist nl[4], *p;
42190795Sgshapiro
42290795Sgshapiro		nl[0].n_name = "_nprocs";
42390795Sgshapiro		nl[1].n_name = "_allproc";
42490795Sgshapiro		nl[2].n_name = "_zombproc";
42590795Sgshapiro		nl[3].n_name = 0;
42690795Sgshapiro
42790795Sgshapiro		if (kvm_nlist(kd, nl) != 0) {
42864565Sgshapiro			for (p = nl; p->n_type != 0; ++p)
42990795Sgshapiro				;
43090795Sgshapiro			_kvm_err(kd, kd->program,
43190795Sgshapiro				 "%s: no such symbol", p->n_name);
43290795Sgshapiro			return (0);
43390795Sgshapiro		}
43490795Sgshapiro		if (KREAD(kd, nl[0].n_value, &nprocs)) {
43590795Sgshapiro			_kvm_err(kd, kd->program, "can't read nprocs");
43664565Sgshapiro			return (0);
43764565Sgshapiro		}
43864565Sgshapiro		size = nprocs * sizeof(struct kinfo_proc);
43964565Sgshapiro		kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size);
44064565Sgshapiro		if (kd->procbase == 0)
44164565Sgshapiro			return (0);
44264565Sgshapiro
44364565Sgshapiro		nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value,
44464565Sgshapiro				      nl[2].n_value, nprocs);
44564565Sgshapiro#ifdef notdef
44671348Sgshapiro		size = nprocs * sizeof(struct kinfo_proc);
44790795Sgshapiro		(void)realloc(kd->procbase, size);
44864565Sgshapiro#endif
44964565Sgshapiro	}
45090795Sgshapiro	*cnt = nprocs;
45164565Sgshapiro	return (kd->procbase);
45264565Sgshapiro}
45390795Sgshapiro
45464565Sgshapirovoid
45590795Sgshapiro_kvm_freeprocs(kd)
45638032Speter	kvm_t *kd;
45738032Speter{
45838032Speter	if (kd->procbase) {
45938032Speter		free(kd->procbase);
46038032Speter		kd->procbase = 0;
46138032Speter	}
46238032Speter}
46338032Speter
46438032Spetervoid *
46538032Speter_kvm_realloc(kd, p, n)
46638032Speter	kvm_t *kd;
46738032Speter	void *p;
46838032Speter	size_t n;
46938032Speter{
47038032Speter	void *np = (void *)realloc(p, n);
47138032Speter
47238032Speter	if (np == 0) {
47338032Speter		free(p);
47438032Speter		_kvm_err(kd, kd->program, "out of memory");
47538032Speter	}
47638032Speter	return (np);
47738032Speter}
47838032Speter
47990795Sgshapiro#ifndef MAX
48090795Sgshapiro#define MAX(a, b) ((a) > (b) ? (a) : (b))
48190795Sgshapiro#endif
48290795Sgshapiro
48390795Sgshapiro/*
48438032Speter * Read in an argument vector from the user address space of process kp.
48590795Sgshapiro * addr if the user-space base address of narg null-terminated contiguous
48638032Speter * strings.  This is used to read in both the command arguments and
48790795Sgshapiro * environment strings.  Read at most maxcnt characters of strings.
48838032Speter */
48938032Speterstatic char **
49038032Speterkvm_argv(kd, kp, addr, narg, maxcnt)
491132946Sgshapiro	kvm_t *kd;
49238032Speter	struct kinfo_proc *kp;
49338032Speter	register u_long addr;
49438032Speter	register int narg;
49538032Speter	register int maxcnt;
49638032Speter{
49738032Speter	register char *np, *cp, *ep, *ap;
49838032Speter	register u_long oaddr = -1;
49938032Speter	register int len, cc;
50038032Speter	register char **argv;
50138032Speter
50238032Speter	/*
50338032Speter	 * Check that there aren't an unreasonable number of agruments,
50438032Speter	 * and that the address is in user space.
50538032Speter	 */
50664565Sgshapiro	if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS)
50738032Speter		return (0);
50838032Speter
50938032Speter	/*
51038032Speter	 * kd->argv : work space for fetching the strings from the target
51138032Speter	 *            process's space, and is converted for returning to caller
51238032Speter	 */
51338032Speter	if (kd->argv == 0) {
51438032Speter		/*
51538032Speter		 * Try to avoid reallocs.
51638032Speter		 */
51738032Speter		kd->argc = MAX(narg + 1, 32);
51838032Speter		kd->argv = (char **)_kvm_malloc(kd, kd->argc *
51938032Speter						sizeof(*kd->argv));
52038032Speter		if (kd->argv == 0)
52190795Sgshapiro			return (0);
52290795Sgshapiro	} else if (narg + 1 > kd->argc) {
52390795Sgshapiro		kd->argc = MAX(2 * kd->argc, narg + 1);
52490795Sgshapiro		kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc *
52590795Sgshapiro						sizeof(*kd->argv));
52690795Sgshapiro		if (kd->argv == 0)
52790795Sgshapiro			return (0);
52890795Sgshapiro	}
52990795Sgshapiro	/*
53071348Sgshapiro	 * kd->argspc : returned to user, this is where the kd->argv
53138032Speter	 *              arrays are left pointing to the collected strings.
53238032Speter	 */
53338032Speter	if (kd->argspc == 0) {
534132946Sgshapiro		kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE);
535132946Sgshapiro		if (kd->argspc == 0)
53638032Speter			return (0);
53738032Speter		kd->arglen = PAGE_SIZE;
53838032Speter	}
53938032Speter	/*
54038032Speter	 * kd->argbuf : used to pull in pages from the target process.
54138032Speter	 *              the strings are copied out of here.
54238032Speter	 */
54338032Speter	if (kd->argbuf == 0) {
54438032Speter		kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE);
54590795Sgshapiro		if (kd->argbuf == 0)
54638032Speter			return (0);
54738032Speter	}
54838032Speter
54990795Sgshapiro	/* Pull in the target process'es argv vector */
55038032Speter	cc = sizeof(char *) * narg;
55138032Speter	if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc)
55290795Sgshapiro		return (0);
55338032Speter	/*
554120259Sgshapiro	 * ap : saved start address of string we're working on in kd->argspc
555120259Sgshapiro	 * np : pointer to next place to write in kd->argspc
556120259Sgshapiro	 * len: length of data in kd->argspc
557120259Sgshapiro	 * argv: pointer to the argv vector that we are hunting around the
558120259Sgshapiro	 *       target process space for, and converting to addresses in
559120259Sgshapiro	 *       our address space (kd->argspc).
560120259Sgshapiro	 */
561120259Sgshapiro	ap = np = kd->argspc;
562120259Sgshapiro	argv = kd->argv;
563120259Sgshapiro	len = 0;
56438032Speter	/*
56538032Speter	 * Loop over pages, filling in the argument vector.
56638032Speter	 * Note that the argv strings could be pointing *anywhere* in
56738032Speter	 * the user address space and are no longer contiguous.
568120259Sgshapiro	 * Note that *argv is modified when we are going to fetch a string
56938032Speter	 * that crosses a page boundary.  We copy the next part of the string
57038032Speter	 * into to "np" and eventually convert the pointer.
57138032Speter	 */
57238032Speter	while (argv < kd->argv + narg && *argv != 0) {
57390795Sgshapiro
57490795Sgshapiro		/* get the address that the current argv string is on */
57538032Speter		addr = (u_long)*argv & ~(PAGE_SIZE - 1);
57638032Speter
57738032Speter		/* is it the same page as the last one? */
57838032Speter		if (addr != oaddr) {
57990795Sgshapiro			if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) !=
58090795Sgshapiro			    PAGE_SIZE)
58190795Sgshapiro				return (0);
58238032Speter			oaddr = addr;
58338032Speter		}
58464565Sgshapiro
58538032Speter		/* offset within the page... kd->argbuf */
58690795Sgshapiro		addr = (u_long)*argv & (PAGE_SIZE - 1);
58738032Speter
58890795Sgshapiro		/* cp = start of string, cc = count of chars in this chunk */
58938032Speter		cp = kd->argbuf + addr;
59038032Speter		cc = PAGE_SIZE - addr;
59138032Speter
59290795Sgshapiro		/* dont get more than asked for by user process */
59338032Speter		if (maxcnt > 0 && cc > maxcnt - len)
59490795Sgshapiro			cc = maxcnt - len;
59538032Speter
59690795Sgshapiro		/* pointer to end of string if we found it in this page */
59738032Speter		ep = memchr(cp, '\0', cc);
59890795Sgshapiro		if (ep != 0)
59938032Speter			cc = ep - cp + 1;
60038032Speter		/*
60138032Speter		 * at this point, cc is the count of the chars that we are
60238032Speter		 * going to retrieve this time. we may or may not have found
603132946Sgshapiro		 * the end of it.  (ep points to the null if the end is known)
60438032Speter		 */
60590795Sgshapiro
60638032Speter		/* will we exceed the malloc/realloced buffer? */
60738032Speter		if (len + cc > kd->arglen) {
60838032Speter			register int off;
609132946Sgshapiro			register char **pp;
61038032Speter			register char *op = kd->argspc;
61138032Speter
61238032Speter			kd->arglen *= 2;
61338032Speter			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc,
61438032Speter							  kd->arglen);
61538032Speter			if (kd->argspc == 0)
61638032Speter				return (0);
61738032Speter			/*
618132946Sgshapiro			 * Adjust argv pointers in case realloc moved
619132946Sgshapiro			 * the string space.
62038032Speter			 */
62138032Speter			off = kd->argspc - op;
62238032Speter			for (pp = kd->argv; pp < argv; pp++)
62338032Speter				*pp += off;
62438032Speter			ap += off;
62538032Speter			np += off;
62638032Speter		}
62738032Speter		/* np = where to put the next part of the string in kd->argspc*/
628132946Sgshapiro		/* np is kinda redundant.. could use "kd->argspc + len" */
62938032Speter		memcpy(np, cp, cc);
63090795Sgshapiro		np += cc;	/* inc counters */
63142580Speter		len += cc;
63238032Speter
63338032Speter		/*
63438032Speter		 * if end of string found, set the *argv pointer to the
63538032Speter		 * saved beginning of string, and advance. argv points to
63638032Speter		 * somewhere in kd->argv..  This is initially relative
63738032Speter		 * to the target process, but when we close it off, we set
63890795Sgshapiro		 * it to point in our address space.
63938032Speter		 */
64038032Speter		if (ep != 0) {
64138032Speter			*argv++ = ap;
64238032Speter			ap = np;
64338032Speter		} else {
64438032Speter			/* update the address relative to the target process */
64564565Sgshapiro			*argv += cc;
64638032Speter		}
64738032Speter
64838032Speter		if (maxcnt > 0 && len >= maxcnt) {
64938032Speter			/*
65038032Speter			 * We're stopping prematurely.  Terminate the
65138032Speter			 * current string.
65238032Speter			 */
65338032Speter			if (ep == 0) {
65438032Speter				*np = '\0';
65538032Speter				*argv++ = ap;
65690795Sgshapiro			}
65738032Speter			break;
65838032Speter		}
65938032Speter	}
66038032Speter	/* Make sure argv is terminated. */
66138032Speter	*argv = 0;
66238032Speter	return (kd->argv);
66338032Speter}
66438032Speter
66538032Speterstatic void
66664565Sgshapirops_str_a(p, addr, n)
66738032Speter	struct ps_strings *p;
66838032Speter	u_long *addr;
66938032Speter	int *n;
67064565Sgshapiro{
67138032Speter	*addr = (u_long)p->ps_argvstr;
67298125Sgshapiro	*n = p->ps_nargvstr;
67338032Speter}
67438032Speter
67538032Speterstatic void
67638032Speterps_str_e(p, addr, n)
67738032Speter	struct ps_strings *p;
67890795Sgshapiro	u_long *addr;
67990795Sgshapiro	int *n;
68038032Speter{
68190795Sgshapiro	*addr = (u_long)p->ps_envstr;
68290795Sgshapiro	*n = p->ps_nenvstr;
68338032Speter}
68438032Speter
68538032Speter/*
68690795Sgshapiro * Determine if the proc indicated by p is still active.
68790795Sgshapiro * This test is not 100% foolproof in theory, but chances of
68838032Speter * being wrong are very low.
68938032Speter */
69038032Speterstatic int
69138032Speterproc_verify(curkp)
69238032Speter	struct kinfo_proc *curkp;
69338032Speter{
69464565Sgshapiro	struct kinfo_proc newkp;
69538032Speter	int mib[4];
69638032Speter	size_t len;
69738032Speter
69890795Sgshapiro	mib[0] = CTL_KERN;
69938032Speter	mib[1] = KERN_PROC;
70038032Speter	mib[2] = KERN_PROC_PID;
70138032Speter	mib[3] = curkp->ki_pid;
70290795Sgshapiro	len = sizeof(newkp);
70390795Sgshapiro	if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1)
70438032Speter		return (0);
70538032Speter	return (curkp->ki_pid == newkp.ki_pid &&
70690795Sgshapiro	    (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB));
70764565Sgshapiro}
70890795Sgshapiro
70938032Speterstatic char **
71038032Speterkvm_doargv(kd, kp, nchr, info)
71138032Speter	kvm_t *kd;
71238032Speter	struct kinfo_proc *kp;
71338032Speter	int nchr;
71438032Speter	void (*info)(struct ps_strings *, u_long *, int *);
71590795Sgshapiro{
71638032Speter	char **ap;
71738032Speter	u_long addr;
71864565Sgshapiro	int cnt;
71938032Speter	static struct ps_strings arginfo;
72038032Speter	static u_long ps_strings;
72190795Sgshapiro	size_t len;
72238032Speter
72338032Speter	if (ps_strings == NULL) {
72438032Speter		len = sizeof(ps_strings);
72538032Speter		if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL,
72638032Speter		    0) == -1)
72738032Speter			ps_strings = PS_STRINGS;
72838032Speter	}
72938032Speter
73038032Speter	/*
73138032Speter	 * Pointers are stored at the top of the user stack.
73238032Speter	 */
73338032Speter	if (kp->ki_stat == SZOMB ||
73438032Speter	    kvm_uread(kd, kp, ps_strings, (char *)&arginfo,
73538032Speter		      sizeof(arginfo)) != sizeof(arginfo))
73638032Speter		return (0);
73738032Speter
73864565Sgshapiro	(*info)(&arginfo, &addr, &cnt);
73938032Speter	if (cnt == 0)
74038032Speter		return (0);
74138032Speter	ap = kvm_argv(kd, kp, addr, cnt, nchr);
74238032Speter	/*
74390795Sgshapiro	 * For live kernels, make sure this process didn't go away.
74438032Speter	 */
74538032Speter	if (ap != 0 && ISALIVE(kd) && !proc_verify(kp))
74638032Speter		ap = 0;
74738032Speter	return (ap);
74838032Speter}
74938032Speter
75038032Speter/*
75138032Speter * Get the command args.  This code is now machine independent.
75238032Speter */
75390795Sgshapirochar **
75438032Speterkvm_getargv(kd, kp, nchr)
75538032Speter	kvm_t *kd;
75638032Speter	const struct kinfo_proc *kp;
75738032Speter	int nchr;
75890795Sgshapiro{
75938032Speter	int oid[4];
76038032Speter	int i;
76138032Speter	size_t bufsz;
76238032Speter	static int buflen;
76338032Speter	static char *buf, *p;
76490795Sgshapiro	static char **bufp;
76538032Speter	static int argc;
76638032Speter
76738032Speter	if (!ISALIVE(kd)) {
76864565Sgshapiro		_kvm_err(kd, kd->program,
76938032Speter		    "cannot read user space from dead kernel");
77090795Sgshapiro		return (0);
77142580Speter	}
77238032Speter
77338032Speter	if (!buflen) {
77438032Speter		bufsz = sizeof(buflen);
77538032Speter		i = sysctlbyname("kern.ps_arg_cache_limit",
77638032Speter		    &buflen, &bufsz, NULL, 0);
77790795Sgshapiro		if (i == -1) {
77838032Speter			buflen = 0;
77938032Speter		} else {
78090795Sgshapiro			buf = malloc(buflen);
78190795Sgshapiro			if (buf == NULL)
78238032Speter				buflen = 0;
78338032Speter			argc = 32;
78464565Sgshapiro			bufp = malloc(sizeof(char *) * argc);
78538032Speter		}
78638032Speter	}
78738032Speter	if (buf != NULL) {
78864565Sgshapiro		oid[0] = CTL_KERN;
78990795Sgshapiro		oid[1] = KERN_PROC;
79090795Sgshapiro		oid[2] = KERN_PROC_ARGS;
79198125Sgshapiro		oid[3] = kp->ki_pid;
79238032Speter		bufsz = buflen;
79338032Speter		i = sysctl(oid, 4, buf, &bufsz, 0, 0);
79438032Speter		if (i == 0 && bufsz > 0) {
79538032Speter			i = 0;
79690795Sgshapiro			p = buf;
79790795Sgshapiro			do {
79838032Speter				bufp[i++] = p;
79938032Speter				p += strlen(p) + 1;
80038032Speter				if (i >= argc) {
80190795Sgshapiro					argc += argc;
80264565Sgshapiro					bufp = realloc(bufp,
80338032Speter					    sizeof(char *) * argc);
80438032Speter				}
80590795Sgshapiro			} while (p < buf + bufsz);
80638032Speter			bufp[i++] = 0;
80738032Speter			return (bufp);
80890795Sgshapiro		}
80990795Sgshapiro	}
81064565Sgshapiro	if (kp->ki_flag & P_SYSTEM)
81190795Sgshapiro		return (NULL);
81290795Sgshapiro	return (kvm_doargv(kd, kp, nchr, ps_str_a));
81338032Speter}
81438032Speter
81538032Speterchar **
81690795Sgshapirokvm_getenvv(kd, kp, nchr)
81738032Speter	kvm_t *kd;
81838032Speter	const struct kinfo_proc *kp;
81938032Speter	int nchr;
82038032Speter{
82138032Speter	return (kvm_doargv(kd, kp, nchr, ps_str_e));
82238032Speter}
82338032Speter
82438032Speter/*
82538032Speter * Read from user space.  The user context is given by p.
82690795Sgshapiro */
82790795Sgshapirossize_t
82838032Speterkvm_uread(kd, kp, uva, buf, len)
82938032Speter	kvm_t *kd;
83038032Speter	struct kinfo_proc *kp;
83138032Speter	register u_long uva;
83290795Sgshapiro	register char *buf;
83390795Sgshapiro	register size_t len;
83464565Sgshapiro{
83564565Sgshapiro	register char *cp;
83664565Sgshapiro	char procfile[MAXPATHLEN];
83790795Sgshapiro	ssize_t amount;
83890795Sgshapiro	int fd;
83964565Sgshapiro
84038032Speter	if (!ISALIVE(kd)) {
84190795Sgshapiro		_kvm_err(kd, kd->program,
84238032Speter		    "cannot read user space from dead kernel");
84338032Speter		return (0);
84464565Sgshapiro	}
84538032Speter
84638032Speter	sprintf(procfile, "/proc/%d/mem", kp->ki_pid);
84790795Sgshapiro	fd = open(procfile, O_RDONLY, 0);
84838032Speter	if (fd < 0) {
84938032Speter		_kvm_err(kd, kd->program, "cannot open %s", procfile);
85038032Speter		close(fd);
85138032Speter		return (0);
85238032Speter	}
85338032Speter
85438032Speter	cp = buf;
85538032Speter	while (len > 0) {
85638032Speter		errno = 0;
85738032Speter		if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) {
85838032Speter			_kvm_err(kd, kd->program, "invalid address (%x) in %s",
85938032Speter			    uva, procfile);
86038032Speter			break;
86138032Speter		}
86238032Speter		amount = read(fd, cp, len);
86338032Speter		if (amount < 0) {
86438032Speter			_kvm_syserr(kd, kd->program, "error reading %s",
86538032Speter			    procfile);
86664565Sgshapiro			break;
86738032Speter		}
86890795Sgshapiro		if (amount == 0) {
86938032Speter			_kvm_err(kd, kd->program, "EOF reading %s", procfile);
87038032Speter			break;
87138032Speter		}
87238032Speter		cp += amount;
87338032Speter		uva += amount;
87438032Speter		len -= amount;
87538032Speter	}
87638032Speter
87738032Speter	close(fd);
87838032Speter	return ((ssize_t)(cp - buf));
87938032Speter}
88038032Speter