1 static char *sccsid = "@(#)gmon.c 4.8 (Berkeley) 12/10/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 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 ); 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 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 for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) { 99 if ( froms[fromindex] == 0 ) { 100 continue; 101 } 102 frompc = s_lowpc + (fromindex<<1); 103 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 104 # ifdef DEBUG 105 fprintf( stderr , 106 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 107 frompc , tos[toindex].selfpc , tos[toindex].count ); 108 # endif DEBUG 109 rawarc.raw_frompc = (unsigned long) frompc; 110 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 111 rawarc.raw_count = tos[toindex].count; 112 write( fd , &rawarc , sizeof rawarc ); 113 } 114 } 115 close( fd ); 116 } 117 118 asm(".text"); 119 asm("#the beginning of mcount()"); 120 asm(".data"); 121 mcount() 122 { 123 register char *selfpc; /* r11 => r5 */ 124 register unsigned short *frompcindex; /* r10 => r4 */ 125 register struct tostruct *top; /* r9 => r3 */ 126 register struct tostruct *prevtop; /* r8 => r2 */ 127 register long toindex; /* r7 => r1 */ 128 static int profiling = 0; 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 (tolimit == 0) { 147 goto out; 148 } 149 if (profiling) { 150 goto out; 151 } 152 profiling = 1; 153 /* 154 * check that frompcindex is a reasonable pc value. 155 * for example: signal catchers get called from the stack, 156 * not from text space. too bad. 157 */ 158 frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 159 if ((unsigned long)frompcindex > s_textsize) { 160 goto done; 161 } 162 frompcindex = 163 &froms[(((long)frompcindex) + sizeof(*froms) - 1) / sizeof(*froms)]; 164 toindex = *frompcindex; 165 if (toindex == 0) { 166 /* 167 * first time traversing this arc 168 */ 169 toindex = ++tos[0].link; 170 if (toindex >= tolimit) { 171 goto overflow; 172 } 173 *frompcindex = toindex; 174 top = &tos[toindex]; 175 top->selfpc = selfpc; 176 top->count = 1; 177 top->link = 0; 178 goto done; 179 } 180 top = &tos[toindex]; 181 if (top->selfpc == selfpc) { 182 /* 183 * arc at front of chain; usual case. 184 */ 185 top->count++; 186 goto done; 187 } 188 /* 189 * have to go looking down chain for it. 190 * top points to what we are looking at, 191 * prevtop points to previous top. 192 * we know it is not at the head of the chain. 193 */ 194 for (; /* goto done */; ) { 195 if (top->link == 0) { 196 /* 197 * top is end of the chain and none of the chain 198 * had top->selfpc == selfpc. 199 * so we allocate a new tostruct 200 * and link it to the head of the chain. 201 */ 202 toindex = ++tos[0].link; 203 if (toindex >= tolimit) { 204 goto overflow; 205 } 206 top = &tos[toindex]; 207 top->selfpc = selfpc; 208 top->count = 1; 209 top->link = *frompcindex; 210 *frompcindex = toindex; 211 goto done; 212 } 213 /* 214 * otherwise, check the next arc on the chain. 215 */ 216 prevtop = top; 217 top = &tos[top->link]; 218 if (top->selfpc == selfpc) { 219 /* 220 * there it is. 221 * increment its count 222 * move it to the head of the chain. 223 */ 224 top->count++; 225 toindex = prevtop->link; 226 prevtop->link = top->link; 227 top->link = *frompcindex; 228 *frompcindex = toindex; 229 goto done; 230 } 231 232 } 233 done: 234 profiling = 0; 235 /* and fall through */ 236 out: 237 asm(" rsb"); 238 239 overflow: 240 tolimit = 0; 241 # define TOLIMIT "mcount: tos overflow\n" 242 write(2, TOLIMIT, sizeof(TOLIMIT)); 243 goto out; 244 } 245 asm(".text"); 246 asm("#the end of mcount()"); 247 asm(".data"); 248 249 /*VARARGS1*/ 250 monitor( lowpc , highpc , buf , bufsiz , nfunc ) 251 char *lowpc; 252 char *highpc; 253 int *buf, bufsiz; 254 int nfunc; /* not used, available for compatability only */ 255 { 256 register o; 257 258 if ( lowpc == 0 ) { 259 profil( (char *) 0 , 0 , 0 , 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 o = sizeof(struct phdr); 269 buf = (int *) ( ( (int) buf ) + o ); 270 bufsiz -= o; 271 if ( bufsiz <= 0 ) 272 return; 273 o = ( ( (char *) highpc - (char *) lowpc) ); 274 if( bufsiz < o ) 275 o = ( (float) bufsiz / o ) * 65536; 276 else 277 o = 65536; 278 profil( buf , bufsiz , lowpc , o ); 279 } 280 281 /* 282 * This is a stub for the "brk" system call, which we want to 283 * catch so that it will not deallocate our data space. 284 * (of which the program is not aware) 285 */ 286 extern char *curbrk; 287 288 brk(addr) 289 char *addr; 290 { 291 292 if (addr < minsbrk) 293 addr = minsbrk; 294 asm(" chmk $17"); 295 asm(" jcc 1f"); 296 asm(" jmp cerror"); 297 asm("1:"); 298 curbrk = addr; 299 return (0); 300 } 301