[BACK]Return to gprof.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / gprof

Annotation of src/usr.bin/gprof/gprof.c, Revision 1.1

1.1     ! deraadt     1: /*     $NetBSD: gprof.c,v 1.8 1995/04/19 07:15:59 cgd Exp $    */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1983, 1993
        !             5:  *     The Regents of the University of California.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by the University of
        !            18:  *     California, Berkeley and its contributors.
        !            19:  * 4. Neither the name of the University nor the names of its contributors
        !            20:  *    may be used to endorse or promote products derived from this software
        !            21:  *    without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            33:  * SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: #ifndef lint
        !            37: static char copyright[] =
        !            38: "@(#) Copyright (c) 1983, 1993\n\
        !            39:        The Regents of the University of California.  All rights reserved.\n";
        !            40: #endif /* not lint */
        !            41:
        !            42: #ifndef lint
        !            43: #if 0
        !            44: static char sccsid[] = "@(#)gprof.c    8.1 (Berkeley) 6/6/93";
        !            45: #else
        !            46: static char rcsid[] = "$NetBSD: gprof.c,v 1.8 1995/04/19 07:15:59 cgd Exp $";
        !            47: #endif
        !            48: #endif /* not lint */
        !            49:
        !            50: #include "gprof.h"
        !            51:
        !            52: char   *whoami = "gprof";
        !            53:
        !            54:     /*
        !            55:      * things which get -E excluded by default.
        !            56:      */
        !            57: char   *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
        !            58:
        !            59: static struct gmonhdr  gmonhdr;
        !            60:
        !            61: main(argc, argv)
        !            62:     int argc;
        !            63:     char **argv;
        !            64: {
        !            65:     char       **sp;
        !            66:     nltype     **timesortnlp;
        !            67:
        !            68:     --argc;
        !            69:     argv++;
        !            70:     debug = 0;
        !            71:     bflag = TRUE;
        !            72:     while ( *argv != 0 && **argv == '-' ) {
        !            73:        (*argv)++;
        !            74:        switch ( **argv ) {
        !            75:        case 'a':
        !            76:            aflag = TRUE;
        !            77:            break;
        !            78:        case 'b':
        !            79:            bflag = FALSE;
        !            80:            break;
        !            81:        case 'C':
        !            82:            Cflag = TRUE;
        !            83:            cyclethreshold = atoi( *++argv );
        !            84:            break;
        !            85:        case 'c':
        !            86: #if defined(vax) || defined(tahoe) || defined(sparc)
        !            87:            cflag = TRUE;
        !            88: #else
        !            89:            fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n");
        !            90:            exit(1);
        !            91: #endif
        !            92:            break;
        !            93:        case 'd':
        !            94:            dflag = TRUE;
        !            95:            setlinebuf(stdout);
        !            96:            debug |= atoi( *++argv );
        !            97:            debug |= ANYDEBUG;
        !            98: #          ifdef DEBUG
        !            99:                printf("[main] debug = %d\n", debug);
        !           100: #          else not DEBUG
        !           101:                printf("%s: -d ignored\n", whoami);
        !           102: #          endif DEBUG
        !           103:            break;
        !           104:        case 'E':
        !           105:            ++argv;
        !           106:            addlist( Elist , *argv );
        !           107:            Eflag = TRUE;
        !           108:            addlist( elist , *argv );
        !           109:            eflag = TRUE;
        !           110:            break;
        !           111:        case 'e':
        !           112:            addlist( elist , *++argv );
        !           113:            eflag = TRUE;
        !           114:            break;
        !           115:        case 'F':
        !           116:            ++argv;
        !           117:            addlist( Flist , *argv );
        !           118:            Fflag = TRUE;
        !           119:            addlist( flist , *argv );
        !           120:            fflag = TRUE;
        !           121:            break;
        !           122:        case 'f':
        !           123:            addlist( flist , *++argv );
        !           124:            fflag = TRUE;
        !           125:            break;
        !           126:        case 'k':
        !           127:            addlist( kfromlist , *++argv );
        !           128:            addlist( ktolist , *++argv );
        !           129:            kflag = TRUE;
        !           130:            break;
        !           131:        case 's':
        !           132:            sflag = TRUE;
        !           133:            break;
        !           134:        case 'z':
        !           135:            zflag = TRUE;
        !           136:            break;
        !           137:        }
        !           138:        argv++;
        !           139:     }
        !           140:     if ( *argv != 0 ) {
        !           141:        a_outname  = *argv;
        !           142:        argv++;
        !           143:     } else {
        !           144:        a_outname  = A_OUTNAME;
        !           145:     }
        !           146:     if ( *argv != 0 ) {
        !           147:        gmonname = *argv;
        !           148:        argv++;
        !           149:     } else {
        !           150:        gmonname = GMONNAME;
        !           151:     }
        !           152:        /*
        !           153:         *      turn off default functions
        !           154:         */
        !           155:     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
        !           156:        Eflag = TRUE;
        !           157:        addlist( Elist , *sp );
        !           158:        eflag = TRUE;
        !           159:        addlist( elist , *sp );
        !           160:     }
        !           161:        /*
        !           162:         *      get information about a.out file.
        !           163:         */
        !           164:     getnfile();
        !           165:        /*
        !           166:         *      get information about mon.out file(s).
        !           167:         */
        !           168:     do {
        !           169:        getpfile( gmonname );
        !           170:        if ( *argv != 0 ) {
        !           171:            gmonname = *argv;
        !           172:        }
        !           173:     } while ( *argv++ != 0 );
        !           174:        /*
        !           175:         *      how many ticks per second?
        !           176:         *      if we can't tell, report time in ticks.
        !           177:         */
        !           178:     if (hz == 0) {
        !           179:        hz = 1;
        !           180:        fprintf(stderr, "time is in ticks, not seconds\n");
        !           181:     }
        !           182:        /*
        !           183:         *      dump out a gmon.sum file if requested
        !           184:         */
        !           185:     if ( sflag ) {
        !           186:        dumpsum( GMONSUM );
        !           187:     }
        !           188:        /*
        !           189:         *      assign samples to procedures
        !           190:         */
        !           191:     asgnsamples();
        !           192:        /*
        !           193:         *      assemble the dynamic profile
        !           194:         */
        !           195:     timesortnlp = doarcs();
        !           196:        /*
        !           197:         *      print the dynamic profile
        !           198:         */
        !           199:     printgprof( timesortnlp );
        !           200:        /*
        !           201:         *      print the flat profile
        !           202:         */
        !           203:     printprof();
        !           204:        /*
        !           205:         *      print the index
        !           206:         */
        !           207:     printindex();
        !           208:     done();
        !           209: }
        !           210:
        !           211:     /*
        !           212:      * Set up string and symbol tables from a.out.
        !           213:      * and optionally the text space.
        !           214:      * On return symbol table is sorted by value.
        !           215:      */
        !           216: getnfile()
        !           217: {
        !           218:     FILE       *nfile;
        !           219:     int                valcmp();
        !           220:
        !           221:     nfile = fopen( a_outname ,"r");
        !           222:     if (nfile == NULL) {
        !           223:        perror( a_outname );
        !           224:        done();
        !           225:     }
        !           226:     fread(&xbuf, 1, sizeof(xbuf), nfile);
        !           227:     if (N_BADMAG(xbuf)) {
        !           228:        fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
        !           229:        done();
        !           230:     }
        !           231:     getstrtab(nfile);
        !           232:     getsymtab(nfile);
        !           233:     gettextspace( nfile );
        !           234:     qsort(nl, nname, sizeof(nltype), valcmp);
        !           235:     fclose(nfile);
        !           236: #   ifdef DEBUG
        !           237:        if ( debug & AOUTDEBUG ) {
        !           238:            register int j;
        !           239:
        !           240:            for (j = 0; j < nname; j++){
        !           241:                printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
        !           242:            }
        !           243:        }
        !           244: #   endif DEBUG
        !           245: }
        !           246:
        !           247: getstrtab(nfile)
        !           248:     FILE       *nfile;
        !           249: {
        !           250:
        !           251:     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
        !           252:     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
        !           253:        fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
        !           254:                whoami , a_outname );
        !           255:        done();
        !           256:     }
        !           257:     strtab = calloc(ssiz, 1);
        !           258:     if (strtab == NULL) {
        !           259:        fprintf(stderr, "%s: %s: no room for %d bytes of string table\n",
        !           260:                whoami , a_outname , ssiz);
        !           261:        done();
        !           262:     }
        !           263:     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
        !           264:        fprintf(stderr, "%s: %s: error reading string table\n",
        !           265:                whoami , a_outname );
        !           266:        done();
        !           267:     }
        !           268: }
        !           269:
        !           270:     /*
        !           271:      * Read in symbol table
        !           272:      */
        !           273: getsymtab(nfile)
        !           274:     FILE       *nfile;
        !           275: {
        !           276:     register long      i;
        !           277:     int                        askfor;
        !           278:     struct nlist       nbuf;
        !           279:
        !           280:     /* pass1 - count symbols */
        !           281:     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
        !           282:     nname = 0;
        !           283:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
        !           284:        fread(&nbuf, sizeof(nbuf), 1, nfile);
        !           285:        if ( ! funcsymbol( &nbuf ) ) {
        !           286:            continue;
        !           287:        }
        !           288:        nname++;
        !           289:     }
        !           290:     if (nname == 0) {
        !           291:        fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
        !           292:        done();
        !           293:     }
        !           294:     askfor = nname + 1;
        !           295:     nl = (nltype *) calloc( askfor , sizeof(nltype) );
        !           296:     if (nl == 0) {
        !           297:        fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
        !           298:                whoami, askfor * sizeof(nltype) );
        !           299:        done();
        !           300:     }
        !           301:
        !           302:     /* pass2 - read symbols */
        !           303:     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
        !           304:     npe = nl;
        !           305:     nname = 0;
        !           306:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
        !           307:        fread(&nbuf, sizeof(nbuf), 1, nfile);
        !           308:        if ( ! funcsymbol( &nbuf ) ) {
        !           309: #          ifdef DEBUG
        !           310:                if ( debug & AOUTDEBUG ) {
        !           311:                    printf( "[getsymtab] rejecting: 0x%x %s\n" ,
        !           312:                            nbuf.n_type , strtab + nbuf.n_un.n_strx );
        !           313:                }
        !           314: #          endif DEBUG
        !           315:            continue;
        !           316:        }
        !           317:        npe->value = nbuf.n_value;
        !           318:        npe->name = strtab+nbuf.n_un.n_strx;
        !           319: #      ifdef DEBUG
        !           320:            if ( debug & AOUTDEBUG ) {
        !           321:                printf( "[getsymtab] %d %s 0x%08x\n" ,
        !           322:                        nname , npe -> name , npe -> value );
        !           323:            }
        !           324: #      endif DEBUG
        !           325:        npe++;
        !           326:        nname++;
        !           327:     }
        !           328:     npe->value = -1;
        !           329: }
        !           330:
        !           331:     /*
        !           332:      * read in the text space of an a.out file
        !           333:      */
        !           334: gettextspace( nfile )
        !           335:     FILE       *nfile;
        !           336: {
        !           337:
        !           338:     if ( cflag == 0 ) {
        !           339:        return;
        !           340:     }
        !           341:     textspace = (u_char *) malloc( xbuf.a_text );
        !           342:     if ( textspace == 0 ) {
        !           343:        fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
        !           344:                        whoami , xbuf.a_text );
        !           345:        fprintf( stderr , "can't do -c\n" );
        !           346:        return;
        !           347:     }
        !           348:     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
        !           349:     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
        !           350:        fprintf( stderr , "%s: couldn't read text space:  " , whoami );
        !           351:        fprintf( stderr , "can't do -c\n" );
        !           352:        free( textspace );
        !           353:        textspace = 0;
        !           354:        return;
        !           355:     }
        !           356: }
        !           357:     /*
        !           358:      * information from a gmon.out file is in two parts:
        !           359:      * an array of sampling hits within pc ranges,
        !           360:      * and the arcs.
        !           361:      */
        !           362: getpfile(filename)
        !           363:     char *filename;
        !           364: {
        !           365:     FILE               *pfile;
        !           366:     FILE               *openpfile();
        !           367:     struct rawarc      arc;
        !           368:
        !           369:     pfile = openpfile(filename);
        !           370:     readsamples(pfile);
        !           371:        /*
        !           372:         *      the rest of the file consists of
        !           373:         *      a bunch of <from,self,count> tuples.
        !           374:         */
        !           375:     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
        !           376: #      ifdef DEBUG
        !           377:            if ( debug & SAMPLEDEBUG ) {
        !           378:                printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
        !           379:                        arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
        !           380:            }
        !           381: #      endif DEBUG
        !           382:            /*
        !           383:             *  add this arc
        !           384:             */
        !           385:        tally( &arc );
        !           386:     }
        !           387:     fclose(pfile);
        !           388: }
        !           389:
        !           390: FILE *
        !           391: openpfile(filename)
        !           392:     char *filename;
        !           393: {
        !           394:     struct gmonhdr     tmp;
        !           395:     FILE               *pfile;
        !           396:     int                        size;
        !           397:     int                        rate;
        !           398:
        !           399:     if((pfile = fopen(filename, "r")) == NULL) {
        !           400:        perror(filename);
        !           401:        done();
        !           402:     }
        !           403:     fread(&tmp, sizeof(struct gmonhdr), 1, pfile);
        !           404:     if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc ||
        !           405:         tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) {
        !           406:        fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
        !           407:        done();
        !           408:     }
        !           409:     gmonhdr = tmp;
        !           410:     if ( gmonhdr.version == GMONVERSION ) {
        !           411:        rate = gmonhdr.profrate;
        !           412:        size = sizeof(struct gmonhdr);
        !           413:     } else {
        !           414:        fseek(pfile, sizeof(struct ophdr), SEEK_SET);
        !           415:        size = sizeof(struct ophdr);
        !           416:        gmonhdr.profrate = rate = hertz();
        !           417:        gmonhdr.version = GMONVERSION;
        !           418:     }
        !           419:     if (hz == 0) {
        !           420:        hz = rate;
        !           421:     } else if (hz != rate) {
        !           422:        fprintf(stderr,
        !           423:            "%s: profile clock rate (%d) %s (%d) in first gmon file\n",
        !           424:            filename, rate, "incompatible with clock rate", hz);
        !           425:        done();
        !           426:     }
        !           427:     s_lowpc = (unsigned long) gmonhdr.lpc;
        !           428:     s_highpc = (unsigned long) gmonhdr.hpc;
        !           429:     lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT);
        !           430:     highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT);
        !           431:     sampbytes = gmonhdr.ncnt - size;
        !           432:     nsamples = sampbytes / sizeof (UNIT);
        !           433: #   ifdef DEBUG
        !           434:        if ( debug & SAMPLEDEBUG ) {
        !           435:            printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n",
        !           436:                gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt );
        !           437:            printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
        !           438:                s_lowpc , s_highpc );
        !           439:            printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
        !           440:                lowpc , highpc );
        !           441:            printf( "[openpfile] sampbytes %d nsamples %d\n" ,
        !           442:                sampbytes , nsamples );
        !           443:            printf( "[openpfile] sample rate %d\n" , hz );
        !           444:        }
        !           445: #   endif DEBUG
        !           446:     return(pfile);
        !           447: }
        !           448:
        !           449: tally( rawp )
        !           450:     struct rawarc      *rawp;
        !           451: {
        !           452:     nltype             *parentp;
        !           453:     nltype             *childp;
        !           454:
        !           455:     parentp = nllookup( rawp -> raw_frompc );
        !           456:     childp = nllookup( rawp -> raw_selfpc );
        !           457:     if ( parentp == 0 || childp == 0 )
        !           458:        return;
        !           459:     if ( kflag
        !           460:         && onlist( kfromlist , parentp -> name )
        !           461:         && onlist( ktolist , childp -> name ) ) {
        !           462:        return;
        !           463:     }
        !           464:     childp -> ncall += rawp -> raw_count;
        !           465: #   ifdef DEBUG
        !           466:        if ( debug & TALLYDEBUG ) {
        !           467:            printf( "[tally] arc from %s to %s traversed %d times\n" ,
        !           468:                    parentp -> name , childp -> name , rawp -> raw_count );
        !           469:        }
        !           470: #   endif DEBUG
        !           471:     addarc( parentp , childp , rawp -> raw_count );
        !           472: }
        !           473:
        !           474: /*
        !           475:  * dump out the gmon.sum file
        !           476:  */
        !           477: dumpsum( sumfile )
        !           478:     char *sumfile;
        !           479: {
        !           480:     register nltype *nlp;
        !           481:     register arctype *arcp;
        !           482:     struct rawarc arc;
        !           483:     FILE *sfile;
        !           484:
        !           485:     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
        !           486:        perror( sumfile );
        !           487:        done();
        !           488:     }
        !           489:     /*
        !           490:      * dump the header; use the last header read in
        !           491:      */
        !           492:     if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) {
        !           493:        perror( sumfile );
        !           494:        done();
        !           495:     }
        !           496:     /*
        !           497:      * dump the samples
        !           498:      */
        !           499:     if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) {
        !           500:        perror( sumfile );
        !           501:        done();
        !           502:     }
        !           503:     /*
        !           504:      * dump the normalized raw arc information
        !           505:      */
        !           506:     for ( nlp = nl ; nlp < npe ; nlp++ ) {
        !           507:        for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
        !           508:            arc.raw_frompc = arcp -> arc_parentp -> value;
        !           509:            arc.raw_selfpc = arcp -> arc_childp -> value;
        !           510:            arc.raw_count = arcp -> arc_count;
        !           511:            if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
        !           512:                perror( sumfile );
        !           513:                done();
        !           514:            }
        !           515: #          ifdef DEBUG
        !           516:                if ( debug & SAMPLEDEBUG ) {
        !           517:                    printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
        !           518:                            arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
        !           519:                }
        !           520: #          endif DEBUG
        !           521:        }
        !           522:     }
        !           523:     fclose( sfile );
        !           524: }
        !           525:
        !           526: valcmp(p1, p2)
        !           527:     nltype *p1, *p2;
        !           528: {
        !           529:     if ( p1 -> value < p2 -> value ) {
        !           530:        return LESSTHAN;
        !           531:     }
        !           532:     if ( p1 -> value > p2 -> value ) {
        !           533:        return GREATERTHAN;
        !           534:     }
        !           535:     return EQUALTO;
        !           536: }
        !           537:
        !           538: readsamples(pfile)
        !           539:     FILE       *pfile;
        !           540: {
        !           541:     register i;
        !           542:     UNIT       sample;
        !           543:
        !           544:     if (samples == 0) {
        !           545:        samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
        !           546:        if (samples == 0) {
        !           547:            fprintf( stderr , "%s: No room for %d sample pc's\n",
        !           548:                whoami , sampbytes / sizeof (UNIT));
        !           549:            done();
        !           550:        }
        !           551:     }
        !           552:     for (i = 0; i < nsamples; i++) {
        !           553:        fread(&sample, sizeof (UNIT), 1, pfile);
        !           554:        if (feof(pfile))
        !           555:                break;
        !           556:        samples[i] += sample;
        !           557:     }
        !           558:     if (i != nsamples) {
        !           559:        fprintf(stderr,
        !           560:            "%s: unexpected EOF after reading %d/%d samples\n",
        !           561:                whoami , --i , nsamples );
        !           562:        done();
        !           563:     }
        !           564: }
        !           565:
        !           566: /*
        !           567:  *     Assign samples to the procedures to which they belong.
        !           568:  *
        !           569:  *     There are three cases as to where pcl and pch can be
        !           570:  *     with respect to the routine entry addresses svalue0 and svalue1
        !           571:  *     as shown in the following diagram.  overlap computes the
        !           572:  *     distance between the arrows, the fraction of the sample
        !           573:  *     that is to be credited to the routine which starts at svalue0.
        !           574:  *
        !           575:  *         svalue0                                         svalue1
        !           576:  *            |                                               |
        !           577:  *            v                                               v
        !           578:  *
        !           579:  *            +-----------------------------------------------+
        !           580:  *            |                                               |
        !           581:  *       |  ->|    |<-         ->|         |<-         ->|    |<-  |
        !           582:  *       |         |             |         |             |         |
        !           583:  *       +---------+             +---------+             +---------+
        !           584:  *
        !           585:  *       ^         ^             ^         ^             ^         ^
        !           586:  *       |         |             |         |             |         |
        !           587:  *      pcl       pch           pcl       pch           pcl       pch
        !           588:  *
        !           589:  *     For the vax we assert that samples will never fall in the first
        !           590:  *     two bytes of any routine, since that is the entry mask,
        !           591:  *     thus we give call alignentries() to adjust the entry points if
        !           592:  *     the entry mask falls in one bucket but the code for the routine
        !           593:  *     doesn't start until the next bucket.  In conjunction with the
        !           594:  *     alignment of routine addresses, this should allow us to have
        !           595:  *     only one sample for every four bytes of text space and never
        !           596:  *     have any overlap (the two end cases, above).
        !           597:  */
        !           598: asgnsamples()
        !           599: {
        !           600:     register int       j;
        !           601:     UNIT               ccnt;
        !           602:     double             time;
        !           603:     unsigned long      pcl, pch;
        !           604:     register int       i;
        !           605:     unsigned long      overlap;
        !           606:     unsigned long      svalue0, svalue1;
        !           607:
        !           608:     /* read samples and assign to namelist symbols */
        !           609:     scale = highpc - lowpc;
        !           610:     scale /= nsamples;
        !           611:     alignentries();
        !           612:     for (i = 0, j = 1; i < nsamples; i++) {
        !           613:        ccnt = samples[i];
        !           614:        if (ccnt == 0)
        !           615:                continue;
        !           616:        pcl = lowpc + scale * i;
        !           617:        pch = lowpc + scale * (i + 1);
        !           618:        time = ccnt;
        !           619: #      ifdef DEBUG
        !           620:            if ( debug & SAMPLEDEBUG ) {
        !           621:                printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
        !           622:                        pcl , pch , ccnt );
        !           623:            }
        !           624: #      endif DEBUG
        !           625:        totime += time;
        !           626:        for (j = j - 1; j < nname; j++) {
        !           627:            svalue0 = nl[j].svalue;
        !           628:            svalue1 = nl[j+1].svalue;
        !           629:                /*
        !           630:                 *      if high end of tick is below entry address,
        !           631:                 *      go for next tick.
        !           632:                 */
        !           633:            if (pch < svalue0)
        !           634:                    break;
        !           635:                /*
        !           636:                 *      if low end of tick into next routine,
        !           637:                 *      go for next routine.
        !           638:                 */
        !           639:            if (pcl >= svalue1)
        !           640:                    continue;
        !           641:            overlap = min(pch, svalue1) - max(pcl, svalue0);
        !           642:            if (overlap > 0) {
        !           643: #              ifdef DEBUG
        !           644:                    if (debug & SAMPLEDEBUG) {
        !           645:                        printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
        !           646:                                nl[j].value/sizeof(UNIT), svalue0, svalue1,
        !           647:                                nl[j].name,
        !           648:                                overlap * time / scale, overlap);
        !           649:                    }
        !           650: #              endif DEBUG
        !           651:                nl[j].time += overlap * time / scale;
        !           652:            }
        !           653:        }
        !           654:     }
        !           655: #   ifdef DEBUG
        !           656:        if (debug & SAMPLEDEBUG) {
        !           657:            printf("[asgnsamples] totime %f\n", totime);
        !           658:        }
        !           659: #   endif DEBUG
        !           660: }
        !           661:
        !           662:
        !           663: unsigned long
        !           664: min(a, b)
        !           665:     unsigned long a,b;
        !           666: {
        !           667:     if (a<b)
        !           668:        return(a);
        !           669:     return(b);
        !           670: }
        !           671:
        !           672: unsigned long
        !           673: max(a, b)
        !           674:     unsigned long a,b;
        !           675: {
        !           676:     if (a>b)
        !           677:        return(a);
        !           678:     return(b);
        !           679: }
        !           680:
        !           681:     /*
        !           682:      * calculate scaled entry point addresses (to save time in asgnsamples),
        !           683:      * and possibly push the scaled entry points over the entry mask,
        !           684:      * if it turns out that the entry point is in one bucket and the code
        !           685:      * for a routine is in the next bucket.
        !           686:      */
        !           687: alignentries()
        !           688: {
        !           689:     register struct nl *nlp;
        !           690:     unsigned long      bucket_of_entry;
        !           691:     unsigned long      bucket_of_code;
        !           692:
        !           693:     for (nlp = nl; nlp < npe; nlp++) {
        !           694:        nlp -> svalue = nlp -> value / sizeof(UNIT);
        !           695:        bucket_of_entry = (nlp->svalue - lowpc) / scale;
        !           696:        bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
        !           697:        if (bucket_of_entry < bucket_of_code) {
        !           698: #          ifdef DEBUG
        !           699:                if (debug & SAMPLEDEBUG) {
        !           700:                    printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
        !           701:                            nlp->svalue, nlp->svalue + UNITS_TO_CODE);
        !           702:                }
        !           703: #          endif DEBUG
        !           704:            nlp->svalue += UNITS_TO_CODE;
        !           705:        }
        !           706:     }
        !           707: }
        !           708:
        !           709: bool
        !           710: funcsymbol( nlistp )
        !           711:     struct nlist       *nlistp;
        !           712: {
        !           713:     extern char        *strtab;        /* string table from a.out */
        !           714:     extern int aflag;          /* if static functions aren't desired */
        !           715:     char       *name, c;
        !           716:
        !           717:        /*
        !           718:         *      must be a text symbol,
        !           719:         *      and static text symbols don't qualify if aflag set.
        !           720:         */
        !           721:     if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
        !           722:           || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
        !           723:        return FALSE;
        !           724:     }
        !           725:        /*
        !           726:         *      can't have any `funny' characters in name,
        !           727:         *      where `funny' includes  `.', .o file names
        !           728:         *                      and     `$', pascal labels.
        !           729:         *      need to make an exception for sparc .mul & co.
        !           730:         *      perhaps we should just drop this code entirely...
        !           731:         */
        !           732:     name = strtab + nlistp -> n_un.n_strx;
        !           733: #ifdef sparc
        !           734:     if (nlistp -> n_value & 3)
        !           735:        return FALSE;
        !           736:     if ( *name == '.' ) {
        !           737:        char *p = name + 1;
        !           738:        if ( *p == 'u' )
        !           739:            p++;
        !           740:        if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 ||
        !           741:             strcmp ( p, "rem" ) == 0 )
        !           742:                return TRUE;
        !           743:     }
        !           744: #endif
        !           745:     while ( c = *name++ ) {
        !           746:        if ( c == '.' || c == '$' ) {
        !           747:            return FALSE;
        !           748:        }
        !           749:     }
        !           750:     return TRUE;
        !           751: }
        !           752:
        !           753: done()
        !           754: {
        !           755:
        !           756:     exit(0);
        !           757: }