1 /* gmon_io.c - Input and output from/to gmon.out files. 2 3 Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 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 2 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 "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 38 enum gmon_ptr_size { 39 ptr_32bit, 40 ptr_64bit 41 }; 42 43 enum gmon_ptr_signedness { 44 ptr_signed, 45 ptr_unsigned 46 }; 47 48 static enum gmon_ptr_size gmon_get_ptr_size (void); 49 static enum gmon_ptr_signedness gmon_get_ptr_signedness (void); 50 51 #ifdef BFD_HOST_U_64_BIT 52 static int gmon_io_read_64 (FILE *, BFD_HOST_U_64_BIT *); 53 static int gmon_io_write_64 (FILE *, BFD_HOST_U_64_BIT); 54 #endif 55 static int gmon_read_raw_arc 56 (FILE *, bfd_vma *, bfd_vma *, unsigned long *); 57 static int gmon_write_raw_arc 58 (FILE *, bfd_vma, bfd_vma, unsigned long); 59 60 int gmon_input = 0; 61 int gmon_file_version = 0; /* 0 == old (non-versioned) file format. */ 62 63 static enum gmon_ptr_size 64 gmon_get_ptr_size () 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 89 static enum gmon_ptr_signedness 90 gmon_get_ptr_signedness () 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 101 int 102 gmon_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 113 static int 114 gmon_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 125 int 126 gmon_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 160 int 161 gmon_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 168 int 169 gmon_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 180 static int 181 gmon_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 192 int 193 gmon_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 213 int 214 gmon_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 224 int 225 gmon_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 232 static int 233 gmon_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 266 static int 267 gmon_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 291 void 292 gmon_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 #ifdef SET_BINARY 304 SET_BINARY (fileno (stdin)); 305 #endif 306 } 307 else 308 { 309 ifp = fopen (filename, FOPEN_RB); 310 311 if (!ifp) 312 { 313 perror (filename); 314 done (1); 315 } 316 } 317 318 if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1) 319 { 320 fprintf (stderr, _("%s: file too short to be a gmon file\n"), 321 filename); 322 done (1); 323 } 324 325 if ((file_format == FF_MAGIC) 326 || (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))) 327 { 328 if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)) 329 { 330 fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), 331 whoami, filename); 332 done (1); 333 } 334 335 /* Right magic, so it's probably really a new gmon.out file. */ 336 gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version); 337 338 if (gmon_file_version != GMON_VERSION && gmon_file_version != 0) 339 { 340 fprintf (stderr, 341 _("%s: file `%s' has unsupported version %d\n"), 342 whoami, filename, gmon_file_version); 343 done (1); 344 } 345 346 /* Read in all the records. */ 347 while (fread (&tag, sizeof (tag), 1, ifp) == 1) 348 { 349 switch (tag) 350 { 351 case GMON_TAG_TIME_HIST: 352 ++nhist; 353 gmon_input |= INPUT_HISTOGRAM; 354 hist_read_rec (ifp, filename); 355 break; 356 357 case GMON_TAG_CG_ARC: 358 ++narcs; 359 gmon_input |= INPUT_CALL_GRAPH; 360 cg_read_rec (ifp, filename); 361 break; 362 363 case GMON_TAG_BB_COUNT: 364 ++nbbs; 365 gmon_input |= INPUT_BB_COUNTS; 366 bb_read_rec (ifp, filename); 367 break; 368 369 default: 370 fprintf (stderr, 371 _("%s: %s: found bad tag %d (file corrupted?)\n"), 372 whoami, filename, tag); 373 done (1); 374 } 375 } 376 } 377 else if (file_format == FF_AUTO 378 || file_format == FF_BSD 379 || file_format == FF_BSD44) 380 { 381 struct hdr 382 { 383 bfd_vma low_pc; 384 bfd_vma high_pc; 385 unsigned int ncnt; 386 }; 387 unsigned int i; 388 int samp_bytes, header_size = 0; 389 unsigned long count; 390 bfd_vma from_pc, self_pc; 391 static struct hdr h; 392 UNIT raw_bin_count; 393 struct hdr tmp; 394 unsigned int version; 395 396 /* Information from a gmon.out file is in two parts: an array of 397 sampling hits within pc ranges, and the arcs. */ 398 gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH; 399 400 /* This fseek() ought to work even on stdin as long as it's 401 not an interactive device (heck, is there anybody who would 402 want to type in a gmon.out at the terminal?). */ 403 if (fseek (ifp, 0, SEEK_SET) < 0) 404 { 405 perror (filename); 406 done (1); 407 } 408 409 /* The beginning of the old BSD header and the 4.4BSD header 410 are the same: lowpc, highpc, ncnt */ 411 if (gmon_io_read_vma (ifp, &tmp.low_pc) 412 || gmon_io_read_vma (ifp, &tmp.high_pc) 413 || gmon_io_read_32 (ifp, &tmp.ncnt)) 414 { 415 bad_gmon_file: 416 fprintf (stderr, _("%s: file too short to be a gmon file\n"), 417 filename); 418 done (1); 419 } 420 421 /* Check to see if this a 4.4BSD-style header. */ 422 if (gmon_io_read_32 (ifp, &version)) 423 goto bad_gmon_file; 424 425 if (version == GMONVERSION) 426 { 427 unsigned int profrate; 428 429 /* 4.4BSD format header. */ 430 if (gmon_io_read_32 (ifp, &profrate)) 431 goto bad_gmon_file; 432 433 if (!s_highpc) 434 hz = profrate; 435 else if (hz != (int) profrate) 436 { 437 fprintf (stderr, 438 _("%s: profiling rate incompatible with first gmon file\n"), 439 filename); 440 done (1); 441 } 442 443 switch (gmon_get_ptr_size ()) 444 { 445 case ptr_32bit: 446 header_size = GMON_HDRSIZE_BSD44_32; 447 break; 448 449 case ptr_64bit: 450 header_size = GMON_HDRSIZE_BSD44_64; 451 break; 452 } 453 } 454 else 455 { 456 /* Old style BSD format. */ 457 if (file_format == FF_BSD44) 458 { 459 fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), 460 whoami, filename); 461 done (1); 462 } 463 464 switch (gmon_get_ptr_size ()) 465 { 466 case ptr_32bit: 467 header_size = GMON_HDRSIZE_OLDBSD_32; 468 break; 469 470 case ptr_64bit: 471 header_size = GMON_HDRSIZE_OLDBSD_64; 472 break; 473 } 474 } 475 476 /* Position the file to after the header. */ 477 if (fseek (ifp, header_size, SEEK_SET) < 0) 478 { 479 perror (filename); 480 done (1); 481 } 482 483 if (s_highpc && (tmp.low_pc != h.low_pc 484 || tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt)) 485 { 486 fprintf (stderr, _("%s: incompatible with first gmon file\n"), 487 filename); 488 done (1); 489 } 490 491 h = tmp; 492 s_lowpc = (bfd_vma) h.low_pc; 493 s_highpc = (bfd_vma) h.high_pc; 494 lowpc = (bfd_vma) h.low_pc / sizeof (UNIT); 495 highpc = (bfd_vma) h.high_pc / sizeof (UNIT); 496 samp_bytes = h.ncnt - header_size; 497 hist_num_bins = samp_bytes / sizeof (UNIT); 498 499 DBG (SAMPLEDEBUG, 500 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n", 501 (unsigned long) h.low_pc, (unsigned long) h.high_pc, 502 h.ncnt); 503 printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n", 504 (unsigned long) s_lowpc, (unsigned long) s_highpc); 505 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n", 506 (unsigned long) lowpc, (unsigned long) highpc); 507 printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n", 508 samp_bytes, hist_num_bins)); 509 510 /* Make sure that we have sensible values. */ 511 if (samp_bytes < 0 || lowpc > highpc) 512 { 513 fprintf (stderr, 514 _("%s: file '%s' does not appear to be in gmon.out format\n"), 515 whoami, filename); 516 done (1); 517 } 518 519 if (hist_num_bins) 520 ++nhist; 521 522 if (!hist_sample) 523 { 524 hist_sample = 525 (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0])); 526 527 memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0])); 528 } 529 530 for (i = 0; i < hist_num_bins; ++i) 531 { 532 if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1) 533 { 534 fprintf (stderr, 535 _("%s: unexpected EOF after reading %d/%d bins\n"), 536 whoami, --i, hist_num_bins); 537 done (1); 538 } 539 540 hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count); 541 } 542 543 /* The rest of the file consists of a bunch of 544 <from,self,count> tuples. */ 545 while (gmon_read_raw_arc (ifp, &from_pc, &self_pc, &count) == 0) 546 { 547 ++narcs; 548 549 DBG (SAMPLEDEBUG, 550 printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n", 551 (unsigned long) from_pc, (unsigned long) self_pc, count)); 552 553 /* Add this arc. */ 554 cg_tally (from_pc, self_pc, count); 555 } 556 557 fclose (ifp); 558 559 if (hz == HZ_WRONG) 560 { 561 /* How many ticks per second? If we can't tell, report 562 time in ticks. */ 563 hz = hertz (); 564 565 if (hz == HZ_WRONG) 566 { 567 hz = 1; 568 fprintf (stderr, _("time is in ticks, not seconds\n")); 569 } 570 } 571 } 572 else 573 { 574 fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), 575 whoami, file_format); 576 done (1); 577 } 578 579 if (output_style & STYLE_GMON_INFO) 580 { 581 printf (_("File `%s' (version %d) contains:\n"), 582 filename, gmon_file_version); 583 printf (nhist == 1 ? 584 _("\t%d histogram record\n") : 585 _("\t%d histogram records\n"), nhist); 586 printf (narcs == 1 ? 587 _("\t%d call-graph record\n") : 588 _("\t%d call-graph records\n"), narcs); 589 printf (nbbs == 1 ? 590 _("\t%d basic-block count record\n") : 591 _("\t%d basic-block count records\n"), nbbs); 592 first_output = FALSE; 593 } 594 } 595 596 597 void 598 gmon_out_write (const char *filename) 599 { 600 FILE *ofp; 601 struct gmon_hdr ghdr; 602 603 ofp = fopen (filename, FOPEN_WB); 604 if (!ofp) 605 { 606 perror (filename); 607 done (1); 608 } 609 610 if (file_format == FF_AUTO || file_format == FF_MAGIC) 611 { 612 /* Write gmon header. */ 613 614 memcpy (&ghdr.cookie[0], GMON_MAGIC, 4); 615 bfd_put_32 (core_bfd, (bfd_vma) GMON_VERSION, (bfd_byte *) ghdr.version); 616 617 if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1) 618 { 619 perror (filename); 620 done (1); 621 } 622 623 /* Write execution time histogram if we have one. */ 624 if (gmon_input & INPUT_HISTOGRAM) 625 hist_write_hist (ofp, filename); 626 627 /* Write call graph arcs if we have any. */ 628 if (gmon_input & INPUT_CALL_GRAPH) 629 cg_write_arcs (ofp, filename); 630 631 /* Write basic-block info if we have it. */ 632 if (gmon_input & INPUT_BB_COUNTS) 633 bb_write_blocks (ofp, filename); 634 } 635 else if (file_format == FF_BSD || file_format == FF_BSD44) 636 { 637 UNIT raw_bin_count; 638 unsigned int i, hdrsize; 639 unsigned padsize; 640 char pad[3*4]; 641 Arc *arc; 642 Sym *sym; 643 644 memset (pad, 0, sizeof (pad)); 645 646 hdrsize = 0; 647 /* Decide how large the header will be. Use the 4.4BSD format 648 header if explicitly specified, or if the profiling rate is 649 non-standard. Otherwise, use the old BSD format. */ 650 if (file_format == FF_BSD44 651 || hz != hertz()) 652 { 653 padsize = 3*4; 654 switch (gmon_get_ptr_size ()) 655 { 656 case ptr_32bit: 657 hdrsize = GMON_HDRSIZE_BSD44_32; 658 break; 659 660 case ptr_64bit: 661 hdrsize = GMON_HDRSIZE_BSD44_64; 662 break; 663 } 664 } 665 else 666 { 667 padsize = 0; 668 switch (gmon_get_ptr_size ()) 669 { 670 case ptr_32bit: 671 hdrsize = GMON_HDRSIZE_OLDBSD_32; 672 break; 673 674 case ptr_64bit: 675 hdrsize = GMON_HDRSIZE_OLDBSD_64; 676 /* FIXME: Checking host compiler defines here means that we can't 677 use a cross gprof alpha OSF. */ 678 #if defined(__alpha__) && defined (__osf__) 679 padsize = 4; 680 #endif 681 break; 682 } 683 } 684 685 /* Write the parts of the headers that are common to both the 686 old BSD and 4.4BSD formats. */ 687 if (gmon_io_write_vma (ofp, s_lowpc) 688 || gmon_io_write_vma (ofp, s_highpc) 689 || gmon_io_write_32 (ofp, hist_num_bins * sizeof (UNIT) + hdrsize)) 690 { 691 perror (filename); 692 done (1); 693 } 694 695 /* Write out the 4.4BSD header bits, if that's what we're using. */ 696 if (file_format == FF_BSD44 697 || hz != hertz()) 698 { 699 if (gmon_io_write_32 (ofp, GMONVERSION) 700 || gmon_io_write_32 (ofp, (unsigned int) hz)) 701 { 702 perror (filename); 703 done (1); 704 } 705 } 706 707 /* Now write out any necessary padding after the meaningful 708 header bits. */ 709 if (padsize != 0 710 && fwrite (pad, 1, padsize, ofp) != padsize) 711 { 712 perror (filename); 713 done (1); 714 } 715 716 /* Dump the samples. */ 717 for (i = 0; i < hist_num_bins; ++i) 718 { 719 bfd_put_16 (core_bfd, (bfd_vma) hist_sample[i], 720 (bfd_byte *) &raw_bin_count[0]); 721 if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1) 722 { 723 perror (filename); 724 done (1); 725 } 726 } 727 728 /* Dump the normalized raw arc information. */ 729 for (sym = symtab.base; sym < symtab.limit; ++sym) 730 { 731 for (arc = sym->cg.children; arc; arc = arc->next_child) 732 { 733 if (gmon_write_raw_arc (ofp, arc->parent->addr, 734 arc->child->addr, arc->count)) 735 { 736 perror (filename); 737 done (1); 738 } 739 DBG (SAMPLEDEBUG, 740 printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n", 741 (unsigned long) arc->parent->addr, 742 (unsigned long) arc->child->addr, arc->count)); 743 } 744 } 745 746 fclose (ofp); 747 } 748 else 749 { 750 fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), 751 whoami, file_format); 752 done (1); 753 } 754 } 755