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