xref: /netbsd/usr.sbin/kgmon/kgmon.c (revision e55a0464)
1*e55a0464Smsaitoh /*	$NetBSD: kgmon.c,v 1.26 2019/07/11 03:49:52 msaitoh 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
349c194566Slukem __COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\
359c194566Slukem  The Regents of the University of California.  All rights reserved.");
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*e55a0464Smsaitoh __RCSID("$NetBSD: kgmon.c,v 1.26 2019/07/11 03:49:52 msaitoh 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
64aec3ddbeSdogcow 	{ "__gmonparam", 0, 0, 0, 0 },
657bb1d933Spk #define	N_PROFHZ	1
66aec3ddbeSdogcow 	{ "_profhz", 0, 0, 0, 0 },
67aec3ddbeSdogcow 	{ 0, 0, 0, 0, 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;
90a8bdc6a1Schristos 	char *sys, *kmemf;
9136adb5cbScgd 
92aa0a3ef5Schristos 	setprogname(argv[0]);
93a8bdc6a1Schristos 	(void)seteuid(getuid());
947bb1d933Spk 	kmemf = NULL;
95a8bdc6a1Schristos 	sys = 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':
105a8bdc6a1Schristos 			sys = 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) {
141a8bdc6a1Schristos 		sys = *argv;
14236adb5cbScgd 		if (*++argv) {
14336adb5cbScgd 			kmemf = *argv;
14436adb5cbScgd 			++kflag;
14536adb5cbScgd 		}
14636adb5cbScgd 	}
14736adb5cbScgd #endif
148a8bdc6a1Schristos 	accessmode = openfiles(sys, 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
171a8bdc6a1Schristos openfiles(char *sys, 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)
183595db245Sdyoung 			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;
195a8bdc6a1Schristos 	kvp->kd = kvm_openfiles(sys, kmemf, NULL, openmode, errbuf);
1967bb1d933Spk 	if (kvp->kd == NULL) {
1977bb1d933Spk 		if (openmode == O_RDWR) {
1987bb1d933Spk 			openmode = O_RDONLY;
199a8bdc6a1Schristos 			kvp->kd = kvm_openfiles(sys, kmemf, NULL, O_RDONLY,
2007bb1d933Spk 			    errbuf);
2017bb1d933Spk 		}
202aa0a3ef5Schristos 		if (kvp->kd == NULL)
203595db245Sdyoung 			errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
2047bb1d933Spk 		kern_readonly(GMON_PROF_ON);
20536adb5cbScgd 	}
206aa0a3ef5Schristos 	if (kvm_nlist(kvp->kd, nl) < 0)
207a8bdc6a1Schristos 		errx(EXIT_FAILURE, "%s: no namelist", sys);
208aa0a3ef5Schristos 	if (!nl[N_GMONPARAM].n_value)
209595db245Sdyoung 		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)
224*e55a0464Smsaitoh 		(void)fprintf(stderr, "-r suppressed\n");
22536adb5cbScgd 	if (bflag)
226*e55a0464Smsaitoh 		(void)fprintf(stderr, "-b suppressed\n");
22736adb5cbScgd 	if (hflag)
228*e55a0464Smsaitoh 		(void)fprintf(stderr, "-h suppressed\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)
253595db245Sdyoung 		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());
283e7dd2c75Slukem 	} else if ((size_t)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;
306a8bdc6a1Schristos 	size_t kcountsize;
30736adb5cbScgd 
3087bb1d933Spk 	setprof(kvp, GMON_PROF_OFF);
3097bb1d933Spk 	fp = fopen("gmon.out", "w");
310595db245Sdyoung 	if (fp == NULL) {
311aa0a3ef5Schristos 		warn("cannot open `gmon.out'");
31236adb5cbScgd 		return;
31336adb5cbScgd 	}
3147bb1d933Spk 
3157bb1d933Spk 	/*
3167bb1d933Spk 	 * Build the gmon header and write it to a file.
3177bb1d933Spk 	 */
3187bb1d933Spk 	bzero(&h, sizeof(h));
3197bb1d933Spk 	h.lpc = kvp->gpm.lowpc;
3207bb1d933Spk 	h.hpc = kvp->gpm.highpc;
3217bb1d933Spk 	h.ncnt = kvp->gpm.kcountsize + sizeof(h);
3227bb1d933Spk 	h.version = GMONVERSION;
3237bb1d933Spk 	h.profrate = getprofhz(kvp);
324a8bdc6a1Schristos 	if (fwrite(&h, sizeof(h), 1, fp) != 1)
3254329d94fSdyoung 		err(EXIT_FAILURE, "writing header to gmon.out");
3267bb1d933Spk 
327a8bdc6a1Schristos 	kcountsize = (size_t)kvp->gpm.kcountsize;
328a8bdc6a1Schristos 
3297bb1d933Spk 	/*
3307bb1d933Spk 	 * Write out the tick buffer.
3317bb1d933Spk 	 */
3327bb1d933Spk 	mib[0] = CTL_KERN;
3337bb1d933Spk 	mib[1] = KERN_PROF;
334a8bdc6a1Schristos 	if ((tickbuf = malloc(kcountsize)) == NULL)
335a8bdc6a1Schristos 		err(EXIT_FAILURE, "Cannot allocate %zu kcount space",
336a8bdc6a1Schristos 		    kcountsize);
3377bb1d933Spk 	if (kflag) {
338a8bdc6a1Schristos 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, tickbuf,
339a8bdc6a1Schristos 		    kcountsize);
3407bb1d933Spk 	} else {
3417bb1d933Spk 		mib[2] = GPROF_COUNT;
342a8bdc6a1Schristos 		i = kcountsize;
3437bb1d933Spk 		if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0)
3447bb1d933Spk 			i = 0;
3457bb1d933Spk 	}
346a8bdc6a1Schristos 	if (i != kcountsize)
347a8bdc6a1Schristos 		errx(EXIT_FAILURE, "read ticks: read %zu, got %zu: %s",
348a8bdc6a1Schristos 		    kcountsize, i,
3497bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
350a8bdc6a1Schristos 	if ((fwrite(tickbuf, kcountsize, 1, fp)) != 1)
3515b001910Suebayasi 		err(EXIT_FAILURE, "writing ticks to gmon.out");
3527bb1d933Spk 	free(tickbuf);
3537bb1d933Spk 
3547bb1d933Spk 	/*
3557bb1d933Spk 	 * Write out the arc info.
3567bb1d933Spk 	 */
357a8bdc6a1Schristos 	if ((froms = malloc((size_t)kvp->gpm.fromssize)) == NULL)
358a8bdc6a1Schristos 		err(EXIT_FAILURE, "cannot allocate %zu froms space",
359a8bdc6a1Schristos 		    (size_t)kvp->gpm.fromssize);
3607bb1d933Spk 	if (kflag) {
361a8bdc6a1Schristos 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, froms,
362a8bdc6a1Schristos 		    (size_t)kvp->gpm.fromssize);
3637bb1d933Spk 	} else {
3647bb1d933Spk 		mib[2] = GPROF_FROMS;
3657bb1d933Spk 		i = kvp->gpm.fromssize;
3667bb1d933Spk 		if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
3677bb1d933Spk 			i = 0;
3687bb1d933Spk 	}
369aa0a3ef5Schristos 	if (i != kvp->gpm.fromssize)
370595db245Sdyoung 		errx(EXIT_FAILURE, "read froms: read %lu, got %lu: %s",
3717ffe3c61Senami 		    kvp->gpm.fromssize, (u_long)i,
3727bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
373a8bdc6a1Schristos 	if ((tos = malloc((size_t)kvp->gpm.tossize)) == NULL)
374a8bdc6a1Schristos 		err(EXIT_FAILURE, "cannot allocate %zu tos space",
375a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize);
3767bb1d933Spk 	if (kflag) {
3777bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
378a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize);
3797bb1d933Spk 	} else {
3807bb1d933Spk 		mib[2] = GPROF_TOS;
3817bb1d933Spk 		i = kvp->gpm.tossize;
3827bb1d933Spk 		if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
3837bb1d933Spk 			i = 0;
3847bb1d933Spk 	}
385aa0a3ef5Schristos 	if (i != kvp->gpm.tossize)
386a8bdc6a1Schristos 		errx(EXIT_FAILURE, "read tos: read %zu, got %zu: %s",
387a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize, i,
3887bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
38936adb5cbScgd 	if (debug)
390aa0a3ef5Schristos 		(void)fprintf(stderr, "%s: lowpc 0x%lx, textsize 0x%lx\n",
391aa0a3ef5Schristos 		     getprogname(), kvp->gpm.lowpc, kvp->gpm.textsize);
3927bb1d933Spk 	endfrom = kvp->gpm.fromssize / sizeof(*froms);
3937bb1d933Spk 	for (fromindex = 0; fromindex < endfrom; ++fromindex) {
39436adb5cbScgd 		if (froms[fromindex] == 0)
39536adb5cbScgd 			continue;
3967bb1d933Spk 		frompc = (u_long)kvp->gpm.lowpc +
3977bb1d933Spk 		    (fromindex * kvp->gpm.hashfraction * sizeof(*froms));
39836adb5cbScgd 		for (toindex = froms[fromindex]; toindex != 0;
39936adb5cbScgd 		   toindex = tos[toindex].link) {
40036adb5cbScgd 			if (debug)
40136adb5cbScgd 			    (void)fprintf(stderr,
402d71f6e87Smrg 			    "%s: [mcleanup] frompc 0x%lx selfpc 0x%lx count %ld\n",
403aa0a3ef5Schristos 			    getprogname(), frompc, tos[toindex].selfpc,
4047bb1d933Spk 			    tos[toindex].count);
40536adb5cbScgd 			rawarc.raw_frompc = frompc;
40636adb5cbScgd 			rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
40736adb5cbScgd 			rawarc.raw_count = tos[toindex].count;
408a8bdc6a1Schristos 			if (fwrite(&rawarc, sizeof(rawarc), 1,fp) != 1){
4094329d94fSdyoung 				err(EXIT_FAILURE,
4104329d94fSdyoung 				    "writing raw arc to gmon.out");
4114329d94fSdyoung 			}
41236adb5cbScgd 		}
41336adb5cbScgd 	}
4142a8477a7Schristos 	free(tos);
415a8bdc6a1Schristos 	(void)fclose(fp);
41636adb5cbScgd }
41736adb5cbScgd 
4187bb1d933Spk /*
4197bb1d933Spk  * Get the profiling rate.
4207bb1d933Spk  */
421aa0a3ef5Schristos static int
4221ef7bd2aSperry getprofhz(struct kvmvars *kvp)
42336adb5cbScgd {
424191b5f2eScgd 	int mib[2], profrate;
425191b5f2eScgd 	size_t size;
4267bb1d933Spk 	struct clockinfo clockrate;
42736adb5cbScgd 
4287bb1d933Spk 	if (kflag) {
4297bb1d933Spk 		profrate = 1;
4307bb1d933Spk 		if (kvm_read(kvp->kd, nl[N_PROFHZ].n_value, &profrate,
4317bb1d933Spk 		    sizeof profrate) != sizeof profrate)
432aa0a3ef5Schristos 			warnx("get clockrate: %s", kvm_geterr(kvp->kd));
4337bb1d933Spk 		return (profrate);
43436adb5cbScgd 	}
4357bb1d933Spk 	mib[0] = CTL_KERN;
4367bb1d933Spk 	mib[1] = KERN_CLOCKRATE;
4377bb1d933Spk 	clockrate.profhz = 1;
4387bb1d933Spk 	size = sizeof clockrate;
4397bb1d933Spk 	if (sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
440aa0a3ef5Schristos 		warn("get clockrate");
4417bb1d933Spk 	return (clockrate.profhz);
44236adb5cbScgd }
44336adb5cbScgd 
4447bb1d933Spk /*
4457bb1d933Spk  * Reset the kernel profiling date structures.
4467bb1d933Spk  */
447aa0a3ef5Schristos static void
4481ef7bd2aSperry reset(struct kvmvars *kvp)
44936adb5cbScgd {
4507bb1d933Spk 	char *zbuf;
451a8bdc6a1Schristos 	size_t biggest;
4527bb1d933Spk 	int mib[3];
45336adb5cbScgd 
4547bb1d933Spk 	setprof(kvp, GMON_PROF_OFF);
45536adb5cbScgd 
456a8bdc6a1Schristos 	biggest = (size_t)kvp->gpm.kcountsize;
457a8bdc6a1Schristos 	if ((size_t)kvp->gpm.fromssize > biggest)
458a8bdc6a1Schristos 		biggest = (size_t)kvp->gpm.fromssize;
459a8bdc6a1Schristos 	if ((size_t)kvp->gpm.tossize > biggest)
460a8bdc6a1Schristos 		biggest = (size_t)kvp->gpm.tossize;
461aa0a3ef5Schristos 	if ((zbuf = malloc(biggest)) == NULL)
462595db245Sdyoung 		err(EXIT_FAILURE, "cannot allocate zbuf space");
463a8bdc6a1Schristos 	(void)memset(zbuf, 0, biggest);
4647bb1d933Spk 	if (kflag) {
465e7dd2c75Slukem 		if ((size_t)kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
466a8bdc6a1Schristos 		    (size_t)kvp->gpm.kcountsize) != kvp->gpm.kcountsize)
467595db245Sdyoung 			errx(EXIT_FAILURE, "tickbuf zero: %s",
468595db245Sdyoung 			     kvm_geterr(kvp->kd));
469e7dd2c75Slukem 		if ((size_t)kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
470a8bdc6a1Schristos 		    (size_t)kvp->gpm.fromssize) != kvp->gpm.fromssize)
471595db245Sdyoung 			errx(EXIT_FAILURE, "froms zero: %s",
472595db245Sdyoung 			     kvm_geterr(kvp->kd));
473e7dd2c75Slukem 		if ((size_t)kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
474a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize) != kvp->gpm.tossize)
475595db245Sdyoung 			errx(EXIT_FAILURE, "tos zero: %s", kvm_geterr(kvp->kd));
476aa0a3ef5Schristos 		free(zbuf);
4777bb1d933Spk 		return;
4787bb1d933Spk 	}
4797bb1d933Spk 	(void)seteuid(0);
4807bb1d933Spk 	mib[0] = CTL_KERN;
4817bb1d933Spk 	mib[1] = KERN_PROF;
4827bb1d933Spk 	mib[2] = GPROF_COUNT;
483a8bdc6a1Schristos 	if (sysctl(mib, 3, NULL, NULL, zbuf, (size_t)kvp->gpm.kcountsize) < 0)
484595db245Sdyoung 		err(EXIT_FAILURE, "tickbuf zero");
4857bb1d933Spk 	mib[2] = GPROF_FROMS;
486a8bdc6a1Schristos 	if (sysctl(mib, 3, NULL, NULL, zbuf, (size_t)kvp->gpm.fromssize) < 0)
487595db245Sdyoung 		err(EXIT_FAILURE, "froms zero");
4887bb1d933Spk 	mib[2] = GPROF_TOS;
489a8bdc6a1Schristos 	if (sysctl(mib, 3, NULL, NULL, zbuf, (size_t)kvp->gpm.tossize) < 0)
490595db245Sdyoung 		err(EXIT_FAILURE, "tos zero");
4917bb1d933Spk 	(void)seteuid(getuid());
4927bb1d933Spk 	free(zbuf);
49336adb5cbScgd }
494