1 /* File format for coverage information
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
3 Contributed by Bob Manson <manson@cygnus.com>.
4 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
6 This file is part of GCC.
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 3, or (at your option) any later
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
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
27 /* Routines declared in gcov-io.h. This file should be #included by
28 another source file, after having #included gcov-io.h. */
30 static gcov_unsigned_t
*gcov_read_words (void *buffer
, unsigned);
35 int error
; /* < 0 overflow, > 0 disk error. */
36 int mode
; /* < 0 writing, > 0 reading. */
37 int endian
; /* Swap endianness. */
40 /* Save the current position in the gcov file. */
41 /* We need to expose this function when compiling for gcov-tool. */
48 return ftell (gcov_var
.file
);
51 /* Return nonzero if the error flag is set. */
52 /* We need to expose this function when compiling for gcov-tool. */
59 return gcov_var
.file
? gcov_var
.error
: 1;
63 /* Move to beginning of file and initialize for writing. */
64 GCOV_LINKAGE
inline void
68 fseek (gcov_var
.file
, 0L, SEEK_SET
);
72 static inline gcov_unsigned_t
73 from_file (gcov_unsigned_t value
)
75 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
77 return __builtin_bswap32 (value
);
82 /* Open a gcov file. NAME is the name of the file to open and MODE
83 indicates whether a new file should be created, or an existing file
84 opened. If MODE is >= 0 an existing file will be opened, if
85 possible, and if MODE is <= 0, a new file will be created. Use
86 MODE=0 to attempt to reopen an existing file and then fall back on
87 creating a new one. If MODE > 0, the file will be opened in
88 read-only mode. Otherwise it will be opened for modification.
89 Return zero on failure, non-zero on success. */
93 gcov_open (const char *name
)
95 gcov_open (const char *name
, int mode
)
102 struct flock s_flock
;
105 s_flock
.l_whence
= SEEK_SET
;
107 s_flock
.l_len
= 0; /* Until EOF. */
108 s_flock
.l_pid
= getpid ();
109 #elif GCOV_LOCKED_WITH_LOCKING
113 gcov_nonruntime_assert (!gcov_var
.file
);
115 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
121 /* Read-only mode - acquire a read-lock. */
122 s_flock
.l_type
= F_RDLCK
;
123 /* pass mode (ignored) for compatibility */
124 fd
= open (name
, O_RDONLY
, S_IRUSR
| S_IWUSR
);
128 /* Write mode - acquire a write-lock. */
129 s_flock
.l_type
= F_WRLCK
;
130 /* Truncate if force new mode. */
131 fd
= open (name
, O_RDWR
| O_CREAT
| (mode
< 0 ? O_TRUNC
: 0), 0666);
136 while (fcntl (fd
, F_SETLKW
, &s_flock
) && errno
== EINTR
)
139 gcov_var
.file
= fdopen (fd
, (mode
> 0) ? "rb" : "r+b");
146 #elif GCOV_LOCKED_WITH_LOCKING
149 /* pass mode (ignored) for compatibility */
150 fd
= open (name
, O_RDONLY
| O_BINARY
, S_IRUSR
| S_IWUSR
);
154 /* Truncate if force new mode. */
155 fd
= open (name
, O_RDWR
| O_BINARY
| O_CREAT
| (mode
< 0 ? O_TRUNC
: 0),
161 if (_locking (fd
, _LK_LOCK
, LONG_MAX
) < 0)
167 gcov_var
.file
= fdopen (fd
, (mode
> 0) ? "rb" : "r+b");
176 /* Open an existing file. */
177 gcov_var
.file
= fopen (name
, (mode
> 0) ? "rb" : "r+b");
182 /* Create a new file. */
183 gcov_var
.file
= fopen (name
, "w+b");
189 gcov_var
.mode
= mode
? mode
: 1;
194 /* Close the current gcov file. Flushes data to disk. Returns nonzero
195 on failure or error flag set. */
202 fclose (gcov_var
.file
);
206 return gcov_var
.error
;
209 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
210 /* Check if MAGIC is EXPECTED. Use it to determine endianness of the
211 file. Returns +1 for same endian, -1 for other endian and zero for
215 gcov_magic (gcov_unsigned_t magic
, gcov_unsigned_t expected
)
217 if (magic
== expected
)
220 if (__builtin_bswap32 (magic
) == expected
)
230 /* Write unsigned VALUE to coverage file. */
233 gcov_write_unsigned (gcov_unsigned_t value
)
235 gcov_unsigned_t r
= fwrite (&value
, sizeof (value
), 1, gcov_var
.file
);
240 /* Write counter VALUE to coverage file. Sets error flag
245 gcov_write_counter (gcov_type value
)
247 gcov_write_unsigned ((gcov_unsigned_t
) value
);
248 if (sizeof (value
) > sizeof (gcov_unsigned_t
))
249 gcov_write_unsigned ((gcov_unsigned_t
) (value
>> 32));
251 gcov_write_unsigned (0);
253 #endif /* IN_LIBGCOV */
256 /* Write STRING to coverage file. Sets error flag on file
257 error, overflow flag on overflow */
260 gcov_write_string (const char *string
)
265 length
= strlen (string
) + 1;
267 gcov_write_unsigned (length
);
270 gcov_unsigned_t r
= fwrite (string
, length
, 1, gcov_var
.file
);
278 /* Write FILENAME to coverage file. Sets error flag on file
279 error, overflow flag on overflow */
282 gcov_write_filename (const char *filename
)
284 if (profile_abs_path_flag
&& filename
&& filename
[0]
285 && !(IS_DIR_SEPARATOR (filename
[0])
286 #if HAVE_DOS_BASED_FILE_SYSTEM
287 || filename
[1] == ':'
291 char *buf
= getcwd (NULL
, 0);
292 if (buf
!= NULL
&& buf
[0])
294 size_t len
= strlen (buf
);
295 buf
= (char*)xrealloc (buf
, len
+ strlen (filename
) + 2);
296 if (!IS_DIR_SEPARATOR (buf
[len
- 1]))
298 strcat (buf
, filename
);
299 gcov_write_string (buf
);
305 gcov_write_string (filename
);
309 /* Move to a given position in a gcov file. */
312 gcov_seek (gcov_position_t base
)
314 fseek (gcov_var
.file
, base
, SEEK_SET
);
318 /* Write a tag TAG and reserve space for the record length. Return a
319 value to be used for gcov_write_length. */
321 GCOV_LINKAGE gcov_position_t
322 gcov_write_tag (gcov_unsigned_t tag
)
324 gcov_position_t result
= gcov_position ();
325 gcov_write_unsigned (tag
);
326 gcov_write_unsigned (0);
331 /* Write a record length using POSITION, which was returned by
332 gcov_write_tag. The current file position is the end of the
333 record, and is restored before returning. Returns nonzero on
337 gcov_write_length (gcov_position_t position
)
339 gcov_position_t current_position
= gcov_position ();
340 gcov_nonruntime_assert (gcov_var
.mode
< 0);
341 gcov_nonruntime_assert (current_position
>= position
+ 2 * GCOV_WORD_SIZE
);
343 gcov_seek (position
+ GCOV_WORD_SIZE
);
344 gcov_write_unsigned (current_position
- position
- 2 * GCOV_WORD_SIZE
);
345 gcov_seek (current_position
);
348 #else /* IN_LIBGCOV */
350 /* Write a tag TAG and length LENGTH. */
353 gcov_write_tag_length (gcov_unsigned_t tag
, gcov_unsigned_t length
)
355 gcov_write_unsigned (tag
);
356 gcov_write_unsigned (length
);
359 /* Write a summary structure to the gcov file. Return nonzero on
363 gcov_write_summary (gcov_unsigned_t tag
, const struct gcov_summary
*summary
)
365 gcov_write_tag_length (tag
, GCOV_TAG_SUMMARY_LENGTH
);
366 gcov_write_unsigned (summary
->runs
);
367 gcov_write_unsigned (summary
->sum_max
);
370 #endif /* IN_LIBGCOV */
374 /* Return a pointer to read COUNT bytes from the gcov file. Returns
375 NULL on failure (read past EOF). */
378 gcov_read_bytes (void *buffer
, unsigned count
)
380 if (gcov_var
.mode
<= 0)
383 unsigned read
= fread (buffer
, count
, 1, gcov_var
.file
);
390 /* Read WORDS gcov_unsigned_t values from gcov file. */
392 static gcov_unsigned_t
*
393 gcov_read_words (void *buffer
, unsigned words
)
395 return (gcov_unsigned_t
*)gcov_read_bytes (buffer
, GCOV_WORD_SIZE
* words
);
398 /* Read unsigned value from a coverage file. Sets error flag on file
399 error, overflow flag on overflow */
401 GCOV_LINKAGE gcov_unsigned_t
402 gcov_read_unsigned (void)
404 gcov_unsigned_t value
;
405 gcov_unsigned_t allocated_buffer
[1];
406 gcov_unsigned_t
*buffer
= gcov_read_words (&allocated_buffer
, 1);
411 value
= from_file (buffer
[0]);
415 /* Read counter value from a coverage file. Sets error flag on file
416 error, overflow flag on overflow */
418 GCOV_LINKAGE gcov_type
419 gcov_read_counter (void)
422 gcov_unsigned_t allocated_buffer
[2];
423 gcov_unsigned_t
*buffer
= gcov_read_words (&allocated_buffer
, 2);
427 value
= from_file (buffer
[0]);
428 if (sizeof (value
) > sizeof (gcov_unsigned_t
))
429 value
|= ((gcov_type
) from_file (buffer
[1])) << 32;
436 /* Mangle filename path of BASE and output new allocated pointer with
440 mangle_path (char const *base
)
442 /* Convert '/' to '#', convert '..' to '^',
443 convert ':' to '~' on DOS based file system. */
445 char *buffer
= (char *)xmalloc (strlen (base
) + 1);
448 #if HAVE_DOS_BASED_FILE_SYSTEM
449 if (base
[0] && base
[1] == ':')
457 for (; *base
; base
= probe
)
461 for (probe
= base
; *probe
; probe
++)
465 if (len
== 2 && base
[0] == '.' && base
[1] == '.')
469 memcpy (ptr
, base
, len
);
479 /* Terminate the string. */
485 /* We need to expose the below function when compiling for gcov-tool. */
487 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
488 /* Read string from coverage file. Returns a pointer to a static
489 buffer, or NULL on empty string. You must copy the string before
490 calling another gcov function. */
492 GCOV_LINKAGE
const char *
493 gcov_read_string (void)
495 unsigned length
= gcov_read_unsigned ();
500 void *buffer
= XNEWVEC (char *, length
);
501 return (const char *) gcov_read_bytes (buffer
, length
);
506 gcov_read_summary (struct gcov_summary
*summary
)
508 summary
->runs
= gcov_read_unsigned ();
509 summary
->sum_max
= gcov_read_unsigned ();
512 /* We need to expose the below function when compiling for gcov-tool. */
514 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
515 /* Reset to a known position. BASE should have been obtained from
516 gcov_position, LENGTH should be a record length. */
519 gcov_sync (gcov_position_t base
, gcov_unsigned_t length
)
521 gcov_nonruntime_assert (gcov_var
.mode
> 0);
523 fseek (gcov_var
.file
, base
, SEEK_SET
);
528 /* Return the modification time of the current gcov file. */
535 if (fstat (fileno (gcov_var
.file
), &status
))
538 return status
.st_mtime
;