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