xref: /original-bsd/usr.sbin/kgmon/kgmon.c (revision fb9118b1)
1 /*
2  * Copyright (c) 1983 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) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)kgmon.c	5.3 (Berkeley) 10/13/86";
15 #endif not lint
16 
17 #include <sys/param.h>
18 #include <machine/pte.h>
19 #include <sys/file.h>
20 #include <sys/vm.h>
21 #include <stdio.h>
22 #include <nlist.h>
23 #include <ctype.h>
24 #include <sys/gprof.h>
25 
26 #define	PROFILING_ON	0
27 #define PROFILING_OFF	3
28 
29 /*
30  * froms is actually a bunch of unsigned shorts indexing tos
31  */
32 u_short	*froms;
33 struct	tostruct *tos;
34 char	*s_lowpc;
35 u_long	s_textsize;
36 int	ssiz;
37 off_t	sbuf;
38 
39 struct nlist nl[] = {
40 #define	N_SYSMAP	0
41 	{ "_Sysmap" },
42 #define	N_SYSSIZE	1
43 	{ "_Syssize" },
44 #define N_FROMS		2
45 	{ "_froms" },
46 #define	N_PROFILING	3
47 	{ "_profiling" },
48 #define	N_S_LOWPC	4
49 	{ "_s_lowpc" },
50 #define	N_S_TEXTSIZE	5
51 	{ "_s_textsize" },
52 #define	N_SBUF		6
53 	{ "_sbuf" },
54 #define N_SSIZ		7
55 	{ "_ssiz" },
56 #define	N_TOS		8
57 	{ "_tos" },
58 	0,
59 };
60 
61 #if defined(vax)
62 #define	clear(x)	((x) &~ 0x80000000)
63 #endif
64 #if defined(tahoe)
65 #define	clear(x)	((x) &~ 0xc0000000)
66 #endif
67 
68 struct	pte *Sysmap;
69 
70 char	*system = "/vmunix";
71 char	*kmemf = "/dev/kmem";
72 int	kmem;
73 int	bflag, hflag, kflag, rflag, pflag;
74 int	debug = 0;
75 
76 main(argc, argv)
77 	int argc;
78 	char *argv[];
79 {
80 	int mode, disp, openmode = O_RDONLY;
81 
82 	argc--, argv++;
83 	while (argc > 0 && argv[0][0] == '-') {
84 		switch (argv[0][1]) {
85 		case 'b':
86 			bflag++;
87 			openmode = O_RDWR;
88 			break;
89 		case 'h':
90 			hflag++;
91 			openmode = O_RDWR;
92 			break;
93 		case 'r':
94 			rflag++;
95 			openmode = O_RDWR;
96 			break;
97 		case 'p':
98 			pflag++;
99 			openmode = O_RDWR;
100 			break;
101 		default:
102 			printf("Usage: kgmon [ -b -h -r -p system memory ]\n");
103 			exit(1);
104 		}
105 		argc--, argv++;
106 	}
107 	if (argc > 0) {
108 		system = *argv;
109 		argv++, argc--;
110 	}
111 	nlist(system, nl);
112 	if (nl[0].n_type == 0) {
113 		fprintf(stderr, "%s: no namelist\n", system);
114 		exit(2);
115 	}
116 	if (argc > 0) {
117 		kmemf = *argv;
118 		kflag++;
119 	}
120 	kmem = open(kmemf, openmode);
121 	if (kmem < 0) {
122 		openmode = O_RDONLY;
123 		kmem = open(kmemf, openmode);
124 		if (kmem < 0) {
125 			fprintf(stderr, "cannot open ");
126 			perror(kmemf);
127 			exit(3);
128 		}
129 		fprintf(stderr, "%s opened read-only\n", kmemf);
130 		if (rflag)
131 			fprintf(stderr, "-r supressed\n");
132 		if (bflag)
133 			fprintf(stderr, "-b supressed\n");
134 		if (hflag)
135 			fprintf(stderr, "-h supressed\n");
136 		rflag = 0;
137 		bflag = 0;
138 		hflag = 0;
139 	}
140 	if (kflag) {
141 		off_t off;
142 
143 		off = clear(nl[N_SYSMAP].n_value);
144 		lseek(kmem, off, L_SET);
145 		nl[N_SYSSIZE].n_value *= 4;
146 		Sysmap = (struct pte *)malloc(nl[N_SYSSIZE].n_value);
147 		if (Sysmap == 0) {
148 			perror("Sysmap");
149 			exit(4);
150 		}
151 		read(kmem, Sysmap, nl[N_SYSSIZE].n_value);
152 	}
153 	mode = kfetch(N_PROFILING);
154 	if (hflag)
155 		disp = PROFILING_OFF;
156 	else if (bflag)
157 		disp = PROFILING_ON;
158 	else
159 		disp = mode;
160 	if (pflag) {
161 		if (openmode == O_RDONLY && mode == PROFILING_ON)
162 			fprintf(stderr, "data may be inconsistent\n");
163 		dumpstate();
164 	}
165 	if (rflag)
166 		resetstate();
167 	turnonoff(disp);
168 	fprintf(stdout, "kernel profiling is %s.\n", disp ? "off" : "running");
169 }
170 
171 dumpstate()
172 {
173 	int i;
174 	int fd;
175 	off_t kfroms, ktos;
176 	int fromindex, endfrom, fromssize, tossize;
177 	u_long frompc;
178 	int toindex;
179 	struct rawarc rawarc;
180 	char buf[BUFSIZ];
181 
182 	turnonoff(PROFILING_OFF);
183 	fd = creat("gmon.out", 0666);
184 	if (fd < 0) {
185 		perror("gmon.out");
186 		return;
187 	}
188 	ssiz = kfetch(N_SSIZ);
189 	sbuf = kfetch(N_SBUF);
190 	klseek(kmem, (off_t)sbuf, L_SET);
191 	for (i = ssiz; i > 0; i -= BUFSIZ) {
192 		read(kmem, buf, i < BUFSIZ ? i : BUFSIZ);
193 		write(fd, buf, i < BUFSIZ ? i : BUFSIZ);
194 	}
195 	s_textsize = kfetch(N_S_TEXTSIZE);
196 	fromssize = s_textsize / HASHFRACTION;
197 	froms = (u_short *)malloc(fromssize);
198 	kfroms = kfetch(N_FROMS);
199 	klseek(kmem, kfroms, L_SET);
200 	i = read(kmem, ((char *)(froms)), fromssize);
201 	if (i != fromssize) {
202 		fprintf(stderr, "read froms: request %d, got %d", fromssize, i);
203 		perror("");
204 		exit(5);
205 	}
206 	tossize = (s_textsize * ARCDENSITY / 100) * sizeof(struct tostruct);
207 	tos = (struct tostruct *)malloc(tossize);
208 	ktos = kfetch(N_TOS);
209 	klseek(kmem, ktos, L_SET);
210 	i = read(kmem, ((char *)(tos)), tossize);
211 	if (i != tossize) {
212 		fprintf(stderr, "read tos: request %d, got %d", tossize, i);
213 		perror("");
214 		exit(6);
215 	}
216 	s_lowpc = (char *)kfetch(N_S_LOWPC);
217 	if (debug)
218 		fprintf(stderr, "s_lowpc 0x%x, s_textsize 0x%x\n",
219 		    s_lowpc, s_textsize);
220 	endfrom = fromssize / sizeof(*froms);
221 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
222 		if (froms[fromindex] == 0)
223 			continue;
224 		frompc = (u_long)s_lowpc +
225 		    (fromindex * HASHFRACTION * sizeof(*froms));
226 		for (toindex = froms[fromindex]; toindex != 0;
227 		   toindex = tos[toindex].link) {
228 			if (debug)
229 			    fprintf(stderr,
230 			    "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
231 			    frompc, tos[toindex].selfpc, tos[toindex].count);
232 			rawarc.raw_frompc = frompc;
233 			rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
234 			rawarc.raw_count = tos[toindex].count;
235 			write(fd, &rawarc, sizeof (rawarc));
236 		}
237 	}
238 	close(fd);
239 }
240 
241 resetstate()
242 {
243 	int i;
244 	off_t kfroms, ktos;
245 	int fromssize, tossize;
246 	char buf[BUFSIZ];
247 
248 	turnonoff(PROFILING_OFF);
249 	bzero(buf, BUFSIZ);
250 	ssiz = kfetch(N_SSIZ);
251 	sbuf = kfetch(N_SBUF);
252 	ssiz -= sizeof(struct phdr);
253 	sbuf += sizeof(struct phdr);
254 	klseek(kmem, (off_t)sbuf, L_SET);
255 	for (i = ssiz; i > 0; i -= BUFSIZ)
256 		if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) {
257 			perror("sbuf write");
258 			exit(7);
259 		}
260 	s_textsize = kfetch(N_S_TEXTSIZE);
261 	fromssize = s_textsize / HASHFRACTION;
262 	kfroms = kfetch(N_FROMS);
263 	klseek(kmem, kfroms, L_SET);
264 	for (i = fromssize; i > 0; i -= BUFSIZ)
265 		if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) {
266 			perror("kforms write");
267 			exit(8);
268 		}
269 	tossize = (s_textsize * ARCDENSITY / 100) * sizeof(struct tostruct);
270 	ktos = kfetch(N_TOS);
271 	klseek(kmem, ktos, L_SET);
272 	for (i = tossize; i > 0; i -= BUFSIZ)
273 		if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) {
274 			perror("ktos write");
275 			exit(9);
276 		}
277 }
278 
279 turnonoff(onoff)
280 	int onoff;
281 {
282 	off_t off;
283 
284 	if ((off = nl[N_PROFILING].n_value) == 0) {
285 		printf("profiling: not defined in kernel\n");
286 		exit(10);
287 	}
288 	klseek(kmem, off, L_SET);
289 	write(kmem, (char *)&onoff, sizeof (onoff));
290 }
291 
292 kfetch(index)
293 	int index;
294 {
295 	off_t off;
296 	int value;
297 
298 	if ((off = nl[index].n_value) == 0) {
299 		printf("%s: not defined in kernel\n", nl[index].n_name);
300 		exit(11);
301 	}
302 	if (klseek(kmem, off, L_SET) == -1) {
303 		perror("lseek");
304 		exit(12);
305 	}
306 	if (read(kmem, (char *)&value, sizeof (value)) != sizeof (value)) {
307 		perror("read");
308 		exit(13);
309 	}
310 	return (value);
311 }
312 
313 klseek(fd, base, off)
314 	int fd, base, off;
315 {
316 
317 	if (kflag) {
318 		/* get kernel pte */
319 		base = clear(base);
320 		base = ((int)ptob(Sysmap[btop(base)].pg_pfnum))+(base&(NBPG-1));
321 	}
322 	return (lseek(fd, base, off));
323 }
324