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