LCOV - code coverage report
Current view: top level - gcc - gcov-io.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 80.4 % 153 123
Test Date: 2026-02-28 14:20:25 Functions: 85.7 % 28 24
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* File format for coverage information
       2              :    Copyright (C) 1996-2026 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 3, 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              : 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.
      21              : 
      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/>.  */
      26              : 
      27              : /* Routines declared in gcov-io.h.  This file should be #included by
      28              :    another source file, after having #included gcov-io.h.  */
      29              : 
      30              : static gcov_unsigned_t *gcov_read_words (void *buffer, unsigned);
      31              : 
      32              : /* Indicates the last gcov file access error or that no error occurred
      33              :    so far.  */
      34              : enum gcov_file_error
      35              : {
      36              :   GCOV_FILE_COUNTER_OVERFLOW = -1,
      37              :   GCOV_FILE_NO_ERROR = 0,
      38              :   GCOV_FILE_WRITE_ERROR = 1,
      39              :   GCOV_FILE_EOF = 2
      40              : };
      41              : 
      42              : struct gcov_var
      43              : {
      44              :   FILE *file;
      45              :   enum gcov_file_error error;
      46              :   int mode;                     /* < 0 writing, > 0 reading.  */
      47              :   int endian;                   /* Swap endianness.  */
      48              : #ifdef IN_GCOV_TOOL
      49              :   gcov_position_t pos;          /* File position for stdin support.  */
      50              : #endif
      51              : } gcov_var;
      52              : 
      53              : #define GCOV_MODE_STDIN 2
      54              : 
      55              : /* Save the current position in the gcov file.  */
      56              : /* We need to expose this function when compiling for gcov-tool.  */
      57              : #ifndef IN_GCOV_TOOL
      58              : static inline
      59              : #endif
      60              : gcov_position_t
      61        54003 : gcov_position (void)
      62              : {
      63              : #ifdef IN_GCOV_TOOL
      64              :   if (gcov_var.mode == GCOV_MODE_STDIN)
      65              :     return gcov_var.pos;
      66              : #endif
      67        20163 :   return ftell (gcov_var.file);
      68              : }
      69              : 
      70              : /* Return nonzero if the error flag is set.  */
      71              : /* We need to expose this function when compiling for gcov-tool.  */
      72              : #if !defined (IN_GCOV_TOOL) && !defined (IN_GCC)
      73              : static inline
      74              : #endif
      75              : int
      76        22315 : gcov_is_error (void)
      77              : {
      78        22315 :   return gcov_var.file ? gcov_var.error : 1;
      79              : }
      80              : 
      81              : #if IN_LIBGCOV
      82              : /* Move to beginning of file, initialize for writing, and clear file error
      83              :    status.  */
      84              : 
      85              : GCOV_LINKAGE inline void
      86              : gcov_rewrite (void)
      87              : {
      88              :   gcov_var.mode = -1;
      89              :   gcov_var.error = GCOV_FILE_NO_ERROR;
      90              :   fseek (gcov_var.file, 0L, SEEK_SET);
      91              : }
      92              : #endif
      93              : 
      94              : static inline gcov_unsigned_t
      95       139742 : from_file (gcov_unsigned_t value)
      96              : {
      97              : #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
      98       139742 :   if (gcov_var.endian)
      99            0 :     return __builtin_bswap32 (value);
     100              : #endif
     101              :   return value;
     102              : }
     103              : 
     104              : /* Open a gcov file. NAME is the name of the file to open and MODE
     105              :    indicates whether a new file should be created, or an existing file
     106              :    opened. If MODE is >= 0 an existing file will be opened, if
     107              :    possible, and if MODE is <= 0, a new file will be created. Use
     108              :    MODE=0 to attempt to reopen an existing file and then fall back on
     109              :    creating a new one.  If MODE > 0, the file will be opened in
     110              :    read-only mode.  Otherwise it will be opened for modification.
     111              :    Return zero on failure, non-zero on success.  */
     112              : 
     113              : GCOV_LINKAGE int
     114          606 : gcov_open (const char *name, int mode)
     115              : {
     116              : #if GCOV_LOCKED
     117          606 :   struct flock s_flock;
     118          606 :   int fd;
     119              : 
     120          606 :   s_flock.l_whence = SEEK_SET;
     121          606 :   s_flock.l_start = 0;
     122          606 :   s_flock.l_len = 0; /* Until EOF.  */
     123          606 :   s_flock.l_pid = getpid ();
     124              : #elif GCOV_LOCKED_WITH_LOCKING
     125              :   int fd;
     126              : #endif
     127              : 
     128          606 :   gcov_nonruntime_assert (!gcov_var.file);
     129          606 :   gcov_var.error = GCOV_FILE_NO_ERROR;
     130              : #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
     131          606 :   gcov_var.endian = 0;
     132              : #endif
     133              : #ifdef IN_GCOV_TOOL
     134              :   gcov_var.pos = 0;
     135              :   if (!name)
     136              :     {
     137              :       gcov_nonruntime_assert (gcov_var.mode > 0);
     138              :       gcov_var.file = stdin;
     139              :       gcov_var.mode = GCOV_MODE_STDIN;
     140              :       return 1;
     141              :     }
     142              : #endif
     143              : #if GCOV_LOCKED
     144          606 :   if (mode > 0)
     145              :     {
     146              :       /* Read-only mode - acquire a read-lock.  */
     147          446 :       s_flock.l_type = F_RDLCK;
     148              :       /* pass mode (ignored) for compatibility */
     149          446 :       fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR);
     150              :     }
     151              :   else
     152              :      {
     153              :        /* Write mode - acquire a write-lock.  */
     154          160 :        s_flock.l_type = F_WRLCK;
     155              :        /* Truncate if force new mode.  */
     156          160 :        fd = open (name, O_RDWR | O_CREAT | (mode < 0 ? O_TRUNC : 0), 0666);
     157              :     }
     158          606 :   if (fd < 0)
     159              :     return 0;
     160              : 
     161          544 :   while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
     162            0 :     continue;
     163              : 
     164          704 :   gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
     165              : 
     166          544 :   if (!gcov_var.file)
     167              :     {
     168            0 :       close (fd);
     169            0 :       return 0;
     170              :     }
     171              : #elif GCOV_LOCKED_WITH_LOCKING
     172              :   if (mode > 0)
     173              :     {
     174              :       /* pass mode (ignored) for compatibility */
     175              :       fd = open (name, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
     176              :     }
     177              :   else
     178              :      {
     179              :        /* Truncate if force new mode.  */
     180              :        fd = open (name, O_RDWR | O_BINARY | O_CREAT | (mode < 0 ? O_TRUNC : 0),
     181              :                   0666);
     182              :     }
     183              :   if (fd < 0)
     184              :     return 0;
     185              : 
     186              :   if (_locking (fd, _LK_LOCK, LONG_MAX) < 0)
     187              :     {
     188              :       close (fd);
     189              :       return 0;
     190              :     }
     191              : 
     192              :   gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
     193              : 
     194              :   if (!gcov_var.file)
     195              :     {
     196              :       close (fd);
     197              :       return 0;
     198              :     }
     199              : #else
     200              :   if (mode >= 0)
     201              :     /* Open an existing file.  */
     202              :     gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
     203              : 
     204              :   if (gcov_var.file)
     205              :     mode = 1;
     206              :   else if (mode <= 0)
     207              :     /* Create a new file.  */
     208              :     gcov_var.file = fopen (name, "w+b");
     209              : 
     210              :   if (!gcov_var.file)
     211              :     return 0;
     212              : #endif
     213              : 
     214          544 :   gcov_var.mode = mode ? mode : 1;
     215              : 
     216          544 :   return 1;
     217            0 : }
     218              : 
     219              : /* Close the current gcov file. Flushes data to disk. Returns nonzero
     220              :    on failure or error flag set.  */
     221              : 
     222              : GCOV_LINKAGE int
     223          544 : gcov_close (void)
     224              : {
     225              : #ifdef IN_GCOV_TOOL
     226              :   if (gcov_var.file == stdin)
     227              :     gcov_var.file = 0;
     228              :   else
     229              : #endif
     230          544 :   if (gcov_var.file)
     231              :     {
     232          544 :       if (fclose (gcov_var.file))
     233            0 :         gcov_var.error = GCOV_FILE_WRITE_ERROR;
     234              : 
     235          544 :       gcov_var.file = 0;
     236              :     }
     237          544 :   gcov_var.mode = 0;
     238          544 :   return gcov_var.error;
     239              : }
     240              : 
     241              : #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
     242              : /* Check if MAGIC is EXPECTED. Use it to determine endianness of the
     243              :    file. Returns +1 for same endian, -1 for other endian and zero for
     244              :    not EXPECTED.  */
     245              : 
     246              : GCOV_LINKAGE int
     247          384 : gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
     248              : {
     249          384 :   if (magic == expected)
     250              :     return 1;
     251              : 
     252            0 :   if (__builtin_bswap32 (magic) == expected)
     253              :     {
     254            0 :       gcov_var.endian = 1;
     255            0 :       return -1;
     256              :     }
     257              :   return 0;
     258              : }
     259              : #endif
     260              : 
     261              : #if !IN_GCOV
     262              : /* Write DATA of LENGTH characters to coverage file.  */
     263              : 
     264              : GCOV_LINKAGE void
     265            0 : gcov_write (const void *data, unsigned length)
     266              : {
     267            0 :   gcov_unsigned_t r = fwrite (data, length, 1, gcov_var.file);
     268            0 :   if (r != 1)
     269            0 :     gcov_var.error = GCOV_FILE_WRITE_ERROR;
     270            0 : }
     271              : 
     272              : /* Write unsigned VALUE to coverage file.  */
     273              : 
     274              : GCOV_LINKAGE void
     275       136550 : gcov_write_unsigned (gcov_unsigned_t value)
     276              : {
     277       136550 :   gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file);
     278       136550 :   if (r != 1)
     279            0 :     gcov_var.error = GCOV_FILE_WRITE_ERROR;
     280       136550 : }
     281              : 
     282              : #if !IN_LIBGCOV
     283              : /* Write STRING to coverage file.  Sets error flag on file
     284              :    error, overflow flag on overflow */
     285              : 
     286              : GCOV_LINKAGE void
     287        15217 : gcov_write_string (const char *string)
     288              : {
     289        15217 :   unsigned length = 0;
     290              : 
     291        15217 :   if (string)
     292         8804 :     length = strlen (string) + 1;
     293              : 
     294        15217 :   gcov_write_unsigned (length);
     295        15217 :   if (length > 0)
     296              :     {
     297         8804 :       gcov_unsigned_t r = fwrite (string, length, 1, gcov_var.file);
     298         8804 :       if (r != 1)
     299            0 :         gcov_var.error = GCOV_FILE_WRITE_ERROR;
     300              :     }
     301        15217 : }
     302              : #endif
     303              : 
     304              : #if !IN_LIBGCOV
     305              : /* Write FILENAME to coverage file.  Sets error flag on file
     306              :    error, overflow flag on overflow */
     307              : 
     308              : GCOV_LINKAGE void
     309         7568 : gcov_write_filename (const char *filename)
     310              : {
     311         7568 :   if (profile_abs_path_flag && filename && filename[0]
     312            8 :       && !(IS_DIR_SEPARATOR (filename[0])
     313              : #if HAVE_DOS_BASED_FILE_SYSTEM
     314              :            || filename[1] == ':'
     315              : #endif
     316              :           ))
     317              :     {
     318            0 :       char *buf = getcwd (NULL, 0);
     319            0 :       if (buf != NULL && buf[0])
     320              :         {
     321            0 :           size_t len = strlen (buf);
     322            0 :           buf = (char*)xrealloc (buf, len + strlen (filename) + 2);
     323            0 :           if (!IS_DIR_SEPARATOR (buf[len - 1]))
     324            0 :             strcat (buf, "/");
     325            0 :           strcat (buf, filename);
     326            0 :           gcov_write_string (buf);
     327            0 :           free (buf);
     328            0 :           return;
     329              :         }
     330              :     }
     331              : 
     332         7568 :   gcov_write_string (filename);
     333              : }
     334              : 
     335              : /* Move to a given position in a gcov file.  */
     336              : 
     337              : static void
     338        33840 : gcov_seek (gcov_position_t base)
     339              : {
     340            0 :   fseek (gcov_var.file, base, SEEK_SET);
     341            0 : }
     342              : 
     343              : /* Write a tag TAG and reserve space for the record length. Return a
     344              :    value to be used for gcov_write_length.  */
     345              : 
     346              : GCOV_LINKAGE gcov_position_t
     347        16920 : gcov_write_tag (gcov_unsigned_t tag)
     348              : {
     349        16920 :   gcov_position_t result = gcov_position ();
     350        16920 :   gcov_write_unsigned (tag);
     351        16920 :   gcov_write_unsigned (0);
     352              : 
     353        16920 :   return result;
     354              : }
     355              : 
     356              : /* Write a record length using POSITION, which was returned by
     357              :    gcov_write_tag.  The current file position is the end of the
     358              :    record, and is restored before returning.  Returns nonzero on
     359              :    overflow.  */
     360              : 
     361              : GCOV_LINKAGE void
     362        16920 : gcov_write_length (gcov_position_t position)
     363              : {
     364        16920 :   gcov_position_t current_position = gcov_position ();
     365        16920 :   gcov_nonruntime_assert (gcov_var.mode < 0);
     366        16920 :   gcov_nonruntime_assert (current_position >= position + 2 * GCOV_WORD_SIZE);
     367              : 
     368        16920 :   gcov_seek (position + GCOV_WORD_SIZE);
     369        16920 :   gcov_write_unsigned (current_position - position - 2 * GCOV_WORD_SIZE);
     370        16920 :   gcov_seek (current_position);
     371        16920 : }
     372              : 
     373              : #else /* IN_LIBGCOV */
     374              : 
     375              : /* Write an object summary structure to the gcov file.  */
     376              : 
     377              : GCOV_LINKAGE void
     378              : gcov_write_object_summary (const struct gcov_summary *summary)
     379              : {
     380              :   gcov_write_unsigned (GCOV_TAG_OBJECT_SUMMARY);
     381              :   gcov_write_unsigned (GCOV_TAG_OBJECT_SUMMARY_LENGTH);
     382              :   gcov_write_unsigned (summary->runs);
     383              :   gcov_write_unsigned (summary->sum_max);
     384              : }
     385              : 
     386              : #endif /* IN_LIBGCOV */
     387              : 
     388              : #endif /*!IN_GCOV */
     389              : 
     390              : /* Return a pointer to read COUNT bytes from the gcov file.  Returns
     391              :    NULL on failure (read past EOF).  */
     392              : 
     393              : static void *
     394       143017 : gcov_read_bytes (void *buffer, unsigned count)
     395              : {
     396       143017 :   if (gcov_var.mode <= 0)
     397              :     return NULL;
     398              : 
     399       143017 :   unsigned read = fread (buffer, count, 1, gcov_var.file);
     400       143017 :   if (read != 1)
     401              :     {
     402          140 :       if (feof (gcov_var.file))
     403          140 :         gcov_var.error = GCOV_FILE_EOF;
     404          140 :       return NULL;
     405              :     }
     406              : 
     407              : #ifdef IN_GCOV_TOOL
     408              :   gcov_var.pos += count;
     409              : #endif
     410              :   return buffer;
     411              : }
     412              : 
     413              : /* Read WORDS gcov_unsigned_t values from gcov file.  */
     414              : 
     415              : static gcov_unsigned_t *
     416       134511 : gcov_read_words (void *buffer, unsigned words)
     417              : {
     418            0 :   return (gcov_unsigned_t *)gcov_read_bytes (buffer, GCOV_WORD_SIZE * words);
     419              : }
     420              : 
     421              : /* Read unsigned value from a coverage file. Sets error flag on file
     422              :    error, overflow flag on overflow */
     423              : 
     424              : GCOV_LINKAGE gcov_unsigned_t
     425       129140 : gcov_read_unsigned (void)
     426              : {
     427       129140 :   gcov_unsigned_t value;
     428       129140 :   gcov_unsigned_t allocated_buffer[1];
     429       129140 :   gcov_unsigned_t *buffer = gcov_read_words (&allocated_buffer, 1);
     430              : 
     431       129140 :   if (!buffer)
     432              :     return 0;
     433              : 
     434       129000 :   value = from_file (buffer[0]);
     435              :   return value;
     436              : }
     437              : 
     438              : /* Read counter value from a coverage file. Sets error flag on file
     439              :    error, overflow flag on overflow */
     440              : 
     441              : GCOV_LINKAGE gcov_type
     442         5371 : gcov_read_counter (void)
     443              : {
     444         5371 :   gcov_type value;
     445         5371 :   gcov_unsigned_t allocated_buffer[2];
     446         5371 :   gcov_unsigned_t *buffer = gcov_read_words (&allocated_buffer, 2);
     447              : 
     448         5371 :   if (!buffer)
     449              :     return 0;
     450         5371 :   value = from_file (buffer[0]);
     451         5371 :   if (sizeof (value) > sizeof (gcov_unsigned_t))
     452         5371 :     value |= ((gcov_type) from_file (buffer[1])) << 32;
     453              :   else if (buffer[1])
     454              :     gcov_var.error = GCOV_FILE_COUNTER_OVERFLOW;
     455              : 
     456         5371 :   return value;
     457              : }
     458              : 
     459              : /* Mangle filename path of BASE and output new allocated pointer with
     460              :    mangled path.  */
     461              : 
     462              : char *
     463            3 : mangle_path (char const *base)
     464              : {
     465              :   /* Convert '/' to '#', convert '..' to '^',
     466              :      convert ':' to '~' on DOS based file system.  */
     467            3 :   const char *probe;
     468            3 :   char *buffer = (char *)xmalloc (strlen (base) + 1);
     469            3 :   char *ptr = buffer;
     470              : 
     471              : #if HAVE_DOS_BASED_FILE_SYSTEM
     472              :   if (base[0] && base[1] == ':')
     473              :     {
     474              :       ptr[0] = base[0];
     475              :       ptr[1] = '~';
     476              :       ptr += 2;
     477              :       base += 2;
     478              :     }
     479              : #endif
     480           36 :   for (; *base; base = probe)
     481              :     {
     482              :       size_t len;
     483              : 
     484          209 :       for (probe = base; *probe; probe++)
     485          206 :         if (*probe == '/')
     486              :           break;
     487           30 :       len = probe - base;
     488           30 :       if (len == 2 && base[0] == '.' && base[1] == '.')
     489            0 :         *ptr++ = '^';
     490              :       else
     491              :         {
     492           30 :           memcpy (ptr, base, len);
     493           30 :           ptr += len;
     494              :         }
     495           30 :       if (*probe)
     496              :         {
     497           27 :           *ptr++ = '#';
     498           27 :           probe++;
     499              :         }
     500              :     }
     501              : 
     502              :   /* Terminate the string.  */
     503            3 :   *ptr = '\0';
     504              : 
     505            3 :   return buffer;
     506              : }
     507              : 
     508              : /* We need to expose the below function when compiling for gcov-tool.  */
     509              : 
     510              : #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
     511              : /* Read string from coverage file.  Allocate the buffer for the string
     512              :    from the heap or die.  Return a pointer to the string, or NULL on
     513              :    empty string.  */
     514              : 
     515              : GCOV_LINKAGE const char *
     516        14729 : gcov_read_string (void)
     517              : {
     518        14729 :   unsigned length = gcov_read_unsigned ();
     519              : 
     520        14729 :   if (!length)
     521              :     return 0;
     522              : 
     523         8506 :   void *buffer = XNEWVEC (char *, length);
     524         8506 :   return (const char *) gcov_read_bytes (buffer, length);
     525              : }
     526              : #endif
     527              : 
     528              : GCOV_LINKAGE void
     529          129 : gcov_read_summary (struct gcov_summary *summary)
     530              : {
     531          129 :   summary->runs = gcov_read_unsigned ();
     532          129 :   summary->sum_max = gcov_read_unsigned ();
     533          129 : }
     534              : 
     535              : /* We need to expose the below function when compiling for gcov-tool.  */
     536              : 
     537              : #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
     538              : /* Reset to a known position.  BASE should have been obtained from
     539              :    gcov_position, LENGTH should be a record length.  */
     540              : 
     541              : GCOV_LINKAGE void
     542        20163 : gcov_sync (gcov_position_t base, gcov_unsigned_t length)
     543              : {
     544        20163 :   gcov_nonruntime_assert (gcov_var.mode > 0);
     545        20163 :   base += length;
     546              : #ifdef IN_GCOV_TOOL
     547              :   if (gcov_var.mode == GCOV_MODE_STDIN)
     548              :     {
     549              :       while (gcov_var.pos < base)
     550              :         {
     551              :           ++gcov_var.pos;
     552              :           (void)fgetc (gcov_var.file);
     553              :         }
     554              :       return;
     555              :     }
     556              : #endif
     557        20163 :   fseek (gcov_var.file, base, SEEK_SET);
     558        20163 : }
     559              : #endif
     560              : 
     561              : #if IN_GCOV > 0
     562              : /* Return the modification time of the current gcov file.  */
     563              : 
     564              : GCOV_LINKAGE time_t
     565          140 : gcov_time (void)
     566              : {
     567          140 :   struct stat status;
     568              : 
     569          140 :   if (fstat (fileno (gcov_var.file), &status))
     570              :     return 0;
     571              :   else
     572          140 :     return status.st_mtime;
     573              : }
     574              : #endif /* IN_GCOV */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.