xref: /netbsd/usr.sbin/kgmon/kgmon.c (revision 595db245)
1*595db245Sdyoung /*	$NetBSD: kgmon.c,v 1.20 2006/08/13 00:20:25 dyoung Exp $	*/
2d71f6e87Smrg 
336adb5cbScgd /*
47bb1d933Spk  * Copyright (c) 1983, 1992, 1993
57bb1d933Spk  *	The Regents of the University of California.  All rights reserved.
636adb5cbScgd  *
736adb5cbScgd  * Redistribution and use in source and binary forms, with or without
836adb5cbScgd  * modification, are permitted provided that the following conditions
936adb5cbScgd  * are met:
1036adb5cbScgd  * 1. Redistributions of source code must retain the above copyright
1136adb5cbScgd  *    notice, this list of conditions and the following disclaimer.
1236adb5cbScgd  * 2. Redistributions in binary form must reproduce the above copyright
1336adb5cbScgd  *    notice, this list of conditions and the following disclaimer in the
1436adb5cbScgd  *    documentation and/or other materials provided with the distribution.
15326b2259Sagc  * 3. Neither the name of the University nor the names of its contributors
1636adb5cbScgd  *    may be used to endorse or promote products derived from this software
1736adb5cbScgd  *    without specific prior written permission.
1836adb5cbScgd  *
1936adb5cbScgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2036adb5cbScgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2136adb5cbScgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2236adb5cbScgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2336adb5cbScgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2436adb5cbScgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2536adb5cbScgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2636adb5cbScgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2736adb5cbScgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2836adb5cbScgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2936adb5cbScgd  * SUCH DAMAGE.
3036adb5cbScgd  */
3136adb5cbScgd 
32d71f6e87Smrg #include <sys/cdefs.h>
3336adb5cbScgd #ifndef lint
34d71f6e87Smrg __COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\n\
35d71f6e87Smrg 	The Regents of the University of California.  All rights reserved.\n");
3636adb5cbScgd #endif /* not lint */
3736adb5cbScgd 
3836adb5cbScgd #ifndef lint
39d71f6e87Smrg #if 0
40d71f6e87Smrg static char sccsid[] = "from: @(#)kgmon.c	8.1 (Berkeley) 6/6/93";
41d71f6e87Smrg #else
42*595db245Sdyoung __RCSID("$NetBSD: kgmon.c,v 1.20 2006/08/13 00:20:25 dyoung Exp $");
43d71f6e87Smrg #endif
4436adb5cbScgd #endif /* not lint */
4536adb5cbScgd 
4636adb5cbScgd #include <sys/param.h>
4736adb5cbScgd #include <sys/file.h>
487bb1d933Spk #include <sys/sysctl.h>
497bb1d933Spk #include <sys/gmon.h>
50d71f6e87Smrg 
51d71f6e87Smrg #include <ctype.h>
527bb1d933Spk #include <errno.h>
537bb1d933Spk #include <kvm.h>
54aa0a3ef5Schristos #include <err.h>
557bb1d933Spk #include <limits.h>
56d71f6e87Smrg #include <nlist.h>
5736adb5cbScgd #include <stdio.h>
587bb1d933Spk #include <stdlib.h>
597bb1d933Spk #include <string.h>
60d71f6e87Smrg #include <unistd.h>
6136adb5cbScgd 
62aa0a3ef5Schristos static struct nlist nl[] = {
637bb1d933Spk #define	N_GMONPARAM	0
647bb1d933Spk 	{ "__gmonparam" },
657bb1d933Spk #define	N_PROFHZ	1
667bb1d933Spk 	{ "_profhz" },
67d71f6e87Smrg 	{ 0, }
6836adb5cbScgd };
6936adb5cbScgd 
707bb1d933Spk struct kvmvars {
717bb1d933Spk 	kvm_t	*kd;
727bb1d933Spk 	struct gmonparam gpm;
737bb1d933Spk };
7436adb5cbScgd 
75aa0a3ef5Schristos static int	bflag, hflag, kflag, rflag, pflag;
76aa0a3ef5Schristos static int	debug = 0;
77aa0a3ef5Schristos static void	setprof(struct kvmvars *kvp, int state);
78aa0a3ef5Schristos static void	dumpstate(struct kvmvars *kvp);
79aa0a3ef5Schristos static void	reset(struct kvmvars *kvp);
80aa0a3ef5Schristos static int	openfiles(char *, char *, struct kvmvars *);
81aa0a3ef5Schristos static int	getprof(struct kvmvars *);
82aa0a3ef5Schristos static void	kern_readonly(int);
83aa0a3ef5Schristos static int	getprofhz(struct kvmvars *);
8436adb5cbScgd 
857bb1d933Spk int
867bb1d933Spk main(int argc, char **argv)
8736adb5cbScgd {
887bb1d933Spk 	int ch, mode, disp, accessmode;
897bb1d933Spk 	struct kvmvars kvmvars;
907bb1d933Spk 	char *system, *kmemf;
9136adb5cbScgd 
92aa0a3ef5Schristos 	setprogname(argv[0]);
937bb1d933Spk 	seteuid(getuid());
947bb1d933Spk 	kmemf = NULL;
957bb1d933Spk 	system = NULL;
96780f68fdSeeh 	while ((ch = getopt(argc, argv, "M:N:bdhpr")) != -1) {
9736adb5cbScgd 		switch((char)ch) {
987bb1d933Spk 
9936adb5cbScgd 		case 'M':
10036adb5cbScgd 			kmemf = optarg;
10136adb5cbScgd 			kflag = 1;
10236adb5cbScgd 			break;
1037bb1d933Spk 
10436adb5cbScgd 		case 'N':
10536adb5cbScgd 			system = optarg;
10636adb5cbScgd 			break;
1077bb1d933Spk 
10836adb5cbScgd 		case 'b':
10936adb5cbScgd 			bflag = 1;
11036adb5cbScgd 			break;
1117bb1d933Spk 
11236adb5cbScgd 		case 'h':
11336adb5cbScgd 			hflag = 1;
11436adb5cbScgd 			break;
1157bb1d933Spk 
11636adb5cbScgd 		case 'p':
11736adb5cbScgd 			pflag = 1;
11836adb5cbScgd 			break;
1197bb1d933Spk 
12036adb5cbScgd 		case 'r':
12136adb5cbScgd 			rflag = 1;
12236adb5cbScgd 			break;
1237bb1d933Spk 
124780f68fdSeeh 		case 'd':
125780f68fdSeeh 			debug = 1;
126780f68fdSeeh 			break;
127780f68fdSeeh 
12836adb5cbScgd 		default:
12936adb5cbScgd 			(void)fprintf(stderr,
130b1440f78Shira 			    "usage: %s [-bdhrp] [-M core] [-N system]\n",
131b1440f78Shira 			    getprogname());
13236adb5cbScgd 			exit(1);
13336adb5cbScgd 		}
1347bb1d933Spk 	}
13536adb5cbScgd 	argc -= optind;
13636adb5cbScgd 	argv += optind;
13736adb5cbScgd 
13836adb5cbScgd #define BACKWARD_COMPATIBILITY
13936adb5cbScgd #ifdef	BACKWARD_COMPATIBILITY
14036adb5cbScgd 	if (*argv) {
14136adb5cbScgd 		system = *argv;
14236adb5cbScgd 		if (*++argv) {
14336adb5cbScgd 			kmemf = *argv;
14436adb5cbScgd 			++kflag;
14536adb5cbScgd 		}
14636adb5cbScgd 	}
14736adb5cbScgd #endif
1487bb1d933Spk 	accessmode = openfiles(system, kmemf, &kvmvars);
1497bb1d933Spk 	mode = getprof(&kvmvars);
1507bb1d933Spk 	if (hflag)
1517bb1d933Spk 		disp = GMON_PROF_OFF;
1527bb1d933Spk 	else if (bflag)
1537bb1d933Spk 		disp = GMON_PROF_ON;
1547bb1d933Spk 	else
1557bb1d933Spk 		disp = mode;
1567bb1d933Spk 	if (pflag)
1577bb1d933Spk 		dumpstate(&kvmvars);
1587bb1d933Spk 	if (rflag)
1597bb1d933Spk 		reset(&kvmvars);
1607bb1d933Spk 	if (accessmode == O_RDWR)
1617bb1d933Spk 		setprof(&kvmvars, disp);
162aa0a3ef5Schristos 	(void)fprintf(stdout, "%s: kernel profiling is %s.\n",
163aa0a3ef5Schristos 	     getprogname(), disp == GMON_PROF_OFF ? "off" : "running");
1647bb1d933Spk 	return (0);
1657bb1d933Spk }
16636adb5cbScgd 
1677bb1d933Spk /*
1687bb1d933Spk  * Check that profiling is enabled and open any ncessary files.
1697bb1d933Spk  */
170aa0a3ef5Schristos static int
1711ef7bd2aSperry openfiles(char *system, char *kmemf, struct kvmvars *kvp)
1727bb1d933Spk {
173191b5f2eScgd 	int mib[3], state, openmode;
174191b5f2eScgd 	size_t size;
1757bb1d933Spk 	char errbuf[_POSIX2_LINE_MAX];
1767bb1d933Spk 
1777bb1d933Spk 	if (!kflag) {
1787bb1d933Spk 		mib[0] = CTL_KERN;
1797bb1d933Spk 		mib[1] = KERN_PROF;
1807bb1d933Spk 		mib[2] = GPROF_STATE;
1817bb1d933Spk 		size = sizeof state;
182aa0a3ef5Schristos 		if (sysctl(mib, 3, &state, &size, NULL, 0) < 0)
183*595db245Sdyoung 			err(EXIT_FAILURE, "profiling not defined in kernel");
1847bb1d933Spk 		if (!(bflag || hflag || rflag ||
1857bb1d933Spk 		    (pflag && state == GMON_PROF_ON)))
1867bb1d933Spk 			return (O_RDONLY);
1877bb1d933Spk 		(void)seteuid(0);
1887bb1d933Spk 		if (sysctl(mib, 3, NULL, NULL, &state, size) >= 0)
1897bb1d933Spk 			return (O_RDWR);
1907bb1d933Spk 		(void)seteuid(getuid());
1917bb1d933Spk 		kern_readonly(state);
1927bb1d933Spk 		return (O_RDONLY);
1937bb1d933Spk 	}
1947bb1d933Spk 	openmode = (bflag || hflag || pflag || rflag) ? O_RDWR : O_RDONLY;
1957bb1d933Spk 	kvp->kd = kvm_openfiles(system, kmemf, NULL, openmode, errbuf);
1967bb1d933Spk 	if (kvp->kd == NULL) {
1977bb1d933Spk 		if (openmode == O_RDWR) {
1987bb1d933Spk 			openmode = O_RDONLY;
1997bb1d933Spk 			kvp->kd = kvm_openfiles(system, kmemf, NULL, O_RDONLY,
2007bb1d933Spk 			    errbuf);
2017bb1d933Spk 		}
202aa0a3ef5Schristos 		if (kvp->kd == NULL)
203*595db245Sdyoung 			errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
2047bb1d933Spk 		kern_readonly(GMON_PROF_ON);
20536adb5cbScgd 	}
206aa0a3ef5Schristos 	if (kvm_nlist(kvp->kd, nl) < 0)
207*595db245Sdyoung 		errx(EXIT_FAILURE, "%s: no namelist", system);
208aa0a3ef5Schristos 	if (!nl[N_GMONPARAM].n_value)
209*595db245Sdyoung 		errx(EXIT_FAILURE, "profiling not defined in kernel");
2107bb1d933Spk 	return (openmode);
2117bb1d933Spk }
2127bb1d933Spk 
2137bb1d933Spk /*
2147bb1d933Spk  * Suppress options that require a writable kernel.
2157bb1d933Spk  */
216aa0a3ef5Schristos static void
2171ef7bd2aSperry kern_readonly(int mode)
2187bb1d933Spk {
2197bb1d933Spk 
220aa0a3ef5Schristos 	(void)fprintf(stderr, "%s: kernel read-only: ", getprogname());
2217bb1d933Spk 	if (pflag && mode == GMON_PROF_ON)
2227bb1d933Spk 		(void)fprintf(stderr, "data may be inconsistent\n");
22336adb5cbScgd 	if (rflag)
22436adb5cbScgd 		(void)fprintf(stderr, "-r supressed\n");
22536adb5cbScgd 	if (bflag)
22636adb5cbScgd 		(void)fprintf(stderr, "-b supressed\n");
22736adb5cbScgd 	if (hflag)
22836adb5cbScgd 		(void)fprintf(stderr, "-h supressed\n");
22936adb5cbScgd 	rflag = bflag = hflag = 0;
23036adb5cbScgd }
231e9d867efSmycroft 
2327bb1d933Spk /*
2337bb1d933Spk  * Get the state of kernel profiling.
2347bb1d933Spk  */
235aa0a3ef5Schristos static int
2361ef7bd2aSperry getprof(struct kvmvars *kvp)
237c78c6a22Smrg {
238191b5f2eScgd 	int mib[3];
239191b5f2eScgd 	size_t size;
2407bb1d933Spk 
2417bb1d933Spk 	if (kflag) {
2427bb1d933Spk 		size = kvm_read(kvp->kd, nl[N_GMONPARAM].n_value, &kvp->gpm,
2437bb1d933Spk 		    sizeof kvp->gpm);
2447bb1d933Spk 	} else {
2457bb1d933Spk 		mib[0] = CTL_KERN;
2467bb1d933Spk 		mib[1] = KERN_PROF;
2477bb1d933Spk 		mib[2] = GPROF_GMONPARAM;
2487bb1d933Spk 		size = sizeof kvp->gpm;
2497bb1d933Spk 		if (sysctl(mib, 3, &kvp->gpm, &size, NULL, 0) < 0)
2507bb1d933Spk 			size = 0;
2517bb1d933Spk 	}
252aa0a3ef5Schristos 	if (size != sizeof kvp->gpm)
253*595db245Sdyoung 		errx(EXIT_FAILURE, "cannot get gmonparam: %s",
2547bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
2557bb1d933Spk 	return (kvp->gpm.state);
2567bb1d933Spk }
2577bb1d933Spk 
2587bb1d933Spk /*
2597bb1d933Spk  * Enable or disable kernel profiling according to the state variable.
2607bb1d933Spk  */
261aa0a3ef5Schristos static void
2621ef7bd2aSperry setprof(struct kvmvars *kvp, int state)
2637bb1d933Spk {
2647bb1d933Spk 	struct gmonparam *p = (struct gmonparam *)nl[N_GMONPARAM].n_value;
265191b5f2eScgd 	int mib[3], oldstate;
266191b5f2eScgd 	size_t sz;
2677bb1d933Spk 
2687bb1d933Spk 	sz = sizeof(state);
2697bb1d933Spk 	if (!kflag) {
2707bb1d933Spk 		mib[0] = CTL_KERN;
2717bb1d933Spk 		mib[1] = KERN_PROF;
2727bb1d933Spk 		mib[2] = GPROF_STATE;
2737bb1d933Spk 		if (sysctl(mib, 3, &oldstate, &sz, NULL, 0) < 0)
2747bb1d933Spk 			goto bad;
2757bb1d933Spk 		if (oldstate == state)
2767bb1d933Spk 			return;
2777bb1d933Spk 		(void)seteuid(0);
2787bb1d933Spk 		if (sysctl(mib, 3, NULL, NULL, &state, sz) >= 0) {
2797bb1d933Spk 			(void)seteuid(getuid());
2807bb1d933Spk 			return;
2817bb1d933Spk 		}
2827bb1d933Spk 		(void)seteuid(getuid());
2837bb1d933Spk 	} else if (kvm_write(kvp->kd, (u_long)&p->state, (void *)&state, sz)
2847bb1d933Spk 	    == sz)
2857bb1d933Spk 		return;
2867bb1d933Spk bad:
287aa0a3ef5Schristos 	warnx("cannot turn profiling %s", state == GMON_PROF_OFF ?
288aa0a3ef5Schristos 	    "off" : "on");
2897bb1d933Spk }
2907bb1d933Spk 
2917bb1d933Spk /*
2927bb1d933Spk  * Build the gmon.out file.
2937bb1d933Spk  */
294aa0a3ef5Schristos static void
2951ef7bd2aSperry dumpstate(struct kvmvars *kvp)
2967bb1d933Spk {
2971ef7bd2aSperry 	FILE *fp;
29836adb5cbScgd 	struct rawarc rawarc;
29936adb5cbScgd 	struct tostruct *tos;
300d71f6e87Smrg 	u_long frompc;
3017bb1d933Spk 	u_short *froms, *tickbuf;
302191b5f2eScgd 	int mib[3];
303191b5f2eScgd 	size_t i;
3047bb1d933Spk 	struct gmonhdr h;
3057bb1d933Spk 	int fromindex, endfrom, toindex;
30636adb5cbScgd 
3077bb1d933Spk 	setprof(kvp, GMON_PROF_OFF);
3087bb1d933Spk 	fp = fopen("gmon.out", "w");
309*595db245Sdyoung 	if (fp == NULL) {
310aa0a3ef5Schristos 		warn("cannot open `gmon.out'");
31136adb5cbScgd 		return;
31236adb5cbScgd 	}
3137bb1d933Spk 
3147bb1d933Spk 	/*
3157bb1d933Spk 	 * Build the gmon header and write it to a file.
3167bb1d933Spk 	 */
3177bb1d933Spk 	bzero(&h, sizeof(h));
3187bb1d933Spk 	h.lpc = kvp->gpm.lowpc;
3197bb1d933Spk 	h.hpc = kvp->gpm.highpc;
3207bb1d933Spk 	h.ncnt = kvp->gpm.kcountsize + sizeof(h);
3217bb1d933Spk 	h.version = GMONVERSION;
3227bb1d933Spk 	h.profrate = getprofhz(kvp);
3234329d94fSdyoung 	if (fwrite((char *)&h, sizeof(h), 1, fp) != 1)
3244329d94fSdyoung 		err(EXIT_FAILURE, "writing header to gmon.out");
3257bb1d933Spk 
3267bb1d933Spk 	/*
3277bb1d933Spk 	 * Write out the tick buffer.
3287bb1d933Spk 	 */
3297bb1d933Spk 	mib[0] = CTL_KERN;
3307bb1d933Spk 	mib[1] = KERN_PROF;
331aa0a3ef5Schristos 	if ((tickbuf = malloc(kvp->gpm.kcountsize)) == NULL)
332*595db245Sdyoung 		err(EXIT_FAILURE, "cannot allocate kcount space");
3337bb1d933Spk 	if (kflag) {
3347bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, (void *)tickbuf,
3357bb1d933Spk 		    kvp->gpm.kcountsize);
3367bb1d933Spk 	} else {
3377bb1d933Spk 		mib[2] = GPROF_COUNT;
3387bb1d933Spk 		i = kvp->gpm.kcountsize;
3397bb1d933Spk 		if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0)
3407bb1d933Spk 			i = 0;
3417bb1d933Spk 	}
342aa0a3ef5Schristos 	if (i != kvp->gpm.kcountsize)
343*595db245Sdyoung 		errx(EXIT_FAILURE, "read ticks: read %lu, got %lu: %s",
3447ffe3c61Senami 		    kvp->gpm.kcountsize, (u_long)i,
3457bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
346aa0a3ef5Schristos 	if ((fwrite(tickbuf, kvp->gpm.kcountsize, 1, fp)) != 1)
347*595db245Sdyoung 		err(EXIT_FAILURE, "writing tocks to gmon.out");
3487bb1d933Spk 	free(tickbuf);
3497bb1d933Spk 
3507bb1d933Spk 	/*
3517bb1d933Spk 	 * Write out the arc info.
3527bb1d933Spk 	 */
353aa0a3ef5Schristos 	if ((froms = malloc(kvp->gpm.fromssize)) == NULL)
354*595db245Sdyoung 		err(EXIT_FAILURE, "cannot allocate froms space");
3557bb1d933Spk 	if (kflag) {
3567bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, (void *)froms,
3577bb1d933Spk 		    kvp->gpm.fromssize);
3587bb1d933Spk 	} else {
3597bb1d933Spk 		mib[2] = GPROF_FROMS;
3607bb1d933Spk 		i = kvp->gpm.fromssize;
3617bb1d933Spk 		if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
3627bb1d933Spk 			i = 0;
3637bb1d933Spk 	}
364aa0a3ef5Schristos 	if (i != kvp->gpm.fromssize)
365*595db245Sdyoung 		errx(EXIT_FAILURE, "read froms: read %lu, got %lu: %s",
3667ffe3c61Senami 		    kvp->gpm.fromssize, (u_long)i,
3677bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
368aa0a3ef5Schristos 	if ((tos = malloc(kvp->gpm.tossize)) == NULL)
369*595db245Sdyoung 		err(EXIT_FAILURE, "cannot allocate tos space");
3707bb1d933Spk 	if (kflag) {
3717bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
3727bb1d933Spk 		    kvp->gpm.tossize);
3737bb1d933Spk 	} else {
3747bb1d933Spk 		mib[2] = GPROF_TOS;
3757bb1d933Spk 		i = kvp->gpm.tossize;
3767bb1d933Spk 		if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
3777bb1d933Spk 			i = 0;
3787bb1d933Spk 	}
379aa0a3ef5Schristos 	if (i != kvp->gpm.tossize)
380*595db245Sdyoung 		errx(EXIT_FAILURE, "read tos: read %lu, got %lu: %s",
3817ffe3c61Senami 		    kvp->gpm.tossize, (u_long)i,
3827bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
38336adb5cbScgd 	if (debug)
384aa0a3ef5Schristos 		(void)fprintf(stderr, "%s: lowpc 0x%lx, textsize 0x%lx\n",
385aa0a3ef5Schristos 		     getprogname(), kvp->gpm.lowpc, kvp->gpm.textsize);
3867bb1d933Spk 	endfrom = kvp->gpm.fromssize / sizeof(*froms);
3877bb1d933Spk 	for (fromindex = 0; fromindex < endfrom; ++fromindex) {
38836adb5cbScgd 		if (froms[fromindex] == 0)
38936adb5cbScgd 			continue;
3907bb1d933Spk 		frompc = (u_long)kvp->gpm.lowpc +
3917bb1d933Spk 		    (fromindex * kvp->gpm.hashfraction * sizeof(*froms));
39236adb5cbScgd 		for (toindex = froms[fromindex]; toindex != 0;
39336adb5cbScgd 		   toindex = tos[toindex].link) {
39436adb5cbScgd 			if (debug)
39536adb5cbScgd 			    (void)fprintf(stderr,
396d71f6e87Smrg 			    "%s: [mcleanup] frompc 0x%lx selfpc 0x%lx count %ld\n",
397aa0a3ef5Schristos 			    getprogname(), frompc, tos[toindex].selfpc,
3987bb1d933Spk 			    tos[toindex].count);
39936adb5cbScgd 			rawarc.raw_frompc = frompc;
40036adb5cbScgd 			rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
40136adb5cbScgd 			rawarc.raw_count = tos[toindex].count;
4024329d94fSdyoung 			if (fwrite((char *)&rawarc, sizeof(rawarc), 1,fp) != 1){
4034329d94fSdyoung 				err(EXIT_FAILURE,
4044329d94fSdyoung 				    "writing raw arc to gmon.out");
4054329d94fSdyoung 			}
40636adb5cbScgd 		}
40736adb5cbScgd 	}
4082a8477a7Schristos 	free(tos);
4097bb1d933Spk 	fclose(fp);
41036adb5cbScgd }
41136adb5cbScgd 
4127bb1d933Spk /*
4137bb1d933Spk  * Get the profiling rate.
4147bb1d933Spk  */
415aa0a3ef5Schristos static int
4161ef7bd2aSperry getprofhz(struct kvmvars *kvp)
41736adb5cbScgd {
418191b5f2eScgd 	int mib[2], profrate;
419191b5f2eScgd 	size_t size;
4207bb1d933Spk 	struct clockinfo clockrate;
42136adb5cbScgd 
4227bb1d933Spk 	if (kflag) {
4237bb1d933Spk 		profrate = 1;
4247bb1d933Spk 		if (kvm_read(kvp->kd, nl[N_PROFHZ].n_value, &profrate,
4257bb1d933Spk 		    sizeof profrate) != sizeof profrate)
426aa0a3ef5Schristos 			warnx("get clockrate: %s", kvm_geterr(kvp->kd));
4277bb1d933Spk 		return (profrate);
42836adb5cbScgd 	}
4297bb1d933Spk 	mib[0] = CTL_KERN;
4307bb1d933Spk 	mib[1] = KERN_CLOCKRATE;
4317bb1d933Spk 	clockrate.profhz = 1;
4327bb1d933Spk 	size = sizeof clockrate;
4337bb1d933Spk 	if (sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
434aa0a3ef5Schristos 		warn("get clockrate");
4357bb1d933Spk 	return (clockrate.profhz);
43636adb5cbScgd }
43736adb5cbScgd 
4387bb1d933Spk /*
4397bb1d933Spk  * Reset the kernel profiling date structures.
4407bb1d933Spk  */
441aa0a3ef5Schristos static void
4421ef7bd2aSperry reset(struct kvmvars *kvp)
44336adb5cbScgd {
4447bb1d933Spk 	char *zbuf;
4457bb1d933Spk 	u_long biggest;
4467bb1d933Spk 	int mib[3];
44736adb5cbScgd 
4487bb1d933Spk 	setprof(kvp, GMON_PROF_OFF);
44936adb5cbScgd 
4507bb1d933Spk 	biggest = kvp->gpm.kcountsize;
4517bb1d933Spk 	if (kvp->gpm.fromssize > biggest)
4527bb1d933Spk 		biggest = kvp->gpm.fromssize;
4537bb1d933Spk 	if (kvp->gpm.tossize > biggest)
4547bb1d933Spk 		biggest = kvp->gpm.tossize;
455aa0a3ef5Schristos 	if ((zbuf = malloc(biggest)) == NULL)
456*595db245Sdyoung 		err(EXIT_FAILURE, "cannot allocate zbuf space");
4577bb1d933Spk 	bzero(zbuf, biggest);
4587bb1d933Spk 	if (kflag) {
4597bb1d933Spk 		if (kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
460aa0a3ef5Schristos 		    kvp->gpm.kcountsize) != kvp->gpm.kcountsize)
461*595db245Sdyoung 			errx(EXIT_FAILURE, "tickbuf zero: %s",
462*595db245Sdyoung 			     kvm_geterr(kvp->kd));
4637bb1d933Spk 		if (kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
464aa0a3ef5Schristos 		    kvp->gpm.fromssize) != kvp->gpm.fromssize)
465*595db245Sdyoung 			errx(EXIT_FAILURE, "froms zero: %s",
466*595db245Sdyoung 			     kvm_geterr(kvp->kd));
4677bb1d933Spk 		if (kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
468aa0a3ef5Schristos 		    kvp->gpm.tossize) != kvp->gpm.tossize)
469*595db245Sdyoung 			errx(EXIT_FAILURE, "tos zero: %s", kvm_geterr(kvp->kd));
470aa0a3ef5Schristos 		free(zbuf);
4717bb1d933Spk 		return;
4727bb1d933Spk 	}
4737bb1d933Spk 	(void)seteuid(0);
4747bb1d933Spk 	mib[0] = CTL_KERN;
4757bb1d933Spk 	mib[1] = KERN_PROF;
4767bb1d933Spk 	mib[2] = GPROF_COUNT;
477aa0a3ef5Schristos 	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.kcountsize) < 0)
478*595db245Sdyoung 		err(EXIT_FAILURE, "tickbuf zero");
4797bb1d933Spk 	mib[2] = GPROF_FROMS;
480aa0a3ef5Schristos 	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.fromssize) < 0)
481*595db245Sdyoung 		err(EXIT_FAILURE, "froms zero");
4827bb1d933Spk 	mib[2] = GPROF_TOS;
483aa0a3ef5Schristos 	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.tossize) < 0)
484*595db245Sdyoung 		err(EXIT_FAILURE, "tos zero");
4857bb1d933Spk 	(void)seteuid(getuid());
4867bb1d933Spk 	free(zbuf);
48736adb5cbScgd }
488