kvm_proc.c revision 113340
1100384Speter/*- 2100384Speter * Copyright (c) 1989, 1992, 1993 3100384Speter * The Regents of the University of California. All rights reserved. 4100384Speter * 5100384Speter * This code is derived from software developed by the Computer Systems 6100384Speter * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 7100384Speter * BG 91-66 and contributed to Berkeley. 8100384Speter * 9100384Speter * Redistribution and use in source and binary forms, with or without 10100384Speter * modification, are permitted provided that the following conditions 11100384Speter * are met: 12100384Speter * 1. Redistributions of source code must retain the above copyright 13100384Speter * notice, this list of conditions and the following disclaimer. 14100384Speter * 2. Redistributions in binary form must reproduce the above copyright 15100384Speter * notice, this list of conditions and the following disclaimer in the 16100384Speter * documentation and/or other materials provided with the distribution. 17100384Speter * 3. All advertising materials mentioning features or use of this software 18100384Speter * must display the following acknowledgement: 19100384Speter * This product includes software developed by the University of 20100384Speter * California, Berkeley and its contributors. 21100384Speter * 4. Neither the name of the University nor the names of its contributors 22100384Speter * may be used to endorse or promote products derived from this software 23100384Speter * without specific prior written permission. 24100384Speter * 25100384Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26100384Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27118031Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28118031Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29118031Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30104738Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31191673Sjamie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32191673Sjamie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33104738Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34205014Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35205014Snwhitehorn * SUCH DAMAGE. 36100384Speter */ 37100384Speter 38162954Sphk#if 0 39100384Speter#if defined(LIBC_SCCS) && !defined(lint) 40100384Speterstatic char sccsid[] = "@(#)kvm_proc.c 8.3 (Berkeley) 9/23/93"; 41100384Speter#endif /* LIBC_SCCS and not lint */ 42100384Speter#endif 43185435Sbz 44100384Speter#include <sys/cdefs.h> 45161343Sjkim__FBSDID("$FreeBSD: head/lib/libkvm/kvm_proc.c 113340 2003-04-10 17:41:40Z julian $"); 46100384Speter 47100384Speter/* 48100384Speter * Proc traversal interface for kvm. ps and w are (probably) the exclusive 49205014Snwhitehorn * users of this code, so we've factored it out into a separate module. 50151909Sps * Thus, we keep this grunge out of the other kvm applications (i.e., 51100384Speter * most other applications are interested only in open/close/read/nlist). 52100384Speter */ 53100384Speter 54100384Speter#include <sys/param.h> 55183044Sobrien#define _WANT_UCRED /* make ucred.h give us 'struct ucred' */ 56100384Speter#include <sys/ucred.h> 57100384Speter#include <sys/user.h> 58100384Speter#include <sys/proc.h> 59100384Speter#include <sys/exec.h> 60100384Speter#include <sys/stat.h> 61146950Sps#include <sys/ioctl.h> 62100384Speter#include <sys/tty.h> 63100384Speter#include <sys/file.h> 64100384Speter#include <stdio.h> 65100384Speter#include <stdlib.h> 66100384Speter#include <unistd.h> 67100384Speter#include <nlist.h> 68150883Sjhb#include <kvm.h> 69113859Sjhb 70100384Speter#include <vm/vm.h> 71100384Speter#include <vm/vm_param.h> 72100384Speter#include <vm/swap_pager.h> 73183044Sobrien 74162551Sdavidxu#include <sys/sysctl.h> 75100384Speter 76162551Sdavidxu#include <limits.h> 77100384Speter#include <memory.h> 78127140Sjhb#include <paths.h> 79157285Sps 80174381Sjhb#include "kvm_private.h" 81174381Sjhb 82157285Sps#define KREAD(kd, addr, obj) \ 83100384Speter (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) 84191673Sjamie 85191673Sjamie/* 86191673Sjamie * Read proc's from memory file into buffer bp, which has space to hold 87191673Sjamie * at most maxcnt procs. 88100384Speter */ 89100384Speterstatic int 90100384Speterkvm_proclist(kd, what, arg, p, bp, maxcnt) 91100384Speter kvm_t *kd; 92100384Speter int what, arg; 93100384Speter struct proc *p; 94100384Speter struct kinfo_proc *bp; 95151582Sps int maxcnt; 96205014Snwhitehorn{ 97151582Sps int cnt = 0; 98183188Sobrien struct kinfo_proc kinfo_proc, *kp; 99183188Sobrien struct pgrp pgrp; 100119333Speter struct session sess; 101119333Speter struct tty tty; 102174380Sjhb struct vmspace vmspace; 103163018Sdavidxu struct procsig procsig; 104119333Speter struct pstats pstats; 105100384Speter struct ucred ucred; 106121719Speter struct thread mtd; 107121719Speter struct kse mke; 108174377Sjhb struct ksegrp mkg; 109121719Speter struct proc proc; 110121719Speter struct proc pproc; 111174377Sjhb struct timeval tv; 112174377Sjhb 113174377Sjhb kp = &kinfo_proc; 114174377Sjhb kp->ki_structsize = sizeof(kinfo_proc); 115174377Sjhb for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) { 116174377Sjhb memset(kp, 0, sizeof *kp); 117121719Speter if (KREAD(kd, (u_long)p, &proc)) { 118174377Sjhb _kvm_err(kd, kd->program, "can't read proc at %x", p); 119174377Sjhb return (-1); 120174377Sjhb } 121205014Snwhitehorn if (proc.p_state != PRS_ZOMBIE) { 122205014Snwhitehorn if (KREAD(kd, (u_long)TAILQ_FIRST(&proc.p_threads), 123205014Snwhitehorn &mtd)) { 124205014Snwhitehorn _kvm_err(kd, kd->program, 125205014Snwhitehorn "can't read thread at %x", 126205014Snwhitehorn TAILQ_FIRST(&proc.p_threads)); 127205014Snwhitehorn return (-1); 128205014Snwhitehorn } 129205014Snwhitehorn if (proc.p_flag & P_THREADED == 0) { 130205014Snwhitehorn if (KREAD(kd, 131207007Skib (u_long)TAILQ_FIRST(&proc.p_ksegrps), 132207007Skib &mkg)) { 133207007Skib _kvm_err(kd, kd->program, 134207007Skib "can't read ksegrp at %x", 135207007Skib TAILQ_FIRST(&proc.p_ksegrps)); 136207007Skib return (-1); 137207007Skib } 138207007Skib if (KREAD(kd, 139207007Skib (u_long)TAILQ_FIRST(&mkg.kg_kseq), &mke)) { 140207007Skib _kvm_err(kd, kd->program, 141207007Skib "can't read kse at %x", 142207007Skib TAILQ_FIRST(&mkg.kg_kseq)); 143207007Skib return (-1); 144207007Skib } 145207007Skib } 146207007Skib } 147207007Skib if (KREAD(kd, (u_long)proc.p_ucred, &ucred) == 0) { 148207007Skib kp->ki_ruid = ucred.cr_ruid; 149207007Skib kp->ki_svuid = ucred.cr_svuid; 150207007Skib kp->ki_rgid = ucred.cr_rgid; 151207007Skib kp->ki_svgid = ucred.cr_svgid; 152207007Skib kp->ki_ngroups = ucred.cr_ngroups; 153100384Speter bcopy(ucred.cr_groups, kp->ki_groups, 154119333Speter NGROUPS * sizeof(gid_t)); 155100384Speter kp->ki_uid = ucred.cr_uid; 156127140Sjhb } 157127140Sjhb 158136152Sjhb switch(what) { 159100384Speter 160136152Sjhb case KERN_PROC_PID: 161136152Sjhb if (proc.p_pid != (pid_t)arg) 162136152Sjhb continue; 163136152Sjhb break; 164136152Sjhb 165100384Speter case KERN_PROC_UID: 166100384Speter if (kp->ki_uid != (uid_t)arg) 167127140Sjhb continue; 168127140Sjhb break; 169127140Sjhb 170207007Skib case KERN_PROC_RUID: 171127140Sjhb if (kp->ki_ruid != (uid_t)arg) 172100384Speter continue; 173100384Speter break; 174100384Speter } 175100384Speter /* 176128597Smarcel * We're going to add another proc to the set. If this 177174526Sjhb * will overflow the buffer, assume the reason is because 178100384Speter * nprocs (or the proc list) is corrupt and declare an error. 179100384Speter */ 180172003Sjhb if (cnt >= maxcnt) { 181174424Sscottl _kvm_err(kd, kd->program, "nprocs corrupt"); 182156266Sps return (-1); 183100384Speter } 184172003Sjhb /* 185100384Speter * gather kinfo_proc 186100384Speter */ 187100384Speter kp->ki_paddr = p; 188172003Sjhb kp->ki_addr = proc.p_uarea; 189174526Sjhb /* kp->ki_kstack = proc.p_thread.td_kstack; XXXKSE */ 190100384Speter kp->ki_args = proc.p_args; 191100384Speter kp->ki_tracep = proc.p_tracevp; 192100384Speter kp->ki_textvp = proc.p_textvp; 193100384Speter kp->ki_fd = proc.p_fd; 194174526Sjhb kp->ki_vmspace = proc.p_vmspace; 195174526Sjhb if (proc.p_procsig != NULL) { 196156266Sps if (KREAD(kd, (u_long)proc.p_procsig, &procsig)) { 197156266Sps _kvm_err(kd, kd->program, 198156266Sps "can't read procsig at %x", proc.p_procsig); 199156266Sps return (-1); 200174526Sjhb } 201174526Sjhb kp->ki_sigignore = procsig.ps_sigignore; 202156266Sps kp->ki_sigcatch = procsig.ps_sigcatch; 203156266Sps } 204100384Speter if ((proc.p_sflag & PS_INMEM) && proc.p_stats != NULL) { 205128597Smarcel if (KREAD(kd, (u_long)proc.p_stats, &pstats)) { 206100384Speter _kvm_err(kd, kd->program, 207128597Smarcel "can't read stats at %x", proc.p_stats); 208100384Speter return (-1); 209128260Speter } 210100384Speter kp->ki_start = pstats.p_start; 211147178Spjd kp->ki_rusage = pstats.p_ru; 212147178Spjd kp->ki_childtime.tv_sec = pstats.p_cru.ru_utime.tv_sec + 213147178Spjd pstats.p_cru.ru_stime.tv_sec; 214100384Speter kp->ki_childtime.tv_usec = 215100384Speter pstats.p_cru.ru_utime.tv_usec + 216147178Spjd pstats.p_cru.ru_stime.tv_usec; 217147178Spjd } 218147302Spjd if (proc.p_oppid) 219147302Spjd kp->ki_ppid = proc.p_oppid; 220100384Speter else if (proc.p_pptr) { 221147178Spjd if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) { 222147178Spjd _kvm_err(kd, kd->program, 223174526Sjhb "can't read pproc at %x", proc.p_pptr); 224147178Spjd return (-1); 225147178Spjd } 226147178Spjd kp->ki_ppid = pproc.p_pid; 227147178Spjd } else 228100384Speter kp->ki_ppid = 0; 229147178Spjd if (proc.p_pgrp == NULL) 230100384Speter goto nopgrp; 231100384Speter if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) { 232100384Speter _kvm_err(kd, kd->program, "can't read pgrp at %x", 233128597Smarcel proc.p_pgrp); 234100384Speter return (-1); 235100384Speter } 236119333Speter kp->ki_pgid = pgrp.pg_id; 237119333Speter kp->ki_jobc = pgrp.pg_jobc; 238100384Speter if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) { 239113859Sjhb _kvm_err(kd, kd->program, "can't read session at %x", 240113859Sjhb pgrp.pg_session); 241100384Speter return (-1); 242100384Speter } 243113859Sjhb kp->ki_sid = sess.s_sid; 244113859Sjhb (void)memcpy(kp->ki_login, sess.s_login, 245100384Speter sizeof(kp->ki_login)); 246100384Speter kp->ki_kiflag = sess.s_ttyvp ? KI_CTTY : 0; 247113859Sjhb if (sess.s_leader == p) 248113859Sjhb kp->ki_kiflag |= KI_SLEADER; 249113859Sjhb if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) { 250113859Sjhb if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) { 251113859Sjhb _kvm_err(kd, kd->program, 252113859Sjhb "can't read tty at %x", sess.s_ttyp); 253113859Sjhb return (-1); 254113859Sjhb } 255113859Sjhb kp->ki_tdev = tty.t_dev; 256113859Sjhb if (tty.t_pgrp != NULL) { 257113859Sjhb if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) { 258113859Sjhb _kvm_err(kd, kd->program, 259100384Speter "can't read tpgrp at %x", 260100384Speter tty.t_pgrp); 261100384Speter return (-1); 262100384Speter } 263142059Sjhb kp->ki_tpgid = pgrp.pg_id; 264142059Sjhb } else 265142059Sjhb kp->ki_tpgid = -1; 266142059Sjhb if (tty.t_session != NULL) { 267210431Skib if (KREAD(kd, (u_long)tty.t_session, &sess)) { 268142059Sjhb _kvm_err(kd, kd->program, 269142059Sjhb "can't read session at %x", 270100384Speter tty.t_session); 271142059Sjhb return (-1); 272142059Sjhb } 273142059Sjhb kp->ki_tsid = sess.s_sid; 274100384Speter } 275100384Speter } else { 276142059Sjhbnopgrp: 277142059Sjhb kp->ki_tdev = NODEV; 278142059Sjhb } 279100384Speter if ((proc.p_state != PRS_ZOMBIE) && mtd.td_wmesg) 280142059Sjhb (void)kvm_read(kd, (u_long)mtd.td_wmesg, 281210545Salc kp->ki_wmesg, WMESGLEN); 282210545Salc 283142059Sjhb#ifdef sparc 284210545Salc (void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_rssize, 285210545Salc (char *)&kp->ki_rssize, 286210545Salc sizeof(kp->ki_rssize)); 287142059Sjhb (void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_tsize, 288142059Sjhb (char *)&kp->ki_tsize, 289142059Sjhb 3 * sizeof(kp->ki_rssize)); /* XXX */ 290142059Sjhb#else 291177789Skib (void)kvm_read(kd, (u_long)proc.p_vmspace, 292210545Salc (char *)&vmspace, sizeof(vmspace)); 293177789Skib kp->ki_size = vmspace.vm_map.size; 294177789Skib kp->ki_rssize = vmspace.vm_swrss; /* XXX */ 295177789Skib kp->ki_swrss = vmspace.vm_swrss; 296177789Skib kp->ki_tsize = vmspace.vm_tsize; 297177789Skib kp->ki_dsize = vmspace.vm_dsize; 298177789Skib kp->ki_ssize = vmspace.vm_ssize; 299210475Salc#endif 300142059Sjhb 301210545Salc switch (what) { 302210475Salc 303210475Salc case KERN_PROC_PGRP: 304210475Salc if (kp->ki_pgid != (pid_t)arg) 305142059Sjhb continue; 306142059Sjhb break; 307142059Sjhb 308142059Sjhb case KERN_PROC_TTY: 309142059Sjhb if ((proc.p_flag & P_CONTROLT) == 0 || 310142059Sjhb kp->ki_tdev != (dev_t)arg) 311142059Sjhb continue; 312156440Sups break; 313142059Sjhb } 314142059Sjhb if (proc.p_comm[0] != 0) { 315142059Sjhb strncpy(kp->ki_comm, proc.p_comm, MAXCOMLEN); 316142059Sjhb kp->ki_comm[MAXCOMLEN] = 0; 317142059Sjhb } 318142059Sjhb if ((proc.p_state != PRS_ZOMBIE) && 319156440Sups (mtd.td_blocked != 0)) { 320156440Sups kp->ki_kiflag |= KI_LOCKBLOCK; 321142059Sjhb if (mtd.td_lockname) 322142059Sjhb (void)kvm_read(kd, 323142059Sjhb (u_long)mtd.td_lockname, 324142059Sjhb kp->ki_lockname, LOCKNAMELEN); 325100384Speter kp->ki_lockname[LOCKNAMELEN] = 0; 326142059Sjhb } 327142059Sjhb bintime2timeval(&proc.p_runtime, &tv); 328142059Sjhb kp->ki_runtime = (u_int64_t)tv.tv_sec * 1000000 + tv.tv_usec; 329142059Sjhb kp->ki_pid = proc.p_pid; 330142059Sjhb kp->ki_siglist = proc.p_siglist; 331142059Sjhb SIGSETOR(kp->ki_siglist, mtd.td_siglist); 332142059Sjhb kp->ki_sigmask = mtd.td_sigmask; 333142059Sjhb kp->ki_xstat = proc.p_xstat; 334142059Sjhb kp->ki_acflag = proc.p_acflag; 335100384Speter kp->ki_lock = proc.p_lock; 336100384Speter if (proc.p_state != PRS_ZOMBIE) { 337156440Sups kp->ki_swtime = proc.p_swtime; 338142059Sjhb kp->ki_flag = proc.p_flag; 339142059Sjhb kp->ki_sflag = proc.p_sflag; 340142059Sjhb kp->ki_traceflag = proc.p_traceflag; 341142059Sjhb if (proc.p_state == PRS_NORMAL) { 342142059Sjhb if (TD_ON_RUNQ(&mtd) || 343142059Sjhb TD_CAN_RUN(&mtd) || 344142059Sjhb TD_IS_RUNNING(&mtd)) { 345156440Sups kp->ki_stat = SRUN; 346156440Sups } else if (mtd.td_state == 347142059Sjhb TDS_INHIBITED) { 348142059Sjhb if (P_SHOULDSTOP(&proc)) { 349142059Sjhb kp->ki_stat = SSTOP; 350142059Sjhb } else if ( 351142059Sjhb TD_IS_SLEEPING(&mtd)) { 352100384Speter kp->ki_stat = SSLEEP; 353100384Speter } else if (TD_ON_LOCK(&mtd)) { 354142059Sjhb kp->ki_stat = SLOCK; 355156440Sups } else { 356156440Sups kp->ki_stat = SWAIT; 357210429Salc } 358156440Sups } 359100384Speter } else { 360100384Speter kp->ki_stat = SIDL; 361142059Sjhb } 362142059Sjhb /* Stuff from the thread */ 363142059Sjhb kp->ki_pri.pri_level = mtd.td_priority; 364142059Sjhb kp->ki_pri.pri_native = mtd.td_base_pri; 365142059Sjhb kp->ki_lastcpu = mtd.td_lastcpu; 366142059Sjhb kp->ki_wchan = mtd.td_wchan; 367142059Sjhb kp->ki_oncpu = mtd.td_oncpu; 368142059Sjhb 369142059Sjhb if (!(proc.p_flag & P_THREADED)) { 370142059Sjhb /* stuff from the ksegrp */ 371142059Sjhb kp->ki_slptime = mkg.kg_slptime; 372142059Sjhb kp->ki_pri.pri_class = mkg.kg_pri_class; 373142059Sjhb kp->ki_pri.pri_user = mkg.kg_user_pri; 374177789Skib kp->ki_nice = mkg.kg_nice; 375177789Skib kp->ki_estcpu = mkg.kg_estcpu; 376177789Skib 377177789Skib /* Stuff from the kse */ 378177789Skib kp->ki_pctcpu = mke.ke_pctcpu; 379177789Skib kp->ki_rqindex = mke.ke_rqindex; 380177789Skib } else { 381177789Skib kp->ki_tdflags = -1; 382177789Skib /* All the rest are 0 for now */ 383177789Skib } 384177789Skib } else { 385177789Skib kp->ki_stat = SZOMB; 386177789Skib } 387177789Skib bcopy(&kinfo_proc, bp, sizeof(kinfo_proc)); 388177789Skib ++bp; 389114987Speter ++cnt; 390100384Speter } 391119333Speter return (cnt); 392119333Speter} 393100384Speter 394100384Speter/* 395100384Speter * Build proc info array by reading in proc list from a crash dump. 396100384Speter * Return number of procs read. maxcnt is the max we will read. 397100384Speter */ 398100384Speterstatic int 399100384Speterkvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt) 400100384Speter kvm_t *kd; 401100384Speter int what, arg; 402100384Speter u_long a_allproc; 403100384Speter u_long a_zombproc; 404100384Speter int maxcnt; 405100384Speter{ 406100384Speter struct kinfo_proc *bp = kd->procbase; 407100384Speter int acnt, zcnt; 408100384Speter struct proc *p; 409100384Speter 410100384Speter if (KREAD(kd, a_allproc, &p)) { 411100384Speter _kvm_err(kd, kd->program, "cannot read allproc"); 412100384Speter return (-1); 413100384Speter } 414100384Speter acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt); 415100384Speter if (acnt < 0) 416100384Speter return (acnt); 417100384Speter 418100384Speter if (KREAD(kd, a_zombproc, &p)) { 419100384Speter _kvm_err(kd, kd->program, "cannot read zombproc"); 420100384Speter return (-1); 421100384Speter } 422100384Speter zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt); 423107849Salfred if (zcnt < 0) 424107849Salfred zcnt = 0; 425107849Salfred 426107849Salfred return (acnt + zcnt); 427100384Speter} 428100384Speter 429100384Speterstruct kinfo_proc * 430100384Speterkvm_getprocs(kd, op, arg, cnt) 431100384Speter kvm_t *kd; 432100384Speter int op, arg; 433100384Speter int *cnt; 434100384Speter{ 435100384Speter int mib[4], st, nprocs; 436114987Speter size_t size; 437100384Speter 438100384Speter if (kd->procbase != 0) { 439119333Speter free((void *)kd->procbase); 440100384Speter /* 441100384Speter * Clear this pointer in case this call fails. Otherwise, 442107849Salfred * kvm_close() will free it again. 443107849Salfred */ 444107849Salfred kd->procbase = 0; 445107849Salfred } 446107849Salfred if (ISALIVE(kd)) { 447205014Snwhitehorn size = 0; 448114987Speter mib[0] = CTL_KERN; 449100384Speter mib[1] = KERN_PROC; 450100384Speter mib[2] = op; 451100384Speter mib[3] = arg; 452100384Speter st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, NULL, &size, NULL, 0); 453100384Speter if (st == -1) { 454100384Speter _kvm_syserr(kd, kd->program, "kvm_getprocs"); 455100384Speter return (0); 456100384Speter } 457100384Speter /* 458100384Speter * We can't continue with a size of 0 because we pass 459100384Speter * it to realloc() (via _kvm_realloc()), and passing 0 460100384Speter * to realloc() results in undefined behavior. 461100384Speter */ 462119333Speter if (size == 0) { 463119333Speter /* 464119333Speter * XXX: We should probably return an invalid, 465100384Speter * but non-NULL, pointer here so any client 466100384Speter * program trying to dereference it will 467100384Speter * crash. However, _kvm_freeprocs() calls 468100384Speter * free() on kd->procbase if it isn't NULL, 469100384Speter * and free()'ing a junk pointer isn't good. 470100384Speter * Then again, _kvm_freeprocs() isn't used 471119333Speter * anywhere . . . 472100384Speter */ 473100384Speter kd->procbase = _kvm_malloc(kd, 1); 474100384Speter goto liveout; 475100384Speter } 476100384Speter do { 477100384Speter size += size / 10; 478100384Speter kd->procbase = (struct kinfo_proc *) 479100384Speter _kvm_realloc(kd, kd->procbase, size); 480100384Speter if (kd->procbase == 0) 481100384Speter return (0); 482100384Speter st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, 483100384Speter kd->procbase, &size, NULL, 0); 484100384Speter } while (st == -1 && errno == ENOMEM); 485100384Speter if (st == -1) { 486100384Speter _kvm_syserr(kd, kd->program, "kvm_getprocs"); 487100384Speter return (0); 488100384Speter } 489100384Speter /* 490100384Speter * We have to check the size again because sysctl() 491169181Salc * may "round up" oldlenp if oldp is NULL; hence it 492100384Speter * might've told us that there was data to get when 493100384Speter * there really isn't any. 494100384Speter */ 495100384Speter if (size > 0 && 496100384Speter kd->procbase->ki_structsize != sizeof(struct kinfo_proc)) { 497100384Speter _kvm_err(kd, kd->program, 498107849Salfred "kinfo_proc size mismatch (expected %d, got %d)", 499107849Salfred sizeof(struct kinfo_proc), 500107849Salfred kd->procbase->ki_structsize); 501107849Salfred return (0); 502100384Speter } 503100384Speterliveout: 504100384Speter nprocs = size == 0 ? 0 : size / kd->procbase->ki_structsize; 505100384Speter } else { 506100384Speter struct nlist nl[4], *p; 507100384Speter 508100384Speter nl[0].n_name = "_nprocs"; 509100384Speter nl[1].n_name = "_allproc"; 510100384Speter nl[2].n_name = "_zombproc"; 511100384Speter nl[3].n_name = 0; 512100384Speter 513100384Speter if (kvm_nlist(kd, nl) != 0) { 514100384Speter for (p = nl; p->n_type != 0; ++p) 515100384Speter ; 516100384Speter _kvm_err(kd, kd->program, 517100384Speter "%s: no such symbol", p->n_name); 518100384Speter return (0); 519100384Speter } 520114987Speter if (KREAD(kd, nl[0].n_value, &nprocs)) { 521100384Speter _kvm_err(kd, kd->program, "can't read nprocs"); 522107849Salfred return (0); 523107849Salfred } 524107849Salfred size = nprocs * sizeof(struct kinfo_proc); 525107849Salfred kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size); 526107849Salfred if (kd->procbase == 0) 527107849Salfred return (0); 528100384Speter 529100384Speter nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value, 530100384Speter nl[2].n_value, nprocs); 531100384Speter#ifdef notdef 532171215Speter size = nprocs * sizeof(struct kinfo_proc); 533171215Speter (void)realloc(kd->procbase, size); 534171215Speter#endif 535171215Speter } 536171215Speter *cnt = nprocs; 537171215Speter return (kd->procbase); 538171215Speter} 539171215Speter 540171215Spetervoid 541171215Speter_kvm_freeprocs(kd) 542171215Speter kvm_t *kd; 543205014Snwhitehorn{ 544205014Snwhitehorn if (kd->procbase) { 545171215Speter free(kd->procbase); 546171215Speter kd->procbase = 0; 547171215Speter } 548171215Speter} 549171215Speter 550100384Spetervoid * 551119333Speter_kvm_realloc(kd, p, n) 552100384Speter kvm_t *kd; 553142059Sjhb void *p; 554142059Sjhb size_t n; 555100384Speter{ 556100384Speter void *np = (void *)realloc(p, n); 557142059Sjhb 558142059Sjhb if (np == 0) { 559100384Speter free(p); 560100384Speter _kvm_err(kd, kd->program, "out of memory"); 561142059Sjhb } 562142059Sjhb return (np); 563142059Sjhb} 564142059Sjhb 565142059Sjhb#ifndef MAX 566142059Sjhb#define MAX(a, b) ((a) > (b) ? (a) : (b)) 567142059Sjhb#endif 568100384Speter 569142059Sjhb/* 570142059Sjhb * Read in an argument vector from the user address space of process kp. 571142059Sjhb * addr if the user-space base address of narg null-terminated contiguous 572100384Speter * strings. This is used to read in both the command arguments and 573100384Speter * environment strings. Read at most maxcnt characters of strings. 574100384Speter */ 575125171Speterstatic char ** 576125171Speterkvm_argv(kd, kp, addr, narg, maxcnt) 577142059Sjhb kvm_t *kd; 578142059Sjhb struct kinfo_proc *kp; 579125171Speter u_long addr; 580125171Speter int narg; 581142059Sjhb int maxcnt; 582142059Sjhb{ 583125171Speter char *np, *cp, *ep, *ap; 584142059Sjhb u_long oaddr = -1; 585142059Sjhb int len, cc; 586142059Sjhb char **argv; 587125171Speter 588125171Speter /* 589125171Speter * Check that there aren't an unreasonable number of agruments, 590119333Speter * and that the address is in user space. 591100384Speter */ 592142059Sjhb if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS) 593142059Sjhb return (0); 594100384Speter 595100384Speter /* 596142059Sjhb * kd->argv : work space for fetching the strings from the target 597142059Sjhb * process's space, and is converted for returning to caller 598100384Speter */ 599100384Speter if (kd->argv == 0) { 600142059Sjhb /* 601142059Sjhb * Try to avoid reallocs. 602142059Sjhb */ 603142059Sjhb kd->argc = MAX(narg + 1, 32); 604142059Sjhb kd->argv = (char **)_kvm_malloc(kd, kd->argc * 605100384Speter sizeof(*kd->argv)); 606142059Sjhb if (kd->argv == 0) 607100384Speter return (0); 608197049Skib } else if (narg + 1 > kd->argc) { 609197049Skib kd->argc = MAX(2 * kd->argc, narg + 1); 610100384Speter kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc * 611100384Speter sizeof(*kd->argv)); 612198508Skib if (kd->argv == 0) 613198508Skib return (0); 614198508Skib } 615198508Skib /* 616198508Skib * kd->argspc : returned to user, this is where the kd->argv 617198508Skib * arrays are left pointing to the collected strings. 618198508Skib */ 619198508Skib if (kd->argspc == 0) { 620198508Skib kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE); 621198508Skib if (kd->argspc == 0) 622198508Skib return (0); 623198508Skib kd->arglen = PAGE_SIZE; 624198508Skib } 625198508Skib /* 626198508Skib * kd->argbuf : used to pull in pages from the target process. 627198508Skib * the strings are copied out of here. 628198508Skib */ 629198508Skib if (kd->argbuf == 0) { 630198508Skib kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE); 631198508Skib if (kd->argbuf == 0) 632198508Skib return (0); 633198508Skib } 634198508Skib 635198508Skib /* Pull in the target process'es argv vector */ 636198508Skib cc = sizeof(char *) * narg; 637198508Skib if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc) 638198508Skib return (0); 639198508Skib /* 640198508Skib * ap : saved start address of string we're working on in kd->argspc 641198508Skib * np : pointer to next place to write in kd->argspc 642198508Skib * len: length of data in kd->argspc 643198508Skib * argv: pointer to the argv vector that we are hunting around the 644198508Skib * target process space for, and converting to addresses in 645198508Skib * our address space (kd->argspc). 646146950Sps */ 647146950Sps ap = np = kd->argspc; 648146950Sps argv = kd->argv; 649146950Sps len = 0; 650146950Sps /* 651146950Sps * Loop over pages, filling in the argument vector. 652146950Sps * Note that the argv strings could be pointing *anywhere* in 653146950Sps * the user address space and are no longer contiguous. 654146950Sps * Note that *argv is modified when we are going to fetch a string 655146950Sps * that crosses a page boundary. We copy the next part of the string 656146950Sps * into to "np" and eventually convert the pointer. 657146950Sps */ 658146950Sps while (argv < kd->argv + narg && *argv != 0) { 659146950Sps 660146950Sps /* get the address that the current argv string is on */ 661146950Sps addr = (u_long)*argv & ~(PAGE_SIZE - 1); 662146950Sps 663146950Sps /* is it the same page as the last one? */ 664146950Sps if (addr != oaddr) { 665146950Sps if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) != 666146950Sps PAGE_SIZE) 667146950Sps return (0); 668146950Sps oaddr = addr; 669146950Sps } 670146950Sps 671146950Sps /* offset within the page... kd->argbuf */ 672146950Sps addr = (u_long)*argv & (PAGE_SIZE - 1); 673146950Sps 674146950Sps /* cp = start of string, cc = count of chars in this chunk */ 675146950Sps cp = kd->argbuf + addr; 676146950Sps cc = PAGE_SIZE - addr; 677146950Sps 678146950Sps /* dont get more than asked for by user process */ 679146950Sps if (maxcnt > 0 && cc > maxcnt - len) 680146950Sps cc = maxcnt - len; 681146950Sps 682146950Sps /* pointer to end of string if we found it in this page */ 683146950Sps ep = memchr(cp, '\0', cc); 684146950Sps if (ep != 0) 685146950Sps cc = ep - cp + 1; 686146950Sps /* 687146950Sps * at this point, cc is the count of the chars that we are 688146950Sps * going to retrieve this time. we may or may not have found 689146950Sps * the end of it. (ep points to the null if the end is known) 690146950Sps */ 691146950Sps 692146950Sps /* will we exceed the malloc/realloced buffer? */ 693146950Sps if (len + cc > kd->arglen) { 694146950Sps int off; 695146950Sps char **pp; 696146950Sps char *op = kd->argspc; 697146950Sps 698146950Sps kd->arglen *= 2; 699146950Sps kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, 700146950Sps kd->arglen); 701146950Sps if (kd->argspc == 0) 702146950Sps return (0); 703100384Speter /* 704119333Speter * Adjust argv pointers in case realloc moved 705114987Speter * the string space. 706114987Speter */ 707142934Sps off = kd->argspc - op; 708146950Sps for (pp = kd->argv; pp < argv; pp++) 709146950Sps *pp += off; 710146950Sps ap += off; 711146950Sps np += off; 712114987Speter } 713114987Speter /* np = where to put the next part of the string in kd->argspc*/ 714114987Speter /* np is kinda redundant.. could use "kd->argspc + len" */ 715114987Speter memcpy(np, cp, cc); 716114987Speter np += cc; /* inc counters */ 717114987Speter len += cc; 718114987Speter 719114987Speter /* 720142934Sps * if end of string found, set the *argv pointer to the 721142934Sps * saved beginning of string, and advance. argv points to 722142934Sps * somewhere in kd->argv.. This is initially relative 723146950Sps * to the target process, but when we close it off, we set 724146950Sps * it to point in our address space. 725142934Sps */ 726114987Speter if (ep != 0) { 727114987Speter *argv++ = ap; 728114987Speter ap = np; 729119333Speter } else { 730119333Speter /* update the address relative to the target process */ 731100384Speter *argv += cc; 732123425Speter } 733123425Speter 734123425Speter if (maxcnt > 0 && len >= maxcnt) { 735123425Speter /* 736100384Speter * We're stopping prematurely. Terminate the 737123425Speter * current string. 738123425Speter */ 739123425Speter if (ep == 0) { 740123425Speter *np = '\0'; 741123425Speter *argv++ = ap; 742100384Speter } 743123425Speter break; 744123425Speter } 745123425Speter } 746123425Speter /* Make sure argv is terminated. */ 747100384Speter *argv = 0; 748100384Speter return (kd->argv); 749100384Speter} 750100384Speter 751100384Speterstatic void 752119333Speterps_str_a(p, addr, n) 753100384Speter struct ps_strings *p; 754136152Sjhb u_long *addr; 755136152Sjhb int *n; 756100384Speter{ 757100384Speter *addr = (u_long)p->ps_argvstr; 758136152Sjhb *n = p->ps_nargvstr; 759100384Speter} 760100384Speter 761136152Sjhbstatic void 762207007Skibps_str_e(p, addr, n) 763136152Sjhb struct ps_strings *p; 764100384Speter u_long *addr; 765100384Speter int *n; 766100384Speter{ 767100384Speter *addr = (u_long)p->ps_envstr; 768144450Sjhb *n = p->ps_nenvstr; 769144450Sjhb} 770100384Speter 771144450Sjhb/* 772144450Sjhb * Determine if the proc indicated by p is still active. 773144450Sjhb * This test is not 100% foolproof in theory, but chances of 774144450Sjhb * being wrong are very low. 775144450Sjhb */ 776100384Speterstatic int 777144450Sjhbproc_verify(curkp) 778144450Sjhb struct kinfo_proc *curkp; 779100384Speter{ 780144450Sjhb struct kinfo_proc newkp; 781144450Sjhb int mib[4]; 782144450Sjhb size_t len; 783144450Sjhb 784144450Sjhb mib[0] = CTL_KERN; 785144450Sjhb mib[1] = KERN_PROC; 786144450Sjhb mib[2] = KERN_PROC_PID; 787144450Sjhb mib[3] = curkp->ki_pid; 788144450Sjhb len = sizeof(newkp); 789144450Sjhb if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1) 790144450Sjhb return (0); 791100384Speter return (curkp->ki_pid == newkp.ki_pid && 792144450Sjhb (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB)); 793144450Sjhb} 794144450Sjhb 795144450Sjhbstatic char ** 796144450Sjhbkvm_doargv(kd, kp, nchr, info) 797144450Sjhb kvm_t *kd; 798144450Sjhb struct kinfo_proc *kp; 799144450Sjhb int nchr; 800144450Sjhb void (*info)(struct ps_strings *, u_long *, int *); 801144450Sjhb{ 802144450Sjhb char **ap; 803144450Sjhb u_long addr; 804144450Sjhb int cnt; 805144450Sjhb static struct ps_strings arginfo; 806144450Sjhb static u_long ps_strings; 807144450Sjhb size_t len; 808100384Speter 809144450Sjhb if (ps_strings == NULL) { 810144450Sjhb len = sizeof(ps_strings); 811144450Sjhb if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL, 812144450Sjhb 0) == -1) 813144450Sjhb ps_strings = PS_STRINGS; 814100384Speter } 815144450Sjhb 816144450Sjhb /* 817144450Sjhb * Pointers are stored at the top of the user stack. 818144450Sjhb */ 819144450Sjhb if (kp->ki_stat == SZOMB || 820100384Speter kvm_uread(kd, kp, ps_strings, (char *)&arginfo, 821100384Speter sizeof(arginfo)) != sizeof(arginfo)) 822100384Speter return (0); 823100384Speter 824119333Speter (*info)(&arginfo, &addr, &cnt); 825100384Speter if (cnt == 0) 826144450Sjhb return (0); 827144450Sjhb ap = kvm_argv(kd, kp, addr, cnt, nchr); 828100384Speter /* 829144450Sjhb * For live kernels, make sure this process didn't go away. 830144450Sjhb */ 831144450Sjhb if (ap != 0 && ISALIVE(kd) && !proc_verify(kp)) 832144450Sjhb ap = 0; 833144450Sjhb return (ap); 834100384Speter} 835100384Speter 836100384Speter/* 837100384Speter * Get the command args. This code is now machine independent. 838147813Sjhb */ 839147813Sjhbchar ** 840147813Sjhbkvm_getargv(kd, kp, nchr) 841147813Sjhb kvm_t *kd; 842147813Sjhb const struct kinfo_proc *kp; 843147813Sjhb int nchr; 844147813Sjhb{ 845147813Sjhb int oid[4]; 846205014Snwhitehorn int i; 847147813Sjhb size_t bufsz; 848147813Sjhb static unsigned long buflen; 849147813Sjhb static char *buf, *p; 850147813Sjhb static char **bufp; 851147813Sjhb static int argc; 852147813Sjhb 853147813Sjhb if (!ISALIVE(kd)) { 854147813Sjhb _kvm_err(kd, kd->program, 855147813Sjhb "cannot read user space from dead kernel"); 856147813Sjhb return (0); 857147813Sjhb } 858147813Sjhb 859147813Sjhb if (!buflen) { 860205014Snwhitehorn bufsz = sizeof(buflen); 861147813Sjhb i = sysctlbyname("kern.ps_arg_cache_limit", 862147813Sjhb &buflen, &bufsz, NULL, 0); 863147813Sjhb if (i == -1) { 864147813Sjhb buflen = 0; 865205319Skib } else { 866151909Sps buf = malloc(buflen); 867151359Sps if (buf == NULL) 868151359Sps buflen = 0; 869151359Sps argc = 32; 870151909Sps bufp = malloc(sizeof(char *) * argc); 871151909Sps } 872151359Sps } 873151359Sps if (buf != NULL) { 874151909Sps oid[0] = CTL_KERN; 875151359Sps oid[1] = KERN_PROC; 876151359Sps oid[2] = KERN_PROC_ARGS; 877151359Sps oid[3] = kp->ki_pid; 878151909Sps bufsz = buflen; 879151359Sps i = sysctl(oid, 4, buf, &bufsz, 0, 0); 880151909Sps if (i == 0 && bufsz > 0) { 881151359Sps i = 0; 882151909Sps p = buf; 883151359Sps do { 884151359Sps bufp[i++] = p; 885151909Sps p += strlen(p) + 1; 886151909Sps if (i >= argc) { 887151359Sps argc += argc; 888151909Sps bufp = realloc(bufp, 889151359Sps sizeof(char *) * argc); 890151359Sps } 891151359Sps } while (p < buf + bufsz); 892151359Sps bufp[i++] = 0; 893151359Sps return (bufp); 894151359Sps } 895151359Sps } 896151359Sps if (kp->ki_flag & P_SYSTEM) 897151359Sps return (NULL); 898151359Sps return (kvm_doargv(kd, kp, nchr, ps_str_a)); 899151359Sps} 900151359Sps 901151359Spschar ** 902151359Spskvm_getenvv(kd, kp, nchr) 903151359Sps kvm_t *kd; 904151359Sps const struct kinfo_proc *kp; 905151359Sps int nchr; 906151359Sps{ 907151359Sps return (kvm_doargv(kd, kp, nchr, ps_str_e)); 908151909Sps} 909151359Sps 910151359Sps/* 911151359Sps * Read from user space. The user context is given by p. 912151359Sps */ 913151359Spsssize_t 914151359Spskvm_uread(kd, kp, uva, buf, len) 915151359Sps kvm_t *kd; 916151359Sps struct kinfo_proc *kp; 917151359Sps u_long uva; 918151359Sps char *buf; 919151359Sps size_t len; 920151359Sps{ 921151359Sps char *cp; 922151359Sps char procfile[MAXPATHLEN]; 923151359Sps ssize_t amount; 924151359Sps int fd; 925151359Sps 926151359Sps if (!ISALIVE(kd)) { 927151359Sps _kvm_err(kd, kd->program, 928151909Sps "cannot read user space from dead kernel"); 929151909Sps return (0); 930151909Sps } 931151909Sps 932151909Sps sprintf(procfile, "/proc/%d/mem", kp->ki_pid); 933151909Sps fd = open(procfile, O_RDONLY, 0); 934151909Sps if (fd < 0) { 935151909Sps _kvm_err(kd, kd->program, "cannot open %s", procfile); 936151909Sps close(fd); 937151909Sps return (0); 938151909Sps } 939151909Sps 940151909Sps cp = buf; 941151909Sps while (len > 0) { 942151909Sps errno = 0; 943151909Sps if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) { 944151909Sps _kvm_err(kd, kd->program, "invalid address (%x) in %s", 945151909Sps uva, procfile); 946151909Sps break; 947151909Sps } 948151909Sps amount = read(fd, cp, len); 949151909Sps if (amount < 0) { 950151909Sps _kvm_syserr(kd, kd->program, "error reading %s", 951151909Sps procfile); 952151909Sps break; 953151909Sps } 954151909Sps if (amount == 0) { 955151909Sps _kvm_err(kd, kd->program, "EOF reading %s", procfile); 956151909Sps break; 957151909Sps } 958151909Sps cp += amount; 959151909Sps uva += amount; 960151909Sps len -= amount; 961151909Sps } 962151909Sps 963151909Sps close(fd); 964151909Sps return ((ssize_t)(cp - buf)); 965151909Sps} 966151909Sps