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
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
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
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
32 #if defined(inhibit_libc)
33 /* If libc and its header files are not available, provide dummy functions. */
35 void __gcov_init (void *p);
36 void __gcov_flush (void);
38 void __gcov_init (void *p) { }
39 void __gcov_flush (void) { }
43 /* It is incorrect to include config.h here, because this file is being
44 compiled for the target, and hence definitions concerning only the host
49 #include "coretypes.h"
52 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
56 #if defined (TARGET_HAS_F_SETLKW)
63 /* Chain of per-object gcov structures. */
64 static struct gcov_info *gcov_list;
66 /* A program checksum allows us to distinguish program data for an
67 object file included in multiple programs. */
68 static unsigned gcov_crc32;
71 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
73 unsigned expected = GCOV_VERSION;
77 for (ix = 4; ix--; expected >>= 8, version >>= 8)
84 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
88 /* Dump the coverage counts. We merge with existing counts when
89 possible, to avoid growing the .da files ad infinitum. We use this
90 program's checksum to make sure we only accumulate whole program
91 statistics to the correct summary. An object file might be embedded
92 in two separate programs, and we must keep the two program
93 summaries separate. */
98 struct gcov_info *ptr;
100 struct gcov_summary program;
101 gcov_type program_max_one = 0;
102 gcov_type program_max_sum = 0;
103 gcov_type program_sum = 0;
104 unsigned program_arcs = 0;
106 memset (&program, 0, sizeof (program));
107 program.checksum = gcov_crc32;
109 for (ptr = gcov_list; ptr; ptr = ptr->next)
111 struct gcov_summary object;
112 struct gcov_summary local_prg;
116 const struct function_info *fn_info;
117 gcov_type **counters;
118 gcov_type *count_ptr;
119 gcov_type object_max_one = 0;
120 unsigned tag, length;
121 unsigned arc_data_index, f_sect_index, sect_index;
127 counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
128 for (ix = 0; ix < ptr->n_counter_sections; ix++)
129 counters[ix] = ptr->counter_sections[ix].counters;
131 for (arc_data_index = 0;
132 arc_data_index < ptr->n_counter_sections
133 && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
137 if (arc_data_index == ptr->n_counter_sections)
139 /* For now; later we may want to just measure other profiles,
140 but now I am lazy to check for all consequences. */
143 for (ix = ptr->counter_sections[arc_data_index].n_counters,
144 count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
146 gcov_type count = *count_ptr++;
148 if (count > object_max_one)
149 object_max_one = count;
151 if (object_max_one > program_max_one)
152 program_max_one = object_max_one;
154 memset (&local_prg, 0, sizeof (local_prg));
155 memset (&object, 0, sizeof (object));
157 /* Open for modification */
158 merging = gcov_open (ptr->filename, 0);
162 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
169 /* Merge data from file. */
170 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
172 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
179 length = gcov_read_unsigned ();
180 if (length != GCOV_VERSION)
182 gcov_version_mismatch (ptr, length);
186 /* Merge execution counts for each function. */
187 for (ix = ptr->n_functions, fn_info = ptr->functions;
190 tag = gcov_read_unsigned ();
191 length = gcov_read_unsigned ();
194 if (tag != GCOV_TAG_FUNCTION)
197 fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
198 ptr->filename, fn_info->name);
202 if (strcmp (gcov_read_string (), fn_info->name)
203 || gcov_read_unsigned () != fn_info->checksum)
207 for (f_sect_index = 0;
208 f_sect_index < fn_info->n_counter_sections;
213 tag = gcov_read_unsigned ();
214 length = gcov_read_unsigned ();
217 sect_index < ptr->n_counter_sections;
219 if (ptr->counter_sections[sect_index].tag == tag)
221 if (sect_index == ptr->n_counter_sections
222 || fn_info->counter_sections[f_sect_index].tag != tag)
225 n_counters = fn_info->counter_sections[f_sect_index].n_counters;
226 if (n_counters != length / 8)
229 for (jx = 0; jx < n_counters; jx++)
230 counters[sect_index][jx] += gcov_read_counter ();
232 counters[sect_index] += n_counters;
234 if ((error = gcov_is_error ()))
238 /* Check object summary */
239 if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
241 gcov_read_unsigned ();
242 gcov_read_summary (&object);
244 /* Check program summary */
245 while (!gcov_is_eof ())
247 unsigned long base = gcov_position ();
249 tag = gcov_read_unsigned ();
250 gcov_read_unsigned ();
251 if (tag != GCOV_TAG_PROGRAM_SUMMARY
252 && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
253 && tag != GCOV_TAG_INCORRECT_SUMMARY)
255 gcov_read_summary (&local_prg);
256 if ((error = gcov_is_error ()))
259 fprintf (stderr, error < 0 ?
260 "profiling:%s:Overflow merging\n" :
261 "profiling:%s:Error merging\n",
266 if (local_prg.checksum != program.checksum)
268 if (tag == GCOV_TAG_PLACEHOLDER_SUMMARY)
271 "profiling:%s:Concurrent race detected\n",
276 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
280 && memcmp (&program, &local_prg, sizeof (program)))
282 fprintf (stderr, "profiling:%s:Invocation mismatch\n",
287 memcpy (&program, &local_prg, sizeof (program));
295 object.arcs = ptr->counter_sections[arc_data_index].n_counters;
297 if (object.arc_max_one < object_max_one)
298 object.arc_max_one = object_max_one;
299 object.arc_sum_max += object_max_one;
301 /* Write out the data. */
302 gcov_write_unsigned (GCOV_DATA_MAGIC);
303 gcov_write_unsigned (GCOV_VERSION);
305 /* Write execution counts for each function. */
306 for (ix = 0; ix < ptr->n_counter_sections; ix++)
307 counters[ix] = ptr->counter_sections[ix].counters;
308 for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
310 /* Announce function. */
311 base = gcov_write_tag (GCOV_TAG_FUNCTION);
312 gcov_write_string (fn_info->name);
313 gcov_write_unsigned (fn_info->checksum);
314 gcov_write_length (base);
317 for (f_sect_index = 0;
318 f_sect_index < fn_info->n_counter_sections;
321 tag = fn_info->counter_sections[f_sect_index].tag;
323 sect_index < ptr->n_counter_sections;
325 if (ptr->counter_sections[sect_index].tag == tag)
327 if (sect_index == ptr->n_counter_sections)
330 base = gcov_write_tag (tag);
331 for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
333 gcov_type count = *counters[sect_index]++;
335 if (tag == GCOV_TAG_ARC_COUNTS)
337 object.arc_sum += count;
338 if (object.arc_max_sum < count)
339 object.arc_max_sum = count;
341 gcov_write_counter (count);
343 gcov_write_length (base);
347 /* Object file summary. */
348 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
352 ptr->wkspc = gcov_seek_end ();
353 gcov_write_summary (GCOV_TAG_PLACEHOLDER_SUMMARY, &program);
357 /* Zap trailing program summary */
358 gcov_seek (ptr->wkspc, 0);
361 gcov_write_unsigned (local_prg.runs
362 ? GCOV_TAG_PLACEHOLDER_SUMMARY
363 : GCOV_TAG_INCORRECT_SUMMARY);
367 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
372 program_arcs += ptr->counter_sections[arc_data_index].n_counters;
373 program_sum += object.arc_sum;
374 if (program_max_sum < object.arc_max_sum)
375 program_max_sum = object.arc_max_sum;
380 /* Generate whole program statistics. */
382 program.arcs = program_arcs;
383 program.arc_sum = program_sum;
384 if (program.arc_max_one < program_max_one)
385 program.arc_max_one = program_max_one;
386 if (program.arc_max_sum < program_max_sum)
387 program.arc_max_sum = program_max_sum;
388 program.arc_sum_max += program_max_one;
390 /* Upate whole program statistics. */
391 for (ptr = gcov_list; ptr; ptr = ptr->next)
392 if (ptr->filename && ptr->wkspc)
394 if (!gcov_open (ptr->filename, 1))
396 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
400 gcov_seek (ptr->wkspc, 0);
401 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
403 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
407 /* Add a new object file onto the bb chain. Invoked automatically
408 when running an object file's global ctors. */
411 __gcov_init (struct gcov_info *info)
415 if (info->version != GCOV_VERSION)
416 gcov_version_mismatch (info, info->version);
419 const char *ptr = info->filename;
420 unsigned crc32 = gcov_crc32;
425 unsigned value = *ptr << 24;
427 for (ix = 8; ix--; value <<= 1)
431 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
443 info->next = gcov_list;
449 /* Called before fork or exec - write out profile information gathered so
450 far and reset it to zero. This avoids duplication or loss of the
451 profile information gathered so far. */
456 struct gcov_info *ptr;
459 for (ptr = gcov_list; ptr; ptr = ptr->next)
463 for (j = 0; j < ptr->n_counter_sections; j++)
464 for (i = ptr->counter_sections[j].n_counters; i--;)
465 ptr->counter_sections[j].counters[i] = 0;
469 #endif /* inhibit_libc */