1 /* $NetBSD: kgmon.c,v 1.23 2008/07/21 13:36:58 lukem Exp $ */
4 * Copyright (c) 1983, 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "from: @(#)kgmon.c 8.1 (Berkeley) 6/6/93";
42 __RCSID("$NetBSD: kgmon.c,v 1.23 2008/07/21 13:36:58 lukem Exp $");
46 #include <sys/param.h>
48 #include <sys/sysctl.h>
62 static struct nlist nl
[] = {
64 { "__gmonparam", 0, 0, 0, 0 },
66 { "_profhz", 0, 0, 0, 0 },
75 static int bflag
, hflag
, kflag
, rflag
, pflag
;
77 static void setprof(struct kvmvars
*kvp
, int state
);
78 static void dumpstate(struct kvmvars
*kvp
);
79 static void reset(struct kvmvars
*kvp
);
80 static int openfiles(char *, char *, struct kvmvars
*);
81 static int getprof(struct kvmvars
*);
82 static void kern_readonly(int);
83 static int getprofhz(struct kvmvars
*);
86 main(int argc
, char **argv
)
88 int ch
, mode
, disp
, accessmode
;
89 struct kvmvars kvmvars
;
93 (void)seteuid(getuid());
96 while ((ch
= getopt(argc
, argv
, "M:N:bdhpr")) != -1) {
129 (void)fprintf(stderr
,
130 "usage: %s [-bdhrp] [-M core] [-N system]\n",
138 #define BACKWARD_COMPATIBILITY
139 #ifdef BACKWARD_COMPATIBILITY
148 accessmode
= openfiles(sys
, kmemf
, &kvmvars
);
149 mode
= getprof(&kvmvars
);
151 disp
= GMON_PROF_OFF
;
160 if (accessmode
== O_RDWR
)
161 setprof(&kvmvars
, disp
);
162 (void)fprintf(stdout
, "%s: kernel profiling is %s.\n",
163 getprogname(), disp
== GMON_PROF_OFF
? "off" : "running");
168 * Check that profiling is enabled and open any ncessary files.
171 openfiles(char *sys
, char *kmemf
, struct kvmvars
*kvp
)
173 int mib
[3], state
, openmode
;
175 char errbuf
[_POSIX2_LINE_MAX
];
180 mib
[2] = GPROF_STATE
;
182 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0)
183 err(EXIT_FAILURE
, "profiling not defined in kernel");
184 if (!(bflag
|| hflag
|| rflag
||
185 (pflag
&& state
== GMON_PROF_ON
)))
188 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
190 (void)seteuid(getuid());
191 kern_readonly(state
);
194 openmode
= (bflag
|| hflag
|| pflag
|| rflag
) ? O_RDWR
: O_RDONLY
;
195 kvp
->kd
= kvm_openfiles(sys
, kmemf
, NULL
, openmode
, errbuf
);
196 if (kvp
->kd
== NULL
) {
197 if (openmode
== O_RDWR
) {
199 kvp
->kd
= kvm_openfiles(sys
, kmemf
, NULL
, O_RDONLY
,
203 errx(EXIT_FAILURE
, "kvm_openfiles: %s", errbuf
);
204 kern_readonly(GMON_PROF_ON
);
206 if (kvm_nlist(kvp
->kd
, nl
) < 0)
207 errx(EXIT_FAILURE
, "%s: no namelist", sys
);
208 if (!nl
[N_GMONPARAM
].n_value
)
209 errx(EXIT_FAILURE
, "profiling not defined in kernel");
214 * Suppress options that require a writable kernel.
217 kern_readonly(int mode
)
220 (void)fprintf(stderr
, "%s: kernel read-only: ", getprogname());
221 if (pflag
&& mode
== GMON_PROF_ON
)
222 (void)fprintf(stderr
, "data may be inconsistent\n");
224 (void)fprintf(stderr
, "-r supressed\n");
226 (void)fprintf(stderr
, "-b supressed\n");
228 (void)fprintf(stderr
, "-h supressed\n");
229 rflag
= bflag
= hflag
= 0;
233 * Get the state of kernel profiling.
236 getprof(struct kvmvars
*kvp
)
242 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
247 mib
[2] = GPROF_GMONPARAM
;
248 size
= sizeof kvp
->gpm
;
249 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
252 if (size
!= sizeof kvp
->gpm
)
253 errx(EXIT_FAILURE
, "cannot get gmonparam: %s",
254 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
255 return (kvp
->gpm
.state
);
259 * Enable or disable kernel profiling according to the state variable.
262 setprof(struct kvmvars
*kvp
, int state
)
264 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
265 int mib
[3], oldstate
;
272 mib
[2] = GPROF_STATE
;
273 if (sysctl(mib
, 3, &oldstate
, &sz
, NULL
, 0) < 0)
275 if (oldstate
== state
)
278 if (sysctl(mib
, 3, NULL
, NULL
, &state
, sz
) >= 0) {
279 (void)seteuid(getuid());
282 (void)seteuid(getuid());
283 } else if ((size_t)kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, sz
)
287 warnx("cannot turn profiling %s", state
== GMON_PROF_OFF
?
292 * Build the gmon.out file.
295 dumpstate(struct kvmvars
*kvp
)
298 struct rawarc rawarc
;
299 struct tostruct
*tos
;
301 u_short
*froms
, *tickbuf
;
305 int fromindex
, endfrom
, toindex
;
308 setprof(kvp
, GMON_PROF_OFF
);
309 fp
= fopen("gmon.out", "w");
311 warn("cannot open `gmon.out'");
316 * Build the gmon header and write it to a file.
318 bzero(&h
, sizeof(h
));
319 h
.lpc
= kvp
->gpm
.lowpc
;
320 h
.hpc
= kvp
->gpm
.highpc
;
321 h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
322 h
.version
= GMONVERSION
;
323 h
.profrate
= getprofhz(kvp
);
324 if (fwrite(&h
, sizeof(h
), 1, fp
) != 1)
325 err(EXIT_FAILURE
, "writing header to gmon.out");
327 kcountsize
= (size_t)kvp
->gpm
.kcountsize
;
330 * Write out the tick buffer.
334 if ((tickbuf
= malloc(kcountsize
)) == NULL
)
335 err(EXIT_FAILURE
, "Cannot allocate %zu kcount space",
338 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, tickbuf
,
341 mib
[2] = GPROF_COUNT
;
343 if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
347 errx(EXIT_FAILURE
, "read ticks: read %zu, got %zu: %s",
349 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
350 if ((fwrite(tickbuf
, kcountsize
, 1, fp
)) != 1)
351 err(EXIT_FAILURE
, "writing tocks to gmon.out");
355 * Write out the arc info.
357 if ((froms
= malloc((size_t)kvp
->gpm
.fromssize
)) == NULL
)
358 err(EXIT_FAILURE
, "cannot allocate %zu froms space",
359 (size_t)kvp
->gpm
.fromssize
);
361 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, froms
,
362 (size_t)kvp
->gpm
.fromssize
);
364 mib
[2] = GPROF_FROMS
;
365 i
= kvp
->gpm
.fromssize
;
366 if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
369 if (i
!= kvp
->gpm
.fromssize
)
370 errx(EXIT_FAILURE
, "read froms: read %lu, got %lu: %s",
371 kvp
->gpm
.fromssize
, (u_long
)i
,
372 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
373 if ((tos
= malloc((size_t)kvp
->gpm
.tossize
)) == NULL
)
374 err(EXIT_FAILURE
, "cannot allocate %zu tos space",
375 (size_t)kvp
->gpm
.tossize
);
377 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
378 (size_t)kvp
->gpm
.tossize
);
381 i
= kvp
->gpm
.tossize
;
382 if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
385 if (i
!= kvp
->gpm
.tossize
)
386 errx(EXIT_FAILURE
, "read tos: read %zu, got %zu: %s",
387 (size_t)kvp
->gpm
.tossize
, i
,
388 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
390 (void)fprintf(stderr
, "%s: lowpc 0x%lx, textsize 0x%lx\n",
391 getprogname(), kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
392 endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
393 for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
394 if (froms
[fromindex
] == 0)
396 frompc
= (u_long
)kvp
->gpm
.lowpc
+
397 (fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
398 for (toindex
= froms
[fromindex
]; toindex
!= 0;
399 toindex
= tos
[toindex
].link
) {
401 (void)fprintf(stderr
,
402 "%s: [mcleanup] frompc 0x%lx selfpc 0x%lx count %ld\n",
403 getprogname(), frompc
, tos
[toindex
].selfpc
,
405 rawarc
.raw_frompc
= frompc
;
406 rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
407 rawarc
.raw_count
= tos
[toindex
].count
;
408 if (fwrite(&rawarc
, sizeof(rawarc
), 1,fp
) != 1){
410 "writing raw arc to gmon.out");
419 * Get the profiling rate.
422 getprofhz(struct kvmvars
*kvp
)
424 int mib
[2], profrate
;
426 struct clockinfo clockrate
;
430 if (kvm_read(kvp
->kd
, nl
[N_PROFHZ
].n_value
, &profrate
,
431 sizeof profrate
) != sizeof profrate
)
432 warnx("get clockrate: %s", kvm_geterr(kvp
->kd
));
436 mib
[1] = KERN_CLOCKRATE
;
437 clockrate
.profhz
= 1;
438 size
= sizeof clockrate
;
439 if (sysctl(mib
, 2, &clockrate
, &size
, NULL
, 0) < 0)
440 warn("get clockrate");
441 return (clockrate
.profhz
);
445 * Reset the kernel profiling date structures.
448 reset(struct kvmvars
*kvp
)
454 setprof(kvp
, GMON_PROF_OFF
);
456 biggest
= (size_t)kvp
->gpm
.kcountsize
;
457 if ((size_t)kvp
->gpm
.fromssize
> biggest
)
458 biggest
= (size_t)kvp
->gpm
.fromssize
;
459 if ((size_t)kvp
->gpm
.tossize
> biggest
)
460 biggest
= (size_t)kvp
->gpm
.tossize
;
461 if ((zbuf
= malloc(biggest
)) == NULL
)
462 err(EXIT_FAILURE
, "cannot allocate zbuf space");
463 (void)memset(zbuf
, 0, biggest
);
465 if ((size_t)kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
466 (size_t)kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
)
467 errx(EXIT_FAILURE
, "tickbuf zero: %s",
468 kvm_geterr(kvp
->kd
));
469 if ((size_t)kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
470 (size_t)kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
)
471 errx(EXIT_FAILURE
, "froms zero: %s",
472 kvm_geterr(kvp
->kd
));
473 if ((size_t)kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
474 (size_t)kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
)
475 errx(EXIT_FAILURE
, "tos zero: %s", kvm_geterr(kvp
->kd
));
482 mib
[2] = GPROF_COUNT
;
483 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, (size_t)kvp
->gpm
.kcountsize
) < 0)
484 err(EXIT_FAILURE
, "tickbuf zero");
485 mib
[2] = GPROF_FROMS
;
486 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, (size_t)kvp
->gpm
.fromssize
) < 0)
487 err(EXIT_FAILURE
, "froms zero");
489 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, (size_t)kvp
->gpm
.tossize
) < 0)
490 err(EXIT_FAILURE
, "tos zero");
491 (void)seteuid(getuid());