Default to dwarf version 4 on hppa64-hpux
[official-gcc.git] / gcc / gcov-io.c
blobd3e56afb0a5d45b28059e9083e823bffbeff49c9
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
11 version.
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.
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);
32 struct gcov_var
34 FILE *file;
35 int error; /* < 0 overflow, > 0 disk error. */
36 int mode; /* < 0 writing, > 0 reading. */
37 int endian; /* Swap endianness. */
38 } gcov_var;
40 /* Save the current position in the gcov file. */
41 /* We need to expose this function when compiling for gcov-tool. */
42 #ifndef IN_GCOV_TOOL
43 static inline
44 #endif
45 gcov_position_t
46 gcov_position (void)
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. */
53 #ifndef IN_GCOV_TOOL
54 static inline
55 #endif
56 int
57 gcov_is_error (void)
59 return gcov_var.file ? gcov_var.error : 1;
62 #if IN_LIBGCOV
63 /* Move to beginning of file and initialize for writing. */
64 GCOV_LINKAGE inline void
65 gcov_rewrite (void)
67 gcov_var.mode = -1;
68 fseek (gcov_var.file, 0L, SEEK_SET);
70 #endif
72 static inline gcov_unsigned_t
73 from_file (gcov_unsigned_t value)
75 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
76 if (gcov_var.endian)
77 return __builtin_bswap32 (value);
78 #endif
79 return 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. */
91 GCOV_LINKAGE int
92 #if IN_LIBGCOV
93 gcov_open (const char *name)
94 #else
95 gcov_open (const char *name, int mode)
96 #endif
98 #if IN_LIBGCOV
99 int mode = 0;
100 #endif
101 #if GCOV_LOCKED
102 struct flock s_flock;
103 int fd;
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 ();
109 #elif GCOV_LOCKED_WITH_LOCKING
110 int fd;
111 #endif
113 gcov_nonruntime_assert (!gcov_var.file);
114 gcov_var.error = 0;
115 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
116 gcov_var.endian = 0;
117 #endif
118 #if GCOV_LOCKED
119 if (mode > 0)
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);
126 else
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);
133 if (fd < 0)
134 return 0;
136 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
137 continue;
139 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
141 if (!gcov_var.file)
143 close (fd);
144 return 0;
146 #elif GCOV_LOCKED_WITH_LOCKING
147 if (mode > 0)
149 /* pass mode (ignored) for compatibility */
150 fd = open (name, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
152 else
154 /* Truncate if force new mode. */
155 fd = open (name, O_RDWR | O_BINARY | O_CREAT | (mode < 0 ? O_TRUNC : 0),
156 0666);
158 if (fd < 0)
159 return 0;
161 if (_locking (fd, _LK_LOCK, LONG_MAX) < 0)
163 close (fd);
164 return 0;
167 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
169 if (!gcov_var.file)
171 close (fd);
172 return 0;
174 #else
175 if (mode >= 0)
176 /* Open an existing file. */
177 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
179 if (gcov_var.file)
180 mode = 1;
181 else if (mode <= 0)
182 /* Create a new file. */
183 gcov_var.file = fopen (name, "w+b");
185 if (!gcov_var.file)
186 return 0;
187 #endif
189 gcov_var.mode = mode ? mode : 1;
191 return 1;
194 /* Close the current gcov file. Flushes data to disk. Returns nonzero
195 on failure or error flag set. */
197 GCOV_LINKAGE int
198 gcov_close (void)
200 if (gcov_var.file)
202 if (fclose (gcov_var.file))
203 gcov_var.error = 1;
205 gcov_var.file = 0;
207 gcov_var.mode = 0;
208 return gcov_var.error;
211 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
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. */
216 GCOV_LINKAGE int
217 gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
219 if (magic == expected)
220 return 1;
222 if (__builtin_bswap32 (magic) == expected)
224 gcov_var.endian = 1;
225 return -1;
227 return 0;
229 #endif
231 #if !IN_GCOV
232 /* Write DATA of LENGTH characters to coverage file. */
234 GCOV_LINKAGE void
235 gcov_write (const void *data, unsigned length)
237 gcov_unsigned_t r = fwrite (data, length, 1, gcov_var.file);
238 if (r != 1)
239 gcov_var.error = 1;
242 /* Write unsigned VALUE to coverage file. */
244 GCOV_LINKAGE void
245 gcov_write_unsigned (gcov_unsigned_t value)
247 gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file);
248 if (r != 1)
249 gcov_var.error = 1;
252 #if !IN_LIBGCOV
253 /* Write STRING to coverage file. Sets error flag on file
254 error, overflow flag on overflow */
256 GCOV_LINKAGE void
257 gcov_write_string (const char *string)
259 unsigned length = 0;
261 if (string)
262 length = strlen (string) + 1;
264 gcov_write_unsigned (length);
265 if (length > 0)
267 gcov_unsigned_t r = fwrite (string, length, 1, gcov_var.file);
268 if (r != 1)
269 gcov_var.error = 1;
272 #endif
274 #if !IN_LIBGCOV
275 /* Write FILENAME to coverage file. Sets error flag on file
276 error, overflow flag on overflow */
278 GCOV_LINKAGE void
279 gcov_write_filename (const char *filename)
281 if (profile_abs_path_flag && filename && filename[0]
282 && !(IS_DIR_SEPARATOR (filename[0])
283 #if HAVE_DOS_BASED_FILE_SYSTEM
284 || filename[1] == ':'
285 #endif
288 char *buf = getcwd (NULL, 0);
289 if (buf != NULL && buf[0])
291 size_t len = strlen (buf);
292 buf = (char*)xrealloc (buf, len + strlen (filename) + 2);
293 if (!IS_DIR_SEPARATOR (buf[len - 1]))
294 strcat (buf, "/");
295 strcat (buf, filename);
296 gcov_write_string (buf);
297 free (buf);
298 return;
302 gcov_write_string (filename);
304 #endif
306 /* Move to a given position in a gcov file. */
308 GCOV_LINKAGE void
309 gcov_seek (gcov_position_t base)
311 fseek (gcov_var.file, base, SEEK_SET);
314 #if !IN_LIBGCOV
315 /* Write a tag TAG and reserve space for the record length. Return a
316 value to be used for gcov_write_length. */
318 GCOV_LINKAGE gcov_position_t
319 gcov_write_tag (gcov_unsigned_t tag)
321 gcov_position_t result = gcov_position ();
322 gcov_write_unsigned (tag);
323 gcov_write_unsigned (0);
325 return result;
328 /* Write a record length using POSITION, which was returned by
329 gcov_write_tag. The current file position is the end of the
330 record, and is restored before returning. Returns nonzero on
331 overflow. */
333 GCOV_LINKAGE void
334 gcov_write_length (gcov_position_t position)
336 gcov_position_t current_position = gcov_position ();
337 gcov_nonruntime_assert (gcov_var.mode < 0);
338 gcov_nonruntime_assert (current_position >= position + 2 * GCOV_WORD_SIZE);
340 gcov_seek (position + GCOV_WORD_SIZE);
341 gcov_write_unsigned (current_position - position - 2 * GCOV_WORD_SIZE);
342 gcov_seek (current_position);
345 #else /* IN_LIBGCOV */
347 /* Write a summary structure to the gcov file. */
349 GCOV_LINKAGE void
350 gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
352 gcov_write_unsigned (tag);
353 gcov_write_unsigned (GCOV_TAG_SUMMARY_LENGTH);
354 gcov_write_unsigned (summary->runs);
355 gcov_write_unsigned (summary->sum_max);
358 #endif /* IN_LIBGCOV */
360 #endif /*!IN_GCOV */
362 /* Return a pointer to read COUNT bytes from the gcov file. Returns
363 NULL on failure (read past EOF). */
365 static void *
366 gcov_read_bytes (void *buffer, unsigned count)
368 if (gcov_var.mode <= 0)
369 return NULL;
371 unsigned read = fread (buffer, count, 1, gcov_var.file);
372 if (read != 1)
373 return NULL;
375 return buffer;
378 /* Read WORDS gcov_unsigned_t values from gcov file. */
380 static gcov_unsigned_t *
381 gcov_read_words (void *buffer, unsigned words)
383 return (gcov_unsigned_t *)gcov_read_bytes (buffer, GCOV_WORD_SIZE * words);
386 /* Read unsigned value from a coverage file. Sets error flag on file
387 error, overflow flag on overflow */
389 GCOV_LINKAGE gcov_unsigned_t
390 gcov_read_unsigned (void)
392 gcov_unsigned_t value;
393 gcov_unsigned_t allocated_buffer[1];
394 gcov_unsigned_t *buffer = gcov_read_words (&allocated_buffer, 1);
396 if (!buffer)
397 return 0;
399 value = from_file (buffer[0]);
400 return value;
403 /* Read counter value from a coverage file. Sets error flag on file
404 error, overflow flag on overflow */
406 GCOV_LINKAGE gcov_type
407 gcov_read_counter (void)
409 gcov_type value;
410 gcov_unsigned_t allocated_buffer[2];
411 gcov_unsigned_t *buffer = gcov_read_words (&allocated_buffer, 2);
413 if (!buffer)
414 return 0;
415 value = from_file (buffer[0]);
416 if (sizeof (value) > sizeof (gcov_unsigned_t))
417 value |= ((gcov_type) from_file (buffer[1])) << 32;
418 else if (buffer[1])
419 gcov_var.error = -1;
421 return value;
424 /* Mangle filename path of BASE and output new allocated pointer with
425 mangled path. */
427 char *
428 mangle_path (char const *base)
430 /* Convert '/' to '#', convert '..' to '^',
431 convert ':' to '~' on DOS based file system. */
432 const char *probe;
433 char *buffer = (char *)xmalloc (strlen (base) + 1);
434 char *ptr = buffer;
436 #if HAVE_DOS_BASED_FILE_SYSTEM
437 if (base[0] && base[1] == ':')
439 ptr[0] = base[0];
440 ptr[1] = '~';
441 ptr += 2;
442 base += 2;
444 #endif
445 for (; *base; base = probe)
447 size_t len;
449 for (probe = base; *probe; probe++)
450 if (*probe == '/')
451 break;
452 len = probe - base;
453 if (len == 2 && base[0] == '.' && base[1] == '.')
454 *ptr++ = '^';
455 else
457 memcpy (ptr, base, len);
458 ptr += len;
460 if (*probe)
462 *ptr++ = '#';
463 probe++;
467 /* Terminate the string. */
468 *ptr = '\0';
470 return buffer;
473 /* We need to expose the below function when compiling for gcov-tool. */
475 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
476 /* Read string from coverage file. Returns a pointer to a static
477 buffer, or NULL on empty string. You must copy the string before
478 calling another gcov function. */
480 GCOV_LINKAGE const char *
481 gcov_read_string (void)
483 unsigned length = gcov_read_unsigned ();
485 if (!length)
486 return 0;
488 void *buffer = XNEWVEC (char *, length);
489 return (const char *) gcov_read_bytes (buffer, length);
491 #endif
493 GCOV_LINKAGE void
494 gcov_read_summary (struct gcov_summary *summary)
496 summary->runs = gcov_read_unsigned ();
497 summary->sum_max = gcov_read_unsigned ();
500 /* We need to expose the below function when compiling for gcov-tool. */
502 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
503 /* Reset to a known position. BASE should have been obtained from
504 gcov_position, LENGTH should be a record length. */
506 GCOV_LINKAGE void
507 gcov_sync (gcov_position_t base, gcov_unsigned_t length)
509 gcov_nonruntime_assert (gcov_var.mode > 0);
510 base += length;
511 fseek (gcov_var.file, base, SEEK_SET);
513 #endif
515 #if IN_GCOV > 0
516 /* Return the modification time of the current gcov file. */
518 GCOV_LINKAGE time_t
519 gcov_time (void)
521 struct stat status;
523 if (fstat (fileno (gcov_var.file), &status))
524 return 0;
525 else
526 return status.st_mtime;
528 #endif /* IN_GCOV */