xref: /openbsd-src/gnu/usr.bin/binutils/gprof/gmon_io.c (revision c074d1c999f3e07019cd5e9a2f190b057ef3b935)
1b55d4692Sfgsch /* gmon_io.c - Input and output from/to gmon.out files.
2b55d4692Sfgsch 
3*c074d1c9Sdrahn    Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
4b55d4692Sfgsch 
5b55d4692Sfgsch    This file is part of GNU Binutils.
6b55d4692Sfgsch 
7b55d4692Sfgsch    This program is free software; you can redistribute it and/or modify
8b55d4692Sfgsch    it under the terms of the GNU General Public License as published by
9b55d4692Sfgsch    the Free Software Foundation; either version 2 of the License, or
10b55d4692Sfgsch    (at your option) any later version.
11b55d4692Sfgsch 
12b55d4692Sfgsch    This program is distributed in the hope that it will be useful,
13b55d4692Sfgsch    but WITHOUT ANY WARRANTY; without even the implied warranty of
14b55d4692Sfgsch    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b55d4692Sfgsch    GNU General Public License for more details.
16b55d4692Sfgsch 
17b55d4692Sfgsch    You should have received a copy of the GNU General Public License
18b55d4692Sfgsch    along with this program; if not, write to the Free Software
19b55d4692Sfgsch    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20b55d4692Sfgsch    02111-1307, USA.  */
21b55d4692Sfgsch 
22*c074d1c9Sdrahn #include "gprof.h"
23*c074d1c9Sdrahn #include "search_list.h"
24*c074d1c9Sdrahn #include "source.h"
25*c074d1c9Sdrahn #include "symtab.h"
262159047fSniklas #include "cg_arcs.h"
272159047fSniklas #include "basic_blocks.h"
28b305b0f1Sespie #include "corefile.h"
292159047fSniklas #include "call_graph.h"
302159047fSniklas #include "gmon_io.h"
312159047fSniklas #include "gmon_out.h"
32b55d4692Sfgsch #include "gmon.h"		/* Fetch header for old format.  */
332159047fSniklas #include "hertz.h"
342159047fSniklas #include "hist.h"
352159047fSniklas #include "libiberty.h"
362159047fSniklas 
37*c074d1c9Sdrahn enum gmon_ptr_size {
38*c074d1c9Sdrahn   ptr_32bit,
39*c074d1c9Sdrahn   ptr_64bit
40*c074d1c9Sdrahn };
41*c074d1c9Sdrahn 
42*c074d1c9Sdrahn enum gmon_ptr_signedness {
43*c074d1c9Sdrahn   ptr_signed,
44*c074d1c9Sdrahn   ptr_unsigned
45*c074d1c9Sdrahn };
46*c074d1c9Sdrahn 
47*c074d1c9Sdrahn static enum gmon_ptr_size gmon_get_ptr_size PARAMS ((void));
48*c074d1c9Sdrahn static enum gmon_ptr_signedness gmon_get_ptr_signedness PARAMS ((void));
49*c074d1c9Sdrahn 
50*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
51*c074d1c9Sdrahn static int gmon_io_read_64 PARAMS ((FILE *, BFD_HOST_U_64_BIT *));
52*c074d1c9Sdrahn static int gmon_io_write_64 PARAMS ((FILE *, BFD_HOST_U_64_BIT));
53*c074d1c9Sdrahn #endif
54*c074d1c9Sdrahn static int gmon_read_raw_arc
55*c074d1c9Sdrahn   PARAMS ((FILE *, bfd_vma *, bfd_vma *, unsigned long *));
56*c074d1c9Sdrahn static int gmon_write_raw_arc
57*c074d1c9Sdrahn   PARAMS ((FILE *, bfd_vma, bfd_vma, unsigned long));
58*c074d1c9Sdrahn 
592159047fSniklas int gmon_input = 0;
60b55d4692Sfgsch int gmon_file_version = 0;	/* 0 == old (non-versioned) file format.  */
612159047fSniklas 
62*c074d1c9Sdrahn static enum gmon_ptr_size
gmon_get_ptr_size()63*c074d1c9Sdrahn gmon_get_ptr_size ()
64b55d4692Sfgsch {
65*c074d1c9Sdrahn   int size;
66b55d4692Sfgsch 
67*c074d1c9Sdrahn   /* Pick best size for pointers.  Start with the ELF size, and if not
68*c074d1c9Sdrahn      elf go with the architecture's address size.  */
69*c074d1c9Sdrahn   size = bfd_get_arch_size (core_bfd);
70*c074d1c9Sdrahn   if (size == -1)
71*c074d1c9Sdrahn     size = bfd_arch_bits_per_address (core_bfd);
72*c074d1c9Sdrahn 
73*c074d1c9Sdrahn   switch (size)
74b55d4692Sfgsch     {
75*c074d1c9Sdrahn     case 32:
76*c074d1c9Sdrahn       return ptr_32bit;
77b55d4692Sfgsch 
78*c074d1c9Sdrahn     case 64:
79*c074d1c9Sdrahn       return ptr_64bit;
80b55d4692Sfgsch 
81b55d4692Sfgsch     default:
82*c074d1c9Sdrahn       fprintf (stderr, _("%s: address size has unexpected value of %u\n"),
83*c074d1c9Sdrahn 	       whoami, size);
84b55d4692Sfgsch       done (1);
85b55d4692Sfgsch     }
86*c074d1c9Sdrahn }
87*c074d1c9Sdrahn 
88*c074d1c9Sdrahn static enum gmon_ptr_signedness
gmon_get_ptr_signedness()89*c074d1c9Sdrahn gmon_get_ptr_signedness ()
90*c074d1c9Sdrahn {
91*c074d1c9Sdrahn   int sext;
92*c074d1c9Sdrahn 
93*c074d1c9Sdrahn   /* Figure out whether to sign extend.  If BFD doesn't know, assume no.  */
94*c074d1c9Sdrahn   sext = bfd_get_sign_extend_vma (core_bfd);
95*c074d1c9Sdrahn   if (sext == -1)
96*c074d1c9Sdrahn     return ptr_unsigned;
97*c074d1c9Sdrahn   return (sext ? ptr_signed : ptr_unsigned);
98b55d4692Sfgsch }
99b55d4692Sfgsch 
100b55d4692Sfgsch int
gmon_io_read_32(ifp,valp)101*c074d1c9Sdrahn gmon_io_read_32 (ifp, valp)
102*c074d1c9Sdrahn      FILE *ifp;
103*c074d1c9Sdrahn      unsigned int *valp;
104b55d4692Sfgsch {
105b55d4692Sfgsch   char buf[4];
106b55d4692Sfgsch 
107b55d4692Sfgsch   if (fread (buf, 1, 4, ifp) != 4)
108b55d4692Sfgsch     return 1;
109b55d4692Sfgsch   *valp = bfd_get_32 (core_bfd, buf);
110b55d4692Sfgsch   return 0;
111b55d4692Sfgsch }
112b55d4692Sfgsch 
113*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
114*c074d1c9Sdrahn static int
gmon_io_read_64(ifp,valp)115*c074d1c9Sdrahn gmon_io_read_64 (ifp, valp)
116*c074d1c9Sdrahn      FILE *ifp;
117*c074d1c9Sdrahn      BFD_HOST_U_64_BIT *valp;
118*c074d1c9Sdrahn {
119*c074d1c9Sdrahn   char buf[8];
120*c074d1c9Sdrahn 
121*c074d1c9Sdrahn   if (fread (buf, 1, 8, ifp) != 8)
122*c074d1c9Sdrahn     return 1;
123*c074d1c9Sdrahn   *valp = bfd_get_64 (core_bfd, buf);
124*c074d1c9Sdrahn   return 0;
125*c074d1c9Sdrahn }
126*c074d1c9Sdrahn #endif
127*c074d1c9Sdrahn 
128b55d4692Sfgsch int
gmon_io_read_vma(ifp,valp)129*c074d1c9Sdrahn gmon_io_read_vma (ifp, valp)
130*c074d1c9Sdrahn      FILE *ifp;
131*c074d1c9Sdrahn      bfd_vma *valp;
132*c074d1c9Sdrahn {
133*c074d1c9Sdrahn   unsigned int val32;
134*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
135*c074d1c9Sdrahn   BFD_HOST_U_64_BIT val64;
136*c074d1c9Sdrahn #endif
137*c074d1c9Sdrahn 
138*c074d1c9Sdrahn   switch (gmon_get_ptr_size ())
139*c074d1c9Sdrahn     {
140*c074d1c9Sdrahn     case ptr_32bit:
141*c074d1c9Sdrahn       if (gmon_io_read_32 (ifp, &val32))
142*c074d1c9Sdrahn 	return 1;
143*c074d1c9Sdrahn       if (gmon_get_ptr_signedness () == ptr_signed)
144*c074d1c9Sdrahn         *valp = (int) val32;
145*c074d1c9Sdrahn       else
146*c074d1c9Sdrahn         *valp = val32;
147*c074d1c9Sdrahn       break;
148*c074d1c9Sdrahn 
149*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
150*c074d1c9Sdrahn     case ptr_64bit:
151*c074d1c9Sdrahn       if (gmon_io_read_64 (ifp, &val64))
152*c074d1c9Sdrahn 	return 1;
153*c074d1c9Sdrahn #ifdef BFD_HOST_64_BIT
154*c074d1c9Sdrahn       if (gmon_get_ptr_signedness () == ptr_signed)
155*c074d1c9Sdrahn         *valp = (BFD_HOST_64_BIT) val64;
156*c074d1c9Sdrahn       else
157*c074d1c9Sdrahn #endif
158*c074d1c9Sdrahn         *valp = val64;
159*c074d1c9Sdrahn       break;
160*c074d1c9Sdrahn #endif
161*c074d1c9Sdrahn     }
162*c074d1c9Sdrahn   return 0;
163*c074d1c9Sdrahn }
164*c074d1c9Sdrahn 
165*c074d1c9Sdrahn int
gmon_io_read(ifp,buf,n)166*c074d1c9Sdrahn gmon_io_read (ifp, buf, n)
167*c074d1c9Sdrahn      FILE *ifp;
168*c074d1c9Sdrahn      char *buf;
169*c074d1c9Sdrahn      size_t n;
170b55d4692Sfgsch {
171b55d4692Sfgsch   if (fread (buf, 1, n, ifp) != n)
172b55d4692Sfgsch     return 1;
173b55d4692Sfgsch   return 0;
174b55d4692Sfgsch }
175b55d4692Sfgsch 
176b55d4692Sfgsch int
gmon_io_write_32(ofp,val)177*c074d1c9Sdrahn gmon_io_write_32 (ofp, val)
178*c074d1c9Sdrahn      FILE *ofp;
179*c074d1c9Sdrahn      unsigned int val;
180b55d4692Sfgsch {
181b55d4692Sfgsch   char buf[4];
182b55d4692Sfgsch 
183*c074d1c9Sdrahn   bfd_put_32 (core_bfd, (bfd_vma) val, buf);
184b55d4692Sfgsch   if (fwrite (buf, 1, 4, ofp) != 4)
185b55d4692Sfgsch     return 1;
186b55d4692Sfgsch   return 0;
187b55d4692Sfgsch }
188b55d4692Sfgsch 
189*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
190*c074d1c9Sdrahn static int
gmon_io_write_64(ofp,val)191*c074d1c9Sdrahn gmon_io_write_64 (ofp, val)
192*c074d1c9Sdrahn      FILE *ofp;
193*c074d1c9Sdrahn      BFD_HOST_U_64_BIT val;
194*c074d1c9Sdrahn {
195*c074d1c9Sdrahn   char buf[8];
196*c074d1c9Sdrahn 
197*c074d1c9Sdrahn   bfd_put_64 (core_bfd, (bfd_vma) val, buf);
198*c074d1c9Sdrahn   if (fwrite (buf, 1, 8, ofp) != 8)
199*c074d1c9Sdrahn     return 1;
200*c074d1c9Sdrahn   return 0;
201*c074d1c9Sdrahn }
202*c074d1c9Sdrahn #endif
203*c074d1c9Sdrahn 
204b55d4692Sfgsch int
gmon_io_write_vma(ofp,val)205*c074d1c9Sdrahn gmon_io_write_vma (ofp, val)
206*c074d1c9Sdrahn      FILE *ofp;
207*c074d1c9Sdrahn      bfd_vma val;
208*c074d1c9Sdrahn {
209*c074d1c9Sdrahn 
210*c074d1c9Sdrahn   switch (gmon_get_ptr_size ())
211*c074d1c9Sdrahn     {
212*c074d1c9Sdrahn     case ptr_32bit:
213*c074d1c9Sdrahn       if (gmon_io_write_32 (ofp, (unsigned int) val))
214*c074d1c9Sdrahn 	return 1;
215*c074d1c9Sdrahn       break;
216*c074d1c9Sdrahn 
217*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
218*c074d1c9Sdrahn     case ptr_64bit:
219*c074d1c9Sdrahn       if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) val))
220*c074d1c9Sdrahn 	return 1;
221*c074d1c9Sdrahn       break;
222*c074d1c9Sdrahn #endif
223*c074d1c9Sdrahn     }
224*c074d1c9Sdrahn   return 0;
225*c074d1c9Sdrahn }
226*c074d1c9Sdrahn 
227*c074d1c9Sdrahn int
gmon_io_write_8(ofp,val)228*c074d1c9Sdrahn gmon_io_write_8 (ofp, val)
229*c074d1c9Sdrahn      FILE *ofp;
230*c074d1c9Sdrahn      unsigned int val;
231b55d4692Sfgsch {
232b55d4692Sfgsch   char buf[1];
233b55d4692Sfgsch 
234b55d4692Sfgsch   bfd_put_8 (core_bfd, val, buf);
235b55d4692Sfgsch   if (fwrite (buf, 1, 1, ofp) != 1)
236b55d4692Sfgsch     return 1;
237b55d4692Sfgsch   return 0;
238b55d4692Sfgsch }
239b55d4692Sfgsch 
240b55d4692Sfgsch int
gmon_io_write(ofp,buf,n)241*c074d1c9Sdrahn gmon_io_write (ofp, buf, n)
242*c074d1c9Sdrahn      FILE *ofp;
243*c074d1c9Sdrahn      char *buf;
244*c074d1c9Sdrahn      size_t n;
245b55d4692Sfgsch {
246b55d4692Sfgsch   if (fwrite (buf, 1, n, ofp) != n)
247b55d4692Sfgsch     return 1;
248b55d4692Sfgsch   return 0;
249b55d4692Sfgsch }
250b55d4692Sfgsch 
251*c074d1c9Sdrahn static int
gmon_read_raw_arc(ifp,fpc,spc,cnt)252*c074d1c9Sdrahn gmon_read_raw_arc (ifp, fpc, spc, cnt)
253*c074d1c9Sdrahn      FILE *ifp;
254*c074d1c9Sdrahn      bfd_vma *fpc;
255*c074d1c9Sdrahn      bfd_vma *spc;
256*c074d1c9Sdrahn      unsigned long *cnt;
2572159047fSniklas {
258*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
259*c074d1c9Sdrahn   BFD_HOST_U_64_BIT cnt64;
260*c074d1c9Sdrahn #endif
261*c074d1c9Sdrahn   unsigned int cnt32;
262*c074d1c9Sdrahn 
263*c074d1c9Sdrahn   if (gmon_io_read_vma (ifp, fpc)
264*c074d1c9Sdrahn       || gmon_io_read_vma (ifp, spc))
265*c074d1c9Sdrahn     return 1;
266*c074d1c9Sdrahn 
267*c074d1c9Sdrahn   switch (gmon_get_ptr_size ())
2682159047fSniklas     {
269*c074d1c9Sdrahn     case ptr_32bit:
270*c074d1c9Sdrahn       if (gmon_io_read_32 (ifp, &cnt32))
271*c074d1c9Sdrahn 	return 1;
272*c074d1c9Sdrahn       *cnt = cnt32;
273*c074d1c9Sdrahn       break;
274*c074d1c9Sdrahn 
275*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
276*c074d1c9Sdrahn     case ptr_64bit:
277*c074d1c9Sdrahn       if (gmon_io_read_64 (ifp, &cnt64))
278*c074d1c9Sdrahn 	return 1;
279*c074d1c9Sdrahn       *cnt = cnt64;
280*c074d1c9Sdrahn       break;
281*c074d1c9Sdrahn #endif
2822159047fSniklas     }
283*c074d1c9Sdrahn   return 0;
2842159047fSniklas }
2852159047fSniklas 
286*c074d1c9Sdrahn static int
gmon_write_raw_arc(ofp,fpc,spc,cnt)287*c074d1c9Sdrahn gmon_write_raw_arc (ofp, fpc, spc, cnt)
288*c074d1c9Sdrahn      FILE *ofp;
289*c074d1c9Sdrahn      bfd_vma fpc;
290*c074d1c9Sdrahn      bfd_vma spc;
291*c074d1c9Sdrahn      unsigned long cnt;
2922159047fSniklas {
293*c074d1c9Sdrahn 
294*c074d1c9Sdrahn   if (gmon_io_write_vma (ofp, fpc)
295*c074d1c9Sdrahn       || gmon_io_write_vma (ofp, spc))
296*c074d1c9Sdrahn     return 1;
297*c074d1c9Sdrahn 
298*c074d1c9Sdrahn   switch (gmon_get_ptr_size ())
2992159047fSniklas     {
300*c074d1c9Sdrahn     case ptr_32bit:
301*c074d1c9Sdrahn       if (gmon_io_write_32 (ofp, (unsigned int) cnt))
302*c074d1c9Sdrahn 	return 1;
3032159047fSniklas       break;
304*c074d1c9Sdrahn 
305*c074d1c9Sdrahn #ifdef BFD_HOST_U_64_BIT
306*c074d1c9Sdrahn     case ptr_64bit:
307*c074d1c9Sdrahn       if (gmon_io_write_64 (ofp, (BFD_HOST_U_64_BIT) cnt))
308*c074d1c9Sdrahn 	return 1;
3092159047fSniklas       break;
310*c074d1c9Sdrahn #endif
3112159047fSniklas     }
312*c074d1c9Sdrahn   return 0;
3132159047fSniklas }
3142159047fSniklas 
3152159047fSniklas void
gmon_out_read(filename)316*c074d1c9Sdrahn gmon_out_read (filename)
317*c074d1c9Sdrahn      const char *filename;
3182159047fSniklas {
3192159047fSniklas   FILE *ifp;
3202159047fSniklas   struct gmon_hdr ghdr;
3212159047fSniklas   unsigned char tag;
3222159047fSniklas   int nhist = 0, narcs = 0, nbbs = 0;
3232159047fSniklas 
324b55d4692Sfgsch   /* Open gmon.out file.  */
3252159047fSniklas   if (strcmp (filename, "-") == 0)
3262159047fSniklas     {
3272159047fSniklas       ifp = stdin;
328b305b0f1Sespie #ifdef SET_BINARY
329b305b0f1Sespie       SET_BINARY (fileno (stdin));
330b305b0f1Sespie #endif
3312159047fSniklas     }
3322159047fSniklas   else
3332159047fSniklas     {
3342159047fSniklas       ifp = fopen (filename, FOPEN_RB);
335b55d4692Sfgsch 
3362159047fSniklas       if (!ifp)
3372159047fSniklas 	{
3382159047fSniklas 	  perror (filename);
3392159047fSniklas 	  done (1);
3402159047fSniklas 	}
3412159047fSniklas     }
342b55d4692Sfgsch 
3432159047fSniklas   if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1)
3442159047fSniklas     {
345b305b0f1Sespie       fprintf (stderr, _("%s: file too short to be a gmon file\n"),
3462159047fSniklas 	       filename);
3472159047fSniklas       done (1);
3482159047fSniklas     }
3492159047fSniklas 
350b55d4692Sfgsch   if ((file_format == FF_MAGIC)
351b55d4692Sfgsch       || (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)))
3522159047fSniklas     {
3532159047fSniklas       if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))
3542159047fSniklas 	{
355b305b0f1Sespie 	  fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
3562159047fSniklas 		   whoami, filename);
3572159047fSniklas 	  done (1);
3582159047fSniklas 	}
3592159047fSniklas 
360b55d4692Sfgsch       /* Right magic, so it's probably really a new gmon.out file.  */
3612159047fSniklas       gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version);
362b55d4692Sfgsch 
3632159047fSniklas       if (gmon_file_version != GMON_VERSION && gmon_file_version != 0)
3642159047fSniklas 	{
3652159047fSniklas 	  fprintf (stderr,
366b305b0f1Sespie 		   _("%s: file `%s' has unsupported version %d\n"),
3672159047fSniklas 		   whoami, filename, gmon_file_version);
3682159047fSniklas 	  done (1);
3692159047fSniklas 	}
3702159047fSniklas 
371b55d4692Sfgsch       /* Read in all the records.  */
3722159047fSniklas       while (fread (&tag, sizeof (tag), 1, ifp) == 1)
3732159047fSniklas 	{
3742159047fSniklas 	  switch (tag)
3752159047fSniklas 	    {
3762159047fSniklas 	    case GMON_TAG_TIME_HIST:
3772159047fSniklas 	      ++nhist;
3782159047fSniklas 	      gmon_input |= INPUT_HISTOGRAM;
3792159047fSniklas 	      hist_read_rec (ifp, filename);
3802159047fSniklas 	      break;
3812159047fSniklas 
3822159047fSniklas 	    case GMON_TAG_CG_ARC:
3832159047fSniklas 	      ++narcs;
3842159047fSniklas 	      gmon_input |= INPUT_CALL_GRAPH;
3852159047fSniklas 	      cg_read_rec (ifp, filename);
3862159047fSniklas 	      break;
3872159047fSniklas 
3882159047fSniklas 	    case GMON_TAG_BB_COUNT:
3892159047fSniklas 	      ++nbbs;
3902159047fSniklas 	      gmon_input |= INPUT_BB_COUNTS;
3912159047fSniklas 	      bb_read_rec (ifp, filename);
3922159047fSniklas 	      break;
3932159047fSniklas 
3942159047fSniklas 	    default:
3952159047fSniklas 	      fprintf (stderr,
396b305b0f1Sespie 		       _("%s: %s: found bad tag %d (file corrupted?)\n"),
3972159047fSniklas 		       whoami, filename, tag);
3982159047fSniklas 	      done (1);
3992159047fSniklas 	    }
4002159047fSniklas 	}
4012159047fSniklas     }
402b305b0f1Sespie   else if (file_format == FF_AUTO
403b305b0f1Sespie 	   || file_format == FF_BSD
404b305b0f1Sespie 	   || file_format == FF_BSD44)
4052159047fSniklas     {
4062159047fSniklas       struct hdr
4072159047fSniklas       {
4082159047fSniklas 	bfd_vma low_pc;
4092159047fSniklas 	bfd_vma high_pc;
4102159047fSniklas 	int ncnt;
4112159047fSniklas       };
412*c074d1c9Sdrahn       int i, samp_bytes, header_size = 0;
413b305b0f1Sespie       unsigned long count;
4142159047fSniklas       bfd_vma from_pc, self_pc;
4152159047fSniklas       static struct hdr h;
4162159047fSniklas       UNIT raw_bin_count;
4172159047fSniklas       struct hdr tmp;
418*c074d1c9Sdrahn       int version;
4192159047fSniklas 
420b55d4692Sfgsch       /* Information from a gmon.out file is in two parts: an array of
421b55d4692Sfgsch 	 sampling hits within pc ranges, and the arcs.  */
4222159047fSniklas       gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH;
4232159047fSniklas 
424b55d4692Sfgsch       /* This fseek() ought to work even on stdin as long as it's
425b55d4692Sfgsch 	 not an interactive device (heck, is there anybody who would
426b55d4692Sfgsch 	 want to type in a gmon.out at the terminal?).  */
4272159047fSniklas       if (fseek (ifp, 0, SEEK_SET) < 0)
4282159047fSniklas 	{
4292159047fSniklas 	  perror (filename);
4302159047fSniklas 	  done (1);
4312159047fSniklas 	}
432b55d4692Sfgsch 
433*c074d1c9Sdrahn       /* The beginning of the old BSD header and the 4.4BSD header
434*c074d1c9Sdrahn 	 are the same: lowpc, highpc, ncnt  */
435*c074d1c9Sdrahn       if (gmon_io_read_vma (ifp, &tmp.low_pc)
436*c074d1c9Sdrahn           || gmon_io_read_vma (ifp, &tmp.high_pc)
437*c074d1c9Sdrahn           || gmon_io_read_32 (ifp, &tmp.ncnt))
4382159047fSniklas 	{
439*c074d1c9Sdrahn  bad_gmon_file:
440b305b0f1Sespie           fprintf (stderr, _("%s: file too short to be a gmon file\n"),
4412159047fSniklas 		   filename);
4422159047fSniklas 	  done (1);
4432159047fSniklas 	}
444b55d4692Sfgsch 
445*c074d1c9Sdrahn       /* Check to see if this a 4.4BSD-style header.  */
446*c074d1c9Sdrahn       if (gmon_io_read_32 (ifp, &version))
447*c074d1c9Sdrahn 	goto bad_gmon_file;
448191aa565Sniklas 
449*c074d1c9Sdrahn       if (version == GMONVERSION)
450191aa565Sniklas 	{
451191aa565Sniklas 	  int profrate;
452191aa565Sniklas 
453b305b0f1Sespie 	  /* 4.4BSD format header.  */
454*c074d1c9Sdrahn           if (gmon_io_read_32 (ifp, &profrate))
455*c074d1c9Sdrahn 	    goto bad_gmon_file;
456b55d4692Sfgsch 
457191aa565Sniklas 	  if (!s_highpc)
458191aa565Sniklas 	    hz = profrate;
459191aa565Sniklas 	  else if (hz != profrate)
460191aa565Sniklas 	    {
461191aa565Sniklas 	      fprintf (stderr,
462b305b0f1Sespie 		       _("%s: profiling rate incompatible with first gmon file\n"),
463191aa565Sniklas 		       filename);
464191aa565Sniklas 	      done (1);
465191aa565Sniklas 	    }
466b305b0f1Sespie 
467*c074d1c9Sdrahn 	  switch (gmon_get_ptr_size ())
468*c074d1c9Sdrahn 	    {
469*c074d1c9Sdrahn 	    case ptr_32bit:
470*c074d1c9Sdrahn 	      header_size = GMON_HDRSIZE_BSD44_32;
471*c074d1c9Sdrahn 	      break;
472*c074d1c9Sdrahn 
473*c074d1c9Sdrahn 	    case ptr_64bit:
474*c074d1c9Sdrahn 	      header_size = GMON_HDRSIZE_BSD44_64;
475*c074d1c9Sdrahn 	      break;
476*c074d1c9Sdrahn 	    }
477191aa565Sniklas 	}
478b305b0f1Sespie       else
479b305b0f1Sespie 	{
480b55d4692Sfgsch 	  /* Old style BSD format.  */
481b305b0f1Sespie 	  if (file_format == FF_BSD44)
482b305b0f1Sespie 	    {
483b305b0f1Sespie 	      fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
484b305b0f1Sespie 		       whoami, filename);
485b305b0f1Sespie 	      done (1);
486b305b0f1Sespie 	    }
487b305b0f1Sespie 
488*c074d1c9Sdrahn 	  switch (gmon_get_ptr_size ())
489*c074d1c9Sdrahn 	    {
490*c074d1c9Sdrahn 	    case ptr_32bit:
491*c074d1c9Sdrahn 	      header_size = GMON_HDRSIZE_OLDBSD_32;
492*c074d1c9Sdrahn 	      break;
493*c074d1c9Sdrahn 
494*c074d1c9Sdrahn 	    case ptr_64bit:
495*c074d1c9Sdrahn 	      header_size = GMON_HDRSIZE_OLDBSD_64;
496*c074d1c9Sdrahn 	      break;
497*c074d1c9Sdrahn 	    }
498*c074d1c9Sdrahn 	}
499*c074d1c9Sdrahn 
500*c074d1c9Sdrahn       /* Position the file to after the header.  */
501*c074d1c9Sdrahn       if (fseek (ifp, header_size, SEEK_SET) < 0)
502b305b0f1Sespie 	{
503b305b0f1Sespie 	  perror (filename);
504b305b0f1Sespie 	  done (1);
505b305b0f1Sespie 	}
506b305b0f1Sespie 
507b55d4692Sfgsch       if (s_highpc && (tmp.low_pc != h.low_pc
508b55d4692Sfgsch 		       || tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt))
5092159047fSniklas 	{
510b305b0f1Sespie 	  fprintf (stderr, _("%s: incompatible with first gmon file\n"),
5112159047fSniklas 		   filename);
5122159047fSniklas 	  done (1);
5132159047fSniklas 	}
514b55d4692Sfgsch 
5152159047fSniklas       h = tmp;
5162159047fSniklas       s_lowpc = (bfd_vma) h.low_pc;
5172159047fSniklas       s_highpc = (bfd_vma) h.high_pc;
5182159047fSniklas       lowpc = (bfd_vma) h.low_pc / sizeof (UNIT);
5192159047fSniklas       highpc = (bfd_vma) h.high_pc / sizeof (UNIT);
520b305b0f1Sespie       samp_bytes = h.ncnt - header_size;
5212159047fSniklas       hist_num_bins = samp_bytes / sizeof (UNIT);
522b55d4692Sfgsch 
5232159047fSniklas       DBG (SAMPLEDEBUG,
5242159047fSniklas 	   printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
525b305b0f1Sespie 		   (unsigned long) h.low_pc, (unsigned long) h.high_pc,
526b305b0f1Sespie 		   h.ncnt);
5272159047fSniklas 	   printf ("[gmon_out_read]   s_lowpc 0x%lx   s_highpc 0x%lx\n",
528b305b0f1Sespie 		   (unsigned long) s_lowpc, (unsigned long) s_highpc);
5292159047fSniklas 	   printf ("[gmon_out_read]     lowpc 0x%lx     highpc 0x%lx\n",
530b305b0f1Sespie 		   (unsigned long) lowpc, (unsigned long) highpc);
5312159047fSniklas 	   printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
5322159047fSniklas 		   samp_bytes, hist_num_bins));
5332159047fSniklas 
534b305b0f1Sespie       /* Make sure that we have sensible values.  */
535b305b0f1Sespie       if (samp_bytes < 0 || lowpc > highpc)
536b305b0f1Sespie 	{
537b305b0f1Sespie 	  fprintf (stderr,
538b305b0f1Sespie 	    _("%s: file '%s' does not appear to be in gmon.out format\n"),
539b305b0f1Sespie 	    whoami, filename);
540b305b0f1Sespie 	  done (1);
541b305b0f1Sespie 	}
542b305b0f1Sespie 
5432159047fSniklas       if (hist_num_bins)
5442159047fSniklas 	++nhist;
5452159047fSniklas 
5462159047fSniklas       if (!hist_sample)
5472159047fSniklas 	{
5482159047fSniklas 	  hist_sample =
5492159047fSniklas 	    (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
550b55d4692Sfgsch 
5512159047fSniklas 	  memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
5522159047fSniklas 	}
5532159047fSniklas 
5542159047fSniklas       for (i = 0; i < hist_num_bins; ++i)
5552159047fSniklas 	{
5562159047fSniklas 	  if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1)
5572159047fSniklas 	    {
5582159047fSniklas 	      fprintf (stderr,
559b305b0f1Sespie 		       _("%s: unexpected EOF after reading %d/%d bins\n"),
5602159047fSniklas 		       whoami, --i, hist_num_bins);
5612159047fSniklas 	      done (1);
5622159047fSniklas 	    }
563b55d4692Sfgsch 
5642159047fSniklas 	  hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
5652159047fSniklas 	}
5662159047fSniklas 
567b55d4692Sfgsch       /* The rest of the file consists of a bunch of
568b55d4692Sfgsch 	 <from,self,count> tuples.  */
569*c074d1c9Sdrahn       while (gmon_read_raw_arc (ifp, &from_pc, &self_pc, &count) == 0)
5702159047fSniklas 	{
5712159047fSniklas 	  ++narcs;
572b55d4692Sfgsch 
5732159047fSniklas 	  DBG (SAMPLEDEBUG,
574b305b0f1Sespie 	     printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
575b305b0f1Sespie 		     (unsigned long) from_pc, (unsigned long) self_pc, count));
576b55d4692Sfgsch 
577b55d4692Sfgsch 	  /* Add this arc.  */
5782159047fSniklas 	  cg_tally (from_pc, self_pc, count);
5792159047fSniklas 	}
580b55d4692Sfgsch 
5812159047fSniklas       fclose (ifp);
5822159047fSniklas 
5832159047fSniklas       if (hz == HZ_WRONG)
5842159047fSniklas 	{
585b55d4692Sfgsch 	  /* How many ticks per second?  If we can't tell, report
586b55d4692Sfgsch 	     time in ticks.  */
5872159047fSniklas 	  hz = hertz ();
588b55d4692Sfgsch 
5892159047fSniklas 	  if (hz == HZ_WRONG)
5902159047fSniklas 	    {
5912159047fSniklas 	      hz = 1;
592b305b0f1Sespie 	      fprintf (stderr, _("time is in ticks, not seconds\n"));
5932159047fSniklas 	    }
5942159047fSniklas 	}
5952159047fSniklas     }
5962159047fSniklas   else
5972159047fSniklas     {
598b305b0f1Sespie       fprintf (stderr, _("%s: don't know how to deal with file format %d\n"),
5992159047fSniklas 	       whoami, file_format);
6002159047fSniklas       done (1);
6012159047fSniklas     }
6022159047fSniklas 
6032159047fSniklas   if (output_style & STYLE_GMON_INFO)
6042159047fSniklas     {
605b305b0f1Sespie       printf (_("File `%s' (version %d) contains:\n"),
6062159047fSniklas 	      filename, gmon_file_version);
607*c074d1c9Sdrahn       printf (nhist == 1 ?
608*c074d1c9Sdrahn 	      _("\t%d histogram record\n") :
609*c074d1c9Sdrahn 	      _("\t%d histogram records\n"), nhist);
610*c074d1c9Sdrahn       printf (narcs == 1 ?
611*c074d1c9Sdrahn 	      _("\t%d call-graph record\n") :
612*c074d1c9Sdrahn 	      _("\t%d call-graph records\n"), narcs);
613*c074d1c9Sdrahn       printf (nbbs == 1 ?
614*c074d1c9Sdrahn 	      _("\t%d basic-block count record\n") :
615*c074d1c9Sdrahn 	      _("\t%d basic-block count records\n"), nbbs);
6162159047fSniklas       first_output = FALSE;
6172159047fSniklas     }
6182159047fSniklas }
6192159047fSniklas 
6202159047fSniklas 
6212159047fSniklas void
gmon_out_write(filename)622*c074d1c9Sdrahn gmon_out_write (filename)
623*c074d1c9Sdrahn      const char *filename;
6242159047fSniklas {
6252159047fSniklas   FILE *ofp;
6262159047fSniklas   struct gmon_hdr ghdr;
6272159047fSniklas 
6282159047fSniklas   ofp = fopen (filename, FOPEN_WB);
6292159047fSniklas   if (!ofp)
6302159047fSniklas     {
6312159047fSniklas       perror (filename);
6322159047fSniklas       done (1);
6332159047fSniklas     }
6342159047fSniklas 
6352159047fSniklas   if (file_format == FF_AUTO || file_format == FF_MAGIC)
6362159047fSniklas     {
637b55d4692Sfgsch       /* Write gmon header.  */
6382159047fSniklas 
6392159047fSniklas       memcpy (&ghdr.cookie[0], GMON_MAGIC, 4);
640*c074d1c9Sdrahn       bfd_put_32 (core_bfd, (bfd_vma) GMON_VERSION, (bfd_byte *) ghdr.version);
641b55d4692Sfgsch 
6422159047fSniklas       if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1)
6432159047fSniklas 	{
6442159047fSniklas 	  perror (filename);
6452159047fSniklas 	  done (1);
6462159047fSniklas 	}
6472159047fSniklas 
648b55d4692Sfgsch       /* Write execution time histogram if we have one.  */
6492159047fSniklas       if (gmon_input & INPUT_HISTOGRAM)
6502159047fSniklas 	hist_write_hist (ofp, filename);
6512159047fSniklas 
652b55d4692Sfgsch       /* Write call graph arcs if we have any.  */
6532159047fSniklas       if (gmon_input & INPUT_CALL_GRAPH)
6542159047fSniklas 	cg_write_arcs (ofp, filename);
6552159047fSniklas 
656b55d4692Sfgsch       /* Write basic-block info if we have it.  */
6572159047fSniklas       if (gmon_input & INPUT_BB_COUNTS)
6582159047fSniklas 	bb_write_blocks (ofp, filename);
6592159047fSniklas     }
660b305b0f1Sespie   else if (file_format == FF_BSD || file_format == FF_BSD44)
6612159047fSniklas     {
6622159047fSniklas       UNIT raw_bin_count;
663*c074d1c9Sdrahn       int i, hdrsize;
664*c074d1c9Sdrahn       unsigned padsize;
665*c074d1c9Sdrahn       char pad[3*4];
6662159047fSniklas       Arc *arc;
6672159047fSniklas       Sym *sym;
6682159047fSniklas 
669*c074d1c9Sdrahn       memset (pad, 0, sizeof (pad));
6702159047fSniklas 
671*c074d1c9Sdrahn       hdrsize = 0;
672*c074d1c9Sdrahn       /* Decide how large the header will be.  Use the 4.4BSD format
673*c074d1c9Sdrahn          header if explicitly specified, or if the profiling rate is
674*c074d1c9Sdrahn          non-standard.  Otherwise, use the old BSD format.  */
675b305b0f1Sespie       if (file_format == FF_BSD44
676b305b0f1Sespie 	  || hz != hertz())
677b305b0f1Sespie 	{
678*c074d1c9Sdrahn 	  padsize = 3*4;
679*c074d1c9Sdrahn 	  switch (gmon_get_ptr_size ())
6802159047fSniklas 	    {
681*c074d1c9Sdrahn 	    case ptr_32bit:
682*c074d1c9Sdrahn 	      hdrsize = GMON_HDRSIZE_BSD44_32;
683*c074d1c9Sdrahn 	      break;
684*c074d1c9Sdrahn 
685*c074d1c9Sdrahn 	    case ptr_64bit:
686*c074d1c9Sdrahn 	      hdrsize = GMON_HDRSIZE_BSD44_64;
687*c074d1c9Sdrahn 	      break;
6882159047fSniklas 	    }
689b305b0f1Sespie 	}
690b305b0f1Sespie       else
691b305b0f1Sespie 	{
692*c074d1c9Sdrahn 	  padsize = 0;
693*c074d1c9Sdrahn 	  switch (gmon_get_ptr_size ())
694*c074d1c9Sdrahn 	    {
695*c074d1c9Sdrahn 	    case ptr_32bit:
696*c074d1c9Sdrahn 	      hdrsize = GMON_HDRSIZE_OLDBSD_32;
697*c074d1c9Sdrahn 	      break;
698*c074d1c9Sdrahn 
699*c074d1c9Sdrahn 	    case ptr_64bit:
700*c074d1c9Sdrahn 	      hdrsize = GMON_HDRSIZE_OLDBSD_64;
701*c074d1c9Sdrahn 	      /* FIXME: Checking host compiler defines here means that we can't
702*c074d1c9Sdrahn 		 use a cross gprof alpha OSF.  */
703*c074d1c9Sdrahn #if defined(__alpha__) && defined (__osf__)
704*c074d1c9Sdrahn 	      padsize = 4;
705*c074d1c9Sdrahn #endif
706*c074d1c9Sdrahn 	      break;
707*c074d1c9Sdrahn 	    }
708*c074d1c9Sdrahn 	}
709*c074d1c9Sdrahn 
710*c074d1c9Sdrahn       /* Write the parts of the headers that are common to both the
711*c074d1c9Sdrahn 	 old BSD and 4.4BSD formats.  */
712*c074d1c9Sdrahn       if (gmon_io_write_vma (ofp, s_lowpc)
713*c074d1c9Sdrahn           || gmon_io_write_vma (ofp, s_highpc)
714*c074d1c9Sdrahn           || gmon_io_write_32 (ofp, hist_num_bins * sizeof (UNIT) + hdrsize))
715b305b0f1Sespie 	{
716b305b0f1Sespie 	  perror (filename);
717b305b0f1Sespie 	  done (1);
718b305b0f1Sespie 	}
719*c074d1c9Sdrahn 
720*c074d1c9Sdrahn       /* Write out the 4.4BSD header bits, if that's what we're using.  */
721*c074d1c9Sdrahn       if (file_format == FF_BSD44
722*c074d1c9Sdrahn 	  || hz != hertz())
723*c074d1c9Sdrahn 	{
724*c074d1c9Sdrahn           if (gmon_io_write_32 (ofp, GMONVERSION)
725*c074d1c9Sdrahn 	      || gmon_io_write_32 (ofp, (unsigned int) hz))
726*c074d1c9Sdrahn 	    {
727*c074d1c9Sdrahn 	      perror (filename);
728*c074d1c9Sdrahn 	      done (1);
729*c074d1c9Sdrahn 	    }
730*c074d1c9Sdrahn 	}
731*c074d1c9Sdrahn 
732*c074d1c9Sdrahn       /* Now write out any necessary padding after the meaningful
733*c074d1c9Sdrahn 	 header bits.  */
734*c074d1c9Sdrahn       if (padsize != 0
735*c074d1c9Sdrahn           && fwrite (pad, 1, padsize, ofp) != padsize)
736*c074d1c9Sdrahn         {
737*c074d1c9Sdrahn           perror (filename);
738*c074d1c9Sdrahn 	  done (1);
739b305b0f1Sespie 	}
7402159047fSniklas 
741b55d4692Sfgsch       /* Dump the samples.  */
7422159047fSniklas       for (i = 0; i < hist_num_bins; ++i)
7432159047fSniklas 	{
744*c074d1c9Sdrahn 	  bfd_put_16 (core_bfd, (bfd_vma) hist_sample[i],
745*c074d1c9Sdrahn 		      (bfd_byte *) &raw_bin_count[0]);
7462159047fSniklas 	  if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1)
7472159047fSniklas 	    {
7482159047fSniklas 	      perror (filename);
7492159047fSniklas 	      done (1);
7502159047fSniklas 	    }
7512159047fSniklas 	}
7522159047fSniklas 
753b55d4692Sfgsch       /* Dump the normalized raw arc information.  */
7542159047fSniklas       for (sym = symtab.base; sym < symtab.limit; ++sym)
7552159047fSniklas 	{
7562159047fSniklas 	  for (arc = sym->cg.children; arc; arc = arc->next_child)
7572159047fSniklas 	    {
758*c074d1c9Sdrahn 	      if (gmon_write_raw_arc (ofp, arc->parent->addr,
759*c074d1c9Sdrahn 				      arc->child->addr, arc->count))
7602159047fSniklas 		{
7612159047fSniklas 		  perror (filename);
7622159047fSniklas 		  done (1);
7632159047fSniklas 		}
7642159047fSniklas 	      DBG (SAMPLEDEBUG,
765b305b0f1Sespie 		   printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %lu\n",
766b305b0f1Sespie 			   (unsigned long) arc->parent->addr,
767b305b0f1Sespie 			   (unsigned long) arc->child->addr, arc->count));
7682159047fSniklas 	    }
7692159047fSniklas 	}
770b55d4692Sfgsch 
7712159047fSniklas       fclose (ofp);
7722159047fSniklas     }
7732159047fSniklas   else
7742159047fSniklas     {
775b305b0f1Sespie       fprintf (stderr, _("%s: don't know how to deal with file format %d\n"),
7762159047fSniklas 	       whoami, file_format);
7772159047fSniklas       done (1);
7782159047fSniklas     }
7792159047fSniklas }
780