Merge from trunk: 215733-215743
[official-gcc.git] / gcc-4_6_3-mobile / gcc / gcov-io.c
blob61ecd4630f018e449376cf79b0ae6bcfdf992aee
1 /* File format for coverage information
2 Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007,
3 2008 Free Software Foundation, Inc.
4 Contributed by Bob Manson <manson@cygnus.com>.
5 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
12 version.
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
19 Under Section 7 of GPL version 3, you are granted additional
20 permissions described in the GCC Runtime Library Exception, version
21 3.1, as published by the Free Software Foundation.
23 You should have received a copy of the GNU General Public License and
24 a copy of the GCC Runtime Library Exception along with this program;
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26 <http://www.gnu.org/licenses/>. */
28 /* Routines declared in gcov-io.h. This file should be #included by
29 another source file, after having #included gcov-io.h. */
31 /* Redefine these here, rather than using the ones in system.h since
32 * including system.h leads to conflicting definitions of other
33 * symbols and macros. */
34 #undef MIN
35 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
37 #if !IN_GCOV
38 static void gcov_write_block (unsigned);
39 static gcov_unsigned_t *gcov_write_words (unsigned);
40 #endif
41 static const gcov_unsigned_t *gcov_read_words (unsigned);
42 #if !IN_LIBGCOV
43 static void gcov_allocate (unsigned);
44 #endif
46 #ifdef __GCOV_KERNEL__
47 struct gcov_var gcov_var ATTRIBUTE_HIDDEN;
48 #endif
50 static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
52 #if !IN_LIBGCOV
53 if (gcov_var.endian)
55 value = (value >> 16) | (value << 16);
56 value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
58 #endif
59 return value;
62 /* Open a gcov file. NAME is the name of the file to open and MODE
63 indicates whether a new file should be created, or an existing file
64 opened. If MODE is >= 0 an existing file will be opened, if
65 possible, and if MODE is <= 0, a new file will be created. Use
66 MODE=0 to attempt to reopen an existing file and then fall back on
67 creating a new one. If MODE < 0, the file will be opened in
68 read-only mode. Otherwise it will be opened for modification.
69 Return zero on failure, >0 on opening an existing file and <0 on
70 creating a new one. */
72 #ifndef __GCOV_KERNEL__
73 GCOV_LINKAGE int
74 #if IN_LIBGCOV
75 gcov_open (const char *name)
76 #else
77 gcov_open (const char *name, int mode)
78 #endif
80 #if IN_LIBGCOV
81 const int mode = 0;
82 #endif
83 #if GCOV_LOCKED
84 struct flock s_flock;
85 int fd;
87 s_flock.l_whence = SEEK_SET;
88 s_flock.l_start = 0;
89 s_flock.l_len = 0; /* Until EOF. */
90 s_flock.l_pid = getpid ();
91 #endif
93 gcc_assert (!gcov_var.file);
94 gcov_var.start = 0;
95 gcov_var.offset = gcov_var.length = 0;
96 gcov_var.overread = -1u;
97 gcov_var.error = 0;
98 #if !IN_LIBGCOV
99 gcov_var.endian = 0;
100 #endif
101 #if GCOV_LOCKED
102 if (mode > 0)
104 /* Read-only mode - acquire a read-lock. */
105 s_flock.l_type = F_RDLCK;
106 fd = open (name, O_RDONLY);
108 else
110 /* Write mode - acquire a write-lock. */
111 s_flock.l_type = F_WRLCK;
112 fd = open (name, O_RDWR | O_CREAT, 0666);
114 if (fd < 0)
115 return 0;
117 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
118 continue;
120 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
122 if (!gcov_var.file)
124 close (fd);
125 return 0;
128 if (mode > 0)
129 gcov_var.mode = 1;
130 else if (mode == 0)
132 struct stat st;
134 if (fstat (fd, &st) < 0)
136 fclose (gcov_var.file);
137 gcov_var.file = 0;
138 return 0;
140 if (st.st_size != 0)
141 gcov_var.mode = 1;
142 else
143 gcov_var.mode = mode * 2 + 1;
145 else
146 gcov_var.mode = mode * 2 + 1;
147 #else
148 if (mode >= 0)
149 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
151 if (gcov_var.file)
152 gcov_var.mode = 1;
153 else if (mode <= 0)
155 gcov_var.file = fopen (name, "w+b");
156 if (gcov_var.file)
157 gcov_var.mode = mode * 2 + 1;
159 if (!gcov_var.file)
160 return 0;
161 #endif
163 setbuf (gcov_var.file, (char *)0);
165 return 1;
167 #else /* __GCOV_KERNEL__ */
169 extern _GCOV_FILE *gcov_current_file;
171 GCOV_LINKAGE int
172 gcov_open (const char *name)
174 gcov_var.start = 0;
175 gcov_var.offset = gcov_var.length = 0;
176 gcov_var.overread = -1u;
177 gcov_var.error = 0;
178 gcov_var.file = gcov_current_file;
179 gcov_var.mode = 1;
181 return 1;
183 #endif /* __GCOV_KERNEL__ */
185 /* Close the current gcov file. Flushes data to disk. Returns nonzero
186 on failure or error flag set. */
188 GCOV_LINKAGE int
189 gcov_close (void)
191 if (gcov_var.file)
193 #if !IN_GCOV
194 if (gcov_var.offset && gcov_var.mode < 0)
195 gcov_write_block (gcov_var.offset);
196 #endif
197 _GCOV_fclose (gcov_var.file);
198 gcov_var.file = 0;
199 gcov_var.length = 0;
201 #if !IN_LIBGCOV
202 free (gcov_var.buffer);
203 gcov_var.alloc = 0;
204 gcov_var.buffer = 0;
205 #endif
206 gcov_var.mode = 0;
207 return gcov_var.error;
210 #if !IN_LIBGCOV
211 /* Modify FILENAME to a canonical form after stripping known prefixes
212 in place. It removes '/proc/self/cwd' and '/proc/self/cwd/.'.
213 Returns the in-place modified filename. */
215 GCOV_LINKAGE char *
216 gcov_canonical_filename (char *filename)
218 static char cwd_dot_str[] = "/proc/self/cwd/./";
219 int cwd_dot_len = strlen (cwd_dot_str);
220 int cwd_len = cwd_dot_len - 2; /* without trailing './' */
221 int filename_len = strlen (filename);
222 /* delete the longer prefix first */
223 if (0 == strncmp (filename, cwd_dot_str, cwd_dot_len))
225 memmove (filename, filename + cwd_dot_len, filename_len - cwd_dot_len);
226 filename[filename_len - cwd_dot_len] = '\0';
227 return filename;
230 if (0 == strncmp (filename, cwd_dot_str, cwd_len))
232 memmove (filename, filename + cwd_len, filename_len - cwd_len);
233 filename[filename_len - cwd_len] = '\0';
234 return filename;
236 return filename;
239 /* Read LEN words and construct load latency info LL_INFO. */
241 GCOV_LINKAGE void
242 gcov_read_pmu_load_latency_info (gcov_pmu_ll_info_t *ll_info,
243 gcov_unsigned_t len ATTRIBUTE_UNUSED)
245 const char *filename;
246 ll_info->counts = gcov_read_unsigned ();
247 ll_info->self = gcov_read_unsigned ();
248 ll_info->cum = gcov_read_unsigned ();
249 ll_info->lt_10 = gcov_read_unsigned ();
250 ll_info->lt_32 = gcov_read_unsigned ();
251 ll_info->lt_64 = gcov_read_unsigned ();
252 ll_info->lt_256 = gcov_read_unsigned ();
253 ll_info->lt_1024 = gcov_read_unsigned ();
254 ll_info->gt_1024 = gcov_read_unsigned ();
255 ll_info->wself = gcov_read_unsigned ();
256 ll_info->code_addr = gcov_read_counter ();
257 ll_info->line = gcov_read_unsigned ();
258 ll_info->discriminator = gcov_read_unsigned ();
259 filename = gcov_read_string ();
260 if (filename)
261 ll_info->filename = gcov_canonical_filename (xstrdup (filename));
262 else
263 ll_info->filename = 0;
266 /* Read LEN words and construct branch mispredict info BRM_INFO. */
268 GCOV_LINKAGE void
269 gcov_read_pmu_branch_mispredict_info (gcov_pmu_brm_info_t *brm_info,
270 gcov_unsigned_t len ATTRIBUTE_UNUSED)
272 const char *filename;
273 brm_info->counts = gcov_read_unsigned ();
274 brm_info->self = gcov_read_unsigned ();
275 brm_info->cum = gcov_read_unsigned ();
276 brm_info->code_addr = gcov_read_counter ();
277 brm_info->line = gcov_read_unsigned ();
278 brm_info->discriminator = gcov_read_unsigned ();
279 filename = gcov_read_string ();
280 if (filename)
281 brm_info->filename = gcov_canonical_filename (xstrdup (filename));
282 else
283 brm_info->filename = 0;
286 /* Read LEN words from an open gcov file and construct data into pmu
287 tool header TOOL_HEADER. */
289 GCOV_LINKAGE void gcov_read_pmu_tool_header (gcov_pmu_tool_header_t *header,
290 gcov_unsigned_t len ATTRIBUTE_UNUSED)
292 const char *str;
293 str = gcov_read_string ();
294 header->host_cpu = str ? xstrdup (str) : 0;
295 str = gcov_read_string ();
296 header->hostname = str ? xstrdup (str) : 0;
297 str = gcov_read_string ();
298 header->kernel_version = str ? xstrdup (str) : 0;
299 str = gcov_read_string ();
300 header->column_header = str ? xstrdup (str) : 0;
301 str = gcov_read_string ();
302 header->column_description = str ? xstrdup (str) : 0;
303 str = gcov_read_string ();
304 header->full_header = str ? xstrdup (str) : 0;
306 #endif
308 #if !IN_LIBGCOV
309 /* Check if MAGIC is EXPECTED. Use it to determine endianness of the
310 file. Returns +1 for same endian, -1 for other endian and zero for
311 not EXPECTED. */
313 GCOV_LINKAGE int
314 gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
316 if (magic == expected)
317 return 1;
318 magic = (magic >> 16) | (magic << 16);
319 magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
320 if (magic == expected)
322 gcov_var.endian = 1;
323 return -1;
325 return 0;
327 #endif
329 #if !IN_LIBGCOV
330 static void
331 gcov_allocate (unsigned length)
333 size_t new_size = gcov_var.alloc;
335 if (!new_size)
336 new_size = GCOV_BLOCK_SIZE;
337 new_size += length;
338 new_size *= 2;
340 gcov_var.alloc = new_size;
341 gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2);
343 #endif
345 #if !IN_GCOV
346 /* Write out the current block, if needs be. */
348 static void
349 gcov_write_block (unsigned size)
351 if (_GCOV_fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
352 gcov_var.error = 1;
353 gcov_var.start += size;
354 gcov_var.offset -= size;
357 #if IN_LIBGCOV
358 /* Return the number of words STRING would need including the length
359 field in the output stream itself. This should be identical to
360 "alloc" calculation in gcov_write_string(). */
362 GCOV_LINKAGE gcov_unsigned_t
363 gcov_string_length (const char *string)
365 gcov_unsigned_t len = (string) ? strlen (string) : 0;
366 /* + 1 because of the length field. */
367 gcov_unsigned_t alloc = 1 + ((len + 4) >> 2);
369 /* Can not write a bigger than GCOV_BLOCK_SIZE string yet */
370 gcc_assert (alloc < GCOV_BLOCK_SIZE);
371 return alloc;
373 #endif
375 /* Allocate space to write BYTES bytes to the gcov file. Return a
376 pointer to those bytes, or NULL on failure. */
378 static gcov_unsigned_t *
379 gcov_write_words (unsigned words)
381 gcov_unsigned_t *result;
383 gcc_assert (gcov_var.mode < 0);
384 #if IN_LIBGCOV
385 if (gcov_var.offset + words >= GCOV_BLOCK_SIZE)
387 gcov_write_block (MIN (gcov_var.offset, GCOV_BLOCK_SIZE));
388 if (gcov_var.offset)
390 gcc_assert (gcov_var.offset < GCOV_BLOCK_SIZE);
391 memcpy (gcov_var.buffer,
392 gcov_var.buffer + GCOV_BLOCK_SIZE,
393 gcov_var.offset << 2);
396 #else
397 if (gcov_var.offset + words > gcov_var.alloc)
398 gcov_allocate (gcov_var.offset + words);
399 #endif
400 result = &gcov_var.buffer[gcov_var.offset];
401 gcov_var.offset += words;
403 return result;
406 /* Write unsigned VALUE to coverage file. Sets error flag
407 appropriately. */
409 GCOV_LINKAGE void
410 gcov_write_unsigned (gcov_unsigned_t value)
412 gcov_unsigned_t *buffer = gcov_write_words (1);
414 buffer[0] = value;
417 /* Write counter VALUE to coverage file. Sets error flag
418 appropriately. */
420 #if IN_LIBGCOV
421 GCOV_LINKAGE void
422 gcov_write_counter (gcov_type value)
424 gcov_unsigned_t *buffer = gcov_write_words (2);
426 buffer[0] = (gcov_unsigned_t) value;
427 if (sizeof (value) > sizeof (gcov_unsigned_t))
428 buffer[1] = (gcov_unsigned_t) (value >> 32);
429 else
430 buffer[1] = 0;
432 #endif /* IN_LIBGCOV */
434 /* Write STRING to coverage file. Sets error flag on file
435 error, overflow flag on overflow */
437 GCOV_LINKAGE void
438 gcov_write_string (const char *string)
440 unsigned length = 0;
441 unsigned alloc = 0;
442 gcov_unsigned_t *buffer;
444 if (string)
446 length = strlen (string);
447 alloc = (length + 4) >> 2;
450 buffer = gcov_write_words (1 + alloc);
452 buffer[0] = alloc;
453 buffer[alloc] = 0;
454 memcpy (&buffer[1], string, length);
457 #if !IN_LIBGCOV
458 /* Write a tag TAG and reserve space for the record length. Return a
459 value to be used for gcov_write_length. */
461 GCOV_LINKAGE gcov_position_t
462 gcov_write_tag (gcov_unsigned_t tag)
464 gcov_position_t result = gcov_var.start + gcov_var.offset;
465 gcov_unsigned_t *buffer = gcov_write_words (2);
467 buffer[0] = tag;
468 buffer[1] = 0;
470 return result;
473 /* Write a record length using POSITION, which was returned by
474 gcov_write_tag. The current file position is the end of the
475 record, and is restored before returning. Returns nonzero on
476 overflow. */
478 GCOV_LINKAGE void
479 gcov_write_length (gcov_position_t position)
481 unsigned offset;
482 gcov_unsigned_t length;
483 gcov_unsigned_t *buffer;
485 gcc_assert (gcov_var.mode < 0);
486 gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset);
487 gcc_assert (position >= gcov_var.start);
488 offset = position - gcov_var.start;
489 length = gcov_var.offset - offset - 2;
490 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
491 buffer[1] = length;
492 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
493 gcov_write_block (gcov_var.offset);
496 #else /* IN_LIBGCOV */
498 /* Write a tag TAG and length LENGTH. */
500 GCOV_LINKAGE void
501 gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
503 gcov_unsigned_t *buffer = gcov_write_words (2);
505 buffer[0] = tag;
506 buffer[1] = length;
509 /* Write a summary structure to the gcov file. Return nonzero on
510 overflow. */
512 GCOV_LINKAGE void
513 gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
515 unsigned ix;
516 const struct gcov_ctr_summary *csum;
518 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
519 gcov_write_unsigned (summary->checksum);
520 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
522 gcov_write_unsigned (csum->num);
523 gcov_write_unsigned (csum->runs);
524 gcov_write_counter (csum->sum_all);
525 gcov_write_counter (csum->run_max);
526 gcov_write_counter (csum->sum_max);
529 #endif /* IN_LIBGCOV */
531 #endif /*!IN_GCOV */
533 /* Return a pointer to read BYTES bytes from the gcov file. Returns
534 NULL on failure (read past EOF). */
536 static const gcov_unsigned_t *
537 gcov_read_words (unsigned words)
539 const gcov_unsigned_t *result;
540 unsigned excess = gcov_var.length - gcov_var.offset;
542 gcc_assert (gcov_var.mode > 0);
543 gcc_assert (words < GCOV_BLOCK_SIZE);
544 if (excess < words)
546 gcov_var.start += gcov_var.offset;
547 #if IN_LIBGCOV
548 if (excess)
550 gcc_assert (excess < GCOV_BLOCK_SIZE);
551 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4);
553 #else
554 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4);
555 #endif
556 gcov_var.offset = 0;
557 gcov_var.length = excess;
558 #if IN_LIBGCOV
559 excess = (sizeof (gcov_var.buffer) / sizeof (gcov_var.buffer[0])) - gcov_var.length;
560 #else
561 if (gcov_var.length + words > gcov_var.alloc)
562 gcov_allocate (gcov_var.length + words);
563 excess = gcov_var.alloc - gcov_var.length;
564 #endif
565 excess = _GCOV_fread (gcov_var.buffer + gcov_var.length,
566 1, excess << 2, gcov_var.file) >> 2;
567 gcov_var.length += excess;
568 if (gcov_var.length < words)
570 gcov_var.overread += words - gcov_var.length;
571 gcov_var.length = 0;
572 return 0;
575 result = &gcov_var.buffer[gcov_var.offset];
576 gcov_var.offset += words;
577 return result;
580 /* Read unsigned value from a coverage file. Sets error flag on file
581 error, overflow flag on overflow */
583 GCOV_LINKAGE gcov_unsigned_t
584 gcov_read_unsigned (void)
586 gcov_unsigned_t value;
587 const gcov_unsigned_t *buffer = gcov_read_words (1);
589 if (!buffer)
590 return 0;
591 value = from_file (buffer[0]);
592 return value;
595 /* Read counter value from a coverage file. Sets error flag on file
596 error, overflow flag on overflow */
598 GCOV_LINKAGE gcov_type
599 gcov_read_counter (void)
601 gcov_type value;
602 const gcov_unsigned_t *buffer = gcov_read_words (2);
604 if (!buffer)
605 return 0;
606 value = from_file (buffer[0]);
607 if (sizeof (value) > sizeof (gcov_unsigned_t))
608 value |= ((gcov_type) from_file (buffer[1])) << 32;
609 else if (buffer[1])
610 gcov_var.error = -1;
612 return value;
615 /* Read string from coverage file. Returns a pointer to a static
616 buffer, or NULL on empty string. You must copy the string before
617 calling another gcov function. */
619 GCOV_LINKAGE const char *
620 gcov_read_string (void)
622 unsigned length = gcov_read_unsigned ();
624 if (!length)
625 return 0;
627 return (const char *) gcov_read_words (length);
630 GCOV_LINKAGE void
631 gcov_read_summary (struct gcov_summary *summary)
633 unsigned ix;
634 struct gcov_ctr_summary *csum;
636 summary->checksum = gcov_read_unsigned ();
637 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
639 csum->num = gcov_read_unsigned ();
640 csum->runs = gcov_read_unsigned ();
641 csum->sum_all = gcov_read_counter ();
642 csum->run_max = gcov_read_counter ();
643 csum->sum_max = gcov_read_counter ();
647 #if !IN_LIBGCOV && IN_GCOV != 1
648 /* Read LEN words (unsigned type) and construct MOD_INFO. */
650 GCOV_LINKAGE void
651 gcov_read_module_info (struct gcov_module_info *mod_info,
652 gcov_unsigned_t len)
654 gcov_unsigned_t src_filename_len, filename_len, i, j, num_strings;
655 mod_info->ident = gcov_read_unsigned ();
656 mod_info->is_primary = gcov_read_unsigned ();
657 mod_info->is_exported = gcov_read_unsigned ();
658 mod_info->lang = gcov_read_unsigned ();
659 mod_info->num_quote_paths = gcov_read_unsigned ();
660 mod_info->num_bracket_paths = gcov_read_unsigned ();
661 mod_info->num_cpp_defines = gcov_read_unsigned ();
662 mod_info->num_cpp_includes = gcov_read_unsigned ();
663 mod_info->num_cl_args = gcov_read_unsigned ();
664 len -= 9;
666 filename_len = gcov_read_unsigned ();
667 mod_info->da_filename = (char *) xmalloc (filename_len *
668 sizeof (gcov_unsigned_t));
669 for (i = 0; i < filename_len; i++)
670 ((gcov_unsigned_t *) mod_info->da_filename)[i] = gcov_read_unsigned ();
671 len -= (filename_len + 1);
673 src_filename_len = gcov_read_unsigned ();
674 mod_info->source_filename = (char *) xmalloc (src_filename_len *
675 sizeof (gcov_unsigned_t));
676 for (i = 0; i < src_filename_len; i++)
677 ((gcov_unsigned_t *) mod_info->source_filename)[i] = gcov_read_unsigned ();
678 len -= (src_filename_len + 1);
680 num_strings = mod_info->num_quote_paths + mod_info->num_bracket_paths +
681 mod_info->num_cpp_defines + mod_info->num_cpp_includes +
682 mod_info->num_cl_args;
683 for (j = 0; j < num_strings; j++)
685 gcov_unsigned_t string_len = gcov_read_unsigned ();
686 mod_info->string_array[j] =
687 (char *) xmalloc (string_len * sizeof (gcov_unsigned_t));
688 for (i = 0; i < string_len; i++)
689 ((gcov_unsigned_t *) mod_info->string_array[j])[i] =
690 gcov_read_unsigned ();
691 len -= (string_len + 1);
693 gcc_assert (!len);
695 #endif
697 #if !IN_LIBGCOV
698 /* Reset to a known position. BASE should have been obtained from
699 gcov_position, LENGTH should be a record length. */
701 GCOV_LINKAGE void
702 gcov_sync (gcov_position_t base, gcov_unsigned_t length)
704 #ifdef __GCOV_KERNEL__
705 /* should not reach this point */
706 gcc_assert (0);
707 #else /* __GCOV_KERNEL__ */
708 gcc_assert (gcov_var.mode > 0);
709 base += length;
710 if (base - gcov_var.start <= gcov_var.length)
711 gcov_var.offset = base - gcov_var.start;
712 else
714 gcov_var.offset = gcov_var.length = 0;
715 _GCOV_fseek (gcov_var.file, base << 2, SEEK_SET);
716 gcov_var.start = _GCOV_ftell (gcov_var.file) >> 2;
718 #endif /* __GCOV_KERNEL__ */
720 #endif
722 #if IN_LIBGCOV
723 /* Move to a given position in a gcov file. */
725 GCOV_LINKAGE void
726 gcov_seek (gcov_position_t base)
728 gcc_assert (gcov_var.mode < 0);
729 if (gcov_var.offset)
730 gcov_write_block (gcov_var.offset);
731 _GCOV_fseek (gcov_var.file, base << 2, SEEK_SET);
732 gcov_var.start = _GCOV_ftell (gcov_var.file) >> 2;
735 /* Truncate the gcov file at the current position. */
737 GCOV_LINKAGE void
738 gcov_truncate (void)
740 #ifdef __GCOV_KERNEL__
741 /* should not reach this point */
742 gcc_assert (0);
743 #else /* __GCOV_KERNEL__ */
744 long offs;
745 int filenum;
746 gcc_assert (gcov_var.mode < 0);
747 if (gcov_var.offset)
748 gcov_write_block (gcov_var.offset);
749 offs = ftell (gcov_var.file);
750 filenum = fileno (gcov_var.file);
751 if (offs == -1 || filenum == -1 || ftruncate (filenum, offs))
752 gcov_var.error = 1;
753 #endif /* __GCOV_KERNEL__ */
755 #endif
757 #ifndef __GCOV_KERNEL__
758 /* Convert an unsigned NUMBER to a percentage after dividing by
759 100. */
761 GCOV_LINKAGE float
762 convert_unsigned_to_pct (const unsigned number)
764 return (float)number / 100.0f;
766 #endif
768 #if !IN_LIBGCOV && IN_GCOV != 1
769 /* Print load latency information given by LL_INFO in a human readable
770 format into an open output file pointed by FP. NEWLINE specifies
771 whether or not to print a trailing newline. */
773 GCOV_LINKAGE void
774 print_load_latency_line (FILE *fp, const gcov_pmu_ll_info_t *ll_info,
775 const enum print_newline newline)
777 if (!ll_info)
778 return;
779 fprintf (fp, " %u %.2f%% %.2f%% %.2f%% %.2f%% %.2f%% %.2f%% %.2f%% "
780 "%.2f%% %.2f%% " HOST_WIDEST_INT_PRINT_HEX " %s %d %d",
781 ll_info->counts,
782 convert_unsigned_to_pct (ll_info->self),
783 convert_unsigned_to_pct (ll_info->cum),
784 convert_unsigned_to_pct (ll_info->lt_10),
785 convert_unsigned_to_pct (ll_info->lt_32),
786 convert_unsigned_to_pct (ll_info->lt_64),
787 convert_unsigned_to_pct (ll_info->lt_256),
788 convert_unsigned_to_pct (ll_info->lt_1024),
789 convert_unsigned_to_pct (ll_info->gt_1024),
790 convert_unsigned_to_pct (ll_info->wself),
791 ll_info->code_addr,
792 ll_info->filename,
793 ll_info->line,
794 ll_info->discriminator);
795 if (newline == add_newline)
796 fprintf (fp, "\n");
799 /* Print BRM_INFO into the file pointed by FP. NEWLINE specifies
800 whether or not to print a trailing newline. */
802 GCOV_LINKAGE void
803 print_branch_mispredict_line (FILE *fp, const gcov_pmu_brm_info_t *brm_info,
804 const enum print_newline newline)
806 if (!brm_info)
807 return;
808 fprintf (fp, " %u %.2f%% %.2f%% " HOST_WIDEST_INT_PRINT_HEX " %s %d %d",
809 brm_info->counts,
810 convert_unsigned_to_pct (brm_info->self),
811 convert_unsigned_to_pct (brm_info->cum),
812 brm_info->code_addr,
813 brm_info->filename,
814 brm_info->line,
815 brm_info->discriminator);
816 if (newline == add_newline)
817 fprintf (fp, "\n");
820 /* Print TOOL_HEADER into the file pointed by FP. NEWLINE specifies
821 whether or not to print a trailing newline. */
823 GCOV_LINKAGE void
824 print_pmu_tool_header (FILE *fp, gcov_pmu_tool_header_t *tool_header,
825 const enum print_newline newline)
827 if (!tool_header)
828 return;
829 fprintf (fp, "\nhost_cpu: %s\n", tool_header->host_cpu);
830 fprintf (fp, "hostname: %s\n", tool_header->hostname);
831 fprintf (fp, "kernel_version: %s\n", tool_header->kernel_version);
832 fprintf (fp, "column_header: %s\n", tool_header->column_header);
833 fprintf (fp, "column_description: %s\n", tool_header->column_description);
834 fprintf (fp, "full_header: %s\n", tool_header->full_header);
835 if (newline == add_newline)
836 fprintf (fp, "\n");
838 #endif
840 #if IN_GCOV > 0
841 /* Return the modification time of the current gcov file. */
843 GCOV_LINKAGE time_t
844 gcov_time (void)
846 struct stat status;
848 if (fstat (fileno (gcov_var.file), &status))
849 return 0;
850 else
851 return status.st_mtime;
853 #endif /* IN_GCOV */
855 #ifdef __GCOV_KERNEL__
857 /* File fclose operation in kernel mode. */
860 kernel_file_fclose (gcov_kernel_vfile *fp)
862 return 0;
865 /* File ftell operation in kernel mode. It currently should not
866 be called. */
868 long
869 kernel_file_ftell (gcov_kernel_vfile *fp)
871 gcc_assert (0); /* should not reach here */
872 return 0;
875 /* File fseek operation in kernel mode. It should only be called
876 with OFFSET==0 and WHENCE==0 to a freshly opened file. */
879 kernel_file_fseek (gcov_kernel_vfile *fp, long offset, int whence)
881 gcc_assert (offset == 0 && whence == 0 && fp->count == 0);
882 return 0;
885 /* File ftruncate operation in kernel mode. It currently should not
886 be called. */
889 kernel_file_ftruncate (gcov_kernel_vfile *fp, off_t value)
891 gcc_assert (0); /* should not reach here */
892 return 0;
895 /* File fread operation in kernel mode. It currently should not
896 be called. */
899 kernel_file_fread (void *ptr, size_t size, size_t nitems,
900 gcov_kernel_vfile *fp)
902 gcc_assert (0); /* should not reach here */
903 return 0;
906 /* File fwrite operation in kernel mode. It outputs the data
907 to a buffer in the virual file. */
910 kernel_file_fwrite (const void *ptr, size_t size,
911 size_t nitems, gcov_kernel_vfile *fp)
913 char *vbuf;
914 unsigned vsize, vpos;
915 unsigned len;
917 if (!fp) return 0;
919 vbuf = fp->buf;
920 vsize = fp->size;
921 vpos = fp->count;
923 if (vsize <= vpos)
925 printk (KERN_ERR
926 "GCOV_KERNEL: something wrong: vbuf=%p vsize=%u vpos=%u\n",
927 vbuf, vsize, vpos);
928 return 0;
930 len = vsize - vpos;
931 len /= size;
933 if (len > nitems)
934 len = nitems;
936 memcpy (vbuf+vpos, ptr, size*len);
937 fp->count += len*size;
939 if (len != nitems)
940 printk (KERN_ERR
941 "GCOV_KERNEL: something wrong: size=%lu nitems=%lu ret=%d\n",
942 size, nitems, len);
943 return len;
946 /* File fileno operation in kernel mode. It currently should not
947 be called. */
950 kernel_file_fileno (gcov_kernel_vfile *fp)
952 gcc_assert (0); /* should not reach here */
953 return 0;
955 #else /* __GCOV_KERNEL__ */
957 #if IN_GCOV != 1
958 /* Delete pmu tool header TOOL_HEADER. */
960 GCOV_LINKAGE void
961 destroy_pmu_tool_header (gcov_pmu_tool_header_t *tool_header)
963 if (!tool_header)
964 return;
965 if (tool_header->host_cpu)
966 free (tool_header->host_cpu);
967 if (tool_header->hostname)
968 free (tool_header->hostname);
969 if (tool_header->kernel_version)
970 free (tool_header->kernel_version);
971 if (tool_header->column_header)
972 free (tool_header->column_header);
973 if (tool_header->column_description)
974 free (tool_header->column_description);
975 if (tool_header->full_header)
976 free (tool_header->full_header);
978 #endif
980 #endif /* GCOV_KERNEL */