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