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