kvm_proc.c revision 94028
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1989, 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software developed by the Computer Systems
61573Srgrimes * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
71573Srgrimes * BG 91-66 and contributed to Berkeley.
81573Srgrimes *
91573Srgrimes * Redistribution and use in source and binary forms, with or without
101573Srgrimes * modification, are permitted provided that the following conditions
111573Srgrimes * are met:
121573Srgrimes * 1. Redistributions of source code must retain the above copyright
131573Srgrimes *    notice, this list of conditions and the following disclaimer.
141573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151573Srgrimes *    notice, this list of conditions and the following disclaimer in the
161573Srgrimes *    documentation and/or other materials provided with the distribution.
171573Srgrimes * 3. All advertising materials mentioning features or use of this software
181573Srgrimes *    must display the following acknowledgement:
191573Srgrimes *	This product includes software developed by the University of
201573Srgrimes *	California, Berkeley and its contributors.
211573Srgrimes * 4. Neither the name of the University nor the names of its contributors
221573Srgrimes *    may be used to endorse or promote products derived from this software
231573Srgrimes *    without specific prior written permission.
241573Srgrimes *
251573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351573Srgrimes * SUCH DAMAGE.
3653239Sphk *
3753239Sphk * $FreeBSD: head/lib/libkvm/kvm_proc.c 94028 2002-04-07 04:47:58Z dd $
381573Srgrimes */
391573Srgrimes
4083551Sdillon#include <sys/cdefs.h>
4183551Sdillon__FBSDID("$FreeBSD: head/lib/libkvm/kvm_proc.c 94028 2002-04-07 04:47:58Z dd $");
4283551Sdillon
431573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
441573Srgrimesstatic char sccsid[] = "@(#)kvm_proc.c	8.3 (Berkeley) 9/23/93";
451573Srgrimes#endif /* LIBC_SCCS and not lint */
461573Srgrimes
471573Srgrimes/*
481573Srgrimes * Proc traversal interface for kvm.  ps and w are (probably) the exclusive
491573Srgrimes * users of this code, so we've factored it out into a separate module.
501573Srgrimes * Thus, we keep this grunge out of the other kvm applications (i.e.,
511573Srgrimes * most other applications are interested only in open/close/read/nlist).
521573Srgrimes */
531573Srgrimes
541573Srgrimes#include <sys/param.h>
551573Srgrimes#include <sys/user.h>
561573Srgrimes#include <sys/proc.h>
571573Srgrimes#include <sys/exec.h>
581573Srgrimes#include <sys/stat.h>
591573Srgrimes#include <sys/ioctl.h>
601573Srgrimes#include <sys/tty.h>
612029Sdg#include <sys/file.h>
6217141Sjkh#include <stdio.h>
6317141Sjkh#include <stdlib.h>
641573Srgrimes#include <unistd.h>
651573Srgrimes#include <nlist.h>
661573Srgrimes#include <kvm.h>
671573Srgrimes
681573Srgrimes#include <vm/vm.h>
691573Srgrimes#include <vm/vm_param.h>
701573Srgrimes#include <vm/swap_pager.h>
711573Srgrimes
721573Srgrimes#include <sys/sysctl.h>
731573Srgrimes
741573Srgrimes#include <limits.h>
7512682Speter#include <memory.h>
761573Srgrimes#include <paths.h>
771573Srgrimes
781573Srgrimes#include "kvm_private.h"
791573Srgrimes
8017141Sjkh#if used
811573Srgrimesstatic char *
821573Srgrimeskvm_readswap(kd, p, va, cnt)
831573Srgrimes	kvm_t *kd;
841573Srgrimes	const struct proc *p;
851573Srgrimes	u_long va;
861573Srgrimes	u_long *cnt;
871573Srgrimes{
881603Srgrimes#ifdef __FreeBSD__
891603Srgrimes	/* XXX Stubbed out, our vm system is differnet */
901603Srgrimes	_kvm_err(kd, kd->program, "kvm_readswap not implemented");
911603Srgrimes	return(0);
921603Srgrimes#endif	/* __FreeBSD__ */
931573Srgrimes}
9417141Sjkh#endif
951573Srgrimes
961573Srgrimes#define KREAD(kd, addr, obj) \
971573Srgrimes	(kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
981573Srgrimes
991573Srgrimes/*
1001573Srgrimes * Read proc's from memory file into buffer bp, which has space to hold
1011573Srgrimes * at most maxcnt procs.
1021573Srgrimes */
1031573Srgrimesstatic int
1041573Srgrimeskvm_proclist(kd, what, arg, p, bp, maxcnt)
1051573Srgrimes	kvm_t *kd;
1061573Srgrimes	int what, arg;
1071573Srgrimes	struct proc *p;
1081573Srgrimes	struct kinfo_proc *bp;
1091573Srgrimes	int maxcnt;
1101573Srgrimes{
11192913Sobrien	int cnt = 0;
11269896Smckusick	struct kinfo_proc kinfo_proc, *kp;
1131573Srgrimes	struct pgrp pgrp;
1141573Srgrimes	struct session sess;
1151573Srgrimes	struct tty tty;
11669896Smckusick	struct vmspace vmspace;
11769896Smckusick	struct procsig procsig;
11869896Smckusick	struct pstats pstats;
11969896Smckusick	struct ucred ucred;
12090360Sjulian	struct thread mainthread;
1211573Srgrimes	struct proc proc;
12226947Stegge	struct proc pproc;
12391075Sgreen	struct timeval tv;
1241573Srgrimes
12569896Smckusick	kp = &kinfo_proc;
12669896Smckusick	kp->ki_structsize = sizeof(kinfo_proc);
12770525Sben	for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) {
12882266Speter		memset(kp, 0, sizeof *kp);
1291573Srgrimes		if (KREAD(kd, (u_long)p, &proc)) {
1301573Srgrimes			_kvm_err(kd, kd->program, "can't read proc at %x", p);
1311573Srgrimes			return (-1);
1321573Srgrimes		}
13390360Sjulian		if (KREAD(kd, (u_long)TAILQ_FIRST(&proc.p_threads),
13490360Sjulian		    &mainthread)) {
13590360Sjulian			_kvm_err(kd, kd->program, "can't read thread at %x",
13690360Sjulian			    TAILQ_FIRST(&proc.p_threads));
13790360Sjulian			return (-1);
13890360Sjulian		}
13977183Srwatson		if (KREAD(kd, (u_long)proc.p_ucred, &ucred) == 0) {
14077183Srwatson			kp->ki_ruid = ucred.cr_ruid;
14177183Srwatson			kp->ki_svuid = ucred.cr_svuid;
14277183Srwatson			kp->ki_rgid = ucred.cr_rgid;
14377183Srwatson			kp->ki_svgid = ucred.cr_svgid;
14469896Smckusick			kp->ki_ngroups = ucred.cr_ngroups;
14569896Smckusick			bcopy(ucred.cr_groups, kp->ki_groups,
14669896Smckusick			    NGROUPS * sizeof(gid_t));
14769896Smckusick			kp->ki_uid = ucred.cr_uid;
14869896Smckusick		}
1491573Srgrimes
1501573Srgrimes		switch(what) {
1518870Srgrimes
1521573Srgrimes		case KERN_PROC_PID:
1531573Srgrimes			if (proc.p_pid != (pid_t)arg)
1541573Srgrimes				continue;
1551573Srgrimes			break;
1561573Srgrimes
1571573Srgrimes		case KERN_PROC_UID:
15869896Smckusick			if (kp->ki_uid != (uid_t)arg)
1591573Srgrimes				continue;
1601573Srgrimes			break;
1611573Srgrimes
1621573Srgrimes		case KERN_PROC_RUID:
16369896Smckusick			if (kp->ki_ruid != (uid_t)arg)
1641573Srgrimes				continue;
1651573Srgrimes			break;
1661573Srgrimes		}
1671573Srgrimes		/*
1681573Srgrimes		 * We're going to add another proc to the set.  If this
1691573Srgrimes		 * will overflow the buffer, assume the reason is because
1701573Srgrimes		 * nprocs (or the proc list) is corrupt and declare an error.
1711573Srgrimes		 */
1721573Srgrimes		if (cnt >= maxcnt) {
1731573Srgrimes			_kvm_err(kd, kd->program, "nprocs corrupt");
1741573Srgrimes			return (-1);
1751573Srgrimes		}
1761573Srgrimes		/*
17769896Smckusick		 * gather kinfo_proc
1781573Srgrimes		 */
17969896Smckusick		kp->ki_paddr = p;
18083366Sjulian		kp->ki_addr = proc.p_uarea;
18183366Sjulian		/* kp->ki_kstack = proc.p_thread.td_kstack; XXXKSE */
18269896Smckusick		kp->ki_args = proc.p_args;
18369896Smckusick		kp->ki_tracep = proc.p_tracep;
18469896Smckusick		kp->ki_textvp = proc.p_textvp;
18569896Smckusick		kp->ki_fd = proc.p_fd;
18669896Smckusick		kp->ki_vmspace = proc.p_vmspace;
18769896Smckusick		if (proc.p_procsig != NULL) {
18869896Smckusick			if (KREAD(kd, (u_long)proc.p_procsig, &procsig)) {
18969896Smckusick				_kvm_err(kd, kd->program,
19069896Smckusick				    "can't read procsig at %x", proc.p_procsig);
19169896Smckusick				return (-1);
19269896Smckusick			}
19369896Smckusick			kp->ki_sigignore = procsig.ps_sigignore;
19469896Smckusick			kp->ki_sigcatch = procsig.ps_sigcatch;
19569896Smckusick		}
19671577Sjhb		if ((proc.p_sflag & PS_INMEM) && proc.p_stats != NULL) {
19769896Smckusick			if (KREAD(kd, (u_long)proc.p_stats, &pstats)) {
19869896Smckusick				_kvm_err(kd, kd->program,
19969896Smckusick				    "can't read stats at %x", proc.p_stats);
20069896Smckusick				return (-1);
20169896Smckusick			}
20269896Smckusick			kp->ki_start = pstats.p_start;
20369896Smckusick			kp->ki_rusage = pstats.p_ru;
20469896Smckusick			kp->ki_childtime.tv_sec = pstats.p_cru.ru_utime.tv_sec +
20569896Smckusick			    pstats.p_cru.ru_stime.tv_sec;
20669896Smckusick			kp->ki_childtime.tv_usec =
20769896Smckusick			    pstats.p_cru.ru_utime.tv_usec +
20869896Smckusick			    pstats.p_cru.ru_stime.tv_usec;
20969896Smckusick		}
21026947Stegge		if (proc.p_oppid)
21169896Smckusick			kp->ki_ppid = proc.p_oppid;
21226947Stegge		else if (proc.p_pptr) {
21369896Smckusick			if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) {
21469896Smckusick				_kvm_err(kd, kd->program,
21569896Smckusick				    "can't read pproc at %x", proc.p_pptr);
21669896Smckusick				return (-1);
21769896Smckusick			}
21869896Smckusick			kp->ki_ppid = pproc.p_pid;
21926947Stegge		} else
22069896Smckusick			kp->ki_ppid = 0;
22182266Speter		if (proc.p_pgrp == NULL)
22282266Speter			goto nopgrp;
22382266Speter		if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) {
22482266Speter			_kvm_err(kd, kd->program, "can't read pgrp at %x",
22582266Speter				 proc.p_pgrp);
22682266Speter			return (-1);
22782266Speter		}
22869896Smckusick		kp->ki_pgid = pgrp.pg_id;
22969896Smckusick		kp->ki_jobc = pgrp.pg_jobc;
2301573Srgrimes		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
2318870Srgrimes			_kvm_err(kd, kd->program, "can't read session at %x",
2321573Srgrimes				pgrp.pg_session);
2331573Srgrimes			return (-1);
2341573Srgrimes		}
23569896Smckusick		kp->ki_sid = sess.s_sid;
23669896Smckusick		(void)memcpy(kp->ki_login, sess.s_login,
23769896Smckusick						sizeof(kp->ki_login));
23869896Smckusick		kp->ki_kiflag = sess.s_ttyvp ? KI_CTTY : 0;
23969896Smckusick		if (sess.s_leader == p)
24069896Smckusick			kp->ki_kiflag |= KI_SLEADER;
2411573Srgrimes		if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) {
2421573Srgrimes			if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
2431573Srgrimes				_kvm_err(kd, kd->program,
2441573Srgrimes					 "can't read tty at %x", sess.s_ttyp);
2451573Srgrimes				return (-1);
2461573Srgrimes			}
24769896Smckusick			kp->ki_tdev = tty.t_dev;
2481573Srgrimes			if (tty.t_pgrp != NULL) {
2491573Srgrimes				if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
2501573Srgrimes					_kvm_err(kd, kd->program,
2518870Srgrimes						 "can't read tpgrp at &x",
2521573Srgrimes						tty.t_pgrp);
2531573Srgrimes					return (-1);
2541573Srgrimes				}
25569896Smckusick				kp->ki_tpgid = pgrp.pg_id;
2561573Srgrimes			} else
25769896Smckusick				kp->ki_tpgid = -1;
25869896Smckusick			if (tty.t_session != NULL) {
25969896Smckusick				if (KREAD(kd, (u_long)tty.t_session, &sess)) {
26069896Smckusick					_kvm_err(kd, kd->program,
26169896Smckusick					    "can't read session at %x",
26269896Smckusick					    tty.t_session);
26369896Smckusick					return (-1);
26469896Smckusick				}
26569896Smckusick				kp->ki_tsid = sess.s_sid;
26669896Smckusick			}
26782266Speter		} else {
26882266Speternopgrp:
26969896Smckusick			kp->ki_tdev = NODEV;
27082266Speter		}
27190360Sjulian		if (mainthread.td_wmesg)	/* XXXKSE */
27290360Sjulian			(void)kvm_read(kd, (u_long)mainthread.td_wmesg,
27369896Smckusick			    kp->ki_wmesg, WMESGLEN);
2741573Srgrimes
2751573Srgrimes#ifdef sparc
2761573Srgrimes		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_rssize,
27769896Smckusick		    (char *)&kp->ki_rssize,
27869896Smckusick		    sizeof(kp->ki_rssize));
2791573Srgrimes		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_tsize,
28069896Smckusick		    (char *)&kp->ki_tsize,
28169896Smckusick		    3 * sizeof(kp->ki_rssize));	/* XXX */
2821573Srgrimes#else
2831573Srgrimes		(void)kvm_read(kd, (u_long)proc.p_vmspace,
28469896Smckusick		    (char *)&vmspace, sizeof(vmspace));
28569896Smckusick		kp->ki_size = vmspace.vm_map.size;
28669896Smckusick		kp->ki_rssize = vmspace.vm_swrss; /* XXX */
28769896Smckusick		kp->ki_swrss = vmspace.vm_swrss;
28869896Smckusick		kp->ki_tsize = vmspace.vm_tsize;
28969896Smckusick		kp->ki_dsize = vmspace.vm_dsize;
29069896Smckusick		kp->ki_ssize = vmspace.vm_ssize;
2911573Srgrimes#endif
2921573Srgrimes
2931573Srgrimes		switch (what) {
2941573Srgrimes
2951573Srgrimes		case KERN_PROC_PGRP:
29669896Smckusick			if (kp->ki_pgid != (pid_t)arg)
2971573Srgrimes				continue;
2981573Srgrimes			break;
2991573Srgrimes
3001573Srgrimes		case KERN_PROC_TTY:
3018870Srgrimes			if ((proc.p_flag & P_CONTROLT) == 0 ||
30269896Smckusick			     kp->ki_tdev != (dev_t)arg)
3031573Srgrimes				continue;
3041573Srgrimes			break;
3051573Srgrimes		}
30669896Smckusick		if (proc.p_comm[0] != 0) {
30769896Smckusick			strncpy(kp->ki_comm, proc.p_comm, MAXCOMLEN);
30869896Smckusick			kp->ki_comm[MAXCOMLEN] = 0;
30969896Smckusick		}
31090360Sjulian		if (mainthread.td_blocked != 0) {	/* XXXKSE */
31169896Smckusick			kp->ki_kiflag |= KI_MTXBLOCK;
31290360Sjulian			if (mainthread.td_mtxname)	/* XXXKSE */
31390360Sjulian				(void)kvm_read(kd, (u_long)mainthread.td_mtxname,
31469896Smckusick				    kp->ki_mtxname, MTXNAMELEN);
31569896Smckusick			kp->ki_mtxname[MTXNAMELEN] = 0;
31669896Smckusick		}
31791075Sgreen		bintime2timeval(&proc.p_runtime, &tv);
31891075Sgreen		kp->ki_runtime = (u_int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
31969896Smckusick		kp->ki_pid = proc.p_pid;
32069896Smckusick		kp->ki_siglist = proc.p_siglist;
32169896Smckusick		kp->ki_sigmask = proc.p_sigmask;
32269896Smckusick		kp->ki_xstat = proc.p_xstat;
32369896Smckusick		kp->ki_acflag = proc.p_acflag;
32483366Sjulian		kp->ki_pctcpu = proc.p_kse.ke_pctcpu;		/* XXXKSE */
32583366Sjulian		kp->ki_estcpu = proc.p_ksegrp.kg_estcpu;	/* XXXKSE */
32683366Sjulian		kp->ki_slptime = proc.p_kse.ke_slptime;		/* XXXKSE */
32769896Smckusick		kp->ki_swtime = proc.p_swtime;
32869896Smckusick		kp->ki_flag = proc.p_flag;
32971577Sjhb		kp->ki_sflag = proc.p_sflag;
33090360Sjulian		kp->ki_wchan = mainthread.td_wchan;		/* XXXKSE */
33169896Smckusick		kp->ki_traceflag = proc.p_traceflag;
33269896Smckusick		kp->ki_stat = proc.p_stat;
33390592Sjulian		kp->ki_pri.pri_class = proc.p_ksegrp.kg_pri_class; /* XXXKSE */
33490592Sjulian		kp->ki_pri.pri_user = proc.p_ksegrp.kg_user_pri; /* XXXKSE */
33590592Sjulian		kp->ki_pri.pri_level = mainthread.td_priority;	/* XXXKSE */
33690592Sjulian		kp->ki_pri.pri_native = mainthread.td_base_pri; /* XXXKSE */
33783366Sjulian		kp->ki_nice = proc.p_ksegrp.kg_nice;		/* XXXKSE */
33869896Smckusick		kp->ki_lock = proc.p_lock;
33983366Sjulian		kp->ki_rqindex = proc.p_kse.ke_rqindex;		/* XXXKSE */
34083366Sjulian		kp->ki_oncpu = proc.p_kse.ke_oncpu;		/* XXXKSE */
34190360Sjulian		kp->ki_lastcpu = mainthread.td_lastcpu;	/* XXXKSE */
34269896Smckusick		bcopy(&kinfo_proc, bp, sizeof(kinfo_proc));
3431573Srgrimes		++bp;
3441573Srgrimes		++cnt;
3451573Srgrimes	}
3461573Srgrimes	return (cnt);
3471573Srgrimes}
3481573Srgrimes
3491573Srgrimes/*
3501573Srgrimes * Build proc info array by reading in proc list from a crash dump.
3511573Srgrimes * Return number of procs read.  maxcnt is the max we will read.
3521573Srgrimes */
3531573Srgrimesstatic int
3541573Srgrimeskvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt)
3551573Srgrimes	kvm_t *kd;
3561573Srgrimes	int what, arg;
3571573Srgrimes	u_long a_allproc;
3581573Srgrimes	u_long a_zombproc;
3591573Srgrimes	int maxcnt;
3601573Srgrimes{
36192913Sobrien	struct kinfo_proc *bp = kd->procbase;
36292913Sobrien	int acnt, zcnt;
3631573Srgrimes	struct proc *p;
3641573Srgrimes
3651573Srgrimes	if (KREAD(kd, a_allproc, &p)) {
3661573Srgrimes		_kvm_err(kd, kd->program, "cannot read allproc");
3671573Srgrimes		return (-1);
3681573Srgrimes	}
3691573Srgrimes	acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt);
3701573Srgrimes	if (acnt < 0)
3711573Srgrimes		return (acnt);
3721573Srgrimes
3731573Srgrimes	if (KREAD(kd, a_zombproc, &p)) {
3741573Srgrimes		_kvm_err(kd, kd->program, "cannot read zombproc");
3751573Srgrimes		return (-1);
3761573Srgrimes	}
3771573Srgrimes	zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt);
3781573Srgrimes	if (zcnt < 0)
3791573Srgrimes		zcnt = 0;
3801573Srgrimes
3811573Srgrimes	return (acnt + zcnt);
3821573Srgrimes}
3831573Srgrimes
3841573Srgrimesstruct kinfo_proc *
3851573Srgrimeskvm_getprocs(kd, op, arg, cnt)
3861573Srgrimes	kvm_t *kd;
3871573Srgrimes	int op, arg;
3881573Srgrimes	int *cnt;
3891573Srgrimes{
39038534Sdfr	int mib[4], st, nprocs;
39138534Sdfr	size_t size;
3921573Srgrimes
3931573Srgrimes	if (kd->procbase != 0) {
3941573Srgrimes		free((void *)kd->procbase);
3958870Srgrimes		/*
3961573Srgrimes		 * Clear this pointer in case this call fails.  Otherwise,
3971573Srgrimes		 * kvm_close() will free it again.
3981573Srgrimes		 */
3991573Srgrimes		kd->procbase = 0;
4001573Srgrimes	}
4011573Srgrimes	if (ISALIVE(kd)) {
4021573Srgrimes		size = 0;
4031573Srgrimes		mib[0] = CTL_KERN;
4041573Srgrimes		mib[1] = KERN_PROC;
4051573Srgrimes		mib[2] = op;
4061573Srgrimes		mib[3] = arg;
40716158Sphk		st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, NULL, &size, NULL, 0);
4081573Srgrimes		if (st == -1) {
4091573Srgrimes			_kvm_syserr(kd, kd->program, "kvm_getprocs");
4101573Srgrimes			return (0);
4111573Srgrimes		}
41294028Sdd		/*
41394028Sdd		 * We can't continue with a size of 0 because we pass
41494028Sdd		 * it to realloc() (via _kvm_realloc()), and passing 0
41594028Sdd		 * to realloc() results in undefined behavior.
41694028Sdd		 */
41794028Sdd		if (size == 0) {
41894028Sdd			/*
41994028Sdd			 * XXX: We should probably return an invalid,
42094028Sdd			 * but non-NULL, pointer here so any client
42194028Sdd			 * program trying to dereference it will
42294028Sdd			 * crash.  However, _kvm_freeprocs() calls
42394028Sdd			 * free() on kd->procbase if it isn't NULL,
42494028Sdd			 * and free()'ing a junk pointer isn't good.
42594028Sdd			 * Then again, _kvm_freeprocs() isn't used
42694028Sdd			 * anywhere . . .
42794028Sdd			 */
42894028Sdd			kd->procbase = _kvm_malloc(kd, 1);
42994028Sdd			goto liveout;
43094028Sdd		}
43140268Sdes		do {
43240268Sdes			size += size / 10;
43340268Sdes			kd->procbase = (struct kinfo_proc *)
43441880Sbde			    _kvm_realloc(kd, kd->procbase, size);
43540268Sdes			if (kd->procbase == 0)
43640268Sdes				return (0);
43740268Sdes			st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4,
43841880Sbde			    kd->procbase, &size, NULL, 0);
43940268Sdes		} while (st == -1 && errno == ENOMEM);
4401573Srgrimes		if (st == -1) {
4411573Srgrimes			_kvm_syserr(kd, kd->program, "kvm_getprocs");
4421573Srgrimes			return (0);
4431573Srgrimes		}
44494028Sdd		/*
44594028Sdd		 * We have to check the size again because sysctl()
44694028Sdd		 * may "round up" oldlenp if oldp is NULL; hence it
44794028Sdd		 * might've told us that there was data to get when
44894028Sdd		 * there really isn't any.
44994028Sdd		 */
45076182Sdwmalone		if (size > 0 &&
45176182Sdwmalone		    kd->procbase->ki_structsize != sizeof(struct kinfo_proc)) {
4521573Srgrimes			_kvm_err(kd, kd->program,
45369896Smckusick			    "kinfo_proc size mismatch (expected %d, got %d)",
45469896Smckusick			    sizeof(struct kinfo_proc),
45569896Smckusick			    kd->procbase->ki_structsize);
4561573Srgrimes			return (0);
4571573Srgrimes		}
45894028Sddliveout:
45976243Sdwmalone		nprocs = size == 0 ? 0 : size / kd->procbase->ki_structsize;
4601573Srgrimes	} else {
4611573Srgrimes		struct nlist nl[4], *p;
4621573Srgrimes
4631573Srgrimes		nl[0].n_name = "_nprocs";
4641573Srgrimes		nl[1].n_name = "_allproc";
4651573Srgrimes		nl[2].n_name = "_zombproc";
4661573Srgrimes		nl[3].n_name = 0;
4671573Srgrimes
4681573Srgrimes		if (kvm_nlist(kd, nl) != 0) {
4691573Srgrimes			for (p = nl; p->n_type != 0; ++p)
4701573Srgrimes				;
4711573Srgrimes			_kvm_err(kd, kd->program,
4721573Srgrimes				 "%s: no such symbol", p->n_name);
4731573Srgrimes			return (0);
4741573Srgrimes		}
4751573Srgrimes		if (KREAD(kd, nl[0].n_value, &nprocs)) {
4761573Srgrimes			_kvm_err(kd, kd->program, "can't read nprocs");
4771573Srgrimes			return (0);
4781573Srgrimes		}
4791573Srgrimes		size = nprocs * sizeof(struct kinfo_proc);
4801573Srgrimes		kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size);
4811573Srgrimes		if (kd->procbase == 0)
4821573Srgrimes			return (0);
4831573Srgrimes
4841573Srgrimes		nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value,
4851573Srgrimes				      nl[2].n_value, nprocs);
4861573Srgrimes#ifdef notdef
4871573Srgrimes		size = nprocs * sizeof(struct kinfo_proc);
4881573Srgrimes		(void)realloc(kd->procbase, size);
4891573Srgrimes#endif
4901573Srgrimes	}
4911573Srgrimes	*cnt = nprocs;
4921573Srgrimes	return (kd->procbase);
4931573Srgrimes}
4941573Srgrimes
4951573Srgrimesvoid
4961573Srgrimes_kvm_freeprocs(kd)
4971573Srgrimes	kvm_t *kd;
4981573Srgrimes{
4991573Srgrimes	if (kd->procbase) {
5001573Srgrimes		free(kd->procbase);
5011573Srgrimes		kd->procbase = 0;
5021573Srgrimes	}
5031573Srgrimes}
5041573Srgrimes
5051573Srgrimesvoid *
5061573Srgrimes_kvm_realloc(kd, p, n)
5071573Srgrimes	kvm_t *kd;
5081573Srgrimes	void *p;
5091573Srgrimes	size_t n;
5101573Srgrimes{
5111573Srgrimes	void *np = (void *)realloc(p, n);
5121573Srgrimes
51339327Simp	if (np == 0) {
51439327Simp		free(p);
5151573Srgrimes		_kvm_err(kd, kd->program, "out of memory");
51639327Simp	}
5171573Srgrimes	return (np);
5181573Srgrimes}
5191573Srgrimes
5201573Srgrimes#ifndef MAX
5211573Srgrimes#define MAX(a, b) ((a) > (b) ? (a) : (b))
5221573Srgrimes#endif
5231573Srgrimes
5241573Srgrimes/*
52569896Smckusick * Read in an argument vector from the user address space of process kp.
52612682Speter * addr if the user-space base address of narg null-terminated contiguous
5271573Srgrimes * strings.  This is used to read in both the command arguments and
5281573Srgrimes * environment strings.  Read at most maxcnt characters of strings.
5291573Srgrimes */
5301573Srgrimesstatic char **
53169896Smckusickkvm_argv(kd, kp, addr, narg, maxcnt)
5321573Srgrimes	kvm_t *kd;
53369896Smckusick	struct kinfo_proc *kp;
53492913Sobrien	u_long addr;
53592913Sobrien	int narg;
53692913Sobrien	int maxcnt;
5371573Srgrimes{
53892913Sobrien	char *np, *cp, *ep, *ap;
53992913Sobrien	u_long oaddr = -1;
54092913Sobrien	int len, cc;
54192913Sobrien	char **argv;
5421573Srgrimes
5431573Srgrimes	/*
5441573Srgrimes	 * Check that there aren't an unreasonable number of agruments,
5451573Srgrimes	 * and that the address is in user space.
5461573Srgrimes	 */
54712885Speter	if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS)
5481573Srgrimes		return (0);
5491573Srgrimes
55012885Speter	/*
55112885Speter	 * kd->argv : work space for fetching the strings from the target
55212885Speter	 *            process's space, and is converted for returning to caller
55312885Speter	 */
5541573Srgrimes	if (kd->argv == 0) {
5551573Srgrimes		/*
5561573Srgrimes		 * Try to avoid reallocs.
5571573Srgrimes		 */
5581573Srgrimes		kd->argc = MAX(narg + 1, 32);
5598870Srgrimes		kd->argv = (char **)_kvm_malloc(kd, kd->argc *
5601573Srgrimes						sizeof(*kd->argv));
5611573Srgrimes		if (kd->argv == 0)
5621573Srgrimes			return (0);
5631573Srgrimes	} else if (narg + 1 > kd->argc) {
5641573Srgrimes		kd->argc = MAX(2 * kd->argc, narg + 1);
5658870Srgrimes		kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc *
5661573Srgrimes						sizeof(*kd->argv));
5671573Srgrimes		if (kd->argv == 0)
5681573Srgrimes			return (0);
5691573Srgrimes	}
57012885Speter	/*
57112885Speter	 * kd->argspc : returned to user, this is where the kd->argv
57212885Speter	 *              arrays are left pointing to the collected strings.
57312885Speter	 */
5741573Srgrimes	if (kd->argspc == 0) {
57515533Sphk		kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE);
5761573Srgrimes		if (kd->argspc == 0)
5771573Srgrimes			return (0);
57815533Sphk		kd->arglen = PAGE_SIZE;
5791573Srgrimes	}
58012885Speter	/*
58112885Speter	 * kd->argbuf : used to pull in pages from the target process.
58212885Speter	 *              the strings are copied out of here.
58312885Speter	 */
58412682Speter	if (kd->argbuf == 0) {
58515533Sphk		kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE);
58612682Speter		if (kd->argbuf == 0)
58712682Speter			return (0);
58812682Speter	}
58912885Speter
59012885Speter	/* Pull in the target process'es argv vector */
59112682Speter	cc = sizeof(char *) * narg;
59269896Smckusick	if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc)
59312682Speter		return (0);
59412885Speter	/*
59512885Speter	 * ap : saved start address of string we're working on in kd->argspc
59612885Speter	 * np : pointer to next place to write in kd->argspc
59712885Speter	 * len: length of data in kd->argspc
59812885Speter	 * argv: pointer to the argv vector that we are hunting around the
59912885Speter	 *       target process space for, and converting to addresses in
60012885Speter	 *       our address space (kd->argspc).
60112885Speter	 */
60212682Speter	ap = np = kd->argspc;
6031573Srgrimes	argv = kd->argv;
6041573Srgrimes	len = 0;
6051573Srgrimes	/*
6061573Srgrimes	 * Loop over pages, filling in the argument vector.
60712885Speter	 * Note that the argv strings could be pointing *anywhere* in
60812885Speter	 * the user address space and are no longer contiguous.
60912885Speter	 * Note that *argv is modified when we are going to fetch a string
61012885Speter	 * that crosses a page boundary.  We copy the next part of the string
61112885Speter	 * into to "np" and eventually convert the pointer.
6121573Srgrimes	 */
61312682Speter	while (argv < kd->argv + narg && *argv != 0) {
61412885Speter
61512885Speter		/* get the address that the current argv string is on */
61615533Sphk		addr = (u_long)*argv & ~(PAGE_SIZE - 1);
61712885Speter
61812885Speter		/* is it the same page as the last one? */
61912682Speter		if (addr != oaddr) {
62069896Smckusick			if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) !=
62115533Sphk			    PAGE_SIZE)
62212682Speter				return (0);
62312682Speter			oaddr = addr;
62412682Speter		}
62512885Speter
62612885Speter		/* offset within the page... kd->argbuf */
62715533Sphk		addr = (u_long)*argv & (PAGE_SIZE - 1);
62812885Speter
62912885Speter		/* cp = start of string, cc = count of chars in this chunk */
63012682Speter		cp = kd->argbuf + addr;
63115533Sphk		cc = PAGE_SIZE - addr;
63212885Speter
63312885Speter		/* dont get more than asked for by user process */
6341573Srgrimes		if (maxcnt > 0 && cc > maxcnt - len)
63512885Speter			cc = maxcnt - len;
63612885Speter
63712885Speter		/* pointer to end of string if we found it in this page */
63812682Speter		ep = memchr(cp, '\0', cc);
63912682Speter		if (ep != 0)
64012682Speter			cc = ep - cp + 1;
64112885Speter		/*
64212885Speter		 * at this point, cc is the count of the chars that we are
64312885Speter		 * going to retrieve this time. we may or may not have found
64412885Speter		 * the end of it.  (ep points to the null if the end is known)
64512885Speter		 */
64612885Speter
64712885Speter		/* will we exceed the malloc/realloced buffer? */
6481573Srgrimes		if (len + cc > kd->arglen) {
64992913Sobrien			int off;
65092913Sobrien			char **pp;
65192913Sobrien			char *op = kd->argspc;
6521573Srgrimes
6531573Srgrimes			kd->arglen *= 2;
6541573Srgrimes			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc,
6551573Srgrimes							  kd->arglen);
6561573Srgrimes			if (kd->argspc == 0)
6571573Srgrimes				return (0);
6581573Srgrimes			/*
6591573Srgrimes			 * Adjust argv pointers in case realloc moved
6601573Srgrimes			 * the string space.
6611573Srgrimes			 */
6621573Srgrimes			off = kd->argspc - op;
66312682Speter			for (pp = kd->argv; pp < argv; pp++)
6641573Srgrimes				*pp += off;
66512682Speter			ap += off;
66612682Speter			np += off;
6671573Srgrimes		}
66812885Speter		/* np = where to put the next part of the string in kd->argspc*/
66912885Speter		/* np is kinda redundant.. could use "kd->argspc + len" */
67012682Speter		memcpy(np, cp, cc);
67112885Speter		np += cc;	/* inc counters */
6721573Srgrimes		len += cc;
67312885Speter
67412885Speter		/*
67512885Speter		 * if end of string found, set the *argv pointer to the
67612885Speter		 * saved beginning of string, and advance. argv points to
67712885Speter		 * somewhere in kd->argv..  This is initially relative
67812885Speter		 * to the target process, but when we close it off, we set
67912885Speter		 * it to point in our address space.
68012885Speter		 */
68112682Speter		if (ep != 0) {
68212682Speter			*argv++ = ap;
68312682Speter			ap = np;
68412885Speter		} else {
68512885Speter			/* update the address relative to the target process */
68612682Speter			*argv += cc;
68712885Speter		}
68812885Speter
6891573Srgrimes		if (maxcnt > 0 && len >= maxcnt) {
6901573Srgrimes			/*
6911573Srgrimes			 * We're stopping prematurely.  Terminate the
69212682Speter			 * current string.
6931573Srgrimes			 */
69412682Speter			if (ep == 0) {
69512682Speter				*np = '\0';
69612682Speter				*argv++ = ap;
69712885Speter			}
69812885Speter			break;
6991573Srgrimes		}
7001573Srgrimes	}
70112682Speter	/* Make sure argv is terminated. */
70212682Speter	*argv = 0;
70312682Speter	return (kd->argv);
7041573Srgrimes}
7051573Srgrimes
7061573Srgrimesstatic void
7071573Srgrimesps_str_a(p, addr, n)
7081573Srgrimes	struct ps_strings *p;
7091573Srgrimes	u_long *addr;
7101573Srgrimes	int *n;
7111573Srgrimes{
7121573Srgrimes	*addr = (u_long)p->ps_argvstr;
7131573Srgrimes	*n = p->ps_nargvstr;
7141573Srgrimes}
7151573Srgrimes
7161573Srgrimesstatic void
7171573Srgrimesps_str_e(p, addr, n)
7181573Srgrimes	struct ps_strings *p;
7191573Srgrimes	u_long *addr;
7201573Srgrimes	int *n;
7211573Srgrimes{
7221573Srgrimes	*addr = (u_long)p->ps_envstr;
7231573Srgrimes	*n = p->ps_nenvstr;
7241573Srgrimes}
7251573Srgrimes
7261573Srgrimes/*
7271573Srgrimes * Determine if the proc indicated by p is still active.
7281573Srgrimes * This test is not 100% foolproof in theory, but chances of
7291573Srgrimes * being wrong are very low.
7301573Srgrimes */
7311573Srgrimesstatic int
73269896Smckusickproc_verify(curkp)
73369896Smckusick	struct kinfo_proc *curkp;
7341573Srgrimes{
73569896Smckusick	struct kinfo_proc newkp;
73641880Sbde	int mib[4];
73738534Sdfr	size_t len;
7381573Srgrimes
73937316Sphk	mib[0] = CTL_KERN;
74037316Sphk	mib[1] = KERN_PROC;
74137316Sphk	mib[2] = KERN_PROC_PID;
74269896Smckusick	mib[3] = curkp->ki_pid;
74369896Smckusick	len = sizeof(newkp);
74469896Smckusick	if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1)
74541880Sbde		return (0);
74669896Smckusick	return (curkp->ki_pid == newkp.ki_pid &&
74769896Smckusick	    (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB));
7481573Srgrimes}
7491573Srgrimes
7501573Srgrimesstatic char **
7511573Srgrimeskvm_doargv(kd, kp, nchr, info)
7521573Srgrimes	kvm_t *kd;
75369896Smckusick	struct kinfo_proc *kp;
7541573Srgrimes	int nchr;
75512682Speter	void (*info)(struct ps_strings *, u_long *, int *);
7561573Srgrimes{
75769896Smckusick	char **ap;
7581573Srgrimes	u_long addr;
7591573Srgrimes	int cnt;
76041880Sbde	static struct ps_strings arginfo;
76141880Sbde	static u_long ps_strings;
76214236Speter	size_t len;
7631573Srgrimes
76437316Sphk	if (ps_strings == NULL) {
76541880Sbde		len = sizeof(ps_strings);
76641880Sbde		if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL,
76741880Sbde		    0) == -1)
76837316Sphk			ps_strings = PS_STRINGS;
76937316Sphk	}
77014236Speter
7711573Srgrimes	/*
7721573Srgrimes	 * Pointers are stored at the top of the user stack.
7731573Srgrimes	 */
77469896Smckusick	if (kp->ki_stat == SZOMB ||
77569896Smckusick	    kvm_uread(kd, kp, ps_strings, (char *)&arginfo,
77612682Speter		      sizeof(arginfo)) != sizeof(arginfo))
7771573Srgrimes		return (0);
7781573Srgrimes
7791573Srgrimes	(*info)(&arginfo, &addr, &cnt);
78012682Speter	if (cnt == 0)
78112682Speter		return (0);
78269896Smckusick	ap = kvm_argv(kd, kp, addr, cnt, nchr);
7831573Srgrimes	/*
7841573Srgrimes	 * For live kernels, make sure this process didn't go away.
7851573Srgrimes	 */
78669896Smckusick	if (ap != 0 && ISALIVE(kd) && !proc_verify(kp))
7871573Srgrimes		ap = 0;
7881573Srgrimes	return (ap);
7891573Srgrimes}
7901573Srgrimes
7911573Srgrimes/*
7921573Srgrimes * Get the command args.  This code is now machine independent.
7931573Srgrimes */
7941573Srgrimeschar **
7951573Srgrimeskvm_getargv(kd, kp, nchr)
7961573Srgrimes	kvm_t *kd;
7971573Srgrimes	const struct kinfo_proc *kp;
7981573Srgrimes	int nchr;
7991573Srgrimes{
80053239Sphk	int oid[4];
80158642Sobrien	int i;
80258642Sobrien	size_t bufsz;
80386179Speter	static unsigned long buflen;
80453239Sphk	static char *buf, *p;
80553239Sphk	static char **bufp;
80653239Sphk	static int argc;
80753239Sphk
80855127Speter	if (!ISALIVE(kd)) {
80955127Speter		_kvm_err(kd, kd->program,
81055127Speter		    "cannot read user space from dead kernel");
81155127Speter		return (0);
81255127Speter	}
81355127Speter
81453239Sphk	if (!buflen) {
81558642Sobrien		bufsz = sizeof(buflen);
81653239Sphk		i = sysctlbyname("kern.ps_arg_cache_limit",
81758642Sobrien		    &buflen, &bufsz, NULL, 0);
81853239Sphk		if (i == -1) {
81958642Sobrien			buflen = 0;
82053239Sphk		} else {
82153239Sphk			buf = malloc(buflen);
82253239Sphk			if (buf == NULL)
82353239Sphk				buflen = 0;
82453239Sphk			argc = 32;
82553239Sphk			bufp = malloc(sizeof(char *) * argc);
82653239Sphk		}
82753239Sphk	}
82853239Sphk	if (buf != NULL) {
82953239Sphk		oid[0] = CTL_KERN;
83053239Sphk		oid[1] = KERN_PROC;
83153239Sphk		oid[2] = KERN_PROC_ARGS;
83269896Smckusick		oid[3] = kp->ki_pid;
83358642Sobrien		bufsz = buflen;
83458642Sobrien		i = sysctl(oid, 4, buf, &bufsz, 0, 0);
83558642Sobrien		if (i == 0 && bufsz > 0) {
83653239Sphk			i = 0;
83753239Sphk			p = buf;
83853239Sphk			do {
83953239Sphk				bufp[i++] = p;
84053239Sphk				p += strlen(p) + 1;
84153239Sphk				if (i >= argc) {
84253239Sphk					argc += argc;
84353239Sphk					bufp = realloc(bufp,
84453239Sphk					    sizeof(char *) * argc);
84553239Sphk				}
84658642Sobrien			} while (p < buf + bufsz);
84753239Sphk			bufp[i++] = 0;
84853239Sphk			return (bufp);
84953239Sphk		}
85053239Sphk	}
85169896Smckusick	if (kp->ki_flag & P_SYSTEM)
85253239Sphk		return (NULL);
8531573Srgrimes	return (kvm_doargv(kd, kp, nchr, ps_str_a));
8541573Srgrimes}
8551573Srgrimes
8561573Srgrimeschar **
8571573Srgrimeskvm_getenvv(kd, kp, nchr)
8581573Srgrimes	kvm_t *kd;
8591573Srgrimes	const struct kinfo_proc *kp;
8601573Srgrimes	int nchr;
8611573Srgrimes{
8621573Srgrimes	return (kvm_doargv(kd, kp, nchr, ps_str_e));
8631573Srgrimes}
8641573Srgrimes
8651573Srgrimes/*
8661573Srgrimes * Read from user space.  The user context is given by p.
8671573Srgrimes */
8681573Srgrimesssize_t
86969896Smckusickkvm_uread(kd, kp, uva, buf, len)
8701573Srgrimes	kvm_t *kd;
87169896Smckusick	struct kinfo_proc *kp;
87292913Sobrien	u_long uva;
87392913Sobrien	char *buf;
87492913Sobrien	size_t len;
8751573Srgrimes{
87692913Sobrien	char *cp;
8772029Sdg	char procfile[MAXPATHLEN];
8782029Sdg	ssize_t amount;
8792029Sdg	int fd;
8801573Srgrimes
88114236Speter	if (!ISALIVE(kd)) {
88232568Sbde		_kvm_err(kd, kd->program,
88332568Sbde		    "cannot read user space from dead kernel");
88432568Sbde		return (0);
88514236Speter	}
88614236Speter
88769896Smckusick	sprintf(procfile, "/proc/%d/mem", kp->ki_pid);
8882029Sdg	fd = open(procfile, O_RDONLY, 0);
8892029Sdg	if (fd < 0) {
8902029Sdg		_kvm_err(kd, kd->program, "cannot open %s", procfile);
8912029Sdg		close(fd);
8922029Sdg		return (0);
8932029Sdg	}
8942029Sdg
89532568Sbde	cp = buf;
8961573Srgrimes	while (len > 0) {
89732568Sbde		errno = 0;
8987166Sjoerg		if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) {
89932568Sbde			_kvm_err(kd, kd->program, "invalid address (%x) in %s",
90032568Sbde			    uva, procfile);
9011573Srgrimes			break;
9022029Sdg		}
9034095Sdg		amount = read(fd, cp, len);
9042029Sdg		if (amount < 0) {
90532568Sbde			_kvm_syserr(kd, kd->program, "error reading %s",
90632568Sbde			    procfile);
9072029Sdg			break;
9082029Sdg		}
90932568Sbde		if (amount == 0) {
91032568Sbde			_kvm_err(kd, kd->program, "EOF reading %s", procfile);
91132568Sbde			break;
91232568Sbde		}
9132029Sdg		cp += amount;
9142029Sdg		uva += amount;
9152029Sdg		len -= amount;
9161573Srgrimes	}
9172029Sdg
9182029Sdg	close(fd);
91932568Sbde	return ((ssize_t)(cp - buf));
9201573Srgrimes}
921