FSF GCC merge 02/23/03
[official-gcc.git] / gcc / libgcov.c
blob57bfb2632652114af581d7958df4f115001b01dd
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 *count_ptr;
116 gcov_type object_max_one = 0;
118 ptr->wkspc = 0;
119 if (!ptr->filename)
120 continue;
122 for (ix = ptr->n_arc_counts, count_ptr = ptr->arc_counts; ix--;)
124 gcov_type count = *count_ptr++;
126 if (count > object_max_one)
127 object_max_one = count;
129 if (object_max_one > program_max_one)
130 program_max_one = object_max_one;
132 memset (&local_prg, 0, sizeof (local_prg));
133 memset (&object, 0, sizeof (object));
135 /* Open for modification */
136 if ((da_file = fopen (ptr->filename, "r+b")))
137 merging = 1;
138 else if ((da_file = fopen (ptr->filename, "w+b")))
140 else
142 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
143 ptr->filename = 0;
144 continue;
147 #if defined (TARGET_HAS_F_SETLKW)
148 /* After a fork, another process might try to read and/or write
149 the same file simultaneously. So if we can, lock the file to
150 avoid race conditions. */
151 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
152 && errno == EINTR)
153 continue;
154 #endif
155 if (merging)
157 /* Merge data from file. */
158 unsigned tag, length;
160 if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
162 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
163 ptr->filename);
164 read_fatal:;
165 fclose (da_file);
166 ptr->filename = 0;
167 continue;
169 if (gcov_read_unsigned (da_file, &length) || length != GCOV_VERSION)
171 gcov_version_mismatch (ptr, length);
172 goto read_fatal;
175 /* Merge execution counts for each function. */
176 count_ptr = ptr->arc_counts;
177 for (ix = ptr->n_functions, fn_info = ptr->functions;
178 ix--; fn_info++)
180 if (gcov_read_unsigned (da_file, &tag)
181 || gcov_read_unsigned (da_file, &length))
183 read_error:;
184 fprintf (stderr, "profiling:%s:Error merging\n",
185 ptr->filename);
186 goto read_fatal;
189 /* Check function */
190 if (tag != GCOV_TAG_FUNCTION)
192 read_mismatch:;
193 fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
194 ptr->filename, fn_info->name);
195 goto read_fatal;
198 unsigned flength, checksum;
200 if (gcov_read_unsigned (da_file, &flength)
201 || gcov_skip_string (da_file, flength)
202 || gcov_read_unsigned (da_file, &checksum))
203 goto read_error;
204 if (flength != strlen (fn_info->name)
205 || checksum != fn_info->checksum)
206 goto read_mismatch;
208 /* Check arc counts */
209 if (gcov_read_unsigned (da_file, &tag)
210 || gcov_read_unsigned (da_file, &length))
211 goto read_error;
212 if (tag != GCOV_TAG_ARC_COUNTS
213 || length / 8 != fn_info->n_arc_counts)
214 goto read_mismatch;
216 gcov_type count;
218 for (jx = fn_info->n_arc_counts; jx--; count_ptr++)
219 if (gcov_read_counter (da_file, &count))
220 goto read_error;
221 else
222 *count_ptr += count;
226 /* Check object summary */
227 if (gcov_read_unsigned (da_file, &tag)
228 || gcov_read_unsigned (da_file, &length))
229 goto read_error;
230 if (tag != GCOV_TAG_OBJECT_SUMMARY)
231 goto read_mismatch;
232 if (gcov_read_summary (da_file, &object))
233 goto read_error;
235 /* Check program summary */
236 while (1)
238 long base = ftell (da_file);
240 if (gcov_read_unsigned (da_file, &tag)
241 || gcov_read_unsigned (da_file, &length))
243 if (feof (da_file))
244 break;
245 goto read_error;
247 if (tag != GCOV_TAG_PROGRAM_SUMMARY
248 && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
249 && tag != GCOV_TAG_INCORRECT_SUMMARY)
250 goto read_mismatch;
251 if (gcov_read_summary (da_file, &local_prg))
252 goto read_error;
253 if (local_prg.checksum != program.checksum)
254 continue;
255 if (tag == GCOV_TAG_PLACEHOLDER_SUMMARY)
257 fprintf (stderr,
258 "profiling:%s:Concurrent race detected\n",
259 ptr->filename);
260 goto read_fatal;
262 merging = -1;
263 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
264 break;
266 if (program.runs
267 && memcmp (&program, &local_prg, sizeof (program)))
269 fprintf (stderr, "profiling:%s:Invocation mismatch\n",
270 ptr->filename);
271 local_prg.runs = 0;
273 else
274 memcpy (&program, &local_prg, sizeof (program));
275 ptr->wkspc = base;
276 break;
278 fseek (da_file, 0, SEEK_SET);
281 object.runs++;
282 object.arcs = ptr->n_arc_counts;
283 object.arc_sum = 0;
284 if (object.arc_max_one < object_max_one)
285 object.arc_max_one = object_max_one;
286 object.arc_sum_max += object_max_one;
288 /* Write out the data. */
289 if (/* magic */
290 gcov_write_unsigned (da_file, GCOV_DATA_MAGIC)
291 /* version number */
292 || gcov_write_unsigned (da_file, GCOV_VERSION))
294 write_error:;
295 fclose (da_file);
296 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
297 ptr->filename = 0;
298 continue;
301 /* Write execution counts for each function. */
302 count_ptr = ptr->arc_counts;
303 for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
305 /* Announce function. */
306 if (gcov_write_unsigned (da_file, GCOV_TAG_FUNCTION)
307 || !(base = gcov_reserve_length (da_file))
308 /* function name */
309 || gcov_write_string (da_file, fn_info->name,
310 strlen (fn_info->name))
311 /* function checksum */
312 || gcov_write_unsigned (da_file, fn_info->checksum)
313 || gcov_write_length (da_file, base))
314 goto write_error;
316 /* arc counts. */
317 if (gcov_write_unsigned (da_file, GCOV_TAG_ARC_COUNTS)
318 || !(base = gcov_reserve_length (da_file)))
319 goto write_error;
321 for (jx = fn_info->n_arc_counts; jx--;)
323 gcov_type count = *count_ptr++;
325 object.arc_sum += count;
326 if (object.arc_max_sum < count)
327 object.arc_max_sum = count;
328 if (gcov_write_counter (da_file, count))
329 goto write_error; /* RIP Edsger Dijkstra */
331 if (gcov_write_length (da_file, base))
332 goto write_error;
335 /* Object file summary. */
336 if (gcov_write_summary (da_file, GCOV_TAG_OBJECT_SUMMARY, &object))
337 goto write_error;
339 if (merging >= 0)
341 if (fseek (da_file, 0, SEEK_END))
342 goto write_error;
343 ptr->wkspc = ftell (da_file);
344 if (gcov_write_summary (da_file, GCOV_TAG_PLACEHOLDER_SUMMARY,
345 &program))
346 goto write_error;
348 else if (ptr->wkspc)
350 /* Zap trailing program summary */
351 if (fseek (da_file, ptr->wkspc, SEEK_SET))
352 goto write_error;
353 if (!local_prg.runs)
354 ptr->wkspc = 0;
355 if (gcov_write_unsigned (da_file,
356 local_prg.runs ? GCOV_TAG_PLACEHOLDER_SUMMARY
357 : GCOV_TAG_INCORRECT_SUMMARY))
358 goto write_error;
360 if (fflush (da_file))
361 goto write_error;
363 if (fclose (da_file))
365 fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
366 ptr->filename = 0;
368 else
370 program_arcs += ptr->n_arc_counts;
371 program_sum += object.arc_sum;
372 if (program_max_sum < object.arc_max_sum)
373 program_max_sum = object.arc_max_sum;
377 /* Generate whole program statistics. */
378 program.runs++;
379 program.arcs = program_arcs;
380 program.arc_sum = program_sum;
381 if (program.arc_max_one < program_max_one)
382 program.arc_max_one = program_max_one;
383 if (program.arc_max_sum < program_max_sum)
384 program.arc_max_sum = program_max_sum;
385 program.arc_sum_max += program_max_one;
387 /* Upate whole program statistics. */
388 for (ptr = gcov_list; ptr; ptr = ptr->next)
389 if (ptr->filename && ptr->wkspc)
391 FILE *da_file;
393 da_file = fopen (ptr->filename, "r+b");
394 if (!da_file)
396 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
397 continue;
400 #if defined (TARGET_HAS_F_SETLKW)
401 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
402 && errno == EINTR)
403 continue;
404 #endif
405 if (fseek (da_file, ptr->wkspc, SEEK_SET)
406 || gcov_write_summary (da_file, GCOV_TAG_PROGRAM_SUMMARY, &program)
407 || fflush (da_file))
408 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
409 if (fclose (da_file))
410 fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
414 /* Add a new object file onto the bb chain. Invoked automatically
415 when running an object file's global ctors. */
417 void
418 __gcov_init (struct gcov_info *info)
420 if (!info->version)
421 return;
422 if (info->version != GCOV_VERSION)
423 gcov_version_mismatch (info, info->version);
424 else
426 const char *ptr = info->filename;
427 unsigned crc32 = gcov_crc32;
431 unsigned ix;
432 unsigned value = *ptr << 24;
434 for (ix = 8; ix--; value <<= 1)
436 unsigned feedback;
438 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
439 crc32 <<= 1;
440 crc32 ^= feedback;
443 while (*ptr++);
445 gcov_crc32 = crc32;
447 if (!gcov_list)
448 atexit (gcov_exit);
450 info->next = gcov_list;
451 gcov_list = info;
453 info->version = 0;
456 /* Called before fork or exec - write out profile information gathered so
457 far and reset it to zero. This avoids duplication or loss of the
458 profile information gathered so far. */
460 void
461 __gcov_flush (void)
463 struct gcov_info *ptr;
465 gcov_exit ();
466 for (ptr = gcov_list; ptr; ptr = ptr->next)
468 unsigned i;
470 for (i = ptr->n_arc_counts; i--;)
471 ptr->arc_counts[i] = 0;