]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov-io.c
Update copyright years.
[thirdparty/gcc.git] / gcc / gcov-io.c
CommitLineData
44359ced 1/* File format for coverage information
f1717362 2 Copyright (C) 1996-2016 Free Software Foundation, Inc.
44359ced 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
8c4c00c1 10Software Foundation; either version 3, or (at your option) any later
44359ced 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
cf09cacb 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
8c4c00c1 25<http://www.gnu.org/licenses/>. */
44359ced 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
80abd9e4 30#if !IN_GCOV
31static void gcov_write_block (unsigned);
9e0943d4 32static gcov_unsigned_t *gcov_write_words (unsigned);
80abd9e4 33#endif
9e0943d4 34static const gcov_unsigned_t *gcov_read_words (unsigned);
80abd9e4 35#if !IN_LIBGCOV
36static void gcov_allocate (unsigned);
37#endif
38
67745126 39/* Optimum number of gcov_unsigned_t's read from or written to disk. */
40#define GCOV_BLOCK_SIZE (1 << 10)
41
f6c27254 42struct gcov_var
67745126 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. */
e76f6040 67/* We need to expose this function when compiling for gcov-tool. */
68#ifndef IN_GCOV_TOOL
69static inline
70#endif
71gcov_position_t
67745126 72gcov_position (void)
73{
f1919901 74 gcov_nonruntime_assert (gcov_var.mode > 0);
67745126 75 return gcov_var.start + gcov_var.offset;
76}
77
78/* Return nonzero if the error flag is set. */
e76f6040 79/* We need to expose this function when compiling for gcov-tool. */
80#ifndef IN_GCOV_TOOL
81static inline
82#endif
83int
67745126 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{
67745126 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
b4d48d67 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
44359ced 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
35ab2622 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
118 creating a new one. If MODE < 0, the file will be opened in
119 read-only mode. Otherwise it will be opened for modification.
120 Return zero on failure, >0 on opening an existing file and <0 on
121 creating a new one. */
44359ced 122
123GCOV_LINKAGE int
b4d48d67 124#if IN_LIBGCOV
125gcov_open (const char *name)
126#else
44359ced 127gcov_open (const char *name, int mode)
b4d48d67 128#endif
44359ced 129{
b4d48d67 130#if IN_LIBGCOV
131 const int mode = 0;
132#endif
3ddf7676 133#if GCOV_LOCKED
44359ced 134 struct flock s_flock;
9131ff41 135 int fd;
44359ced 136
44359ced 137 s_flock.l_whence = SEEK_SET;
138 s_flock.l_start = 0;
139 s_flock.l_len = 0; /* Until EOF. */
140 s_flock.l_pid = getpid ();
141#endif
48e1416a 142
f1919901 143 gcov_nonruntime_assert (!gcov_var.file);
80abd9e4 144 gcov_var.start = 0;
145 gcov_var.offset = gcov_var.length = 0;
9e0943d4 146 gcov_var.overread = -1u;
80abd9e4 147 gcov_var.error = 0;
b4d48d67 148#if !IN_LIBGCOV
149 gcov_var.endian = 0;
150#endif
9131ff41 151#if GCOV_LOCKED
152 if (mode > 0)
35ab2622 153 {
154 /* Read-only mode - acquire a read-lock. */
155 s_flock.l_type = F_RDLCK;
d3cf0a31 156 /* pass mode (ignored) for compatibility */
157 fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR);
35ab2622 158 }
ca3f7d34 159 else if (mode < 0)
160 {
161 /* Write mode - acquire a write-lock. */
162 s_flock.l_type = F_WRLCK;
163 fd = open (name, O_RDWR | O_CREAT | O_TRUNC, 0666);
164 }
165 else /* mode == 0 */
35ab2622 166 {
ca3f7d34 167 /* Read-Write mode - acquire a write-lock. */
35ab2622 168 s_flock.l_type = F_WRLCK;
169 fd = open (name, O_RDWR | O_CREAT, 0666);
170 }
9131ff41 171 if (fd < 0)
172 return 0;
173
174 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
175 continue;
176
35ab2622 177 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b");
178
9131ff41 179 if (!gcov_var.file)
180 {
181 close (fd);
182 return 0;
183 }
184
185 if (mode > 0)
186 gcov_var.mode = 1;
187 else if (mode == 0)
188 {
189 struct stat st;
190
191 if (fstat (fd, &st) < 0)
192 {
193 fclose (gcov_var.file);
194 gcov_var.file = 0;
195 return 0;
196 }
197 if (st.st_size != 0)
198 gcov_var.mode = 1;
199 else
200 gcov_var.mode = mode * 2 + 1;
201 }
202 else
203 gcov_var.mode = mode * 2 + 1;
204#else
44359ced 205 if (mode >= 0)
35ab2622 206 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
207
80abd9e4 208 if (gcov_var.file)
209 gcov_var.mode = 1;
210 else if (mode <= 0)
44359ced 211 {
44359ced 212 gcov_var.file = fopen (name, "w+b");
80abd9e4 213 if (gcov_var.file)
b4d48d67 214 gcov_var.mode = mode * 2 + 1;
44359ced 215 }
216 if (!gcov_var.file)
217 return 0;
44359ced 218#endif
219
9131ff41 220 setbuf (gcov_var.file, (char *)0);
48e1416a 221
b4d48d67 222 return 1;
44359ced 223}
224
225/* Close the current gcov file. Flushes data to disk. Returns nonzero
226 on failure or error flag set. */
227
228GCOV_LINKAGE int
53b2c31f 229gcov_close (void)
44359ced 230{
44359ced 231 if (gcov_var.file)
232 {
80abd9e4 233#if !IN_GCOV
234 if (gcov_var.offset && gcov_var.mode < 0)
235 gcov_write_block (gcov_var.offset);
236#endif
44359ced 237 fclose (gcov_var.file);
238 gcov_var.file = 0;
239 gcov_var.length = 0;
240 }
241#if !IN_LIBGCOV
242 free (gcov_var.buffer);
243 gcov_var.alloc = 0;
244 gcov_var.buffer = 0;
245#endif
80abd9e4 246 gcov_var.mode = 0;
247 return gcov_var.error;
248}
249
b4d48d67 250#if !IN_LIBGCOV
251/* Check if MAGIC is EXPECTED. Use it to determine endianness of the
252 file. Returns +1 for same endian, -1 for other endian and zero for
253 not EXPECTED. */
254
255GCOV_LINKAGE int
256gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
257{
258 if (magic == expected)
259 return 1;
260 magic = (magic >> 16) | (magic << 16);
261 magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
262 if (magic == expected)
263 {
264 gcov_var.endian = 1;
265 return -1;
266 }
267 return 0;
268}
269#endif
270
80abd9e4 271#if !IN_LIBGCOV
272static void
273gcov_allocate (unsigned length)
274{
275 size_t new_size = gcov_var.alloc;
48e1416a 276
80abd9e4 277 if (!new_size)
278 new_size = GCOV_BLOCK_SIZE;
279 new_size += length;
280 new_size *= 2;
48e1416a 281
80abd9e4 282 gcov_var.alloc = new_size;
2457c754 283 gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2);
44359ced 284}
80abd9e4 285#endif
44359ced 286
287#if !IN_GCOV
80abd9e4 288/* Write out the current block, if needs be. */
289
290static void
291gcov_write_block (unsigned size)
292{
9e0943d4 293 if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
80abd9e4 294 gcov_var.error = 1;
295 gcov_var.start += size;
296 gcov_var.offset -= size;
297}
298
44359ced 299/* Allocate space to write BYTES bytes to the gcov file. Return a
300 pointer to those bytes, or NULL on failure. */
301
b4d48d67 302static gcov_unsigned_t *
9e0943d4 303gcov_write_words (unsigned words)
44359ced 304{
b4d48d67 305 gcov_unsigned_t *result;
44359ced 306
f1919901 307 gcov_nonruntime_assert (gcov_var.mode < 0);
44359ced 308#if IN_LIBGCOV
80abd9e4 309 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
310 {
311 gcov_write_block (GCOV_BLOCK_SIZE);
312 if (gcov_var.offset)
44359ced 313 {
80abd9e4 314 memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
44359ced 315 }
80abd9e4 316 }
44359ced 317#else
9e0943d4 318 if (gcov_var.offset + words > gcov_var.alloc)
319 gcov_allocate (gcov_var.offset + words);
44359ced 320#endif
9e0943d4 321 result = &gcov_var.buffer[gcov_var.offset];
322 gcov_var.offset += words;
48e1416a 323
44359ced 324 return result;
325}
326
327/* Write unsigned VALUE to coverage file. Sets error flag
328 appropriately. */
329
330GCOV_LINKAGE void
834f169c 331gcov_write_unsigned (gcov_unsigned_t value)
44359ced 332{
9e0943d4 333 gcov_unsigned_t *buffer = gcov_write_words (1);
44359ced 334
b4d48d67 335 buffer[0] = value;
44359ced 336}
337
338/* Write counter VALUE to coverage file. Sets error flag
339 appropriately. */
340
341#if IN_LIBGCOV
342GCOV_LINKAGE void
343gcov_write_counter (gcov_type value)
344{
9e0943d4 345 gcov_unsigned_t *buffer = gcov_write_words (2);
44359ced 346
b4d48d67 347 buffer[0] = (gcov_unsigned_t) value;
348 if (sizeof (value) > sizeof (gcov_unsigned_t))
349 buffer[1] = (gcov_unsigned_t) (value >> 32);
350 else
351 buffer[1] = 0;
44359ced 352}
353#endif /* IN_LIBGCOV */
354
3f2c2dd8 355#if !IN_LIBGCOV
44359ced 356/* Write STRING to coverage file. Sets error flag on file
357 error, overflow flag on overflow */
358
359GCOV_LINKAGE void
360gcov_write_string (const char *string)
361{
362 unsigned length = 0;
b4d48d67 363 unsigned alloc = 0;
364 gcov_unsigned_t *buffer;
44359ced 365
366 if (string)
367 {
368 length = strlen (string);
b4d48d67 369 alloc = (length + 4) >> 2;
44359ced 370 }
48e1416a 371
9e0943d4 372 buffer = gcov_write_words (1 + alloc);
80abd9e4 373
b4d48d67 374 buffer[0] = alloc;
375 buffer[alloc] = 0;
376 memcpy (&buffer[1], string, length);
44359ced 377}
3f2c2dd8 378#endif
44359ced 379
3ddf7676 380#if !IN_LIBGCOV
44359ced 381/* Write a tag TAG and reserve space for the record length. Return a
382 value to be used for gcov_write_length. */
383
834f169c 384GCOV_LINKAGE gcov_position_t
385gcov_write_tag (gcov_unsigned_t tag)
44359ced 386{
80abd9e4 387 gcov_position_t result = gcov_var.start + gcov_var.offset;
9e0943d4 388 gcov_unsigned_t *buffer = gcov_write_words (2);
44359ced 389
b4d48d67 390 buffer[0] = tag;
391 buffer[1] = 0;
48e1416a 392
44359ced 393 return result;
394}
395
396/* Write a record length using POSITION, which was returned by
397 gcov_write_tag. The current file position is the end of the
398 record, and is restored before returning. Returns nonzero on
399 overflow. */
400
401GCOV_LINKAGE void
834f169c 402gcov_write_length (gcov_position_t position)
44359ced 403{
80abd9e4 404 unsigned offset;
405 gcov_unsigned_t length;
b4d48d67 406 gcov_unsigned_t *buffer;
80abd9e4 407
f1919901 408 gcov_nonruntime_assert (gcov_var.mode < 0);
409 gcov_nonruntime_assert (position + 2 <= gcov_var.start + gcov_var.offset);
410 gcov_nonruntime_assert (position >= gcov_var.start);
80abd9e4 411 offset = position - gcov_var.start;
9e0943d4 412 length = gcov_var.offset - offset - 2;
b4d48d67 413 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
414 buffer[1] = length;
80abd9e4 415 if (gcov_var.offset >= GCOV_BLOCK_SIZE)
416 gcov_write_block (gcov_var.offset);
44359ced 417}
834f169c 418
419#else /* IN_LIBGCOV */
3ddf7676 420
421/* Write a tag TAG and length LENGTH. */
422
423GCOV_LINKAGE void
834f169c 424gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
3ddf7676 425{
9e0943d4 426 gcov_unsigned_t *buffer = gcov_write_words (2);
3ddf7676 427
b4d48d67 428 buffer[0] = tag;
429 buffer[1] = length;
3ddf7676 430}
44359ced 431
7ef5b942 432/* Write a summary structure to the gcov file. Return nonzero on
44359ced 433 overflow. */
434
435GCOV_LINKAGE void
834f169c 436gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
44359ced 437{
2c2093b3 438 unsigned ix, h_ix, bv_ix, h_cnt = 0;
ab6a34f2 439 const struct gcov_ctr_summary *csum;
2c2093b3 440 unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE];
441
442 /* Count number of non-zero histogram entries, and fill in a bit vector
443 of non-zero indices. The histogram is only currently computed for arc
444 counters. */
445 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
446 histo_bitvector[bv_ix] = 0;
447 csum = &summary->ctrs[GCOV_COUNTER_ARCS];
448 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
449 {
450 if (csum->histogram[h_ix].num_counters > 0)
451 {
452 histo_bitvector[h_ix / 32] |= 1 << (h_ix % 32);
453 h_cnt++;
454 }
455 }
9af5ce0c 456 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH (h_cnt));
44359ced 457 gcov_write_unsigned (summary->checksum);
834f169c 458 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
ab6a34f2 459 {
460 gcov_write_unsigned (csum->num);
461 gcov_write_unsigned (csum->runs);
462 gcov_write_counter (csum->sum_all);
463 gcov_write_counter (csum->run_max);
464 gcov_write_counter (csum->sum_max);
2c2093b3 465 if (ix != GCOV_COUNTER_ARCS)
466 {
467 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
468 gcov_write_unsigned (0);
469 continue;
470 }
471 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
472 gcov_write_unsigned (histo_bitvector[bv_ix]);
473 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
474 {
475 if (!csum->histogram[h_ix].num_counters)
476 continue;
477 gcov_write_unsigned (csum->histogram[h_ix].num_counters);
478 gcov_write_counter (csum->histogram[h_ix].min_value);
479 gcov_write_counter (csum->histogram[h_ix].cum_value);
480 }
ab6a34f2 481 }
44359ced 482}
483#endif /* IN_LIBGCOV */
484
485#endif /*!IN_GCOV */
486
487/* Return a pointer to read BYTES bytes from the gcov file. Returns
6473f3f4 488 NULL on failure (read past EOF). */
44359ced 489
b4d48d67 490static const gcov_unsigned_t *
9e0943d4 491gcov_read_words (unsigned words)
44359ced 492{
b4d48d67 493 const gcov_unsigned_t *result;
80abd9e4 494 unsigned excess = gcov_var.length - gcov_var.offset;
48e1416a 495
f1919901 496 gcov_nonruntime_assert (gcov_var.mode > 0);
9e0943d4 497 if (excess < words)
44359ced 498 {
80abd9e4 499 gcov_var.start += gcov_var.offset;
80abd9e4 500 if (excess)
501 {
d69521d8 502#if IN_LIBGCOV
80abd9e4 503 memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4);
80abd9e4 504#else
d69521d8 505 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset,
506 excess * 4);
80abd9e4 507#endif
d69521d8 508 }
80abd9e4 509 gcov_var.offset = 0;
510 gcov_var.length = excess;
511#if IN_LIBGCOV
80abd9e4 512 excess = GCOV_BLOCK_SIZE;
513#else
9e0943d4 514 if (gcov_var.length + words > gcov_var.alloc)
515 gcov_allocate (gcov_var.length + words);
80abd9e4 516 excess = gcov_var.alloc - gcov_var.length;
517#endif
1278fdc3 518 excess = fread (gcov_var.buffer + gcov_var.length,
9e0943d4 519 1, excess << 2, gcov_var.file) >> 2;
80abd9e4 520 gcov_var.length += excess;
9e0943d4 521 if (gcov_var.length < words)
80abd9e4 522 {
9e0943d4 523 gcov_var.overread += words - gcov_var.length;
80abd9e4 524 gcov_var.length = 0;
525 return 0;
526 }
44359ced 527 }
9e0943d4 528 result = &gcov_var.buffer[gcov_var.offset];
529 gcov_var.offset += words;
44359ced 530 return result;
531}
532
533/* Read unsigned value from a coverage file. Sets error flag on file
534 error, overflow flag on overflow */
535
834f169c 536GCOV_LINKAGE gcov_unsigned_t
53b2c31f 537gcov_read_unsigned (void)
44359ced 538{
b4d48d67 539 gcov_unsigned_t value;
9e0943d4 540 const gcov_unsigned_t *buffer = gcov_read_words (1);
44359ced 541
542 if (!buffer)
543 return 0;
b4d48d67 544 value = from_file (buffer[0]);
44359ced 545 return value;
546}
547
548/* Read counter value from a coverage file. Sets error flag on file
549 error, overflow flag on overflow */
550
551GCOV_LINKAGE gcov_type
53b2c31f 552gcov_read_counter (void)
44359ced 553{
b4d48d67 554 gcov_type value;
9e0943d4 555 const gcov_unsigned_t *buffer = gcov_read_words (2);
44359ced 556
557 if (!buffer)
558 return 0;
b4d48d67 559 value = from_file (buffer[0]);
560 if (sizeof (value) > sizeof (gcov_unsigned_t))
561 value |= ((gcov_type) from_file (buffer[1])) << 32;
562 else if (buffer[1])
563 gcov_var.error = -1;
8a5df2ce 564
44359ced 565 return value;
566}
567
e76f6040 568/* We need to expose the below function when compiling for gcov-tool. */
569
570#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
44359ced 571/* Read string from coverage file. Returns a pointer to a static
572 buffer, or NULL on empty string. You must copy the string before
573 calling another gcov function. */
574
575GCOV_LINKAGE const char *
53b2c31f 576gcov_read_string (void)
44359ced 577{
578 unsigned length = gcov_read_unsigned ();
48e1416a 579
44359ced 580 if (!length)
581 return 0;
582
9e0943d4 583 return (const char *) gcov_read_words (length);
44359ced 584}
3f2c2dd8 585#endif
44359ced 586
587GCOV_LINKAGE void
588gcov_read_summary (struct gcov_summary *summary)
589{
2c2093b3 590 unsigned ix, h_ix, bv_ix, h_cnt = 0;
ab6a34f2 591 struct gcov_ctr_summary *csum;
2c2093b3 592 unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE];
593 unsigned cur_bitvector;
48e1416a 594
44359ced 595 summary->checksum = gcov_read_unsigned ();
834f169c 596 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
ab6a34f2 597 {
598 csum->num = gcov_read_unsigned ();
599 csum->runs = gcov_read_unsigned ();
600 csum->sum_all = gcov_read_counter ();
601 csum->run_max = gcov_read_counter ();
602 csum->sum_max = gcov_read_counter ();
2c2093b3 603 memset (csum->histogram, 0,
604 sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
605 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++)
606 {
607 histo_bitvector[bv_ix] = gcov_read_unsigned ();
960a9b56 608#if IN_LIBGCOV
609 /* When building libgcov we don't include system.h, which includes
610 hwint.h (where popcount_hwi is declared). However, libgcov.a
611 is built by the bootstrapped compiler and therefore the builtins
612 are always available. */
613 h_cnt += __builtin_popcount (histo_bitvector[bv_ix]);
614#else
615 h_cnt += popcount_hwi (histo_bitvector[bv_ix]);
616#endif
2c2093b3 617 }
618 bv_ix = 0;
619 h_ix = 0;
620 cur_bitvector = 0;
621 while (h_cnt--)
622 {
623 /* Find the index corresponding to the next entry we will read in.
624 First find the next non-zero bitvector and re-initialize
625 the histogram index accordingly, then right shift and increment
626 the index until we find a set bit. */
627 while (!cur_bitvector)
628 {
629 h_ix = bv_ix * 32;
f1919901 630 if (bv_ix >= GCOV_HISTOGRAM_BITVECTOR_SIZE)
631 gcov_error ("corrupted profile info: summary histogram "
632 "bitvector is corrupt");
2c2093b3 633 cur_bitvector = histo_bitvector[bv_ix++];
2c2093b3 634 }
635 while (!(cur_bitvector & 0x1))
636 {
637 h_ix++;
638 cur_bitvector >>= 1;
639 }
f1919901 640 if (h_ix >= GCOV_HISTOGRAM_SIZE)
641 gcov_error ("corrupted profile info: summary histogram "
642 "index is corrupt");
2c2093b3 643
644 csum->histogram[h_ix].num_counters = gcov_read_unsigned ();
645 csum->histogram[h_ix].min_value = gcov_read_counter ();
646 csum->histogram[h_ix].cum_value = gcov_read_counter ();
647 /* Shift off the index we are done with and increment to the
648 corresponding next histogram entry. */
649 cur_bitvector >>= 1;
650 h_ix++;
651 }
ab6a34f2 652 }
44359ced 653}
654
e76f6040 655/* We need to expose the below function when compiling for gcov-tool. */
656
657#if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
80abd9e4 658/* Reset to a known position. BASE should have been obtained from
659 gcov_position, LENGTH should be a record length. */
660
661GCOV_LINKAGE void
662gcov_sync (gcov_position_t base, gcov_unsigned_t length)
663{
f1919901 664 gcov_nonruntime_assert (gcov_var.mode > 0);
80abd9e4 665 base += length;
666 if (base - gcov_var.start <= gcov_var.length)
667 gcov_var.offset = base - gcov_var.start;
668 else
669 {
670 gcov_var.offset = gcov_var.length = 0;
9e0943d4 671 fseek (gcov_var.file, base << 2, SEEK_SET);
672 gcov_var.start = ftell (gcov_var.file) >> 2;
80abd9e4 673 }
674}
675#endif
676
677#if IN_LIBGCOV
f0b5f617 678/* Move to a given position in a gcov file. */
80abd9e4 679
680GCOV_LINKAGE void
681gcov_seek (gcov_position_t base)
682{
80abd9e4 683 if (gcov_var.offset)
684 gcov_write_block (gcov_var.offset);
421055ca 685 fseek (gcov_var.file, base << 2, SEEK_SET);
9e0943d4 686 gcov_var.start = ftell (gcov_var.file) >> 2;
80abd9e4 687}
688#endif
689
44359ced 690#if IN_GCOV > 0
691/* Return the modification time of the current gcov file. */
692
693GCOV_LINKAGE time_t
53b2c31f 694gcov_time (void)
44359ced 695{
696 struct stat status;
48e1416a 697
44359ced 698 if (fstat (fileno (gcov_var.file), &status))
699 return 0;
700 else
701 return status.st_mtime;
702}
703#endif /* IN_GCOV */
2c2093b3 704
e3ba12e8 705#if !IN_GCOV
2c2093b3 706/* Determine the index into histogram for VALUE. */
707
e3ba12e8 708#if IN_LIBGCOV
2c2093b3 709static unsigned
e3ba12e8 710#else
711GCOV_LINKAGE unsigned
712#endif
713gcov_histo_index (gcov_type value)
2c2093b3 714{
715 gcov_type_unsigned v = (gcov_type_unsigned)value;
716 unsigned r = 0;
717 unsigned prev2bits = 0;
718
719 /* Find index into log2 scale histogram, where each of the log2
720 sized buckets is divided into 4 linear sub-buckets for better
721 focus in the higher buckets. */
722
723 /* Find the place of the most-significant bit set. */
724 if (v > 0)
960a9b56 725 {
726#if IN_LIBGCOV
727 /* When building libgcov we don't include system.h, which includes
728 hwint.h (where floor_log2 is declared). However, libgcov.a
729 is built by the bootstrapped compiler and therefore the builtins
730 are always available. */
731 r = sizeof (long long) * __CHAR_BIT__ - 1 - __builtin_clzll (v);
732#else
733 /* We use floor_log2 from hwint.c, which takes a HOST_WIDE_INT
3a4303e7 734 that is 64 bits and gcov_type_unsigned is 64 bits. */
960a9b56 735 r = floor_log2 (v);
960a9b56 736#endif
737 }
2c2093b3 738
739 /* If at most the 2 least significant bits are set (value is
740 0 - 3) then that value is our index into the lowest set of
741 four buckets. */
742 if (r < 2)
743 return (unsigned)value;
744
f1919901 745 gcov_nonruntime_assert (r < 64);
2c2093b3 746
747 /* Find the two next most significant bits to determine which
748 of the four linear sub-buckets to select. */
749 prev2bits = (v >> (r - 2)) & 0x3;
750 /* Finally, compose the final bucket index from the log2 index and
751 the next 2 bits. The minimum r value at this point is 2 since we
752 returned above if r was 2 or more, so the minimum bucket at this
753 point is 4. */
754 return (r - 1) * 4 + prev2bits;
755}
756
757/* Merge SRC_HISTO into TGT_HISTO. The counters are assumed to be in
758 the same relative order in both histograms, and are matched up
759 and merged in reverse order. Each counter is assigned an equal portion of
760 its entry's original cumulative counter value when computing the
761 new merged cum_value. */
762
e3ba12e8 763static void gcov_histogram_merge (gcov_bucket_type *tgt_histo,
764 gcov_bucket_type *src_histo)
2c2093b3 765{
766 int src_i, tgt_i, tmp_i = 0;
767 unsigned src_num, tgt_num, merge_num;
768 gcov_type src_cum, tgt_cum, merge_src_cum, merge_tgt_cum, merge_cum;
769 gcov_type merge_min;
770 gcov_bucket_type tmp_histo[GCOV_HISTOGRAM_SIZE];
771 int src_done = 0;
772
9af5ce0c 773 memset (tmp_histo, 0, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
2c2093b3 774
775 /* Assume that the counters are in the same relative order in both
776 histograms. Walk the histograms from largest to smallest entry,
777 matching up and combining counters in order. */
778 src_num = 0;
779 src_cum = 0;
780 src_i = GCOV_HISTOGRAM_SIZE - 1;
781 for (tgt_i = GCOV_HISTOGRAM_SIZE - 1; tgt_i >= 0 && !src_done; tgt_i--)
782 {
783 tgt_num = tgt_histo[tgt_i].num_counters;
784 tgt_cum = tgt_histo[tgt_i].cum_value;
785 /* Keep going until all of the target histogram's counters at this
786 position have been matched and merged with counters from the
787 source histogram. */
788 while (tgt_num > 0 && !src_done)
789 {
790 /* If this is either the first time through this loop or we just
791 exhausted the previous non-zero source histogram entry, look
792 for the next non-zero source histogram entry. */
793 if (!src_num)
794 {
795 /* Locate the next non-zero entry. */
796 while (src_i >= 0 && !src_histo[src_i].num_counters)
797 src_i--;
798 /* If source histogram has fewer counters, then just copy over the
799 remaining target counters and quit. */
800 if (src_i < 0)
801 {
802 tmp_histo[tgt_i].num_counters += tgt_num;
803 tmp_histo[tgt_i].cum_value += tgt_cum;
804 if (!tmp_histo[tgt_i].min_value ||
805 tgt_histo[tgt_i].min_value < tmp_histo[tgt_i].min_value)
806 tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value;
807 while (--tgt_i >= 0)
808 {
809 tmp_histo[tgt_i].num_counters
810 += tgt_histo[tgt_i].num_counters;
811 tmp_histo[tgt_i].cum_value += tgt_histo[tgt_i].cum_value;
812 if (!tmp_histo[tgt_i].min_value ||
813 tgt_histo[tgt_i].min_value
814 < tmp_histo[tgt_i].min_value)
815 tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value;
816 }
817
818 src_done = 1;
819 break;
820 }
821
822 src_num = src_histo[src_i].num_counters;
823 src_cum = src_histo[src_i].cum_value;
824 }
825
826 /* The number of counters to merge on this pass is the minimum
827 of the remaining counters from the current target and source
828 histogram entries. */
829 merge_num = tgt_num;
830 if (src_num < merge_num)
831 merge_num = src_num;
832
833 /* The merged min_value is the sum of the min_values from target
834 and source. */
835 merge_min = tgt_histo[tgt_i].min_value + src_histo[src_i].min_value;
836
837 /* Compute the portion of source and target entries' cum_value
838 that will be apportioned to the counters being merged.
839 The total remaining cum_value from each entry is divided
840 equally among the counters from that histogram entry if we
841 are not merging all of them. */
842 merge_src_cum = src_cum;
843 if (merge_num < src_num)
844 merge_src_cum = merge_num * src_cum / src_num;
845 merge_tgt_cum = tgt_cum;
846 if (merge_num < tgt_num)
847 merge_tgt_cum = merge_num * tgt_cum / tgt_num;
848 /* The merged cum_value is the sum of the source and target
849 components. */
850 merge_cum = merge_src_cum + merge_tgt_cum;
851
852 /* Update the remaining number of counters and cum_value left
853 to be merged from this source and target entry. */
854 src_cum -= merge_src_cum;
855 tgt_cum -= merge_tgt_cum;
856 src_num -= merge_num;
857 tgt_num -= merge_num;
858
859 /* The merged counters get placed in the new merged histogram
860 at the entry for the merged min_value. */
9af5ce0c 861 tmp_i = gcov_histo_index (merge_min);
f1919901 862 gcov_nonruntime_assert (tmp_i < GCOV_HISTOGRAM_SIZE);
2c2093b3 863 tmp_histo[tmp_i].num_counters += merge_num;
864 tmp_histo[tmp_i].cum_value += merge_cum;
865 if (!tmp_histo[tmp_i].min_value ||
866 merge_min < tmp_histo[tmp_i].min_value)
867 tmp_histo[tmp_i].min_value = merge_min;
868
869 /* Ensure the search for the next non-zero src_histo entry starts
870 at the next smallest histogram bucket. */
871 if (!src_num)
872 src_i--;
873 }
874 }
875
f1919901 876 gcov_nonruntime_assert (tgt_i < 0);
2c2093b3 877
878 /* In the case where there were more counters in the source histogram,
879 accumulate the remaining unmerged cumulative counter values. Add
880 those to the smallest non-zero target histogram entry. Otherwise,
881 the total cumulative counter values in the histogram will be smaller
882 than the sum_all stored in the summary, which will complicate
883 computing the working set information from the histogram later on. */
884 if (src_num)
885 src_i--;
886 while (src_i >= 0)
887 {
888 src_cum += src_histo[src_i].cum_value;
889 src_i--;
890 }
891 /* At this point, tmp_i should be the smallest non-zero entry in the
892 tmp_histo. */
f1919901 893 gcov_nonruntime_assert (tmp_i >= 0 && tmp_i < GCOV_HISTOGRAM_SIZE
894 && tmp_histo[tmp_i].num_counters > 0);
2c2093b3 895 tmp_histo[tmp_i].cum_value += src_cum;
896
897 /* Finally, copy the merged histogram into tgt_histo. */
9af5ce0c 898 memcpy (tgt_histo, tmp_histo,
899 sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
2c2093b3 900}
e3ba12e8 901#endif /* !IN_GCOV */
8515a84d 902
903/* This is used by gcov-dump (IN_GCOV == -1) and in the compiler
904 (!IN_GCOV && !IN_LIBGCOV). */
905#if IN_GCOV <= 0 && !IN_LIBGCOV
906/* Compute the working set information from the counter histogram in
907 the profile summary. This is an array of information corresponding to a
908 range of percentages of the total execution count (sum_all), and includes
909 the number of counters required to cover that working set percentage and
910 the minimum counter value in that working set. */
911
912GCOV_LINKAGE void
913compute_working_sets (const struct gcov_ctr_summary *summary,
914 gcov_working_set_t *gcov_working_sets)
915{
916 gcov_type working_set_cum_values[NUM_GCOV_WORKING_SETS];
917 gcov_type ws_cum_hotness_incr;
918 gcov_type cum, tmp_cum;
919 const gcov_bucket_type *histo_bucket;
920 unsigned ws_ix, c_num, count;
921 int h_ix;
922
923 /* Compute the amount of sum_all that the cumulative hotness grows
924 by in each successive working set entry, which depends on the
925 number of working set entries. */
926 ws_cum_hotness_incr = summary->sum_all / NUM_GCOV_WORKING_SETS;
927
928 /* Next fill in an array of the cumulative hotness values corresponding
929 to each working set summary entry we are going to compute below.
930 Skip 0% statistics, which can be extrapolated from the
931 rest of the summary data. */
932 cum = ws_cum_hotness_incr;
933 for (ws_ix = 0; ws_ix < NUM_GCOV_WORKING_SETS;
934 ws_ix++, cum += ws_cum_hotness_incr)
935 working_set_cum_values[ws_ix] = cum;
936 /* The last summary entry is reserved for (roughly) 99.9% of the
937 working set. Divide by 1024 so it becomes a shift, which gives
938 almost exactly 99.9%. */
939 working_set_cum_values[NUM_GCOV_WORKING_SETS-1]
940 = summary->sum_all - summary->sum_all/1024;
941
942 /* Next, walk through the histogram in decending order of hotness
943 and compute the statistics for the working set summary array.
944 As histogram entries are accumulated, we check to see which
945 working set entries have had their expected cum_value reached
946 and fill them in, walking the working set entries in increasing
947 size of cum_value. */
948 ws_ix = 0; /* The current entry into the working set array. */
949 cum = 0; /* The current accumulated counter sum. */
950 count = 0; /* The current accumulated count of block counters. */
951 for (h_ix = GCOV_HISTOGRAM_SIZE - 1;
952 h_ix >= 0 && ws_ix < NUM_GCOV_WORKING_SETS; h_ix--)
953 {
954 histo_bucket = &summary->histogram[h_ix];
955
956 /* If we haven't reached the required cumulative counter value for
957 the current working set percentage, simply accumulate this histogram
958 entry into the running sums and continue to the next histogram
959 entry. */
960 if (cum + histo_bucket->cum_value < working_set_cum_values[ws_ix])
961 {
962 cum += histo_bucket->cum_value;
963 count += histo_bucket->num_counters;
964 continue;
965 }
966
967 /* If adding the current histogram entry's cumulative counter value
968 causes us to exceed the current working set size, then estimate
969 how many of this histogram entry's counter values are required to
970 reach the working set size, and fill in working set entries
971 as we reach their expected cumulative value. */
972 for (c_num = 0, tmp_cum = cum;
973 c_num < histo_bucket->num_counters && ws_ix < NUM_GCOV_WORKING_SETS;
974 c_num++)
975 {
976 count++;
977 /* If we haven't reached the last histogram entry counter, add
978 in the minimum value again. This will underestimate the
979 cumulative sum so far, because many of the counter values in this
980 entry may have been larger than the minimum. We could add in the
981 average value every time, but that would require an expensive
982 divide operation. */
983 if (c_num + 1 < histo_bucket->num_counters)
984 tmp_cum += histo_bucket->min_value;
985 /* If we have reached the last histogram entry counter, then add
986 in the entire cumulative value. */
987 else
988 tmp_cum = cum + histo_bucket->cum_value;
989
990 /* Next walk through successive working set entries and fill in
991 the statistics for any whose size we have reached by accumulating
992 this histogram counter. */
993 while (ws_ix < NUM_GCOV_WORKING_SETS
994 && tmp_cum >= working_set_cum_values[ws_ix])
995 {
996 gcov_working_sets[ws_ix].num_counters = count;
997 gcov_working_sets[ws_ix].min_counter
998 = histo_bucket->min_value;
999 ws_ix++;
1000 }
1001 }
1002 /* Finally, update the running cumulative value since we were
1003 using a temporary above. */
1004 cum += histo_bucket->cum_value;
1005 }
f1919901 1006 gcov_nonruntime_assert (ws_ix == NUM_GCOV_WORKING_SETS);
8515a84d 1007}
1008#endif /* IN_GCOV <= 0 && !IN_LIBGCOV */