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