* Copyright (c) 1989 The Regents of the University of California.
* %sccs.include.redist.c%
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)kvm_hp300.c 5.21 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
#include <machine/vmparam.h>
#define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */
#define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */
#include <vm/vm.h> /* ??? kinfo_proc currently includes this*/
#include <sys/kinfo_proc.h>
#include <hp300/hp300/pte.h>
static const 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 */
static struct ste
*Sysseg
;
#define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp))
#define pftoc(f) ((f) - lowram)
#define iskva(v) ((u_long)(v) & KERNBASE)
static struct nlist nl
[] = {
#define X_DMMIN X_NSWAP+1
#define X_DMMAX X_DMMIN+1
* everything here and down, only if a dead kernel
#define X_SYSMAP X_DMMAX+1
#define X_DEADKERNEL X_SYSMAP
#define X_ALLPROC X_SYSMAP+1
#define X_ZOMBPROC X_ALLPROC+1
#define X_NPROCS X_ZOMBPROC+1
#define X_SYSSEG (X_NPROCS+1)
#define X_LOWRAM (X_SYSSEG+1)
static void seterr(), setsyserr(), vstodb();
static int getkvars(), kvm_doprocs(), kvm_init(), klseek();
* 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
)
const char *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 (kvminit
== 0 && kvm_init(NULL
, NULL
, NULL
, 0) == -1) /*XXX*/
if (kvmfilesopen
== 0 && kvm_openfiles(NULL
, NULL
, NULL
) == -1)
/* otherwise kmem is a copy of mem, and will be closed below */
char dbversion
[_POSIX2_LINE_MAX
];
char kversion
[_POSIX2_LINE_MAX
];
if (kvmfilesopen
== 0 && kvm_openfiles(NULL
, NULL
, NULL
) == -1)
goto win
; /* off to the races */
sprintf(dbname
, "%s/kvm_%s", _PATH_VARRUN
, basename(unixf
));
if ((db
= dbm_open(dbname
, O_RDONLY
, 0)) == NULL
)
* read version out of database
bcopy("VERSION", symbuf
, 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
, 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("symbol too large");
(void)strcpy(symbuf
, 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
;
seterr("nlist (hard way) failed");
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 (got %d total, kinfo_proc: %d)",
copysize
, sizeof (struct kinfo_proc
));
kvmnprocs
= copysize
/ sizeof (struct kinfo_proc
);
if (kvm_read((void *)nl
[X_NPROCS
].n_value
, &nprocs
,
sizeof (int)) != sizeof (int)) {
seterr("can't read nproc");
if ((kvmprocbase
= (struct kinfo_proc
*)
malloc(nprocs
* sizeof (struct kinfo_proc
))) == NULL
) {
seterr("out of memory (addr: %x nprocs = %d)",
nl
[X_NPROCS
].n_value
, nprocs
);
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((void *) 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 (kvm_read(proc
.p_cred
, &eproc
.e_pcred
,
sizeof (struct pcred
)) == sizeof (struct pcred
))
(void) kvm_read(eproc
.e_pcred
.pc_ucred
, &eproc
.e_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
)
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
;
eproc
.e_flag
= sess
.s_ttyvp
? EPROC_CTTY
: 0;
eproc
.e_flag
|= EPROC_SLEADER
;
kvm_read(proc
.p_wmesg
, eproc
.e_wmesg
, WMESGLEN
);
(void) kvm_read(proc
.p_vmspace
, &eproc
.e_vm
,
sizeof (struct vmspace
));
eproc
.e_xsize
= eproc
.e_xrssize
=
eproc
.e_xccount
= eproc
.e_xswrss
= 0;
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((void *) 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
;
register struct kinfo_proc
*kp
= (struct kinfo_proc
*)p
;
if (kvminit
== 0 && kvm_init(NULL
, NULL
, NULL
, 0) == -1)
if (p
->p_stat
== SZOMB
) {
seterr("zombie process");
* Read u-area one page at a time for the benefit of post-mortems
for (i
= 0; i
< UPAGES
; i
++) {
if (klseek(kmem
, (long)up
, 0) == -1)
if (read(kmem
, user
.upages
[i
], CLBYTES
) != CLBYTES
) {
seterr("cant read page %x of u of pid %d from %s",
pcbpf
= (int) btop(p
->p_addr
); /* what should this be really? */
* Conjure up a physical address for the arguments.
if (kp
->kp_eproc
.e_vm
.vm_pmap
.pm_ptab
) {
struct pte pte
[CLSIZE
*2];
(long)&kp
->kp_eproc
.e_vm
.vm_pmap
.pm_ptab
[btoc(USRSTACK
-CLBYTES
*2)], 0) == -1)
if (read(kmem
, (char *)&pte
, sizeof(pte
)) == sizeof(pte
)) {
argaddr0
= ctob(pftoc(pte
[CLSIZE
*0].pg_pfnum
));
argaddr1
= ctob(pftoc(pte
[CLSIZE
*1].pg_pfnum
));
kp
->kp_eproc
.e_vm
.vm_rssize
=
kp
->kp_eproc
.e_vm
.vm_pmap
.pm_stats
.resident_count
; /* XXX */
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",
pteaddr
= &Usrptmap
[btokmx(p
->p_p0br
) + p
->p_szpt
- 1];
if (klseek(kmem
, (long)pteaddr
, 0) == -1)
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
);
static char cmdbuf
[CLBYTES
*2];
int argi
[CLBYTES
*2/sizeof (int)];
#if defined(NEWVM) && defined(hp300)
stkoff
= 20; /* XXX for sigcode */
if (up
== NULL
|| p
->p_pid
== 0 || p
->p_pid
== 2)
if ((p
->p_flag
& SLOAD
) == 0 || argaddr1
== 0) {
goto retucomm
; /* XXX for now */
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 */
ip
-= stkoff
/ sizeof (int);
for (cp
= (char *)ip
; cp
< &argspac
.argc
[CLBYTES
*2-stkoff
]; 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",
(void) strcpy(cmdbuf
, " (");
(void) strncat(cmdbuf
, p
->p_comm
, sizeof (p
->p_comm
));
(void) strcat(cmdbuf
, ")");
if ((ret
= kvm_nlist(nl
)) == -1)
/* We must do the sys map first because klseek uses it */
addr
= (long) nl
[X_LOWRAM
].n_value
;
(void) lseek(kmem
, addr
, 0);
if (read(kmem
, (char *) &lowram
, sizeof (lowram
))
seterr("can't read lowram");
Sysseg
= (struct ste
*) malloc(NBPG
);
seterr("out of space for Sysseg");
addr
= (long) nl
[X_SYSSEG
].n_value
;
(void) lseek(kmem
, addr
, 0);
read(kmem
, (char *)&addr
, sizeof(addr
));
(void) lseek(kmem
, (long)addr
, 0);
if (read(kmem
, (char *) Sysseg
, NBPG
) != NBPG
) {
seterr("can't read Sysseg");
if (kvm_read((void *) nl
[X_NSWAP
].n_value
, &nswap
, sizeof (long)) !=
seterr("can't read nswap");
if (kvm_read((void *) nl
[X_DMMIN
].n_value
, &dmmin
, sizeof (long)) !=
seterr("can't read dmmin");
if (kvm_read((void *) nl
[X_DMMAX
].n_value
, &dmmax
, sizeof (long)) !=
seterr("can't read dmmax");
fprintf(stderr
, "kvm_nlist: can't find following names:");
for (i
= 0; nl
[i
].n_name
[0] != '\0'; i
++)
fprintf(stderr
, " %s", nl
[i
].n_name
);
fprintf(stderr
, ": continuing...\n");
if (kvmfilesopen
== 0 && kvm_openfiles(NULL
, NULL
, NULL
) == -1)
if (klseek(kmem
, (off_t
) loc
, 0) == -1)
if (read(kmem
, buf
, len
) != len
) {
seterr("error reading kmem at %x", loc
);
lseek(mem
, (off_t
) loc
, 0);
if (read(mem
, buf
, len
) != len
) {
seterr("error reading mem at %x", 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
);
off_t newloc
= (off_t
) -1;
ste
= *(int *)&Sysseg
[loc
>> SG_ISHIFT
];
seterr("vtophys: segment not valid (%x)", ste
);
p
= btop(loc
& SG_PMASK
);
newloc
= (ste
& SG_FRAME
) + (p
* sizeof(struct pte
));
(void) lseek(kmem
, (long)(newloc
-(off_t
)ptob(lowram
)), 0);
if (read(kmem
, (char *)&pte
, sizeof pte
) != sizeof pte
) {
seterr("vtophys: cannot locate pte");
if (pte
== PG_NV
|| newloc
< (off_t
)ptob(lowram
)) {
seterr("vtophys: page not valid");
newloc
= (newloc
- (off_t
)ptob(lowram
)) + (loc
& PGOFSET
);
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
[_POSIX2_LINE_MAX
];
fmt
= va_arg(ap
, char *);
(void) vsnprintf(errbuf
, _POSIX2_LINE_MAX
, fmt
, ap
);
fmt
= va_arg(ap
, char *);
(void) vsnprintf(errbuf
, _POSIX2_LINE_MAX
, fmt
, ap
);
for (cp
=errbuf
; *cp
; cp
++)
snprintf(cp
, _POSIX2_LINE_MAX
- (cp
- errbuf
), ": %s", strerror(errno
));