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"
38 int gmon_file_version
= 0; /* 0 == old (non-versioned) file format. */
41 DEFUN (gmon_io_read_32
, (ifp
, valp
), FILE * ifp AND
unsigned int *valp
)
45 if (fread (buf
, 1, 4, ifp
) != 4)
47 *valp
= bfd_get_32 (core_bfd
, buf
);
52 DEFUN (gmon_io_read_64
, (ifp
, valp
), FILE * ifp AND BFD_HOST_U_64_BIT
*valp
)
56 if (fread (buf
, 1, 8, ifp
) != 8)
58 *valp
= bfd_get_64 (core_bfd
, buf
);
63 DEFUN (gmon_io_read_vma
, (ifp
, valp
), FILE * ifp AND bfd_vma
*valp
)
66 BFD_HOST_U_64_BIT val64
;
68 switch (bfd_arch_bits_per_address (core_bfd
))
71 if (gmon_io_read_32 (ifp
, &val32
))
77 if (gmon_io_read_64 (ifp
, &val64
))
83 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
84 whoami
, bfd_arch_bits_per_address (core_bfd
));
91 DEFUN (gmon_io_read
, (ifp
, buf
, n
), FILE * ifp AND
char *buf AND
size_t n
)
93 if (fread (buf
, 1, n
, ifp
) != n
)
99 DEFUN (gmon_io_write_32
, (ofp
, val
), FILE * ofp AND
unsigned int val
)
103 bfd_put_32 (core_bfd
, val
, buf
);
104 if (fwrite (buf
, 1, 4, ofp
) != 4)
110 DEFUN (gmon_io_write_64
, (ofp
, val
), FILE * ofp AND BFD_HOST_U_64_BIT val
)
114 bfd_put_64 (core_bfd
, val
, buf
);
115 if (fwrite (buf
, 1, 8, ofp
) != 8)
121 DEFUN (gmon_io_write_vma
, (ofp
, val
), FILE * ofp AND bfd_vma val
)
124 switch (bfd_arch_bits_per_address (core_bfd
))
127 if (gmon_io_write_32 (ofp
, (unsigned int) val
))
132 if (gmon_io_write_64 (ofp
, (BFD_HOST_U_64_BIT
) val
))
137 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
138 whoami
, bfd_arch_bits_per_address (core_bfd
));
145 DEFUN (gmon_io_write_8
, (ofp
, val
), FILE * ofp AND
unsigned char val
)
149 bfd_put_8 (core_bfd
, val
, buf
);
150 if (fwrite (buf
, 1, 1, ofp
) != 1)
156 DEFUN (gmon_io_write
, (ofp
, buf
, n
), FILE * ofp AND
char *buf AND
size_t n
)
158 if (fwrite (buf
, 1, n
, ofp
) != n
)
164 DEFUN (gmon_read_raw_arc
, (ifp
, fpc
, spc
, cnt
), FILE * ifp AND bfd_vma
* fpc AND bfd_vma
* spc AND
unsigned long * cnt
)
166 BFD_HOST_U_64_BIT cnt64
;
169 if (gmon_io_read_vma (ifp
, fpc
)
170 || gmon_io_read_vma (ifp
, spc
))
173 switch (bfd_arch_bits_per_address (core_bfd
))
176 if (gmon_io_read_32 (ifp
, &cnt32
))
182 if (gmon_io_read_64 (ifp
, &cnt64
))
188 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
189 whoami
, bfd_arch_bits_per_address (core_bfd
));
196 DEFUN (gmon_write_raw_arc
, (ofp
, fpc
, spc
, cnt
), FILE * ofp AND bfd_vma fpc AND bfd_vma spc AND
unsigned long cnt
)
199 if (gmon_io_write_vma (ofp
, fpc
)
200 || gmon_io_write_vma (ofp
, spc
))
203 switch (bfd_arch_bits_per_address (core_bfd
))
206 if (gmon_io_write_32 (ofp
, (unsigned int) cnt
))
211 if (gmon_io_write_64 (ofp
, (BFD_HOST_U_64_BIT
) cnt
))
216 fprintf (stderr
, _("%s: bits per address has unexpected value of %u\n"),
217 whoami
, bfd_arch_bits_per_address (core_bfd
));
224 DEFUN (gmon_out_read
, (filename
), const char *filename
)
227 struct gmon_hdr ghdr
;
229 int nhist
= 0, narcs
= 0, nbbs
= 0;
231 /* Open gmon.out file. */
232 if (strcmp (filename
, "-") == 0)
236 SET_BINARY (fileno (stdin
));
241 ifp
= fopen (filename
, FOPEN_RB
);
250 if (fread (&ghdr
, sizeof (struct gmon_hdr
), 1, ifp
) != 1)
252 fprintf (stderr
, _("%s: file too short to be a gmon file\n"),
257 if ((file_format
== FF_MAGIC
)
258 || (file_format
== FF_AUTO
&& !strncmp (&ghdr
.cookie
[0], GMON_MAGIC
, 4)))
260 if (file_format
== FF_MAGIC
&& strncmp (&ghdr
.cookie
[0], GMON_MAGIC
, 4))
262 fprintf (stderr
, _("%s: file `%s' has bad magic cookie\n"),
267 /* Right magic, so it's probably really a new gmon.out file. */
268 gmon_file_version
= bfd_get_32 (core_bfd
, (bfd_byte
*) ghdr
.version
);
270 if (gmon_file_version
!= GMON_VERSION
&& gmon_file_version
!= 0)
273 _("%s: file `%s' has unsupported version %d\n"),
274 whoami
, filename
, gmon_file_version
);
278 /* Read in all the records. */
279 while (fread (&tag
, sizeof (tag
), 1, ifp
) == 1)
283 case GMON_TAG_TIME_HIST
:
285 gmon_input
|= INPUT_HISTOGRAM
;
286 hist_read_rec (ifp
, filename
);
289 case GMON_TAG_CG_ARC
:
291 gmon_input
|= INPUT_CALL_GRAPH
;
292 cg_read_rec (ifp
, filename
);
295 case GMON_TAG_BB_COUNT
:
297 gmon_input
|= INPUT_BB_COUNTS
;
298 bb_read_rec (ifp
, filename
);
303 _("%s: %s: found bad tag %d (file corrupted?)\n"),
304 whoami
, filename
, tag
);
309 else if (file_format
== FF_AUTO
310 || file_format
== FF_BSD
311 || file_format
== FF_BSD44
)
319 int i
, samp_bytes
, header_size
= 0;
321 bfd_vma from_pc
, self_pc
;
327 /* Information from a gmon.out file is in two parts: an array of
328 sampling hits within pc ranges, and the arcs. */
329 gmon_input
= INPUT_HISTOGRAM
| INPUT_CALL_GRAPH
;
331 /* This fseek() ought to work even on stdin as long as it's
332 not an interactive device (heck, is there anybody who would
333 want to type in a gmon.out at the terminal?). */
334 if (fseek (ifp
, 0, SEEK_SET
) < 0)
340 /* The beginning of the old BSD header and the 4.4BSD header
341 are the same: lowpc, highpc, ncnt */
342 if (gmon_io_read_vma (ifp
, &tmp
.low_pc
)
343 || gmon_io_read_vma (ifp
, &tmp
.high_pc
)
344 || gmon_io_read_32 (ifp
, &tmp
.ncnt
))
347 fprintf (stderr
, _("%s: file too short to be a gmon file\n"),
352 /* Check to see if this a 4.4BSD-style header. */
353 if (gmon_io_read_32 (ifp
, &version
))
356 if (version
== GMONVERSION
)
360 /* 4.4BSD format header. */
361 if (gmon_io_read_32 (ifp
, &profrate
))
366 else if (hz
!= profrate
)
369 _("%s: profiling rate incompatible with first gmon file\n"),
374 switch (bfd_arch_bits_per_address (core_bfd
))
377 header_size
= GMON_HDRSIZE_BSD44_32
;
381 header_size
= GMON_HDRSIZE_BSD44_64
;
386 _("%s: bits per address has unexpected value of %u\n"),
387 whoami
, bfd_arch_bits_per_address (core_bfd
));
393 /* Old style BSD format. */
394 if (file_format
== FF_BSD44
)
396 fprintf (stderr
, _("%s: file `%s' has bad magic cookie\n"),
401 switch (bfd_arch_bits_per_address (core_bfd
))
404 header_size
= GMON_HDRSIZE_OLDBSD_32
;
408 header_size
= GMON_HDRSIZE_OLDBSD_64
;
413 _("%s: bits per address has unexpected value of %u\n"),
414 whoami
, bfd_arch_bits_per_address (core_bfd
));
419 /* Position the file to after the header. */
420 if (fseek (ifp
, header_size
, SEEK_SET
) < 0)
426 if (s_highpc
&& (tmp
.low_pc
!= h
.low_pc
427 || tmp
.high_pc
!= h
.high_pc
|| tmp
.ncnt
!= h
.ncnt
))
429 fprintf (stderr
, _("%s: incompatible with first gmon file\n"),
435 s_lowpc
= (bfd_vma
) h
.low_pc
;
436 s_highpc
= (bfd_vma
) h
.high_pc
;
437 lowpc
= (bfd_vma
) h
.low_pc
/ sizeof (UNIT
);
438 highpc
= (bfd_vma
) h
.high_pc
/ sizeof (UNIT
);
439 samp_bytes
= h
.ncnt
- header_size
;
440 hist_num_bins
= samp_bytes
/ sizeof (UNIT
);
443 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
444 (unsigned long) h
.low_pc
, (unsigned long) h
.high_pc
,
446 printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n",
447 (unsigned long) s_lowpc
, (unsigned long) s_highpc
);
448 printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n",
449 (unsigned long) lowpc
, (unsigned long) highpc
);
450 printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
451 samp_bytes
, hist_num_bins
));
453 /* Make sure that we have sensible values. */
454 if (samp_bytes
< 0 || lowpc
> highpc
)
457 _("%s: file '%s' does not appear to be in gmon.out format\n"),
468 (int *) xmalloc (hist_num_bins
* sizeof (hist_sample
[0]));
470 memset (hist_sample
, 0, hist_num_bins
* sizeof (hist_sample
[0]));
473 for (i
= 0; i
< hist_num_bins
; ++i
)
475 if (fread (raw_bin_count
, sizeof (raw_bin_count
), 1, ifp
) != 1)
478 _("%s: unexpected EOF after reading %d/%d bins\n"),
479 whoami
, --i
, hist_num_bins
);
483 hist_sample
[i
] += bfd_get_16 (core_bfd
, (bfd_byte
*) raw_bin_count
);
486 /* The rest of the file consists of a bunch of
487 <from,self,count> tuples. */
488 while (gmon_read_raw_arc (ifp
, &from_pc
, &self_pc
, &count
) == 0)
493 printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
494 (unsigned long) from_pc
, (unsigned long) self_pc
, count
));
497 cg_tally (from_pc
, self_pc
, count
);
504 /* How many ticks per second? If we can't tell, report
511 fprintf (stderr
, _("time is in ticks, not seconds\n"));
517 fprintf (stderr
, _("%s: don't know how to deal with file format %d\n"),
518 whoami
, file_format
);
522 if (output_style
& STYLE_GMON_INFO
)
524 printf (_("File `%s' (version %d) contains:\n"),
525 filename
, gmon_file_version
);
527 _("\t%d histogram record\n") :
528 _("\t%d histogram records\n"), nhist
);
530 _("\t%d call-graph record\n") :
531 _("\t%d call-graph records\n"), narcs
);
533 _("\t%d basic-block count record\n") :
534 _("\t%d basic-block count records\n"), nbbs
);
535 first_output
= false;
541 DEFUN (gmon_out_write
, (filename
), const char *filename
)
544 struct gmon_hdr ghdr
;
546 ofp
= fopen (filename
, FOPEN_WB
);
553 if (file_format
== FF_AUTO
|| file_format
== FF_MAGIC
)
555 /* Write gmon header. */
557 memcpy (&ghdr
.cookie
[0], GMON_MAGIC
, 4);
558 bfd_put_32 (core_bfd
, GMON_VERSION
, (bfd_byte
*) ghdr
.version
);
560 if (fwrite (&ghdr
, sizeof (ghdr
), 1, ofp
) != 1)
566 /* Write execution time histogram if we have one. */
567 if (gmon_input
& INPUT_HISTOGRAM
)
568 hist_write_hist (ofp
, filename
);
570 /* Write call graph arcs if we have any. */
571 if (gmon_input
& INPUT_CALL_GRAPH
)
572 cg_write_arcs (ofp
, filename
);
574 /* Write basic-block info if we have it. */
575 if (gmon_input
& INPUT_BB_COUNTS
)
576 bb_write_blocks (ofp
, filename
);
578 else if (file_format
== FF_BSD
|| file_format
== FF_BSD44
)
587 memset (pad
, 0, sizeof (pad
));
590 /* Decide how large the header will be. Use the 4.4BSD format
591 header if explicitly specified, or if the profiling rate is
592 non-standard. Otherwise, use the old BSD format. */
593 if (file_format
== FF_BSD44
597 switch (bfd_arch_bits_per_address (core_bfd
))
600 hdrsize
= GMON_HDRSIZE_BSD44_32
;
604 hdrsize
= GMON_HDRSIZE_BSD44_64
;
609 _("%s: bits per address has unexpected value of %u\n"),
610 whoami
, bfd_arch_bits_per_address (core_bfd
));
617 switch (bfd_arch_bits_per_address (core_bfd
))
620 hdrsize
= GMON_HDRSIZE_OLDBSD_32
;
624 hdrsize
= GMON_HDRSIZE_OLDBSD_64
;
625 /* FIXME: Checking host compiler defines here means that we can't
626 use a cross gprof alpha OSF. */
627 #if defined(__alpha__) && defined (__osf__)
634 _("%s: bits per address has unexpected value of %u\n"),
635 whoami
, bfd_arch_bits_per_address (core_bfd
));
640 /* Write the parts of the headers that are common to both the
641 old BSD and 4.4BSD formats. */
642 if (gmon_io_write_vma (ofp
, s_lowpc
)
643 || gmon_io_write_vma (ofp
, s_highpc
)
644 || gmon_io_write_32 (ofp
, hist_num_bins
* sizeof (UNIT
) + hdrsize
))
650 /* Write out the 4.4BSD header bits, if that's what we're using. */
651 if (file_format
== FF_BSD44
654 if (gmon_io_write_32 (ofp
, GMONVERSION
)
655 || gmon_io_write_32 (ofp
, hz
))
662 /* Now write out any necessary padding after the meaningful
665 && fwrite (pad
, 1, padsize
, ofp
) != padsize
)
671 /* Dump the samples. */
672 for (i
= 0; i
< hist_num_bins
; ++i
)
674 bfd_put_16 (core_bfd
, hist_sample
[i
], (bfd_byte
*) & raw_bin_count
[0]);
675 if (fwrite (&raw_bin_count
[0], sizeof (raw_bin_count
), 1, ofp
) != 1)
682 /* Dump the normalized raw arc information. */
683 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
)
685 for (arc
= sym
->cg
.children
; arc
; arc
= arc
->next_child
)
687 if (gmon_write_raw_arc (ofp
, arc
->parent
->addr
,
688 arc
->child
->addr
, arc
->count
))
694 printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n",
695 (unsigned long) arc
->parent
->addr
,
696 (unsigned long) arc
->child
->addr
, arc
->count
));
704 fprintf (stderr
, _("%s: don't know how to deal with file format %d\n"),
705 whoami
, file_format
);