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