1/* gmon_io.c - Input and output from/to gmon.out files. 2 3 Copyright (C) 1999-2017 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 "binary-io.h" 24#include "search_list.h" 25#include "source.h" 26#include "symtab.h" 27#include "cg_arcs.h" 28#include "basic_blocks.h" 29#include "corefile.h" 30#include "call_graph.h" 31#include "gmon_io.h" 32#include "gmon_out.h" 33#include "gmon.h" /* Fetch header for old format. */ 34#include "hertz.h" 35#include "hist.h" 36#include "libiberty.h" 37 38enum gmon_ptr_size { 39 ptr_32bit, 40 ptr_64bit 41}; 42 43enum gmon_ptr_signedness { 44 ptr_signed, 45 ptr_unsigned 46}; 47 48static enum gmon_ptr_size gmon_get_ptr_size (void); 49static enum gmon_ptr_signedness gmon_get_ptr_signedness (void); 50 51#ifdef BFD_HOST_U_64_BIT 52static int gmon_io_read_64 (FILE *, BFD_HOST_U_64_BIT *); 53static int gmon_io_write_64 (FILE *, BFD_HOST_U_64_BIT); 54#endif 55static int gmon_read_raw_arc 56 (FILE *, bfd_vma *, bfd_vma *, unsigned long *); 57static int gmon_write_raw_arc 58 (FILE *, bfd_vma, bfd_vma, unsigned long); 59 60int gmon_input = 0; 61int gmon_file_version = 0; /* 0 == old (non-versioned) file format. */ 62 63static enum gmon_ptr_size 64gmon_get_ptr_size (void) 65{ 66 int size; 67 68 /* Pick best size for pointers. Start with the ELF size, and if not 69 elf go with the architecture's address size. */ 70 size = bfd_get_arch_size (core_bfd); 71 if (size == -1) 72 size = bfd_arch_bits_per_address (core_bfd); 73 74 switch (size) 75 { 76 case 32: 77 return ptr_32bit; 78 79 case 64: 80 return ptr_64bit; 81 82 default: 83 fprintf (stderr, _("%s: address size has unexpected value of %u\n"), 84 whoami, size); 85 done (1); 86 } 87} 88 89static enum gmon_ptr_signedness 90gmon_get_ptr_signedness (void) 91{ 92 int sext; 93 94 /* Figure out whether to sign extend. If BFD doesn't know, assume no. */ 95 sext = bfd_get_sign_extend_vma (core_bfd); 96 if (sext == -1) 97 return ptr_unsigned; 98 return (sext ? ptr_signed : ptr_unsigned); 99} 100 101int 102gmon_io_read_32 (FILE *ifp, unsigned int *valp) 103{ 104 char buf[4]; 105 106 if (fread (buf, 1, 4, ifp) != 4) 107 return 1; 108 *valp = bfd_get_32 (core_bfd, buf); 109 return 0; 110} 111 112#ifdef BFD_HOST_U_64_BIT 113static int 114gmon_io_read_64 (FILE *ifp, BFD_HOST_U_64_BIT *valp) 115{ 116 char buf[8]; 117 118 if (fread (buf, 1, 8, ifp) != 8) 119 return 1; 120 *valp = bfd_get_64 (core_bfd, buf); 121 return 0; 122} 123#endif 124 125int 126gmon_io_read_vma (FILE *ifp, bfd_vma *valp) 127{ 128 unsigned int val32; 129#ifdef BFD_HOST_U_64_BIT 130 BFD_HOST_U_64_BIT val64; 131#endif 132 133 switch (gmon_get_ptr_size ()) 134 { 135 case ptr_32bit: 136 if (gmon_io_read_32 (ifp, &val32)) 137 return 1; 138 if (gmon_get_ptr_signedness () == ptr_signed) 139 *valp = (int) val32; 140 else 141 *valp = val32; 142 break; 143 144#ifdef BFD_HOST_U_64_BIT 145 case ptr_64bit: 146 if (gmon_io_read_64 (ifp, &val64)) 147 return 1; 148#ifdef BFD_HOST_64_BIT 149 if (gmon_get_ptr_signedness () == ptr_signed) 150 *valp = (BFD_HOST_64_BIT) val64; 151 else 152#endif 153 *valp = val64; 154 break; 155#endif 156 } 157 return 0; 158} 159 160int 161gmon_io_read (FILE *ifp, char *buf, size_t n) 162{ 163 if (fread (buf, 1, n, ifp) != n) 164 return 1; 165 return 0; 166} 167 168int 169gmon_io_write_32 (FILE *ofp, unsigned int val) 170{ 171 char buf[4]; 172 173 bfd_put_32 (core_bfd, (bfd_vma) val, buf); 174 if (fwrite (buf, 1, 4, ofp) != 4) 175 return 1; 176 return 0; 177} 178 179#ifdef BFD_HOST_U_64_BIT 180static int 181gmon_io_write_64 (FILE *ofp, BFD_HOST_U_64_BIT val) 182{ 183 char buf[8]; 184 185 bfd_put_64 (core_bfd, (bfd_vma) val, buf); 186 if (fwrite (buf, 1, 8, ofp) != 8) 187 return 1; 188 return 0; 189} 190#endif 191 192int 193gmon_io_write_vma (FILE *ofp, bfd_vma val) 194{ 195 196 switch (gmon_get_ptr_size ()) 197 { 198 case ptr_32bit: 199 if (gmon_io_write_32 (ofp, (unsigned int) val)) 200 return 1; 201 break; 202 203#ifdef BFD_HOST_U_64_BIT 204 case ptr_64bit: 205 if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) val)) 206 return 1; 207 break; 208#endif 209 } 210 return 0; 211} 212 213int 214gmon_io_write_8 (FILE *ofp, unsigned int val) 215{ 216 char buf[1]; 217 218 bfd_put_8 (core_bfd, val, buf); 219 if (fwrite (buf, 1, 1, ofp) != 1) 220 return 1; 221 return 0; 222} 223 224int 225gmon_io_write (FILE *ofp, char *buf, size_t n) 226{ 227 if (fwrite (buf, 1, n, ofp) != n) 228 return 1; 229 return 0; 230} 231 232static int 233gmon_read_raw_arc (FILE *ifp, bfd_vma *fpc, bfd_vma *spc, unsigned long *cnt) 234{ 235#ifdef BFD_HOST_U_64_BIT 236 BFD_HOST_U_64_BIT cnt64; 237#endif 238 unsigned int cnt32; 239 240 if (gmon_io_read_vma (ifp, fpc) 241 || gmon_io_read_vma (ifp, spc)) 242 return 1; 243 244 switch (gmon_get_ptr_size ()) 245 { 246 case ptr_32bit: 247 if (gmon_io_read_32 (ifp, &cnt32)) 248 return 1; 249 *cnt = cnt32; 250 break; 251 252#ifdef BFD_HOST_U_64_BIT 253 case ptr_64bit: 254 if (gmon_io_read_64 (ifp, &cnt64)) 255 return 1; 256 *cnt = cnt64; 257 break; 258#endif 259 260 default: 261 return 1; 262 } 263 return 0; 264} 265 266static int 267gmon_write_raw_arc (FILE *ofp, bfd_vma fpc, bfd_vma spc, unsigned long cnt) 268{ 269 270 if (gmon_io_write_vma (ofp, fpc) 271 || gmon_io_write_vma (ofp, spc)) 272 return 1; 273 274 switch (gmon_get_ptr_size ()) 275 { 276 case ptr_32bit: 277 if (gmon_io_write_32 (ofp, (unsigned int) cnt)) 278 return 1; 279 break; 280 281#ifdef BFD_HOST_U_64_BIT 282 case ptr_64bit: 283 if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) cnt)) 284 return 1; 285 break; 286#endif 287 } 288 return 0; 289} 290 291void 292gmon_out_read (const char *filename) 293{ 294 FILE *ifp; 295 struct gmon_hdr ghdr; 296 unsigned char tag; 297 int nhist = 0, narcs = 0, nbbs = 0; 298 299 /* Open gmon.out file. */ 300 if (strcmp (filename, "-") == 0) 301 { 302 ifp = stdin; 303 SET_BINARY (fileno (stdin)); 304 } 305 else 306 { 307 ifp = fopen (filename, FOPEN_RB); 308 309 if (!ifp) 310 { 311 perror (filename); 312 done (1); 313 } 314 } 315 316 if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1) 317 { 318 fprintf (stderr, _("%s: file too short to be a gmon file\n"), 319 filename); 320 done (1); 321 } 322 323 if ((file_format == FF_MAGIC) 324 || (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))) 325 { 326 if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)) 327 { 328 fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), 329 whoami, filename); 330 done (1); 331 } 332 333 /* Right magic, so it's probably really a new gmon.out file. */ 334 gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version); 335 336 if (gmon_file_version != GMON_VERSION && gmon_file_version != 0) 337 { 338 fprintf (stderr, 339 _("%s: file `%s' has unsupported version %d\n"), 340 whoami, filename, gmon_file_version); 341 done (1); 342 } 343 344 /* Read in all the records. */ 345 while (fread (&tag, sizeof (tag), 1, ifp) == 1) 346 { 347 switch (tag) 348 { 349 case GMON_TAG_TIME_HIST: 350 ++nhist; 351 gmon_input |= INPUT_HISTOGRAM; 352 hist_read_rec (ifp, filename); 353 break; 354 355 case GMON_TAG_CG_ARC: 356 ++narcs; 357 gmon_input |= INPUT_CALL_GRAPH; 358 cg_read_rec (ifp, filename); 359 break; 360 361 case GMON_TAG_BB_COUNT: 362 ++nbbs; 363 gmon_input |= INPUT_BB_COUNTS; 364 bb_read_rec (ifp, filename); 365 break; 366 367 default: 368 fprintf (stderr, 369 _("%s: %s: found bad tag %d (file corrupted?)\n"), 370 whoami, filename, tag); 371 done (1); 372 } 373 } 374 } 375 else if (file_format == FF_AUTO 376 || file_format == FF_BSD 377 || file_format == FF_BSD44) 378 { 379 struct hdr 380 { 381 bfd_vma low_pc; 382 bfd_vma high_pc; 383 unsigned int ncnt; 384 }; 385 unsigned int i; 386 int samp_bytes, header_size = 0; 387 unsigned long count; 388 bfd_vma from_pc, self_pc; 389 UNIT raw_bin_count; 390 struct hdr tmp; 391 unsigned int version; 392 unsigned int hist_num_bins; 393 394 /* Information from a gmon.out file is in two parts: an array of 395 sampling hits within pc ranges, and the arcs. */ 396 gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH; 397 398 /* This fseek() ought to work even on stdin as long as it's 399 not an interactive device (heck, is there anybody who would 400 want to type in a gmon.out at the terminal?). */ 401 if (fseek (ifp, 0, SEEK_SET) < 0) 402 { 403 perror (filename); 404 done (1); 405 } 406 407 /* The beginning of the old BSD header and the 4.4BSD header 408 are the same: lowpc, highpc, ncnt */ 409 if (gmon_io_read_vma (ifp, &tmp.low_pc) 410 || gmon_io_read_vma (ifp, &tmp.high_pc) 411 || gmon_io_read_32 (ifp, &tmp.ncnt)) 412 { 413 bad_gmon_file: 414 fprintf (stderr, _("%s: file too short to be a gmon file\n"), 415 filename); 416 done (1); 417 } 418 419 /* Check to see if this a 4.4BSD-style header. */ 420 if (gmon_io_read_32 (ifp, &version)) 421 goto bad_gmon_file; 422 423 if (version == GMONVERSION) 424 { 425 unsigned int profrate; 426 427 /* 4.4BSD format header. */ 428 if (gmon_io_read_32 (ifp, &profrate)) 429 goto bad_gmon_file; 430 431 if (!histograms) 432 hz = profrate; 433 else if (hz != (int) profrate) 434 { 435 fprintf (stderr, 436 _("%s: profiling rate incompatible with first gmon file\n"), 437 filename); 438 done (1); 439 } 440 441 switch (gmon_get_ptr_size ()) 442 { 443 case ptr_32bit: 444 header_size = GMON_HDRSIZE_BSD44_32; 445 break; 446 447 case ptr_64bit: 448 header_size = GMON_HDRSIZE_BSD44_64; 449 break; 450 } 451 } 452 else 453 { 454 /* Old style BSD format. */ 455 if (file_format == FF_BSD44) 456 { 457 fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), 458 whoami, filename); 459 done (1); 460 } 461 462 switch (gmon_get_ptr_size ()) 463 { 464 case ptr_32bit: 465 header_size = GMON_HDRSIZE_OLDBSD_32; 466 break; 467 468 case ptr_64bit: 469 header_size = GMON_HDRSIZE_OLDBSD_64; 470 break; 471 } 472 } 473 474 /* Position the file to after the header. */ 475 if (fseek (ifp, header_size, SEEK_SET) < 0) 476 { 477 perror (filename); 478 done (1); 479 } 480 481 samp_bytes = tmp.ncnt - header_size; 482 hist_num_bins = samp_bytes / sizeof (UNIT); 483 if (histograms && (tmp.low_pc != histograms->lowpc 484 || tmp.high_pc != histograms->highpc 485 || (hist_num_bins != histograms->num_bins))) 486 { 487 fprintf (stderr, _("%s: incompatible with first gmon file\n"), 488 filename); 489 done (1); 490 } 491 492 if (!histograms) 493 { 494 num_histograms = 1; 495 histograms = (struct histogram *) xmalloc (sizeof (struct histogram)); 496 histograms->lowpc = tmp.low_pc; 497 histograms->highpc = tmp.high_pc; 498 histograms->num_bins = hist_num_bins; 499 hist_scale = (double)((tmp.high_pc - tmp.low_pc) / sizeof (UNIT)) 500 / hist_num_bins; 501 histograms->sample = (int *) xmalloc (hist_num_bins * sizeof (int)); 502 memset (histograms->sample, 0, 503 hist_num_bins * sizeof (int)); 504 } 505 506 DBG (SAMPLEDEBUG, 507 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n", 508 (unsigned long) tmp.low_pc, (unsigned long) tmp.high_pc, 509 tmp.ncnt); 510 printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n", 511 samp_bytes, hist_num_bins)); 512 513 /* Make sure that we have sensible values. */ 514 if (samp_bytes < 0 || histograms->lowpc > histograms->highpc) 515 { 516 fprintf (stderr, 517 _("%s: file '%s' does not appear to be in gmon.out format\n"), 518 whoami, filename); 519 done (1); 520 } 521 522 if (hist_num_bins) 523 ++nhist; 524 525 for (i = 0; i < hist_num_bins; ++i) 526 { 527 if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1) 528 { 529 fprintf (stderr, 530 _("%s: unexpected EOF after reading %d/%d bins\n"), 531 whoami, --i, hist_num_bins); 532 done (1); 533 } 534 535 histograms->sample[i] 536 += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count); 537 } 538 539 /* The rest of the file consists of a bunch of 540 <from,self,count> tuples. */ 541 while (gmon_read_raw_arc (ifp, &from_pc, &self_pc, &count) == 0) 542 { 543 ++narcs; 544 545 DBG (SAMPLEDEBUG, 546 printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n", 547 (unsigned long) from_pc, (unsigned long) self_pc, count)); 548 549 /* Add this arc. */ 550 cg_tally (from_pc, self_pc, count); 551 } 552 553 if (hz == HZ_WRONG) 554 { 555 /* How many ticks per second? If we can't tell, report 556 time in ticks. */ 557 hz = hertz (); 558 559 if (hz == HZ_WRONG) 560 { 561 hz = 1; 562 fprintf (stderr, _("time is in ticks, not seconds\n")); 563 } 564 } 565 } 566 else 567 { 568 fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), 569 whoami, file_format); 570 done (1); 571 } 572 573 if (ifp != stdin) 574 fclose (ifp); 575 576 if (output_style & STYLE_GMON_INFO) 577 { 578 printf (_("File `%s' (version %d) contains:\n"), 579 filename, gmon_file_version); 580 printf (nhist == 1 ? 581 _("\t%d histogram record\n") : 582 _("\t%d histogram records\n"), nhist); 583 printf (narcs == 1 ? 584 _("\t%d call-graph record\n") : 585 _("\t%d call-graph records\n"), narcs); 586 printf (nbbs == 1 ? 587 _("\t%d basic-block count record\n") : 588 _("\t%d basic-block count records\n"), nbbs); 589 first_output = FALSE; 590 } 591} 592 593 594void 595gmon_out_write (const char *filename) 596{ 597 FILE *ofp; 598 struct gmon_hdr ghdr; 599 600 ofp = fopen (filename, FOPEN_WB); 601 if (!ofp) 602 { 603 perror (filename); 604 done (1); 605 } 606 607 if (file_format == FF_AUTO || file_format == FF_MAGIC) 608 { 609 /* Write gmon header. */ 610 611 memcpy (&ghdr.cookie[0], GMON_MAGIC, 4); 612 bfd_put_32 (core_bfd, (bfd_vma) GMON_VERSION, (bfd_byte *) ghdr.version); 613 614 if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1) 615 { 616 perror (filename); 617 done (1); 618 } 619 620 /* Write execution time histogram if we have one. */ 621 if (gmon_input & INPUT_HISTOGRAM) 622 hist_write_hist (ofp, filename); 623 624 /* Write call graph arcs if we have any. */ 625 if (gmon_input & INPUT_CALL_GRAPH) 626 cg_write_arcs (ofp, filename); 627 628 /* Write basic-block info if we have it. */ 629 if (gmon_input & INPUT_BB_COUNTS) 630 bb_write_blocks (ofp, filename); 631 } 632 else if (file_format == FF_BSD || file_format == FF_BSD44) 633 { 634 UNIT raw_bin_count; 635 unsigned int i, hdrsize; 636 unsigned padsize; 637 char pad[3*4]; 638 Arc *arc; 639 Sym *sym; 640 641 memset (pad, 0, sizeof (pad)); 642 643 hdrsize = 0; 644 /* Decide how large the header will be. Use the 4.4BSD format 645 header if explicitly specified, or if the profiling rate is 646 non-standard. Otherwise, use the old BSD format. */ 647 if (file_format == FF_BSD44 648 || hz != hertz()) 649 { 650 padsize = 3*4; 651 switch (gmon_get_ptr_size ()) 652 { 653 case ptr_32bit: 654 hdrsize = GMON_HDRSIZE_BSD44_32; 655 break; 656 657 case ptr_64bit: 658 hdrsize = GMON_HDRSIZE_BSD44_64; 659 break; 660 } 661 } 662 else 663 { 664 padsize = 0; 665 switch (gmon_get_ptr_size ()) 666 { 667 case ptr_32bit: 668 hdrsize = GMON_HDRSIZE_OLDBSD_32; 669 break; 670 671 case ptr_64bit: 672 hdrsize = GMON_HDRSIZE_OLDBSD_64; 673 /* FIXME: Checking host compiler defines here means that we can't 674 use a cross gprof alpha OSF. */ 675#if defined(__alpha__) && defined (__osf__) 676 padsize = 4; 677#endif 678 break; 679 } 680 } 681 682 /* Write the parts of the headers that are common to both the 683 old BSD and 4.4BSD formats. */ 684 if (gmon_io_write_vma (ofp, histograms->lowpc) 685 || gmon_io_write_vma (ofp, histograms->highpc) 686 || gmon_io_write_32 (ofp, histograms->num_bins 687 * sizeof (UNIT) + hdrsize)) 688 { 689 perror (filename); 690 done (1); 691 } 692 693 /* Write out the 4.4BSD header bits, if that's what we're using. */ 694 if (file_format == FF_BSD44 695 || hz != hertz()) 696 { 697 if (gmon_io_write_32 (ofp, GMONVERSION) 698 || gmon_io_write_32 (ofp, (unsigned int) hz)) 699 { 700 perror (filename); 701 done (1); 702 } 703 } 704 705 /* Now write out any necessary padding after the meaningful 706 header bits. */ 707 if (padsize != 0 708 && fwrite (pad, 1, padsize, ofp) != padsize) 709 { 710 perror (filename); 711 done (1); 712 } 713 714 /* Dump the samples. */ 715 for (i = 0; i < histograms->num_bins; ++i) 716 { 717 bfd_put_16 (core_bfd, (bfd_vma) histograms->sample[i], 718 (bfd_byte *) &raw_bin_count[0]); 719 if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1) 720 { 721 perror (filename); 722 done (1); 723 } 724 } 725 726 /* Dump the normalized raw arc information. */ 727 for (sym = symtab.base; sym < symtab.limit; ++sym) 728 { 729 for (arc = sym->cg.children; arc; arc = arc->next_child) 730 { 731 if (gmon_write_raw_arc (ofp, arc->parent->addr, 732 arc->child->addr, arc->count)) 733 { 734 perror (filename); 735 done (1); 736 } 737 DBG (SAMPLEDEBUG, 738 printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n", 739 (unsigned long) arc->parent->addr, 740 (unsigned long) arc->child->addr, arc->count)); 741 } 742 } 743 744 fclose (ofp); 745 } 746 else 747 { 748 fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), 749 whoami, file_format); 750 done (1); 751 } 752} 753