]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov-io.c
Adjust by-value function vec arguments to by-reference.
[thirdparty/gcc.git] / gcc / gcov-io.c
CommitLineData
ca29da43 1/* File format for coverage information
99dee823 2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
ca29da43
NS
3 Contributed by Bob Manson <manson@cygnus.com>.
4 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
9dcd6f09 10Software Foundation; either version 3, or (at your option) any later
ca29da43
NS
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
ad01c437
JM
18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
9dcd6f09 25<http://www.gnu.org/licenses/>. */
ca29da43
NS
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
23eb66d1 30static gcov_unsigned_t *gcov_read_words (void *buffer, unsigned);
40d6b753 31
88d67744 32struct gcov_var
40d6b753
RX
33{
34 FILE *file;
40d6b753 35 int error; /* < 0 overflow, > 0 disk error. */
23eb66d1 36 int mode; /* < 0 writing, > 0 reading. */
17d1594b 37 int endian; /* Swap endianness. */
40d6b753
RX
38} gcov_var;
39
40/* Save the current position in the gcov file. */
c77556a5
RX
41/* We need to expose this function when compiling for gcov-tool. */
42#ifndef IN_GCOV_TOOL
43static inline
44#endif
45gcov_position_t
40d6b753
RX
46gcov_position (void)
47{
23eb66d1 48 return ftell (gcov_var.file);
40d6b753
RX
49}
50
51/* Return nonzero if the error flag is set. */
c77556a5
RX
52/* We need to expose this function when compiling for gcov-tool. */
53#ifndef IN_GCOV_TOOL
54static inline
55#endif
56int
40d6b753
RX
57gcov_is_error (void)
58{
59 return gcov_var.file ? gcov_var.error : 1;
60}
61
62#if IN_LIBGCOV
63/* Move to beginning of file and initialize for writing. */
64GCOV_LINKAGE inline void
65gcov_rewrite (void)
66{
40d6b753 67 gcov_var.mode = -1;
40d6b753
RX
68 fseek (gcov_var.file, 0L, SEEK_SET);
69}
70#endif
71
23eb66d1 72static inline gcov_unsigned_t
73from_file (gcov_unsigned_t value)
160e2e4f 74{
17d1594b 75#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
160e2e4f 76 if (gcov_var.endian)
23eb66d1 77 return __builtin_bswap32 (value);
160e2e4f
NS
78#endif
79 return value;
80}
81
ca29da43
NS
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
ad467730
NV
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
fc0911e0 87 creating a new one. If MODE > 0, the file will be opened in
ad467730 88 read-only mode. Otherwise it will be opened for modification.
fc0911e0 89 Return zero on failure, non-zero on success. */
ca29da43
NS
90
91GCOV_LINKAGE int
160e2e4f
NS
92#if IN_LIBGCOV
93gcov_open (const char *name)
94#else
ca29da43 95gcov_open (const char *name, int mode)
160e2e4f 96#endif
ca29da43 97{
160e2e4f 98#if IN_LIBGCOV
74d2b907 99 int mode = 0;
160e2e4f 100#endif
474f141e 101#if GCOV_LOCKED
ca29da43 102 struct flock s_flock;
c2cd64b5 103 int fd;
ca29da43 104
ca29da43
NS
105 s_flock.l_whence = SEEK_SET;
106 s_flock.l_start = 0;
107 s_flock.l_len = 0; /* Until EOF. */
108 s_flock.l_pid = getpid ();
9ec469f5
EB
109#elif GCOV_LOCKED_WITH_LOCKING
110 int fd;
ca29da43 111#endif
b8698a0f 112
e3f0315f 113 gcov_nonruntime_assert (!gcov_var.file);
7d63a2fa 114 gcov_var.error = 0;
de8bfcc8 115#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
160e2e4f
NS
116 gcov_var.endian = 0;
117#endif
c2cd64b5
JJ
118#if GCOV_LOCKED
119 if (mode > 0)
ad467730
NV
120 {
121 /* Read-only mode - acquire a read-lock. */
122 s_flock.l_type = F_RDLCK;
2588b26e
RM
123 /* pass mode (ignored) for compatibility */
124 fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR);
ad467730 125 }
fc0911e0 126 else
55428cc3
LA
127 {
128 /* Write mode - acquire a write-lock. */
129 s_flock.l_type = F_WRLCK;
fc0911e0
NS
130 /* Truncate if force new mode. */
131 fd = open (name, O_RDWR | O_CREAT | (mode < 0 ? O_TRUNC : 0), 0666);
ad467730 132 }
c2cd64b5
JJ
133 if (fd < 0)
134 return 0;
135
136 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
137 continue;
138
ad467730
NV
139 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
140
9ec469f5
EB
141 if (!gcov_var.file)
142 {
143 close (fd);
144 return 0;
145 }
146#elif GCOV_LOCKED_WITH_LOCKING
147 if (mode > 0)
148 {
149 /* pass mode (ignored) for compatibility */
150 fd = open (name, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
151 }
152 else
153 {
154 /* Truncate if force new mode. */
155 fd = open (name, O_RDWR | O_BINARY | O_CREAT | (mode < 0 ? O_TRUNC : 0),
156 0666);
157 }
158 if (fd < 0)
159 return 0;
160
161 if (_locking (fd, _LK_LOCK, LONG_MAX) < 0)
162 {
163 close (fd);
164 return 0;
165 }
166
167 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
168
c2cd64b5
JJ
169 if (!gcov_var.file)
170 {
171 close (fd);
172 return 0;
173 }
c2cd64b5 174#else
ca29da43 175 if (mode >= 0)
fc0911e0 176 /* Open an existing file. */
ad467730
NV
177 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
178
7d63a2fa 179 if (gcov_var.file)
fc0911e0 180 mode = 1;
7d63a2fa 181 else if (mode <= 0)
fc0911e0
NS
182 /* Create a new file. */
183 gcov_var.file = fopen (name, "w+b");
184
ca29da43
NS
185 if (!gcov_var.file)
186 return 0;
ca29da43
NS
187#endif
188
fc0911e0
NS
189 gcov_var.mode = mode ? mode : 1;
190
160e2e4f 191 return 1;
ca29da43
NS
192}
193
194/* Close the current gcov file. Flushes data to disk. Returns nonzero
195 on failure or error flag set. */
196
197GCOV_LINKAGE int
82a30d6f 198gcov_close (void)
ca29da43 199{
ca29da43
NS
200 if (gcov_var.file)
201 {
929f2cf4
VL
202 if (fclose (gcov_var.file))
203 gcov_var.error = 1;
204
ca29da43 205 gcov_var.file = 0;
ca29da43 206 }
7d63a2fa
NS
207 gcov_var.mode = 0;
208 return gcov_var.error;
209}
210
17d1594b 211#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
160e2e4f
NS
212/* Check if MAGIC is EXPECTED. Use it to determine endianness of the
213 file. Returns +1 for same endian, -1 for other endian and zero for
214 not EXPECTED. */
215
216GCOV_LINKAGE int
217gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
218{
219 if (magic == expected)
220 return 1;
23eb66d1 221
222 if (__builtin_bswap32 (magic) == expected)
160e2e4f
NS
223 {
224 gcov_var.endian = 1;
225 return -1;
226 }
227 return 0;
228}
229#endif
230
ca29da43 231#if !IN_GCOV
23eb66d1 232/* Write unsigned VALUE to coverage file. */
ca29da43
NS
233
234GCOV_LINKAGE void
9b514d25 235gcov_write_unsigned (gcov_unsigned_t value)
ca29da43 236{
23eb66d1 237 gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file);
238 if (r != 1)
239 gcov_var.error = 1;
ca29da43
NS
240}
241
242/* Write counter VALUE to coverage file. Sets error flag
243 appropriately. */
244
245#if IN_LIBGCOV
246GCOV_LINKAGE void
247gcov_write_counter (gcov_type value)
248{
23eb66d1 249 gcov_write_unsigned ((gcov_unsigned_t) value);
160e2e4f 250 if (sizeof (value) > sizeof (gcov_unsigned_t))
23eb66d1 251 gcov_write_unsigned ((gcov_unsigned_t) (value >> 32));
160e2e4f 252 else
23eb66d1 253 gcov_write_unsigned (0);
ca29da43
NS
254}
255#endif /* IN_LIBGCOV */
256
796621e8 257#if !IN_LIBGCOV
ca29da43
NS
258/* Write STRING to coverage file. Sets error flag on file
259 error, overflow flag on overflow */
260
261GCOV_LINKAGE void
262gcov_write_string (const char *string)
263{
264 unsigned length = 0;
ca29da43
NS
265
266 if (string)
23eb66d1 267 length = strlen (string) + 1;
7d63a2fa 268
23eb66d1 269 gcov_write_unsigned (length);
270 if (length > 0)
0040ecb0 271 {
23eb66d1 272 gcov_unsigned_t r = fwrite (string, length, 1, gcov_var.file);
273 if (r != 1)
274 gcov_var.error = 1;
0040ecb0 275 }
ca29da43 276}
796621e8 277#endif
ca29da43 278
676519f7
BE
279#if !IN_LIBGCOV
280/* Write FILENAME to coverage file. Sets error flag on file
281 error, overflow flag on overflow */
282
283GCOV_LINKAGE void
284gcov_write_filename (const char *filename)
285{
286 if (profile_abs_path_flag && filename && filename[0]
287 && !(IS_DIR_SEPARATOR (filename[0])
288#if HAVE_DOS_BASED_FILE_SYSTEM
289 || filename[1] == ':'
290#endif
291 ))
292 {
293 char *buf = getcwd (NULL, 0);
294 if (buf != NULL && buf[0])
295 {
296 size_t len = strlen (buf);
297 buf = (char*)xrealloc (buf, len + strlen (filename) + 2);
298 if (!IS_DIR_SEPARATOR (buf[len - 1]))
299 strcat (buf, "/");
300 strcat (buf, filename);
301 gcov_write_string (buf);
302 free (buf);
303 return;
304 }
305 }
306
307 gcov_write_string (filename);
308}
309#endif
310
23eb66d1 311/* Move to a given position in a gcov file. */
312
313GCOV_LINKAGE void
314gcov_seek (gcov_position_t base)
315{
316 fseek (gcov_var.file, base, SEEK_SET);
317}
318
474f141e 319#if !IN_LIBGCOV
ca29da43
NS
320/* Write a tag TAG and reserve space for the record length. Return a
321 value to be used for gcov_write_length. */
322
9b514d25
NS
323GCOV_LINKAGE gcov_position_t
324gcov_write_tag (gcov_unsigned_t tag)
ca29da43 325{
23eb66d1 326 gcov_position_t result = gcov_position ();
327 gcov_write_unsigned (tag);
328 gcov_write_unsigned (0);
b8698a0f 329
ca29da43
NS
330 return result;
331}
332
333/* Write a record length using POSITION, which was returned by
334 gcov_write_tag. The current file position is the end of the
335 record, and is restored before returning. Returns nonzero on
336 overflow. */
337
338GCOV_LINKAGE void
9b514d25 339gcov_write_length (gcov_position_t position)
ca29da43 340{
23eb66d1 341 gcov_position_t current_position = gcov_position ();
e3f0315f 342 gcov_nonruntime_assert (gcov_var.mode < 0);
23eb66d1 343 gcov_nonruntime_assert (current_position >= position + 2 * GCOV_WORD_SIZE);
344
345 gcov_seek (position + GCOV_WORD_SIZE);
346 gcov_write_unsigned (current_position - position - 2 * GCOV_WORD_SIZE);
347 gcov_seek (current_position);
ca29da43 348}
9b514d25
NS
349
350#else /* IN_LIBGCOV */
474f141e
NS
351
352/* Write a tag TAG and length LENGTH. */
353
354GCOV_LINKAGE void
9b514d25 355gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
474f141e 356{
23eb66d1 357 gcov_write_unsigned (tag);
358 gcov_write_unsigned (length);
474f141e 359}
ca29da43 360
6356f892 361/* Write a summary structure to the gcov file. Return nonzero on
ca29da43
NS
362 overflow. */
363
364GCOV_LINKAGE void
9b514d25 365gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
ca29da43 366{
512cc015 367 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
7f3577f5 368 gcov_write_unsigned (summary->runs);
512cc015 369 gcov_write_unsigned (summary->sum_max);
ca29da43 370}
512cc015 371
ca29da43
NS
372#endif /* IN_LIBGCOV */
373
374#endif /*!IN_GCOV */
375
23eb66d1 376/* Return a pointer to read COUNT bytes from the gcov file. Returns
71c0e7fc 377 NULL on failure (read past EOF). */
ca29da43 378
23eb66d1 379static void *
380gcov_read_bytes (void *buffer, unsigned count)
ca29da43 381{
1bba63a7
AK
382 if (gcov_var.mode <= 0)
383 return NULL;
384
23eb66d1 385 unsigned read = fread (buffer, count, 1, gcov_var.file);
386 if (read != 1)
387 return NULL;
388
389 return buffer;
390}
391
392/* Read WORDS gcov_unsigned_t values from gcov file. */
393
394static gcov_unsigned_t *
395gcov_read_words (void *buffer, unsigned words)
396{
397 return (gcov_unsigned_t *)gcov_read_bytes (buffer, GCOV_WORD_SIZE * words);
ca29da43
NS
398}
399
400/* Read unsigned value from a coverage file. Sets error flag on file
401 error, overflow flag on overflow */
402
9b514d25 403GCOV_LINKAGE gcov_unsigned_t
82a30d6f 404gcov_read_unsigned (void)
ca29da43 405{
160e2e4f 406 gcov_unsigned_t value;
23eb66d1 407 gcov_unsigned_t allocated_buffer[1];
408 gcov_unsigned_t *buffer = gcov_read_words (&allocated_buffer, 1);
ca29da43
NS
409
410 if (!buffer)
411 return 0;
23eb66d1 412
160e2e4f 413 value = from_file (buffer[0]);
ca29da43
NS
414 return value;
415}
416
417/* Read counter value from a coverage file. Sets error flag on file
418 error, overflow flag on overflow */
419
420GCOV_LINKAGE gcov_type
82a30d6f 421gcov_read_counter (void)
ca29da43 422{
160e2e4f 423 gcov_type value;
23eb66d1 424 gcov_unsigned_t allocated_buffer[2];
425 gcov_unsigned_t *buffer = gcov_read_words (&allocated_buffer, 2);
ca29da43
NS
426
427 if (!buffer)
428 return 0;
160e2e4f
NS
429 value = from_file (buffer[0]);
430 if (sizeof (value) > sizeof (gcov_unsigned_t))
431 value |= ((gcov_type) from_file (buffer[1])) << 32;
432 else if (buffer[1])
433 gcov_var.error = -1;
6d9901e7 434
ca29da43
NS
435 return value;
436}
437
1f2bb38a
ML
438/* Mangle filename path of BASE and output new allocated pointer with
439 mangled path. */
440
441char *
442mangle_path (char const *base)
443{
444 /* Convert '/' to '#', convert '..' to '^',
445 convert ':' to '~' on DOS based file system. */
446 const char *probe;
12502bf2 447 char *buffer = (char *)xmalloc (strlen (base) + 1);
1f2bb38a
ML
448 char *ptr = buffer;
449
450#if HAVE_DOS_BASED_FILE_SYSTEM
451 if (base[0] && base[1] == ':')
452 {
453 ptr[0] = base[0];
454 ptr[1] = '~';
455 ptr += 2;
456 base += 2;
457 }
458#endif
459 for (; *base; base = probe)
460 {
461 size_t len;
462
463 for (probe = base; *probe; probe++)
464 if (*probe == '/')
465 break;
466 len = probe - base;
467 if (len == 2 && base[0] == '.' && base[1] == '.')
468 *ptr++ = '^';
469 else
470 {
471 memcpy (ptr, base, len);
472 ptr += len;
473 }
474 if (*probe)
475 {
476 *ptr++ = '#';
477 probe++;
478 }
479 }
480
481 /* Terminate the string. */
482 *ptr = '\0';
483
484 return buffer;
485}
486
c77556a5
RX
487/* We need to expose the below function when compiling for gcov-tool. */
488
489#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
ca29da43
NS
490/* Read string from coverage file. Returns a pointer to a static
491 buffer, or NULL on empty string. You must copy the string before
492 calling another gcov function. */
493
494GCOV_LINKAGE const char *
82a30d6f 495gcov_read_string (void)
ca29da43
NS
496{
497 unsigned length = gcov_read_unsigned ();
b8698a0f 498
ca29da43
NS
499 if (!length)
500 return 0;
501
23eb66d1 502 void *buffer = XNEWVEC (char *, length);
503 return (const char *) gcov_read_bytes (buffer, length);
ca29da43 504}
796621e8 505#endif
ca29da43
NS
506
507GCOV_LINKAGE void
508gcov_read_summary (struct gcov_summary *summary)
509{
7f3577f5 510 summary->runs = gcov_read_unsigned ();
512cc015 511 summary->sum_max = gcov_read_unsigned ();
ca29da43
NS
512}
513
c77556a5
RX
514/* We need to expose the below function when compiling for gcov-tool. */
515
516#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
7d63a2fa
NS
517/* Reset to a known position. BASE should have been obtained from
518 gcov_position, LENGTH should be a record length. */
519
520GCOV_LINKAGE void
521gcov_sync (gcov_position_t base, gcov_unsigned_t length)
522{
e3f0315f 523 gcov_nonruntime_assert (gcov_var.mode > 0);
7d63a2fa 524 base += length;
23eb66d1 525 fseek (gcov_var.file, base, SEEK_SET);
7d63a2fa
NS
526}
527#endif
528
ca29da43
NS
529#if IN_GCOV > 0
530/* Return the modification time of the current gcov file. */
531
532GCOV_LINKAGE time_t
82a30d6f 533gcov_time (void)
ca29da43
NS
534{
535 struct stat status;
b8698a0f 536
ca29da43
NS
537 if (fstat (fileno (gcov_var.file), &status))
538 return 0;
539 else
540 return status.st_mtime;
541}
542#endif /* IN_GCOV */