kgmon.c revision 134505
1246149Ssjg/*
2246149Ssjg * Copyright (c) 1983, 1992, 1993
3246149Ssjg *	The Regents of the University of California.  All rights reserved.
4246149Ssjg *
5246149Ssjg * Redistribution and use in source and binary forms, with or without
6246149Ssjg * modification, are permitted provided that the following conditions
7246149Ssjg * are met:
8246149Ssjg * 1. Redistributions of source code must retain the above copyright
9246149Ssjg *    notice, this list of conditions and the following disclaimer.
10246149Ssjg * 2. Redistributions in binary form must reproduce the above copyright
11246149Ssjg *    notice, this list of conditions and the following disclaimer in the
12246149Ssjg *    documentation and/or other materials provided with the distribution.
13246149Ssjg * 4. Neither the name of the University nor the names of its contributors
14246149Ssjg *    may be used to endorse or promote products derived from this software
15246149Ssjg *    without specific prior written permission.
16246149Ssjg *
17246149Ssjg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18246149Ssjg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19246149Ssjg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20246149Ssjg * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21246149Ssjg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22246149Ssjg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23246149Ssjg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24246149Ssjg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25246149Ssjg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26246149Ssjg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27246149Ssjg * SUCH DAMAGE.
28246149Ssjg */
29246149Ssjg
30246149Ssjg#ifndef lint
31246149Ssjgstatic const char copyright[] =
32246149Ssjg"@(#) Copyright (c) 1983, 1992, 1993\n\
33246149Ssjg	The Regents of the University of California.  All rights reserved.\n";
34246149Ssjg#endif /* not lint */
35246149Ssjg
36246149Ssjg#ifndef lint
37246149Ssjg#if 0
38253883Ssjgstatic char sccsid[] = "@(#)kgmon.c	8.1 (Berkeley) 6/6/93";
39246149Ssjg#endif
40249033Ssjgstatic const char rcsid[] =
41249033Ssjg  "$FreeBSD: head/usr.sbin/kgmon/kgmon.c 134505 2004-08-30 03:11:46Z marcel $";
42246149Ssjg#endif /* not lint */
43246149Ssjg
44246149Ssjg#include <sys/param.h>
45246149Ssjg#include <sys/file.h>
46246149Ssjg#include <sys/time.h>
47246149Ssjg#include <sys/sysctl.h>
48246149Ssjg#include <sys/gmon.h>
49246149Ssjg#include <ctype.h>
50246149Ssjg#include <err.h>
51246149Ssjg#include <errno.h>
52246149Ssjg#include <kvm.h>
53246149Ssjg#include <limits.h>
54246149Ssjg#include <nlist.h>
55246149Ssjg#include <paths.h>
56246149Ssjg#include <stddef.h>
57246149Ssjg#include <stdio.h>
58246149Ssjg#include <stdlib.h>
59246149Ssjg#include <string.h>
60246149Ssjg#include <unistd.h>
61246149Ssjg
62246149Ssjgstruct nlist nl[] = {
63246149Ssjg#define	N_GMONPARAM	0
64246149Ssjg	{ "__gmonparam" },
65246149Ssjg#define	N_PROFHZ	1
66246149Ssjg	{ "_profhz" },
67246149Ssjg	{ NULL },
68246149Ssjg};
69246149Ssjg
70246149Ssjgstruct kvmvars {
71246149Ssjg	kvm_t	*kd;
72246149Ssjg	struct gmonparam gpm;
73246149Ssjg};
74246149Ssjg
75246149Ssjgint	Bflag, bflag, hflag, kflag, rflag, pflag;
76246149Ssjgint	debug = 0;
77246149Ssjgint	getprof(struct kvmvars *);
78246149Ssjgint	getprofhz(struct kvmvars *);
79246149Ssjgvoid	kern_readonly(int);
80253883Ssjgint	openfiles(char *, char *, struct kvmvars *);
81246149Ssjgvoid	setprof(struct kvmvars *kvp, int state);
82246149Ssjgvoid	dumpstate(struct kvmvars *kvp);
83246149Ssjgvoid	reset(struct kvmvars *kvp);
84246149Ssjgstatic void usage(void);
85246149Ssjg
86246149Ssjgint
87246149Ssjgmain(int argc, char **argv)
88246149Ssjg{
89246149Ssjg	int ch, mode, disp, accessmode;
90246149Ssjg	struct kvmvars kvmvars;
91246149Ssjg	char *system, *kmemf;
92246149Ssjg
93246149Ssjg	seteuid(getuid());
94246149Ssjg	kmemf = NULL;
95246149Ssjg	system = NULL;
96246149Ssjg	while ((ch = getopt(argc, argv, "M:N:Bbhpr")) != -1) {
97246149Ssjg		switch((char)ch) {
98246149Ssjg
99246149Ssjg		case 'M':
100246149Ssjg			kmemf = optarg;
101246149Ssjg			kflag = 1;
102246149Ssjg			break;
103246149Ssjg
104246149Ssjg		case 'N':
105246149Ssjg			system = optarg;
106246149Ssjg			break;
107246149Ssjg
108246149Ssjg		case 'B':
109246149Ssjg			Bflag = 1;
110253883Ssjg			break;
111253883Ssjg
112253883Ssjg		case 'b':
113253883Ssjg			bflag = 1;
114253883Ssjg			break;
115253883Ssjg
116246149Ssjg		case 'h':
117246149Ssjg			hflag = 1;
118246149Ssjg			break;
119246149Ssjg
120246149Ssjg		case 'p':
121246149Ssjg			pflag = 1;
122246149Ssjg			break;
123246149Ssjg
124246149Ssjg		case 'r':
125246149Ssjg			rflag = 1;
126246149Ssjg			break;
127246149Ssjg
128246149Ssjg		default:
129250837Ssjg			usage();
130250837Ssjg		}
131250837Ssjg	}
132250837Ssjg	argc -= optind;
133250837Ssjg	argv += optind;
134250837Ssjg
135246149Ssjg#define BACKWARD_COMPATIBILITY
136246149Ssjg#ifdef	BACKWARD_COMPATIBILITY
137246149Ssjg	if (*argv) {
138246149Ssjg		system = *argv;
139246149Ssjg		if (*++argv) {
140246149Ssjg			kmemf = *argv;
141246149Ssjg			++kflag;
142246149Ssjg		}
143246149Ssjg	}
144246149Ssjg#endif
145246149Ssjg	if (system == NULL)
146246149Ssjg		system = (char *)getbootfile();
147246149Ssjg	accessmode = openfiles(system, kmemf, &kvmvars);
148246149Ssjg	mode = getprof(&kvmvars);
149246149Ssjg	if (hflag)
150246149Ssjg		disp = GMON_PROF_OFF;
151246149Ssjg	else if (Bflag)
152246149Ssjg		disp = GMON_PROF_HIRES;
153246149Ssjg	else if (bflag)
154246149Ssjg		disp = GMON_PROF_ON;
155246149Ssjg	else
156246149Ssjg		disp = mode;
157246149Ssjg	if (pflag)
158246149Ssjg		dumpstate(&kvmvars);
159246149Ssjg	if (rflag)
160246149Ssjg		reset(&kvmvars);
161249033Ssjg	if (accessmode == O_RDWR)
162246149Ssjg		setprof(&kvmvars, disp);
163250837Ssjg	(void)fprintf(stdout, "kgmon: kernel profiling is %s.\n",
164250837Ssjg		      disp == GMON_PROF_OFF ? "off" :
165250837Ssjg		      disp == GMON_PROF_HIRES ? "running (high resolution)" :
166246149Ssjg		      disp == GMON_PROF_ON ? "running" :
167246149Ssjg		      disp == GMON_PROF_BUSY ? "busy" :
168246149Ssjg		      disp == GMON_PROF_ERROR ? "off (error)" :
169246149Ssjg		      "in an unknown state");
170246149Ssjg	return (0);
171246149Ssjg}
172246149Ssjg
173246149Ssjgstatic void
174246149Ssjgusage()
175246149Ssjg{
176246149Ssjg	fprintf(stderr, "usage: kgmon [-Bbhrp] [-M core] [-N system]\n");
177246149Ssjg	exit(1);
178246149Ssjg}
179246149Ssjg
180246149Ssjg/*
181246149Ssjg * Check that profiling is enabled and open any ncessary files.
182246149Ssjg */
183246149Ssjgint
184246149Ssjgopenfiles(system, kmemf, kvp)
185246149Ssjg	char *system;
186246149Ssjg	char *kmemf;
187246149Ssjg	struct kvmvars *kvp;
188246149Ssjg{
189246149Ssjg	size_t size;
190249033Ssjg	int mib[3], state, openmode;
191250837Ssjg	char errbuf[_POSIX2_LINE_MAX];
192250837Ssjg
193249033Ssjg	if (!kflag) {
194249033Ssjg		mib[0] = CTL_KERN;
195249033Ssjg		mib[1] = KERN_PROF;
196253883Ssjg		mib[2] = GPROF_STATE;
197249033Ssjg		size = sizeof state;
198246149Ssjg		if (sysctl(mib, 3, &state, &size, NULL, 0) < 0)
199246149Ssjg			errx(20, "profiling not defined in kernel");
200246149Ssjg		if (!(Bflag || bflag || hflag || rflag ||
201246149Ssjg		    (pflag &&
202246149Ssjg		     (state == GMON_PROF_HIRES || state == GMON_PROF_ON))))
203246149Ssjg			return (O_RDONLY);
204246149Ssjg		(void)seteuid(0);
205246149Ssjg		if (sysctl(mib, 3, NULL, NULL, &state, size) >= 0)
206246149Ssjg			return (O_RDWR);
207246149Ssjg		(void)seteuid(getuid());
208246149Ssjg		kern_readonly(state);
209246149Ssjg		return (O_RDONLY);
210246149Ssjg	}
211246149Ssjg	openmode = (Bflag || bflag || hflag || pflag || rflag)
212246149Ssjg		   ? O_RDWR : O_RDONLY;
213250837Ssjg	kvp->kd = kvm_openfiles(system, kmemf, NULL, openmode, errbuf);
214249033Ssjg	if (kvp->kd == NULL) {
215250837Ssjg		if (openmode == O_RDWR) {
216250837Ssjg			openmode = O_RDONLY;
217250837Ssjg			kvp->kd = kvm_openfiles(system, kmemf, NULL, O_RDONLY,
218249033Ssjg			    errbuf);
219246149Ssjg		}
220249033Ssjg		if (kvp->kd == NULL)
221249033Ssjg			errx(2, "kvm_openfiles: %s", errbuf);
222249033Ssjg		kern_readonly(GMON_PROF_ON);
223249033Ssjg	}
224249033Ssjg	if (kvm_nlist(kvp->kd, nl) < 0)
225249033Ssjg		errx(3, "%s: no namelist", system);
226246149Ssjg	if (!nl[N_GMONPARAM].n_value)
227246149Ssjg		errx(20, "profiling not defined in kernel");
228246149Ssjg	return (openmode);
229246149Ssjg}
230246149Ssjg
231246149Ssjg/*
232246149Ssjg * Suppress options that require a writable kernel.
233246149Ssjg */
234249033Ssjgvoid
235249033Ssjgkern_readonly(mode)
236249033Ssjg	int mode;
237249033Ssjg{
238246149Ssjg
239246149Ssjg	(void)fprintf(stderr, "kgmon: kernel read-only: ");
240246149Ssjg	if (pflag && (mode == GMON_PROF_HIRES || mode == GMON_PROF_ON))
241246149Ssjg		(void)fprintf(stderr, "data may be inconsistent\n");
242246149Ssjg	if (rflag)
243246149Ssjg		(void)fprintf(stderr, "-r supressed\n");
244246149Ssjg	if (Bflag)
245246149Ssjg		(void)fprintf(stderr, "-B supressed\n");
246246149Ssjg	if (bflag)
247246149Ssjg		(void)fprintf(stderr, "-b supressed\n");
248246149Ssjg	if (hflag)
249246149Ssjg		(void)fprintf(stderr, "-h supressed\n");
250246149Ssjg	rflag = Bflag = bflag = hflag = 0;
251246149Ssjg}
252246149Ssjg
253246149Ssjg/*
254246149Ssjg * Get the state of kernel profiling.
255246149Ssjg */
256246149Ssjgint
257249033Ssjggetprof(kvp)
258249033Ssjg	struct kvmvars *kvp;
259246149Ssjg{
260253883Ssjg	size_t size;
261246149Ssjg	int mib[3];
262246149Ssjg
263246149Ssjg	if (kflag) {
264246149Ssjg		size = kvm_read(kvp->kd, nl[N_GMONPARAM].n_value, &kvp->gpm,
265246149Ssjg		    sizeof kvp->gpm);
266246149Ssjg	} else {
267246149Ssjg		mib[0] = CTL_KERN;
268246149Ssjg		mib[1] = KERN_PROF;
269246149Ssjg		mib[2] = GPROF_GMONPARAM;
270246149Ssjg		size = sizeof kvp->gpm;
271246149Ssjg		if (sysctl(mib, 3, &kvp->gpm, &size, NULL, 0) < 0)
272246149Ssjg			size = 0;
273246149Ssjg	}
274246149Ssjg
275246149Ssjg	/*
276246149Ssjg	 * Accept certain undersized "structs" from old kernels.  We need
277246149Ssjg	 * everything up to hashfraction, and want profrate and
278246149Ssjg	 * histcounter_type.  Assume that the kernel doesn't put garbage
279246149Ssjg	 * in any padding that is returned instead of profrate and
280246149Ssjg	 * histcounter_type.  This is a bad assumption for dead kernels,
281246149Ssjg	 * since kvm_read() will normally return garbage for bytes beyond
282246149Ssjg	 * the end of the actual kernel struct, if any.
283246149Ssjg	 */
284246149Ssjg	if (size < offsetof(struct gmonparam, hashfraction) +
285246149Ssjg	    sizeof(kvp->gpm.hashfraction) || size > sizeof(kvp->gpm))
286246149Ssjg		errx(4, "cannot get gmonparam: %s",
287246149Ssjg		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
288246149Ssjg	bzero((char *)&kvp->gpm + size, sizeof(kvp->gpm) - size);
289246149Ssjg	if (kvp->gpm.profrate == 0)
290246149Ssjg		kvp->gpm.profrate = getprofhz(kvp);
291246149Ssjg#ifdef __i386__
292246149Ssjg	if (kvp->gpm.histcounter_type == 0) {
293246149Ssjg		/*
294246149Ssjg		 * This fixup only works for not-so-old i386 kernels.  The
295246149Ssjg		 * magic 16 is the kernel FUNCTION_ALIGNMENT.  64-bit
296246149Ssjg		 * counters are signed; smaller counters are unsigned.
297246149Ssjg		 */
298246149Ssjg		kvp->gpm.histcounter_type = 16 /
299246149Ssjg		    (kvp->gpm.textsize / kvp->gpm.kcountsize) * CHAR_BIT;
300246149Ssjg		if (kvp->gpm.histcounter_type == 64)
301246149Ssjg			kvp->gpm.histcounter_type = -64;
302246149Ssjg	}
303246149Ssjg#endif
304246149Ssjg
305246149Ssjg	return (kvp->gpm.state);
306246149Ssjg}
307246149Ssjg
308246149Ssjg/*
309246149Ssjg * Enable or disable kernel profiling according to the state variable.
310246149Ssjg */
311246149Ssjgvoid
312246149Ssjgsetprof(kvp, state)
313246149Ssjg	struct kvmvars *kvp;
314246149Ssjg	int state;
315250837Ssjg{
316250837Ssjg	struct gmonparam *p = (struct gmonparam *)nl[N_GMONPARAM].n_value;
317246149Ssjg	size_t sz;
318246149Ssjg	int mib[3], oldstate;
319246149Ssjg
320246149Ssjg	sz = sizeof(state);
321246149Ssjg	if (!kflag) {
322246149Ssjg		mib[0] = CTL_KERN;
323246149Ssjg		mib[1] = KERN_PROF;
324246149Ssjg		mib[2] = GPROF_STATE;
325246149Ssjg		if (sysctl(mib, 3, &oldstate, &sz, NULL, 0) < 0)
326246149Ssjg			goto bad;
327246149Ssjg		if (oldstate == state)
328246149Ssjg			return;
329246149Ssjg		(void)seteuid(0);
330246149Ssjg		if (sysctl(mib, 3, NULL, NULL, &state, sz) >= 0) {
331246149Ssjg			(void)seteuid(getuid());
332246149Ssjg			return;
333246149Ssjg		}
334246149Ssjg		(void)seteuid(getuid());
335246149Ssjg	} else if (kvm_write(kvp->kd, (u_long)&p->state, (void *)&state, sz)
336246149Ssjg	    == sz)
337246149Ssjg		return;
338246149Ssjgbad:
339253883Ssjg	warnx("warning: cannot turn profiling %s",
340253883Ssjg	    state == GMON_PROF_OFF ? "off" : "on");
341253883Ssjg}
342253883Ssjg
343253883Ssjg/*
344253883Ssjg * Build the gmon.out file.
345253883Ssjg */
346253883Ssjgvoid
347253883Ssjgdumpstate(kvp)
348246149Ssjg	struct kvmvars *kvp;
349246149Ssjg{
350246149Ssjg	register FILE *fp;
351246149Ssjg	struct rawarc rawarc;
352246149Ssjg	struct tostruct *tos;
353246149Ssjg	u_long frompc;
354246149Ssjg	u_short *froms, *tickbuf;
355246149Ssjg	size_t i;
356246149Ssjg	int mib[3];
357246149Ssjg	struct gmonhdr h;
358246149Ssjg	int fromindex, endfrom, toindex;
359246149Ssjg
360246149Ssjg	setprof(kvp, GMON_PROF_OFF);
361246149Ssjg	fp = fopen("gmon.out", "w");
362246149Ssjg	if (fp == 0) {
363246149Ssjg		warn("gmon.out");
364246149Ssjg		return;
365246149Ssjg	}
366246149Ssjg
367246149Ssjg	/*
368246149Ssjg	 * Build the gmon header and write it to a file.
369246149Ssjg	 */
370246149Ssjg	bzero(&h, sizeof(h));
371246149Ssjg	h.lpc = kvp->gpm.lowpc;
372246149Ssjg	h.hpc = kvp->gpm.highpc;
373246149Ssjg	h.ncnt = kvp->gpm.kcountsize + sizeof(h);
374246149Ssjg	h.version = GMONVERSION;
375246149Ssjg	h.profrate = kvp->gpm.profrate;
376246149Ssjg	h.histcounter_type = kvp->gpm.histcounter_type;
377246149Ssjg	fwrite((char *)&h, sizeof(h), 1, fp);
378246149Ssjg
379246149Ssjg	/*
380246149Ssjg	 * Write out the tick buffer.
381246149Ssjg	 */
382246149Ssjg	mib[0] = CTL_KERN;
383246149Ssjg	mib[1] = KERN_PROF;
384246149Ssjg	if ((tickbuf = (u_short *)malloc(kvp->gpm.kcountsize)) == NULL)
385246149Ssjg		errx(5, "cannot allocate kcount space");
386246149Ssjg	if (kflag) {
387246149Ssjg		i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, (void *)tickbuf,
388253883Ssjg		    kvp->gpm.kcountsize);
389246149Ssjg	} else {
390246149Ssjg		mib[2] = GPROF_COUNT;
391246149Ssjg		i = kvp->gpm.kcountsize;
392246149Ssjg		if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0)
393246149Ssjg			i = 0;
394253883Ssjg	}
395246149Ssjg	if (i != kvp->gpm.kcountsize)
396246149Ssjg		errx(6, "read ticks: read %lu, got %ld: %s",
397246149Ssjg		    kvp->gpm.kcountsize, (long)i,
398246149Ssjg		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
399246149Ssjg	if ((fwrite(tickbuf, kvp->gpm.kcountsize, 1, fp)) != 1)
400246149Ssjg		err(7, "writing tocks to gmon.out");
401246149Ssjg	free(tickbuf);
402246149Ssjg
403246149Ssjg	/*
404246149Ssjg	 * Write out the arc info.
405246149Ssjg	 */
406246149Ssjg	if ((froms = (u_short *)malloc(kvp->gpm.fromssize)) == NULL)
407246149Ssjg		errx(8, "cannot allocate froms space");
408246149Ssjg	if (kflag) {
409246149Ssjg		i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, (void *)froms,
410246149Ssjg		    kvp->gpm.fromssize);
411246149Ssjg	} else {
412246149Ssjg		mib[2] = GPROF_FROMS;
413246149Ssjg		i = kvp->gpm.fromssize;
414246149Ssjg		if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
415246149Ssjg			i = 0;
416246149Ssjg	}
417246149Ssjg	if (i != kvp->gpm.fromssize)
418246149Ssjg		errx(9, "read froms: read %lu, got %ld: %s",
419246149Ssjg		    kvp->gpm.fromssize, (long)i,
420246149Ssjg		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
421246149Ssjg	if ((tos = (struct tostruct *)malloc(kvp->gpm.tossize)) == NULL)
422246149Ssjg		errx(10, "cannot allocate tos space");
423246149Ssjg	if (kflag) {
424246149Ssjg		i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
425246149Ssjg		    kvp->gpm.tossize);
426246149Ssjg	} else {
427246149Ssjg		mib[2] = GPROF_TOS;
428246149Ssjg		i = kvp->gpm.tossize;
429246149Ssjg		if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
430246149Ssjg			i = 0;
431246149Ssjg	}
432246149Ssjg	if (i != kvp->gpm.tossize)
433246149Ssjg		errx(11, "read tos: read %lu, got %ld: %s",
434246149Ssjg		    kvp->gpm.tossize, (long)i,
435246149Ssjg		    kflag ? kvm_geterr(kvp->kd) : strerror(errno));
436246149Ssjg	if (debug)
437246149Ssjg		warnx("lowpc 0x%lx, textsize 0x%lx",
438246149Ssjg		    (unsigned long)kvp->gpm.lowpc, kvp->gpm.textsize);
439246149Ssjg	endfrom = kvp->gpm.fromssize / sizeof(*froms);
440246149Ssjg	for (fromindex = 0; fromindex < endfrom; ++fromindex) {
441246149Ssjg		if (froms[fromindex] == 0)
442246149Ssjg			continue;
443246149Ssjg		frompc = (u_long)kvp->gpm.lowpc +
444246149Ssjg		    (fromindex * kvp->gpm.hashfraction * sizeof(*froms));
445246149Ssjg		for (toindex = froms[fromindex]; toindex != 0;
446246149Ssjg		     toindex = tos[toindex].link) {
447246149Ssjg			if (debug)
448246149Ssjg				warnx("[mcleanup] frompc 0x%lx selfpc 0x%lx "
449246149Ssjg				    "count %ld", frompc, tos[toindex].selfpc,
450246149Ssjg				    tos[toindex].count);
451246149Ssjg			rawarc.raw_frompc = frompc;
452246149Ssjg			rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
453246149Ssjg			rawarc.raw_count = tos[toindex].count;
454246149Ssjg			fwrite((char *)&rawarc, sizeof(rawarc), 1, fp);
455246149Ssjg		}
456246149Ssjg	}
457246149Ssjg	fclose(fp);
458246149Ssjg}
459246149Ssjg
460246149Ssjg/*
461246149Ssjg * Get the profiling rate.
462246149Ssjg */
463246149Ssjgint
464246149Ssjggetprofhz(kvp)
465246149Ssjg	struct kvmvars *kvp;
466246149Ssjg{
467246149Ssjg	size_t size;
468246149Ssjg	int mib[2], profrate;
469246149Ssjg	struct clockinfo clockrate;
470246149Ssjg
471246149Ssjg	if (kflag) {
472246149Ssjg		profrate = 1;
473246149Ssjg		if (kvm_read(kvp->kd, nl[N_PROFHZ].n_value, &profrate,
474246149Ssjg		    sizeof profrate) != sizeof profrate)
475246149Ssjg			warnx("get clockrate: %s", kvm_geterr(kvp->kd));
476246149Ssjg		return (profrate);
477246149Ssjg	}
478246149Ssjg	mib[0] = CTL_KERN;
479246149Ssjg	mib[1] = KERN_CLOCKRATE;
480246149Ssjg	clockrate.profhz = 1;
481246149Ssjg	size = sizeof clockrate;
482246149Ssjg	if (sysctl(mib, 2, &clockrate, &size, NULL, 0) < 0)
483246149Ssjg		warn("get clockrate");
484246149Ssjg	return (clockrate.profhz);
485246149Ssjg}
486246149Ssjg
487246149Ssjg/*
488246149Ssjg * Reset the kernel profiling date structures.
489246149Ssjg */
490246149Ssjgvoid
491246149Ssjgreset(kvp)
492246149Ssjg	struct kvmvars *kvp;
493246149Ssjg{
494246149Ssjg	char *zbuf;
495246149Ssjg	u_long biggest;
496246149Ssjg	int mib[3];
497246149Ssjg
498246149Ssjg	setprof(kvp, GMON_PROF_OFF);
499246149Ssjg
500246149Ssjg	biggest = kvp->gpm.kcountsize;
501246149Ssjg	if (kvp->gpm.fromssize > biggest)
502246149Ssjg		biggest = kvp->gpm.fromssize;
503246149Ssjg	if (kvp->gpm.tossize > biggest)
504246149Ssjg		biggest = kvp->gpm.tossize;
505246149Ssjg	if ((zbuf = (char *)malloc(biggest)) == NULL)
506246149Ssjg		errx(12, "cannot allocate zbuf space");
507246149Ssjg	bzero(zbuf, biggest);
508246149Ssjg	if (kflag) {
509246149Ssjg		if (kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
510246149Ssjg		    kvp->gpm.kcountsize) != kvp->gpm.kcountsize)
511246149Ssjg			errx(13, "tickbuf zero: %s", kvm_geterr(kvp->kd));
512246149Ssjg		if (kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
513246149Ssjg		    kvp->gpm.fromssize) != kvp->gpm.fromssize)
514246149Ssjg			errx(14, "froms zero: %s", kvm_geterr(kvp->kd));
515246149Ssjg		if (kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
516246149Ssjg		    kvp->gpm.tossize) != kvp->gpm.tossize)
517246149Ssjg			errx(15, "tos zero: %s", kvm_geterr(kvp->kd));
518246149Ssjg		return;
519246149Ssjg	}
520246149Ssjg	(void)seteuid(0);
521246149Ssjg	mib[0] = CTL_KERN;
522246149Ssjg	mib[1] = KERN_PROF;
523246149Ssjg	mib[2] = GPROF_COUNT;
524246149Ssjg	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.kcountsize) < 0)
525246149Ssjg		err(13, "tickbuf zero");
526246149Ssjg	mib[2] = GPROF_FROMS;
527246149Ssjg	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.fromssize) < 0)
528246149Ssjg		err(14, "froms zero");
529246149Ssjg	mib[2] = GPROF_TOS;
530246149Ssjg	if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.tossize) < 0)
531246149Ssjg		err(15, "tos zero");
532246149Ssjg	(void)seteuid(getuid());
533246149Ssjg	free(zbuf);
534246149Ssjg}
535246149Ssjg