* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software developed by the Computer Systems
* Engineering group at Lawrence Berkeley Laboratory under DARPA contract
* BG 91-66 and contributed to Berkeley.
* %sccs.include.redist.c%
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)kvm_proc.c 5.25 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
* Proc traversal interface for kvm. ps and w are (probably) the exclusive
* users of this code, so we've factored it out into a separate module.
* Thus, we keep this grunge out of the other kvm applications (i.e.,
* most other applications are interested only in open/close/read/nlist).
#include <vm/swap_pager.h>
#include <sys/kinfo_proc.h>
kvm_readswap(kd
, p
, va
, cnt
)
register u_long addr
, head
;
register u_long offset
, pagestart
, sbstart
, pgoff
;
register off_t seekpoint
;
struct pager_struct pager
;
head
= (u_long
)&p
->p_vmspace
->vm_map
.header
;
* Look through the address map for the memory object
* that corresponds to the given virtual address.
* The header just has the entire valid range.
if (kvm_read(kd
, addr
, (char *)&vme
, sizeof(vme
)) !=
if (va
>= vme
.start
&& va
<= vme
.end
&&
vme
.object
.vm_object
!= 0)
if (addr
== 0 || addr
== head
)
* We found the right object -- follow shadow links.
offset
= va
- vme
.start
+ vme
.offset
;
addr
= (u_long
)vme
.object
.vm_object
;
if (kvm_read(kd
, addr
, (char *)&vmo
, sizeof(vmo
)) !=
addr
= (u_long
)vmo
.shadow
;
offset
+= vmo
.shadow_offset
;
offset
+= vmo
.paging_offset
;
* Read in the pager info and make sure it's a swap device.
addr
= (u_long
)vmo
.pager
;
if (kvm_read(kd
, addr
, (char *)&pager
, sizeof(pager
)) != sizeof(pager
)
|| pager
.pg_type
!= PG_SWAP
)
* Read in the swap_pager private data, and compute the
addr
= (u_long
)pager
.pg_data
;
if (kvm_read(kd
, addr
, (char *)&swap
, sizeof(swap
)) != sizeof(swap
))
ix
= offset
/ dbtob(swap
.sw_bsize
);
if (swap
.sw_blocks
== 0 || ix
>= swap
.sw_nblocks
)
addr
= (u_long
)&swap
.sw_blocks
[ix
];
if (kvm_read(kd
, addr
, (char *)&swb
, sizeof(swb
)) != sizeof(swb
))
sbstart
= (offset
/ dbtob(swap
.sw_bsize
)) * dbtob(swap
.sw_bsize
);
pagestart
= offset
/ NBPG
;
pgoff
= pagestart
- sbstart
;
if (swb
.swb_block
== 0 || (swb
.swb_mask
& (1 << pgoff
)) == 0)
seekpoint
= dbtob(swb
.swb_block
) + ctob(pgoff
);
if (lseek(kd
->swfd
, seekpoint
, 0) == -1 && errno
!= 0)
if (read(kd
->swfd
, page
, sizeof(page
)) != sizeof(page
))
#define KREAD(kd, addr, obj) \
(kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
* Read proc's from memory file into buffer bp, which has space to hold
kvm_proclist(kd
, what
, arg
, p
, bp
, maxcnt
)
for (; cnt
< maxcnt
&& p
!= 0; p
= proc
.p_nxt
) {
if (KREAD(kd
, (u_long
)p
, &proc
)) {
_kvm_err(kd
, kd
->program
, "can't read proc at %x", p
);
if (KREAD(kd
, (u_long
)proc
.p_cred
, &eproc
.e_pcred
) == 0)
KREAD(kd
, (u_long
)eproc
.e_pcred
.pc_ucred
,
if (proc
.p_pid
!= (pid_t
)arg
)
if (eproc
.e_ucred
.cr_uid
!= (uid_t
)arg
)
if (eproc
.e_pcred
.p_ruid
!= (uid_t
)arg
)
* We're going to add another proc to the set. If this
* will overflow the buffer, assume the reason is because
* nprocs (or the proc list) is corrupt and declare an error.
_kvm_err(kd
, kd
->program
, "nprocs corrupt");
if (KREAD(kd
, (u_long
)proc
.p_pgrp
, &pgrp
)) {
_kvm_err(kd
, kd
->program
, "can't read pgrp at %x",
eproc
.e_sess
= pgrp
.pg_session
;
eproc
.e_pgid
= pgrp
.pg_id
;
eproc
.e_jobc
= pgrp
.pg_jobc
;
if (KREAD(kd
, (u_long
)pgrp
.pg_session
, &sess
)) {
_kvm_err(kd
, kd
->program
, "can't read session at %x",
if ((proc
.p_flag
& SCTTY
) && sess
.s_ttyp
!= NULL
) {
if (KREAD(kd
, (u_long
)sess
.s_ttyp
, &tty
)) {
_kvm_err(kd
, kd
->program
,
"can't read tty at %x", sess
.s_ttyp
);
eproc
.e_tdev
= tty
.t_dev
;
eproc
.e_tsess
= tty
.t_session
;
if (tty
.t_pgrp
!= NULL
) {
if (KREAD(kd
, (u_long
)tty
.t_pgrp
, &pgrp
)) {
_kvm_err(kd
, kd
->program
,
"can't read tpgrp at &x",
eproc
.e_tpgid
= pgrp
.pg_id
;
eproc
.e_flag
= sess
.s_ttyvp
? EPROC_CTTY
: 0;
eproc
.e_flag
|= EPROC_SLEADER
;
(void)kvm_read(kd
, (u_long
)proc
.p_wmesg
,
eproc
.e_wmesg
, WMESGLEN
);
(void)kvm_read(kd
, (u_long
)&proc
.p_vmspace
->vm_rssize
,
(char *)&eproc
.e_vm
.vm_rssize
,
sizeof(eproc
.e_vm
.vm_rssize
));
(void)kvm_read(kd
, (u_long
)&proc
.p_vmspace
->vm_tsize
,
(char *)&eproc
.e_vm
.vm_tsize
,
3 * sizeof(eproc
.e_vm
.vm_rssize
)); /* XXX */
(void)kvm_read(kd
, (u_long
)proc
.p_vmspace
,
(char *)&eproc
.e_vm
, sizeof(eproc
.e_vm
));
eproc
.e_xsize
= eproc
.e_xrssize
= 0;
eproc
.e_xccount
= eproc
.e_xswrss
= 0;
if (eproc
.e_pgid
!= (pid_t
)arg
)
if ((proc
.p_flag
&SCTTY
) == 0 ||
eproc
.e_tdev
!= (dev_t
)arg
)
bcopy((char *)&proc
, (char *)&bp
->kp_proc
, sizeof(proc
));
bcopy((char *)&eproc
, (char *)&bp
->kp_eproc
, sizeof(eproc
));
* Build proc info array by reading in proc list from a crash dump.
* Return number of procs read. maxcnt is the max we will read.
kvm_deadprocs(kd
, what
, arg
, a_allproc
, a_zombproc
, maxcnt
)
register struct kinfo_proc
*bp
= kd
->procbase
;
if (KREAD(kd
, a_allproc
, &p
)) {
_kvm_err(kd
, kd
->program
, "cannot read allproc");
acnt
= kvm_proclist(kd
, what
, arg
, p
, bp
, maxcnt
);
if (KREAD(kd
, a_zombproc
, &p
)) {
_kvm_err(kd
, kd
->program
, "cannot read zombproc");
zcnt
= kvm_proclist(kd
, what
, arg
, p
, bp
+ acnt
, maxcnt
- acnt
);
kvm_getprocs(kd
, op
, arg
, cnt
)
free((void *)kd
->procbase
);
* Clear this pointer in case this call fails. Otherwise,
* kvm_close() will free it again.
st
= getkerninfo(op
, NULL
, &size
, arg
);
_kvm_syserr(kd
, kd
->program
, "kvm_getprocs");
kd
->procbase
= (struct kinfo_proc
*)_kvm_malloc(kd
, st
);
st
= getkerninfo(op
, kd
->procbase
, &size
, arg
);
_kvm_syserr(kd
, kd
->program
, "kvm_getprocs");
if (size
% sizeof(struct kinfo_proc
) != 0) {
_kvm_err(kd
, kd
->program
,
"proc size mismatch (%d total, %d chunks)",
size
, sizeof(struct kinfo_proc
));
nprocs
= size
/ sizeof(struct kinfo_proc
);
nl
[0].n_name
= "_nprocs";
nl
[1].n_name
= "_allproc";
nl
[2].n_name
= "_zombproc";
if (kvm_nlist(kd
, nl
) != 0) {
for (p
= nl
; p
->n_type
!= 0; ++p
)
_kvm_err(kd
, kd
->program
,
"%s: no such symbol", p
->n_name
);
if (KREAD(kd
, nl
[0].n_value
, &nprocs
)) {
_kvm_err(kd
, kd
->program
, "can't read nprocs");
size
= nprocs
* sizeof(struct kinfo_proc
);
kd
->procbase
= (struct kinfo_proc
*)_kvm_malloc(kd
, size
);
nprocs
= kvm_deadprocs(kd
, op
, arg
, nl
[1].n_value
,
size
= nprocs
* sizeof(struct kinfo_proc
);
(void)realloc(kd
->procbase
, size
);
void *np
= (void *)realloc(p
, n
);
_kvm_err(kd
, kd
->program
, "out of memory");
#define MAX(a, b) ((a) > (b) ? (a) : (b))
* Read in an argument vector from the user address space of process p.
* addr if the user-space base address of narg null-terminated contiguous
* strings. This is used to read in both the command arguments and
* environment strings. Read at most maxcnt characters of strings.
kvm_argv(kd
, p
, addr
, narg
, maxcnt
)
* Check that there aren't an unreasonable number of agruments,
* and that the address is in user space.
if (narg
> 512 || addr
< VM_MIN_ADDRESS
|| addr
>= VM_MAXUSER_ADDRESS
)
kd
->argc
= MAX(narg
+ 1, 32);
kd
->argv
= (char **)_kvm_malloc(kd
, kd
->argc
*
} else if (narg
+ 1 > kd
->argc
) {
kd
->argc
= MAX(2 * kd
->argc
, narg
+ 1);
kd
->argv
= (char **)_kvm_realloc(kd
, kd
->argv
, kd
->argc
*
kd
->argspc
= (char *)_kvm_malloc(kd
, NBPG
);
* Loop over pages, filling in the argument vector.
while (addr
< VM_MAXUSER_ADDRESS
) {
cc
= NBPG
- (addr
& PGOFSET
);
if (maxcnt
> 0 && cc
> maxcnt
- len
)
if (len
+ cc
> kd
->arglen
) {
register char *op
= kd
->argspc
;
kd
->argspc
= (char *)_kvm_realloc(kd
, kd
->argspc
,
* Adjust argv pointers in case realloc moved
for (pp
= kd
->argv
; pp
< argv
; ++pp
)
if (kvm_uread(kd
, p
, addr
, cp
, cc
) != cc
)
if (maxcnt
== 0 && len
> 16 * NBPG
)
if (maxcnt
> 0 && len
>= maxcnt
) {
* We're stopping prematurely. Terminate the
* argv and current string.
*addr
= (u_long
)p
->ps_argvstr
;
*addr
= (u_long
)p
->ps_envstr
;
* Determine if the proc indicated by p is still active.
* This test is not 100% foolproof in theory, but chances of
* being wrong are very low.
proc_verify(kd
, kernp
, p
)
* Just read in the whole proc. It's not that big relative
* to the cost of the read system call.
if (kvm_read(kd
, kernp
, (char *)&kernproc
, sizeof(kernproc
)) !=
return (p
->p_pid
== kernproc
.p_pid
&&
(kernproc
.p_stat
!= SZOMB
|| p
->p_stat
== SZOMB
));
kvm_doargv(kd
, kp
, nchr
, info
)
const struct kinfo_proc
*kp
;
int (*info
)(struct ps_strings
*, u_long
*, int *);
register const struct proc
*p
= &kp
->kp_proc
;
struct ps_strings arginfo
;
* Pointers are stored at the top of the user stack.
if (p
->p_stat
== SZOMB
||
kvm_uread(kd
, p
, USRSTACK
- sizeof(arginfo
), (char *)&arginfo
,
sizeof(arginfo
)) != sizeof(arginfo
))
(*info
)(&arginfo
, &addr
, &cnt
);
ap
= kvm_argv(kd
, p
, addr
, cnt
, nchr
);
* For live kernels, make sure this process didn't go away.
if (ap
!= 0 && ISALIVE(kd
) &&
!proc_verify(kd
, (u_long
)kp
->kp_eproc
.e_paddr
, p
))
* Get the command args. This code is now machine independent.
kvm_getargv(kd
, kp
, nchr
)
const struct kinfo_proc
*kp
;
return (kvm_doargv(kd
, kp
, nchr
, ps_str_a
));
kvm_getenvv(kd
, kp
, nchr
)
const struct kinfo_proc
*kp
;
return (kvm_doargv(kd
, kp
, nchr
, ps_str_e
));
* Read from user space. The user context is given by p.
kvm_uread(kd
, p
, uva
, buf
, len
)
cc
= _kvm_uvatop(kd
, p
, uva
, &pa
);
if (lseek(kd
->pmfd
, (off_t
)pa
, 0) == -1 && errno
!= 0) {
_kvm_err(kd
, 0, "invalid address (%x)", uva
);
cc
= read(kd
->pmfd
, cp
, cc
);
_kvm_syserr(kd
, 0, _PATH_MEM
);
_kvm_err(kd
, kd
->program
, "short read");
} else if (ISALIVE(kd
)) {
dp
= kvm_readswap(kd
, p
, uva
, &cnt
);
_kvm_err(kd
, 0, "invalid address (%x)", uva
);
return (ssize_t
)(cp
- buf
);