xref: /original-bsd/usr.sbin/pstat/pstat.c (revision 0a83ae40)
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[] = "@(#)pstat.c	5.17 (Berkeley) 01/01/88";
15 #endif /* not lint */
16 
17 /*
18  * Print system stuff
19  */
20 
21 #include <sys/param.h>
22 #include <sys/dir.h>
23 #define	KERNEL
24 #include <sys/file.h>
25 #undef	KERNEL
26 #include <sys/user.h>
27 #include <sys/proc.h>
28 #include <sys/text.h>
29 #include <sys/inode.h>
30 #include <sys/map.h>
31 #include <sys/ioctl.h>
32 #include <sys/tty.h>
33 #include <sys/conf.h>
34 #include <sys/vm.h>
35 #include <nlist.h>
36 #include <machine/pte.h>
37 #include <stdio.h>
38 
39 #define mask(x)		(x&0377)
40 #define	clear(x)	((int)x &~ KERNBASE)
41 
42 char	*fcore	= "/dev/kmem";
43 char	*fmem	= "/dev/mem";
44 char	*fnlist	= "/vmunix";
45 int	fc, fm;
46 
47 struct nlist nl[] = {
48 #define	SINODE	0
49 	{ "_inode" },
50 #define	STEXT	1
51 	{ "_text" },
52 #define	SPROC	2
53 	{ "_proc" },
54 #define	SCONS	3
55 	{ "_cons" },
56 #define	SFIL	4
57 	{ "_file" },
58 #define	USRPTMA	5
59 	{ "_Usrptmap" },
60 #define	USRPT	6
61 	{ "_usrpt" },
62 #define	SWAPMAP	7
63 	{ "_swapmap" },
64 #define	SNPROC	8
65 	{ "_nproc" },
66 #define	SNTEXT	9
67 	{ "_ntext" },
68 #define	SNFILE	10
69 	{ "_nfile" },
70 #define	SNINODE	11
71 	{ "_ninode" },
72 #define	SNSWAPMAP 12
73 	{ "_nswapmap" },
74 #define	SPTY	13
75 	{ "_pt_tty" },
76 #define	SDMMIN	14
77 	{ "_dmmin" },
78 #define	SDMMAX	15
79 	{ "_dmmax" },
80 #define	SNSWDEV	16
81 	{ "_nswdev" },
82 #define	SSWDEVT	17
83 	{ "_swdevt" },
84 #define	SYSMAP	18
85 	{ "_Sysmap" },
86 #define	SNPTY	19
87 	{ "_npty" },
88 #ifdef vax
89 #define	SDZ	(SNPTY+1)
90 	{ "_dz_tty" },
91 #define	SNDZ	(SNPTY+2)
92 	{ "_dz_cnt" },
93 #define	SDMF	(SNPTY+3)
94 	{ "_dmf_tty" },
95 #define	SNDMF	(SNPTY+4)
96 	{ "_ndmf" },
97 #define	SDH	(SNPTY+5)
98 	{ "_dh11" },
99 #define	SNDH	(SNPTY+6)
100 	{ "_ndh11" },
101 #define	SDHU	(SNPTY+7)
102 	{ "_dhu_tty" },
103 #define	SNDHU	(SNPTY+8)
104 	{ "_ndhu" },
105 #define	SDMZ	(SNPTY+9)
106 	{ "_dmz_tty" },
107 #define	SNDMZ	(SNPTY+10)
108 	{ "_ndmz" },
109 #define	SQD	(SNPTY+11)
110 	{ "_qd_tty" },
111 #define	SNQD	(SNPTY+12)
112 	{ "_nNQD" },
113 #endif
114 #ifdef tahoe
115 #define	SVX	(SNPTY+1)
116 	{ "_vx_tty" },
117 #define	SNVX	(SNPTY+2)
118 	{ "_nvx" },
119 #endif
120 	{ "" }
121 };
122 
123 int	inof;
124 int	txtf;
125 int	prcf;
126 int	ttyf;
127 int	usrf;
128 long	ubase;
129 int	filf;
130 int	swpf;
131 int	totflg;
132 char	partab[1];
133 struct	cdevsw	cdevsw[1];
134 struct	bdevsw	bdevsw[1];
135 int	allflg;
136 int	kflg;
137 struct	pte *Usrptma;
138 struct	pte *usrpt;
139 u_long	getword();
140 off_t	mkphys();
141 
142 main(argc, argv)
143 	int argc;
144 	char **argv;
145 {
146 	extern char *optarg;
147 	extern int optind;
148 	int ch;
149 
150 	while ((ch = getopt(argc, argv, "Tafikptu:sx")) != EOF)
151 		switch((char)ch) {
152 		case 'T':
153 			totflg++;
154 			break;
155 		case 'a':
156 			allflg++;
157 			/*FALLTHROUGH*/
158 		case 'p':
159 			prcf++;
160 			break;
161 		case 'f':
162 			filf++;
163 			break;
164 		case 'i':
165 			inof++;
166 			break;
167 		case 'k':			/* undocumented */
168 			kflg++;
169 			fcore = fmem = "/vmcore";
170 			break;
171 		case 't':
172 			ttyf++;
173 			break;
174 		case 'u':
175 			usrf++;
176 			sscanf(optarg, "%x", &ubase);
177 			break;
178 		case 's':
179 			swpf++;
180 			break;
181 		case 'x':
182 			txtf++;
183 			break;
184 		case '?':
185 		default:
186 			printf("usage: pstat -[Tafiptsx] [-u [ubase]] [system] [core]\n");
187 			exit(1);
188 		}
189 	argc -= optind;
190 	argv += optind;
191 
192 	if (argc>1) {
193 		fcore = fmem = argv[1];
194 		kflg++;
195 	}
196 	if ((fc = open(fcore, O_RDONLY, 0)) < 0) {
197 		perror(fcore);
198 		exit(1);
199 	}
200 	if ((fm = open(fmem, O_RDONLY, 0)) < 0) {
201 		perror(fmem);
202 		exit(1);
203 	}
204 	if (argc>0)
205 		fnlist = argv[0];
206 	nlist(fnlist, nl);
207 	if (nl[0].n_type == 0) {
208 		printf("pstat: no namelist.\n");
209 		exit(1);
210 	}
211 	usrpt = (struct pte *)nl[USRPT].n_value;
212 	Usrptma = (struct pte *)nl[USRPTMA].n_value;
213 	if (!(filf | totflg | inof | prcf | txtf | ttyf | usrf | swpf)) {
214 		printf("pstat: one or more of -[aixptfsu] is required\n");
215 		exit(1);
216 	}
217 	if (filf||totflg)
218 		dofile();
219 	if (inof||totflg)
220 		doinode();
221 	if (prcf||totflg)
222 		doproc();
223 	if (txtf||totflg)
224 		dotext();
225 	if (ttyf)
226 		dotty();
227 	if (usrf)
228 		dousr();
229 	if (swpf||totflg)
230 		doswap();
231 }
232 
233 doinode()
234 {
235 	register struct inode *ip;
236 	struct inode *xinode, *ainode;
237 	register int nin;
238 	int ninode;
239 
240 	nin = 0;
241 	ninode = getword(nl[SNINODE].n_value);
242 	xinode = (struct inode *)calloc(ninode, sizeof (struct inode));
243 	ainode = (struct inode *)getword(nl[SINODE].n_value);
244 	if (ninode < 0 || ninode > 10000) {
245 		fprintf(stderr, "number of inodes is preposterous (%d)\n",
246 			ninode);
247 		return;
248 	}
249 	if (xinode == NULL) {
250 		fprintf(stderr, "can't allocate memory for inode table\n");
251 		return;
252 	}
253 	lseek(fc, mkphys((off_t)ainode), 0);
254 	read(fc, xinode, ninode * sizeof(struct inode));
255 	for (ip = xinode; ip < &xinode[ninode]; ip++)
256 		if (ip->i_count)
257 			nin++;
258 	if (totflg) {
259 		printf("%3d/%3d inodes\n", nin, ninode);
260 		return;
261 	}
262 	printf("%d/%d active inodes\n", nin, ninode);
263 printf("   LOC      FLAGS    CNT DEVICE  RDC WRC  INO  MODE  NLK UID   SIZE/DEV\n");
264 	for (ip = xinode; ip < &xinode[ninode]; ip++) {
265 		if (ip->i_count == 0)
266 			continue;
267 		printf("%8.1x ", ainode + (ip - xinode));
268 		putf(ip->i_flag&ILOCKED, 'L');
269 		putf(ip->i_flag&IUPD, 'U');
270 		putf(ip->i_flag&IACC, 'A');
271 		putf(ip->i_flag&IMOUNT, 'M');
272 		putf(ip->i_flag&IWANT, 'W');
273 		putf(ip->i_flag&ITEXT, 'T');
274 		putf(ip->i_flag&ICHG, 'C');
275 		putf(ip->i_flag&ISHLOCK, 'S');
276 		putf(ip->i_flag&IEXLOCK, 'E');
277 		putf(ip->i_flag&ILWAIT, 'Z');
278 		printf("%4d", ip->i_count&0377);
279 		printf("%4d,%3d", major(ip->i_dev), minor(ip->i_dev));
280 		printf("%4d", ip->i_shlockc&0377);
281 		printf("%4d", ip->i_exlockc&0377);
282 		printf("%6d", ip->i_number);
283 		printf("%6x", ip->i_mode & 0xffff);
284 		printf("%4d", ip->i_nlink);
285 		printf("%4d", ip->i_uid);
286 		if ((ip->i_mode&IFMT)==IFBLK || (ip->i_mode&IFMT)==IFCHR)
287 			printf("%6d,%3d", major(ip->i_rdev), minor(ip->i_rdev));
288 		else
289 			printf("%10ld", ip->i_size);
290 		printf("\n");
291 	}
292 	free(xinode);
293 }
294 
295 u_long
296 getword(loc)
297 	off_t loc;
298 {
299 	u_long word;
300 
301 	if (kflg)
302 		loc = clear(loc);
303 	lseek(fc, loc, 0);
304 	read(fc, &word, sizeof (word));
305 	return (word);
306 }
307 
308 putf(v, n)
309 {
310 	if (v)
311 		printf("%c", n);
312 	else
313 		printf(" ");
314 }
315 
316 dotext()
317 {
318 	register struct text *xp;
319 	int ntext;
320 	struct text *xtext, *atext;
321 	int ntx, ntxca;
322 
323 	ntx = ntxca = 0;
324 	ntext = getword(nl[SNTEXT].n_value);
325 	xtext = (struct text *)calloc(ntext, sizeof (struct text));
326 	atext = (struct text *)getword(nl[STEXT].n_value);
327 	if (ntext < 0 || ntext > 10000) {
328 		fprintf(stderr, "number of texts is preposterous (%d)\n",
329 			ntext);
330 		return;
331 	}
332 	if (xtext == NULL) {
333 		fprintf(stderr, "can't allocate memory for text table\n");
334 		return;
335 	}
336 	lseek(fc, mkphys((off_t)atext), 0);
337 	read(fc, xtext, ntext * sizeof (struct text));
338 	for (xp = xtext; xp < &xtext[ntext]; xp++) {
339 		if (xp->x_iptr != NULL)
340 			ntxca++;
341 		if (xp->x_count != 0)
342 			ntx++;
343 	}
344 	if (totflg) {
345 		printf("%3d/%3d texts active, %3d used\n", ntx, ntext, ntxca);
346 		return;
347 	}
348 	printf("%d/%d active texts, %d used\n", ntx, ntext, ntxca);
349 	printf("\
350    LOC   FLAGS DADDR     CADDR  RSS SIZE     IPTR   CNT CCNT      FORW     BACK\n");
351 	for (xp = xtext; xp < &xtext[ntext]; xp++) {
352 		if (xp->x_iptr == NULL)
353 			continue;
354 		printf("%8.1x", atext + (xp - xtext));
355 		printf(" ");
356 		putf(xp->x_flag&XPAGI, 'P');
357 		putf(xp->x_flag&XTRC, 'T');
358 		putf(xp->x_flag&XWRIT, 'W');
359 		putf(xp->x_flag&XLOAD, 'L');
360 		putf(xp->x_flag&XLOCK, 'K');
361 		putf(xp->x_flag&XWANT, 'w');
362 		printf("%5x", xp->x_daddr[0]);
363 		printf("%10x", xp->x_caddr);
364 		printf("%5d", xp->x_rssize);
365 		printf("%5d", xp->x_size);
366 		printf("%10.1x", xp->x_iptr);
367 		printf("%5d", xp->x_count&0377);
368 		printf("%5d", xp->x_ccount);
369 		printf("%10x", xp->x_forw);
370 		printf("%9x", xp->x_back);
371 		printf("\n");
372 	}
373 	free(xtext);
374 }
375 
376 doproc()
377 {
378 	struct proc *xproc, *aproc;
379 	int nproc;
380 	register struct proc *pp;
381 	register loc, np;
382 	struct pte apte;
383 
384 	nproc = getword(nl[SNPROC].n_value);
385 	xproc = (struct proc *)calloc(nproc, sizeof (struct proc));
386 	aproc = (struct proc *)getword(nl[SPROC].n_value);
387 	if (nproc < 0 || nproc > 10000) {
388 		fprintf(stderr, "number of procs is preposterous (%d)\n",
389 			nproc);
390 		return;
391 	}
392 	if (xproc == NULL) {
393 		fprintf(stderr, "can't allocate memory for proc table\n");
394 		return;
395 	}
396 	lseek(fc, mkphys((off_t)aproc), 0);
397 	read(fc, xproc, nproc * sizeof (struct proc));
398 	np = 0;
399 	for (pp=xproc; pp < &xproc[nproc]; pp++)
400 		if (pp->p_stat)
401 			np++;
402 	if (totflg) {
403 		printf("%3d/%3d processes\n", np, nproc);
404 		return;
405 	}
406 	printf("%d/%d processes\n", np, nproc);
407 	printf("   LOC    S    F POIP PRI      SIG  UID SLP TIM  CPU  NI   PGRP    PID   PPID    ADDR   RSS SRSS SIZE    WCHAN    LINK   TEXTP\n");
408 	for (pp=xproc; pp<&xproc[nproc]; pp++) {
409 		if (pp->p_stat==0 && allflg==0)
410 			continue;
411 		printf("%8x", aproc + (pp - xproc));
412 		printf(" %2d", pp->p_stat);
413 		printf(" %4x", pp->p_flag & 0xffff);
414 		printf(" %4d", pp->p_poip);
415 		printf(" %3d", pp->p_pri);
416 		printf(" %8x", pp->p_sig);
417 		printf(" %4d", pp->p_uid);
418 		printf(" %3d", pp->p_slptime);
419 		printf(" %3d", pp->p_time);
420 		printf(" %4d", pp->p_cpu&0377);
421 		printf(" %3d", pp->p_nice);
422 		printf(" %6d", pp->p_pgrp);
423 		printf(" %6d", pp->p_pid);
424 		printf(" %6d", pp->p_ppid);
425 		if (kflg)
426 			pp->p_addr = (struct pte *)clear((int)pp->p_addr);
427 		if (pp->p_flag & SLOAD) {
428 			lseek(fc, (long)pp->p_addr, 0);
429 			read(fc, &apte, sizeof(apte));
430 			printf(" %8x", apte.pg_pfnum);
431 		} else
432 			printf(" %8x", pp->p_swaddr);
433 		printf(" %4x", pp->p_rssize);
434 		printf(" %4x", pp->p_swrss);
435 		printf(" %5x", pp->p_dsize+pp->p_ssize);
436 		printf(" %7x", clear(pp->p_wchan));
437 		printf(" %7x", clear(pp->p_link));
438 		printf(" %7x", clear(pp->p_textp));
439 		printf("\n");
440 	}
441 	free(xproc);
442 }
443 
444 static char mesg[] =
445 " # RAW CAN OUT     MODE     ADDR DEL COL     STATE  PGRP DISC\n";
446 static int ttyspace = 128;
447 static struct tty *tty;
448 
449 dotty()
450 {
451 	extern char *malloc();
452 
453 	if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) {
454 		printf("pstat: out of memory\n");
455 		return;
456 	}
457 	printf("1 cons\n");
458 	if (kflg)
459 		nl[SCONS].n_value = clear(nl[SCONS].n_value);
460 	lseek(fc, (long)nl[SCONS].n_value, 0);
461 	read(fc, tty, sizeof(*tty));
462 	printf(mesg);
463 	ttyprt(&tty[0], 0);
464 #ifdef vax
465 	if (nl[SNQD].n_type != 0)
466 		doqdss();
467 	if (nl[SNDZ].n_type != 0)
468 		dottytype("dz", SDZ, SNDZ);
469 	if (nl[SNDH].n_type != 0)
470 		dottytype("dh", SDH, SNDH);
471 	if (nl[SNDMF].n_type != 0)
472 		dottytype("dmf", SDMF, SNDMF);
473 	if (nl[SNDHU].n_type != 0)
474 		dottytype("dhu", SDHU, SNDHU);
475 	if (nl[SNDMZ].n_type != 0)
476 		dottytype("dmz", SDMZ, SNDMZ);
477 #endif
478 #ifdef tahoe
479 	if (nl[SNVX].n_type != 0)
480 		dottytype("vx", SVX, SNVX);
481 #endif
482 	if (nl[SNPTY].n_type != 0)
483 		dottytype("pty", SPTY, SNPTY);
484 }
485 
486 /*
487  * Special case the qdss because there are 4 tty structs per qdss
488  * and only the first of each is used as a tty.
489  */
490 #ifdef vax
491 doqdss()
492 {
493 	int nqd;
494 	register struct tty *tp;
495 
496 	if (kflg) {
497 		nl[SNQD].n_value = clear(nl[SNQD].n_value);
498 		nl[SQD].n_value = clear(nl[SQD].n_value);
499 	}
500 	lseek(fc, (long)nl[SNQD].n_value, 0);
501 	read(fc, &nqd, sizeof(nqd));
502 	printf("%d qd\n", nqd);
503 	lseek(fc, (long)nl[SQD].n_value, 0);
504 	read(fc, tty, nqd * sizeof(struct tty) * 4);
505 	printf(mesg);
506 	for (tp = tty; tp < &tty[nqd * 4]; tp += 4)
507 		ttyprt(tp, tp - tty);
508 }
509 #endif
510 
511 dottytype(name, type, number)
512 char *name;
513 {
514 	int ntty;
515 	register struct tty *tp;
516 	extern char *realloc();
517 
518 	if (tty == (struct tty *)0)
519 		return;
520 	if (kflg) {
521 		nl[number].n_value = clear(nl[number].n_value);
522 		nl[type].n_value = clear(nl[type].n_value);
523 	}
524 	lseek(fc, (long)nl[number].n_value, 0);
525 	read(fc, &ntty, sizeof(ntty));
526 	printf("%d %s lines\n", ntty, name);
527 	if (ntty > ttyspace) {
528 		ttyspace = ntty;
529 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
530 			printf("pstat: out of memory\n");
531 			return;
532 		}
533 	}
534 	lseek(fc, (long)nl[type].n_value, 0);
535 	read(fc, tty, ntty * sizeof(struct tty));
536 	printf(mesg);
537 	for (tp = tty; tp < &tty[ntty]; tp++)
538 		ttyprt(tp, tp - tty);
539 }
540 
541 ttyprt(atp, line)
542 struct tty *atp;
543 {
544 	register struct tty *tp;
545 
546 	printf("%2d", line);
547 	tp = atp;
548 	switch (tp->t_line) {
549 
550 #ifdef notdef
551 	case NETLDISC:
552 		if (tp->t_rec)
553 			printf("%4d%4d", 0, tp->t_inbuf);
554 		else
555 			printf("%4d%4d", tp->t_inbuf, 0);
556 		break;
557 #endif
558 
559 	default:
560 		printf("%4d%4d", tp->t_rawq.c_cc, tp->t_canq.c_cc);
561 	}
562 	printf("%4d %8x %8x%4d%4d", tp->t_outq.c_cc, tp->t_flags,
563 		tp->t_addr, tp->t_delct, tp->t_col);
564 	putf(tp->t_state&TS_TIMEOUT, 'T');
565 	putf(tp->t_state&TS_WOPEN, 'W');
566 	putf(tp->t_state&TS_ISOPEN, 'O');
567 	putf(tp->t_state&TS_FLUSH, 'F');
568 	putf(tp->t_state&TS_CARR_ON, 'C');
569 	putf(tp->t_state&TS_BUSY, 'B');
570 	putf(tp->t_state&TS_ASLEEP, 'A');
571 	putf(tp->t_state&TS_XCLUDE, 'X');
572 	putf(tp->t_state&TS_TTSTOP, 'S');
573 	putf(tp->t_state&TS_HUPCLS, 'H');
574 	printf("%6d", tp->t_pgrp);
575 	switch (tp->t_line) {
576 
577 	case OTTYDISC:
578 		printf("\n");
579 		break;
580 
581 	case NTTYDISC:
582 		printf(" ntty\n");
583 		break;
584 
585 	case NETLDISC:
586 		printf(" berknet\n");
587 		break;
588 
589 	case TABLDISC:
590 		printf(" tab\n");
591 		break;
592 
593 	case SLIPDISC:
594 		printf(" slip\n");
595 		break;
596 
597 	default:
598 		printf(" %d\n", tp->t_line);
599 	}
600 }
601 
602 dousr()
603 {
604 	struct user U;
605 	register i, j, *ip;
606 	register struct nameidata *nd = &U.u_nd;
607 
608 	/* This wins only if CLBYTES >= sizeof (struct user) */
609 	lseek(fm, ubase * NBPG, 0);
610 	read(fm, &U, sizeof(U));
611 	printf("pcb");
612 	ip = (int *)&U.u_pcb;
613 	while (ip < &U.u_arg[0]) {
614 		if ((ip - (int *)&U.u_pcb) % 4 == 0)
615 			printf("\t");
616 		printf("%x ", *ip++);
617 		if ((ip - (int *)&U.u_pcb) % 4 == 0)
618 			printf("\n");
619 	}
620 	if ((ip - (int *)&U.u_pcb) % 4 != 0)
621 		printf("\n");
622 	printf("arg");
623 	for (i=0; i<sizeof(U.u_arg)/sizeof(U.u_arg[0]); i++) {
624 		if (i%5==0)
625 			printf("\t");
626 		printf(" %.1x", U.u_arg[i]);
627 		if (i%5==4)
628 			printf("\n");
629 	}
630 	if (i%5)
631 		printf("\n");
632 	printf("segflg\t%d\nerror %d\n", nd->ni_segflg, U.u_error);
633 	printf("uids\t%d,%d,%d,%d\n", U.u_uid,U.u_gid,U.u_ruid,U.u_rgid);
634 	printf("procp\t%.1x\n", U.u_procp);
635 	printf("ap\t%.1x\n", U.u_ap);
636 	printf("r_val?\t%.1x %.1x\n", U.u_r.r_val1, U.u_r.r_val2);
637 	printf("base, count, offset %.1x %.1x %ld\n", nd->ni_base,
638 		nd->ni_count, nd->ni_offset);
639 	printf("cdir rdir %.1x %.1x\n", U.u_cdir, U.u_rdir);
640 	printf("dirp %.1x\n", nd->ni_dirp);
641 	printf("dent %d %.14s\n", nd->ni_dent.d_ino, nd->ni_dent.d_name);
642 	printf("pdir %.1o\n", nd->ni_pdir);
643 	printf("file");
644 	for (i=0; i<NOFILE; i++) {
645 		if (i % 8 == 0)
646 			printf("\t");
647 		printf("%9.1x", U.u_ofile[i]);
648 		if (i % 8 == 7)
649 			printf("\n");
650 	}
651 	if (i % 8)
652 		printf("\n");
653 	printf("pofile");
654 	for (i=0; i<NOFILE; i++) {
655 		if (i % 8 == 0)
656 			printf("\t");
657 		printf("%9.1x", U.u_pofile[i]);
658 		if (i % 8 == 7)
659 			printf("\n");
660 	}
661 	if (i % 8)
662 		printf("\n");
663 	printf("ssave");
664 	for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
665 		if (i%5==0)
666 			printf("\t");
667 		printf("%9.1x", U.u_ssave.val[i]);
668 		if (i%5==4)
669 			printf("\n");
670 	}
671 	if (i%5)
672 		printf("\n");
673 	printf("sigs");
674 	for (i=0; i<NSIG; i++) {
675 		if (i % 8 == 0)
676 			printf("\t");
677 		printf("%.1x ", U.u_signal[i]);
678 		if (i % 8 == 7)
679 			printf("\n");
680 	}
681 	if (i % 8)
682 		printf("\n");
683 	printf("code\t%.1x\n", U.u_code);
684 	printf("ar0\t%.1x\n", U.u_ar0);
685 	printf("prof\t%x %x %x %x\n", U.u_prof.pr_base, U.u_prof.pr_size,
686 	    U.u_prof.pr_off, U.u_prof.pr_scale);
687 	printf("\neosys\t%d\n", U.u_eosys);
688 	printf("ttyp\t%.1x\n", U.u_ttyp);
689 	printf("ttyd\t%d,%d\n", major(U.u_ttyd), minor(U.u_ttyd));
690 	printf("comm %.14s\n", U.u_comm);
691 	printf("start\t%ld\n", U.u_start.tv_sec);
692 	printf("acflag\t%ld\n", U.u_acflag);
693 	printf("cmask\t%ld\n", U.u_cmask);
694 	printf("sizes\t%.1x %.1x %.1x\n", U.u_tsize, U.u_dsize, U.u_ssize);
695 	printf("ru\t");
696 	ip = (int *)&U.u_ru;
697 	for (i = 0; i < sizeof(U.u_ru)/sizeof(int); i++)
698 		printf("%ld ", ip[i]);
699 	printf("\n");
700 	ip = (int *)&U.u_cru;
701 	printf("cru\t");
702 	for (i = 0; i < sizeof(U.u_cru)/sizeof(int); i++)
703 		printf("%ld ", ip[i]);
704 	printf("\n");
705 #ifdef notdef
706 	i =  U.u_stack - &U;
707 	while (U[++i] == 0);
708 	i &= ~07;
709 	while (i < 512) {
710 		printf("%x ", 0140000+2*i);
711 		for (j=0; j<8; j++)
712 			printf("%9x", U[i++]);
713 		printf("\n");
714 	}
715 #endif
716 }
717 
718 oatoi(s)
719 char *s;
720 {
721 	register v;
722 
723 	v = 0;
724 	while (*s)
725 		v = (v<<3) + *s++ - '0';
726 	return(v);
727 }
728 
729 dofile()
730 {
731 	int nfile;
732 	struct file *xfile, *afile;
733 	register struct file *fp;
734 	register nf;
735 	int loc;
736 	static char *dtypes[] = { "???", "inode", "socket" };
737 
738 	nf = 0;
739 	nfile = getword(nl[SNFILE].n_value);
740 	xfile = (struct file *)calloc(nfile, sizeof (struct file));
741 	afile = (struct file *)getword(nl[SFIL].n_value);
742 	if (nfile < 0 || nfile > 10000) {
743 		fprintf(stderr, "number of files is preposterous (%d)\n",
744 			nfile);
745 		return;
746 	}
747 	if (xfile == NULL) {
748 		fprintf(stderr, "can't allocate memory for file table\n");
749 		return;
750 	}
751 	lseek(fc, mkphys((off_t)afile), 0);
752 	read(fc, xfile, nfile * sizeof (struct file));
753 	for (fp=xfile; fp < &xfile[nfile]; fp++)
754 		if (fp->f_count)
755 			nf++;
756 	if (totflg) {
757 		printf("%3d/%3d files\n", nf, nfile);
758 		return;
759 	}
760 	printf("%d/%d open files\n", nf, nfile);
761 	printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
762 	for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) {
763 		if (fp->f_count==0)
764 			continue;
765 		printf("%8x ", loc);
766 		if (fp->f_type <= DTYPE_SOCKET)
767 			printf("%-8.8s", dtypes[fp->f_type]);
768 		else
769 			printf("%8d", fp->f_type);
770 		putf(fp->f_flag&FREAD, 'R');
771 		putf(fp->f_flag&FWRITE, 'W');
772 		putf(fp->f_flag&FAPPEND, 'A');
773 		putf(fp->f_flag&FSHLOCK, 'S');
774 		putf(fp->f_flag&FEXLOCK, 'X');
775 		putf(fp->f_flag&FASYNC, 'I');
776 		printf("  %3d", mask(fp->f_count));
777 		printf("  %3d", mask(fp->f_msgcount));
778 		printf("  %8.1x", fp->f_data);
779 		if (fp->f_offset < 0)
780 			printf("  %x\n", fp->f_offset);
781 		else
782 			printf("  %ld\n", fp->f_offset);
783 	}
784 	free(xfile);
785 }
786 
787 int dmmin, dmmax, nswdev;
788 
789 doswap()
790 {
791 	struct proc *proc;
792 	int nproc;
793 	struct text *xtext;
794 	int ntext;
795 	struct map *swapmap;
796 	int nswapmap;
797 	struct swdevt *swdevt, *sw;
798 	register struct proc *pp;
799 	int nswap, used, tused, free, waste;
800 	int db, sb;
801 	register struct mapent *me;
802 	register struct text *xp;
803 	int i, j;
804 	long rmalloc();
805 
806 	nproc = getword(nl[SNPROC].n_value);
807 	ntext = getword(nl[SNTEXT].n_value);
808 	if (nproc < 0 || nproc > 10000 || ntext < 0 || ntext > 10000) {
809 		fprintf(stderr, "number of procs/texts is preposterous (%d, %d)\n",
810 			nproc, ntext);
811 		return;
812 	}
813 	proc = (struct proc *)calloc(nproc, sizeof (struct proc));
814 	if (proc == NULL) {
815 		fprintf(stderr, "can't allocate memory for proc table\n");
816 		exit(1);
817 	}
818 	xtext = (struct text *)calloc(ntext, sizeof (struct text));
819 	if (xtext == NULL) {
820 		fprintf(stderr, "can't allocate memory for text table\n");
821 		exit(1);
822 	}
823 	nswapmap = getword(nl[SNSWAPMAP].n_value);
824 	swapmap = (struct map *)calloc(nswapmap, sizeof (struct map));
825 	if (swapmap == NULL) {
826 		fprintf(stderr, "can't allocate memory for swapmap\n");
827 		exit(1);
828 	}
829 	nswdev = getword(nl[SNSWDEV].n_value);
830 	swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt));
831 	if (swdevt == NULL) {
832 		fprintf(stderr, "can't allocate memory for swdevt table\n");
833 		exit(1);
834 	}
835 	lseek(fc, mkphys((off_t)nl[SSWDEVT].n_value), L_SET);
836 	read(fc, swdevt, nswdev * sizeof (struct swdevt));
837 	lseek(fc, mkphys((off_t)getword(nl[SPROC].n_value)), 0);
838 	read(fc, proc, nproc * sizeof (struct proc));
839 	lseek(fc, mkphys((off_t)getword(nl[STEXT].n_value)), 0);
840 	read(fc, xtext, ntext * sizeof (struct text));
841 	lseek(fc, mkphys((off_t)getword(nl[SWAPMAP].n_value)), 0);
842 	read(fc, swapmap, nswapmap * sizeof (struct map));
843 	swapmap->m_name = "swap";
844 	swapmap->m_limit = (struct mapent *)&swapmap[nswapmap];
845 	dmmin = getword(nl[SDMMIN].n_value);
846 	dmmax = getword(nl[SDMMAX].n_value);
847 	nswap = 0;
848 	for (sw = swdevt; sw < &swdevt[nswdev]; sw++)
849 		if (sw->sw_freed)
850 			nswap += sw->sw_nblks;
851 	free = 0;
852 	for (me = (struct mapent *)(swapmap+1);
853 	    me < (struct mapent *)&swapmap[nswapmap]; me++)
854 		free += me->m_size;
855 	tused = 0;
856 	for (xp = xtext; xp < &xtext[ntext]; xp++)
857 		if (xp->x_iptr!=NULL) {
858 			tused += ctod(clrnd(xp->x_size));
859 			if (xp->x_flag & XPAGI)
860 				tused += ctod(clrnd(ctopt(xp->x_size)));
861 		}
862 	used = tused;
863 	waste = 0;
864 	for (pp = proc; pp < &proc[nproc]; pp++) {
865 		if (pp->p_stat == 0 || pp->p_stat == SZOMB)
866 			continue;
867 		if (pp->p_flag & SSYS)
868 			continue;
869 		db = ctod(pp->p_dsize), sb = up(db);
870 		used += sb;
871 		waste += sb - db;
872 		db = ctod(pp->p_ssize), sb = up(db);
873 		used += sb;
874 		waste += sb - db;
875 		if ((pp->p_flag&SLOAD) == 0)
876 			used += ctod(vusize(pp));
877 	}
878 	if (totflg) {
879 #define	btok(x)	((x) / (1024 / DEV_BSIZE))
880 		printf("%3d/%3d 00k swap\n",
881 		    btok(used/100), btok((used+free)/100));
882 		return;
883 	}
884 	printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n",
885 	    btok(used), btok(tused), btok(free), btok(waste),
886 /* a dmmax/2 block goes to argmap */
887 	    btok(nswap - dmmax/2 - (used + free)));
888 	printf("avail: ");
889 	for (i = dmmax; i >= dmmin; i /= 2) {
890 		j = 0;
891 		while (rmalloc(swapmap, i) != 0)
892 			j++;
893 		if (j) printf("%d*%dk ", j, btok(i));
894 	}
895 	free = 0;
896 	for (me = (struct mapent *)(swapmap+1);
897 	    me < (struct mapent *)&swapmap[nswapmap]; me++)
898 		free += me->m_size;
899 	printf("%d*1k\n", btok(free));
900 }
901 
902 up(size)
903 	register int size;
904 {
905 	register int i, block;
906 
907 	i = 0;
908 	block = dmmin;
909 	while (i < size) {
910 		i += block;
911 		if (block < dmmax)
912 			block *= 2;
913 	}
914 	return (i);
915 }
916 
917 /*
918  * Compute number of pages to be allocated to the u. area
919  * and data and stack area page tables, which are stored on the
920  * disk immediately after the u. area.
921  */
922 vusize(p)
923 	register struct proc *p;
924 {
925 	register int tsz = p->p_tsize / NPTEPG;
926 
927 	/*
928 	 * We do not need page table space on the disk for page
929 	 * table pages wholly containing text.
930 	 */
931 	return (clrnd(UPAGES +
932 	    clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz));
933 }
934 
935 /*
936  * Allocate 'size' units from the given
937  * map. Return the base of the allocated space.
938  * In a map, the addresses are increasing and the
939  * list is terminated by a 0 size.
940  *
941  * Algorithm is first-fit.
942  *
943  * This routine knows about the interleaving of the swapmap
944  * and handles that.
945  */
946 long
947 rmalloc(mp, size)
948 	register struct map *mp;
949 	long size;
950 {
951 	register struct mapent *ep = (struct mapent *)(mp+1);
952 	register int addr;
953 	register struct mapent *bp;
954 	swblk_t first, rest;
955 
956 	if (size <= 0 || size > dmmax)
957 		return (0);
958 	/*
959 	 * Search for a piece of the resource map which has enough
960 	 * free space to accomodate the request.
961 	 */
962 	for (bp = ep; bp->m_size; bp++) {
963 		if (bp->m_size >= size) {
964 			/*
965 			 * If allocating from swapmap,
966 			 * then have to respect interleaving
967 			 * boundaries.
968 			 */
969 			if (nswdev > 1 &&
970 			    (first = dmmax - bp->m_addr%dmmax) < bp->m_size) {
971 				if (bp->m_size - first < size)
972 					continue;
973 				addr = bp->m_addr + first;
974 				rest = bp->m_size - first - size;
975 				bp->m_size = first;
976 				if (rest)
977 					rmfree(mp, rest, addr+size);
978 				return (addr);
979 			}
980 			/*
981 			 * Allocate from the map.
982 			 * If there is no space left of the piece
983 			 * we allocated from, move the rest of
984 			 * the pieces to the left.
985 			 */
986 			addr = bp->m_addr;
987 			bp->m_addr += size;
988 			if ((bp->m_size -= size) == 0) {
989 				do {
990 					bp++;
991 					(bp-1)->m_addr = bp->m_addr;
992 				} while ((bp-1)->m_size = bp->m_size);
993 			}
994 			if (addr % CLSIZE)
995 				return (0);
996 			return (addr);
997 		}
998 	}
999 	return (0);
1000 }
1001 
1002 /*
1003  * Free the previously allocated space at addr
1004  * of size units into the specified map.
1005  * Sort addr into map and combine on
1006  * one or both ends if possible.
1007  */
1008 rmfree(mp, size, addr)
1009 	struct map *mp;
1010 	long size, addr;
1011 {
1012 	struct mapent *firstbp;
1013 	register struct mapent *bp;
1014 	register int t;
1015 
1016 	/*
1017 	 * Both address and size must be
1018 	 * positive, or the protocol has broken down.
1019 	 */
1020 	if (addr <= 0 || size <= 0)
1021 		goto badrmfree;
1022 	/*
1023 	 * Locate the piece of the map which starts after the
1024 	 * returned space (or the end of the map).
1025 	 */
1026 	firstbp = bp = (struct mapent *)(mp + 1);
1027 	for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
1028 		continue;
1029 	/*
1030 	 * If the piece on the left abuts us,
1031 	 * then we should combine with it.
1032 	 */
1033 	if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
1034 		/*
1035 		 * Check no overlap (internal error).
1036 		 */
1037 		if ((bp-1)->m_addr+(bp-1)->m_size > addr)
1038 			goto badrmfree;
1039 		/*
1040 		 * Add into piece on the left by increasing its size.
1041 		 */
1042 		(bp-1)->m_size += size;
1043 		/*
1044 		 * If the combined piece abuts the piece on
1045 		 * the right now, compress it in also,
1046 		 * by shifting the remaining pieces of the map over.
1047 		 */
1048 		if (bp->m_addr && addr+size >= bp->m_addr) {
1049 			if (addr+size > bp->m_addr)
1050 				goto badrmfree;
1051 			(bp-1)->m_size += bp->m_size;
1052 			while (bp->m_size) {
1053 				bp++;
1054 				(bp-1)->m_addr = bp->m_addr;
1055 				(bp-1)->m_size = bp->m_size;
1056 			}
1057 		}
1058 		goto done;
1059 	}
1060 	/*
1061 	 * Don't abut on the left, check for abutting on
1062 	 * the right.
1063 	 */
1064 	if (addr+size >= bp->m_addr && bp->m_size) {
1065 		if (addr+size > bp->m_addr)
1066 			goto badrmfree;
1067 		bp->m_addr -= size;
1068 		bp->m_size += size;
1069 		goto done;
1070 	}
1071 	/*
1072 	 * Don't abut at all.  Make a new entry
1073 	 * and check for map overflow.
1074 	 */
1075 	do {
1076 		t = bp->m_addr;
1077 		bp->m_addr = addr;
1078 		addr = t;
1079 		t = bp->m_size;
1080 		bp->m_size = size;
1081 		bp++;
1082 	} while (size = t);
1083 	/*
1084 	 * Segment at bp is to be the delimiter;
1085 	 * If there is not room for it
1086 	 * then the table is too full
1087 	 * and we must discard something.
1088 	 */
1089 	if (bp+1 > mp->m_limit) {
1090 		/*
1091 		 * Back bp up to last available segment.
1092 		 * which contains a segment already and must
1093 		 * be made into the delimiter.
1094 		 * Discard second to last entry,
1095 		 * since it is presumably smaller than the last
1096 		 * and move the last entry back one.
1097 		 */
1098 		bp--;
1099 		printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
1100 		    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
1101 		bp[-1] = bp[0];
1102 		bp[0].m_size = bp[0].m_addr = 0;
1103 	}
1104 done:
1105 	return;
1106 badrmfree:
1107 	printf("bad rmfree\n");
1108 }
1109 /*
1110  * "addr"  is a kern virt addr and does not correspond
1111  * To a phys addr after zipping out the high bit..
1112  * since it was valloc'd in the kernel.
1113  *
1114  * We return the phys addr by simulating kernel vm (/dev/kmem)
1115  * when we are reading a crash dump.
1116  */
1117 off_t
1118 mkphys(addr)
1119 	off_t addr;
1120 {
1121 	register off_t o;
1122 
1123 	if (!kflg)
1124 		return(addr);
1125 	addr = clear(addr);
1126 	o = addr & PGOFSET;
1127 	addr >>= PGSHIFT;
1128 	addr &= PG_PFNUM;
1129 	addr *=  NBPW;
1130 	addr = getword(nl[SYSMAP].n_value + addr);
1131 	addr = ((addr & PG_PFNUM) << PGSHIFT) | o;
1132 	return(addr);
1133 }
1134