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