1 /* File format for coverage information
2 Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007,
3 2008 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 3, 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 Under Section 7 of GPL version 3, you are granted additional
20 permissions described in the GCC Runtime Library Exception, version
21 3.1, as published by the Free Software Foundation.
23 You should have received a copy of the GNU General Public License and
24 a copy of the GCC Runtime Library Exception along with this program;
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26 <http://www.gnu.org/licenses/>. */
28 /* Routines declared in gcov-io.h. This file should be #included by
29 another source file, after having #included gcov-io.h. */
32 static void gcov_write_block (unsigned);
33 static gcov_unsigned_t
*gcov_write_words (unsigned);
35 static const gcov_unsigned_t
*gcov_read_words (unsigned);
37 static void gcov_allocate (unsigned);
40 static inline gcov_unsigned_t
from_file (gcov_unsigned_t value
)
45 value
= (value
>> 16) | (value
<< 16);
46 value
= ((value
& 0xff00ff) << 8) | ((value
>> 8) & 0xff00ff);
52 /* Open a gcov file. NAME is the name of the file to open and MODE
53 indicates whether a new file should be created, or an existing file
54 opened. If MODE is >= 0 an existing file will be opened, if
55 possible, and if MODE is <= 0, a new file will be created. Use
56 MODE=0 to attempt to reopen an existing file and then fall back on
57 creating a new one. If MODE < 0, the file will be opened in
58 read-only mode. Otherwise it will be opened for modification.
59 Return zero on failure, >0 on opening an existing file and <0 on
60 creating a new one. */
64 gcov_open (const char *name
)
66 gcov_open (const char *name
, int mode
)
76 s_flock
.l_whence
= SEEK_SET
;
78 s_flock
.l_len
= 0; /* Until EOF. */
79 s_flock
.l_pid
= getpid ();
82 gcc_assert (!gcov_var
.file
);
84 gcov_var
.offset
= gcov_var
.length
= 0;
85 gcov_var
.overread
= -1u;
93 /* Read-only mode - acquire a read-lock. */
94 s_flock
.l_type
= F_RDLCK
;
95 fd
= open (name
, O_RDONLY
);
99 /* Write mode - acquire a write-lock. */
100 s_flock
.l_type
= F_WRLCK
;
101 fd
= open (name
, O_RDWR
| O_CREAT
, 0666);
106 while (fcntl (fd
, F_SETLKW
, &s_flock
) && errno
== EINTR
)
109 gcov_var
.file
= fdopen (fd
, (mode
> 0) ? "rb" : "r+b");
123 if (fstat (fd
, &st
) < 0)
125 fclose (gcov_var
.file
);
132 gcov_var
.mode
= mode
* 2 + 1;
135 gcov_var
.mode
= mode
* 2 + 1;
138 gcov_var
.file
= fopen (name
, (mode
> 0) ? "rb" : "r+b");
144 gcov_var
.file
= fopen (name
, "w+b");
146 gcov_var
.mode
= mode
* 2 + 1;
152 setbuf (gcov_var
.file
, (char *)0);
157 /* Close the current gcov file. Flushes data to disk. Returns nonzero
158 on failure or error flag set. */
166 if (gcov_var
.offset
&& gcov_var
.mode
< 0)
167 gcov_write_block (gcov_var
.offset
);
169 fclose (gcov_var
.file
);
174 free (gcov_var
.buffer
);
179 return gcov_var
.error
;
183 /* Check if MAGIC is EXPECTED. Use it to determine endianness of the
184 file. Returns +1 for same endian, -1 for other endian and zero for
188 gcov_magic (gcov_unsigned_t magic
, gcov_unsigned_t expected
)
190 if (magic
== expected
)
192 magic
= (magic
>> 16) | (magic
<< 16);
193 magic
= ((magic
& 0xff00ff) << 8) | ((magic
>> 8) & 0xff00ff);
194 if (magic
== expected
)
205 gcov_allocate (unsigned length
)
207 size_t new_size
= gcov_var
.alloc
;
210 new_size
= GCOV_BLOCK_SIZE
;
214 gcov_var
.alloc
= new_size
;
215 gcov_var
.buffer
= XRESIZEVAR (gcov_unsigned_t
, gcov_var
.buffer
, new_size
<< 2);
220 /* Write out the current block, if needs be. */
223 gcov_write_block (unsigned size
)
225 if (fwrite (gcov_var
.buffer
, size
<< 2, 1, gcov_var
.file
) != 1)
227 gcov_var
.start
+= size
;
228 gcov_var
.offset
-= size
;
231 /* Allocate space to write BYTES bytes to the gcov file. Return a
232 pointer to those bytes, or NULL on failure. */
234 static gcov_unsigned_t
*
235 gcov_write_words (unsigned words
)
237 gcov_unsigned_t
*result
;
239 gcc_assert (gcov_var
.mode
< 0);
241 if (gcov_var
.offset
>= GCOV_BLOCK_SIZE
)
243 gcov_write_block (GCOV_BLOCK_SIZE
);
246 gcc_assert (gcov_var
.offset
== 1);
247 memcpy (gcov_var
.buffer
, gcov_var
.buffer
+ GCOV_BLOCK_SIZE
, 4);
251 if (gcov_var
.offset
+ words
> gcov_var
.alloc
)
252 gcov_allocate (gcov_var
.offset
+ words
);
254 result
= &gcov_var
.buffer
[gcov_var
.offset
];
255 gcov_var
.offset
+= words
;
260 /* Write unsigned VALUE to coverage file. Sets error flag
264 gcov_write_unsigned (gcov_unsigned_t value
)
266 gcov_unsigned_t
*buffer
= gcov_write_words (1);
271 /* Write counter VALUE to coverage file. Sets error flag
276 gcov_write_counter (gcov_type value
)
278 gcov_unsigned_t
*buffer
= gcov_write_words (2);
280 buffer
[0] = (gcov_unsigned_t
) value
;
281 if (sizeof (value
) > sizeof (gcov_unsigned_t
))
282 buffer
[1] = (gcov_unsigned_t
) (value
>> 32);
286 #endif /* IN_LIBGCOV */
289 /* Write STRING to coverage file. Sets error flag on file
290 error, overflow flag on overflow */
293 gcov_write_string (const char *string
)
297 gcov_unsigned_t
*buffer
;
301 length
= strlen (string
);
302 alloc
= (length
+ 4) >> 2;
305 buffer
= gcov_write_words (1 + alloc
);
309 memcpy (&buffer
[1], string
, length
);
314 /* Write a tag TAG and reserve space for the record length. Return a
315 value to be used for gcov_write_length. */
317 GCOV_LINKAGE gcov_position_t
318 gcov_write_tag (gcov_unsigned_t tag
)
320 gcov_position_t result
= gcov_var
.start
+ gcov_var
.offset
;
321 gcov_unsigned_t
*buffer
= gcov_write_words (2);
329 /* Write a record length using POSITION, which was returned by
330 gcov_write_tag. The current file position is the end of the
331 record, and is restored before returning. Returns nonzero on
335 gcov_write_length (gcov_position_t position
)
338 gcov_unsigned_t length
;
339 gcov_unsigned_t
*buffer
;
341 gcc_assert (gcov_var
.mode
< 0);
342 gcc_assert (position
+ 2 <= gcov_var
.start
+ gcov_var
.offset
);
343 gcc_assert (position
>= gcov_var
.start
);
344 offset
= position
- gcov_var
.start
;
345 length
= gcov_var
.offset
- offset
- 2;
346 buffer
= (gcov_unsigned_t
*) &gcov_var
.buffer
[offset
];
348 if (gcov_var
.offset
>= GCOV_BLOCK_SIZE
)
349 gcov_write_block (gcov_var
.offset
);
352 #else /* IN_LIBGCOV */
354 /* Write a tag TAG and length LENGTH. */
357 gcov_write_tag_length (gcov_unsigned_t tag
, gcov_unsigned_t length
)
359 gcov_unsigned_t
*buffer
= gcov_write_words (2);
365 /* Write a summary structure to the gcov file. Return nonzero on
369 gcov_write_summary (gcov_unsigned_t tag
, const struct gcov_summary
*summary
)
372 const struct gcov_ctr_summary
*csum
;
374 gcov_write_tag_length (tag
, GCOV_TAG_SUMMARY_LENGTH
);
375 gcov_write_unsigned (summary
->checksum
);
376 for (csum
= summary
->ctrs
, ix
= GCOV_COUNTERS_SUMMABLE
; ix
--; csum
++)
378 gcov_write_unsigned (csum
->num
);
379 gcov_write_unsigned (csum
->runs
);
380 gcov_write_counter (csum
->sum_all
);
381 gcov_write_counter (csum
->run_max
);
382 gcov_write_counter (csum
->sum_max
);
385 #endif /* IN_LIBGCOV */
389 /* Return a pointer to read BYTES bytes from the gcov file. Returns
390 NULL on failure (read past EOF). */
392 static const gcov_unsigned_t
*
393 gcov_read_words (unsigned words
)
395 const gcov_unsigned_t
*result
;
396 unsigned excess
= gcov_var
.length
- gcov_var
.offset
;
398 gcc_assert (gcov_var
.mode
> 0);
401 gcov_var
.start
+= gcov_var
.offset
;
405 gcc_assert (excess
== 1);
406 memcpy (gcov_var
.buffer
, gcov_var
.buffer
+ gcov_var
.offset
, 4);
409 memmove (gcov_var
.buffer
, gcov_var
.buffer
+ gcov_var
.offset
, excess
* 4);
412 gcov_var
.length
= excess
;
414 gcc_assert (!gcov_var
.length
|| gcov_var
.length
== 1);
415 excess
= GCOV_BLOCK_SIZE
;
417 if (gcov_var
.length
+ words
> gcov_var
.alloc
)
418 gcov_allocate (gcov_var
.length
+ words
);
419 excess
= gcov_var
.alloc
- gcov_var
.length
;
421 excess
= fread (gcov_var
.buffer
+ gcov_var
.length
,
422 1, excess
<< 2, gcov_var
.file
) >> 2;
423 gcov_var
.length
+= excess
;
424 if (gcov_var
.length
< words
)
426 gcov_var
.overread
+= words
- gcov_var
.length
;
431 result
= &gcov_var
.buffer
[gcov_var
.offset
];
432 gcov_var
.offset
+= words
;
436 /* Read unsigned value from a coverage file. Sets error flag on file
437 error, overflow flag on overflow */
439 GCOV_LINKAGE gcov_unsigned_t
440 gcov_read_unsigned (void)
442 gcov_unsigned_t value
;
443 const gcov_unsigned_t
*buffer
= gcov_read_words (1);
447 value
= from_file (buffer
[0]);
451 /* Read counter value from a coverage file. Sets error flag on file
452 error, overflow flag on overflow */
454 GCOV_LINKAGE gcov_type
455 gcov_read_counter (void)
458 const gcov_unsigned_t
*buffer
= gcov_read_words (2);
462 value
= from_file (buffer
[0]);
463 if (sizeof (value
) > sizeof (gcov_unsigned_t
))
464 value
|= ((gcov_type
) from_file (buffer
[1])) << 32;
471 /* Read string from coverage file. Returns a pointer to a static
472 buffer, or NULL on empty string. You must copy the string before
473 calling another gcov function. */
476 GCOV_LINKAGE
const char *
477 gcov_read_string (void)
479 unsigned length
= gcov_read_unsigned ();
484 return (const char *) gcov_read_words (length
);
489 gcov_read_summary (struct gcov_summary
*summary
)
492 struct gcov_ctr_summary
*csum
;
494 summary
->checksum
= gcov_read_unsigned ();
495 for (csum
= summary
->ctrs
, ix
= GCOV_COUNTERS_SUMMABLE
; ix
--; csum
++)
497 csum
->num
= gcov_read_unsigned ();
498 csum
->runs
= gcov_read_unsigned ();
499 csum
->sum_all
= gcov_read_counter ();
500 csum
->run_max
= gcov_read_counter ();
501 csum
->sum_max
= gcov_read_counter ();
506 /* Reset to a known position. BASE should have been obtained from
507 gcov_position, LENGTH should be a record length. */
510 gcov_sync (gcov_position_t base
, gcov_unsigned_t length
)
512 gcc_assert (gcov_var
.mode
> 0);
514 if (base
- gcov_var
.start
<= gcov_var
.length
)
515 gcov_var
.offset
= base
- gcov_var
.start
;
518 gcov_var
.offset
= gcov_var
.length
= 0;
519 fseek (gcov_var
.file
, base
<< 2, SEEK_SET
);
520 gcov_var
.start
= ftell (gcov_var
.file
) >> 2;
526 /* Move to a given position in a gcov file. */
529 gcov_seek (gcov_position_t base
)
531 gcc_assert (gcov_var
.mode
< 0);
533 gcov_write_block (gcov_var
.offset
);
534 fseek (gcov_var
.file
, base
<< 2, SEEK_SET
);
535 gcov_var
.start
= ftell (gcov_var
.file
) >> 2;
540 /* Return the modification time of the current gcov file. */
547 if (fstat (fileno (gcov_var
.file
), &status
))
550 return status
.st_mtime
;