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