1 /* File format for coverage information
2 Copyright (C) 1996, 1997, 1998, 2000, 2002,
3 2003 Free Software Foundation, Inc.
4 Contributed by Bob Manson <manson@cygnus.com>.
5 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to the Free
21 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 /* Routines declared in gcov-io.h. This file should be #included by
25 another source file, after having #included gcov-io.h. */
28 static void gcov_write_block (unsigned);
29 static unsigned char *gcov_write_bytes (unsigned);
31 static const unsigned char *gcov_read_bytes (unsigned);
33 static void gcov_allocate (unsigned);
36 /* Open a gcov file. NAME is the name of the file to open and MODE
37 indicates whether a new file should be created, or an existing file
38 opened for modification. If MODE is >= 0 an existing file will be
39 opened, if possible, and if MODE is <= 0, a new file will be
40 created. Use MODE=0 to attempt to reopen an existing file and then
41 fall back on creating a new one. Return zero on failure, >0 on
42 opening an existing file and <0 on creating a new one. */
45 gcov_open (const char *name
, int mode
)
51 s_flock
.l_type
= F_WRLCK
;
52 s_flock
.l_whence
= SEEK_SET
;
54 s_flock
.l_len
= 0; /* Until EOF. */
55 s_flock
.l_pid
= getpid ();
61 gcov_var
.offset
= gcov_var
.length
= 0;
62 gcov_var
.overread
= -4u;
65 gcov_var
.file
= fopen (name
, "r+b");
71 gcov_var
.file
= fopen (name
, "w+b");
78 setbuf (gcov_var
.file
, (char *)0);
81 while (fcntl (fileno (gcov_var
.file
), F_SETLKW
, &s_flock
)
89 /* Close the current gcov file. Flushes data to disk. Returns nonzero
90 on failure or error flag set. */
98 if (gcov_var
.offset
&& gcov_var
.mode
< 0)
99 gcov_write_block (gcov_var
.offset
);
101 fclose (gcov_var
.file
);
106 free (gcov_var
.buffer
);
111 return gcov_var
.error
;
116 gcov_allocate (unsigned length
)
118 size_t new_size
= gcov_var
.alloc
;
121 new_size
= GCOV_BLOCK_SIZE
;
125 gcov_var
.alloc
= new_size
;
126 gcov_var
.buffer
= xrealloc (gcov_var
.buffer
, new_size
);
131 /* Write out the current block, if needs be. */
134 gcov_write_block (unsigned size
)
136 if (fwrite (gcov_var
.buffer
, size
, 1, gcov_var
.file
) != 1)
138 gcov_var
.start
+= size
;
139 gcov_var
.offset
-= size
;
142 /* Allocate space to write BYTES bytes to the gcov file. Return a
143 pointer to those bytes, or NULL on failure. */
145 static unsigned char *
146 gcov_write_bytes (unsigned bytes
)
148 char unsigned *result
;
150 GCOV_CHECK_WRITING ();
152 if (gcov_var
.offset
>= GCOV_BLOCK_SIZE
)
154 gcov_write_block (GCOV_BLOCK_SIZE
);
157 GCOV_CHECK (gcov_var
.offset
== 4);
158 memcpy (gcov_var
.buffer
, gcov_var
.buffer
+ GCOV_BLOCK_SIZE
, 4);
162 if (gcov_var
.offset
+ bytes
> gcov_var
.alloc
)
163 gcov_allocate (gcov_var
.offset
+ bytes
);
165 result
= &gcov_var
.buffer
[gcov_var
.offset
];
166 gcov_var
.offset
+= bytes
;
171 /* Write unsigned VALUE to coverage file. Sets error flag
175 gcov_write_unsigned (gcov_unsigned_t value
)
177 unsigned char *buffer
= gcov_write_bytes (4);
185 if (sizeof (value
) > 4 && value
)
191 /* Write counter VALUE to coverage file. Sets error flag
196 gcov_write_counter (gcov_type value
)
198 unsigned char *buffer
= gcov_write_bytes (8);
206 if ((sizeof (value
) > 8 && value
) || value
< 0)
210 #endif /* IN_LIBGCOV */
213 /* Write STRING to coverage file. Sets error flag on file
214 error, overflow flag on overflow */
217 gcov_write_string (const char *string
)
222 unsigned char *buffer
;
228 length
= strlen (string
);
229 rem
= 4 - (length
& 3);
232 buffer
= gcov_write_bytes (4 + length
+ rem
);
240 memcpy (buffer
+ 4, string
, length
);
241 memcpy (buffer
+ 4 + length
, &pad
, rem
);
246 /* Write a tag TAG and reserve space for the record length. Return a
247 value to be used for gcov_write_length. */
249 GCOV_LINKAGE gcov_position_t
250 gcov_write_tag (gcov_unsigned_t tag
)
252 gcov_position_t result
= gcov_var
.start
+ gcov_var
.offset
;
253 unsigned char *buffer
= gcov_write_bytes (8);
261 memset (buffer
+ 4, 0, 4);
265 /* Write a record length using POSITION, which was returned by
266 gcov_write_tag. The current file position is the end of the
267 record, and is restored before returning. Returns nonzero on
271 gcov_write_length (gcov_position_t position
)
274 gcov_unsigned_t length
;
275 unsigned char *buffer
;
278 GCOV_CHECK_WRITING ();
279 GCOV_CHECK (position
+ 8 <= gcov_var
.start
+ gcov_var
.offset
);
280 GCOV_CHECK (position
>= gcov_var
.start
);
281 offset
= position
- gcov_var
.start
;
282 length
= gcov_var
.offset
- offset
- 8;
283 buffer
= &gcov_var
.buffer
[offset
+ 4];
289 if (gcov_var
.offset
>= GCOV_BLOCK_SIZE
)
290 gcov_write_block (gcov_var
.offset
);
293 #else /* IN_LIBGCOV */
295 /* Write a tag TAG and length LENGTH. */
298 gcov_write_tag_length (gcov_unsigned_t tag
, gcov_unsigned_t length
)
300 unsigned char *buffer
= gcov_write_bytes (8);
310 buffer
[ix
+ 4] = length
;
316 /* Write a summary structure to the gcov file. Return nonzero on
320 gcov_write_summary (gcov_unsigned_t tag
, const struct gcov_summary
*summary
)
323 const struct gcov_ctr_summary
*csum
;
325 gcov_write_tag_length (tag
, GCOV_TAG_SUMMARY_LENGTH
);
326 gcov_write_unsigned (summary
->checksum
);
327 for (csum
= summary
->ctrs
, ix
= GCOV_COUNTERS_SUMMABLE
; ix
--; csum
++)
329 gcov_write_unsigned (csum
->num
);
330 gcov_write_unsigned (csum
->runs
);
331 gcov_write_counter (csum
->sum_all
);
332 gcov_write_counter (csum
->run_max
);
333 gcov_write_counter (csum
->sum_max
);
336 #endif /* IN_LIBGCOV */
340 /* Return a pointer to read BYTES bytes from the gcov file. Returns
341 NULL on failure (read past EOF). */
343 static const unsigned char *
344 gcov_read_bytes (unsigned bytes
)
346 const unsigned char *result
;
347 unsigned excess
= gcov_var
.length
- gcov_var
.offset
;
349 GCOV_CHECK_READING ();
352 gcov_var
.start
+= gcov_var
.offset
;
356 GCOV_CHECK (excess
== 4);
357 memcpy (gcov_var
.buffer
, gcov_var
.buffer
+ gcov_var
.offset
, 4);
360 memmove (gcov_var
.buffer
, gcov_var
.buffer
+ gcov_var
.offset
, excess
);
363 gcov_var
.length
= excess
;
365 GCOV_CHECK (!gcov_var
.length
|| gcov_var
.length
== 4);
366 excess
= GCOV_BLOCK_SIZE
;
368 if (gcov_var
.length
+ bytes
> gcov_var
.alloc
)
369 gcov_allocate (gcov_var
.length
+ bytes
);
370 excess
= gcov_var
.alloc
- gcov_var
.length
;
372 excess
= fread (gcov_var
.buffer
+ gcov_var
.length
,
373 1, excess
, gcov_var
.file
);
374 gcov_var
.length
+= excess
;
375 if (gcov_var
.length
< bytes
)
377 gcov_var
.overread
+= bytes
- gcov_var
.length
;
382 result
= &gcov_var
.buffer
[gcov_var
.offset
];
383 gcov_var
.offset
+= bytes
;
387 /* Read unsigned value from a coverage file. Sets error flag on file
388 error, overflow flag on overflow */
390 GCOV_LINKAGE gcov_unsigned_t
391 gcov_read_unsigned ()
393 gcov_unsigned_t value
= 0;
395 const unsigned char *buffer
= gcov_read_bytes (4);
399 for (ix
= sizeof (value
); ix
< 4; ix
++)
402 for (ix
= 0; ix
!= 4; ix
++)
410 /* Read counter value from a coverage file. Sets error flag on file
411 error, overflow flag on overflow */
413 GCOV_LINKAGE gcov_type
418 const unsigned char *buffer
= gcov_read_bytes (8);
422 for (ix
= sizeof (value
); ix
< 8; ix
++)
425 for (ix
= 0; ix
!= 8; ix
++)
435 /* Read string from coverage file. Returns a pointer to a static
436 buffer, or NULL on empty string. You must copy the string before
437 calling another gcov function. */
440 GCOV_LINKAGE
const char *
443 unsigned length
= gcov_read_unsigned ();
448 length
+= 4 - (length
& 3);
449 return (const char *) gcov_read_bytes (length
);
454 gcov_read_summary (struct gcov_summary
*summary
)
457 struct gcov_ctr_summary
*csum
;
459 summary
->checksum
= gcov_read_unsigned ();
460 for (csum
= summary
->ctrs
, ix
= GCOV_COUNTERS_SUMMABLE
; ix
--; csum
++)
462 csum
->num
= gcov_read_unsigned ();
463 csum
->runs
= gcov_read_unsigned ();
464 csum
->sum_all
= gcov_read_counter ();
465 csum
->run_max
= gcov_read_counter ();
466 csum
->sum_max
= gcov_read_counter ();
471 /* Reset to a known position. BASE should have been obtained from
472 gcov_position, LENGTH should be a record length. */
475 gcov_sync (gcov_position_t base
, gcov_unsigned_t length
)
477 GCOV_CHECK_READING ();
479 if (base
- gcov_var
.start
<= gcov_var
.length
)
480 gcov_var
.offset
= base
- gcov_var
.start
;
483 gcov_var
.offset
= gcov_var
.length
= 0;
484 fseek (gcov_var
.file
, base
, SEEK_SET
);
485 gcov_var
.start
= ftell (gcov_var
.file
);
491 /* Move to the a set position in a gcov file. BASE is zero to move to
492 the end, and nonzero to move to that position. */
495 gcov_seek (gcov_position_t base
)
497 GCOV_CHECK_WRITING ();
499 gcov_write_block (gcov_var
.offset
);
500 fseek (gcov_var
.file
, base
, base
? SEEK_SET
: SEEK_END
);
501 gcov_var
.start
= ftell (gcov_var
.file
);
506 /* Return the modification time of the current gcov file. */
513 if (fstat (fileno (gcov_var
.file
), &status
))
516 return status
.st_mtime
;