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