Blame gprof/gmon_io.c

Packit ba3681
/* gmon_io.c - Input and output from/to gmon.out files.
Packit ba3681
Packit ba3681
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit ba3681
Packit ba3681
   This file is part of GNU Binutils.
Packit ba3681
Packit ba3681
   This program is free software; you can redistribute it and/or modify
Packit ba3681
   it under the terms of the GNU General Public License as published by
Packit ba3681
   the Free Software Foundation; either version 3 of the License, or
Packit ba3681
   (at your option) any later version.
Packit ba3681
Packit ba3681
   This program is distributed in the hope that it will be useful,
Packit ba3681
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ba3681
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit ba3681
   GNU General Public License for more details.
Packit ba3681
Packit ba3681
   You should have received a copy of the GNU General Public License
Packit ba3681
   along with this program; if not, write to the Free Software
Packit ba3681
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
Packit ba3681
   02110-1301, USA.  */
Packit ba3681

Packit ba3681
#include "gprof.h"
Packit ba3681
#include "binary-io.h"
Packit ba3681
#include "search_list.h"
Packit ba3681
#include "source.h"
Packit ba3681
#include "symtab.h"
Packit ba3681
#include "cg_arcs.h"
Packit ba3681
#include "basic_blocks.h"
Packit ba3681
#include "corefile.h"
Packit ba3681
#include "call_graph.h"
Packit ba3681
#include "gmon_io.h"
Packit ba3681
#include "gmon_out.h"
Packit ba3681
#include "gmon.h"		/* Fetch header for old format.  */
Packit ba3681
#include "hertz.h"
Packit ba3681
#include "hist.h"
Packit ba3681
#include "libiberty.h"
Packit ba3681
Packit ba3681
enum gmon_ptr_size {
Packit ba3681
  ptr_32bit,
Packit ba3681
  ptr_64bit
Packit ba3681
};
Packit ba3681
Packit ba3681
enum gmon_ptr_signedness {
Packit ba3681
  ptr_signed,
Packit ba3681
  ptr_unsigned
Packit ba3681
};
Packit ba3681
Packit ba3681
static enum gmon_ptr_size gmon_get_ptr_size (void);
Packit ba3681
static enum gmon_ptr_signedness gmon_get_ptr_signedness (void);
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
static int gmon_io_read_64 (FILE *, BFD_HOST_U_64_BIT *);
Packit ba3681
static int gmon_io_write_64 (FILE *, BFD_HOST_U_64_BIT);
Packit ba3681
#endif
Packit ba3681
static int gmon_read_raw_arc
Packit ba3681
  (FILE *, bfd_vma *, bfd_vma *, unsigned long *);
Packit ba3681
static int gmon_write_raw_arc
Packit ba3681
  (FILE *, bfd_vma, bfd_vma, unsigned long);
Packit ba3681
Packit ba3681
int gmon_input = 0;
Packit ba3681
int gmon_file_version = 0;	/* 0 == old (non-versioned) file format.  */
Packit ba3681
Packit ba3681
static enum gmon_ptr_size
Packit ba3681
gmon_get_ptr_size (void)
Packit ba3681
{
Packit ba3681
  int size;
Packit ba3681
Packit ba3681
  /* Pick best size for pointers.  Start with the ELF size, and if not
Packit ba3681
     elf go with the architecture's address size.  */
Packit ba3681
  size = bfd_get_arch_size (core_bfd);
Packit ba3681
  if (size == -1)
Packit ba3681
    size = bfd_arch_bits_per_address (core_bfd);
Packit ba3681
Packit ba3681
  switch (size)
Packit ba3681
    {
Packit ba3681
    case 32:
Packit ba3681
      return ptr_32bit;
Packit ba3681
Packit ba3681
    case 64:
Packit ba3681
      return ptr_64bit;
Packit ba3681
Packit ba3681
    default:
Packit ba3681
      fprintf (stderr, _("%s: address size has unexpected value of %u\n"),
Packit ba3681
	       whoami, size);
Packit ba3681
      done (1);
Packit ba3681
    }
Packit ba3681
}
Packit ba3681
Packit ba3681
static enum gmon_ptr_signedness
Packit ba3681
gmon_get_ptr_signedness (void)
Packit ba3681
{
Packit ba3681
  int sext;
Packit ba3681
Packit ba3681
  /* Figure out whether to sign extend.  If BFD doesn't know, assume no.  */
Packit ba3681
  sext = bfd_get_sign_extend_vma (core_bfd);
Packit ba3681
  if (sext == -1)
Packit ba3681
    return ptr_unsigned;
Packit ba3681
  return (sext ? ptr_signed : ptr_unsigned);
Packit ba3681
}
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_read_32 (FILE *ifp, unsigned int *valp)
Packit ba3681
{
Packit ba3681
  char buf[4];
Packit ba3681
Packit ba3681
  if (fread (buf, 1, 4, ifp) != 4)
Packit ba3681
    return 1;
Packit ba3681
  *valp = bfd_get_32 (core_bfd, buf);
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
static int
Packit ba3681
gmon_io_read_64 (FILE *ifp, BFD_HOST_U_64_BIT *valp)
Packit ba3681
{
Packit ba3681
  char buf[8];
Packit ba3681
Packit ba3681
  if (fread (buf, 1, 8, ifp) != 8)
Packit ba3681
    return 1;
Packit ba3681
  *valp = bfd_get_64 (core_bfd, buf);
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
#endif
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_read_vma (FILE *ifp, bfd_vma *valp)
Packit ba3681
{
Packit ba3681
  unsigned int val32;
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
  BFD_HOST_U_64_BIT val64;
Packit ba3681
#endif
Packit ba3681
Packit ba3681
  switch (gmon_get_ptr_size ())
Packit ba3681
    {
Packit ba3681
    case ptr_32bit:
Packit ba3681
      if (gmon_io_read_32 (ifp, &val32))
Packit ba3681
	return 1;
Packit ba3681
      if (gmon_get_ptr_signedness () == ptr_signed)
Packit ba3681
        *valp = (int) val32;
Packit ba3681
      else
Packit ba3681
        *valp = val32;
Packit ba3681
      break;
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
    case ptr_64bit:
Packit ba3681
      if (gmon_io_read_64 (ifp, &val64))
Packit ba3681
	return 1;
Packit ba3681
#ifdef BFD_HOST_64_BIT
Packit ba3681
      if (gmon_get_ptr_signedness () == ptr_signed)
Packit ba3681
        *valp = (BFD_HOST_64_BIT) val64;
Packit ba3681
      else
Packit ba3681
#endif
Packit ba3681
        *valp = val64;
Packit ba3681
      break;
Packit ba3681
#endif
Packit ba3681
    }
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_read (FILE *ifp, char *buf, size_t n)
Packit ba3681
{
Packit ba3681
  if (fread (buf, 1, n, ifp) != n)
Packit ba3681
    return 1;
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_write_32 (FILE *ofp, unsigned int val)
Packit ba3681
{
Packit ba3681
  char buf[4];
Packit ba3681
Packit ba3681
  bfd_put_32 (core_bfd, (bfd_vma) val, buf);
Packit ba3681
  if (fwrite (buf, 1, 4, ofp) != 4)
Packit ba3681
    return 1;
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
static int
Packit ba3681
gmon_io_write_64 (FILE *ofp, BFD_HOST_U_64_BIT val)
Packit ba3681
{
Packit ba3681
  char buf[8];
Packit ba3681
Packit ba3681
  bfd_put_64 (core_bfd, (bfd_vma) val, buf);
Packit ba3681
  if (fwrite (buf, 1, 8, ofp) != 8)
Packit ba3681
    return 1;
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
#endif
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_write_vma (FILE *ofp, bfd_vma val)
Packit ba3681
{
Packit ba3681
Packit ba3681
  switch (gmon_get_ptr_size ())
Packit ba3681
    {
Packit ba3681
    case ptr_32bit:
Packit ba3681
      if (gmon_io_write_32 (ofp, (unsigned int) val))
Packit ba3681
	return 1;
Packit ba3681
      break;
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
    case ptr_64bit:
Packit ba3681
      if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) val))
Packit ba3681
	return 1;
Packit ba3681
      break;
Packit ba3681
#endif
Packit ba3681
    }
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_write_8 (FILE *ofp, unsigned int val)
Packit ba3681
{
Packit ba3681
  char buf[1];
Packit ba3681
Packit ba3681
  bfd_put_8 (core_bfd, val, buf);
Packit ba3681
  if (fwrite (buf, 1, 1, ofp) != 1)
Packit ba3681
    return 1;
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
int
Packit ba3681
gmon_io_write (FILE *ofp, char *buf, size_t n)
Packit ba3681
{
Packit ba3681
  if (fwrite (buf, 1, n, ofp) != n)
Packit ba3681
    return 1;
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
static int
Packit ba3681
gmon_read_raw_arc (FILE *ifp, bfd_vma *fpc, bfd_vma *spc, unsigned long *cnt)
Packit ba3681
{
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
  BFD_HOST_U_64_BIT cnt64;
Packit ba3681
#endif
Packit ba3681
  unsigned int cnt32;
Packit ba3681
Packit ba3681
  if (gmon_io_read_vma (ifp, fpc)
Packit ba3681
      || gmon_io_read_vma (ifp, spc))
Packit ba3681
    return 1;
Packit ba3681
Packit ba3681
  switch (gmon_get_ptr_size ())
Packit ba3681
    {
Packit ba3681
    case ptr_32bit:
Packit ba3681
      if (gmon_io_read_32 (ifp, &cnt32))
Packit ba3681
	return 1;
Packit ba3681
      *cnt = cnt32;
Packit ba3681
      break;
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
    case ptr_64bit:
Packit ba3681
      if (gmon_io_read_64 (ifp, &cnt64))
Packit ba3681
	return 1;
Packit ba3681
      *cnt = cnt64;
Packit ba3681
      break;
Packit ba3681
#endif
Packit ba3681
Packit ba3681
    default:
Packit ba3681
      return 1;
Packit ba3681
    }
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
static int
Packit ba3681
gmon_write_raw_arc (FILE *ofp, bfd_vma fpc, bfd_vma spc, unsigned long cnt)
Packit ba3681
{
Packit ba3681
Packit ba3681
  if (gmon_io_write_vma (ofp, fpc)
Packit ba3681
      || gmon_io_write_vma (ofp, spc))
Packit ba3681
    return 1;
Packit ba3681
Packit ba3681
  switch (gmon_get_ptr_size ())
Packit ba3681
    {
Packit ba3681
    case ptr_32bit:
Packit ba3681
      if (gmon_io_write_32 (ofp, (unsigned int) cnt))
Packit ba3681
	return 1;
Packit ba3681
      break;
Packit ba3681
Packit ba3681
#ifdef BFD_HOST_U_64_BIT
Packit ba3681
    case ptr_64bit:
Packit ba3681
      if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) cnt))
Packit ba3681
	return 1;
Packit ba3681
      break;
Packit ba3681
#endif
Packit ba3681
    }
Packit ba3681
  return 0;
Packit ba3681
}
Packit ba3681
Packit ba3681
void
Packit ba3681
gmon_out_read (const char *filename)
Packit ba3681
{
Packit ba3681
  FILE *ifp;
Packit ba3681
  struct gmon_hdr ghdr;
Packit ba3681
  unsigned char tag;
Packit ba3681
  int nhist = 0, narcs = 0, nbbs = 0;
Packit ba3681
Packit ba3681
  /* Open gmon.out file.  */
Packit ba3681
  if (strcmp (filename, "-") == 0)
Packit ba3681
    {
Packit ba3681
      ifp = stdin;
Packit ba3681
      SET_BINARY (fileno (stdin));
Packit ba3681
    }
Packit ba3681
  else
Packit ba3681
    {
Packit ba3681
      ifp = fopen (filename, FOPEN_RB);
Packit ba3681
Packit ba3681
      if (!ifp)
Packit ba3681
	{
Packit ba3681
	  perror (filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
    }
Packit ba3681
Packit ba3681
  if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1)
Packit ba3681
    {
Packit ba3681
      fprintf (stderr, _("%s: file too short to be a gmon file\n"),
Packit ba3681
	       filename);
Packit ba3681
      done (1);
Packit ba3681
    }
Packit ba3681
Packit ba3681
  if ((file_format == FF_MAGIC)
Packit ba3681
      || (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)))
Packit ba3681
    {
Packit ba3681
      if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))
Packit ba3681
	{
Packit ba3681
	  fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
Packit ba3681
		   whoami, filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Right magic, so it's probably really a new gmon.out file.  */
Packit ba3681
      gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version);
Packit ba3681
Packit ba3681
      if (gmon_file_version != GMON_VERSION && gmon_file_version != 0)
Packit ba3681
	{
Packit ba3681
	  fprintf (stderr,
Packit ba3681
		   _("%s: file `%s' has unsupported version %d\n"),
Packit ba3681
		   whoami, filename, gmon_file_version);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Read in all the records.  */
Packit ba3681
      while (fread (&tag, sizeof (tag), 1, ifp) == 1)
Packit ba3681
	{
Packit ba3681
	  switch (tag)
Packit ba3681
	    {
Packit ba3681
	    case GMON_TAG_TIME_HIST:
Packit ba3681
	      ++nhist;
Packit ba3681
	      gmon_input |= INPUT_HISTOGRAM;
Packit ba3681
	      hist_read_rec (ifp, filename);
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    case GMON_TAG_CG_ARC:
Packit ba3681
	      ++narcs;
Packit ba3681
	      gmon_input |= INPUT_CALL_GRAPH;
Packit ba3681
	      cg_read_rec (ifp, filename);
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    case GMON_TAG_BB_COUNT:
Packit ba3681
	      ++nbbs;
Packit ba3681
	      gmon_input |= INPUT_BB_COUNTS;
Packit ba3681
	      bb_read_rec (ifp, filename);
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    default:
Packit ba3681
	      fprintf (stderr,
Packit ba3681
		       _("%s: %s: found bad tag %d (file corrupted?)\n"),
Packit ba3681
		       whoami, filename, tag);
Packit ba3681
	      done (1);
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
    }
Packit ba3681
  else if (file_format == FF_AUTO
Packit ba3681
	   || file_format == FF_BSD
Packit ba3681
	   || file_format == FF_BSD44)
Packit ba3681
    {
Packit ba3681
      struct hdr
Packit ba3681
      {
Packit ba3681
	bfd_vma low_pc;
Packit ba3681
	bfd_vma high_pc;
Packit ba3681
	unsigned int ncnt;
Packit ba3681
      };
Packit ba3681
      unsigned int i;
Packit ba3681
      int samp_bytes, header_size = 0;
Packit ba3681
      unsigned long count;
Packit ba3681
      bfd_vma from_pc, self_pc;
Packit ba3681
      UNIT raw_bin_count;
Packit ba3681
      struct hdr tmp;
Packit ba3681
      unsigned int version;
Packit ba3681
      unsigned int hist_num_bins;
Packit ba3681
Packit ba3681
      /* Information from a gmon.out file is in two parts: an array of
Packit ba3681
	 sampling hits within pc ranges, and the arcs.  */
Packit ba3681
      gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH;
Packit ba3681
Packit ba3681
      /* This fseek() ought to work even on stdin as long as it's
Packit ba3681
	 not an interactive device (heck, is there anybody who would
Packit ba3681
	 want to type in a gmon.out at the terminal?).  */
Packit ba3681
      if (fseek (ifp, 0, SEEK_SET) < 0)
Packit ba3681
	{
Packit ba3681
	  perror (filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* The beginning of the old BSD header and the 4.4BSD header
Packit ba3681
	 are the same: lowpc, highpc, ncnt  */
Packit ba3681
      if (gmon_io_read_vma (ifp, &tmp.low_pc)
Packit ba3681
          || gmon_io_read_vma (ifp, &tmp.high_pc)
Packit ba3681
          || gmon_io_read_32 (ifp, &tmp.ncnt))
Packit ba3681
	{
Packit ba3681
 bad_gmon_file:
Packit ba3681
          fprintf (stderr, _("%s: file too short to be a gmon file\n"),
Packit ba3681
		   filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Check to see if this a 4.4BSD-style header.  */
Packit ba3681
      if (gmon_io_read_32 (ifp, &version))
Packit ba3681
	goto bad_gmon_file;
Packit ba3681
Packit ba3681
      if (version == GMONVERSION)
Packit ba3681
	{
Packit ba3681
	  unsigned int profrate;
Packit ba3681
Packit ba3681
	  /* 4.4BSD format header.  */
Packit ba3681
          if (gmon_io_read_32 (ifp, &profrate))
Packit ba3681
	    goto bad_gmon_file;
Packit ba3681
Packit ba3681
	  if (!histograms)
Packit ba3681
	    hz = profrate;
Packit ba3681
	  else if (hz != (int) profrate)
Packit ba3681
	    {
Packit ba3681
	      fprintf (stderr,
Packit ba3681
		       _("%s: profiling rate incompatible with first gmon file\n"),
Packit ba3681
		       filename);
Packit ba3681
	      done (1);
Packit ba3681
	    }
Packit ba3681
Packit ba3681
	  switch (gmon_get_ptr_size ())
Packit ba3681
	    {
Packit ba3681
	    case ptr_32bit:
Packit ba3681
	      header_size = GMON_HDRSIZE_BSD44_32;
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    case ptr_64bit:
Packit ba3681
	      header_size = GMON_HDRSIZE_BSD44_64;
Packit ba3681
	      break;
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
      else
Packit ba3681
	{
Packit ba3681
	  /* Old style BSD format.  */
Packit ba3681
	  if (file_format == FF_BSD44)
Packit ba3681
	    {
Packit ba3681
	      fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
Packit ba3681
		       whoami, filename);
Packit ba3681
	      done (1);
Packit ba3681
	    }
Packit ba3681
Packit ba3681
	  switch (gmon_get_ptr_size ())
Packit ba3681
	    {
Packit ba3681
	    case ptr_32bit:
Packit ba3681
	      header_size = GMON_HDRSIZE_OLDBSD_32;
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    case ptr_64bit:
Packit ba3681
	      header_size = GMON_HDRSIZE_OLDBSD_64;
Packit ba3681
	      break;
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Position the file to after the header.  */
Packit ba3681
      if (fseek (ifp, header_size, SEEK_SET) < 0)
Packit ba3681
	{
Packit ba3681
	  perror (filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      samp_bytes = tmp.ncnt - header_size;
Packit ba3681
      hist_num_bins = samp_bytes / sizeof (UNIT);
Packit ba3681
      if (histograms && (tmp.low_pc != histograms->lowpc
Packit ba3681
			 || tmp.high_pc != histograms->highpc
Packit ba3681
			 || (hist_num_bins != histograms->num_bins)))
Packit ba3681
	{
Packit ba3681
	  fprintf (stderr, _("%s: incompatible with first gmon file\n"),
Packit ba3681
		   filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      if (!histograms)
Packit ba3681
	{
Packit ba3681
	  num_histograms = 1;
Packit ba3681
	  histograms = (struct histogram *) xmalloc (sizeof (struct histogram));
Packit ba3681
	  histograms->lowpc = tmp.low_pc;
Packit ba3681
	  histograms->highpc = tmp.high_pc;
Packit ba3681
	  histograms->num_bins = hist_num_bins;
Packit ba3681
	  hist_scale = (double)((tmp.high_pc - tmp.low_pc) / sizeof (UNIT))
Packit ba3681
	    / hist_num_bins;
Packit ba3681
	  histograms->sample = (int *) xmalloc (hist_num_bins * sizeof (int));
Packit ba3681
	  memset (histograms->sample, 0,
Packit ba3681
		  hist_num_bins * sizeof (int));
Packit ba3681
	}
Packit ba3681
Packit ba3681
      DBG (SAMPLEDEBUG,
Packit ba3681
	   printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
Packit ba3681
		   (unsigned long) tmp.low_pc, (unsigned long) tmp.high_pc,
Packit ba3681
		   tmp.ncnt);
Packit ba3681
	   printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
Packit ba3681
		   samp_bytes, hist_num_bins));
Packit ba3681
Packit ba3681
      /* Make sure that we have sensible values.  */
Packit ba3681
      if (samp_bytes < 0 || histograms->lowpc > histograms->highpc)
Packit ba3681
	{
Packit ba3681
	  fprintf (stderr,
Packit ba3681
	    _("%s: file '%s' does not appear to be in gmon.out format\n"),
Packit ba3681
	    whoami, filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      if (hist_num_bins)
Packit ba3681
	++nhist;
Packit ba3681
Packit ba3681
      for (i = 0; i < hist_num_bins; ++i)
Packit ba3681
	{
Packit ba3681
	  if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1)
Packit ba3681
	    {
Packit ba3681
	      fprintf (stderr,
Packit ba3681
		       _("%s: unexpected EOF after reading %d/%d bins\n"),
Packit ba3681
		       whoami, --i, hist_num_bins);
Packit ba3681
	      done (1);
Packit ba3681
	    }
Packit ba3681
Packit ba3681
	  histograms->sample[i]
Packit ba3681
	    += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* The rest of the file consists of a bunch of
Packit ba3681
	 <from,self,count> tuples.  */
Packit ba3681
      while (gmon_read_raw_arc (ifp, &from_pc, &self_pc, &count) == 0)
Packit ba3681
	{
Packit ba3681
	  ++narcs;
Packit ba3681
Packit ba3681
	  DBG (SAMPLEDEBUG,
Packit ba3681
	     printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
Packit ba3681
		     (unsigned long) from_pc, (unsigned long) self_pc, count));
Packit ba3681
Packit ba3681
	  /* Add this arc.  */
Packit ba3681
	  cg_tally (from_pc, self_pc, count);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      if (hz == HZ_WRONG)
Packit ba3681
	{
Packit ba3681
	  /* How many ticks per second?  If we can't tell, report
Packit ba3681
	     time in ticks.  */
Packit ba3681
	  hz = hertz ();
Packit ba3681
Packit ba3681
	  if (hz == HZ_WRONG)
Packit ba3681
	    {
Packit ba3681
	      hz = 1;
Packit ba3681
	      fprintf (stderr, _("time is in ticks, not seconds\n"));
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
    }
Packit ba3681
  else
Packit ba3681
    {
Packit ba3681
      fprintf (stderr, _("%s: don't know how to deal with file format %d\n"),
Packit ba3681
	       whoami, file_format);
Packit ba3681
      done (1);
Packit ba3681
    }
Packit ba3681
Packit ba3681
  if (ifp != stdin)
Packit ba3681
    fclose (ifp);
Packit ba3681
Packit ba3681
  if (output_style & STYLE_GMON_INFO)
Packit ba3681
    {
Packit ba3681
      printf (_("File `%s' (version %d) contains:\n"),
Packit ba3681
	      filename, gmon_file_version);
Packit ba3681
      printf (nhist == 1 ?
Packit ba3681
	      _("\t%d histogram record\n") :
Packit ba3681
	      _("\t%d histogram records\n"), nhist);
Packit ba3681
      printf (narcs == 1 ?
Packit ba3681
	      _("\t%d call-graph record\n") :
Packit ba3681
	      _("\t%d call-graph records\n"), narcs);
Packit ba3681
      printf (nbbs == 1 ?
Packit ba3681
	      _("\t%d basic-block count record\n") :
Packit ba3681
	      _("\t%d basic-block count records\n"), nbbs);
Packit ba3681
      first_output = FALSE;
Packit ba3681
    }
Packit ba3681
}
Packit ba3681
Packit ba3681
Packit ba3681
void
Packit ba3681
gmon_out_write (const char *filename)
Packit ba3681
{
Packit ba3681
  FILE *ofp;
Packit ba3681
  struct gmon_hdr ghdr;
Packit ba3681
Packit ba3681
  ofp = fopen (filename, FOPEN_WB);
Packit ba3681
  if (!ofp)
Packit ba3681
    {
Packit ba3681
      perror (filename);
Packit ba3681
      done (1);
Packit ba3681
    }
Packit ba3681
Packit ba3681
  if (file_format == FF_AUTO || file_format == FF_MAGIC)
Packit ba3681
    {
Packit ba3681
      /* Write gmon header.  */
Packit ba3681
Packit ba3681
      memcpy (&ghdr.cookie[0], GMON_MAGIC, 4);
Packit ba3681
      bfd_put_32 (core_bfd, (bfd_vma) GMON_VERSION, (bfd_byte *) ghdr.version);
Packit ba3681
Packit ba3681
      if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1)
Packit ba3681
	{
Packit ba3681
	  perror (filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Write execution time histogram if we have one.  */
Packit ba3681
      if (gmon_input & INPUT_HISTOGRAM)
Packit ba3681
	hist_write_hist (ofp, filename);
Packit ba3681
Packit ba3681
      /* Write call graph arcs if we have any.  */
Packit ba3681
      if (gmon_input & INPUT_CALL_GRAPH)
Packit ba3681
	cg_write_arcs (ofp, filename);
Packit ba3681
Packit ba3681
      /* Write basic-block info if we have it.  */
Packit ba3681
      if (gmon_input & INPUT_BB_COUNTS)
Packit ba3681
	bb_write_blocks (ofp, filename);
Packit ba3681
    }
Packit ba3681
  else if (file_format == FF_BSD || file_format == FF_BSD44)
Packit ba3681
    {
Packit ba3681
      UNIT raw_bin_count;
Packit ba3681
      unsigned int i, hdrsize;
Packit ba3681
      unsigned padsize;
Packit ba3681
      char pad[3*4];
Packit ba3681
      Arc *arc;
Packit ba3681
      Sym *sym;
Packit ba3681
Packit ba3681
      memset (pad, 0, sizeof (pad));
Packit ba3681
Packit ba3681
      hdrsize = 0;
Packit ba3681
      /* Decide how large the header will be.  Use the 4.4BSD format
Packit ba3681
         header if explicitly specified, or if the profiling rate is
Packit ba3681
         non-standard.  Otherwise, use the old BSD format.  */
Packit ba3681
      if (file_format == FF_BSD44
Packit ba3681
	  || hz != hertz())
Packit ba3681
	{
Packit ba3681
	  padsize = 3*4;
Packit ba3681
	  switch (gmon_get_ptr_size ())
Packit ba3681
	    {
Packit ba3681
	    case ptr_32bit:
Packit ba3681
	      hdrsize = GMON_HDRSIZE_BSD44_32;
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    case ptr_64bit:
Packit ba3681
	      hdrsize = GMON_HDRSIZE_BSD44_64;
Packit ba3681
	      break;
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
      else
Packit ba3681
	{
Packit ba3681
	  padsize = 0;
Packit ba3681
	  switch (gmon_get_ptr_size ())
Packit ba3681
	    {
Packit ba3681
	    case ptr_32bit:
Packit ba3681
	      hdrsize = GMON_HDRSIZE_OLDBSD_32;
Packit ba3681
	      break;
Packit ba3681
Packit ba3681
	    case ptr_64bit:
Packit ba3681
	      hdrsize = GMON_HDRSIZE_OLDBSD_64;
Packit ba3681
	      /* FIXME: Checking host compiler defines here means that we can't
Packit ba3681
		 use a cross gprof alpha OSF.  */
Packit ba3681
#if defined(__alpha__) && defined (__osf__)
Packit ba3681
	      padsize = 4;
Packit ba3681
#endif
Packit ba3681
	      break;
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Write the parts of the headers that are common to both the
Packit ba3681
	 old BSD and 4.4BSD formats.  */
Packit ba3681
      if (gmon_io_write_vma (ofp, histograms->lowpc)
Packit ba3681
          || gmon_io_write_vma (ofp, histograms->highpc)
Packit ba3681
          || gmon_io_write_32 (ofp, histograms->num_bins
Packit ba3681
			       * sizeof (UNIT) + hdrsize))
Packit ba3681
	{
Packit ba3681
	  perror (filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Write out the 4.4BSD header bits, if that's what we're using.  */
Packit ba3681
      if (file_format == FF_BSD44
Packit ba3681
	  || hz != hertz())
Packit ba3681
	{
Packit ba3681
          if (gmon_io_write_32 (ofp, GMONVERSION)
Packit ba3681
	      || gmon_io_write_32 (ofp, (unsigned int) hz))
Packit ba3681
	    {
Packit ba3681
	      perror (filename);
Packit ba3681
	      done (1);
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Now write out any necessary padding after the meaningful
Packit ba3681
	 header bits.  */
Packit ba3681
      if (padsize != 0
Packit ba3681
          && fwrite (pad, 1, padsize, ofp) != padsize)
Packit ba3681
        {
Packit ba3681
          perror (filename);
Packit ba3681
	  done (1);
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Dump the samples.  */
Packit ba3681
      for (i = 0; i < histograms->num_bins; ++i)
Packit ba3681
	{
Packit ba3681
	  bfd_put_16 (core_bfd, (bfd_vma) histograms->sample[i],
Packit ba3681
		      (bfd_byte *) &raw_bin_count[0]);
Packit ba3681
	  if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1)
Packit ba3681
	    {
Packit ba3681
	      perror (filename);
Packit ba3681
	      done (1);
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
Packit ba3681
      /* Dump the normalized raw arc information.  */
Packit ba3681
      for (sym = symtab.base; sym < symtab.limit; ++sym)
Packit ba3681
	{
Packit ba3681
	  for (arc = sym->cg.children; arc; arc = arc->next_child)
Packit ba3681
	    {
Packit ba3681
	      if (gmon_write_raw_arc (ofp, arc->parent->addr,
Packit ba3681
				      arc->child->addr, arc->count))
Packit ba3681
		{
Packit ba3681
		  perror (filename);
Packit ba3681
		  done (1);
Packit ba3681
		}
Packit ba3681
	      DBG (SAMPLEDEBUG,
Packit ba3681
		   printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n",
Packit ba3681
			   (unsigned long) arc->parent->addr,
Packit ba3681
			   (unsigned long) arc->child->addr, arc->count));
Packit ba3681
	    }
Packit ba3681
	}
Packit ba3681
Packit ba3681
      fclose (ofp);
Packit ba3681
    }
Packit ba3681
  else
Packit ba3681
    {
Packit ba3681
      fprintf (stderr, _("%s: don't know how to deal with file format %d\n"),
Packit ba3681
	       whoami, file_format);
Packit ba3681
      done (1);
Packit ba3681
    }
Packit ba3681
}