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"
42 enum gmon_ptr_signedness
{
47 static enum gmon_ptr_size gmon_get_ptr_size
PARAMS ((void));
48 static enum gmon_ptr_signedness gmon_get_ptr_signedness
PARAMS ((void));
50 #ifdef BFD_HOST_U_64_BIT
51 static int gmon_io_read_64
PARAMS ((FILE *, BFD_HOST_U_64_BIT
*));
52 static int gmon_io_write_64
PARAMS ((FILE *, BFD_HOST_U_64_BIT
));
54 static int gmon_read_raw_arc
55 PARAMS ((FILE *, bfd_vma
*, bfd_vma
*, unsigned long *));
56 static int gmon_write_raw_arc
57 PARAMS ((FILE *, bfd_vma
, bfd_vma
, unsigned long));
60 int gmon_file_version
= 0; /* 0 == old (non-versioned) file format. */
62 static enum gmon_ptr_size
67 /* Pick best size for pointers. Start with the ELF size, and if not
68 elf go with the architecture's address size. */
69 size
= bfd_get_arch_size (core_bfd
);
71 size
= bfd_arch_bits_per_address (core_bfd
);
82 fprintf (stderr
, _("%s: address size has unexpected value of %u\n"),
88 static enum gmon_ptr_signedness
89 gmon_get_ptr_signedness ()
93 /* Figure out whether to sign extend. If BFD doesn't know, assume no. */
94 sext
= bfd_get_sign_extend_vma (core_bfd
);
97 return (sext
? ptr_signed
: ptr_unsigned
);
101 gmon_io_read_32 (ifp
, valp
)
107 if (fread (buf
, 1, 4, ifp
) != 4)
109 *valp
= bfd_get_32 (core_bfd
, buf
);
113 #ifdef BFD_HOST_U_64_BIT
115 gmon_io_read_64 (ifp
, valp
)
117 BFD_HOST_U_64_BIT
*valp
;
121 if (fread (buf
, 1, 8, ifp
) != 8)
123 *valp
= bfd_get_64 (core_bfd
, buf
);
129 gmon_io_read_vma (ifp
, valp
)
134 #ifdef BFD_HOST_U_64_BIT
135 BFD_HOST_U_64_BIT val64
;
138 switch (gmon_get_ptr_size ())
141 if (gmon_io_read_32 (ifp
, &val32
))
143 if (gmon_get_ptr_signedness () == ptr_signed
)
149 #ifdef BFD_HOST_U_64_BIT
151 if (gmon_io_read_64 (ifp
, &val64
))
153 #ifdef BFD_HOST_64_BIT
154 if (gmon_get_ptr_signedness () == ptr_signed
)
155 *valp
= (BFD_HOST_64_BIT
) val64
;
166 gmon_io_read (ifp
, buf
, n
)
171 if (fread (buf
, 1, n
, ifp
) != n
)
177 gmon_io_write_32 (ofp
, val
)
183 bfd_put_32 (core_bfd
, (bfd_vma
) val
, buf
);
184 if (fwrite (buf
, 1, 4, ofp
) != 4)
189 #ifdef BFD_HOST_U_64_BIT
191 gmon_io_write_64 (ofp
, val
)
193 BFD_HOST_U_64_BIT val
;
197 bfd_put_64 (core_bfd
, (bfd_vma
) val
, buf
);
198 if (fwrite (buf
, 1, 8, ofp
) != 8)
205 gmon_io_write_vma (ofp
, val
)
210 switch (gmon_get_ptr_size ())
213 if (gmon_io_write_32 (ofp
, (unsigned int) val
))
217 #ifdef BFD_HOST_U_64_BIT
219 if (gmon_io_write_64 (ofp
, (BFD_HOST_U_64_BIT
) val
))
228 gmon_io_write_8 (ofp
, val
)
234 bfd_put_8 (core_bfd
, val
, buf
);
235 if (fwrite (buf
, 1, 1, ofp
) != 1)
241 gmon_io_write (ofp
, buf
, n
)
246 if (fwrite (buf
, 1, n
, ofp
) != n
)
252 gmon_read_raw_arc (ifp
, fpc
, spc
, cnt
)
258 #ifdef BFD_HOST_U_64_BIT
259 BFD_HOST_U_64_BIT cnt64
;
263 if (gmon_io_read_vma (ifp
, fpc
)
264 || gmon_io_read_vma (ifp
, spc
))
267 switch (gmon_get_ptr_size ())
270 if (gmon_io_read_32 (ifp
, &cnt32
))
275 #ifdef BFD_HOST_U_64_BIT
277 if (gmon_io_read_64 (ifp
, &cnt64
))
287 gmon_write_raw_arc (ofp
, fpc
, spc
, cnt
)
294 if (gmon_io_write_vma (ofp
, fpc
)
295 || gmon_io_write_vma (ofp
, spc
))
298 switch (gmon_get_ptr_size ())
301 if (gmon_io_write_32 (ofp
, (unsigned int) cnt
))
305 #ifdef BFD_HOST_U_64_BIT
307 if (gmon_io_write_64 (ofp
, (BFD_HOST_U_64_BIT
) cnt
))
316 gmon_out_read (filename
)
317 const char *filename
;
320 struct gmon_hdr ghdr
;
322 int nhist
= 0, narcs
= 0, nbbs
= 0;
324 /* Open gmon.out file. */
325 if (strcmp (filename
, "-") == 0)
329 SET_BINARY (fileno (stdin
));
334 ifp
= fopen (filename
, FOPEN_RB
);
343 if (fread (&ghdr
, sizeof (struct gmon_hdr
), 1, ifp
) != 1)
345 fprintf (stderr
, _("%s: file too short to be a gmon file\n"),
350 if ((file_format
== FF_MAGIC
)
351 || (file_format
== FF_AUTO
&& !strncmp (&ghdr
.cookie
[0], GMON_MAGIC
, 4)))
353 if (file_format
== FF_MAGIC
&& strncmp (&ghdr
.cookie
[0], GMON_MAGIC
, 4))
355 fprintf (stderr
, _("%s: file `%s' has bad magic cookie\n"),
360 /* Right magic, so it's probably really a new gmon.out file. */
361 gmon_file_version
= bfd_get_32 (core_bfd
, (bfd_byte
*) ghdr
.version
);
363 if (gmon_file_version
!= GMON_VERSION
&& gmon_file_version
!= 0)
366 _("%s: file `%s' has unsupported version %d\n"),
367 whoami
, filename
, gmon_file_version
);
371 /* Read in all the records. */
372 while (fread (&tag
, sizeof (tag
), 1, ifp
) == 1)
376 case GMON_TAG_TIME_HIST
:
378 gmon_input
|= INPUT_HISTOGRAM
;
379 hist_read_rec (ifp
, filename
);
382 case GMON_TAG_CG_ARC
:
384 gmon_input
|= INPUT_CALL_GRAPH
;
385 cg_read_rec (ifp
, filename
);
388 case GMON_TAG_BB_COUNT
:
390 gmon_input
|= INPUT_BB_COUNTS
;
391 bb_read_rec (ifp
, filename
);
396 _("%s: %s: found bad tag %d (file corrupted?)\n"),
397 whoami
, filename
, tag
);
402 else if (file_format
== FF_AUTO
403 || file_format
== FF_BSD
404 || file_format
== FF_BSD44
)
412 int i
, samp_bytes
, header_size
= 0;
414 bfd_vma from_pc
, self_pc
;
420 /* Information from a gmon.out file is in two parts: an array of
421 sampling hits within pc ranges, and the arcs. */
422 gmon_input
= INPUT_HISTOGRAM
| INPUT_CALL_GRAPH
;
424 /* This fseek() ought to work even on stdin as long as it's
425 not an interactive device (heck, is there anybody who would
426 want to type in a gmon.out at the terminal?). */
427 if (fseek (ifp
, 0, SEEK_SET
) < 0)
433 /* The beginning of the old BSD header and the 4.4BSD header
434 are the same: lowpc, highpc, ncnt */
435 if (gmon_io_read_vma (ifp
, &tmp
.low_pc
)
436 || gmon_io_read_vma (ifp
, &tmp
.high_pc
)
437 || gmon_io_read_32 (ifp
, &tmp
.ncnt
))
440 fprintf (stderr
, _("%s: file too short to be a gmon file\n"),
445 /* Check to see if this a 4.4BSD-style header. */
446 if (gmon_io_read_32 (ifp
, &version
))
449 if (version
== GMONVERSION
)
453 /* 4.4BSD format header. */
454 if (gmon_io_read_32 (ifp
, &profrate
))
459 else if (hz
!= profrate
)
462 _("%s: profiling rate incompatible with first gmon file\n"),
467 switch (gmon_get_ptr_size ())
470 header_size
= GMON_HDRSIZE_BSD44_32
;
474 header_size
= GMON_HDRSIZE_BSD44_64
;
480 /* Old style BSD format. */
481 if (file_format
== FF_BSD44
)
483 fprintf (stderr
, _("%s: file `%s' has bad magic cookie\n"),
488 switch (gmon_get_ptr_size ())
491 header_size
= GMON_HDRSIZE_OLDBSD_32
;
495 header_size
= GMON_HDRSIZE_OLDBSD_64
;
500 /* Position the file to after the header. */
501 if (fseek (ifp
, header_size
, SEEK_SET
) < 0)
507 if (s_highpc
&& (tmp
.low_pc
!= h
.low_pc
508 || tmp
.high_pc
!= h
.high_pc
|| tmp
.ncnt
!= h
.ncnt
))
510 fprintf (stderr
, _("%s: incompatible with first gmon file\n"),
516 s_lowpc
= (bfd_vma
) h
.low_pc
;
517 s_highpc
= (bfd_vma
) h
.high_pc
;
518 lowpc
= (bfd_vma
) h
.low_pc
/ sizeof (UNIT
);
519 highpc
= (bfd_vma
) h
.high_pc
/ sizeof (UNIT
);
520 samp_bytes
= h
.ncnt
- header_size
;
521 hist_num_bins
= samp_bytes
/ sizeof (UNIT
);
524 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
525 (unsigned long) h
.low_pc
, (unsigned long) h
.high_pc
,
527 printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n",
528 (unsigned long) s_lowpc
, (unsigned long) s_highpc
);
529 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n",
530 (unsigned long) lowpc
, (unsigned long) highpc
);
531 printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
532 samp_bytes
, hist_num_bins
));
534 /* Make sure that we have sensible values. */
535 if (samp_bytes
< 0 || lowpc
> highpc
)
538 _("%s: file '%s' does not appear to be in gmon.out format\n"),
549 (int *) xmalloc (hist_num_bins
* sizeof (hist_sample
[0]));
551 memset (hist_sample
, 0, hist_num_bins
* sizeof (hist_sample
[0]));
554 for (i
= 0; i
< hist_num_bins
; ++i
)
556 if (fread (raw_bin_count
, sizeof (raw_bin_count
), 1, ifp
) != 1)
559 _("%s: unexpected EOF after reading %d/%d bins\n"),
560 whoami
, --i
, hist_num_bins
);
564 hist_sample
[i
] += bfd_get_16 (core_bfd
, (bfd_byte
*) raw_bin_count
);
567 /* The rest of the file consists of a bunch of
568 <from,self,count> tuples. */
569 while (gmon_read_raw_arc (ifp
, &from_pc
, &self_pc
, &count
) == 0)
574 printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
575 (unsigned long) from_pc
, (unsigned long) self_pc
, count
));
578 cg_tally (from_pc
, self_pc
, count
);
585 /* How many ticks per second? If we can't tell, report
592 fprintf (stderr
, _("time is in ticks, not seconds\n"));
598 fprintf (stderr
, _("%s: don't know how to deal with file format %d\n"),
599 whoami
, file_format
);
603 if (output_style
& STYLE_GMON_INFO
)
605 printf (_("File `%s' (version %d) contains:\n"),
606 filename
, gmon_file_version
);
608 _("\t%d histogram record\n") :
609 _("\t%d histogram records\n"), nhist
);
611 _("\t%d call-graph record\n") :
612 _("\t%d call-graph records\n"), narcs
);
614 _("\t%d basic-block count record\n") :
615 _("\t%d basic-block count records\n"), nbbs
);
616 first_output
= FALSE
;
622 gmon_out_write (filename
)
623 const char *filename
;
626 struct gmon_hdr ghdr
;
628 ofp
= fopen (filename
, FOPEN_WB
);
635 if (file_format
== FF_AUTO
|| file_format
== FF_MAGIC
)
637 /* Write gmon header. */
639 memcpy (&ghdr
.cookie
[0], GMON_MAGIC
, 4);
640 bfd_put_32 (core_bfd
, (bfd_vma
) GMON_VERSION
, (bfd_byte
*) ghdr
.version
);
642 if (fwrite (&ghdr
, sizeof (ghdr
), 1, ofp
) != 1)
648 /* Write execution time histogram if we have one. */
649 if (gmon_input
& INPUT_HISTOGRAM
)
650 hist_write_hist (ofp
, filename
);
652 /* Write call graph arcs if we have any. */
653 if (gmon_input
& INPUT_CALL_GRAPH
)
654 cg_write_arcs (ofp
, filename
);
656 /* Write basic-block info if we have it. */
657 if (gmon_input
& INPUT_BB_COUNTS
)
658 bb_write_blocks (ofp
, filename
);
660 else if (file_format
== FF_BSD
|| file_format
== FF_BSD44
)
669 memset (pad
, 0, sizeof (pad
));
672 /* Decide how large the header will be. Use the 4.4BSD format
673 header if explicitly specified, or if the profiling rate is
674 non-standard. Otherwise, use the old BSD format. */
675 if (file_format
== FF_BSD44
679 switch (gmon_get_ptr_size ())
682 hdrsize
= GMON_HDRSIZE_BSD44_32
;
686 hdrsize
= GMON_HDRSIZE_BSD44_64
;
693 switch (gmon_get_ptr_size ())
696 hdrsize
= GMON_HDRSIZE_OLDBSD_32
;
700 hdrsize
= GMON_HDRSIZE_OLDBSD_64
;
701 /* FIXME: Checking host compiler defines here means that we can't
702 use a cross gprof alpha OSF. */
703 #if defined(__alpha__) && defined (__osf__)
710 /* Write the parts of the headers that are common to both the
711 old BSD and 4.4BSD formats. */
712 if (gmon_io_write_vma (ofp
, s_lowpc
)
713 || gmon_io_write_vma (ofp
, s_highpc
)
714 || gmon_io_write_32 (ofp
, hist_num_bins
* sizeof (UNIT
) + hdrsize
))
720 /* Write out the 4.4BSD header bits, if that's what we're using. */
721 if (file_format
== FF_BSD44
724 if (gmon_io_write_32 (ofp
, GMONVERSION
)
725 || gmon_io_write_32 (ofp
, (unsigned int) hz
))
732 /* Now write out any necessary padding after the meaningful
735 && fwrite (pad
, 1, padsize
, ofp
) != padsize
)
741 /* Dump the samples. */
742 for (i
= 0; i
< hist_num_bins
; ++i
)
744 bfd_put_16 (core_bfd
, (bfd_vma
) hist_sample
[i
],
745 (bfd_byte
*) &raw_bin_count
[0]);
746 if (fwrite (&raw_bin_count
[0], sizeof (raw_bin_count
), 1, ofp
) != 1)
753 /* Dump the normalized raw arc information. */
754 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
)
756 for (arc
= sym
->cg
.children
; arc
; arc
= arc
->next_child
)
758 if (gmon_write_raw_arc (ofp
, arc
->parent
->addr
,
759 arc
->child
->addr
, arc
->count
))
765 printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n",
766 (unsigned long) arc
->parent
->addr
,
767 (unsigned long) arc
->child
->addr
, arc
->count
));
775 fprintf (stderr
, _("%s: don't know how to deal with file format %d\n"),
776 whoami
, file_format
);