From 252b5132c753830d5fd56823373aed85f2a0db63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 3 May 1999 07:29:11 +0000 Subject: 19990502 sourceware import --- gprof/gmon_io.c | 454 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) create mode 100644 gprof/gmon_io.c (limited to 'gprof/gmon_io.c') diff --git a/gprof/gmon_io.c b/gprof/gmon_io.c new file mode 100644 index 0000000..ff294f5 --- /dev/null +++ b/gprof/gmon_io.c @@ -0,0 +1,454 @@ +/* + * Input and output from/to gmon.out files. + */ +#include "cg_arcs.h" +#include "basic_blocks.h" +#include "bfd.h" +#include "corefile.h" +#include "call_graph.h" +#include "gmon_io.h" +#include "gmon_out.h" +#include "gmon.h" /* fetch header for old format */ +#include "gprof.h" +#include "hertz.h" +#include "hist.h" +#include "libiberty.h" + +int gmon_input = 0; +int gmon_file_version = 0; /* 0 == old (non-versioned) file format */ + +/* + * This probably ought to be in libbfd. + */ +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); + } +} + + +/* + * This probably ought to be in libbfd. + */ +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 +DEFUN (gmon_out_read, (filename), const char *filename) +{ + FILE *ifp; + struct gmon_hdr ghdr; + unsigned char tag; + int nhist = 0, narcs = 0, nbbs = 0; + + /* open gmon.out file: */ + + if (strcmp (filename, "-") == 0) + { + ifp = stdin; + } + else + { + ifp = fopen (filename, FOPEN_RB); + if (!ifp) + { + perror (filename); + done (1); + } + } + if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1) + { + fprintf (stderr, _("%s: file too short to be a gmon file\n"), + filename); + done (1); + } + + if ((file_format == FF_MAGIC) || + (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))) + { + if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)) + { + fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), + whoami, filename); + done (1); + } + + /* right magic, so it's probably really a new gmon.out file */ + + gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version); + if (gmon_file_version != GMON_VERSION && gmon_file_version != 0) + { + fprintf (stderr, + _("%s: file `%s' has unsupported version %d\n"), + whoami, filename, gmon_file_version); + done (1); + } + + /* read in all the records: */ + while (fread (&tag, sizeof (tag), 1, ifp) == 1) + { + switch (tag) + { + case GMON_TAG_TIME_HIST: + ++nhist; + gmon_input |= INPUT_HISTOGRAM; + hist_read_rec (ifp, filename); + break; + + case GMON_TAG_CG_ARC: + ++narcs; + gmon_input |= INPUT_CALL_GRAPH; + cg_read_rec (ifp, filename); + break; + + case GMON_TAG_BB_COUNT: + ++nbbs; + gmon_input |= INPUT_BB_COUNTS; + bb_read_rec (ifp, filename); + break; + + default: + fprintf (stderr, + _("%s: %s: found bad tag %d (file corrupted?)\n"), + whoami, filename, tag); + done (1); + } + } + } + else if (file_format == FF_AUTO + || file_format == FF_BSD + || file_format == FF_BSD44) + { + struct hdr + { + bfd_vma low_pc; + bfd_vma high_pc; + int ncnt; + }; + 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. + */ + gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH; + + /* + * This fseek() ought to work even on stdin as long as it's + * not an interactive device (heck, is there anybody who would + * want to type in a gmon.out at the terminal?). + */ + if (fseek (ifp, 0, SEEK_SET) < 0) + { + perror (filename); + 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; + else if (hz != profrate) + { + fprintf (stderr, + _("%s: profiling rate incompatible with first gmon file\n"), + filename); + done (1); + } + + header_size = sizeof (struct raw_phdr); + } + else + { + /* old style BSD format. */ + if (file_format == FF_BSD44) + { + fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"), + whoami, filename); + 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 || + tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt)) + { + fprintf (stderr, _("%s: incompatible with first gmon file\n"), + filename); + done (1); + } + h = tmp; + s_lowpc = (bfd_vma) h.low_pc; + s_highpc = (bfd_vma) h.high_pc; + lowpc = (bfd_vma) h.low_pc / sizeof (UNIT); + highpc = (bfd_vma) h.high_pc / sizeof (UNIT); + samp_bytes = h.ncnt - header_size; + hist_num_bins = samp_bytes / sizeof (UNIT); + DBG (SAMPLEDEBUG, + printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n", + h.low_pc, h.high_pc, h.ncnt); + printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n", + s_lowpc, s_highpc); + printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n", + lowpc, highpc); + printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n", + samp_bytes, hist_num_bins)); + + if (hist_num_bins) + { + ++nhist; + } + + if (!hist_sample) + { + hist_sample = + (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0])); + memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0])); + } + + for (i = 0; i < hist_num_bins; ++i) + { + if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1) + { + fprintf (stderr, + _("%s: unexpected EOF after reading %d/%d bins\n"), + whoami, --i, hist_num_bins); + done (1); + } + hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count); + } + + /* + * The rest of the file consists of a bunch of + * 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); + count = bfd_get_32 (core_bfd, (bfd_byte *) raw_arc.count); + DBG (SAMPLEDEBUG, + printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n", + from_pc, self_pc, count)); + /* add this arc: */ + cg_tally (from_pc, self_pc, count); + } + fclose (ifp); + + if (hz == HZ_WRONG) + { + /* + * How many ticks per second? If we can't tell, report + * time in ticks. + */ + hz = hertz (); + if (hz == HZ_WRONG) + { + hz = 1; + fprintf (stderr, _("time is in ticks, not seconds\n")); + } + } + } + else + { + fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), + whoami, file_format); + done (1); + } + + if (output_style & STYLE_GMON_INFO) + { + printf (_("File `%s' (version %d) contains:\n"), + filename, gmon_file_version); + printf (_("\t%d histogram record%s\n"), + nhist, nhist == 1 ? "" : "s"); + printf (_("\t%d call-graph record%s\n"), + narcs, narcs == 1 ? "" : "s"); + printf (_("\t%d basic-block count record%s\n"), + nbbs, nbbs == 1 ? "" : "s"); + first_output = FALSE; + } +} + + +void +DEFUN (gmon_out_write, (filename), const char *filename) +{ + FILE *ofp; + struct gmon_hdr ghdr; + + ofp = fopen (filename, FOPEN_WB); + if (!ofp) + { + perror (filename); + done (1); + } + + if (file_format == FF_AUTO || file_format == FF_MAGIC) + { + /* write gmon header: */ + + memcpy (&ghdr.cookie[0], GMON_MAGIC, 4); + bfd_put_32 (core_bfd, GMON_VERSION, (bfd_byte *) ghdr.version); + if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1) + { + perror (filename); + done (1); + } + + /* write execution time histogram if we have one: */ + if (gmon_input & INPUT_HISTOGRAM) + { + hist_write_hist (ofp, filename); + } + + /* write call graph arcs if we have any: */ + if (gmon_input & INPUT_CALL_GRAPH) + { + cg_write_arcs (ofp, filename); + } + + /* write basic-block info if we have it: */ + if (gmon_input & INPUT_BB_COUNTS) + { + bb_write_blocks (ofp, filename); + } + } + 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) + { + bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & raw_bin_count[0]); + if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1) + { + perror (filename); + done (1); + } + } + + /* dump the normalized raw arc information: */ + + for (sym = symtab.base; sym < symtab.limit; ++sym) + { + 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); + } + DBG (SAMPLEDEBUG, + printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n", + arc->parent->addr, arc->child->addr, arc->count)); + } + } + fclose (ofp); + } + else + { + fprintf (stderr, _("%s: don't know how to deal with file format %d\n"), + whoami, file_format); + done (1); + } +} -- cgit v1.1