allow only /bin/csh, not /bin/oldcsh
[unix-history] / usr / src / usr.bin / gprof / gprof.c
index 095b8ad..3868583 100644 (file)
@@ -1,30 +1,74 @@
 #ifndef lint
 #ifndef lint
-    static     char *sccsid = "@(#)gprof.c     1.5 (Berkeley) %G%";
+    static     char *sccsid = "@(#)gprof.c     1.18 (Berkeley) %G%";
 #endif lint
 
 #include "gprof.h"
 
 #endif lint
 
 #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;
     while ( *argv != 0 && **argv == '-' ) {
        (*argv)++;
 
     --argc;
     argv++;
     debug = 0;
     while ( *argv != 0 && **argv == '-' ) {
        (*argv)++;
-       if ( **argv == 'd' ) {
+       switch ( **argv ) {
+       case 'a':
+           aflag = TRUE;
+           break;
+       case 'b':
+           bflag = TRUE;
+           break;
+       case 'c':
+           cflag = TRUE;
+           break;
+       case 'd':
+           dflag = TRUE;
            (*argv)++;
            debug |= atoi( *argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
                printf( "[main] debug = %d\n" , debug );
 #          endif DEBUG
            (*argv)++;
            debug |= atoi( *argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
                printf( "[main] debug = %d\n" , debug );
 #          endif DEBUG
-       } else if ( **argv == 'z' ) {
-           zflg++;
-       } else if ( **argv == 'c' ) {
-           cflag++;
+           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++;
     }
@@ -39,6 +83,15 @@ main(argc, argv)
        argv++;
     } else {
        gmonname = GMONNAME;
        argv++;
     } else {
        gmonname = GMONNAME;
+    }
+       /*
+        *      turn off default functions
+        */
+    for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
+       Eflag = TRUE;
+       addlist( Elist , *sp );
+       eflag = TRUE;
+       addlist( elist , *sp );
     }
        /*
         *      get information about a.out file.
     }
        /*
         *      get information about a.out file.
@@ -47,7 +100,18 @@ main(argc, argv)
        /*
         *      get information about mon.out file(s).
         */
        /*
         *      get information about mon.out file(s).
         */
-    getpfile( gmonname );
+    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
         */
@@ -63,11 +127,11 @@ main(argc, argv)
     done();
 }
 
     done();
 }
 
-/*
- * Set up string and symbol tables from a.out.
*     and optionally the text space.
- * On return symbol table is sorted by value.
- */
+    /*
    * Set up string and symbol tables from a.out.
    * and optionally the text space.
    * On return symbol table is sorted by value.
    */
 getnfile()
 {
     FILE       *nfile;
 getnfile()
 {
     FILE       *nfile;
@@ -79,7 +143,7 @@ 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);
        done();
     }
     getstrtab(nfile);
@@ -104,17 +168,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();
     }
 }
@@ -134,27 +200,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();
     }
 
@@ -164,7 +223,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;
@@ -195,14 +260,15 @@ gettextspace( nfile )
     }
     textspace = malloc( xbuf.a_text );
     if ( textspace == 0 ) {
     }
     textspace = malloc( xbuf.a_text );
     if ( textspace == 0 ) {
-       fprintf( stderr , "gprof: ran out room for %d bytes of text space:  " );
-       fprintf( stderr , "can't do -c\n" , xbuf.a_text );
+       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 ) {
        return;
     }
     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
-       fprintf( stderr , "couldn't read text space:  " );
-       fprintf( stderr , "can't do -c\n" , xbuf.a_text );
+       fprintf( stderr , "%s: couldn't read text space:  " , whoami );
+       fprintf( stderr , "can't do -c\n" );
        free( textspace );
        textspace = 0;
        return;
        free( textspace );
        textspace = 0;
        return;
@@ -245,19 +311,38 @@ FILE *
 openpfile(filename)
     char *filename;
 {
 openpfile(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);
+    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;
     s_lowpc = (unsigned long) h.lowpc;
     s_highpc = (unsigned long) h.highpc;
-    lowpc = h.lowpc - (UNIT *)0;
-    highpc = h.highpc - (UNIT *)0;
+    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);
 }
 
@@ -279,6 +364,58 @@ tally( rawp )
     addarc( parentp , childp , 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 - 1 ; 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();
+           }
+#          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
+       }
+    }
+    fclose( sfile );
+}
+
 valcmp(p1, p2)
     nltype *p1, *p2;
 {
 valcmp(p1, p2)
     nltype *p1, *p2;
 {
@@ -300,8 +437,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();
        }
     }
@@ -313,8 +450,8 @@ 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();
     }
 }
@@ -335,7 +472,7 @@ asgnsamples()
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
     scale /= nsamples;
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
     scale /= nsamples;
-    for (i=0; i < nsamples; i++) {
+    for (i = 0, j = 1; i < nsamples; i++) {
        ccnt = samples[i];
        if (ccnt == 0)
                continue;
        ccnt = samples[i];
        if (ccnt == 0)
                continue;
@@ -344,12 +481,12 @@ asgnsamples()
        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++) {
+       for (j = j - 1; j < nname; j++) {
            svalue0 = nl[j].value / sizeof(UNIT);
            svalue1 = nl[j+1].value / sizeof(UNIT);
            if (pch < svalue0)
            svalue0 = nl[j].value / sizeof(UNIT);
            svalue1 = nl[j+1].value / sizeof(UNIT);
            if (pch < svalue0)
@@ -360,8 +497,9 @@ asgnsamples()
            if (overlap>0) {
 #              ifdef DEBUG
                    if ( debug & SAMPLEDEBUG ) {
            if (overlap>0) {
 #              ifdef DEBUG
                    if ( debug & SAMPLEDEBUG ) {
-                       printf( "[asgnsamples] %s gets %f ticks\n" ,
-                               nl[j].name , overlap*time/scale );
+                       printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" ,
+                               svalue0 , svalue1 , nl[j].name , 
+                               overlap*time/scale );
                    }
 #              endif DEBUG
                nl[j].time += overlap*time/scale;
                    }
 #              endif DEBUG
                nl[j].time += overlap*time/scale;
@@ -373,10 +511,6 @@ asgnsamples()
            printf( "[asgnsamples] totime %f\n" , totime );
        }
 #   endif DEBUG
            printf( "[asgnsamples] totime %f\n" , totime );
        }
 #   endif DEBUG
-    if (totime==0.0) {
-       fprintf( stderr , "No time accumulated\n" );
-       totime=1.0;
-    }
 }
 
 
 }
 
 
@@ -398,6 +532,35 @@ max(a, b)
     return(b);
 }
 
     return(b);
 }
 
+bool
+funcsymbol( nlistp )
+    struct nlist       *nlistp;
+{
+    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()
 {