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