1 /* gmon_io.c - Input and output from/to gmon.out files.
3 Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
5 This file is part of GNU Binutils.
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 2 of the License, or
10 (at your option) any later version.
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.
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., 59 Temple Place - Suite 330, Boston, MA
23 #include "search_list.h"
27 #include "basic_blocks.h"
29 #include "call_graph.h"
32 #include "gmon.h" /* Fetch header for old format. */
35 #include "libiberty.h"
37 #ifdef BFD_HOST_U_64_BIT
38 static int gmon_io_read_64
PARAMS ((FILE *, BFD_HOST_U_64_BIT
*));
39 static int gmon_io_write_64
PARAMS ((FILE *, BFD_HOST_U_64_BIT
));
41 static int gmon_read_raw_arc
42 PARAMS ((FILE *, bfd_vma
*, bfd_vma
*, unsigned long *));
43 static int gmon_write_raw_arc
44 PARAMS ((FILE *, bfd_vma
, bfd_vma
, unsigned long));
47 int gmon_file_version
= 0; /* 0 == old (non-versioned) file format. */
50 gmon_io_read_32 (ifp
, valp
)
56 if (fread (buf
, 1, 4, ifp
) != 4)
58 *valp
= bfd_get_32 (core_bfd
, buf
);
62 #ifdef BFD_HOST_U_64_BIT
64 gmon_io_read_64 (ifp
, valp
)
66 BFD_HOST_U_64_BIT
*valp
;
70 if (fread (buf
, 1, 8, ifp
) != 8)
72 *valp
= bfd_get_64 (core_bfd
, buf
);
78 gmon_io_read_vma (ifp
, valp
)
83 #ifdef BFD_HOST_U_64_BIT
84 BFD_HOST_U_64_BIT val64
;
87 switch (bfd_arch_bits_per_address (core_bfd
))
90 if (gmon_io_read_32 (ifp
, &val32
))
95 #ifdef BFD_HOST_U_64_BIT
97 if (gmon_io_read_64 (ifp
, &val64
))
104 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
105 whoami
, bfd_arch_bits_per_address (core_bfd
));
112 gmon_io_read (ifp
, buf
, n
)
117 if (fread (buf
, 1, n
, ifp
) != n
)
123 gmon_io_write_32 (ofp
, val
)
129 bfd_put_32 (core_bfd
, (bfd_vma
) val
, buf
);
130 if (fwrite (buf
, 1, 4, ofp
) != 4)
135 #ifdef BFD_HOST_U_64_BIT
137 gmon_io_write_64 (ofp
, val
)
139 BFD_HOST_U_64_BIT val
;
143 bfd_put_64 (core_bfd
, (bfd_vma
) val
, buf
);
144 if (fwrite (buf
, 1, 8, ofp
) != 8)
151 gmon_io_write_vma (ofp
, val
)
156 switch (bfd_arch_bits_per_address (core_bfd
))
159 if (gmon_io_write_32 (ofp
, (unsigned int) val
))
163 #ifdef BFD_HOST_U_64_BIT
165 if (gmon_io_write_64 (ofp
, (BFD_HOST_U_64_BIT
) val
))
171 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
172 whoami
, bfd_arch_bits_per_address (core_bfd
));
179 gmon_io_write_8 (ofp
, val
)
185 bfd_put_8 (core_bfd
, val
, buf
);
186 if (fwrite (buf
, 1, 1, ofp
) != 1)
192 gmon_io_write (ofp
, buf
, n
)
197 if (fwrite (buf
, 1, n
, ofp
) != n
)
203 gmon_read_raw_arc (ifp
, fpc
, spc
, cnt
)
209 #ifdef BFD_HOST_U_64_BIT
210 BFD_HOST_U_64_BIT cnt64
;
214 if (gmon_io_read_vma (ifp
, fpc
)
215 || gmon_io_read_vma (ifp
, spc
))
218 switch (bfd_arch_bits_per_address (core_bfd
))
221 if (gmon_io_read_32 (ifp
, &cnt32
))
226 #ifdef BFD_HOST_U_64_BIT
228 if (gmon_io_read_64 (ifp
, &cnt64
))
235 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
236 whoami
, bfd_arch_bits_per_address (core_bfd
));
243 gmon_write_raw_arc (ofp
, fpc
, spc
, cnt
)
250 if (gmon_io_write_vma (ofp
, fpc
)
251 || gmon_io_write_vma (ofp
, spc
))
254 switch (bfd_arch_bits_per_address (core_bfd
))
257 if (gmon_io_write_32 (ofp
, (unsigned int) cnt
))
261 #ifdef BFD_HOST_U_64_BIT
263 if (gmon_io_write_64 (ofp
, (BFD_HOST_U_64_BIT
) cnt
))
269 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
270 whoami
, bfd_arch_bits_per_address (core_bfd
));
277 gmon_out_read (filename
)
278 const char *filename
;
281 struct gmon_hdr ghdr
;
283 int nhist
= 0, narcs
= 0, nbbs
= 0;
285 /* Open gmon.out file. */
286 if (strcmp (filename
, "-") == 0)
290 SET_BINARY (fileno (stdin
));
295 ifp
= fopen (filename
, FOPEN_RB
);
304 if (fread (&ghdr
, sizeof (struct gmon_hdr
), 1, ifp
) != 1)
306 fprintf (stderr
, _("%s: file too short to be a gmon file\n"),
311 if ((file_format
== FF_MAGIC
)
312 || (file_format
== FF_AUTO
&& !strncmp (&ghdr
.cookie
[0], GMON_MAGIC
, 4)))
314 if (file_format
== FF_MAGIC
&& strncmp (&ghdr
.cookie
[0], GMON_MAGIC
, 4))
316 fprintf (stderr
, _("%s: file `%s' has bad magic cookie\n"),
321 /* Right magic, so it's probably really a new gmon.out file. */
322 gmon_file_version
= bfd_get_32 (core_bfd
, (bfd_byte
*) ghdr
.version
);
324 if (gmon_file_version
!= GMON_VERSION
&& gmon_file_version
!= 0)
327 _("%s: file `%s' has unsupported version %d\n"),
328 whoami
, filename
, gmon_file_version
);
332 /* Read in all the records. */
333 while (fread (&tag
, sizeof (tag
), 1, ifp
) == 1)
337 case GMON_TAG_TIME_HIST
:
339 gmon_input
|= INPUT_HISTOGRAM
;
340 hist_read_rec (ifp
, filename
);
343 case GMON_TAG_CG_ARC
:
345 gmon_input
|= INPUT_CALL_GRAPH
;
346 cg_read_rec (ifp
, filename
);
349 case GMON_TAG_BB_COUNT
:
351 gmon_input
|= INPUT_BB_COUNTS
;
352 bb_read_rec (ifp
, filename
);
357 _("%s: %s: found bad tag %d (file corrupted?)\n"),
358 whoami
, filename
, tag
);
363 else if (file_format
== FF_AUTO
364 || file_format
== FF_BSD
365 || file_format
== FF_BSD44
)
373 int i
, samp_bytes
, header_size
= 0;
375 bfd_vma from_pc
, self_pc
;
381 /* Information from a gmon.out file is in two parts: an array of
382 sampling hits within pc ranges, and the arcs. */
383 gmon_input
= INPUT_HISTOGRAM
| INPUT_CALL_GRAPH
;
385 /* This fseek() ought to work even on stdin as long as it's
386 not an interactive device (heck, is there anybody who would
387 want to type in a gmon.out at the terminal?). */
388 if (fseek (ifp
, 0, SEEK_SET
) < 0)
394 /* The beginning of the old BSD header and the 4.4BSD header
395 are the same: lowpc, highpc, ncnt */
396 if (gmon_io_read_vma (ifp
, &tmp
.low_pc
)
397 || gmon_io_read_vma (ifp
, &tmp
.high_pc
)
398 || gmon_io_read_32 (ifp
, &tmp
.ncnt
))
401 fprintf (stderr
, _("%s: file too short to be a gmon file\n"),
406 /* Check to see if this a 4.4BSD-style header. */
407 if (gmon_io_read_32 (ifp
, &version
))
410 if (version
== GMONVERSION
)
414 /* 4.4BSD format header. */
415 if (gmon_io_read_32 (ifp
, &profrate
))
420 else if (hz
!= profrate
)
423 _("%s: profiling rate incompatible with first gmon file\n"),
428 switch (bfd_arch_bits_per_address (core_bfd
))
431 header_size
= GMON_HDRSIZE_BSD44_32
;
435 header_size
= GMON_HDRSIZE_BSD44_64
;
440 _("%s: bits per address has unexpected value of %u\n"),
441 whoami
, bfd_arch_bits_per_address (core_bfd
));
447 /* Old style BSD format. */
448 if (file_format
== FF_BSD44
)
450 fprintf (stderr
, _("%s: file `%s' has bad magic cookie\n"),
455 switch (bfd_arch_bits_per_address (core_bfd
))
458 header_size
= GMON_HDRSIZE_OLDBSD_32
;
462 header_size
= GMON_HDRSIZE_OLDBSD_64
;
467 _("%s: bits per address has unexpected value of %u\n"),
468 whoami
, bfd_arch_bits_per_address (core_bfd
));
473 /* Position the file to after the header. */
474 if (fseek (ifp
, header_size
, SEEK_SET
) < 0)
480 if (s_highpc
&& (tmp
.low_pc
!= h
.low_pc
481 || tmp
.high_pc
!= h
.high_pc
|| tmp
.ncnt
!= h
.ncnt
))
483 fprintf (stderr
, _("%s: incompatible with first gmon file\n"),
489 s_lowpc
= (bfd_vma
) h
.low_pc
;
490 s_highpc
= (bfd_vma
) h
.high_pc
;
491 lowpc
= (bfd_vma
) h
.low_pc
/ sizeof (UNIT
);
492 highpc
= (bfd_vma
) h
.high_pc
/ sizeof (UNIT
);
493 samp_bytes
= h
.ncnt
- header_size
;
494 hist_num_bins
= samp_bytes
/ sizeof (UNIT
);
497 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
498 (unsigned long) h
.low_pc
, (unsigned long) h
.high_pc
,
500 printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n",
501 (unsigned long) s_lowpc
, (unsigned long) s_highpc
);
502 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n",
503 (unsigned long) lowpc
, (unsigned long) highpc
);
504 printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
505 samp_bytes
, hist_num_bins
));
507 /* Make sure that we have sensible values. */
508 if (samp_bytes
< 0 || lowpc
> highpc
)
511 _("%s: file '%s' does not appear to be in gmon.out format\n"),
522 (int *) xmalloc (hist_num_bins
* sizeof (hist_sample
[0]));
524 memset (hist_sample
, 0, hist_num_bins
* sizeof (hist_sample
[0]));
527 for (i
= 0; i
< hist_num_bins
; ++i
)
529 if (fread (raw_bin_count
, sizeof (raw_bin_count
), 1, ifp
) != 1)
532 _("%s: unexpected EOF after reading %d/%d bins\n"),
533 whoami
, --i
, hist_num_bins
);
537 hist_sample
[i
] += bfd_get_16 (core_bfd
, (bfd_byte
*) raw_bin_count
);
540 /* The rest of the file consists of a bunch of
541 <from,self,count> tuples. */
542 while (gmon_read_raw_arc (ifp
, &from_pc
, &self_pc
, &count
) == 0)
547 printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
548 (unsigned long) from_pc
, (unsigned long) self_pc
, count
));
551 cg_tally (from_pc
, self_pc
, count
);
558 /* How many ticks per second? If we can't tell, report
565 fprintf (stderr
, _("time is in ticks, not seconds\n"));
571 fprintf (stderr
, _("%s: don't know how to deal with file format %d\n"),
572 whoami
, file_format
);
576 if (output_style
& STYLE_GMON_INFO
)
578 printf (_("File `%s' (version %d) contains:\n"),
579 filename
, gmon_file_version
);
581 _("\t%d histogram record\n") :
582 _("\t%d histogram records\n"), nhist
);
584 _("\t%d call-graph record\n") :
585 _("\t%d call-graph records\n"), narcs
);
587 _("\t%d basic-block count record\n") :
588 _("\t%d basic-block count records\n"), nbbs
);
589 first_output
= false;
595 gmon_out_write (filename
)
596 const char *filename
;
599 struct gmon_hdr ghdr
;
601 ofp
= fopen (filename
, FOPEN_WB
);
608 if (file_format
== FF_AUTO
|| file_format
== FF_MAGIC
)
610 /* Write gmon header. */
612 memcpy (&ghdr
.cookie
[0], GMON_MAGIC
, 4);
613 bfd_put_32 (core_bfd
, (bfd_vma
) GMON_VERSION
, (bfd_byte
*) ghdr
.version
);
615 if (fwrite (&ghdr
, sizeof (ghdr
), 1, ofp
) != 1)
621 /* Write execution time histogram if we have one. */
622 if (gmon_input
& INPUT_HISTOGRAM
)
623 hist_write_hist (ofp
, filename
);
625 /* Write call graph arcs if we have any. */
626 if (gmon_input
& INPUT_CALL_GRAPH
)
627 cg_write_arcs (ofp
, filename
);
629 /* Write basic-block info if we have it. */
630 if (gmon_input
& INPUT_BB_COUNTS
)
631 bb_write_blocks (ofp
, filename
);
633 else if (file_format
== FF_BSD
|| file_format
== FF_BSD44
)
642 memset (pad
, 0, sizeof (pad
));
645 /* Decide how large the header will be. Use the 4.4BSD format
646 header if explicitly specified, or if the profiling rate is
647 non-standard. Otherwise, use the old BSD format. */
648 if (file_format
== FF_BSD44
652 switch (bfd_arch_bits_per_address (core_bfd
))
655 hdrsize
= GMON_HDRSIZE_BSD44_32
;
659 hdrsize
= GMON_HDRSIZE_BSD44_64
;
664 _("%s: bits per address has unexpected value of %u\n"),
665 whoami
, bfd_arch_bits_per_address (core_bfd
));
672 switch (bfd_arch_bits_per_address (core_bfd
))
675 hdrsize
= GMON_HDRSIZE_OLDBSD_32
;
679 hdrsize
= GMON_HDRSIZE_OLDBSD_64
;
680 /* FIXME: Checking host compiler defines here means that we can't
681 use a cross gprof alpha OSF. */
682 #if defined(__alpha__) && defined (__osf__)
689 _("%s: bits per address has unexpected value of %u\n"),
690 whoami
, bfd_arch_bits_per_address (core_bfd
));
695 /* Write the parts of the headers that are common to both the
696 old BSD and 4.4BSD formats. */
697 if (gmon_io_write_vma (ofp
, s_lowpc
)
698 || gmon_io_write_vma (ofp
, s_highpc
)
699 || gmon_io_write_32 (ofp
, hist_num_bins
* sizeof (UNIT
) + hdrsize
))
705 /* Write out the 4.4BSD header bits, if that's what we're using. */
706 if (file_format
== FF_BSD44
709 if (gmon_io_write_32 (ofp
, GMONVERSION
)
710 || gmon_io_write_32 (ofp
, (unsigned int) hz
))
717 /* Now write out any necessary padding after the meaningful
720 && fwrite (pad
, 1, padsize
, ofp
) != padsize
)
726 /* Dump the samples. */
727 for (i
= 0; i
< hist_num_bins
; ++i
)
729 bfd_put_16 (core_bfd
, (bfd_vma
) hist_sample
[i
],
730 (bfd_byte
*) &raw_bin_count
[0]);
731 if (fwrite (&raw_bin_count
[0], sizeof (raw_bin_count
), 1, ofp
) != 1)
738 /* Dump the normalized raw arc information. */
739 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
)
741 for (arc
= sym
->cg
.children
; arc
; arc
= arc
->next_child
)
743 if (gmon_write_raw_arc (ofp
, arc
->parent
->addr
,
744 arc
->child
->addr
, arc
->count
))
750 printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n",
751 (unsigned long) arc
->parent
->addr
,
752 (unsigned long) arc
->child
->addr
, arc
->count
));
760 fprintf (stderr
, _("%s: don't know how to deal with file format %d\n"),
761 whoami
, file_format
);