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