[RFC] Cross-gprof cleanup in gmon_io
Jason R Thorpe
thorpej@wasabisystems.com
Sat Jan 26 15:51:00 GMT 2002
Hi folks...
I was recently looking into some problems with binutils 2.11.2 gprof
on NetBSD/alpha, and in the process of fixing it (binutils gprof gets
the size of the "count" member wrong in the "raw_arc" structure on
LP64 platforms -- it uses u_int, even though 4.4BSD used u_long),
eliminated the GMON_PTR_SIZE constant in favor of using the
bits-per-address info in the bfd arch info. This appears to be
something in the binutils-current gprof TODO list.
Before I port this stuff forward to binutils-current, I would like
some feedback on how I implemented it.
The following patch is against binutils 2.11.2 -- when I'm ready to
officially submit it to the master binutils sources, I'll post an
updated patch with a ChangeLog entry describing it in detail.
--
-- Jason R. Thorpe <thorpej@wasabisystems.com>
-------------- next part --------------
Index: gmon.h
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/gprof/gmon.h,v
retrieving revision 1.3
diff -c -r1.3 gmon.h
*** gmon.h 2001/08/14 04:43:11 1.3
--- gmon.h 2002/01/26 22:34:23
***************
*** 35,71 ****
#ifndef gmon_h
#define gmon_h
! struct raw_phdr
! {
! /* FIXME: Checking a host compiler define means that we can't use
! a cross gprof to the alpha. */
! char low_pc[GMON_PTR_SIZE]; /* base pc address of sample buffer */
! char high_pc[GMON_PTR_SIZE];/* max pc address of sampled buffer */
! char ncnt[4]; /* size of sample buffer (plus this header) */
!
! char version[4]; /* version number */
! char profrate[4]; /* profiling clock rate */
! char spare[3*4]; /* reserved */
! };
#define GMONVERSION 0x00051879
! struct old_raw_phdr
! {
! char low_pc[GMON_PTR_SIZE]; /* base pc address of sample buffer */
! char high_pc[GMON_PTR_SIZE];/* max pc address of sampled buffer */
! char ncnt[4]; /* size of sample buffer (plus this header) */
! /* FIXME: Checking host compiler defines here means that we can't
! use a cross gprof alpha OSF. */
#if defined (__alpha__) && defined (__osf__)
! /*
! * DEC's OSF v3.0 uses 4 bytes of padding to bring the header to
! * a size that is a multiple of 8.
! */
! char pad[4];
#endif
! };
/*
* Histogram counters are unsigned shorts:
--- 35,87 ----
#ifndef gmon_h
#define gmon_h
! /* Size of the 4.4BSD gmon header */
! #define GMON_HDRSIZE_BSD44_32 (4 + 4 + 4 + 4 + 4 + (3 * 4))
! #define GMON_HDRSIZE_BSD44_64 (8 + 8 + 4 + 4 + 4 + (3 * 4))
!
! #if 0 /* For documentation purposes only. */
! struct raw_phdr
! {
! char low_pc[sizeof(void *)]; /* base pc address of sample buffer */
! char high_pc[sizeof(void *)];/* max pc address of sampled buffer */
! char ncnt[4]; /* size of sample buffer (plus this
! header) */
!
! char version[4]; /* version number */
! char profrate[4]; /* profiling clock rate */
! char spare[3*4]; /* reserved */
! };
! #endif
#define GMONVERSION 0x00051879
! /* Size of the old BSD gmon header */
! #define GMON_HDRSIZE_OLDBSD_32 (4 + 4 + 4)
!
! /* FIXME: Checking host compiler defines here means that we can't
! use a cross gprof alpha OSF. */
! #if defined(__alpha__) && defined (__osf__)
! #define GMON_HDRSIZE_OLDBSD_64 (8 + 8 + 4 + 4)
! #else
! #define GMON_HDRSIZE_OLDBSD_64 (8 + 8 + 4)
! #endif
! #if 0 /* For documentation purposes only. */
! struct old_raw_phdr
! {
! char low_pc[sizeof(void *)]; /* base pc address of sample buffer */
! char high_pc[sizeof(void *)];/* max pc address of sampled buffer */
! char ncnt[4]; /* size of sample buffer (plus this
! header) */
#if defined (__alpha__) && defined (__osf__)
! /*
! * DEC's OSF v3.0 uses 4 bytes of padding to bring the header to
! * a size that is a multiple of 8.
! */
! char pad[4];
#endif
! };
! #endif
/*
* Histogram counters are unsigned shorts:
***************
*** 120,131 ****
* as to get a packed representation (otherwise, different compilers
* might introduce different padding):
*/
! struct raw_arc
! {
! char from_pc[GMON_PTR_SIZE];
! char self_pc[GMON_PTR_SIZE];
! char count[4];
! };
/*
* General rounding functions:
--- 136,149 ----
* as to get a packed representation (otherwise, different compilers
* might introduce different padding):
*/
! #if 0 /* For documentation purposes only. */
! struct raw_arc
! {
! char from_pc[sizeof(void *)];
! char self_pc[sizeof(void *)];
! char count[sizeof(u_long)];
! };
! #endif
/*
* General rounding functions:
Index: gmon_io.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/gprof/gmon_io.c,v
retrieving revision 1.4
diff -c -r1.4 gmon_io.c
*** gmon_io.c 2001/08/14 04:43:11 1.4
--- gmon_io.c 2002/01/26 22:34:23
***************
*** 36,63 ****
int gmon_file_version = 0; /* 0 == old (non-versioned) file format. */
int
DEFUN (gmon_io_read_vma, (ifp, valp), FILE * ifp AND bfd_vma *valp)
{
char buf[8];
bfd_vma val;
! switch (GMON_PTR_SIZE)
{
! case 4:
! if (fread (buf, 1, 4, ifp) != 4)
return 1;
! val = bfd_get_32 (core_bfd, buf);
break;
! case 8:
! if (fread (buf, 1, 8, ifp) != 8)
return 1;
! val = bfd_get_64 (core_bfd, buf);
break;
default:
! fprintf (stderr, _("%s: GMON_PTR_SIZE has unexpected value of %u\n"),
! whoami, GMON_PTR_SIZE);
done (1);
}
*valp = val;
--- 36,87 ----
int gmon_file_version = 0; /* 0 == old (non-versioned) file format. */
int
+ DEFUN (gmon_io_read_32, (ifp, valp), FILE * ifp AND unsigned int *valp)
+ {
+ char buf[4];
+
+ if (fread (buf, 1, 4, ifp) != 4)
+ return 1;
+ *valp = bfd_get_32 (core_bfd, buf);
+ return 0;
+ }
+
+ int
+ DEFUN (gmon_io_read_64, (ifp, valp), FILE * ifp AND BFD_HOST_U_64_BIT *valp)
+ {
+ char buf[8];
+
+ if (fread (buf, 1, 8, ifp) != 8)
+ return 1;
+ *valp = bfd_get_64 (core_bfd, buf);
+ return 0;
+ }
+
+ int
DEFUN (gmon_io_read_vma, (ifp, valp), FILE * ifp AND bfd_vma *valp)
{
char buf[8];
bfd_vma val;
+ unsigned int val32;
+ BFD_HOST_U_64_BIT val64;
! switch (bfd_arch_bits_per_address (core_bfd))
{
! case 32:
! if (gmon_io_read_32 (ifp, &val32))
return 1;
! val = val32;
break;
! case 64:
! if (gmon_io_read_64 (ifp, &val64))
return 1;
! val = val64;
break;
default:
! fprintf (stderr, _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
done (1);
}
*valp = val;
***************
*** 65,84 ****
}
int
! DEFUN (gmon_io_read_32, (ifp, valp), FILE * ifp AND unsigned int *valp)
{
char buf[4];
! if (fread (buf, 1, 4, ifp) != 4)
return 1;
- *valp = bfd_get_32 (core_bfd, buf);
return 0;
}
int
! DEFUN (gmon_io_read, (ifp, buf, n), FILE * ifp AND char *buf AND size_t n)
{
! if (fread (buf, 1, n, ifp) != n)
return 1;
return 0;
}
--- 89,119 ----
}
int
! DEFUN (gmon_io_read, (ifp, buf, n), FILE * ifp AND char *buf AND size_t n)
{
+ if (fread (buf, 1, n, ifp) != n)
+ return 1;
+ return 0;
+ }
+
+ int
+ DEFUN (gmon_io_write_32, (ofp, val), FILE * ofp AND unsigned int val)
+ {
char buf[4];
! bfd_put_32 (core_bfd, val, buf);
! if (fwrite (buf, 1, 4, ofp) != 4)
return 1;
return 0;
}
int
! DEFUN (gmon_io_write_64, (ofp, val), FILE * ofp AND BFD_HOST_U_64_BIT val)
{
! char buf[8];
!
! bfd_put_64 (core_bfd, val, buf);
! if (fwrite (buf, 1, 8, ofp) != 8)
return 1;
return 0;
}
***************
*** 88,127 ****
{
char buf[8];
! switch (GMON_PTR_SIZE)
{
! case 4:
! bfd_put_32 (core_bfd, val, buf);
! if (fwrite (buf, 1, 4, ofp) != 4)
return 1;
break;
! case 8:
! bfd_put_64 (core_bfd, val, buf);
! if (fwrite (buf, 1, 8, ofp) != 8)
return 1;
break;
default:
! fprintf (stderr, _("%s: GMON_PTR_SIZE has unexpected value of %u\n"),
! whoami, GMON_PTR_SIZE);
done (1);
}
return 0;
}
int
- DEFUN (gmon_io_write_32, (ofp, val), FILE * ofp AND unsigned int val)
- {
- char buf[4];
-
- bfd_put_32 (core_bfd, val, buf);
- if (fwrite (buf, 1, 4, ofp) != 4)
- return 1;
- return 0;
- }
-
- int
DEFUN (gmon_io_write_8, (ofp, val), FILE * ofp AND unsigned char val)
{
char buf[1];
--- 123,149 ----
{
char buf[8];
! switch (bfd_arch_bits_per_address (core_bfd))
{
! case 32:
! if (gmon_io_write_32 (ofp, (unsigned int) val))
return 1;
break;
! case 64:
! if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) val))
return 1;
break;
default:
! fprintf (stderr, _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
done (1);
}
return 0;
}
int
DEFUN (gmon_io_write_8, (ofp, val), FILE * ofp AND unsigned char val)
{
char buf[1];
***************
*** 139,178 ****
return 1;
return 0;
}
! /* get_vma and put_vma are for backwards compatibility only */
! static bfd_vma
! DEFUN (get_vma, (abfd, addr), bfd * abfd AND bfd_byte * addr)
! {
! switch (sizeof (char*))
! {
! case 4:
! return bfd_get_32 (abfd, addr);
! case 8:
! return bfd_get_64 (abfd, addr);
default:
! fprintf (stderr, _("%s: bfd_vma has unexpected size of %ld bytes\n"),
! whoami, (long) sizeof (char*));
done (1);
}
}
! static void
! DEFUN (put_vma, (abfd, val, addr), bfd * abfd AND bfd_vma val AND bfd_byte * addr)
{
! switch (sizeof (char*))
{
! case 4:
! bfd_put_32 (abfd, val, addr);
break;
! case 8:
! bfd_put_64 (abfd, val, addr);
break;
default:
! fprintf (stderr, _("%s: bfd_vma has unexpected size of %ld bytes\n"),
! whoami, (long) sizeof (char*));
done (1);
}
}
void
--- 161,225 ----
return 1;
return 0;
}
+
+ int
+ DEFUN (gmon_read_raw_arc, (ifp, fpc, spc, cnt), FILE * ifp AND bfd_vma *fpc AND bfd_vma *spc AND unsigned long *cnt)
+ {
+ BFD_HOST_U_64_BIT cnt64;
+ unsigned int cnt32;
+
+ if (gmon_io_read_vma (ifp, fpc)
+ || gmon_io_read_vma (ifp, spc))
+ return 1;
! switch (bfd_arch_bits_per_address (core_bfd))
! {
! case 32:
! if (gmon_io_read_32 (ifp, &cnt32))
! return 1;
! *cnt = cnt32;
! break;
!
! case 64:
! if (gmon_io_read_64 (ifp, &cnt64))
! return 1;
! *cnt = cnt64;
! break;
!
default:
! fprintf (stderr, _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
done (1);
}
+ return 0;
}
! int
! DEFUN (gmon_write_raw_arc, (ofp, fpc, spc, cnt), FILE * ofp AND bfd_vma fpc AND bfd_vma spc AND unsigned long cnt)
{
!
! if (gmon_io_write_vma (ofp, fpc)
! || gmon_io_write_vma (ofp, spc))
! return 1;
!
! switch (bfd_arch_bits_per_address (core_bfd))
{
! case 32:
! if (gmon_io_write_32 (ofp, (unsigned int) cnt))
! return 1;
break;
!
! case 64:
! if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) cnt))
! return 1;
break;
+
default:
! fprintf (stderr, _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
done (1);
}
+ return 0;
}
void
***************
*** 274,284 ****
int i, samp_bytes, header_size;
unsigned long count;
bfd_vma from_pc, self_pc;
- struct raw_arc raw_arc;
- struct raw_phdr raw;
static struct hdr h;
UNIT raw_bin_count;
struct hdr tmp;
/* Information from a gmon.out file is in two parts: an array of
sampling hits within pc ranges, and the arcs. */
--- 321,330 ----
int i, samp_bytes, header_size;
unsigned long count;
bfd_vma from_pc, self_pc;
static struct hdr h;
UNIT raw_bin_count;
struct hdr tmp;
+ int version;
/* Information from a gmon.out file is in two parts: an array of
sampling hits within pc ranges, and the arcs. */
***************
*** 293,317 ****
done (1);
}
! if (fread (&raw, 1, sizeof (struct raw_phdr), ifp)
! != sizeof (struct raw_phdr))
{
! fprintf (stderr, _("%s: file too short to be a gmon file\n"),
filename);
done (1);
}
! tmp.low_pc = get_vma (core_bfd, (bfd_byte *) &raw.low_pc[0]);
! tmp.high_pc = get_vma (core_bfd, (bfd_byte *) &raw.high_pc[0]);
! tmp.ncnt = bfd_get_32 (core_bfd, (bfd_byte *) &raw.ncnt[0]);
! if (bfd_get_32 (core_bfd, (bfd_byte *) &raw.version[0])
! == GMONVERSION)
{
int profrate;
/* 4.4BSD format header. */
! profrate = bfd_get_32 (core_bfd, (bfd_byte *) &raw.profrate[0]);
if (!s_highpc)
hz = profrate;
--- 339,367 ----
done (1);
}
! /* The beginning of the old BSD header and the 4.4BSD header
! are the same: lowpc, highpc, ncnt */
! if (gmon_io_read_vma (ifp, &tmp.low_pc)
! || gmon_io_read_vma (ifp, &tmp.high_pc)
! || gmon_io_read_32 (ifp, &tmp.ncnt))
{
! bad_gmon_file:
! fprintf (stderr, _("%s: file too short to be a gmon file\n"),
filename);
done (1);
}
! /* Check to see if this a 4.4BSD-style header. */
! if (gmon_io_read_32 (ifp, &version))
! goto bad_gmon_file;
! if (version == GMONVERSION)
{
int profrate;
/* 4.4BSD format header. */
! if (gmon_io_read_32 (ifp, &profrate))
! goto bad_gmon_file;
if (!s_highpc)
hz = profrate;
***************
*** 323,329 ****
done (1);
}
! header_size = sizeof (struct raw_phdr);
}
else
{
--- 373,394 ----
done (1);
}
! switch (bfd_arch_bits_per_address (core_bfd))
! {
! case 32:
! header_size = GMON_HDRSIZE_BSD44_32;
! break;
!
! case 64:
! header_size = GMON_HDRSIZE_BSD44_64;
! break;
!
! default:
! fprintf (stderr,
! _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
! done (1);
! }
}
else
{
***************
*** 335,347 ****
done (1);
}
! if (fseek (ifp, sizeof (struct old_raw_phdr), SEEK_SET) < 0)
{
! perror (filename);
! done (1);
}
! header_size = sizeof (struct old_raw_phdr);
}
if (s_highpc && (tmp.low_pc != h.low_pc
--- 400,428 ----
done (1);
}
! switch (bfd_arch_bits_per_address (core_bfd))
{
! case 32:
! header_size = GMON_HDRSIZE_OLDBSD_32;
! break;
!
! case 64:
! header_size = GMON_HDRSIZE_OLDBSD_64;
! break;
!
! default:
! fprintf (stderr,
! _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
! done (1);
}
+ }
! /* Position the file to after the header. */
! if (fseek (ifp, header_size, SEEK_SET) < 0)
! {
! perror (filename);
! done (1);
}
if (s_highpc && (tmp.low_pc != h.low_pc
***************
*** 406,421 ****
/* The rest of the file consists of a bunch of
<from,self,count> tuples. */
! while (fread (&raw_arc, sizeof (raw_arc), 1, ifp) == 1)
{
++narcs;
- from_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.from_pc);
- self_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.self_pc);
- #if defined(__arch64__)
- count = bfd_get_64 (core_bfd, (bfd_byte *) raw_arc.count);
- #else
- count = bfd_get_32 (core_bfd, (bfd_byte *) raw_arc.count);
- #endif
DBG (SAMPLEDEBUG,
printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
--- 487,495 ----
/* The rest of the file consists of a bunch of
<from,self,count> tuples. */
! while (gmon_read_raw_arc (ifp, &from_pc, &self_pc, &count) == 0)
{
++narcs;
DBG (SAMPLEDEBUG,
printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
***************
*** 502,544 ****
}
else if (file_format == FF_BSD || file_format == FF_BSD44)
{
- struct raw_arc raw_arc;
UNIT raw_bin_count;
! struct raw_phdr h;
! int i;
Arc *arc;
Sym *sym;
! memset (&h, 0, sizeof h);
! put_vma (core_bfd, s_lowpc, (bfd_byte *) &h.low_pc);
! put_vma (core_bfd, s_highpc, (bfd_byte *) &h.high_pc);
! bfd_put_32 (core_bfd,
! hist_num_bins * sizeof (UNIT) + sizeof (struct raw_phdr),
! (bfd_byte *) &h.ncnt);
!
! /* Write header. Use new style BSD format is explicitly
! specified, or if the profiling rate is non-standard;
! otherwise, use the old BSD format. */
if (file_format == FF_BSD44
! || hz != hertz ())
{
! bfd_put_32 (core_bfd, GMONVERSION, (bfd_byte *) &h.version);
! bfd_put_32 (core_bfd, hz, (bfd_byte *) &h.profrate);
! if (fwrite (&h, sizeof (struct raw_phdr), 1, ofp) != 1)
{
! perror (filename);
! done (1);
}
}
else
{
! if (fwrite (&h, sizeof (struct old_raw_phdr), 1, ofp) != 1)
{
perror (filename);
done (1);
}
}
/* Dump the samples. */
for (i = 0; i < hist_num_bins; ++i)
{
--- 576,670 ----
}
else if (file_format == FF_BSD || file_format == FF_BSD44)
{
UNIT raw_bin_count;
! int i, hdrsize, padsize;
! char pad[3*4];
Arc *arc;
Sym *sym;
+
+ memset (pad, 0, sizeof (pad));
! /* Decide how large the header will be. Use the 4.4BSD format
! header if explicitly specified, or if the profiling rate is
! non-standard. Otherwise, use the old BSD format. */
if (file_format == FF_BSD44
! || hz != hertz())
{
! padsize = 3*4;
! switch (bfd_arch_bits_per_address (core_bfd))
{
! case 32:
! hdrsize = GMON_HDRSIZE_BSD44_32;
! break;
!
! case 64:
! hdrsize = GMON_HDRSIZE_BSD44_64;
! break;
!
! default:
! fprintf (stderr,
! _("%s: bits per address has unexpected value of %u\n"),
! whoami, bfd_arch_bits_per_address (core_bfd));
! done (1);
}
}
else
{
! padsize = 0;
! switch (bfd_arch_bits_per_address (core_bfd))
{
+ case 32:
+ hdrsize = GMON_HDRSIZE_OLDBSD_32;
+ break;
+
+ case 64:
+ hdrsize = GMON_HDRSIZE_OLDBSD_64;
+ /* FIXME: Checking host compiler defines here means that we can't
+ use a cross gprof alpha OSF. */
+ #if defined(__alpha__) && defined (__osf__)
+ padsize = 4;
+ #endif
+ break;
+
+ default:
+ fprintf (stderr,
+ _("%s: bits per address has unexpected value of %u\n"),
+ whoami, bfd_arch_bits_per_address (core_bfd));
+ done (1);
+ }
+ }
+
+ /* Write the parts of the headers that are common to both the
+ old BSD and 4.4BSD formats. */
+ if (gmon_io_write_vma (ofp, s_lowpc)
+ || gmon_io_write_vma (ofp, s_highpc)
+ || gmon_io_write_32 (ofp, hist_num_bins * sizeof (UNIT) + hdrsize))
+ {
+ perror (filename);
+ done (1);
+ }
+
+ /* Write out the 4.4BSD header bits, if that's what we're using. */
+ if (file_format == FF_BSD44
+ || hz != hertz())
+ {
+ if (gmon_io_write_32 (ofp, GMONVERSION)
+ || gmon_io_write_32 (ofp, hz))
+ {
perror (filename);
done (1);
}
}
+ /* Now write out any necessary padding after the meaningful
+ header bits. */
+ if (padsize != 0
+ && fwrite (pad, 1, padsize, ofp) != padsize)
+ {
+ perror (filename);
+ done (1);
+ }
+
/* Dump the samples. */
for (i = 0; i < hist_num_bins; ++i)
{
***************
*** 555,566 ****
{
for (arc = sym->cg.children; arc; arc = arc->next_child)
{
! put_vma (core_bfd, arc->parent->addr,
! (bfd_byte *) raw_arc.from_pc);
! put_vma (core_bfd, arc->child->addr,
! (bfd_byte *) raw_arc.self_pc);
! bfd_put_32 (core_bfd, arc->count, (bfd_byte *) raw_arc.count);
! if (fwrite (&raw_arc, sizeof (raw_arc), 1, ofp) != 1)
{
perror (filename);
done (1);
--- 681,688 ----
{
for (arc = sym->cg.children; arc; arc = arc->next_child)
{
! if (gmon_write_raw_arc (ofp, arc->parent->addr,
! arc->child->addr, arc->count))
{
perror (filename);
done (1);
More information about the Binutils
mailing list