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