* java/util/Properties.java (load): Only skip line if the first
[official-gcc.git] / gcc / libgcov.c
blob657de36d30030a225275083ff91b857d778dc20e
1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file. (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
20 executable.)
22 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23 WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 for more details.
27 You should have received a copy of the GNU General Public License
28 along with GCC; see the file COPYING. If not, write to the Free
29 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
30 02111-1307, USA. */
32 /* It is incorrect to include config.h here, because this file is being
33 compiled for the target, and hence definitions concerning only the host
34 do not apply. */
36 #include "tconfig.h"
37 #include "tsystem.h"
38 #include "coretypes.h"
39 #include "tm.h"
41 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
42 #include <stdio.h>
44 #include "gcov-io.h"
45 #include <string.h>
46 #if defined (TARGET_HAS_F_SETLKW)
47 #include <fcntl.h>
48 #include <errno.h>
49 #endif
51 /* Chain of per-object gcov structures. */
52 static struct gcov_info *gcov_list;
54 /* A program checksum allows us to distinguish program data for an
55 object file included in multiple programs. */
56 static unsigned gcov_crc32;
58 static void
59 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
61 unsigned expected = GCOV_VERSION;
62 unsigned ix;
63 char e[4], v[4];
65 for (ix = 4; ix--; expected >>= 8, version >>= 8)
67 e[ix] = expected;
68 v[ix] = version;
71 fprintf (stderr,
72 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
73 ptr->filename, e, v);
76 /* Dump the coverage counts. We merge with existing counts when
77 possible, to avoid growing the .da files ad infinitum. We use this
78 program's checksum to make sure we only accumulate whole program
79 statistics to the correct summary. An object file might be embedded
80 in two separate programs, and we must keep the two program
81 summaries separate. */
83 static void
84 gcov_exit (void)
86 struct gcov_info *ptr;
87 unsigned ix, jx;
88 struct gcov_summary program;
89 gcov_type program_max_one = 0;
90 gcov_type program_max_sum = 0;
91 gcov_type program_sum = 0;
92 unsigned program_arcs = 0;
94 #if defined (TARGET_HAS_F_SETLKW)
95 struct flock s_flock;
97 s_flock.l_type = F_WRLCK;
98 s_flock.l_whence = SEEK_SET;
99 s_flock.l_start = 0;
100 s_flock.l_len = 0; /* Until EOF. */
101 s_flock.l_pid = getpid ();
102 #endif
104 memset (&program, 0, sizeof (program));
105 program.checksum = gcov_crc32;
107 for (ptr = gcov_list; ptr; ptr = ptr->next)
109 FILE *da_file;
110 struct gcov_summary object;
111 struct gcov_summary local_prg;
112 int merging = 0;
113 long base;
114 const struct function_info *fn_info;
115 gcov_type **counters;
116 gcov_type *count_ptr;
117 gcov_type object_max_one = 0;
118 gcov_type count;
119 unsigned tag, length, flength, checksum;
120 unsigned arc_data_index, f_sect_index, sect_index;
122 ptr->wkspc = 0;
123 if (!ptr->filename)
124 continue;
126 counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
127 for (ix = 0; ix < ptr->n_counter_sections; ix++)
128 counters[ix] = ptr->counter_sections[ix].counters;
130 for (arc_data_index = 0;
131 arc_data_index < ptr->n_counter_sections
132 && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
133 arc_data_index++)
134 continue;
136 if (arc_data_index == ptr->n_counter_sections)
138 /* For now; later we may want to just measure other profiles,
139 but now I am lazy to check for all consequences. */
140 abort ();
142 for (ix = ptr->counter_sections[arc_data_index].n_counters,
143 count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
145 gcov_type count = *count_ptr++;
147 if (count > object_max_one)
148 object_max_one = count;
150 if (object_max_one > program_max_one)
151 program_max_one = object_max_one;
153 memset (&local_prg, 0, sizeof (local_prg));
154 memset (&object, 0, sizeof (object));
156 /* Open for modification */
157 if ((da_file = fopen (ptr->filename, "r+b")))
158 merging = 1;
159 else if ((da_file = fopen (ptr->filename, "w+b")))
161 else
163 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
164 ptr->filename = 0;
165 continue;
168 #if defined (TARGET_HAS_F_SETLKW)
169 /* After a fork, another process might try to read and/or write
170 the same file simultaneously. So if we can, lock the file to
171 avoid race conditions. */
172 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
173 && errno == EINTR)
174 continue;
175 #endif
176 if (merging)
178 /* Merge data from file. */
180 if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
182 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
183 ptr->filename);
184 read_fatal:;
185 fclose (da_file);
186 ptr->filename = 0;
187 continue;
189 if (gcov_read_unsigned (da_file, &length) || length != GCOV_VERSION)
191 gcov_version_mismatch (ptr, length);
192 goto read_fatal;
195 /* Merge execution counts for each function. */
196 for (ix = ptr->n_functions, fn_info = ptr->functions;
197 ix--; fn_info++)
199 if (gcov_read_unsigned (da_file, &tag)
200 || gcov_read_unsigned (da_file, &length))
202 read_error:;
203 fprintf (stderr, "profiling:%s:Error merging\n",
204 ptr->filename);
205 goto read_fatal;
208 /* Check function */
209 if (tag != GCOV_TAG_FUNCTION)
211 read_mismatch:;
212 fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
213 ptr->filename, fn_info->name);
214 goto read_fatal;
217 if (gcov_read_unsigned (da_file, &flength)
218 || gcov_skip_string (da_file, flength)
219 || gcov_read_unsigned (da_file, &checksum))
220 goto read_error;
221 if (flength != strlen (fn_info->name)
222 || checksum != fn_info->checksum)
223 goto read_mismatch;
225 /* Counters. */
226 for (f_sect_index = 0;
227 f_sect_index < fn_info->n_counter_sections;
228 f_sect_index++)
230 if (gcov_read_unsigned (da_file, &tag)
231 || gcov_read_unsigned (da_file, &length))
232 goto read_error;
233 for (sect_index = 0;
234 sect_index < ptr->n_counter_sections;
235 sect_index++)
236 if (ptr->counter_sections[sect_index].tag == tag)
237 break;
238 if (fn_info->counter_sections[f_sect_index].tag != tag
239 || sect_index == ptr->n_counter_sections
240 || length / 8 != fn_info->counter_sections[f_sect_index].n_counters)
241 goto read_mismatch;
243 for (jx = fn_info->counter_sections[f_sect_index].n_counters;
244 jx--; counters[sect_index]++)
245 if (gcov_read_counter (da_file, &count))
246 goto read_error;
247 else
248 *counters[sect_index] += count;
252 /* Check object summary */
253 if (gcov_read_unsigned (da_file, &tag)
254 || gcov_read_unsigned (da_file, &length))
255 goto read_error;
256 if (tag != GCOV_TAG_OBJECT_SUMMARY)
257 goto read_mismatch;
258 if (gcov_read_summary (da_file, &object))
259 goto read_error;
261 /* Check program summary */
262 while (1)
264 long base = ftell (da_file);
266 if (gcov_read_unsigned (da_file, &tag)
267 || gcov_read_unsigned (da_file, &length))
269 if (feof (da_file))
270 break;
271 goto read_error;
273 if (tag != GCOV_TAG_PROGRAM_SUMMARY
274 && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
275 && tag != GCOV_TAG_INCORRECT_SUMMARY)
276 goto read_mismatch;
277 if (gcov_read_summary (da_file, &local_prg))
278 goto read_error;
279 if (local_prg.checksum != program.checksum)
280 continue;
281 if (tag == GCOV_TAG_PLACEHOLDER_SUMMARY)
283 fprintf (stderr,
284 "profiling:%s:Concurrent race detected\n",
285 ptr->filename);
286 goto read_fatal;
288 merging = -1;
289 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
290 break;
292 if (program.runs
293 && memcmp (&program, &local_prg, sizeof (program)))
295 fprintf (stderr, "profiling:%s:Invocation mismatch\n",
296 ptr->filename);
297 local_prg.runs = 0;
299 else
300 memcpy (&program, &local_prg, sizeof (program));
301 ptr->wkspc = base;
302 break;
304 fseek (da_file, 0, SEEK_SET);
307 object.runs++;
308 object.arcs = ptr->counter_sections[arc_data_index].n_counters;
309 object.arc_sum = 0;
310 if (object.arc_max_one < object_max_one)
311 object.arc_max_one = object_max_one;
312 object.arc_sum_max += object_max_one;
314 /* Write out the data. */
315 if (/* magic */
316 gcov_write_unsigned (da_file, GCOV_DATA_MAGIC)
317 /* version number */
318 || gcov_write_unsigned (da_file, GCOV_VERSION))
320 write_error:;
321 fclose (da_file);
322 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
323 ptr->filename = 0;
324 continue;
327 /* Write execution counts for each function. */
328 for (ix = 0; ix < ptr->n_counter_sections; ix++)
329 counters[ix] = ptr->counter_sections[ix].counters;
330 for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
332 /* Announce function. */
333 if (gcov_write_unsigned (da_file, GCOV_TAG_FUNCTION)
334 || !(base = gcov_reserve_length (da_file))
335 /* function name */
336 || gcov_write_string (da_file, fn_info->name,
337 strlen (fn_info->name))
338 /* function checksum */
339 || gcov_write_unsigned (da_file, fn_info->checksum)
340 || gcov_write_length (da_file, base))
341 goto write_error;
343 /* counters. */
344 for (f_sect_index = 0;
345 f_sect_index < fn_info->n_counter_sections;
346 f_sect_index++)
348 tag = fn_info->counter_sections[f_sect_index].tag;
349 for (sect_index = 0;
350 sect_index < ptr->n_counter_sections;
351 sect_index++)
352 if (ptr->counter_sections[sect_index].tag == tag)
353 break;
354 if (sect_index == ptr->n_counter_sections)
355 abort ();
357 if (gcov_write_unsigned (da_file, tag)
358 || !(base = gcov_reserve_length (da_file)))
359 goto write_error;
361 for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
363 gcov_type count = *counters[sect_index]++;
365 if (tag == GCOV_TAG_ARC_COUNTS)
367 object.arc_sum += count;
368 if (object.arc_max_sum < count)
369 object.arc_max_sum = count;
371 if (gcov_write_counter (da_file, count))
372 goto write_error; /* RIP Edsger Dijkstra */
374 if (gcov_write_length (da_file, base))
375 goto write_error;
379 /* Object file summary. */
380 if (gcov_write_summary (da_file, GCOV_TAG_OBJECT_SUMMARY, &object))
381 goto write_error;
383 if (merging >= 0)
385 if (fseek (da_file, 0, SEEK_END))
386 goto write_error;
387 ptr->wkspc = ftell (da_file);
388 if (gcov_write_summary (da_file, GCOV_TAG_PLACEHOLDER_SUMMARY,
389 &program))
390 goto write_error;
392 else if (ptr->wkspc)
394 /* Zap trailing program summary */
395 if (fseek (da_file, ptr->wkspc, SEEK_SET))
396 goto write_error;
397 if (!local_prg.runs)
398 ptr->wkspc = 0;
399 if (gcov_write_unsigned (da_file,
400 local_prg.runs ? GCOV_TAG_PLACEHOLDER_SUMMARY
401 : GCOV_TAG_INCORRECT_SUMMARY))
402 goto write_error;
404 if (fflush (da_file))
405 goto write_error;
407 if (fclose (da_file))
409 fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
410 ptr->filename = 0;
412 else
414 program_arcs += ptr->counter_sections[arc_data_index].n_counters;
415 program_sum += object.arc_sum;
416 if (program_max_sum < object.arc_max_sum)
417 program_max_sum = object.arc_max_sum;
419 free(counters);
422 /* Generate whole program statistics. */
423 program.runs++;
424 program.arcs = program_arcs;
425 program.arc_sum = program_sum;
426 if (program.arc_max_one < program_max_one)
427 program.arc_max_one = program_max_one;
428 if (program.arc_max_sum < program_max_sum)
429 program.arc_max_sum = program_max_sum;
430 program.arc_sum_max += program_max_one;
432 /* Upate whole program statistics. */
433 for (ptr = gcov_list; ptr; ptr = ptr->next)
434 if (ptr->filename && ptr->wkspc)
436 FILE *da_file;
438 da_file = fopen (ptr->filename, "r+b");
439 if (!da_file)
441 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
442 continue;
445 #if defined (TARGET_HAS_F_SETLKW)
446 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
447 && errno == EINTR)
448 continue;
449 #endif
450 if (fseek (da_file, ptr->wkspc, SEEK_SET)
451 || gcov_write_summary (da_file, GCOV_TAG_PROGRAM_SUMMARY, &program)
452 || fflush (da_file))
453 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
454 if (fclose (da_file))
455 fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
459 /* Add a new object file onto the bb chain. Invoked automatically
460 when running an object file's global ctors. */
462 void
463 __gcov_init (struct gcov_info *info)
465 if (!info->version)
466 return;
467 if (info->version != GCOV_VERSION)
468 gcov_version_mismatch (info, info->version);
469 else
471 const char *ptr = info->filename;
472 unsigned crc32 = gcov_crc32;
476 unsigned ix;
477 unsigned value = *ptr << 24;
479 for (ix = 8; ix--; value <<= 1)
481 unsigned feedback;
483 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
484 crc32 <<= 1;
485 crc32 ^= feedback;
488 while (*ptr++);
490 gcov_crc32 = crc32;
492 if (!gcov_list)
493 atexit (gcov_exit);
495 info->next = gcov_list;
496 gcov_list = info;
498 info->version = 0;
501 /* Called before fork or exec - write out profile information gathered so
502 far and reset it to zero. This avoids duplication or loss of the
503 profile information gathered so far. */
505 void
506 __gcov_flush (void)
508 struct gcov_info *ptr;
510 gcov_exit ();
511 for (ptr = gcov_list; ptr; ptr = ptr->next)
513 unsigned i, j;
515 for (j = 0; j < ptr->n_counter_sections; j++)
516 for (i = ptr->counter_sections[j].n_counters; i--;)
517 ptr->counter_sections[j].counters[i] = 0;