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