1 /* hist.c - Histogram related operations. 2 3 Copyright (C) 1999-2020 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 PTR, const PTR); 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 PTR lp, const PTR 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 } 755