1 static char *sccsid = "@(#)gmon.c 4.7 (Berkeley) 12/04/82"; 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 unsigned short 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 s_lowpc = lowpc; 35 s_highpc = highpc; 36 s_textsize = highpc - lowpc; 37 monsize = (s_textsize + 1) / 2 + sizeof(struct phdr); 38 buffer = sbrk( monsize ); 39 if ( buffer == (char *) -1 ) { 40 write( 2 , MSG , sizeof(MSG) ); 41 return; 42 } 43 froms = (unsigned short *) sbrk( s_textsize ); 44 if ( froms == (unsigned short *) -1 ) { 45 write( 2 , MSG , sizeof(MSG) ); 46 froms = 0; 47 return; 48 } 49 limit = s_textsize * DENSITY / 100; 50 if ( limit < MINCNT ) { 51 limit = MINCNT; 52 } else if ( limit > 65534 ) { 53 limit = 65534; 54 } 55 tos = (struct tostruct *) sbrk( limit * sizeof( struct tostruct ) ); 56 if ( tos == (struct tostruct *) -1 ) { 57 write( 2 , MSG , sizeof(MSG) ); 58 froms = 0; 59 tos = 0; 60 return; 61 } 62 tos[0].link = 0; 63 /* 64 * tolimit is what mcount checks to see if 65 * all the data structures are ready!!! 66 * make sure it won't overflow. 67 */ 68 tolimit = limit; 69 monitor( lowpc , highpc , buffer , monsize , tolimit ); 70 } 71 72 _mcleanup() 73 { 74 int fd; 75 int fromindex; 76 char *frompc; 77 int toindex; 78 struct rawarc rawarc; 79 80 fd = creat( "gmon.out" , 0666 ); 81 if ( fd < 0 ) { 82 perror( "mcount: gmon.out" ); 83 return; 84 } 85 # ifdef DEBUG 86 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 87 # endif DEBUG 88 write( fd , sbuf , ssiz ); 89 for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) { 90 if ( froms[fromindex] == 0 ) { 91 continue; 92 } 93 frompc = s_lowpc + (fromindex<<1); 94 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 95 # ifdef DEBUG 96 fprintf( stderr , 97 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 98 frompc , tos[toindex].selfpc , tos[toindex].count ); 99 # endif DEBUG 100 rawarc.raw_frompc = (unsigned long) frompc; 101 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 102 rawarc.raw_count = tos[toindex].count; 103 write( fd , &rawarc , sizeof rawarc ); 104 } 105 } 106 close( fd ); 107 } 108 109 /* 110 * This routine is massaged so that it may be jsb'ed to 111 */ 112 asm("#define _mcount mcount"); 113 mcount() 114 { 115 register char *selfpc; /* r11 */ 116 register unsigned short *frompcindex; /* r10 */ 117 register struct tostruct *top; /* r9 */ 118 static int profiling = 0; 119 120 asm( " forgot to run ex script on gcrt0.s" ); 121 asm( "#define r11 r5" ); 122 asm( "#define r10 r4" ); 123 asm( "#define r9 r3" ); 124 #ifdef lint 125 selfpc = (char *) 0; 126 frompcindex = 0; 127 #else not lint 128 /* 129 * find the return address for mcount, 130 * and the return address for mcount's caller. 131 */ 132 asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 133 asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 134 #endif not lint 135 /* 136 * check that we are profiling 137 * and that we aren't recursively invoked. 138 */ 139 if ( tolimit == 0 ) { 140 goto out; 141 } 142 if ( profiling ) { 143 goto out; 144 } 145 profiling = 1; 146 /* 147 * check that frompcindex is a reasonable pc value. 148 * for example: signal catchers get called from the stack, 149 * not from text space. too bad. 150 */ 151 frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc ); 152 if ( (unsigned long) frompcindex > s_textsize ) { 153 goto done; 154 } 155 frompcindex = &froms[ ( (long) frompcindex ) >> 1 ]; 156 if ( *frompcindex == 0 ) { 157 *frompcindex = ++tos[0].link; 158 if ( *frompcindex >= tolimit ) { 159 goto overflow; 160 } 161 top = &tos[ *frompcindex ]; 162 top->selfpc = selfpc; 163 top->count = 0; 164 top->link = 0; 165 } else { 166 top = &tos[ *frompcindex ]; 167 } 168 for ( ; /* goto done */ ; top = &tos[ top -> link ] ) { 169 if ( top -> selfpc == selfpc ) { 170 top -> count++; 171 goto done; 172 } 173 if ( top -> link == 0 ) { 174 top -> link = ++tos[0].link; 175 if ( top -> link >= tolimit ) 176 goto overflow; 177 top = &tos[ top -> link ]; 178 top -> selfpc = selfpc; 179 top -> count = 1; 180 top -> link = 0; 181 goto done; 182 } 183 } 184 done: 185 profiling = 0; 186 /* and fall through */ 187 out: 188 asm( " rsb" ); 189 asm( "#undef r11" ); 190 asm( "#undef r10" ); 191 asm( "#undef r9" ); 192 asm( "#undef _mcount"); 193 194 overflow: 195 tolimit = 0; 196 # define TOLIMIT "mcount: tos overflow\n" 197 write( 2 , TOLIMIT , sizeof( TOLIMIT ) ); 198 goto out; 199 } 200 201 /*VARARGS1*/ 202 monitor( lowpc , highpc , buf , bufsiz , nfunc ) 203 char *lowpc; 204 char *highpc; 205 int *buf, bufsiz; 206 int nfunc; /* not used, available for compatability only */ 207 { 208 register o; 209 210 if ( lowpc == 0 ) { 211 profil( (char *) 0 , 0 , 0 , 0 ); 212 _mcleanup(); 213 return; 214 } 215 sbuf = buf; 216 ssiz = bufsiz; 217 ( (struct phdr *) buf ) -> lpc = lowpc; 218 ( (struct phdr *) buf ) -> hpc = highpc; 219 ( (struct phdr *) buf ) -> ncnt = ssiz; 220 o = sizeof(struct phdr); 221 buf = (int *) ( ( (int) buf ) + o ); 222 bufsiz -= o; 223 if ( bufsiz <= 0 ) 224 return; 225 o = ( ( (char *) highpc - (char *) lowpc) ); 226 if( bufsiz < o ) 227 o = ( (float) bufsiz / o ) * 65536; 228 else 229 o = 65536; 230 profil( buf , bufsiz , lowpc , o ); 231 } 232 233 /* 234 * This is a stub for the "brk" system call, which we want to 235 * catch so that it will not deallocate our data space. 236 * (of which the program is not aware) 237 */ 238 asm("#define _curbrk curbrk"); 239 extern char *curbrk; 240 241 brk(addr) 242 char *addr; 243 { 244 245 if (addr < minsbrk) 246 addr = minsbrk; 247 asm(" chmk $17"); 248 asm(" jcc 1f"); 249 asm(" jmp cerror"); 250 asm("1:"); 251 curbrk = addr; 252 return (0); 253 } 254