OSDN Git Service

3bd2729d9d2e9618fe4a6c39e402cd2dbc58928c
[pf3gnuchains/gcc-fork.git] / gcc / gcov-io.h
1 /* File format for coverage information
2    Copyright (C) 1996, 1997, 1998, 2000, 2002 Free Software Foundation, Inc.
3    Contributed by Bob Manson <manson@cygnus.com>.
4    Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, USA.  */
22
23 /* Coverage information is held in two files.  A basic block graph
24    file, which is generated by the compiler, and a counter file, which
25    is generated by the program under test.  Both files use a similar
26    structure.  We do not attempt to make these files backwards
27    compatible with previous versions, as you only need coverage
28    information when developing a program.  We do hold version
29    information, so that mismatches can be detected, and we use a
30    format that allows tools to skip information they do not understand
31    or are not interested in.
32
33    Numbers are recorded in big endian unsigned binary form.  Either in
34    32 or 64 bits.  Strings are stored with a length count and NUL
35    terminator, and 0 to 3 bytes of zero padding up to the next 4 byte
36    boundary.  Zero length and NULL strings are simply stored as a
37    length of zero (they have no trailing NUL or padding).
38
39         int32:  byte3 byte2 byte1 byte0
40         int64:  byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0
41         string: int32:0 | int32:length char* char:0 padding
42         padding: | char:0 | char:0 char:0 | char:0 char:0 char:0
43         item: int32 | int64 | string
44
45    The basic format of the files is
46
47         file : int32:magic int32:version record*
48
49    The magic ident is different for the bbg and the counter files.
50    The version is the same for both files and is derived from gcc's
51    version number.  Although the ident and version are formally 32 bit
52    numbers, they are derived from 4 character ASCII strings.  The
53    version number consists of the single character major version
54    number, a two character minor version number (leading zero for
55    versions less than 10), and a single character indicating the
56    status of the release.  That will be 'e' experimental, 'p'
57    prerelease and 'r' for release.  Because, by good fortune, these are
58    in alphabetical order, string collating can be used to compare
59    version strings, and because numbers are stored big endian, numeric
60    comparison can be used when it is read as a 32 bit value.  Be aware
61    that the 'e' designation will (naturally) be unstable and might be
62    incompatible with itself.  For gcc 3.4 experimental, it would be
63    '304e' (0x33303465).  When the major version reaches 10, the letters
64    A-Z will be used.  Assuming minor increments releases every 6
65    months, we have to make a major increment every 50 years.  Assuming
66    major increments releases every 5 years, we're ok for the next 155
67    years -- good enough for me.
68
69    A record has a tag, length and variable amount of data.
70
71         record: header data
72         header: int32:tag int32:length
73         data: item*
74
75    Records are not nested, but there is a record hierarchy.  Tag
76    numbers reflect this hierarchy.  Tags are unique across bbg and da
77    files.  Some record types have a varying amount of data.  The LENGTH
78    is usually used to determine how much data.  The tag value is split
79    into 4 8-bit fields, one for each of four possible levels.  The
80    most significant is allocated first.  Unused levels are zero.
81    Active levels are odd-valued, so that the LSB of the level is one.
82    A sub-level incorporates the values of its superlevels.  This
83    formatting allows you to determine the tag heirarchy, without
84    understanding the tags themselves, and is similar to the standard
85    section numbering used in technical documents.  Level values
86    [1..3f] are used for common tags, values [41..9f] for the graph
87    file and [a1..ff] for the counter file.
88
89    The basic block graph file contains the following records
90         bbg:  function-graph*
91         function-graph: announce_function basic_blocks {arcs | lines}*
92         announce_function: header string:name int32:checksum
93                 string:source int32:lineno
94         basic_block: header int32:flags*
95         arcs: header int32:block_no arc*
96         arc:  int32:dest_block int32:flags
97         lines: header int32:block_no line*
98                int32:0 string:NULL
99         line:  int32:line_no | int32:0 string:filename
100
101    The BASIC_BLOCK record holds per-bb flags.  The number of blocks
102    can be inferred from its data length.  There is one ARCS record per
103    basic block.  The number of arcs from a bb is implicit from the
104    data length.  It enumerates the destination bb and per-arc flags.
105    There is one LINES record per basic block, it enumerates the source
106    lines which belong to that basic block.  Source file names are
107    introduced by a line number of 0, following lines are from the new
108    source file.  The initial source file for the function is NULL, but
109    the current source file should be remembered from one LINES record
110    to the next.  The end of a block is indicated by an empty filename
111    - this does not reset the current source file.  Note there is no
112    ordering of the ARCS and LINES records: they may be in any order,
113    interleaved in any manner.  The current filename follows the order
114    the LINES records are stored in the file, *not* the ordering of the
115    blocks they are for.
116
117    The data file contains the following records.
118         da:   {function-data* summary:object summary:program*}*
119         function-data:  announce_function arc_counts
120         announce_function: header string:name int32:checksum
121         arc_counts: header int64:count*
122         summary: in32:checksum int32:runs int32:arcs int64:sum int64:max \
123                 int64:max_sum int64:sum_max
124
125    The ANNOUNCE_FUNCTION record is the same as that in the BBG file,
126    but without the source location.
127    The ARC_COUNTS gives the counter values for those arcs that are
128    instrumented.  The SUMMARY records give information about the whole
129    object file and about the whole program.  The checksum is used for
130    whole program summaries, and disambiguates different programs which
131    include the same instrumented object file.  There may be several
132    program summaries, each with a unique checksum.  The object
133    summary's checkum is zero.  Note that the da file might contain
134    information from several runs concatenated, or the data might be
135    merged.
136
137    This file is included by both the compiler, gcov tools and the
138    runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
139    distinguish which case is which.  If IN_LIBGCOV is non-zero,
140    libgcov is being built. If IN_GCOV is non-zero, the gcov tools are
141    being built. Otherwise the compiler is being built. IN_GCOV may be
142    positive or negative. If positive, we are compiling a tool that
143    requires additional functions (see the code for knowledge of what
144    those functions are).  */
145
146 #ifndef GCC_GCOV_IO_H
147 #define GCC_GCOV_IO_H
148
149 #if IN_LIBGCOV
150 #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
151 typedef long gcov_type;
152 #else
153 typedef long long gcov_type;
154 #endif
155 #endif /* IN_LIBGCOV */
156 #if IN_GCOV
157 typedef HOST_WIDEST_INT gcov_type;
158 #if IN_GCOV > 0
159 #include <sys/types.h>
160 #endif
161 #endif
162
163 /* File suffixes.  */
164 #define GCOV_DATA_SUFFIX ".da"
165 #define GCOV_GRAPH_SUFFIX ".bbg"
166
167 /* File magic.  */
168 #define GCOV_DATA_MAGIC  0x67636f76 /* "gcov" */
169 #define GCOV_GRAPH_MAGIC 0x67626267 /* "gbbg" */
170
171 /* gcov-iov.h is automatically generated by the makefile from
172    version.c, it looks like
173         #define GCOV_VERSION ((unsigned)0x89abcdef)
174 */
175 #include "gcov-iov.h"
176
177 /* The record tags.  Values [1..3f] are for tags which may be in either
178    file.  Values [41..9f] for those in the bbg file and [a1..ff] for
179    the data file.  */
180
181 #define GCOV_TAG_FUNCTION        ((unsigned)0x01000000)
182 #define GCOV_TAG_BLOCKS          ((unsigned)0x01410000)
183 #define GCOV_TAG_ARCS            ((unsigned)0x01430000)
184 #define GCOV_TAG_LINES           ((unsigned)0x01450000)
185 #define GCOV_TAG_ARC_COUNTS      ((unsigned)0x01a10000)
186 #define GCOV_TAG_OBJECT_SUMMARY  ((unsigned)0xa1000000)
187 #define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000)
188 #define GCOV_TAG_PLACEHOLDER_SUMMARY ((unsigned)0xa5000000)
189 #define GCOV_TAG_INCORRECT_SUMMARY ((unsigned)0xa7000000)
190
191 /* The tag level mask has 1's in the position of the inner levels, &
192    the lsb of the current level, and zero on the current and outer
193    levels.  */
194 #define GCOV_TAG_MASK(TAG) (((TAG) - 1) ^ (TAG))
195
196 /* Return nonzero if SUB is an immediate subtag of TAG.  */
197 #define GCOV_TAG_IS_SUBTAG(TAG,SUB)                             \
198         (GCOV_TAG_MASK (TAG) >> 8 == GCOV_TAG_MASK (SUB)        \
199          && !(((SUB) ^ (TAG)) & ~GCOV_TAG_MASK(TAG)))
200
201 /* Return nonzero if SUB is at a sublevel to TAG.  */
202 #define GCOV_TAG_IS_SUBLEVEL(TAG,SUB)                           \
203         (GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB))
204
205 /* Basic block flags.  */
206 #define GCOV_BLOCK_UNEXPECTED   (1 << 1)
207
208 /* Arc flags.  */
209 #define GCOV_ARC_ON_TREE        (1 << 0)
210 #define GCOV_ARC_FAKE           (1 << 1)
211 #define GCOV_ARC_FALLTHROUGH    (1 << 2)
212
213 /* Structured records.  */
214
215 /* Object & program summary record.  */
216 struct gcov_summary
217 {
218   unsigned checksum;      /* checksum of program */
219   unsigned runs;          /* number of program runs */
220   unsigned arcs;          /* number of instrumented arcs */
221   gcov_type arc_sum;      /* sum of all arc counters */
222   gcov_type arc_max_one;  /* max counter on any one run */
223   gcov_type arc_max_sum;  /* maximum arc_sum */
224   gcov_type arc_sum_max;  /* sum of max_one */
225 };
226
227 /* Structures embedded in coveraged program.  The structures generated
228    by write_profile must match these.  */
229
230 /* Information about section of counters for a function.  */
231 struct counter_section
232 {
233   unsigned tag;         /* Tag of the section.  */
234   unsigned n_counters;  /* Number of counters in the section.  */
235 };
236
237 #if IN_LIBGCOV
238 /* Information about section of counters for an object file.  */
239 struct counter_section_data
240 {
241   unsigned tag;         /* Tag of the section.  */
242   unsigned n_counters;  /* Number of counters in the section.  */
243   gcov_type *counters;  /* The data.  */
244 };
245
246 /* Information about a single function.  */
247 struct function_info
248 {
249   const char *name;             /* (mangled) name of function */
250   unsigned checksum;            /* function checksum */
251   unsigned n_counter_sections;  /* Number of types of counters */
252   const struct counter_section *counter_sections;
253                                 /* The section descriptions */
254 };
255
256 /* Information about a single object file.  */
257 struct gcov_info
258 {
259   unsigned long version;        /* expected version number */
260   struct gcov_info *next;       /* link to next, used by libgcc */
261
262   const char *filename;         /* output file name */
263   long wkspc;                   /* libgcc workspace */
264
265   unsigned n_functions;             /* number of functions */
266   const struct function_info *functions; /* table of functions */
267
268   unsigned n_counter_sections;  /* Number of types of counters */
269   const struct counter_section_data *counter_sections;
270                                 /* The data to be put into the sections.  */
271 };
272
273 /* Register a new object file module.  */
274 extern void __gcov_init (struct gcov_info *);
275
276 /* Called before fork, to avoid double counting.  */
277 extern void __gcov_flush (void);
278
279 /* Since this file is used in both host and target files, and we don't
280    include ansidecl.h in target files, provide some necessary macros.  */
281 #ifndef ATTRIBUTE_UNUSED
282 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
283 #endif
284
285 #endif /* IN_LIBGCOV */
286
287 /* Because small reads and writes, interspersed with seeks cause lots
288    of disk activity, we buffer the entire count files.  */
289
290 static struct gcov_var
291 {
292   FILE *file;
293   size_t position;
294   size_t length;
295   size_t alloc;
296   unsigned modified;
297   int error;
298   unsigned char *buffer;
299 } gcov_var;
300
301 /* Functions for reading and writing gcov files.  */
302 static int gcov_open (const char */*name*/, int /*truncate*/);
303 static int gcov_close (void);
304 #if !IN_GCOV
305 static unsigned char *gcov_write_bytes (unsigned);
306 static void gcov_write_unsigned (unsigned);
307 #if IN_LIBGCOV
308 static void gcov_write_counter (gcov_type);
309 #endif
310 static void gcov_write_string (const char *);
311 static unsigned long gcov_write_tag (unsigned);
312 static void gcov_write_length (unsigned long /*position*/);
313 #if IN_LIBGCOV
314 static void gcov_write_summary (unsigned, const struct gcov_summary *);
315 #endif
316 #endif /* !IN_GCOV */
317 static const unsigned char *gcov_read_bytes (unsigned);
318 static unsigned gcov_read_unsigned (void);
319 static gcov_type gcov_read_counter (void);
320 static const char *gcov_read_string (void);
321 static void gcov_read_summary (struct gcov_summary *);
322
323 static unsigned long gcov_position (void);
324 static void gcov_seek (unsigned long /*base*/, unsigned /*length */);
325 static unsigned long gcov_seek_end (void);
326 static int gcov_is_eof (void);
327 static int gcov_is_error (void);
328 #if IN_GCOV > 0
329 static time_t gcov_time (void);
330 #endif
331
332 /* Open a gcov file. NAME is the name of the file to open and MODE
333    indicates whether a new file should be created, or an existing file
334    opened for modification. If MODE is >= 0 an existing file will be
335    opened, if possible, and if MODE is <= 0, a new file will be
336    created. Use MODE=0 to attempt to reopen an existing file and then
337    fall back on creating a new one.  Return zero on failure, >0 on
338    opening an existing file and <0 on creating a new one.  */
339
340 static int
341 gcov_open (const char *name, int mode)
342 {
343   int result = 1;
344   size_t alloc = 1024;
345 #if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
346   struct flock s_flock;
347
348   s_flock.l_type = F_WRLCK;
349   s_flock.l_whence = SEEK_SET;
350   s_flock.l_start = 0;
351   s_flock.l_len = 0; /* Until EOF.  */
352   s_flock.l_pid = getpid ();
353 #endif
354   
355   if (gcov_var.file)
356     abort ();
357   gcov_var.position = gcov_var.length = 0;
358   gcov_var.error = gcov_var.modified = 0;
359   if (mode >= 0)
360     gcov_var.file = fopen (name, "r+b");
361   if (!gcov_var.file && mode <= 0)
362     {
363       result = -1;
364       gcov_var.file = fopen (name, "w+b");
365     }
366   if (!gcov_var.file)
367     return 0;
368
369 #if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
370   while (fcntl (fileno (gcov_var.file), F_SETLKW, &s_flock)
371          && errno == EINTR)
372     continue;
373 #endif
374
375   if (result >= 0)
376     {
377       if (fseek (gcov_var.file, 0, SEEK_END))
378         {
379           fclose (gcov_var.file);
380           gcov_var.file = 0;
381           return 0;
382         }
383       gcov_var.length = ftell (gcov_var.file);
384       fseek (gcov_var.file, 0, SEEK_SET);
385       alloc += gcov_var.length;
386     }
387   if (alloc > gcov_var.alloc)
388     {
389       if (gcov_var.buffer)
390         free (gcov_var.buffer);
391       gcov_var.alloc = alloc;
392 #if IN_LIBGCOV
393       gcov_var.buffer = malloc (gcov_var.alloc);
394       if (!gcov_var.buffer)
395         {
396           fclose (gcov_var.file);
397           gcov_var.file = 0;
398           gcov_var.length = 0;
399           gcov_var.alloc = 0;
400           return 0;
401         }
402 #else
403       gcov_var.buffer = xmalloc (gcov_var.alloc);
404 #endif
405     }
406   if (result >= 0
407       && fread (gcov_var.buffer, gcov_var.length, 1, gcov_var.file) != 1)
408     {
409       fclose (gcov_var.file);
410       gcov_var.file = 0;
411       gcov_var.length = 0;
412       return 0;
413     }
414   return result;
415 }
416
417 /* Close the current gcov file. Flushes data to disk. Returns nonzero
418    on failure or error flag set.  */
419
420 static int
421 gcov_close ()
422 {
423   int result = 0;
424   
425   if (gcov_var.file)
426     {
427       if (gcov_var.modified
428           && (fseek (gcov_var.file, 0, SEEK_SET)
429               || fwrite (gcov_var.buffer, gcov_var.length,
430                          1, gcov_var.file) != 1))
431         result = 1;
432       fclose (gcov_var.file);
433       gcov_var.file = 0;
434       gcov_var.length = 0;
435     }
436 #if !IN_LIBGCOV
437   free (gcov_var.buffer);
438   gcov_var.alloc = 0;
439   gcov_var.buffer = 0;
440 #endif
441   return result ? 1 : gcov_var.error;
442 }
443
444 #if !IN_GCOV
445 /* Allocate space to write BYTES bytes to the gcov file. Return a
446    pointer to those bytes, or NULL on failure.  */
447
448 static unsigned char *
449 gcov_write_bytes (unsigned bytes)
450 {
451   char unsigned *result;
452
453   if (gcov_var.position + bytes > gcov_var.alloc)
454     {
455       size_t new_size = (gcov_var.alloc + bytes) * 3 / 2;
456
457       if (!gcov_var.buffer)
458         return 0;
459 #if IN_LIBGCOV
460       result = realloc (gcov_var.buffer, new_size);
461       if (!result)
462         {
463           free (gcov_var.buffer);
464           gcov_var.buffer = 0;
465           gcov_var.alloc = 0;
466           gcov_var.position = gcov_var.length = 0;
467           gcov_var.error = 1;
468           return 0;
469         }
470 #else
471       result = xrealloc (gcov_var.buffer, new_size);
472 #endif
473       gcov_var.alloc = new_size;
474       gcov_var.buffer = result;
475     }
476   
477   result = &gcov_var.buffer[gcov_var.position];
478   gcov_var.position += bytes;
479   gcov_var.modified = 1;
480   if (gcov_var.position > gcov_var.length)
481     gcov_var.length = gcov_var.position;
482   return result;
483 }
484
485 /* Write unsigned VALUE to coverage file.  Sets error flag
486    appropriately.  */
487
488 static void
489 gcov_write_unsigned (unsigned value)
490 {
491   unsigned char *buffer = gcov_write_bytes (4);
492   unsigned ix;
493
494   if (!buffer)
495     return;
496   for (ix = 4; ix--; )
497     {
498       buffer[ix] = value;
499       value >>= 8;
500     }
501   if (sizeof (value) > 4 && value)
502     gcov_var.error = -1;
503
504   return;
505 }
506
507 /* Write counter VALUE to coverage file.  Sets error flag
508    appropriately.  */
509
510 #if IN_LIBGCOV
511 static void
512 gcov_write_counter (gcov_type value)
513 {
514   unsigned char *buffer = gcov_write_bytes (8);
515   unsigned ix;
516
517   if (!buffer)
518     return;
519   for (ix = 8; ix--; )
520     {
521       buffer[ix] = value;
522       value >>= 8;
523     }
524   if ((sizeof (value) > 8 && value) || value < 0)
525     gcov_var.error = -1;
526   return;
527 }
528 #endif /* IN_LIBGCOV */
529
530 /* Write STRING to coverage file.  Sets error flag on file
531    error, overflow flag on overflow */
532
533 static void
534 gcov_write_string (const char *string)
535 {
536   unsigned length = 0;
537   unsigned pad = 0;
538   unsigned rem = 0;
539   unsigned char *buffer;
540
541   if (string)
542     {
543       length = strlen (string);
544       rem = 4 - (length & 3);
545     }
546   
547   buffer = gcov_write_bytes (4 + length + rem);
548   if (buffer)
549     {
550       unsigned ix;
551       unsigned value = length;
552       
553       for (ix = 4; ix--; )
554         {
555           buffer[ix] = value;
556           value >>= 8;
557         }
558       memcpy (buffer + 4, string, length);
559       memcpy (buffer + 4 + length, &pad, rem);
560     }
561 }
562
563 /* Write a tag TAG and reserve space for the record length. Return a
564    value to be used for gcov_write_length.  */
565
566 static unsigned long
567 gcov_write_tag (unsigned tag)
568 {
569   unsigned long result = gcov_var.position;
570   unsigned char *buffer = gcov_write_bytes (8);
571   unsigned ix;
572
573   if (!buffer)
574     return 0;
575   for (ix = 4; ix--; )
576     {
577       buffer[ix] = tag;
578       tag >>= 8;
579     }
580   memset (buffer + 4, 0, 4);
581   return result;
582 }
583
584 /* Write a record length using POSITION, which was returned by
585    gcov_write_tag.  The current file position is the end of the
586    record, and is restored before returning.  Returns nonzero on
587    overflow.  */
588
589 static void
590 gcov_write_length (unsigned long position)
591 {
592   if (position)
593     {
594       unsigned length = gcov_var.position - position - 8;
595       unsigned char *buffer = &gcov_var.buffer[position + 4];
596       unsigned ix;
597       
598       for (ix = 4; ix--; )
599         {
600           buffer[ix] = length;
601           length >>= 8;
602         }
603     }
604 }
605
606 #if IN_LIBGCOV
607 /* Write a summary structure to the gcov file.  Return non-zero on
608    overflow.  */
609
610 static void
611 gcov_write_summary (unsigned tag, const struct gcov_summary *summary)
612 {
613   unsigned long base;
614
615   base = gcov_write_tag (tag);
616   gcov_write_unsigned (summary->checksum);
617   gcov_write_unsigned (summary->runs);
618   gcov_write_unsigned (summary->arcs);
619   gcov_write_counter (summary->arc_sum);
620   gcov_write_counter (summary->arc_max_one);
621   gcov_write_counter (summary->arc_max_sum);
622   gcov_write_counter (summary->arc_sum_max);
623   gcov_write_length (base);
624 }
625 #endif /* IN_LIBGCOV */
626
627 #endif /*!IN_GCOV */
628
629 /* Return a pointer to read BYTES bytes from the gcov file. Returns
630    NULL on failure (read past EOF). */
631
632 static const unsigned char *
633 gcov_read_bytes (unsigned bytes)
634 {
635   const unsigned char *result;
636   
637   if (gcov_var.position + bytes > gcov_var.length)
638     {
639       gcov_var.error = 1;
640       return 0;
641     }
642   
643   result = &gcov_var.buffer[gcov_var.position];
644   gcov_var.position += bytes;
645   return result;
646 }
647
648 /* Read unsigned value from a coverage file. Sets error flag on file
649    error, overflow flag on overflow */
650
651 static unsigned
652 gcov_read_unsigned ()
653 {
654   unsigned value = 0;
655   unsigned ix;
656   const unsigned char *buffer = gcov_read_bytes (4);
657
658   if (!buffer)
659     return 0;
660   for (ix = sizeof (value); ix < 4; ix++)
661     if (buffer[ix])
662       gcov_var.error = -1;
663   for (ix = 0; ix != 4; ix++)
664     {
665       value <<= 8;
666       value |= buffer[ix];
667     }
668   return value;
669 }
670
671 /* Read counter value from a coverage file. Sets error flag on file
672    error, overflow flag on overflow */
673
674 static gcov_type
675 gcov_read_counter ()
676 {
677   gcov_type value = 0;
678   unsigned ix;
679   const unsigned char *buffer = gcov_read_bytes (8);
680
681   if (!buffer)
682     return 0;
683   for (ix = sizeof (value); ix < 8; ix++)
684     if (buffer[ix])
685       gcov_var.error = -1;
686   for (ix = 0; ix != 8; ix++)
687     {
688       value <<= 8;
689       value |= buffer[ix];
690     }
691   if (value < 0)
692     gcov_var.error = -1;
693   return value;
694 }
695
696 /* Read string from coverage file. Returns a pointer to a static
697    buffer, or NULL on empty string. You must copy the string before
698    calling another gcov function.  */
699
700 static const char *
701 gcov_read_string ()
702 {
703   unsigned length = gcov_read_unsigned ();
704   
705   if (!length)
706     return 0;
707
708   length += 4 - (length & 3);
709   return (const char *) gcov_read_bytes (length);
710 }
711
712 #define GCOV_SUMMARY_LENGTH 44
713 static void
714 gcov_read_summary (struct gcov_summary *summary)
715 {
716   summary->checksum = gcov_read_unsigned ();
717   summary->runs = gcov_read_unsigned ();
718   summary->arcs = gcov_read_unsigned ();
719   summary->arc_sum = gcov_read_counter ();
720   summary->arc_max_one = gcov_read_counter ();
721   summary->arc_max_sum =  gcov_read_counter ();
722   summary->arc_sum_max = gcov_read_counter ();
723 }
724
725 /* Save the current position in the gcov file.  */
726
727 static inline unsigned long
728 gcov_position (void)
729 {
730   return gcov_var.position;
731 }
732
733 /* Reset to a known position.  BASE should have been obtained from
734    gcov_save_position, LENGTH should be a record length, or zero.  */
735
736 static inline void
737 gcov_seek (unsigned long base, unsigned length)
738 {
739   if (gcov_var.buffer)
740     {
741       base += length;
742       if (gcov_var.length < base)
743         {
744           gcov_var.error = 1;
745           base = gcov_var.length;
746         }
747       gcov_var.position = base;
748     }
749 }
750
751 /* Move to the end of the gcov file.  */
752
753 static inline unsigned long
754 gcov_seek_end ()
755 {
756   gcov_var.position = gcov_var.length;
757   return gcov_var.position;
758 }
759
760 /* Tests whether we have reached end of .da file.  */
761
762 static inline int
763 gcov_is_eof ()
764 {
765   return gcov_var.position == gcov_var.length;
766 }
767
768 /* Return non-zero if the error flag is set.  */
769
770 static inline int
771 gcov_is_error ()
772 {
773   return gcov_var.file ? gcov_var.error : 1;
774 }
775
776 #if IN_GCOV > 0
777 /* Return the modification time of the current gcov file.  */
778
779 static time_t
780 gcov_time ()
781 {
782   struct stat status;
783   
784   if (fstat (fileno (gcov_var.file), &status))
785     return 0;
786   else
787     return status.st_mtime;
788 }
789 #endif /* IN_GCOV */
790 #endif /* GCC_GCOV_IO_H */