From 252b5132c753830d5fd56823373aed85f2a0db63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 3 May 1999 07:29:11 +0000 Subject: 19990502 sourceware import --- gprof/.gdbinit | 1 + gprof/ChangeLog | 1319 +++++++++++++++ gprof/Makefile.am | 74 + gprof/Makefile.in | 726 +++++++++ gprof/NOTES | 438 +++++ gprof/TEST | 7 + gprof/TODO | 72 + gprof/aclocal.m4 | 1109 +++++++++++++ gprof/alpha.c | 168 ++ gprof/basic_blocks.c | 635 ++++++++ gprof/basic_blocks.h | 23 + gprof/bb_exit_func.c | 78 + gprof/bbconv.pl | 36 + gprof/bsd_callg_bl.m | 108 ++ gprof/call_graph.c | 116 ++ gprof/call_graph.h | 13 + gprof/cg_arcs.c | 685 ++++++++ gprof/cg_arcs.h | 36 + gprof/cg_dfn.c | 281 ++++ gprof/cg_dfn.h | 17 + gprof/cg_print.c | 1276 +++++++++++++++ gprof/cg_print.h | 14 + gprof/configure | 4403 ++++++++++++++++++++++++++++++++++++++++++++++++++ gprof/configure.bat | 18 + gprof/configure.in | 29 + gprof/corefile.c | 762 +++++++++ gprof/corefile.h | 21 + gprof/flat_bl.m | 27 + gprof/fsf_callg_bl.m | 83 + gprof/gconfig.in | 129 ++ gprof/gen-c-prog.awk | 26 + gprof/gmon.h | 156 ++ gprof/gmon_io.c | 454 ++++++ gprof/gmon_io.h | 20 + gprof/gmon_out.h | 51 + gprof/gprof.1 | 252 +++ gprof/gprof.c | 659 ++++++++ gprof/gprof.h | 157 ++ gprof/gprof.texi | 2028 +++++++++++++++++++++++ gprof/hertz.c | 54 + gprof/hertz.h | 22 + gprof/hist.c | 596 +++++++ gprof/hist.h | 23 + gprof/i386.c | 104 ++ gprof/po/Make-in | 251 +++ gprof/po/POTFILES.in | 38 + gprof/po/gprof.pot | 470 ++++++ gprof/search_list.c | 44 + gprof/search_list.h | 20 + gprof/source.c | 223 +++ gprof/source.h | 55 + gprof/sparc.c | 88 + gprof/stamp-h.in | 1 + gprof/sym_ids.c | 372 +++++ gprof/sym_ids.h | 25 + gprof/symtab.c | 269 +++ gprof/symtab.h | 111 ++ gprof/tahoe.c | 345 ++++ gprof/utils.c | 106 ++ gprof/utils.h | 7 + gprof/vax.c | 350 ++++ 61 files changed, 20081 insertions(+) create mode 100644 gprof/.gdbinit create mode 100644 gprof/ChangeLog create mode 100644 gprof/Makefile.am create mode 100644 gprof/Makefile.in create mode 100644 gprof/NOTES create mode 100644 gprof/TEST create mode 100644 gprof/TODO create mode 100644 gprof/aclocal.m4 create mode 100644 gprof/alpha.c create mode 100644 gprof/basic_blocks.c create mode 100644 gprof/basic_blocks.h create mode 100644 gprof/bb_exit_func.c create mode 100755 gprof/bbconv.pl create mode 100644 gprof/bsd_callg_bl.m create mode 100644 gprof/call_graph.c create mode 100644 gprof/call_graph.h create mode 100644 gprof/cg_arcs.c create mode 100644 gprof/cg_arcs.h create mode 100644 gprof/cg_dfn.c create mode 100644 gprof/cg_dfn.h create mode 100644 gprof/cg_print.c create mode 100644 gprof/cg_print.h create mode 100755 gprof/configure create mode 100644 gprof/configure.bat create mode 100644 gprof/configure.in create mode 100644 gprof/corefile.c create mode 100644 gprof/corefile.h create mode 100644 gprof/flat_bl.m create mode 100644 gprof/fsf_callg_bl.m create mode 100644 gprof/gconfig.in create mode 100644 gprof/gen-c-prog.awk create mode 100644 gprof/gmon.h create mode 100644 gprof/gmon_io.c create mode 100644 gprof/gmon_io.h create mode 100644 gprof/gmon_out.h create mode 100644 gprof/gprof.1 create mode 100644 gprof/gprof.c create mode 100644 gprof/gprof.h create mode 100644 gprof/gprof.texi create mode 100644 gprof/hertz.c create mode 100644 gprof/hertz.h create mode 100644 gprof/hist.c create mode 100644 gprof/hist.h create mode 100644 gprof/i386.c create mode 100644 gprof/po/Make-in create mode 100644 gprof/po/POTFILES.in create mode 100644 gprof/po/gprof.pot create mode 100644 gprof/search_list.c create mode 100644 gprof/search_list.h create mode 100644 gprof/source.c create mode 100644 gprof/source.h create mode 100644 gprof/sparc.c create mode 100644 gprof/stamp-h.in create mode 100644 gprof/sym_ids.c create mode 100644 gprof/sym_ids.h create mode 100644 gprof/symtab.c create mode 100644 gprof/symtab.h create mode 100644 gprof/tahoe.c create mode 100644 gprof/utils.c create mode 100644 gprof/utils.h create mode 100644 gprof/vax.c (limited to 'gprof') diff --git a/gprof/.gdbinit b/gprof/.gdbinit new file mode 100644 index 0000000..e519472 --- /dev/null +++ b/gprof/.gdbinit @@ -0,0 +1 @@ +dir .. diff --git a/gprof/ChangeLog b/gprof/ChangeLog new file mode 100644 index 0000000..24626c2 --- /dev/null +++ b/gprof/ChangeLog @@ -0,0 +1,1319 @@ +1999-04-26 Tom Tromey + + * aclocal.m4, configure: Updated for new version of libtool. + +1999-04-06 Ian Lance Taylor + + * gprof.h (LC_MESSAGES): Never define. + * gprof.c (main): Don't pass LC_MESSAGES to setlocale if the + system does not define it. + +1999-04-05 H.J. Lu + + * corefile.c (core_create_line_syms): Don't use fixed size array + for prev_name and prev_filename. + +1999-04-04 Michael Hohmuth + + * gprof.h (FF_BSD44): Define. + * gmon.h (struct raw_phdr): Add version, profrate, and spare + fields unconditionally. + (struct old_raw_phdr): New struct. + * gprof.c (main): Handle -O 4.4bsd. + * gmon_io.c (gmon_out_read): Handle BSD 4.4 format, either + automatically or by user specification. + (gmon_out_write): Handle BSD 4.4 format. + * configure.in: Don't set BSD44_FORMAT. + * gprof.texi (Miscellaneous Options): Document -O 4.4bsd. + * configure, gconfig.in: Rebuild. + +Tue Feb 16 17:01:33 1999 Ian Lance Taylor + + * configure.in: Change AC_PREREQ to 2.13. Change AM_PROG_INSTALL + to AC_PROG_INSTALL. Remove AM_CYGWIN32. Change AM_EXEEXT to + AC_EXEEXT. Add comment to AC_DEFINE. + * acconfig.h: Remove. + * aclocal.m4: Rebuild. + * configure: Rebuild. + * Makefile.in: Rebuild. + * gconfig.in: Rebuild. + +Sun Dec 6 21:57:50 1998 Ian Lance Taylor + + * gprof.texi (Symspecs): Mention that you have to add any + underscore yourself when naming a symbol. + +Mon Nov 2 15:05:33 1998 Geoffrey Noer + + * configure.in: detect cygwin* instead of cygwin32* + * configure: regenerate + +Wed Aug 12 14:59:06 1998 Ian Lance Taylor + + Avoid some overflow cases: + * basic_blocks.h (bb_min_calls): Change to unsigned long. + * call_graph.h (cg_tally): Change count parameter to unsigned + long. + * cg_arcs.h (Arc): Change count field to unsigned long. + (arc_add): Change count parameter to unsigned long. + * source.h (Source_File): Change ncalls field to unsigned long. + * symtab.h (Sym): Change fields ncalls, bb_calls, and + cg.self_calls to unsigned long. + * Many files: Update accordingly. + + * configure, Makefile.in, aclocal.m4: Rebuild with current tools. + +Fri Jul 10 17:29:49 1998 Stan Cox + + * configure.in (BSD44_FORMAT): Define for cygwin32, win32, mingw32 + * configure: Rebuild. + +Fri Jun 12 13:40:05 1998 Tom Tromey + + * po/Make-in (all-yes): If maintainer mode, depend on .pot file. + ($(PACKAGE).pot): Unconditionally depend on POTFILES. + +Sun May 10 22:35:33 1998 Jeffrey A Law (law@cygnus.com) + + * po/Make-in (install-info): New target. + +Tue May 5 18:28:40 1998 Tom Tromey + + * gprof.h (_): Undefine BFD's version. + +Tue Apr 28 19:17:33 1998 Tom Tromey + + * gprof.c (main): Conditionally call setlocale. + * gprof.h: Include if HAVE_LOCALE_H. + (LC_MESSAGES): Now can be defined even when ENABLE_NLS. + +Tue Apr 28 19:50:09 1998 Ian Lance Taylor + + * corefile.c: Rename from core.c. + * corefile.h: Rename from core.h. + * Many .c files: Include corefile.h rather than core.h. + * Makefile.am (sources): Change core.c to corefile.c. + (noinst_HEADERS): Change core.h to corefile.h. + ($(OBJECTS)): Depend upon corefile.h rather than core.h. + (corefile.o): Rename target from core.o, depend upon corefile.c. + * Makefile.in, po/POTFILES.in: Rebuild. + +Mon Apr 27 16:50:40 1998 Ian Lance Taylor + + * configure.in: Change version number to 2.9.4 + * configure: Rebuild. + +Wed Apr 22 16:01:17 1998 Tom Tromey + + * po/Make-in (MKINSTALLDIRS): Don't look in $(top_srcdir). + +Wed Apr 22 00:00:22 1998 Tom Tromey + + * gprof.h: Added includes and defines for gettext. + * configure.in (ALL_LINGUAS): New macro. + Call CY_GNU_GETTEXT. Create po/Makefile.in and po/Makefile. + * acconfig.h (ENABLE_NLS, HAVE_CATGETS, HAVE_GETTEXT, HAVE_STPCPY, + HAVE_LC_MESSAGES): Define. + * gprof.c (main): Call setlocale, bindtextdomain, textdomain. + * Makefile.am (SUBDIRS): New macro. + (INCLUDES): Look in intl dirs for headers. Define LOCALEDIR. + (gprof_DEPENDENCIES): Added INTLDEPS. + (gprof_LDADD): Added INTLLLIBS. + (POTFILES): New macro. + (po/POTFILES.in): New target. + * Many files: Wrap user-visible strings with gettext invocation. + +Tue Apr 7 12:43:37 1998 Ian Lance Taylor + + From hjl@lucon.org : + * Makefile.am (diststuff): New target. + * Makefile.in: Rebuild. + +Mon Mar 30 12:47:48 1998 Ian Lance Taylor + + * configure.in: Set version to 2.9.1. + * configure: Rebuild. + + * Branched binutils 2.9. + +Sat Mar 28 23:09:08 1998 Ian Lance Taylor + + Fix some gcc -Wall warnings: + * cg_arcs.c (num_cycles): Change to unsigned int. + (numarcs): Likewise. + (arc_add): Change maxarcs to unsigned int. + (cg_assemble): Change index to unsigned int. + * cg_arcs.h (num_cycles, numarcs): Update declarations. + * cg_print.c (cg_print): Change index to unsigned int. + (cg_print_index): Change index, nnames, todo, i, and j to unsigned + int. + (cg_print_file_ordering): Change symbol_count and index2 to + unsigned int. + * core.c (symbol_map_count): Change to unsigned int. + (core_create_function_syms): Change j to unsigned int. + (core_create_line_syms): Add cast to avoid warning. + * hist.c (hist_assign_samples): Change j to unsigned int. + (hist_print): Change index to unsigned i nt. Add cast to avoid + warning. + * sym_ids.c (parse_spec): Add casts to avoid warning. + * symtab.c (symtab_finalize): Change j to unsigned int. + (sym_lookup): Update printf format strings. + * symtab.h (Sym_Table): Change len to unsigned int. + * tahoe.c (tahoe_reladdr): Add casts to avoid warnings. + +Tue Mar 24 19:00:11 1998 Ian Lance Taylor + + Add --demangle and --no-demangle options: + * gprof.h (demangle): Declare. + * gprof.c (demangle): New global variable. + (OPTION_DEMANGLE, OPTION_NO_DEMANGLE): Define. + (long_options): Add "demangle" and "no-demangle". + (usage): Mention --demangle and --no-demangle. + (main): Handle OPTION_DEMANGLE and OPTION_NO_DEMANGLE. + * utils.c (print_name_only): Only demangle symbol name if demangle + is true. + * gprof.texi (Output Options): Document new options. + +Fri Mar 20 19:21:56 1998 Ian Lance Taylor + + * Makefile.in: Rebuild with automake 1.2e. + * aclocal.m4, configure: Rebuild with libtool 1.2. + +Thu Feb 12 14:36:05 1998 Ian Lance Taylor + + * gprof.c (usage): Update bug-gnu-utils address. + +Sat Feb 7 15:43:12 1998 Ian Lance Taylor + + * configure, aclocal.m4: Rebuild with new libtool. + +Fri Feb 6 12:02:28 1998 Ian Lance Taylor + + * alpha.c (alpha_Instruction): Use int, not signed. + +Fri Feb 6 02:00:19 1998 Jeffrey A Law (law@cygnus.com) + + * core.c (core_init): Adding missing "break". + +Thu Feb 5 12:49:37 1998 Ian Lance Taylor + + * configure, Makefile.in, aclocal.m4: Rebuild with new libtool. + +Tue Feb 3 14:25:25 1998 Brent Baccala + + * bbconv.pl: New file. + * Makefile.am (EXTRA_DIST): Add bbconv.pl. + * Makefile.in: Rebuild. + + * gprof.texi: Extensive additions to document all arguments and + output formats. + + * symtab.c (symtab_finalize): Prefer function symbols over line + symbols. + (dbg_sym_lookup): Correct debugging messages. + + * gprof.c (main): --sum implies --line. + + * cg_print.c (cg_print): When doing line by line profiling, don't + use a non-function as a main listing item. + + * call_graph.c (cg_tally): When using line by line profiling, use + the function symbol as the child. + + * symtab.h (NBBS): Define. + (Sym): Add bb_addr and bb_calls fields. + * basic_blocks.c (bb_read_rec): Save multiple basic blocks per + symbol. + (bb_write_blocks): Adjust for multiple basic blocks per symbol. + (print_exec_counts): Don't check whether a symbol is the start of + a basic block. Print all basic blocks for a symbol. + (annotate_with_count): Rewrite to print all basic block counts and + to pay attention to width argument. + (print_annotated_source): Don't check whether symbol is the start + of a basic block. + + Make it possible to build a cross gprof, although a few cases are + still not handled: + * configure.in: Don't set MY_TARGET. + * gprof.h: Don't include MACHINE_H. Don't define FOPEN_RB or + FOPEN_WB; just get them from sysdep.h. + * core.h (min_insn_size, offset_to_code): Declare. + * core.c (MIN_INSN_SIZE): Don't define. + (min_insn_size, offset_to_code): New variables. + (core_init): Initialize min_insn_size and offset_to_code. + (find_call): New function. + (core_create_line_syms): Don't use min_dist. Set is_static in + pass 2. + * hist.c (UNITS_TO_CODE): Define. + * gprof.c (default_excluded_list): Add "__mcount_internal". + * gmon.h: Change TARGET_alpha to __alpha__. + * hertz.h: Ifdef MACH, define hertz as HZ. + * alpha.c (alpha_Instruction): Rename from Instruction. Change + all references. + (alpha_find_call): Rename from find_call. + * alpha.h: Remove. + * dummy.c, dummy.h: Remove. + * i386.c (i386_iscall): Rename from iscall. Change all + references. Check for call instruction, not jump or lcall. + (i386_find_call): Rename from find_call. Correct for VMA. + Correct call destination computation. Don't dereference symbol if + it is NULL. + * i386.h: Remove. + * ns532.c, ns532.h: Remove. + * sparc.c (CALL): Define. + (sparc_find_call): Rename from find_call. + * sparc.h: Remove. + * tahoe.c: Include cg_arcs.h, core.h, hist.h, and symtab.h. Don't + include time_host.h. + (CALLF, PC): Define. + (enum tahoe_opermodes, tahoe_operandenum): Define. Rename all + references to opermodes or operandenum to these. + (tahoe_operandmode): Rename from operandmode. Call abort if + switch does not return. + (tahoe_operandname): Rename from operandname. Call abort if + switch does not return. + (tahoe_operandlength): Rename from operandlength. Call abort if + switch does not return. + (tahoe_reladdr): Rename from reladdr. + (tahoe_find_call): Rename from find_call. Use core_text_space + rather than textspace. + * tahoe.h: Remove. + * vax.c (CALLS, PC): Define. + (enum opermodes, operandenum, struct modebyte): Define. + (vax_operandmode): Rename from operandmode. Call abort if switch + does not return. + (vax_operandname): Rename from operandname. Call abort if switch + does not return. + (vax_operandlength): Rename from operandlength. Call abort if + switch does not return. + (vax_reladdr): Rename from reladdr. + (vax_find_call): Rename from find_call. + * vax.h: Remove. + * Makefile.am (AUTOMAKE_OPTIONS): Set to cygnus. + (MY_TARGET): Remove. + (INCLUDES): Remove -DTARGET_$(MY_TARGET) and -DMACHINE_H= + \"$(MY_TARGET).h\". + (gprof_SOURCES): Add i386.c, alpha.c, vax.c, tahoe.c, sparc.c. + (gprof_DEPENDENCIES): Remove $(MY_TARGET).o. + (gprof_LDADD): Likewise. + (noinst_HEADERS): Remove alpha.h, i386.h, ns532.h, sparc.h, + tahoe.h, vax.h, dummy.h. + (EXTRA_DIST): Remove alpha.c, i386.c, ns532.c, sparc.c, tahoe.c, + vax.c, dummy.c. + ($(OBJECTS)): Don't depend upon $(MY_TARGET).h. + ($(MY_TARGET).o): Remove target. + (i386.o, alpha.o, vax.o, tahoe.o, sparc.o): New targets. + * configure, Makefile.in, aclocal.m4: Rebuild. + +Mon Dec 29 14:17:08 1997 Ian Lance Taylor + + * core.c (core_sym_class): Treat weak symbols as text symbols. + From Dean Gaudet . + +Wed Sep 24 11:35:43 1997 Ian Lance Taylor + + * aclocal.m4: Rebuild with new libtool. + * Makefile.in: Rebuild with current automake. + * configure: Rebuild. + +Sat Aug 9 16:25:01 1997 Ian Lance Taylor + + * configure.in: Change version number to 2.8.2. Call + AM_PROG_LIBTOOL. Remove shared library handling; now handled by + libtool. Add AM_CONFIG_HEADER. Change AC_PROG_INSTALL to + AM_PROG_INSTALL. Add AM_EXEEXT. + * Makefile.am (LINK): Remove. + (gprof_LDFLAGS): Remove + (gprof_DEPENDENCIES): Change libbfd.a to libbfd.la. + (gprof_LDADD): Likewise. + ($(OBJECTS)): Depend upon gconfig.h and ../bfd/config.h. + * gprof.h: Undefine PACKAGE and VERSION after including BFD + sysdep.h file, then include new gconfig.h file. + * gprof.c (VERSION): Don't define. + * acconfig.h: New file. + * stamp-h.in: New file. + * gconfig.in: New file, created by autoheader. + * Makefile.in, configure, aclocal.m4: Rebuild. + +Sat Jun 28 23:20:42 1997 Ian Lance Taylor + + * aclocal.m4, configure, Makefile.in: Rebuild with automake 1.2. + +Mon Jun 16 15:31:39 1997 Ian Lance Taylor + + * Makefile.am (INCLUDES): Add -DDEBUG. + * Makefile.in: Rebuild. + +Tue Apr 15 14:19:30 1997 Ian Lance Taylor + + Change to use automake: + * Makefile.am: New file. + * configure.in: Run AM_INIT_AUTOMAKE, AM_MAINTAINER_MODE, and + AM_CYGWIN32. + * aclocal.m4: New file, created by aclocal. + * Makefile.in: Replace with file created by automake --cygnus. + * configure: Rebuild. + +Thu Apr 3 13:21:25 1997 Ian Lance Taylor + + * gprof.c (VERSION): Define as "2.8.1". + + * Branched binutils 2.8. + +Thu Mar 27 17:15:23 1997 Ian Lance Taylor + + * gprof.c (main): Correct copyright message. + +Mon Mar 24 11:12:26 1997 Ian Lance Taylor + + * Makefile.in (.c.o): Define TARGET_$(MY_TARGET) when compiling. + * gmon.h: Use bytes counts rather than sizeof in struct raw_phdr + and struct raw_arc. + +Mon Mar 17 10:54:47 1997 David Mosberger-Tang + + * cg_arcs.c (arc_add): memset() newly alloced arc to ensure + all fields are initialized with 0. + +Sat Mar 15 19:17:31 1997 H.J. Lu + + * symtab.h (find_call): Declare. + * cg_arcs.c (cg_assemble): Don't declare find_call. + * hist.c (scale_and_align_entries): Declare. + +Thu Feb 27 12:46:53 1997 Ian Lance Taylor + + * configure.in: Define BSD44_FORMAT if the target looks like a + BSD4.4 derived system. + * configure: Rebuild. + * Makefile.in (.c.o): Add @DEFS@. + * gmon_io.c (gmon_out_read): In BSD44_FORMAT code, get profrate + from profrate field, not version field. + +Thu Jan 16 17:42:54 1997 Ian Lance Taylor + + * dummy.c (find_call): Clear ignore_direct_calls. + +Tue Dec 31 15:44:10 1996 Ian Lance Taylor + + * Makefile.in (.c.o): Add -D_GNU_SOURCE. Put $(CFLAGS) at the + end. + (gprof): Put $(CFLAGS) after the other options. + +Tue Nov 26 17:08:38 1996 Ian Lance Taylor + + * configure: Rebuild with autoconf 2.12. + +Wed Oct 2 15:23:16 1996 Ian Lance Taylor + + * sparc.c (find_call): Align p_lowpc to avoid bus error. + +Tue Oct 1 15:58:10 1996 Ian Lance Taylor + + * gprof.c (usage): Print bug report address. + (main): Change version printing to match current GNU standards. + +Fri Aug 30 12:16:11 1996 Ian Lance Taylor + + * gmon.h: Replace #elif with #else/#endif. + +Thu Aug 29 17:04:10 1996 Michael Meissner + + * configure.in (i[345]86-*-*): Recognize i686 for pentium pro. + * configure: Regenerate. + +Thu Aug 22 17:12:30 1996 Ian Lance Taylor + + * configure.in: Set and substitute HLDENV. + * configure: Rebuild. + * Makefile.in (HLDENV): New variable. + (gprof): Use $(HLDENV). + +Wed Aug 7 14:43:51 1996 Philippe De Muyter + + * core.c (read_function_mappings): Cast xmalloc return. + +Thu Jul 4 12:01:42 1996 Ian Lance Taylor + + * gprof.c (VERSION): Define as "2.7.1". + + * Released binutils 2.7. + + * bb_exit_func.c: Rename from __bb_exit_func.c, so that it can be + stored on a System V file system. + +Thu Jun 27 11:36:22 1996 Ian Lance Taylor + + * configure.in: Call AC_ISC_POSIX. + * configure: Rebuild. + * Makefile.in (gprof): Pass $(CFLAGS) during link. + * hertz.c: Don't include ; let sysdep.h handle that. + If HAVE_SETITIMER is not defined, try using sysconf. + +Mon Jun 24 18:27:28 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) + + * Makefile.in (exec_prefix, bindir, libdir, mandir, infodir, datadir, + INSTALL_PROGRAM, INSTALL_DATA): Use autoconf-set values. + * configure.in (AC_PREREQ): autoconf 2.5 or higher. + (AC_PROG_INSTALL): added. + * configure: Rebuilt. + +Mon Jun 24 12:03:09 1996 Ian Lance Taylor + + * configure.in: On alpha*-*-osf*, link against libbfd.a if not + using shared libraries. + * configure: Rebuild with autoconf 2.10. + +Tue Jun 18 17:35:58 1996 Ian Lance Taylor + + * core.c (core_create_line_syms): Use xstrdup rather than strdup. + * source.c (source_file_lookup_path): Likewise. + +Mon Apr 8 14:44:33 1996 Ian Lance Taylor + + * configure.in: Permit --enable-shared to specify a list of + directories. + * configure: Rebuild. + +Thu Mar 21 17:18:25 1996 Ian Lance Taylor + + * core.c (core_create_function_syms): Move filename and func_name + inside ifdef where they are used. + + * core.c (core_sym_class): Parenthesize && within ||. + * symtab.c (symtab_finalize): Correct parenthesization. + + * cg_print.h (cg_print_file_ordering): Declare. + (cg_print_function_ordering): Declare. + + * __bb_exit_func.c (__bb_exit_func): Replace bcopy with memcpy. + * cg_arcs.c (arc_add): Likewise. + * cg_print.c (cg_print_function_ordering): Likewise. + +Thu Mar 21 17:02:02 1996 David Mosberger-Tang + + * gprof.c (default_excluded_list): Add "__mcount". + + * gprof.c (main): Change ifdef __osf__ to __alpha__. + + * gmon_io.c (gmon_out_read): If BSD44_FORMAT is defined, get the + profiling rate from the header. + + * gmon.h (struct raw_phdr): Only include pad if both __alpha__ and + __osf__ are defined. Add new fields if BSD44_FORMAT is defined. + + * alpha.h (MIN_INSN_SIZE): Define. + * core.c (MIN_INSN_SIZE): If not defined, define as 1. + (core_sym_class): Ignore debugging symbols. + (core_create_line_syms): Use MIN_INSN_SIZE when gathering line + information. + +Wed Mar 20 18:15:47 1996 Andreas Schwab + + * cg_print.c (cg_print_function_ordering): Fix __GNUC__ misspelled + as __GNU_C__. + (order_and_dump_functions_by_arcs): Likewise. + +Tue Mar 12 12:19:50 1996 Ian Lance Taylor + + * configure: Rebuild with autoconf 2.8. + +Sun Feb 18 15:06:18 1996 Ian Lance Taylor + + * configure.in: Check for 'do not mix' from native linker before + trying to use -rpath. + * configure: Rebuild. + +Tue Feb 13 15:32:53 1996 Ian Lance Taylor + + * configure.in: Set HDLFLAGS for *-*-hpux with --enable-shared. + * configure: Rebuild. + +Wed Feb 7 14:03:17 1996 Ian Lance Taylor + + * configure.in: Don't set CC. Look for --enable-shared. Set + BFDLIB and HLDFLAGS and substitute them. + * configure: Rebuild. + * Makefile.in (LIBS): Use @BFDLIB@. + (HLDFLAGS): New variable. + (gprof): Use $(HLDFLAGS). + +Mon Feb 5 16:34:44 1996 Ian Lance Taylor + + Support for building bfd and opcodes as shared libraries, based on + patches from Alan Modra : + * Makefile.in (LIBDEPS): New variable. + (LIBS): Use -L../bfd -lbfd. + (gprof): Depend upon $(LIBDEPS) rather than $(LIBS). + +Sat Dec 30 10:11:03 1995 Jeffrey A Law (law@cygnus.com) + + * gprof.c (long_options): Add "--function-ordering" and + "--file-ordering" options. + (usage): Add new options to usage message. + (main): Handle new options. + * gprof.h (STYLE_FUNCTION_ORDER): Define. + (STYLE_FILE_ORDER): Define. + (function_mapping_file): Declare. + * cg_arcs.c (arcs, numarcs): New globals. + (arc_add): Put new arcs into the arc array so the function/file + ordering code can examine them. + * cg_arcs.h (struct arc): New field "has_been_placed". + (arcs, numarcs): Declare new globals. + * core.c (symbol_map, symbol_map_count): New globals. + (read_function_mappings): New function to read in a function + to object map file. + (core_init): Call read_function_mappings if a function mapping + file exists. + (core_create_function_syms): Handle function to object file + mappings. + * symtab.h (struct sym): New fields "mapped", "has_been_placed", + "nuses", "prev". + * cg_print.c (cmp_arc_count): New function for sorting arcs. + (cmp_fun_nuses): Likewise for functions. + (cg_print_function_ordering): New function to print a suggested + function ordering. + (cg_print_file_ordering): Likewise for ordering .o files. + (order_and_dump_functions_by_arcs): Helper function for function + and object file ordering code. + +Sun Dec 24 21:32:27 1995 Jeffrey A Law (law@cygnus.com) + + * core.c (core_sym_class): Ignore symbols without BSF_FUNCTION + set if ignore_non_function is set. + * gprof.h (ignore_non_functions): Declare. + * gprof.c (ignore_non_functions): Define. + (long_options): Add "ignore-non-functions". + (usage): Add new options. + (main): Recognize "-D" and "--ignore-non-functions" option. + +Tue Nov 21 13:24:39 1995 Ken Raeburn + + * Makefile.in (.m.c): Strip out directory name from function + name. + + * hist.c (scale_and_align_entries): Don't use DEFUN_VOID. Do + UNITS_TO_CODE adjustment unconditionally; compiler can optimize + away zero-offset case. Refer to scaled_addr, not aligned_addr. + + * vax.c: Don't include vax.h here. + +Thu Nov 16 03:41:37 1995 Ken Raeburn + + Version 2.6 released. + +Wed Nov 8 11:40:04 1995 Ian Lance Taylor + + * gprof.c (main): Cast getenv return value. + +Mon Nov 6 15:05:00 1995 Ken Raeburn + + * Makefile.in (TAGS): New target. + +Wed Nov 1 12:51:21 1995 Per Bothner + + * Makefile.in (DISTSTUFF): Rename to GEN_FILES, to avoid confusion. + (all): Depend on $(GEN_FILES), not diststuff (which also depends + on info). + +Wed Nov 1 15:23:15 1995 Manfred Hollstein KS/EF4A 60/1F/110 #40283 + + * sym_ids.c: Include . + +Wed Oct 25 13:24:31 1995 Per Bothner + + * Makefile.in (diststuff): Also make info. + (mostlyclean): Don't remove gprof.info*. + (maintainer-clean realclean): Also remove *.info*. + +Fri Oct 6 16:25:32 1995 Ken Raeburn + + Mon Sep 25 22:49:32 1995 Andreas Schwab + + * Makefile.in: Add dependecies for $(OBJS) on header files. + + * cg_print.c (print_cycle, print_members, cg_print_index): Fix new + style output format to make it consistent. + * dummy.c (find_call): Fix typo in error message. + +Wed Sep 20 13:21:02 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New target, synonym for + realclean. + +Fri Sep 8 14:38:08 1995 Ian Lance Taylor + + * Makefile.in (install): Don't install in $(tooldir). + +Fri Aug 25 15:30:05 1995 Ken Raeburn + + NS32K changes from Ian Dall: + * configure.in: Use ns32k, not ns532. + * ns532.c: Include symtab.h. + (find_call): Renamed from findcall. Print a message. + * ns532.h: Remove dummy.h comments. + +Tue Aug 22 10:00:45 1995 Jeffrey A. Law + + * Makefile.in (install): Remove "brokensed" hack, unnecessary now + that we're using autoconf. + +Wed Jul 19 18:46:13 1995 Fred Fish + + * core.c (get_src_info): Cast arg 7 of bfd_find_nearest_line + to proper type of "unsigned int *". + +Fri Jun 16 15:29:36 1995 Ken Raeburn + + * configure.in: Use changequote around use of []. + +Mon Jun 12 12:14:52 1995 J.T. Conklin + + * Makefile.in (distclean, realclean): Remove config.cache and + config.log. + +Wed May 17 17:56:53 1995 J.T. Conklin + + * Makefile.in (Makefile): Added config.status to dependency list. + (config.status): New target. + (SHELL): New definition. + +Tue Apr 25 21:11:12 1995 Ken Raeburn + + * Makefile.in (install): Depend on "all". + +Thu Apr 20 17:29:07 1995 Ken Raeburn + + * Makefile.in: Change all references to MY_MACHINE to MY_TARGET, + to match configure script. + +Wed Apr 19 11:19:37 1995 J.T. Conklin + + * gen-c-prog.awk: Changed reference to "make-c-prog.awk" in + comment emitted by this script to gen-c-prog.awk. + + * Makefile.in, configure.in: Converted to use autoconf. + * configure: New file, generated with autoconf 2.3. + * config/{mt-alpha, mt-dummy, mt-i386, mt-ns532, mt-sparc, + mt-tahoe, mt-vax}: Removed. + +Mon Mar 13 21:44:24 1995 Ken Raeburn + + * __bb_exit_func.c: New file, from David Mosberger-Tang. + + Thu Feb 9 16:56:07 1995 David Mosberger-Tang + + * All *.c: More cleanup towards GNU format. + + * gmon_out.h (struct gmon_hist_hdr, struct gmon_cg_arc_record): + replaced sizeof (bfd_vma) by size (char*) because Ken tells me + that bfd_vma is only guaranteed to be at least as big as a pointer. + + (GMON_Record_tag): added explicit enumeration values to ensure + compatibility across compilers. + + * gmon_io.c (get_vma, put_vma): replaced sizeof(bfd_vma) by + sizeof(char*). + +Tue Feb 7 17:24:12 1995 Ken Raeburn + + * All *.c and *.h files: Ran "indent -gnu". Cleaned up a couple + of constructs GNU indent couldn't handle. Block comments not yet + rewritten in GNU format. + + * gprof.c (VERSION): Changed to 2.6, to get in sync for next + binutils release. + +Sun Feb 5 16:19:46 1995 David Mosberger-Tang + + * symtab.c (symtab_finalize): ensure globals symbols really + are favored over static ones---even if their name looks less + preferable; this is important for HP-UX; for example, there + is a static label Ltext_something that aliases the global + symbol _start + + * hist.c (hist_print): auto-scaling is now in effect for FSF-style + output only; also, auto-scaling is now performed based on + per-call, rather than total execution time, which is what it was + meant to be. + + * gprof.h (File_Format): new type. + + * gprof.c (VERSION): upped to 2.7---seems to be completely out of + sync with Cygnus version numbers though... + + (long_options): renamed --gmon-info to --file-info, --width added, + renamed --old-file-format to --file-format + (main): dito; also added support to read prof files, but as + mon_out_read() is not implemented, it's #ifdef'd out for now + + (usage): update to reflect new options. + + * gmon_io.c: replaced "old_file_format" by more general + "file_format" option + + * gmon.h (struct raw_phdr): fixed declaration for OSF/1. + + * core.c (core_sym_class): added back check for __gnu_compiled and + ___gnu_compiled for the benefit of systems without + bfd_find_nearest_line() support + + (get_src_info): now the libbfd is fixed, invoke bfd_find_nearest_line() + with section-relative addresses + + (core_create_function_syms): get_src_info() calls are currently + enabled for OSF/1 only. It appears to work allright for SunOS + 4.1.x as well, but on SPARCs it gets painfully slow with the + current implementation of aout_32_find_nearest_line(); + unfortunately, this means that static functions will not have their + filename printed in the call-graph function index; line-level + profiling should still work, but requires some patience + + * cg_print.c (cg_print_index): sanitised printing of index when + using FSF-style output; in particular, output width is now controlled + via option --width and the function tries hard to keep columns + aligned even in the presence of (occasional) long names + + * NOTES: a first shot at updating the documentation. + +Wed Feb 1 19:07:44 1995 David Mosberger-Tang + + * core.c (core_create_function_syms): fixed computation of min_vma + and max_vma. + + * *.c: removed rcsid. + +Tue Jan 31 16:18:18 1995 Ken Raeburn + + * Lots of changes from David Mosberger-Tang: + + Tue Oct 25 19:20:14 1994 David Mosberger-Tang + + * gprof.c (main): put parentheses around & within &&. + + * basic_blocks.c (bb_read_rec): print warning message (once) when + ignoring basic-block execution counts. + + * source.c (source_file_lookup_name): corrected second argument to + strcmp(). + + * hist.c (print_header): merged Fri Oct 21 18:58:02 1994 change by + Ken Raeburn from binutils-2.5.1. + + * gmon_io.c (gmon_out_read): the output stule STYLE_GMON_INFO is now + supported both for old and new (versioned) gmon.out files. Old + files are identified as version 0. + + * gmon.h (struct raw_arc): count field is now sizeof(long) bytes + long (instead of 4) because that is what OSF/1 v3.0 uses. + + * core.c: minor fixes and debugging info changes. + + Sun Sep 11 18:47:47 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * core.c (core_init): if .text cannot be found, try $CODE$ (the + name of the text-section under HP-UX). + + * hist.c (hist_assign_samples): fixed off-by-one bug: highpc + points one past the last sampling bin, so hist_scale should be + computed as "hist_scale /= hist_num_bins", not "hist_scale /= + hist_num_bins - 1". + + * gmon_io.c, hist.c, hist.h: renamed hist_num_samples to + hist_num_bins. + + * configure.in: added alpha-*-*) for per-target config. + + * alpha.c, alpha.h: created. + + * gprof.c (default_excluded_list): , added. + + * core.c (core_create_function_syms, core_create_line_syms): + explicitly keep two sentinels "" and "" that catch + all addresses outside the text-space. Thus, sym_lookup(&symtab, + addr) continues to guarantee not to return 0 on any address. It + also avoids incorrectly crediting the first/last symbol in the + text-space. + + * core.c (core_create_line_syms): always create function symbols + first, then merge in line symbols; this is so that if parts of the + program were compiled without -g, function-level symbols are + available still. + + * utils.c (print_name_only): support for print_path added. + + * symtab.c (cmp_addr): also use is_func flag in comparison. + (symtab_finalize): return immediately when table empty; now + more careful about getting rid of the right duplicate symbol. + + * sparc.c (find_call): many fixes---this function was rather + botched in binutils-2.4 already; it should work again. + + * source.c (source_file_lookup_path): PATH is now strdup'ed (it is + not good to rely on get_src_info() to return distinct string + pointers). + + * search_list.c (search_list_append): added cast for xmalloc(). + + * hist.c: added explicit initialization to some of the global + variables; fixed SItab (scales were off by a factor of 10). + + * hist.h: include of bfd.h added. + + * gprof.c, gprof.h (print_path): added. + + * gprof.h (MAX): fixed. + + * gmon_out.h: renamed gmon_time_hist_hdr to gmon_hist_hdr. + + * gmon_io.c: added some casts to (long) so we can always print as %lx + + * core.c (core_get_text_space): fixed to make it work. + + * cg_print.c (cg_print_index): added support for print_path option. + + * cg_dfn.h (cg_dfn): wrap prototype in PARAMS(). + + * call_graph.c, gmon_io.c, hist.c: avoid taking address of array + as some compilers complain (e.g., DEC's OSF/1 compiler) + + * basic_blocks.c, gmon_io.c, hist.c, source.c, sym_ids.c, + symtab.c: calls to memset() had 2nd and 3rd args reversed. + + Sat Sep 10 21:53:13 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * gprof.c: added "_mcount" to default_excluded_list. + (main): if output_style==0 and there is either a histogram or a + call-graph, always generate flat and call-graph, no matter what + line_granularity is set to. + + * source.c (source_file_lookup_name): if searching for sf->name + fails, try again with filename obtained after stripping off any + partial path from sf->name. + + * gprof.h (SRCDEBUG): added. + + * search_list.c (search_list_append): directories were added in wrong + order. + + * reimplemented selection mechanism from ground up; it is now possible + to accurately control what gets included/excluded in each of the + output styles; a "symbol-specification" (spec) is the basic means + to select a set of symbols; a spec has the syntax: + + spec == (FILENAME:(FUNCNAME|LINE_NUM) | NAME). + arc == spec/spec. + + any of the terminal symbols can be empty, in which case they + match anything (wildcards). NAME is interpreted as a FILENAME + if it contains a dot (e.g., foo.c), as LINE_NUM if it starts + with a digit, and as FUNCNAME otherwise. + + For example, to get a call-graph display that ignores arcs + from foo() to bar(), you'd say "--no-graph=foo/bar"; to + show only arcs into bar() (no matter what the caller), + you'd say "--graph=/bar"; and to get a call-graph without + any arc info, you'd say "--graph=/"; similarly, to + get a flat profile without mcount, you'd say "--no-flat=mcount" + and to get a flat profile that shows includes all functions + you'd say "--flat=""" (i.e., an empty spec) + + * hist.c (hist_print): top_time wasn't initialized to 0.0. + + Fri Sep 9 01:10:21 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * gmon_out.h: all headers now declared in terms of characters + to avoid getting into trouble with different compilers introducing + different amount of padding; the code already accessed the fields + through bfd functions, so that didn't have to change. + + * hist.c (hist_read_rec, hist_write_rec): added support for + collection pc histograms measuring quantities other than time; + the histogram header now includes a field that specifies the + dimension of the quantity measured by the histogram bins + (normally, this is "seconds", but other meaningful dimensions + include such things as "I-cache misses", "instruction issue stalls" + etc.); there is also a field to specify a one-character + abbreviation for the dimension; in the case of time, this would + be 's'; in most other cases it probably would be '1' (not a physical + dimension). + + Thu Sep 8 16:05:08 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * gprof.c, gmon_io.[ch]: BSD_COMPATIBLE is gone and new_file_version + has become old_file_version; gmon_io.c now always supports old-style + gmon.out files; it first tries to read gmon.out as a new version + file, if that fails, it tries to read it in the old format; + although not very likely, it is possible for gprof to mistake an + old-style file as a new one (the first 4 bytes would have to + be "gmon"---including the trailing '\0'); in that case, it is + necessary to specify --old-file-version + + * gprof.h: removed dependency on SYSV; the code now always uses + strrchr(), memset(), and memcpy() and does not include either + of string.h or strings.h; this should make gprof compile on + any (Unix) system without configuration (per suggestion of + raeburn@cygnus.com) + + * gprof.c (usage): fixed location of --new-file-format option. + + * cg_arcs.c (propagate_flags): fixed typo in declaration. + + * flat_bl.m: removed formfeed at end of file; the form-feed + is now printed cg_print.c only when necessary. + + * major rewrite of gprof---too many changes to mention all of + them. new features: + + + -l now requests profiling at the line level (as opposed + to function level); in this mode, gprof creates a "symbol" + (aka name-list entry) for each line of source code, instead + of one per function) + + + support for a new gmon.out file format; the new format + consists of a header with a magic and a version number, + followed by a sequence of profile data; profile data + can any of: (a) PC histogram, (b) call-graph arcs, or + (c) basic-block execution counts; the version number makes + it possible to extend gmon.out in a backwards compatible + fashion + + + support for tcov style annotated output: if the gmon.out file + contains basic-block execution counts, the user can request + the generation of annotated source files, much like Sun's + tcov used to do + + + long options + + + new scheme to suppress symbols that aren't function names + (e.g., avoids mistaking a goto label as a function) + + + reorganized source code to make it more managable; as a + side effect, gprof now compiles cleanly with "gcc -Wall" + + Thu Sep 1 15:46:49 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * gprof.c (funcsymbol): bfd_find_nearest_line() is now used as a + final cross-check to determine whether a static symbol should be + considered as a function-name. + + Fri Aug 5 19:32:36 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * gmon_io.c (gmon_out_read): recognize "-" as the filename for + stdin; this is useful if you wanna keep gmon.out files compressed; + this way you can "gzcat" the compressed file into gprof. + + * gprof.c: flag_min_count now initialized with 1 instead of 0. + + * basic_blocks.c (bb_annotate_source): added support for creating + .tcov files when option flag_annotate_make_files is TRUE. + (annotate_with_count): all counts less than the minimum count + specified by -m are now annotated with hash-marks. + + * gprof.c (main): -A is now followed by a string of option chars. + + * basic_blocks.c (annotate_with_count): replaced b->count with + cnt. + + * source.c: flag_annotate_source replaced by source_lock_map. + + * source.h: source_lock_map added. + + * gprof.c (main): new command-line syntax: -S simply specifies + which source-files user is interested in; -A requests annotated + source files and -AA requests that all lines in a source file + are annotated. + + Thu Aug 4 23:27:03 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * basic_blocks.c (PATH_MAX): if undefined, define as 1024. + + * sparc.c, i386.c, tahoe.c, vax.c: added include of "time_hist.h" + so s_lowpc etc. get declared. + + * arcs.h (doarcs): created. + + * arcs.c: reordered static functions such that they get defined + before use. + + * gprof.c (main): added options: + -A: request annotation of all source lines (with -S) + -m: minimum execution count (with default basic-block display) + -N: force new file format (only if BSD_COMPATIBLE is defined) + -S: annotate source file + -t: set table length (with -S) + + * Makefile (OBJS): added basic_blocks.o call_graph.o gmon_io.o + source.o time_hist.o + + Fri Jul 1 15:23:50 1994 David Mosberger-Tang (davidm@piston.cs.arizona.edu) + + * gprof.c (asgnsamples): computation of "pcl" and "pch" depended + on the fact being able to store a long in a double without loss of + precision; this does not hold on machines with 64 bit longs and 64 + bit doubles. + +Fri Oct 21 18:58:02 1994 Ken Raeburn + + * printgprof.c (flatprofheader): Always set totime to 1.0 if not + greater than 0.0. Suggested by Harold Assink + . + +Fri Sep 23 15:06:45 1994 Ken Raeburn + + * printgprof.c (printprof): Use free, not cfree. + (printgprof, printindex): Ditto. + +Thu Sep 1 10:40:45 1994 Jeff Law (law@snake.cs.utah.edu) + + * gprof.h (kfromlist, ktolist, flist, Flist, elist, Elist): Make + decls extern to keep native HP compiler quiet. + +Tue Aug 30 11:12:13 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * gprof.c (funcsymbol): Ignore ___gnu_compiled as well as + __gnu_compiled, for the benefit of systems which add a leading + underscore. + +Wed Aug 24 12:49:13 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * configure.in: Change i386-*-* to i[345]86-*-*. + +Sun Jul 10 00:35:31 1994 Ian Dall (dall@hfrd.dsto.gov.au) + + * ns532.c, ns532.h: New Files. ns532 support. + + * config/mt-ns532: New File. ns532 support. + + * gprof.c: user register int i instead of defaulting the int. + Allows compilation with -Dregister= for debugging. + + * configure.in: Add ns532 support. + +Thu Jun 23 11:22:41 1994 Jeff Law (law@snake.cs.utah.edu) + + * Makefile.in (gprof): Depend on $(LIBS). + +Fri May 27 12:24:57 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + From binutils-2.4 release: + + Wed May 11 22:32:00 1994 DJ Delorie (dj@ctron.com) + + * configure.bat: [new] build makefile from makefile.in (dos) + * hertz.c: allow static HERTZ (msdos needs it) + * gprof.c: allow target to select "r" or "rb" for fopen + * gprof.c: ignore __gnu_compiled symbols + * i386.h: dfine FOPEN_RB to "rb" for dos. + +Tue May 17 15:30:22 1994 E. Michael Smith (ems@cygnus.com) + + * Makefile.in (.m.c:): Added .SUFFIXES : .m + so flat_bl.c would make from flat_bl.m file. + +Thu May 5 19:23:24 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * Makefile.in (install-info): Check for gprof.info in build dir, + fall back to srcdir. Depend on it. + + * gprof.h (TRUE, FALSE): Always use undef before defining them. + +Mon Apr 4 23:47:30 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * Makefile.in (MY_MACHINE): Renamed from MACHINE to avoid losing + makes (osf1) in which the value of MACHINE can not be changed. + * config/*.mt: Changed appropriately. + +Wed Mar 30 16:12:40 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * gprof.c (getsymtab): Change nosyms to long. Rename + get_symtab_upper_bound to bfd_get_symtab_upper_bound. Check for + errors from bfd_get_symtab_upper_bound and + bfd_canonicalize_symtab. + +Tue Mar 22 10:50:52 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * gprof.c (funcsymbol): Use bfd_get_symbol_info instead of + bfd_decode_symclass. + +Sun Mar 20 15:40:21 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * Makefile.in: Avoid bug in hpux sed. + +Wed Dec 15 20:16:40 1993 david d `zoo' zuhn (zoo@andros.cygnus.com) + + * gprof.texi (Invoking): add text about -v flag + + * gprof.1: add text about -v flag + +Wed Dec 8 16:55:06 1993 david d `zoo' zuhn (zoo@andros.cygnus.com) + + * gprof.c (VERSION): defined a version macro, print the value + when the -v option is used + +Tue Jul 6 10:11:56 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * Makefile.in: Install correctly. + +Thu Jun 24 14:43:22 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * gprof.c (main): Get whoami from argv, instead of hardcoding. + Use it in usage message. Split usage message to fit in 80 cols. + +Sun Jun 20 20:58:02 1993 Ken Raeburn (raeburn@poseidon.cygnus.com) + + * Makefile.in: Undo 15 June change. + +Wed Jun 16 12:54:53 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * gmon.h, gprof.h: structs of chars used to hold external + representations. + * gprof.c (getpfile, openpfile, readsamples): Swap data in using + new structures. + +Tue Jun 15 23:09:17 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * Makefile.in (.c.o): Look in ../include, not ../bfd, for bfd.h. + +Mon Jun 14 16:22:59 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) + + * Makefile.in: remove parentdir support + +Mon Jun 7 12:56:17 1993 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in (INCLUDES): Add -I../bfd for sysdep.h and bfd.h. + * configure.in: No longer need to configure to get sysdep.h. + +Tue May 18 21:44:11 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in (install): should not depend on install-info + +Mon Apr 26 12:37:46 1993 Ian Lance Taylor (ian@cygnus.com) + + * gprof.h: Include ansidecl.h before sysdep.h. Undefine hz. + +Tue Apr 13 16:14:03 1993 Per Bothner (bothner@cygnus.com) + + * M Makefile.in: Add -g to CFLAGS. + Ads LDFLAGS and use in place of CFLAGS where appropriate. + * configure.in: Make a sysdep.hlink in the same way other + bfd-based directories do. + * gprof.h (UNIT): Replace non-standard 'u_short' by 'unsigned + short'. + * gprof.h: #include sysdep.h instead of a bunch of stuff. + * gprof.c (main): Fix typo gproff->gprof. + +Thu Mar 25 19:00:37 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * gprof.texi: add INFO-DIR-ENTRY + +Tue Mar 23 00:03:11 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: add installcheck target + +Sat Feb 27 18:17:10 1993 Per Bothner (bothner@rtl.cygnus.com) + + * gprof.c (funcsymbol): Invert test for aflag. + +Thu Feb 25 16:01:50 1993 Per Bothner (bothner@rtl.cygnus.com) + + * printgprof (xmalloc, xrealloc): Cast results of malloc + and realloc to PTR. + +Wed Feb 3 13:55:33 1993 Jeffrey Osier (jeffrey@fowanton.cygnus.com) + + * Makefile.in: created info, install-info, dvi + +Wed Jan 6 00:58:09 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: fix install rule for $(PROG) + +Fri Oct 9 11:25:41 1992 Mark Eichin (eichin@cygnus.com) + + * gprof.1: updated SYNOPSIS to match actual behavior. + +Mon Oct 5 17:50:16 1992 Per Bothner (bothner@cygnus.com) + + * gen-c-prog.awk: New awk script, lightly changed from + previously deleted make-c-prog.awk. Converts a text file + to a c function that prints that text. + * flat_bl.m, fsf_callg_bl.m, bsd_callg_bl.m: New files. + Inputs to gen-c-prog.awk, containing text describing + gprof output. + * blurbs.c: Removed. Use *_bl.c instead. + * Makefile.in: Use gen-cprog.awk to generate *_bl.c files + from *_bl.m files. Also, improve *clean rules. + * printgprof.c (printgprof): Usw new function names from *_bl.c. + + +Sun Aug 30 19:54:53 1992 Per Bothner (bothner@rtl.cygnus.com) + + * gprof.h, gprof.c, printfgprof.c: Add support for two + output styles: The default is similar to the old FSF gprof, + while -T sets the variable bsd_style_output, which causes + output matching Berkeley's gprof. The biggest differences + are that with the FSF style output, the flat profile comes + before the call graph; numbers come before explanations; + and there is less gratuitous white space. + * gprof.h, gprof.c, printfgprof.c: New discard_underscores + variable causes discarding of initial underscores when + printing symbol names. It is set unless there is a "main" + symbol (without an underscore). + * printfgprof.c: New function printnameonly(), called + by printname(). It handles stripping of initial '_', + as well as C++ name-demangling. + * gprof.callg, gprof.flat, make-c-prog.awk: Removed. + It is just as convenient to edit blurbs.c directly. + * Makefile.in: Removed rule for making blurbs.c. + * blurbs.c: This is now a true source file (as opposed + to being generated from gprof.callg and gprof.flat). + Change style to use one long string literal, instead of + one literal per output line. Add FSF-style blurb for call graph. + +Wed Aug 19 14:36:39 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: always create installation directories. + +Wed Aug 12 15:14:14 1992 Mark Eichin (eichin@cygnus.com) + + * Makefile.in: change ${MACHINE} to $(MACHINE). + +Sun Jul 19 17:34:01 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: removed installation of the now useless + call.{flag,callg} files. + + * gprof.1: now uses the standard man macros instead of the new BSD + mandoc macros. + +Sun Jul 12 19:06:00 1992 John Gilmore (gnu at cygnus.com) + + * configure.in: Remove host section, expand target section. + * config/mt-{tahoe,vax}: Add, to match existing support files. + * config/tmake-*: Remove leftover crud. + + * blurbs.c: New file, created from gprof.flat and gprof.callg by + * make-c-prog.awk: which processes text files into C programs. + * printgprof.c (flatprofheader, gprofheader): Call new functions + to print blurbs. + (printblurb): Remove. + * Makefile.in: Infrastructure to build blurbs. + * pathnames.h: has been removed. Gprof now has no filename + dependencies in it. + * gprof.c: Lint. + +Sat Jul 11 18:07:21 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: define man1dir and install the man page + +Fri Jul 10 21:14:08 1992 david d `zoo' zuhn (zoo@cygnus.com) + + * Makefile.in: added dummy info and install-info targets + +Thu Jun 4 11:34:02 1992 Mark Eichin (eichin at cygnus.com) + + * lookup.c: fixed fencepost in nllookup and added dbg_nllookup for + help in debugging the problem (with -DDEBUG) + * gprof.c: symbol values are now real values, don't add the vma + anymore. (done for solaris; should verify this on other platforms) + * ChangeLog: created. diff --git a/gprof/Makefile.am b/gprof/Makefile.am new file mode 100644 index 0000000..7ae1492 --- /dev/null +++ b/gprof/Makefile.am @@ -0,0 +1,74 @@ +## Process this file with automake to generate Makefile.in + +AUTOMAKE_OPTIONS = cygnus + +SUFFIXES = .m + +SUBDIRS = po + +INCLUDES = -D_GNU_SOURCE -DDEBUG -I../bfd -I$(srcdir)/../include -I$(srcdir)/../bfd -I$(srcdir)/../intl -I../intl -DLOCALEDIR="\"$(prefix)/share/locale\"" + +bin_PROGRAMS = gprof + +## Convenience var listing pure sources. +sources = basic_blocks.c call_graph.c cg_arcs.c cg_dfn.c \ + cg_print.c corefile.c gmon_io.c gprof.c hertz.c hist.c source.c \ + search_list.c symtab.c sym_ids.c utils.c \ + i386.c alpha.c vax.c tahoe.c sparc.c +gprof_SOURCES = $(sources) flat_bl.c bsd_callg_bl.c fsf_callg_bl.c +gprof_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a $(INTLDEPS) +gprof_LDADD = ../bfd/libbfd.la ../libiberty/libiberty.a $(INTLLIBS) + +noinst_HEADERS = \ + basic_blocks.h call_graph.h cg_arcs.h cg_dfn.h cg_print.h \ + corefile.h gmon.h gmon_io.h gmon_out.h gprof.h hertz.h hist.h \ + search_list.h source.h sym_ids.h symtab.h utils.h + +EXTRA_DIST = flat_bl.c bsd_callg_bl.c fsf_callg_bl.c bbconv.pl + +BUILT_SOURCES = flat_bl.c bsd_callg_bl.c fsf_callg_bl.c + +diststuff: $(BUILT_SOURCES) info + +.m.c: + awk -f $(srcdir)/gen-c-prog.awk > ./$*.c \ + FUNCTION=`(echo $*|sed -e 's,.*/,,g' -e 's/_bl//')`_blurb \ + FILE=$*.m $(srcdir)/$*.m + +POTFILES = $(sources) $(noinst_HEADERS) +po/POTFILES.in: @MAINT@ Makefile + for file in $(POTFILES); do echo $$file; done | sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in + +info_TEXINFOS = gprof.texi +man_MANS = gprof.1 + +# Dependencies. +$(OBJECTS): ../bfd/bfd.h call_graph.h cg_arcs.h cg_print.h \ + corefile.h gmon_io.h gmon_out.h gprof.h hertz.h hist.h \ + search_list.h source.h sym_ids.h symtab.h utils.h \ + $(srcdir)/../include/libiberty.h $(srcdir)/../bfd/sysdep.h \ + gconfig.h ../bfd/config.h +basic_blocks.o: basic_blocks.c +bsd_call_bl.o: bsd_call_bl.c +call_graph.o: call_graph.c +cg_arcs.o: cg_arcs.c +cg_dfn.o: cg_dfn.c +cg_print.o: cg_print.c +corefile.o: corefile.c +flat_bl.o: flat_bl.c +fsf_callg_bl.o: fsf_callg_bl.c +gmon_io.o: gmon_io.c +gprof.o: gprof.c +hertz.o: hertz.c +hist.o: hist.c +search_list.o: search_list.c +source.o: source.c +symtab.o: symtab.c +sym_ids.o: sym_ids.c +utils.o: utils.c +i386.o: i386.c +alpha.o: alpha.c +vax.o: vax.c +tahoe.o: tahoe.c +sparc.o: sparc.c diff --git a/gprof/Makefile.in b/gprof/Makefile.in new file mode 100644 index 0000000..4aadd88 --- /dev/null +++ b/gprof/Makefile.in @@ -0,0 +1,726 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AS = @AS@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +DATADIRNAME = @DATADIRNAME@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GT_NO = @GT_NO@ +GT_YES = @GT_YES@ +INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@ +INSTOBJEXT = @INSTOBJEXT@ +INTLDEPS = @INTLDEPS@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +LD = @LD@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +NM = @NM@ +PACKAGE = @PACKAGE@ +POFILES = @POFILES@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +USE_SYMBOL_UNDERSCORE = @USE_SYMBOL_UNDERSCORE@ +VERSION = @VERSION@ +l = @l@ + +AUTOMAKE_OPTIONS = cygnus + +SUFFIXES = .m + +SUBDIRS = po + +INCLUDES = -D_GNU_SOURCE -DDEBUG -I../bfd -I$(srcdir)/../include -I$(srcdir)/../bfd -I$(srcdir)/../intl -I../intl -DLOCALEDIR="\"$(prefix)/share/locale\"" + +bin_PROGRAMS = gprof + +sources = basic_blocks.c call_graph.c cg_arcs.c cg_dfn.c \ + cg_print.c corefile.c gmon_io.c gprof.c hertz.c hist.c source.c \ + search_list.c symtab.c sym_ids.c utils.c \ + i386.c alpha.c vax.c tahoe.c sparc.c + +gprof_SOURCES = $(sources) flat_bl.c bsd_callg_bl.c fsf_callg_bl.c +gprof_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a $(INTLDEPS) +gprof_LDADD = ../bfd/libbfd.la ../libiberty/libiberty.a $(INTLLIBS) + +noinst_HEADERS = \ + basic_blocks.h call_graph.h cg_arcs.h cg_dfn.h cg_print.h \ + corefile.h gmon.h gmon_io.h gmon_out.h gprof.h hertz.h hist.h \ + search_list.h source.h sym_ids.h symtab.h utils.h + + +EXTRA_DIST = flat_bl.c bsd_callg_bl.c fsf_callg_bl.c bbconv.pl + +BUILT_SOURCES = flat_bl.c bsd_callg_bl.c fsf_callg_bl.c + +POTFILES = $(sources) $(noinst_HEADERS) + +info_TEXINFOS = gprof.texi +man_MANS = gprof.1 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = gconfig.h +CONFIG_CLEAN_FILES = +bin_PROGRAMS = gprof$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +gprof_OBJECTS = basic_blocks.o call_graph.o cg_arcs.o cg_dfn.o \ +cg_print.o corefile.o gmon_io.o gprof.o hertz.o hist.o source.o \ +search_list.o symtab.o sym_ids.o utils.o i386.o alpha.o vax.o tahoe.o \ +sparc.o flat_bl.o bsd_callg_bl.o fsf_callg_bl.o +gprof_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +TEXI2DVI = `if test -f $(top_srcdir)/../texinfo/util/texi2dvi; then echo $(top_srcdir)/../texinfo/util/texi2dvi; else echo texi2dvi; fi` +TEXINFO_TEX = $(top_srcdir)/../texinfo/texinfo.tex +INFO_DEPS = gprof.info +DVIS = gprof.dvi +TEXINFOS = gprof.texi +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = ./stamp-h.in ChangeLog Makefile.am Makefile.in TODO \ +aclocal.m4 configure configure.in gconfig.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(gprof_SOURCES) +OBJECTS = $(gprof_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .dvi .info .lo .m .o .ps .s .texi .texinfo .txi +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --cygnus Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +gconfig.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/gconfig.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=gconfig.h:gconfig.in \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/gconfig.in: @MAINTAINER_MODE_TRUE@$(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f gconfig.h + +maintainer-clean-hdr: + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +gprof$(EXEEXT): $(gprof_OBJECTS) $(gprof_DEPENDENCIES) + @rm -f gprof$(EXEEXT) + $(LINK) $(gprof_LDFLAGS) $(gprof_OBJECTS) $(gprof_LDADD) $(LIBS) + +gprof.info: gprof.texi +gprof.dvi: gprof.texi + + +DVIPS = dvips + +.texi.info: + @rm -f $@ $@-[0-9] $@-[0-9][0-9] + $(MAKEINFO) -I $(srcdir) $< + +.texi.dvi: + TEXINPUTS=$(top_srcdir)/../texinfo/texinfo.tex:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.texi: + @rm -f $@ $@-[0-9] $@-[0-9][0-9] + $(MAKEINFO) -I $(srcdir) $< + +.texinfo.info: + @rm -f $@ $@-[0-9] $@-[0-9][0-9] + $(MAKEINFO) -I $(srcdir) $< + +.texinfo: + @rm -f $@ $@-[0-9] $@-[0-9][0-9] + $(MAKEINFO) -I $(srcdir) $< + +.texinfo.dvi: + TEXINPUTS=$(top_srcdir)/../texinfo/texinfo.tex:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.txi.info: + @rm -f $@ $@-[0-9] $@-[0-9][0-9] + $(MAKEINFO) -I $(srcdir) $< + +.txi.dvi: + TEXINPUTS=$(top_srcdir)/../texinfo/texinfo.tex:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.txi: + @rm -f $@ $@-[0-9] $@-[0-9][0-9] + $(MAKEINFO) -I $(srcdir) $< +.dvi.ps: + $(DVIPS) $< -o $@ + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(infodir) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \ + if test -f $$d/$$ifile; then \ + echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \ + $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \ + else : ; fi; \ + done; \ + done + @$(POST_INSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\ + install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\ + done; \ + else : ; fi + +uninstall-info: + $(PRE_UNINSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + ii=yes; \ + else ii=; fi; \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + test -z "$ii" \ + || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \ + done + @$(NORMAL_UNINSTALL) + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \ + done + +dist-info: $(INFO_DEPS) + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + if test -f $$base; then d=.; else d=$(srcdir); fi; \ + for file in `cd $$d && eval echo $$base*`; do \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done; \ + done + +mostlyclean-aminfo: + -rm -f gprof.aux gprof.cp gprof.cps gprof.dvi gprof.fn gprof.fns \ + gprof.ky gprof.kys gprof.ps gprof.log gprof.pg gprof.toc \ + gprof.tp gprof.tps gprof.vr gprof.vrs gprof.op gprof.tr \ + gprof.cv gprof.cn + +clean-aminfo: + +distclean-aminfo: + +maintainer-clean-aminfo: + for i in $(INFO_DEPS); do \ + rm -f $$i; \ + if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \ + rm -f $$i-[0-9]*; \ + fi; \ + done +clean-info: mostlyclean-aminfo + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man1 + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive install-info-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) gconfig.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)gconfig.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags gconfig.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + @for file in $(DISTFILES); do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info +info-am: $(INFO_DEPS) +info: info-recursive +dvi-am: $(DVIS) +dvi: dvi-recursive +check-am: +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-info-am: +install-info: install-info-recursive +all-recursive-am: gconfig.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: install-binPROGRAMS +install-exec: install-exec-recursive + +install-data-am: install-man +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: uninstall-binPROGRAMS uninstall-man +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) $(MANS) $(HEADERS) gconfig.h +all-redirect: all-recursive-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(mandir)/man1 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-hdr mostlyclean-binPROGRAMS \ + mostlyclean-compile mostlyclean-libtool \ + mostlyclean-aminfo mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-binPROGRAMS clean-compile clean-libtool \ + clean-aminfo clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-binPROGRAMS distclean-compile \ + distclean-libtool distclean-aminfo distclean-tags \ + distclean-generic clean-am + -rm -f libtool + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-aminfo maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-libtool distclean-libtool \ +clean-libtool maintainer-clean-libtool install-info-am uninstall-info \ +mostlyclean-aminfo distclean-aminfo clean-aminfo \ +maintainer-clean-aminfo install-man1 uninstall-man1 install-man \ +uninstall-man install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-info-am \ +install-info all-recursive-am install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +diststuff: $(BUILT_SOURCES) info + +.m.c: + awk -f $(srcdir)/gen-c-prog.awk > ./$*.c \ + FUNCTION=`(echo $*|sed -e 's,.*/,,g' -e 's/_bl//')`_blurb \ + FILE=$*.m $(srcdir)/$*.m +po/POTFILES.in: @MAINT@ Makefile + for file in $(POTFILES); do echo $$file; done | sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in + +# Dependencies. +$(OBJECTS): ../bfd/bfd.h call_graph.h cg_arcs.h cg_print.h \ + corefile.h gmon_io.h gmon_out.h gprof.h hertz.h hist.h \ + search_list.h source.h sym_ids.h symtab.h utils.h \ + $(srcdir)/../include/libiberty.h $(srcdir)/../bfd/sysdep.h \ + gconfig.h ../bfd/config.h +basic_blocks.o: basic_blocks.c +bsd_call_bl.o: bsd_call_bl.c +call_graph.o: call_graph.c +cg_arcs.o: cg_arcs.c +cg_dfn.o: cg_dfn.c +cg_print.o: cg_print.c +corefile.o: corefile.c +flat_bl.o: flat_bl.c +fsf_callg_bl.o: fsf_callg_bl.c +gmon_io.o: gmon_io.c +gprof.o: gprof.c +hertz.o: hertz.c +hist.o: hist.c +search_list.o: search_list.c +source.o: source.c +symtab.o: symtab.c +sym_ids.o: sym_ids.c +utils.o: utils.c +i386.o: i386.c +alpha.o: alpha.c +vax.o: vax.c +tahoe.o: tahoe.c +sparc.o: sparc.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gprof/NOTES b/gprof/NOTES new file mode 100644 index 0000000..511af30 --- /dev/null +++ b/gprof/NOTES @@ -0,0 +1,438 @@ +Sun Feb 5 16:09:16 1995 + +This file documents the changes and new features available with this +version of GNU gprof. + +* New Features + + o Long options + + o Supports generalized file format, without breaking backward compatibility: + new file format supports basic-block execution counts and non-realtime + histograms (see below) + + o Supports profiling at the line level: flat profiles, call-graph profiles, + and execution-counts can all be displayed at a level that identifies + individual lines rather than just functions + + o Test-coverage support (similar to Sun tcov program): source files + can be annotated with the number of times a function was invoked + or with the number of times each basic-block in a function was + executed + + o Generalized histograms: not just execution-time, but arbitrary + histograms are support (for example, performance counter based + profiles) + + o Powerful mechanism to select data to be included/excluded from + analysis and/or output + + o Support for DEC OSF/1 v3.0 + + o Full cross-platform profiling support: gprof uses BFD to support + arbitrary, non-native object file formats and non-native byte-orders + (this feature has not been tested yet) + + o In the call-graph function index, static function names are now + printed together with the filename in which the function was defined + (required bfd_find_nearest_line() support and symbolic debugging + information to be present in the executable file) + + o Major overhaul of source code (compiles cleanly with -Wall, etc.) + +* Supported Platforms + +The current version is known to work on: + + o DEC OSF/1 v3.0 + All features supported. + + o SunOS 4.1.x + All features supported. + + o Solaris 2.3 + Line-level profiling unsupported because bfd_find_nearest_line() + is not fully implemented for Elf binaries. + + o HP-UX 9.01 + Line-level profiling unsupported because bfd_find_nearest_line() + is not fully implemented for SOM binaries. + +* Detailed Description + +** User Interface Changes + +The command-line interface is backwards compatible with earlier +versions of GNU gprof and Berkeley gprof. The only exception is +the option to delete arcs from the call graph. The old syntax +was: + + -k fromname toname + +while the new syntax is: + + -k fromname/toname + +This change was necessary to be compatible with long-option parsing. +Also, "fromname" and "toname" can now be arbitrary symspecs rather +than just function names (see below for an explanation of symspecs). +For example, option "-k gprof.c/" suppresses all arcs due to calls out +of file "gprof.c". + +*** Sym Specs + +It is often necessary to apply gprof only to specific parts of a +program. GNU gprof has a simple but powerful mechanism to achieve +this. So called {\em symspecs\/} provide the foundation for this +mechanism. A symspec selects the parts of a profiled program to which +an operation should be applied to. The syntax of a symspec is +simple: + + filename_containing_a_dot + | funcname_not_containing_a_dot + | linenumber + | ( [ any_filename ] `:' ( any_funcname | linenumber ) ) + +Here are some examples: + + main.c Selects everything in file "main.c"---the + dot in the string tells gprof to interpret + the string as a filename, rather than as + a function name. To select a file whose + name does contain a dot, a trailing colon + should be specified. For example, "odd:" is + interpreted as the file named "odd". + + main Selects all functions named "main". Notice + that there may be multiple instances of the + same function name because some of the + definitions may be local (i.e., static). + Unless a function name is unique in a program, + you must use the colon notation explained + below to specify a function from a specific + source file. Sometimes, functionnames contain + dots. In such cases, it is necessar to + add a leading colon to the name. For example, + ":.mul" selects function ".mul". + + main.c:main Selects function "main" in file "main.c". + + main.c:134 Selects line 134 in file "main.c". + +IMPLEMENTATION NOTE: The source code uses the type sym_id for symspecs. +At some point, this probably ought to be changed to "sym_spec" to make +reading the code easier. + +*** Long options + +GNU gprof now supports long options. The following is a list of all +supported options. Options that are listed without description +operate in the same manner as the corresponding option in older +versions of gprof. + +Short Form: Long Form: +----------- ---------- +-l --line + Request profiling at the line-level rather + than just at the function level. Source + lines are identified by symbols of the form: + + func (file:line) + + where "func" is the function name, "file" is the + file name and "line" is the line-number that + corresponds to the line. + + To work properly, the binary must contain symbolic + debugging information. This means that the source + have to be translated with option "-g" specified. + Functions for which there is no symbolic debugging + information available are treated as if "--line" + had not been specified. However, the line number + printed with such symbols is usually incorrect + and should be ignored. + +-a --no-static +-A[symspec] --annotated-source[=symspec] + Request output in the form of annotated source + files. If "symspec" is specified, print output only + for symbols selected by "symspec". If the option + is specified multiple times, annotated output is + generated for the union of all symspecs. + + Examples: + + -A Prints annotated source for all + source files. + -Agprof.c Prints annotated source for file + gprof.c. + -Afoobar Prints annotated source for files + containing a function named "foobar". + The entire file will be printed, but + only the function itself will be + annotated with profile data. + +-J[symspec] --no-annotated-source[=symspec] + Suppress annotated source output. If specified + without argument, annotated output is suppressed + completely. With an argument, annotated output + is suppressed only for the symbols selected by + "symspec". If the option is specified multiple + times, annotated output is suppressed for the + union of all symspecs. This option has lower + precedence than --annotated-source + +-p[symspec] --flat-profile[=symspec] + Request output in the form of a flat profile + (unless any other output-style option is specified, + this option is turned on by default). If + "symspec" is specified, include only symbols + selected by "symspec" in flat profile. If the + option is specified multiple times, the flat + profile includes symbols selected by the union + of all symspecs. + +-P[symspec] --no-flat-profile[=symspec] + Suppress output in the flat profile. If given + without an argument, the flat profile is suppressed + completely. If "symspec" is specified, suppress + the selected symbols in the flat profile. If the + option is specified multiple times, the union of + the selected symbols is suppressed. This option + has lower precedence than --flat-profile. + +-q[symspec] --graph[=symspec] + Request output in the form of a call-graph + (unless any other output-style option is specified, + this option is turned on by default). If "symspec" + is specified, include only symbols selected by + "symspec" in the call-graph. If the option is + specified multiple times, the call-graph includes + symbols selected by the union of all symspecs. + +-Q[symspec] --no-graph[=symspec] + Suppress output in the call-graph. If given without + an argument, the call-graph is suppressed completely. + With a "symspec", suppress the selected symbols + from the call-graph. If the option is specified + multiple times, the union of the selected symbols + is suppressed. This option has lower precedence + than --graph. + +-C[symspec] --exec-counts[=symspec] + Request output in the form of execution counts. + If "symspec" is present, include only symbols + selected by "symspec" in the execution count + listing. If the option is specified multiple + times, the execution count listing includes + symbols selected by the union of all symspecs. + +-Z[symspec] --no-exec-counts[=symspec] + Suppress output in the execution count listing. + If given without an argument, the listing is + suppressed completely. With a "symspec", suppress + the selected symbols from the call-graph. If the + option is specified multiple times, the union of + the selected symbols is suppressed. This option + has lower precedence than --exec-counts. + +-i --file-info + Print information about the profile files that + are read. The information consists of the + number and types of records present in the + profile file. Currently, a profile file can + contain any number and any combination of histogram, + call-graph, or basic-block count records. + +-s --sum + +-x --all-lines + This option affects annotated source output only. + By default, only the lines at the beginning of + a basic-block are annotated. If this option is + specified, every line in a basic-block is annotated + by repeating the annotation for the first line. + This option is identical to tcov's "-a". + +-I dirs --directory-path=dirs + This option affects annotated source output only. + Specifies the list of directories to be searched + for source files. The argument "dirs" is a colon + separated list of directories. By default, gprof + searches for source files relative to the current + working directory only. + +-z --display-unused-functions + +-m num --min-count=num + This option affects annotated source and execution + count output only. Symbols that are executed + less than "num" times are suppressed. For annotated + source output, suppressed symbols are marked + by five hash-marks (#####). In an execution count + output, suppressed symbols do not appear at all. + +-L --print-path + Normally, source filenames are printed with the path + component suppressed. With this option, gprof + can be forced to print the full pathname of + source filenames. The full pathname is determined + from symbolic debugging information in the image file + and is relative to the directory in which the compiler + was invoked. + +-y --separate-files + This option affects annotated source output only. + Normally, gprof prints annotated source files + to standard-output. If this option is specified, + annotated source for a file named "path/filename" + is generated in the file "filename-ann". That is, + annotated output is {\em always\/} generated in + gprof's current working directory. Care has to + be taken if a program consists of files that have + identical filenames, but distinct paths. + +-c --static-call-graph + +-t num --table-length=num + This option affects annotated source output only. + After annotating a source file, gprof generates + an execution count summary consisting of a table + of lines with the top execution counts. By + default, this table is ten entries long. + This option can be used to change the table length + or, by specifying an argument value of 0, it can be + suppressed completely. + +-n symspec --time=symspec + Only symbols selected by "symspec" are considered + in total and percentage time computations. + However, this option does not affect percentage time + computation for the flat profile. + If the option is specified multiple times, the union + of all selected symbols is used in time computations. + +-N --no-time=symspec + Exclude the symbols selected by "symspec" from + total and percentage time computations. + However, this option does not affect percentage time + computation for the flat profile. + This option is ignored if any --time options are + specified. + +-w num --width=num + Sets the output line width. Currently, this option + affects the printing of the call-graph function index + only. + +-e +-E +-f +-F +-k +-b --brief +-dnum --debug[=num] + +-h --help + Prints a usage message. + +-O name --file-format=name + Selects the format of the profile data files. + Recognized formats are "auto", "bsd", "magic", + and "prof". The last one is not yet supported. + Format "auto" attempts to detect the file format + automatically (this is the default behavior). + It attempts to read the profile data files as + "magic" files and if this fails, falls back to + the "bsd" format. "bsd" forces gprof to read + the data files in the BSD format. "magic" forces + gprof to read the data files in the "magic" format. + +-T --traditional +-v --version + +** File Format Changes + +The old BSD-derived format used for profile data does not contain a +magic cookie that allows to check whether a data file really is a +gprof file. Furthermore, it does not provide a version number, thus +rendering changes to the file format almost impossible. GNU gprof +uses a new file format that provides these features. For backward +compatibility, GNU gprof continues to support the old BSD-derived +format, but not all features are supported with it. For example, +basic-block execution counts cannot be accommodated by the old file +format. + +The new file format is defined in header file \file{gmon_out.h}. It +consists of a header containing the magic cookie and a version number, +as well as some spare bytes available for future extensions. All data +in a profile data file is in the native format of the host on which +the profile was collected. GNU gprof adapts automatically to the +byte-order in use. + +In the new file format, the header is followed by a sequence of +records. Currently, there are three different record types: histogram +records, call-graph arc records, and basic-block execution count +records. Each file can contain any number of each record type. When +reading a file, GNU gprof will ensure records of the same type are +compatible with each other and compute the union of all records. For +example, for basic-block execution counts, the union is simply the sum +of all execution counts for each basic-block. + +*** Histogram Records + +Histogram records consist of a header that is followed by an array of +bins. The header contains the text-segment range that the histogram +spans, the size of the histogram in bytes (unlike in the old BSD +format, this does not include the size of the header), the rate of the +profiling clock, and the physical dimension that the bin counts +represent after being scaled by the profiling clock rate. The +physical dimension is specified in two parts: a long name of up to 15 +characters and a single character abbreviation. For example, a +histogram representing real-time would specify the long name as +"seconds" and the abbreviation as "s". This feature is useful for +architectures that support performance monitor hardware (which, +fortunately, is becoming increasingly common). For example, under DEC +OSF/1, the "uprofile" command can be used to produce a histogram of, +say, instruction cache misses. In this case, the dimension in the +histogram header could be set to "i-cache misses" and the abbreviation +could be set to "1" (because it is simply a count, not a physical +dimension). Also, the profiling rate would have to be set to 1 in +this case. + +Histogram bins are 16-bit numbers and each bin represent an equal +amount of text-space. For example, if the text-segment is one +thousand bytes long and if there are ten bins in the histogram, each +bin represents one hundred bytes. + + +*** Call-Graph Records + +Call-graph records have a format that is identical to the one used in +the BSD-derived file format. It consists of an arc in the call graph +and a count indicating the number of times the arc was traversed +during program execution. Arcs are specified by a pair of addresses: +the first must be within caller's function and the second must be +within the callee's function. When performing profiling at the +function level, these addresses can point anywhere within the +respective function. However, when profiling at the line-level, it is +better if the addresses are as close to the call-site/entry-point as +possible. This will ensure that the line-level call-graph is able to +identify exactly which line of source code performed calls to a +function. + +*** Basic-Block Execution Count Records + +Basic-block execution count records consist of a header followed by a +sequence of address/count pairs. The header simply specifies the +length of the sequence. In an address/count pair, the address +identifies a basic-block and the count specifies the number of times +that basic-block was executed. Any address within the basic-address can +be used. + +IMPLEMENTATION NOTE: gcc -a can be used to instrument a program to +record basic-block execution counts. However, the __bb_exit_func() +that is currently present in libgcc2.c does not generate a gmon.out +file in a suiteable format. This should be fixed for future releases +of gcc. In the meantime, contact davidm@cs.arizona.edu for a version +of __bb_exit_func() to is appropriate. diff --git a/gprof/TEST b/gprof/TEST new file mode 100644 index 0000000..78a9030 --- /dev/null +++ b/gprof/TEST @@ -0,0 +1,7 @@ +- check whether old file format is properly read when input comes from + stdin + +- check whether underscores are properly dealt with (both, on systems + that prepend them to each C name and on systems that don't) + +- ensure gprof fails gracefully when no debugging info available diff --git a/gprof/TODO b/gprof/TODO new file mode 100644 index 0000000..20111c6 --- /dev/null +++ b/gprof/TODO @@ -0,0 +1,72 @@ + +- gmon_io.c cannot deal with target architecture that have a pointer size + that is different from the host architectures pointer size---fix this + (gmon_out.h, and gmon_io.c) +- add support for prof file format so that prof files can be displayed + at the line-level (this is useful for the uprofile tool under DEC's + OSF/1) +- take a hard look at --file-ordering (broken) and --function-ordering + ++ documentation ++ optimize bfd_find_nearest_line_num() (or replace by different interface) ++ cleanup _bfd_ecoff_find_nearest_line_num() fixes & description ++ ensure "cc -pg" produces good files under OSF/1 v3.0 ++ make sure gprof works together with OSF/1 v3.0's profiling libraries ++ implement symtab_parse(); modify sym_lookup() to consider addr_high ++ change gprof.c to collect lists, then invoke symtab_parse() for + each list ++ Questions: + o is -c (--static-call-graph) useful at all? i can't see + how; if it were deleted, gprof would be completely machine + independent => yup, it is + o are (long) option names appropriate? + o -k (--exclude-arc) cannot be implemented with getopt(); + is new syntax (-k from/to) acceptable? If not, how to + fix it? + o in the FSF output, the call-graph index now prints + the filename of static functions in parentheses; e.g., + static function foo() that is defined in file bar.c + would be printed as: + + [4] foo (bar.c) + + is this acceptable? should it be done only optionally? + o symbols with addresses that map back to a different + name are suppressed (happens with labels, for example); + is this acceptable? should it be done only optionally? ++ generalize to allow arbitrary histograms (not just time histograms) ++ basic-block information currently replaces all symbols created from + the core because of an ugly ordering conflict---for now, the current + solution works, but something cleaner is desirable ==> cleaned up, + but it's slower now ++ convert to very new file format (back to trivial format, that is :) ++ replace "dummy.h" for Alpha (if there is any use to it) ++ add support for execution time profiling at a basic-block level ++ fix filename-off-by-one bug for Alpha (see ~/tmp/d.[ch])---no longer + relevant ++ "-pg -a" doesn't work as expected because mcleanup() will overwrite + the file generated by __bb_exit_func() (or vice versa) ++ first basic-block of fac() seems to get credited to last basic-block + of previous function => bug in basic_blocks.c ++ flat profile should provide automatic scaling for per-call times because + otherwise they'll always be zero on a fast machine with tons of small + functions ++ make "-a" imply to retain line number info (without actually generating + the debugging information (unless -g is specified)---no, this is a + bad idea, because it is not clear what level of debugging info should + be requested (e.g., -g vs. -g3); leaving it up to the user seems best ++ add long options support (or at least use getopt instead of ad-hoc + implementation) ++ split into files according to abstract objects that are manipulated ++ replace sccsid by rcsid & add "end of ..." to every .c file ++ use DBG() everywhere ++ fix spacing (" ," -> "," etc.) ++ use DEFUNs everywhere ++ make compile cleanly with -Wall ++ "gcc -pg -O2" doesn't work on tecc.c unless -fno-omit-frame-pointer is + specified; find out why ++ make things portable (prototypes, const, etc.) ++ if NEW_GMON_OUT is not defined, have a flag that will allow to + read new gmon.out style files. The idea being that everyone + will use the new format for basic-block style profiling but + the old format for regular gpprofiling diff --git a/gprof/aclocal.m4 b/gprof/aclocal.m4 new file mode 100644 index 0000000..ad20122 --- /dev/null +++ b/gprof/aclocal.m4 @@ -0,0 +1,1109 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + + +# serial 35 AC_PROG_LIBTOOL +AC_DEFUN(AC_PROG_LIBTOOL, +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl + +# Save cache, so that ltconfig can load it +AC_CACHE_SAVE + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +DLLTOOL="$DLLTOOL" AS="$AS" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) + +# Reload cache, that may have been modified by ltconfig +AC_CACHE_LOAD + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +AC_DEFUN(AC_LIBTOOL_SETUP, +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_RANLIB])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_SYS_NM_PARSE])dnl +AC_REQUIRE([AC_SYS_SYMBOL_UNDERSCORE])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +dnl + +# Check for any special flags to pass to ltconfig. +libtool_flags="--cache-file=$cache_file" +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$lt_dlopen" = yes && libtool_flags="$libtool_flags --enable-dlopen" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$host" in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +*-*-cygwin*) + AC_SYS_LIBTOOL_CYGWIN + ;; + +esac + +# enable the --disable-libtool-lock switch + +AC_ARG_ENABLE(libtool-lock, +[ --disable-libtool-lock force libtool not to do file locking], +need_locks=$enableval, +need_locks=yes) + +if test x"$need_locks" = xno; then + libtool_flags="$libtool_flags --disable-lock" +fi +]) + +# AC_LIBTOOL_DLOPEN - check for dlopen support +AC_DEFUN(AC_LIBTOOL_DLOPEN, [lt_dlopen=yes]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_SHARED, +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN(AC_DISABLE_SHARED, +[AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_STATIC, +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN(AC_DISABLE_STATIC, +[AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_FAST_INSTALL, +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN(AC_DISABLE_FAST_INSTALL, +[AC_ENABLE_FAST_INSTALL(no)]) + + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AC_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. +changequote(,)dnl + /* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' +changequote([,])dnl + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_SUBST(LD) +AC_PROG_LD_GNU +]) + +AC_DEFUN(AC_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AC_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + ac_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + break + else + ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm +fi]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) + +# AC_SYS_NM_PARSE - Check for command to grab the raw symbol name followed +# by C symbol name from nm. +AC_DEFUN(AC_SYS_NM_PARSE, +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_NM])dnl +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output]) +AC_CACHE_VAL(ac_cv_sys_global_symbol_pipe, +[# These are sane defaults that work on at least a few old systems. +# {They come from Ultrix. What could be older than Ultrix?!! ;)} + +changequote(,)dnl +# Character class describing NM global symbol codes. +ac_symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +ac_symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +ac_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Define system-specific variables. +case "$host_os" in +aix*) + ac_symcode='[BCDT]' + ;; +cygwin* | mingw*) + ac_symcode='[ABCDGISTW]' + ;; +hpux*) + ac_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" + ;; +irix*) + ac_symcode='[BCDEGRST]' + ;; +solaris*) + ac_symcode='[BDT]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + ac_symcode='[ABCDGISTW]' +fi +changequote([,])dnl + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($ac_symcode\)[ ][ ]*\($ac_symprfx\)$ac_sympat$/$ac_symxfrm/p'" + + # Check to see that the pipe works correctly. + ac_pipe_works=no + rm -f conftest.$ac_ext + cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then + + # Try sorting and uniquifying the output. + if sort "$ac_nlist" | uniq > "$ac_nlist"T; then + mv -f "$ac_nlist"T "$ac_nlist" + else + rm -f "$ac_nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then + if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$ac_global_symbol_to_cdecl"' < "$ac_nlist" >> conftest.c' + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +changequote(,)dnl +lt_preloaded_symbols[] = +changequote([,])dnl +{ +EOF + sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftestm.$ac_objext + ac_save_LIBS="$LIBS" + ac_save_CFLAGS="$CFLAGS" + LIBS="conftestm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if AC_TRY_EVAL(ac_link) && test -s conftest; then + ac_pipe_works=yes + else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.c >&AC_FD_CC + fi + LIBS="$ac_save_LIBS" + CFLAGS="$ac_save_CFLAGS" + else + echo "cannot find nm_test_func in $ac_nlist" >&AC_FD_CC + fi + else + echo "cannot find nm_test_var in $ac_nlist" >&AC_FD_CC + fi + else + echo "cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "$progname: failed program was:" >&AC_FD_CC + cat conftest.c >&AC_FD_CC + fi + rm -rf conftest* + + # Do not use the global_symbol_pipe unless it works. + if test "$ac_pipe_works" = yes; then + if test x"$ac_symprfx" = x"_"; then + ac_cv_sys_symbol_underscore=yes + else + ac_cv_sys_symbol_underscore=no + fi + break + else + ac_cv_sys_global_symbol_pipe= + fi +done +]) + +ac_result=yes +if test -z "$ac_cv_sys_global_symbol_pipe"; then + ac_result=no +fi +AC_MSG_RESULT($ac_result) +]) + +# AC_SYS_LIBTOOL_CYGWIN - find tools needed on cygwin +AC_DEFUN(AC_SYS_LIBTOOL_CYGWIN, +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +AC_CHECK_TOOL(AS, as, false) +]) + +# AC_SYS_SYMBOL_UNDERSCORE - does the compiler prefix global symbols +# with an underscore? +AC_DEFUN(AC_SYS_SYMBOL_UNDERSCORE, +[AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_SYS_NM_PARSE])dnl +AC_MSG_CHECKING([for _ prefix in compiled symbols]) +AC_CACHE_VAL(ac_cv_sys_symbol_underscore, +[ac_cv_sys_symbol_underscore=no +cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if egrep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if egrep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC + fi + fi + else + echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.c >&AC_FD_CC +fi +rm -rf conftest* +]) +AC_MSG_RESULT($ac_cv_sys_symbol_underscore) +USE_SYMBOL_UNDERSCORE=${ac_cv_sys_symbol_underscore=no} +AC_SUBST(USE_SYMBOL_UNDERSCORE)dnl +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN(AC_CHECK_LIBM, [ +AC_CHECK_LIB(mw, _mwvalidcheckl) +AC_CHECK_LIB(m, cos) +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library, adds --enable-ltdl-convenience to +# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor +# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed +# to be `${top_builddir}/libltdl'. Make sure you start DIR with +# '${top_builddir}/' (note the single quotes!) if your package is not +# flat, and, if you're not using automake, define top_builddir as +# appropriate in the Makefiles. +AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [ + case "$enable_ltdl_convenience" in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library, and adds --enable-ltdl-install to +# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor +# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed +# to be `${top_builddir}/libltdl'. Make sure you start DIR with +# '${top_builddir}/' (note the single quotes!) if your package is not +# flat, and, if you're not using automake, define top_builddir as +# appropriate in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [ + AC_CHECK_LIB(ltdl, main, LIBLTDL="-lltdl", [ + case "$enable_ltdl_install" in + no) AC_MSG_WARN([libltdl not installed, but installation disabled]) ;; + "") enable_ltdl_install=yes + ac_configure_args="$ac_configure_args --enable-ltdl-install" ;; + esac + ]) + if test x"$enable_ltdl_install" != x"no"; then + LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la + fi +]) + +dnl old names +AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl +AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl +AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl +AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl +AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl +AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl +AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl +AC_DEFUN(AM_SYS_NM_PARSE, [indir([AC_SYS_NM_PARSE])])dnl +AC_DEFUN(AM_SYS_SYMBOL_UNDERSCORE, [indir([AC_SYS_SYMBOL_UNDERSCORE])])dnl +AC_DEFUN(AM_SYS_LIBTOOL_CYGWIN, [indir([AC_SYS_LIBTOOL_CYGWIN])])dnl + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + +# This file is derived from `gettext.m4'. The difference is that the +# included macros assume Cygnus-style source and build trees. + +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 3 + +AC_DEFUN(CY_WITH_NLS, + [AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) + + USE_INCLUDED_LIBINTL=no + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if NLS is requested]) + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If gettext or catgets are available (in this order) we + dnl use this. Else we have to fall back to GNU NLS library. + dnl catgets is only used if permitted by option --with-catgets. + nls_cv_header_intl= + nls_cv_header_libgt= + CATOBJEXT=NONE + + AC_CHECK_HEADER(libintl.h, + [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc, + [AC_TRY_LINK([#include ], [return (int) gettext ("")], + gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)]) + + if test "$gt_cv_func_gettext_libc" != "yes"; then + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CACHE_CHECK([for gettext in libintl], + gt_cv_func_gettext_libintl, + [AC_TRY_LINK([], [return (int) gettext ("")], + gt_cv_func_gettext_libintl=yes, + gt_cv_func_gettext_libintl=no)])]) + fi + + if test "$gt_cv_func_gettext_libc" = "yes" \ + || test "$gt_cv_func_gettext_libintl" = "yes"; then + AC_DEFINE(HAVE_GETTEXT, 1, + [Define as 1 if you have gettext and don't want to use GNU gettext.]) + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + INSTOBJEXT=.mo + fi + fi + ]) + + dnl In the standard gettext, we would now check for catgets. + dnl However, we never want to use catgets for our releases. + + if test "$CATOBJEXT" = "NONE"; then + dnl Neither gettext nor catgets in included in the C library. + dnl Fall back on GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + INTLOBJS="\$(GETTOBJS)" + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_SUBST(MSGFMT) + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.gmo + INSTOBJEXT=.mo + DATADIRNAME=share + INTLDEPS='$(top_builddir)/../intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + else + DATADIRNAME=share + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + # If this is used in GNU gettext we have to set USE_NLS to `yes' + # because some of the sources are only built for this goal. + if test "$PACKAGE" = gettext; then + USE_NLS=yes + USE_INCLUDED_LIBINTL=yes + fi + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLDEPS) + AC_SUBST(INTLLIBS) + AC_SUBST(INTLOBJS) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +AC_DEFUN(CY_GNU_GETTEXT, + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + + AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \ +unistd.h values.h sys/param.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + if test "${ac_cv_func_stpcpy+set}" != "set"; then + AC_CHECK_FUNCS(stpcpy) + fi + if test "${ac_cv_func_stpcpy}" = "yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have the stpcpy function]) + fi + + AM_LC_MESSAGES + CY_WITH_NLS + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl The reference to in the installed file + dnl must be resolved because we cannot expect the users of this + dnl to define HAVE_LOCALE_H. + if test $ac_cv_header_locale_h = yes; then + INCLUDE_LOCALE_H="#include " + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header . Take care yourself. */" + fi + AC_SUBST(INCLUDE_LOCALE_H) + + dnl Determine which catalog format we have (if any is needed) + dnl For now we know about two different formats: + dnl Linux libc-5 and the normal X/Open format + if test -f $srcdir/po2tbl.sed.in; then + if test "$CATOBJEXT" = ".cat"; then + AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen) + + dnl Transform the SED scripts while copying because some dumb SEDs + dnl cannot handle comments. + sed -e '/^#/d' $srcdir/$msgformat-msg.sed > po2msg.sed + fi + dnl po2tbl.sed is always needed. + sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \ + $srcdir/po2tbl.sed.in > po2tbl.sed + fi + + dnl In the intl/Makefile.in we have a special dependency which makes + dnl only sense for gettext. We comment this out for non-gettext + dnl packages. + if test "$PACKAGE" = "gettext"; then + GT_NO="#NO#" + GT_YES= + else + GT_NO= + GT_YES="#YES#" + fi + AC_SUBST(GT_NO) + AC_SUBST(GT_YES) + + MKINSTALLDIRS="\$(srcdir)/../../mkinstalldirs" + AC_SUBST(MKINSTALLDIRS) + + dnl *** For now the libtool support in intl/Makefile is not for real. + l= + AC_SUBST(l) + + dnl Generate list of files to be processed by xgettext which will + dnl be included in po/Makefile. But only do this if the po directory + dnl exists in srcdir. + if test -d $srcdir/po; then + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + fi + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AM_PATH_PROG_WITH_TEST, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +AC_DEFUN(AM_LC_MESSAGES, + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your locale.h file contains LC_MESSAGES.]) + fi + fi]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +# Define a conditional. + +AC_DEFUN(AM_CONDITIONAL, +[AC_SUBST($1_TRUE) +AC_SUBST($1_FALSE) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi]) + diff --git a/gprof/alpha.c b/gprof/alpha.c new file mode 100644 index 0000000..ad4f22e --- /dev/null +++ b/gprof/alpha.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1983, 1998 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. + */ +#include "gprof.h" +#include "cg_arcs.h" +#include "corefile.h" +#include "hist.h" +#include "symtab.h" + +/* + * Opcodes of the call instructions: + */ +#define OP_Jxx 0x1a +#define OP_BSR 0x34 + +#define Jxx_FUNC_JMP 0 +#define Jxx_FUNC_JSR 1 +#define Jxx_FUNC_RET 2 +#define Jxx_FUNC_JSR_COROUTINE 3 + +typedef union + { + struct + { + unsigned other:26; + unsigned op_code:6; + } + a; /* any format */ + struct + { + int disp:21; + unsigned ra:5; + unsigned op_code:6; + } + b; /* branch format */ + struct + { + int hint:14; + unsigned func:2; + unsigned rb:5; + unsigned ra:5; + unsigned op_code:6; + } + j; /* jump format */ + } +alpha_Instruction; + +static Sym indirect_child; + + +/* + * On the Alpha we can only detect PC relative calls, which are + * usually generated for calls to functions within the same + * object file only. This is still better than nothing, however. + * (In particular it should be possible to find functions that + * potentially call integer division routines, for example.) + */ +void +alpha_find_call (parent, p_lowpc, p_highpc) + Sym *parent; + bfd_vma p_lowpc; + bfd_vma p_highpc; +{ + static bfd_vma delta = 0; + bfd_vma dest_pc; + alpha_Instruction *pc; + Sym *child; + + if (!delta) + { + delta = (bfd_vma) core_text_space - core_text_sect->vma; + + sym_init (&indirect_child); + indirect_child.name = _(""); + indirect_child.cg.prop.fract = 1.0; + indirect_child.cg.cyc.head = &indirect_child; + } + + if (!core_text_space) + { + return; + } + if (p_lowpc < s_lowpc) + { + p_lowpc = s_lowpc; + } + if (p_highpc > s_highpc) + { + p_highpc = s_highpc; + } + DBG (CALLDEBUG, printf (_("[find_call] %s: 0x%lx to 0x%lx\n"), + parent->name, p_lowpc, p_highpc)); + for (pc = (alpha_Instruction *) (p_lowpc + delta); + pc < (alpha_Instruction *) (p_highpc + delta); + ++pc) + { + switch (pc->a.op_code) + { + case OP_Jxx: + /* + * There is no simple and reliable way to determine the + * target of a jsr (the hint bits help, but there aren't + * enough bits to get a satisfactory hit rate). Instead, + * for any indirect jump we simply add an arc from PARENT + * to INDIRECT_CHILD---that way the user it at least able + * to see that there are other calls as well. + */ + if (pc->j.func == Jxx_FUNC_JSR + || pc->j.func == Jxx_FUNC_JSR_COROUTINE) + { + DBG (CALLDEBUG, + printf (_("[find_call] 0x%lx: jsr%s \n"), + (bfd_vma) pc - delta, + pc->j.func == Jxx_FUNC_JSR ? "" : "_coroutine")); + arc_add (parent, &indirect_child, (unsigned long) 0); + } + break; + + case OP_BSR: + DBG (CALLDEBUG, + printf (_("[find_call] 0x%lx: bsr"), (bfd_vma) pc - delta)); + /* + * Regular PC relative addressing. Check that this is the + * address of a function. The linker sometimes redirects + * the entry point by 8 bytes to skip loading the global + * pointer, so we all for either address: + */ + dest_pc = ((bfd_vma) (pc + 1 + pc->b.disp)) - delta; + if (dest_pc >= s_lowpc && dest_pc <= s_highpc) + { + child = sym_lookup (&symtab, dest_pc); + DBG (CALLDEBUG, + printf (" 0x%lx\t; name=%s, addr=0x%lx", + dest_pc, child->name, child->addr)); + if (child->addr == dest_pc || child->addr == dest_pc - 8) + { + DBG (CALLDEBUG, printf ("\n")); + /* a hit: */ + arc_add (parent, child, (unsigned long) 0); + continue; + } + } + /* + * Something funny going on. + */ + DBG (CALLDEBUG, printf ("\tbut it's a botch\n")); + break; + + default: + break; + } + } +} diff --git a/gprof/basic_blocks.c b/gprof/basic_blocks.c new file mode 100644 index 0000000..07b6f8d --- /dev/null +++ b/gprof/basic_blocks.c @@ -0,0 +1,635 @@ +/* + * Basic-block level related code: reading/writing of basic-block info + * to/from gmon.out; computing and formatting of basic-block related + * statistics. + */ +#include +#include +#include "basic_blocks.h" +#include "corefile.h" +#include "gmon_io.h" +#include "gmon_out.h" +#include "gprof.h" +#include "libiberty.h" +#include "source.h" +#include "sym_ids.h" + + +/* + * Default option values: + */ +bool bb_annotate_all_lines = FALSE; +unsigned long bb_min_calls = 1; +int bb_table_length = 10; + +/* + * Variables used to compute annotated source listing stats: + */ +static long num_executable_lines; +static long num_lines_executed; + + +/* + * Helper for sorting. Compares two symbols and returns result + * such that sorting will be increasing according to filename, line + * number, and address (in that order). + */ + +static int +DEFUN (cmp_bb, (lp, rp), const void *lp AND const void *rp) +{ + int r; + const Sym *left = *(const Sym **) lp; + const Sym *right = *(const Sym **) rp; + + if (left->file && right->file) + { + r = strcmp (left->file->name, right->file->name); + if (r) + { + return r; + } + + if (left->line_num != right->line_num) + { + return left->line_num - right->line_num; + } + } + + if (left->addr < right->addr) + { + return -1; + } + else if (left->addr > right->addr) + { + return 1; + } + else + { + return 0; + } +} + + +/* + * Helper for sorting. Order basic blocks in decreasing number of + * calls, ties are broken in increasing order of line numbers. + */ +static int +DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp) +{ + const Sym *left = *(const Sym **) lp; + const Sym *right = *(const Sym **) rp; + + if (!left) + { + return 1; + } + else if (!right) + { + return -1; + } + + if (left->ncalls < right->ncalls) + return 1; + else if (left->ncalls > right->ncalls) + return -1; + + return left->line_num - right->line_num; +} + + +/* + * Skip over variable length string. + */ +static void +DEFUN (fskip_string, (fp), FILE * fp) +{ + int ch; + + while ((ch = fgetc (fp)) != EOF) + { + if (ch == '\0') + { + break; + } + } +} + + +/* + * Read a basic-block record from file IFP. FILENAME is the name + * of file IFP and is provided for formatting error-messages only. + */ +void +DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename) +{ + int nblocks, b; + bfd_vma addr; + unsigned long ncalls; + Sym *sym; + + if (fread (&nblocks, sizeof (nblocks), 1, ifp) != 1) + { + fprintf (stderr, _("%s: %s: unexpected end of file\n"), whoami, filename); + done (1); + } + + nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks); + if (gmon_file_version == 0) + { + fskip_string (ifp); + } + + for (b = 0; b < nblocks; ++b) + { + if (gmon_file_version == 0) + { + int line_num; + /* + * Version 0 had lots of extra stuff that we don't + * care about anymore. + */ + if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1) + || (fread (&addr, sizeof (addr), 1, ifp) != 1) + || (fskip_string (ifp), FALSE) + || (fskip_string (ifp), FALSE) + || (fread (&line_num, sizeof (line_num), 1, ifp) != 1)) + { + perror (filename); + done (1); + } + } + else + { + if (fread (&addr, sizeof (addr), 1, ifp) != 1 + || fread (&ncalls, sizeof (ncalls), 1, ifp) != 1) + { + perror (filename); + done (1); + } + } + + /* + * Basic-block execution counts are meaningful only if we're + * profiling at the line-by-line level: + */ + if (line_granularity) + { + + /* convert from target to host endianness: */ + + addr = get_vma (core_bfd, (bfd_byte *) & addr); + ncalls = bfd_get_32 (core_bfd, (bfd_byte *) &ncalls); + + sym = sym_lookup (&symtab, addr); + + if (sym) + { + int i; + + DBG (BBDEBUG, + printf ("[bb_read_rec] 0x%lx->0x%lx (%s:%d) cnt=%lu\n", + addr, sym->addr, sym->name, sym->line_num, ncalls)); + + for (i = 0; i < NBBS; i++) + { + if (! sym->bb_addr[i] || sym->bb_addr[i] == addr) + { + sym->bb_addr[i] = addr; + sym->bb_calls[i] += ncalls; + break; + } + } + } + } + else + { + static bool user_warned = FALSE; + + if (!user_warned) + { + user_warned = TRUE; + fprintf (stderr, + _("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"), + whoami); + } + } + } + return; +} + + +/* + * Write all basic-blocks with non-zero counts to file OFP. FILENAME + * is the name of OFP and is provided for producing error-messages + * only. + */ +void +DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename) +{ + const unsigned char tag = GMON_TAG_BB_COUNT; + int nblocks = 0; + bfd_vma addr; + unsigned long ncalls; + Sym *sym; + int i; + + /* count how many non-zero blocks with have: */ + + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + for (i = 0; i < NBBS && sym->bb_addr[i]; i++) + ; + nblocks += i; + } + + /* write header: */ + bfd_put_32 (core_bfd, nblocks, (bfd_byte *) & nblocks); + if (fwrite (&tag, sizeof (tag), 1, ofp) != 1 + || fwrite (&nblocks, sizeof (nblocks), 1, ofp) != 1) + { + perror (filename); + done (1); + } + + /* write counts: */ + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + for (i = 0; i < NBBS && sym->bb_addr[i]; i++) + { + put_vma (core_bfd, sym->bb_addr[i], (bfd_byte *) & addr); + bfd_put_32 (core_bfd, sym->bb_calls[i], (bfd_byte *) & ncalls); + + if (fwrite (&addr, sizeof (addr), 1, ofp) != 1 + || fwrite (&ncalls, sizeof (ncalls), 1, ofp) != 1) + { + perror (filename); + done (1); + } + } + } +} + + +/* + * Output basic-block statistics in a format that is easily parseable. + * Current the format is: + * + * :: (: + */ +void +DEFUN_VOID (print_exec_counts) +{ + Sym **sorted_bbs, *sym; + int i, j, len; + + if (first_output) + { + first_output = FALSE; + } + else + { + printf ("\f\n"); + } + + /* sort basic-blocks according to function name and line number: */ + + sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0])); + len = 0; + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + /* + * Accept symbol if it's in the INCL_EXEC table + * or there is no INCL_EXEC table + * and it does not appear in the EXCL_EXEC table. + */ + if (sym_lookup (&syms[INCL_EXEC], sym->addr) + || (syms[INCL_EXEC].len == 0 + && !sym_lookup (&syms[EXCL_EXEC], sym->addr))) + { + sorted_bbs[len++] = sym; + } + } + qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb); + + /* output basic-blocks: */ + + for (i = 0; i < len; ++i) + { + if (sym->ncalls > 0 || ! ignore_zeros) + { + printf (_("%s:%d: (%s:0x%lx) %lu executions\n"), + sym->file ? sym->file->name : _(""), sym->line_num, + sym->name, sym->addr, sym->ncalls); + } + for (j = 0; j < NBBS && sym->bb_addr[j]; j ++) + { + if (sym->bb_calls[j] > 0 || ! ignore_zeros) + { + printf (_("%s:%d: (%s:0x%lx) %lu executions\n"), + sym->file ? sym->file->name : _(""), sym->line_num, + sym->name, sym->bb_addr[j], sym->bb_calls[j]); + } + } + } + free (sorted_bbs); +} + +/* + * Helper for bb_annotated_source: format annotation containing + * number of line executions. Depends on being called on each + * line of a file in sequential order. + * + * Global variable bb_annotate_all_lines enables execution count + * compression (counts are supressed if identical to the last one) + * and prints counts on all executed lines. Otherwise, print + * all basic-block execution counts exactly once on the line + * that starts the basic-block. + */ + +static void +DEFUN (annotate_with_count, (buf, width, line_num, arg), + char *buf AND int width AND int line_num AND void *arg) +{ + Source_File *sf = arg; + Sym *b; + int i; + static unsigned long last_count; + unsigned long last_print = (unsigned long) -1; + + b = NULL; + if (line_num <= sf->num_lines) + { + b = sf->line[line_num - 1]; + } + if (!b) + { + for (i = 0; i < width; i++) + buf[i] = ' '; + buf[width] = '\0'; + } + else + { + char tmpbuf[NBBS * 30]; + char *p; + unsigned long ncalls; + int ncalls_set; + int len; + + ++num_executable_lines; + + p = tmpbuf; + *p = '\0'; + + ncalls = 0; + ncalls_set = 0; + + /* If this is a function entry point, label the line no matter what. + * Otherwise, we're in the middle of a function, so check to see + * if the first basic-block address is larger than the starting + * address of the line. If so, then this line begins with a + * a portion of the previous basic-block, so print that prior + * execution count (if bb_annotate_all_lines is set). + */ + + if (b->is_func) + { + sprintf (p, "%lu", b->ncalls); + p += strlen (p); + last_count = b->ncalls; + last_print = last_count; + ncalls = b->ncalls; + ncalls_set = 1; + } + else if (bb_annotate_all_lines + && b->bb_addr[0] && b->bb_addr[0] > b->addr) + { + sprintf (p, "%lu", last_count); + p += strlen (p); + last_print = last_count; + ncalls = last_count; + ncalls_set = 1; + } + + /* Loop through all of this line's basic-blocks. For each one, + * update last_count, then compress sequential identical counts + * (if bb_annotate_all_lines) and print the execution count. + */ + + for (i = 0; i < NBBS && b->bb_addr[i]; i++) + { + last_count = b->bb_calls[i]; + if (! ncalls_set) + { + ncalls = 0; + ncalls_set = 1; + } + ncalls += last_count; + + if (bb_annotate_all_lines && last_count == last_print) + { + continue; + } + + if (p > tmpbuf) + *p++ = ','; + sprintf (p, "%lu", last_count); + p += strlen (p); + + last_print = last_count; + } + + /* We're done. If nothing has been printed on this line, + * print the last execution count (bb_annotate_all_lines), + * which could be from either a previous line (if there were + * no BBs on this line), or from this line (if all our BB + * counts were compressed out because they were identical). + */ + + if (bb_annotate_all_lines && p == tmpbuf) + { + sprintf (p, "%lu", last_count); + p += strlen (p); + ncalls = last_count; + ncalls_set = 1; + } + + if (! ncalls_set) + { + int c; + + for (c = 0; c < width; c++) + buf[c] = ' '; + buf[width] = '\0'; + return; + } + + ++num_lines_executed; + + if (ncalls < bb_min_calls) + { + strcpy (tmpbuf, "#####"); + p = tmpbuf + 5; + } + + strcpy (p, " -> "); + p += 4; + + len = p - tmpbuf; + if (len >= width) + { + strncpy (buf, tmpbuf, width); + buf[width] = '\0'; + } + else + { + int c; + + strcpy (buf + width - len, tmpbuf); + for (c = 0; c < width - len; ++c) + buf[c] = ' '; + } + } +} + +/* + * Annotate the files named in SOURCE_FILES with basic-block statistics + * (execution counts). After each source files, a few statistics + * regarding that source file are printed. + */ +void +DEFUN_VOID (print_annotated_source) +{ + Sym *sym, *line_stats, *new_line; + Source_File *sf; + int i, table_len; + FILE *ofp; + + /* + * Find maximum line number for each source file that user is + * interested in: + */ + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + /* + * Accept symbol if it's file is known, its line number is + * bigger than anything we have seen for that file so far and + * if it's in the INCL_ANNO table or there is no INCL_ANNO + * table and it does not appear in the EXCL_ANNO table. + */ + if (sym->file && sym->line_num > sym->file->num_lines + && (sym_lookup (&syms[INCL_ANNO], sym->addr) + || (syms[INCL_ANNO].len == 0 + && !sym_lookup (&syms[EXCL_ANNO], sym->addr)))) + { + sym->file->num_lines = sym->line_num; + } + } + + /* allocate line descriptors: */ + + for (sf = first_src_file; sf; sf = sf->next) + { + if (sf->num_lines > 0) + { + sf->line = (void *) xmalloc (sf->num_lines * sizeof (sf->line[0])); + memset (sf->line, 0, sf->num_lines * sizeof (sf->line[0])); + } + } + + /* count executions per line: */ + + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + if (sym->file && sym->file->num_lines + && (sym_lookup (&syms[INCL_ANNO], sym->addr) + || (syms[INCL_ANNO].len == 0 + && !sym_lookup (&syms[EXCL_ANNO], sym->addr)))) + { + sym->file->ncalls += sym->ncalls; + line_stats = sym->file->line[sym->line_num - 1]; + if (!line_stats) + { + /* common case has at most one basic-block per source line: */ + sym->file->line[sym->line_num - 1] = sym; + } + else if (!line_stats->addr) + { + /* sym is the 3rd .. nth basic block for this line: */ + line_stats->ncalls += sym->ncalls; + } + else + { + /* sym is the second basic block for this line */ + new_line = (Sym *) xmalloc (sizeof (*new_line)); + *new_line = *line_stats; + new_line->addr = 0; + new_line->ncalls += sym->ncalls; + sym->file->line[sym->line_num - 1] = new_line; + } + } + } + + /* plod over source files, annotating them: */ + + for (sf = first_src_file; sf; sf = sf->next) + { + if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0)) + { + continue; + } + + num_executable_lines = num_lines_executed = 0; + ofp = annotate_source (sf, 16, annotate_with_count, sf); + if (!ofp) + { + continue; + } + + if (bb_table_length > 0) + { + fprintf (ofp, _("\n\nTop %d Lines:\n\n Line Count\n\n"), + bb_table_length); + + /* abuse line arrays---it's not needed anymore: */ + qsort (sf->line, sf->num_lines, sizeof (sf->line[0]), cmp_ncalls); + table_len = bb_table_length; + if (table_len > sf->num_lines) + { + table_len = sf->num_lines; + } + for (i = 0; i < table_len; ++i) + { + sym = sf->line[i]; + if (!sym || sym->ncalls == 0) + { + break; + } + fprintf (ofp, "%9d %10lu\n", sym->line_num, sym->ncalls); + } + } + + free (sf->line); + sf->line = 0; + + fprintf (ofp, _("\nExecution Summary:\n\n")); + fprintf (ofp, _("%9ld Executable lines in this file\n"), + num_executable_lines); + fprintf (ofp, _("%9ld Lines executed\n"), num_lines_executed); + fprintf (ofp, _("%9.2f Percent of the file executed\n"), + num_executable_lines + ? 100.0 * num_lines_executed / (double) num_executable_lines + : 100.0); + fprintf (ofp, _("\n%9lu Total number of line executions\n"), + sf->ncalls); + fprintf (ofp, _("%9.2f Average executions per line\n"), + num_executable_lines + ? (double) sf->ncalls / (double) num_executable_lines + : 0.0); + if (ofp != stdout) + { + fclose (ofp); + } + } +} diff --git a/gprof/basic_blocks.h b/gprof/basic_blocks.h new file mode 100644 index 0000000..923eca1 --- /dev/null +++ b/gprof/basic_blocks.h @@ -0,0 +1,23 @@ +#ifndef basic_blocks_h +#define basic_blocks_h + +#include +#include "gprof.h" +#include "source.h" +#include "symtab.h" + +/* + * Options: + */ +extern bool bb_annotate_all_lines; /* force annotation of all lines? */ +extern int bb_table_length; /* length of most-used bb table */ +extern unsigned long bb_min_calls; /* minimum execution count */ + +extern void bb_read_rec PARAMS ((FILE * ifp, const char *filename)); +extern void bb_write_blocks PARAMS ((FILE * ofp, const char *filename)); +extern void bb_create_syms PARAMS ((void)); + +extern void print_annotated_source PARAMS ((void)); +extern void print_exec_counts PARAMS ((void)); + +#endif /* basic_blocks_h */ diff --git a/gprof/bb_exit_func.c b/gprof/bb_exit_func.c new file mode 100644 index 0000000..8133215 --- /dev/null +++ b/gprof/bb_exit_func.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1994 David Mosberger-Tang. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + * + * __bb_exit_func() dumps all the basic-block statistics linked into + * the bb_head chain to .d files. + */ +#include +#include +#include "bfd.h" +#include "gmon_out.h" + +/* structure emitted by -a */ +struct bb { + long zero_word; + const char *filename; + long *counts; + long ncounts; + struct bb *next; + const unsigned long *addresses; +}; + +struct bb *__bb_head = (struct bb *)0; + + +void +__bb_exit_func (void) +{ + const int version = GMON_VERSION; + struct gmon_hdr ghdr; + struct bb *ptr; + FILE *fp; + /* + * GEN_GMON_CNT_FILE should be defined on systems with mcleanup() + * functions that do not write basic-block to gmon.out. In such + * cases profiling with "-pg -a" would result in a gmon.out file + * without basic-block info (because the file written here would + * be overwritten. Thus, a separate file is generated instead. + * The two files can easily be combined by specifying them + * on gprof's command line (and possibly generating a gmon.sum + * file with "gprof -s"). + */ +#ifndef GEN_GMON_CNT_FILE +# define OUT_NAME "gmon.out" +#else +# define OUT_NAME "gmon.cnt" +#endif + fp = fopen(OUT_NAME, "wb"); + if (!fp) { + perror(OUT_NAME); + return; + } /* if */ + memcpy(&ghdr.cookie[0], GMON_MAGIC, 4); + memcpy(&ghdr.version, &version, sizeof(version)); + fwrite(&ghdr, sizeof(ghdr), 1, fp); + + for (ptr = __bb_head; ptr != 0; ptr = ptr->next) { + u_int ncounts = ptr->ncounts; + u_char tag; + u_int i; + + tag = GMON_TAG_BB_COUNT; + fwrite(&tag, sizeof(tag), 1, fp); + fwrite(&ncounts, sizeof(ncounts), 1, fp); + + for (i = 0; i < ncounts; ++i) { + fwrite(&ptr->addresses[i], sizeof(ptr->addresses[0]), 1, fp); + fwrite(&ptr->counts[i], sizeof(ptr->counts[0]), 1, fp); + } /* for */ + } /* for */ + fclose (fp); +} /* __bb_exit_func */ + + /*** end of __bb_exit_func.c ***/ diff --git a/gprof/bbconv.pl b/gprof/bbconv.pl new file mode 100755 index 0000000..7312f51 --- /dev/null +++ b/gprof/bbconv.pl @@ -0,0 +1,36 @@ +#! /usr/bin/perl + +# This script converts a "bb.out" file into a format +# suitable for processing by gprof + +# Write a new-style gmon header + +print pack("A4Ix12", "gmon", 1); + + +# The input file format contains header lines and data lines. +# Header lines contain a count of how many data lines follow before +# the next header line. $blockcount is set to the count that +# appears in each header line, then decremented at each data line. +# $blockcount should always be zero at the start of a header line, +# and should never be zero at the start of a data line. + +$blockcount=0; + +while (<>) { + if (/^File .*, ([0-9]+) basic blocks/) { + print STDERR "Miscount: line $.\n" if ($blockcount != 0); + $blockcount = $1; + + print pack("cI", 2, $blockcount); + } + if (/Block.*executed([ 0-9]+) time.* address= 0x([0-9a-fA-F]*)/) { + print STDERR "Miscount: line $.\n" if ($blockcount == 0); + $blockcount-- if ($blockcount > 0); + + $count = $1; + $addr = hex $2; + + print pack("II",$addr,$count); + } +} diff --git a/gprof/bsd_callg_bl.m b/gprof/bsd_callg_bl.m new file mode 100644 index 0000000..533c96c --- /dev/null +++ b/gprof/bsd_callg_bl.m @@ -0,0 +1,108 @@ + + + +call graph profile: + The sum of self and descendents is the major sort + for this listing. + + function entries: + +index the index of the function in the call graph + listing, as an aid to locating it (see below). + +%time the percentage of the total time of the program + accounted for by this function and its + descendents. + +self the number of seconds spent in this function + itself. + +descendents + the number of seconds spent in the descendents of + this function on behalf of this function. + +called the number of times this function is called (other + than recursive calls). + +self the number of times this function calls itself + recursively. + +name the name of the function, with an indication of + its membership in a cycle, if any. + +index the index of the function in the call graph + listing, as an aid to locating it. + + + + parent listings: + +self* the number of seconds of this function's self time + which is due to calls from this parent. + +descendents* + the number of seconds of this function's + descendent time which is due to calls from this + parent. + +called** the number of times this function is called by + this parent. This is the numerator of the + fraction which divides up the function's time to + its parents. + +total* the number of times this function was called by + all of its parents. This is the denominator of + the propagation fraction. + +parents the name of this parent, with an indication of the + parent's membership in a cycle, if any. + +index the index of this parent in the call graph + listing, as an aid in locating it. + + + + children listings: + +self* the number of seconds of this child's self time + which is due to being called by this function. + +descendent* + the number of seconds of this child's descendent's + time which is due to being called by this + function. + +called** the number of times this child is called by this + function. This is the numerator of the + propagation fraction for this child. + +total* the number of times this child is called by all + functions. This is the denominator of the + propagation fraction. + +children the name of this child, and an indication of its + membership in a cycle, if any. + +index the index of this child in the call graph listing, + as an aid to locating it. + + + + * these fields are omitted for parents (or + children) in the same cycle as the function. If + the function (or child) is a member of a cycle, + the propagated times and propagation denominator + represent the self time and descendent time of the + cycle as a whole. + + ** static-only parents and children are indicated + by a call count of 0. + + + + cycle listings: + the cycle as a whole is listed with the same + fields as a function entry. Below it are listed + the members of the cycle, and their contributions + to the time and call counts of the cycle. + diff --git a/gprof/call_graph.c b/gprof/call_graph.c new file mode 100644 index 0000000..8f12cbd --- /dev/null +++ b/gprof/call_graph.c @@ -0,0 +1,116 @@ +#include "cg_arcs.h" +#include "call_graph.h" +#include "corefile.h" +#include "gmon_io.h" +#include "gmon_out.h" +#include "symtab.h" +#include "sym_ids.h" + +extern void +DEFUN (cg_tally, (from_pc, self_pc, count), + bfd_vma from_pc AND bfd_vma self_pc AND unsigned long count) +{ + Sym *parent; + Sym *child; + + parent = sym_lookup (&symtab, from_pc); + child = sym_lookup (&symtab, self_pc); + + if (child == NULL || parent == NULL) + return; + + /* If we're doing line-by-line profiling, both the parent and the + child will probably point to line symbols instead of function + symbols. For the parent this is fine, since this identifies the + line number in the calling routing, but the child should always + point to a function entry point, so we back up in the symbol + table until we find it. + + For normal profiling, is_func will be set on all symbols, so this + code will do nothing. */ + + while (child >= symtab.base && ! child->is_func) + --child; + + if (child < symtab.base) + return; + + /* + * Keep arc if it is on INCL_ARCS table or if the INCL_ARCS table + * is empty and it is not in the EXCL_ARCS table. + */ + if (sym_id_arc_is_present (&syms[INCL_ARCS], parent, child) + || (syms[INCL_ARCS].len == 0 + && !sym_id_arc_is_present (&syms[EXCL_ARCS], parent, child))) + { + child->ncalls += count; + DBG (TALLYDEBUG, + printf (_("[cg_tally] arc from %s to %s traversed %lu times\n"), + parent->name, child->name, count)); + arc_add (parent, child, count); + } +} + + +/* + * Read a record from file IFP describing an arc in the function + * call-graph and the count of how many times the arc has been + * traversed. FILENAME is the name of file IFP and is provided + * for formatting error-messages only. + */ +void +DEFUN (cg_read_rec, (ifp, filename), FILE * ifp AND CONST char *filename) +{ + bfd_vma from_pc, self_pc; + struct gmon_cg_arc_record arc; + unsigned long count; + + if (fread (&arc, sizeof (arc), 1, ifp) != 1) + { + fprintf (stderr, _("%s: %s: unexpected end of file\n"), + whoami, filename); + done (1); + } + from_pc = get_vma (core_bfd, (bfd_byte *) arc.from_pc); + self_pc = get_vma (core_bfd, (bfd_byte *) arc.self_pc); + count = bfd_get_32 (core_bfd, (bfd_byte *) arc.count); + DBG (SAMPLEDEBUG, + printf ("[cg_read_rec] frompc 0x%lx selfpc 0x%lx count %lu\n", + from_pc, self_pc, count)); + /* add this arc: */ + cg_tally (from_pc, self_pc, count); +} + + +/* + * Write all the arcs in the call-graph to file OFP. FILENAME is + * the name of OFP and is provided for formatting error-messages + * only. + */ +void +DEFUN (cg_write_arcs, (ofp, filename), FILE * ofp AND const char *filename) +{ + const unsigned char tag = GMON_TAG_CG_ARC; + struct gmon_cg_arc_record raw_arc; + Arc *arc; + Sym *sym; + + for (sym = symtab.base; sym < symtab.limit; sym++) + { + for (arc = sym->cg.children; arc; arc = arc->next_child) + { + put_vma (core_bfd, arc->parent->addr, (bfd_byte *) raw_arc.from_pc); + put_vma (core_bfd, arc->child->addr, (bfd_byte *) raw_arc.self_pc); + bfd_put_32 (core_bfd, arc->count, (bfd_byte *) raw_arc.count); + if (fwrite (&tag, sizeof (tag), 1, ofp) != 1 + || fwrite (&raw_arc, sizeof (raw_arc), 1, ofp) != 1) + { + perror (filename); + done (1); + } + DBG (SAMPLEDEBUG, + printf ("[cg_write_arcs] frompc 0x%lx selfpc 0x%lx count %lu\n", + arc->parent->addr, arc->child->addr, arc->count)); + } + } +} diff --git a/gprof/call_graph.h b/gprof/call_graph.h new file mode 100644 index 0000000..be5139b --- /dev/null +++ b/gprof/call_graph.h @@ -0,0 +1,13 @@ +#ifndef call_graph_h +#define call_graph_h + +#include +#include "gprof.h" +#include "symtab.h" + +extern void cg_tally PARAMS ((bfd_vma from_pc, bfd_vma self_pc, + unsigned long count)); +extern void cg_read_rec PARAMS ((FILE * ifp, const char *filename)); +extern void cg_write_arcs PARAMS ((FILE * ofp, const char *filename)); + +#endif /* call_graph_h */ diff --git a/gprof/cg_arcs.c b/gprof/cg_arcs.c new file mode 100644 index 0000000..0702317 --- /dev/null +++ b/gprof/cg_arcs.c @@ -0,0 +1,685 @@ +/* + * Copyright (c) 1983 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. + */ +#include "libiberty.h" +#include "gprof.h" +#include "call_graph.h" +#include "cg_arcs.h" +#include "cg_dfn.h" +#include "cg_print.h" +#include "utils.h" +#include "sym_ids.h" + +Sym *cycle_header; +unsigned int num_cycles; +Arc **arcs; +unsigned int numarcs; + +/* + * Return TRUE iff PARENT has an arc to covers the address + * range covered by CHILD. + */ +Arc * +DEFUN (arc_lookup, (parent, child), Sym * parent AND Sym * child) +{ + Arc *arc; + + if (!parent || !child) + { + printf ("[arc_lookup] parent == 0 || child == 0\n"); + return 0; + } + DBG (LOOKUPDEBUG, printf ("[arc_lookup] parent %s child %s\n", + parent->name, child->name)); + for (arc = parent->cg.children; arc; arc = arc->next_child) + { + DBG (LOOKUPDEBUG, printf ("[arc_lookup]\t parent %s child %s\n", + arc->parent->name, arc->child->name)); + if (child->addr >= arc->child->addr + && child->end_addr <= arc->child->end_addr) + { + return arc; + } + } + return 0; +} + + +/* + * Add (or just increment) an arc: + */ +void +DEFUN (arc_add, (parent, child, count), + Sym * parent AND Sym * child AND unsigned long count) +{ + static unsigned int maxarcs = 0; + Arc *arc, **newarcs; + + DBG (TALLYDEBUG, printf ("[arc_add] %lu arcs from %s to %s\n", + count, parent->name, child->name)); + arc = arc_lookup (parent, child); + if (arc) + { + /* + * A hit: just increment the count. + */ + DBG (TALLYDEBUG, printf ("[tally] hit %lu += %lu\n", + arc->count, count)); + arc->count += count; + return; + } + arc = (Arc *) xmalloc (sizeof (*arc)); + memset (arc, 0, sizeof (*arc)); + arc->parent = parent; + arc->child = child; + arc->count = count; + + /* If this isn't an arc for a recursive call to parent, then add it + to the array of arcs. */ + if (parent != child) + { + /* If we've exhausted space in our current array, get a new one + and copy the contents. We might want to throttle the doubling + factor one day. */ + if (numarcs == maxarcs) + { + /* Determine how much space we want to allocate. */ + if (maxarcs == 0) + maxarcs = 1; + maxarcs *= 2; + + /* Allocate the new array. */ + newarcs = (Arc **)xmalloc(sizeof (Arc *) * maxarcs); + + /* Copy the old array's contents into the new array. */ + memcpy (newarcs, arcs, numarcs * sizeof (Arc *)); + + /* Free up the old array. */ + free (arcs); + + /* And make the new array be the current array. */ + arcs = newarcs; + } + + /* Place this arc in the arc array. */ + arcs[numarcs++] = arc; + } + + /* prepend this child to the children of this parent: */ + arc->next_child = parent->cg.children; + parent->cg.children = arc; + + /* prepend this parent to the parents of this child: */ + arc->next_parent = child->cg.parents; + child->cg.parents = arc; +} + + +static int +DEFUN (cmp_topo, (lp, rp), const PTR lp AND const PTR rp) +{ + const Sym *left = *(const Sym **) lp; + const Sym *right = *(const Sym **) rp; + + return left->cg.top_order - right->cg.top_order; +} + + +static void +DEFUN (propagate_time, (parent), Sym * parent) +{ + Arc *arc; + Sym *child; + double share, prop_share; + + if (parent->cg.prop.fract == 0.0) + { + return; + } + + /* gather time from children of this parent: */ + + for (arc = parent->cg.children; arc; arc = arc->next_child) + { + child = arc->child; + if (arc->count == 0 || child == parent || child->cg.prop.fract == 0) + { + continue; + } + if (child->cg.cyc.head != child) + { + if (parent->cg.cyc.num == child->cg.cyc.num) + { + continue; + } + if (parent->cg.top_order <= child->cg.top_order) + { + fprintf (stderr, "[propagate] toporder botches\n"); + } + child = child->cg.cyc.head; + } + else + { + if (parent->cg.top_order <= child->cg.top_order) + { + fprintf (stderr, "[propagate] toporder botches\n"); + continue; + } + } + if (child->ncalls == 0) + { + continue; + } + + /* distribute time for this arc: */ + arc->time = child->hist.time * (((double) arc->count) + / ((double) child->ncalls)); + arc->child_time = child->cg.child_time + * (((double) arc->count) / ((double) child->ncalls)); + share = arc->time + arc->child_time; + parent->cg.child_time += share; + + /* (1 - cg.prop.fract) gets lost along the way: */ + prop_share = parent->cg.prop.fract * share; + + /* fix things for printing: */ + parent->cg.prop.child += prop_share; + arc->time *= parent->cg.prop.fract; + arc->child_time *= parent->cg.prop.fract; + + /* add this share to the parent's cycle header, if any: */ + if (parent->cg.cyc.head != parent) + { + parent->cg.cyc.head->cg.child_time += share; + parent->cg.cyc.head->cg.prop.child += prop_share; + } + DBG (PROPDEBUG, + printf ("[prop_time] child \t"); + print_name (child); + printf (" with %f %f %lu/%lu\n", child->hist.time, + child->cg.child_time, arc->count, child->ncalls); + printf ("[prop_time] parent\t"); + print_name (parent); + printf ("\n[prop_time] share %f\n", share)); + } +} + + +/* + * Compute the time of a cycle as the sum of the times of all + * its members. + */ +static void +DEFUN_VOID (cycle_time) +{ + Sym *member, *cyc; + + for (cyc = &cycle_header[1]; cyc <= &cycle_header[num_cycles]; ++cyc) + { + for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next) + { + if (member->cg.prop.fract == 0.0) + { + /* + * All members have the same propfraction except those + * that were excluded with -E. + */ + continue; + } + cyc->hist.time += member->hist.time; + } + cyc->cg.prop.self = cyc->cg.prop.fract * cyc->hist.time; + } +} + + +static void +DEFUN_VOID (cycle_link) +{ + Sym *sym, *cyc, *member; + Arc *arc; + int num; + + /* count the number of cycles, and initialize the cycle lists: */ + + num_cycles = 0; + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + /* this is how you find unattached cycles: */ + if (sym->cg.cyc.head == sym && sym->cg.cyc.next) + { + ++num_cycles; + } + } + + /* + * cycle_header is indexed by cycle number: i.e. it is origin 1, + * not origin 0. + */ + cycle_header = (Sym *) xmalloc ((num_cycles + 1) * sizeof (Sym)); + + /* + * Now link cycles to true cycle-heads, number them, accumulate + * the data for the cycle. + */ + num = 0; + cyc = cycle_header; + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + if (!(sym->cg.cyc.head == sym && sym->cg.cyc.next != 0)) + { + continue; + } + ++num; + ++cyc; + sym_init (cyc); + cyc->cg.print_flag = TRUE; /* should this be printed? */ + cyc->cg.top_order = DFN_NAN; /* graph call chain top-sort order */ + cyc->cg.cyc.num = num; /* internal number of cycle on */ + cyc->cg.cyc.head = cyc; /* pointer to head of cycle */ + cyc->cg.cyc.next = sym; /* pointer to next member of cycle */ + DBG (CYCLEDEBUG, printf ("[cycle_link] "); + print_name (sym); + printf (" is the head of cycle %d\n", num)); + + /* link members to cycle header: */ + for (member = sym; member; member = member->cg.cyc.next) + { + member->cg.cyc.num = num; + member->cg.cyc.head = cyc; + } + + /* + * Count calls from outside the cycle and those among cycle + * members: + */ + for (member = sym; member; member = member->cg.cyc.next) + { + for (arc = member->cg.parents; arc; arc = arc->next_parent) + { + if (arc->parent == member) + { + continue; + } + if (arc->parent->cg.cyc.num == num) + { + cyc->cg.self_calls += arc->count; + } + else + { + cyc->ncalls += arc->count; + } + } + } + } +} + + +/* + * Check if any parent of this child (or outside parents of this + * cycle) have their print flags on and set the print flag of the + * child (cycle) appropriately. Similarly, deal with propagation + * fractions from parents. + */ +static void +DEFUN (inherit_flags, (child), Sym * child) +{ + Sym *head, *parent, *member; + Arc *arc; + + head = child->cg.cyc.head; + if (child == head) + { + /* just a regular child, check its parents: */ + child->cg.print_flag = FALSE; + child->cg.prop.fract = 0.0; + for (arc = child->cg.parents; arc; arc = arc->next_parent) + { + parent = arc->parent; + if (child == parent) + { + continue; + } + child->cg.print_flag |= parent->cg.print_flag; + /* + * If the child was never actually called (e.g., this arc + * is static (and all others are, too)) no time propagates + * along this arc. + */ + if (child->ncalls != 0) + { + child->cg.prop.fract += parent->cg.prop.fract + * (((double) arc->count) / ((double) child->ncalls)); + } + } + } + else + { + /* + * Its a member of a cycle, look at all parents from outside + * the cycle. + */ + head->cg.print_flag = FALSE; + head->cg.prop.fract = 0.0; + for (member = head->cg.cyc.next; member; member = member->cg.cyc.next) + { + for (arc = member->cg.parents; arc; arc = arc->next_parent) + { + if (arc->parent->cg.cyc.head == head) + { + continue; + } + parent = arc->parent; + head->cg.print_flag |= parent->cg.print_flag; + /* + * If the cycle was never actually called (e.g. this + * arc is static (and all others are, too)) no time + * propagates along this arc. + */ + if (head->ncalls != 0) + { + head->cg.prop.fract += parent->cg.prop.fract + * (((double) arc->count) / ((double) head->ncalls)); + } + } + } + for (member = head; member; member = member->cg.cyc.next) + { + member->cg.print_flag = head->cg.print_flag; + member->cg.prop.fract = head->cg.prop.fract; + } + } +} + + +/* + * In one top-to-bottom pass over the topologically sorted symbols + * propagate: + * cg.print_flag as the union of parents' print_flags + * propfraction as the sum of fractional parents' propfractions + * and while we're here, sum time for functions. + */ +static void +DEFUN (propagate_flags, (symbols), Sym ** symbols) +{ + int index; + Sym *old_head, *child; + + old_head = 0; + for (index = symtab.len - 1; index >= 0; --index) + { + child = symbols[index]; + /* + * If we haven't done this function or cycle, inherit things + * from parent. This way, we are linear in the number of arcs + * since we do all members of a cycle (and the cycle itself) + * as we hit the first member of the cycle. + */ + if (child->cg.cyc.head != old_head) + { + old_head = child->cg.cyc.head; + inherit_flags (child); + } + DBG (PROPDEBUG, + printf ("[prop_flags] "); + print_name (child); + printf ("inherits print-flag %d and prop-fract %f\n", + child->cg.print_flag, child->cg.prop.fract)); + if (!child->cg.print_flag) + { + /* + * Printflag is off. It gets turned on by being in the + * INCL_GRAPH table, or there being an empty INCL_GRAPH + * table and not being in the EXCL_GRAPH table. + */ + if (sym_lookup (&syms[INCL_GRAPH], child->addr) + || (syms[INCL_GRAPH].len == 0 + && !sym_lookup (&syms[EXCL_GRAPH], child->addr))) + { + child->cg.print_flag = TRUE; + } + } + else + { + /* + * This function has printing parents: maybe someone wants + * to shut it up by putting it in the EXCL_GRAPH table. + * (But favor INCL_GRAPH over EXCL_GRAPH.) + */ + if (!sym_lookup (&syms[INCL_GRAPH], child->addr) + && sym_lookup (&syms[EXCL_GRAPH], child->addr)) + { + child->cg.print_flag = FALSE; + } + } + if (child->cg.prop.fract == 0.0) + { + /* + * No parents to pass time to. Collect time from children + * if its in the INCL_TIME table, or there is an empty + * INCL_TIME table and its not in the EXCL_TIME table. + */ + if (sym_lookup (&syms[INCL_TIME], child->addr) + || (syms[INCL_TIME].len == 0 + && !sym_lookup (&syms[EXCL_TIME], child->addr))) + { + child->cg.prop.fract = 1.0; + } + } + else + { + /* + * It has parents to pass time to, but maybe someone wants + * to shut it up by puttting it in the EXCL_TIME table. + * (But favor being in INCL_TIME tabe over being in + * EXCL_TIME table.) + */ + if (!sym_lookup (&syms[INCL_TIME], child->addr) + && sym_lookup (&syms[EXCL_TIME], child->addr)) + { + child->cg.prop.fract = 0.0; + } + } + child->cg.prop.self = child->hist.time * child->cg.prop.fract; + print_time += child->cg.prop.self; + DBG (PROPDEBUG, + printf ("[prop_flags] "); + print_name (child); + printf (" ends up with printflag %d and prop-fract %f\n", + child->cg.print_flag, child->cg.prop.fract); + printf ("[prop_flags] time %f propself %f print_time %f\n", + child->hist.time, child->cg.prop.self, print_time)); + } +} + + +/* + * Compare by decreasing propagated time. If times are equal, but one + * is a cycle header, say that's first (e.g. less, i.e. -1). If one's + * name doesn't have an underscore and the other does, say that one is + * first. All else being equal, compare by names. + */ +static int +DEFUN (cmp_total, (lp, rp), const PTR lp AND const PTR rp) +{ + const Sym *left = *(const Sym **) lp; + const Sym *right = *(const Sym **) rp; + double diff; + + diff = (left->cg.prop.self + left->cg.prop.child) + - (right->cg.prop.self + right->cg.prop.child); + if (diff < 0.0) + { + return 1; + } + if (diff > 0.0) + { + return -1; + } + if (!left->name && left->cg.cyc.num != 0) + { + return -1; + } + if (!right->name && right->cg.cyc.num != 0) + { + return 1; + } + if (!left->name) + { + return -1; + } + if (!right->name) + { + return 1; + } + if (left->name[0] != '_' && right->name[0] == '_') + { + return -1; + } + if (left->name[0] == '_' && right->name[0] != '_') + { + return 1; + } + if (left->ncalls > right->ncalls) + { + return -1; + } + if (left->ncalls < right->ncalls) + { + return 1; + } + return strcmp (left->name, right->name); +} + + +/* + * Topologically sort the graph (collapsing cycles), and propagates + * time bottom up and flags top down. + */ +Sym ** +DEFUN_VOID (cg_assemble) +{ + Sym *parent, **time_sorted_syms, **top_sorted_syms; + unsigned int index; + Arc *arc; + + /* + * initialize various things: + * zero out child times. + * count self-recursive calls. + * indicate that nothing is on cycles. + */ + for (parent = symtab.base; parent < symtab.limit; parent++) + { + parent->cg.child_time = 0.0; + arc = arc_lookup (parent, parent); + if (arc && parent == arc->child) + { + parent->ncalls -= arc->count; + parent->cg.self_calls = arc->count; + } + else + { + parent->cg.self_calls = 0; + } + parent->cg.prop.fract = 0.0; + parent->cg.prop.self = 0.0; + parent->cg.prop.child = 0.0; + parent->cg.print_flag = FALSE; + parent->cg.top_order = DFN_NAN; + parent->cg.cyc.num = 0; + parent->cg.cyc.head = parent; + parent->cg.cyc.next = 0; + if (ignore_direct_calls) + { + find_call (parent, parent->addr, (parent + 1)->addr); + } + } + /* + * Topologically order things. If any node is unnumbered, number + * it and any of its descendents. + */ + for (parent = symtab.base; parent < symtab.limit; parent++) + { + if (parent->cg.top_order == DFN_NAN) + { + cg_dfn (parent); + } + } + + /* link together nodes on the same cycle: */ + cycle_link (); + + /* sort the symbol table in reverse topological order: */ + top_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + for (index = 0; index < symtab.len; ++index) + { + top_sorted_syms[index] = &symtab.base[index]; + } + qsort (top_sorted_syms, symtab.len, sizeof (Sym *), cmp_topo); + DBG (DFNDEBUG, + printf ("[cg_assemble] topological sort listing\n"); + for (index = 0; index < symtab.len; ++index) + { + printf ("[cg_assemble] "); + printf ("%d:", top_sorted_syms[index]->cg.top_order); + print_name (top_sorted_syms[index]); + printf ("\n"); + } + ); + /* + * Starting from the topological top, propagate print flags to + * children. also, calculate propagation fractions. this happens + * before time propagation since time propagation uses the + * fractions. + */ + propagate_flags (top_sorted_syms); + + /* + * Starting from the topological bottom, propogate children times + * up to parents. + */ + cycle_time (); + for (index = 0; index < symtab.len; ++index) + { + propagate_time (top_sorted_syms[index]); + } + + free (top_sorted_syms); + + /* + * Now, sort by CG.PROP.SELF + CG.PROP.CHILD. Sorting both the regular + * function names and cycle headers. + */ + time_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *)); + for (index = 0; index < symtab.len; index++) + { + time_sorted_syms[index] = &symtab.base[index]; + } + for (index = 1; index <= num_cycles; index++) + { + time_sorted_syms[symtab.len + index - 1] = &cycle_header[index]; + } + qsort (time_sorted_syms, symtab.len + num_cycles, sizeof (Sym *), + cmp_total); + for (index = 0; index < symtab.len + num_cycles; index++) + { + time_sorted_syms[index]->cg.index = index + 1; + } + return time_sorted_syms; +} diff --git a/gprof/cg_arcs.h b/gprof/cg_arcs.h new file mode 100644 index 0000000..caa0197 --- /dev/null +++ b/gprof/cg_arcs.h @@ -0,0 +1,36 @@ +#ifndef cg_arcs_h +#define cg_arcs_h + +#include "gprof.h" +#include "symtab.h" + +/* + * Arc structure for call-graph. + * + * With pointers to the symbols of the parent and the child, a count + * of how many times this arc was traversed, and pointers to the next + * parent of this child and the next child of this parent. + */ +typedef struct arc + { + Sym *parent; /* source vertice of arc */ + Sym *child; /* dest vertice of arc */ + unsigned long count; /* # of calls from parent to child */ + double time; /* time inherited along arc */ + double child_time; /* child-time inherited along arc */ + struct arc *next_parent; /* next parent of CHILD */ + struct arc *next_child; /* next child of PARENT */ + int has_been_placed; /* have this arc's functions been placed? */ + } +Arc; + +extern unsigned int num_cycles; /* number of cycles discovered */ +extern Sym *cycle_header; /* cycle headers */ + +extern void arc_add PARAMS ((Sym * parent, Sym * child, unsigned long count)); +extern Arc *arc_lookup PARAMS ((Sym * parent, Sym * child)); +extern Sym **cg_assemble PARAMS ((void)); +extern Arc **arcs; +extern unsigned int numarcs; + +#endif /* cg_arcs_h */ diff --git a/gprof/cg_dfn.c b/gprof/cg_dfn.c new file mode 100644 index 0000000..c9e37ab --- /dev/null +++ b/gprof/cg_dfn.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 1983 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. + */ +#include +#include "gprof.h" +#include "cg_arcs.h" +#include "cg_dfn.h" +#include "symtab.h" +#include "utils.h" + +#define DFN_DEPTH 100 + +typedef struct + { + Sym *sym; + int cycle_top; + } +DFN_Stack; + +DFN_Stack dfn_stack[DFN_DEPTH]; +int dfn_depth = 0; +int dfn_counter = DFN_NAN; + + +/* + * Is CHILD already numbered? + */ +static bool +DEFUN (is_numbered, (child), Sym * child) +{ + return child->cg.top_order != DFN_NAN && child->cg.top_order != DFN_BUSY; +} + + +/* + * Is CHILD already busy? + */ +static bool +DEFUN (is_busy, (child), Sym * child) +{ + if (child->cg.top_order == DFN_NAN) + { + return FALSE; + } + return TRUE; +} + + +/* + * CHILD is part of a cycle. Find the top caller into this cycle + * that is not part of the cycle and make all functions in cycle + * members of that cycle (top caller == caller with smallest + * depth-first number). + */ +static void +DEFUN (find_cycle, (child), Sym * child) +{ + Sym *head = 0; + Sym *tail; + int cycle_top; + int index; + + for (cycle_top = dfn_depth; cycle_top > 0; --cycle_top) + { + head = dfn_stack[cycle_top].sym; + if (child == head) + { + break; + } + if (child->cg.cyc.head != child && child->cg.cyc.head == head) + { + break; + } + } + if (cycle_top <= 0) + { + fprintf (stderr, "[find_cycle] couldn't find head of cycle\n"); + done (1); + } +#ifdef DEBUG + if (debug_level & DFNDEBUG) + { + printf ("[find_cycle] dfn_depth %d cycle_top %d ", + dfn_depth, cycle_top); + if (head) + { + print_name (head); + } + else + { + printf (""); + } + printf ("\n"); + } +#endif + if (cycle_top == dfn_depth) + { + /* + * This is previous function, e.g. this calls itself. Sort of + * boring. + * + * Since we are taking out self-cycles elsewhere no need for + * the special case, here. + */ + DBG (DFNDEBUG, + printf ("[find_cycle] "); + print_name (child); + printf ("\n")); + } + else + { + /* + * Glom intervening functions that aren't already glommed into + * this cycle. Things have been glommed when their cyclehead + * field points to the head of the cycle they are glommed + * into. + */ + for (tail = head; tail->cg.cyc.next; tail = tail->cg.cyc.next) + { + /* void: chase down to tail of things already glommed */ + DBG (DFNDEBUG, + printf ("[find_cycle] tail "); + print_name (tail); + printf ("\n")); + } + /* + * If what we think is the top of the cycle has a cyclehead + * field, then it's not really the head of the cycle, which is + * really what we want. + */ + if (head->cg.cyc.head != head) + { + head = head->cg.cyc.head; + DBG (DFNDEBUG, printf ("[find_cycle] new cyclehead "); + print_name (head); + printf ("\n")); + } + for (index = cycle_top + 1; index <= dfn_depth; ++index) + { + child = dfn_stack[index].sym; + if (child->cg.cyc.head == child) + { + /* + * Not yet glommed anywhere, glom it and fix any + * children it has glommed. + */ + tail->cg.cyc.next = child; + child->cg.cyc.head = head; + DBG (DFNDEBUG, printf ("[find_cycle] glomming "); + print_name (child); + printf (" onto "); + print_name (head); + printf ("\n")); + for (tail = child; tail->cg.cyc.next; tail = tail->cg.cyc.next) + { + tail->cg.cyc.next->cg.cyc.head = head; + DBG (DFNDEBUG, printf ("[find_cycle] and its tail "); + print_name (tail->cg.cyc.next); + printf (" onto "); + print_name (head); + printf ("\n")); + } + } + else if (child->cg.cyc.head != head /* firewall */ ) + { + fprintf (stderr, "[find_cycle] glommed, but not to head\n"); + done (1); + } + } + } +} + + +/* + * Prepare for visiting the children of PARENT. Push a parent onto + * the stack and mark it busy. + */ +static void +DEFUN (pre_visit, (parent), Sym * parent) +{ + ++dfn_depth; + if (dfn_depth >= DFN_DEPTH) + { + fprintf (stderr, "[pre_visit] dfn_stack overflow\n"); + done (1); + } + dfn_stack[dfn_depth].sym = parent; + dfn_stack[dfn_depth].cycle_top = dfn_depth; + parent->cg.top_order = DFN_BUSY; + DBG (DFNDEBUG, printf ("[pre_visit]\t\t%d:", dfn_depth); + print_name (parent); + printf ("\n")); +} + + +/* + * Done with visiting node PARENT. Pop PARENT off dfn_stack + * and number functions if PARENT is head of a cycle. + */ +static void +DEFUN (post_visit, (parent), Sym * parent) +{ + Sym *member; + + DBG (DFNDEBUG, printf ("[post_visit]\t%d: ", dfn_depth); + print_name (parent); + printf ("\n")); + /* + * Number functions and things in their cycles unless the function + * is itself part of a cycle: + */ + if (parent->cg.cyc.head == parent) + { + ++dfn_counter; + for (member = parent; member; member = member->cg.cyc.next) + { + member->cg.top_order = dfn_counter; + DBG (DFNDEBUG, printf ("[post_visit]\t\tmember "); + print_name (member); + printf ("-> cg.top_order = %d\n", dfn_counter)); + } + } + else + { + DBG (DFNDEBUG, printf ("[post_visit]\t\tis part of a cycle\n")); + } + --dfn_depth; +} + + +/* + * Given this PARENT, depth first number its children. + */ +void +DEFUN (cg_dfn, (parent), Sym * parent) +{ + Arc *arc; + + DBG (DFNDEBUG, printf ("[dfn] dfn( "); + print_name (parent); + printf (")\n")); + /* + * If we're already numbered, no need to look any further: + */ + if (is_numbered (parent)) + { + return; + } + /* + * If we're already busy, must be a cycle: + */ + if (is_busy (parent)) + { + find_cycle (parent); + return; + } + pre_visit (parent); + /* + * Recursively visit children: + */ + for (arc = parent->cg.children; arc; arc = arc->next_child) + { + cg_dfn (arc->child); + } + post_visit (parent); +} diff --git a/gprof/cg_dfn.h b/gprof/cg_dfn.h new file mode 100644 index 0000000..4bd3030 --- /dev/null +++ b/gprof/cg_dfn.h @@ -0,0 +1,17 @@ +#ifndef cg_dfn_h +#define cg_dfn_h + +/* + * Flags which mark a symbol as topologically ``busy'' or as + * topologically ``not_numbered'': + */ +#define DFN_BUSY -1 +#define DFN_NAN 0 + +/* + * Depth-first numbering of a call-graph. + */ + +extern void cg_dfn PARAMS ((Sym * root)); + +#endif /* cg_dfn_h */ diff --git a/gprof/cg_print.c b/gprof/cg_print.c new file mode 100644 index 0000000..e645bc7 --- /dev/null +++ b/gprof/cg_print.c @@ -0,0 +1,1276 @@ +#include "libiberty.h" +#include "cg_arcs.h" +#include "cg_print.h" +#include "hist.h" +#include "utils.h" + +/* + * Return value of comparison functions used to sort tables: + */ +#define LESSTHAN -1 +#define EQUALTO 0 +#define GREATERTHAN 1 + +static void order_and_dump_functions_by_arcs PARAMS ((Arc **, unsigned long, + int, Arc **, + unsigned long *)); +/* declarations of automatically generated functions to output blurbs: */ +extern void bsd_callg_blurb PARAMS ((FILE * fp)); +extern void fsf_callg_blurb PARAMS ((FILE * fp)); + +double print_time = 0.0; + + +static void +DEFUN_VOID (print_header) +{ + if (first_output) + { + first_output = FALSE; + } + else + { + printf ("\f\n"); + } + if (!bsd_style_output) + { + if (print_descriptions) + { + printf (_("\t\t Call graph (explanation follows)\n\n")); + } + else + { + printf (_("\t\t\tCall graph\n\n")); + } + } + printf (_("\ngranularity: each sample hit covers %ld byte(s)"), + (long) hist_scale * sizeof (UNIT)); + if (print_time > 0.0) + { + printf (_(" for %.2f%% of %.2f seconds\n\n"), + 100.0 / print_time, print_time / hz); + } + else + { + printf (_(" no time propagated\n\n")); + /* + * This doesn't hurt, since all the numerators will be 0.0: + */ + print_time = 1.0; + } + if (bsd_style_output) + { + printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n", + "", "", "", "", _("called"), _("total"), _("parents")); + printf ("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n", + _("index"), _("%time"), _("self"), _("descendents"), + _("called"), _("self"), _("name"), _("index")); + printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n", + "", "", "", "", _("called"), _("total"), _("children")); + printf ("\n"); + } + else + { + printf (_("index %% time self children called name\n")); + } +} + + +/* + * Print a cycle header. + */ +static void +DEFUN (print_cycle, (cyc), Sym * cyc) +{ + char buf[BUFSIZ]; + + sprintf (buf, "[%d]", cyc->cg.index); + printf (bsd_style_output + ? "%-6.6s %5.1f %7.2f %11.2f %7lu" + : "%-6.6s %5.1f %7.2f %7.2f %7lu", buf, + 100 * (cyc->cg.prop.self + cyc->cg.prop.child) / print_time, + cyc->cg.prop.self / hz, cyc->cg.prop.child / hz, cyc->ncalls); + if (cyc->cg.self_calls != 0) + { + printf ("+%-7lu", cyc->cg.self_calls); + } + else + { + printf (" %7.7s", ""); + } + printf (_(" [%d]\n"), cyc->cg.cyc.num, cyc->cg.index); +} + + +/* + * Compare LEFT and RIGHT membmer. Major comparison key is + * CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS. + */ +static int +DEFUN (cmp_member, (left, right), Sym * left AND Sym * right) +{ + double left_time = left->cg.prop.self + left->cg.prop.child; + double right_time = right->cg.prop.self + right->cg.prop.child; + unsigned long left_calls = left->ncalls + left->cg.self_calls; + unsigned long right_calls = right->ncalls + right->cg.self_calls; + + if (left_time > right_time) + { + return GREATERTHAN; + } + if (left_time < right_time) + { + return LESSTHAN; + } + + if (left_calls > right_calls) + { + return GREATERTHAN; + } + if (left_calls < right_calls) + { + return LESSTHAN; + } + return EQUALTO; +} + + +/* + * Sort members of a cycle. + */ +static void +DEFUN (sort_members, (cyc), Sym * cyc) +{ + Sym *todo, *doing, *prev; + /* + * Detach cycle members from cyclehead, and insertion sort them + * back on. + */ + todo = cyc->cg.cyc.next; + cyc->cg.cyc.next = 0; + for (doing = todo; doing && doing->cg.cyc.next; doing = todo) + { + todo = doing->cg.cyc.next; + for (prev = cyc; prev->cg.cyc.next; prev = prev->cg.cyc.next) + { + if (cmp_member (doing, prev->cg.cyc.next) == GREATERTHAN) + { + break; + } + } + doing->cg.cyc.next = prev->cg.cyc.next; + prev->cg.cyc.next = doing; + } +} + + +/* + * Print the members of a cycle. + */ +static void +DEFUN (print_members, (cyc), Sym * cyc) +{ + Sym *member; + + sort_members (cyc); + for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next) + { + printf (bsd_style_output + ? "%6.6s %5.5s %7.2f %11.2f %7lu" + : "%6.6s %5.5s %7.2f %7.2f %7lu", + "", "", member->cg.prop.self / hz, member->cg.prop.child / hz, + member->ncalls); + if (member->cg.self_calls != 0) + { + printf ("+%-7lu", member->cg.self_calls); + } + else + { + printf (" %7.7s", ""); + } + printf (" "); + print_name (member); + printf ("\n"); + } +} + + +/* + * Compare two arcs to/from the same child/parent. + * - if one arc is a self arc, it's least. + * - if one arc is within a cycle, it's less than. + * - if both arcs are within a cycle, compare arc counts. + * - if neither arc is within a cycle, compare with + * time + child_time as major key + * arc count as minor key + */ +static int +DEFUN (cmp_arc, (left, right), Arc * left AND Arc * right) +{ + Sym *left_parent = left->parent; + Sym *left_child = left->child; + Sym *right_parent = right->parent; + Sym *right_child = right->child; + double left_time, right_time; + + DBG (TIMEDEBUG, + printf ("[cmp_arc] "); + print_name (left_parent); + printf (" calls "); + print_name (left_child); + printf (" %f + %f %lu/%lu\n", left->time, left->child_time, + left->count, left_child->ncalls); + printf ("[cmp_arc] "); + print_name (right_parent); + printf (" calls "); + print_name (right_child); + printf (" %f + %f %lu/%lu\n", right->time, right->child_time, + right->count, right_child->ncalls); + printf ("\n"); + ); + if (left_parent == left_child) + { + return LESSTHAN; /* left is a self call */ + } + if (right_parent == right_child) + { + return GREATERTHAN; /* right is a self call */ + } + + if (left_parent->cg.cyc.num != 0 && left_child->cg.cyc.num != 0 + && left_parent->cg.cyc.num == left_child->cg.cyc.num) + { + /* left is a call within a cycle */ + if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0 + && right_parent->cg.cyc.num == right_child->cg.cyc.num) + { + /* right is a call within the cycle, too */ + if (left->count < right->count) + { + return LESSTHAN; + } + if (left->count > right->count) + { + return GREATERTHAN; + } + return EQUALTO; + } + else + { + /* right isn't a call within the cycle */ + return LESSTHAN; + } + } + else + { + /* left isn't a call within a cycle */ + if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0 + && right_parent->cg.cyc.num == right_child->cg.cyc.num) + { + /* right is a call within a cycle */ + return GREATERTHAN; + } + else + { + /* neither is a call within a cycle */ + left_time = left->time + left->child_time; + right_time = right->time + right->child_time; + if (left_time < right_time) + { + return LESSTHAN; + } + if (left_time > right_time) + { + return GREATERTHAN; + } + if (left->count < right->count) + { + return LESSTHAN; + } + if (left->count > right->count) + { + return GREATERTHAN; + } + return EQUALTO; + } + } +} + + +static void +DEFUN (sort_parents, (child), Sym * child) +{ + Arc *arc, *detached, sorted, *prev; + + /* + * Unlink parents from child, then insertion sort back on to + * sorted's parents. + * *arc the arc you have detached and are inserting. + * *detached the rest of the arcs to be sorted. + * sorted arc list onto which you insertion sort. + * *prev arc before the arc you are comparing. + */ + sorted.next_parent = 0; + for (arc = child->cg.parents; arc; arc = detached) + { + detached = arc->next_parent; + + /* consider *arc as disconnected; insert it into sorted: */ + for (prev = &sorted; prev->next_parent; prev = prev->next_parent) + { + if (cmp_arc (arc, prev->next_parent) != GREATERTHAN) + { + break; + } + } + arc->next_parent = prev->next_parent; + prev->next_parent = arc; + } + + /* reattach sorted arcs to child: */ + child->cg.parents = sorted.next_parent; +} + + +static void +DEFUN (print_parents, (child), Sym * child) +{ + Sym *parent; + Arc *arc; + Sym *cycle_head; + + if (child->cg.cyc.head != 0) + { + cycle_head = child->cg.cyc.head; + } + else + { + cycle_head = child; + } + if (!child->cg.parents) + { + printf (bsd_style_output + ? _("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s \n") + : _("%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s \n"), + "", "", "", "", "", ""); + return; + } + sort_parents (child); + for (arc = child->cg.parents; arc; arc = arc->next_parent) + { + parent = arc->parent; + if (child == parent || (child->cg.cyc.num != 0 + && parent->cg.cyc.num == child->cg.cyc.num)) + { + /* selfcall or call among siblings: */ + printf (bsd_style_output + ? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s " + : "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ", + "", "", "", "", + arc->count, ""); + print_name (parent); + printf ("\n"); + } + else + { + /* regular parent of child: */ + printf (bsd_style_output + ? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu " + : "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ", + "", "", + arc->time / hz, arc->child_time / hz, + arc->count, cycle_head->ncalls); + print_name (parent); + printf ("\n"); + } + } +} + + +static void +DEFUN (sort_children, (parent), Sym * parent) +{ + Arc *arc, *detached, sorted, *prev; + /* + * Unlink children from parent, then insertion sort back on to + * sorted's children. + * *arc the arc you have detached and are inserting. + * *detached the rest of the arcs to be sorted. + * sorted arc list onto which you insertion sort. + * *prev arc before the arc you are comparing. + */ + sorted.next_child = 0; + for (arc = parent->cg.children; arc; arc = detached) + { + detached = arc->next_child; + + /* consider *arc as disconnected; insert it into sorted: */ + for (prev = &sorted; prev->next_child; prev = prev->next_child) + { + if (cmp_arc (arc, prev->next_child) != LESSTHAN) + { + break; + } + } + arc->next_child = prev->next_child; + prev->next_child = arc; + } + + /* reattach sorted children to parent: */ + parent->cg.children = sorted.next_child; +} + + +static void +DEFUN (print_children, (parent), Sym * parent) +{ + Sym *child; + Arc *arc; + + sort_children (parent); + arc = parent->cg.children; + for (arc = parent->cg.children; arc; arc = arc->next_child) + { + child = arc->child; + if (child == parent || (child->cg.cyc.num != 0 + && child->cg.cyc.num == parent->cg.cyc.num)) + { + /* self call or call to sibling: */ + printf (bsd_style_output + ? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s " + : "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ", + "", "", "", "", arc->count, ""); + print_name (child); + printf ("\n"); + } + else + { + /* regular child of parent: */ + printf (bsd_style_output + ? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu " + : "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ", + "", "", + arc->time / hz, arc->child_time / hz, + arc->count, child->cg.cyc.head->ncalls); + print_name (child); + printf ("\n"); + } + } +} + + +static void +DEFUN (print_line, (np), Sym * np) +{ + char buf[BUFSIZ]; + + sprintf (buf, "[%d]", np->cg.index); + printf (bsd_style_output + ? "%-6.6s %5.1f %7.2f %11.2f" + : "%-6.6s %5.1f %7.2f %7.2f", buf, + 100 * (np->cg.prop.self + np->cg.prop.child) / print_time, + np->cg.prop.self / hz, np->cg.prop.child / hz); + if ((np->ncalls + np->cg.self_calls) != 0) + { + printf (" %7lu", np->ncalls); + if (np->cg.self_calls != 0) + { + printf ("+%-7lu ", np->cg.self_calls); + } + else + { + printf (" %7.7s ", ""); + } + } + else + { + printf (" %7.7s %7.7s ", "", ""); + } + print_name (np); + printf ("\n"); +} + + +/* + * Print dynamic call graph. + */ +void +DEFUN (cg_print, (timesortsym), Sym ** timesortsym) +{ + unsigned int index; + Sym *parent; + + if (print_descriptions && bsd_style_output) + { + bsd_callg_blurb (stdout); + } + + print_header (); + + for (index = 0; index < symtab.len + num_cycles; ++index) + { + parent = timesortsym[index]; + if ((ignore_zeros && parent->ncalls == 0 + && parent->cg.self_calls == 0 && parent->cg.prop.self == 0 + && parent->cg.prop.child == 0) + || !parent->cg.print_flag + || (line_granularity && ! parent->is_func)) + { + continue; + } + if (!parent->name && parent->cg.cyc.num != 0) + { + /* cycle header: */ + print_cycle (parent); + print_members (parent); + } + else + { + print_parents (parent); + print_line (parent); + print_children (parent); + } + if (bsd_style_output) + printf ("\n"); + printf ("-----------------------------------------------\n"); + if (bsd_style_output) + printf ("\n"); + } + free (timesortsym); + if (print_descriptions && !bsd_style_output) + { + fsf_callg_blurb (stdout); + } +} + + +static int +DEFUN (cmp_name, (left, right), const PTR left AND const PTR right) +{ + const Sym **npp1 = (const Sym **) left; + const Sym **npp2 = (const Sym **) right; + + return strcmp ((*npp1)->name, (*npp2)->name); +} + + +void +DEFUN_VOID (cg_print_index) +{ + unsigned int index; + unsigned int nnames, todo, i, j; + int col, starting_col; + Sym **name_sorted_syms, *sym; + const char *filename; + char buf[20]; + int column_width = (output_width - 1) / 3; /* don't write in last col! */ + /* + * Now, sort regular function name alphabetically to create an + * index: + */ + name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *)); + for (index = 0, nnames = 0; index < symtab.len; index++) + { + if (ignore_zeros && symtab.base[index].ncalls == 0 + && symtab.base[index].hist.time == 0) + { + continue; + } + name_sorted_syms[nnames++] = &symtab.base[index]; + } + qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name); + for (index = 1, todo = nnames; index <= num_cycles; index++) + { + name_sorted_syms[todo++] = &cycle_header[index]; + } + printf ("\f\n"); + printf (_("Index by function name\n\n")); + index = (todo + 2) / 3; + for (i = 0; i < index; i++) + { + col = 0; + starting_col = 0; + for (j = i; j < todo; j += index) + { + sym = name_sorted_syms[j]; + if (sym->cg.print_flag) + { + sprintf (buf, "[%d]", sym->cg.index); + } + else + { + sprintf (buf, "(%d)", sym->cg.index); + } + if (j < nnames) + { + if (bsd_style_output) + { + printf ("%6.6s %-19.19s", buf, sym->name); + } + else + { + col += strlen (buf); + for (; col < starting_col + 5; ++col) + { + putchar (' '); + } + printf (" %s ", buf); + col += print_name_only (sym); + if (!line_granularity && sym->is_static && sym->file) + { + filename = sym->file->name; + if (!print_path) + { + filename = strrchr (filename, '/'); + if (filename) + { + ++filename; + } + else + { + filename = sym->file->name; + } + } + printf (" (%s)", filename); + col += strlen (filename) + 3; + } + } + } + else + { + if (bsd_style_output) + { + printf ("%6.6s ", buf); + sprintf (buf, _(""), sym->cg.cyc.num); + printf ("%-19.19s", buf); + } + else + { + col += strlen (buf); + for (; col < starting_col + 5; ++col) + putchar (' '); + printf (" %s ", buf); + sprintf (buf, _(""), sym->cg.cyc.num); + printf ("%s", buf); + col += strlen (buf); + } + } + starting_col += column_width; + } + printf ("\n"); + } + free (name_sorted_syms); +} + +/* Compare two arcs based on their usage counts. We want to sort + in descending order. */ +static int +DEFUN (cmp_arc_count, (left, right), const PTR left AND const PTR right) +{ + const Arc **npp1 = (const Arc **) left; + const Arc **npp2 = (const Arc **) right; + + if ((*npp1)->count > (*npp2)->count) + return -1; + else if ((*npp1)->count < (*npp2)->count) + return 1; + else + return 0; +} + +/* Compare two funtions based on their usage counts. We want to sort + in descending order. */ +static int +DEFUN (cmp_fun_nuses, (left, right), const PTR left AND const PTR right) +{ + const Sym **npp1 = (const Sym **) left; + const Sym **npp2 = (const Sym **) right; + + if ((*npp1)->nuses > (*npp2)->nuses) + return -1; + else if ((*npp1)->nuses < (*npp2)->nuses) + return 1; + else + return 0; +} + +/* Print a suggested function ordering based on the profiling data. + + We perform 4 major steps when ordering functions: + + * Group unused functions together and place them at the + end of the function order. + + * Search the highest use arcs (those which account for 90% of + the total arc count) for functions which have several parents. + + Group those with the most call sites together (currently the + top 1.25% which have at least five different call sites). + + These are emitted at the start of the function order. + + * Use a greedy placement algorithm to place functions which + occur in the top 99% of the arcs in the profile. Some provisions + are made to handle high usage arcs where the parent and/or + child has already been placed. + + * Run the same greedy placement algorithm on the remaining + arcs to place the leftover functions. + + + The various "magic numbers" should (one day) be tuneable by command + line options. They were arrived at by benchmarking a few applications + with various values to see which values produced better overall function + orderings. + + Of course, profiling errors, machine limitations (PA long calls), and + poor cutoff values for the placement algorithm may limit the usefullness + of the resulting function order. Improvements would be greatly appreciated. + + Suggestions: + + * Place the functions with many callers near the middle of the + list to reduce long calls. + + * Propagate arc usage changes as functions are placed. Ie if + func1 and func2 are placed together, arcs to/from those arcs + to the same parent/child should be combined, then resort the + arcs to choose the next one. + + * Implement some global positioning algorithm to place the + chains made by the greedy local positioning algorithm. Probably + by examining arcs which haven't been placed yet to tie two + chains together. + + * Take a function's size and time into account in the algorithm; + size in particular is important on the PA (long calls). Placing + many small functions onto their own page may be wise. + + * Use better profiling information; many published algorithms + are based on call sequences through time, rather than just + arc counts. + + * Prodecure cloning could improve performance when a small number + of arcs account for most of the calls to a particular function. + + * Use relocation information to avoid moving unused functions + completely out of the code stream; this would avoid severe lossage + when the profile data bears little resemblance to actual runs. + + * Propagation of arc usages should also improve .o link line + ordering which shares the same arc placement algorithm with + the function ordering code (in fact it is a degenerate case + of function ordering). */ + +void +DEFUN_VOID (cg_print_function_ordering) +{ + unsigned long index, used, unused, scratch_index; + unsigned long unplaced_arc_count, high_arc_count, scratch_arc_count; +#ifdef __GNUC__ + unsigned long long total_arcs, tmp_arcs_count; +#else + unsigned long total_arcs, tmp_arcs_count; +#endif + Sym **unused_syms, **used_syms, **scratch_syms; + Arc **unplaced_arcs, **high_arcs, **scratch_arcs; + + index = 0; + used = 0; + unused = 0; + scratch_index = 0; + unplaced_arc_count = 0; + high_arc_count = 0; + scratch_arc_count = 0; + + /* First group all the unused functions together. */ + unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + + /* Walk through all the functions; mark those which are never + called as placed (we'll emit them as a group later). */ + for (index = 0, used = 0, unused = 0; index < symtab.len; index++) + { + if (symtab.base[index].ncalls == 0) + { + /* Filter out gprof generated names. */ + if (strcmp (symtab.base[index].name, "") + && strcmp (symtab.base[index].name, "")) + { + unused_syms[unused++] = &symtab.base[index]; + symtab.base[index].has_been_placed = 1; + } + } + else + { + used_syms[used++] = &symtab.base[index]; + symtab.base[index].has_been_placed = 0; + symtab.base[index].next = 0; + symtab.base[index].prev = 0; + symtab.base[index].nuses = 0; + } + } + + /* Sort the arcs from most used to least used. */ + qsort (arcs, numarcs, sizeof (Arc *), cmp_arc_count); + + /* Compute the total arc count. Also mark arcs as unplaced. + + Note we don't compensate for overflow if that happens! + Overflow is much less likely when this file is compiled + with GCC as it can double-wide integers via long long. */ + total_arcs = 0; + for (index = 0; index < numarcs; index++) + { + total_arcs += arcs[index]->count; + arcs[index]->has_been_placed = 0; + } + + /* We want to pull out those functions which are referenced + by many highly used arcs and emit them as a group. This + could probably use some tuning. */ + tmp_arcs_count = 0; + for (index = 0; index < numarcs; index++) + { + tmp_arcs_count += arcs[index]->count; + + /* Count how many times each parent and child are used up + to our threshhold of arcs (90%). */ + if ((double)tmp_arcs_count / (double)total_arcs > 0.90) + break; + + arcs[index]->child->nuses++; + } + + /* Now sort a temporary symbol table based on the number of + times each function was used in the highest used arcs. */ + memcpy (scratch_syms, used_syms, used * sizeof (Sym *)); + qsort (scratch_syms, used, sizeof (Sym *), cmp_fun_nuses); + + /* Now pick out those symbols we're going to emit as + a group. We take up to 1.25% of the used symbols. */ + for (index = 0; index < used / 80; index++) + { + Sym *sym = scratch_syms[index]; + Arc *arc; + + /* If we hit symbols that aren't used from many call sites, + then we can quit. We choose five as the low limit for + no particular reason. */ + if (sym->nuses == 5) + break; + + /* We're going to need the arcs between these functions. + Unfortunately, we don't know all these functions + until we're done. So we keep track of all the arcs + to the functions we care about, then prune out those + which are uninteresting. + + An interesting variation would be to quit when we found + multi-call site functions which account for some percentage + of the arcs. */ + + arc = sym->cg.children; + while (arc) + { + if (arc->parent != arc->child) + scratch_arcs[scratch_arc_count++] = arc; + arc->has_been_placed = 1; + arc = arc->next_child; + } + + arc = sym->cg.parents; + while (arc) + { + if (arc->parent != arc->child) + scratch_arcs[scratch_arc_count++] = arc; + arc->has_been_placed = 1; + arc = arc->next_parent; + } + + /* Keep track of how many symbols we're going to place. */ + scratch_index = index; + + /* A lie, but it makes identifying these functions easier + later. */ + sym->has_been_placed = 1; + } + + /* Now walk through the temporary arcs and copy those we care about + into the high arcs array. */ + for (index = 0; index < scratch_arc_count; index++) + { + Arc *arc = scratch_arcs[index]; + + /* If this arc refers to highly used functions, then + then we want to keep it. */ + if (arc->child->has_been_placed + && arc->parent->has_been_placed) + { + high_arcs[high_arc_count++] = scratch_arcs[index]; + + /* We need to turn of has_been_placed since we're going to + use the main arc placement algorithm on these arcs. */ + arc->child->has_been_placed = 0; + arc->parent->has_been_placed = 0; + } + } + + /* Dump the multi-site high usage functions which are not going + to be ordered by the main ordering algorithm. */ + for (index = 0; index < scratch_index; index++) + { + if (scratch_syms[index]->has_been_placed) + printf ("%s\n", scratch_syms[index]->name); + } + + /* Now we can order the multi-site high use functions based on the + arcs between them. */ + qsort (high_arcs, high_arc_count, sizeof (Arc *), cmp_arc_count); + order_and_dump_functions_by_arcs (high_arcs, high_arc_count, 1, + unplaced_arcs, &unplaced_arc_count); + + /* Order and dump the high use functions left, these typically + have only a few call sites. */ + order_and_dump_functions_by_arcs (arcs, numarcs, 0, + unplaced_arcs, &unplaced_arc_count); + + /* Now place the rarely used functions. */ + order_and_dump_functions_by_arcs (unplaced_arcs, unplaced_arc_count, 1, + scratch_arcs, &scratch_arc_count); + + /* Output any functions not emitted by the order_and_dump calls. */ + for (index = 0; index < used; index++) + if (used_syms[index]->has_been_placed == 0) + printf("%s\n", used_syms[index]->name); + + /* Output the unused functions. */ + for (index = 0; index < unused; index++) + printf("%s\n", unused_syms[index]->name); + + unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + + free (unused_syms); + free (used_syms); + free (scratch_syms); + free (high_arcs); + free (scratch_arcs); + free (unplaced_arcs); +} + +/* Place functions based on the arcs in ARCS with NUMARCS entries; + place unused arcs into UNPLACED_ARCS/UNPLACED_ARC_COUNT. + + If ALL is nonzero, then place all functions referenced by ARCS, + else only place those referenced in the top 99% of the arcs in ARCS. */ + +#define MOST 0.99 +static void +order_and_dump_functions_by_arcs (arcs, numarcs, all, + unplaced_arcs, unplaced_arc_count) + Arc **arcs; + unsigned long numarcs; + int all; + Arc **unplaced_arcs; + unsigned long *unplaced_arc_count; +{ +#ifdef __GNUC__ + unsigned long long tmp_arcs, total_arcs; +#else + unsigned long tmp_arcs, total_arcs; +#endif + unsigned int index; + + /* If needed, compute the total arc count. + + Note we don't compensate for overflow if that happens! */ + if (! all) + { + total_arcs = 0; + for (index = 0; index < numarcs; index++) + total_arcs += arcs[index]->count; + } + else + total_arcs = 0; + + tmp_arcs = 0; + for (index = 0; index < numarcs; index++) + { + Sym *sym1, *sym2; + Sym *child, *parent; + + tmp_arcs += arcs[index]->count; + + /* Ignore this arc if it's already been placed. */ + if (arcs[index]->has_been_placed) + continue; + + child = arcs[index]->child; + parent = arcs[index]->parent; + + /* If we're not using all arcs, and this is a rarely used + arc, then put it on the unplaced_arc list. Similarly + if both the parent and child of this arc have been placed. */ + if ((! all && (double)tmp_arcs / (double)total_arcs > MOST) + || child->has_been_placed || parent->has_been_placed) + { + unplaced_arcs[(*unplaced_arc_count)++] = arcs[index]; + continue; + } + + /* If all slots in the parent and child are full, then there isn't + anything we can do right now. We'll place this arc on the + unplaced arc list in the hope that a global positioning + algorithm can use it to place function chains. */ + if (parent->next && parent->prev && child->next && child->prev) + { + unplaced_arcs[(*unplaced_arc_count)++] = arcs[index]; + continue; + } + + /* If the parent is unattached, then find the closest + place to attach it onto child's chain. Similarly + for the opposite case. */ + if (!parent->next && !parent->prev) + { + int next_count = 0; + int prev_count = 0; + Sym *prev = child; + Sym *next = child; + + /* Walk to the beginning and end of the child's chain. */ + while (next->next) + { + next = next->next; + next_count++; + } + + while (prev->prev) + { + prev = prev->prev; + prev_count++; + } + + /* Choose the closest. */ + child = next_count < prev_count ? next : prev; + } + else if (! child->next && !child->prev) + { + int next_count = 0; + int prev_count = 0; + Sym *prev = parent; + Sym *next = parent; + + while (next->next) + { + next = next->next; + next_count++; + } + + while (prev->prev) + { + prev = prev->prev; + prev_count++; + } + + parent = prev_count < next_count ? prev : next; + } + else + { + /* Couldn't find anywhere to attach the functions, + put the arc on the unplaced arc list. */ + unplaced_arcs[(*unplaced_arc_count)++] = arcs[index]; + continue; + } + + /* Make sure we don't tie two ends together. */ + sym1 = parent; + if (sym1->next) + while (sym1->next) + sym1 = sym1->next; + else + while (sym1->prev) + sym1 = sym1->prev; + + sym2 = child; + if (sym2->next) + while (sym2->next) + sym2 = sym2->next; + else + while (sym2->prev) + sym2 = sym2->prev; + + if (sym1 == child + && sym2 == parent) + { + /* This would tie two ends together. */ + unplaced_arcs[(*unplaced_arc_count)++] = arcs[index]; + continue; + } + + if (parent->next) + { + /* Must attach to the parent's prev field. */ + if (! child->next) + { + /* parent-prev and child-next */ + parent->prev = child; + child->next = parent; + arcs[index]->has_been_placed = 1; + } + } + else if (parent->prev) + { + /* Must attach to the parent's next field. */ + if (! child->prev) + { + /* parent-next and child-prev */ + parent->next = child; + child->prev = parent; + arcs[index]->has_been_placed = 1; + } + } + else + { + /* Can attach to either field in the parent, depends + on where we've got space in the child. */ + if (child->prev) + { + /* parent-prev and child-next */ + parent->prev = child; + child->next = parent; + arcs[index]->has_been_placed = 1; + } + else + { + /* parent-next and child-prev */ + parent->next = child; + child->prev = parent; + arcs[index]->has_been_placed = 1; + } + } + } + + /* Dump the chains of functions we've made. */ + for (index = 0; index < numarcs; index++) + { + Sym *sym; + if (arcs[index]->parent->has_been_placed + || arcs[index]->child->has_been_placed) + continue; + + sym = arcs[index]->parent; + + /* If this symbol isn't attached to any other + symbols, then we've got a rarely used arc. + + Skip it for now, we'll deal with them later. */ + if (sym->next == NULL + && sym->prev == NULL) + continue; + + /* Get to the start of this chain. */ + while (sym->prev) + sym = sym->prev; + + while (sym) + { + /* Mark it as placed. */ + sym->has_been_placed = 1; + printf ("%s\n", sym->name); + sym = sym->next; + } + } + + /* If we want to place all the arcs, then output those which weren't + placed by the main algorithm. */ + if (all) + for (index = 0; index < numarcs; index++) + { + Sym *sym; + if (arcs[index]->parent->has_been_placed + || arcs[index]->child->has_been_placed) + continue; + + sym = arcs[index]->parent; + + sym->has_been_placed = 1; + printf ("%s\n", sym->name); + } +} + +/* Print a suggested .o ordering for files on a link line based + on profiling information. This uses the function placement + code for the bulk of its work. */ + +struct function_map { + char *function_name; + char *file_name; +}; + +void +DEFUN_VOID (cg_print_file_ordering) +{ + unsigned long scratch_arc_count, index; + Arc **scratch_arcs; + extern struct function_map *symbol_map; + extern unsigned int symbol_map_count; + char *last; + + scratch_arc_count = 0; + + scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *)); + for (index = 0; index < numarcs; index++) + { + if (! arcs[index]->parent->mapped + || ! arcs[index]->child->mapped) + arcs[index]->has_been_placed = 1; + } + + order_and_dump_functions_by_arcs (arcs, numarcs, 0, + scratch_arcs, &scratch_arc_count); + + /* Output .o's not handled by the main placement algorithm. */ + for (index = 0; index < symtab.len; index++) + { + if (symtab.base[index].mapped + && ! symtab.base[index].has_been_placed) + printf ("%s\n", symtab.base[index].name); + } + + /* Now output any .o's that didn't have any text symbols. */ + last = NULL; + for (index = 0; index < symbol_map_count; index++) + { + unsigned int index2; + + /* Don't bother searching if this symbol is the + same as the previous one. */ + if (last && !strcmp (last, symbol_map[index].file_name)) + continue; + + for (index2 = 0; index2 < symtab.len; index2++) + { + if (! symtab.base[index2].mapped) + continue; + + if (!strcmp (symtab.base[index2].name, symbol_map[index].file_name)) + break; + } + + /* If we didn't find it in the symbol table, then it must be a .o + with no text symbols. Output it last. */ + if (index2 == symtab.len) + printf ("%s\n", symbol_map[index].file_name); + last = symbol_map[index].file_name; + } +} diff --git a/gprof/cg_print.h b/gprof/cg_print.h new file mode 100644 index 0000000..782c4aa --- /dev/null +++ b/gprof/cg_print.h @@ -0,0 +1,14 @@ +#ifndef cg_print_h +#define cg_print_h + +#include "gprof.h" +#include "symtab.h" + +extern double print_time; /* total of time being printed */ + +extern void cg_print PARAMS ((Sym ** cg)); +extern void cg_print_index PARAMS ((void)); +extern void cg_print_file_ordering PARAMS ((void)); +extern void cg_print_function_ordering PARAMS ((void)); + +#endif /* cg_print_h */ diff --git a/gprof/configure b/gprof/configure new file mode 100755 index 0000000..5ff5137 --- /dev/null +++ b/gprof/configure @@ -0,0 +1,4403 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-shared[=PKGS] build shared libraries [default=yes]" +ac_help="$ac_help + --enable-static[=PKGS] build static libraries [default=yes]" +ac_help="$ac_help + --enable-fast-install[=PKGS] optimize for fast installation [default=yes]" +ac_help="$ac_help + --with-gnu-ld assume the C compiler uses GNU ld [default=no]" +ac_help="$ac_help + --disable-libtool-lock force libtool not to do file locking" +ac_help="$ac_help + --disable-nls do not use Native Language Support" +ac_help="$ac_help + --with-included-gettext use the GNU gettext library included here" +ac_help="$ac_help + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=gprof.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:590: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:611: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:629: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:664: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:717: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:774: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=gprof + +VERSION=2.9.4 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:820: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:833: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:846: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:859: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:872: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi + +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:958: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:988: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1018: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1069: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1101: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1112 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1117: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1143: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1148: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1176: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 +echo "configure:1219: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 +echo "configure:1243: checking for GNU ld" >&5 +else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 +echo "configure:1246: checking for non-GNU ld" >&5 +fi +if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } + +echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 +echo "configure:1282: checking if the linker ($LD) is GNU ld" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6 + + +echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 +echo "configure:1298: checking for BSD-compatible nm" >&5 +if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + # Let the user override the test. + ac_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + break + else + ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm +fi +fi + +NM="$ac_cv_path_NM" +echo "$ac_t""$NM" 1>&6 + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output""... $ac_c" 1>&6 +echo "configure:1336: checking command to parse $NM output" >&5 +if eval "test \"`echo '$''{'ac_cv_sys_global_symbol_pipe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # These are sane defaults that work on at least a few old systems. +# {They come from Ultrix. What could be older than Ultrix?!! ;)} + +# Character class describing NM global symbol codes. +ac_symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +ac_symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +ac_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Define system-specific variables. +case "$host_os" in +aix*) + ac_symcode='[BCDT]' + ;; +cygwin* | mingw*) + ac_symcode='[ABCDGISTW]' + ;; +hpux*) + ac_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" + ;; +irix*) + ac_symcode='[BCDEGRST]' + ;; +solaris*) + ac_symcode='[BDT]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + ac_symcode='[ABCDGISTW]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.* \($ac_symcode\) *\($ac_symprfx\)$ac_sympat$/$ac_symxfrm/p'" + + # Check to see that the pipe works correctly. + ac_pipe_works=no + rm -f conftest.$ac_ext + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + # Now try to grab the symbols. + ac_nlist=conftest.nm + + if { (eval echo configure:1403: \"$NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist\") 1>&5; (eval $NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5; } && test -s "$ac_nlist"; then + + # Try sorting and uniquifying the output. + if sort "$ac_nlist" | uniq > "$ac_nlist"T; then + mv -f "$ac_nlist"T "$ac_nlist" + else + rm -f "$ac_nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then + if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$ac_global_symbol_to_cdecl"' < "$ac_nlist" >> conftest.c' + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftestm.$ac_objext + ac_save_LIBS="$LIBS" + ac_save_CFLAGS="$CFLAGS" + LIBS="conftestm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo configure:1455: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_pipe_works=yes + else + echo "configure: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$ac_save_LIBS" + CFLAGS="$ac_save_CFLAGS" + else + echo "cannot find nm_test_func in $ac_nlist" >&5 + fi + else + echo "cannot find nm_test_var in $ac_nlist" >&5 + fi + else + echo "cannot run $ac_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + rm -rf conftest* + + # Do not use the global_symbol_pipe unless it works. + if test "$ac_pipe_works" = yes; then + if test x"$ac_symprfx" = x"_"; then + ac_cv_sys_symbol_underscore=yes + else + ac_cv_sys_symbol_underscore=no + fi + break + else + ac_cv_sys_global_symbol_pipe= + fi +done + +fi + + +ac_result=yes +if test -z "$ac_cv_sys_global_symbol_pipe"; then + ac_result=no +fi +echo "$ac_t""$ac_result" 1>&6 + +echo $ac_n "checking for _ prefix in compiled symbols""... $ac_c" 1>&6 +echo "configure:1501: checking for _ prefix in compiled symbols" >&5 +if eval "test \"`echo '$''{'ac_cv_sys_symbol_underscore'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_sys_symbol_underscore=no +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if { (eval echo configure:1513: \"$NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist\") 1>&5; (eval $NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5; } && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if egrep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if egrep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&5 + fi + fi + else + echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&5 + fi +else + echo "configure: failed program was:" >&5 + cat conftest.c >&5 +fi +rm -rf conftest* + +fi + +echo "$ac_t""$ac_cv_sys_symbol_underscore" 1>&6 +USE_SYMBOL_UNDERSCORE=${ac_cv_sys_symbol_underscore=no} + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1539: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + + +# Check for any special flags to pass to ltconfig. +libtool_flags="--cache-file=$cache_file" +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$lt_dlopen" = yes && libtool_flags="$libtool_flags --enable-dlopen" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$host" in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 1581 "configure"' > conftest.$ac_ext + if { (eval echo configure:1582: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6 +echo "configure:1603: checking whether the C compiler needs -belf" >&5 +if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + lt_cv_cc_needs_belf=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + lt_cv_cc_needs_belf=no +fi +rm -f conftest* +fi + +echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +*-*-cygwin*) + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1638: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +DLLTOOL="$ac_cv_prog_DLLTOOL" +if test -n "$DLLTOOL"; then + echo "$ac_t""$DLLTOOL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_DLLTOOL"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1670: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_DLLTOOL="dlltool" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_DLLTOOL" && ac_cv_prog_DLLTOOL="false" +fi +fi +DLLTOOL="$ac_cv_prog_DLLTOOL" +if test -n "$DLLTOOL"; then + echo "$ac_t""$DLLTOOL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + DLLTOOL="false" +fi +fi + +# Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1705: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AS="${ac_tool_prefix}as" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AS="$ac_cv_prog_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_AS"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1737: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AS="as" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AS" && ac_cv_prog_AS="false" +fi +fi +AS="$ac_cv_prog_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + AS="false" +fi +fi + + + ;; + +esac + +# enable the --disable-libtool-lock switch + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + need_locks=$enableval +else + need_locks=yes +fi + + +if test x"$need_locks" = xno; then + libtool_flags="$libtool_flags --disable-lock" +fi + + +# Save cache, so that ltconfig can load it +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +DLLTOOL="$DLLTOOL" AS="$AS" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; } + +# Reload cache, that may have been modified by ltconfig +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log + + + + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1875: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1905: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1956: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1988: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1999 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:2004: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:2030: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:2035: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:2063: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:2106: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 +echo "configure:2160: checking for POSIXized ISC" >&5 +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + echo "$ac_t""yes" 1>&6 + ISC=yes # If later tests want to check for ISC. + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + echo "$ac_t""no" 1>&6 + ISC= +fi + + +ALL_LINGUAS= +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:2183: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2204: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2221: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2238: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:2263: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2276: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2343: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2367: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2421: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:2442: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <&6 +echo "configure:2482: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:2515: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:2550: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:2562: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:2583: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:2616: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:2648: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2678: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2706: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:2733: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext < addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:2760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2785: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2795: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_func in getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2824: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +echo "configure:2877: checking for working mmap" >&5 +if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat > conftest.$ac_ext < +#include +#include + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include +# endif + +/* Assume that all systems that can run configure have sys/param.h. */ +# ifndef HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +#ifdef __cplusplus +extern "C" { void *malloc(unsigned); } +#else +char *malloc(); +#endif + +int +main() +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize(); + + /* + * First, make a file with some known garbage in it. + */ + data = malloc(pagesize); + if (!data) + exit(1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand(); + umask(0); + fd = creat("conftestmmap", 0600); + if (fd < 0) + exit(1); + if (write(fd, data, pagesize) != pagesize) + exit(1); + close(fd); + + /* + * Next, try to mmap the file at a fixed address which + * already has something else allocated at it. If we can, + * also make sure that we see the same garbage. + */ + fd = open("conftestmmap", O_RDWR); + if (fd < 0) + exit(1); + data2 = malloc(2 * pagesize); + if (!data2) + exit(1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit(1); + + /* + * Finally, make sure that changes to the mapped area + * do not percolate back to the file as seen by read(). + * (This is a bug on some variants of i386 svr4.0.) + */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = malloc(pagesize); + if (!data3) + exit(1); + if (read(fd, data3, pagesize) != pagesize) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit(1); + close(fd); + unlink("conftestmmap"); + exit(0); +} + +EOF +if { (eval echo configure:3025: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_mmap_fixed_mapped=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + + + for ac_hdr in argz.h limits.h locale.h nl_types.h malloc.h string.h \ +unistd.h values.h sys/param.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3053: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3063: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + for ac_func in getcwd munmap putenv setenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3093: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + + if test "${ac_cv_func_stpcpy+set}" != "set"; then + for ac_func in stpcpy +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3150: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3178: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + fi + if test "${ac_cv_func_stpcpy}" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_STPCPY 1 +EOF + + fi + + if test $ac_cv_header_locale_h = yes; then + echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6 +echo "configure:3212: checking for LC_MESSAGES" >&5 +if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +return LC_MESSAGES +; return 0; } +EOF +if { (eval echo configure:3224: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + am_cv_val_LC_MESSAGES=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + am_cv_val_LC_MESSAGES=no +fi +rm -f conftest* +fi + +echo "$ac_t""$am_cv_val_LC_MESSAGES" 1>&6 + if test $am_cv_val_LC_MESSAGES = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_LC_MESSAGES 1 +EOF + + fi + fi + echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6 +echo "configure:3245: checking whether NLS is requested" >&5 + # Check whether --enable-nls or --disable-nls was given. +if test "${enable_nls+set}" = set; then + enableval="$enable_nls" + USE_NLS=$enableval +else + USE_NLS=yes +fi + + echo "$ac_t""$USE_NLS" 1>&6 + + + USE_INCLUDED_LIBINTL=no + + if test "$USE_NLS" = "yes"; then + cat >> confdefs.h <<\EOF +#define ENABLE_NLS 1 +EOF + + echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6 +echo "configure:3265: checking whether included gettext is requested" >&5 + # Check whether --with-included-gettext or --without-included-gettext was given. +if test "${with_included_gettext+set}" = set; then + withval="$with_included_gettext" + nls_cv_force_use_gnu_gettext=$withval +else + nls_cv_force_use_gnu_gettext=no +fi + + echo "$ac_t""$nls_cv_force_use_gnu_gettext" 1>&6 + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + nls_cv_header_intl= + nls_cv_header_libgt= + CATOBJEXT=NONE + + ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for libintl.h""... $ac_c" 1>&6 +echo "configure:3284: checking for libintl.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3294: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + echo $ac_n "checking for gettext in libc""... $ac_c" 1>&6 +echo "configure:3311: checking for gettext in libc" >&5 +if eval "test \"`echo '$''{'gt_cv_func_gettext_libc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +return (int) gettext ("") +; return 0; } +EOF +if { (eval echo configure:3323: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + gt_cv_func_gettext_libc=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gt_cv_func_gettext_libc=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gt_cv_func_gettext_libc" 1>&6 + + if test "$gt_cv_func_gettext_libc" != "yes"; then + echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6 +echo "configure:3339: checking for bindtextdomain in -lintl" >&5 +ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lintl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + echo $ac_n "checking for gettext in libintl""... $ac_c" 1>&6 +echo "configure:3374: checking for gettext in libintl" >&5 +if eval "test \"`echo '$''{'gt_cv_func_gettext_libintl'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + gt_cv_func_gettext_libintl=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gt_cv_func_gettext_libintl=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gt_cv_func_gettext_libintl" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + fi + + if test "$gt_cv_func_gettext_libc" = "yes" \ + || test "$gt_cv_func_gettext_libintl" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_GETTEXT 1 +EOF + + # Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3414: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$MSGFMT" in + /*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then + ac_cv_path_MSGFMT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="no" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test -n "$MSGFMT"; then + echo "$ac_t""$MSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + if test "$MSGFMT" != "no"; then + for ac_func in dcgettext +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3448: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3476: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3503: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GMSGFMT" in + /*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GMSGFMT="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT="$ac_cv_path_GMSGFMT" +if test -n "$GMSGFMT"; then + echo "$ac_t""$GMSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + # Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3539: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$XGETTEXT" in + /*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test -n "$XGETTEXT"; then + echo "$ac_t""$XGETTEXT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + CATOBJEXT=.gmo + DATADIRNAME=share +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CATOBJEXT=.mo + DATADIRNAME=lib +fi +rm -f conftest* + INSTOBJEXT=.mo + fi + fi + +else + echo "$ac_t""no" 1>&6 +fi + + + + if test "$CATOBJEXT" = "NONE"; then + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + INTLOBJS="\$(GETTOBJS)" + # Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3611: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$MSGFMT" in + /*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then + ac_cv_path_MSGFMT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="msgfmt" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test -n "$MSGFMT"; then + echo "$ac_t""$MSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3645: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GMSGFMT" in + /*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GMSGFMT="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT="$ac_cv_path_GMSGFMT" +if test -n "$GMSGFMT"; then + echo "$ac_t""$GMSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + # Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3681: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$XGETTEXT" in + /*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test -n "$XGETTEXT"; then + echo "$ac_t""$XGETTEXT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.gmo + INSTOBJEXT=.mo + DATADIRNAME=share + INTLDEPS='$(top_builddir)/../intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + if test "$XGETTEXT" != ":"; then + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + echo "$ac_t""found xgettext programs is not GNU xgettext; ignore it" 1>&6 + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + else + DATADIRNAME=share + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + # If this is used in GNU gettext we have to set USE_NLS to `yes' + # because some of the sources are only built for this goal. + if test "$PACKAGE" = gettext; then + USE_NLS=yes + USE_INCLUDED_LIBINTL=yes + fi + + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + + + + + + + + + + + + + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6 +echo "configure:3771: checking for catalogs to be installed" >&5 + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + echo "$ac_t""$LINGUAS" 1>&6 + fi + + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + if test $ac_cv_header_locale_h = yes; then + INCLUDE_LOCALE_H="#include " + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header . Take care yourself. */" + fi + + + if test -f $srcdir/po2tbl.sed.in; then + if test "$CATOBJEXT" = ".cat"; then + ac_safe=`echo "linux/version.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for linux/version.h""... $ac_c" 1>&6 +echo "configure:3799: checking for linux/version.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3809: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + msgformat=linux +else + echo "$ac_t""no" 1>&6 +msgformat=xopen +fi + + + sed -e '/^#/d' $srcdir/$msgformat-msg.sed > po2msg.sed + fi + sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \ + $srcdir/po2tbl.sed.in > po2tbl.sed + fi + + if test "$PACKAGE" = "gettext"; then + GT_NO="#NO#" + GT_YES= + else + GT_NO= + GT_YES="#YES#" + fi + + + + MKINSTALLDIRS="\$(srcdir)/../../mkinstalldirs" + + + l= + + + if test -d $srcdir/po; then + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + fi + + +echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 +echo "configure:3872: checking whether to enable maintainer-specific portions of Makefiles" >&5 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6 + + +if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + MAINT=$MAINTAINER_MODE_TRUE + + +echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 +echo "configure:3895: checking for Cygwin environment" >&5 +if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cygwin=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cygwin=no +fi +rm -f conftest* +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cygwin" 1>&6 +CYGWIN= +test "$ac_cv_cygwin" = yes && CYGWIN=yes +echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 +echo "configure:3928: checking for mingw32 environment" >&5 +if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_mingw32=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_mingw32=no +fi +rm -f conftest* +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_mingw32" 1>&6 +MINGW32= +test "$ac_cv_mingw32" = yes && MINGW32=yes + + +echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 +echo "configure:3959: checking for executable suffix" >&5 +if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$CYGWIN" = yes || test "$MINGW32" = yes; then + ac_cv_exeext=.exe +else + rm -f conftest* + echo 'int main () { return 0; }' > conftest.$ac_ext + ac_cv_exeext= + if { (eval echo configure:3969: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + for file in conftest.*; do + case $file in + *.c | *.o | *.obj | *.ilk | *.pdb) ;; + *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;; + esac + done + else + { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; } + fi + rm -f conftest* + test x"${ac_cv_exeext}" = x && ac_cv_exeext=no +fi +fi + +EXEEXT="" +test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext} +echo "$ac_t""${ac_cv_exeext}" 1>&6 +ac_exeext=$EXEEXT + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile po/Makefile.in:po/Make-in gconfig.h:gconfig.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@RANLIB@%$RANLIB%g +s%@CC@%$CC%g +s%@LD@%$LD%g +s%@NM@%$NM%g +s%@USE_SYMBOL_UNDERSCORE@%$USE_SYMBOL_UNDERSCORE%g +s%@LN_S@%$LN_S%g +s%@DLLTOOL@%$DLLTOOL%g +s%@AS@%$AS%g +s%@LIBTOOL@%$LIBTOOL%g +s%@CPP@%$CPP%g +s%@ALLOCA@%$ALLOCA%g +s%@USE_NLS@%$USE_NLS%g +s%@MSGFMT@%$MSGFMT%g +s%@GMSGFMT@%$GMSGFMT%g +s%@XGETTEXT@%$XGETTEXT%g +s%@USE_INCLUDED_LIBINTL@%$USE_INCLUDED_LIBINTL%g +s%@CATALOGS@%$CATALOGS%g +s%@CATOBJEXT@%$CATOBJEXT%g +s%@DATADIRNAME@%$DATADIRNAME%g +s%@GMOFILES@%$GMOFILES%g +s%@INSTOBJEXT@%$INSTOBJEXT%g +s%@INTLDEPS@%$INTLDEPS%g +s%@INTLLIBS@%$INTLLIBS%g +s%@INTLOBJS@%$INTLOBJS%g +s%@POFILES@%$POFILES%g +s%@POSUB@%$POSUB%g +s%@INCLUDE_LOCALE_H@%$INCLUDE_LOCALE_H%g +s%@GT_NO@%$GT_NO%g +s%@GT_YES@%$GT_YES%g +s%@MKINSTALLDIRS@%$MKINSTALLDIRS%g +s%@l@%$l%g +s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g +s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g +s%@MAINT@%$MAINT%g +s%@EXEEXT@%$EXEEXT%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h +sed -e '/POTFILES =/r po/POTFILES' po/Makefile.in > po/Makefile +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/gprof/configure.bat b/gprof/configure.bat new file mode 100644 index 0000000..22ef37e --- /dev/null +++ b/gprof/configure.bat @@ -0,0 +1,18 @@ +@echo off +echo Configuring gprof for go32 +rem This batch file assumes a unix-type "sed" program + +echo # Makefile generated by "configure.bat"> Makefile + +if exist config.sed del config.sed + +echo "/^###$/ i\ ">>config.sed +echo "MY_MACHINE=i386\ ">>config.sed +echo "CC=gcc ">>config.sed + +echo # >> config.sed + +sed -e "s/^\"//" -e "s/\"$//" -e "s/[ ]*$//" config.sed > config2.sed +sed -f config2.sed Makefile.in >> Makefile +del config.sed +del config2.sed diff --git a/gprof/configure.in b/gprof/configure.in new file mode 100644 index 0000000..b50b55d --- /dev/null +++ b/gprof/configure.in @@ -0,0 +1,29 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.13) +AC_INIT(gprof.c) + +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE(gprof, 2.9.4) + +AM_PROG_LIBTOOL + +dnl For simplicity, we use the BFD configuration file for most +dnl things. However, we also need our own configuration file for +dnl the automake PACKAGE and VERSION macros. We don't name it +dnl config.h, to avoid any possible confusion with the bfd config.h. +AM_CONFIG_HEADER(gconfig.h:gconfig.in) + +AC_PROG_CC +AC_PROG_INSTALL + +AC_ISC_POSIX + +ALL_LINGUAS= +CY_GNU_GETTEXT + +AM_MAINTAINER_MODE +AC_EXEEXT + +AC_OUTPUT(Makefile po/Makefile.in:po/Make-in, +[sed -e '/POTFILES =/r po/POTFILES' po/Makefile.in > po/Makefile]) diff --git a/gprof/corefile.c b/gprof/corefile.c new file mode 100644 index 0000000..a6e6f83 --- /dev/null +++ b/gprof/corefile.c @@ -0,0 +1,762 @@ +#include "libiberty.h" +#include "gprof.h" +#include "corefile.h" +#include "symtab.h" + +bfd *core_bfd; +int core_num_syms; +asymbol **core_syms; +asection *core_text_sect; +PTR core_text_space; + +int min_insn_size; +int offset_to_code; + +/* For mapping symbols to specific .o files during file ordering. */ +struct function_map { + char *function_name; + char *file_name; +}; + +struct function_map *symbol_map; +unsigned int symbol_map_count; + +extern void i386_find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); +extern void alpha_find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); +extern void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); +extern void tahoe_find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); +extern void sparc_find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); + +static void +DEFUN (read_function_mappings, (filename), const char *filename) +{ + FILE *file = fopen (filename, "r"); + char dummy[1024]; + int count = 0; + + if (!file) + { + fprintf (stderr, _("%s: could not open %s.\n"), whoami, filename); + done (1); + } + + /* First parse the mapping file so we know how big we need to + make our tables. We also do some sanity checks at this + time. */ + while (!feof (file)) + { + int matches; + + matches = fscanf (file, "%[^\n:]", dummy); + if (!matches) + { + fprintf (stderr, _("%s: unable to parse mapping file %s.\n"), + whoami, filename); + done (1); + } + + /* Just skip messages about files with no symbols. */ + if (!strncmp (dummy, "No symbols in ", 14)) + { + fscanf (file, "\n"); + continue; + } + + /* Don't care what else is on this line at this point. */ + fscanf (file, "%[^\n]\n", dummy); + count++; + } + + /* Now we know how big we need to make our table. */ + symbol_map = ((struct function_map *) + xmalloc (count * sizeof (struct function_map))); + + /* Rewind the input file so we can read it again. */ + rewind (file); + + /* Read each entry and put it into the table. */ + count = 0; + while (!feof (file)) + { + int matches; + char *tmp; + + matches = fscanf (file, "%[^\n:]", dummy); + if (!matches) + { + fprintf (stderr, _("%s: unable to parse mapping file %s.\n"), + whoami, filename); + done (1); + } + + /* Just skip messages about files with no symbols. */ + if (!strncmp (dummy, "No symbols in ", 14)) + { + fscanf (file, "\n"); + continue; + } + + /* dummy has the filename, go ahead and copy it. */ + symbol_map[count].file_name = xmalloc (strlen (dummy) + 1); + strcpy (symbol_map[count].file_name, dummy); + + /* Now we need the function name. */ + fscanf (file, "%[^\n]\n", dummy); + tmp = strrchr (dummy, ' ') + 1; + symbol_map[count].function_name = xmalloc (strlen (tmp) + 1); + strcpy (symbol_map[count].function_name, tmp); + count++; + } + + /* Record the size of the map table for future reference. */ + symbol_map_count = count; +} + +void +DEFUN (core_init, (a_out_name), const char *a_out_name) +{ + core_bfd = bfd_openr (a_out_name, 0); + + if (!core_bfd) + { + perror (a_out_name); + done (1); + } + + if (!bfd_check_format (core_bfd, bfd_object)) + { + fprintf (stderr, _("%s: %s: not in a.out format\n"), whoami, a_out_name); + done (1); + } + + /* get core's text section: */ + core_text_sect = bfd_get_section_by_name (core_bfd, ".text"); + if (!core_text_sect) + { + core_text_sect = bfd_get_section_by_name (core_bfd, "$CODE$"); + if (!core_text_sect) + { + fprintf (stderr, _("%s: can't find .text section in %s\n"), + whoami, a_out_name); + done (1); + } + } + + /* read core's symbol table: */ + + /* this will probably give us more than we need, but that's ok: */ + core_num_syms = bfd_get_symtab_upper_bound (core_bfd); + if (core_num_syms < 0) + { + fprintf (stderr, "%s: %s: %s\n", whoami, a_out_name, + bfd_errmsg (bfd_get_error ())); + done (1); + } + + core_syms = (asymbol **) xmalloc (core_num_syms); + core_num_syms = bfd_canonicalize_symtab (core_bfd, core_syms); + if (core_num_syms < 0) + { + fprintf (stderr, "%s: %s: %s\n", whoami, a_out_name, + bfd_errmsg (bfd_get_error ())); + done (1); + } + + min_insn_size = 1; + offset_to_code = 0; + + switch (bfd_get_arch (core_bfd)) + { + case bfd_arch_vax: + case bfd_arch_tahoe: + offset_to_code = 2; + break; + + case bfd_arch_alpha: + min_insn_size = 4; + break; + + default: + break; + } + + if (function_mapping_file) + read_function_mappings (function_mapping_file); +} + + +/* + * Read in the text space of an a.out file + */ +void +DEFUN (core_get_text_space, (core_bfd), bfd * core_bfd) +{ + core_text_space = (PTR) malloc (core_text_sect->_raw_size); + + if (!core_text_space) + { + fprintf (stderr, _("%s: ran out room for %ld bytes of text space\n"), + whoami, core_text_sect->_raw_size); + done (1); + } + if (!bfd_get_section_contents (core_bfd, core_text_sect, core_text_space, + 0, core_text_sect->_raw_size)) + { + bfd_perror ("bfd_get_section_contents"); + free (core_text_space); + core_text_space = 0; + } + if (!core_text_space) + { + fprintf (stderr, _("%s: can't do -c\n"), whoami); + } +} + + +void +DEFUN (find_call, (parent, p_lowpc, p_highpc), + Sym * parent AND bfd_vma p_lowpc AND bfd_vma p_highpc) +{ + switch (bfd_get_arch (core_bfd)) + { + case bfd_arch_i386: + i386_find_call (parent, p_lowpc, p_highpc); + break; + + case bfd_arch_alpha: + alpha_find_call (parent, p_lowpc, p_highpc); + break; + + case bfd_arch_vax: + vax_find_call (parent, p_lowpc, p_highpc); + break; + + case bfd_arch_sparc: + sparc_find_call (parent, p_lowpc, p_highpc); + break; + + case bfd_arch_tahoe: + tahoe_find_call (parent, p_lowpc, p_highpc); + break; + + default: + fprintf (stderr, _("%s: -c not supported on architecture %s\n"), + whoami, bfd_printable_name(core_bfd)); + + /* Don't give the error more than once. */ + ignore_direct_calls = FALSE; + } +} + +/* + * Return class of symbol SYM. The returned class can be any of: + * 0 -> symbol is not interesting to us + * 'T' -> symbol is a global name + * 't' -> symbol is a local (static) name + */ +static int +DEFUN (core_sym_class, (sym), asymbol * sym) +{ + symbol_info syminfo; + const char *name; + char sym_prefix; + int i; + + if (sym->section == NULL || (sym->flags & BSF_DEBUGGING) != 0) + { + return 0; + } + + /* + * Must be a text symbol, and static text symbols don't qualify if + * ignore_static_funcs set. + */ + if (ignore_static_funcs && (sym->flags & BSF_LOCAL)) + { + DBG (AOUTDEBUG, printf ("[core_sym_class] %s: not a function\n", + sym->name)); + return 0; + } + + bfd_get_symbol_info (core_bfd, sym, &syminfo); + i = syminfo.type; + + if (i == 'T') + { + return i; /* it's a global symbol */ + } + + if (i == 'W') + { + /* Treat weak symbols as text symbols. FIXME: a weak symbol may + also be a data symbol. */ + return 'T'; + } + + if (i != 't') + { + /* not a static text symbol */ + DBG (AOUTDEBUG, printf ("[core_sym_class] %s is of class %c\n", + sym->name, i)); + return 0; + } + + /* do some more filtering on static function-names: */ + + if (ignore_static_funcs) + { + return 0; + } + /* + * Can't zero-length name or funny characters in name, where + * `funny' includes: `.' (.o file names) and `$' (Pascal labels). + */ + if (!sym->name || sym->name[0] == '\0') + { + return 0; + } + + for (name = sym->name; *name; ++name) + { + if (*name == '.' || *name == '$') + { + return 0; + } + } + /* + * 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. + */ + sym_prefix = bfd_get_symbol_leading_char (core_bfd); + if ((sym_prefix && sym_prefix != sym->name[0]) + /* + * 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 (sym->name, "__gnu_compiled", 14) + || !strncmp (sym->name, "___gnu_compiled", 15)) + { + return 0; + } + + /* If the object file supports marking of function symbols, then we can + zap anything that doesn't have BSF_FUNCTION set. */ + if (ignore_non_functions && (sym->flags & BSF_FUNCTION) == 0) + return 0; + + return 't'; /* it's a static text symbol */ +} + + +/* + * Get whatever source info we can get regarding address ADDR: + */ +static bool +DEFUN (get_src_info, (addr, filename, name, line_num), + bfd_vma addr AND const char **filename AND const char **name + AND int *line_num) +{ + const char *fname = 0, *func_name = 0; + int l = 0; + + if (bfd_find_nearest_line (core_bfd, core_text_sect, core_syms, + addr - core_text_sect->vma, + &fname, &func_name, (unsigned int *) &l) + && fname && func_name && l) + { + DBG (AOUTDEBUG, printf ("[get_src_info] 0x%lx -> %s:%d (%s)\n", + addr, fname, l, func_name)); + *filename = fname; + *name = func_name; + *line_num = l; + return TRUE; + } + else + { + DBG (AOUTDEBUG, printf ("[get_src_info] no info for 0x%lx (%s:%d,%s)\n", + (long) addr, fname ? fname : "", l, + func_name ? func_name : "")); + return FALSE; + } +} + + +/* + * Read in symbol table from core. One symbol per function is + * entered. + */ +void +DEFUN (core_create_function_syms, (core_bfd), bfd * core_bfd) +{ + bfd_vma min_vma = ~0, max_vma = 0; + int class; + long i, found, skip; + unsigned int j; + + /* pass 1 - determine upper bound on number of function names: */ + symtab.len = 0; + for (i = 0; i < core_num_syms; ++i) + { + if (!core_sym_class (core_syms[i])) + { + continue; + } + + /* This should be replaced with a binary search or hashed + search. Gross. + + Don't create a symtab entry for a function that has + a mapping to a file, unless it's the first function + in the file. */ + skip = 0; + for (j = 0; j < symbol_map_count; j++) + if (!strcmp (core_syms[i]->name, symbol_map[j].function_name)) + { + if (j > 0 && ! strcmp (symbol_map [j].file_name, + symbol_map [j - 1].file_name)) + skip = 1; + break; + } + if (!skip) + ++symtab.len; + } + + if (symtab.len == 0) + { + fprintf (stderr, _("%s: file `%s' has no symbols\n"), whoami, a_out_name); + done (1); + } + + /* the "+ 2" is for the sentinels: */ + symtab.base = (Sym *) xmalloc ((symtab.len + 2) * sizeof (Sym)); + + /* pass 2 - create symbols: */ + + symtab.limit = symtab.base; + for (i = 0; i < core_num_syms; ++i) + { + class = core_sym_class (core_syms[i]); + if (!class) + { + DBG (AOUTDEBUG, + printf ("[core_create_function_syms] rejecting: 0x%lx %s\n", + core_syms[i]->value, core_syms[i]->name)); + continue; + } + /* This should be replaced with a binary search or hashed + search. Gross. */ + + skip = 0; + found = 0; + for (j = 0; j < symbol_map_count; j++) + if (!strcmp (core_syms[i]->name, symbol_map[j].function_name)) + { + if (j > 0 && ! strcmp (symbol_map [j].file_name, + symbol_map [j - 1].file_name)) + skip = 1; + else + found = j; + break; + } + + if (skip) + continue; + + sym_init (symtab.limit); + + /* symbol offsets are always section-relative: */ + + symtab.limit->addr = core_syms[i]->value + core_syms[i]->section->vma; + if (symbol_map_count + && !strcmp (core_syms[i]->name, symbol_map[found].function_name)) + { + symtab.limit->name = symbol_map[found].file_name; + symtab.limit->mapped = 1; + } + else + { + symtab.limit->name = core_syms[i]->name; + symtab.limit->mapped = 0; + } + + /* Lookup filename and line number, if we can */ + + { + const char *filename, *func_name; + + if (get_src_info (symtab.limit->addr, &filename, &func_name, + &symtab.limit->line_num)) + { + symtab.limit->file = source_file_lookup_path (filename); + + /* FIXME: Checking __osf__ here does not work with a cross + gprof. */ +#ifdef __osf__ + /* + * Suppress symbols that are not function names. This is + * useful to suppress code-labels and aliases. + * + * This is known to be useful under DEC's OSF/1. Under SunOS 4.x, + * labels do not appear in the symbol table info, so this isn't + * necessary. + */ + + if (strcmp (symtab.limit->name, func_name) != 0) + { + /* + * The symbol's address maps to a different name, so + * it can't be a function-entry point. This happens + * for labels, for example. + */ + DBG (AOUTDEBUG, + printf ("[core_create_function_syms: rej %s (maps to %s)\n", + symtab.limit->name, func_name)); + continue; + } +#endif + } + } + + symtab.limit->is_func = TRUE; + symtab.limit->is_bb_head = TRUE; + if (class == 't') + { + symtab.limit->is_static = TRUE; + } + + min_vma = MIN (symtab.limit->addr, min_vma); + max_vma = MAX (symtab.limit->addr, max_vma); + + /* + * If we see "main" without an initial '_', we assume names + * are *not* prefixed by '_'. + */ + if (symtab.limit->name[0] == 'm' && discard_underscores + && strcmp (symtab.limit->name, "main") == 0) + { + discard_underscores = 0; + } + + DBG (AOUTDEBUG, printf ("[core_create_function_syms] %ld %s 0x%lx\n", + (long) (symtab.limit - symtab.base), + symtab.limit->name, symtab.limit->addr)); + ++symtab.limit; + } + + /* create sentinels: */ + + sym_init (symtab.limit); + symtab.limit->name = ""; + symtab.limit->addr = 0; + symtab.limit->end_addr = min_vma - 1; + ++symtab.limit; + + sym_init (symtab.limit); + symtab.limit->name = ""; + symtab.limit->addr = max_vma + 1; + symtab.limit->end_addr = ~0; + ++symtab.limit; + + symtab.len = symtab.limit - symtab.base; + symtab_finalize (&symtab); +} + + +/* + * Read in symbol table from core. One symbol per line of source code + * is entered. + */ +void +DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd) +{ + char *prev_name, *prev_filename; + int prev_name_len, prev_filename_len; + bfd_vma vma, min_vma = ~0, max_vma = 0; + bfd_vma offset; + Sym *prev, dummy, *sentinel, *sym; + const char *filename; + int prev_line_num; + Sym_Table ltab; + /* + * Create symbols for functions as usual. This is necessary in + * cases where parts of a program were not compiled with -g. For + * those parts we still want to get info at the function level: + */ + core_create_function_syms (core_bfd); + + /* pass 1 - counter number of symbols: */ + + /* + * To find all line information, walk through all possible + * text-space addresses (one by one!) and get the debugging + * info for each address. When the debugging info changes, + * it is time to create a new symbol. + * + * Of course, this is rather slow and it would be better if + * bfd would provide an iterator for enumerating all line infos + */ + prev_name_len = PATH_MAX; + prev_filename_len = PATH_MAX; + prev_name = xmalloc (prev_name_len); + prev_filename = xmalloc (prev_filename_len); + ltab.len = 0; + prev_line_num = 0; + for (offset = 0; offset < core_text_sect->_raw_size; offset += min_insn_size) + { + int len; + + vma = core_text_sect->vma + offset; + if (!get_src_info (vma, &filename, &dummy.name, &dummy.line_num) + || (prev_line_num == dummy.line_num + && prev_name != NULL + && strcmp (prev_name, dummy.name) == 0 + && strcmp (prev_filename, filename) == 0)) + { + continue; + } + + ++ltab.len; + prev_line_num = dummy.line_num; + + len = strlen (dummy.name); + if (len >= prev_name_len) + { + prev_name_len = len + 1024; + free (prev_name); + prev_name = xmalloc (prev_name_len); + } + strcpy (prev_name, dummy.name); + + len = strlen (filename); + if (len >= prev_filename_len) + { + prev_filename_len = len + 1024; + free (prev_filename); + prev_filename = xmalloc (prev_filename_len); + } + strcpy (prev_filename, filename); + + min_vma = MIN (vma, min_vma); + max_vma = MAX (vma, max_vma); + } + + free (prev_name); + free (prev_filename); + + /* make room for function symbols, too: */ + ltab.len += symtab.len; + ltab.base = (Sym *) xmalloc (ltab.len * sizeof (Sym)); + ltab.limit = ltab.base; + + /* pass 2 - create symbols: */ + + /* We now set is_static as we go along, rather than by running + through the symbol table at the end. + + The old way called symtab_finalize before the is_static pass, + causing a problem since symtab_finalize uses is_static as part of + its address conflict resolution algorithm. Since global symbols + were prefered over static symbols, and all line symbols were + global at that point, static function names that conflicted with + their own line numbers (static, but labeled as global) were + rejected in favor of the line num. + + This was not the desired functionality. We always want to keep + our function symbols and discard any conflicting line symbols. + Perhaps symtab_finalize should be modified to make this + distinction as well, but the current fix works and the code is a + lot cleaner now. */ + + prev = 0; + for (offset = 0; offset < core_text_sect->_raw_size; offset += min_insn_size) + { + sym_init (ltab.limit); + if (!get_src_info (core_text_sect->vma + offset, &filename, + <ab.limit->name, <ab.limit->line_num) + || (prev && prev->line_num == ltab.limit->line_num + && strcmp (prev->name, ltab.limit->name) == 0 + && strcmp (prev->file->name, filename) == 0)) + { + continue; + } + + /* make name pointer a malloc'ed string: */ + ltab.limit->name = xstrdup (ltab.limit->name); + ltab.limit->file = source_file_lookup_path (filename); + + ltab.limit->addr = core_text_sect->vma + offset; + + /* Set is_static based on the enclosing function, using either: + * 1) the previous symbol, if it's from the same function, or + * 2) a symtab lookup + */ + + if (prev && ltab.limit->file == prev->file && + strcmp (ltab.limit->name, prev->name) == 0) + { + ltab.limit->is_static = prev->is_static; + } + else + { + sym = sym_lookup(&symtab, ltab.limit->addr); + ltab.limit->is_static = sym->is_static; + } + + prev = ltab.limit; + + /* + * If we see "main" without an initial '_', we assume names + * are *not* prefixed by '_'. + */ + if (ltab.limit->name[0] == 'm' && discard_underscores + && strcmp (ltab.limit->name, "main") == 0) + { + discard_underscores = 0; + } + + DBG (AOUTDEBUG, printf ("[core_create_line_syms] %d %s 0x%lx\n", + ltab.limit - ltab.base, ltab.limit->name, + ltab.limit->addr)); + ++ltab.limit; + } + + /* update sentinels: */ + + sentinel = sym_lookup (&symtab, 0); + if (strcmp (sentinel->name, "") == 0 + && min_vma <= sentinel->end_addr) + { + sentinel->end_addr = min_vma - 1; + } + + sentinel = sym_lookup (&symtab, ~0); + if (strcmp (sentinel->name, "") == 0 && max_vma >= sentinel->addr) + { + sentinel->addr = max_vma + 1; + } + + /* copy in function symbols: */ + memcpy (ltab.limit, symtab.base, symtab.len * sizeof (Sym)); + ltab.limit += symtab.len; + + if ((unsigned int) (ltab.limit - ltab.base) != ltab.len) + { + fprintf (stderr, + _("%s: somebody miscounted: ltab.len=%d instead of %ld\n"), + whoami, ltab.len, (long) (ltab.limit - ltab.base)); + done (1); + } + + /* finalize ltab and make it symbol table: */ + + symtab_finalize (<ab); + free (symtab.base); + symtab = ltab; + +} diff --git a/gprof/corefile.h b/gprof/corefile.h new file mode 100644 index 0000000..b396f85 --- /dev/null +++ b/gprof/corefile.h @@ -0,0 +1,21 @@ +#ifndef corefile_h +#define corefile_h + +#include "bfd.h" + +extern bfd *core_bfd; /* bfd for core-file */ +extern int core_num_syms; /* # of entries in symbol-table */ +extern asymbol **core_syms; /* symbol table in a.out */ +extern asection *core_text_sect; /* core text section */ +extern PTR core_text_space; /* text space of a.out in core */ + +extern int min_insn_size; /* size of smallest instruction, in bytes */ +extern int offset_to_code; /* offset (in bytes) of code from entry + address of routine */ + +extern void core_init PARAMS ((const char *a_out_name)); +extern void core_get_text_space PARAMS ((bfd * core_bfd)); +extern void core_create_function_syms PARAMS ((bfd * core_bfd)); +extern void core_create_line_syms PARAMS ((bfd * core_bfd)); + +#endif /* corefile_h */ diff --git a/gprof/flat_bl.m b/gprof/flat_bl.m new file mode 100644 index 0000000..db2871a --- /dev/null +++ b/gprof/flat_bl.m @@ -0,0 +1,27 @@ + + % the percentage of the total running time of the +time program used by this function. + +cumulative a running sum of the number of seconds accounted + seconds for by this function and those listed above it. + + self the number of seconds accounted for by this +seconds function alone. This is the major sort for this + listing. + +calls the number of times this function was invoked, if + this function is profiled, else blank. + + self the average number of milliseconds spent in this +ms/call function per call, if this function is profiled, + else blank. + + total the average number of milliseconds spent in this +ms/call function and its descendents per call, if this + function is profiled, else blank. + +name the name of the function. This is the minor sort + for this listing. The index shows the location of + the function in the gprof listing. If the index is + in parenthesis it shows where it would appear in + the gprof listing if it were to be printed. diff --git a/gprof/fsf_callg_bl.m b/gprof/fsf_callg_bl.m new file mode 100644 index 0000000..7e16821 --- /dev/null +++ b/gprof/fsf_callg_bl.m @@ -0,0 +1,83 @@ + + This table describes the call tree of the program, and was sorted by + the total amount of time spent in each function and its children. + + Each entry in this table consists of several lines. The line with the + index number at the left hand margin lists the current function. + The lines above it list the functions that called this function, + and the lines below it list the functions this one called. + This line lists: + index A unique number given to each element of the table. + Index numbers are sorted numerically. + The index number is printed next to every function name so + it is easier to look up where the function in the table. + + % time This is the percentage of the `total' time that was spent + in this function and its children. Note that due to + different viewpoints, functions excluded by options, etc, + these numbers will NOT add up to 100%. + + self This is the total amount of time spent in this function. + + children This is the total amount of time propagated into this + function by its children. + + called This is the number of times the function was called. + If the function called itself recursively, the number + only includes non-recursive calls, and is followed by + a `+' and the number of recursive calls. + + name The name of the current function. The index number is + printed after it. If the function is a member of a + cycle, the cycle number is printed between the + function's name and the index number. + + + For the function's parents, the fields have the following meanings: + + self This is the amount of time that was propagated directly + from the function into this parent. + + children This is the amount of time that was propagated from + the function's children into this parent. + + called This is the number of times this parent called the + function `/' the total number of times the function + was called. Recursive calls to the function are not + included in the number after the `/'. + + name This is the name of the parent. The parent's index + number is printed after it. If the parent is a + member of a cycle, the cycle number is printed between + the name and the index number. + + If the parents of the function cannot be determined, the word + `' is printed in the `name' field, and all the other + fields are blank. + + For the function's children, the fields have the following meanings: + + self This is the amount of time that was propagated directly + from the child into the function. + + children This is the amount of time that was propagated from the + child's children to the function. + + called This is the number of times the function called + this child `/' the total number of times the child + was called. Recursive calls by the child are not + listed in the number after the `/'. + + name This is the name of the child. The child's index + number is printed after it. If the child is a + member of a cycle, the cycle number is printed + between the name and the index number. + + If there are any cycles (circles) in the call graph, there is an + entry for the cycle-as-a-whole. This entry shows who called the + cycle (as parents) and the members of the cycle (as children.) + The `+' recursive calls entry shows the number of function calls that + were internal to the cycle, and the calls entry for each member shows, + for that member, how many times it was called from other members of + the cycle. + diff --git a/gprof/gconfig.in b/gprof/gconfig.in new file mode 100644 index 0000000..347e8e0 --- /dev/null +++ b/gprof/gconfig.in @@ -0,0 +1,129 @@ +/* gconfig.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you have the __argz_count function. */ +#undef HAVE___ARGZ_COUNT + +/* Define if you have the __argz_next function. */ +#undef HAVE___ARGZ_NEXT + +/* Define if you have the __argz_stringify function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Define if you have the dcgettext function. */ +#undef HAVE_DCGETTEXT + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the munmap function. */ +#undef HAVE_MUNMAP + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the setenv function. */ +#undef HAVE_SETENV + +/* Define if you have the setlocale function. */ +#undef HAVE_SETLOCALE + +/* Define if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_VALUES_H + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + +/* Define if you have the stpcpy function */ +#undef HAVE_STPCPY + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if NLS is requested */ +#undef ENABLE_NLS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + diff --git a/gprof/gen-c-prog.awk b/gprof/gen-c-prog.awk new file mode 100644 index 0000000..b59c1f8 --- /dev/null +++ b/gprof/gen-c-prog.awk @@ -0,0 +1,26 @@ +NR == 1 { + FS="\""; + print "/* ==> Do not modify this file!! It is created automatically" + printf " from %s using the gen-c-prog.awk script. <== */\n\n", FILE + print "#include " +} + + { + if (curfun != FUNCTION) + { + if (curfun) + print "}" + curfun = FUNCTION + print "" + print "void"; + printf "%s (file)\n", FUNCTION + print " FILE *file;"; + print "{"; + } + printf " fputs (\""; + for (i = 1; i < NF; i++) + printf "%s\\\"", $i; + printf "%s\\n\", file);\n", $NF; +} + +END { print "}" } diff --git a/gprof/gmon.h b/gprof/gmon.h new file mode 100644 index 0000000..541fa4d --- /dev/null +++ b/gprof/gmon.h @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)gmon.h 5.2 (Berkeley) 5/6/91 + */ +#ifndef gmon_h +#define gmon_h + +struct raw_phdr + { + /* FIXME: Checking a host compiler define means that we can't use + a cross gprof to the alpha. */ +#ifdef __alpha__ + char low_pc[8]; /* base pc address of sample buffer */ + char high_pc[8]; /* max pc address of sampled buffer */ +#else + char low_pc[4]; /* base pc address of sample buffer */ + char high_pc[4]; /* max pc address of sampled buffer */ +#endif + char ncnt[4]; /* size of sample buffer (plus this header) */ + + char version[4]; /* version number */ + char profrate[4]; /* profiling clock rate */ + char spare[3*4]; /* reserved */ + }; + +#define GMONVERSION 0x00051879 + +struct old_raw_phdr + { + /* FIXME: Checking a host compiler define means that we can't use + a cross gprof to the alpha. */ +#ifdef __alpha__ + char low_pc[8]; /* base pc address of sample buffer */ + char high_pc[8]; /* max pc address of sampled buffer */ +#else + char low_pc[4]; /* base pc address of sample buffer */ + char high_pc[4]; /* max pc address of sampled buffer */ +#endif + char ncnt[4]; /* size of sample buffer (plus this header) */ + + /* FIXME: Checking host compiler defines here means that we can't + use a cross gprof alpha OSF. */ +#if defined (__alpha__) && defined (__osf__) + /* + * DEC's OSF v3.0 uses 4 bytes of padding to bring the header to + * a size that is a multiple of 8. + */ + char pad[4]; +#endif + }; + +/* + * Histogram counters are unsigned shorts: + */ +#define HISTCOUNTER unsigned short + +/* + * Fraction of text space to allocate for histogram counters here, 1/2: + */ +#define HISTFRACTION 2 + +/* + * Fraction of text space to allocate for from hash buckets. The + * value of HASHFRACTION is based on the minimum number of bytes of + * separation between two subroutine call points in the object code. + * Given MIN_SUBR_SEPARATION bytes of separation the value of + * HASHFRACTION is calculated as: + * + * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1); + * + * For the VAX, the shortest two call sequence is: + * + * calls $0,(r0) + * calls $0,(r0) + * + * which is separated by only three bytes, thus HASHFRACTION is + * calculated as: + * + * HASHFRACTION = 3 / (2 * 2 - 1) = 1 + * + * Note that the division above rounds down, thus if MIN_SUBR_FRACTION + * is less than three, this algorithm will not work! + */ +#define HASHFRACTION 1 + +/* + * Percent of text space to allocate for tostructs with a minimum: + */ +#define ARCDENSITY 2 +#define MINARCS 50 + +struct tostruct + { + char *selfpc; + int count; + unsigned short link; + }; + +/* + * A raw arc, with pointers to the calling site and the called site + * and a count. Everything is defined in terms of characters so + * as to get a packed representation (otherwise, different compilers + * might introduce different padding): + */ +struct raw_arc + { + /* FIXME: Checking a host compiler define means that we can't use + a cross gprof to the alpha. */ +#ifdef __alpha__ + char from_pc[8]; + char self_pc[8]; + char count[8]; +#else + char from_pc[4]; + char self_pc[4]; + char count[4]; +#endif + }; + +/* + * General rounding functions: + */ +#define ROUNDDOWN(x,y) (((x)/(y))*(y)) +#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) + +#endif /* gmon_h */ diff --git a/gprof/gmon_io.c b/gprof/gmon_io.c new file mode 100644 index 0000000..ff294f5 --- /dev/null +++ b/gprof/gmon_io.c @@ -0,0 +1,454 @@ +/* + * Input and output from/to gmon.out files. + */ +#include "cg_arcs.h" +#include "basic_blocks.h" +#include "bfd.h" +#include "corefile.h" +#include "call_graph.h" +#include "gmon_io.h" +#include "gmon_out.h" +#include "gmon.h" /* fetch header for old format */ +#include "gprof.h" +#include "hertz.h" +#include "hist.h" +#include "libiberty.h" + +int gmon_input = 0; +int gmon_file_version = 0; /* 0 == old (non-versioned) file format */ + +/* + * This probably ought to be in libbfd. + */ +bfd_vma +DEFUN (get_vma, (abfd, addr), bfd * abfd AND bfd_byte * addr) +{ + switch (sizeof (char*)) + { + case 4: + return bfd_get_32 (abfd, addr); + case 8: + return bfd_get_64 (abfd, addr); + default: + fprintf (stderr, _("%s: bfd_vma has unexpected size of %ld bytes\n"), + whoami, (long) sizeof (char*)); + done (1); + } +} + + +/* + * This probably ought to be in libbfd. + */ +void +DEFUN (put_vma, (abfd, val, addr), bfd * abfd AND bfd_vma val AND bfd_byte * addr) +{ + switch (sizeof (char*)) + { + case 4: + bfd_put_32 (abfd, val, addr); + break; + case 8: + bfd_put_64 (abfd, val, addr); + break; + default: + fprintf (stderr, _("%s: bfd_vma has unexpected size of %ld bytes\n"), + whoami, (long) sizeof (char*)); + done (1); + } +} + + +void +DEFUN (gmon_out_read, (filename), const char *filename) +{ + FILE *ifp; + struct gmon_hdr ghdr; + unsigned char tag; + int nhist = 0, narcs = 0, nbbs = 0; + + /* open gmon.out file: */ + + if (strcmp (filename, "-") == 0) + { + ifp = stdin; + } + else + { + ifp = fopen (filename, FOPEN_RB); + if (!ifp) + { + perror (filename); + done (1); + } + } + if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1) + { + fprintf (stderr, _("%s: file too short to be a gmon file\n"), + filename); + done (1); + } + + if ((file_format == FF_MAGIC) || + (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))) + { + if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)) + { + fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), + whoami, filename); + done (1); + } + + /* right magic, so it's probably really a new gmon.out file */ + + gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version); + if (gmon_file_version != GMON_VERSION && gmon_file_version != 0) + { + fprintf (stderr, + _("%s: file `%s' has unsupported version %d\n"), + whoami, filename, gmon_file_version); + done (1); + } + + /* read in all the records: */ + while (fread (&tag, sizeof (tag), 1, ifp) == 1) + { + switch (tag) + { + case GMON_TAG_TIME_HIST: + ++nhist; + gmon_input |= INPUT_HISTOGRAM; + hist_read_rec (ifp, filename); + break; + + case GMON_TAG_CG_ARC: + ++narcs; + gmon_input |= INPUT_CALL_GRAPH; + cg_read_rec (ifp, filename); + break; + + case GMON_TAG_BB_COUNT: + ++nbbs; + gmon_input |= INPUT_BB_COUNTS; + bb_read_rec (ifp, filename); + break; + + default: + fprintf (stderr, + _("%s: %s: found bad tag %d (file corrupted?)\n"), + whoami, filename, tag); + done (1); + } + } + } + else if (file_format == FF_AUTO + || file_format == FF_BSD + || file_format == FF_BSD44) + { + struct hdr + { + bfd_vma low_pc; + bfd_vma high_pc; + int ncnt; + }; + int i, samp_bytes, header_size; + unsigned long count; + bfd_vma from_pc, self_pc; + struct raw_arc raw_arc; + struct raw_phdr raw; + static struct hdr h; + UNIT raw_bin_count; + struct hdr tmp; + + /* + * Information from a gmon.out file is in two parts: an array of + * sampling hits within pc ranges, and the arcs. + */ + gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH; + + /* + * This fseek() ought to work even on stdin as long as it's + * not an interactive device (heck, is there anybody who would + * want to type in a gmon.out at the terminal?). + */ + if (fseek (ifp, 0, SEEK_SET) < 0) + { + perror (filename); + done (1); + } + if (fread (&raw, 1, sizeof (struct raw_phdr), ifp) + != sizeof (struct raw_phdr)) + { + fprintf (stderr, _("%s: file too short to be a gmon file\n"), + filename); + done (1); + } + tmp.low_pc = get_vma (core_bfd, (bfd_byte *) &raw.low_pc[0]); + tmp.high_pc = get_vma (core_bfd, (bfd_byte *) &raw.high_pc[0]); + tmp.ncnt = bfd_get_32 (core_bfd, (bfd_byte *) &raw.ncnt[0]); + + if (bfd_get_32 (core_bfd, (bfd_byte *) &raw.version[0]) + == GMONVERSION) + { + int profrate; + + /* 4.4BSD format header. */ + + profrate = bfd_get_32 (core_bfd, (bfd_byte *) &raw.profrate[0]); + if (!s_highpc) + hz = profrate; + else if (hz != profrate) + { + fprintf (stderr, + _("%s: profiling rate incompatible with first gmon file\n"), + filename); + done (1); + } + + header_size = sizeof (struct raw_phdr); + } + else + { + /* old style BSD format. */ + if (file_format == FF_BSD44) + { + fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), + whoami, filename); + done (1); + } + + if (fseek (ifp, sizeof (struct old_raw_phdr), SEEK_SET) < 0) + { + perror (filename); + done (1); + } + + header_size = sizeof (struct old_raw_phdr); + } + + if (s_highpc && (tmp.low_pc != h.low_pc || + tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt)) + { + fprintf (stderr, _("%s: incompatible with first gmon file\n"), + filename); + done (1); + } + h = tmp; + s_lowpc = (bfd_vma) h.low_pc; + s_highpc = (bfd_vma) h.high_pc; + lowpc = (bfd_vma) h.low_pc / sizeof (UNIT); + highpc = (bfd_vma) h.high_pc / sizeof (UNIT); + samp_bytes = h.ncnt - header_size; + hist_num_bins = samp_bytes / sizeof (UNIT); + DBG (SAMPLEDEBUG, + printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n", + h.low_pc, h.high_pc, h.ncnt); + printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n", + s_lowpc, s_highpc); + printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n", + lowpc, highpc); + printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n", + samp_bytes, hist_num_bins)); + + if (hist_num_bins) + { + ++nhist; + } + + if (!hist_sample) + { + hist_sample = + (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0])); + memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0])); + } + + for (i = 0; i < hist_num_bins; ++i) + { + if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1) + { + fprintf (stderr, + _("%s: unexpected EOF after reading %d/%d bins\n"), + whoami, --i, hist_num_bins); + done (1); + } + hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count); + } + + /* + * The rest of the file consists of a bunch of + * tuples: + */ + while (fread (&raw_arc, sizeof (raw_arc), 1, ifp) == 1) + { + ++narcs; + from_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.from_pc); + self_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.self_pc); + count = bfd_get_32 (core_bfd, (bfd_byte *) raw_arc.count); + DBG (SAMPLEDEBUG, + printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n", + from_pc, self_pc, count)); + /* add this arc: */ + cg_tally (from_pc, self_pc, count); + } + fclose (ifp); + + if (hz == HZ_WRONG) + { + /* + * How many ticks per second? If we can't tell, report + * time in ticks. + */ + hz = hertz (); + if (hz == HZ_WRONG) + { + hz = 1; + fprintf (stderr, _("time is in ticks, not seconds\n")); + } + } + } + else + { + fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), + whoami, file_format); + done (1); + } + + if (output_style & STYLE_GMON_INFO) + { + printf (_("File `%s' (version %d) contains:\n"), + filename, gmon_file_version); + printf (_("\t%d histogram record%s\n"), + nhist, nhist == 1 ? "" : "s"); + printf (_("\t%d call-graph record%s\n"), + narcs, narcs == 1 ? "" : "s"); + printf (_("\t%d basic-block count record%s\n"), + nbbs, nbbs == 1 ? "" : "s"); + first_output = FALSE; + } +} + + +void +DEFUN (gmon_out_write, (filename), const char *filename) +{ + FILE *ofp; + struct gmon_hdr ghdr; + + ofp = fopen (filename, FOPEN_WB); + if (!ofp) + { + perror (filename); + done (1); + } + + if (file_format == FF_AUTO || file_format == FF_MAGIC) + { + /* write gmon header: */ + + memcpy (&ghdr.cookie[0], GMON_MAGIC, 4); + bfd_put_32 (core_bfd, GMON_VERSION, (bfd_byte *) ghdr.version); + if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1) + { + perror (filename); + done (1); + } + + /* write execution time histogram if we have one: */ + if (gmon_input & INPUT_HISTOGRAM) + { + hist_write_hist (ofp, filename); + } + + /* write call graph arcs if we have any: */ + if (gmon_input & INPUT_CALL_GRAPH) + { + cg_write_arcs (ofp, filename); + } + + /* write basic-block info if we have it: */ + if (gmon_input & INPUT_BB_COUNTS) + { + bb_write_blocks (ofp, filename); + } + } + else if (file_format == FF_BSD || file_format == FF_BSD44) + { + struct raw_arc raw_arc; + UNIT raw_bin_count; + struct raw_phdr h; + int i; + Arc *arc; + Sym *sym; + + memset (&h, 0, sizeof h); + put_vma (core_bfd, s_lowpc, (bfd_byte *) &h.low_pc); + put_vma (core_bfd, s_highpc, (bfd_byte *) &h.high_pc); + bfd_put_32 (core_bfd, + hist_num_bins * sizeof (UNIT) + sizeof (struct raw_phdr), + (bfd_byte *) &h.ncnt); + + /* Write header. Use new style BSD format is explicitly + specified, or if the profiling rate is non-standard; + otherwise, use the old BSD format. */ + if (file_format == FF_BSD44 + || hz != hertz ()) + { + bfd_put_32 (core_bfd, GMONVERSION, (bfd_byte *) &h.version); + bfd_put_32 (core_bfd, hz, (bfd_byte *) &h.profrate); + if (fwrite (&h, sizeof (struct raw_phdr), 1, ofp) != 1) + { + perror (filename); + done (1); + } + } + else + { + if (fwrite (&h, sizeof (struct old_raw_phdr), 1, ofp) != 1) + { + perror (filename); + done (1); + } + } + + /* dump the samples: */ + + for (i = 0; i < hist_num_bins; ++i) + { + bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & raw_bin_count[0]); + if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1) + { + perror (filename); + done (1); + } + } + + /* dump the normalized raw arc information: */ + + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + for (arc = sym->cg.children; arc; arc = arc->next_child) + { + put_vma (core_bfd, arc->parent->addr, + (bfd_byte *) raw_arc.from_pc); + put_vma (core_bfd, arc->child->addr, + (bfd_byte *) raw_arc.self_pc); + bfd_put_32 (core_bfd, arc->count, (bfd_byte *) raw_arc.count); + if (fwrite (&raw_arc, sizeof (raw_arc), 1, ofp) != 1) + { + perror (filename); + done (1); + } + DBG (SAMPLEDEBUG, + printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n", + arc->parent->addr, arc->child->addr, arc->count)); + } + } + fclose (ofp); + } + else + { + fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), + whoami, file_format); + done (1); + } +} diff --git a/gprof/gmon_io.h b/gprof/gmon_io.h new file mode 100644 index 0000000..bf257a4 --- /dev/null +++ b/gprof/gmon_io.h @@ -0,0 +1,20 @@ +#ifndef gmon_io_h +#define gmon_io_h + +#include "bfd.h" +#include "gmon.h" + +#define INPUT_HISTOGRAM (1<<0) +#define INPUT_CALL_GRAPH (1<<1) +#define INPUT_BB_COUNTS (1<<2) + +extern int gmon_input; /* what input did we see? */ +extern int gmon_file_version; /* file version are we dealing with */ + +extern bfd_vma get_vma PARAMS ((bfd * abfd, bfd_byte * addr)); +extern void put_vma PARAMS ((bfd * abfd, bfd_vma val, bfd_byte * addr)); + +extern void gmon_out_read PARAMS ((const char *filename)); +extern void gmon_out_write PARAMS ((const char *filename)); + +#endif /* gmon_io_h */ diff --git a/gprof/gmon_out.h b/gprof/gmon_out.h new file mode 100644 index 0000000..2144fb5 --- /dev/null +++ b/gprof/gmon_out.h @@ -0,0 +1,51 @@ +/* + * This file specifies the format of gmon.out files. It should have + * as few external dependencies as possible as it is going to be + * included in many different programs. That is, minimize the + * number of #include's. + * + * A gmon.out file consists of a header (defined by gmon_hdr) followed + * by a sequence of records. Each record starts with a one-byte tag + * identifying the type of records, followed by records specific data. + */ +#ifndef gmon_out_h +#define gmon_out_h + +#define GMON_MAGIC "gmon" /* magic cookie */ +#define GMON_VERSION 1 /* version number */ + +/* + * Raw header as it appears on file (without padding): + */ +struct gmon_hdr + { + char cookie[4]; + char version[4]; + char spare[3 * 4]; + }; + +/* types of records in this file: */ +typedef enum + { + GMON_TAG_TIME_HIST = 0, GMON_TAG_CG_ARC = 1, GMON_TAG_BB_COUNT = 2 + } +GMON_Record_Tag; + +struct gmon_hist_hdr + { + char low_pc[sizeof (char*)]; /* base pc address of sample buffer */ + char high_pc[sizeof (char*)]; /* max pc address of sampled buffer */ + char hist_size[4]; /* size of sample buffer */ + char prof_rate[4]; /* profiling clock rate */ + char dimen[15]; /* phys. dim., usually "seconds" */ + char dimen_abbrev; /* usually 's' for "seconds" */ + }; + +struct gmon_cg_arc_record + { + char from_pc[sizeof (char*)]; /* address within caller's body */ + char self_pc[sizeof (char*)]; /* address within callee's body */ + char count[4]; /* number of arc traversals */ + }; + +#endif /* gmon_out_h */ diff --git a/gprof/gprof.1 b/gprof/gprof.1 new file mode 100644 index 0000000..5a734da --- /dev/null +++ b/gprof/gprof.1 @@ -0,0 +1,252 @@ +.\" Copyright (c) 1983, 1990 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. +.\" +.\" @(#)gprof.1 6.6 (Berkeley) 7/24/90 +.\" +.TH GPROF 1 "January 29, 1993" +.SH NAME +gprof \- display call graph profile data +.SH SYNOPSIS +.B gprof [ \-abcsz ] [ \-e|\-E +.I name +.B ] [ \-f|\-F +.I name +.B ] +.B [ \-k +.I fromname toname +.B ] [ +.I objfile +.B [ +.I gmon.out +.B ] +.B ] +.SH DESCRIPTION +.B gprof +produces an execution profile of C, Pascal, or Fortran77 programs. +The effect of called routines is incorporated in the profile of each caller. +The profile data is taken from the call graph profile file +\&(`gmon.out' default) which is created by programs +that are compiled with the +.B \-pg +option of +.BR cc ( 1 ) , +.BR pc ( 1 ) , +and +.BR f77 ( 1 ) . +The +.B \-pg +option also links in versions of the library routines +that are compiled for profiling. +.B Gprof +reads the given object file (the default is `a.out') +and establishes the relation between its symbol table +and the call graph profile from `gmon.out'. +If more than one profile file is specified, +the +.B gprof +output shows the sum of the profile information in the given profile files. +.PP +.B Gprof +calculates the amount of time spent in each routine. +Next, these times are propagated along the edges of the call graph. +Cycles are discovered, and calls into a cycle are made to share the time +of the cycle. +The first listing shows the functions +sorted according to the time they represent +including the time of their call graph descendants. +Below each function entry is shown its (direct) call graph children, +and how their times are propagated to this function. +A similar display above the function shows how this function's time and the +time of its descendants is propagated to its (direct) call graph parents. +.PP +Cycles are also shown, with an entry for the cycle as a whole and +a listing of the members of the cycle and their contributions to the +time and call counts of the cycle. +.PP +Second, a flat profile is given, +similar to that provided by +.BR prof ( 1 ) . +This listing gives the total execution times, the call counts, +the time in milliseconds the call spent in the routine itself, and +the time in milliseconds the call spent in the routine itself including +its descendants. +.PP +Finally, an index of the function names is provided. +.SH OPTIONS +The following options are available: +.TP +.B \-a +suppresses the printing of statically declared functions. +If this option is given, all relevant information about the static function +(e.g., time samples, calls to other functions, calls from other functions) +belongs to the function loaded just before the static function in the +\&`objfile' file. +.TP +.B \-b +suppresses the printing of a description of each field in the profile. +.TP +.B \-c +the static call graph of the program is discovered by a heuristic +that examines the text space of the object file. +Static-only parents or children are shown +with call counts of 0. +.TP +.BI "\-e " name +suppresses the printing of the graph profile entry for routine +.I name +and all its descendants +(unless they have other ancestors that aren't suppressed). +More than one +.B \-e +option may be given. +Only one +.I name +may be given with each +.B \-e +option. +.TP +.BI "\-E " name +suppresses the printing of the graph profile entry for routine +.I name +(and its descendants) as +.B \-e , +above, and also excludes the time spent in +.I name +(and its descendants) from the total and percentage time computations. +(For example, +.BI "\-E " mcount +.BI "\-E " mcleanup +is the default.) +.TP +.BI "\-f " name +prints the graph profile entry of only the specified routine +.I name +and its descendants. +More than one +.B \-f +option may be given. +Only one +.I name +may be given with each +.B \-f +option. +.TP +.BI "\-F " name +prints the graph profile entry of only the routine +.I name +and its descendants (as +.B \-f , +above) and also uses only the times of the printed routines +in total time and percentage computations. +More than one +.B \-F +option may be given. +Only one +.I name +may be given with each +.B \-F +option. +The +.B \-F +option +overrides +the +.B \-E +option. +.TP +.BI "\-k " "fromname toname" +will delete any arcs from routine +.I fromname +to routine +.IR toname . +This can be used to break undesired cycles. +More than one +.B \-k +option may be given. +Only one pair of routine names may be given with each +.B \-k +option. +.TP +.B \-s +a profile file `gmon.sum' is produced that represents +the sum of the profile information in all the specified profile files. +This summary profile file may be given to later +executions of gprof (probably also with a +.BR \-s ) +to accumulate profile data across several runs of an `objfile' file. +.TP +.B -v +prints the version number for gprof, and then exits. +.TP +.B -z +displays routines that have zero usage (as shown by call counts +and accumulated time). +This is useful with the +.B \-c +option for discovering which routines were never called. +.PP +.SH FILES +.ta \w'gmon.sum 'u +a.out the namelist and text space. +.br +gmon.out dynamic call graph and profile. +.br +gmon.sum summarized dynamic call graph and profile. +.SH SEE ALSO +.BR monitor ( 3 ) , +.BR profil ( 2 ) , +.BR cc ( 1 ) , +.BR prof ( 1 ) +.sp +``An Execution Profiler for Modular Programs'', +by S. Graham, P. Kessler, M. McKusick; +.I +Software \- Practice and Experience, +Vol. 13, pp. 671-685, 1983. +.sp +``gprof: A Call Graph Execution Profiler'', +by S. Graham, P. Kessler, M. McKusick; +.I +Proceedings of the SIGPLAN '82 Symposium on Compiler Construction, +SIGPLAN Notices, Vol. 17, No 6, pp. 120-126, June 1982. +.SH HISTORY +.B Gprof +appeared in 4.2 BSD. +.SH BUGS +The granularity of the sampling is shown, but remains +statistical at best. +We assume that the time for each execution of a function +can be expressed by the total time for the function divided +by the number of times the function is called. +Thus the time propagated along the call graph arcs to the function's +parents is directly proportional to the number of times that +arc is traversed. +.PP +Parents that are not themselves profiled will have the time of +their profiled children propagated to them, but they will appear +to be spontaneously invoked in the call graph listing, and will +not have their time propagated further. +Similarly, signal catchers, even though profiled, will appear +to be spontaneous (although for more obscure reasons). +Any profiled children of signal catchers should have their times +propagated properly, unless the signal catcher was invoked during +the execution of the profiling routine, in which case all is lost. +.PP +The profiled program must call +.BR exit ( 2 ) +or return normally for the profiling information to be saved +in the `gmon.out' file. diff --git a/gprof/gprof.c b/gprof/gprof.c new file mode 100644 index 0000000..cb90487 --- /dev/null +++ b/gprof/gprof.c @@ -0,0 +1,659 @@ +/* + * Copyright (c) 1983, 1998 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. + */ +#include "getopt.h" +#include "libiberty.h" +#include "gprof.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 "source.h" +#include "sym_ids.h" + +const char *whoami; +const char *function_mapping_file; +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; +bool bsd_style_output = FALSE; +bool demangle = TRUE; +bool discard_underscores = TRUE; +bool ignore_direct_calls = FALSE; +bool ignore_static_funcs = FALSE; +bool ignore_zeros = TRUE; +bool line_granularity = FALSE; +bool print_descriptions = TRUE; +bool print_path = FALSE; +bool ignore_non_functions = FALSE; +File_Format file_format = FF_AUTO; + +bool first_output = TRUE; + +char copyright[] = + N_("@(#) Copyright (c) 1983 Regents of the University of California.\n\ + All rights reserved.\n"); + +static char *gmon_name = GMONNAME; /* profile filename */ + +bfd *abfd; + +/* + * Functions that get excluded by default: + */ +static char *default_excluded_list[] = +{ + "_gprof_mcount", "mcount", "_mcount", "__mcount", "__mcount_internal", + "__mcleanup", + "", "", + 0 +}; + +/* Codes used for the long options with no short synonyms. 150 isn't + special; it's just an arbitrary non-ASCII char value. */ + +#define OPTION_DEMANGLE (150) +#define OPTION_NO_DEMANGLE (OPTION_DEMANGLE + 1) + +static struct option long_options[] = +{ + {"line", no_argument, 0, 'l'}, + {"no-static", no_argument, 0, 'a'}, + {"ignore-non-functions", no_argument, 0, 'D'}, + + /* 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", no_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'}, + {"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'}, + /* + * These are for backwards-compatibility only. Their functionality + * is provided by the output style options already: + */ + {"", 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 +DEFUN (usage, (stream, status), FILE * stream AND int status) +{ + fprintf (stream, _("\ +Usage: %s [-[abcDhilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][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]\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] [--no-demangle]\n\ + [image-file] [profile-file...]\n"), + whoami); + if (status == 0) + fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n")); + done (status); +} + + +int +DEFUN (main, (argc, argv), int argc AND char **argv) +{ + char **sp, *str; + Sym **cg = 0; + int ch, user_specified = 0; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + whoami = argv[0]; + xmalloc_set_program_name (whoami); + + while ((ch = getopt_long (argc, argv, + "aA::bBcCdD::e:E:f:F:hiI:J::k:lLm:n::N::O:p::P::q::Q::st:Tvw:xyzZ::", + long_options, 0)) + != EOF) + { + switch (ch) + { + case 'a': + 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': + print_descriptions = FALSE; + break; + case 'B': + output_style |= STYLE_CALL_GRAPH; + user_specified |= STYLE_CALL_GRAPH; + break; + case 'c': + 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': + 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': + sym_id_add (optarg, EXCL_TIME); + case 'e': + sym_id_add (optarg, EXCL_GRAPH); + break; + case 'F': + sym_id_add (optarg, INCL_TIME); + case 'f': + sym_id_add (optarg, INCL_GRAPH); + break; + 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': + 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': + output_style |= STYLE_SUMMARY_FILE; + user_specified |= STYLE_SUMMARY_FILE; + 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"), VERSION); + 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': + 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_ANNOTATED_SOURCE; + break; + case OPTION_DEMANGLE: + demangle = TRUE; + break; + case OPTION_NO_DEMANGLE: + demangle = FALSE; + break; + default: + usage (stderr, 1); + } + } + + /* 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); + } + + /* --sum implies --line, otherwise we'd lose b-b counts in gmon.sum */ + if (output_style & STYLE_SUMMARY_FILE) + { + line_granularity = 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); + } + + if (optind < argc) + { + a_out_name = argv[optind++]; + } + if (optind < argc) + { + gmon_name = argv[optind++]; + } + + /* + * Turn off default functions: + */ + for (sp = &default_excluded_list[0]; *sp; sp++) + { + sym_id_add (*sp, EXCL_TIME); + sym_id_add (*sp, EXCL_GRAPH); +#ifdef __alpha__ + sym_id_add (*sp, EXCL_FLAT); +#endif + } + + /* + * For line-by-line profiling, also want to keep those + * functions off the flat profile: + */ + if (line_granularity) + { + for (sp = &default_excluded_list[0]; *sp; sp++) + { + sym_id_add (*sp, EXCL_FLAT); + } + } + + /* + * 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 (line_granularity) + { + core_create_line_syms (core_bfd); + } + else + { + core_create_function_syms (core_bfd); + } + + /* + * Translate sym specs into syms: + */ + sym_id_parse (); + + if (file_format == FF_PROF) + { +#ifdef PROF_SUPPORT_IMPLEMENTED + /* + * Get information about mon.out file(s): + */ + do + { + mon_out_read (gmon_name); + if (optind < argc) + { + gmon_name = argv[optind]; + } + } + while (optind++ < argc); +#else + fprintf (stderr, + _("%s: sorry, file format `prof' is not yet supported\n"), + whoami); + done (1); +#endif + } + else + { + /* + * Get information about gmon.out file(s): + */ + do + { + gmon_out_read (gmon_name); + if (optind < argc) + { + gmon_name = argv[optind]; + } + } + while (optind++ < argc); + } + + /* + * If user did not specify output style, try to guess something + * reasonable: + */ + if (output_style == 0) + { + if (gmon_input & (INPUT_HISTOGRAM | INPUT_CALL_GRAPH)) + { + output_style = STYLE_FLAT_PROFILE | STYLE_CALL_GRAPH; + } + else + { + output_style = STYLE_EXEC_COUNTS; + } + output_style &= ~user_specified; + } + + /* + * Dump a gmon.sum file if requested (before any other processing!): + */ + if (output_style & STYLE_SUMMARY_FILE) + { + gmon_out_write (GMONSUM); + } + + if (gmon_input & INPUT_HISTOGRAM) + { + hist_assign_samples (); + } + + if (gmon_input & INPUT_CALL_GRAPH) + { + cg = cg_assemble (); + } + + /* 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); + } + + 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); + } + + /* output whatever user whishes to see: */ + + if (cg && (output_style & STYLE_CALL_GRAPH) && bsd_style_output) + { + cg_print (cg); /* print the dynamic profile */ + } + + if (output_style & STYLE_FLAT_PROFILE) + { + hist_print (); /* print the flat profile */ + } + + if (cg && (output_style & STYLE_CALL_GRAPH)) + { + if (!bsd_style_output) + { + cg_print (cg); /* print the dynamic profile */ + } + cg_print_index (); + } + + if (output_style & STYLE_EXEC_COUNTS) + { + print_exec_counts (); + } + + if (output_style & STYLE_ANNOTATED_SOURCE) + { + print_annotated_source (); + } + if (output_style & STYLE_FUNCTION_ORDER) + { + cg_print_function_ordering (); + } + if (output_style & STYLE_FILE_ORDER) + { + cg_print_file_ordering (); + } + return 0; +} + +void +done (status) + int status; +{ + exit (status); +} diff --git a/gprof/gprof.h b/gprof/gprof.h new file mode 100644 index 0000000..8f62aee --- /dev/null +++ b/gprof/gprof.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1983 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. + * + * @(#)gprof.h 5.9 (Berkeley) 6/1/90 + */ +#ifndef gprof_h +#define gprof_h + +#include + +/* Include the BFD sysdep.h file. */ +#include "sysdep.h" + +/* Undefine the BFD PACKAGE and VERSION macros before including the + gprof config.h file. */ +#undef PACKAGE +#undef VERSION +/* Also undefine BFD's `_' macro; we have our own definition. */ +#undef _ + +#include "gconfig.h" + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* AIX defines hz as a macro. */ +#undef hz + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#define A_OUTNAME "a.out" /* default core filename */ +#define GMONNAME "gmon.out" /* default profile filename */ +#define GMONSUM "gmon.sum" /* profile summary filename */ + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +/* Stubs that do something close enough. */ +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + + +/* + * These may already be defined on some systems. We could probably + * just use the BFD versions of these, since BFD has already dealt + * with this problem. + */ +#undef FALSE +#define FALSE 0 +#undef TRUE +#define TRUE 1 + +#define STYLE_FLAT_PROFILE (1<<0) +#define STYLE_CALL_GRAPH (1<<1) +#define STYLE_SUMMARY_FILE (1<<2) +#define STYLE_EXEC_COUNTS (1<<3) +#define STYLE_ANNOTATED_SOURCE (1<<4) +#define STYLE_GMON_INFO (1<<5) +#define STYLE_FUNCTION_ORDER (1<<6) +#define STYLE_FILE_ORDER (1<<7) + +#define ANYDEBUG (1<<0) /* 1 */ +#define DFNDEBUG (1<<1) /* 2 */ +#define CYCLEDEBUG (1<<2) /* 4 */ +#define ARCDEBUG (1<<3) /* 8 */ +#define TALLYDEBUG (1<<4) /* 16 */ +#define TIMEDEBUG (1<<5) /* 32 */ +#define SAMPLEDEBUG (1<<6) /* 64 */ +#define AOUTDEBUG (1<<7) /* 128 */ +#define CALLDEBUG (1<<8) /* 256 */ +#define LOOKUPDEBUG (1<<9) /* 512 */ +#define PROPDEBUG (1<<10) /* 1024 */ +#define BBDEBUG (1<<11) /* 2048 */ +#define IDDEBUG (1<<12) /* 4096 */ +#define SRCDEBUG (1<<13) /* 8192 */ + +#ifdef DEBUG +#define DBG(l,s) if (debug_level & (l)) {s;} +#else +#define DBG(l,s) +#endif + +typedef enum + { + FF_AUTO = 0, FF_MAGIC, FF_BSD, FF_BSD44, FF_PROF + } +File_Format; + +typedef int bool; +typedef unsigned char UNIT[2]; /* unit of profiling */ + +extern const char *whoami; /* command-name, for error messages */ +extern const char *function_mapping_file; /* file mapping functions to files */ +extern const char *a_out_name; /* core filename */ +extern long hz; /* ticks per second */ + +/* + * Command-line options: + */ +extern int debug_level; /* debug level */ +extern int output_style; +extern int output_width; /* controls column width in index */ +extern bool bsd_style_output; /* as opposed to FSF style output */ +extern bool demangle; /* demangle symbol names? */ +extern bool discard_underscores; /* discard leading underscores? */ +extern bool ignore_direct_calls; /* don't count direct calls */ +extern bool ignore_static_funcs; /* suppress static functions */ +extern bool ignore_zeros; /* ignore unused symbols/files */ +extern bool line_granularity; /* function or line granularity? */ +extern bool print_descriptions; /* output profile description */ +extern bool print_path; /* print path or just filename? */ +extern bool ignore_non_functions;/* Ignore non-function symbols. */ + +extern File_Format file_format; /* requested file format */ + +extern bool first_output; /* no output so far? */ + +extern void done PARAMS ((int status)); + +#endif /* gprof_h */ diff --git a/gprof/gprof.texi b/gprof/gprof.texi new file mode 100644 index 0000000..43d8b9f --- /dev/null +++ b/gprof/gprof.texi @@ -0,0 +1,2028 @@ +\input texinfo @c -*-texinfo-*- +@setfilename gprof.info +@settitle GNU gprof +@setchapternewpage odd + +@ifinfo +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. zoo@cygnus.com is developing this facility. +@format +START-INFO-DIR-ENTRY +* gprof: (gprof). Profiling your program's execution +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents the gprof profiler of the GNU system. + +Copyright (C) 1988, 1992, 1997, 1998, 1999 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@finalout +@smallbook + +@titlepage +@title GNU gprof +@subtitle The @sc{gnu} Profiler +@author Jay Fenlason and Richard Stallman + +@page + +This manual describes the @sc{gnu} profiler, @code{gprof}, and how you +can use it to determine which parts of a program are taking most of the +execution time. We assume that you know how to write, compile, and +execute programs. @sc{gnu} @code{gprof} was written by Jay Fenlason. + +This manual was edited January 1993 by Jeffrey Osier +and updated September 1997 by Brent Baccala. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1988, 1992, 1997, 1998 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the same conditions as for modified versions. + +@end titlepage + +@ifinfo +@node Top +@top Profiling a Program: Where Does It Spend Its Time? + +This manual describes the @sc{gnu} profiler, @code{gprof}, and how you +can use it to determine which parts of a program are taking most of the +execution time. We assume that you know how to write, compile, and +execute programs. @sc{gnu} @code{gprof} was written by Jay Fenlason. + +This manual was updated August 1997 by Brent Baccala. + +@menu +* Introduction:: What profiling means, and why it is useful. + +* Compiling:: How to compile your program for profiling. +* Executing:: Executing your program to generate profile data +* Invoking:: How to run @code{gprof}, and its options + +* Output:: Interpreting @code{gprof}'s output + +* Inaccuracy:: Potential problems you should be aware of +* How do I?:: Answers to common questions +* Incompatibilities:: (between @sc{gnu} @code{gprof} and Unix @code{gprof}.) +* Details:: Details of how profiling is done +@end menu +@end ifinfo + +@node Introduction +@chapter Introduction to Profiling + +Profiling allows you to learn where your program spent its time and which +functions called which other functions while it was executing. This +information can show you which pieces of your program are slower than you +expected, and might be candidates for rewriting to make your program +execute faster. It can also tell you which functions are being called more +or less often than you expected. This may help you spot bugs that had +otherwise been unnoticed. + +Since the profiler uses information collected during the actual execution +of your program, it can be used on programs that are too large or too +complex to analyze by reading the source. However, how your program is run +will affect the information that shows up in the profile data. If you +don't use some feature of your program while it is being profiled, no +profile information will be generated for that feature. + +Profiling has several steps: + +@itemize @bullet +@item +You must compile and link your program with profiling enabled. +@xref{Compiling}. + +@item +You must execute your program to generate a profile data file. +@xref{Executing}. + +@item +You must run @code{gprof} to analyze the profile data. +@xref{Invoking}. +@end itemize + +The next three chapters explain these steps in greater detail. + +Several forms of output are available from the analysis. + +The @dfn{flat profile} shows how much time your program spent in each function, +and how many times that function was called. If you simply want to know +which functions burn most of the cycles, it is stated concisely here. +@xref{Flat Profile}. + +The @dfn{call graph} shows, for each function, which functions called it, which +other functions it called, and how many times. There is also an estimate +of how much time was spent in the subroutines of each function. This can +suggest places where you might try to eliminate function calls that use a +lot of time. @xref{Call Graph}. + +The @dfn{annotated source} listing is a copy of the program's +source code, labeled with the number of times each line of the +program was executed. @xref{Annotated Source}. + +To better understand how profiling works, you may wish to read +a description of its implementation. +@xref{Implementation}. + +@node Compiling +@chapter Compiling a Program for Profiling + +The first step in generating profile information for your program is +to compile and link it with profiling enabled. + +To compile a source file for profiling, specify the @samp{-pg} option when +you run the compiler. (This is in addition to the options you normally +use.) + +To link the program for profiling, if you use a compiler such as @code{cc} +to do the linking, simply specify @samp{-pg} in addition to your usual +options. The same option, @samp{-pg}, alters either compilation or linking +to do what is necessary for profiling. Here are examples: + +@example +cc -g -c myprog.c utils.c -pg +cc -o myprog myprog.o utils.o -pg +@end example + +The @samp{-pg} option also works with a command that both compiles and links: + +@example +cc -o myprog myprog.c utils.c -g -pg +@end example + +If you run the linker @code{ld} directly instead of through a compiler +such as @code{cc}, you may have to specify a profiling startup file +@file{gcrt0.o} as the first input file instead of the usual startup +file @file{crt0.o}. In addition, you would probably want to +specify the profiling C library, @file{libc_p.a}, by writing +@samp{-lc_p} instead of the usual @samp{-lc}. This is not absolutely +necessary, but doing this gives you number-of-calls information for +standard library functions such as @code{read} and @code{open}. For +example: + +@example +ld -o myprog /lib/gcrt0.o myprog.o utils.o -lc_p +@end example + +If you compile only some of the modules of the program with @samp{-pg}, you +can still profile the program, but you won't get complete information about +the modules that were compiled without @samp{-pg}. The only information +you get for the functions in those modules is the total time spent in them; +there is no record of how many times they were called, or from where. This +will not affect the flat profile (except that the @code{calls} field for +the functions will be blank), but will greatly reduce the usefulness of the +call graph. + +If you wish to perform line-by-line profiling, +you will also need to specify the @samp{-g} option, +instructing the compiler to insert debugging symbols into the program +that match program addresses to source code lines. +@xref{Line-by-line}. + +In addition to the @samp{-pg} and @samp{-g} options, +you may also wish to specify the @samp{-a} option when compiling. +This will instrument +the program to perform basic-block counting. As the program runs, +it will count how many times it executed each branch of each @samp{if} +statement, each iteration of each @samp{do} loop, etc. This will +enable @code{gprof} to construct an annotated source code +listing showing how many times each line of code was executed. + +@node Executing +@chapter Executing the Program + +Once the program is compiled for profiling, you must run it in order to +generate the information that @code{gprof} needs. Simply run the program +as usual, using the normal arguments, file names, etc. The program should +run normally, producing the same output as usual. It will, however, run +somewhat slower than normal because of the time spent collecting and the +writing the profile data. + +The way you run the program---the arguments and input that you give +it---may have a dramatic effect on what the profile information shows. The +profile data will describe the parts of the program that were activated for +the particular input you use. For example, if the first command you give +to your program is to quit, the profile data will show the time used in +initialization and in cleanup, but not much else. + +Your program will write the profile data into a file called @file{gmon.out} +just before exiting. If there is already a file called @file{gmon.out}, +its contents are overwritten. There is currently no way to tell the +program to write the profile data under a different name, but you can rename +the file afterward if you are concerned that it may be overwritten. + +In order to write the @file{gmon.out} file properly, your program must exit +normally: by returning from @code{main} or by calling @code{exit}. Calling +the low-level function @code{_exit} does not write the profile data, and +neither does abnormal termination due to an unhandled signal. + +The @file{gmon.out} file is written in the program's @emph{current working +directory} at the time it exits. This means that if your program calls +@code{chdir}, the @file{gmon.out} file will be left in the last directory +your program @code{chdir}'d to. If you don't have permission to write in +this directory, the file is not written, and you will get an error message. + +Older versions of the @sc{gnu} profiling library may also write a file +called @file{bb.out}. This file, if present, contains an human-readable +listing of the basic-block execution counts. Unfortunately, the +appearance of a human-readable @file{bb.out} means the basic-block +counts didn't get written into @file{gmon.out}. +The Perl script @code{bbconv.pl}, included with the @code{gprof} +source distribution, will convert a @file{bb.out} file into +a format readable by @code{gprof}. + +@node Invoking +@chapter @code{gprof} Command Summary + +After you have a profile data file @file{gmon.out}, you can run @code{gprof} +to interpret the information in it. The @code{gprof} program prints a +flat profile and a call graph on standard output. Typically you would +redirect the output of @code{gprof} into a file with @samp{>}. + +You run @code{gprof} like this: + +@smallexample +gprof @var{options} [@var{executable-file} [@var{profile-data-files}@dots{}]] [> @var{outfile}] +@end smallexample + +@noindent +Here square-brackets indicate optional arguments. + +If you omit the executable file name, the file @file{a.out} is used. If +you give no profile data file name, the file @file{gmon.out} is used. If +any file is not in the proper format, or if the profile data file does not +appear to belong to the executable file, an error message is printed. + +You can give more than one profile data file by entering all their names +after the executable file name; then the statistics in all the data files +are summed together. + +The order of these options does not matter. + +@menu +* Output Options:: Controlling @code{gprof}'s output style +* Analysis Options:: Controlling how @code{gprof} analyses its data +* Miscellaneous Options:: +* Depricated Options:: Options you no longer need to use, but which + have been retained for compatibility +* Symspecs:: Specifying functions to include or exclude +@end menu + +@node Output Options,Analysis Options,,Invoking +@section Output Options + +These options specify which of several output formats +@code{gprof} should produce. + +Many of these options take an optional @dfn{symspec} to specify +functions to be included or excluded. These options can be +specified multiple times, with different symspecs, to include +or exclude sets of symbols. @xref{Symspecs}. + +Specifying any of these options overrides the default (@samp{-p -q}), +which prints a flat profile and call graph analysis +for all functions. + +@table @code + +@item -A[@var{symspec}] +@itemx --annotated-source[=@var{symspec}] +The @samp{-A} option causes @code{gprof} to print annotated source code. +If @var{symspec} is specified, print output only for matching symbols. +@xref{Annotated Source}. + +@item -b +@itemx --brief +If the @samp{-b} option is given, @code{gprof} doesn't print the +verbose blurbs that try to explain the meaning of all of the fields in +the tables. This is useful if you intend to print out the output, or +are tired of seeing the blurbs. + +@item -C[@var{symspec}] +@itemx --exec-counts[=@var{symspec}] +The @samp{-C} option causes @code{gprof} to +print a tally of functions and the number of times each was called. +If @var{symspec} is specified, print tally only for matching symbols. + +If the profile data file contains basic-block count records, specifing +the @samp{-l} option, along with @samp{-C}, will cause basic-block +execution counts to be tallied and displayed. + +@item -i +@itemx --file-info +The @samp{-i} option causes @code{gprof} to display summary information +about the profile data file(s) and then exit. The number of histogram, +call graph, and basic-block count records is displayed. + +@item -I @var{dirs} +@itemx --directory-path=@var{dirs} +The @samp{-I} option specifies a list of search directories in +which to find source files. Environment variable @var{GPROF_PATH} +can also be used to convery this information. +Used mostly for annotated source output. + +@item -J[@var{symspec}] +@itemx --no-annotated-source[=@var{symspec}] +The @samp{-J} option causes @code{gprof} not to +print annotated source code. +If @var{symspec} is specified, @code{gprof} prints annotated source, +but excludes matching symbols. + +@item -L +@itemx --print-path +Normally, source filenames are printed with the path +component suppressed. The @samp{-L} option causes @code{gprof} +to print the full pathname of +source filenames, which is determined +from symbolic debugging information in the image file +and is relative to the directory in which the compiler +was invoked. + +@item -p[@var{symspec}] +@itemx --flat-profile[=@var{symspec}] +The @samp{-p} option causes @code{gprof} to print a flat profile. +If @var{symspec} is specified, print flat profile only for matching symbols. +@xref{Flat Profile}. + +@item -P[@var{symspec}] +@itemx --no-flat-profile[=@var{symspec}] +The @samp{-P} option causes @code{gprof} to suppress printing a flat profile. +If @var{symspec} is specified, @code{gprof} prints a flat profile, +but excludes matching symbols. + +@item -q[@var{symspec}] +@itemx --graph[=@var{symspec}] +The @samp{-q} option causes @code{gprof} to print the call graph analysis. +If @var{symspec} is specified, print call graph only for matching symbols +and their children. +@xref{Call Graph}. + +@item -Q[@var{symspec}] +@itemx --no-graph[=@var{symspec}] +The @samp{-Q} option causes @code{gprof} to suppress printing the +call graph. +If @var{symspec} is specified, @code{gprof} prints a call graph, +but excludes matching symbols. + +@item -y +@itemx --separate-files +This option affects annotated source output only. +Normally, gprof prints annotated source files +to standard-output. If this option is specified, +annotated source for a file named @file{path/filename} +is generated in the file @file{filename-ann}. + +@item -Z[@var{symspec}] +@itemx --no-exec-counts[=@var{symspec}] +The @samp{-Z} option causes @code{gprof} not to +print a tally of functions and the number of times each was called. +If @var{symspec} is specified, print tally, but exclude matching symbols. + +@item --function-ordering +The @samp{--function-ordering} option causes @code{gprof} to print a +suggested function ordering for the program based on profiling data. +This option suggests an ordering which may improve paging, tlb and +cache behavior for the program on systems which support arbitrary +ordering of functions in an executable. + +The exact details of how to force the linker to place functions +in a particular order is system dependent and out of the scope of this +manual. + +@item --file-ordering @var{map_file} +The @samp{--file-ordering} option causes @code{gprof} to print a +suggested .o link line ordering for the program based on profiling data. +This option suggests an ordering which may improve paging, tlb and +cache behavior for the program on systems which do not support arbitrary +ordering of functions in an executable. + +Use of the @samp{-a} argument is highly recommended with this option. + +The @var{map_file} argument is a pathname to a file which provides +function name to object file mappings. The format of the file is similar to +the output of the program @code{nm}. + +@smallexample +@group +c-parse.o:00000000 T yyparse +c-parse.o:00000004 C yyerrflag +c-lang.o:00000000 T maybe_objc_method_name +c-lang.o:00000000 T print_lang_statistics +c-lang.o:00000000 T recognize_objc_keyword +c-decl.o:00000000 T print_lang_identifier +c-decl.o:00000000 T print_lang_type +@dots{} + +@end group +@end smallexample + +GNU @code{nm} @samp{--extern-only} @samp{--defined-only} @samp{-v} @samp{--print-file-name} can be used to create @var{map_file}. + +@item -T +@itemx --traditional +The @samp{-T} option causes @code{gprof} to print its output in +``traditional'' BSD style. + +@item -w @var{width} +@itemx --width=@var{width} +Sets width of output lines to @var{width}. +Currently only used when printing the function index at the bottom +of the call graph. + +@item -x +@itemx --all-lines +This option affects annotated source output only. +By default, only the lines at the beginning of a basic-block +are annotated. If this option is specified, every line in +a basic-block is annotated by repeating the annotation for the +first line. This behavior is similar to @code{tcov}'s @samp{-a}. + +@item --demangle +@itemx --no-demangle +These options control whether C++ symbol names should be demangled when +printing output. The default is to demangle symbols. The +@code{--no-demangle} option may be used to turn off demangling. + +@end table + +@node Analysis Options,Miscellaneous Options,Output Options,Invoking +@section Analysis Options + +@table @code + +@item -a +@itemx --no-static +The @samp{-a} option causes @code{gprof} to suppress the printing of +statically declared (private) functions. (These are functions whose +names are not listed as global, and which are not visible outside the +file/function/block where they were defined.) Time spent in these +functions, calls to/from them, etc, will all be attributed to the +function that was loaded directly before it in the executable file. +@c This is compatible with Unix @code{gprof}, but a bad idea. +This option affects both the flat profile and the call graph. + +@item -c +@itemx --static-call-graph +The @samp{-c} option causes the call graph of the program to be +augmented by a heuristic which examines the text space of the object +file and identifies function calls in the binary machine code. +Since normal call graph records are only generated when functions are +entered, this option identifies children that could have been called, +but never were. Calls to functions that were not compiled with +profiling enabled are also identified, but only if symbol table +entries are present for them. +Calls to dynamic library routines are typically @emph{not} found +by this option. +Parents or children identified via this heuristic +are indicated in the call graph with call counts of @samp{0}. + +@item -D +@itemx --ignore-non-functions +The @samp{-D} option causes @code{gprof} to ignore symbols which +are not known to be functions. This option will give more accurate +profile data on systems where it is supported (Solaris and HPUX for +example). + +@item -k @var{from}/@var{to} +The @samp{-k} option allows you to delete from the call graph any arcs from +symbols matching symspec @var{from} to those matching symspec @var{to}. + +@item -l +@itemx --line +The @samp{-l} option enables line-by-line profiling, which causes +histogram hits to be charged to individual source code lines, +instead of functions. +If the program was compiled with basic-block counting enabled, +this option will also identify how many times each line of +code was executed. +While line-by-line profiling can help isolate where in a large function +a program is spending its time, it also significantly increases +the running time of @code{gprof}, and magnifies statistical +inaccuracies. +@xref{Sampling Error}. + +@item -m @var{num} +@itemx --min-count=@var{num} +This option affects execution count output only. +Symbols that are executed less than @var{num} times are suppressed. + +@item -n[@var{symspec}] +@itemx --time[=@var{symspec}] +The @samp{-n} option causes @code{gprof}, in its call graph analysis, +to only propagate times for symbols matching @var{symspec}. + +@item -N[@var{symspec}] +@itemx --no-time[=@var{symspec}] +The @samp{-n} option causes @code{gprof}, in its call graph analysis, +not to propagate times for symbols matching @var{symspec}. + +@item -z +@itemx --display-unused-functions +If you give the @samp{-z} option, @code{gprof} will mention all +functions in the flat profile, even those that were never called, and +that had no time spent in them. This is useful in conjunction with the +@samp{-c} option for discovering which routines were never called. + +@end table + +@node Miscellaneous Options,Depricated Options,Analysis Options,Invoking +@section Miscellaneous Options + +@table @code + +@item -d[@var{num}] +@itemx --debug[=@var{num}] +The @samp{-d @var{num}} option specifies debugging options. +If @var{num} is not specified, enable all debugging. +@xref{Debugging}. + +@item -O@var{name} +@itemx --file-format=@var{name} +Selects the format of the profile data files. Recognized formats are +@samp{auto} (the default), @samp{bsd}, @samp{4.4bsd}, @samp{magic}, and +@samp{prof} (not yet supported). + +@item -s +@itemx --sum +The @samp{-s} option causes @code{gprof} to summarize the information +in the profile data files it read in, and write out a profile data +file called @file{gmon.sum}, which contains all the information from +the profile data files that @code{gprof} read in. The file @file{gmon.sum} +may be one of the specified input files; the effect of this is to +merge the data in the other input files into @file{gmon.sum}. + +Eventually you can run @code{gprof} again without @samp{-s} to analyze the +cumulative data in the file @file{gmon.sum}. + +@item -v +@itemx --version +The @samp{-v} flag causes @code{gprof} to print the current version +number, and then exit. + +@end table + +@node Depricated Options,Symspecs,Miscellaneous Options,Invoking +@section Depricated Options + +@table @code + +These options have been replaced with newer versions that use symspecs. + +@item -e @var{function_name} +The @samp{-e @var{function}} option tells @code{gprof} to not print +information about the function @var{function_name} (and its +children@dots{}) in the call graph. The function will still be listed +as a child of any functions that call it, but its index number will be +shown as @samp{[not printed]}. More than one @samp{-e} option may be +given; only one @var{function_name} may be indicated with each @samp{-e} +option. + +@item -E @var{function_name} +The @code{-E @var{function}} option works like the @code{-e} option, but +time spent in the function (and children who were not called from +anywhere else), will not be used to compute the percentages-of-time for +the call graph. More than one @samp{-E} option may be given; only one +@var{function_name} may be indicated with each @samp{-E} option. + +@item -f @var{function_name} +The @samp{-f @var{function}} option causes @code{gprof} to limit the +call graph to the function @var{function_name} and its children (and +their children@dots{}). More than one @samp{-f} option may be given; +only one @var{function_name} may be indicated with each @samp{-f} +option. + +@item -F @var{function_name} +The @samp{-F @var{function}} option works like the @code{-f} option, but +only time spent in the function and its children (and their +children@dots{}) will be used to determine total-time and +percentages-of-time for the call graph. More than one @samp{-F} option +may be given; only one @var{function_name} may be indicated with each +@samp{-F} option. The @samp{-F} option overrides the @samp{-E} option. + +@end table + +Note that only one function can be specified with each @code{-e}, +@code{-E}, @code{-f} or @code{-F} option. To specify more than one +function, use multiple options. For example, this command: + +@example +gprof -e boring -f foo -f bar myprogram > gprof.output +@end example + +@noindent +lists in the call graph all functions that were reached from either +@code{foo} or @code{bar} and were not reachable from @code{boring}. + +@node Symspecs,,Depricated Options,Invoking +@section Symspecs + +Many of the output options allow functions to be included or excluded +using @dfn{symspecs} (symbol specifications), which observe the +following syntax: + +@example + filename_containing_a_dot +| funcname_not_containing_a_dot +| linenumber +| ( [ any_filename ] `:' ( any_funcname | linenumber ) ) +@end example + +Here are some sample symspecs: + +@table @samp +@item main.c +Selects everything in file @file{main.c}---the +dot in the string tells gprof to interpret +the string as a filename, rather than as +a function name. To select a file whose +name does not contain a dot, a trailing colon +should be specified. For example, @samp{odd:} is +interpreted as the file named @file{odd}. + +@item main +Selects all functions named @samp{main}. + +Note that there may be multiple instances of the same function name +because some of the definitions may be local (i.e., static). Unless a +function name is unique in a program, you must use the colon notation +explained below to specify a function from a specific source file. + +Sometimes, function names contain dots. In such cases, it is necessar +to add a leading colon to the name. For example, @samp{:.mul} selects +function @samp{.mul}. + +In some object file formats, symbols have a leading underscore. gprof +will normally not print these underscores. However, you must use the +underscore when you name a symbol in a symspec. You can use the +@code{nm} program to see whether symbols have underscores for the object +file format you are using. + +@item main.c:main +Selects function @samp{main} in file @file{main.c}. + +@item main.c:134 +Selects line 134 in file @file{main.c}. +@end table + +@node Output +@chapter Interpreting @code{gprof}'s Output + +@code{gprof} can produce several different output styles, the +most important of which are described below. The simplest output +styles (file information, execution count, and function and file ordering) +are not described here, but are documented with the respective options +that trigger them. +@xref{Output Options}. + +@menu +* Flat Profile:: The flat profile shows how much time was spent + executing directly in each function. +* Call Graph:: The call graph shows which functions called which + others, and how much time each function used + when its subroutine calls are included. +* Line-by-line:: @code{gprof} can analyze individual source code lines +* Annotated Source:: The annotated source listing displays source code + labeled with execution counts +@end menu + + +@node Flat Profile,Call Graph,,Output +@section The Flat Profile +@cindex flat profile + +The @dfn{flat profile} shows the total amount of time your program +spent executing each function. Unless the @samp{-z} option is given, +functions with no apparent time spent in them, and no apparent calls +to them, are not mentioned. Note that if a function was not compiled +for profiling, and didn't run long enough to show up on the program +counter histogram, it will be indistinguishable from a function that +was never called. + +This is part of a flat profile for a small program: + +@smallexample +@group +Flat profile: + +Each sample counts as 0.01 seconds. + % cumulative self self total + time seconds seconds calls ms/call ms/call name + 33.34 0.02 0.02 7208 0.00 0.00 open + 16.67 0.03 0.01 244 0.04 0.12 offtime + 16.67 0.04 0.01 8 1.25 1.25 memccpy + 16.67 0.05 0.01 7 1.43 1.43 write + 16.67 0.06 0.01 mcount + 0.00 0.06 0.00 236 0.00 0.00 tzset + 0.00 0.06 0.00 192 0.00 0.00 tolower + 0.00 0.06 0.00 47 0.00 0.00 strlen + 0.00 0.06 0.00 45 0.00 0.00 strchr + 0.00 0.06 0.00 1 0.00 50.00 main + 0.00 0.06 0.00 1 0.00 0.00 memcpy + 0.00 0.06 0.00 1 0.00 10.11 print + 0.00 0.06 0.00 1 0.00 0.00 profil + 0.00 0.06 0.00 1 0.00 50.00 report +@dots{} +@end group +@end smallexample + +@noindent +The functions are sorted by first by decreasing run-time spent in them, +then by decreasing number of calls, then alphabetically by name. The +functions @samp{mcount} and @samp{profil} are part of the profiling +aparatus and appear in every flat profile; their time gives a measure of +the amount of overhead due to profiling. + +Just before the column headers, a statement appears indicating +how much time each sample counted as. +This @dfn{sampling period} estimates the margin of error in each of the time +figures. A time figure that is not much larger than this is not +reliable. In this example, each sample counted as 0.01 seconds, +suggesting a 100 Hz sampling rate. +The program's total execution time was 0.06 +seconds, as indicated by the @samp{cumulative seconds} field. Since +each sample counted for 0.01 seconds, this means only six samples +were taken during the run. Two of the samples occured while the +program was in the @samp{open} function, as indicated by the +@samp{self seconds} field. Each of the other four samples +occured one each in @samp{offtime}, @samp{memccpy}, @samp{write}, +and @samp{mcount}. +Since only six samples were taken, none of these values can +be regarded as particularly reliable. +In another run, +the @samp{self seconds} field for +@samp{mcount} might well be @samp{0.00} or @samp{0.02}. +@xref{Sampling Error}, for a complete discussion. + +The remaining functions in the listing (those whose +@samp{self seconds} field is @samp{0.00}) didn't appear +in the histogram samples at all. However, the call graph +indicated that they were called, so therefore they are listed, +sorted in decreasing order by the @samp{calls} field. +Clearly some time was spent executing these functions, +but the paucity of histogram samples prevents any +determination of how much time each took. + +Here is what the fields in each line mean: + +@table @code +@item % time +This is the percentage of the total execution time your program spent +in this function. These should all add up to 100%. + +@item cumulative seconds +This is the cumulative total number of seconds the computer spent +executing this functions, plus the time spent in all the functions +above this one in this table. + +@item self seconds +This is the number of seconds accounted for by this function alone. +The flat profile listing is sorted first by this number. + +@item calls +This is the total number of times the function was called. If the +function was never called, or the number of times it was called cannot +be determined (probably because the function was not compiled with +profiling enabled), the @dfn{calls} field is blank. + +@item self ms/call +This represents the average number of milliseconds spent in this +function per call, if this function is profiled. Otherwise, this field +is blank for this function. + +@item total ms/call +This represents the average number of milliseconds spent in this +function and its descendants per call, if this function is profiled. +Otherwise, this field is blank for this function. +This is the only field in the flat profile that uses call graph analysis. + +@item name +This is the name of the function. The flat profile is sorted by this +field alphabetically after the @dfn{self seconds} and @dfn{calls} +fields are sorted. +@end table + +@node Call Graph,Line-by-line,Flat Profile,Output +@section The Call Graph +@cindex call graph + +The @dfn{call graph} shows how much time was spent in each function +and its children. From this information, you can find functions that, +while they themselves may not have used much time, called other +functions that did use unusual amounts of time. + +Here is a sample call from a small program. This call came from the +same @code{gprof} run as the flat profile example in the previous +chapter. + +@smallexample +@group +granularity: each sample hit covers 2 byte(s) for 20.00% of 0.05 seconds + +index % time self children called name + +[1] 100.0 0.00 0.05 start [1] + 0.00 0.05 1/1 main [2] + 0.00 0.00 1/2 on_exit [28] + 0.00 0.00 1/1 exit [59] +----------------------------------------------- + 0.00 0.05 1/1 start [1] +[2] 100.0 0.00 0.05 1 main [2] + 0.00 0.05 1/1 report [3] +----------------------------------------------- + 0.00 0.05 1/1 main [2] +[3] 100.0 0.00 0.05 1 report [3] + 0.00 0.03 8/8 timelocal [6] + 0.00 0.01 1/1 print [9] + 0.00 0.01 9/9 fgets [12] + 0.00 0.00 12/34 strncmp [40] + 0.00 0.00 8/8 lookup [20] + 0.00 0.00 1/1 fopen [21] + 0.00 0.00 8/8 chewtime [24] + 0.00 0.00 8/16 skipspace [44] +----------------------------------------------- +[4] 59.8 0.01 0.02 8+472 [4] + 0.01 0.02 244+260 offtime [7] + 0.00 0.00 236+1 tzset [26] +----------------------------------------------- +@end group +@end smallexample + +The lines full of dashes divide this table into @dfn{entries}, one for each +function. Each entry has one or more lines. + +In each entry, the primary line is the one that starts with an index number +in square brackets. The end of this line says which function the entry is +for. The preceding lines in the entry describe the callers of this +function and the following lines describe its subroutines (also called +@dfn{children} when we speak of the call graph). + +The entries are sorted by time spent in the function and its subroutines. + +The internal profiling function @code{mcount} (@pxref{Flat Profile}) +is never mentioned in the call graph. + +@menu +* Primary:: Details of the primary line's contents. +* Callers:: Details of caller-lines' contents. +* Subroutines:: Details of subroutine-lines' contents. +* Cycles:: When there are cycles of recursion, + such as @code{a} calls @code{b} calls @code{a}@dots{} +@end menu + +@node Primary +@subsection The Primary Line + +The @dfn{primary line} in a call graph entry is the line that +describes the function which the entry is about and gives the overall +statistics for this function. + +For reference, we repeat the primary line from the entry for function +@code{report} in our main example, together with the heading line that +shows the names of the fields: + +@smallexample +@group +index % time self children called name +@dots{} +[3] 100.0 0.00 0.05 1 report [3] +@end group +@end smallexample + +Here is what the fields in the primary line mean: + +@table @code +@item index +Entries are numbered with consecutive integers. Each function +therefore has an index number, which appears at the beginning of its +primary line. + +Each cross-reference to a function, as a caller or subroutine of +another, gives its index number as well as its name. The index number +guides you if you wish to look for the entry for that function. + +@item % time +This is the percentage of the total time that was spent in this +function, including time spent in subroutines called from this +function. + +The time spent in this function is counted again for the callers of +this function. Therefore, adding up these percentages is meaningless. + +@item self +This is the total amount of time spent in this function. This +should be identical to the number printed in the @code{seconds} field +for this function in the flat profile. + +@item children +This is the total amount of time spent in the subroutine calls made by +this function. This should be equal to the sum of all the @code{self} +and @code{children} entries of the children listed directly below this +function. + +@item called +This is the number of times the function was called. + +If the function called itself recursively, there are two numbers, +separated by a @samp{+}. The first number counts non-recursive calls, +and the second counts recursive calls. + +In the example above, the function @code{report} was called once from +@code{main}. + +@item name +This is the name of the current function. The index number is +repeated after it. + +If the function is part of a cycle of recursion, the cycle number is +printed between the function's name and the index number +(@pxref{Cycles}). For example, if function @code{gnurr} is part of +cycle number one, and has index number twelve, its primary line would +be end like this: + +@example +gnurr [12] +@end example +@end table + +@node Callers, Subroutines, Primary, Call Graph +@subsection Lines for a Function's Callers + +A function's entry has a line for each function it was called by. +These lines' fields correspond to the fields of the primary line, but +their meanings are different because of the difference in context. + +For reference, we repeat two lines from the entry for the function +@code{report}, the primary line and one caller-line preceding it, together +with the heading line that shows the names of the fields: + +@smallexample +index % time self children called name +@dots{} + 0.00 0.05 1/1 main [2] +[3] 100.0 0.00 0.05 1 report [3] +@end smallexample + +Here are the meanings of the fields in the caller-line for @code{report} +called from @code{main}: + +@table @code +@item self +An estimate of the amount of time spent in @code{report} itself when it was +called from @code{main}. + +@item children +An estimate of the amount of time spent in subroutines of @code{report} +when @code{report} was called from @code{main}. + +The sum of the @code{self} and @code{children} fields is an estimate +of the amount of time spent within calls to @code{report} from @code{main}. + +@item called +Two numbers: the number of times @code{report} was called from @code{main}, +followed by the total number of nonrecursive calls to @code{report} from +all its callers. + +@item name and index number +The name of the caller of @code{report} to which this line applies, +followed by the caller's index number. + +Not all functions have entries in the call graph; some +options to @code{gprof} request the omission of certain functions. +When a caller has no entry of its own, it still has caller-lines +in the entries of the functions it calls. + +If the caller is part of a recursion cycle, the cycle number is +printed between the name and the index number. +@end table + +If the identity of the callers of a function cannot be determined, a +dummy caller-line is printed which has @samp{} as the +``caller's name'' and all other fields blank. This can happen for +signal handlers. +@c What if some calls have determinable callers' names but not all? +@c FIXME - still relevant? + +@node Subroutines, Cycles, Callers, Call Graph +@subsection Lines for a Function's Subroutines + +A function's entry has a line for each of its subroutines---in other +words, a line for each other function that it called. These lines' +fields correspond to the fields of the primary line, but their meanings +are different because of the difference in context. + +For reference, we repeat two lines from the entry for the function +@code{main}, the primary line and a line for a subroutine, together +with the heading line that shows the names of the fields: + +@smallexample +index % time self children called name +@dots{} +[2] 100.0 0.00 0.05 1 main [2] + 0.00 0.05 1/1 report [3] +@end smallexample + +Here are the meanings of the fields in the subroutine-line for @code{main} +calling @code{report}: + +@table @code +@item self +An estimate of the amount of time spent directly within @code{report} +when @code{report} was called from @code{main}. + +@item children +An estimate of the amount of time spent in subroutines of @code{report} +when @code{report} was called from @code{main}. + +The sum of the @code{self} and @code{children} fields is an estimate +of the total time spent in calls to @code{report} from @code{main}. + +@item called +Two numbers, the number of calls to @code{report} from @code{main} +followed by the total number of nonrecursive calls to @code{report}. +This ratio is used to determine how much of @code{report}'s @code{self} +and @code{children} time gets credited to @code{main}. +@xref{Assumptions}. + +@item name +The name of the subroutine of @code{main} to which this line applies, +followed by the subroutine's index number. + +If the caller is part of a recursion cycle, the cycle number is +printed between the name and the index number. +@end table + +@node Cycles,, Subroutines, Call Graph +@subsection How Mutually Recursive Functions Are Described +@cindex cycle +@cindex recursion cycle + +The graph may be complicated by the presence of @dfn{cycles of +recursion} in the call graph. A cycle exists if a function calls +another function that (directly or indirectly) calls (or appears to +call) the original function. For example: if @code{a} calls @code{b}, +and @code{b} calls @code{a}, then @code{a} and @code{b} form a cycle. + +Whenever there are call paths both ways between a pair of functions, they +belong to the same cycle. If @code{a} and @code{b} call each other and +@code{b} and @code{c} call each other, all three make one cycle. Note that +even if @code{b} only calls @code{a} if it was not called from @code{a}, +@code{gprof} cannot determine this, so @code{a} and @code{b} are still +considered a cycle. + +The cycles are numbered with consecutive integers. When a function +belongs to a cycle, each time the function name appears in the call graph +it is followed by @samp{}. + +The reason cycles matter is that they make the time values in the call +graph paradoxical. The ``time spent in children'' of @code{a} should +include the time spent in its subroutine @code{b} and in @code{b}'s +subroutines---but one of @code{b}'s subroutines is @code{a}! How much of +@code{a}'s time should be included in the children of @code{a}, when +@code{a} is indirectly recursive? + +The way @code{gprof} resolves this paradox is by creating a single entry +for the cycle as a whole. The primary line of this entry describes the +total time spent directly in the functions of the cycle. The +``subroutines'' of the cycle are the individual functions of the cycle, and +all other functions that were called directly by them. The ``callers'' of +the cycle are the functions, outside the cycle, that called functions in +the cycle. + +Here is an example portion of a call graph which shows a cycle containing +functions @code{a} and @code{b}. The cycle was entered by a call to +@code{a} from @code{main}; both @code{a} and @code{b} called @code{c}. + +@smallexample +index % time self children called name +---------------------------------------- + 1.77 0 1/1 main [2] +[3] 91.71 1.77 0 1+5 [3] + 1.02 0 3 b [4] + 0.75 0 2 a [5] +---------------------------------------- + 3 a [5] +[4] 52.85 1.02 0 0 b [4] + 2 a [5] + 0 0 3/6 c [6] +---------------------------------------- + 1.77 0 1/1 main [2] + 2 b [4] +[5] 38.86 0.75 0 1 a [5] + 3 b [4] + 0 0 3/6 c [6] +---------------------------------------- +@end smallexample + +@noindent +(The entire call graph for this program contains in addition an entry for +@code{main}, which calls @code{a}, and an entry for @code{c}, with callers +@code{a} and @code{b}.) + +@smallexample +index % time self children called name + +[1] 100.00 0 1.93 0 start [1] + 0.16 1.77 1/1 main [2] +---------------------------------------- + 0.16 1.77 1/1 start [1] +[2] 100.00 0.16 1.77 1 main [2] + 1.77 0 1/1 a [5] +---------------------------------------- + 1.77 0 1/1 main [2] +[3] 91.71 1.77 0 1+5 [3] + 1.02 0 3 b [4] + 0.75 0 2 a [5] + 0 0 6/6 c [6] +---------------------------------------- + 3 a [5] +[4] 52.85 1.02 0 0 b [4] + 2 a [5] + 0 0 3/6 c [6] +---------------------------------------- + 1.77 0 1/1 main [2] + 2 b [4] +[5] 38.86 0.75 0 1 a [5] + 3 b [4] + 0 0 3/6 c [6] +---------------------------------------- + 0 0 3/6 b [4] + 0 0 3/6 a [5] +[6] 0.00 0 0 6 c [6] +---------------------------------------- +@end smallexample + +The @code{self} field of the cycle's primary line is the total time +spent in all the functions of the cycle. It equals the sum of the +@code{self} fields for the individual functions in the cycle, found +in the entry in the subroutine lines for these functions. + +The @code{children} fields of the cycle's primary line and subroutine lines +count only subroutines outside the cycle. Even though @code{a} calls +@code{b}, the time spent in those calls to @code{b} is not counted in +@code{a}'s @code{children} time. Thus, we do not encounter the problem of +what to do when the time in those calls to @code{b} includes indirect +recursive calls back to @code{a}. + +The @code{children} field of a caller-line in the cycle's entry estimates +the amount of time spent @emph{in the whole cycle}, and its other +subroutines, on the times when that caller called a function in the cycle. + +The @code{calls} field in the primary line for the cycle has two numbers: +first, the number of times functions in the cycle were called by functions +outside the cycle; second, the number of times they were called by +functions in the cycle (including times when a function in the cycle calls +itself). This is a generalization of the usual split into nonrecursive and +recursive calls. + +The @code{calls} field of a subroutine-line for a cycle member in the +cycle's entry says how many time that function was called from functions in +the cycle. The total of all these is the second number in the primary line's +@code{calls} field. + +In the individual entry for a function in a cycle, the other functions in +the same cycle can appear as subroutines and as callers. These lines show +how many times each function in the cycle called or was called from each other +function in the cycle. The @code{self} and @code{children} fields in these +lines are blank because of the difficulty of defining meanings for them +when recursion is going on. + +@node Line-by-line,Annotated Source,Call Graph,Output +@section Line-by-line Profiling + +@code{gprof}'s @samp{-l} option causes the program to perform +@dfn{line-by-line} profiling. In this mode, histogram +samples are assigned not to functions, but to individual +lines of source code. The program usually must be compiled +with a @samp{-g} option, in addition to @samp{-pg}, in order +to generate debugging symbols for tracking source code lines. + +The flat profile is the most useful output table +in line-by-line mode. +The call graph isn't as useful as normal, since +the current version of @code{gprof} does not propagate +call graph arcs from source code lines to the enclosing function. +The call graph does, however, show each line of code +that called each function, along with a count. + +Here is a section of @code{gprof}'s output, without line-by-line profiling. +Note that @code{ct_init} accounted for four histogram hits, and +13327 calls to @code{init_block}. + +@smallexample +Flat profile: + +Each sample counts as 0.01 seconds. + % cumulative self self total + time seconds seconds calls us/call us/call name + 30.77 0.13 0.04 6335 6.31 6.31 ct_init + + + Call graph (explanation follows) + + +granularity: each sample hit covers 4 byte(s) for 7.69% of 0.13 seconds + +index % time self children called name + + 0.00 0.00 1/13496 name_too_long + 0.00 0.00 40/13496 deflate + 0.00 0.00 128/13496 deflate_fast + 0.00 0.00 13327/13496 ct_init +[7] 0.0 0.00 0.00 13496 init_block + +@end smallexample + +Now let's look at some of @code{gprof}'s output from the same program run, +this time with line-by-line profiling enabled. Note that @code{ct_init}'s +four histogram hits are broken down into four lines of source code - one hit +occured on each of lines 349, 351, 382 and 385. In the call graph, +note how +@code{ct_init}'s 13327 calls to @code{init_block} are broken down +into one call from line 396, 3071 calls from line 384, 3730 calls +from line 385, and 6525 calls from 387. + +@smallexample +Flat profile: + +Each sample counts as 0.01 seconds. + % cumulative self + time seconds seconds calls name + 7.69 0.10 0.01 ct_init (trees.c:349) + 7.69 0.11 0.01 ct_init (trees.c:351) + 7.69 0.12 0.01 ct_init (trees.c:382) + 7.69 0.13 0.01 ct_init (trees.c:385) + + + Call graph (explanation follows) + + +granularity: each sample hit covers 4 byte(s) for 7.69% of 0.13 seconds + + % time self children called name + + 0.00 0.00 1/13496 name_too_long (gzip.c:1440) + 0.00 0.00 1/13496 deflate (deflate.c:763) + 0.00 0.00 1/13496 ct_init (trees.c:396) + 0.00 0.00 2/13496 deflate (deflate.c:727) + 0.00 0.00 4/13496 deflate (deflate.c:686) + 0.00 0.00 5/13496 deflate (deflate.c:675) + 0.00 0.00 12/13496 deflate (deflate.c:679) + 0.00 0.00 16/13496 deflate (deflate.c:730) + 0.00 0.00 128/13496 deflate_fast (deflate.c:654) + 0.00 0.00 3071/13496 ct_init (trees.c:384) + 0.00 0.00 3730/13496 ct_init (trees.c:385) + 0.00 0.00 6525/13496 ct_init (trees.c:387) +[6] 0.0 0.00 0.00 13496 init_block (trees.c:408) + +@end smallexample + + +@node Annotated Source,,Line-by-line,Output +@section The Annotated Source Listing + +@code{gprof}'s @samp{-A} option triggers an annotated source listing, +which lists the program's source code, each function labeled with the +number of times it was called. You may also need to specify the +@samp{-I} option, if @code{gprof} can't find the source code files. + +Compiling with @samp{gcc @dots{} -g -pg -a} augments your program +with basic-block counting code, in addition to function counting code. +This enables @code{gprof} to determine how many times each line +of code was exeucted. +For example, consider the following function, taken from gzip, +with line numbers added: + +@smallexample + 1 ulg updcrc(s, n) + 2 uch *s; + 3 unsigned n; + 4 @{ + 5 register ulg c; + 6 + 7 static ulg crc = (ulg)0xffffffffL; + 8 + 9 if (s == NULL) @{ +10 c = 0xffffffffL; +11 @} else @{ +12 c = crc; +13 if (n) do @{ +14 c = crc_32_tab[...]; +15 @} while (--n); +16 @} +17 crc = c; +18 return c ^ 0xffffffffL; +19 @} + +@end smallexample + +@code{updcrc} has at least five basic-blocks. +One is the function itself. The +@code{if} statement on line 9 generates two more basic-blocks, one +for each branch of the @code{if}. A fourth basic-block results from +the @code{if} on line 13, and the contents of the @code{do} loop form +the fifth basic-block. The compiler may also generate additional +basic-blocks to handle various special cases. + +A program augmented for basic-block counting can be analyzed with +@code{gprof -l -A}. I also suggest use of the @samp{-x} option, +which ensures that each line of code is labeled at least once. +Here is @code{updcrc}'s +annotated source listing for a sample @code{gzip} run: + +@smallexample + ulg updcrc(s, n) + uch *s; + unsigned n; + 2 ->@{ + register ulg c; + + static ulg crc = (ulg)0xffffffffL; + + 2 -> if (s == NULL) @{ + 1 -> c = 0xffffffffL; + 1 -> @} else @{ + 1 -> c = crc; + 1 -> if (n) do @{ + 26312 -> c = crc_32_tab[...]; +26312,1,26311 -> @} while (--n); + @} + 2 -> crc = c; + 2 -> return c ^ 0xffffffffL; + 2 ->@} +@end smallexample + +In this example, the function was called twice, passing once through +each branch of the @code{if} statement. The body of the @code{do} +loop was executed a total of 26312 times. Note how the @code{while} +statement is annotated. It began execution 26312 times, once for +each iteration through the loop. One of those times (the last time) +it exited, while it branched back to the beginning of the loop 26311 times. + +@node Inaccuracy +@chapter Inaccuracy of @code{gprof} Output + +@menu +* Sampling Error:: Statistical margins of error +* Assumptions:: Estimating children times +@end menu + +@node Sampling Error,Assumptions,,Inaccuracy +@section Statistical Sampling Error + +The run-time figures that @code{gprof} gives you are based on a sampling +process, so they are subject to statistical inaccuracy. If a function runs +only a small amount of time, so that on the average the sampling process +ought to catch that function in the act only once, there is a pretty good +chance it will actually find that function zero times, or twice. + +By contrast, the number-of-calls and basic-block figures +are derived by counting, not +sampling. They are completely accurate and will not vary from run to run +if your program is deterministic. + +The @dfn{sampling period} that is printed at the beginning of the flat +profile says how often samples are taken. The rule of thumb is that a +run-time figure is accurate if it is considerably bigger than the sampling +period. + +The actual amount of error can be predicted. +For @var{n} samples, the @emph{expected} error +is the square-root of @var{n}. For example, +if the sampling period is 0.01 seconds and @code{foo}'s run-time is 1 second, +@var{n} is 100 samples (1 second/0.01 seconds), sqrt(@var{n}) is 10 samples, so +the expected error in @code{foo}'s run-time is 0.1 seconds (10*0.01 seconds), +or ten percent of the observed value. +Again, if the sampling period is 0.01 seconds and @code{bar}'s run-time is +100 seconds, @var{n} is 10000 samples, sqrt(@var{n}) is 100 samples, so +the expected error in @code{bar}'s run-time is 1 second, +or one percent of the observed value. +It is likely to +vary this much @emph{on the average} from one profiling run to the next. +(@emph{Sometimes} it will vary more.) + +This does not mean that a small run-time figure is devoid of information. +If the program's @emph{total} run-time is large, a small run-time for one +function does tell you that that function used an insignificant fraction of +the whole program's time. Usually this means it is not worth optimizing. + +One way to get more accuracy is to give your program more (but similar) +input data so it will take longer. Another way is to combine the data from +several runs, using the @samp{-s} option of @code{gprof}. Here is how: + +@enumerate +@item +Run your program once. + +@item +Issue the command @samp{mv gmon.out gmon.sum}. + +@item +Run your program again, the same as before. + +@item +Merge the new data in @file{gmon.out} into @file{gmon.sum} with this command: + +@example +gprof -s @var{executable-file} gmon.out gmon.sum +@end example + +@item +Repeat the last two steps as often as you wish. + +@item +Analyze the cumulative data using this command: + +@example +gprof @var{executable-file} gmon.sum > @var{output-file} +@end example +@end enumerate + +@node Assumptions,,Sampling Error,Inaccuracy +@section Estimating @code{children} Times + +Some of the figures in the call graph are estimates---for example, the +@code{children} time values and all the the time figures in caller and +subroutine lines. + +There is no direct information about these measurements in the profile +data itself. Instead, @code{gprof} estimates them by making an assumption +about your program that might or might not be true. + +The assumption made is that the average time spent in each call to any +function @code{foo} is not correlated with who called @code{foo}. If +@code{foo} used 5 seconds in all, and 2/5 of the calls to @code{foo} came +from @code{a}, then @code{foo} contributes 2 seconds to @code{a}'s +@code{children} time, by assumption. + +This assumption is usually true enough, but for some programs it is far +from true. Suppose that @code{foo} returns very quickly when its argument +is zero; suppose that @code{a} always passes zero as an argument, while +other callers of @code{foo} pass other arguments. In this program, all the +time spent in @code{foo} is in the calls from callers other than @code{a}. +But @code{gprof} has no way of knowing this; it will blindly and +incorrectly charge 2 seconds of time in @code{foo} to the children of +@code{a}. + +@c FIXME - has this been fixed? +We hope some day to put more complete data into @file{gmon.out}, so that +this assumption is no longer needed, if we can figure out how. For the +nonce, the estimated figures are usually more useful than misleading. + +@node How do I? +@chapter Answers to Common Questions + +@table @asis +@item How do I find which lines in my program were executed the most times? + +Compile your program with basic-block counting enabled, run it, then +use the following pipeline: + +@example +gprof -l -C @var{objfile} | sort -k 3 -n -r +@end example + +This listing will show you the lines in your code executed most often, +but not necessarily those that consumed the most time. + +@item How do I find which lines in my program called a particular function? + +Use @code{gprof -l} and lookup the function in the call graph. +The callers will be broken down by function and line number. + +@item How do I analyze a program that runs for less than a second? + +Try using a shell script like this one: + +@example +for i in `seq 1 100`; do + fastprog + mv gmon.out gmon.out.$i +done + +gprof -s fastprog gmon.out.* + +gprof fastprog gmon.sum +@end example + +If your program is completely deterministic, all the call counts +will be simple multiples of 100 (i.e. a function called once in +each run will appear with a call count of 100). + +@end table + +@node Incompatibilities +@chapter Incompatibilities with Unix @code{gprof} + +@sc{gnu} @code{gprof} and Berkeley Unix @code{gprof} use the same data +file @file{gmon.out}, and provide essentially the same information. But +there are a few differences. + +@itemize @bullet +@item +@sc{gnu} @code{gprof} uses a new, generalized file format with support +for basic-block execution counts and non-realtime histograms. A magic +cookie and version number allows @code{gprof} to easily identify +new style files. Old BSD-style files can still be read. +@xref{File Format}. + +@item +For a recursive function, Unix @code{gprof} lists the function as a +parent and as a child, with a @code{calls} field that lists the number +of recursive calls. @sc{gnu} @code{gprof} omits these lines and puts +the number of recursive calls in the primary line. + +@item +When a function is suppressed from the call graph with @samp{-e}, @sc{gnu} +@code{gprof} still lists it as a subroutine of functions that call it. + +@item +@sc{gnu} @code{gprof} accepts the @samp{-k} with its argument +in the form @samp{from/to}, instead of @samp{from to}. + +@item +In the annotated source listing, +if there are multiple basic blocks on the same line, +@sc{gnu} @code{gprof} prints all of their counts, seperated by commas. + +@ignore - it does this now +@item +The function names printed in @sc{gnu} @code{gprof} output do not include +the leading underscores that are added internally to the front of all +C identifiers on many operating systems. +@end ignore + +@item +The blurbs, field widths, and output formats are different. @sc{gnu} +@code{gprof} prints blurbs after the tables, so that you can see the +tables without skipping the blurbs. +@end itemize + +@node Details +@chapter Details of Profiling + +@menu +* Implementation:: How a program collets profiling information +* File Format:: Format of @samp{gmon.out} files +* Internals:: @code{gprof}'s internal operation +* Debugging:: Using @code{gprof}'s @samp{-d} option +@end menu + +@node Implementation,File Format,,Details +@section Implementation of Profiling + +Profiling works by changing how every function in your program is compiled +so that when it is called, it will stash away some information about where +it was called from. From this, the profiler can figure out what function +called it, and can count how many times it was called. This change is made +by the compiler when your program is compiled with the @samp{-pg} option, +which causes every function to call @code{mcount} +(or @code{_mcount}, or @code{__mcount}, depending on the OS and compiler) +as one of its first operations. + +The @code{mcount} routine, included in the profiling library, +is responsible for recording in an in-memory call graph table +both its parent routine (the child) and its parent's parent. This is +typically done by examining the stack frame to find both +the address of the child, and the return address in the original parent. +Since this is a very machine-dependant operation, @code{mcount} +itself is typically a short assembly-language stub routine +that extracts the required +information, and then calls @code{__mcount_internal} +(a normal C function) with two arguments - @code{frompc} and @code{selfpc}. +@code{__mcount_internal} is responsible for maintaining +the in-memory call graph, which records @code{frompc}, @code{selfpc}, +and the number of times each of these call arcs was transversed. + +GCC Version 2 provides a magical function (@code{__builtin_return_address}), +which allows a generic @code{mcount} function to extract the +required information from the stack frame. However, on some +architectures, most notably the SPARC, using this builtin can be +very computationally expensive, and an assembly language version +of @code{mcount} is used for performance reasons. + +Number-of-calls information for library routines is collected by using a +special version of the C library. The programs in it are the same as in +the usual C library, but they were compiled with @samp{-pg}. If you +link your program with @samp{gcc @dots{} -pg}, it automatically uses the +profiling version of the library. + +Profiling also involves watching your program as it runs, and keeping a +histogram of where the program counter happens to be every now and then. +Typically the program counter is looked at around 100 times per second of +run time, but the exact frequency may vary from system to system. + +This is done is one of two ways. Most UNIX-like operating systems +provide a @code{profil()} system call, which registers a memory +array with the kernel, along with a scale +factor that determines how the program's address space maps +into the array. +Typical scaling values cause every 2 to 8 bytes of address space +to map into a single array slot. +On every tick of the system clock +(assuming the profiled program is running), the value of the +program counter is examined and the corresponding slot in +the memory array is incremented. Since this is done in the kernel, +which had to interrupt the process anyway to handle the clock +interrupt, very little additional system overhead is required. + +However, some operating systems, most notably Linux 2.0 (and earlier), +do not provide a @code{profil()} system call. On such a system, +arrangements are made for the kernel to periodically deliver +a signal to the process (typically via @code{setitimer()}), +which then performs the same operation of examining the +program counter and incrementing a slot in the memory array. +Since this method requires a signal to be delivered to +user space every time a sample is taken, it uses considerably +more overhead than kernel-based profiling. Also, due to the +added delay required to deliver the signal, this method is +less accurate as well. + +A special startup routine allocates memory for the histogram and +either calls @code{profil()} or sets up +a clock signal handler. +This routine (@code{monstartup}) can be invoked in several ways. +On Linux systems, a special profiling startup file @code{gcrt0.o}, +which invokes @code{monstartup} before @code{main}, +is used instead of the default @code{crt0.o}. +Use of this special startup file is one of the effects +of using @samp{gcc @dots{} -pg} to link. +On SPARC systems, no special startup files are used. +Rather, the @code{mcount} routine, when it is invoked for +the first time (typically when @code{main} is called), +calls @code{monstartup}. + +If the compiler's @samp{-a} option was used, basic-block counting +is also enabled. Each object file is then compiled with a static array +of counts, initially zero. +In the executable code, every time a new basic-block begins +(i.e. when an @code{if} statement appears), an extra instruction +is inserted to increment the corresponding count in the array. +At compile time, a paired array was constructed that recorded +the starting address of each basic-block. Taken together, +the two arrays record the starting address of every basic-block, +along with the number of times it was executed. + +The profiling library also includes a function (@code{mcleanup}) which is +typically registered using @code{atexit()} to be called as the +program exits, and is responsible for writing the file @file{gmon.out}. +Profiling is turned off, various headers are output, and the histogram +is written, followed by the call-graph arcs and the basic-block counts. + +The output from @code{gprof} gives no indication of parts of your program that +are limited by I/O or swapping bandwidth. This is because samples of the +program counter are taken at fixed intervals of the program's run time. +Therefore, the +time measurements in @code{gprof} output say nothing about time that your +program was not running. For example, a part of the program that creates +so much data that it cannot all fit in physical memory at once may run very +slowly due to thrashing, but @code{gprof} will say it uses little time. On +the other hand, sampling by run time has the advantage that the amount of +load due to other users won't directly affect the output you get. + +@node File Format,Internals,Implementation,Details +@section Profiling Data File Format + +The old BSD-derived file format used for profile data does not contain a +magic cookie that allows to check whether a data file really is a +gprof file. Furthermore, it does not provide a version number, thus +rendering changes to the file format almost impossible. @sc{gnu} @code{gprof} +uses a new file format that provides these features. For backward +compatibility, @sc{gnu} @code{gprof} continues to support the old BSD-derived +format, but not all features are supported with it. For example, +basic-block execution counts cannot be accommodated by the old file +format. + +The new file format is defined in header file @file{gmon_out.h}. It +consists of a header containing the magic cookie and a version number, +as well as some spare bytes available for future extensions. All data +in a profile data file is in the native format of the host on which +the profile was collected. @sc{gnu} @code{gprof} adapts automatically to the +byte-order in use. + +In the new file format, the header is followed by a sequence of +records. Currently, there are three different record types: histogram +records, call-graph arc records, and basic-block execution count +records. Each file can contain any number of each record type. When +reading a file, @sc{gnu} @code{gprof} will ensure records of the same type are +compatible with each other and compute the union of all records. For +example, for basic-block execution counts, the union is simply the sum +of all execution counts for each basic-block. + +@subsection Histogram Records + +Histogram records consist of a header that is followed by an array of +bins. The header contains the text-segment range that the histogram +spans, the size of the histogram in bytes (unlike in the old BSD +format, this does not include the size of the header), the rate of the +profiling clock, and the physical dimension that the bin counts +represent after being scaled by the profiling clock rate. The +physical dimension is specified in two parts: a long name of up to 15 +characters and a single character abbreviation. For example, a +histogram representing real-time would specify the long name as +"seconds" and the abbreviation as "s". This feature is useful for +architectures that support performance monitor hardware (which, +fortunately, is becoming increasingly common). For example, under DEC +OSF/1, the "uprofile" command can be used to produce a histogram of, +say, instruction cache misses. In this case, the dimension in the +histogram header could be set to "i-cache misses" and the abbreviation +could be set to "1" (because it is simply a count, not a physical +dimension). Also, the profiling rate would have to be set to 1 in +this case. + +Histogram bins are 16-bit numbers and each bin represent an equal +amount of text-space. For example, if the text-segment is one +thousand bytes long and if there are ten bins in the histogram, each +bin represents one hundred bytes. + + +@subsection Call-Graph Records + +Call-graph records have a format that is identical to the one used in +the BSD-derived file format. It consists of an arc in the call graph +and a count indicating the number of times the arc was traversed +during program execution. Arcs are specified by a pair of addresses: +the first must be within caller's function and the second must be +within the callee's function. When performing profiling at the +function level, these addresses can point anywhere within the +respective function. However, when profiling at the line-level, it is +better if the addresses are as close to the call-site/entry-point as +possible. This will ensure that the line-level call-graph is able to +identify exactly which line of source code performed calls to a +function. + +@subsection Basic-Block Execution Count Records + +Basic-block execution count records consist of a header followed by a +sequence of address/count pairs. The header simply specifies the +length of the sequence. In an address/count pair, the address +identifies a basic-block and the count specifies the number of times +that basic-block was executed. Any address within the basic-address can +be used. + +@node Internals,Debugging,File Format,Details +@section @code{gprof}'s Internal Operation + +Like most programs, @code{gprof} begins by processing its options. +During this stage, it may building its symspec list +(@code{sym_ids.c:sym_id_add}), if +options are specified which use symspecs. +@code{gprof} maintains a single linked list of symspecs, +which will eventually get turned into 12 symbol tables, +organized into six include/exclude pairs - one +pair each for the flat profile (INCL_FLAT/EXCL_FLAT), +the call graph arcs (INCL_ARCS/EXCL_ARCS), +printing in the call graph (INCL_GRAPH/EXCL_GRAPH), +timing propagation in the call graph (INCL_TIME/EXCL_TIME), +the annotated source listing (INCL_ANNO/EXCL_ANNO), +and the execution count listing (INCL_EXEC/EXCL_EXEC). + +After option processing, @code{gprof} finishes +building the symspec list by adding all the symspecs in +@code{default_excluded_list} to the exclude lists +EXCL_TIME and EXCL_GRAPH, and if line-by-line profiling is specified, +EXCL_FLAT as well. +These default excludes are not added to EXCL_ANNO, EXCL_ARCS, and EXCL_EXEC. + +Next, the BFD library is called to open the object file, +verify that it is an object file, +and read its symbol table (@code{core.c:core_init}), +using @code{bfd_canonicalize_symtab} after mallocing +an appropiate sized array of asymbols. At this point, +function mappings are read (if the @samp{--file-ordering} option +has been specified), and the core text space is read into +memory (if the @samp{-c} option was given). + +@code{gprof}'s own symbol table, an array of Sym structures, +is now built. +This is done in one of two ways, by one of two routines, depending +on whether line-by-line profiling (@samp{-l} option) has been +enabled. +For normal profiling, the BFD canonical symbol table is scanned. +For line-by-line profiling, every +text space address is examined, and a new symbol table entry +gets created every time the line number changes. +In either case, two passes are made through the symbol +table - one to count the size of the symbol table required, +and the other to actually read the symbols. In between the +two passes, a single array of type @code{Sym} is created of +the appropiate length. +Finally, @code{symtab.c:symtab_finalize} +is called to sort the symbol table and remove duplicate entries +(entries with the same memory address). + +The symbol table must be a contiguous array for two reasons. +First, the @code{qsort} library function (which sorts an array) +will be used to sort the symbol table. +Also, the symbol lookup routine (@code{symtab.c:sym_lookup}), +which finds symbols +based on memory address, uses a binary search algorithm +which requires the symbol table to be a sorted array. +Function symbols are indicated with an @code{is_func} flag. +Line number symbols have no special flags set. +Additionally, a symbol can have an @code{is_static} flag +to indicate that it is a local symbol. + +With the symbol table read, the symspecs can now be translated +into Syms (@code{sym_ids.c:sym_id_parse}). Remember that a single +symspec can match multiple symbols. +An array of symbol tables +(@code{syms}) is created, each entry of which is a symbol table +of Syms to be included or excluded from a particular listing. +The master symbol table and the symspecs are examined by nested +loops, and every symbol that matches a symspec is inserted +into the appropriate syms table. This is done twice, once to +count the size of each required symbol table, and again to build +the tables, which have been malloced between passes. +From now on, to determine whether a symbol is on an include +or exclude symspec list, @code{gprof} simply uses its +standard symbol lookup routine on the appropriate table +in the @code{syms} array. + +Now the profile data file(s) themselves are read +(@code{gmon_io.c:gmon_out_read}), +first by checking for a new-style @samp{gmon.out} header, +then assuming this is an old-style BSD @samp{gmon.out} +if the magic number test failed. + +New-style histogram records are read by @code{hist.c:hist_read_rec}. +For the first histogram record, allocate a memory array to hold +all the bins, and read them in. +When multiple profile data files (or files with multiple histogram +records) are read, the starting address, ending address, number +of bins and sampling rate must match between the various histograms, +or a fatal error will result. +If everything matches, just sum the additional histograms into +the existing in-memory array. + +As each call graph record is read (@code{call_graph.c:cg_read_rec}), +the parent and child addresses +are matched to symbol table entries, and a call graph arc is +created by @code{cg_arcs.c:arc_add}, unless the arc fails a symspec +check against INCL_ARCS/EXCL_ARCS. As each arc is added, +a linked list is maintained of the parent's child arcs, and of the child's +parent arcs. +Both the child's call count and the arc's call count are +incremented by the record's call count. + +Basic-block records are read (@code{basic_blocks.c:bb_read_rec}), +but only if line-by-line profiling has been selected. +Each basic-block address is matched to a corresponding line +symbol in the symbol table, and an entry made in the symbol's +bb_addr and bb_calls arrays. Again, if multiple basic-block +records are present for the same address, the call counts +are cumulative. + +A gmon.sum file is dumped, if requested (@code{gmon_io.c:gmon_out_write}). + +If histograms were present in the data files, assign them to symbols +(@code{hist.c:hist_assign_samples}) by iterating over all the sample +bins and assigning them to symbols. Since the symbol table +is sorted in order of ascending memory addresses, we can +simple follow along in the symbol table as we make our pass +over the sample bins. +This step includes a symspec check against INCL_FLAT/EXCL_FLAT. +Depending on the histogram +scale factor, a sample bin may span multiple symbols, +in which case a fraction of the sample count is allocated +to each symbol, proportional to the degree of overlap. +This effect is rare for normal profiling, but overlaps +are more common during line-by-line profiling, and can +cause each of two adjacent lines to be credited with half +a hit, for example. + +If call graph data is present, @code{cg_arcs.c:cg_assemble} is called. +First, if @samp{-c} was specified, a machine-dependant +routine (@code{find_call}) scans through each symbol's machine code, +looking for subroutine call instructions, and adding them +to the call graph with a zero call count. +A topological sort is performed by depth-first numbering +all the symbols (@code{cg_dfn.c:cg_dfn}), so that +children are always numbered less than their parents, +then making a array of pointers into the symbol table and sorting it into +numerical order, which is reverse topological +order (children appear before parents). +Cycles are also detected at this point, all members +of which are assigned the same topological number. +Two passes are now made through this sorted array of symbol pointers. +The first pass, from end to beginning (parents to children), +computes the fraction of child time to propogate to each parent +and a print flag. +The print flag reflects symspec handling of INCL_GRAPH/EXCL_GRAPH, +with a parent's include or exclude (print or no print) property +being propagated to its children, unless they themselves explicitly appear +in INCL_GRAPH or EXCL_GRAPH. +A second pass, from beginning to end (children to parents) actually +propogates the timings along the call graph, subject +to a check against INCL_TIME/EXCL_TIME. +With the print flag, fractions, and timings now stored in the symbol +structures, the topological sort array is now discarded, and a +new array of pointers is assembled, this time sorted by propagated time. + +Finally, print the various outputs the user requested, which is now fairly +straightforward. The call graph (@code{cg_print.c:cg_print}) and +flat profile (@code{hist.c:hist_print}) are regurgitations of values +already computed. The annotated source listing +(@code{basic_blocks.c:print_annotated_source}) uses basic-block +information, if present, to label each line of code with call counts, +otherwise only the function call counts are presented. + +The function ordering code is marginally well documented +in the source code itself (@code{cg_print.c}). Basically, +the functions with the most use and the most parents are +placed first, followed by other functions with the most use, +followed by lower use functions, followed by unused functions +at the end. + +@node Debugging,,Internals,Details +@subsection Debugging @code{gprof} + +If @code{gprof} was compiled with debugging enabled, +the @samp{-d} option triggers debugging output +(to stdout) which can be helpful in understanding its operation. +The debugging number specified is interpreted as a sum of the following +options: + +@table @asis +@item 2 - Topological sort +Monitor depth-first numbering of symbols during call graph analysis +@item 4 - Cycles +Shows symbols as they are identified as cycle heads +@item 16 - Tallying +As the call graph arcs are read, show each arc and how +the total calls to each function are tallied +@item 32 - Call graph arc sorting +Details sorting individual parents/children within each call graph entry +@item 64 - Reading histogram and call graph records +Shows address ranges of histograms as they are read, and each +call graph arc +@item 128 - Symbol table +Reading, classifying, and sorting the symbol table from the object file. +For line-by-line profiling (@samp{-l} option), also shows line numbers +being assigned to memory addresses. +@item 256 - Static call graph +Trace operation of @samp{-c} option +@item 512 - Symbol table and arc table lookups +Detail operation of lookup routines +@item 1024 - Call graph propagation +Shows how function times are propagated along the call graph +@item 2048 - Basic-blocks +Shows basic-block records as they are read from profile data +(only meaningful with @samp{-l} option) +@item 4096 - Symspecs +Shows symspec-to-symbol pattern matching operation +@item 8192 - Annotate source +Tracks operation of @samp{-A} option +@end table + +@contents +@bye + +NEEDS AN INDEX + +-T - "traditional BSD style": How is it different? Should the +differences be documented? + +example flat file adds up to 100.01%... + +note: time estimates now only go out to one decimal place (0.0), where +they used to extend two (78.67). diff --git a/gprof/hertz.c b/gprof/hertz.c new file mode 100644 index 0000000..75314ac --- /dev/null +++ b/gprof/hertz.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1983 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. + */ +#include "hertz.h" + + +#ifdef __MSDOS__ +#define HERTZ 18 +#endif + +int +hertz () +{ +#ifdef HERTZ + return HERTZ; +#else /* ! defined (HERTZ) */ +#ifdef HAVE_SETITIMER + struct itimerval tim; + + tim.it_interval.tv_sec = 0; + tim.it_interval.tv_usec = 1; + tim.it_value.tv_sec = 0; + tim.it_value.tv_usec = 0; + setitimer (ITIMER_REAL, &tim, 0); + setitimer (ITIMER_REAL, 0, &tim); + if (tim.it_interval.tv_usec < 2) + { + return HZ_WRONG; + } + return 1000000 / tim.it_interval.tv_usec; +#else /* ! defined (HAVE_SETITIMER) */ +#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK) + return sysconf (_SC_CLK_TCK); +#else /* ! defined (HAVE_SYSCONF) || ! defined (_SC_CLK_TCK) */ + return HZ_WRONG; +#endif /* ! defined (HAVE_SYSCONF) || ! defined (_SC_CLK_TCK) */ +#endif /* ! defined (HAVE_SETITIMER) */ +#endif /* ! defined (HERTZ) */ +} diff --git a/gprof/hertz.h b/gprof/hertz.h new file mode 100644 index 0000000..2ea01ba --- /dev/null +++ b/gprof/hertz.h @@ -0,0 +1,22 @@ +#ifndef hertz_h +#define hertz_h + +#include "gprof.h" + +#define HZ_WRONG 0 /* impossible clock frequency */ + +/* + * Discover the tick frequency of the machine if something goes wrong, + * we return HZ_WRONG, an impossible sampling frequency. + */ + +/* FIXME: Checking for MACH here makes no sense when for a cross + gprof. */ +#ifdef MACH +#include +#define hertz() (HZ) +#else +extern int hertz PARAMS ((void)); +#endif + +#endif /* hertz_h */ diff --git a/gprof/hist.c b/gprof/hist.c new file mode 100644 index 0000000..5cdbbbb --- /dev/null +++ b/gprof/hist.c @@ -0,0 +1,596 @@ +/* + * Histogram related operations. + */ +#include +#include "libiberty.h" +#include "gprof.h" +#include "corefile.h" +#include "gmon_io.h" +#include "gmon_out.h" +#include "hist.h" +#include "symtab.h" +#include "sym_ids.h" +#include "utils.h" + +#define UNITS_TO_CODE (offset_to_code / sizeof(UNIT)) + +static void scale_and_align_entries PARAMS ((void)); + +/* declarations of automatically generated functions to output blurbs: */ +extern void flat_blurb PARAMS ((FILE * fp)); + +bfd_vma s_lowpc; /* lowest address in .text */ +bfd_vma s_highpc = 0; /* highest address in .text */ +bfd_vma lowpc, highpc; /* same, but expressed in UNITs */ +int hist_num_bins = 0; /* number of histogram samples */ +int *hist_sample = 0; /* histogram samples (shorts in the file!) */ +double hist_scale; +char hist_dimension[sizeof (((struct gmon_hist_hdr *) 0)->dimen) + 1] = + "seconds"; +char hist_dimension_abbrev = 's'; + +static double accum_time; /* accumulated time so far for print_line() */ +static double total_time; /* total time for all routines */ +/* + * Table of SI prefixes for powers of 10 (used to automatically + * scale some of the values in the flat profile). + */ +const struct + { + char prefix; + double scale; + } +SItab[] = +{ + { + 'T', 1e-12 + } + , /* tera */ + { + 'G', 1e-09 + } + , /* giga */ + { + 'M', 1e-06 + } + , /* mega */ + { + 'K', 1e-03 + } + , /* kilo */ + { + ' ', 1e-00 + } + , + { + 'm', 1e+03 + } + , /* milli */ + { + 'u', 1e+06 + } + , /* micro */ + { + 'n', 1e+09 + } + , /* nano */ + { + 'p', 1e+12 + } + , /* pico */ + { + 'f', 1e+15 + } + , /* femto */ + { + 'a', 1e+18 + } + , /* ato */ +}; + +/* + * Read the histogram from file IFP. FILENAME is the name of IFP and + * is provided for formatting error messages only. + */ +void +DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename) +{ + struct gmon_hist_hdr hdr; + bfd_vma n_lowpc, n_highpc; + int i, ncnt, profrate; + UNIT count; + + if (fread (&hdr, sizeof (hdr), 1, ifp) != 1) + { + fprintf (stderr, _("%s: %s: unexpected end of file\n"), + whoami, filename); + done (1); + } + + n_lowpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.low_pc); + n_highpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.high_pc); + ncnt = bfd_get_32 (core_bfd, (bfd_byte *) hdr.hist_size); + profrate = bfd_get_32 (core_bfd, (bfd_byte *) hdr.prof_rate); + strncpy (hist_dimension, hdr.dimen, sizeof (hdr.dimen)); + hist_dimension[sizeof (hdr.dimen)] = '\0'; + hist_dimension_abbrev = hdr.dimen_abbrev; + + if (!s_highpc) + { + + /* this is the first histogram record: */ + + s_lowpc = n_lowpc; + s_highpc = n_highpc; + lowpc = (bfd_vma) n_lowpc / sizeof (UNIT); + highpc = (bfd_vma) n_highpc / sizeof (UNIT); + hist_num_bins = ncnt; + hz = profrate; + } + + DBG (SAMPLEDEBUG, + printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %d\n", + n_lowpc, n_highpc, ncnt); + printf ("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %d\n", + s_lowpc, s_highpc, hist_num_bins); + printf ("[hist_read_rec] lowpc 0x%lx highpc 0x%lx\n", + lowpc, highpc)); + + if (n_lowpc != s_lowpc || n_highpc != s_highpc + || ncnt != hist_num_bins || hz != profrate) + { + fprintf (stderr, _("%s: `%s' is incompatible with first gmon file\n"), + whoami, filename); + done (1); + } + + if (!hist_sample) + { + hist_sample = (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0])); + memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0])); + } + + for (i = 0; i < hist_num_bins; ++i) + { + if (fread (&count[0], sizeof (count), 1, ifp) != 1) + { + fprintf (stderr, + _("%s: %s: unexpected EOF after reading %d of %d samples\n"), + whoami, filename, i, hist_num_bins); + done (1); + } + hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]); + } +} + + +/* + * Write execution histogram to file OFP. FILENAME is the name + * of OFP and is provided for formatting error-messages only. + */ +void +DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename) +{ + struct gmon_hist_hdr hdr; + unsigned char tag; + UNIT count; + int i; + + /* write header: */ + + tag = GMON_TAG_TIME_HIST; + put_vma (core_bfd, s_lowpc, (bfd_byte *) hdr.low_pc); + put_vma (core_bfd, s_highpc, (bfd_byte *) hdr.high_pc); + bfd_put_32 (core_bfd, hist_num_bins, (bfd_byte *) hdr.hist_size); + bfd_put_32 (core_bfd, hz, (bfd_byte *) hdr.prof_rate); + strncpy (hdr.dimen, hist_dimension, sizeof (hdr.dimen)); + hdr.dimen_abbrev = hist_dimension_abbrev; + + if (fwrite (&tag, sizeof (tag), 1, ofp) != 1 + || fwrite (&hdr, sizeof (hdr), 1, ofp) != 1) + { + perror (filename); + done (1); + } + + for (i = 0; i < hist_num_bins; ++i) + { + bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & count[0]); + if (fwrite (&count[0], sizeof (count), 1, ofp) != 1) + { + perror (filename); + done (1); + } + } +} + + +/* + * Calculate scaled entry point addresses (to save time in + * hist_assign_samples), and, on architectures that have procedure + * entry masks at the start of a function, possibly push the scaled + * entry points over the procedure entry mask, if it turns out that + * the entry point is in one bin and the code for a routine is in the + * next bin. + */ +static void +scale_and_align_entries () +{ + Sym *sym; + bfd_vma bin_of_entry; + bfd_vma bin_of_code; + + for (sym = symtab.base; sym < symtab.limit; sym++) + { + sym->hist.scaled_addr = sym->addr / sizeof (UNIT); + bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale; + bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale; + if (bin_of_entry < bin_of_code) + { + DBG (SAMPLEDEBUG, + printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n", + sym->hist.scaled_addr, + sym->hist.scaled_addr + UNITS_TO_CODE)); + sym->hist.scaled_addr += UNITS_TO_CODE; + } + } +} + + +/* + * Assign samples to the symbol to which they belong. + * + * Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC) + * which may overlap one more symbol address ranges. If a symbol + * overlaps with the bin's address range by O percent, then O percent + * of the bin's count is credited to that symbol. + * + * There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be + * with respect to the symbol's address range [SYM_LOW_PC, + * SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes + * the distance (in UNITs) between the arrows, the fraction of the + * sample that is to be credited to the symbol which starts at + * SYM_LOW_PC. + * + * sym_low_pc sym_high_pc + * | | + * v v + * + * +-----------------------------------------------+ + * | | + * | ->| |<- ->| |<- ->| |<- | + * | | | | | | + * +---------+ +---------+ +---------+ + * + * ^ ^ ^ ^ ^ ^ + * | | | | | | + * bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc + * + * 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 call + * scale_and_align_entries() to adjust the entry points if the entry + * mask falls in one bin but the code for the routine doesn't start + * until the next bin. 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). + */ +void +DEFUN_VOID (hist_assign_samples) +{ + bfd_vma bin_low_pc, bin_high_pc; + bfd_vma sym_low_pc, sym_high_pc; + bfd_vma overlap, addr; + int bin_count, i; + unsigned int j; + double time, credit; + + /* read samples and assign to symbols: */ + hist_scale = highpc - lowpc; + hist_scale /= hist_num_bins; + scale_and_align_entries (); + + /* iterate over all sample bins: */ + + for (i = 0, j = 1; i < hist_num_bins; ++i) + { + bin_count = hist_sample[i]; + if (!bin_count) + { + continue; + } + bin_low_pc = lowpc + (bfd_vma) (hist_scale * i); + bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1)); + time = bin_count; + DBG (SAMPLEDEBUG, + printf ( + "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%d\n", + sizeof (UNIT) * bin_low_pc, sizeof (UNIT) * bin_high_pc, + bin_count)); + total_time += time; + + /* credit all symbols that are covered by bin I: */ + + for (j = j - 1; j < symtab.len; ++j) + { + sym_low_pc = symtab.base[j].hist.scaled_addr; + sym_high_pc = symtab.base[j + 1].hist.scaled_addr; + /* + * If high end of bin is below entry address, go for next + * bin: + */ + if (bin_high_pc < sym_low_pc) + { + break; + } + /* + * If low end of bin is above high end of symbol, go for + * next symbol. + */ + if (bin_low_pc >= sym_high_pc) + { + continue; + } + overlap = + MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc); + if (overlap > 0) + { + DBG (SAMPLEDEBUG, + printf ( + "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n", + symtab.base[j].addr, sizeof (UNIT) * sym_high_pc, + symtab.base[j].name, overlap * time / hist_scale, + overlap)); + addr = symtab.base[j].addr; + credit = overlap * time / hist_scale; + /* + * Credit symbol if it appears in INCL_FLAT or that + * table is empty and it does not appear it in + * EXCL_FLAT. + */ + if (sym_lookup (&syms[INCL_FLAT], addr) + || (syms[INCL_FLAT].len == 0 + && !sym_lookup (&syms[EXCL_FLAT], addr))) + { + symtab.base[j].hist.time += credit; + } + else + { + total_time -= credit; + } + } + } + } + DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n", + total_time)); +} + + +/* + * Print header for flag histogram profile: + */ +static void +DEFUN (print_header, (prefix), const char prefix) +{ + char unit[64]; + + sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev); + + if (bsd_style_output) + { + printf (_("\ngranularity: each sample hit covers %ld byte(s)"), + (long) hist_scale * sizeof (UNIT)); + if (total_time > 0.0) + { + printf (_(" for %.2f%% of %.2f %s\n\n"), + 100.0 / total_time, total_time / hz, hist_dimension); + } + } + else + { + printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension); + } + + if (total_time <= 0.0) + { + printf (_(" no time accumulated\n\n")); + /* this doesn't hurt since all the numerators will be zero: */ + total_time = 1.0; + } + + printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", + "% ", _("cumulative"), _("self "), "", _("self "), _("total "), ""); + printf ("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", + _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit, + _("name")); +} + + +static void +DEFUN (print_line, (sym, scale), Sym * sym AND double scale) +{ + if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0) + { + return; + } + + accum_time += sym->hist.time; + if (bsd_style_output) + { + printf ("%5.1f %10.2f %8.2f", + total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0, + accum_time / hz, sym->hist.time / hz); + } + else + { + printf ("%6.2f %9.2f %8.2f", + total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0, + accum_time / hz, sym->hist.time / hz); + } + if (sym->ncalls != 0) + { + printf (" %8lu %8.2f %8.2f ", + sym->ncalls, scale * sym->hist.time / hz / sym->ncalls, + scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls); + } + else + { + printf (" %8.8s %8.8s %8.8s ", "", "", ""); + } + if (bsd_style_output) + { + print_name (sym); + } + else + { + print_name_only (sym); + } + printf ("\n"); +} + + +/* + * Compare LP and RP. The primary comparison key is execution time, + * the secondary is number of invocation, and the tertiary is the + * lexicographic order of the function names. + */ +static int +DEFUN (cmp_time, (lp, rp), const PTR lp AND const PTR rp) +{ + const Sym *left = *(const Sym **) lp; + const Sym *right = *(const Sym **) rp; + double time_diff; + + time_diff = right->hist.time - left->hist.time; + if (time_diff > 0.0) + { + return 1; + } + if (time_diff < 0.0) + { + return -1; + } + + if (right->ncalls > left->ncalls) + { + return 1; + } + if (right->ncalls < left->ncalls) + { + return -1; + } + + return strcmp (left->name, right->name); +} + + +/* + * Print the flat histogram profile. + */ +void +DEFUN_VOID (hist_print) +{ + Sym **time_sorted_syms, *top_dog, *sym; + unsigned int index; + int log_scale; + double top_time, time; + bfd_vma addr; + + if (first_output) + { + first_output = FALSE; + } + else + { + printf ("\f\n"); + } + + accum_time = 0.0; + if (bsd_style_output) + { + if (print_descriptions) + { + printf (_("\n\n\nflat profile:\n")); + flat_blurb (stdout); + } + } + else + { + printf (_("Flat profile:\n")); + } + /* + * Sort the symbol table by time (call-count and name as secondary + * and tertiary keys): + */ + time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); + for (index = 0; index < symtab.len; ++index) + { + time_sorted_syms[index] = &symtab.base[index]; + } + qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time); + + if (bsd_style_output) + { + log_scale = 5; /* milli-seconds is BSD-default */ + } + else + { + /* + * Search for symbol with highest per-call execution time and + * scale accordingly: + */ + log_scale = 0; + top_dog = 0; + top_time = 0.0; + for (index = 0; index < symtab.len; ++index) + { + sym = time_sorted_syms[index]; + if (sym->ncalls != 0) + { + time = (sym->hist.time + sym->cg.child_time) / sym->ncalls; + if (time > top_time) + { + top_dog = sym; + top_time = time; + } + } + } + if (top_dog && top_dog->ncalls != 0 && top_time > 0.0) + { + top_time /= hz; + while (SItab[log_scale].scale * top_time < 1000.0 + && ((size_t) log_scale + < sizeof (SItab) / sizeof (SItab[0]) - 1)) + { + ++log_scale; + } + } + } + + /* + * For now, the dimension is always seconds. In the future, we + * may also want to support other (pseudo-)dimensions (such as + * I-cache misses etc.). + */ + print_header (SItab[log_scale].prefix); + for (index = 0; index < symtab.len; ++index) + { + addr = time_sorted_syms[index]->addr; + /* + * Print symbol if its in INCL_FLAT table or that table + * is empty and the symbol is not in EXCL_FLAT. + */ + if (sym_lookup (&syms[INCL_FLAT], addr) + || (syms[INCL_FLAT].len == 0 + && !sym_lookup (&syms[EXCL_FLAT], addr))) + { + print_line (time_sorted_syms[index], SItab[log_scale].scale); + } + } + free (time_sorted_syms); + + if (print_descriptions && !bsd_style_output) + { + flat_blurb (stdout); + } +} diff --git a/gprof/hist.h b/gprof/hist.h new file mode 100644 index 0000000..df62ef7 --- /dev/null +++ b/gprof/hist.h @@ -0,0 +1,23 @@ +#ifndef hist_h +#define hist_h + +#include "bfd.h" + +extern bfd_vma s_lowpc; /* lowpc from the profile file */ +extern bfd_vma s_highpc; /* highpc from the profile file */ +extern bfd_vma lowpc, highpc; /* range profiled, in UNIT's */ +extern int hist_num_bins; /* number of histogram bins */ +extern int *hist_sample; /* code histogram */ +/* + * Scale factor converting samples to pc values: each sample covers + * HIST_SCALE bytes: + */ +extern double hist_scale; + + +extern void hist_read_rec PARAMS ((FILE * ifp, const char *filename)); +extern void hist_write_hist PARAMS ((FILE * ofp, const char *filename)); +extern void hist_assign_samples PARAMS ((void)); +extern void hist_print PARAMS ((void)); + +#endif /* hist_h */ diff --git a/gprof/i386.c b/gprof/i386.c new file mode 100644 index 0000000..18aad1c --- /dev/null +++ b/gprof/i386.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1983 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. + */ +#include "gprof.h" +#include "cg_arcs.h" +#include "corefile.h" +#include "hist.h" +#include "symtab.h" + + +int +DEFUN (i386_iscall, (ip), unsigned char *ip) +{ + if (*ip == 0xe8) + return 1; + return 0; +} + + +void +i386_find_call (parent, p_lowpc, p_highpc) + Sym *parent; + bfd_vma p_lowpc; + bfd_vma p_highpc; +{ + unsigned char *instructp; + Sym *child; + bfd_vma destpc, delta; + + if (core_text_space == 0) + { + return; + } + if (p_lowpc < s_lowpc) + { + p_lowpc = s_lowpc; + } + if (p_highpc > s_highpc) + { + p_highpc = s_highpc; + } + DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n", + parent->name, p_lowpc, p_highpc)); + + delta = (bfd_vma) core_text_space - core_text_sect->vma; + + for (instructp = (unsigned char *) (p_lowpc + delta); + instructp < (unsigned char *) (p_highpc + delta); + instructp ++) + { + if (i386_iscall (instructp)) + { + DBG (CALLDEBUG, + printf ("[findcall]\t0x%x:call", + instructp - (unsigned char *) delta)); + /* + * regular pc relative addressing + * check that this is the address of + * a function. + */ + + destpc = ((bfd_vma) bfd_get_32 (core_bfd, instructp + 1) + + (bfd_vma) instructp - (bfd_vma) delta + 5); + if (destpc >= s_lowpc && destpc <= s_highpc) + { + child = sym_lookup (&symtab, destpc); + if (child && child->addr == destpc) + { + /* + * a hit + */ + DBG (CALLDEBUG, + printf ("\tdestpc 0x%lx (%s)\n", destpc, child->name)); + arc_add (parent, child, (unsigned long) 0); + instructp += 4; /* call is a 5 byte instruction */ + continue; + } + } + /* + * else: + * it looked like a callf, but it: + * a) wasn't actually a callf, or + * b) didn't point to a known function in the symtab, or + * c) something funny is going on. + */ + DBG (CALLDEBUG, printf ("\tbut it's a botch\n")); + } + } +} diff --git a/gprof/po/Make-in b/gprof/po/Make-in new file mode 100644 index 0000000..0552db1 --- /dev/null +++ b/gprof/po/Make-in @@ -0,0 +1,251 @@ +# Makefile for program source directory in GNU NLS utilities package. +# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = $(prefix)/@DATADIRNAME@ +localedir = $(datadir)/locale +gnulocaledir = $(prefix)/share/locale +gettextsrcdir = $(prefix)/share/gettext/po +subdir = po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +MKINSTALLDIRS = @MKINSTALLDIRS@ + +CC = @CC@ +GENCAT = @GENCAT@ +GMSGFMT = PATH=../src:$$PATH @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = PATH=../src:$$PATH @XGETTEXT@ +MSGMERGE = PATH=../src:$$PATH msgmerge + +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ + +INCLUDES = -I.. -I$(top_srcdir)/intl + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) + +SOURCES = cat-id-tbl.c +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \ +stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES) + +POTFILES = \ + +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +INSTOBJEXT = @INSTOBJEXT@ + +.SUFFIXES: +.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat + +.c.o: + $(COMPILE) $< + +.po.pox: + $(MAKE) $(PACKAGE).pot + $(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox + +.po.mo: + $(MSGFMT) -o $@ $< + +.po.gmo: + file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \ + && rm -f $$file && $(GMSGFMT) -o $$file $< + +.po.cat: + sed -f ../intl/po2msg.sed < $< > $*.msg \ + && rm -f $@ && $(GENCAT) $@ $*.msg + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) @MAINT@ $(PACKAGE).pot +all-no: + +$(srcdir)/$(PACKAGE).pot: $(POTFILES) + $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \ + --add-comments --keyword=_ --keyword=N_ \ + --files-from=$(srcdir)/POTFILES.in + rm -f $(srcdir)/$(PACKAGE).pot + mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot + +$(srcdir)/cat-id-tbl.c: stamp-cat-id; @: +$(srcdir)/stamp-cat-id: $(PACKAGE).pot + rm -f cat-id-tbl.tmp + sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \ + | sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp + if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \ + rm cat-id-tbl.tmp; \ + else \ + echo cat-id-tbl.c changed; \ + rm -f $(srcdir)/cat-id-tbl.c; \ + mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \ + fi + cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id + + +install: install-exec install-data +install-exec: +install-info: +install-data: install-data-@USE_NLS@ +install-data-no: all +install-data-yes: all + if test -r $(MKINSTALLDIRS); then \ + $(MKINSTALLDIRS) $(datadir); \ + else \ + $(top_srcdir)/mkinstalldirs $(datadir); \ + fi + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + case "$$cat" in \ + *.gmo) destdir=$(gnulocaledir);; \ + *) destdir=$(localedir);; \ + esac; \ + lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ + dir=$$destdir/$$lang/LC_MESSAGES; \ + if test -r $(MKINSTALLDIRS); then \ + $(MKINSTALLDIRS) $$dir; \ + else \ + $(top_srcdir)/mkinstalldirs $$dir; \ + fi; \ + if test -r $$cat; then \ + $(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \ + echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \ + else \ + $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \ + echo "installing $(srcdir)/$$cat as" \ + "$$dir/$(PACKAGE)$(INSTOBJEXT)"; \ + fi; \ + if test -r $$cat.m; then \ + $(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \ + echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \ + else \ + if test -r $(srcdir)/$$cat.m ; then \ + $(INSTALL_DATA) $(srcdir)/$$cat.m \ + $$dir/$(PACKAGE)$(INSTOBJEXT).m; \ + echo "installing $(srcdir)/$$cat as" \ + "$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \ + else \ + true; \ + fi; \ + fi; \ + done + if test "$(PACKAGE)" = "gettext"; then \ + if test -r $(MKINSTALLDIRS); then \ + $(MKINSTALLDIRS) $(gettextsrcdir); \ + else \ + $(top_srcdir)/mkinstalldirs $(gettextsrcdir); \ + fi; \ + $(INSTALL_DATA) $(srcdir)/Makefile.in.in \ + $(gettextsrcdir)/Makefile.in.in; \ + else \ + : ; \ + fi + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ + rm -f $(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \ + rm -f $(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \ + rm -f $(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \ + rm -f $(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \ + done + rm -f $(gettextsrcdir)/po-Makefile.in.in + +check: all + +cat-id-tbl.o: ../intl/libgettext.h + +dvi info tags TAGS ID: + +mostlyclean: + rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f $(GMOFILES) + +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: update-po $(DISTFILES) + dists="$(DISTFILES)"; \ + for file in $$dists; do \ + ln $(srcdir)/$$file $(distdir) 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir); \ + done + +update-po: Makefile + $(MAKE) $(PACKAGE).pot + PATH=`pwd`/../src:$$PATH; \ + cd $(srcdir); \ + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ + mv $$lang.po $$lang.old.po; \ + echo "$$lang:"; \ + if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \ + rm -f $$lang.old.po; \ + else \ + echo "msgmerge for $$cat failed!"; \ + rm -f $$lang.po; \ + mv $$lang.old.po $$lang.po; \ + fi; \ + done + +POTFILES: POTFILES.in + ( if test 'x$(srcdir)' != 'x.'; then \ + posrcprefix='$(top_srcdir)/'; \ + else \ + posrcprefix="../"; \ + fi; \ + rm -f $@-t $@ \ + && (sed -e '/^#/d' -e '/^[ ]*$$/d' \ + -e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \ + | sed -e '$$s/\\$$//') > $@-t \ + && chmod a-w $@-t \ + && mv $@-t $@ ) + +POTFILES.in: @MAINT@ ../Makefile + cd .. && $(MAKE) po/POTFILES.in + +Makefile: Make-in ../config.status POTFILES + cd .. \ + && CONFIG_FILES=$(subdir)/Makefile.in:$(subdir)/Make-in \ + CONFIG_HEADERS= $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gprof/po/POTFILES.in b/gprof/po/POTFILES.in new file mode 100644 index 0000000..56d8641 --- /dev/null +++ b/gprof/po/POTFILES.in @@ -0,0 +1,38 @@ +alpha.c +basic_blocks.c +basic_blocks.h +bb_exit_func.c +call_graph.c +call_graph.h +cg_arcs.c +cg_arcs.h +cg_dfn.c +cg_dfn.h +cg_print.c +cg_print.h +corefile.c +corefile.h +gmon.h +gmon_io.c +gmon_io.h +gmon_out.h +gprof.c +gprof.h +hertz.c +hertz.h +hist.c +hist.h +i386.c +search_list.c +search_list.h +source.c +source.h +sparc.c +sym_ids.c +sym_ids.h +symtab.c +symtab.h +tahoe.c +utils.c +utils.h +vax.c diff --git a/gprof/po/gprof.pot b/gprof/po/gprof.pot new file mode 100644 index 0000000..36bf787 --- /dev/null +++ b/gprof/po/gprof.pot @@ -0,0 +1,470 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 1998-06-12 19:33-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: ENCODING\n" + +#: alpha.c:89 +msgid "" +msgstr "" + +#: alpha.c:106 +#, c-format +msgid "[find_call] %s: 0x%lx to 0x%lx\n" +msgstr "" + +#: alpha.c:127 +#, c-format +msgid "[find_call] 0x%lx: jsr%s \n" +msgstr "" + +#: alpha.c:136 +#, c-format +msgid "[find_call] 0x%lx: bsr" +msgstr "" + +#: basic_blocks.c:134 call_graph.c:70 hist.c:105 +#, c-format +msgid "%s: %s: unexpected end of file\n" +msgstr "" + +#: basic_blocks.c:214 +#, c-format +msgid "%s: warning: ignoring basic-block exec counts (use -l or --line)\n" +msgstr "" + +#: basic_blocks.c:322 basic_blocks.c:330 +#, c-format +msgid "%s:%d: (%s:0x%lx) %d executions\n" +msgstr "" + +#: basic_blocks.c:323 basic_blocks.c:331 +msgid "" +msgstr "" + +#: basic_blocks.c:584 +#, c-format +msgid "" +"\n" +"\n" +"Top %d Lines:\n" +"\n" +" Line Count\n" +"\n" +msgstr "" + +#: basic_blocks.c:608 +msgid "" +"\n" +"Execution Summary:\n" +"\n" +msgstr "" + +#: basic_blocks.c:609 +#, c-format +msgid "%9ld Executable lines in this file\n" +msgstr "" + +#: basic_blocks.c:611 +#, c-format +msgid "%9ld Lines executed\n" +msgstr "" + +#: basic_blocks.c:612 +#, c-format +msgid "%9.2f Percent of the file executed\n" +msgstr "" + +#: basic_blocks.c:616 +#, c-format +msgid "" +"\n" +"%9d Total number of line executions\n" +msgstr "" + +#: basic_blocks.c:617 +#, c-format +msgid "%9.2f Average executions per line\n" +msgstr "" + +#: call_graph.c:48 +#, c-format +msgid "[cg_tally] arc from %s to %s traversed %d times\n" +msgstr "" + +#: cg_print.c:39 +msgid "" +"\t\t Call graph (explanation follows)\n" +"\n" +msgstr "" + +#: cg_print.c:43 +msgid "" +"\t\t\tCall graph\n" +"\n" +msgstr "" + +#: cg_print.c:46 hist.c:381 +#, c-format +msgid "" +"\n" +"granularity: each sample hit covers %ld byte(s)" +msgstr "" + +#: cg_print.c:50 +msgid "" +" for %.2f%% of %.2f seconds\n" +"\n" +msgstr "" + +#: cg_print.c:55 +msgid "" +" no time propagated\n" +"\n" +msgstr "" + +#: cg_print.c:64 cg_print.c:67 cg_print.c:69 +msgid "called" +msgstr "" + +#: cg_print.c:64 cg_print.c:69 +msgid "total" +msgstr "" + +#: cg_print.c:64 +msgid "parents" +msgstr "" + +#: cg_print.c:66 cg_print.c:67 +msgid "index" +msgstr "" + +#: cg_print.c:66 +msgid "%time" +msgstr "" + +#: cg_print.c:66 cg_print.c:67 +msgid "self" +msgstr "" + +#: cg_print.c:66 +msgid "descendents" +msgstr "" + +#: cg_print.c:67 hist.c:405 +msgid "name" +msgstr "" + +#: cg_print.c:69 +msgid "children" +msgstr "" + +#: cg_print.c:74 +msgid "index %% time self children called name\n" +msgstr "" + +#: cg_print.c:101 +#, c-format +msgid " [%d]\n" +msgstr "" + +#: cg_print.c:353 +#, c-format +msgid "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s \n" +msgstr "" + +#: cg_print.c:354 +#, c-format +msgid "%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s \n" +msgstr "" + +#: cg_print.c:587 +msgid "" +"Index by function name\n" +"\n" +msgstr "" + +#: cg_print.c:644 cg_print.c:653 +#, c-format +msgid "" +msgstr "" + +#: corefile.c:39 +#, c-format +msgid "%s: could not open %s.\n" +msgstr "" + +#: corefile.c:53 corefile.c:87 +#, c-format +msgid "%s: unable to parse mapping file %s.\n" +msgstr "" + +#: corefile.c:128 +#, c-format +msgid "%s: %s: not in a.out format\n" +msgstr "" + +#: corefile.c:139 +#, c-format +msgid "%s: can't find .text section in %s\n" +msgstr "" + +#: corefile.c:198 +#, c-format +msgid "%s: ran out room for %ld bytes of text space\n" +msgstr "" + +#: corefile.c:211 +#, c-format +msgid "%s: can't do -c\n" +msgstr "" + +#: corefile.c:243 +#, c-format +msgid "%s: -c not supported on architecture %s\n" +msgstr "" + +#: corefile.c:432 +#, c-format +msgid "%s: file `%s' has no symbols\n" +msgstr "" + +#: corefile.c:726 +#, c-format +msgid "%s: somebody miscounted: ltab.len=%d instead of %ld\n" +msgstr "" + +#: gmon_io.c:33 gmon_io.c:55 +#, c-format +msgid "%s: bfd_vma has unexpected size of %ld bytes\n" +msgstr "" + +#: gmon_io.c:87 gmon_io.c:179 +#, c-format +msgid "%s: file too short to be a gmon file\n" +msgstr "" + +#: gmon_io.c:97 +#, c-format +msgid "%s: file `%s' has bad magic cookie\n" +msgstr "" + +#: gmon_io.c:108 +#, c-format +msgid "%s: file `%s' has unsupported version %d\n" +msgstr "" + +#: gmon_io.c:138 +#, c-format +msgid "%s: %s: found bad tag %d (file corrupted?)\n" +msgstr "" + +#: gmon_io.c:197 +#, c-format +msgid "%s: profiling rate incompatible with first gmon file\n" +msgstr "" + +#: gmon_io.c:207 +#, c-format +msgid "%s: incompatible with first gmon file\n" +msgstr "" + +#: gmon_io.c:245 +#, c-format +msgid "%s: unexpected EOF after reading %d/%d bins\n" +msgstr "" + +#: gmon_io.c:280 +msgid "time is in ticks, not seconds\n" +msgstr "" + +#: gmon_io.c:286 gmon_io.c:410 +#, c-format +msgid "%s: don't know how to deal with file format %d\n" +msgstr "" + +#: gmon_io.c:293 +#, c-format +msgid "File `%s' (version %d) contains:\n" +msgstr "" + +#: gmon_io.c:295 +#, c-format +msgid "\t%d histogram record%s\n" +msgstr "" + +#: gmon_io.c:297 +#, c-format +msgid "\t%d call-graph record%s\n" +msgstr "" + +#: gmon_io.c:299 +#, c-format +msgid "\t%d basic-block count record%s\n" +msgstr "" + +#: gprof.c:59 +msgid "" +"@(#) Copyright (c) 1983 Regents of the University of California.\n" +" All rights reserved.\n" +msgstr "" + +#: gprof.c:144 +#, c-format +msgid "" +"Usage: %s [-[abcDhilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][name]] [-I dirs]\n" +"\t[-d[num]] [-k from/to] [-m min-count] [-t table-length]\n" +"\t[--[no-]annotated-source[=name]] [--[no-]exec-counts[=name]]\n" +"\t[--[no-]flat-profile[=name]] [--[no-]graph[=name]]\n" +"\t[--[no-]time=name] [--all-lines] [--brief] [--debug[=level]]\n" +"\t[--function-ordering] [--file-ordering]\n" +"\t[--directory-path=dirs] [--display-unused-functions]\n" +"\t[--file-format=name] [--file-info] [--help] [--line] [--min-count=n]\n" +"\t[--no-static] [--print-path] [--separate-files]\n" +"\t[--static-call-graph] [--sum] [--table-length=len] [--traditional]\n" +"\t[--version] [--width=n] [--ignore-non-functions]\n" +"\t[--demangle] [--no-demangle]\n" +"\t[image-file] [profile-file...]\n" +msgstr "" + +#: gprof.c:160 +msgid "Report bugs to bug-gnu-utils@gnu.org\n" +msgstr "" + +#: gprof.c:229 +#, c-format +msgid "%s: debugging not supported; -d ignored\n" +msgstr "" + +#: gprof.c:306 +#, c-format +msgid "%s: unknown file format %s\n" +msgstr "" + +#. This output is intended to follow the GNU standards document. +#: gprof.c:390 +#, c-format +msgid "GNU gprof %s\n" +msgstr "" + +#: gprof.c:391 +msgid "" +"Based on BSD gprof, copyright 1983 Regents of the University of California.\n" +msgstr "" + +#: gprof.c:392 +msgid "" +"This program is free software. This program has absolutely no warranty.\n" +msgstr "" + +#: gprof.c:438 +#, c-format +msgid "" +"%s: Only one of --function-ordering and --file-ordering may be specified.\n" +msgstr "" + +#: gprof.c:538 +#, c-format +msgid "%s: sorry, file format `prof' is not yet supported\n" +msgstr "" + +#: gprof.c:599 +#, c-format +msgid "%s: gmon.out file is missing histogram\n" +msgstr "" + +#: gprof.c:606 +#, c-format +msgid "%s: gmon.out file is missing call-graph data\n" +msgstr "" + +#: hist.c:142 +#, c-format +msgid "%s: `%s' is incompatible with first gmon file\n" +msgstr "" + +#: hist.c:158 +#, c-format +msgid "%s: %s: unexpected EOF after reading %d of %d samples\n" +msgstr "" + +#: hist.c:377 +#, c-format +msgid "%c%c/call" +msgstr "" + +#: hist.c:385 +msgid "" +" for %.2f%% of %.2f %s\n" +"\n" +msgstr "" + +#: hist.c:391 +#, c-format +msgid "" +"\n" +"Each sample counts as %g %s.\n" +msgstr "" + +#: hist.c:396 +msgid "" +" no time accumulated\n" +"\n" +msgstr "" + +#: hist.c:402 +msgid "cumulative" +msgstr "" + +#: hist.c:402 +msgid "self " +msgstr "" + +#: hist.c:402 +msgid "total " +msgstr "" + +#: hist.c:404 +msgid "time" +msgstr "" + +#: hist.c:404 +msgid "calls" +msgstr "" + +#: hist.c:515 +msgid "" +"\n" +"\n" +"\n" +"flat profile:\n" +msgstr "" + +#: hist.c:521 +msgid "Flat profile:\n" +msgstr "" + +#: source.c:140 +#, c-format +msgid "%s: could not locate `%s'\n" +msgstr "" + +#: source.c:200 +#, c-format +msgid "*** File %s:\n" +msgstr "" + +#: utils.c:93 +#, c-format +msgid " " +msgstr "" diff --git a/gprof/search_list.c b/gprof/search_list.c new file mode 100644 index 0000000..d475dbf --- /dev/null +++ b/gprof/search_list.c @@ -0,0 +1,44 @@ +#include "libiberty.h" +#include "gprof.h" +#include "search_list.h" + + +void +DEFUN (search_list_append, (list, paths), + Search_List * list AND const char *paths) +{ + Search_List_Elem *new_el; + const char *beg, *colon; + int len; + + colon = paths - 1; + do + { + beg = colon + 1; + colon = strchr (beg, ':'); + if (colon) + { + len = colon - beg; + } + else + { + len = strlen (beg); + } + new_el = (Search_List_Elem *) xmalloc (sizeof (*new_el) + len); + memcpy (new_el->path, beg, len); + new_el->path[len] = '\0'; + + /* append new path at end of list: */ + new_el->next = 0; + if (list->tail) + { + list->tail->next = new_el; + } + else + { + list->head = new_el; + } + list->tail = new_el; + } + while (colon); +} diff --git a/gprof/search_list.h b/gprof/search_list.h new file mode 100644 index 0000000..54dfe35 --- /dev/null +++ b/gprof/search_list.h @@ -0,0 +1,20 @@ +#ifndef search_list_h +#define search_list_h + +typedef struct search_list_elem + { + struct search_list_elem *next; + char path[1]; + } +Search_List_Elem; + +typedef struct + { + struct search_list_elem *head; + struct search_list_elem *tail; + } +Search_List; + +extern void search_list_append PARAMS ((Search_List * list, const char *paths)); + +#endif /* search_list_h */ diff --git a/gprof/source.c b/gprof/source.c new file mode 100644 index 0000000..4901a04 --- /dev/null +++ b/gprof/source.c @@ -0,0 +1,223 @@ +/* + * Keeps track of source files. + */ +#include "gprof.h" +#include "libiberty.h" +#include "search_list.h" +#include "source.h" + +#define EXT_ANNO "-ann" /* postfix of annotated files */ + +/* + * Default option values: + */ +bool create_annotation_files = FALSE; + +Search_List src_search_list = +{0, 0}; +Source_File *first_src_file = 0; + + +Source_File * +DEFUN (source_file_lookup_path, (path), const char *path) +{ + Source_File *sf; + + for (sf = first_src_file; sf; sf = sf->next) + { + if (strcmp (path, sf->name) == 0) + { + break; + } + } + if (!sf) + { + /* create a new source file descriptor: */ + + sf = (Source_File *) xmalloc (sizeof (*sf)); + memset (sf, 0, sizeof (*sf)); + sf->name = xstrdup (path); + sf->next = first_src_file; + first_src_file = sf; + } + return sf; +} + + +Source_File * +DEFUN (source_file_lookup_name, (filename), const char *filename) +{ + const char *fname; + Source_File *sf; + /* + * The user cannot know exactly how a filename will be stored in + * the debugging info (e.g., ../include/foo.h + * vs. /usr/include/foo.h). So we simply compare the filename + * component of a path only: + */ + for (sf = first_src_file; sf; sf = sf->next) + { + fname = strrchr (sf->name, '/'); + if (fname) + { + ++fname; + } + else + { + fname = sf->name; + } + if (strcmp (filename, fname) == 0) + { + break; + } + } + return sf; +} + + +FILE * +DEFUN (annotate_source, (sf, max_width, annote, arg), + Source_File * sf AND int max_width + AND void (*annote) PARAMS ((char *buf, int w, int l, void *arg)) + AND void *arg) +{ + static bool first_file = TRUE; + int i, line_num, nread; + bool new_line; + char buf[8192]; + char fname[PATH_MAX]; + char *annotation, *name_only; + FILE *ifp, *ofp; + Search_List_Elem *sle = src_search_list.head; + + /* + * Open input file. If open fails, walk along search-list until + * open succeeds or reaching end of list: + */ + strcpy (fname, sf->name); + if (sf->name[0] == '/') + { + sle = 0; /* don't use search list for absolute paths */ + } + name_only = 0; + while (TRUE) + { + DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n", + sf->name, fname)); + ifp = fopen (fname, FOPEN_RB); + if (ifp) + { + break; + } + if (!sle && !name_only) + { + name_only = strrchr (sf->name, '/'); + if (name_only) + { + /* try search-list again, but this time with name only: */ + ++name_only; + sle = src_search_list.head; + } + } + if (sle) + { + strcpy (fname, sle->path); + strcat (fname, "/"); + if (name_only) + { + strcat (fname, name_only); + } + else + { + strcat (fname, sf->name); + } + sle = sle->next; + } + else + { + if (errno == ENOENT) + { + fprintf (stderr, _("%s: could not locate `%s'\n"), + whoami, sf->name); + } + else + { + perror (sf->name); + } + return 0; + } + } + + ofp = stdout; + if (create_annotation_files) + { + /* try to create annotated source file: */ + const char *filename; + + /* create annotation files in the current working directory: */ + filename = strrchr (sf->name, '/'); + if (filename) + { + ++filename; + } + else + { + filename = sf->name; + } + + strcpy (fname, filename); + strcat (fname, EXT_ANNO); + ofp = fopen (fname, "w"); + if (!ofp) + { + perror (fname); + return 0; + } + } + + /* + * Print file names if output goes to stdout and there are + * more than one source file: + */ + if (ofp == stdout) + { + if (first_file) + { + first_file = FALSE; + } + else + { + fputc ('\n', ofp); + } + if (first_output) + { + first_output = FALSE; + } + else + { + fprintf (ofp, "\f\n"); + } + fprintf (ofp, _("*** File %s:\n"), sf->name); + } + + annotation = xmalloc (max_width + 1); + line_num = 1; + new_line = TRUE; + while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0) + { + for (i = 0; i < nread; ++i) + { + if (new_line) + { + (*annote) (annotation, max_width, line_num, arg); + fputs (annotation, ofp); + ++line_num; + new_line = FALSE; + } + new_line = (buf[i] == '\n'); + fputc (buf[i], ofp); + } + } + free (annotation); + return ofp; +} diff --git a/gprof/source.h b/gprof/source.h new file mode 100644 index 0000000..b33bad3 --- /dev/null +++ b/gprof/source.h @@ -0,0 +1,55 @@ +#ifndef source_h +#define source_h + +#include +#include "gprof.h" +#include "search_list.h" + +typedef struct source_file + { + struct source_file *next; + const char *name; /* name of source file */ + unsigned long ncalls; /* # of "calls" to this file */ + int num_lines; /* # of lines in file */ + int nalloced; /* number of lines allocated */ + void **line; /* usage-dependent per-line data */ + } +Source_File; + +/* + * Options: + */ +extern bool create_annotation_files; /* create annotated output files? */ + +/* + * List of directories to search for source files: + */ +extern Search_List src_search_list; + +/* + * Chain of source-file descriptors: + */ +extern Source_File *first_src_file; + +/* + * Returns pointer to source file descriptor for PATH/FILENAME. + */ +extern Source_File *source_file_lookup_path PARAMS ((const char *path)); +extern Source_File *source_file_lookup_name PARAMS ((const char *filename)); + +/* + * Read source file SF output annotated source. The annotation is at + * MAX_WIDTH characters wide and for each source-line an annotation is + * obtained by invoking function ANNOTE. ARG is an argument passed to + * ANNOTE that is left uninterpreted by annotate_source(). + * + * Returns a pointer to the output file (which maybe stdout) such + * that summary statistics can be printed. If the returned file + * is not stdout, it should be closed when done with it. + */ +extern FILE *annotate_source PARAMS ((Source_File * sf, int max_width, + void (*annote) (char *b, int w, int l, + void *arg), + void *arg)); + +#endif /* source_h */ diff --git a/gprof/sparc.c b/gprof/sparc.c new file mode 100644 index 0000000..ad702b1 --- /dev/null +++ b/gprof/sparc.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1983 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. + */ +#include "gprof.h" +#include "cg_arcs.h" +#include "corefile.h" +#include "hist.h" +#include "symtab.h" + + /* + * opcode of the `callf' instruction + */ +#define CALL (0xc0000000) + +void +sparc_find_call (parent, p_lowpc, p_highpc) + Sym *parent; + bfd_vma p_lowpc; + bfd_vma p_highpc; +{ + bfd_vma dest_pc, delta; + unsigned int *instr; + Sym *child; + + delta = (bfd_vma) core_text_space - core_text_sect->vma; + + if (core_text_space == 0) + { + return; + } + if (p_lowpc < s_lowpc) + { + p_lowpc = s_lowpc; + } + if (p_highpc > s_highpc) + { + p_highpc = s_highpc; + } + DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n", + parent->name, p_lowpc, p_highpc)); + for (instr = (unsigned int *) (((p_lowpc + delta) + 3) &~ 3); + instr < (unsigned int *) (p_highpc + delta); + ++instr) + { + if ((*instr & CALL)) + { + DBG (CALLDEBUG, + printf ("[find_call] 0x%lx: callf", (bfd_vma) instr - delta)); + /* + * Regular pc relative addressing check that this is the + * address of a function. + */ + dest_pc = ((bfd_vma) (instr + (*instr & ~CALL))) - delta; + if (dest_pc >= s_lowpc && dest_pc <= s_highpc) + { + child = sym_lookup (&symtab, dest_pc); + DBG (CALLDEBUG, + printf ("\tdest_pc=0x%lx, (name=%s, addr=0x%lx)\n", + dest_pc, child->name, child->addr)); + if (child->addr == dest_pc) + { + /* a hit: */ + arc_add (parent, child, (unsigned long) 0); + continue; + } + } + /* + * Something funny going on. + */ + DBG (CALLDEBUG, printf ("\tbut it's a botch\n")); + } + } +} diff --git a/gprof/stamp-h.in b/gprof/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/gprof/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/gprof/sym_ids.c b/gprof/sym_ids.c new file mode 100644 index 0000000..ba3ca28 --- /dev/null +++ b/gprof/sym_ids.c @@ -0,0 +1,372 @@ +#include + +#include "libiberty.h" +#include "cg_arcs.h" +#include "sym_ids.h" + +struct sym_id + { + struct sym_id *next; + char *spec; /* parsing modifies this */ + Table_Id which_table; + bool has_right; + struct match + { + int prev_index; /* index of prev match */ + Sym *prev_match; /* previous match */ + Sym *first_match; /* chain of all matches */ + Sym sym; + } + left, right; + } + *id_list; + +Sym_Table syms[NUM_TABLES]; + +#ifdef DEBUG +const char *table_name[] = +{ + "INCL_GRAPH", "EXCL_GRAPH", + "INCL_ARCS", "EXCL_ARCS", + "INCL_FLAT", "EXCL_FLAT", + "INCL_TIME", "EXCL_TIME", + "INCL_ANNO", "EXCL_ANNO", + "INCL_EXEC", "EXCL_EXEC" +}; +#endif /* DEBUG */ + +/* + * This is the table in which we keep all the syms that match + * the right half of an arc id. It is NOT sorted according + * to the addresses, because it is accessed only through + * the left half's CHILDREN pointers (so it's crucial not + * to reorder this table once pointers into it exist). + */ +static Sym_Table right_ids; + +static Source_File non_existent_file = +{ + 0, "" +}; + + +void +DEFUN (sym_id_add, (spec, which_table), + const char *spec AND Table_Id which_table) +{ + struct sym_id *id; + int len = strlen (spec); + + id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1); + memset (id, 0, sizeof (*id)); + + id->spec = (char *) id + sizeof (*id); + strcpy (id->spec, spec); + id->which_table = which_table; + + id->next = id_list; + id_list = id; +} + + +/* + * A spec has the syntax FILENAME:(FUNCNAME|LINENUM). As a convenience + * to the user, a spec without a colon is interpreted as: + * + * (i) a FILENAME if it contains a dot + * (ii) a FUNCNAME if it starts with a non-digit character + * (iii) a LINENUM if it starts with a digit + * + * A FUNCNAME containing a dot can be specified by :FUNCNAME, a + * FILENAME not containing a dot can be specified by FILENAME:. + */ +static void +DEFUN (parse_spec, (spec, sym), char *spec AND Sym * sym) +{ + char *colon; + + sym_init (sym); + colon = strrchr (spec, ':'); + if (colon) + { + *colon = '\0'; + if (colon > spec) + { + sym->file = source_file_lookup_name (spec); + if (!sym->file) + { + sym->file = &non_existent_file; + } + } + spec = colon + 1; + if (strlen (spec)) + { + if (isdigit ((unsigned char) spec[0])) + { + sym->line_num = atoi (spec); + } + else + { + sym->name = spec; + } + } + } + else if (strlen (spec)) + { + /* no colon: spec is a filename if it contains a dot: */ + if (strchr (spec, '.')) + { + sym->file = source_file_lookup_name (spec); + if (!sym->file) + { + sym->file = &non_existent_file; + } + } + else if (isdigit ((unsigned char) *spec)) + { + sym->line_num = atoi (spec); + } + else if (strlen (spec)) + { + sym->name = spec; + } + } +} + + +/* + * A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined + * by parse_spec(). + */ +static void +DEFUN (parse_id, (id), struct sym_id *id) +{ + char *slash; + + DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec)); + + slash = strchr (id->spec, '/'); + if (slash) + { + parse_spec (slash + 1, &id->right.sym); + *slash = '\0'; + id->has_right = TRUE; + } + parse_spec (id->spec, &id->left.sym); + +#ifdef DEBUG + if (debug_level & IDDEBUG) + { + printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*"); + if (id->left.sym.name) + { + printf ("%s", id->left.sym.name); + } + else if (id->left.sym.line_num) + { + printf ("%d", id->left.sym.line_num); + } + else + { + printf ("*"); + } + if (id->has_right) + { + printf ("/%s:", + id->right.sym.file ? id->right.sym.file->name : "*"); + if (id->right.sym.name) + { + printf ("%s", id->right.sym.name); + } + else if (id->right.sym.line_num) + { + printf ("%d", id->right.sym.line_num); + } + else + { + printf ("*"); + } + } + printf ("\n"); + } +#endif +} + + +/* + * Return TRUE iff PATTERN matches SYM. + */ +static bool +DEFUN (match, (pattern, sym), Sym * pattern AND Sym * sym) +{ + return (pattern->file ? pattern->file == sym->file : TRUE) + && (pattern->line_num ? pattern->line_num == sym->line_num : TRUE) + && (pattern->name ? strcmp (pattern->name, sym->name) == 0 : TRUE); +} + + +static void +DEFUN (extend_match, (m, sym, tab, second_pass), + struct match *m AND Sym * sym AND Sym_Table * tab AND bool second_pass) +{ + if (m->prev_match != sym - 1) + { + /* discontinuity: add new match to table: */ + if (second_pass) + { + tab->base[tab->len] = *sym; + m->prev_index = tab->len; + + /* link match into match's chain: */ + tab->base[tab->len].next = m->first_match; + m->first_match = &tab->base[tab->len]; + } + ++tab->len; + } + + /* extend match to include this symbol: */ + if (second_pass) + { + tab->base[m->prev_index].end_addr = sym->end_addr; + } + m->prev_match = sym; +} + + +/* + * Go through sym_id list produced by option processing and fill + * in the various symbol tables indicating what symbols should + * be displayed or suppressed for the various kinds of outputs. + * + * This can potentially produce huge tables and in particulars + * tons of arcs, but this happens only if the user makes silly + * requests---you get what you ask for! + */ +void +DEFUN_VOID (sym_id_parse) +{ + Sym *sym, *left, *right; + struct sym_id *id; + Sym_Table *tab; + + /* + * Convert symbol ids into Syms, so we can deal with them more easily: + */ + for (id = id_list; id; id = id->next) + { + parse_id (id); + } + + /* first determine size of each table: */ + + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + for (id = id_list; id; id = id->next) + { + if (match (&id->left.sym, sym)) + { + extend_match (&id->left, sym, &syms[id->which_table], FALSE); + } + if (id->has_right && match (&id->right.sym, sym)) + { + extend_match (&id->right, sym, &right_ids, FALSE); + } + } + } + + /* create tables of appropriate size and reset lengths: */ + + for (tab = syms; tab < &syms[NUM_TABLES]; ++tab) + { + if (tab->len) + { + tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym)); + tab->limit = tab->base + tab->len; + tab->len = 0; + } + } + if (right_ids.len) + { + right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym)); + right_ids.limit = right_ids.base + right_ids.len; + right_ids.len = 0; + } + + /* make a second pass through symtab, creating syms as necessary: */ + + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + for (id = id_list; id; id = id->next) + { + if (match (&id->left.sym, sym)) + { + extend_match (&id->left, sym, &syms[id->which_table], TRUE); + } + if (id->has_right && match (&id->right.sym, sym)) + { + extend_match (&id->right, sym, &right_ids, TRUE); + } + } + } + + /* go through ids creating arcs as needed: */ + + for (id = id_list; id; id = id->next) + { + if (id->has_right) + { + for (left = id->left.first_match; left; left = left->next) + { + for (right = id->right.first_match; right; right = right->next) + { + DBG (IDDEBUG, + printf ( + "[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n", + left->file ? left->file->name : "*", + left->name ? left->name : "*", left->addr, + left->end_addr, + right->file ? right->file->name : "*", + right->name ? right->name : "*", right->addr, + right->end_addr, + table_name[id->which_table])); + arc_add (left, right, (unsigned long) 0); + } + } + } + } + + /* finally, we can sort the tables and we're done: */ + + for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab) + { + DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n", + table_name[tab - &syms[0]])); + symtab_finalize (tab); + } +} + + +/* + * Symbol tables storing the FROM symbols of arcs do not necessarily + * have distinct address ranges. For example, somebody might request + * -k /_mcount to suppress any arcs into _mcount, while at the same + * time requesting -k a/b. Fortunately, those symbol tables don't get + * very big (the user has to type them!), so a linear search is probably + * tolerable. + */ +bool +DEFUN (sym_id_arc_is_present, (symtab, from, to), + Sym_Table * symtab AND Sym * from AND Sym * to) +{ + Sym *sym; + + for (sym = symtab->base; sym < symtab->limit; ++sym) + { + if (from->addr >= sym->addr && from->addr <= sym->end_addr + && arc_lookup (sym, to)) + { + return TRUE; + } + } + return FALSE; +} diff --git a/gprof/sym_ids.h b/gprof/sym_ids.h new file mode 100644 index 0000000..9096338 --- /dev/null +++ b/gprof/sym_ids.h @@ -0,0 +1,25 @@ +#ifndef sym_ids_h +#define sym_ids_h + +#include "symtab.h" + +typedef enum + { + INCL_GRAPH = 0, EXCL_GRAPH, + INCL_ARCS, EXCL_ARCS, + INCL_FLAT, EXCL_FLAT, + INCL_TIME, EXCL_TIME, + INCL_ANNO, EXCL_ANNO, + INCL_EXEC, EXCL_EXEC, + NUM_TABLES + } +Table_Id; + +extern Sym_Table syms[NUM_TABLES]; + +extern void sym_id_add PARAMS ((const char *spec, Table_Id which_table)); +extern void sym_id_parse PARAMS ((void)); +extern bool sym_id_arc_is_present PARAMS ((Sym_Table * symtab, + Sym * from, Sym * to)); + +#endif /* sym_ids_h */ diff --git a/gprof/symtab.c b/gprof/symtab.c new file mode 100644 index 0000000..182c657 --- /dev/null +++ b/gprof/symtab.c @@ -0,0 +1,269 @@ +#include "gprof.h" +#include "cg_arcs.h" +#include "corefile.h" +#include "symtab.h" + +Sym_Table symtab; + + +/* + * Initialize a symbol (so it's empty). + */ +void +DEFUN (sym_init, (sym), Sym * sym) +{ + memset (sym, 0, sizeof (*sym)); + /* + * It is not safe to assume that a binary zero corresponds to + * a floating-point 0.0, so initialize floats explicitly: + */ + sym->hist.time = 0.0; + sym->cg.child_time = 0.0; + sym->cg.prop.fract = 0.0; + sym->cg.prop.self = 0.0; + sym->cg.prop.child = 0.0; +} + + +/* + * Compare the function entry-point of two symbols and return <0, =0, + * or >0 depending on whether the left value is smaller than, equal + * to, or greater than the right value. If two symbols are equal + * but one has is_func set and the other doesn't, we make the + * non-function symbol one "bigger" so that the function symbol will + * survive duplicate removal. Finally, if both symbols have the + * same is_func value, we discriminate against is_static such that + * the global symbol survives. + */ +static int +DEFUN (cmp_addr, (lp, rp), const PTR lp AND const PTR rp) +{ + Sym *left = (Sym *) lp; + Sym *right = (Sym *) rp; + + if (left->addr > right->addr) + { + return 1; + } + else if (left->addr < right->addr) + { + return -1; + } + + if (left->is_func != right->is_func) + { + return right->is_func - left->is_func; + } + + return left->is_static - right->is_static; +} + + +void +DEFUN (symtab_finalize, (tab), Sym_Table * tab) +{ + Sym *src, *dst; + bfd_vma prev_addr; + + if (!tab->len) + { + return; + } + + /* + * Sort symbol table in order of increasing function addresses: + */ + qsort (tab->base, tab->len, sizeof (Sym), cmp_addr); + + /* + * Remove duplicate entries to speed-up later processing and + * set end_addr if its not set yet: + */ + prev_addr = tab->base[0].addr + 1; + for (src = dst = tab->base; src < tab->limit; ++src) + { + if (src->addr == prev_addr) + { + /* + * If same address, favor global symbol over static one, + * then function over line number. If both symbols are + * either static or global and either function or line, check + * whether one has name beginning with underscore while + * the other doesn't. In such cases, keep sym without + * underscore. This takes cares of compiler generated + * symbols (such as __gnu_compiled, __c89_used, etc.). + */ + if ((!src->is_static && dst[-1].is_static) + || ((src->is_static == dst[-1].is_static) + && ((src->is_func && !dst[-1].is_func) + || ((src->is_func == dst[-1].is_func) + && ((src->name[0] != '_' && dst[-1].name[0] == '_') + || (src->name[0] + && src->name[1] != '_' + && dst[-1].name[1] == '_')))))) + { + DBG (AOUTDEBUG | IDDEBUG, + printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c", + src->name, src->is_static ? 't' : 'T', + src->is_func ? 'F' : 'f', + dst[-1].name, dst[-1].is_static ? 't' : 'T', + dst[-1].is_func ? 'F' : 'f'); + printf (" (addr=%lx)\n", src->addr)); + dst[-1] = *src; + } + else + { + DBG (AOUTDEBUG | IDDEBUG, + printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c", + dst[-1].name, dst[-1].is_static ? 't' : 'T', + dst[-1].is_func ? 'F' : 'f', + src->name, src->is_static ? 't' : 'T', + src->is_func ? 'F' : 'f'); + printf (" (addr=%lx)\n", src->addr)); + } + } + else + { + if (dst > tab->base && dst[-1].end_addr == 0) + { + dst[-1].end_addr = src->addr - 1; + } + + /* retain sym only if it has a non-empty address range: */ + if (!src->end_addr || src->addr <= src->end_addr) + { + *dst++ = *src; + prev_addr = src->addr; + } + } + } + if (tab->len > 0 && dst[-1].end_addr == 0) + { + dst[-1].end_addr = core_text_sect->vma + core_text_sect->_raw_size - 1; + } + + DBG (AOUTDEBUG | IDDEBUG, + printf ("[symtab_finalize]: removed %d duplicate entries\n", + tab->len - (int) (dst - tab->base))); + + tab->limit = dst; + tab->len = tab->limit - tab->base; + + DBG (AOUTDEBUG | IDDEBUG, + unsigned int j; + + for (j = 0; j < tab->len; ++j) + { + printf ("[symtab_finalize] 0x%lx-0x%lx\t%s\n", + (long) tab->base[j].addr, (long) tab->base[j].end_addr, + tab->base[j].name); + } + ); +} + + +#ifdef DEBUG + +Sym * +DEFUN (dbg_sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address) +{ + long low, mid, high; + Sym *sym; + + fprintf (stderr, "[dbg_sym_lookup] address 0x%lx\n", address); + + sym = symtab->base; + for (low = 0, high = symtab->len - 1; low != high;) + { + mid = (high + low) >> 1; + fprintf (stderr, "[dbg_sym_lookup] low=0x%lx, mid=0x%lx, high=0x%lx\n", + low, mid, high); + fprintf (stderr, "[dbg_sym_lookup] sym[m]=0x%lx sym[m + 1]=0x%lx\n", + sym[mid].addr, sym[mid + 1].addr); + if (sym[mid].addr <= address && sym[mid + 1].addr > address) + { + return &sym[mid]; + } + if (sym[mid].addr > address) + { + high = mid; + } + else + { + low = mid + 1; + } + } + fprintf (stderr, "[dbg_sym_lookup] binary search fails???\n"); + return 0; +} + +#endif /* DEBUG */ + + +/* + * Look up an address in the symbol-table that is sorted by address. + * If address does not hit any symbol, 0 is returned. + */ +Sym * +DEFUN (sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address) +{ + long low, high; + long mid = -1; + Sym *sym; +#ifdef DEBUG + int probes = 0; +#endif /* DEBUG */ + + if (!symtab->len) + { + return 0; + } + + sym = symtab->base; + for (low = 0, high = symtab->len - 1; low != high;) + { + DBG (LOOKUPDEBUG, ++probes); + mid = (high + low) / 2; + if (sym[mid].addr <= address && sym[mid + 1].addr > address) + { + if (address > sym[mid].end_addr) + { + /* + * Address falls into gap between sym[mid] and + * sym[mid + 1]: + */ + return 0; + } + else + { + DBG (LOOKUPDEBUG, + printf ("[sym_lookup] %d probes (symtab->len=%u)\n", + probes, symtab->len - 1)); + return &sym[mid]; + } + } + if (sym[mid].addr > address) + { + high = mid; + } + else + { + low = mid + 1; + } + } + if (sym[mid + 1].addr <= address) + { + if (address > sym[mid + 1].end_addr) + { + /* address is beyond end of sym[mid + 1]: */ + return 0; + } + else + { + DBG (LOOKUPDEBUG, printf ("[sym_lookup] %d (%u) probes, fall off\n", + probes, symtab->len - 1)); + return &sym[mid + 1]; + } + } + return 0; +} diff --git a/gprof/symtab.h b/gprof/symtab.h new file mode 100644 index 0000000..a6a450e --- /dev/null +++ b/gprof/symtab.h @@ -0,0 +1,111 @@ +#ifndef symtab_h +#define symtab_h + +#include "bfd.h" +#include "gprof.h" + +/* + * For a profile to be intelligible to a human user, it is necessary + * to map code-addresses into source-code information. Source-code + * information can be any combination of: (i) function-name, (ii) + * source file-name, and (iii) source line number. + * + * The symbol table is used to map addresses into source-code + * information. + */ + +#include "source.h" + +#define NBBS 10 + +/* + * Symbol-entry. For each external in the specified file we gather + * its address, the number of calls and compute its share of cpu time. + */ +typedef struct sym + { + /* + * Common information: + * + * In the symbol-table, fields ADDR and FUNC_NAME are guaranteed + * to contain valid information. FILE may be 0, if unknown and + * LINE_NUM maybe 0 if unknown. + */ + bfd_vma addr; /* address of entry point */ + bfd_vma end_addr; /* end-address */ + const char *name; /* name of function this sym is from */ + Source_File *file; /* source file symbol comes from */ + int line_num; /* source line number */ + unsigned int is_func:1, /* is this a function entry point? */ + is_static:1, /* is this a local (static) symbol? */ + is_bb_head:1, /* is this the head of a basic-blk? */ + mapped:1, /* this symbol was mapped to another name */ + has_been_placed:1; /* have we placed this symbol? */ + unsigned long ncalls; /* how many times executed */ + int nuses; /* how many times this symbol appears in + a particular context */ + bfd_vma bb_addr[NBBS]; /* address of basic-block start */ + unsigned long bb_calls[NBBS]; /* how many times basic-block was called */ + struct sym *next; /* for building chains of syms */ + struct sym *prev; /* for building chains of syms */ + + /* profile-specific information: */ + + /* histogram specific info: */ + struct + { + double time; /* (weighted) ticks in this routine */ + bfd_vma scaled_addr; /* scaled entry point */ + } + hist; + + /* call-graph specific info: */ + struct + { + unsigned long self_calls; /* how many calls to self */ + double child_time; /* cumulative ticks in children */ + int index; /* index in the graph list */ + int top_order; /* graph call chain top-sort order */ + bool print_flag; /* should this be printed? */ + struct + { + double fract; /* what % of time propagates */ + double self; /* how much self time propagates */ + double child; /* how much child time propagates */ + } + prop; + struct + { + int num; /* internal number of cycle on */ + struct sym *head; /* head of cycle */ + struct sym *next; /* next member of cycle */ + } + cyc; + struct arc *parents; /* list of caller arcs */ + struct arc *children; /* list of callee arcs */ + } + cg; + } +Sym; + +/* + * Symbol-tables are always assumed to be sorted in increasing order + * of addresses: + */ +typedef struct + { + unsigned int len; /* # of symbols in this table */ + Sym *base; /* first element in symbol table */ + Sym *limit; /* limit = base + len */ + } +Sym_Table; + +extern Sym_Table symtab; /* the symbol table */ + +extern void sym_init PARAMS ((Sym * sym)); +extern void symtab_finalize PARAMS ((Sym_Table * symtab)); +extern Sym *sym_lookup PARAMS ((Sym_Table * symtab, bfd_vma address)); + +extern void find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); + +#endif /* symtab_h */ diff --git a/gprof/tahoe.c b/gprof/tahoe.c new file mode 100644 index 0000000..d133c17 --- /dev/null +++ b/gprof/tahoe.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 1983 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. + */ +#include "gprof.h" +#include "cg_arcs.h" +#include "corefile.h" +#include "hist.h" +#include "symtab.h" + + /* + * opcode of the `callf' instruction + */ +#define CALLF 0xfe + + /* + * register for pc relative addressing + */ +#define PC 0xf + +enum tahoe_opermodes + { + literal, indexed, reg, regdef, autodec, autoinc, autoincdef, + bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef, + immediate, absolute, byterel, bytereldef, wordrel, wordreldef, + longrel, longreldef + }; +typedef enum tahoe_opermodes tahoe_operandenum; + +/* + * A symbol to be the child of indirect callf: + */ +Sym indirectchild; + + +tahoe_operandenum +tahoe_operandmode (modep) + unsigned char *modep; +{ + long usesreg = ((long) *modep) & 0xf; + + switch (((long) *modep) >> 4) + { + case 0: + case 1: + case 2: + case 3: + return literal; + case 4: + return indexed; + case 5: + return reg; + case 6: + return regdef; + case 7: + return autodec; + case 8: + return usesreg != 0xe ? autoinc : immediate; + case 9: + return usesreg != PC ? autoincdef : absolute; + case 10: + return usesreg != PC ? bytedisp : byterel; + case 11: + return usesreg != PC ? bytedispdef : bytereldef; + case 12: + return usesreg != PC ? worddisp : wordrel; + case 13: + return usesreg != PC ? worddispdef : wordreldef; + case 14: + return usesreg != PC ? longdisp : longrel; + case 15: + return usesreg != PC ? longdispdef : longreldef; + } + /* NOTREACHED */ + abort (); +} + +char * +tahoe_operandname (mode) + tahoe_operandenum mode; +{ + + switch (mode) + { + case literal: + return "literal"; + case indexed: + return "indexed"; + case reg: + return "register"; + case regdef: + return "register deferred"; + case autodec: + return "autodecrement"; + case autoinc: + return "autoincrement"; + case autoincdef: + return "autoincrement deferred"; + case bytedisp: + return "byte displacement"; + case bytedispdef: + return "byte displacement deferred"; + case byterel: + return "byte relative"; + case bytereldef: + return "byte relative deferred"; + case worddisp: + return "word displacement"; + case worddispdef: + return "word displacement deferred"; + case wordrel: + return "word relative"; + case wordreldef: + return "word relative deferred"; + case immediate: + return "immediate"; + case absolute: + return "absolute"; + case longdisp: + return "long displacement"; + case longdispdef: + return "long displacement deferred"; + case longrel: + return "long relative"; + case longreldef: + return "long relative deferred"; + } + /* NOTREACHED */ + abort (); +} + +long +tahoe_operandlength (modep) + unsigned char *modep; +{ + + switch (tahoe_operandmode (modep)) + { + case literal: + case reg: + case regdef: + case autodec: + case autoinc: + case autoincdef: + return 1; + case bytedisp: + case bytedispdef: + case byterel: + case bytereldef: + return 2; + case worddisp: + case worddispdef: + case wordrel: + case wordreldef: + return 3; + case immediate: + case absolute: + case longdisp: + case longdispdef: + case longrel: + case longreldef: + return 5; + case indexed: + return 1 + tahoe_operandlength (modep + 1); + } + /* NOTREACHED */ + abort (); +} + +bfd_vma +tahoe_reladdr (modep) + char *modep; +{ + tahoe_operandenum mode = tahoe_operandmode (modep); + char *cp; + short *sp; + long *lp; + int i; + long value = 0; + + cp = modep; + ++cp; /* skip over the mode */ + switch (mode) + { + default: + fprintf (stderr, "[reladdr] not relative address\n"); + return (bfd_vma) modep; + case byterel: + return (bfd_vma) (cp + sizeof *cp + *cp); + case wordrel: + for (i = 0; (size_t) i < sizeof *sp; i++) + value = (value << 8) + (cp[i] & 0xff); + return (bfd_vma) (cp + sizeof *sp + value); + case longrel: + for (i = 0; (size_t) i < sizeof *lp; i++) + value = (value << 8) + (cp[i] & 0xff); + return (bfd_vma) (cp + sizeof *lp + value); + } +} + +void +tahoe_find_call (parent, p_lowpc, p_highpc) + Sym *parent; + bfd_vma p_lowpc; + bfd_vma p_highpc; +{ + unsigned char *instructp; + long length; + Sym *child; + tahoe_operandenum mode; + tahoe_operandenum firstmode; + bfd_vma destpc; + static bool inited = FALSE; + + if (!inited) + { + inited = TRUE; + sym_init (&indirectchild); + indirectchild.cg.prop.fract = 1.0; + indirectchild.cg.cyc.head = &indirectchild; + } + + if (core_text_space == 0) + { + return; + } + if (p_lowpc < s_lowpc) + { + p_lowpc = s_lowpc; + } + if (p_highpc > s_highpc) + { + p_highpc = s_highpc; + } + DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n", + parent->name, p_lowpc, p_highpc)); + for (instructp = (unsigned char *) core_text_space + p_lowpc; + instructp < (unsigned char *) core_text_space + p_highpc; + instructp += length) + { + length = 1; + if (*instructp == CALLF) + { + /* + * maybe a callf, better check it out. + * skip the count of the number of arguments. + */ + DBG (CALLDEBUG, printf ("[findcall]\t0x%x:callf", + instructp - (unsigned char *) core_text_space)); + firstmode = tahoe_operandmode (instructp + length); + switch (firstmode) + { + case literal: + case immediate: + break; + default: + goto botched; + } + length += tahoe_operandlength (instructp + length); + mode = tahoe_operandmode (instructp + length); + DBG (CALLDEBUG, + printf ("\tfirst operand is %s", tahoe_operandname (firstmode)); + printf ("\tsecond operand is %s\n", tahoe_operandname (mode)); + ); + switch (mode) + { + case regdef: + case bytedispdef: + case worddispdef: + case longdispdef: + case bytereldef: + case wordreldef: + case longreldef: + /* + * indirect call: call through pointer + * either *d(r) as a parameter or local + * (r) as a return value + * *f as a global pointer + * [are there others that we miss?, + * e.g. arrays of pointers to functions???] + */ + arc_add (parent, &indirectchild, (unsigned long) 0); + length += tahoe_operandlength (instructp + length); + continue; + case byterel: + case wordrel: + case longrel: + /* + * regular pc relative addressing + * check that this is the address of + * a function. + */ + destpc = tahoe_reladdr (instructp + length) + - (bfd_vma) core_text_space; + if (destpc >= s_lowpc && destpc <= s_highpc) + { + child = sym_lookup (&symtab, destpc); + DBG (CALLDEBUG, + printf ("[findcall]\tdestpc 0x%lx", destpc); + printf (" child->name %s", child->name); + printf (" child->addr 0x%lx\n", child->addr); + ); + if (child->addr == destpc) + { + /* + * a hit + */ + arc_add (parent, child, (unsigned long) 0); + length += tahoe_operandlength (instructp + length); + continue; + } + goto botched; + } + /* + * else: + * it looked like a callf, + * but it wasn't to anywhere. + */ + goto botched; + default: + botched: + /* + * something funny going on. + */ + DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n")); + length = 1; + continue; + } + } + } +} diff --git a/gprof/utils.c b/gprof/utils.c new file mode 100644 index 0000000..e1f031d --- /dev/null +++ b/gprof/utils.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1983, 1998 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. + */ +#include +#include "gprof.h" +#include "cg_arcs.h" +#include "symtab.h" + + +/* + * Print name of symbol. Return number of characters printed. + */ +int +DEFUN (print_name_only, (self), Sym * self) +{ + const char *name = self->name; + const char *filename; + char *demangled = 0; + char buf[PATH_MAX]; + int size = 0; + + if (name) + { + if (!bsd_style_output) + { + if (name[0] == '_' && name[1] && discard_underscores) + { + name++; + } + if (demangle) + { + demangled = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS); + if (demangled) + { + name = demangled; + } + } + } + printf ("%s", name); + size = strlen (name); + if (line_granularity && self->file) + { + filename = self->file->name; + if (!print_path) + { + filename = strrchr (filename, '/'); + if (filename) + { + ++filename; + } + else + { + filename = self->file->name; + } + } + sprintf (buf, " (%s:%d)", filename, self->line_num); + printf (buf); + size += strlen (buf); + } + if (demangled) + { + free (demangled); + } + DBG (DFNDEBUG, printf ("{%d} ", self->cg.top_order)); + DBG (PROPDEBUG, printf ("%4.0f%% ", 100.0 * self->cg.prop.fract)); + } + return size; +} + + +void +DEFUN (print_name, (self), Sym * self) +{ + print_name_only (self); + + if (self->cg.cyc.num != 0) + { + printf (_(" "), self->cg.cyc.num); + } + if (self->cg.index != 0) + { + if (self->cg.print_flag) + { + printf (" [%d]", self->cg.index); + } + else + { + printf (" (%d)", self->cg.index); + } + } +} diff --git a/gprof/utils.h b/gprof/utils.h new file mode 100644 index 0000000..27fb9c6 --- /dev/null +++ b/gprof/utils.h @@ -0,0 +1,7 @@ +#ifndef utils_h +#define utils_h + +extern int print_name_only PARAMS ((Sym * self)); +extern void print_name PARAMS ((Sym * self)); + +#endif /* utils_h */ diff --git a/gprof/vax.c b/gprof/vax.c new file mode 100644 index 0000000..1a7bd8d --- /dev/null +++ b/gprof/vax.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 1983 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. + */ +#include "gprof.h" +#include "cg_arcs.h" +#include "corefile.h" +#include "hist.h" +#include "symtab.h" + + /* + * opcode of the `calls' instruction + */ +#define CALLS 0xfb + + /* + * register for pc relative addressing + */ +#define PC 0xf + +enum opermodes + { + literal, indexed, reg, regdef, autodec, autoinc, autoincdef, + bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef, + immediate, absolute, byterel, bytereldef, wordrel, wordreldef, + longrel, longreldef + }; +typedef enum opermodes operandenum; + +struct modebyte + { + unsigned int regfield:4; + unsigned int modefield:4; + }; + +/* + * A symbol to be the child of indirect calls: + */ +Sym indirectchild; + + +static operandenum +vax_operandmode (modep) + struct modebyte *modep; +{ + long usesreg = modep->regfield; + + switch (modep->modefield) + { + case 0: + case 1: + case 2: + case 3: + return literal; + case 4: + return indexed; + case 5: + return reg; + case 6: + return regdef; + case 7: + return autodec; + case 8: + return usesreg != PC ? autoinc : immediate; + case 9: + return usesreg != PC ? autoincdef : absolute; + case 10: + return usesreg != PC ? bytedisp : byterel; + case 11: + return usesreg != PC ? bytedispdef : bytereldef; + case 12: + return usesreg != PC ? worddisp : wordrel; + case 13: + return usesreg != PC ? worddispdef : wordreldef; + case 14: + return usesreg != PC ? longdisp : longrel; + case 15: + return usesreg != PC ? longdispdef : longreldef; + } + /* NOTREACHED */ + abort (); +} + +static char * +vax_operandname (mode) + operandenum mode; +{ + + switch (mode) + { + case literal: + return "literal"; + case indexed: + return "indexed"; + case reg: + return "register"; + case regdef: + return "register deferred"; + case autodec: + return "autodecrement"; + case autoinc: + return "autoincrement"; + case autoincdef: + return "autoincrement deferred"; + case bytedisp: + return "byte displacement"; + case bytedispdef: + return "byte displacement deferred"; + case byterel: + return "byte relative"; + case bytereldef: + return "byte relative deferred"; + case worddisp: + return "word displacement"; + case worddispdef: + return "word displacement deferred"; + case wordrel: + return "word relative"; + case wordreldef: + return "word relative deferred"; + case immediate: + return "immediate"; + case absolute: + return "absolute"; + case longdisp: + return "long displacement"; + case longdispdef: + return "long displacement deferred"; + case longrel: + return "long relative"; + case longreldef: + return "long relative deferred"; + } + /* NOTREACHED */ + abort (); +} + +static long +vax_operandlength (modep) + struct modebyte *modep; +{ + + switch (vax_operandmode (modep)) + { + case literal: + case reg: + case regdef: + case autodec: + case autoinc: + case autoincdef: + return 1; + case bytedisp: + case bytedispdef: + case byterel: + case bytereldef: + return 2; + case worddisp: + case worddispdef: + case wordrel: + case wordreldef: + return 3; + case immediate: + case absolute: + case longdisp: + case longdispdef: + case longrel: + case longreldef: + return 5; + case indexed: + return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1); + } + /* NOTREACHED */ + abort (); +} + +static bfd_vma +vax_reladdr (modep) + struct modebyte *modep; +{ + operandenum mode = vax_operandmode (modep); + char *cp; + short *sp; + long *lp; + + cp = (char *) modep; + ++cp; /* skip over the mode */ + switch (mode) + { + default: + fprintf (stderr, "[reladdr] not relative address\n"); + return (bfd_vma) modep; + case byterel: + return (bfd_vma) (cp + sizeof *cp + *cp); + case wordrel: + sp = (short *) cp; + return (bfd_vma) (cp + sizeof *sp + *sp); + case longrel: + lp = (long *) cp; + return (bfd_vma) (cp + sizeof *lp + *lp); + } +} + + +void +vax_find_call (parent, p_lowpc, p_highpc) + Sym *parent; + bfd_vma p_lowpc; + bfd_vma p_highpc; +{ + unsigned char *instructp; + long length; + Sym *child; + operandenum mode; + operandenum firstmode; + bfd_vma destpc; + static bool inited = FALSE; + + if (!inited) + { + inited = TRUE; + sym_init (&indirectchild); + indirectchild.cg.prop.fract = 1.0; + indirectchild.cg.cyc.head = &indirectchild; + } + + if (core_text_space == 0) + { + return; + } + if (p_lowpc < s_lowpc) + { + p_lowpc = s_lowpc; + } + if (p_highpc > s_highpc) + { + p_highpc = s_highpc; + } + DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n", + parent->name, p_lowpc, p_highpc)); + for (instructp = (unsigned char *) core_text_space + p_lowpc; + instructp < (unsigned char *) core_text_space + p_highpc; + instructp += length) + { + length = 1; + if (*instructp == CALLS) + { + /* + * maybe a calls, better check it out. + * skip the count of the number of arguments. + */ + DBG (CALLDEBUG, + printf ("[findcall]\t0x%x:calls", + instructp - (unsigned char *) core_text_space)); + firstmode = vax_operandmode ((struct modebyte *) (instructp + length)); + switch (firstmode) + { + case literal: + case immediate: + break; + default: + goto botched; + } + length += vax_operandlength ((struct modebyte *) (instructp + length)); + mode = vax_operandmode ((struct modebyte *) (instructp + length)); + DBG (CALLDEBUG, + printf ("\tfirst operand is %s", vax_operandname (firstmode)); + printf ("\tsecond operand is %s\n", vax_operandname (mode))); + switch (mode) + { + case regdef: + case bytedispdef: + case worddispdef: + case longdispdef: + case bytereldef: + case wordreldef: + case longreldef: + /* + * indirect call: call through pointer + * either *d(r) as a parameter or local + * (r) as a return value + * *f as a global pointer + * [are there others that we miss?, + * e.g. arrays of pointers to functions???] + */ + arc_add (parent, &indirectchild, (unsigned long) 0); + length += vax_operandlength ( + (struct modebyte *) (instructp + length)); + continue; + case byterel: + case wordrel: + case longrel: + /* + * regular pc relative addressing + * check that this is the address of + * a function. + */ + destpc = vax_reladdr ((struct modebyte *) (instructp + length)) + - (bfd_vma) core_text_space; + if (destpc >= s_lowpc && destpc <= s_highpc) + { + child = sym_lookup (&symtab, destpc); + DBG (CALLDEBUG, + printf ("[findcall]\tdestpc 0x%lx", destpc); + printf (" child->name %s", child->name); + printf (" child->addr 0x%lx\n", child->addr); + ); + if (child->addr == destpc) + { + /* + * a hit + */ + arc_add (parent, child, (unsigned long) 0); + length += vax_operandlength ((struct modebyte *) + (instructp + length)); + continue; + } + goto botched; + } + /* + * else: + * it looked like a calls, + * but it wasn't to anywhere. + */ + goto botched; + default: + botched: + /* + * something funny going on. + */ + DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n")); + length = 1; + continue; + } + } + } +} -- cgit v1.1