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 static char sccsid[] = "@(#)gmon.c 5.7 (Berkeley) 05/06/91"; 10 #endif /* not lint */ 11 12 #include <unistd.h> 13 14 #ifdef DEBUG 15 #include <stdio.h> 16 #endif 17 18 #include "gmon.h" 19 20 extern mcount() asm ("mcount"); 21 extern mcount2() asm ("mcount2"); 22 extern char *minbrk asm ("minbrk"); 23 24 /* 25 * froms is actually a bunch of unsigned shorts indexing tos 26 */ 27 static int profiling = 3; 28 static unsigned short *froms; 29 static struct tostruct *tos = 0; 30 static long tolimit = 0; 31 static char *s_lowpc = 0; 32 static char *s_highpc = 0; 33 static unsigned long s_textsize = 0; 34 35 static int ssiz; 36 static char *sbuf; 37 static int s_scale; 38 /* see profil(2) where this is describe (incorrectly) */ 39 #define SCALE_1_TO_1 0x10000L 40 41 #define MSG "No space for monitor buffer(s)\n" 42 43 monstartup(lowpc, highpc) 44 char *lowpc; 45 char *highpc; 46 { 47 int monsize; 48 char *buffer; 49 50 /* 51 * round lowpc and highpc to multiples of the density we're using 52 * so the rest of the scaling (here and in gprof) stays in ints. 53 */ 54 lowpc = (char *) 55 ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 56 s_lowpc = lowpc; 57 highpc = (char *) 58 ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 59 s_highpc = highpc; 60 s_textsize = highpc - lowpc; 61 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 62 buffer = sbrk( monsize ); 63 if ( buffer == (char *) -1 ) { 64 write( 2 , MSG , sizeof(MSG) - 1 ); 65 return; 66 } 67 froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 68 if ( froms == (unsigned short *) -1 ) { 69 write( 2 , MSG , sizeof(MSG) - 1 ); 70 froms = 0; 71 return; 72 } 73 tolimit = s_textsize * ARCDENSITY / 100; 74 if ( tolimit < MINARCS ) { 75 tolimit = MINARCS; 76 } else if ( tolimit > 65534 ) { 77 tolimit = 65534; 78 } 79 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 80 if ( tos == (struct tostruct *) -1 ) { 81 write( 2 , MSG , sizeof(MSG) - 1 ); 82 froms = 0; 83 tos = 0; 84 return; 85 } 86 minbrk = sbrk(0); 87 tos[0].link = 0; 88 monitor( lowpc , highpc , buffer , monsize , tolimit ); 89 } 90 91 _mcleanup() 92 { 93 int fd; 94 int fromindex; 95 int endfrom; 96 char *frompc; 97 int toindex; 98 struct rawarc rawarc; 99 100 fd = creat( "gmon.out" , 0666 ); 101 if ( fd < 0 ) { 102 perror( "mcount: gmon.out" ); 103 return; 104 } 105 # ifdef DEBUG 106 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 107 # endif DEBUG 108 write( fd , sbuf , ssiz ); 109 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 110 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 111 if ( froms[fromindex] == 0 ) { 112 continue; 113 } 114 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 115 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 116 # ifdef DEBUG 117 fprintf( stderr , 118 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 119 frompc , tos[toindex].selfpc , tos[toindex].count ); 120 # endif DEBUG 121 rawarc.raw_frompc = (unsigned long) frompc; 122 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 123 rawarc.raw_count = tos[toindex].count; 124 write( fd , &rawarc , sizeof rawarc ); 125 } 126 } 127 close( fd ); 128 } 129 130 asm(".text; .globl mcount; mcount: pushl 16(fp); calls $1,mcount2; rsb"); 131 132 mcount2(frompcindex, selfpc) 133 register unsigned short *frompcindex; 134 register char *selfpc; 135 { 136 register struct tostruct *top; 137 register struct tostruct *prevtop; 138 register long toindex; 139 140 /* 141 * check that we are profiling 142 * and that we aren't recursively invoked. 143 */ 144 if (profiling) 145 return; 146 profiling++; 147 /* 148 * check that frompcindex is a reasonable pc value. 149 * for example: signal catchers get called from the stack, 150 * not from text space. too bad. 151 */ 152 frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 153 if ((unsigned long)frompcindex > s_textsize) { 154 goto done; 155 } 156 frompcindex = 157 &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 158 toindex = *frompcindex; 159 if (toindex == 0) { 160 /* 161 * first time traversing this arc 162 */ 163 toindex = ++tos[0].link; 164 if (toindex >= tolimit) { 165 goto overflow; 166 } 167 *frompcindex = toindex; 168 top = &tos[toindex]; 169 top->selfpc = selfpc; 170 top->count = 1; 171 top->link = 0; 172 goto done; 173 } 174 top = &tos[toindex]; 175 if (top->selfpc == selfpc) { 176 /* 177 * arc at front of chain; usual case. 178 */ 179 top->count++; 180 goto done; 181 } 182 /* 183 * have to go looking down chain for it. 184 * top points to what we are looking at, 185 * prevtop points to previous top. 186 * we know it is not at the head of the chain. 187 */ 188 for (; /* goto done */; ) { 189 if (top->link == 0) { 190 /* 191 * top is end of the chain and none of the chain 192 * had top->selfpc == selfpc. 193 * so we allocate a new tostruct 194 * and link it to the head of the chain. 195 */ 196 toindex = ++tos[0].link; 197 if (toindex >= tolimit) { 198 goto overflow; 199 } 200 top = &tos[toindex]; 201 top->selfpc = selfpc; 202 top->count = 1; 203 top->link = *frompcindex; 204 *frompcindex = toindex; 205 goto done; 206 } 207 /* 208 * otherwise, check the next arc on the chain. 209 */ 210 prevtop = top; 211 top = &tos[top->link]; 212 if (top->selfpc == selfpc) { 213 /* 214 * there it is. 215 * increment its count 216 * move it to the head of the chain. 217 */ 218 top->count++; 219 toindex = prevtop->link; 220 prevtop->link = top->link; 221 top->link = *frompcindex; 222 *frompcindex = toindex; 223 goto done; 224 } 225 226 } 227 done: 228 profiling--; 229 return; 230 231 overflow: 232 profiling++; /* halt further profiling */ 233 # define TOLIMIT "mcount: tos overflow\n" 234 write(2, TOLIMIT, sizeof(TOLIMIT) - 1); 235 return; 236 } 237 238 /*VARARGS1*/ 239 monitor( lowpc , highpc , buf , bufsiz , nfunc ) 240 char *lowpc; 241 char *highpc; 242 char *buf; /* declared ``short buffer[]'' in monitor(3) */ 243 int bufsiz; 244 int nfunc; /* not used, available for compatability only */ 245 { 246 register o; 247 248 if ( lowpc == 0 ) { 249 moncontrol(0); 250 _mcleanup(); 251 return; 252 } 253 sbuf = buf; 254 ssiz = bufsiz; 255 ( (struct phdr *) buf ) -> lpc = lowpc; 256 ( (struct phdr *) buf ) -> hpc = highpc; 257 ( (struct phdr *) buf ) -> ncnt = ssiz; 258 bufsiz -= sizeof(struct phdr); 259 if ( bufsiz <= 0 ) 260 return; 261 o = highpc - lowpc; 262 if( bufsiz < o ) 263 s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 264 else 265 s_scale = SCALE_1_TO_1; 266 moncontrol(1); 267 } 268 269 /* 270 * Control profiling 271 * profiling is what mcount checks to see if 272 * all the data structures are ready. 273 */ 274 moncontrol(mode) 275 int mode; 276 { 277 if (mode) { 278 /* start */ 279 profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 280 (int)s_lowpc, s_scale); 281 profiling = 0; 282 } else { 283 /* stop */ 284 profil((char *)0, 0, 0, 0); 285 profiling = 3; 286 } 287 } 288