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