1/* gmon_io.c - Input and output from/to gmon.out files.
2
3   Copyright (C) 1999-2017 Free Software Foundation, Inc.
4
5   This file is part of GNU Binutils.
6
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 3 of the License, or
10   (at your option) any later version.
11
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.
16
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., 51 Franklin Street - Fifth Floor, Boston, MA
20   02110-1301, USA.  */
21
22#include "gprof.h"
23#include "binary-io.h"
24#include "search_list.h"
25#include "source.h"
26#include "symtab.h"
27#include "cg_arcs.h"
28#include "basic_blocks.h"
29#include "corefile.h"
30#include "call_graph.h"
31#include "gmon_io.h"
32#include "gmon_out.h"
33#include "gmon.h"		/* Fetch header for old format.  */
34#include "hertz.h"
35#include "hist.h"
36#include "libiberty.h"
37
38enum gmon_ptr_size {
39  ptr_32bit,
40  ptr_64bit
41};
42
43enum gmon_ptr_signedness {
44  ptr_signed,
45  ptr_unsigned
46};
47
48static enum gmon_ptr_size gmon_get_ptr_size (void);
49static enum gmon_ptr_signedness gmon_get_ptr_signedness (void);
50
51#ifdef BFD_HOST_U_64_BIT
52static int gmon_io_read_64 (FILE *, BFD_HOST_U_64_BIT *);
53static int gmon_io_write_64 (FILE *, BFD_HOST_U_64_BIT);
54#endif
55static int gmon_read_raw_arc
56  (FILE *, bfd_vma *, bfd_vma *, unsigned long *);
57static int gmon_write_raw_arc
58  (FILE *, bfd_vma, bfd_vma, unsigned long);
59
60int gmon_input = 0;
61int gmon_file_version = 0;	/* 0 == old (non-versioned) file format.  */
62
63static enum gmon_ptr_size
64gmon_get_ptr_size (void)
65{
66  int size;
67
68  /* Pick best size for pointers.  Start with the ELF size, and if not
69     elf go with the architecture's address size.  */
70  size = bfd_get_arch_size (core_bfd);
71  if (size == -1)
72    size = bfd_arch_bits_per_address (core_bfd);
73
74  switch (size)
75    {
76    case 32:
77      return ptr_32bit;
78
79    case 64:
80      return ptr_64bit;
81
82    default:
83      fprintf (stderr, _("%s: address size has unexpected value of %u\n"),
84	       whoami, size);
85      done (1);
86    }
87}
88
89static enum gmon_ptr_signedness
90gmon_get_ptr_signedness (void)
91{
92  int sext;
93
94  /* Figure out whether to sign extend.  If BFD doesn't know, assume no.  */
95  sext = bfd_get_sign_extend_vma (core_bfd);
96  if (sext == -1)
97    return ptr_unsigned;
98  return (sext ? ptr_signed : ptr_unsigned);
99}
100
101int
102gmon_io_read_32 (FILE *ifp, unsigned int *valp)
103{
104  char buf[4];
105
106  if (fread (buf, 1, 4, ifp) != 4)
107    return 1;
108  *valp = bfd_get_32 (core_bfd, buf);
109  return 0;
110}
111
112#ifdef BFD_HOST_U_64_BIT
113static int
114gmon_io_read_64 (FILE *ifp, BFD_HOST_U_64_BIT *valp)
115{
116  char buf[8];
117
118  if (fread (buf, 1, 8, ifp) != 8)
119    return 1;
120  *valp = bfd_get_64 (core_bfd, buf);
121  return 0;
122}
123#endif
124
125int
126gmon_io_read_vma (FILE *ifp, bfd_vma *valp)
127{
128  unsigned int val32;
129#ifdef BFD_HOST_U_64_BIT
130  BFD_HOST_U_64_BIT val64;
131#endif
132
133  switch (gmon_get_ptr_size ())
134    {
135    case ptr_32bit:
136      if (gmon_io_read_32 (ifp, &val32))
137	return 1;
138      if (gmon_get_ptr_signedness () == ptr_signed)
139        *valp = (int) val32;
140      else
141        *valp = val32;
142      break;
143
144#ifdef BFD_HOST_U_64_BIT
145    case ptr_64bit:
146      if (gmon_io_read_64 (ifp, &val64))
147	return 1;
148#ifdef BFD_HOST_64_BIT
149      if (gmon_get_ptr_signedness () == ptr_signed)
150        *valp = (BFD_HOST_64_BIT) val64;
151      else
152#endif
153        *valp = val64;
154      break;
155#endif
156    }
157  return 0;
158}
159
160int
161gmon_io_read (FILE *ifp, char *buf, size_t n)
162{
163  if (fread (buf, 1, n, ifp) != n)
164    return 1;
165  return 0;
166}
167
168int
169gmon_io_write_32 (FILE *ofp, unsigned int val)
170{
171  char buf[4];
172
173  bfd_put_32 (core_bfd, (bfd_vma) val, buf);
174  if (fwrite (buf, 1, 4, ofp) != 4)
175    return 1;
176  return 0;
177}
178
179#ifdef BFD_HOST_U_64_BIT
180static int
181gmon_io_write_64 (FILE *ofp, BFD_HOST_U_64_BIT val)
182{
183  char buf[8];
184
185  bfd_put_64 (core_bfd, (bfd_vma) val, buf);
186  if (fwrite (buf, 1, 8, ofp) != 8)
187    return 1;
188  return 0;
189}
190#endif
191
192int
193gmon_io_write_vma (FILE *ofp, bfd_vma val)
194{
195
196  switch (gmon_get_ptr_size ())
197    {
198    case ptr_32bit:
199      if (gmon_io_write_32 (ofp, (unsigned int) val))
200	return 1;
201      break;
202
203#ifdef BFD_HOST_U_64_BIT
204    case ptr_64bit:
205      if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) val))
206	return 1;
207      break;
208#endif
209    }
210  return 0;
211}
212
213int
214gmon_io_write_8 (FILE *ofp, unsigned int val)
215{
216  char buf[1];
217
218  bfd_put_8 (core_bfd, val, buf);
219  if (fwrite (buf, 1, 1, ofp) != 1)
220    return 1;
221  return 0;
222}
223
224int
225gmon_io_write (FILE *ofp, char *buf, size_t n)
226{
227  if (fwrite (buf, 1, n, ofp) != n)
228    return 1;
229  return 0;
230}
231
232static int
233gmon_read_raw_arc (FILE *ifp, bfd_vma *fpc, bfd_vma *spc, unsigned long *cnt)
234{
235#ifdef BFD_HOST_U_64_BIT
236  BFD_HOST_U_64_BIT cnt64;
237#endif
238  unsigned int cnt32;
239
240  if (gmon_io_read_vma (ifp, fpc)
241      || gmon_io_read_vma (ifp, spc))
242    return 1;
243
244  switch (gmon_get_ptr_size ())
245    {
246    case ptr_32bit:
247      if (gmon_io_read_32 (ifp, &cnt32))
248	return 1;
249      *cnt = cnt32;
250      break;
251
252#ifdef BFD_HOST_U_64_BIT
253    case ptr_64bit:
254      if (gmon_io_read_64 (ifp, &cnt64))
255	return 1;
256      *cnt = cnt64;
257      break;
258#endif
259
260    default:
261      return 1;
262    }
263  return 0;
264}
265
266static int
267gmon_write_raw_arc (FILE *ofp, bfd_vma fpc, bfd_vma spc, unsigned long cnt)
268{
269
270  if (gmon_io_write_vma (ofp, fpc)
271      || gmon_io_write_vma (ofp, spc))
272    return 1;
273
274  switch (gmon_get_ptr_size ())
275    {
276    case ptr_32bit:
277      if (gmon_io_write_32 (ofp, (unsigned int) cnt))
278	return 1;
279      break;
280
281#ifdef BFD_HOST_U_64_BIT
282    case ptr_64bit:
283      if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) cnt))
284	return 1;
285      break;
286#endif
287    }
288  return 0;
289}
290
291void
292gmon_out_read (const char *filename)
293{
294  FILE *ifp;
295  struct gmon_hdr ghdr;
296  unsigned char tag;
297  int nhist = 0, narcs = 0, nbbs = 0;
298
299  /* Open gmon.out file.  */
300  if (strcmp (filename, "-") == 0)
301    {
302      ifp = stdin;
303      SET_BINARY (fileno (stdin));
304    }
305  else
306    {
307      ifp = fopen (filename, FOPEN_RB);
308
309      if (!ifp)
310	{
311	  perror (filename);
312	  done (1);
313	}
314    }
315
316  if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1)
317    {
318      fprintf (stderr, _("%s: file too short to be a gmon file\n"),
319	       filename);
320      done (1);
321    }
322
323  if ((file_format == FF_MAGIC)
324      || (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)))
325    {
326      if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))
327	{
328	  fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
329		   whoami, filename);
330	  done (1);
331	}
332
333      /* Right magic, so it's probably really a new gmon.out file.  */
334      gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version);
335
336      if (gmon_file_version != GMON_VERSION && gmon_file_version != 0)
337	{
338	  fprintf (stderr,
339		   _("%s: file `%s' has unsupported version %d\n"),
340		   whoami, filename, gmon_file_version);
341	  done (1);
342	}
343
344      /* Read in all the records.  */
345      while (fread (&tag, sizeof (tag), 1, ifp) == 1)
346	{
347	  switch (tag)
348	    {
349	    case GMON_TAG_TIME_HIST:
350	      ++nhist;
351	      gmon_input |= INPUT_HISTOGRAM;
352	      hist_read_rec (ifp, filename);
353	      break;
354
355	    case GMON_TAG_CG_ARC:
356	      ++narcs;
357	      gmon_input |= INPUT_CALL_GRAPH;
358	      cg_read_rec (ifp, filename);
359	      break;
360
361	    case GMON_TAG_BB_COUNT:
362	      ++nbbs;
363	      gmon_input |= INPUT_BB_COUNTS;
364	      bb_read_rec (ifp, filename);
365	      break;
366
367	    default:
368	      fprintf (stderr,
369		       _("%s: %s: found bad tag %d (file corrupted?)\n"),
370		       whoami, filename, tag);
371	      done (1);
372	    }
373	}
374    }
375  else if (file_format == FF_AUTO
376	   || file_format == FF_BSD
377	   || file_format == FF_BSD44)
378    {
379      struct hdr
380      {
381	bfd_vma low_pc;
382	bfd_vma high_pc;
383	unsigned int ncnt;
384      };
385      unsigned int i;
386      int samp_bytes, header_size = 0;
387      unsigned long count;
388      bfd_vma from_pc, self_pc;
389      UNIT raw_bin_count;
390      struct hdr tmp;
391      unsigned int version;
392      unsigned int hist_num_bins;
393
394      /* Information from a gmon.out file is in two parts: an array of
395	 sampling hits within pc ranges, and the arcs.  */
396      gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH;
397
398      /* This fseek() ought to work even on stdin as long as it's
399	 not an interactive device (heck, is there anybody who would
400	 want to type in a gmon.out at the terminal?).  */
401      if (fseek (ifp, 0, SEEK_SET) < 0)
402	{
403	  perror (filename);
404	  done (1);
405	}
406
407      /* The beginning of the old BSD header and the 4.4BSD header
408	 are the same: lowpc, highpc, ncnt  */
409      if (gmon_io_read_vma (ifp, &tmp.low_pc)
410          || gmon_io_read_vma (ifp, &tmp.high_pc)
411          || gmon_io_read_32 (ifp, &tmp.ncnt))
412	{
413 bad_gmon_file:
414          fprintf (stderr, _("%s: file too short to be a gmon file\n"),
415		   filename);
416	  done (1);
417	}
418
419      /* Check to see if this a 4.4BSD-style header.  */
420      if (gmon_io_read_32 (ifp, &version))
421	goto bad_gmon_file;
422
423      if (version == GMONVERSION)
424	{
425	  unsigned int profrate;
426
427	  /* 4.4BSD format header.  */
428          if (gmon_io_read_32 (ifp, &profrate))
429	    goto bad_gmon_file;
430
431	  if (!histograms)
432	    hz = profrate;
433	  else if (hz != (int) profrate)
434	    {
435	      fprintf (stderr,
436		       _("%s: profiling rate incompatible with first gmon file\n"),
437		       filename);
438	      done (1);
439	    }
440
441	  switch (gmon_get_ptr_size ())
442	    {
443	    case ptr_32bit:
444	      header_size = GMON_HDRSIZE_BSD44_32;
445	      break;
446
447	    case ptr_64bit:
448	      header_size = GMON_HDRSIZE_BSD44_64;
449	      break;
450	    }
451	}
452      else
453	{
454	  /* Old style BSD format.  */
455	  if (file_format == FF_BSD44)
456	    {
457	      fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
458		       whoami, filename);
459	      done (1);
460	    }
461
462	  switch (gmon_get_ptr_size ())
463	    {
464	    case ptr_32bit:
465	      header_size = GMON_HDRSIZE_OLDBSD_32;
466	      break;
467
468	    case ptr_64bit:
469	      header_size = GMON_HDRSIZE_OLDBSD_64;
470	      break;
471	    }
472	}
473
474      /* Position the file to after the header.  */
475      if (fseek (ifp, header_size, SEEK_SET) < 0)
476	{
477	  perror (filename);
478	  done (1);
479	}
480
481      samp_bytes = tmp.ncnt - header_size;
482      hist_num_bins = samp_bytes / sizeof (UNIT);
483      if (histograms && (tmp.low_pc != histograms->lowpc
484			 || tmp.high_pc != histograms->highpc
485			 || (hist_num_bins != histograms->num_bins)))
486	{
487	  fprintf (stderr, _("%s: incompatible with first gmon file\n"),
488		   filename);
489	  done (1);
490	}
491
492      if (!histograms)
493	{
494	  num_histograms = 1;
495	  histograms = (struct histogram *) xmalloc (sizeof (struct histogram));
496	  histograms->lowpc = tmp.low_pc;
497	  histograms->highpc = tmp.high_pc;
498	  histograms->num_bins = hist_num_bins;
499	  hist_scale = (double)((tmp.high_pc - tmp.low_pc) / sizeof (UNIT))
500	    / hist_num_bins;
501	  histograms->sample = (int *) xmalloc (hist_num_bins * sizeof (int));
502	  memset (histograms->sample, 0,
503		  hist_num_bins * sizeof (int));
504	}
505
506      DBG (SAMPLEDEBUG,
507	   printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
508		   (unsigned long) tmp.low_pc, (unsigned long) tmp.high_pc,
509		   tmp.ncnt);
510	   printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
511		   samp_bytes, hist_num_bins));
512
513      /* Make sure that we have sensible values.  */
514      if (samp_bytes < 0 || histograms->lowpc > histograms->highpc)
515	{
516	  fprintf (stderr,
517	    _("%s: file '%s' does not appear to be in gmon.out format\n"),
518	    whoami, filename);
519	  done (1);
520	}
521
522      if (hist_num_bins)
523	++nhist;
524
525      for (i = 0; i < hist_num_bins; ++i)
526	{
527	  if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1)
528	    {
529	      fprintf (stderr,
530		       _("%s: unexpected EOF after reading %d/%d bins\n"),
531		       whoami, --i, hist_num_bins);
532	      done (1);
533	    }
534
535	  histograms->sample[i]
536	    += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
537	}
538
539      /* The rest of the file consists of a bunch of
540	 <from,self,count> tuples.  */
541      while (gmon_read_raw_arc (ifp, &from_pc, &self_pc, &count) == 0)
542	{
543	  ++narcs;
544
545	  DBG (SAMPLEDEBUG,
546	     printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
547		     (unsigned long) from_pc, (unsigned long) self_pc, count));
548
549	  /* Add this arc.  */
550	  cg_tally (from_pc, self_pc, count);
551	}
552
553      if (hz == HZ_WRONG)
554	{
555	  /* How many ticks per second?  If we can't tell, report
556	     time in ticks.  */
557	  hz = hertz ();
558
559	  if (hz == HZ_WRONG)
560	    {
561	      hz = 1;
562	      fprintf (stderr, _("time is in ticks, not seconds\n"));
563	    }
564	}
565    }
566  else
567    {
568      fprintf (stderr, _("%s: don't know how to deal with file format %d\n"),
569	       whoami, file_format);
570      done (1);
571    }
572
573  if (ifp != stdin)
574    fclose (ifp);
575
576  if (output_style & STYLE_GMON_INFO)
577    {
578      printf (_("File `%s' (version %d) contains:\n"),
579	      filename, gmon_file_version);
580      printf (nhist == 1 ?
581	      _("\t%d histogram record\n") :
582	      _("\t%d histogram records\n"), nhist);
583      printf (narcs == 1 ?
584	      _("\t%d call-graph record\n") :
585	      _("\t%d call-graph records\n"), narcs);
586      printf (nbbs == 1 ?
587	      _("\t%d basic-block count record\n") :
588	      _("\t%d basic-block count records\n"), nbbs);
589      first_output = FALSE;
590    }
591}
592
593
594void
595gmon_out_write (const char *filename)
596{
597  FILE *ofp;
598  struct gmon_hdr ghdr;
599
600  ofp = fopen (filename, FOPEN_WB);
601  if (!ofp)
602    {
603      perror (filename);
604      done (1);
605    }
606
607  if (file_format == FF_AUTO || file_format == FF_MAGIC)
608    {
609      /* Write gmon header.  */
610
611      memcpy (&ghdr.cookie[0], GMON_MAGIC, 4);
612      bfd_put_32 (core_bfd, (bfd_vma) GMON_VERSION, (bfd_byte *) ghdr.version);
613
614      if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1)
615	{
616	  perror (filename);
617	  done (1);
618	}
619
620      /* Write execution time histogram if we have one.  */
621      if (gmon_input & INPUT_HISTOGRAM)
622	hist_write_hist (ofp, filename);
623
624      /* Write call graph arcs if we have any.  */
625      if (gmon_input & INPUT_CALL_GRAPH)
626	cg_write_arcs (ofp, filename);
627
628      /* Write basic-block info if we have it.  */
629      if (gmon_input & INPUT_BB_COUNTS)
630	bb_write_blocks (ofp, filename);
631    }
632  else if (file_format == FF_BSD || file_format == FF_BSD44)
633    {
634      UNIT raw_bin_count;
635      unsigned int i, hdrsize;
636      unsigned padsize;
637      char pad[3*4];
638      Arc *arc;
639      Sym *sym;
640
641      memset (pad, 0, sizeof (pad));
642
643      hdrsize = 0;
644      /* Decide how large the header will be.  Use the 4.4BSD format
645         header if explicitly specified, or if the profiling rate is
646         non-standard.  Otherwise, use the old BSD format.  */
647      if (file_format == FF_BSD44
648	  || hz != hertz())
649	{
650	  padsize = 3*4;
651	  switch (gmon_get_ptr_size ())
652	    {
653	    case ptr_32bit:
654	      hdrsize = GMON_HDRSIZE_BSD44_32;
655	      break;
656
657	    case ptr_64bit:
658	      hdrsize = GMON_HDRSIZE_BSD44_64;
659	      break;
660	    }
661	}
662      else
663	{
664	  padsize = 0;
665	  switch (gmon_get_ptr_size ())
666	    {
667	    case ptr_32bit:
668	      hdrsize = GMON_HDRSIZE_OLDBSD_32;
669	      break;
670
671	    case ptr_64bit:
672	      hdrsize = GMON_HDRSIZE_OLDBSD_64;
673	      /* FIXME: Checking host compiler defines here means that we can't
674		 use a cross gprof alpha OSF.  */
675#if defined(__alpha__) && defined (__osf__)
676	      padsize = 4;
677#endif
678	      break;
679	    }
680	}
681
682      /* Write the parts of the headers that are common to both the
683	 old BSD and 4.4BSD formats.  */
684      if (gmon_io_write_vma (ofp, histograms->lowpc)
685          || gmon_io_write_vma (ofp, histograms->highpc)
686          || gmon_io_write_32 (ofp, histograms->num_bins
687			       * sizeof (UNIT) + hdrsize))
688	{
689	  perror (filename);
690	  done (1);
691	}
692
693      /* Write out the 4.4BSD header bits, if that's what we're using.  */
694      if (file_format == FF_BSD44
695	  || hz != hertz())
696	{
697          if (gmon_io_write_32 (ofp, GMONVERSION)
698	      || gmon_io_write_32 (ofp, (unsigned int) hz))
699	    {
700	      perror (filename);
701	      done (1);
702	    }
703	}
704
705      /* Now write out any necessary padding after the meaningful
706	 header bits.  */
707      if (padsize != 0
708          && fwrite (pad, 1, padsize, ofp) != padsize)
709        {
710          perror (filename);
711	  done (1);
712	}
713
714      /* Dump the samples.  */
715      for (i = 0; i < histograms->num_bins; ++i)
716	{
717	  bfd_put_16 (core_bfd, (bfd_vma) histograms->sample[i],
718		      (bfd_byte *) &raw_bin_count[0]);
719	  if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1)
720	    {
721	      perror (filename);
722	      done (1);
723	    }
724	}
725
726      /* Dump the normalized raw arc information.  */
727      for (sym = symtab.base; sym < symtab.limit; ++sym)
728	{
729	  for (arc = sym->cg.children; arc; arc = arc->next_child)
730	    {
731	      if (gmon_write_raw_arc (ofp, arc->parent->addr,
732				      arc->child->addr, arc->count))
733		{
734		  perror (filename);
735		  done (1);
736		}
737	      DBG (SAMPLEDEBUG,
738		   printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n",
739			   (unsigned long) arc->parent->addr,
740			   (unsigned long) arc->child->addr, arc->count));
741	    }
742	}
743
744      fclose (ofp);
745    }
746  else
747    {
748      fprintf (stderr, _("%s: don't know how to deal with file format %d\n"),
749	       whoami, file_format);
750      done (1);
751    }
752}
753