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