a56095e3ce0a5621b1f410c7eefccecf6aa9e065
* Copyright (c) 1989 The Regents of the University of California.
* %sccs.include.redist.c%
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)kvm_proc.c 5.8 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
#include <machine/vmparam.h>
static char *unixf
, *memf
, *kmemf
, *swapf
;
static int unixx
, mem
, kmem
, swap
;
static int kvmfilesopen
= 0;
static struct kinfo_proc
*kvmprocbase
, *kvmprocptr
;
char upages
[UPAGES
][NBPG
];
static struct pte
*Usrptmap
, *usrpt
;
static struct pte
*Sysmap
;
static int argaddr0
; /* XXX */
#define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp))
#define pftoc(f) ((f) - lowram)
#define iskva(v) ((v) & KERNBASE)
static struct nlist nl
[] = {
* everything here and down, only if a dead kernel
#define X_DEADKERNEL X_SYSMAP
#define X_LOWRAM (X_LAST+1)
* returns 0 if files were opened now,
* 1 if files were already opened,
* -1 if files could not be opened.
kvm_openfiles(uf
, mf
, sf
)
unixx
= mem
= kmem
= swap
= -1;
unixf
= (uf
== NULL
) ? _PATH_UNIX
: uf
;
memf
= (mf
== NULL
) ? _PATH_MEM
: mf
;
if ((unixx
= open(unixf
, O_RDONLY
, 0)) == -1) {
setsyserr("can't open %s", unixf
);
if ((mem
= open(memf
, O_RDONLY
, 0)) == -1) {
setsyserr("can't open %s", memf
);
if ((kmem
= open(kmemf
, O_RDONLY
, 0)) == -1) {
setsyserr("can't open %s", kmemf
);
swapf
= (sf
== NULL
) ? _PATH_DRUM
: sf
;
* live kernel - avoid looking up nlist entries
nl
[X_DEADKERNEL
].n_name
= "";
if (swapf
!= NULL
&& ((swap
= open(swapf
, O_RDONLY
, 0)) == -1)) {
seterr("can't open %s", swapf
);
if (kvmfilesopen
== 0 && kvm_openfiles(NULL
, NULL
, NULL
) == -1)
/* otherwise kmem is a copy of mem, and will be closed below */
char dbversion
[LINE_MAX
];
char symbuf
[MAXSYMSIZE
+1];
if (kvmfilesopen
== 0 && kvm_openfiles(NULL
, NULL
, NULL
) == -1)
goto win
; /* off to the races */
sprintf(dbname
, "%s/kvm_%s", KVMDBDIR
, basename(unixf
));
if ((db
= dbm_open(dbname
, O_RDONLY
, 0)) == NULL
)
* read version out of database
bcopy("VERSION", symbuf
+1, sizeof ("VERSION")-1);
key
.dsize
= (sizeof ("VERSION") - 1) + 1;
data
= dbm_fetch(db
, key
);
bcopy(data
.dptr
, dbversion
, data
.dsize
);
dbversionlen
= data
.dsize
;
* read version string from kernel memory
bcopy("_version", symbuf
+1, sizeof ("_version")-1);
key
.dsize
= (sizeof ("_version")-1) + 1;
data
= dbm_fetch(db
, key
);
if (data
.dsize
!= sizeof (struct nlist
))
bcopy(data
.dptr
, &nbuf
, sizeof (struct nlist
));
lseek(kmem
, nbuf
.n_value
, 0);
if (read(kmem
, kversion
, dbversionlen
) != dbversionlen
)
* if they match, we win - otherwise do it the hard way
if (bcmp(dbversion
, kversion
, dbversionlen
) != 0)
* getem from the database.
for (n
= nl
; n
->n_name
&& n
->n_name
[0]; n
++, num
++) {
* clear out fields from users buffer
if ((len
= strlen(n
->n_name
)) > MAXSYMSIZE
) {
seterr("kvm_nlist: symbol too large");
strcpy(symbuf
+1, n
->n_name
);
data
= dbm_fetch(db
, key
);
if (data
.dptr
== NULL
|| data
.dsize
!= sizeof (struct nlist
))
bcopy(data
.dptr
, &nbuf
, sizeof (struct nlist
));
n
->n_value
= nbuf
.n_value
;
n
->n_other
= nbuf
.n_other
;
return (nlist(unixf
, nl
)); /* XXX seterr if -1 */
if (kvminit
== 0 && kvm_init(NULL
, NULL
, NULL
, 0) == -1)
if ((ret
= getkerninfo(what
, NULL
, NULL
, arg
)) == -1) {
setsyserr("can't get estimate for kerninfo");
if ((kvmprocbase
= (struct kinfo_proc
*)malloc(copysize
))
if ((ret
= getkerninfo(what
, kvmprocbase
, ©size
,
setsyserr("can't get proc list");
if (copysize
% sizeof (struct kinfo_proc
)) {
seterr("proc size mismatch (kinfo_proc: %d)",
sizeof (struct kinfo_proc
));
kvmnprocs
= copysize
/ sizeof (struct kinfo_proc
);
if (kvm_read(nl
[X_NPROC
].n_value
, &nproc
, sizeof (int)) !=
seterr("can't read nproc");
if ((kvmprocbase
= (struct kinfo_proc
*)
malloc(nproc
* sizeof (struct kinfo_proc
))) == NULL
) {
seterr("out of memory (addr: %x nproc = %d)",
nl
[X_NPROC
].n_value
, nproc
);
kvmnprocs
= kvm_doprocs(what
, arg
, kvmprocbase
);
realloc(kvmprocbase
, kvmnprocs
* sizeof (struct kinfo_proc
));
kvmprocptr
= kvmprocbase
;
* XXX - should NOT give up so easily - especially since the kernel
* may be corrupt (it died). Should gather as much information as possible.
* Follows proc ptrs instead of reading table since table may go
kvm_doprocs(what
, arg
, buff
)
register char *bp
= buff
;
if (kvm_read(nl
[X_ALLPROC
].n_value
, &p
,
sizeof (struct proc
*)) != sizeof (struct proc
*)) {
seterr("can't read allproc");
for (; p
; p
= proc
.p_nxt
) {
if (kvm_read(p
, &proc
, sizeof (struct proc
)) !=
seterr("can't read proc at %x", p
);
if (proc
.p_pid
!= (pid_t
)arg
)
if (proc
.p_uid
!= (uid_t
)arg
)
if (proc
.p_ruid
!= (uid_t
)arg
)
if (kvm_read(proc
.p_pgrp
, &pgrp
, sizeof (struct pgrp
)) !=
seterr("can't read pgrp at %x", proc
.p_pgrp
);
eproc
.e_sess
= pgrp
.pg_session
;
eproc
.e_pgid
= pgrp
.pg_id
;
eproc
.e_jobc
= pgrp
.pg_jobc
;
if (kvm_read(pgrp
.pg_session
, &sess
, sizeof (struct session
))
!= sizeof (struct session
)) {
seterr("can't read session at %x", pgrp
.pg_session
);
if ((proc
.p_flag
&SCTTY
) && sess
.s_ttyp
!= NULL
) {
if (kvm_read(sess
.s_ttyp
, &tty
, sizeof (struct tty
))
!= sizeof (struct tty
)) {
seterr("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 (kvm_read(tty
.t_pgrp
, &pgrp
, sizeof (struct
pgrp
)) != sizeof (struct pgrp
)) {
seterr("can't read tpgrp at &x",
eproc
.e_tpgid
= pgrp
.pg_id
;
kvm_read(proc
.p_wmesg
, eproc
.e_wmesg
, WMESGLEN
);
kvm_read(proc
.p_textp
, &text
, sizeof (text
));
eproc
.e_xsize
= text
.x_size
;
eproc
.e_xrssize
= text
.x_rssize
;
eproc
.e_xccount
= text
.x_ccount
;
eproc
.e_xswrss
= text
.x_swrss
;
eproc
.e_xsize
= eproc
.e_xrssize
=
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(&proc
, bp
, sizeof (struct proc
));
bp
+= sizeof (struct proc
);
bcopy(&eproc
, bp
, sizeof (struct eproc
));
bp
+= sizeof (struct eproc
);
if (kvm_read(nl
[X_ZOMBPROC
].n_value
, &p
,
sizeof (struct proc
*)) != sizeof (struct proc
*)) {
seterr("can't read zombproc");
if (!kvmprocbase
&& kvm_getprocs(0, 0) == -1)
if (kvmprocptr
>= (kvmprocbase
+ kvmnprocs
)) {
seterr("end of proc list");
return((struct proc
*)(kvmprocptr
++));
return ((struct eproc
*)(((char *)p
) + sizeof (struct proc
)));
kvmprocptr
= kvmprocbase
;
struct pte
*pteaddr
, apte
;
struct pte arguutl
[HIGHPAGES
+(CLSIZE
*2)];
if (kvminit
== 0 && kvm_init(NULL
, NULL
, NULL
, 0) == -1)
if (p
->p_stat
== SZOMB
) {
seterr("zombie process");
if ((p
->p_flag
& SLOAD
) == 0) {
(void) lseek(swap
, (long)dtob(p
->p_swaddr
), 0);
if (read(swap
, (char *)&user
.user
, sizeof (struct user
)) !=
seterr("can't read u for pid %d from %s\n",
pteaddr
= &Usrptmap
[btokmx(p
->p_p0br
) + p
->p_szpt
- 1];
klseek(kmem
, (long)pteaddr
, 0);
if (read(kmem
, (char *)&apte
, sizeof(apte
)) != sizeof(apte
)) {
seterr("can't read indir pte to get u for pid %d from %s",
lseek(mem
, (long)ctob(pftoc(apte
.pg_pfnum
+1)) - sizeof(arguutl
), 0);
if (read(mem
, (char *)arguutl
, sizeof(arguutl
)) != sizeof(arguutl
)) {
seterr("can't read page table for u of pid %d from %s",
if (arguutl
[0].pg_fod
== 0 && arguutl
[0].pg_pfnum
)
argaddr0
= ctob(pftoc(arguutl
[0].pg_pfnum
));
if (arguutl
[CLSIZE
*1].pg_fod
== 0 && arguutl
[CLSIZE
*1].pg_pfnum
)
argaddr1
= ctob(pftoc(arguutl
[CLSIZE
*1].pg_pfnum
));
pcbpf
= arguutl
[CLSIZE
*2].pg_pfnum
;
ncl
= (sizeof (struct user
) + CLBYTES
- 1) / CLBYTES
;
(long)ctob(pftoc(arguutl
[(CLSIZE
*2)+i
].pg_pfnum
)), 0);
if (read(mem
, user
.upages
[i
], CLBYTES
) != CLBYTES
) {
seterr("can't read page %d of u of pid %d from %s",
arguutl
[(CLSIZE
*2)+i
].pg_pfnum
, p
->p_pid
, memf
);
int argi
[CLBYTES
*2/sizeof (int)];
if (up
== NULL
|| p
->p_pid
== 0 || p
->p_pid
== 2)
if ((p
->p_flag
& SLOAD
) == 0 || argaddr1
== 0) {
if (swap
< 0 || p
->p_ssize
== 0)
vstodb(0, CLSIZE
, &up
->u_smap
, &db
, 1);
(void) lseek(swap
, (long)dtob(db
.db_base
), 0);
if (read(swap
, (char *)&argspac
.argc
[CLBYTES
], CLBYTES
)
vstodb(1, CLSIZE
, &up
->u_smap
, &db
, 1);
(void) lseek(swap
, (long)dtob(db
.db_base
), 0);
if (read(swap
, (char *)&argspac
.argc
[0], CLBYTES
) != CLBYTES
)
lseek(mem
, (long)argaddr0
, 0);
if (read(mem
, (char *)&argspac
, CLBYTES
) != CLBYTES
)
bzero(&argspac
, CLBYTES
);
lseek(mem
, (long)argaddr1
, 0);
if (read(mem
, &argspac
.argc
[CLBYTES
], CLBYTES
) != CLBYTES
)
ip
= &argspac
.argi
[CLBYTES
*2/sizeof (int)];
ip
-= 2; /* last arg word and .long 0 */
for (cp
= (char *)ip
; cp
< &argspac
.argc
[CLBYTES
*2]; cp
++) {
else if (c
< ' ' || c
> 0176) {
if (++nbad
>= 5*(0+1)) { /* eflg -> 0 XXX */
} else if (0 == 0 && c
== '=') { /* eflg -> 0 XXX */
(void) strncpy(cmdbuf
, cp
, &argspac
.argc
[CLBYTES
*2] - cp
);
if (cp
[0] == '-' || cp
[0] == '?' || cp
[0] <= ' ') {
(void) strcat(cmdbuf
, " (");
(void) strncat(cmdbuf
, p
->p_comm
, sizeof(p
->p_comm
));
(void) strcat(cmdbuf
, ")");
seterr("error locating command name for pid %d from %s\n",
(void) strcpy(cmdbuf
, " (");
(void) strncat(cmdbuf
, p
->p_comm
, sizeof (p
->p_comm
));
(void) strcat(cmdbuf
, ")");
/* We must do the sys map first because klseek uses it */
Syssize
= nl
[X_SYSSIZE
].n_value
;
calloc((unsigned) Syssize
, sizeof (struct pte
));
seterr("out of space for Sysmap");
addr
= (long) nl
[X_SYSMAP
].n_value
;
(void) lseek(kmem
, addr
, 0);
if (read(kmem
, (char *) Sysmap
, Syssize
* sizeof (struct pte
))
!= Syssize
* sizeof (struct pte
)) {
seterr("can't read Sysmap");
addr
= (long) nl
[X_LOWRAM
].n_value
;
(void) lseek(kmem
, addr
, 0);
if (read(kmem
, (char *) &lowram
, sizeof (lowram
))
seterr("can't read lowram");
usrpt
= (struct pte
*)nl
[X_USRPT
].n_value
;
Usrptmap
= (struct pte
*)nl
[X_USRPTMAP
].n_value
;
if (kvm_read((long)nl
[X_NSWAP
].n_value
, &nswap
, sizeof (long)) !=
seterr("can't read nswap");
if (kvm_read((long)nl
[X_DMMIN
].n_value
, &dmmin
, sizeof (long)) !=
seterr("can't read dmmin");
if (kvm_read((long)nl
[X_DMMAX
].n_value
, &dmmax
, sizeof (long)) !=
seterr("can't read dmmax");
if (kvmfilesopen
== 0 && kvm_openfiles(NULL
, NULL
, NULL
) == -1)
if (read(kmem
, buf
, len
) != len
) {
seterr("error reading kmem at %x\n", loc
);
if (read(mem
, buf
, len
) != len
) {
seterr("error reading mem at %x\n", loc
);
if ((loc
= vtophys(loc
)) == -1)
(void) lseek(fd
, (off_t
)loc
, off
);
* Given a base/size pair in virtual swap area,
* return a physical base/size pair which is the
* (largest) initial, physically contiguous block.
vstodb(vsbase
, vssize
, dmp
, dbp
, rev
)
register struct dblock
*dbp
;
register int blk
= dmmin
;
register swblk_t
*ip
= dmp
->dm_map
;
if (vsbase
< 0 || vsbase
+ vssize
> dmp
->dm_size
)
if (*ip
<= 0 || *ip
+ blk
> nswap
)
dbp
->db_size
= MIN(vssize
, blk
- vsbase
);
dbp
->db_base
= *ip
+ (rev
? blk
- (vsbase
+ dbp
->db_size
) : vsbase
);
register struct pte
*pte
;
newloc
= loc
& ~KERNBASE
;
#if defined(vax) || defined(tahoe)
if ((loc
& KERNBASE
) == 0) {
seterr("vtophys: translating non-kernel address");
seterr("vtophys: page out of bound (%d>=%d)", p
, Syssize
);
if (pte
->pg_v
== 0 && (pte
->pg_fod
|| pte
->pg_pfnum
== 0)) {
seterr("vtophys: page not valid");
if (pte
->pg_pfnum
< lowram
) {
seterr("vtophys: non-RAM page (%d<%d)", pte
->pg_pfnum
, lowram
);
loc
= (long) (ptob(pftoc(pte
->pg_pfnum
)) + (loc
& PGOFSET
));
static char errbuf
[LINE_MAX
];
fmt
= va_arg(ap
, char *);
(void) vsprintf(errbuf
, fmt
, ap
);
fmt
= va_arg(ap
, char *);
(void) vsprintf(errbuf
, fmt
, ap
);
for (cp
=errbuf
; *cp
; cp
++)
sprintf(cp
, ": %s", strerror(errno
));