|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1991 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: /* Mangled into a form that works on Sparc Solaris 2 by Mark Eichin ! 35: * for Cygnus Support, July 1992. ! 36: */ ! 37: ! 38: #ifndef lint ! 39: static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91"; ! 40: #endif /* not lint */ ! 41: ! 42: #include <unistd.h> ! 43: ! 44: #ifdef DEBUG ! 45: #include <stdio.h> ! 46: #endif ! 47: ! 48: #if 0 ! 49: #include "sparc/gmon.h" ! 50: #else ! 51: struct phdr { ! 52: char *lpc; ! 53: char *hpc; ! 54: int ncnt; ! 55: }; ! 56: #define HISTFRACTION 2 ! 57: #define HISTCOUNTER unsigned short ! 58: #define HASHFRACTION 1 ! 59: #define ARCDENSITY 2 ! 60: #define MINARCS 50 ! 61: struct tostruct { ! 62: char *selfpc; ! 63: long count; ! 64: unsigned short link; ! 65: }; ! 66: struct rawarc { ! 67: unsigned long raw_frompc; ! 68: unsigned long raw_selfpc; ! 69: long raw_count; ! 70: }; ! 71: #define ROUNDDOWN(x,y) (((x)/(y))*(y)) ! 72: #define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) ! 73: ! 74: #endif ! 75: ! 76: /* extern mcount() asm ("mcount"); */ ! 77: /*extern*/ char *minbrk /* asm ("minbrk") */; ! 78: ! 79: /* ! 80: * froms is actually a bunch of unsigned shorts indexing tos ! 81: */ ! 82: static int profiling = 3; ! 83: static unsigned short *froms; ! 84: static struct tostruct *tos = 0; ! 85: static long tolimit = 0; ! 86: static char *s_lowpc = 0; ! 87: static char *s_highpc = 0; ! 88: static unsigned long s_textsize = 0; ! 89: ! 90: static int ssiz; ! 91: static char *sbuf; ! 92: static int s_scale; ! 93: /* see profil(2) where this is describe (incorrectly) */ ! 94: #define SCALE_1_TO_1 0x10000L ! 95: ! 96: #define MSG "No space for profiling buffer(s)\n" ! 97: ! 98: monstartup(lowpc, highpc) ! 99: char *lowpc; ! 100: char *highpc; ! 101: { ! 102: int monsize; ! 103: char *buffer; ! 104: register int o; ! 105: ! 106: /* ! 107: * round lowpc and highpc to multiples of the density we're using ! 108: * so the rest of the scaling (here and in gprof) stays in ints. ! 109: */ ! 110: lowpc = (char *) ! 111: ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); ! 112: s_lowpc = lowpc; ! 113: highpc = (char *) ! 114: ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); ! 115: s_highpc = highpc; ! 116: s_textsize = highpc - lowpc; ! 117: monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); ! 118: buffer = sbrk( monsize ); ! 119: if ( buffer == (char *) -1 ) { ! 120: write( 2 , MSG , sizeof(MSG) ); ! 121: return; ! 122: } ! 123: froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); ! 124: if ( froms == (unsigned short *) -1 ) { ! 125: write( 2 , MSG , sizeof(MSG) ); ! 126: froms = 0; ! 127: return; ! 128: } ! 129: tolimit = s_textsize * ARCDENSITY / 100; ! 130: if ( tolimit < MINARCS ) { ! 131: tolimit = MINARCS; ! 132: } else if ( tolimit > 65534 ) { ! 133: tolimit = 65534; ! 134: } ! 135: tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); ! 136: if ( tos == (struct tostruct *) -1 ) { ! 137: write( 2 , MSG , sizeof(MSG) ); ! 138: froms = 0; ! 139: tos = 0; ! 140: return; ! 141: } ! 142: minbrk = sbrk(0); ! 143: tos[0].link = 0; ! 144: sbuf = buffer; ! 145: ssiz = monsize; ! 146: ( (struct phdr *) buffer ) -> lpc = lowpc; ! 147: ( (struct phdr *) buffer ) -> hpc = highpc; ! 148: ( (struct phdr *) buffer ) -> ncnt = ssiz; ! 149: monsize -= sizeof(struct phdr); ! 150: if ( monsize <= 0 ) ! 151: return; ! 152: o = highpc - lowpc; ! 153: if( monsize < o ) ! 154: #ifndef hp300 ! 155: s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; ! 156: #else /* avoid floating point */ ! 157: { ! 158: int quot = o / monsize; ! 159: ! 160: if (quot >= 0x10000) ! 161: s_scale = 1; ! 162: else if (quot >= 0x100) ! 163: s_scale = 0x10000 / quot; ! 164: else if (o >= 0x800000) ! 165: s_scale = 0x1000000 / (o / (monsize >> 8)); ! 166: else ! 167: s_scale = 0x1000000 / ((o << 8) / monsize); ! 168: } ! 169: #endif ! 170: else ! 171: s_scale = SCALE_1_TO_1; ! 172: moncontrol(1); ! 173: } ! 174: ! 175: _mcleanup() ! 176: { ! 177: int fd; ! 178: int fromindex; ! 179: int endfrom; ! 180: char *frompc; ! 181: int toindex; ! 182: struct rawarc rawarc; ! 183: ! 184: moncontrol(0); ! 185: fd = creat( "gmon.out" , 0666 ); ! 186: if ( fd < 0 ) { ! 187: perror( "mcount: gmon.out" ); ! 188: return; ! 189: } ! 190: # ifdef DEBUG ! 191: fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); ! 192: # endif DEBUG ! 193: write( fd , sbuf , ssiz ); ! 194: endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); ! 195: for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { ! 196: if ( froms[fromindex] == 0 ) { ! 197: continue; ! 198: } ! 199: frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); ! 200: for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { ! 201: # ifdef DEBUG ! 202: fprintf( stderr , ! 203: "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , ! 204: frompc , tos[toindex].selfpc , tos[toindex].count ); ! 205: # endif DEBUG ! 206: rawarc.raw_frompc = (unsigned long) frompc; ! 207: rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; ! 208: rawarc.raw_count = tos[toindex].count; ! 209: write( fd , &rawarc , sizeof rawarc ); ! 210: } ! 211: } ! 212: close( fd ); ! 213: } ! 214: ! 215: /* ! 216: * The Sparc stack frame is only held together by the frame pointers ! 217: * in the register windows. According to the SVR4 SPARC ABI ! 218: * Supplement, Low Level System Information/Operating System ! 219: * Interface/Software Trap Types, a type 3 trap will flush all of the ! 220: * register windows to the stack, which will make it possible to walk ! 221: * the frames and find the return addresses. ! 222: * However, it seems awfully expensive to incur a trap (system ! 223: * call) for every function call. It turns out that "call" simply puts ! 224: * the return address in %o7 expecting the "save" in the procedure to ! 225: * shift it into %i7; this means that before the "save" occurs, %o7 ! 226: * contains the address of the call to mcount, and %i7 still contains ! 227: * the caller above that. The asm mcount here simply saves those ! 228: * registers in argument registers and branches to internal_mcount, ! 229: * simulating a call with arguments. ! 230: * Kludges: ! 231: * 1) the branch to internal_mcount is hard coded; it should be ! 232: * possible to tell asm to use the assembler-name of a symbol. ! 233: * 2) in theory, the function calling mcount could have saved %i7 ! 234: * somewhere and reused the register; in practice, I *think* this will ! 235: * break longjmp (and maybe the debugger) but I'm not certain. (I take ! 236: * some comfort in the knowledge that it will break the native mcount ! 237: * as well.) ! 238: * 3) if builtin_return_address worked, this could be portable. ! 239: * However, it would really have to be optimized for arguments of 0 ! 240: * and 1 and do something like what we have here in order to avoid the ! 241: * trap per function call performance hit. ! 242: * 4) the atexit and monsetup calls prevent this from simply ! 243: * being a leaf routine that doesn't do a "save" (and would thus have ! 244: * access to %o7 and %i7 directly) but the call to write() at the end ! 245: * would have also prevented this. ! 246: * ! 247: * -- [eichin:19920702.1107EST] ! 248: */ ! 249: ! 250: /* i7 == last ret, -> frompcindex */ ! 251: /* o7 == current ret, -> selfpc */ ! 252: asm(".global mcount; mcount: mov %i7,%o1; mov %o7,%o0;b,a internal_mcount"); ! 253: ! 254: static internal_mcount(selfpc, frompcindex) ! 255: register char *selfpc; ! 256: register unsigned short *frompcindex; ! 257: { ! 258: register char *nextframe; ! 259: register struct tostruct *top; ! 260: register struct tostruct *prevtop; ! 261: register long toindex; ! 262: static char already_setup; ! 263: ! 264: /* ! 265: * find the return address for mcount, ! 266: * and the return address for mcount's caller. ! 267: */ ! 268: ! 269: if(!already_setup) { ! 270: extern etext(); ! 271: already_setup = 1; ! 272: monstartup(0, etext); ! 273: #ifdef USE_ONEXIT ! 274: on_exit(_mcleanup, 0); ! 275: #else ! 276: atexit(_mcleanup); ! 277: #endif ! 278: } ! 279: /* ! 280: * check that we are profiling ! 281: * and that we aren't recursively invoked. ! 282: */ ! 283: if (profiling) { ! 284: goto out; ! 285: } ! 286: profiling++; ! 287: /* ! 288: * check that frompcindex is a reasonable pc value. ! 289: * for example: signal catchers get called from the stack, ! 290: * not from text space. too bad. ! 291: */ ! 292: frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); ! 293: if ((unsigned long)frompcindex > s_textsize) { ! 294: goto done; ! 295: } ! 296: frompcindex = ! 297: &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; ! 298: toindex = *frompcindex; ! 299: if (toindex == 0) { ! 300: /* ! 301: * first time traversing this arc ! 302: */ ! 303: toindex = ++tos[0].link; ! 304: if (toindex >= tolimit) { ! 305: goto overflow; ! 306: } ! 307: *frompcindex = toindex; ! 308: top = &tos[toindex]; ! 309: top->selfpc = selfpc; ! 310: top->count = 1; ! 311: top->link = 0; ! 312: goto done; ! 313: } ! 314: top = &tos[toindex]; ! 315: if (top->selfpc == selfpc) { ! 316: /* ! 317: * arc at front of chain; usual case. ! 318: */ ! 319: top->count++; ! 320: goto done; ! 321: } ! 322: /* ! 323: * have to go looking down chain for it. ! 324: * top points to what we are looking at, ! 325: * prevtop points to previous top. ! 326: * we know it is not at the head of the chain. ! 327: */ ! 328: for (; /* goto done */; ) { ! 329: if (top->link == 0) { ! 330: /* ! 331: * top is end of the chain and none of the chain ! 332: * had top->selfpc == selfpc. ! 333: * so we allocate a new tostruct ! 334: * and link it to the head of the chain. ! 335: */ ! 336: toindex = ++tos[0].link; ! 337: if (toindex >= tolimit) { ! 338: goto overflow; ! 339: } ! 340: top = &tos[toindex]; ! 341: top->selfpc = selfpc; ! 342: top->count = 1; ! 343: top->link = *frompcindex; ! 344: *frompcindex = toindex; ! 345: goto done; ! 346: } ! 347: /* ! 348: * otherwise, check the next arc on the chain. ! 349: */ ! 350: prevtop = top; ! 351: top = &tos[top->link]; ! 352: if (top->selfpc == selfpc) { ! 353: /* ! 354: * there it is. ! 355: * increment its count ! 356: * move it to the head of the chain. ! 357: */ ! 358: top->count++; ! 359: toindex = prevtop->link; ! 360: prevtop->link = top->link; ! 361: top->link = *frompcindex; ! 362: *frompcindex = toindex; ! 363: goto done; ! 364: } ! 365: ! 366: } ! 367: done: ! 368: profiling--; ! 369: /* and fall through */ ! 370: out: ! 371: return; /* normal return restores saved registers */ ! 372: ! 373: overflow: ! 374: profiling++; /* halt further profiling */ ! 375: # define TOLIMIT "mcount: tos overflow\n" ! 376: write(2, TOLIMIT, sizeof(TOLIMIT)); ! 377: goto out; ! 378: } ! 379: ! 380: /* ! 381: * Control profiling ! 382: * profiling is what mcount checks to see if ! 383: * all the data structures are ready. ! 384: */ ! 385: moncontrol(mode) ! 386: int mode; ! 387: { ! 388: if (mode) { ! 389: /* start */ ! 390: profil((unsigned short *)(sbuf + sizeof(struct phdr)), ! 391: ssiz - sizeof(struct phdr), ! 392: (int)s_lowpc, s_scale); ! 393: profiling = 0; ! 394: } else { ! 395: /* stop */ ! 396: profil((unsigned short *)0, 0, 0, 0); ! 397: profiling = 3; ! 398: } ! 399: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.