OSDN Git Service

* gcov-io.h (gcov_save_position): Remove __inline__ from
[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 FILE *gcov_file;
291 static size_t gcov_position;
292 static size_t gcov_length;
293 static unsigned char *gcov_buffer;
294 static size_t gcov_alloc;
295 static int gcov_modified;
296 static int gcov_errored = 1;
297
298 /* Functions for reading and writing gcov files.  */
299 static int gcov_open (const char */*name*/, int /*truncate*/);
300 static int gcov_close (void);
301 #if !IN_GCOV
302 static unsigned char *gcov_write_bytes (unsigned);
303 static int gcov_write_unsigned (unsigned);
304 #if IN_LIBGCOV
305 static int gcov_write_counter (gcov_type);
306 #endif
307 static int gcov_write_string (const char *);
308 static unsigned long gcov_reserve_length (void);
309 static int gcov_write_length (unsigned long /*position*/);
310 #if IN_LIBGCOV
311 static int gcov_write_summary (unsigned, const struct gcov_summary *);
312 #endif
313 #endif /* !IN_GCOV */
314 static const unsigned char *gcov_read_bytes (unsigned);
315 static int gcov_read_unsigned (unsigned *);
316 static int gcov_read_counter (gcov_type *);
317 #if !IN_LIBGCOV
318 static int gcov_read_string (char **);
319 #endif
320 static int gcov_read_summary (struct gcov_summary *);
321 static unsigned long gcov_save_position (void);
322 static int gcov_resync (unsigned long /*base*/, unsigned /*length */);
323 static unsigned long gcov_seek_end (void);
324 static int gcov_skip (unsigned /*length*/);
325 static int gcov_skip_string (unsigned /*length*/);
326 static int gcov_ok (void);
327 static int gcov_error (void);
328 static int gcov_eof (void);
329 #if IN_GCOV > 0
330 static time_t gcov_time (void);
331 #endif
332
333 /* Open a gcov file. NAME is the name of the file to open and MODE
334    indicates whether a new file should be created, or an existing file
335    opened for modification. If MODE is >= 0 an existing file will be
336    opened, if possible, and if MODE is <= 0, a new file will be
337    created. Use MODE=0 to attempt to reopen an existing file and then
338    fall back on creating a new one.  Return zero on failure, >0 on
339    opening an existing file and <0 on creating a new one.  */
340
341 static int
342 gcov_open (const char *name, int mode)
343 {
344   int result = 1;
345   size_t alloc = 1024;
346 #if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
347   struct flock s_flock;
348
349   s_flock.l_type = F_WRLCK;
350   s_flock.l_whence = SEEK_SET;
351   s_flock.l_start = 0;
352   s_flock.l_len = 0; /* Until EOF.  */
353   s_flock.l_pid = getpid ();
354 #endif
355   
356   if (gcov_file)
357     abort ();
358   gcov_position = gcov_length = 0;
359   gcov_errored = gcov_modified = 0;
360   if (mode >= 0)
361     gcov_file = fopen (name, "r+b");
362   if (!gcov_file && mode <= 0)
363     {
364       result = -1;
365       gcov_file = fopen (name, "w+b");
366     }
367   if (!gcov_file)
368     return 0;
369
370 #if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
371   while (fcntl (fileno (gcov_file), F_SETLKW, &s_flock)
372          && errno == EINTR)
373     continue;
374 #endif
375
376   if (result >= 0)
377     {
378       if (fseek (gcov_file, 0, SEEK_END))
379         {
380           fclose (gcov_file);
381           gcov_file = 0;
382           return 0;
383         }
384       gcov_length = ftell (gcov_file);
385       fseek (gcov_file, 0, SEEK_SET);
386       alloc += gcov_length;
387     }
388   if (alloc > gcov_alloc)
389     {
390       if (gcov_buffer)
391         free (gcov_buffer);
392       gcov_alloc = alloc;
393 #if IN_LIBGCOV
394       gcov_buffer = malloc (gcov_alloc);
395       if (!gcov_buffer)
396         {
397           fclose (gcov_file);
398           gcov_file = 0;
399           gcov_length = 0;
400           gcov_alloc = 0;
401           return 0;
402         }
403 #else
404       gcov_buffer = xmalloc (gcov_alloc);
405 #endif
406     }
407   if (result >= 0 && fread (gcov_buffer, gcov_length, 1, gcov_file) != 1)
408     {
409       fclose (gcov_file);
410       gcov_file = 0;
411       gcov_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_file)
426     {
427       if (gcov_modified
428           && (fseek (gcov_file, 0, SEEK_SET)
429               || fwrite (gcov_buffer, gcov_length, 1, gcov_file) != 1))
430         result = -1;
431       fclose (gcov_file);
432       gcov_file = 0;
433       gcov_length = 0;
434     }
435   return result || gcov_errored;
436 }
437
438 #if !IN_GCOV
439 /* Allocate space to write BYTES bytes to the gcov file. Return a
440    pointer to those bytes, or NULL on failure.  */
441
442 static unsigned char *
443 gcov_write_bytes (unsigned bytes)
444 {
445   char unsigned *result;
446
447   if (gcov_position + bytes > gcov_alloc)
448     {
449       size_t new_size = (gcov_alloc + bytes) * 3 / 2;
450
451       if (!gcov_buffer)
452         return 0;
453 #if IN_LIBGCOV
454       result = realloc (gcov_buffer, new_size);
455       if (!result)
456         {
457           free (gcov_buffer);
458           gcov_buffer = 0;
459           gcov_alloc = 0;
460           gcov_position = gcov_length = 0;
461           return 0;
462         }
463 #else
464       result = xrealloc (gcov_buffer, new_size);
465 #endif
466       gcov_alloc = new_size;
467       gcov_buffer = result;
468     }
469   
470   result = &gcov_buffer[gcov_position];
471   gcov_position += bytes;
472   gcov_modified = 1;
473   if (gcov_position > gcov_length)
474     gcov_length = gcov_position;
475   return result;
476 }
477
478 /* Write VALUE to coverage file.  Return nonzero if failed due to
479    file i/o error, or value error.  */
480
481 static int
482 gcov_write_unsigned (unsigned value)
483 {
484   unsigned char *buffer = gcov_write_bytes (4);
485   unsigned ix;
486
487   if (!buffer)
488     return 1;
489   
490   for (ix = 4; ix--; )
491     {
492       buffer[ix] = value;
493       value >>= 8;
494     }
495   return sizeof (value) > 4 && value;
496 }
497
498 /* Write VALUE to coverage file.  Return nonzero if failed due to
499    file i/o error, or value error.  Negative values are not checked
500    here -- they are checked in gcov_read_counter.  */
501
502 #if IN_LIBGCOV
503 static int
504 gcov_write_counter (gcov_type value)
505 {
506   unsigned char *buffer = gcov_write_bytes (8);
507   unsigned ix;
508
509   if (!buffer)
510     return 1;
511   
512   for (ix = 8; ix--; )
513     {
514       buffer[ix] = value;
515       value >>= 8;
516     }
517   return sizeof (value) > 8 && value;
518 }
519 #endif /* IN_LIBGCOV */
520
521 /* Write VALUE to coverage file.  Return nonzero if failed due to
522    file i/o error, or value error.  */
523
524 static int
525 gcov_write_string (const char *string)
526 {
527   if (string)
528     {
529       unsigned length = strlen (string);
530       unsigned pad = 0;
531       unsigned rem = 4 - (length & 3);
532       unsigned char *buffer;
533
534       if (gcov_write_unsigned (length))
535         return 1;
536       buffer = gcov_write_bytes (length + rem);
537       if (!buffer)
538         return 1;
539       memcpy (buffer, string, length);
540       memcpy (buffer + length, &pad, rem);
541       return 0;
542     }
543   else
544     return gcov_write_unsigned (0);
545 }
546
547 /* Allocate space to write a record tag length.  Return a value to be
548    used for gcov_write_length.  */
549
550 static unsigned long
551 gcov_reserve_length (void)
552 {
553   unsigned long result = gcov_position;
554   unsigned char *buffer = gcov_write_bytes (4);
555
556   if (!buffer)
557     return 0;
558   memset (buffer, 0, 4);
559   return result;
560 }
561
562 /* Write a record length at PLACE.  The current file position is the
563    end of the record, and is restored before returning.  Returns
564    nonzero on failure.  */
565
566 static int
567 gcov_write_length (unsigned long position)
568 {
569   unsigned length = gcov_position - position - 4;
570   unsigned char *buffer = &gcov_buffer[position];
571   unsigned ix;
572
573   if (!position)
574     return 1;
575   for (ix = 4; ix--; )
576     {
577       buffer[ix] = length;
578       length >>= 8;
579     }
580   return 0;
581 }
582
583 #if IN_LIBGCOV
584 /* Write a summary structure to the gcov file.  */
585
586 static int
587 gcov_write_summary (unsigned tag, const struct gcov_summary *summary)
588 {
589   volatile unsigned long base; /* volatile is necessary to work around
590                                   a compiler bug. */
591
592   if (gcov_write_unsigned (tag))
593     return 1;
594   base = gcov_reserve_length ();
595   if (gcov_write_unsigned (summary->checksum))
596     return 1;
597   if (gcov_write_unsigned (summary->runs)
598       || gcov_write_unsigned (summary->arcs))
599     return 1;
600   if (gcov_write_counter (summary->arc_sum)
601       || gcov_write_counter (summary->arc_max_one)
602       || gcov_write_counter (summary->arc_max_sum)
603       || gcov_write_counter (summary->arc_sum_max))
604     return 1;
605   if (gcov_write_length (base))
606     return 1;
607   return 0;
608 }
609 #endif /* IN_LIBGCOV */
610
611 #endif /*!IN_GCOV */
612
613 /* Return a pointer to read BYTES bytes from the gcov file. Returns
614    NULL on failure (read past EOF). */
615
616 static const unsigned char *
617 gcov_read_bytes (unsigned bytes)
618 {
619   const unsigned char *result;
620   
621   if (gcov_position + bytes > gcov_length)
622     return 0;
623   result = &gcov_buffer[gcov_position];
624   gcov_position += bytes;
625   return result;
626 }
627
628 /* Read *VALUE_P from coverage file.  Return nonzero if failed
629    due to file i/o error, or range error.  */
630
631 static int
632 gcov_read_unsigned (unsigned *value_p)
633 {
634   unsigned value = 0;
635   unsigned ix;
636   const unsigned char *buffer = gcov_read_bytes (4);
637
638   if (!buffer)
639     return 1;
640   for (ix = sizeof (value); ix < 4; ix++)
641     if (buffer[ix])
642       return 1;
643   for (ix = 0; ix != 4; ix++)
644     {
645       value <<= 8;
646       value |= buffer[ix];
647     }
648   *value_p = value;
649   return 0;
650 }
651
652 /* Read *VALUE_P from coverage file.  Return nonzero if failed
653    due to file i/o error, or range error.  */
654
655 static int
656 gcov_read_counter (gcov_type *value_p)
657 {
658   gcov_type value = 0;
659   unsigned ix;
660   const unsigned char *buffer = gcov_read_bytes (8);
661
662   if (!buffer)
663     return 1;
664   for (ix = sizeof (value); ix < 8; ix++)
665     if (buffer[ix])
666       return 1;
667   for (ix = 0; ix != 8; ix++)
668     {
669       value <<= 8;
670       value |= buffer[ix];
671     }
672
673   *value_p = value;
674   return value < 0;
675 }
676
677 #if !IN_LIBGCOV
678
679 /* Read string from coverage file.  A buffer is allocated and returned
680    in *STRING_P.  Return nonzero if failed due to file i/o error, or
681    range error.  Uses xmalloc to allocate the string buffer.  */
682
683 static int
684 gcov_read_string (char **string_p)
685 {
686   unsigned length;
687   const unsigned char *buffer;
688
689   if (gcov_read_unsigned (&length))
690     return 1;
691
692   free (*string_p);
693   *string_p = NULL;
694   if (!length)
695     return 0;
696
697   length += 4 - (length & 3);
698   buffer = gcov_read_bytes (length);
699   if (!buffer)
700     return 1;
701   
702   *string_p = xmalloc (length);
703   if (!*string_p)
704     return 1;
705
706   memcpy (*string_p, buffer, length);
707   return 0;
708 }
709
710 #endif /* !IN_LIBGCOV */
711
712 #define GCOV_SUMMARY_LENGTH 44
713 static int
714 gcov_read_summary (struct gcov_summary *summary)
715 {
716   return (gcov_read_unsigned (&summary->checksum)
717           || gcov_read_unsigned (&summary->runs)
718           || gcov_read_unsigned (&summary->arcs)
719           || gcov_read_counter (&summary->arc_sum)
720           || gcov_read_counter (&summary->arc_max_one)
721           || gcov_read_counter (&summary->arc_max_sum)
722           || gcov_read_counter (&summary->arc_sum_max));
723 }
724
725 /* Save the current position in the gcov file.  */
726
727 static inline unsigned long
728 gcov_save_position (void)
729 {
730   return gcov_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 int
737 gcov_resync (unsigned long base, unsigned length)
738 {
739   if (gcov_buffer)
740     gcov_position = base + length;
741   return 0;
742 }
743
744 /* Move to the end of the gcov file.  */
745
746 static inline unsigned long
747 gcov_seek_end ()
748 {
749   gcov_position = gcov_length;
750   return gcov_position;
751 }
752
753 /* Skip LENGTH bytes in the file.  */
754
755 static inline int
756 gcov_skip (unsigned length)
757 {
758   if (gcov_length < gcov_position + length)
759     return 1;
760   gcov_position += length;
761   return 0;
762 }
763
764 /* Skip a string of LENGTH bytes.  */
765
766 static inline int
767 gcov_skip_string (unsigned length)
768 {
769   return gcov_skip (length + 4 - (length & 3));
770 }
771
772 /* Tests whether we have reached end of .da file.  */
773
774 static inline int
775 gcov_eof ()
776 {
777   return gcov_position == gcov_length;
778 }
779
780 /* Return non-zero if the error flag is set.  */
781
782 static inline int
783 gcov_ok ()
784 {
785   return gcov_file != 0 && !gcov_errored;
786 }
787
788 /* Set the error flag. */
789 static inline int
790 gcov_error ()
791 {
792   int error = gcov_errored;
793   
794   gcov_errored = 1;
795   return error;
796 }
797
798 #if IN_GCOV > 0
799 /* Return the modification time of the current gcov file.  */
800
801 static time_t
802 gcov_time ()
803 {
804   struct stat status;
805   
806   if (fstat (fileno (gcov_file), &status))
807     return 0;
808   else
809     return status.st_mtime;
810 }
811 #endif /* IN_GCOV */
812 #endif /* GCC_GCOV_IO_H */