xref: /csrg-svn/old/analyze/analyze.c (revision 950)
1*950Sbill static char *sccsid = "@(#)analyze.c	4.1 (Berkeley) 10/01/80";
2*950Sbill #include <stdio.h>
3*950Sbill #include <sys/param.h>
4*950Sbill #include <sys/dir.h>
5*950Sbill #include <sys/pte.h>
6*950Sbill #include <nlist.h>
7*950Sbill #include <sys/map.h>
8*950Sbill #include <sys/user.h>
9*950Sbill #include <sys/proc.h>
10*950Sbill #include <sys/text.h>
11*950Sbill #include <sys/cmap.h>
12*950Sbill #include <sys/vm.h>
13*950Sbill 
14*950Sbill /*
15*950Sbill  * Analyze - analyze a core (and optional paging area) saved from
16*950Sbill  * a virtual Unix system crash.
17*950Sbill  */
18*950Sbill 
19*950Sbill int	Dflg;
20*950Sbill int	dflg;
21*950Sbill int	vflg;
22*950Sbill int	mflg;
23*950Sbill int	fflg;
24*950Sbill int	sflg;
25*950Sbill 
26*950Sbill /* use vprintf with care; it plays havoc with ``else's'' */
27*950Sbill #define	vprintf	if (vflg) printf
28*950Sbill 
29*950Sbill #define	clear(x)	((int)x & 0x7fffffff)
30*950Sbill 
31*950Sbill struct	proc proc[NPROC];
32*950Sbill struct	text text[NTEXT];
33*950Sbill struct	map swapmap[SMAPSIZ];
34*950Sbill struct	cmap *cmap;
35*950Sbill struct	pte *usrpt;
36*950Sbill struct	pte *Usrptma;
37*950Sbill int	firstfree;
38*950Sbill int	maxfree;
39*950Sbill int	freemem;
40*950Sbill struct	pte p0br[ctopt(MAXTSIZ+MAXDSIZ+MAXSSIZ)][NPTEPG];
41*950Sbill int	pid;
42*950Sbill 
43*950Sbill struct	paginfo {
44*950Sbill 	char	z_type;
45*950Sbill 	char	z_count;
46*950Sbill 	short	z_pid;
47*950Sbill 	struct	pte z_pte;
48*950Sbill } *paginfo;
49*950Sbill #define	ZLOST	0
50*950Sbill #define	ZDATA	1
51*950Sbill #define	ZSTACK	2
52*950Sbill #define	ZUDOT	3
53*950Sbill #define	ZPAGET	4
54*950Sbill #define	ZTEXT	5
55*950Sbill #define	ZFREE	6
56*950Sbill #define	ZINTRAN	7
57*950Sbill 
58*950Sbill #define	NDBLKS	(2*SMAPSIZ)
59*950Sbill struct	dblks {
60*950Sbill 	short	d_first;
61*950Sbill 	short	d_size;
62*950Sbill 	char	d_type;
63*950Sbill 	char	d_index;
64*950Sbill } dblks[NDBLKS];
65*950Sbill int	ndblks;
66*950Sbill 
67*950Sbill #define	DFREE	0
68*950Sbill #define	DDATA	1
69*950Sbill #define	DSTACK	2
70*950Sbill #define	DTEXT	3
71*950Sbill #define	DUDOT	4
72*950Sbill #define	DPAGET	5
73*950Sbill 
74*950Sbill union	{
75*950Sbill 	char buf[UPAGES][512];
76*950Sbill 	struct user U;
77*950Sbill } u_area;
78*950Sbill #define	u	u_area.U
79*950Sbill 
80*950Sbill int	fcore = -1;
81*950Sbill int	fswap = -1;
82*950Sbill 
83*950Sbill struct	nlist nl[] = {
84*950Sbill #define	X_PROC 0
85*950Sbill 	{ "_proc" },
86*950Sbill #define	X_USRPT 1
87*950Sbill 	{ "_usrpt" },
88*950Sbill #define	X_PTMA	2
89*950Sbill 	{ "_Usrptma" },
90*950Sbill #define	X_FIRSTFREE 3
91*950Sbill 	{ "_firstfr" },
92*950Sbill #define	X_MAXFREE 4
93*950Sbill 	{ "_maxfree" },
94*950Sbill #define	X_TEXT 5
95*950Sbill 	{ "_text" },
96*950Sbill #define	X_FREEMEM 6
97*950Sbill 	{ "_freemem" },
98*950Sbill #define	X_CMAP 7
99*950Sbill 	{ "_cmap" },
100*950Sbill #define	X_ECMAP 8
101*950Sbill 	{ "_ecmap" },
102*950Sbill #define	X_SWAPMAP 9
103*950Sbill 	{ "_swapmap" },
104*950Sbill 	{ 0 }
105*950Sbill };
106*950Sbill 
107*950Sbill main(argc, argv)
108*950Sbill 	int argc;
109*950Sbill 	char **argv;
110*950Sbill {
111*950Sbill 	register struct nlist *np;
112*950Sbill 	register struct proc *p;
113*950Sbill 	register struct text *xp;
114*950Sbill 	register struct pte *pte;
115*950Sbill 	register int i;
116*950Sbill 	int w, a;
117*950Sbill 
118*950Sbill 	argc--, argv++;
119*950Sbill 	while (argc > 0 && argv[0][0] == '-') {
120*950Sbill 		register char *cp = *argv++;
121*950Sbill 		argc--;
122*950Sbill 		while (*++cp) switch (*cp) {
123*950Sbill 
124*950Sbill 		case 'm':
125*950Sbill 			mflg++;
126*950Sbill 			break;
127*950Sbill 
128*950Sbill 		case 'v':
129*950Sbill 			vflg++;
130*950Sbill 			break;
131*950Sbill 
132*950Sbill 		case 's':
133*950Sbill 			if (argc < 2)
134*950Sbill 				goto usage;
135*950Sbill 			if ((fswap = open(argv[0], 0)) < 0) {
136*950Sbill 				perror(argv[0]);
137*950Sbill 				exit(1);
138*950Sbill 			}
139*950Sbill 			argc--,argv++;
140*950Sbill 			sflg++;
141*950Sbill 			break;
142*950Sbill 
143*950Sbill 		case 'f':
144*950Sbill 			fflg++;
145*950Sbill 			break;
146*950Sbill 
147*950Sbill 		case 'D':
148*950Sbill 			Dflg++;
149*950Sbill 			break;
150*950Sbill 
151*950Sbill 		case 'd':
152*950Sbill 			dflg++;
153*950Sbill 			break;
154*950Sbill 
155*950Sbill 		default:
156*950Sbill 			goto usage;
157*950Sbill 		}
158*950Sbill 	}
159*950Sbill 	if (argc < 1) {
160*950Sbill usage:
161*950Sbill 		fprintf(stderr, "usage: analyze [ -vmfd ] [ -s swapfile ] corefile [ system ]\n");
162*950Sbill 		exit(1);
163*950Sbill 	}
164*950Sbill 	close(0);
165*950Sbill 	if ((fcore = open(argv[0], 0)) < 0) {
166*950Sbill 		perror(argv[0]);
167*950Sbill 		exit(1);
168*950Sbill 	}
169*950Sbill 	nlist(argc > 1 ? argv[1] : "/vmunix", nl);
170*950Sbill 	if (nl[0].n_value == 0) {
171*950Sbill 		fprintf(stderr, "%s: bad namelist\n",
172*950Sbill 		    argc > 1 ? argv[1] : "/vmunix");
173*950Sbill 		exit(1);
174*950Sbill 	}
175*950Sbill 	for (np = nl; np->n_name[0]; np++)
176*950Sbill 		vprintf("%8.8s %x\n", np->n_name ,np->n_value );
177*950Sbill 	usrpt = (struct pte *)clear(nl[X_USRPT].n_value);
178*950Sbill 	Usrptma = (struct pte *)clear(nl[X_PTMA].n_value);
179*950Sbill 	firstfree = get(nl[X_FIRSTFREE].n_value);
180*950Sbill 	maxfree = get(nl[X_MAXFREE].n_value);
181*950Sbill 	freemem = get(nl[X_FREEMEM].n_value);
182*950Sbill 	paginfo = (struct paginfo *)calloc(maxfree, sizeof (struct paginfo));
183*950Sbill 	if (paginfo == NULL) {
184*950Sbill 		fprintf(stderr, "maxfree %x?... out of mem!\n", maxfree);
185*950Sbill 		exit(1);
186*950Sbill 	}
187*950Sbill 	vprintf("usrpt %x\nUsrptma %x\nfirstfree %x\nmaxfree %x\nfreemem %x\n",
188*950Sbill 		    usrpt, Usrptma, firstfree, maxfree, freemem);
189*950Sbill 	lseek(fcore, (long)clear(nl[X_PROC].n_value), 0);
190*950Sbill 	if (read(fcore, (char *)proc, sizeof proc) != sizeof proc) {
191*950Sbill 	 	perror("proc read");
192*950Sbill 		exit(1);
193*950Sbill 	}
194*950Sbill 	lseek(fcore, (long)clear(nl[X_TEXT].n_value), 0);
195*950Sbill 	if (read(fcore, (char *)text, sizeof text) != sizeof text) {
196*950Sbill 		perror("text read");
197*950Sbill 		exit(1);
198*950Sbill 	}
199*950Sbill 	i = (get(nl[X_ECMAP].n_value) - get(nl[X_CMAP].n_value));
200*950Sbill 	cmap = (struct cmap *)calloc(i, 1);
201*950Sbill 	if (cmap == NULL) {
202*950Sbill 		fprintf(stderr, "not enough mem for %x bytes of cmap\n", i);
203*950Sbill 		exit(1);
204*950Sbill 	}
205*950Sbill 	lseek(fcore, (long)clear(get(nl[X_CMAP].n_value)), 0);
206*950Sbill 	if (read(fcore, (char *)cmap, i) != i) {
207*950Sbill 		perror("cmap read");
208*950Sbill 		exit(1);
209*950Sbill 	}
210*950Sbill 	lseek(fcore, (long)clear(nl[X_SWAPMAP].n_value), 0);
211*950Sbill 	if (read(fcore, (char *)swapmap, sizeof swapmap) != sizeof swapmap) {
212*950Sbill 		perror("swapmap read");
213*950Sbill 		exit(1);
214*950Sbill 	}
215*950Sbill 	for (p = &proc[1]; p < &proc[NPROC]; p++) {
216*950Sbill 		p->p_p0br = (struct pte *)clear(p->p_p0br);
217*950Sbill 		p->p_addr = (struct pte *)clear(p->p_addr);
218*950Sbill 		if (p->p_stat == 0)
219*950Sbill 			continue;
220*950Sbill 		printf("proc %d ", p->p_pid);
221*950Sbill 		if (p->p_stat == SZOMB) {
222*950Sbill 			printf("zombie\n");
223*950Sbill 			continue;
224*950Sbill 		}
225*950Sbill 		if (p->p_flag & SLOAD) {
226*950Sbill 			printf("loaded, p0br %x, ", p->p_p0br);
227*950Sbill 			printf("%d pages of page tables:", p->p_szpt);
228*950Sbill 			a = btokmx(p->p_p0br);
229*950Sbill 			for (i = 0; i < p->p_szpt; i++) {
230*950Sbill 				w = get(&Usrptma[a + i]);
231*950Sbill 				printf(" %x", w & PG_PFNUM);
232*950Sbill 			}
233*950Sbill 			printf("\n");
234*950Sbill 			for(i = 0; i < p->p_szpt; i++) {
235*950Sbill 				w = get(&Usrptma[a + i]);
236*950Sbill 				if (getpt(w, i))
237*950Sbill 					count(p, (struct pte *)&w, ZPAGET);
238*950Sbill 			}
239*950Sbill 		} else {
240*950Sbill 			/* i = ctopt(btoc(u.u_exdata.ux_dsize)); */
241*950Sbill 			i = clrnd(ctopt(p->p_tsize + p->p_dsize + p->p_ssize));
242*950Sbill 			printf("swapped, swaddr %x\n", p->p_swaddr);
243*950Sbill 			duse(p->p_swaddr, clrnd(ctod(UPAGES)), DUDOT, p - proc);
244*950Sbill 			duse(p->p_swaddr + ctod(UPAGES),
245*950Sbill 			    clrnd(i - p->p_tsize / NPTEPG), DPAGET, p - proc);
246*950Sbill 			    /* i, DPAGET, p - proc); */
247*950Sbill 		}
248*950Sbill 		p->p_p0br = (struct pte *)p0br;
249*950Sbill 		p->p_addr = uaddr(p);
250*950Sbill 		p->p_textp = &text[p->p_textp - (struct text *)nl[X_TEXT].n_value];
251*950Sbill 		if (p->p_pid == 2)
252*950Sbill 			continue;
253*950Sbill 		if (getu(p))
254*950Sbill 			continue;
255*950Sbill 		u.u_procp = p;
256*950Sbill 		pdmap();
257*950Sbill 		if ((p->p_flag & SLOAD) == 0)
258*950Sbill 			continue;
259*950Sbill 		pid = p->p_pid;
260*950Sbill 		for (i = 0; i < p->p_tsize; i++) {
261*950Sbill 			pte = tptopte(p, i);
262*950Sbill 			if (pte->pg_fod || pte->pg_pfnum == 0)
263*950Sbill 				continue;
264*950Sbill 			if (pte->pg_pfnum >= firstfree && pte->pg_pfnum < maxfree && cmap[pgtocm(pte->pg_pfnum)].c_intrans)
265*950Sbill 				count(p, pte, ZINTRAN);
266*950Sbill 			else
267*950Sbill 				count(p, pte, ZTEXT);
268*950Sbill 		}
269*950Sbill 		vprintf("\n");
270*950Sbill 		for (i = 0; i < p->p_dsize; i++) {
271*950Sbill 			pte = dptopte(p, i);
272*950Sbill 			if (pte->pg_fod || pte->pg_pfnum == 0)
273*950Sbill 				continue;
274*950Sbill 			if (pte->pg_pfnum >= firstfree && pte->pg_pfnum < maxfree && cmap[pgtocm(pte->pg_pfnum)].c_intrans)
275*950Sbill 				count(p, pte, ZINTRAN);
276*950Sbill 			else
277*950Sbill 				count(p, pte, ZDATA);
278*950Sbill 		}
279*950Sbill 		vprintf("\n");
280*950Sbill 		for (i = 0; i < p->p_ssize; i++) {
281*950Sbill 			pte = sptopte(p, i);
282*950Sbill 			if (pte->pg_fod || pte->pg_pfnum == 0)
283*950Sbill 				continue;
284*950Sbill 			if (pte->pg_pfnum >= firstfree && pte->pg_pfnum < maxfree && cmap[pgtocm(pte->pg_pfnum)].c_intrans)
285*950Sbill 				count(p, pte, ZINTRAN);
286*950Sbill 			else
287*950Sbill 				count(p, pte, ZSTACK);
288*950Sbill 		}
289*950Sbill 		vprintf("\n");
290*950Sbill 		for (i = 0; i < UPAGES; i++)
291*950Sbill 			count(p, &p->p_addr[i], ZUDOT);
292*950Sbill 		vprintf("\n");
293*950Sbill 		vprintf("\n");
294*950Sbill 	}
295*950Sbill 	for (xp = &text[0]; xp < &text[NTEXT]; xp++)
296*950Sbill 		if (xp->x_iptr) {
297*950Sbill 			for (i = 0; i < xp->x_size; i += DMTEXT)
298*950Sbill 				duse(xp->x_daddr[i],
299*950Sbill 				    (xp->x_size - i) > DMTEXT
300*950Sbill 					? DMTEXT : xp->x_size - i,
301*950Sbill 				    DTEXT, xp - text);
302*950Sbill 			if (xp->x_flag & XPAGI)
303*950Sbill 				duse(xp->x_ptdaddr, clrnd(ctopt(xp->x_size)),
304*950Sbill 				    DTEXT, xp - text);
305*950Sbill 		}
306*950Sbill 	dmcheck();
307*950Sbill 	fixfree();
308*950Sbill 	summary();
309*950Sbill 	exit(0);
310*950Sbill }
311*950Sbill 
312*950Sbill pdmap()
313*950Sbill {
314*950Sbill 	register struct text *xp;
315*950Sbill 
316*950Sbill 	if (fswap == -1 && (u.u_procp->p_flag & SLOAD) == 0)
317*950Sbill 		return;
318*950Sbill 	if (Dflg)
319*950Sbill 		printf("disk for pid %d", u.u_procp->p_pid);
320*950Sbill 	if ((xp = u.u_procp->p_textp) && Dflg)
321*950Sbill 		ptdmap(xp->x_daddr, xp->x_size);
322*950Sbill 	pdmseg("data", &u.u_dmap, DDATA);
323*950Sbill 	pdmseg("stack", &u.u_smap, DSTACK);
324*950Sbill 	if (Dflg)
325*950Sbill 		printf("\n");
326*950Sbill }
327*950Sbill 
328*950Sbill ptdmap(dp, size)
329*950Sbill 	register daddr_t *dp;
330*950Sbill 	int size;
331*950Sbill {
332*950Sbill 	register int i;
333*950Sbill 	int rem;
334*950Sbill 
335*950Sbill 	if (Dflg)
336*950Sbill 		printf(" text:");
337*950Sbill 	for (i = 0, rem = size; rem > 0; i++) {
338*950Sbill 		if (Dflg)
339*950Sbill 			printf(" %x<%x>", dp[i], rem < DMTEXT ? rem : DMTEXT);
340*950Sbill 		rem -= rem < DMTEXT ? rem : DMTEXT;
341*950Sbill 	}
342*950Sbill }
343*950Sbill 
344*950Sbill pdmseg(cp, dmp, type)
345*950Sbill 	char *cp;
346*950Sbill 	struct dmap *dmp;
347*950Sbill {
348*950Sbill 	register int i;
349*950Sbill 	int b, rem;
350*950Sbill 
351*950Sbill 	if (Dflg)
352*950Sbill 		printf(", %s:", cp);
353*950Sbill 	b = DMMIN;
354*950Sbill 	for (i = 0, rem = dmp->dm_size; rem > 0; i++) {
355*950Sbill 		if (Dflg)
356*950Sbill 			printf(" %x<%x>", dmp->dm_map[i], rem < b ? rem : b);
357*950Sbill 		duse(dmp->dm_map[i], b, type, u.u_procp - proc);
358*950Sbill 		rem -= b;
359*950Sbill 		if (b < DMMAX)
360*950Sbill 			b *= 2;
361*950Sbill 	}
362*950Sbill }
363*950Sbill 
364*950Sbill duse(first, size, type, index)
365*950Sbill {
366*950Sbill 	register struct dblks *dp;
367*950Sbill 
368*950Sbill 	if (fswap == -1)
369*950Sbill 		return;
370*950Sbill 	dp = &dblks[ndblks];
371*950Sbill 	if (++ndblks > NDBLKS) {
372*950Sbill 		fprintf(stderr, "too many disk blocks, increase NDBLKS\n");
373*950Sbill 		exit(1);
374*950Sbill 	}
375*950Sbill 	dp->d_first = first;
376*950Sbill 	dp->d_size = size;
377*950Sbill 	dp->d_type = type;
378*950Sbill 	dp->d_index = index;
379*950Sbill }
380*950Sbill 
381*950Sbill dsort(d, e)
382*950Sbill 	register struct dblks *d, *e;
383*950Sbill {
384*950Sbill 
385*950Sbill 	return (e->d_first - d->d_first);
386*950Sbill }
387*950Sbill 
388*950Sbill dmcheck()
389*950Sbill {
390*950Sbill 	register struct map *smp;
391*950Sbill 	register struct dblks *d, *e;
392*950Sbill 
393*950Sbill 	for (smp = swapmap; smp->m_size; smp++)
394*950Sbill 		duse(smp->m_addr, smp->m_size, DFREE, 0);
395*950Sbill 	duse(CLSIZE, DMTEXT - CLSIZE, DFREE, 0);
396*950Sbill 	qsort(dblks, ndblks, sizeof (struct dblks), dsort);
397*950Sbill 	d = &dblks[ndblks - 1];
398*950Sbill 	if (d->d_first > 1)
399*950Sbill 		printf("lost swap map: start %x size %x\n", 1, d->d_first);
400*950Sbill 	for (; d > dblks; d--) {
401*950Sbill 		if (dflg)
402*950Sbill 			dprint(d);
403*950Sbill 		e = d - 1;
404*950Sbill 		if (d->d_first + d->d_size > e->d_first) {
405*950Sbill 			printf("overlap in swap mappings:\n");
406*950Sbill 			dprint(d);
407*950Sbill 			dprint(e);
408*950Sbill 		} else if (d->d_first + d->d_size < e->d_first) {
409*950Sbill 			printf("lost swap map: start %x size %x\n",
410*950Sbill 			    d->d_first + d->d_size,
411*950Sbill 			    e->d_first - (d->d_first + d->d_size));
412*950Sbill 		}
413*950Sbill 	}
414*950Sbill 	if (dflg)
415*950Sbill 		dprint(dblks);
416*950Sbill 	if (sflg)
417*950Sbill 		printf("swap space ends at %x\n", d->d_first + d->d_size);
418*950Sbill }
419*950Sbill 
420*950Sbill char *dnames[] = {
421*950Sbill 	"DFREE",
422*950Sbill 	"DDATA",
423*950Sbill 	"DSTACK",
424*950Sbill 	"DTEXT",
425*950Sbill 	"DUDOT",
426*950Sbill 	"DPAGET",
427*950Sbill };
428*950Sbill 
429*950Sbill dprint(d)
430*950Sbill 	register struct dblks *d;
431*950Sbill {
432*950Sbill 
433*950Sbill 	printf("at %4x size %4x type %s", d->d_first, d->d_size,
434*950Sbill 		dnames[d->d_type]);
435*950Sbill 	switch (d->d_type) {
436*950Sbill 
437*950Sbill 	case DSTACK:
438*950Sbill 	case DDATA:
439*950Sbill 		printf(" pid %d", proc[d->d_index].p_pid);
440*950Sbill 		break;
441*950Sbill 	}
442*950Sbill 	printf("\n");
443*950Sbill }
444*950Sbill 
445*950Sbill getpt(x, i)
446*950Sbill 	int x, i;
447*950Sbill {
448*950Sbill 
449*950Sbill 	lseek(fcore, (long)ctob((x & PG_PFNUM)), 0);
450*950Sbill 	if (read(fcore, (char *)(p0br[i]), NBPG) != NBPG) {
451*950Sbill 		perror("read");
452*950Sbill 		fprintf(stderr, "getpt error reading frame %x\n", clear(x));
453*950Sbill 		return (0);
454*950Sbill 	}
455*950Sbill 	return (1);
456*950Sbill }
457*950Sbill 
458*950Sbill checkpg(p, pte, type)
459*950Sbill 	register struct pte *pte;
460*950Sbill 	register struct proc *p;
461*950Sbill 	int type;
462*950Sbill {
463*950Sbill 	char corepg[NBPG], swapg[NBPG];
464*950Sbill 	register int i, count, dblock;
465*950Sbill 	register int pfnum = pte->pg_pfnum;
466*950Sbill 
467*950Sbill 	if (type == ZPAGET || type == ZUDOT)
468*950Sbill 		return (0);
469*950Sbill 	lseek(fcore, (long)(NBPG * pfnum), 0);
470*950Sbill 	if (read(fcore, corepg, NBPG) != NBPG){
471*950Sbill 		perror("read");
472*950Sbill 		fprintf(stderr, "Error reading core page %x\n", pfnum);
473*950Sbill 		return (0);
474*950Sbill 	}
475*950Sbill 	switch (type) {
476*950Sbill 
477*950Sbill 	case ZDATA:
478*950Sbill 		if (ptetodp(p, pte) >= u.u_dmap.dm_size)
479*950Sbill 			return (0);
480*950Sbill 		break;
481*950Sbill 
482*950Sbill 	case ZTEXT:
483*950Sbill 		break;
484*950Sbill 
485*950Sbill 	case ZSTACK:
486*950Sbill 		if (ptetosp(p, pte) >= u.u_smap.dm_size)
487*950Sbill 			return (0);
488*950Sbill 		break;
489*950Sbill 
490*950Sbill 	default:
491*950Sbill 		return(0);
492*950Sbill 		break;
493*950Sbill 	}
494*950Sbill 	dblock = vtod(p, ptetov(p, pte), &u.u_dmap, &u.u_smap);
495*950Sbill 	vprintf("   %x", dblock);
496*950Sbill 	if (pte->pg_fod || pte->pg_pfnum == 0)
497*950Sbill 		return (0);
498*950Sbill 	if (cmap[pgtocm(pte->pg_pfnum)].c_intrans || pte->pg_m || pte->pg_swapm)
499*950Sbill 		return (0);
500*950Sbill 	lseek(fswap, (long)(NBPG * dblock), 0);
501*950Sbill 	if (read(fswap, swapg, NBPG) != NBPG) {
502*950Sbill 		fprintf(stderr,"swap page %x: ", dblock);
503*950Sbill 		perror("read");
504*950Sbill 	}
505*950Sbill 	count = 0;
506*950Sbill 	for (i = 0; i < NBPG; i++)
507*950Sbill 		if (corepg[i] != swapg[i])
508*950Sbill 			count++;
509*950Sbill 	if (count == 0)
510*950Sbill 		vprintf("\tsame");
511*950Sbill 	return (count);
512*950Sbill }
513*950Sbill 
514*950Sbill getu(p)
515*950Sbill 	register struct proc *p;
516*950Sbill {
517*950Sbill 	int i, w, cc, errs = 0;
518*950Sbill 
519*950Sbill 	for (i = 0; i < UPAGES; i++) {
520*950Sbill 		if (p->p_flag & SLOAD) {
521*950Sbill 			lseek(fcore, ctob(p->p_addr[i].pg_pfnum), 0);
522*950Sbill 			if (read(fcore, u_area.buf[i], NBPG) != NBPG)
523*950Sbill 				perror("core u. read"), errs++;
524*950Sbill 		} else if (fswap >= 0) {
525*950Sbill 			lseek(fswap, (long)(NBPG * (p->p_swaddr+i)), 0);
526*950Sbill 			if (read(fswap, u_area.buf[i], NBPG) != NBPG)
527*950Sbill 				perror("swap u. read"), errs++;
528*950Sbill 		}
529*950Sbill 	}
530*950Sbill 	return (errs);
531*950Sbill }
532*950Sbill 
533*950Sbill char	*typepg[] = {
534*950Sbill 	"lost",
535*950Sbill 	"data",
536*950Sbill 	"stack",
537*950Sbill 	"udot",
538*950Sbill 	"paget",
539*950Sbill 	"text",
540*950Sbill 	"free",
541*950Sbill 	"intransit",
542*950Sbill };
543*950Sbill 
544*950Sbill count(p, pte, type)
545*950Sbill 	struct proc *p;
546*950Sbill 	register struct pte *pte;
547*950Sbill 	int type;
548*950Sbill {
549*950Sbill 	register int pfnum = pte->pg_pfnum;
550*950Sbill 	register struct paginfo *zp = &paginfo[pfnum];
551*950Sbill 	int ndif;
552*950Sbill #define	zprintf	if (type==ZINTRAN || vflg) printf
553*950Sbill 
554*950Sbill 	if (type == ZINTRAN && pfnum == 0)
555*950Sbill 		return;
556*950Sbill 	zprintf("page %x %s", pfnum, typepg[type]);
557*950Sbill 	if (sflg == 0 || (ndif = checkpg(p, pte, type)) == 0) {
558*950Sbill 		zprintf("\n");
559*950Sbill 	} else {
560*950Sbill 		if (vflg == 0 && type != ZINTRAN)
561*950Sbill 			printf("page %x %s,", pfnum, typepg[type]);
562*950Sbill 		printf(" %d bytes differ\n",ndif);
563*950Sbill 	}
564*950Sbill 	if (pfnum < firstfree || pfnum > maxfree) {
565*950Sbill 		printf("page number out of range:\n");
566*950Sbill 		printf("\tpage %x type %s pid %d\n", pfnum, typepg[type], pid);
567*950Sbill 		return;
568*950Sbill 	}
569*950Sbill 	if (bad(zp, type)) {
570*950Sbill 		printf("dup page pte %x", *(int *)pte);
571*950Sbill 		dumpcm("", pte->pg_pfnum);
572*950Sbill 		dump(zp);
573*950Sbill 		printf("pte %x and as %s in pid %d\n", zp->z_pte, typepg[type], pid);
574*950Sbill 		return;
575*950Sbill 	}
576*950Sbill 	zp->z_type = type;
577*950Sbill 	zp->z_count++;
578*950Sbill 	zp->z_pid = pid;
579*950Sbill 	zp->z_pte = *pte;
580*950Sbill }
581*950Sbill 
582*950Sbill bad(zp, type)
583*950Sbill 	struct paginfo *zp;
584*950Sbill {
585*950Sbill 	if (type == ZTEXT) {
586*950Sbill 		if (zp->z_type != 0 && zp->z_type != ZTEXT)
587*950Sbill 			return (1);
588*950Sbill 		return (0);
589*950Sbill 	}
590*950Sbill 	return (zp->z_count);
591*950Sbill }
592*950Sbill 
593*950Sbill dump(zp)
594*950Sbill 	struct paginfo *zp;
595*950Sbill {
596*950Sbill 
597*950Sbill 	printf("page %x type %s pid %d ", zp - paginfo, typepg[zp->z_type], zp->z_pid);
598*950Sbill }
599*950Sbill 
600*950Sbill summary()
601*950Sbill {
602*950Sbill 	register int i;
603*950Sbill 	register struct paginfo *zp;
604*950Sbill 	register int pfnum;
605*950Sbill 
606*950Sbill 	for (i = firstfree + UPAGES; i < maxfree; i++) {
607*950Sbill 		zp = &paginfo[i];
608*950Sbill 		if (zp->z_type == ZLOST)
609*950Sbill 			dumpcm("lost", i);
610*950Sbill 		pfnum = pgtocm(i);
611*950Sbill 		if (cmap[pfnum].c_lock && cmap[pfnum].c_type != CSYS)
612*950Sbill 			dumpcm("locked", i);
613*950Sbill 		if (mflg)
614*950Sbill 			dumpcm("mem", i);
615*950Sbill 	}
616*950Sbill }
617*950Sbill 
618*950Sbill char	*tynames[] = {
619*950Sbill 	"sys",
620*950Sbill 	"text",
621*950Sbill 	"data",
622*950Sbill 	"stack"
623*950Sbill };
624*950Sbill dumpcm(cp, pg)
625*950Sbill 	char *cp;
626*950Sbill 	int pg;
627*950Sbill {
628*950Sbill 	int pslot;
629*950Sbill 	int cm;
630*950Sbill 	register struct cmap *c;
631*950Sbill 
632*950Sbill 	printf("%s page %x ", cp, pg);
633*950Sbill 	cm = pgtocm(pg);
634*950Sbill 	c = &cmap[cm];
635*950Sbill 	printf("\t[%x, %x", c->c_page, c->c_ndx);
636*950Sbill 	if (c->c_type != CTEXT)
637*950Sbill 		printf(" (=pid %d)", proc[c->c_ndx].p_pid);
638*950Sbill 	else {
639*950Sbill 		pslot=(text[c->c_ndx].x_caddr - (struct proc *)nl[X_PROC].n_value);
640*950Sbill 		printf(" (=pid");
641*950Sbill 		for(;;) {
642*950Sbill 			printf(" %d", proc[pslot].p_pid);
643*950Sbill 			if (proc[pslot].p_xlink == 0)
644*950Sbill 				break;
645*950Sbill 			pslot=(proc[pslot].p_xlink - (struct proc *)nl[X_PROC].n_value);
646*950Sbill 		}
647*950Sbill 		printf(")");
648*950Sbill 	}
649*950Sbill 	printf("] ");
650*950Sbill 	printf(tynames[c->c_type]);
651*950Sbill 	if (c->c_free)
652*950Sbill 		printf(" free");
653*950Sbill 	if (c->c_gone)
654*950Sbill 		printf(" gone");
655*950Sbill 	if (c->c_lock)
656*950Sbill 		printf(" lock");
657*950Sbill 	if (c->c_want)
658*950Sbill 		printf(" want");
659*950Sbill 	if (c->c_intrans)
660*950Sbill 		printf(" intrans");
661*950Sbill 	if (c->c_blkno)
662*950Sbill 		printf(" blkno %x mdev %d", c->c_blkno, c->c_mdev);
663*950Sbill 	printf("\n");
664*950Sbill }
665*950Sbill 
666*950Sbill fixfree()
667*950Sbill {
668*950Sbill 	register int i, next, prev;
669*950Sbill 
670*950Sbill 	next = CMHEAD;
671*950Sbill 	for (i=freemem/CLSIZE; --i >=0; ) {
672*950Sbill 		prev = next;
673*950Sbill 		next = cmap[next].c_next;
674*950Sbill 		if (cmap[next].c_free == 0) {
675*950Sbill 			printf("link to non free block: in %x to %x\n", cmtopg(prev), cmtopg(next));
676*950Sbill 			dumpcm("bad free link in", cmtopg(prev));
677*950Sbill 			dumpcm("to non free block", cmtopg(next));
678*950Sbill 		}
679*950Sbill 		if (cmtopg(next) > maxfree) {
680*950Sbill 			printf("free list link out of range: in %x to %x\n", cmtopg(prev), cmtopg(next));
681*950Sbill 			dumpcm("bad link in", cmtopg(prev));
682*950Sbill 		}
683*950Sbill 		paginfo[cmtopg(next)].z_type = ZFREE;
684*950Sbill 		if (fflg)
685*950Sbill 			dumpcm("free", cmtopg(next));
686*950Sbill 		paginfo[cmtopg(next)+1].z_type = ZFREE;
687*950Sbill 		if (fflg)
688*950Sbill 			dumpcm("free", cmtopg(next)+1);
689*950Sbill 	}
690*950Sbill }
691*950Sbill 
692*950Sbill get(loc)
693*950Sbill unsigned loc;
694*950Sbill {
695*950Sbill 	int x;
696*950Sbill 
697*950Sbill 	lseek(fcore, (long)clear(loc), 0);
698*950Sbill 	if (read(fcore, (char *)&x, sizeof (int)) != sizeof (int)) {
699*950Sbill 		perror("read");
700*950Sbill 		fprintf(stderr, "get failed on %x\n", clear(loc));
701*950Sbill 		return (0);
702*950Sbill 	}
703*950Sbill 	return (x);
704*950Sbill }
705*950Sbill /*
706*950Sbill  * Convert a virtual page number
707*950Sbill  * to its corresponding disk block number.
708*950Sbill  * Used in pagein/pageout to initiate single page transfers.
709*950Sbill  */
710*950Sbill vtod(p, v, dmap, smap)
711*950Sbill 	register struct proc *p;
712*950Sbill 	register struct dmap *dmap, *smap;
713*950Sbill {
714*950Sbill 	struct dblock db;
715*950Sbill 
716*950Sbill 	if (v < p->p_tsize)
717*950Sbill 		return(p->p_textp->x_daddr[v / DMTEXT] + v % DMTEXT);
718*950Sbill 	if (isassv(p, v))
719*950Sbill 		vstodb(vtosp(p, v), 1, smap, &db, 1);
720*950Sbill 	else
721*950Sbill 		vstodb(vtodp(p, v), 1, dmap, &db, 0);
722*950Sbill 	return (db.db_base);
723*950Sbill }
724*950Sbill 
725*950Sbill /*
726*950Sbill  * Convert a pte pointer to
727*950Sbill  * a virtual page number.
728*950Sbill  */
729*950Sbill ptetov(p, pte)
730*950Sbill 	register struct proc *p;
731*950Sbill 	register struct pte *pte;
732*950Sbill {
733*950Sbill 
734*950Sbill 	if (isatpte(p, pte))
735*950Sbill 		return (tptov(p, ptetotp(p, pte)));
736*950Sbill 	else if (isadpte(p, pte))
737*950Sbill 		return (dptov(p, ptetodp(p, pte)));
738*950Sbill 	else
739*950Sbill 		return (sptov(p, ptetosp(p, pte)));
740*950Sbill }
741*950Sbill 
742*950Sbill /*
743*950Sbill  * Given a base/size pair in virtual swap area,
744*950Sbill  * return a physical base/size pair which is the
745*950Sbill  * (largest) initial, physically contiguous block.
746*950Sbill  */
747*950Sbill vstodb(vsbase, vssize, dmp, dbp, rev)
748*950Sbill 	register int vsbase;
749*950Sbill 	int vssize;
750*950Sbill 	register struct dmap *dmp;
751*950Sbill 	register struct dblock *dbp;
752*950Sbill {
753*950Sbill 	register int blk = DMMIN;
754*950Sbill 	register swblk_t *ip = dmp->dm_map;
755*950Sbill 
756*950Sbill 	if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
757*950Sbill 		panic("vstodb");
758*950Sbill 	while (vsbase >= blk) {
759*950Sbill 		vsbase -= blk;
760*950Sbill 		if (blk < DMMAX)
761*950Sbill 			blk *= 2;
762*950Sbill 		ip++;
763*950Sbill 	}
764*950Sbill 	dbp->db_size = min(vssize, blk - vsbase);
765*950Sbill 	dbp->db_base = *ip + (rev ? blk - (vsbase + vssize) : vsbase);
766*950Sbill }
767*950Sbill 
768*950Sbill panic(cp)
769*950Sbill 	char *cp;
770*950Sbill {
771*950Sbill 	printf("panic!: %s\n", cp);
772*950Sbill }
773*950Sbill 
774*950Sbill min(a, b)
775*950Sbill {
776*950Sbill 	return (a < b ? a : b);
777*950Sbill }
778