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