one more try (nroff -mandoc, *sigh*)
[unix-history] / usr / src / usr.sbin / kgmon / kgmon.c
CommitLineData
528b0614 1/*
c82fa61b
KB
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
32ce521f 5 * %sccs.include.redist.c%
528b0614
DF
6 */
7
8#ifndef lint
9char copyright[] =
c82fa61b 10"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
528b0614 11 All rights reserved.\n";
4d32c205 12#endif /* not lint */
528b0614 13
d841a9ba 14#ifndef lint
32ce521f 15static char sccsid[] = "@(#)kgmon.c 5.10 (Berkeley) %G%";
4d32c205 16#endif /* not lint */
d841a9ba 17
01538592 18#include <machine/pte.h>
306e368d
KB
19
20#include <sys/param.h>
769cbf71 21#include <sys/file.h>
fa7eedc6 22#include <sys/vm.h>
306e368d 23#include <sys/gprof.h>
d841a9ba
KM
24#include <stdio.h>
25#include <nlist.h>
26#include <ctype.h>
7abf8d65 27#include <paths.h>
d841a9ba
KM
28
29#define PROFILING_ON 0
4d32c205 30#define PROFILING_OFF 3
d841a9ba 31
d841a9ba 32u_long s_textsize;
4d32c205 33off_t sbuf, klseek(), lseek();
d841a9ba 34int ssiz;
d841a9ba
KM
35
36struct nlist nl[] = {
37#define N_SYSMAP 0
38 { "_Sysmap" },
39#define N_SYSSIZE 1
40 { "_Syssize" },
41#define N_FROMS 2
42 { "_froms" },
43#define N_PROFILING 3
44 { "_profiling" },
45#define N_S_LOWPC 4
46 { "_s_lowpc" },
47#define N_S_TEXTSIZE 5
48 { "_s_textsize" },
49#define N_SBUF 6
50 { "_sbuf" },
51#define N_SSIZ 7
52 { "_ssiz" },
53#define N_TOS 8
54 { "_tos" },
55 0,
56};
57
58struct pte *Sysmap;
59
d841a9ba 60int kmem;
ecc6febd 61int bflag, hflag, kflag, rflag, pflag;
78e8943b 62int debug = 0;
d841a9ba
KM
63
64main(argc, argv)
65 int argc;
51eb5aa7 66 char **argv;
d841a9ba 67{
4d32c205
KB
68 extern char *optarg;
69 extern int optind;
70 int ch, mode, disp, openmode;
71 char *system, *kmemf, *malloc();
d841a9ba 72
4d32c205
KB
73 while ((ch = getopt(argc, argv, "bhpr")) != EOF)
74 switch((char)ch) {
78e8943b
KM
75 case 'b':
76 bflag++;
77 break;
78 case 'h':
79 hflag++;
78e8943b 80 break;
ecc6febd
KM
81 case 'p':
82 pflag++;
4d32c205
KB
83 break;
84 case 'r':
85 rflag++;
78e8943b
KM
86 break;
87 default:
306e368d
KB
88 (void)fprintf(stderr,
89 "usage: kgmon [-bhrp] [system [core]]\n");
78e8943b
KM
90 exit(1);
91 }
51eb5aa7
KB
92 argc -= optind;
93 argv += optind;
4d32c205 94
306e368d 95 kmemf = _PATH_KMEM;
51eb5aa7 96 if (*argv) {
d841a9ba 97 system = *argv;
51eb5aa7 98 if (*++argv) {
4d32c205 99 kmemf = *argv;
51eb5aa7 100 ++kflag;
4d32c205 101 }
d841a9ba 102 }
4d32c205 103 else
306e368d 104 system = _PATH_UNIX;
4d32c205
KB
105
106 if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
306e368d 107 (void)fprintf(stderr, "kgmon: %s: no namelist\n", system);
01538592 108 exit(2);
d841a9ba 109 }
4d32c205 110 if (!nl[N_PROFILING].n_value) {
306e368d
KB
111 (void)fprintf(stderr,
112 "kgmon: profiling: not defined in kernel.\n");
4d32c205 113 exit(10);
d841a9ba 114 }
51eb5aa7
KB
115
116 openmode = (bflag || hflag || pflag || rflag) ? O_RDWR : O_RDONLY;
ecc6febd 117 kmem = open(kmemf, openmode);
d841a9ba 118 if (kmem < 0) {
769cbf71 119 openmode = O_RDONLY;
ecc6febd 120 kmem = open(kmemf, openmode);
d841a9ba 121 if (kmem < 0) {
d841a9ba 122 perror(kmemf);
01538592 123 exit(3);
d841a9ba 124 }
306e368d 125 (void)fprintf(stderr, "%s opened read-only\n", kmemf);
78e8943b 126 if (rflag)
306e368d 127 (void)fprintf(stderr, "-r supressed\n");
78e8943b 128 if (bflag)
306e368d 129 (void)fprintf(stderr, "-b supressed\n");
78e8943b 130 if (hflag)
306e368d 131 (void)fprintf(stderr, "-h supressed\n");
4d32c205 132 rflag = bflag = hflag = 0;
d841a9ba 133 }
78e8943b 134 if (kflag) {
d841a9ba
KM
135 off_t off;
136
4d32c205
KB
137 Sysmap = (struct pte *)
138 malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
139 if (!Sysmap) {
306e368d
KB
140 (void)fprintf(stderr,
141 "kgmon: can't get memory for Sysmap.\n");
4d32c205 142 exit(1);
d841a9ba 143 }
4d32c205
KB
144 off = nl[N_SYSMAP].n_value & ~KERNBASE;
145 (void)lseek(kmem, off, L_SET);
146 (void)read(kmem, (char *)Sysmap,
147 (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
d841a9ba 148 }
79ec4952 149 mode = kfetch(N_PROFILING);
78e8943b
KM
150 if (hflag)
151 disp = PROFILING_OFF;
152 else if (bflag)
153 disp = PROFILING_ON;
154 else
79ec4952 155 disp = mode;
ecc6febd 156 if (pflag) {
769cbf71 157 if (openmode == O_RDONLY && mode == PROFILING_ON)
306e368d 158 (void)fprintf(stderr, "data may be inconsistent\n");
78e8943b 159 dumpstate();
79ec4952 160 }
78e8943b
KM
161 if (rflag)
162 resetstate();
163 turnonoff(disp);
306e368d
KB
164 (void)fprintf(stdout,
165 "kernel profiling is %s.\n", disp ? "off" : "running");
78e8943b
KM
166}
167
168dumpstate()
169{
306e368d 170 extern int errno;
78e8943b 171 struct rawarc rawarc;
4d32c205
KB
172 struct tostruct *tos;
173 u_long frompc;
174 off_t kfroms, ktos;
175 u_short *froms; /* froms is a bunch of u_shorts indexing tos */
176 int i, fd, fromindex, endfrom, fromssize, tossize, toindex;
306e368d 177 char buf[BUFSIZ], *s_lowpc, *malloc(), *strerror();
78e8943b 178
d841a9ba
KM
179 turnonoff(PROFILING_OFF);
180 fd = creat("gmon.out", 0666);
181 if (fd < 0) {
182 perror("gmon.out");
183 return;
184 }
185 ssiz = kfetch(N_SSIZ);
186 sbuf = kfetch(N_SBUF);
4d32c205 187 (void)klseek(kmem, (off_t)sbuf, L_SET);
d841a9ba
KM
188 for (i = ssiz; i > 0; i -= BUFSIZ) {
189 read(kmem, buf, i < BUFSIZ ? i : BUFSIZ);
190 write(fd, buf, i < BUFSIZ ? i : BUFSIZ);
191 }
192 s_textsize = kfetch(N_S_TEXTSIZE);
78e8943b 193 fromssize = s_textsize / HASHFRACTION;
4d32c205 194 froms = (u_short *)malloc((u_int)fromssize);
d841a9ba 195 kfroms = kfetch(N_FROMS);
4d32c205 196 (void)klseek(kmem, kfroms, L_SET);
78e8943b
KM
197 i = read(kmem, ((char *)(froms)), fromssize);
198 if (i != fromssize) {
306e368d
KB
199 (void)fprintf(stderr, "read kmem: request %d, got %d: %s",
200 fromssize, i, strerror(errno));
78e8943b 201 exit(5);
d841a9ba 202 }
78e8943b 203 tossize = (s_textsize * ARCDENSITY / 100) * sizeof(struct tostruct);
4d32c205 204 tos = (struct tostruct *)malloc((u_int)tossize);
d841a9ba 205 ktos = kfetch(N_TOS);
4d32c205 206 (void)klseek(kmem, ktos, L_SET);
78e8943b
KM
207 i = read(kmem, ((char *)(tos)), tossize);
208 if (i != tossize) {
306e368d
KB
209 (void)fprintf(stderr, "read kmem: request %d, got %d: %s",
210 tossize, i, strerror(errno));
78e8943b 211 exit(6);
d841a9ba
KM
212 }
213 s_lowpc = (char *)kfetch(N_S_LOWPC);
214 if (debug)
306e368d 215 (void)fprintf(stderr, "s_lowpc 0x%x, s_textsize 0x%x\n",
d841a9ba 216 s_lowpc, s_textsize);
78e8943b
KM
217 endfrom = fromssize / sizeof(*froms);
218 for (fromindex = 0; fromindex < endfrom; fromindex++) {
d841a9ba
KM
219 if (froms[fromindex] == 0)
220 continue;
78e8943b
KM
221 frompc = (u_long)s_lowpc +
222 (fromindex * HASHFRACTION * sizeof(*froms));
d841a9ba
KM
223 for (toindex = froms[fromindex]; toindex != 0;
224 toindex = tos[toindex].link) {
225 if (debug)
306e368d 226 (void)fprintf(stderr,
d841a9ba
KM
227 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
228 frompc, tos[toindex].selfpc, tos[toindex].count);
229 rawarc.raw_frompc = frompc;
230 rawarc.raw_selfpc = (u_long)tos[toindex].selfpc;
231 rawarc.raw_count = tos[toindex].count;
4d32c205 232 write(fd, (char *)&rawarc, sizeof (rawarc));
d841a9ba
KM
233 }
234 }
235 close(fd);
78e8943b
KM
236}
237
238resetstate()
239{
78e8943b 240 off_t kfroms, ktos;
4d32c205 241 int i, fromssize, tossize;
78e8943b
KM
242 char buf[BUFSIZ];
243
244 turnonoff(PROFILING_OFF);
245 bzero(buf, BUFSIZ);
246 ssiz = kfetch(N_SSIZ);
247 sbuf = kfetch(N_SBUF);
248 ssiz -= sizeof(struct phdr);
249 sbuf += sizeof(struct phdr);
4d32c205 250 (void)klseek(kmem, (off_t)sbuf, L_SET);
78e8943b
KM
251 for (i = ssiz; i > 0; i -= BUFSIZ)
252 if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) {
253 perror("sbuf write");
01538592 254 exit(7);
78e8943b
KM
255 }
256 s_textsize = kfetch(N_S_TEXTSIZE);
257 fromssize = s_textsize / HASHFRACTION;
258 kfroms = kfetch(N_FROMS);
4d32c205 259 (void)klseek(kmem, kfroms, L_SET);
78e8943b
KM
260 for (i = fromssize; i > 0; i -= BUFSIZ)
261 if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) {
262 perror("kforms write");
01538592 263 exit(8);
78e8943b
KM
264 }
265 tossize = (s_textsize * ARCDENSITY / 100) * sizeof(struct tostruct);
266 ktos = kfetch(N_TOS);
4d32c205 267 (void)klseek(kmem, ktos, L_SET);
78e8943b
KM
268 for (i = tossize; i > 0; i -= BUFSIZ)
269 if (write(kmem, buf, i < BUFSIZ ? i : BUFSIZ) < 0) {
270 perror("ktos write");
01538592 271 exit(9);
78e8943b 272 }
d841a9ba
KM
273}
274
275turnonoff(onoff)
276 int onoff;
277{
4d32c205
KB
278 (void)klseek(kmem, (long)nl[N_PROFILING].n_value, L_SET);
279 (void)write(kmem, (char *)&onoff, sizeof (onoff));
d841a9ba
KM
280}
281
282kfetch(index)
283 int index;
284{
285 off_t off;
286 int value;
287
288 if ((off = nl[index].n_value) == 0) {
289 printf("%s: not defined in kernel\n", nl[index].n_name);
01538592 290 exit(11);
d841a9ba 291 }
769cbf71 292 if (klseek(kmem, off, L_SET) == -1) {
d841a9ba 293 perror("lseek");
01538592 294 exit(12);
d841a9ba
KM
295 }
296 if (read(kmem, (char *)&value, sizeof (value)) != sizeof (value)) {
297 perror("read");
01538592 298 exit(13);
d841a9ba
KM
299 }
300 return (value);
301}
302
4d32c205 303off_t
d841a9ba 304klseek(fd, base, off)
4d32c205
KB
305 int fd, off;
306 off_t base;
d841a9ba 307{
4d32c205
KB
308 if (kflag) { /* get kernel pte */
309 base &= ~KERNBASE;
310 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
d841a9ba
KM
311 }
312 return (lseek(fd, base, off));
313}