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