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