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