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