/etc/securetty is checked, even when root logins across the net.
[unix-history] / usr / src / usr.bin / gprof / gprof.c
index 6dfd9ee..179e519 100644 (file)
@@ -1,28 +1,77 @@
 #ifndef lint
 #ifndef lint
-    static     char *sccsid = "@(#)gprof.c     1.1 (Berkeley) %G%";
+    static     char *sccsid = "@(#)gprof.c     1.22 (Berkeley) %G%";
 #endif lint
 
 #endif lint
 
-#include "dprof.h"
+#include "gprof.h"
+
+char   *whoami = "gprof";
+
+    /*
+     * things which get -E excluded by default.
+     */
+char   *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
 
 main(argc, argv)
 
 main(argc, argv)
-       int argc;
-       char **argv;
+    int argc;
+    char **argv;
 {
 {
+    char       **sp;
 
     --argc;
     argv++;
     debug = 0;
 
     --argc;
     argv++;
     debug = 0;
+    bflag = TRUE;
     while ( *argv != 0 && **argv == '-' ) {
        (*argv)++;
     while ( *argv != 0 && **argv == '-' ) {
        (*argv)++;
-       if ( **argv == 'd' ) {
+       switch ( **argv ) {
+       case 'a':
+           aflag = TRUE;
+           break;
+       case 'b':
+           bflag = FALSE;
+           break;
+       case 'c':
+           cflag = TRUE;
+           break;
+       case 'd':
+           dflag = TRUE;
            (*argv)++;
            debug |= atoi( *argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
            (*argv)++;
            debug |= atoi( *argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
-               printf( "[main] debug = %d\n" , debug );
+               printf("[main] debug = %d\n", debug);
+#          else not DEBUG
+               printf("%s: -d ignored\n", whoami);
 #          endif DEBUG
 #          endif DEBUG
-       } else if ( **argv == 'z' ) {
-           zflg++;
+           break;
+       case 'E':
+           ++argv;
+           addlist( Elist , *argv );
+           Eflag = TRUE;
+           addlist( elist , *argv );
+           eflag = TRUE;
+           break;
+       case 'e':
+           addlist( elist , *++argv );
+           eflag = TRUE;
+           break;
+       case 'F':
+           ++argv;
+           addlist( Flist , *argv );
+           Fflag = TRUE;
+           addlist( flist , *argv );
+           fflag = TRUE;
+           break;
+       case 'f':
+           addlist( flist , *++argv );
+           fflag = TRUE;
+           break;
+       case 's':
+           sflag = TRUE;
+           break;
+       case 'z':
+           zflag = TRUE;
+           break;
        }
        argv++;
     }
        }
        argv++;
     }
@@ -33,11 +82,24 @@ main(argc, argv)
        a_outname  = A_OUTNAME;
     }
     if ( *argv != 0 ) {
        a_outname  = A_OUTNAME;
     }
     if ( *argv != 0 ) {
-       dmonname = *argv;
+       gmonname = *argv;
        argv++;
     } else {
        argv++;
     } else {
-       dmonname = DMONNAME;
+       gmonname = GMONNAME;
     }
     }
+       /*
+        *      turn off default functions
+        */
+    for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
+       Eflag = TRUE;
+       addlist( Elist , *sp );
+       eflag = TRUE;
+       addlist( elist , *sp );
+    }
+       /*
+        *      how long is a clock tick?
+        */
+    hz = hertz();
        /*
         *      get information about a.out file.
         */
        /*
         *      get information about a.out file.
         */
@@ -45,7 +107,18 @@ main(argc, argv)
        /*
         *      get information about mon.out file(s).
         */
        /*
         *      get information about mon.out file(s).
         */
-    getpfile( dmonname );
+    do {
+       getpfile( gmonname );
+       if ( *argv != 0 ) {
+           gmonname = *argv;
+       }
+    } while ( *argv++ != 0 );
+       /*
+        *      dump out a gmon.sum file if requested
+        */
+    if ( sflag ) {
+       dumpsum( GMONSUM );
+    }
        /*
         *      assign samples to procedures
         */
        /*
         *      assign samples to procedures
         */
@@ -61,91 +134,11 @@ main(argc, argv)
     done();
 }
 
     done();
 }
 
-printprof()
-{
-    register nltype    *np;
-    nltype             **sortednlp;
-    int                        index;
-
-    actime = 0.0;
-    putprofheader();
-       /*
-        *      Sort the symbol table in by time
-        */
-    sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
-    if ( sortednlp == (nltype **) 0 ) {
-       fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
-    }
-    for ( index = 0 ; index < nname ; index += 1 ) {
-       sortednlp[ index ] = &nl[ index ];
-    }
-    qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
-    for ( index = 0 ; index < nname ; index += 1 ) {
-       np = sortednlp[ index ];
-       putprofline( np , 1 );
-    }
-    actime = 0.0;
-    printf( "\ngranularity: each sample hit covers %.1f bytes" , scale );
-    printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ );
-}
-
-putprofline( np , cumflag )
-    register nltype    *np;
-    int                        cumflag;
-{
-    double     time;
-    long       calls = np -> ncall + np -> selfcalls;
-
-    if ( zflg == 0 && calls == 0 && np -> time == 0 && np -> childtime == 0 ) {
-       return;
-    }
-    if ( cumflag ) {
-       time = (np->time + np->childtime) / totime;
-       actime += np->time;
-       if ( np -> index != 0 ) {
-           printf( "[%d]" , np -> index );
-       }
-       printf( "\t%5.1f %7.1f" , 100 * time , actime / HZ );
-    } else {
-       printf( "\t%5.5s %7.7s" , "" , "" );
-    }
-    printf( " %7.1f", np -> time / HZ );
-    if ( np -> childtime != 0.0 ) {
-       printf( " %7.1f" , np -> childtime / HZ );
-    } else {
-       printf( " %7.7s" , "" );
-    }
-    if ( calls != 0 ) {
-       printf( " %7d" , np -> ncall );
-       if ( np -> selfcalls != 0 ) {
-           printf( "+%-7d  " , np -> selfcalls );
-       } else {
-           printf( " %7.7s  " , "" );
-       }
-    } else {
-       printf( " %7.7s %7.7s  " , "" , "" );
-    }
-    if ( ! cumflag ) {
-       printf( "    " );
-    }
-    printname( np );
-    printf( "\n" );
-}
-
     /*
     /*
-     * header for putprofline
+     * Set up string and symbol tables from a.out.
+     * and optionally the text space.
+     * On return symbol table is sorted by value.
      */
      */
-putprofheader()
-{
-    
-    printf( "\n\t%5.5s %7.7s %-7.7s %-7.7s %7.7s %7.7s %5.5s\n" ,
-           "%time" , "cumsecs" , "  self" , " child" , "ncall" , "" , "name" );
-}
-
-/*
- * Set up string and symbol tables from a.out.
- * On return symbol table is sorted by value.
- */
 getnfile()
 {
     FILE       *nfile;
 getnfile()
 {
     FILE       *nfile;
@@ -157,11 +150,12 @@ getnfile()
     }
     fread(&xbuf, 1, sizeof(xbuf), nfile);
     if (N_BADMAG(xbuf)) {
     }
     fread(&xbuf, 1, sizeof(xbuf), nfile);
     if (N_BADMAG(xbuf)) {
-       fprintf(stderr, "%s: bad format\n", a_outname );
+       fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
        done();
     }
     getstrtab(nfile);
     getsymtab(nfile);
        done();
     }
     getstrtab(nfile);
     getsymtab(nfile);
+    gettextspace( nfile );
     qsort(nl, nname, sizeof(nltype), valcmp);
     fclose(nfile);
 #   ifdef DEBUG
     qsort(nl, nname, sizeof(nltype), valcmp);
     fclose(nfile);
 #   ifdef DEBUG
@@ -181,17 +175,19 @@ getstrtab(nfile)
 
     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
 
     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
-       fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
+       fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
+               whoami , a_outname );
        done();
     }
     strtab = (char *)calloc(ssiz, 1);
     if (strtab == NULL) {
        done();
     }
     strtab = (char *)calloc(ssiz, 1);
     if (strtab == NULL) {
-       fprintf(stderr, "%s: no room for %d bytes of string table",
-               a_outname , ssiz);
+       fprintf(stderr, "%s: %s: no room for %d bytes of string table",
+               whoami , a_outname , ssiz);
        done();
     }
     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
        done();
     }
     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
-       fprintf(stderr, "%s: error reading string table\n", a_outname );
+       fprintf(stderr, "%s: %s: error reading string table\n",
+               whoami , a_outname );
        done();
     }
 }
        done();
     }
 }
@@ -211,27 +207,20 @@ getsymtab(nfile)
     nname = 0;
     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
        fread(&nbuf, sizeof(nbuf), 1, nfile);
     nname = 0;
     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
        fread(&nbuf, sizeof(nbuf), 1, nfile);
-       if ( nbuf.n_type != N_TEXT+N_EXT ) {
+       if ( ! funcsymbol( &nbuf ) ) {
            continue;
        }
        nname++;
     }
     if (nname == 0) {
            continue;
        }
        nname++;
     }
     if (nname == 0) {
-       fprintf(stderr, "%s: no symbols\n", a_outname );
+       fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
        done();
     }
        done();
     }
-       /*
-        *      ask also for CYCLEFRACTION extra namelist entries for 
-        *      cycle entries.  these hide out at the end of the namelist
-        *      and aren't accessed unless the whole namelist (nname+ncycles)
-        *      is sorted and searched.
-        */
-    ncycles = nname * CYCLEFRACTION;
-    askfor = nname + 1 + ncycles;
+    askfor = nname + 1;
     nl = (nltype *) calloc( askfor , sizeof(nltype) );
     if (nl == 0) {
     nl = (nltype *) calloc( askfor , sizeof(nltype) );
     if (nl == 0) {
-       fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
-               askfor * sizeof(nltype) );
+       fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
+               whoami, askfor * sizeof(nltype) );
        done();
     }
 
        done();
     }
 
@@ -241,7 +230,13 @@ getsymtab(nfile)
     nname = 0;
     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
        fread(&nbuf, sizeof(nbuf), 1, nfile);
     nname = 0;
     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
        fread(&nbuf, sizeof(nbuf), 1, nfile);
-       if ( nbuf.n_type != N_TEXT+N_EXT ) {
+       if ( ! funcsymbol( &nbuf ) ) {
+#          ifdef DEBUG
+               if ( debug & AOUTDEBUG ) {
+                   printf( "[getsymtab] rejecting: 0x%x %s\n" ,
+                           nbuf.n_type , strtab + nbuf.n_un.n_strx );
+               }
+#          endif DEBUG
            continue;
        }
        npe->value = nbuf.n_value;
            continue;
        }
        npe->value = nbuf.n_value;
@@ -256,11 +251,37 @@ getsymtab(nfile)
        nname++;
     }
     npe->value = -1;
        nname++;
     }
     npe->value = -1;
-    npe++;
 }
 
     /*
 }
 
     /*
-     * information from a dmon.out file is in two parts:
+     * read in the text space of an a.out file
+     */
+gettextspace( nfile )
+    FILE       *nfile;
+{
+    unsigned char      *malloc();
+    
+    if ( cflag == 0 ) {
+       return;
+    }
+    textspace = malloc( xbuf.a_text );
+    if ( textspace == 0 ) {
+       fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
+                       whoami , xbuf.a_text );
+       fprintf( stderr , "can't do -c\n" );
+       return;
+    }
+    (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
+    if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
+       fprintf( stderr , "%s: couldn't read text space:  " , whoami );
+       fprintf( stderr , "can't do -c\n" );
+       free( textspace );
+       textspace = 0;
+       return;
+    }
+}
+    /*
+     * information from a gmon.out file is in two parts:
      * an array of sampling hits within pc ranges,
      * and the arcs.
      */
      * an array of sampling hits within pc ranges,
      * and the arcs.
      */
@@ -280,7 +301,7 @@ getpfile(filename)
     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
-               printf( "[getpfile] frompc %d selfpc %d count %d\n" ,
+               printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
                        arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
            }
 #      endif DEBUG
                        arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
            }
 #      endif DEBUG
@@ -292,20 +313,42 @@ getpfile(filename)
     fclose(pfile);
 }
 
     fclose(pfile);
 }
 
-FILE *openpfile(filename)
+FILE *
+openpfile(filename)
     char *filename;
 {
     char *filename;
 {
+    struct hdr tmp;
     FILE       *pfile;
 
     if((pfile = fopen(filename, "r")) == NULL) {
        perror(filename);
        done();
     }
     FILE       *pfile;
 
     if((pfile = fopen(filename, "r")) == NULL) {
        perror(filename);
        done();
     }
-    fread(&h, sizeof(struct hdr), 1, pfile);
-    lowpc = h.lowpc - (UNIT *)0;
-    highpc = h.highpc - (UNIT *)0;
+    fread(&tmp, sizeof(struct hdr), 1, pfile);
+    if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
+        tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
+       fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
+       done();
+    }
+    h = tmp;
+    s_lowpc = (unsigned long) h.lowpc;
+    s_highpc = (unsigned long) h.highpc;
+    lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
+    highpc = (unsigned long)h.highpc / sizeof(UNIT);
     sampbytes = h.ncnt - sizeof(struct hdr);
     nsamples = sampbytes / sizeof (unsigned UNIT);
     sampbytes = h.ncnt - sizeof(struct hdr);
     nsamples = sampbytes / sizeof (unsigned UNIT);
+#   ifdef DEBUG
+       if ( debug & SAMPLEDEBUG ) {
+           printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
+               h.lowpc , h.highpc , h.ncnt );
+           printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
+               s_lowpc , s_highpc );
+           printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
+               lowpc , highpc );
+           printf( "[openpfile] sampbytes %d nsamples %d\n" ,
+               sampbytes , nsamples );
+       }
+#   endif DEBUG
     return(pfile);
 }
 
     return(pfile);
 }
 
@@ -314,8 +357,6 @@ tally( rawp )
 {
     nltype             *parentp;
     nltype             *childp;
 {
     nltype             *parentp;
     nltype             *childp;
-    arctype            *arcp;
-    arctype            *malloc();
 
     parentp = nllookup( rawp -> raw_frompc );
     childp = nllookup( rawp -> raw_selfpc );
 
     parentp = nllookup( rawp -> raw_frompc );
     childp = nllookup( rawp -> raw_selfpc );
@@ -326,34 +367,59 @@ tally( rawp )
                    parentp -> name , childp -> name , rawp -> raw_count );
        }
 #   endif DEBUG
                    parentp -> name , childp -> name , rawp -> raw_count );
        }
 #   endif DEBUG
-    arcp = arclookup( parentp , childp );
-    if ( arcp != 0 ) {
-           /*
-            *  a hit:  just increment the count.
-            */
-#      ifdef DEBUG
-           if ( debug & TALLYDEBUG ) {
-               printf( "[tally] hit %d += %d\n" ,
-                       arcp -> arc_count , rawp -> raw_count );
+    addarc( parentp , childp , rawp -> raw_count );
+}
+
+/*
+ * dump out the gmon.sum file
+ */
+dumpsum( sumfile )
+    char *sumfile;
+{
+    register nltype *nlp;
+    register arctype *arcp;
+    struct rawarc arc;
+    FILE *sfile;
+
+    if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
+       perror( sumfile );
+       done();
+    }
+    /*
+     * dump the header; use the last header read in
+     */
+    if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
+       perror( sumfile );
+       done();
+    }
+    /*
+     * dump the samples
+     */
+    if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
+       perror( sumfile );
+       done();
+    }
+    /*
+     * dump the normalized raw arc information
+     */
+    for ( nlp = nl ; nlp < npe ; nlp++ ) {
+       for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+           arc.raw_frompc = arcp -> arc_parentp -> value;
+           arc.raw_selfpc = arcp -> arc_childp -> value;
+           arc.raw_count = arcp -> arc_count;
+           if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
+               perror( sumfile );
+               done();
            }
            }
-#      endif DEBUG
-       arcp -> arc_count += rawp -> raw_count;
-       return;
+#          ifdef DEBUG
+               if ( debug & SAMPLEDEBUG ) {
+                   printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
+                           arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
+               }
+#          endif DEBUG
+       }
     }
     }
-    arcp = malloc( sizeof *arcp );
-    arcp -> arc_parentp = parentp;
-    arcp -> arc_childp = childp;
-    arcp -> arc_count = rawp -> raw_count;
-       /*
-        *      prepend this child to the children of this parent
-        */
-    arcp -> arc_childlist = parentp -> children;
-    parentp -> children = arcp;
-       /*
-        *      prepend this parent to the parents of this child
-        */
-    arcp -> arc_parentlist = childp -> parents;
-    childp -> parents = arcp;
+    fclose( sfile );
 }
 
 valcmp(p1, p2)
 }
 
 valcmp(p1, p2)
@@ -377,8 +443,8 @@ readsamples(pfile)
     if (samples == 0) {
        samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
        if (samples == 0) {
     if (samples == 0) {
        samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
        if (samples == 0) {
-           fprintf( stderr , "prof: No room for %d sample pc's\n", 
-               sampbytes / sizeof (unsigned UNIT));
+           fprintf( stderr , "%s: No room for %d sample pc's\n", 
+               whoami , sampbytes / sizeof (unsigned UNIT));
            done();
        }
     }
            done();
        }
     }
@@ -390,14 +456,43 @@ readsamples(pfile)
     }
     if (i != nsamples) {
        fprintf(stderr,
     }
     if (i != nsamples) {
        fprintf(stderr,
-           "prof: unexpected EOF after reading %d/%d samples\n",
-               --i, nsamples);
+           "%s: unexpected EOF after reading %d/%d samples\n",
+               whoami , --i , nsamples );
        done();
     }
 }
 
 /*
        done();
     }
 }
 
 /*
- * Assign samples to the procedures to which they belong.
+ *     Assign samples to the procedures to which they belong.
+ *
+ *     There are three cases as to where pcl and pch can be
+ *     with respect to the routine entry addresses svalue0 and svalue1
+ *     as shown in the following diagram.  overlap computes the
+ *     distance between the arrows, the fraction of the sample
+ *     that is to be credited to the routine which starts at svalue0.
+ *
+ *         svalue0                                         svalue1
+ *            |                                               |
+ *            v                                               v
+ *
+ *            +-----------------------------------------------+
+ *            |                                               |
+ *       |  ->|    |<-         ->|         |<-         ->|    |<-  |
+ *       |         |             |         |             |         |
+ *       +---------+             +---------+             +---------+
+ *
+ *       ^         ^             ^         ^             ^         ^
+ *       |         |             |         |             |         |
+ *      pcl       pch           pcl       pch           pcl       pch
+ *
+ *     For the vax we assert that samples will never fall in the first
+ *     two bytes of any routine, since that is the entry mask,
+ *     thus we give call alignentries() to adjust the entry points if
+ *     the entry mask falls in one bucket but the code for the routine
+ *     doesn't start until the next bucket.  In conjunction with the
+ *     alignment of routine addresses, this should allow us to have
+ *     only one sample for every four bytes of text space and never
+ *     have any overlap (the two end cases, above).
  */
 asgnsamples()
 {
  */
 asgnsamples()
 {
@@ -406,84 +501,137 @@ asgnsamples()
     double             time;
     unsigned long      pcl, pch;
     register int       i;
     double             time;
     unsigned long      pcl, pch;
     register int       i;
-    int                        overlap;
+    unsigned long      overlap;
     unsigned long      svalue0, svalue1;
 
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
     scale /= nsamples;
     unsigned long      svalue0, svalue1;
 
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
     scale /= nsamples;
-    for (i=0; i < nsamples; i++) {
+    alignentries();
+    for (i = 0, j = 1; i < nsamples; i++) {
        ccnt = samples[i];
        if (ccnt == 0)
                continue;
        ccnt = samples[i];
        if (ccnt == 0)
                continue;
-       pcl = lowpc + scale*i;
-       pch = lowpc + scale*(i+1);
+       pcl = lowpc + scale * i;
+       pch = lowpc + scale * (i + 1);
        time = ccnt;
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
        time = ccnt;
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
-               printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
-                       ccnt , time , totime );
+               printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
+                       pcl , pch , ccnt );
            }
 #      endif DEBUG
        totime += time;
            }
 #      endif DEBUG
        totime += time;
-       for (j=0; j<nname; j++) {
-           svalue0 = nl[j].value / sizeof(UNIT);
-           svalue1 = nl[j+1].value / sizeof(UNIT);
+       for (j = j - 1; j < nname; j++) {
+           svalue0 = nl[j].svalue;
+           svalue1 = nl[j+1].svalue;
+               /*
+                *      if high end of tick is below entry address, 
+                *      go for next tick.
+                */
            if (pch < svalue0)
                    break;
            if (pch < svalue0)
                    break;
+               /*
+                *      if low end of tick into next routine,
+                *      go for next routine.
+                */
            if (pcl >= svalue1)
                    continue;
            if (pcl >= svalue1)
                    continue;
-           overlap=min(pch,svalue1) - max(pcl,svalue0);
-           if (overlap>0) {
+           overlap = min(pch, svalue1) - max(pcl, svalue0);
+           if (overlap > 0) {
 #              ifdef DEBUG
 #              ifdef DEBUG
-                   if ( debug & SAMPLEDEBUG ) {
-                       printf( "[asgnsamples] %s gets %f ticks\n" ,
-                               nl[j].name , overlap*time/scale );
+                   if (debug & SAMPLEDEBUG) {
+                       printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
+                               nl[j].value/sizeof(UNIT), svalue0, svalue1,
+                               nl[j].name, 
+                               overlap * time / scale, overlap);
                    }
 #              endif DEBUG
                    }
 #              endif DEBUG
-               nl[j].time += overlap*time/scale;
+               nl[j].time += overlap * time / scale;
            }
        }
     }
 #   ifdef DEBUG
            }
        }
     }
 #   ifdef DEBUG
-       if ( debug & SAMPLEDEBUG ) {
-           printf( "[asgnsamples] totime %f\n" , totime );
+       if (debug & SAMPLEDEBUG) {
+           printf("[asgnsamples] totime %f\n", totime);
        }
 #   endif DEBUG
        }
 #   endif DEBUG
-    if (totime==0.0) {
-       fprintf( stderr , "No time accumulated\n" );
-       totime=1.0;
-    }
 }
 
 
 }
 
 
+unsigned long
 min(a, b)
 min(a, b)
-    unsigned a,b;
+    unsigned long a,b;
 {
     if (a<b)
        return(a);
     return(b);
 }
 
 {
     if (a<b)
        return(a);
     return(b);
 }
 
+unsigned long
 max(a, b)
 max(a, b)
-    unsigned a,b;
+    unsigned long a,b;
 {
     if (a>b)
        return(a);
     return(b);
 }
 
 {
     if (a>b)
        return(a);
     return(b);
 }
 
-timecmp( npp1 , npp2 )
-    nltype **npp1, **npp2;
+    /*
+     * calculate scaled entry point addresses (to save time in asgnsamples),
+     * and possibly push the scaled entry points over the entry mask,
+     * if it turns out that the entry point is in one bucket and the code
+     * for a routine is in the next bucket.
+     */
+alignentries()
+{
+    register struct nl *nlp;
+    unsigned long      bucket_of_entry;
+    unsigned long      bucket_of_code;
+
+    for (nlp = nl; nlp < npe; nlp++) {
+       nlp -> svalue = nlp -> value / sizeof(UNIT);
+       bucket_of_entry = (nlp->svalue - lowpc) / scale;
+       bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
+       if (bucket_of_entry < bucket_of_code) {
+#          ifdef DEBUG
+               if (debug & SAMPLEDEBUG) {
+                   printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
+                           nlp->svalue, nlp->svalue + UNITS_TO_CODE);
+               }
+#          endif DEBUG
+           nlp->svalue += UNITS_TO_CODE;
+       }
+    }
+}
+
+bool
+funcsymbol( nlistp )
+    struct nlist       *nlistp;
 {
 {
-    double d;
-
-    d = (*npp2)->time - (*npp1)->time;
-    if (d > 0.0)
-       return(1);
-    if (d < 0.0)
-       return(-1);
-    return(strcmp((*npp1)->name,(*npp2)->name));
+    extern char        *strtab;        /* string table from a.out */
+    extern int aflag;          /* if static functions aren't desired */
+    char       *name;
+
+       /*
+        *      must be a text symbol,
+        *      and static text symbols don't qualify if aflag set.
+        */
+    if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
+          || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
+       return FALSE;
+    }
+       /*
+        *      can't have any `funny' characters in name,
+        *      where `funny' includes  `.', .o file names
+        *                      and     `$', pascal labels.
+        */
+    for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
+       if ( *name == '.' || *name == '$' ) {
+           return FALSE;
+       }
+    }
+    return TRUE;
 }
 
 done()
 }
 
 done()