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