* 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\
#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;
char **sp;
nltype **timesortnlp;
+ whoami = argv[0];
--argc;
argv++;
debug = 0;
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++;
}
* 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
*/
*/
getnfile()
{
- bfd *abfd;
int valcmp();
abfd = bfd_openr (a_outname, NULL);
# 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++) {
# 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" ,
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:
FILE *pfile;
FILE *openpfile();
struct rawarc arc;
+ struct veryrawarc rawarc;
pfile = openpfile(filename);
readsamples(pfile);
* 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" ,
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);
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 ) {
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();
+ }
}
/*
asgnsamples()
{
register int j;
- UNIT ccnt;
+ int ccnt;
double time;
unsigned long pcl, pch;
register int i;
/* 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];
{
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;
}