]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov-io.c
c++: Handle multiple aggregate overloads [PR95319].
[thirdparty/gcc.git] / gcc / gcov-io.c
CommitLineData
ca29da43 1/* File format for coverage information
8d9254fc 2 Copyright (C) 1996-2020 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
7d63a2fa
NS
30#if !IN_GCOV
31static void gcov_write_block (unsigned);
330d2e2a 32static gcov_unsigned_t *gcov_write_words (unsigned);
7d63a2fa 33#endif
330d2e2a 34static const gcov_unsigned_t *gcov_read_words (unsigned);
7d63a2fa
NS
35#if !IN_LIBGCOV
36static void gcov_allocate (unsigned);
37#endif
38
40d6b753
RX
39/* Optimum number of gcov_unsigned_t's read from or written to disk. */
40#define GCOV_BLOCK_SIZE (1 << 10)
41
88d67744 42struct gcov_var
40d6b753
RX
43{
44 FILE *file;
45 gcov_position_t start; /* Position of first byte of block */
46 unsigned offset; /* Read/write position within the block. */
47 unsigned length; /* Read limit in the block. */
48 unsigned overread; /* Number of words overread. */
49 int error; /* < 0 overflow, > 0 disk error. */
50 int mode; /* < 0 writing, > 0 reading */
51#if IN_LIBGCOV
52 /* Holds one block plus 4 bytes, thus all coverage reads & writes
53 fit within this buffer and we always can transfer GCOV_BLOCK_SIZE
54 to and from the disk. libgcov never backtracks and only writes 4
55 or 8 byte objects. */
56 gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1];
57#else
58 int endian; /* Swap endianness. */
59 /* Holds a variable length block, as the compiler can write
60 strings and needs to backtrack. */
61 size_t alloc;
62 gcov_unsigned_t *buffer;
63#endif
64} gcov_var;
65
66/* Save the current position in the gcov file. */
c77556a5
RX
67/* We need to expose this function when compiling for gcov-tool. */
68#ifndef IN_GCOV_TOOL
69static inline
70#endif
71gcov_position_t
40d6b753
RX
72gcov_position (void)
73{
e3f0315f 74 gcov_nonruntime_assert (gcov_var.mode > 0);
40d6b753
RX
75 return gcov_var.start + gcov_var.offset;
76}
77
78/* Return nonzero if the error flag is set. */
c77556a5
RX
79/* We need to expose this function when compiling for gcov-tool. */
80#ifndef IN_GCOV_TOOL
81static inline
82#endif
83int
40d6b753
RX
84gcov_is_error (void)
85{
86 return gcov_var.file ? gcov_var.error : 1;
87}
88
89#if IN_LIBGCOV
90/* Move to beginning of file and initialize for writing. */
91GCOV_LINKAGE inline void
92gcov_rewrite (void)
93{
40d6b753
RX
94 gcov_var.mode = -1;
95 gcov_var.start = 0;
96 gcov_var.offset = 0;
97 fseek (gcov_var.file, 0L, SEEK_SET);
98}
99#endif
100
160e2e4f
NS
101static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
102{
103#if !IN_LIBGCOV
104 if (gcov_var.endian)
105 {
106 value = (value >> 16) | (value << 16);
107 value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
108 }
109#endif
110 return value;
111}
112
ca29da43
NS
113/* Open a gcov file. NAME is the name of the file to open and MODE
114 indicates whether a new file should be created, or an existing file
ad467730
NV
115 opened. If MODE is >= 0 an existing file will be opened, if
116 possible, and if MODE is <= 0, a new file will be created. Use
117 MODE=0 to attempt to reopen an existing file and then fall back on
fc0911e0 118 creating a new one. If MODE > 0, the file will be opened in
ad467730 119 read-only mode. Otherwise it will be opened for modification.
fc0911e0 120 Return zero on failure, non-zero on success. */
ca29da43
NS
121
122GCOV_LINKAGE int
160e2e4f
NS
123#if IN_LIBGCOV
124gcov_open (const char *name)
125#else
ca29da43 126gcov_open (const char *name, int mode)
160e2e4f 127#endif
ca29da43 128{
160e2e4f 129#if IN_LIBGCOV
74d2b907 130 int mode = 0;
160e2e4f 131#endif
474f141e 132#if GCOV_LOCKED
ca29da43 133 struct flock s_flock;
c2cd64b5 134 int fd;
ca29da43 135
ca29da43
NS
136 s_flock.l_whence = SEEK_SET;
137 s_flock.l_start = 0;
138 s_flock.l_len = 0; /* Until EOF. */
139 s_flock.l_pid = getpid ();
140#endif
b8698a0f 141
e3f0315f 142 gcov_nonruntime_assert (!gcov_var.file);
7d63a2fa
NS
143 gcov_var.start = 0;
144 gcov_var.offset = gcov_var.length = 0;
330d2e2a 145 gcov_var.overread = -1u;
7d63a2fa 146 gcov_var.error = 0;
160e2e4f
NS
147#if !IN_LIBGCOV
148 gcov_var.endian = 0;
149#endif
c2cd64b5
JJ
150#if GCOV_LOCKED
151 if (mode > 0)
ad467730
NV
152 {
153 /* Read-only mode - acquire a read-lock. */
154 s_flock.l_type = F_RDLCK;
2588b26e
RM
155 /* pass mode (ignored) for compatibility */
156 fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR);
ad467730 157 }
fc0911e0 158 else
55428cc3
LA
159 {
160 /* Write mode - acquire a write-lock. */
161 s_flock.l_type = F_WRLCK;
fc0911e0
NS
162 /* Truncate if force new mode. */
163 fd = open (name, O_RDWR | O_CREAT | (mode < 0 ? O_TRUNC : 0), 0666);
ad467730 164 }
c2cd64b5
JJ
165 if (fd < 0)
166 return 0;
167
168 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
169 continue;
170
ad467730
NV
171 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
172
c2cd64b5
JJ
173 if (!gcov_var.file)
174 {
175 close (fd);
176 return 0;
177 }
c2cd64b5 178#else
ca29da43 179 if (mode >= 0)
fc0911e0 180 /* Open an existing file. */
ad467730
NV
181 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
182
7d63a2fa 183 if (gcov_var.file)
fc0911e0 184 mode = 1;
7d63a2fa 185 else if (mode <= 0)
fc0911e0
NS
186 /* Create a new file. */
187 gcov_var.file = fopen (name, "w+b");
188
ca29da43
NS
189 if (!gcov_var.file)
190 return 0;
ca29da43
NS
191#endif
192
fc0911e0
NS
193 gcov_var.mode = mode ? mode : 1;
194
c2cd64b5 195 setbuf (gcov_var.file, (char *)0);
b8698a0f 196
160e2e4f 197 return 1;
ca29da43
NS
198}
199
200/* Close the current gcov file. Flushes data to disk. Returns nonzero
201 on failure or error flag set. */
202
203GCOV_LINKAGE int
82a30d6f 204gcov_close (void)
ca29da43 205{
ca29da43
NS
206 if (gcov_var.file)
207 {
7d63a2fa
NS
208#if !IN_GCOV
209 if (gcov_var.offset && gcov_var.mode < 0)
210 gcov_write_block (gcov_var.offset);
211#endif
ca29da43
NS
212 fclose (gcov_var.file);
213 gcov_var.file = 0;
214 gcov_var.length = 0;
215 }
216#if !IN_LIBGCOV
217 free (gcov_var.buffer);
218 gcov_var.alloc = 0;
219 gcov_var.buffer = 0;
220#endif
7d63a2fa
NS
221 gcov_var.mode = 0;
222 return gcov_var.error;
223}
224
160e2e4f
NS
225#if !IN_LIBGCOV
226/* Check if MAGIC is EXPECTED. Use it to determine endianness of the
227 file. Returns +1 for same endian, -1 for other endian and zero for
228 not EXPECTED. */
229
230GCOV_LINKAGE int
231gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
232{
233 if (magic == expected)
234 return 1;
235 magic = (magic >> 16) | (magic << 16);
236 magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
237 if (magic == expected)
238 {
239 gcov_var.endian = 1;
240 return -1;
241 }
242 return 0;
243}
244#endif
245
7d63a2fa
NS
246#if !IN_LIBGCOV
247static void
248gcov_allocate (unsigned length)
249{
250 size_t new_size = gcov_var.alloc;
b8698a0f 251
7d63a2fa
NS
252 if (!new_size)
253 new_size = GCOV_BLOCK_SIZE;
254 new_size += length;
255 new_size *= 2;
b8698a0f 256
7d63a2fa 257 gcov_var.alloc = new_size;
1b4572a8 258 gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2);
ca29da43 259}
7d63a2fa 260#endif
ca29da43
NS
261
262#if !IN_GCOV
7d63a2fa
NS
263/* Write out the current block, if needs be. */
264
265static void
266gcov_write_block (unsigned size)
267{
330d2e2a 268 if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
7d63a2fa
NS
269 gcov_var.error = 1;
270 gcov_var.start += size;
271 gcov_var.offset -= size;
272}
273
ca29da43
NS
274/* Allocate space to write BYTES bytes to the gcov file. Return a
275 pointer to those bytes, or NULL on failure. */
276
160e2e4f 277static gcov_unsigned_t *
330d2e2a 278gcov_write_words (unsigned words)
ca29da43 279{
160e2e4f 280 gcov_unsigned_t *result;
ca29da43 281
e3f0315f 282 gcov_nonruntime_assert (gcov_var.mode < 0);
ca29da43 283#if IN_LIBGCOV
7d63a2fa
NS
284 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
285 {
286 gcov_write_block (GCOV_BLOCK_SIZE);
287 if (gcov_var.offset)
ca29da43 288 {
7d63a2fa 289 memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
ca29da43 290 }
7d63a2fa 291 }
ca29da43 292#else
330d2e2a
NS
293 if (gcov_var.offset + words > gcov_var.alloc)
294 gcov_allocate (gcov_var.offset + words);
ca29da43 295#endif
330d2e2a
NS
296 result = &gcov_var.buffer[gcov_var.offset];
297 gcov_var.offset += words;
b8698a0f 298
ca29da43
NS
299 return result;
300}
301
302/* Write unsigned VALUE to coverage file. Sets error flag
303 appropriately. */
304
305GCOV_LINKAGE void
9b514d25 306gcov_write_unsigned (gcov_unsigned_t value)
ca29da43 307{
330d2e2a 308 gcov_unsigned_t *buffer = gcov_write_words (1);
ca29da43 309
160e2e4f 310 buffer[0] = value;
ca29da43
NS
311}
312
313/* Write counter VALUE to coverage file. Sets error flag
314 appropriately. */
315
316#if IN_LIBGCOV
317GCOV_LINKAGE void
318gcov_write_counter (gcov_type value)
319{
330d2e2a 320 gcov_unsigned_t *buffer = gcov_write_words (2);
ca29da43 321
160e2e4f
NS
322 buffer[0] = (gcov_unsigned_t) value;
323 if (sizeof (value) > sizeof (gcov_unsigned_t))
324 buffer[1] = (gcov_unsigned_t) (value >> 32);
325 else
326 buffer[1] = 0;
ca29da43
NS
327}
328#endif /* IN_LIBGCOV */
329
796621e8 330#if !IN_LIBGCOV
ca29da43
NS
331/* Write STRING to coverage file. Sets error flag on file
332 error, overflow flag on overflow */
333
334GCOV_LINKAGE void
335gcov_write_string (const char *string)
336{
337 unsigned length = 0;
160e2e4f
NS
338 unsigned alloc = 0;
339 gcov_unsigned_t *buffer;
ca29da43
NS
340
341 if (string)
342 {
343 length = strlen (string);
160e2e4f 344 alloc = (length + 4) >> 2;
ca29da43 345 }
b8698a0f 346
330d2e2a 347 buffer = gcov_write_words (1 + alloc);
7d63a2fa 348
160e2e4f 349 buffer[0] = alloc;
0040ecb0
ML
350
351 if (alloc > 0)
352 {
353 buffer[alloc] = 0; /* place nul terminators. */
354 memcpy (&buffer[1], string, length);
355 }
ca29da43 356}
796621e8 357#endif
ca29da43 358
676519f7
BE
359#if !IN_LIBGCOV
360/* Write FILENAME to coverage file. Sets error flag on file
361 error, overflow flag on overflow */
362
363GCOV_LINKAGE void
364gcov_write_filename (const char *filename)
365{
366 if (profile_abs_path_flag && filename && filename[0]
367 && !(IS_DIR_SEPARATOR (filename[0])
368#if HAVE_DOS_BASED_FILE_SYSTEM
369 || filename[1] == ':'
370#endif
371 ))
372 {
373 char *buf = getcwd (NULL, 0);
374 if (buf != NULL && buf[0])
375 {
376 size_t len = strlen (buf);
377 buf = (char*)xrealloc (buf, len + strlen (filename) + 2);
378 if (!IS_DIR_SEPARATOR (buf[len - 1]))
379 strcat (buf, "/");
380 strcat (buf, filename);
381 gcov_write_string (buf);
382 free (buf);
383 return;
384 }
385 }
386
387 gcov_write_string (filename);
388}
389#endif
390
474f141e 391#if !IN_LIBGCOV
ca29da43
NS
392/* Write a tag TAG and reserve space for the record length. Return a
393 value to be used for gcov_write_length. */
394
9b514d25
NS
395GCOV_LINKAGE gcov_position_t
396gcov_write_tag (gcov_unsigned_t tag)
ca29da43 397{
7d63a2fa 398 gcov_position_t result = gcov_var.start + gcov_var.offset;
330d2e2a 399 gcov_unsigned_t *buffer = gcov_write_words (2);
ca29da43 400
160e2e4f
NS
401 buffer[0] = tag;
402 buffer[1] = 0;
b8698a0f 403
ca29da43
NS
404 return result;
405}
406
407/* Write a record length using POSITION, which was returned by
408 gcov_write_tag. The current file position is the end of the
409 record, and is restored before returning. Returns nonzero on
410 overflow. */
411
412GCOV_LINKAGE void
9b514d25 413gcov_write_length (gcov_position_t position)
ca29da43 414{
7d63a2fa
NS
415 unsigned offset;
416 gcov_unsigned_t length;
160e2e4f 417 gcov_unsigned_t *buffer;
7d63a2fa 418
e3f0315f
TJ
419 gcov_nonruntime_assert (gcov_var.mode < 0);
420 gcov_nonruntime_assert (position + 2 <= gcov_var.start + gcov_var.offset);
421 gcov_nonruntime_assert (position >= gcov_var.start);
7d63a2fa 422 offset = position - gcov_var.start;
330d2e2a 423 length = gcov_var.offset - offset - 2;
160e2e4f
NS
424 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
425 buffer[1] = length;
7d63a2fa
NS
426 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
427 gcov_write_block (gcov_var.offset);
ca29da43 428}
9b514d25
NS
429
430#else /* IN_LIBGCOV */
474f141e
NS
431
432/* Write a tag TAG and length LENGTH. */
433
434GCOV_LINKAGE void
9b514d25 435gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
474f141e 436{
330d2e2a 437 gcov_unsigned_t *buffer = gcov_write_words (2);
474f141e 438
160e2e4f
NS
439 buffer[0] = tag;
440 buffer[1] = length;
474f141e 441}
ca29da43 442
6356f892 443/* Write a summary structure to the gcov file. Return nonzero on
ca29da43
NS
444 overflow. */
445
446GCOV_LINKAGE void
9b514d25 447gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
ca29da43 448{
512cc015 449 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
7f3577f5 450 gcov_write_unsigned (summary->runs);
512cc015 451 gcov_write_unsigned (summary->sum_max);
ca29da43 452}
512cc015 453
ca29da43
NS
454#endif /* IN_LIBGCOV */
455
456#endif /*!IN_GCOV */
457
458/* Return a pointer to read BYTES bytes from the gcov file. Returns
71c0e7fc 459 NULL on failure (read past EOF). */
ca29da43 460
160e2e4f 461static const gcov_unsigned_t *
330d2e2a 462gcov_read_words (unsigned words)
ca29da43 463{
160e2e4f 464 const gcov_unsigned_t *result;
7d63a2fa 465 unsigned excess = gcov_var.length - gcov_var.offset;
b8698a0f 466
1bba63a7
AK
467 if (gcov_var.mode <= 0)
468 return NULL;
469
330d2e2a 470 if (excess < words)
ca29da43 471 {
7d63a2fa 472 gcov_var.start += gcov_var.offset;
7d63a2fa
NS
473 if (excess)
474 {
00a7ba58 475#if IN_LIBGCOV
7d63a2fa 476 memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4);
7d63a2fa 477#else
00a7ba58
JJ
478 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset,
479 excess * 4);
7d63a2fa 480#endif
00a7ba58 481 }
7d63a2fa
NS
482 gcov_var.offset = 0;
483 gcov_var.length = excess;
484#if IN_LIBGCOV
7d63a2fa
NS
485 excess = GCOV_BLOCK_SIZE;
486#else
330d2e2a
NS
487 if (gcov_var.length + words > gcov_var.alloc)
488 gcov_allocate (gcov_var.length + words);
7d63a2fa
NS
489 excess = gcov_var.alloc - gcov_var.length;
490#endif
dc1f1d7f 491 excess = fread (gcov_var.buffer + gcov_var.length,
330d2e2a 492 1, excess << 2, gcov_var.file) >> 2;
7d63a2fa 493 gcov_var.length += excess;
330d2e2a 494 if (gcov_var.length < words)
7d63a2fa 495 {
330d2e2a 496 gcov_var.overread += words - gcov_var.length;
7d63a2fa
NS
497 gcov_var.length = 0;
498 return 0;
499 }
ca29da43 500 }
330d2e2a
NS
501 result = &gcov_var.buffer[gcov_var.offset];
502 gcov_var.offset += words;
ca29da43
NS
503 return result;
504}
505
506/* Read unsigned value from a coverage file. Sets error flag on file
507 error, overflow flag on overflow */
508
9b514d25 509GCOV_LINKAGE gcov_unsigned_t
82a30d6f 510gcov_read_unsigned (void)
ca29da43 511{
160e2e4f 512 gcov_unsigned_t value;
330d2e2a 513 const gcov_unsigned_t *buffer = gcov_read_words (1);
ca29da43
NS
514
515 if (!buffer)
516 return 0;
160e2e4f 517 value = from_file (buffer[0]);
ca29da43
NS
518 return value;
519}
520
521/* Read counter value from a coverage file. Sets error flag on file
522 error, overflow flag on overflow */
523
524GCOV_LINKAGE gcov_type
82a30d6f 525gcov_read_counter (void)
ca29da43 526{
160e2e4f 527 gcov_type value;
330d2e2a 528 const gcov_unsigned_t *buffer = gcov_read_words (2);
ca29da43
NS
529
530 if (!buffer)
531 return 0;
160e2e4f
NS
532 value = from_file (buffer[0]);
533 if (sizeof (value) > sizeof (gcov_unsigned_t))
534 value |= ((gcov_type) from_file (buffer[1])) << 32;
535 else if (buffer[1])
536 gcov_var.error = -1;
6d9901e7 537
ca29da43
NS
538 return value;
539}
540
1f2bb38a
ML
541/* Mangle filename path of BASE and output new allocated pointer with
542 mangled path. */
543
544char *
545mangle_path (char const *base)
546{
547 /* Convert '/' to '#', convert '..' to '^',
548 convert ':' to '~' on DOS based file system. */
549 const char *probe;
12502bf2 550 char *buffer = (char *)xmalloc (strlen (base) + 1);
1f2bb38a
ML
551 char *ptr = buffer;
552
553#if HAVE_DOS_BASED_FILE_SYSTEM
554 if (base[0] && base[1] == ':')
555 {
556 ptr[0] = base[0];
557 ptr[1] = '~';
558 ptr += 2;
559 base += 2;
560 }
561#endif
562 for (; *base; base = probe)
563 {
564 size_t len;
565
566 for (probe = base; *probe; probe++)
567 if (*probe == '/')
568 break;
569 len = probe - base;
570 if (len == 2 && base[0] == '.' && base[1] == '.')
571 *ptr++ = '^';
572 else
573 {
574 memcpy (ptr, base, len);
575 ptr += len;
576 }
577 if (*probe)
578 {
579 *ptr++ = '#';
580 probe++;
581 }
582 }
583
584 /* Terminate the string. */
585 *ptr = '\0';
586
587 return buffer;
588}
589
c77556a5
RX
590/* We need to expose the below function when compiling for gcov-tool. */
591
592#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
ca29da43
NS
593/* Read string from coverage file. Returns a pointer to a static
594 buffer, or NULL on empty string. You must copy the string before
595 calling another gcov function. */
596
597GCOV_LINKAGE const char *
82a30d6f 598gcov_read_string (void)
ca29da43
NS
599{
600 unsigned length = gcov_read_unsigned ();
b8698a0f 601
ca29da43
NS
602 if (!length)
603 return 0;
604
330d2e2a 605 return (const char *) gcov_read_words (length);
ca29da43 606}
796621e8 607#endif
ca29da43
NS
608
609GCOV_LINKAGE void
610gcov_read_summary (struct gcov_summary *summary)
611{
7f3577f5 612 summary->runs = gcov_read_unsigned ();
512cc015 613 summary->sum_max = gcov_read_unsigned ();
ca29da43
NS
614}
615
c77556a5
RX
616/* We need to expose the below function when compiling for gcov-tool. */
617
618#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
7d63a2fa
NS
619/* Reset to a known position. BASE should have been obtained from
620 gcov_position, LENGTH should be a record length. */
621
622GCOV_LINKAGE void
623gcov_sync (gcov_position_t base, gcov_unsigned_t length)
624{
e3f0315f 625 gcov_nonruntime_assert (gcov_var.mode > 0);
7d63a2fa
NS
626 base += length;
627 if (base - gcov_var.start <= gcov_var.length)
628 gcov_var.offset = base - gcov_var.start;
629 else
630 {
631 gcov_var.offset = gcov_var.length = 0;
330d2e2a
NS
632 fseek (gcov_var.file, base << 2, SEEK_SET);
633 gcov_var.start = ftell (gcov_var.file) >> 2;
7d63a2fa
NS
634 }
635}
636#endif
637
638#if IN_LIBGCOV
fa10beec 639/* Move to a given position in a gcov file. */
7d63a2fa
NS
640
641GCOV_LINKAGE void
642gcov_seek (gcov_position_t base)
643{
7d63a2fa
NS
644 if (gcov_var.offset)
645 gcov_write_block (gcov_var.offset);
00cf2913 646 fseek (gcov_var.file, base << 2, SEEK_SET);
330d2e2a 647 gcov_var.start = ftell (gcov_var.file) >> 2;
7d63a2fa
NS
648}
649#endif
650
ca29da43
NS
651#if IN_GCOV > 0
652/* Return the modification time of the current gcov file. */
653
654GCOV_LINKAGE time_t
82a30d6f 655gcov_time (void)
ca29da43
NS
656{
657 struct stat status;
b8698a0f 658
ca29da43
NS
659 if (fstat (fileno (gcov_var.file), &status))
660 return 0;
661 else
662 return status.st_mtime;
663}
664#endif /* IN_GCOV */