1 /*- 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)gmon.c 5.5 (Berkeley) 04/12/91"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #ifdef DEBUG 13 #include <stdio.h> 14 #endif 15 16 #include "gmon.h" 17 18 /* 19 * froms is actually a bunch of unsigned shorts indexing tos 20 */ 21 static int profiling = 3; 22 static unsigned short *froms; 23 static struct tostruct *tos = 0; 24 static long tolimit = 0; 25 static char *s_lowpc = 0; 26 static char *s_highpc = 0; 27 static unsigned long s_textsize = 0; 28 29 static int ssiz; 30 static char *sbuf; 31 static int s_scale; 32 /* see profil(2) where this is describe (incorrectly) */ 33 #define SCALE_1_TO_1 0x10000L 34 35 #define MSG "No space for monitor buffer(s)\n" 36 37 monstartup(lowpc, highpc) 38 char *lowpc; 39 char *highpc; 40 { 41 int monsize; 42 char *buffer; 43 char *sbrk(); 44 extern char *minbrk; 45 46 /* 47 * round lowpc and highpc to multiples of the density we're using 48 * so the rest of the scaling (here and in gprof) stays in ints. 49 */ 50 lowpc = (char *) 51 ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 52 s_lowpc = lowpc; 53 highpc = (char *) 54 ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 55 s_highpc = highpc; 56 s_textsize = highpc - lowpc; 57 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 58 buffer = sbrk( monsize ); 59 if ( buffer == (char *) -1 ) { 60 write( 2 , MSG , sizeof(MSG) - 1 ); 61 return; 62 } 63 froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 64 if ( froms == (unsigned short *) -1 ) { 65 write( 2 , MSG , sizeof(MSG) - 1 ); 66 froms = 0; 67 return; 68 } 69 tolimit = s_textsize * ARCDENSITY / 100; 70 if ( tolimit < MINARCS ) { 71 tolimit = MINARCS; 72 } else if ( tolimit > 65534 ) { 73 tolimit = 65534; 74 } 75 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 76 if ( tos == (struct tostruct *) -1 ) { 77 write( 2 , MSG , sizeof(MSG) - 1 ); 78 froms = 0; 79 tos = 0; 80 return; 81 } 82 minbrk = sbrk(0); 83 tos[0].link = 0; 84 monitor( lowpc , highpc , buffer , monsize , tolimit ); 85 } 86 87 _mcleanup() 88 { 89 int fd; 90 int fromindex; 91 int endfrom; 92 char *frompc; 93 int toindex; 94 struct rawarc rawarc; 95 96 fd = creat( "gmon.out" , 0666 ); 97 if ( fd < 0 ) { 98 perror( "mcount: gmon.out" ); 99 return; 100 } 101 # ifdef DEBUG 102 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 103 # endif DEBUG 104 write( fd , sbuf , ssiz ); 105 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 106 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 107 if ( froms[fromindex] == 0 ) { 108 continue; 109 } 110 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 111 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 112 # ifdef DEBUG 113 fprintf( stderr , 114 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 115 frompc , tos[toindex].selfpc , tos[toindex].count ); 116 # endif DEBUG 117 rawarc.raw_frompc = (unsigned long) frompc; 118 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 119 rawarc.raw_count = tos[toindex].count; 120 write( fd , &rawarc , sizeof rawarc ); 121 } 122 } 123 close( fd ); 124 } 125 126 asm(".text"); 127 asm(".align 2"); 128 asm("#the beginning of mcount()"); 129 asm(".data"); 130 mcount() 131 { 132 register char *selfpc; /* r11 => r5 */ 133 register unsigned short *frompcindex; /* r10 => r4 */ 134 register struct tostruct *top; /* r9 => r3 */ 135 register struct tostruct *prevtop; /* r8 => r2 */ 136 register long toindex; /* r7 => r1 */ 137 138 /* 139 * find the return address for mcount, 140 * and the return address for mcount's caller. 141 */ 142 asm(" .text"); /* make sure we're in text space */ 143 asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 144 asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 145 /* 146 * check that we are profiling 147 * and that we aren't recursively invoked. 148 */ 149 if (profiling) { 150 goto out; 151 } 152 profiling++; 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) / (HASHFRACTION * 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--; 235 /* and fall through */ 236 out: 237 asm(" rsb"); 238 239 overflow: 240 profiling++; /* halt further profiling */ 241 # define TOLIMIT "mcount: tos overflow\n" 242 write(2, TOLIMIT, sizeof(TOLIMIT) - 1); 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 char *buf; /* declared ``short buffer[]'' in monitor(3) */ 254 int bufsiz; 255 int nfunc; /* not used, available for compatability only */ 256 { 257 register o; 258 259 if ( lowpc == 0 ) { 260 moncontrol(0); 261 _mcleanup(); 262 return; 263 } 264 sbuf = buf; 265 ssiz = bufsiz; 266 ( (struct phdr *) buf ) -> lpc = lowpc; 267 ( (struct phdr *) buf ) -> hpc = highpc; 268 ( (struct phdr *) buf ) -> ncnt = ssiz; 269 bufsiz -= sizeof(struct phdr); 270 if ( bufsiz <= 0 ) 271 return; 272 o = highpc - lowpc; 273 if( bufsiz < o ) 274 s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 275 else 276 s_scale = SCALE_1_TO_1; 277 moncontrol(1); 278 } 279 280 /* 281 * Control profiling 282 * profiling is what mcount checks to see if 283 * all the data structures are ready. 284 */ 285 moncontrol(mode) 286 int mode; 287 { 288 if (mode) { 289 /* start */ 290 profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 291 s_lowpc, s_scale); 292 profiling = 0; 293 } else { 294 /* stop */ 295 profil((char *)0, 0, 0, 0); 296 profiling = 3; 297 } 298 } 299