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