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: #if defined(LIBC_SCCS) && !defined(lint) 8: static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 3/9/86"; 9: #endif LIBC_SCCS and 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: /* 138: * find the return address for mcount, 139: * and the return address for mcount's caller. 140: */ 141: asm(" .text"); /* make sure we're in text space */ 142: asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 143: asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 144: /* 145: * check that we are profiling 146: * and that we aren't recursively invoked. 147: */ 148: if (profiling) { 149: goto out; 150: } 151: profiling++; 152: /* 153: * check that frompcindex is a reasonable pc value. 154: * for example: signal catchers get called from the stack, 155: * not from text space. too bad. 156: */ 157: frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 158: if ((unsigned long)frompcindex > s_textsize) { 159: goto done; 160: } 161: frompcindex = 162: &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 163: toindex = *frompcindex; 164: if (toindex == 0) { 165: /* 166: * first time traversing this arc 167: */ 168: toindex = ++tos[0].link; 169: if (toindex >= tolimit) { 170: goto overflow; 171: } 172: *frompcindex = toindex; 173: top = &tos[toindex]; 174: top->selfpc = selfpc; 175: top->count = 1; 176: top->link = 0; 177: goto done; 178: } 179: top = &tos[toindex]; 180: if (top->selfpc == selfpc) { 181: /* 182: * arc at front of chain; usual case. 183: */ 184: top->count++; 185: goto done; 186: } 187: /* 188: * have to go looking down chain for it. 189: * top points to what we are looking at, 190: * prevtop points to previous top. 191: * we know it is not at the head of the chain. 192: */ 193: for (; /* goto done */; ) { 194: if (top->link == 0) { 195: /* 196: * top is end of the chain and none of the chain 197: * had top->selfpc == selfpc. 198: * so we allocate a new tostruct 199: * and link it to the head of the chain. 200: */ 201: toindex = ++tos[0].link; 202: if (toindex >= tolimit) { 203: goto overflow; 204: } 205: top = &tos[toindex]; 206: top->selfpc = selfpc; 207: top->count = 1; 208: top->link = *frompcindex; 209: *frompcindex = toindex; 210: goto done; 211: } 212: /* 213: * otherwise, check the next arc on the chain. 214: */ 215: prevtop = top; 216: top = &tos[top->link]; 217: if (top->selfpc == selfpc) { 218: /* 219: * there it is. 220: * increment its count 221: * move it to the head of the chain. 222: */ 223: top->count++; 224: toindex = prevtop->link; 225: prevtop->link = top->link; 226: top->link = *frompcindex; 227: *frompcindex = toindex; 228: goto done; 229: } 230: 231: } 232: done: 233: profiling--; 234: /* and fall through */ 235: out: 236: asm(" rsb"); 237: 238: overflow: 239: profiling++; /* halt further profiling */ 240: # define TOLIMIT "mcount: tos overflow\n" 241: write(2, TOLIMIT, sizeof(TOLIMIT)); 242: goto out; 243: } 244: asm(".text"); 245: asm("#the end of mcount()"); 246: asm(".data"); 247: 248: /*VARARGS1*/ 249: monitor( lowpc , highpc , buf , bufsiz , nfunc ) 250: char *lowpc; 251: char *highpc; 252: char *buf; /* declared ``short buffer[]'' in monitor(3) */ 253: int bufsiz; 254: int nfunc; /* not used, available for compatability only */ 255: { 256: register o; 257: 258: if ( lowpc == 0 ) { 259: moncontrol(0); 260: _mcleanup(); 261: return; 262: } 263: sbuf = buf; 264: ssiz = bufsiz; 265: ( (struct phdr *) buf ) -> lpc = lowpc; 266: ( (struct phdr *) buf ) -> hpc = highpc; 267: ( (struct phdr *) buf ) -> ncnt = ssiz; 268: bufsiz -= sizeof(struct phdr); 269: if ( bufsiz <= 0 ) 270: return; 271: o = highpc - lowpc; 272: if( bufsiz < o ) 273: s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 274: else 275: s_scale = SCALE_1_TO_1; 276: moncontrol(1); 277: } 278: 279: /* 280: * Control profiling 281: * profiling is what mcount checks to see if 282: * all the data structures are ready. 283: */ 284: moncontrol(mode) 285: int mode; 286: { 287: if (mode) { 288: /* start */ 289: profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 290: s_lowpc, s_scale); 291: profiling = 0; 292: } else { 293: /* stop */ 294: profil((char *)0, 0, 0, 0); 295: profiling = 3; 296: } 297: }