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