]>
Commit | Line | Data |
---|---|---|
44359ced | 1 | /* File format for coverage information |
f0b5f617 | 2 | Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007, |
71e45bc2 | 3 | 2008, 2011, 2012 Free Software Foundation, Inc. |
44359ced | 4 | Contributed by Bob Manson <manson@cygnus.com>. |
5 | Completely remangled by Nathan Sidwell <nathan@codesourcery.com>. | |
6 | ||
7 | This file is part of GCC. | |
8 | ||
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 | |
8c4c00c1 | 11 | Software Foundation; either version 3, or (at your option) any later |
44359ced | 12 | version. |
13 | ||
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. | |
18 | ||
cf09cacb | 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. | |
22 | ||
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 | |
8c4c00c1 | 26 | <http://www.gnu.org/licenses/>. */ |
44359ced | 27 | |
28 | /* Routines declared in gcov-io.h. This file should be #included by | |
29 | another source file, after having #included gcov-io.h. */ | |
30 | ||
80abd9e4 | 31 | #if !IN_GCOV |
32 | static void gcov_write_block (unsigned); | |
9e0943d4 | 33 | static gcov_unsigned_t *gcov_write_words (unsigned); |
80abd9e4 | 34 | #endif |
9e0943d4 | 35 | static const gcov_unsigned_t *gcov_read_words (unsigned); |
80abd9e4 | 36 | #if !IN_LIBGCOV |
37 | static void gcov_allocate (unsigned); | |
38 | #endif | |
39 | ||
b4d48d67 | 40 | static inline gcov_unsigned_t from_file (gcov_unsigned_t value) |
41 | { | |
42 | #if !IN_LIBGCOV | |
43 | if (gcov_var.endian) | |
44 | { | |
45 | value = (value >> 16) | (value << 16); | |
46 | value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff); | |
47 | } | |
48 | #endif | |
49 | return value; | |
50 | } | |
51 | ||
44359ced | 52 | /* Open a gcov file. NAME is the name of the file to open and MODE |
53 | indicates whether a new file should be created, or an existing file | |
35ab2622 | 54 | opened. If MODE is >= 0 an existing file will be opened, if |
55 | possible, and if MODE is <= 0, a new file will be created. Use | |
56 | MODE=0 to attempt to reopen an existing file and then fall back on | |
57 | creating a new one. If MODE < 0, the file will be opened in | |
58 | read-only mode. Otherwise it will be opened for modification. | |
59 | Return zero on failure, >0 on opening an existing file and <0 on | |
60 | creating a new one. */ | |
44359ced | 61 | |
62 | GCOV_LINKAGE int | |
b4d48d67 | 63 | #if IN_LIBGCOV |
64 | gcov_open (const char *name) | |
65 | #else | |
44359ced | 66 | gcov_open (const char *name, int mode) |
b4d48d67 | 67 | #endif |
44359ced | 68 | { |
b4d48d67 | 69 | #if IN_LIBGCOV |
70 | const int mode = 0; | |
71 | #endif | |
3ddf7676 | 72 | #if GCOV_LOCKED |
44359ced | 73 | struct flock s_flock; |
9131ff41 | 74 | int fd; |
44359ced | 75 | |
44359ced | 76 | s_flock.l_whence = SEEK_SET; |
77 | s_flock.l_start = 0; | |
78 | s_flock.l_len = 0; /* Until EOF. */ | |
79 | s_flock.l_pid = getpid (); | |
80 | #endif | |
48e1416a | 81 | |
631ceed1 | 82 | gcc_assert (!gcov_var.file); |
80abd9e4 | 83 | gcov_var.start = 0; |
84 | gcov_var.offset = gcov_var.length = 0; | |
9e0943d4 | 85 | gcov_var.overread = -1u; |
80abd9e4 | 86 | gcov_var.error = 0; |
b4d48d67 | 87 | #if !IN_LIBGCOV |
88 | gcov_var.endian = 0; | |
89 | #endif | |
9131ff41 | 90 | #if GCOV_LOCKED |
91 | if (mode > 0) | |
35ab2622 | 92 | { |
93 | /* Read-only mode - acquire a read-lock. */ | |
94 | s_flock.l_type = F_RDLCK; | |
d3cf0a31 | 95 | /* pass mode (ignored) for compatibility */ |
96 | fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR); | |
35ab2622 | 97 | } |
9131ff41 | 98 | else |
35ab2622 | 99 | { |
100 | /* Write mode - acquire a write-lock. */ | |
101 | s_flock.l_type = F_WRLCK; | |
102 | fd = open (name, O_RDWR | O_CREAT, 0666); | |
103 | } | |
9131ff41 | 104 | if (fd < 0) |
105 | return 0; | |
106 | ||
107 | while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) | |
108 | continue; | |
109 | ||
35ab2622 | 110 | gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b"); |
111 | ||
9131ff41 | 112 | if (!gcov_var.file) |
113 | { | |
114 | close (fd); | |
115 | return 0; | |
116 | } | |
117 | ||
118 | if (mode > 0) | |
119 | gcov_var.mode = 1; | |
120 | else if (mode == 0) | |
121 | { | |
122 | struct stat st; | |
123 | ||
124 | if (fstat (fd, &st) < 0) | |
125 | { | |
126 | fclose (gcov_var.file); | |
127 | gcov_var.file = 0; | |
128 | return 0; | |
129 | } | |
130 | if (st.st_size != 0) | |
131 | gcov_var.mode = 1; | |
132 | else | |
133 | gcov_var.mode = mode * 2 + 1; | |
134 | } | |
135 | else | |
136 | gcov_var.mode = mode * 2 + 1; | |
137 | #else | |
44359ced | 138 | if (mode >= 0) |
35ab2622 | 139 | gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b"); |
140 | ||
80abd9e4 | 141 | if (gcov_var.file) |
142 | gcov_var.mode = 1; | |
143 | else if (mode <= 0) | |
44359ced | 144 | { |
44359ced | 145 | gcov_var.file = fopen (name, "w+b"); |
80abd9e4 | 146 | if (gcov_var.file) |
b4d48d67 | 147 | gcov_var.mode = mode * 2 + 1; |
44359ced | 148 | } |
149 | if (!gcov_var.file) | |
150 | return 0; | |
44359ced | 151 | #endif |
152 | ||
9131ff41 | 153 | setbuf (gcov_var.file, (char *)0); |
48e1416a | 154 | |
b4d48d67 | 155 | return 1; |
44359ced | 156 | } |
157 | ||
158 | /* Close the current gcov file. Flushes data to disk. Returns nonzero | |
159 | on failure or error flag set. */ | |
160 | ||
161 | GCOV_LINKAGE int | |
53b2c31f | 162 | gcov_close (void) |
44359ced | 163 | { |
44359ced | 164 | if (gcov_var.file) |
165 | { | |
80abd9e4 | 166 | #if !IN_GCOV |
167 | if (gcov_var.offset && gcov_var.mode < 0) | |
168 | gcov_write_block (gcov_var.offset); | |
169 | #endif | |
44359ced | 170 | fclose (gcov_var.file); |
171 | gcov_var.file = 0; | |
172 | gcov_var.length = 0; | |
173 | } | |
174 | #if !IN_LIBGCOV | |
175 | free (gcov_var.buffer); | |
176 | gcov_var.alloc = 0; | |
177 | gcov_var.buffer = 0; | |
178 | #endif | |
80abd9e4 | 179 | gcov_var.mode = 0; |
180 | return gcov_var.error; | |
181 | } | |
182 | ||
b4d48d67 | 183 | #if !IN_LIBGCOV |
184 | /* Check if MAGIC is EXPECTED. Use it to determine endianness of the | |
185 | file. Returns +1 for same endian, -1 for other endian and zero for | |
186 | not EXPECTED. */ | |
187 | ||
188 | GCOV_LINKAGE int | |
189 | gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected) | |
190 | { | |
191 | if (magic == expected) | |
192 | return 1; | |
193 | magic = (magic >> 16) | (magic << 16); | |
194 | magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff); | |
195 | if (magic == expected) | |
196 | { | |
197 | gcov_var.endian = 1; | |
198 | return -1; | |
199 | } | |
200 | return 0; | |
201 | } | |
202 | #endif | |
203 | ||
80abd9e4 | 204 | #if !IN_LIBGCOV |
205 | static void | |
206 | gcov_allocate (unsigned length) | |
207 | { | |
208 | size_t new_size = gcov_var.alloc; | |
48e1416a | 209 | |
80abd9e4 | 210 | if (!new_size) |
211 | new_size = GCOV_BLOCK_SIZE; | |
212 | new_size += length; | |
213 | new_size *= 2; | |
48e1416a | 214 | |
80abd9e4 | 215 | gcov_var.alloc = new_size; |
2457c754 | 216 | gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2); |
44359ced | 217 | } |
80abd9e4 | 218 | #endif |
44359ced | 219 | |
220 | #if !IN_GCOV | |
80abd9e4 | 221 | /* Write out the current block, if needs be. */ |
222 | ||
223 | static void | |
224 | gcov_write_block (unsigned size) | |
225 | { | |
9e0943d4 | 226 | if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1) |
80abd9e4 | 227 | gcov_var.error = 1; |
228 | gcov_var.start += size; | |
229 | gcov_var.offset -= size; | |
230 | } | |
231 | ||
44359ced | 232 | /* Allocate space to write BYTES bytes to the gcov file. Return a |
233 | pointer to those bytes, or NULL on failure. */ | |
234 | ||
b4d48d67 | 235 | static gcov_unsigned_t * |
9e0943d4 | 236 | gcov_write_words (unsigned words) |
44359ced | 237 | { |
b4d48d67 | 238 | gcov_unsigned_t *result; |
44359ced | 239 | |
631ceed1 | 240 | gcc_assert (gcov_var.mode < 0); |
44359ced | 241 | #if IN_LIBGCOV |
80abd9e4 | 242 | if (gcov_var.offset >= GCOV_BLOCK_SIZE) |
243 | { | |
244 | gcov_write_block (GCOV_BLOCK_SIZE); | |
245 | if (gcov_var.offset) | |
44359ced | 246 | { |
631ceed1 | 247 | gcc_assert (gcov_var.offset == 1); |
80abd9e4 | 248 | memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); |
44359ced | 249 | } |
80abd9e4 | 250 | } |
44359ced | 251 | #else |
9e0943d4 | 252 | if (gcov_var.offset + words > gcov_var.alloc) |
253 | gcov_allocate (gcov_var.offset + words); | |
44359ced | 254 | #endif |
9e0943d4 | 255 | result = &gcov_var.buffer[gcov_var.offset]; |
256 | gcov_var.offset += words; | |
48e1416a | 257 | |
44359ced | 258 | return result; |
259 | } | |
260 | ||
261 | /* Write unsigned VALUE to coverage file. Sets error flag | |
262 | appropriately. */ | |
263 | ||
264 | GCOV_LINKAGE void | |
834f169c | 265 | gcov_write_unsigned (gcov_unsigned_t value) |
44359ced | 266 | { |
9e0943d4 | 267 | gcov_unsigned_t *buffer = gcov_write_words (1); |
44359ced | 268 | |
b4d48d67 | 269 | buffer[0] = value; |
44359ced | 270 | } |
271 | ||
272 | /* Write counter VALUE to coverage file. Sets error flag | |
273 | appropriately. */ | |
274 | ||
275 | #if IN_LIBGCOV | |
276 | GCOV_LINKAGE void | |
277 | gcov_write_counter (gcov_type value) | |
278 | { | |
9e0943d4 | 279 | gcov_unsigned_t *buffer = gcov_write_words (2); |
44359ced | 280 | |
b4d48d67 | 281 | buffer[0] = (gcov_unsigned_t) value; |
282 | if (sizeof (value) > sizeof (gcov_unsigned_t)) | |
283 | buffer[1] = (gcov_unsigned_t) (value >> 32); | |
284 | else | |
285 | buffer[1] = 0; | |
44359ced | 286 | } |
287 | #endif /* IN_LIBGCOV */ | |
288 | ||
3f2c2dd8 | 289 | #if !IN_LIBGCOV |
44359ced | 290 | /* Write STRING to coverage file. Sets error flag on file |
291 | error, overflow flag on overflow */ | |
292 | ||
293 | GCOV_LINKAGE void | |
294 | gcov_write_string (const char *string) | |
295 | { | |
296 | unsigned length = 0; | |
b4d48d67 | 297 | unsigned alloc = 0; |
298 | gcov_unsigned_t *buffer; | |
44359ced | 299 | |
300 | if (string) | |
301 | { | |
302 | length = strlen (string); | |
b4d48d67 | 303 | alloc = (length + 4) >> 2; |
44359ced | 304 | } |
48e1416a | 305 | |
9e0943d4 | 306 | buffer = gcov_write_words (1 + alloc); |
80abd9e4 | 307 | |
b4d48d67 | 308 | buffer[0] = alloc; |
309 | buffer[alloc] = 0; | |
310 | memcpy (&buffer[1], string, length); | |
44359ced | 311 | } |
3f2c2dd8 | 312 | #endif |
44359ced | 313 | |
3ddf7676 | 314 | #if !IN_LIBGCOV |
44359ced | 315 | /* Write a tag TAG and reserve space for the record length. Return a |
316 | value to be used for gcov_write_length. */ | |
317 | ||
834f169c | 318 | GCOV_LINKAGE gcov_position_t |
319 | gcov_write_tag (gcov_unsigned_t tag) | |
44359ced | 320 | { |
80abd9e4 | 321 | gcov_position_t result = gcov_var.start + gcov_var.offset; |
9e0943d4 | 322 | gcov_unsigned_t *buffer = gcov_write_words (2); |
44359ced | 323 | |
b4d48d67 | 324 | buffer[0] = tag; |
325 | buffer[1] = 0; | |
48e1416a | 326 | |
44359ced | 327 | return result; |
328 | } | |
329 | ||
330 | /* Write a record length using POSITION, which was returned by | |
331 | gcov_write_tag. The current file position is the end of the | |
332 | record, and is restored before returning. Returns nonzero on | |
333 | overflow. */ | |
334 | ||
335 | GCOV_LINKAGE void | |
834f169c | 336 | gcov_write_length (gcov_position_t position) |
44359ced | 337 | { |
80abd9e4 | 338 | unsigned offset; |
339 | gcov_unsigned_t length; | |
b4d48d67 | 340 | gcov_unsigned_t *buffer; |
80abd9e4 | 341 | |
631ceed1 | 342 | gcc_assert (gcov_var.mode < 0); |
343 | gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset); | |
344 | gcc_assert (position >= gcov_var.start); | |
80abd9e4 | 345 | offset = position - gcov_var.start; |
9e0943d4 | 346 | length = gcov_var.offset - offset - 2; |
b4d48d67 | 347 | buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset]; |
348 | buffer[1] = length; | |
80abd9e4 | 349 | if (gcov_var.offset >= GCOV_BLOCK_SIZE) |
350 | gcov_write_block (gcov_var.offset); | |
44359ced | 351 | } |
834f169c | 352 | |
353 | #else /* IN_LIBGCOV */ | |
3ddf7676 | 354 | |
355 | /* Write a tag TAG and length LENGTH. */ | |
356 | ||
357 | GCOV_LINKAGE void | |
834f169c | 358 | gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) |
3ddf7676 | 359 | { |
9e0943d4 | 360 | gcov_unsigned_t *buffer = gcov_write_words (2); |
3ddf7676 | 361 | |
b4d48d67 | 362 | buffer[0] = tag; |
363 | buffer[1] = length; | |
3ddf7676 | 364 | } |
44359ced | 365 | |
7ef5b942 | 366 | /* Write a summary structure to the gcov file. Return nonzero on |
44359ced | 367 | overflow. */ |
368 | ||
369 | GCOV_LINKAGE void | |
834f169c | 370 | gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) |
44359ced | 371 | { |
2c2093b3 | 372 | unsigned ix, h_ix, bv_ix, h_cnt = 0; |
ab6a34f2 | 373 | const struct gcov_ctr_summary *csum; |
2c2093b3 | 374 | unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE]; |
375 | ||
376 | /* Count number of non-zero histogram entries, and fill in a bit vector | |
377 | of non-zero indices. The histogram is only currently computed for arc | |
378 | counters. */ | |
379 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
380 | histo_bitvector[bv_ix] = 0; | |
381 | csum = &summary->ctrs[GCOV_COUNTER_ARCS]; | |
382 | for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) | |
383 | { | |
384 | if (csum->histogram[h_ix].num_counters > 0) | |
385 | { | |
386 | histo_bitvector[h_ix / 32] |= 1 << (h_ix % 32); | |
387 | h_cnt++; | |
388 | } | |
389 | } | |
390 | gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH(h_cnt)); | |
44359ced | 391 | gcov_write_unsigned (summary->checksum); |
834f169c | 392 | for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) |
ab6a34f2 | 393 | { |
394 | gcov_write_unsigned (csum->num); | |
395 | gcov_write_unsigned (csum->runs); | |
396 | gcov_write_counter (csum->sum_all); | |
397 | gcov_write_counter (csum->run_max); | |
398 | gcov_write_counter (csum->sum_max); | |
2c2093b3 | 399 | if (ix != GCOV_COUNTER_ARCS) |
400 | { | |
401 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
402 | gcov_write_unsigned (0); | |
403 | continue; | |
404 | } | |
405 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
406 | gcov_write_unsigned (histo_bitvector[bv_ix]); | |
407 | for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) | |
408 | { | |
409 | if (!csum->histogram[h_ix].num_counters) | |
410 | continue; | |
411 | gcov_write_unsigned (csum->histogram[h_ix].num_counters); | |
412 | gcov_write_counter (csum->histogram[h_ix].min_value); | |
413 | gcov_write_counter (csum->histogram[h_ix].cum_value); | |
414 | } | |
ab6a34f2 | 415 | } |
44359ced | 416 | } |
417 | #endif /* IN_LIBGCOV */ | |
418 | ||
419 | #endif /*!IN_GCOV */ | |
420 | ||
421 | /* Return a pointer to read BYTES bytes from the gcov file. Returns | |
6473f3f4 | 422 | NULL on failure (read past EOF). */ |
44359ced | 423 | |
b4d48d67 | 424 | static const gcov_unsigned_t * |
9e0943d4 | 425 | gcov_read_words (unsigned words) |
44359ced | 426 | { |
b4d48d67 | 427 | const gcov_unsigned_t *result; |
80abd9e4 | 428 | unsigned excess = gcov_var.length - gcov_var.offset; |
48e1416a | 429 | |
631ceed1 | 430 | gcc_assert (gcov_var.mode > 0); |
9e0943d4 | 431 | if (excess < words) |
44359ced | 432 | { |
80abd9e4 | 433 | gcov_var.start += gcov_var.offset; |
434 | #if IN_LIBGCOV | |
435 | if (excess) | |
436 | { | |
631ceed1 | 437 | gcc_assert (excess == 1); |
80abd9e4 | 438 | memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4); |
439 | } | |
440 | #else | |
f01f2080 | 441 | memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4); |
80abd9e4 | 442 | #endif |
443 | gcov_var.offset = 0; | |
444 | gcov_var.length = excess; | |
445 | #if IN_LIBGCOV | |
631ceed1 | 446 | gcc_assert (!gcov_var.length || gcov_var.length == 1); |
80abd9e4 | 447 | excess = GCOV_BLOCK_SIZE; |
448 | #else | |
9e0943d4 | 449 | if (gcov_var.length + words > gcov_var.alloc) |
450 | gcov_allocate (gcov_var.length + words); | |
80abd9e4 | 451 | excess = gcov_var.alloc - gcov_var.length; |
452 | #endif | |
1278fdc3 | 453 | excess = fread (gcov_var.buffer + gcov_var.length, |
9e0943d4 | 454 | 1, excess << 2, gcov_var.file) >> 2; |
80abd9e4 | 455 | gcov_var.length += excess; |
9e0943d4 | 456 | if (gcov_var.length < words) |
80abd9e4 | 457 | { |
9e0943d4 | 458 | gcov_var.overread += words - gcov_var.length; |
80abd9e4 | 459 | gcov_var.length = 0; |
460 | return 0; | |
461 | } | |
44359ced | 462 | } |
9e0943d4 | 463 | result = &gcov_var.buffer[gcov_var.offset]; |
464 | gcov_var.offset += words; | |
44359ced | 465 | return result; |
466 | } | |
467 | ||
468 | /* Read unsigned value from a coverage file. Sets error flag on file | |
469 | error, overflow flag on overflow */ | |
470 | ||
834f169c | 471 | GCOV_LINKAGE gcov_unsigned_t |
53b2c31f | 472 | gcov_read_unsigned (void) |
44359ced | 473 | { |
b4d48d67 | 474 | gcov_unsigned_t value; |
9e0943d4 | 475 | const gcov_unsigned_t *buffer = gcov_read_words (1); |
44359ced | 476 | |
477 | if (!buffer) | |
478 | return 0; | |
b4d48d67 | 479 | value = from_file (buffer[0]); |
44359ced | 480 | return value; |
481 | } | |
482 | ||
483 | /* Read counter value from a coverage file. Sets error flag on file | |
484 | error, overflow flag on overflow */ | |
485 | ||
486 | GCOV_LINKAGE gcov_type | |
53b2c31f | 487 | gcov_read_counter (void) |
44359ced | 488 | { |
b4d48d67 | 489 | gcov_type value; |
9e0943d4 | 490 | const gcov_unsigned_t *buffer = gcov_read_words (2); |
44359ced | 491 | |
492 | if (!buffer) | |
493 | return 0; | |
b4d48d67 | 494 | value = from_file (buffer[0]); |
495 | if (sizeof (value) > sizeof (gcov_unsigned_t)) | |
496 | value |= ((gcov_type) from_file (buffer[1])) << 32; | |
497 | else if (buffer[1]) | |
498 | gcov_var.error = -1; | |
8a5df2ce | 499 | |
44359ced | 500 | return value; |
501 | } | |
502 | ||
503 | /* Read string from coverage file. Returns a pointer to a static | |
504 | buffer, or NULL on empty string. You must copy the string before | |
505 | calling another gcov function. */ | |
506 | ||
3f2c2dd8 | 507 | #if !IN_LIBGCOV |
44359ced | 508 | GCOV_LINKAGE const char * |
53b2c31f | 509 | gcov_read_string (void) |
44359ced | 510 | { |
511 | unsigned length = gcov_read_unsigned (); | |
48e1416a | 512 | |
44359ced | 513 | if (!length) |
514 | return 0; | |
515 | ||
9e0943d4 | 516 | return (const char *) gcov_read_words (length); |
44359ced | 517 | } |
3f2c2dd8 | 518 | #endif |
44359ced | 519 | |
520 | GCOV_LINKAGE void | |
521 | gcov_read_summary (struct gcov_summary *summary) | |
522 | { | |
2c2093b3 | 523 | unsigned ix, h_ix, bv_ix, h_cnt = 0; |
ab6a34f2 | 524 | struct gcov_ctr_summary *csum; |
2c2093b3 | 525 | unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE]; |
526 | unsigned cur_bitvector; | |
48e1416a | 527 | |
44359ced | 528 | summary->checksum = gcov_read_unsigned (); |
834f169c | 529 | for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) |
ab6a34f2 | 530 | { |
531 | csum->num = gcov_read_unsigned (); | |
532 | csum->runs = gcov_read_unsigned (); | |
533 | csum->sum_all = gcov_read_counter (); | |
534 | csum->run_max = gcov_read_counter (); | |
535 | csum->sum_max = gcov_read_counter (); | |
2c2093b3 | 536 | memset (csum->histogram, 0, |
537 | sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); | |
538 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
539 | { | |
540 | histo_bitvector[bv_ix] = gcov_read_unsigned (); | |
960a9b56 | 541 | #if IN_LIBGCOV |
542 | /* When building libgcov we don't include system.h, which includes | |
543 | hwint.h (where popcount_hwi is declared). However, libgcov.a | |
544 | is built by the bootstrapped compiler and therefore the builtins | |
545 | are always available. */ | |
546 | h_cnt += __builtin_popcount (histo_bitvector[bv_ix]); | |
547 | #else | |
548 | h_cnt += popcount_hwi (histo_bitvector[bv_ix]); | |
549 | #endif | |
2c2093b3 | 550 | } |
551 | bv_ix = 0; | |
552 | h_ix = 0; | |
553 | cur_bitvector = 0; | |
554 | while (h_cnt--) | |
555 | { | |
556 | /* Find the index corresponding to the next entry we will read in. | |
557 | First find the next non-zero bitvector and re-initialize | |
558 | the histogram index accordingly, then right shift and increment | |
559 | the index until we find a set bit. */ | |
560 | while (!cur_bitvector) | |
561 | { | |
562 | h_ix = bv_ix * 32; | |
0527c3bc | 563 | gcc_assert(bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE); |
2c2093b3 | 564 | cur_bitvector = histo_bitvector[bv_ix++]; |
2c2093b3 | 565 | } |
566 | while (!(cur_bitvector & 0x1)) | |
567 | { | |
568 | h_ix++; | |
569 | cur_bitvector >>= 1; | |
570 | } | |
571 | gcc_assert(h_ix < GCOV_HISTOGRAM_SIZE); | |
572 | ||
573 | csum->histogram[h_ix].num_counters = gcov_read_unsigned (); | |
574 | csum->histogram[h_ix].min_value = gcov_read_counter (); | |
575 | csum->histogram[h_ix].cum_value = gcov_read_counter (); | |
576 | /* Shift off the index we are done with and increment to the | |
577 | corresponding next histogram entry. */ | |
578 | cur_bitvector >>= 1; | |
579 | h_ix++; | |
580 | } | |
ab6a34f2 | 581 | } |
44359ced | 582 | } |
583 | ||
80abd9e4 | 584 | #if !IN_LIBGCOV |
585 | /* Reset to a known position. BASE should have been obtained from | |
586 | gcov_position, LENGTH should be a record length. */ | |
587 | ||
588 | GCOV_LINKAGE void | |
589 | gcov_sync (gcov_position_t base, gcov_unsigned_t length) | |
590 | { | |
631ceed1 | 591 | gcc_assert (gcov_var.mode > 0); |
80abd9e4 | 592 | base += length; |
593 | if (base - gcov_var.start <= gcov_var.length) | |
594 | gcov_var.offset = base - gcov_var.start; | |
595 | else | |
596 | { | |
597 | gcov_var.offset = gcov_var.length = 0; | |
9e0943d4 | 598 | fseek (gcov_var.file, base << 2, SEEK_SET); |
599 | gcov_var.start = ftell (gcov_var.file) >> 2; | |
80abd9e4 | 600 | } |
601 | } | |
602 | #endif | |
603 | ||
604 | #if IN_LIBGCOV | |
f0b5f617 | 605 | /* Move to a given position in a gcov file. */ |
80abd9e4 | 606 | |
607 | GCOV_LINKAGE void | |
608 | gcov_seek (gcov_position_t base) | |
609 | { | |
631ceed1 | 610 | gcc_assert (gcov_var.mode < 0); |
80abd9e4 | 611 | if (gcov_var.offset) |
612 | gcov_write_block (gcov_var.offset); | |
421055ca | 613 | fseek (gcov_var.file, base << 2, SEEK_SET); |
9e0943d4 | 614 | gcov_var.start = ftell (gcov_var.file) >> 2; |
80abd9e4 | 615 | } |
616 | #endif | |
617 | ||
44359ced | 618 | #if IN_GCOV > 0 |
619 | /* Return the modification time of the current gcov file. */ | |
620 | ||
621 | GCOV_LINKAGE time_t | |
53b2c31f | 622 | gcov_time (void) |
44359ced | 623 | { |
624 | struct stat status; | |
48e1416a | 625 | |
44359ced | 626 | if (fstat (fileno (gcov_var.file), &status)) |
627 | return 0; | |
628 | else | |
629 | return status.st_mtime; | |
630 | } | |
631 | #endif /* IN_GCOV */ | |
2c2093b3 | 632 | |
e3ba12e8 | 633 | #if !IN_GCOV |
2c2093b3 | 634 | /* Determine the index into histogram for VALUE. */ |
635 | ||
e3ba12e8 | 636 | #if IN_LIBGCOV |
2c2093b3 | 637 | static unsigned |
e3ba12e8 | 638 | #else |
639 | GCOV_LINKAGE unsigned | |
640 | #endif | |
641 | gcov_histo_index (gcov_type value) | |
2c2093b3 | 642 | { |
643 | gcov_type_unsigned v = (gcov_type_unsigned)value; | |
644 | unsigned r = 0; | |
645 | unsigned prev2bits = 0; | |
646 | ||
647 | /* Find index into log2 scale histogram, where each of the log2 | |
648 | sized buckets is divided into 4 linear sub-buckets for better | |
649 | focus in the higher buckets. */ | |
650 | ||
651 | /* Find the place of the most-significant bit set. */ | |
652 | if (v > 0) | |
960a9b56 | 653 | { |
654 | #if IN_LIBGCOV | |
655 | /* When building libgcov we don't include system.h, which includes | |
656 | hwint.h (where floor_log2 is declared). However, libgcov.a | |
657 | is built by the bootstrapped compiler and therefore the builtins | |
658 | are always available. */ | |
659 | r = sizeof (long long) * __CHAR_BIT__ - 1 - __builtin_clzll (v); | |
660 | #else | |
661 | /* We use floor_log2 from hwint.c, which takes a HOST_WIDE_INT | |
662 | that is either 32 or 64 bits, and gcov_type_unsigned may be 64 bits. | |
663 | Need to check for the case where gcov_type_unsigned is 64 bits | |
664 | and HOST_WIDE_INT is 32 bits and handle it specially. */ | |
665 | #if HOST_BITS_PER_WIDEST_INT == HOST_BITS_PER_WIDE_INT | |
666 | r = floor_log2 (v); | |
667 | #elif HOST_BITS_PER_WIDEST_INT == 2 * HOST_BITS_PER_WIDE_INT | |
668 | HOST_WIDE_INT hwi_v = v >> HOST_BITS_PER_WIDE_INT; | |
669 | if (hwi_v) | |
670 | r = floor_log2 (hwi_v) + HOST_BITS_PER_WIDE_INT; | |
671 | else | |
672 | r = floor_log2 ((HOST_WIDE_INT)v); | |
673 | #else | |
674 | gcc_unreachable (); | |
675 | #endif | |
676 | #endif | |
677 | } | |
2c2093b3 | 678 | |
679 | /* If at most the 2 least significant bits are set (value is | |
680 | 0 - 3) then that value is our index into the lowest set of | |
681 | four buckets. */ | |
682 | if (r < 2) | |
683 | return (unsigned)value; | |
684 | ||
685 | gcc_assert (r < 64); | |
686 | ||
687 | /* Find the two next most significant bits to determine which | |
688 | of the four linear sub-buckets to select. */ | |
689 | prev2bits = (v >> (r - 2)) & 0x3; | |
690 | /* Finally, compose the final bucket index from the log2 index and | |
691 | the next 2 bits. The minimum r value at this point is 2 since we | |
692 | returned above if r was 2 or more, so the minimum bucket at this | |
693 | point is 4. */ | |
694 | return (r - 1) * 4 + prev2bits; | |
695 | } | |
696 | ||
697 | /* Merge SRC_HISTO into TGT_HISTO. The counters are assumed to be in | |
698 | the same relative order in both histograms, and are matched up | |
699 | and merged in reverse order. Each counter is assigned an equal portion of | |
700 | its entry's original cumulative counter value when computing the | |
701 | new merged cum_value. */ | |
702 | ||
e3ba12e8 | 703 | static void gcov_histogram_merge (gcov_bucket_type *tgt_histo, |
704 | gcov_bucket_type *src_histo) | |
2c2093b3 | 705 | { |
706 | int src_i, tgt_i, tmp_i = 0; | |
707 | unsigned src_num, tgt_num, merge_num; | |
708 | gcov_type src_cum, tgt_cum, merge_src_cum, merge_tgt_cum, merge_cum; | |
709 | gcov_type merge_min; | |
710 | gcov_bucket_type tmp_histo[GCOV_HISTOGRAM_SIZE]; | |
711 | int src_done = 0; | |
712 | ||
713 | memset(tmp_histo, 0, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); | |
714 | ||
715 | /* Assume that the counters are in the same relative order in both | |
716 | histograms. Walk the histograms from largest to smallest entry, | |
717 | matching up and combining counters in order. */ | |
718 | src_num = 0; | |
719 | src_cum = 0; | |
720 | src_i = GCOV_HISTOGRAM_SIZE - 1; | |
721 | for (tgt_i = GCOV_HISTOGRAM_SIZE - 1; tgt_i >= 0 && !src_done; tgt_i--) | |
722 | { | |
723 | tgt_num = tgt_histo[tgt_i].num_counters; | |
724 | tgt_cum = tgt_histo[tgt_i].cum_value; | |
725 | /* Keep going until all of the target histogram's counters at this | |
726 | position have been matched and merged with counters from the | |
727 | source histogram. */ | |
728 | while (tgt_num > 0 && !src_done) | |
729 | { | |
730 | /* If this is either the first time through this loop or we just | |
731 | exhausted the previous non-zero source histogram entry, look | |
732 | for the next non-zero source histogram entry. */ | |
733 | if (!src_num) | |
734 | { | |
735 | /* Locate the next non-zero entry. */ | |
736 | while (src_i >= 0 && !src_histo[src_i].num_counters) | |
737 | src_i--; | |
738 | /* If source histogram has fewer counters, then just copy over the | |
739 | remaining target counters and quit. */ | |
740 | if (src_i < 0) | |
741 | { | |
742 | tmp_histo[tgt_i].num_counters += tgt_num; | |
743 | tmp_histo[tgt_i].cum_value += tgt_cum; | |
744 | if (!tmp_histo[tgt_i].min_value || | |
745 | tgt_histo[tgt_i].min_value < tmp_histo[tgt_i].min_value) | |
746 | tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value; | |
747 | while (--tgt_i >= 0) | |
748 | { | |
749 | tmp_histo[tgt_i].num_counters | |
750 | += tgt_histo[tgt_i].num_counters; | |
751 | tmp_histo[tgt_i].cum_value += tgt_histo[tgt_i].cum_value; | |
752 | if (!tmp_histo[tgt_i].min_value || | |
753 | tgt_histo[tgt_i].min_value | |
754 | < tmp_histo[tgt_i].min_value) | |
755 | tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value; | |
756 | } | |
757 | ||
758 | src_done = 1; | |
759 | break; | |
760 | } | |
761 | ||
762 | src_num = src_histo[src_i].num_counters; | |
763 | src_cum = src_histo[src_i].cum_value; | |
764 | } | |
765 | ||
766 | /* The number of counters to merge on this pass is the minimum | |
767 | of the remaining counters from the current target and source | |
768 | histogram entries. */ | |
769 | merge_num = tgt_num; | |
770 | if (src_num < merge_num) | |
771 | merge_num = src_num; | |
772 | ||
773 | /* The merged min_value is the sum of the min_values from target | |
774 | and source. */ | |
775 | merge_min = tgt_histo[tgt_i].min_value + src_histo[src_i].min_value; | |
776 | ||
777 | /* Compute the portion of source and target entries' cum_value | |
778 | that will be apportioned to the counters being merged. | |
779 | The total remaining cum_value from each entry is divided | |
780 | equally among the counters from that histogram entry if we | |
781 | are not merging all of them. */ | |
782 | merge_src_cum = src_cum; | |
783 | if (merge_num < src_num) | |
784 | merge_src_cum = merge_num * src_cum / src_num; | |
785 | merge_tgt_cum = tgt_cum; | |
786 | if (merge_num < tgt_num) | |
787 | merge_tgt_cum = merge_num * tgt_cum / tgt_num; | |
788 | /* The merged cum_value is the sum of the source and target | |
789 | components. */ | |
790 | merge_cum = merge_src_cum + merge_tgt_cum; | |
791 | ||
792 | /* Update the remaining number of counters and cum_value left | |
793 | to be merged from this source and target entry. */ | |
794 | src_cum -= merge_src_cum; | |
795 | tgt_cum -= merge_tgt_cum; | |
796 | src_num -= merge_num; | |
797 | tgt_num -= merge_num; | |
798 | ||
799 | /* The merged counters get placed in the new merged histogram | |
800 | at the entry for the merged min_value. */ | |
801 | tmp_i = gcov_histo_index(merge_min); | |
802 | gcc_assert (tmp_i < GCOV_HISTOGRAM_SIZE); | |
803 | tmp_histo[tmp_i].num_counters += merge_num; | |
804 | tmp_histo[tmp_i].cum_value += merge_cum; | |
805 | if (!tmp_histo[tmp_i].min_value || | |
806 | merge_min < tmp_histo[tmp_i].min_value) | |
807 | tmp_histo[tmp_i].min_value = merge_min; | |
808 | ||
809 | /* Ensure the search for the next non-zero src_histo entry starts | |
810 | at the next smallest histogram bucket. */ | |
811 | if (!src_num) | |
812 | src_i--; | |
813 | } | |
814 | } | |
815 | ||
816 | gcc_assert (tgt_i < 0); | |
817 | ||
818 | /* In the case where there were more counters in the source histogram, | |
819 | accumulate the remaining unmerged cumulative counter values. Add | |
820 | those to the smallest non-zero target histogram entry. Otherwise, | |
821 | the total cumulative counter values in the histogram will be smaller | |
822 | than the sum_all stored in the summary, which will complicate | |
823 | computing the working set information from the histogram later on. */ | |
824 | if (src_num) | |
825 | src_i--; | |
826 | while (src_i >= 0) | |
827 | { | |
828 | src_cum += src_histo[src_i].cum_value; | |
829 | src_i--; | |
830 | } | |
831 | /* At this point, tmp_i should be the smallest non-zero entry in the | |
832 | tmp_histo. */ | |
833 | gcc_assert(tmp_i >= 0 && tmp_i < GCOV_HISTOGRAM_SIZE | |
834 | && tmp_histo[tmp_i].num_counters > 0); | |
835 | tmp_histo[tmp_i].cum_value += src_cum; | |
836 | ||
837 | /* Finally, copy the merged histogram into tgt_histo. */ | |
838 | memcpy(tgt_histo, tmp_histo, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); | |
839 | } | |
e3ba12e8 | 840 | #endif /* !IN_GCOV */ |