1  /* hist.c  -  Histogram related operations.
       2  
       3     Copyright (C) 1999-2023 Free Software Foundation, Inc.
       4  
       5     This file is part of GNU Binutils.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program; if not, write to the Free Software
      19     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
      20     02110-1301, USA.  */
      21  
      22  #include "gprof.h"
      23  #include "libiberty.h"
      24  #include "search_list.h"
      25  #include "source.h"
      26  #include "symtab.h"
      27  #include "corefile.h"
      28  #include "gmon_io.h"
      29  #include "gmon_out.h"
      30  #include "hist.h"
      31  #include "sym_ids.h"
      32  #include "utils.h"
      33  #include "math.h"
      34  #include "stdio.h"
      35  #include "stdlib.h"
      36  
      37  #define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
      38  
      39  static void scale_and_align_entries (void);
      40  static void print_header (int);
      41  static void print_line (Sym *, double);
      42  static int cmp_time (const void *, const void *);
      43  
      44  /* Declarations of automatically generated functions to output blurbs.  */
      45  extern void flat_blurb (FILE * fp);
      46  
      47  static histogram *find_histogram (bfd_vma lowpc, bfd_vma highpc);
      48  static histogram *find_histogram_for_pc (bfd_vma pc);
      49  
      50  histogram * histograms;
      51  unsigned num_histograms;
      52  double hist_scale;
      53  static char hist_dimension[16] = "seconds";
      54  static char hist_dimension_abbrev = 's';
      55  
      56  static double accum_time;	/* Accumulated time so far for print_line(). */
      57  static double total_time;	/* Total time for all routines.  */
      58  
      59  /* Table of SI prefixes for powers of 10 (used to automatically
      60     scale some of the values in the flat profile).  */
      61  const struct
      62    {
      63      char prefix;
      64      double scale;
      65    }
      66  SItab[] =
      67  {
      68    { 'T', 1e-12 },				/* tera */
      69    { 'G', 1e-09 },				/* giga */
      70    { 'M', 1e-06 },				/* mega */
      71    { 'K', 1e-03 },				/* kilo */
      72    { ' ', 1e-00 },
      73    { 'm', 1e+03 },				/* milli */
      74    { 'u', 1e+06 },				/* micro */
      75    { 'n', 1e+09 },				/* nano */
      76    { 'p', 1e+12 },				/* pico */
      77    { 'f', 1e+15 },				/* femto */
      78    { 'a', 1e+18 }				/* ato */
      79  };
      80  
      81  /* Reads just the header part of histogram record into
      82     *RECORD from IFP.  FILENAME is the name of IFP and
      83     is provided for formatting error messages only.
      84  
      85     If FIRST is non-zero, sets global variables HZ, HIST_DIMENSION,
      86     HIST_DIMENSION_ABBREV, HIST_SCALE.  If FIRST is zero, checks
      87     that the new histogram is compatible with already-set values
      88     of those variables and emits an error if that's not so.  */
      89  static void
      90  read_histogram_header (histogram *record,
      91  		       FILE *ifp, const char *filename,
      92  		       int first)
      93  {
      94    unsigned int profrate;
      95    char n_hist_dimension[15];
      96    char n_hist_dimension_abbrev;
      97    double n_hist_scale;
      98  
      99    if (gmon_io_read_vma (ifp, &record->lowpc)
     100        || gmon_io_read_vma (ifp, &record->highpc)
     101        || gmon_io_read_32 (ifp, &record->num_bins)
     102        || gmon_io_read_32 (ifp, &profrate)
     103        || gmon_io_read (ifp, n_hist_dimension, 15)
     104        || gmon_io_read (ifp, &n_hist_dimension_abbrev, 1))
     105      {
     106        fprintf (stderr, _("%s: %s: unexpected end of file\n"),
     107  	       whoami, filename);
     108  
     109        done (1);
     110      }
     111  
     112    n_hist_scale = (double)((record->highpc - record->lowpc) / sizeof (UNIT))
     113      / record->num_bins;
     114  
     115    if (first)
     116      {
     117        /* We don't try to veryfy profrate is the same for all histogram
     118  	 records.  If we have two histogram records for the same
     119  	 address range and profiling samples is done as often
     120  	 as possible as opposed on timer, then the actual profrate will
     121  	 be slightly different.  Most of the time the difference does not
     122  	 matter and insisting that profiling rate is exactly the same
     123  	 will only create inconvenient.  */
     124        hz = profrate;
     125        memcpy (hist_dimension, n_hist_dimension, 15);
     126        hist_dimension_abbrev = n_hist_dimension_abbrev;
     127        hist_scale = n_hist_scale;
     128      }
     129    else
     130      {
     131        if (strncmp (n_hist_dimension, hist_dimension, 15) != 0)
     132  	{
     133  	  fprintf (stderr,
     134  		   _("%s: dimension unit changed between histogram records\n"
     135  		     "%s: from '%s'\n"
     136  		     "%s: to '%s'\n"),
     137  		   whoami, whoami, hist_dimension, whoami, n_hist_dimension);
     138  	  done (1);
     139  	}
     140  
     141        if (n_hist_dimension_abbrev != hist_dimension_abbrev)
     142  	{
     143  	  fprintf (stderr,
     144  		   _("%s: dimension abbreviation changed between histogram records\n"
     145  		     "%s: from '%c'\n"
     146  		     "%s: to '%c'\n"),
     147  		   whoami, whoami, hist_dimension_abbrev, whoami, n_hist_dimension_abbrev);
     148  	  done (1);
     149  	}
     150  
     151        /* The only reason we require the same scale for histograms is that
     152  	 there's code (notably printing code), that prints units,
     153  	 and it would be very confusing to have one unit mean different
     154  	 things for different functions.  */
     155        if (fabs (hist_scale - n_hist_scale) > 0.000001)
     156  	{
     157  	  fprintf (stderr,
     158  		   _("%s: different scales in histogram records"),
     159  		   whoami);
     160  	  done (1);
     161  	}
     162      }
     163  }
     164  
     165  /* Read the histogram from file IFP.  FILENAME is the name of IFP and
     166     is provided for formatting error messages only.  */
     167  
     168  void
     169  hist_read_rec (FILE * ifp, const char *filename)
     170  {
     171    bfd_vma lowpc, highpc;
     172    histogram n_record;
     173    histogram *record, *existing_record;
     174    unsigned i;
     175  
     176    /* 1. Read the header and see if there's existing record for the
     177       same address range and that there are no overlapping records.  */
     178    read_histogram_header (&n_record, ifp, filename, num_histograms == 0);
     179  
     180    existing_record = find_histogram (n_record.lowpc, n_record.highpc);
     181    if (existing_record)
     182      {
     183        record = existing_record;
     184      }
     185    else
     186      {
     187        /* If this record overlaps, but does not completely match an existing
     188  	 record, it's an error.  */
     189        lowpc = n_record.lowpc;
     190        highpc = n_record.highpc;
     191        hist_clip_symbol_address (&lowpc, &highpc);
     192        if (lowpc != highpc)
     193  	{
     194  	  fprintf (stderr,
     195  		   _("%s: overlapping histogram records\n"),
     196  		   whoami);
     197  	  done (1);
     198  	}
     199  
     200        /* This is new record.  Add it to global array and allocate space for
     201  	 the samples.  */
     202        histograms = (struct histogram *)
     203            xrealloc (histograms, sizeof (histogram) * (num_histograms + 1));
     204        memcpy (histograms + num_histograms,
     205  	      &n_record, sizeof (histogram));
     206        record = &histograms[num_histograms];
     207        ++num_histograms;
     208  
     209        record->sample = (int *) xmalloc (record->num_bins
     210  					* sizeof (record->sample[0]));
     211        memset (record->sample, 0, record->num_bins * sizeof (record->sample[0]));
     212      }
     213  
     214    /* 2. We have either a new record (with zeroed histogram data), or an existing
     215       record with some data in the histogram already.  Read new data into the
     216       record, adding hit counts.  */
     217  
     218    DBG (SAMPLEDEBUG,
     219         printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
     220  	       (unsigned long) record->lowpc, (unsigned long) record->highpc,
     221                 record->num_bins));
     222  
     223    for (i = 0; i < record->num_bins; ++i)
     224      {
     225        UNIT count;
     226        if (fread (&count[0], sizeof (count), 1, ifp) != 1)
     227  	{
     228  	  fprintf (stderr,
     229  		  _("%s: %s: unexpected EOF after reading %u of %u samples\n"),
     230  		   whoami, filename, i, record->num_bins);
     231  	  done (1);
     232  	}
     233        record->sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
     234        DBG (SAMPLEDEBUG,
     235  	   printf ("[hist_read_rec] 0x%lx: %u\n",
     236  		   (unsigned long) (record->lowpc
     237                                      + i * (record->highpc - record->lowpc)
     238                                      / record->num_bins),
     239  		   record->sample[i]));
     240      }
     241  }
     242  
     243  
     244  /* Write all execution histograms file OFP.  FILENAME is the name
     245     of OFP and is provided for formatting error-messages only.  */
     246  
     247  void
     248  hist_write_hist (FILE * ofp, const char *filename)
     249  {
     250    UNIT count;
     251    unsigned int i, r;
     252  
     253    for (r = 0; r < num_histograms; ++r)
     254      {
     255        histogram *record = &histograms[r];
     256  
     257        /* Write header.  */
     258  
     259        if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
     260  	  || gmon_io_write_vma (ofp, record->lowpc)
     261  	  || gmon_io_write_vma (ofp, record->highpc)
     262  	  || gmon_io_write_32 (ofp, record->num_bins)
     263  	  || gmon_io_write_32 (ofp, hz)
     264  	  || gmon_io_write (ofp, hist_dimension, 15)
     265  	  || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
     266  	{
     267  	  perror (filename);
     268  	  done (1);
     269  	}
     270  
     271        for (i = 0; i < record->num_bins; ++i)
     272  	{
     273  	  bfd_put_16 (core_bfd, (bfd_vma) record->sample[i], (bfd_byte *) &count[0]);
     274  
     275  	  if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
     276  	    {
     277  	      perror (filename);
     278  	      done (1);
     279  	    }
     280  	}
     281      }
     282  }
     283  
     284  /* Calculate scaled entry point addresses (to save time in
     285     hist_assign_samples), and, on architectures that have procedure
     286     entry masks at the start of a function, possibly push the scaled
     287     entry points over the procedure entry mask, if it turns out that
     288     the entry point is in one bin and the code for a routine is in the
     289     next bin.  */
     290  
     291  static void
     292  scale_and_align_entries (void)
     293  {
     294    Sym *sym;
     295    bfd_vma bin_of_entry;
     296    bfd_vma bin_of_code;
     297  
     298    for (sym = symtab.base; sym < symtab.limit; sym++)
     299      {
     300        histogram *r = find_histogram_for_pc (sym->addr);
     301  
     302        sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
     303  
     304        if (r)
     305  	{
     306  	  bin_of_entry = (sym->hist.scaled_addr - r->lowpc) / hist_scale;
     307  	  bin_of_code = ((sym->hist.scaled_addr + UNITS_TO_CODE - r->lowpc)
     308  		     / hist_scale);
     309  	  if (bin_of_entry < bin_of_code)
     310  	    {
     311  	      DBG (SAMPLEDEBUG,
     312  		   printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
     313  			   (unsigned long) sym->hist.scaled_addr,
     314  			   (unsigned long) (sym->hist.scaled_addr
     315  					    + UNITS_TO_CODE)));
     316  	      sym->hist.scaled_addr += UNITS_TO_CODE;
     317  	    }
     318  	}
     319      }
     320  }
     321  
     322  
     323  /* Assign samples to the symbol to which they belong.
     324  
     325     Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
     326     which may overlap one more symbol address ranges.  If a symbol
     327     overlaps with the bin's address range by O percent, then O percent
     328     of the bin's count is credited to that symbol.
     329  
     330     There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
     331     with respect to the symbol's address range [SYM_LOW_PC,
     332     SYM_HIGH_PC) as shown in the following diagram.  OVERLAP computes
     333     the distance (in UNITs) between the arrows, the fraction of the
     334     sample that is to be credited to the symbol which starts at
     335     SYM_LOW_PC.
     336  
     337  	  sym_low_pc                                      sym_high_pc
     338  	       |                                               |
     339  	       v                                               v
     340  
     341  	       +-----------------------------------------------+
     342  	       |                                               |
     343  	  |  ->|    |<-         ->|         |<-         ->|    |<-  |
     344  	  |         |             |         |             |         |
     345  	  +---------+             +---------+             +---------+
     346  
     347  	  ^         ^             ^         ^             ^         ^
     348  	  |         |             |         |             |         |
     349       bin_low_pc bin_high_pc  bin_low_pc bin_high_pc  bin_low_pc bin_high_pc
     350  
     351     For the VAX we assert that samples will never fall in the first two
     352     bytes of any routine, since that is the entry mask, thus we call
     353     scale_and_align_entries() to adjust the entry points if the entry
     354     mask falls in one bin but the code for the routine doesn't start
     355     until the next bin.  In conjunction with the alignment of routine
     356     addresses, this should allow us to have only one sample for every
     357     four bytes of text space and never have any overlap (the two end
     358     cases, above).  */
     359  
     360  static void
     361  hist_assign_samples_1 (histogram *r)
     362  {
     363    bfd_vma bin_low_pc, bin_high_pc;
     364    bfd_vma sym_low_pc, sym_high_pc;
     365    bfd_vma overlap, addr;
     366    unsigned int bin_count;
     367    unsigned int i, j, k;
     368    double count_time, credit;
     369  
     370    bfd_vma lowpc = r->lowpc / sizeof (UNIT);
     371  
     372    /* Iterate over all sample bins.  */
     373    for (i = 0, k = 1; i < r->num_bins; ++i)
     374      {
     375        bin_count = r->sample[i];
     376        if (! bin_count)
     377  	continue;
     378  
     379        bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
     380        bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
     381        count_time = bin_count;
     382  
     383        DBG (SAMPLEDEBUG,
     384  	   printf (
     385        "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%u\n",
     386  		    (unsigned long) (sizeof (UNIT) * bin_low_pc),
     387  		    (unsigned long) (sizeof (UNIT) * bin_high_pc),
     388  		    bin_count));
     389        total_time += count_time;
     390  
     391        /* Credit all symbols that are covered by bin I.
     392  
     393           PR gprof/13325: Make sure that K does not get decremented
     394  	 and J will never be less than 0.  */
     395        for (j = k - 1; j < symtab.len; k = ++j)
     396  	{
     397  	  sym_low_pc = symtab.base[j].hist.scaled_addr;
     398  	  sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
     399  
     400  	  /* If high end of bin is below entry address,
     401  	     go for next bin.  */
     402  	  if (bin_high_pc < sym_low_pc)
     403  	    break;
     404  
     405  	  /* If low end of bin is above high end of symbol,
     406  	     go for next symbol.  */
     407  	  if (bin_low_pc >= sym_high_pc)
     408  	    continue;
     409  
     410  	  overlap =
     411  	    MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
     412  	  if (overlap > 0)
     413  	    {
     414  	      DBG (SAMPLEDEBUG,
     415  		   printf (
     416  	       "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
     417  			   (unsigned long) symtab.base[j].addr,
     418  			   (unsigned long) (sizeof (UNIT) * sym_high_pc),
     419  			   symtab.base[j].name, overlap * count_time / hist_scale,
     420  			   (long) overlap));
     421  
     422  	      addr = symtab.base[j].addr;
     423  	      credit = overlap * count_time / hist_scale;
     424  
     425  	      /* Credit symbol if it appears in INCL_FLAT or that
     426  		 table is empty and it does not appear it in
     427  		 EXCL_FLAT.  */
     428  	      if (sym_lookup (&syms[INCL_FLAT], addr)
     429  		  || (syms[INCL_FLAT].len == 0
     430  		      && !sym_lookup (&syms[EXCL_FLAT], addr)))
     431  		{
     432  		  symtab.base[j].hist.time += credit;
     433  		}
     434  	      else
     435  		{
     436  		  total_time -= credit;
     437  		}
     438  	    }
     439  	}
     440      }
     441  
     442    DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
     443  			    total_time));
     444  }
     445  
     446  /* Calls 'hist_assign_sampes_1' for all histogram records read so far. */
     447  void
     448  hist_assign_samples (void)
     449  {
     450    unsigned i;
     451  
     452    scale_and_align_entries ();
     453  
     454    for (i = 0; i < num_histograms; ++i)
     455      hist_assign_samples_1 (&histograms[i]);
     456  
     457  }
     458  
     459  /* Print header for flag histogram profile.  */
     460  
     461  static void
     462  print_header (int prefix)
     463  {
     464    char unit[64];
     465  
     466    sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
     467  
     468    if (bsd_style_output)
     469      {
     470        printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
     471  	      (long) hist_scale * (long) sizeof (UNIT));
     472        if (total_time > 0.0)
     473  	{
     474  	  printf (_(" for %.2f%% of %.2f %s\n\n"),
     475  		  100.0 / total_time, total_time / hz, hist_dimension);
     476  	}
     477      }
     478    else
     479      {
     480        printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
     481      }
     482  
     483    if (total_time <= 0.0)
     484      {
     485        printf (_(" no time accumulated\n\n"));
     486  
     487        /* This doesn't hurt since all the numerators will be zero.  */
     488        total_time = 1.0;
     489      }
     490  
     491    printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
     492  	  "%  ", _("cumulative"), _("self  "), "", _("self  "), _("total "),
     493  	  "");
     494    printf ("%5.5s %9.9s  %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
     495  	  _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
     496  	  _("name"));
     497  }
     498  
     499  
     500  static void
     501  print_line (Sym *sym, double scale)
     502  {
     503    if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
     504      return;
     505  
     506    accum_time += sym->hist.time;
     507  
     508    if (bsd_style_output)
     509      printf ("%5.1f %10.2f %8.2f",
     510  	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
     511  	    accum_time / hz, sym->hist.time / hz);
     512    else
     513      printf ("%6.2f %9.2f %8.2f",
     514  	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
     515  	    accum_time / hz, sym->hist.time / hz);
     516  
     517    if (sym->ncalls != 0)
     518      printf (" %8lu %8.2f %8.2f  ",
     519  	    sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
     520  	    scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
     521    else
     522      printf (" %8.8s %8.8s %8.8s  ", "", "", "");
     523  
     524    if (bsd_style_output)
     525      print_name (sym);
     526    else
     527      print_name_only (sym);
     528  
     529    printf ("\n");
     530  }
     531  
     532  
     533  /* Compare LP and RP.  The primary comparison key is execution time,
     534     the secondary is number of invocation, and the tertiary is the
     535     lexicographic order of the function names.  */
     536  
     537  static int
     538  cmp_time (const void *lp, const void *rp)
     539  {
     540    const Sym *left = *(const Sym **) lp;
     541    const Sym *right = *(const Sym **) rp;
     542    double time_diff;
     543  
     544    time_diff = right->hist.time - left->hist.time;
     545  
     546    if (time_diff > 0.0)
     547      return 1;
     548  
     549    if (time_diff < 0.0)
     550      return -1;
     551  
     552    if (right->ncalls > left->ncalls)
     553      return 1;
     554  
     555    if (right->ncalls < left->ncalls)
     556      return -1;
     557  
     558    return strcmp (left->name, right->name);
     559  }
     560  
     561  
     562  /* Print the flat histogram profile.  */
     563  
     564  void
     565  hist_print (void)
     566  {
     567    Sym **time_sorted_syms, *top_dog, *sym;
     568    unsigned int sym_index;
     569    unsigned log_scale;
     570    double top_time;
     571    bfd_vma addr;
     572  
     573    if (first_output)
     574      first_output = false;
     575    else
     576      printf ("\f\n");
     577  
     578    accum_time = 0.0;
     579  
     580    if (bsd_style_output)
     581      {
     582        if (print_descriptions)
     583  	{
     584  	  printf (_("\n\n\nflat profile:\n"));
     585  	  flat_blurb (stdout);
     586  	}
     587      }
     588    else
     589      {
     590        printf (_("Flat profile:\n"));
     591      }
     592  
     593    /* Sort the symbol table by time (call-count and name as secondary
     594       and tertiary keys).  */
     595    time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
     596  
     597    for (sym_index = 0; sym_index < symtab.len; ++sym_index)
     598      time_sorted_syms[sym_index] = &symtab.base[sym_index];
     599  
     600    qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
     601  
     602    if (bsd_style_output)
     603      {
     604        log_scale = 5;		/* Milli-seconds is BSD-default.  */
     605      }
     606    else
     607      {
     608        /* Search for symbol with highest per-call
     609  	 execution time and scale accordingly.  */
     610        log_scale = 0;
     611        top_dog = 0;
     612        top_time = 0.0;
     613  
     614        for (sym_index = 0; sym_index < symtab.len; ++sym_index)
     615  	{
     616  	  sym = time_sorted_syms[sym_index];
     617  
     618  	  if (sym->ncalls != 0)
     619  	    {
     620  	      double call_time;
     621  
     622  	      call_time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
     623  
     624  	      if (call_time > top_time)
     625  		{
     626  		  top_dog = sym;
     627  		  top_time = call_time;
     628  		}
     629  	    }
     630  	}
     631  
     632        if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
     633  	{
     634  	  top_time /= hz;
     635  
     636  	  for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
     637  	    {
     638  	      double scaled_value = SItab[log_scale].scale * top_time;
     639  
     640  	      if (scaled_value >= 1.0 && scaled_value < 1000.0)
     641  		break;
     642  	    }
     643  	}
     644      }
     645  
     646    /* For now, the dimension is always seconds.  In the future, we
     647       may also want to support other (pseudo-)dimensions (such as
     648       I-cache misses etc.).  */
     649    print_header (SItab[log_scale].prefix);
     650  
     651    for (sym_index = 0; sym_index < symtab.len; ++sym_index)
     652      {
     653        addr = time_sorted_syms[sym_index]->addr;
     654  
     655        /* Print symbol if its in INCL_FLAT table or that table
     656  	is empty and the symbol is not in EXCL_FLAT.  */
     657        if (sym_lookup (&syms[INCL_FLAT], addr)
     658  	  || (syms[INCL_FLAT].len == 0
     659  	      && !sym_lookup (&syms[EXCL_FLAT], addr)))
     660  	print_line (time_sorted_syms[sym_index], SItab[log_scale].scale);
     661      }
     662  
     663    free (time_sorted_syms);
     664  
     665    if (print_descriptions && !bsd_style_output)
     666      flat_blurb (stdout);
     667  }
     668  
     669  int
     670  hist_check_address (unsigned address)
     671  {
     672    unsigned i;
     673  
     674    for (i = 0; i < num_histograms; ++i)
     675      if (histograms[i].lowpc <= address && address < histograms[i].highpc)
     676        return 1;
     677  
     678    return 0;
     679  }
     680  
     681  #if ! defined(min)
     682  #define min(a,b) (((a)<(b)) ? (a) : (b))
     683  #endif
     684  #if ! defined(max)
     685  #define max(a,b) (((a)>(b)) ? (a) : (b))
     686  #endif
     687  
     688  void
     689  hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc)
     690  {
     691    unsigned i;
     692    int found = 0;
     693  
     694    if (num_histograms == 0)
     695      {
     696        *p_highpc = *p_lowpc;
     697        return;
     698      }
     699  
     700    for (i = 0; i < num_histograms; ++i)
     701      {
     702        bfd_vma common_low, common_high;
     703        common_low = max (histograms[i].lowpc, *p_lowpc);
     704        common_high = min (histograms[i].highpc, *p_highpc);
     705  
     706        if (common_low < common_high)
     707  	{
     708  	  if (found)
     709  	    {
     710  	      fprintf (stderr,
     711  		       _("%s: found a symbol that covers "
     712  			 "several histogram records"),
     713  			 whoami);
     714  	      done (1);
     715  	    }
     716  
     717  	  found = 1;
     718  	  *p_lowpc = common_low;
     719  	  *p_highpc = common_high;
     720  	}
     721      }
     722  
     723    if (!found)
     724      *p_highpc = *p_lowpc;
     725  }
     726  
     727  /* Find and return exising histogram record having the same lowpc and
     728     highpc as passed via the parameters.  Return NULL if nothing is found.
     729     The return value is valid until any new histogram is read.  */
     730  static histogram *
     731  find_histogram (bfd_vma lowpc, bfd_vma highpc)
     732  {
     733    unsigned i;
     734    for (i = 0; i < num_histograms; ++i)
     735      {
     736        if (histograms[i].lowpc == lowpc && histograms[i].highpc == highpc)
     737  	return &histograms[i];
     738      }
     739    return 0;
     740  }
     741  
     742  /* Given a PC, return histogram record which address range include this PC.
     743     Return NULL if there's no such record.  */
     744  static histogram *
     745  find_histogram_for_pc (bfd_vma pc)
     746  {
     747    unsigned i;
     748    for (i = 0; i < num_histograms; ++i)
     749      {
     750        if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
     751  	return &histograms[i];
     752      }
     753    return 0;
     754  }