home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / gprof / gprof.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-24  |  17.0 KB  |  711 lines

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