xref: /netbsd/usr.sbin/kgmon/kgmon.c (revision bc2926d3)
1*bc2926d3Sryo /*	$NetBSD: kgmon.c,v 1.27 2021/08/14 17:51:20 ryo 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*bc2926d3Sryo __RCSID("$NetBSD: kgmon.c,v 1.27 2021/08/14 17:51:20 ryo 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 
75*bc2926d3Sryo static int	ncpu_mib[2] = { CTL_HW, HW_NCPU };
76*bc2926d3Sryo static int	bflag, cflag_all, hflag, kflag, rflag, pflag;
77aa0a3ef5Schristos static int	debug = 0;
78*bc2926d3Sryo static void	setprof(struct kvmvars *kvp, int state, int cpuid);
79*bc2926d3Sryo static void	dumpstate(struct kvmvars *kvp, int cpuid);
80*bc2926d3Sryo static void	reset(struct kvmvars *kvp, int cpuid);
81aa0a3ef5Schristos static int	openfiles(char *, char *, struct kvmvars *);
82*bc2926d3Sryo static int	getprof(struct kvmvars *, int);
83aa0a3ef5Schristos static void	kern_readonly(int);
84aa0a3ef5Schristos static int	getprofhz(struct kvmvars *);
8536adb5cbScgd 
867bb1d933Spk int
main(int argc,char ** argv)877bb1d933Spk main(int argc, char **argv)
8836adb5cbScgd {
89*bc2926d3Sryo 	int ch, mode, disp, accessmode, ncpu, cpuid = -1;
907bb1d933Spk 	struct kvmvars kvmvars;
91*bc2926d3Sryo 	size_t size;
92a8bdc6a1Schristos 	char *sys, *kmemf;
93*bc2926d3Sryo 	char on_cpu[sizeof(" on cpuXXXXXXXXX")];
94*bc2926d3Sryo 
95*bc2926d3Sryo 	size = sizeof(ncpu);
96*bc2926d3Sryo 	if (sysctl(ncpu_mib, 2, &ncpu, &size, NULL, 0) < 0)
97*bc2926d3Sryo 		ncpu = 1;
9836adb5cbScgd 
99aa0a3ef5Schristos 	setprogname(argv[0]);
100a8bdc6a1Schristos 	(void)seteuid(getuid());
1017bb1d933Spk 	kmemf = NULL;
102a8bdc6a1Schristos 	sys = NULL;
103*bc2926d3Sryo 	while ((ch = getopt(argc, argv, "M:N:bc:dhpr")) != -1) {
10436adb5cbScgd 		switch((char)ch) {
1057bb1d933Spk 
10636adb5cbScgd 		case 'M':
10736adb5cbScgd 			kmemf = optarg;
10836adb5cbScgd 			kflag = 1;
10936adb5cbScgd 			break;
1107bb1d933Spk 
11136adb5cbScgd 		case 'N':
112a8bdc6a1Schristos 			sys = optarg;
11336adb5cbScgd 			break;
1147bb1d933Spk 
11536adb5cbScgd 		case 'b':
11636adb5cbScgd 			bflag = 1;
11736adb5cbScgd 			break;
1187bb1d933Spk 
119*bc2926d3Sryo 		case 'c':
120*bc2926d3Sryo 			if (strcmp(optarg, "all") == 0) {
121*bc2926d3Sryo 				cflag_all = 1;
122*bc2926d3Sryo 				cpuid = 0;
123*bc2926d3Sryo 			} else {
124*bc2926d3Sryo 				cpuid = strtol(optarg, NULL, 10);
125*bc2926d3Sryo 				if (cpuid >= ncpu)
126*bc2926d3Sryo 					errx(1, "illegal CPU id %s", optarg);
127*bc2926d3Sryo 			}
128*bc2926d3Sryo 			break;
129*bc2926d3Sryo 
13036adb5cbScgd 		case 'h':
13136adb5cbScgd 			hflag = 1;
13236adb5cbScgd 			break;
1337bb1d933Spk 
13436adb5cbScgd 		case 'p':
13536adb5cbScgd 			pflag = 1;
13636adb5cbScgd 			break;
1377bb1d933Spk 
13836adb5cbScgd 		case 'r':
13936adb5cbScgd 			rflag = 1;
14036adb5cbScgd 			break;
1417bb1d933Spk 
142780f68fdSeeh 		case 'd':
143780f68fdSeeh 			debug = 1;
144780f68fdSeeh 			break;
145780f68fdSeeh 
14636adb5cbScgd 		default:
14736adb5cbScgd 			(void)fprintf(stderr,
148*bc2926d3Sryo 			    "usage: %s [-bdhrp] [-c cpuid] [-M core] [-N system]\n",
149b1440f78Shira 			    getprogname());
15036adb5cbScgd 			exit(1);
15136adb5cbScgd 		}
1527bb1d933Spk 	}
15336adb5cbScgd 	argc -= optind;
15436adb5cbScgd 	argv += optind;
15536adb5cbScgd 
15636adb5cbScgd #define BACKWARD_COMPATIBILITY
15736adb5cbScgd #ifdef	BACKWARD_COMPATIBILITY
15836adb5cbScgd 	if (*argv) {
159a8bdc6a1Schristos 		sys = *argv;
16036adb5cbScgd 		if (*++argv) {
16136adb5cbScgd 			kmemf = *argv;
16236adb5cbScgd 			++kflag;
16336adb5cbScgd 		}
16436adb5cbScgd 	}
16536adb5cbScgd #endif
166a8bdc6a1Schristos 	accessmode = openfiles(sys, kmemf, &kvmvars);
167*bc2926d3Sryo 
168*bc2926d3Sryo 	do {
169*bc2926d3Sryo 		if (cpuid == -1)
170*bc2926d3Sryo 			on_cpu[0] = '\0';
171*bc2926d3Sryo 		else
172*bc2926d3Sryo 			snprintf(on_cpu, sizeof(on_cpu), " on cpu%d", cpuid);
173*bc2926d3Sryo 
174*bc2926d3Sryo 		mode = getprof(&kvmvars, cpuid);
1757bb1d933Spk 		if (hflag)
1767bb1d933Spk 			disp = GMON_PROF_OFF;
1777bb1d933Spk 		else if (bflag)
1787bb1d933Spk 			disp = GMON_PROF_ON;
1797bb1d933Spk 		else
1807bb1d933Spk 			disp = mode;
1817bb1d933Spk 		if (pflag)
182*bc2926d3Sryo 			dumpstate(&kvmvars, cpuid);
1837bb1d933Spk 		if (rflag)
184*bc2926d3Sryo 			reset(&kvmvars, cpuid);
1857bb1d933Spk 		if (accessmode == O_RDWR)
186*bc2926d3Sryo 			setprof(&kvmvars, disp, cpuid);
187*bc2926d3Sryo 		(void)fprintf(stdout, "%s: kernel profiling is %s%s.\n",
188*bc2926d3Sryo 		    getprogname(), disp == GMON_PROF_OFF ? "off" : "running",
189*bc2926d3Sryo 		    on_cpu);
190*bc2926d3Sryo 
191*bc2926d3Sryo 	} while (cflag_all && ++cpuid < ncpu);
1927bb1d933Spk 	return (0);
1937bb1d933Spk }
19436adb5cbScgd 
1957bb1d933Spk /*
1967bb1d933Spk  * Check that profiling is enabled and open any ncessary files.
1977bb1d933Spk  */
198aa0a3ef5Schristos static int
openfiles(char * sys,char * kmemf,struct kvmvars * kvp)199a8bdc6a1Schristos openfiles(char *sys, char *kmemf, struct kvmvars *kvp)
2007bb1d933Spk {
201191b5f2eScgd 	int mib[3], state, openmode;
202191b5f2eScgd 	size_t size;
2037bb1d933Spk 	char errbuf[_POSIX2_LINE_MAX];
2047bb1d933Spk 
2057bb1d933Spk 	if (!kflag) {
2067bb1d933Spk 		mib[0] = CTL_KERN;
2077bb1d933Spk 		mib[1] = KERN_PROF;
2087bb1d933Spk 		mib[2] = GPROF_STATE;
2097bb1d933Spk 		size = sizeof state;
210aa0a3ef5Schristos 		if (sysctl(mib, 3, &state, &size, NULL, 0) < 0)
211595db245Sdyoung 			err(EXIT_FAILURE, "profiling not defined in kernel");
2127bb1d933Spk 		if (!(bflag || hflag || rflag ||
2137bb1d933Spk 		    (pflag && state == GMON_PROF_ON)))
2147bb1d933Spk 			return (O_RDONLY);
2157bb1d933Spk 		(void)seteuid(0);
2167bb1d933Spk 		if (sysctl(mib, 3, NULL, NULL, &state, size) >= 0)
2177bb1d933Spk 			return (O_RDWR);
2187bb1d933Spk 		(void)seteuid(getuid());
2197bb1d933Spk 		kern_readonly(state);
2207bb1d933Spk 		return (O_RDONLY);
2217bb1d933Spk 	}
2227bb1d933Spk 	openmode = (bflag || hflag || pflag || rflag) ? O_RDWR : O_RDONLY;
223a8bdc6a1Schristos 	kvp->kd = kvm_openfiles(sys, kmemf, NULL, openmode, errbuf);
2247bb1d933Spk 	if (kvp->kd == NULL) {
2257bb1d933Spk 		if (openmode == O_RDWR) {
2267bb1d933Spk 			openmode = O_RDONLY;
227a8bdc6a1Schristos 			kvp->kd = kvm_openfiles(sys, kmemf, NULL, O_RDONLY,
2287bb1d933Spk 			    errbuf);
2297bb1d933Spk 		}
230aa0a3ef5Schristos 		if (kvp->kd == NULL)
231595db245Sdyoung 			errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
2327bb1d933Spk 		kern_readonly(GMON_PROF_ON);
23336adb5cbScgd 	}
234aa0a3ef5Schristos 	if (kvm_nlist(kvp->kd, nl) < 0)
235a8bdc6a1Schristos 		errx(EXIT_FAILURE, "%s: no namelist", sys);
236aa0a3ef5Schristos 	if (!nl[N_GMONPARAM].n_value)
237595db245Sdyoung 		errx(EXIT_FAILURE, "profiling not defined in kernel");
2387bb1d933Spk 	return (openmode);
2397bb1d933Spk }
2407bb1d933Spk 
2417bb1d933Spk /*
2427bb1d933Spk  * Suppress options that require a writable kernel.
2437bb1d933Spk  */
244aa0a3ef5Schristos static void
kern_readonly(int mode)2451ef7bd2aSperry kern_readonly(int mode)
2467bb1d933Spk {
2477bb1d933Spk 
248aa0a3ef5Schristos 	(void)fprintf(stderr, "%s: kernel read-only: ", getprogname());
2497bb1d933Spk 	if (pflag && mode == GMON_PROF_ON)
2507bb1d933Spk 		(void)fprintf(stderr, "data may be inconsistent\n");
25136adb5cbScgd 	if (rflag)
252e55a0464Smsaitoh 		(void)fprintf(stderr, "-r suppressed\n");
25336adb5cbScgd 	if (bflag)
254e55a0464Smsaitoh 		(void)fprintf(stderr, "-b suppressed\n");
25536adb5cbScgd 	if (hflag)
256e55a0464Smsaitoh 		(void)fprintf(stderr, "-h suppressed\n");
25736adb5cbScgd 	rflag = bflag = hflag = 0;
25836adb5cbScgd }
259e9d867efSmycroft 
2607bb1d933Spk /*
2617bb1d933Spk  * Get the state of kernel profiling.
2627bb1d933Spk  */
263aa0a3ef5Schristos static int
getprof(struct kvmvars * kvp,int cpuid)264*bc2926d3Sryo getprof(struct kvmvars *kvp, int cpuid)
265c78c6a22Smrg {
266*bc2926d3Sryo 	int mib[5], miblen, mibparam;
267191b5f2eScgd 	size_t size;
2687bb1d933Spk 
2697bb1d933Spk 	if (kflag) {
2707bb1d933Spk 		size = kvm_read(kvp->kd, nl[N_GMONPARAM].n_value, &kvp->gpm,
2717bb1d933Spk 		    sizeof kvp->gpm);
2727bb1d933Spk 	} else {
2737bb1d933Spk 		mib[0] = CTL_KERN;
2747bb1d933Spk 		mib[1] = KERN_PROF;
275*bc2926d3Sryo 		if (cpuid < 0) {
276*bc2926d3Sryo 			mibparam = 2;
277*bc2926d3Sryo 			miblen = 3;
278*bc2926d3Sryo 		} else {
279*bc2926d3Sryo 			mib[2] = GPROF_PERCPU;
280*bc2926d3Sryo 			mib[3] = cpuid;
281*bc2926d3Sryo 			mibparam = 4;
282*bc2926d3Sryo 			miblen = 5;
283*bc2926d3Sryo 		}
284*bc2926d3Sryo 		mib[mibparam] = GPROF_GMONPARAM;
2857bb1d933Spk 		size = sizeof kvp->gpm;
286*bc2926d3Sryo 		if (sysctl(mib, miblen, &kvp->gpm, &size, NULL, 0) < 0)
2877bb1d933Spk 			size = 0;
2887bb1d933Spk 	}
289aa0a3ef5Schristos 	if (size != sizeof kvp->gpm)
290595db245Sdyoung 		errx(EXIT_FAILURE, "cannot get gmonparam: %s",
2917bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
2927bb1d933Spk 	return (kvp->gpm.state);
2937bb1d933Spk }
2947bb1d933Spk 
2957bb1d933Spk /*
2967bb1d933Spk  * Enable or disable kernel profiling according to the state variable.
2977bb1d933Spk  */
298aa0a3ef5Schristos static void
setprof(struct kvmvars * kvp,int state,int cpuid)299*bc2926d3Sryo setprof(struct kvmvars *kvp, int state, int cpuid)
3007bb1d933Spk {
3017bb1d933Spk 	struct gmonparam *p = (struct gmonparam *)nl[N_GMONPARAM].n_value;
302*bc2926d3Sryo 	int mib[5], miblen, mibparam, oldstate;
303191b5f2eScgd 	size_t sz;
3047bb1d933Spk 
3057bb1d933Spk 	sz = sizeof(state);
3067bb1d933Spk 	if (!kflag) {
3077bb1d933Spk 		mib[0] = CTL_KERN;
3087bb1d933Spk 		mib[1] = KERN_PROF;
309*bc2926d3Sryo 		if (cpuid < 0) {
310*bc2926d3Sryo 			mibparam = 2;
311*bc2926d3Sryo 			miblen = 3;
312*bc2926d3Sryo 		} else {
313*bc2926d3Sryo 			mib[2] = GPROF_PERCPU;
314*bc2926d3Sryo 			mib[3] = cpuid;
315*bc2926d3Sryo 			mibparam = 4;
316*bc2926d3Sryo 			miblen = 5;
317*bc2926d3Sryo 		}
318*bc2926d3Sryo 		mib[mibparam] = GPROF_STATE;
319*bc2926d3Sryo 		if (sysctl(mib, miblen, &oldstate, &sz, NULL, 0) < 0)
3207bb1d933Spk 			goto bad;
3217bb1d933Spk 		if (oldstate == state)
3227bb1d933Spk 			return;
3237bb1d933Spk 		(void)seteuid(0);
324*bc2926d3Sryo 		if (sysctl(mib, miblen, NULL, NULL, &state, sz) >= 0) {
3257bb1d933Spk 			(void)seteuid(getuid());
3267bb1d933Spk 			return;
3277bb1d933Spk 		}
3287bb1d933Spk 		(void)seteuid(getuid());
329e7dd2c75Slukem 	} else if ((size_t)kvm_write(kvp->kd, (u_long)&p->state, (void *)&state, sz)
3307bb1d933Spk 	    == sz)
3317bb1d933Spk 		return;
3327bb1d933Spk bad:
333aa0a3ef5Schristos 	warnx("cannot turn profiling %s", state == GMON_PROF_OFF ?
334aa0a3ef5Schristos 	    "off" : "on");
3357bb1d933Spk }
3367bb1d933Spk 
3377bb1d933Spk /*
3387bb1d933Spk  * Build the gmon.out file.
3397bb1d933Spk  */
340aa0a3ef5Schristos static void
dumpstate(struct kvmvars * kvp,int cpuid)341*bc2926d3Sryo dumpstate(struct kvmvars *kvp, int cpuid)
3427bb1d933Spk {
3431ef7bd2aSperry 	FILE *fp;
34436adb5cbScgd 	struct rawarc rawarc;
34536adb5cbScgd 	struct tostruct *tos;
346d71f6e87Smrg 	u_long frompc;
3477bb1d933Spk 	u_short *froms, *tickbuf;
348*bc2926d3Sryo 	int mib[5], miblen, mibparam;
349191b5f2eScgd 	size_t i;
3507bb1d933Spk 	struct gmonhdr h;
3517bb1d933Spk 	int fromindex, endfrom, toindex;
352a8bdc6a1Schristos 	size_t kcountsize;
353*bc2926d3Sryo 	char gmon_out[sizeof("gmon-XXXXXXXXXXX.out")];
35436adb5cbScgd 
355*bc2926d3Sryo 	mib[0] = CTL_KERN;
356*bc2926d3Sryo 	mib[1] = KERN_PROF;
357*bc2926d3Sryo 	if (cpuid < 0) {
358*bc2926d3Sryo 		mibparam = 2;
359*bc2926d3Sryo 		miblen = 3;
360*bc2926d3Sryo 	} else {
361*bc2926d3Sryo 		mib[2] = GPROF_PERCPU;
362*bc2926d3Sryo 		mib[3] = cpuid;
363*bc2926d3Sryo 		mibparam = 4;
364*bc2926d3Sryo 		miblen = 5;
365*bc2926d3Sryo 	}
366*bc2926d3Sryo 
367*bc2926d3Sryo 	setprof(kvp, GMON_PROF_OFF, cpuid);
368*bc2926d3Sryo 	if (cpuid < 0)
369*bc2926d3Sryo 		strlcpy(gmon_out, "gmon.out", sizeof(gmon_out));
370*bc2926d3Sryo 	else
371*bc2926d3Sryo 		snprintf(gmon_out, sizeof(gmon_out), "gmon-%d.out", cpuid);
372*bc2926d3Sryo 
373*bc2926d3Sryo 	fp = fopen(gmon_out, "w");
374595db245Sdyoung 	if (fp == NULL) {
375*bc2926d3Sryo 		warn("cannot open `%s'", gmon_out);
37636adb5cbScgd 		return;
37736adb5cbScgd 	}
3787bb1d933Spk 
3797bb1d933Spk 	/*
3807bb1d933Spk 	 * Build the gmon header and write it to a file.
3817bb1d933Spk 	 */
3827bb1d933Spk 	bzero(&h, sizeof(h));
3837bb1d933Spk 	h.lpc = kvp->gpm.lowpc;
3847bb1d933Spk 	h.hpc = kvp->gpm.highpc;
3857bb1d933Spk 	h.ncnt = kvp->gpm.kcountsize + sizeof(h);
3867bb1d933Spk 	h.version = GMONVERSION;
3877bb1d933Spk 	h.profrate = getprofhz(kvp);
388a8bdc6a1Schristos 	if (fwrite(&h, sizeof(h), 1, fp) != 1)
3894329d94fSdyoung 		err(EXIT_FAILURE, "writing header to gmon.out");
3907bb1d933Spk 
391a8bdc6a1Schristos 	kcountsize = (size_t)kvp->gpm.kcountsize;
392a8bdc6a1Schristos 
3937bb1d933Spk 	/*
3947bb1d933Spk 	 * Write out the tick buffer.
3957bb1d933Spk 	 */
396a8bdc6a1Schristos 	if ((tickbuf = malloc(kcountsize)) == NULL)
397a8bdc6a1Schristos 		err(EXIT_FAILURE, "Cannot allocate %zu kcount space",
398a8bdc6a1Schristos 		    kcountsize);
3997bb1d933Spk 	if (kflag) {
400a8bdc6a1Schristos 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, tickbuf,
401a8bdc6a1Schristos 		    kcountsize);
4027bb1d933Spk 	} else {
403*bc2926d3Sryo 		mib[mibparam] = GPROF_COUNT;
404a8bdc6a1Schristos 		i = kcountsize;
405*bc2926d3Sryo 		if (sysctl(mib, miblen, tickbuf, &i, NULL, 0) < 0)
4067bb1d933Spk 			i = 0;
4077bb1d933Spk 	}
408a8bdc6a1Schristos 	if (i != kcountsize)
409a8bdc6a1Schristos 		errx(EXIT_FAILURE, "read ticks: read %zu, got %zu: %s",
410a8bdc6a1Schristos 		    kcountsize, i,
4117bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
412a8bdc6a1Schristos 	if ((fwrite(tickbuf, kcountsize, 1, fp)) != 1)
4135b001910Suebayasi 		err(EXIT_FAILURE, "writing ticks to gmon.out");
4147bb1d933Spk 	free(tickbuf);
4157bb1d933Spk 
4167bb1d933Spk 	/*
4177bb1d933Spk 	 * Write out the arc info.
4187bb1d933Spk 	 */
419a8bdc6a1Schristos 	if ((froms = malloc((size_t)kvp->gpm.fromssize)) == NULL)
420a8bdc6a1Schristos 		err(EXIT_FAILURE, "cannot allocate %zu froms space",
421a8bdc6a1Schristos 		    (size_t)kvp->gpm.fromssize);
4227bb1d933Spk 	if (kflag) {
423a8bdc6a1Schristos 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, froms,
424a8bdc6a1Schristos 		    (size_t)kvp->gpm.fromssize);
4257bb1d933Spk 	} else {
426*bc2926d3Sryo 		mib[mibparam] = GPROF_FROMS;
4277bb1d933Spk 		i = kvp->gpm.fromssize;
428*bc2926d3Sryo 		if (sysctl(mib, miblen, froms, &i, NULL, 0) < 0)
4297bb1d933Spk 			i = 0;
4307bb1d933Spk 	}
431aa0a3ef5Schristos 	if (i != kvp->gpm.fromssize)
432595db245Sdyoung 		errx(EXIT_FAILURE, "read froms: read %lu, got %lu: %s",
4337ffe3c61Senami 		    kvp->gpm.fromssize, (u_long)i,
4347bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
435a8bdc6a1Schristos 	if ((tos = malloc((size_t)kvp->gpm.tossize)) == NULL)
436a8bdc6a1Schristos 		err(EXIT_FAILURE, "cannot allocate %zu tos space",
437a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize);
4387bb1d933Spk 	if (kflag) {
4397bb1d933Spk 		i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
440a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize);
4417bb1d933Spk 	} else {
442*bc2926d3Sryo 		mib[mibparam] = GPROF_TOS;
4437bb1d933Spk 		i = kvp->gpm.tossize;
444*bc2926d3Sryo 		if (sysctl(mib, miblen, tos, &i, NULL, 0) < 0)
4457bb1d933Spk 			i = 0;
4467bb1d933Spk 	}
447aa0a3ef5Schristos 	if (i != kvp->gpm.tossize)
448a8bdc6a1Schristos 		errx(EXIT_FAILURE, "read tos: read %zu, got %zu: %s",
449a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize, i,
4507bb1d933Spk 		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
45136adb5cbScgd 	if (debug)
452aa0a3ef5Schristos 		(void)fprintf(stderr, "%s: lowpc 0x%lx, textsize 0x%lx\n",
453aa0a3ef5Schristos 		     getprogname(), kvp->gpm.lowpc, kvp->gpm.textsize);
4547bb1d933Spk 	endfrom = kvp->gpm.fromssize / sizeof(*froms);
4557bb1d933Spk 	for (fromindex = 0; fromindex < endfrom; ++fromindex) {
45636adb5cbScgd 		if (froms[fromindex] == 0)
45736adb5cbScgd 			continue;
4587bb1d933Spk 		frompc = (u_long)kvp->gpm.lowpc +
4597bb1d933Spk 		    (fromindex * kvp->gpm.hashfraction * sizeof(*froms));
46036adb5cbScgd 		for (toindex = froms[fromindex]; toindex != 0;
46136adb5cbScgd 		   toindex = tos[toindex].link) {
46236adb5cbScgd 			if (debug)
46336adb5cbScgd 			    (void)fprintf(stderr,
464d71f6e87Smrg 			    "%s: [mcleanup] frompc 0x%lx selfpc 0x%lx count %ld\n",
465aa0a3ef5Schristos 			    getprogname(), frompc, tos[toindex].selfpc,
4667bb1d933Spk 			    tos[toindex].count);
46736adb5cbScgd 			rawarc.raw_frompc = frompc;
46836adb5cbScgd 			rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
46936adb5cbScgd 			rawarc.raw_count = tos[toindex].count;
470a8bdc6a1Schristos 			if (fwrite(&rawarc, sizeof(rawarc), 1,fp) != 1){
4714329d94fSdyoung 				err(EXIT_FAILURE,
4724329d94fSdyoung 				    "writing raw arc to gmon.out");
4734329d94fSdyoung 			}
47436adb5cbScgd 		}
47536adb5cbScgd 	}
4762a8477a7Schristos 	free(tos);
477a8bdc6a1Schristos 	(void)fclose(fp);
47836adb5cbScgd }
47936adb5cbScgd 
4807bb1d933Spk /*
4817bb1d933Spk  * Get the profiling rate.
4827bb1d933Spk  */
483aa0a3ef5Schristos static int
getprofhz(struct kvmvars * kvp)4841ef7bd2aSperry getprofhz(struct kvmvars *kvp)
48536adb5cbScgd {
486191b5f2eScgd 	int mib[2], profrate;
487191b5f2eScgd 	size_t size;
4887bb1d933Spk 	struct clockinfo clockrate;
48936adb5cbScgd 
4907bb1d933Spk 	if (kflag) {
4917bb1d933Spk 		profrate = 1;
4927bb1d933Spk 		if (kvm_read(kvp->kd, nl[N_PROFHZ].n_value, &profrate,
4937bb1d933Spk 		    sizeof profrate) != sizeof profrate)
494aa0a3ef5Schristos 			warnx("get clockrate: %s", kvm_geterr(kvp->kd));
4957bb1d933Spk 		return (profrate);
49636adb5cbScgd 	}
4977bb1d933Spk 	mib[0] = CTL_KERN;
4987bb1d933Spk 	mib[1] = KERN_CLOCKRATE;
4997bb1d933Spk 	clockrate.profhz = 1;
5007bb1d933Spk 	size = sizeof clockrate;
5017bb1d933Spk 	if (sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
502aa0a3ef5Schristos 		warn("get clockrate");
5037bb1d933Spk 	return (clockrate.profhz);
50436adb5cbScgd }
50536adb5cbScgd 
5067bb1d933Spk /*
5077bb1d933Spk  * Reset the kernel profiling date structures.
5087bb1d933Spk  */
509aa0a3ef5Schristos static void
reset(struct kvmvars * kvp,int cpuid)510*bc2926d3Sryo reset(struct kvmvars *kvp, int cpuid)
51136adb5cbScgd {
5127bb1d933Spk 	char *zbuf;
513a8bdc6a1Schristos 	size_t biggest;
514*bc2926d3Sryo 	int mib[5], miblen, mibparam;
51536adb5cbScgd 
516*bc2926d3Sryo 	mib[0] = CTL_KERN;
517*bc2926d3Sryo 	mib[1] = KERN_PROF;
518*bc2926d3Sryo 	if (cpuid < 0) {
519*bc2926d3Sryo 		mibparam = 2;
520*bc2926d3Sryo 		miblen = 3;
521*bc2926d3Sryo 	} else {
522*bc2926d3Sryo 		mib[2] = GPROF_PERCPU;
523*bc2926d3Sryo 		mib[3] = cpuid;
524*bc2926d3Sryo 		mibparam = 4;
525*bc2926d3Sryo 		miblen = 5;
526*bc2926d3Sryo 	}
527*bc2926d3Sryo 
528*bc2926d3Sryo 	setprof(kvp, GMON_PROF_OFF, cpuid);
52936adb5cbScgd 
530a8bdc6a1Schristos 	biggest = (size_t)kvp->gpm.kcountsize;
531a8bdc6a1Schristos 	if ((size_t)kvp->gpm.fromssize > biggest)
532a8bdc6a1Schristos 		biggest = (size_t)kvp->gpm.fromssize;
533a8bdc6a1Schristos 	if ((size_t)kvp->gpm.tossize > biggest)
534a8bdc6a1Schristos 		biggest = (size_t)kvp->gpm.tossize;
535aa0a3ef5Schristos 	if ((zbuf = malloc(biggest)) == NULL)
536595db245Sdyoung 		err(EXIT_FAILURE, "cannot allocate zbuf space");
537a8bdc6a1Schristos 	(void)memset(zbuf, 0, biggest);
5387bb1d933Spk 	if (kflag) {
539e7dd2c75Slukem 		if ((size_t)kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
540a8bdc6a1Schristos 		    (size_t)kvp->gpm.kcountsize) != kvp->gpm.kcountsize)
541595db245Sdyoung 			errx(EXIT_FAILURE, "tickbuf zero: %s",
542595db245Sdyoung 			     kvm_geterr(kvp->kd));
543e7dd2c75Slukem 		if ((size_t)kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
544a8bdc6a1Schristos 		    (size_t)kvp->gpm.fromssize) != kvp->gpm.fromssize)
545595db245Sdyoung 			errx(EXIT_FAILURE, "froms zero: %s",
546595db245Sdyoung 			     kvm_geterr(kvp->kd));
547e7dd2c75Slukem 		if ((size_t)kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
548a8bdc6a1Schristos 		    (size_t)kvp->gpm.tossize) != kvp->gpm.tossize)
549595db245Sdyoung 			errx(EXIT_FAILURE, "tos zero: %s", kvm_geterr(kvp->kd));
550aa0a3ef5Schristos 		free(zbuf);
5517bb1d933Spk 		return;
5527bb1d933Spk 	}
5537bb1d933Spk 	(void)seteuid(0);
554*bc2926d3Sryo 	mib[mibparam] = GPROF_COUNT;
555*bc2926d3Sryo 	if (sysctl(mib, miblen, NULL, NULL, zbuf, (size_t)kvp->gpm.kcountsize) < 0)
556595db245Sdyoung 		err(EXIT_FAILURE, "tickbuf zero");
557*bc2926d3Sryo 	mib[mibparam] = GPROF_FROMS;
558*bc2926d3Sryo 	if (sysctl(mib, miblen, NULL, NULL, zbuf, (size_t)kvp->gpm.fromssize) < 0)
559595db245Sdyoung 		err(EXIT_FAILURE, "froms zero");
560*bc2926d3Sryo 	mib[mibparam] = GPROF_TOS;
561*bc2926d3Sryo 	if (sysctl(mib, miblen, NULL, NULL, zbuf, (size_t)kvp->gpm.tossize) < 0)
562595db245Sdyoung 		err(EXIT_FAILURE, "tos zero");
5637bb1d933Spk 	(void)seteuid(getuid());
5647bb1d933Spk 	free(zbuf);
56536adb5cbScgd }
566