xref: /netbsd/usr.sbin/kgmon/kgmon.c (revision 1ef7bd2a)
1*1ef7bd2aSperry /*	$NetBSD: kgmon.c,v 1.16 2005/02/06 04:48:58 perry 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*1ef7bd2aSperry __RCSID("$NetBSD: kgmon.c,v 1.16 2005/02/06 04:48:58 perry 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>
547bb1d933Spk #include <limits.h>
55d71f6e87Smrg #include <nlist.h>
5636adb5cbScgd #include <stdio.h>
577bb1d933Spk #include <stdlib.h>
587bb1d933Spk #include <string.h>
59d71f6e87Smrg #include <unistd.h>
6036adb5cbScgd 
6136adb5cbScgd struct nlist nl[] = {
627bb1d933Spk #define	N_GMONPARAM	0
637bb1d933Spk 	{ "__gmonparam" },
647bb1d933Spk #define	N_PROFHZ	1
657bb1d933Spk 	{ "_profhz" },
66d71f6e87Smrg 	{ 0, }
6736adb5cbScgd };
6836adb5cbScgd 
697bb1d933Spk struct kvmvars {
707bb1d933Spk 	kvm_t	*kd;
717bb1d933Spk 	struct gmonparam gpm;
727bb1d933Spk };
7336adb5cbScgd 
7436adb5cbScgd int	bflag, hflag, kflag, rflag, pflag;
7536adb5cbScgd int	debug = 0;
76*1ef7bd2aSperry void	setprof(struct kvmvars *kvp, int state);
77*1ef7bd2aSperry void	dumpstate(struct kvmvars *kvp);
78*1ef7bd2aSperry void	reset(struct kvmvars *kvp);
79*1ef7bd2aSperry int	openfiles(char *, char *, struct kvmvars *);
80*1ef7bd2aSperry int	getprof(struct kvmvars *);
81*1ef7bd2aSperry void	kern_readonly(int);
82*1ef7bd2aSperry int	getprofhz(struct kvmvars *);
8336adb5cbScgd 
847bb1d933Spk int
857bb1d933Spk main(int argc, char **argv)
8636adb5cbScgd {
877bb1d933Spk 	int ch, mode, disp, accessmode;
887bb1d933Spk 	struct kvmvars kvmvars;
897bb1d933Spk 	char *system, *kmemf;
9036adb5cbScgd 
917bb1d933Spk 	seteuid(getuid());
927bb1d933Spk 	kmemf = NULL;
937bb1d933Spk 	system = NULL;
94780f68fdSeeh 	while ((ch = getopt(argc, argv, "M:N:bdhpr")) != -1) {
9536adb5cbScgd 		switch((char)ch) {
967bb1d933Spk 
9736adb5cbScgd 		case 'M':
9836adb5cbScgd 			kmemf = optarg;
9936adb5cbScgd 			kflag = 1;
10036adb5cbScgd 			break;
1017bb1d933Spk 
10236adb5cbScgd 		case 'N':
10336adb5cbScgd 			system = optarg;
10436adb5cbScgd 			break;
1057bb1d933Spk 
10636adb5cbScgd 		case 'b':
10736adb5cbScgd 			bflag = 1;
10836adb5cbScgd 			break;
1097bb1d933Spk 
11036adb5cbScgd 		case 'h':
11136adb5cbScgd 			hflag = 1;
11236adb5cbScgd 			break;
1137bb1d933Spk 
11436adb5cbScgd 		case 'p':
11536adb5cbScgd 			pflag = 1;
11636adb5cbScgd 			break;
1177bb1d933Spk 
11836adb5cbScgd 		case 'r':
11936adb5cbScgd 			rflag = 1;
12036adb5cbScgd 			break;
1217bb1d933Spk 
122780f68fdSeeh 		case 'd':
123780f68fdSeeh 			debug = 1;
124780f68fdSeeh 			break;
125780f68fdSeeh 
12636adb5cbScgd 		default:
12736adb5cbScgd 			(void)fprintf(stderr,
128b1440f78Shira 			    "usage: %s [-bdhrp] [-M core] [-N system]\n",
129b1440f78Shira 			    getprogname());
13036adb5cbScgd 			exit(1);
13136adb5cbScgd 		}
1327bb1d933Spk 	}
13336adb5cbScgd 	argc -= optind;
13436adb5cbScgd 	argv += optind;
13536adb5cbScgd 
13636adb5cbScgd #define BACKWARD_COMPATIBILITY
13736adb5cbScgd #ifdef	BACKWARD_COMPATIBILITY
13836adb5cbScgd 	if (*argv) {
13936adb5cbScgd 		system = *argv;
14036adb5cbScgd 		if (*++argv) {
14136adb5cbScgd 			kmemf = *argv;
14236adb5cbScgd 			++kflag;
14336adb5cbScgd 		}
14436adb5cbScgd 	}
14536adb5cbScgd #endif
1467bb1d933Spk 	accessmode = openfiles(system, kmemf, &kvmvars);
1477bb1d933Spk 	mode = getprof(&kvmvars);
1487bb1d933Spk 	if (hflag)
1497bb1d933Spk 		disp = GMON_PROF_OFF;
1507bb1d933Spk 	else if (bflag)
1517bb1d933Spk 		disp = GMON_PROF_ON;
1527bb1d933Spk 	else
1537bb1d933Spk 		disp = mode;
1547bb1d933Spk 	if (pflag)
1557bb1d933Spk 		dumpstate(&kvmvars);
1567bb1d933Spk 	if (rflag)
1577bb1d933Spk 		reset(&kvmvars);
1587bb1d933Spk 	if (accessmode == O_RDWR)
1597bb1d933Spk 		setprof(&kvmvars, disp);
1607bb1d933Spk 	(void)fprintf(stdout, "kgmon: kernel profiling is %s.\n",
1617bb1d933Spk 		      disp == GMON_PROF_OFF ? "off" : "running");
1627bb1d933Spk 	return (0);
1637bb1d933Spk }
16436adb5cbScgd 
1657bb1d933Spk /*
1667bb1d933Spk  * Check that profiling is enabled and open any ncessary files.
1677bb1d933Spk  */
168d71f6e87Smrg int
169*1ef7bd2aSperry openfiles(char *system, char *kmemf, struct kvmvars *kvp)
1707bb1d933Spk {
171191b5f2eScgd 	int mib[3], state, openmode;
172191b5f2eScgd 	size_t size;
1737bb1d933Spk 	char errbuf[_POSIX2_LINE_MAX];
1747bb1d933Spk 
1757bb1d933Spk 	if (!kflag) {
1767bb1d933Spk 		mib[0] = CTL_KERN;
1777bb1d933Spk 		mib[1] = KERN_PROF;
1787bb1d933Spk 		mib[2] = GPROF_STATE;
1797bb1d933Spk 		size = sizeof state;
1807bb1d933Spk 		if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
1817bb1d933Spk 			(void)fprintf(stderr,
1827bb1d933Spk 			    "kgmon: profiling not defined in kernel.\n");
1837bb1d933Spk 			exit(20);
1847bb1d933Spk 		}
1857bb1d933Spk 		if (!(bflag || hflag || rflag ||
1867bb1d933Spk 		    (pflag && state == GMON_PROF_ON)))
1877bb1d933Spk 			return (O_RDONLY);
1887bb1d933Spk 		(void)seteuid(0);
1897bb1d933Spk 		if (sysctl(mib, 3, NULL, NULL, &state, size) >= 0)
1907bb1d933Spk 			return (O_RDWR);
1917bb1d933Spk 		(void)seteuid(getuid());
1927bb1d933Spk 		kern_readonly(state);
1937bb1d933Spk 		return (O_RDONLY);
1947bb1d933Spk 	}
1957bb1d933Spk 	openmode = (bflag || hflag || pflag || rflag) ? O_RDWR : O_RDONLY;
1967bb1d933Spk 	kvp->kd = kvm_openfiles(system, kmemf, NULL, openmode, errbuf);
1977bb1d933Spk 	if (kvp->kd == NULL) {
1987bb1d933Spk 		if (openmode == O_RDWR) {
1997bb1d933Spk 			openmode = O_RDONLY;
2007bb1d933Spk 			kvp->kd = kvm_openfiles(system, kmemf, NULL, O_RDONLY,
2017bb1d933Spk 			    errbuf);
2027bb1d933Spk 		}
2037bb1d933Spk 		if (kvp->kd == NULL) {
2047bb1d933Spk 			(void)fprintf(stderr, "kgmon: kvm_openfiles: %s\n",
2057bb1d933Spk 			    errbuf);
20636adb5cbScgd 			exit(2);
20736adb5cbScgd 		}
2087bb1d933Spk 		kern_readonly(GMON_PROF_ON);
20936adb5cbScgd 	}
2107bb1d933Spk 	if (kvm_nlist(kvp->kd, nl) < 0) {
2117bb1d933Spk 		(void)fprintf(stderr, "kgmon: %s: no namelist\n", system);
21236adb5cbScgd 		exit(3);
21336adb5cbScgd 	}
2147bb1d933Spk 	if (!nl[N_GMONPARAM].n_value) {
2157bb1d933Spk 		(void)fprintf(stderr,
2167bb1d933Spk 		    "kgmon: profiling not defined in kernel.\n");
2177bb1d933Spk 		exit(20);
2187bb1d933Spk 	}
2197bb1d933Spk 	return (openmode);
2207bb1d933Spk }
2217bb1d933Spk 
2227bb1d933Spk /*
2237bb1d933Spk  * Suppress options that require a writable kernel.
2247bb1d933Spk  */
225d71f6e87Smrg void
226*1ef7bd2aSperry kern_readonly(int mode)
2277bb1d933Spk {
2287bb1d933Spk 
2297bb1d933Spk 	(void)fprintf(stderr, "kgmon: kernel read-only: ");
2307bb1d933Spk 	if (pflag && mode == GMON_PROF_ON)
2317bb1d933Spk 		(void)fprintf(stderr, "data may be inconsistent\n");
23236adb5cbScgd 	if (rflag)
23336adb5cbScgd 		(void)fprintf(stderr, "-r supressed\n");
23436adb5cbScgd 	if (bflag)
23536adb5cbScgd 		(void)fprintf(stderr, "-b supressed\n");
23636adb5cbScgd 	if (hflag)
23736adb5cbScgd 		(void)fprintf(stderr, "-h supressed\n");
23836adb5cbScgd 	rflag = bflag = hflag = 0;
23936adb5cbScgd }
240e9d867efSmycroft 
2417bb1d933Spk /*
2427bb1d933Spk  * Get the state of kernel profiling.
2437bb1d933Spk  */
244d71f6e87Smrg int
245*1ef7bd2aSperry getprof(struct kvmvars *kvp)
246c78c6a22Smrg {
247191b5f2eScgd 	int mib[3];
248191b5f2eScgd 	size_t size;
2497bb1d933Spk 
2507bb1d933Spk 	if (kflag) {
2517bb1d933Spk 		size = kvm_read(kvp->kd, nl[N_GMONPARAM].n_value, &kvp->gpm,
2527bb1d933Spk 		    sizeof kvp->gpm);
2537bb1d933Spk 	} else {
2547bb1d933Spk 		mib[0] = CTL_KERN;
2557bb1d933Spk 		mib[1] = KERN_PROF;
2567bb1d933Spk 		mib[2] = GPROF_GMONPARAM;
2577bb1d933Spk 		size = sizeof kvp->gpm;
2587bb1d933Spk 		if (sysctl(mib, 3, &kvp->gpm, &size, NULL, 0) < 0)
2597bb1d933Spk 			size = 0;
2607bb1d933Spk 	}
2617bb1d933Spk 	if (size != sizeof kvp->gpm) {
2627bb1d933Spk 		(void)fprintf(stderr, "kgmon: cannot get gmonparam: %s\n",
2637bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
2647bb1d933Spk 		exit (4);
2657bb1d933Spk 	}
2667bb1d933Spk 	return (kvp->gpm.state);
2677bb1d933Spk }
2687bb1d933Spk 
2697bb1d933Spk /*
2707bb1d933Spk  * Enable or disable kernel profiling according to the state variable.
2717bb1d933Spk  */
2727bb1d933Spk void
273*1ef7bd2aSperry setprof(struct kvmvars *kvp, int state)
2747bb1d933Spk {
2757bb1d933Spk 	struct gmonparam *p = (struct gmonparam *)nl[N_GMONPARAM].n_value;
276191b5f2eScgd 	int mib[3], oldstate;
277191b5f2eScgd 	size_t sz;
2787bb1d933Spk 
2797bb1d933Spk 	sz = sizeof(state);
2807bb1d933Spk 	if (!kflag) {
2817bb1d933Spk 		mib[0] = CTL_KERN;
2827bb1d933Spk 		mib[1] = KERN_PROF;
2837bb1d933Spk 		mib[2] = GPROF_STATE;
2847bb1d933Spk 		if (sysctl(mib, 3, &oldstate, &sz, NULL, 0) < 0)
2857bb1d933Spk 			goto bad;
2867bb1d933Spk 		if (oldstate == state)
2877bb1d933Spk 			return;
2887bb1d933Spk 		(void)seteuid(0);
2897bb1d933Spk 		if (sysctl(mib, 3, NULL, NULL, &state, sz) >= 0) {
2907bb1d933Spk 			(void)seteuid(getuid());
2917bb1d933Spk 			return;
2927bb1d933Spk 		}
2937bb1d933Spk 		(void)seteuid(getuid());
2947bb1d933Spk 	} else if (kvm_write(kvp->kd, (u_long)&p->state, (void *)&state, sz)
2957bb1d933Spk 	    == sz)
2967bb1d933Spk 		return;
2977bb1d933Spk bad:
2987bb1d933Spk 	(void)fprintf(stderr, "kgmon: warning: cannot turn profiling %s\n",
2997bb1d933Spk 	    state == GMON_PROF_OFF ? "off" : "on");
3007bb1d933Spk }
3017bb1d933Spk 
3027bb1d933Spk /*
3037bb1d933Spk  * Build the gmon.out file.
3047bb1d933Spk  */
3057bb1d933Spk void
306*1ef7bd2aSperry dumpstate(struct kvmvars *kvp)
3077bb1d933Spk {
308*1ef7bd2aSperry 	FILE *fp;
30936adb5cbScgd 	struct rawarc rawarc;
31036adb5cbScgd 	struct tostruct *tos;
311d71f6e87Smrg 	u_long frompc;
3127bb1d933Spk 	u_short *froms, *tickbuf;
313191b5f2eScgd 	int mib[3];
314191b5f2eScgd 	size_t i;
3157bb1d933Spk 	struct gmonhdr h;
3167bb1d933Spk 	int fromindex, endfrom, toindex;
31736adb5cbScgd 
3187bb1d933Spk 	setprof(kvp, GMON_PROF_OFF);
3197bb1d933Spk 	fp = fopen("gmon.out", "w");
3207bb1d933Spk 	if (fp == 0) {
32136adb5cbScgd 		perror("gmon.out");
32236adb5cbScgd 		return;
32336adb5cbScgd 	}
3247bb1d933Spk 
3257bb1d933Spk 	/*
3267bb1d933Spk 	 * Build the gmon header and write it to a file.
3277bb1d933Spk 	 */
3287bb1d933Spk 	bzero(&h, sizeof(h));
3297bb1d933Spk 	h.lpc = kvp->gpm.lowpc;
3307bb1d933Spk 	h.hpc = kvp->gpm.highpc;
3317bb1d933Spk 	h.ncnt = kvp->gpm.kcountsize + sizeof(h);
3327bb1d933Spk 	h.version = GMONVERSION;
3337bb1d933Spk 	h.profrate = getprofhz(kvp);
3347bb1d933Spk 	fwrite((char *)&h, sizeof(h), 1, fp);
3357bb1d933Spk 
3367bb1d933Spk 	/*
3377bb1d933Spk 	 * Write out the tick buffer.
3387bb1d933Spk 	 */
3397bb1d933Spk 	mib[0] = CTL_KERN;
3407bb1d933Spk 	mib[1] = KERN_PROF;
3417bb1d933Spk 	if ((tickbuf = (u_short *)malloc(kvp->gpm.kcountsize)) == NULL) {
3427bb1d933Spk 		fprintf(stderr, "kgmon: cannot allocate kcount space\n");
34336adb5cbScgd 		exit (5);
34436adb5cbScgd 	}
3457bb1d933Spk 	if (kflag) {
3467bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, (void *)tickbuf,
3477bb1d933Spk 		    kvp->gpm.kcountsize);
3487bb1d933Spk 	} else {
3497bb1d933Spk 		mib[2] = GPROF_COUNT;
3507bb1d933Spk 		i = kvp->gpm.kcountsize;
3517bb1d933Spk 		if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0)
3527bb1d933Spk 			i = 0;
3537bb1d933Spk 	}
3547bb1d933Spk 	if (i != kvp->gpm.kcountsize) {
3557ffe3c61Senami 		(void)fprintf(stderr,
356a5372bf5Senami 		    "kgmon: read ticks: read %lu, got %lu: %s\n",
3577ffe3c61Senami 		    kvp->gpm.kcountsize, (u_long)i,
3587bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
35936adb5cbScgd 		exit(6);
36036adb5cbScgd 	}
3617bb1d933Spk 	if ((fwrite(tickbuf, kvp->gpm.kcountsize, 1, fp)) != 1) {
3627bb1d933Spk 		perror("kgmon: writing tocks to gmon.out");
3637bb1d933Spk 		exit(7);
3647bb1d933Spk 	}
3657bb1d933Spk 	free(tickbuf);
3667bb1d933Spk 
3677bb1d933Spk 	/*
3687bb1d933Spk 	 * Write out the arc info.
3697bb1d933Spk 	 */
3707bb1d933Spk 	if ((froms = (u_short *)malloc(kvp->gpm.fromssize)) == NULL) {
3717bb1d933Spk 		fprintf(stderr, "kgmon: cannot allocate froms space\n");
3727bb1d933Spk 		exit (8);
3737bb1d933Spk 	}
3747bb1d933Spk 	if (kflag) {
3757bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, (void *)froms,
3767bb1d933Spk 		    kvp->gpm.fromssize);
3777bb1d933Spk 	} else {
3787bb1d933Spk 		mib[2] = GPROF_FROMS;
3797bb1d933Spk 		i = kvp->gpm.fromssize;
3807bb1d933Spk 		if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
3817bb1d933Spk 			i = 0;
3827bb1d933Spk 	}
3837bb1d933Spk 	if (i != kvp->gpm.fromssize) {
3847ffe3c61Senami 		(void)fprintf(stderr,
385a5372bf5Senami 		   "kgmon: read froms: read %lu, got %lu: %s\n",
3867ffe3c61Senami 		    kvp->gpm.fromssize, (u_long)i,
3877bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
3887bb1d933Spk 		exit(9);
3897bb1d933Spk 	}
3907bb1d933Spk 	if ((tos = (struct tostruct *)malloc(kvp->gpm.tossize)) == NULL) {
3917bb1d933Spk 		fprintf(stderr, "kgmon: cannot allocate tos space\n");
3927bb1d933Spk 		exit(10);
3937bb1d933Spk 	}
3947bb1d933Spk 	if (kflag) {
3957bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
3967bb1d933Spk 		    kvp->gpm.tossize);
3977bb1d933Spk 	} else {
3987bb1d933Spk 		mib[2] = GPROF_TOS;
3997bb1d933Spk 		i = kvp->gpm.tossize;
4007bb1d933Spk 		if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
4017bb1d933Spk 			i = 0;
4027bb1d933Spk 	}
4037bb1d933Spk 	if (i != kvp->gpm.tossize) {
404a5372bf5Senami 		(void)fprintf(stderr,
405a5372bf5Senami 		    "kgmon: read tos: read %lu, got %lu: %s\n",
4067ffe3c61Senami 		    kvp->gpm.tossize, (u_long)i,
4077bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
4087bb1d933Spk 		exit(11);
4097bb1d933Spk 	}
41036adb5cbScgd 	if (debug)
411d71f6e87Smrg 		(void)fprintf(stderr, "kgmon: lowpc 0x%lx, textsize 0x%lx\n",
4127bb1d933Spk 			      kvp->gpm.lowpc, kvp->gpm.textsize);
4137bb1d933Spk 	endfrom = kvp->gpm.fromssize / sizeof(*froms);
4147bb1d933Spk 	for (fromindex = 0; fromindex < endfrom; ++fromindex) {
41536adb5cbScgd 		if (froms[fromindex] == 0)
41636adb5cbScgd 			continue;
4177bb1d933Spk 		frompc = (u_long)kvp->gpm.lowpc +
4187bb1d933Spk 		    (fromindex * kvp->gpm.hashfraction * sizeof(*froms));
41936adb5cbScgd 		for (toindex = froms[fromindex]; toindex != 0;
42036adb5cbScgd 		   toindex = tos[toindex].link) {
42136adb5cbScgd 			if (debug)
42236adb5cbScgd 			    (void)fprintf(stderr,
423d71f6e87Smrg 			    "%s: [mcleanup] frompc 0x%lx selfpc 0x%lx count %ld\n",
4247bb1d933Spk 			    "kgmon", frompc, tos[toindex].selfpc,
4257bb1d933Spk 			    tos[toindex].count);
42636adb5cbScgd 			rawarc.raw_frompc = frompc;
42736adb5cbScgd 			rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
42836adb5cbScgd 			rawarc.raw_count = tos[toindex].count;
4297bb1d933Spk 			fwrite((char *)&rawarc, sizeof(rawarc), 1, fp);
43036adb5cbScgd 		}
43136adb5cbScgd 	}
4327bb1d933Spk 	fclose(fp);
43336adb5cbScgd }
43436adb5cbScgd 
4357bb1d933Spk /*
4367bb1d933Spk  * Get the profiling rate.
4377bb1d933Spk  */
4387bb1d933Spk int
439*1ef7bd2aSperry getprofhz(struct kvmvars *kvp)
44036adb5cbScgd {
441191b5f2eScgd 	int mib[2], profrate;
442191b5f2eScgd 	size_t size;
4437bb1d933Spk 	struct clockinfo clockrate;
44436adb5cbScgd 
4457bb1d933Spk 	if (kflag) {
4467bb1d933Spk 		profrate = 1;
4477bb1d933Spk 		if (kvm_read(kvp->kd, nl[N_PROFHZ].n_value, &profrate,
4487bb1d933Spk 		    sizeof profrate) != sizeof profrate)
4497bb1d933Spk 			(void)fprintf(stderr, "kgmon: get clockrate: %s\n",
4507bb1d933Spk 				kvm_geterr(kvp->kd));
4517bb1d933Spk 		return (profrate);
45236adb5cbScgd 	}
4537bb1d933Spk 	mib[0] = CTL_KERN;
4547bb1d933Spk 	mib[1] = KERN_CLOCKRATE;
4557bb1d933Spk 	clockrate.profhz = 1;
4567bb1d933Spk 	size = sizeof clockrate;
4577bb1d933Spk 	if (sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
4587bb1d933Spk 		(void)fprintf(stderr, "kgmon: get clockrate: %s\n",
4597bb1d933Spk 			strerror(errno));
4607bb1d933Spk 	return (clockrate.profhz);
46136adb5cbScgd }
46236adb5cbScgd 
4637bb1d933Spk /*
4647bb1d933Spk  * Reset the kernel profiling date structures.
4657bb1d933Spk  */
4667bb1d933Spk void
467*1ef7bd2aSperry reset(struct kvmvars *kvp)
46836adb5cbScgd {
4697bb1d933Spk 	char *zbuf;
4707bb1d933Spk 	u_long biggest;
4717bb1d933Spk 	int mib[3];
47236adb5cbScgd 
4737bb1d933Spk 	setprof(kvp, GMON_PROF_OFF);
47436adb5cbScgd 
4757bb1d933Spk 	biggest = kvp->gpm.kcountsize;
4767bb1d933Spk 	if (kvp->gpm.fromssize > biggest)
4777bb1d933Spk 		biggest = kvp->gpm.fromssize;
4787bb1d933Spk 	if (kvp->gpm.tossize > biggest)
4797bb1d933Spk 		biggest = kvp->gpm.tossize;
4807bb1d933Spk 	if ((zbuf = (char *)malloc(biggest)) == NULL) {
4817bb1d933Spk 		fprintf(stderr, "kgmon: cannot allocate zbuf space\n");
48236adb5cbScgd 		exit(12);
48336adb5cbScgd 	}
4847bb1d933Spk 	bzero(zbuf, biggest);
4857bb1d933Spk 	if (kflag) {
4867bb1d933Spk 		if (kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
4877bb1d933Spk 		    kvp->gpm.kcountsize) != kvp->gpm.kcountsize) {
4887bb1d933Spk 			(void)fprintf(stderr, "kgmon: tickbuf zero: %s\n",
4897bb1d933Spk 			    kvm_geterr(kvp->kd));
49036adb5cbScgd 			exit(13);
49136adb5cbScgd 		}
4927bb1d933Spk 		if (kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
4937bb1d933Spk 		    kvp->gpm.fromssize) != kvp->gpm.fromssize) {
4947bb1d933Spk 			(void)fprintf(stderr, "kgmon: froms zero: %s\n",
4957bb1d933Spk 			    kvm_geterr(kvp->kd));
4967bb1d933Spk 			exit(14);
49736adb5cbScgd 		}
4987bb1d933Spk 		if (kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
4997bb1d933Spk 		    kvp->gpm.tossize) != kvp->gpm.tossize) {
5007bb1d933Spk 			(void)fprintf(stderr, "kgmon: tos zero: %s\n",
5017bb1d933Spk 			    kvm_geterr(kvp->kd));
5027bb1d933Spk 			exit(15);
50336adb5cbScgd 		}
5047bb1d933Spk 		return;
5057bb1d933Spk 	}
5067bb1d933Spk 	(void)seteuid(0);
5077bb1d933Spk 	mib[0] = CTL_KERN;
5087bb1d933Spk 	mib[1] = KERN_PROF;
5097bb1d933Spk 	mib[2] = GPROF_COUNT;
5107bb1d933Spk 	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.kcountsize) < 0) {
5117bb1d933Spk 		(void)fprintf(stderr, "kgmon: tickbuf zero: %s\n",
5127bb1d933Spk 		    strerror(errno));
5137bb1d933Spk 		exit(13);
5147bb1d933Spk 	}
5157bb1d933Spk 	mib[2] = GPROF_FROMS;
5167bb1d933Spk 	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.fromssize) < 0) {
5177bb1d933Spk 		(void)fprintf(stderr, "kgmon: froms zero: %s\n",
5187bb1d933Spk 		    strerror(errno));
5197bb1d933Spk 		exit(14);
5207bb1d933Spk 	}
5217bb1d933Spk 	mib[2] = GPROF_TOS;
5227bb1d933Spk 	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.tossize) < 0) {
5237bb1d933Spk 		(void)fprintf(stderr, "kgmon: tos zero: %s\n",
5247bb1d933Spk 		    strerror(errno));
5257bb1d933Spk 		exit(15);
5267bb1d933Spk 	}
5277bb1d933Spk 	(void)seteuid(getuid());
5287bb1d933Spk 	free(zbuf);
52936adb5cbScgd }
530