|
|
1.1 root 1: static char *sccsid = "@(#)analyze.c 4.1 (Berkeley) 10/1/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.