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