source: branches/libc-0.6/src/binutils/gprof/gmon_io.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

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