* elf.c (_bfd_elf_make_section_from_shdr): Only set SEC_DATA if
[deliverable/binutils-gdb.git] / gprof / gprof.c
index 9cf6447b3b791a15c4af42ae5817d13299a1ac87..c8e0995543bcf81bcc6cf2ac8d9a26c9c4e10771 100644 (file)
@@ -17,6 +17,8 @@
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
+#define VERSION "5.6 (Cygnus)"
+
 #ifndef lint
 char copyright[] =
 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
@@ -29,13 +31,22 @@ static char sccsid[] = "@(#)gprof.c 5.6 (Berkeley) 6/1/90";
 
 #include "gprof.h"
 
-char   *whoami = "gprof";
+#ifndef FOPEN_RB
+#define FOPEN_RB "r"
+#endif
+
+bfd    *abfd;
+
+char   *whoami;
 
     /*
      * things which get -E excluded by default.
      */
 char   *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
 
+int discard_underscores = 1; /* Should we discard initial underscores? */
+int bsd_style_output = 0; /* As opposed to FSF style output */
+
 main(argc, argv)
     int argc;
     char **argv;
@@ -43,6 +54,7 @@ main(argc, argv)
     char       **sp;
     nltype     **timesortnlp;
 
+    whoami = argv[0];
     --argc;
     argv++;
     debug = 0;
@@ -100,9 +112,22 @@ main(argc, argv)
        case 's':
            sflag = TRUE;
            break;
+       case 'T': /* "Traditional" output format */
+           bsd_style_output = 1;
+           break;
+        case 'v':
+           printf ("gprof version %s\n", VERSION);
+           exit(0);
+           break;
        case 'z':
            zflag = TRUE;
            break;
+       default:
+           fprintf (stderr, "\
+Usage: %s [-a] [-b] [-c] [-d[num]] [-E function-name] [-e function-name]\n\
+       [-F function-name] [-f function-name] [-k from to] [-s] [-T] [-z]\n\
+       [image-file] [profile-file...]\n", whoami);
+           exit (1);
        }
        argv++;
     }
@@ -163,14 +188,14 @@ main(argc, argv)
         *      assemble the dynamic profile
         */
     timesortnlp = doarcs();
-       /*
-        *      print the dynamic profile
-        */
-    printgprof( timesortnlp ); 
-       /*
-        *      print the flat profile
-        */
-    printprof();       
+       
+    if (bsd_style_output) {
+       printgprof( timesortnlp );      /* print the dynamic profile */
+       printprof();  /* print the flat profile */
+    } else {
+       printprof();  /* print the flat profile */
+       printgprof( timesortnlp );      /* print the dynamic profile */
+    }
        /*
         *      print the index
         */
@@ -185,7 +210,6 @@ main(argc, argv)
      */
 getnfile()
 {
-  bfd  *abfd;
   int          valcmp();
 
   abfd = bfd_openr (a_outname, NULL);
@@ -216,45 +240,33 @@ getnfile()
 #   endif DEBUG
 }
 
-#if 0
-getstrtab(nfile)
-    FILE       *nfile;
-{
-
-    fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
-    if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
-       fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
-               whoami , a_outname );
-       done();
-    }
-    strtab = (char *)calloc(ssiz, 1);
-    if (strtab == NULL) {
-       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) {
-       fprintf(stderr, "%s: %s: error reading string table\n",
-               whoami , a_outname );
-       done();
-    }
-}
-#endif /* 0 */
-    /*
-     * Read in symbol table
-     */
+/*
+ * Read in symbol table
+ */
 getsymtab(abfd)
 bfd    *abfd;
 {
     register long      i;
     int                        askfor;
-    int                        nosyms;
+    long               nosyms;
     asymbol            **syms;
-    i = get_symtab_upper_bound (abfd); /* This will probably give us more
-                                        * than we need, but that's ok.
-                                        */
-    syms = malloc (i);
+    i = bfd_get_symtab_upper_bound (abfd);/* This will probably give us more
+                                          * than we need, but that's ok.
+                                          */
+    if (i < 0)
+      {
+       fprintf (stderr, "%s: %s: %s\n", whoami, a_outname,
+                bfd_errmsg (bfd_get_error ()));
+       exit (1);
+      }
+    syms = (asymbol**)xmalloc (i);
     nosyms = bfd_canonicalize_symtab (abfd, syms);
+    if (nosyms < 0)
+      {
+       fprintf (stderr, "%s: %s: %s\n", whoami, a_outname,
+                bfd_errmsg (bfd_get_error ()));
+       exit (1);
+      }
 
     nname = 0;
     for (i = 0; i < nosyms; i++) {
@@ -288,8 +300,16 @@ bfd        *abfd;
 #          endif DEBUG
        continue;
       }
+      /* Symbol offsets are always section-relative. */
       npe->value = syms[i]->value + syms[i]->section->vma;
       npe->name = syms[i]->name;
+
+      /* If we see "main" without an initial '_', we assume
+        names are *not* prefixed by '_'. */
+      if (npe->name[0] == 'm' && discard_underscores
+         && strcmp(npe->name, "main") == 0)
+         discard_underscores = 0;
+
 #      ifdef DEBUG
       if ( debug & AOUTDEBUG ) {
        printf( "[getsymtab] %d %s 0x%08x\n" ,
@@ -319,16 +339,16 @@ gettextspace( abfd )
     return;
   }
 
-  textspace = (u_char *) malloc( texsec->size );
+  textspace = (u_char *) malloc( texsec->_cooked_size );
 
   if ( textspace == 0 ) {
     fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
-           whoami , texsec->size);
+           whoami , texsec->_cooked_size);
     fprintf( stderr , "can't do -c\n" );
     return;
   }
   bfd_get_section_contents (abfd, texsec, textspace, texsec->filepos, 
-                           texsec->size);
+                           texsec->_cooked_size);
 }
 /*
  *     information from a gmon.out file is in two parts:
@@ -341,6 +361,7 @@ getpfile(filename)
     FILE               *pfile;
     FILE               *openpfile();
     struct rawarc      arc;
+    struct veryrawarc  rawarc;
 
     pfile = openpfile(filename);
     readsamples(pfile);
@@ -348,7 +369,10 @@ getpfile(filename)
         *      the rest of the file consists of
         *      a bunch of <from,self,count> tuples.
         */
-    while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
+    while ( fread( &rawarc , sizeof rawarc , 1 , pfile ) == 1 ) {
+      arc.raw_frompc = bfd_get_32 (abfd, (bfd_byte *) rawarc.raw_frompc);
+      arc.raw_selfpc = bfd_get_32 (abfd, (bfd_byte *) rawarc.raw_selfpc);
+      arc.raw_count  = bfd_get_32 (abfd, (bfd_byte *) rawarc.raw_count);
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
                printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
@@ -368,13 +392,22 @@ openpfile(filename)
     char *filename;
 {
     struct hdr tmp;
+    struct rawhdr raw;
     FILE       *pfile;
 
-    if((pfile = fopen(filename, "r")) == NULL) {
+    if((pfile = fopen(filename, FOPEN_RB)) == NULL) {
        perror(filename);
        done();
     }
-    fread(&tmp, sizeof(struct hdr), 1, pfile);
+    if (sizeof(struct rawhdr) !=  fread(&raw, 1, sizeof(struct rawhdr), pfile))
+      {
+       fprintf(stderr, "%s: file too short to be a gmon file\n", filename);
+       done();
+      }    
+    tmp.lowpc  = (UNIT *)bfd_get_32 (abfd, (bfd_byte *) &raw.lowpc[0]);
+    tmp.highpc = (UNIT *)bfd_get_32 (abfd, (bfd_byte *) &raw.highpc[0]);
+    tmp.ncnt   =         bfd_get_32 (abfd, (bfd_byte *) &raw.ncnt[0]);
+
     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);
@@ -385,7 +418,7 @@ openpfile(filename)
     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);
+    sampbytes = h.ncnt - sizeof(struct rawhdr);
     nsamples = sampbytes / sizeof (UNIT);
 #   ifdef DEBUG
        if ( debug & SAMPLEDEBUG ) {
@@ -492,29 +525,33 @@ valcmp(p1, p2)
 readsamples(pfile)
     FILE       *pfile;
 {
-    register i;
-    UNIT       sample;
+  register i;
+
     
+  if (samples == 0) {
+    samples = (int *) calloc (nsamples, sizeof(int));
     if (samples == 0) {
-       samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
-       if (samples == 0) {
-           fprintf( stderr , "%s: No room for %d sample pc's\n", 
-               whoami , sampbytes / sizeof (UNIT));
-           done();
-       }
-    }
-    for (i = 0; i < nsamples; i++) {
-       fread(&sample, sizeof (UNIT), 1, pfile);
-       if (feof(pfile))
-               break;
-       samples[i] += sample;
+      fprintf( stderr , "%s: No room for %d sample pc's\n", 
+             whoami , nsamples);
+      done();
     }
-    if (i != nsamples) {
-       fprintf(stderr,
+  }
+  for (i = 0; i < nsamples; i++) {
+    UNIT       raw;
+    int value;
+      
+    fread(raw, sizeof (raw), 1, pfile);
+    value = bfd_get_16 (abfd, (bfd_byte *) raw);
+    if (feof(pfile))
+      break;
+    samples[i] += value;
+  }
+  if (i != nsamples) {
+    fprintf(stderr,
            "%s: unexpected EOF after reading %d/%d samples\n",
-               whoami , --i , nsamples );
-       done();
-    }
+           whoami , --i , nsamples );
+    done();
+  }
 }
 
 /*
@@ -552,7 +589,7 @@ readsamples(pfile)
 asgnsamples()
 {
     register int       j;
-    UNIT               ccnt;
+    int                ccnt;
     double             time;
     unsigned long      pcl, pch;
     register int       i;
@@ -561,7 +598,7 @@ asgnsamples()
 
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
-    scale /= nsamples;
+    scale /= nsamples - 1;
     alignentries();
     for (i = 0, j = 1; i < nsamples; i++) {
        ccnt = samples[i];
@@ -666,33 +703,83 @@ funcsymbol( symp )
 {
   extern char  *strtab;        /* string table from a.out */
   extern int   aflag;          /* if static functions aren't desired */
-  char *name;
-  
+  CONST char   *name;
+  int i;
+  char         symprefix;
+  symbol_info  syminfo;
+
   /*
    *   must be a text symbol,
    *   and static text symbols don't qualify if aflag set.
    */
   
+
   if (!symp->section)
     return FALSE;
 
-  if (!aflag && (symp->flags&BSF_LOCAL)) {
-#ifdef DEBUG
+  if (aflag && (symp->flags&BSF_LOCAL)) {
+#if defined(DEBUG)
     fprintf (stderr, "%s(%d):  %s:  not a function\n", __FILE__, __LINE__, symp->name);
 #endif
     return FALSE;
   }
 
+
+  symprefix = bfd_get_symbol_leading_char (abfd);
+  bfd_get_symbol_info (abfd, symp, &syminfo);
+  i = syminfo.type;
+#if defined(DEBUG) && 0
+  if (i != 'T' && i != 't')
+    fprintf (stderr, "%s(%d):  %s is of class %c\n", __FILE__, __LINE__, symp->name, i);
+#endif
+
+  /*
+   * Any external text symbol should be okay.  (Only problem would be
+   * variables in the text section.)
+   */
+
+  if (i == 'T')
+    return TRUE;
+
+  /*
+   * 't' is static text; -a says to ignore it.  So if it's not
+   * a static text symbol, *or* it is and the user gave -a, we
+   * ignore it.
+   */
+
+  if (i != 't' || aflag)
+    return FALSE;
+
   /*
    *   can't have any `funny' characters in name,
    *   where `funny' includes  `.', .o file names
    *                   and     `$', pascal labels.
    */
+  if (!symp->name)
+    return FALSE;
+
   for (name = symp->name; *name; name++) {
     if ( *name == '.' || *name == '$' ) {
       return FALSE;
     }
   }
+
+  /* On systems where the C compiler adds an underscore to all names,
+   * static names without underscores seem usually to be labels in
+   * hand written assembler in the library.  We don't want these
+   * names.  This is certainly necessary on a Sparc running SunOS 4.1
+   * (try profiling a program that does a lot of division). I don't
+   * know whether it has harmful side effects on other systems.
+   * Perhaps it should be made configurable.
+   */
+
+  if (symprefix && symprefix != *symp->name
+      /* Gcc may add special symbols to help gdb figure out the file
+        language.  We want to ignore these, since sometimes they
+        mask the real function.  (dj@ctron)  */
+      || !strncmp (symp->name, "__gnu_compiled", 14))
+    return FALSE;
+
   return TRUE;
 }
 
This page took 0.045821 seconds and 4 git commands to generate.