static char *sccsid
= "@(#)analyze.c 4.4 (Berkeley) %G%";
* Analyze - analyze a core (and optional paging area) saved from
* a virtual Unix system crash.
/* use vprintf with care; it plays havoc with ``else's'' */
#define vprintf if (vflg) printf
#define clear(x) ((int)x & 0x7fffffff)
struct proc
*proc
, *aproc
;
struct text
*text
, *atext
;
struct pte p0br
[ctopt(MAXTSIZ
+MAXDSIZ
+MAXSSIZ
)][NPTEPG
];
register struct nlist
*np
;
register struct text
*xp
;
register struct pte
*pte
;
while (argc
> 0 && argv
[0][0] == '-') {
register char *cp
= *argv
++;
while (*++cp
) switch (*cp
) {
if ((fswap
= open(argv
[0], 0)) < 0) {
fprintf(stderr
, "usage: analyze [ -vmfd ] [ -s swapfile ] corefile [ system ]\n");
if ((fcore
= open(argv
[0], 0)) < 0) {
nlist(argc
> 1 ? argv
[1] : "/vmunix", nl
);
if (nl
[0].n_value
== 0) {
fprintf(stderr
, "%s: bad namelist\n",
argc
> 1 ? argv
[1] : "/vmunix");
for (np
= nl
; np
->n_name
[0]; np
++)
vprintf("%8.8s %x\n", np
->n_name
,np
->n_value
);
usrpt
= (struct pte
*)clear(nl
[X_USRPT
].n_value
);
Usrptma
= (struct pte
*)clear(nl
[X_PTMA
].n_value
);
firstfree
= get(nl
[X_FIRSTFREE
].n_value
);
maxfree
= get(nl
[X_MAXFREE
].n_value
);
freemem
= get(nl
[X_FREEMEM
].n_value
);
paginfo
= (struct paginfo
*)calloc(maxfree
, sizeof (struct paginfo
));
fprintf(stderr
, "maxfree %x?... out of mem!\n", maxfree
);
vprintf("usrpt %x\nUsrptma %x\nfirstfree %x\nmaxfree %x\nfreemem %x\n",
usrpt
, Usrptma
, firstfree
, maxfree
, freemem
);
lseek(fcore
, (long)clear(nl
[X_PROC
].n_value
), 0);
read(fcore
, (char *)&aproc
, sizeof aproc
);
lseek(fcore
, (long)clear(nl
[X_NPROC
].n_value
), 0);
read(fcore
, (char *)&nproc
, sizeof nproc
);
printf("%d procs\n", nproc
);
proc
= (struct proc
*)calloc(nproc
, sizeof (struct proc
));
lseek(fcore
, (long)clear(aproc
), 0);
if (read(fcore
, (char *)proc
, nproc
* sizeof (struct proc
))
!= nproc
* sizeof (struct proc
)) {
lseek(fcore
, (long)clear(nl
[X_TEXT
].n_value
), 0);
read(fcore
, (char *)&atext
, sizeof atext
);
lseek(fcore
, (long)clear(nl
[X_NTEXT
].n_value
), 0);
read(fcore
, (char *)&ntext
, sizeof ntext
);
printf("%d texts\n", ntext
);
text
= (struct text
*)calloc(ntext
, sizeof (struct text
));
lseek(fcore
, (long)clear(atext
), 0);
if (read(fcore
, (char *)text
, ntext
* sizeof (struct text
))
!= ntext
* sizeof (struct text
)) {
i
= (get(nl
[X_ECMAP
].n_value
) - get(nl
[X_CMAP
].n_value
));
ecmx
= i
/ sizeof (struct cmap
);
cmap
= (struct cmap
*)calloc(i
, 1);
fprintf(stderr
, "not enough mem for %x bytes of cmap\n", i
);
lseek(fcore
, (long)clear(get(nl
[X_CMAP
].n_value
)), 0);
if (read(fcore
, (char *)cmap
, i
) != i
) {
{ struct mapent
*aswapmap
;
lseek(fcore
, (long)clear(nl
[X_SWAPMAP
].n_value
), 0);
read(fcore
, (char *)&aswapmap
, sizeof aswapmap
);
lseek(fcore
, (long)clear(nl
[X_NSWAPMAP
].n_value
), 0);
read(fcore
, (char *)&nswapmap
, sizeof nswapmap
);
printf("%d swapmap entries\n", nswapmap
);
swapmap
= (struct mapent
*)calloc(nswapmap
, sizeof (struct mapent
));
dblks
= (struct dblks
*)calloc(2 * nswapmap
, sizeof (struct dblks
));
lseek(fcore
, (long)clear(aswapmap
+1), 0);
if (read(fcore
, (char *)swapmap
, nswapmap
* sizeof (struct mapent
))
!= nswapmap
* sizeof (struct mapent
)) {
for (p
= &proc
[1]; p
< proc
+nproc
; p
++) {
p
->p_p0br
= (struct pte
*)clear(p
->p_p0br
);
p
->p_addr
= (struct pte
*)clear(p
->p_addr
);
printf("proc %d ", p
->p_pid
);
if (p
->p_stat
== SZOMB
) {
printf("loaded, p0br %x, ", p
->p_p0br
);
printf("%d pages of page tables:", p
->p_szpt
);
for (i
= 0; i
< p
->p_szpt
; i
++) {
w
= get(&Usrptma
[a
+ i
]);
printf(" %x", w
& PG_PFNUM
);
for(i
= 0; i
< p
->p_szpt
; i
++) {
w
= get(&Usrptma
[a
+ i
]);
count(p
, (struct pte
*)&w
, ZPAGET
);
/* i = ctopt(btoc(u.u_exdata.ux_dsize)); */
i
= clrnd(ctopt(p
->p_tsize
+ p
->p_dsize
+ p
->p_ssize
));
printf("swapped, swaddr %x\n", p
->p_swaddr
);
duse(p
->p_swaddr
, clrnd(ctod(UPAGES
)), DUDOT
, p
- proc
);
duse(p
->p_swaddr
+ ctod(UPAGES
),
clrnd(i
- p
->p_tsize
/ NPTEPG
), DPAGET
, p
- proc
);
/* i, DPAGET, p - proc); */
p
->p_p0br
= (struct pte
*)p0br
;
p
->p_textp
= &text
[p
->p_textp
- atext
];
if ((p
->p_flag
& SLOAD
) == 0)
for (i
= 0; i
< p
->p_tsize
; i
++) {
if (pte
->pg_fod
|| pte
->pg_pfnum
== 0)
if (pte
->pg_pfnum
>= firstfree
&& pte
->pg_pfnum
< maxfree
&& cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
)
for (i
= 0; i
< p
->p_dsize
; i
++) {
if (pte
->pg_fod
|| pte
->pg_pfnum
== 0)
if (pte
->pg_pfnum
>= firstfree
&& pte
->pg_pfnum
< maxfree
&& cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
)
for (i
= 0; i
< p
->p_ssize
; i
++) {
if (pte
->pg_fod
|| pte
->pg_pfnum
== 0)
if (pte
->pg_pfnum
>= firstfree
&& pte
->pg_pfnum
< maxfree
&& cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
)
for (i
= 0; i
< UPAGES
; i
++)
count(p
, &p
->p_addr
[i
], ZUDOT
);
for (xp
= &text
[0]; xp
< text
+ntext
; xp
++)
for (i
= 0; i
< xp
->x_size
; i
+= DMTEXT
)
(xp
->x_size
- i
) > DMTEXT
? DMTEXT
: xp
->x_size
- i
,
duse(xp
->x_ptdaddr
, clrnd(ctopt(xp
->x_size
)),
register struct text
*xp
;
if (fswap
== -1 && (u
.u_procp
->p_flag
& SLOAD
) == 0)
printf("disk for pid %d", u
.u_procp
->p_pid
);
if ((xp
= u
.u_procp
->p_textp
) && Dflg
)
ptdmap(xp
->x_daddr
, xp
->x_size
);
pdmseg("data", &u
.u_dmap
, DDATA
);
pdmseg("stack", &u
.u_smap
, DSTACK
);
for (i
= 0, rem
= size
; rem
> 0; i
++) {
printf(" %x<%x>", dp
[i
], rem
< DMTEXT
? rem
: DMTEXT
);
rem
-= rem
< DMTEXT
? rem
: DMTEXT
;
for (i
= 0, rem
= dmp
->dm_size
; rem
> 0; i
++) {
printf(" %x<%x>", dmp
->dm_map
[i
], rem
< b
? rem
: b
);
duse(dmp
->dm_map
[i
], b
, type
, u
.u_procp
- proc
);
duse(first
, size
, type
, index
)
register struct dblks
*dp
;
if (++ndblks
> 2*nswapmap
) {
fprintf(stderr
, "too many disk blocks\n");
register struct dblks
*d
, *e
;
return (e
->d_first
- d
->d_first
);
register struct mapent
*smp
;
register struct dblks
*d
, *e
;
for (smp
= swapmap
; smp
->m_size
; smp
++)
duse(smp
->m_addr
, smp
->m_size
, DFREE
, 0);
duse(CLSIZE
, DMTEXT
- CLSIZE
, DFREE
, 0);
qsort(dblks
, ndblks
, sizeof (struct dblks
), dsort
);
printf("lost swap map: start %x size %x\n", 1, d
->d_first
);
if (d
->d_first
+ d
->d_size
> e
->d_first
) {
printf("overlap in swap mappings:\n");
} else if (d
->d_first
+ d
->d_size
< e
->d_first
) {
printf("lost swap map: start %x size %x\n",
e
->d_first
- (d
->d_first
+ d
->d_size
));
printf("swap space ends at %x\n", d
->d_first
+ d
->d_size
);
register struct dblks
*d
;
printf("at %4x size %4x type %s", d
->d_first
, d
->d_size
,
printf(" pid %d", proc
[d
->d_index
].p_pid
);
lseek(fcore
, (long)ctob((x
& PG_PFNUM
)), 0);
if (read(fcore
, (char *)(p0br
[i
]), NBPG
) != NBPG
) {
fprintf(stderr
, "getpt error reading frame %x\n", clear(x
));
register struct pte
*pte
;
char corepg
[NBPG
], swapg
[NBPG
];
register int i
, count
, dblock
;
register int pfnum
= pte
->pg_pfnum
;
if (type
== ZPAGET
|| type
== ZUDOT
)
lseek(fcore
, (long)(NBPG
* pfnum
), 0);
if (read(fcore
, corepg
, NBPG
) != NBPG
){
fprintf(stderr
, "Error reading core page %x\n", pfnum
);
if (ptetodp(p
, pte
) >= u
.u_dmap
.dm_size
)
if (ptetosp(p
, pte
) >= u
.u_smap
.dm_size
)
dblock
= vtod(p
, ptetov(p
, pte
), &u
.u_dmap
, &u
.u_smap
);
if (pte
->pg_fod
|| pte
->pg_pfnum
== 0)
if (cmap
[pgtocm(pte
->pg_pfnum
)].c_intrans
|| pte
->pg_m
|| pte
->pg_swapm
)
lseek(fswap
, (long)(NBPG
* dblock
), 0);
if (read(fswap
, swapg
, NBPG
) != NBPG
) {
fprintf(stderr
,"swap page %x: ", dblock
);
for (i
= 0; i
< NBPG
; i
++)
if (corepg
[i
] != swapg
[i
])
if (uflg
&& (p
->p_flag
& SLOAD
))
printf("pid %d u. pages:", p
->p_pid
);
for (i
= 0; i
< UPAGES
; i
++) {
printf(" %x", p
->p_addr
[i
].pg_pfnum
);
lseek(fcore
, ctob(p
->p_addr
[i
].pg_pfnum
), 0);
if (read(fcore
, u_area
.buf
[i
], NBPG
) != NBPG
)
perror("core u. read"), errs
++;
lseek(fswap
, (long)(NBPG
* (p
->p_swaddr
+i
)), 0);
if (read(fswap
, u_area
.buf
[i
], NBPG
) != NBPG
)
perror("swap u. read"), errs
++;
if (uflg
&& (p
->p_flag
& SLOAD
))
register struct pte
*pte
;
register int pfnum
= pte
->pg_pfnum
;
register struct paginfo
*zp
= &paginfo
[pfnum
];
#define zprintf if (type==ZINTRAN || vflg) printf
if (type
== ZINTRAN
&& pfnum
== 0)
zprintf("page %x %s", pfnum
, typepg
[type
]);
if (sflg
== 0 || (ndif
= checkpg(p
, pte
, type
)) == 0) {
if (vflg
== 0 && type
!= ZINTRAN
)
printf("page %x %s,", pfnum
, typepg
[type
]);
printf(" %d bytes differ\n",ndif
);
if (pfnum
< firstfree
|| pfnum
> maxfree
) {
printf("page number out of range:\n");
printf("\tpage %x type %s pid %d\n", pfnum
, typepg
[type
], pid
);
printf("dup page pte %x", *(int *)pte
);
dumpcm("", pte
->pg_pfnum
);
printf("pte %x and as %s in pid %d\n", zp
->z_pte
, typepg
[type
], pid
);
if (zp
->z_type
!= 0 && zp
->z_type
!= ZTEXT
)
printf("page %x type %s pid %d ", zp
- paginfo
, typepg
[zp
->z_type
], zp
->z_pid
);
register struct paginfo
*zp
;
for (i
= firstfree
+ UPAGES
; i
< maxfree
; i
+= CLSIZE
) {
if (cmap
[pfnum
].c_lock
&& cmap
[pfnum
].c_type
!= CSYS
)
printf("cm %x %s page %x ", cm
, cp
, pg
);
printf("\t[%x, %x", c
->c_page
, c
->c_ndx
);
if (c
->c_type
!= CTEXT
) {
printf(" [text c->c_ndx %d?]", c
->c_ndx
);
printf(" (=pid %d)", proc
[c
->c_ndx
].p_pid
);
printf(" [text c->c_ndx %d?]", c
->c_ndx
);
pslot
= (text
[c
->c_ndx
].x_caddr
- aproc
);
printf(" %d", proc
[pslot
].p_pid
);
if (proc
[pslot
].p_xlink
== 0)
pslot
= (proc
[pslot
].p_xlink
- aproc
);
printf(tynames
[c
->c_type
]);
printf(" blkno %x mdev %d", c
->c_blkno
, c
->c_mdev
);
printf(" hlink %x page %x", c
->c_hlink
, cmtopg(c
->c_hlink
));
register int i
, next
, prev
;
for (i
=freemem
/CLSIZE
; --i
>=0; ) {
next
= cmap
[next
].c_next
;
if (cmap
[next
].c_free
== 0) {
printf("link to non free block: in %x to %x\n", cmtopg(prev
), cmtopg(next
));
dumpcm("bad free link in", cmtopg(prev
));
dumpcm("to non free block", cmtopg(next
));
if (cmtopg(next
) > maxfree
) {
printf("free list link out of range: in %x to %x\n", cmtopg(prev
), cmtopg(next
));
dumpcm("bad link in", cmtopg(prev
));
paginfo
[cmtopg(next
)].z_type
= ZFREE
;
dumpcm("free", cmtopg(next
));
paginfo
[cmtopg(next
)+1].z_type
= ZFREE
;
dumpcm("free", cmtopg(next
)+1);
lseek(fcore
, (long)clear(loc
), 0);
if (read(fcore
, (char *)&x
, sizeof (int)) != sizeof (int)) {
fprintf(stderr
, "get failed on %x\n", clear(loc
));
* Convert a virtual page number
* to its corresponding disk block number.
* Used in pagein/pageout to initiate single page transfers.
register struct dmap
*dmap
, *smap
;
return(p
->p_textp
->x_daddr
[v
/ DMTEXT
] + v
% DMTEXT
);
vstodb(vtosp(p
, v
), 1, smap
, &db
, 1);
vstodb(vtodp(p
, v
), 1, dmap
, &db
, 0);
* Convert a pte pointer to
register struct pte
*pte
;
return (tptov(p
, ptetotp(p
, pte
)));
else if (isadpte(p
, pte
))
return (dptov(p
, ptetodp(p
, pte
)));
return (sptov(p
, ptetosp(p
, pte
)));
* 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 dmap
*dmp
;
register struct dblock
*dbp
;
register int blk
= DMMIN
;
register swblk_t
*ip
= dmp
->dm_map
;
if (vsbase
< 0 || vsbase
+ vssize
> dmp
->dm_size
)
dbp
->db_size
= min(vssize
, blk
- vsbase
);
dbp
->db_base
= *ip
+ (rev
? blk
- (vsbase
+ vssize
) : vsbase
);
printf("panic!: %s\n", cp
);