source: trunk/src/binutils/gprof/gmon_io.c@ 202

Last change on this file since 202 was 10, checked in by bird, 23 years ago

Initial revision

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