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