X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gprof%2Fgprof.c;h=da1411b30a6e20d964cedd287ce77020a854af88;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=809843800a58fa99acd36cf88caf53560edf658b;hpb=9d65137307d0efc6f2623614747ffc30b4ef26eb;p=deliverable%2Fbinutils-gdb.git diff --git a/gprof/gprof.c b/gprof/gprof.c index 809843800a..da1411b30a 100644 --- a/gprof/gprof.c +++ b/gprof/gprof.c @@ -1,721 +1,653 @@ /* - * Copyright (c) 1983 Regents of the University of California. - * All rights reserved. + * Copyright (c) 1983, 1993, 1998, 2001, 2002 + * The Regents of the University of California. All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that: (1) source distributions retain this entire copyright - * notice and comment, and (2) distributions including binaries display - * the following acknowledgement: ``This product includes software - * developed by the University of California, Berkeley and its contributors'' - * in the documentation or other materials provided with the distribution - * and in all advertising materials mentioning features or use of this - * software. Neither the name of the University nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#ifndef lint +#include "gprof.h" +#include "libiberty.h" +#include "bfdver.h" +#include "search_list.h" +#include "source.h" +#include "symtab.h" +#include "basic_blocks.h" +#include "call_graph.h" +#include "cg_arcs.h" +#include "cg_print.h" +#include "corefile.h" +#include "gmon_io.h" +#include "hertz.h" +#include "hist.h" +#include "sym_ids.h" +#include "demangle.h" +#include "getopt.h" + +static void usage (FILE *, int) ATTRIBUTE_NORETURN; + +const char * whoami; +const char * function_mapping_file; +static const char * external_symbol_table; +const char * a_out_name = A_OUTNAME; +long hz = HZ_WRONG; + +/* + * Default options values: + */ +int debug_level = 0; +int output_style = 0; +int output_width = 80; +bfd_boolean bsd_style_output = FALSE; +bfd_boolean demangle = TRUE; +bfd_boolean ignore_direct_calls = FALSE; +bfd_boolean ignore_static_funcs = FALSE; +bfd_boolean ignore_zeros = TRUE; +bfd_boolean line_granularity = FALSE; +bfd_boolean print_descriptions = TRUE; +bfd_boolean print_path = FALSE; +bfd_boolean ignore_non_functions = FALSE; +bfd_boolean inline_file_names = FALSE; +File_Format file_format = FF_AUTO; + +bfd_boolean first_output = TRUE; + char copyright[] = -"@(#) Copyright (c) 1983 Regents of the University of California.\n\ + "@(#) Copyright (c) 1983 Regents of the University of California.\n\ All rights reserved.\n"; -#endif /* not lint */ -#ifndef lint -static char sccsid[] = "@(#)gprof.c 5.6 (Berkeley) 6/1/90"; -#endif /* not lint */ +static char *gmon_name = GMONNAME; /* profile filename */ -#include "gprof.h" +/* + * Functions that get excluded by default: + */ +static char *default_excluded_list[] = +{ + "_gprof_mcount", "mcount", "_mcount", "__mcount", "__mcount_internal", + "__mcleanup", + 0 +}; -bfd *abfd; +/* Codes used for the long options with no short synonyms. 150 isn't + special; it's just an arbitrary non-ASCII char value. */ -char *whoami = "gprof"; +#define OPTION_DEMANGLE (150) +#define OPTION_NO_DEMANGLE (OPTION_DEMANGLE + 1) +#define OPTION_INLINE_FILE_NAMES (OPTION_DEMANGLE + 2) +static struct option long_options[] = +{ + {"line", no_argument, 0, 'l'}, + {"no-static", no_argument, 0, 'a'}, + {"ignore-non-functions", no_argument, 0, 'D'}, + {"external-symbol-table", required_argument, 0, 'S'}, + + /* output styles: */ + + {"annotated-source", optional_argument, 0, 'A'}, + {"no-annotated-source", optional_argument, 0, 'J'}, + {"flat-profile", optional_argument, 0, 'p'}, + {"no-flat-profile", optional_argument, 0, 'P'}, + {"graph", optional_argument, 0, 'q'}, + {"no-graph", optional_argument, 0, 'Q'}, + {"exec-counts", optional_argument, 0, 'C'}, + {"no-exec-counts", optional_argument, 0, 'Z'}, + {"function-ordering", no_argument, 0, 'r'}, + {"file-ordering", required_argument, 0, 'R'}, + {"file-info", no_argument, 0, 'i'}, + {"sum", no_argument, 0, 's'}, + + /* various options to affect output: */ + + {"all-lines", no_argument, 0, 'x'}, + {"demangle", optional_argument, 0, OPTION_DEMANGLE}, + {"no-demangle", no_argument, 0, OPTION_NO_DEMANGLE}, + {"directory-path", required_argument, 0, 'I'}, + {"display-unused-functions", no_argument, 0, 'z'}, + {"inline-file-names", no_argument, 0, OPTION_INLINE_FILE_NAMES}, + {"min-count", required_argument, 0, 'm'}, + {"print-path", no_argument, 0, 'L'}, + {"separate-files", no_argument, 0, 'y'}, + {"static-call-graph", no_argument, 0, 'c'}, + {"table-length", required_argument, 0, 't'}, + {"time", required_argument, 0, 'n'}, + {"no-time", required_argument, 0, 'N'}, + {"width", required_argument, 0, 'w'}, /* - * things which get -E excluded by default. + * These are for backwards-compatibility only. Their functionality + * is provided by the output style options already: */ -char *defaultEs[] = { "mcount" , "__mcleanup" , 0 }; + {"", required_argument, 0, 'e'}, + {"", required_argument, 0, 'E'}, + {"", required_argument, 0, 'f'}, + {"", required_argument, 0, 'F'}, + {"", required_argument, 0, 'k'}, + + /* miscellaneous: */ + + {"brief", no_argument, 0, 'b'}, + {"debug", optional_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {"file-format", required_argument, 0, 'O'}, + {"traditional", no_argument, 0, 'T'}, + {"version", no_argument, 0, 'v'}, + {0, no_argument, 0, 0} +}; + + +static void +usage (FILE *stream, int status) +{ + fprintf (stream, _("\ +Usage: %s [-[abcDhilLrsTvwxyz]] [-[ACeEfFJnNOpPqQRStZ][name]] [-I dirs]\n\ + [-d[num]] [-k from/to] [-m min-count] [-t table-length]\n\ + [--[no-]annotated-source[=name]] [--[no-]exec-counts[=name]]\n\ + [--[no-]flat-profile[=name]] [--[no-]graph[=name]]\n\ + [--[no-]time=name] [--all-lines] [--brief] [--debug[=level]]\n\ + [--function-ordering] [--file-ordering] [--inline-file-names]\n\ + [--directory-path=dirs] [--display-unused-functions]\n\ + [--file-format=name] [--file-info] [--help] [--line] [--min-count=n]\n\ + [--no-static] [--print-path] [--separate-files]\n\ + [--static-call-graph] [--sum] [--table-length=len] [--traditional]\n\ + [--version] [--width=n] [--ignore-non-functions]\n\ + [--demangle[=STYLE]] [--no-demangle] [--external-symbol-table=name] [@FILE]\n\ + [image-file] [profile-file...]\n"), + whoami); + if (REPORT_BUGS_TO[0] && status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); + done (status); +} -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; +int +main (int argc, char **argv) { - char **sp; - nltype **timesortnlp; - - --argc; - argv++; - debug = 0; - bflag = TRUE; - while ( *argv != 0 && **argv == '-' ) { - (*argv)++; - switch ( **argv ) { + char **sp, *str; + Sym **cg = 0; + int ch, user_specified = 0; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif +#ifdef ENABLE_NLS + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); +#endif + + whoami = argv[0]; + xmalloc_set_program_name (whoami); + + expandargv (&argc, &argv); + + while ((ch = getopt_long (argc, argv, + "aA::bBcC::d::De:E:f:F:hiI:J::k:lLm:n:N:O:p::P::q::Q::rR:sS:t:Tvw:xyzZ::", + long_options, 0)) + != EOF) + { + switch (ch) + { case 'a': - aflag = TRUE; - break; + ignore_static_funcs = TRUE; + break; + case 'A': + if (optarg) + { + sym_id_add (optarg, INCL_ANNO); + } + output_style |= STYLE_ANNOTATED_SOURCE; + user_specified |= STYLE_ANNOTATED_SOURCE; + break; case 'b': - bflag = FALSE; - break; + print_descriptions = FALSE; + break; + case 'B': + output_style |= STYLE_CALL_GRAPH; + user_specified |= STYLE_CALL_GRAPH; + break; case 'c': - cflag = TRUE; - break; + ignore_direct_calls = TRUE; + break; + case 'C': + if (optarg) + { + sym_id_add (optarg, INCL_EXEC); + } + output_style |= STYLE_EXEC_COUNTS; + user_specified |= STYLE_EXEC_COUNTS; + break; case 'd': - dflag = TRUE; - (*argv)++; - debug |= atoi( *argv ); - debug |= ANYDEBUG; -# ifdef DEBUG - printf("[main] debug = %d\n", debug); -# else not DEBUG - printf("%s: -d ignored\n", whoami); -# endif DEBUG - break; + if (optarg) + { + debug_level |= atoi (optarg); + debug_level |= ANYDEBUG; + } + else + { + debug_level = ~0; + } + DBG (ANYDEBUG, printf ("[main] debug-level=0x%x\n", debug_level)); +#ifndef DEBUG + printf (_("%s: debugging not supported; -d ignored\n"), whoami); +#endif /* DEBUG */ + break; + case 'D': + ignore_non_functions = TRUE; + break; case 'E': - ++argv; - addlist( Elist , *argv ); - Eflag = TRUE; - addlist( elist , *argv ); - eflag = TRUE; - break; + sym_id_add (optarg, EXCL_TIME); + /* Fall through. */ case 'e': - addlist( elist , *++argv ); - eflag = TRUE; - break; + sym_id_add (optarg, EXCL_GRAPH); + break; case 'F': - ++argv; - addlist( Flist , *argv ); - Fflag = TRUE; - addlist( flist , *argv ); - fflag = TRUE; - break; + sym_id_add (optarg, INCL_TIME); + /* Fall through. */ case 'f': - addlist( flist , *++argv ); - fflag = TRUE; - break; + sym_id_add (optarg, INCL_GRAPH); + break; + /* FIXME: The -g and -G options are not present in the getopt_long + invocation above, and they are not documented in gprof.texi. + Therefore they appear to be deprecated. Test this theory and + delete them if true. */ + case 'g': + sym_id_add (optarg, EXCL_FLAT); + break; + case 'G': + sym_id_add (optarg, INCL_FLAT); + break; + case 'h': + usage (stdout, 0); + case 'i': + output_style |= STYLE_GMON_INFO; + user_specified |= STYLE_GMON_INFO; + break; + case 'I': + search_list_append (&src_search_list, optarg); + break; + case 'J': + if (optarg) + { + sym_id_add (optarg, EXCL_ANNO); + output_style |= STYLE_ANNOTATED_SOURCE; + } + else + { + output_style &= ~STYLE_ANNOTATED_SOURCE; + } + user_specified |= STYLE_ANNOTATED_SOURCE; + break; case 'k': - addlist( kfromlist , *++argv ); - addlist( ktolist , *++argv ); - kflag = TRUE; - break; + sym_id_add (optarg, EXCL_ARCS); + break; + case 'l': + line_granularity = TRUE; + break; + case 'L': + print_path = TRUE; + break; + case 'm': + bb_min_calls = (unsigned long) strtoul (optarg, (char **) NULL, 10); + break; + case 'n': + sym_id_add (optarg, INCL_TIME); + break; + case 'N': + sym_id_add (optarg, EXCL_TIME); + break; + case 'O': + switch (optarg[0]) + { + case 'a': + file_format = FF_AUTO; + break; + case 'm': + file_format = FF_MAGIC; + break; + case 'b': + file_format = FF_BSD; + break; + case '4': + file_format = FF_BSD44; + break; + case 'p': + file_format = FF_PROF; + break; + default: + fprintf (stderr, _("%s: unknown file format %s\n"), + optarg, whoami); + done (1); + } + break; + case 'p': + if (optarg) + { + sym_id_add (optarg, INCL_FLAT); + } + output_style |= STYLE_FLAT_PROFILE; + user_specified |= STYLE_FLAT_PROFILE; + break; + case 'P': + if (optarg) + { + sym_id_add (optarg, EXCL_FLAT); + output_style |= STYLE_FLAT_PROFILE; + } + else + { + output_style &= ~STYLE_FLAT_PROFILE; + } + user_specified |= STYLE_FLAT_PROFILE; + break; + case 'q': + if (optarg) + { + if (strchr (optarg, '/')) + { + sym_id_add (optarg, INCL_ARCS); + } + else + { + sym_id_add (optarg, INCL_GRAPH); + } + } + output_style |= STYLE_CALL_GRAPH; + user_specified |= STYLE_CALL_GRAPH; + break; + case 'r': + output_style |= STYLE_FUNCTION_ORDER; + user_specified |= STYLE_FUNCTION_ORDER; + break; + case 'R': + output_style |= STYLE_FILE_ORDER; + user_specified |= STYLE_FILE_ORDER; + function_mapping_file = optarg; + break; + case 'Q': + if (optarg) + { + if (strchr (optarg, '/')) + { + sym_id_add (optarg, EXCL_ARCS); + } + else + { + sym_id_add (optarg, EXCL_GRAPH); + } + output_style |= STYLE_CALL_GRAPH; + } + else + { + output_style &= ~STYLE_CALL_GRAPH; + } + user_specified |= STYLE_CALL_GRAPH; + break; case 's': - sflag = TRUE; - break; - case 'T': /* "Traditional" output format */ - bsd_style_output = 1; - break; + output_style |= STYLE_SUMMARY_FILE; + user_specified |= STYLE_SUMMARY_FILE; + break; + case 'S': + external_symbol_table = optarg; + DBG (AOUTDEBUG, printf ("external-symbol-table: %s\n", optarg)); + break; + case 't': + bb_table_length = atoi (optarg); + if (bb_table_length < 0) + { + bb_table_length = 0; + } + break; + case 'T': + bsd_style_output = TRUE; + break; + case 'v': + /* This output is intended to follow the GNU standards document. */ + printf (_("GNU gprof %s\n"), BFD_VERSION_STRING); + printf (_("Based on BSD gprof, copyright 1983 Regents of the University of California.\n")); + printf (_("\ +This program is free software. This program has absolutely no warranty.\n")); + done (0); + case 'w': + output_width = atoi (optarg); + if (output_width < 1) + { + output_width = 1; + } + break; + case 'x': + bb_annotate_all_lines = TRUE; + break; + case 'y': + create_annotation_files = TRUE; + break; case 'z': - zflag = TRUE; - break; + ignore_zeros = FALSE; + break; + case 'Z': + if (optarg) + { + sym_id_add (optarg, EXCL_EXEC); + output_style |= STYLE_EXEC_COUNTS; + } + else + { + output_style &= ~STYLE_EXEC_COUNTS; + } + user_specified |= STYLE_EXEC_COUNTS; + break; + case OPTION_DEMANGLE: + demangle = TRUE; + if (optarg != NULL) + { + enum demangling_styles style; + + style = cplus_demangle_name_to_style (optarg); + if (style == unknown_demangling) + { + fprintf (stderr, + _("%s: unknown demangling style `%s'\n"), + whoami, optarg); + xexit (1); + } + + cplus_demangle_set_style (style); + } + break; + case OPTION_NO_DEMANGLE: + demangle = FALSE; + break; + case OPTION_INLINE_FILE_NAMES: + inline_file_names = TRUE; + break; default: - fprintf (stderr, "usage: gprof [-a] [-b] [-c] [-d[num]] \ -[-E function-name] [-e function-name] \ -[-F function-name] [-f function-name] \ -[-k from to] [-s] [-T] [-z] [image-file] \ -[profile file]\n"); - exit (1); + usage (stderr, 1); } - argv++; - } - if ( *argv != 0 ) { - a_outname = *argv; - argv++; - } else { - a_outname = A_OUTNAME; - } - if ( *argv != 0 ) { - gmonname = *argv; - argv++; - } else { - gmonname = GMONNAME; - } - /* - * turn off default functions - */ - for ( sp = &defaultEs[0] ; *sp ; sp++ ) { - Eflag = TRUE; - addlist( Elist , *sp ); - eflag = TRUE; - addlist( elist , *sp ); - } - /* - * how many ticks per second? - * if we can't tell, report time in ticks. - */ - hz = hertz(); - if (hz == 0) { - hz = 1; - fprintf(stderr, "time is in ticks, not seconds\n"); - } - /* - * get information about a.out file. - */ - getnfile(); - /* - * get information about mon.out file(s). - */ - 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 - */ - asgnsamples(); - /* - * assemble the dynamic profile - */ - timesortnlp = doarcs(); - - 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 - */ - printindex(); - done(); -} - - /* - * Set up string and symbol tables from a.out. - * and optionally the text space. - * On return symbol table is sorted by value. - */ -getnfile() -{ - int valcmp(); - - abfd = bfd_openr (a_outname, NULL); - - if (abfd == NULL) { - perror (a_outname); - done(); - } - - if (!bfd_check_format (abfd, bfd_object)) { - fprintf (stderr, "%s: %s: bad format\n", whoami, a_outname); - done(); - } - -/* getstrtab(nfile); */ - getsymtab(abfd); - gettextspace( abfd ); - qsort(nl, nname, sizeof(nltype), valcmp); - -# ifdef DEBUG - if ( debug & AOUTDEBUG ) { - register int j; - - for (j = 0; j < nname; j++){ - printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); } - } -# endif DEBUG -} -/* - * Read in symbol table - */ -getsymtab(abfd) -bfd *abfd; -{ - register long i; - int askfor; - int nosyms; - asymbol **syms; - i = get_symtab_upper_bound (abfd); /* This will probably give us more - * than we need, but that's ok. - */ - syms = (asymbol**)xmalloc (i); - nosyms = bfd_canonicalize_symtab (abfd, syms); - - nname = 0; - for (i = 0; i < nosyms; i++) { - if (!funcsymbol (syms[i])) - continue; - nname++; + /* Don't allow both ordering options, they modify the arc data in-place. */ + if ((user_specified & STYLE_FUNCTION_ORDER) + && (user_specified & STYLE_FILE_ORDER)) + { + fprintf (stderr,_("\ +%s: Only one of --function-ordering and --file-ordering may be specified.\n"), + whoami); + done (1); } - if (nname == 0) { - fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); - done(); - } - askfor = nname + 1; - nl = (nltype *) calloc( askfor , sizeof(nltype) ); - if (nl == 0) { - fprintf(stderr, "%s: No room for %d bytes of symbol table\n", - whoami, askfor * sizeof(nltype) ); - done(); - } + /* --sum implies --line, otherwise we'd lose basic block counts in + gmon.sum */ + if (output_style & STYLE_SUMMARY_FILE) + line_granularity = 1; - /* pass2 - read symbols */ - npe = nl; - nname = 0; - for (i = 0; i < nosyms; i++) { - if (!funcsymbol (syms[i])) { -# ifdef DEBUG - if ( debug & AOUTDEBUG ) { - printf( "[getsymtab] rejecting: 0x%x %s\n" , - syms[i]->value, syms[i]->name); - } -# 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" , - nname , npe -> name , npe -> value ); - } -# endif DEBUG - npe++; - nname++; - } - npe->value = -1; -} + /* append value of GPROF_PATH to source search list if set: */ + str = (char *) getenv ("GPROF_PATH"); + if (str) + search_list_append (&src_search_list, str); -/* - * read in the text space of an a.out file - */ -gettextspace( abfd ) - bfd *abfd; -{ - asection *texsec; - - if ( cflag == 0 ) { - return; - } - - texsec = bfd_get_section_by_name (abfd, ".text"); - if (texsec == NULL) { - return; - } - - textspace = (u_char *) malloc( texsec->_cooked_size ); - - if ( textspace == 0 ) { - fprintf( stderr , "%s: ran out room for %d bytes of text space: " , - whoami , texsec->_cooked_size); - fprintf( stderr , "can't do -c\n" ); - return; - } - bfd_get_section_contents (abfd, texsec, textspace, texsec->filepos, - texsec->_cooked_size); -} -/* - * information from a gmon.out file is in two parts: - * an array of sampling hits within pc ranges, - * and the arcs. - */ -getpfile(filename) - char *filename; -{ - FILE *pfile; - FILE *openpfile(); - struct rawarc arc; - - pfile = openpfile(filename); - readsamples(pfile); - /* - * the rest of the file consists of - * a bunch of tuples. - */ - while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { - arc.raw_frompc = bfd_get_32 (abfd, (bfd_byte *) &arc.raw_frompc); - arc.raw_selfpc = bfd_get_32 (abfd, (bfd_byte *) &arc.raw_selfpc); - arc.raw_count = bfd_get_32 (abfd, (bfd_byte *) &arc.raw_count); -# ifdef DEBUG - if ( debug & SAMPLEDEBUG ) { - printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , - arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); - } -# endif DEBUG - /* - * add this arc - */ - tally( &arc ); - } - fclose(pfile); -} + if (optind < argc) + a_out_name = argv[optind++]; -FILE * -openpfile(filename) - char *filename; -{ - struct hdr tmp; - FILE *pfile; + if (optind < argc) + gmon_name = argv[optind++]; - if((pfile = fopen(filename, "r")) == NULL) { - perror(filename); - done(); + /* Turn off default functions. */ + for (sp = &default_excluded_list[0]; *sp; sp++) + { + sym_id_add (*sp, EXCL_TIME); + sym_id_add (*sp, EXCL_GRAPH); + sym_id_add (*sp, EXCL_FLAT); } - fread(&tmp, sizeof(struct hdr), 1, pfile); - tmp.lowpc = (UNIT *)bfd_get_32 (abfd, (bfd_byte *) &tmp.lowpc); - tmp.highpc = (UNIT *)bfd_get_32 (abfd, (bfd_byte *) &tmp.highpc); - tmp.ncnt = bfd_get_32 (abfd, (bfd_byte *) &tmp.ncnt); - - 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(); + + /* Read symbol table from core file. */ + core_init (a_out_name); + + /* If we should ignore direct function calls, we need to load to + core's text-space. */ + if (ignore_direct_calls) + core_get_text_space (core_bfd); + + /* Create symbols from core image. */ + if (external_symbol_table) + core_create_syms_from (external_symbol_table); + else if (line_granularity) + core_create_line_syms (); + else + core_create_function_syms (); + + /* Translate sym specs into syms. */ + sym_id_parse (); + + if (file_format == FF_PROF) + { + fprintf (stderr, + _("%s: sorry, file format `prof' is not yet supported\n"), + whoami); + done (1); } - 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 (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 ); + else + { + /* Get information about gmon.out file(s). */ + do + { + gmon_out_read (gmon_name); + if (optind < argc) + gmon_name = argv[optind]; } -# endif DEBUG - return(pfile); -} - -tally( rawp ) - struct rawarc *rawp; -{ - nltype *parentp; - nltype *childp; - - parentp = nllookup( rawp -> raw_frompc ); - childp = nllookup( rawp -> raw_selfpc ); - if ( kflag - && onlist( kfromlist , parentp -> name ) - && onlist( ktolist , childp -> name ) ) { - return; + while (optind++ < argc); } - childp -> ncall += rawp -> raw_count; -# ifdef DEBUG - if ( debug & TALLYDEBUG ) { - printf( "[tally] arc from %s to %s traversed %d times\n" , - parentp -> name , childp -> name , rawp -> raw_count ); + + /* If user did not specify output style, try to guess something + reasonable. */ + if (output_style == 0) + { + if (gmon_input & (INPUT_HISTOGRAM | INPUT_CALL_GRAPH)) + { + if (gmon_input & INPUT_HISTOGRAM) + output_style |= STYLE_FLAT_PROFILE; + if (gmon_input & INPUT_CALL_GRAPH) + output_style |= STYLE_CALL_GRAPH; } -# endif DEBUG - addarc( parentp , childp , rawp -> raw_count ); -} + else + output_style = STYLE_EXEC_COUNTS; -/* - * 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(); + output_style &= ~user_specified; } - /* - * 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 (UNIT), nsamples, sfile) != nsamples) { - perror( sumfile ); - done(); + + /* Dump a gmon.sum file if requested (before any other + processing!) */ + if (output_style & STYLE_SUMMARY_FILE) + { + gmon_out_write (GMONSUM); } - /* - * 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(); - } -# 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 - } + + if (gmon_input & INPUT_HISTOGRAM) + { + hist_assign_samples (); } - fclose( sfile ); -} -valcmp(p1, p2) - nltype *p1, *p2; -{ - if ( p1 -> value < p2 -> value ) { - return LESSTHAN; + if (gmon_input & INPUT_CALL_GRAPH) + { + cg = cg_assemble (); } - if ( p1 -> value > p2 -> value ) { - return GREATERTHAN; + + /* Do some simple sanity checks. */ + if ((output_style & STYLE_FLAT_PROFILE) + && !(gmon_input & INPUT_HISTOGRAM)) + { + fprintf (stderr, _("%s: gmon.out file is missing histogram\n"), whoami); + done (1); } - return EQUALTO; -} -readsamples(pfile) - FILE *pfile; -{ - register i; - UNIT sample; - - if (samples == 0) { - samples = (UNIT *) malloc (sampbytes * sizeof(UNIT)); - if (samples == 0) { - fprintf( stderr , "%s: No room for %d sample pc's\n", - whoami , sampbytes / sizeof (UNIT)); - done(); - } - memset (samples, 0, sampbytes * sizeof(UNIT)); + if ((output_style & STYLE_CALL_GRAPH) && !(gmon_input & INPUT_CALL_GRAPH)) + { + fprintf (stderr, + _("%s: gmon.out file is missing call-graph data\n"), whoami); + done (1); } - for (i = 0; i < nsamples; i++) { - fread(&sample, sizeof (UNIT), 1, pfile); - sample = bfd_get_16 (abfd, (bfd_byte *) &sample); - if (feof(pfile)) - break; - samples[i] += sample; + + /* Output whatever user whishes to see. */ + if (cg && (output_style & STYLE_CALL_GRAPH) && bsd_style_output) + { + /* Print the dynamic profile. */ + cg_print (cg); } - if (i != nsamples) { - fprintf(stderr, - "%s: unexpected EOF after reading %d/%d samples\n", - whoami , --i , nsamples ); - done(); + + if (output_style & STYLE_FLAT_PROFILE) + { + /* Print the flat profile. */ + hist_print (); } -} -/* - * 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() -{ - register int j; - UNIT ccnt; - double time; - unsigned long pcl, pch; - register int i; - unsigned long overlap; - unsigned long svalue0, svalue1; - - /* read samples and assign to namelist symbols */ - scale = highpc - lowpc; - scale /= nsamples; - alignentries(); - for (i = 0, j = 1; i < nsamples; i++) { - ccnt = samples[i]; - if (ccnt == 0) - continue; - pcl = lowpc + scale * i; - pch = lowpc + scale * (i + 1); - time = ccnt; -# ifdef DEBUG - if ( debug & SAMPLEDEBUG ) { - printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , - pcl , pch , ccnt ); - } -# endif DEBUG - totime += time; - 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 low end of tick into next routine, - * go for next routine. - */ - if (pcl >= svalue1) - continue; - overlap = min(pch, svalue1) - max(pcl, svalue0); - if (overlap > 0) { -# ifdef DEBUG - 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 - nl[j].time += overlap * time / scale; - } + if (cg && (output_style & STYLE_CALL_GRAPH)) + { + if (!bsd_style_output) + { + /* Print the dynamic profile. */ + cg_print (cg); } + cg_print_index (); } -# ifdef DEBUG - if (debug & SAMPLEDEBUG) { - printf("[asgnsamples] totime %f\n", totime); - } -# endif DEBUG -} - -unsigned long -min(a, b) - unsigned long a,b; -{ - if (ab) - return(a); - return(b); -} + if (output_style & STYLE_ANNOTATED_SOURCE) + print_annotated_source (); - /* - * 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( symp ) - asymbol *symp; -{ - extern char *strtab; /* string table from a.out */ - extern int aflag; /* if static functions aren't desired */ - CONST char *name; - int i; - - /* - * 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)) { -#if defined(DEBUG) - fprintf (stderr, "%s(%d): %s: not a function\n", __FILE__, __LINE__, symp->name); -#endif - 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; - } - } + if (output_style & STYLE_FUNCTION_ORDER) + cg_print_function_ordering (); - i = bfd_decode_symclass (symp); -#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 + if (output_style & STYLE_FILE_ORDER) + cg_print_file_ordering (); - return (i == 'T' || i == 't'); + return 0; } -done() +void +done (int status) { - - exit(0); + exit (status); }