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