Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1983 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef lint | |
35 | char copyright[] = | |
36 | "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ | |
37 | All rights reserved.\n"; | |
38 | #endif /* not lint */ | |
39 | ||
40 | #ifndef lint | |
41 | static char sccsid[] = "@(#)kgmon.c 5.12 (Berkeley) 7/1/91"; | |
42 | #endif /* not lint */ | |
43 | ||
44 | #include <sys/param.h> | |
45 | #if BSD >= 199103 | |
46 | #define NEWVM | |
47 | #endif | |
48 | #include <sys/file.h> | |
49 | #ifndef NEWVM | |
50 | #include <machine/pte.h> | |
51 | #include <sys/vm.h> | |
52 | #endif | |
53 | #include <sys/gprof.h> | |
54 | #include <stdio.h> | |
55 | #include <nlist.h> | |
56 | #include <ctype.h> | |
57 | #include <paths.h> | |
58 | ||
59 | #define PROFILING_ON 0 | |
60 | #define PROFILING_OFF 3 | |
61 | ||
62 | u_long s_textsize; | |
63 | off_t sbuf, klseek(), lseek(); | |
64 | int ssiz; | |
65 | ||
66 | struct nlist nl[] = { | |
67 | #define N_SYSMAP 0 | |
68 | { "_Sysmap" }, | |
69 | #define N_SYSSIZE 1 | |
70 | { "_Syssize" }, | |
71 | #define N_FROMS 2 | |
72 | { "_froms" }, | |
73 | #define N_PROFILING 3 | |
74 | { "_profiling" }, | |
75 | #define N_S_LOWPC 4 | |
76 | { "_s_lowpc" }, | |
77 | #define N_S_TEXTSIZE 5 | |
78 | { "_s_textsize" }, | |
79 | #define N_SBUF 6 | |
80 | { "_sbuf" }, | |
81 | #define N_SSIZ 7 | |
82 | { "_ssiz" }, | |
83 | #define N_TOS 8 | |
84 | { "_tos" }, | |
85 | 0, | |
86 | }; | |
87 | ||
88 | struct pte *Sysmap; | |
89 | ||
90 | int kmem; | |
91 | int bflag, hflag, kflag, rflag, pflag; | |
92 | int debug = 0; | |
93 | ||
94 | main(argc, argv) | |
95 | int argc; | |
96 | char **argv; | |
97 | { | |
98 | extern char *optarg; | |
99 | extern int optind; | |
100 | int ch, mode, disp, openmode; | |
101 | char *system, *kmemf, *malloc(); | |
102 | ||
103 | kmemf = _PATH_KMEM; | |
104 | system = _PATH_UNIX; | |
105 | while ((ch = getopt(argc, argv, "M:N:bhpr")) != EOF) | |
106 | switch((char)ch) { | |
107 | case 'M': | |
108 | kmemf = optarg; | |
109 | kflag = 1; | |
110 | break; | |
111 | case 'N': | |
112 | system = optarg; | |
113 | break; | |
114 | case 'b': | |
115 | bflag = 1; | |
116 | break; | |
117 | case 'h': | |
118 | hflag = 1; | |
119 | break; | |
120 | case 'p': | |
121 | pflag = 1; | |
122 | break; | |
123 | case 'r': | |
124 | rflag = 1; | |
125 | break; | |
126 | default: | |
127 | (void)fprintf(stderr, | |
128 | "usage: kgmon [-bhrp] [-M core] [-N system]\n"); | |
129 | exit(1); | |
130 | } | |
131 | argc -= optind; | |
132 | argv += optind; | |
133 | ||
134 | #define BACKWARD_COMPATIBILITY | |
135 | #ifdef BACKWARD_COMPATIBILITY | |
136 | if (*argv) { | |
137 | system = *argv; | |
138 | if (*++argv) { | |
139 | kmemf = *argv; | |
140 | ++kflag; | |
141 | } | |
142 | } | |
143 | #endif | |
144 | ||
145 | if (nlist(system, nl) < 0 || nl[0].n_type == 0) { | |
146 | (void)fprintf(stderr, "kgmon: %s: no namelist\n", system); | |
147 | exit(2); | |
148 | } | |
149 | if (!nl[N_PROFILING].n_value) { | |
150 | (void)fprintf(stderr, | |
151 | "kgmon: profiling: not defined in kernel.\n"); | |
152 | exit(10); | |
153 | } | |
154 | ||
155 | openmode = (bflag || hflag || pflag || rflag) ? O_RDWR : O_RDONLY; | |
156 | kmem = open(kmemf, openmode); | |
157 | if (kmem < 0) { | |
158 | openmode = O_RDONLY; | |
159 | kmem = open(kmemf, openmode); | |
160 | if (kmem < 0) { | |
161 | perror(kmemf); | |
162 | exit(3); | |
163 | } | |
164 | (void)fprintf(stderr, "%s opened read-only\n", kmemf); | |
165 | if (rflag) | |
166 | (void)fprintf(stderr, "-r supressed\n"); | |
167 | if (bflag) | |
168 | (void)fprintf(stderr, "-b supressed\n"); | |
169 | if (hflag) | |
170 | (void)fprintf(stderr, "-h supressed\n"); | |
171 | rflag = bflag = hflag = 0; | |
172 | } | |
173 | if (kflag) { | |
174 | #ifdef NEWVM | |
175 | (void)fprintf(stderr, | |
176 | "kgmon: can't do core files yet\n"); | |
177 | exit(1); | |
178 | #else | |
179 | off_t off; | |
180 | ||
181 | Sysmap = (struct pte *) | |
182 | malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); | |
183 | if (!Sysmap) { | |
184 | (void)fprintf(stderr, | |
185 | "kgmon: can't get memory for Sysmap.\n"); | |
186 | exit(1); | |
187 | } | |
188 | off = nl[N_SYSMAP].n_value & ~KERNBASE; | |
189 | (void)lseek(kmem, off, L_SET); | |
190 | (void)read(kmem, (char *)Sysmap, | |
191 | (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); | |
192 | #endif | |
193 | } | |
194 | mode = kfetch(N_PROFILING); | |
195 | if (hflag) | |
196 | disp = PROFILING_OFF; | |
197 | else if (bflag) | |
198 | disp = PROFILING_ON; | |
199 | else | |
200 | disp = mode; | |
201 | if (pflag) { | |
202 | if (openmode == O_RDONLY && mode == PROFILING_ON) | |
203 | (void)fprintf(stderr, "data may be inconsistent\n"); | |
204 | dumpstate(); | |
205 | } | |
206 | if (rflag) | |
207 | resetstate(); | |
208 | turnonoff(disp); | |
209 | (void)fprintf(stdout, | |
210 | "kernel profiling is %s.\n", disp ? "off" : "running"); | |
211 | exit(0); | |
212 | } | |
213 | ||
214 | dumpstate() | |
215 | { | |
216 | extern int errno; | |
217 | struct rawarc rawarc; | |
218 | struct tostruct *tos; | |
219 | u_long frompc; | |
220 | off_t kfroms, ktos; | |
221 | u_short *froms; /* froms is a bunch of u_shorts indexing tos */ | |
222 | int i, fd, fromindex, endfrom, fromssize, tossize, toindex; | |
223 | char buf[BUFSIZ], *s_lowpc, *malloc(), *strerror(); | |
224 | ||
225 | turnonoff(PROFILING_OFF); | |
226 | fd = creat("gmon.out", 0666); | |
227 | if (fd < 0) { | |
228 | perror("gmon.out"); | |
229 | return; | |
230 | } | |
231 | ssiz = kfetch(N_SSIZ); | |
232 | sbuf = kfetch(N_SBUF); | |
233 | (void)klseek(kmem, (off_t)sbuf, L_SET); | |
234 | for (i = ssiz; i > 0; i -= BUFSIZ) { | |
235 | read(kmem, buf, i < BUFSIZ ? i : BUFSIZ); | |
236 | write(fd, buf, i < BUFSIZ ? i : BUFSIZ); | |
237 | } | |
238 | s_textsize = kfetch(N_S_TEXTSIZE); | |
239 | fromssize = s_textsize / HASHFRACTION; | |
240 | froms = (u_short *)malloc((u_int)fromssize); | |
241 | kfroms = kfetch(N_FROMS); | |
242 | (void)klseek(kmem, kfroms, L_SET); | |
243 | i = read(kmem, ((char *)(froms)), fromssize); | |
244 | if (i != fromssize) { | |
245 | (void)fprintf(stderr, "read kmem: request %d, got %d: %s", | |
246 | fromssize, i, strerror(errno)); | |
247 | exit(5); | |
248 | } | |
249 | tossize = (s_textsize * ARCDENSITY / 100) * sizeof(struct tostruct); | |
250 | tos = (struct tostruct *)malloc((u_int)tossize); | |
251 | ktos = kfetch(N_TOS); | |
252 | (void)klseek(kmem, ktos, L_SET); | |
253 | i = read(kmem, ((char *)(tos)), tossize); | |
254 | if (i != tossize) { | |
255 | (void)fprintf(stderr, "read kmem: request %d, got %d: %s", | |
256 | tossize, i, strerror(errno)); | |
257 | exit(6); | |
258 | } | |
259 | s_lowpc = (char *)kfetch(N_S_LOWPC); | |
260 | if (debug) | |
261 | (void)fprintf(stderr, "s_lowpc 0x%x, s_textsize 0x%x\n", | |
262 | s_lowpc, s_textsize); | |
263 | endfrom = fromssize / sizeof(*froms); | |
264 | for (fromindex = 0; fromindex < endfrom; fromindex++) { | |
265 | if (froms[fromindex] == 0) | |
266 | continue; | |
267 | frompc = (u_long)s_lowpc + | |
268 | (fromindex * HASHFRACTION * sizeof(*froms)); | |
269 | for (toindex = froms[fromindex]; toindex != 0; | |
270 | toindex = tos[toindex].link) { | |
271 | if (debug) | |
272 | (void)fprintf(stderr, | |
273 | "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , | |
274 | frompc, tos[toindex].selfpc, tos[toindex].count); | |
275 | rawarc.raw_frompc = frompc; | |
276 | rawarc.raw_selfpc = (u_long)tos[toindex].selfpc; | |
277 | rawarc.raw_count = tos[toindex].count; | |
278 | write(fd, (char *)&rawarc, sizeof (rawarc)); | |
279 | } | |
280 | } | |
281 | close(fd); | |
282 | } | |
283 | ||
284 | resetstate() | |
285 | { | |
286 | off_t kfroms, ktos; | |
287 | int i, fromssize, tossize; | |
288 | char buf[BUFSIZ]; | |
289 | ||
290 | turnonoff(PROFILING_OFF); | |
291 | bzero(buf, BUFSIZ); | |
292 | ssiz = kfetch(N_SSIZ); | |
293 | sbuf = kfetch(N_SBUF); | |
294 | ssiz -= sizeof(struct phdr); | |
295 | sbuf += sizeof(struct phdr); | |
296 | (void)klseek(kmem, (off_t)sbuf, L_SET); | |
297 | for (i = ssiz; i > 0; i -= BUFSIZ) | |
298 | if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) { | |
299 | perror("sbuf write"); | |
300 | exit(7); | |
301 | } | |
302 | s_textsize = kfetch(N_S_TEXTSIZE); | |
303 | fromssize = s_textsize / HASHFRACTION; | |
304 | kfroms = kfetch(N_FROMS); | |
305 | (void)klseek(kmem, kfroms, L_SET); | |
306 | for (i = fromssize; i > 0; i -= BUFSIZ) | |
307 | if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) { | |
308 | perror("kforms write"); | |
309 | exit(8); | |
310 | } | |
311 | tossize = (s_textsize * ARCDENSITY / 100) * sizeof(struct tostruct); | |
312 | ktos = kfetch(N_TOS); | |
313 | (void)klseek(kmem, ktos, L_SET); | |
314 | for (i = tossize; i > 0; i -= BUFSIZ) | |
315 | if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) { | |
316 | perror("ktos write"); | |
317 | exit(9); | |
318 | } | |
319 | } | |
320 | ||
321 | turnonoff(onoff) | |
322 | int onoff; | |
323 | { | |
324 | (void)klseek(kmem, (long)nl[N_PROFILING].n_value, L_SET); | |
325 | (void)write(kmem, (char *)&onoff, sizeof (onoff)); | |
326 | } | |
327 | ||
328 | kfetch(index) | |
329 | int index; | |
330 | { | |
331 | off_t off; | |
332 | int value; | |
333 | ||
334 | if ((off = nl[index].n_value) == 0) { | |
335 | printf("%s: not defined in kernel\n", nl[index].n_name); | |
336 | exit(11); | |
337 | } | |
338 | if (klseek(kmem, off, L_SET) == -1) { | |
339 | perror("lseek"); | |
340 | exit(12); | |
341 | } | |
342 | if (read(kmem, (char *)&value, sizeof (value)) != sizeof (value)) { | |
343 | perror("read"); | |
344 | exit(13); | |
345 | } | |
346 | return (value); | |
347 | } | |
348 | ||
349 | off_t | |
350 | klseek(fd, base, off) | |
351 | int fd, off; | |
352 | off_t base; | |
353 | { | |
354 | ||
355 | #ifndef NEWVM | |
356 | if (kflag) { /* get kernel pte */ | |
357 | base &= ~KERNBASE; | |
358 | base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); | |
359 | } | |
360 | #endif | |
361 | return (lseek(fd, base, off)); | |
362 | } |