1/*- 2 * Copyright (c) 1991, 1998 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91"; 36#endif /* not lint */ 37 38#if 0 39#include <unistd.h> 40 41#endif 42#ifdef DEBUG 43#include <stdio.h> 44#endif 45 46#include "gmon.h" 47 48extern mcount() asm ("mcount"); 49extern char *minbrk asm ("minbrk"); 50 51#ifdef __alpha 52extern char *sbrk (); 53#endif 54 55 /* 56 * froms is actually a bunch of unsigned shorts indexing tos 57 */ 58static int profiling = 3; 59static unsigned short *froms; 60static struct tostruct *tos = 0; 61static long tolimit = 0; 62static char *s_lowpc = 0; 63static char *s_highpc = 0; 64static unsigned long s_textsize = 0; 65 66static int ssiz; 67static char *sbuf; 68static int s_scale; 69 /* see profil(2) where this is describe (incorrectly) */ 70#define SCALE_1_TO_1 0x10000L 71 72#define MSG "No space for profiling buffer(s)\n" 73 74monstartup(lowpc, highpc) 75 char *lowpc; 76 char *highpc; 77{ 78 int monsize; 79 char *buffer; 80 register int o; 81 82 /* 83 * round lowpc and highpc to multiples of the density we're using 84 * so the rest of the scaling (here and in gprof) stays in ints. 85 */ 86 lowpc = (char *) 87 ROUNDDOWN((unsigned) lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 88 s_lowpc = lowpc; 89 highpc = (char *) 90 ROUNDUP((unsigned) highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 91 s_highpc = highpc; 92 s_textsize = highpc - lowpc; 93 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 94 buffer = sbrk( monsize ); 95 if ( buffer == (char *) -1 ) { 96 write( 2 , MSG , sizeof(MSG) ); 97 return; 98 } 99 froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 100 if ( froms == (unsigned short *) -1 ) { 101 write( 2 , MSG , sizeof(MSG) ); 102 froms = 0; 103 return; 104 } 105 tolimit = s_textsize * ARCDENSITY / 100; 106 if ( tolimit < MINARCS ) { 107 tolimit = MINARCS; 108 } else if ( tolimit > 65534 ) { 109 tolimit = 65534; 110 } 111 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 112 if ( tos == (struct tostruct *) -1 ) { 113 write( 2 , MSG , sizeof(MSG) ); 114 froms = 0; 115 tos = 0; 116 return; 117 } 118 minbrk = sbrk(0); 119 tos[0].link = 0; 120 sbuf = buffer; 121 ssiz = monsize; 122 ( (struct phdr *) buffer ) -> lpc = lowpc; 123 ( (struct phdr *) buffer ) -> hpc = highpc; 124 ( (struct phdr *) buffer ) -> ncnt = ssiz; 125 monsize -= sizeof(struct phdr); 126 if ( monsize <= 0 ) 127 return; 128 o = highpc - lowpc; 129 if( monsize < o ) 130#ifndef hp300 131 s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; 132#else /* avoid floating point */ 133 { 134 int quot = o / monsize; 135 136 if (quot >= 0x10000) 137 s_scale = 1; 138 else if (quot >= 0x100) 139 s_scale = 0x10000 / quot; 140 else if (o >= 0x800000) 141 s_scale = 0x1000000 / (o / (monsize >> 8)); 142 else 143 s_scale = 0x1000000 / ((o << 8) / monsize); 144 } 145#endif 146 else 147 s_scale = SCALE_1_TO_1; 148 moncontrol(1); 149} 150 151_mcleanup() 152{ 153 int fd; 154 int fromindex; 155 int endfrom; 156 char *frompc; 157 int toindex; 158 struct rawarc rawarc; 159 160 moncontrol(0); 161 fd = creat( "gmon.out" , 0666 ); 162 if ( fd < 0 ) { 163 perror( "mcount: gmon.out" ); 164 return; 165 } 166# ifdef DEBUG 167 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 168# endif DEBUG 169 write( fd , sbuf , ssiz ); 170 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 171 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 172 if ( froms[fromindex] == 0 ) { 173 continue; 174 } 175 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 176 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 177# ifdef DEBUG 178 fprintf( stderr , 179 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 180 frompc , tos[toindex].selfpc , tos[toindex].count ); 181# endif DEBUG 182 rawarc.raw_frompc = (unsigned long) frompc; 183 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 184 rawarc.raw_count = tos[toindex].count; 185 write( fd , &rawarc , sizeof rawarc ); 186 } 187 } 188 close( fd ); 189} 190 191mcount() 192{ 193 register char *selfpc; 194 register unsigned short *frompcindex; 195 register struct tostruct *top; 196 register struct tostruct *prevtop; 197 register long toindex; 198 199 /* 200 * find the return address for mcount, 201 * and the return address for mcount's caller. 202 */ 203 204 /* selfpc = pc pushed by mcount call. 205 This identifies the function that was just entered. */ 206 selfpc = (void *) __builtin_return_address (0); 207 /* frompcindex = pc in preceding frame. 208 This identifies the caller of the function just entered. */ 209 frompcindex = (void *) __builtin_return_address (1); 210 /* 211 * check that we are profiling 212 * and that we aren't recursively invoked. 213 */ 214 if (profiling) { 215 goto out; 216 } 217 profiling++; 218 /* 219 * check that frompcindex is a reasonable pc value. 220 * for example: signal catchers get called from the stack, 221 * not from text space. too bad. 222 */ 223 frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc); 224 if ((unsigned long) frompcindex > s_textsize) { 225 goto done; 226 } 227 frompcindex = 228 &froms[((long) frompcindex) / (HASHFRACTION * sizeof(*froms))]; 229 toindex = *frompcindex; 230 if (toindex == 0) { 231 /* 232 * first time traversing this arc 233 */ 234 toindex = ++tos[0].link; 235 if (toindex >= tolimit) { 236 goto overflow; 237 } 238 *frompcindex = toindex; 239 top = &tos[toindex]; 240 top->selfpc = selfpc; 241 top->count = 1; 242 top->link = 0; 243 goto done; 244 } 245 top = &tos[toindex]; 246 if (top->selfpc == selfpc) { 247 /* 248 * arc at front of chain; usual case. 249 */ 250 top->count++; 251 goto done; 252 } 253 /* 254 * have to go looking down chain for it. 255 * top points to what we are looking at, 256 * prevtop points to previous top. 257 * we know it is not at the head of the chain. 258 */ 259 for (; /* goto done */; ) { 260 if (top->link == 0) { 261 /* 262 * top is end of the chain and none of the chain 263 * had top->selfpc == selfpc. 264 * so we allocate a new tostruct 265 * and link it to the head of the chain. 266 */ 267 toindex = ++tos[0].link; 268 if (toindex >= tolimit) { 269 goto overflow; 270 } 271 top = &tos[toindex]; 272 top->selfpc = selfpc; 273 top->count = 1; 274 top->link = *frompcindex; 275 *frompcindex = toindex; 276 goto done; 277 } 278 /* 279 * otherwise, check the next arc on the chain. 280 */ 281 prevtop = top; 282 top = &tos[top->link]; 283 if (top->selfpc == selfpc) { 284 /* 285 * there it is. 286 * increment its count 287 * move it to the head of the chain. 288 */ 289 top->count++; 290 toindex = prevtop->link; 291 prevtop->link = top->link; 292 top->link = *frompcindex; 293 *frompcindex = toindex; 294 goto done; 295 } 296 297 } 298done: 299 profiling--; 300 /* and fall through */ 301out: 302 return; /* normal return restores saved registers */ 303 304overflow: 305 profiling++; /* halt further profiling */ 306# define TOLIMIT "mcount: tos overflow\n" 307 write(2, TOLIMIT, sizeof(TOLIMIT)); 308 goto out; 309} 310 311/* Control profiling; 312 profiling is what mcount checks to see if 313 all the data structures are ready. */ 314 315moncontrol(mode) 316 int mode; 317{ 318 if (mode) { 319 /* start */ 320 profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 321 (int)s_lowpc, s_scale); 322 profiling = 0; 323 } else { 324 /* stop */ 325 profil((char *) 0, 0, 0, 0); 326 profiling = 3; 327 } 328} 329 330