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 /* 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
38 #include "coretypes.h"
41 #if defined(inhibit_libc)
42 #define IN_LIBGCOV (-1)
44 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
48 #define GCOV_LINKAGE /* nothing */
53 #if defined(inhibit_libc)
54 /* If libc and its header files are not available, provide dummy functions. */
57 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
58 void __gcov_flush (void) {}
61 #ifdef L_gcov_merge_add
62 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
63 unsigned n_counters __attribute__ ((unused))) {}
77 /* Chain of per-object gcov structures. */
78 static struct gcov_info *gcov_list;
80 /* A program checksum allows us to distinguish program data for an
81 object file included in multiple programs. */
82 static gcov_unsigned_t gcov_crc32;
85 gcov_version_mismatch (struct gcov_info *ptr, gcov_unsigned_t version)
87 gcov_unsigned_t expected = GCOV_VERSION;
91 for (ix = 4; ix--; expected >>= 8, version >>= 8)
98 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
102 /* Dump the coverage counts. We merge with existing counts when
103 possible, to avoid growing the .da files ad infinitum. We use this
104 program's checksum to make sure we only accumulate whole program
105 statistics to the correct summary. An object file might be embedded
106 in two separate programs, and we must keep the two program
107 summaries separate. */
112 struct gcov_info *gi_ptr;
113 struct gcov_summary this_program;
114 struct gcov_summary all;
116 memset (&all, 0, sizeof (all));
117 /* Find the totals for this execution. */
118 memset (&this_program, 0, sizeof (this_program));
119 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
121 const struct gcov_ctr_info *ci_ptr;
122 struct gcov_ctr_summary *cs_ptr;
125 for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
126 t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++)
127 if ((1 << t_ix) & gi_ptr->ctr_mask)
129 const gcov_type *c_ptr;
130 gcov_unsigned_t c_num;
132 cs_ptr->num += ci_ptr->num;
133 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
135 cs_ptr->sum_all += *c_ptr;
136 if (cs_ptr->run_max < *c_ptr)
137 cs_ptr->run_max = *c_ptr;
143 /* Now merge each file */
144 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
146 struct gcov_summary this_object;
147 struct gcov_summary object, program;
148 gcov_type *values[GCOV_COUNTERS];
149 const struct gcov_fn_info *fi_ptr;
151 unsigned c_ix, t_ix, f_ix;
152 const struct gcov_ctr_info *ci_ptr;
153 struct gcov_ctr_summary *cs_ptr;
154 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
157 gcov_unsigned_t tag, length;
158 gcov_position_t summary_pos = 0;
160 /* Totals for this object file. */
161 memset (&this_object, 0, sizeof (this_object));
162 for (t_ix = c_ix = 0,
163 ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
164 t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++)
165 if ((1 << t_ix) & gi_ptr->ctr_mask)
167 const gcov_type *c_ptr;
168 gcov_unsigned_t c_num;
170 cs_ptr->num += ci_ptr->num;
171 values[c_ix] = ci_ptr->values;
172 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
174 cs_ptr->sum_all += *c_ptr;
175 if (cs_ptr->run_max < *c_ptr)
176 cs_ptr->run_max = *c_ptr;
182 /* Calculate the function_info stride. This depends on the
183 number of counter types being measured. */
184 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
185 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
187 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
188 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
191 /* Open for modification, if possible */
192 merging = gcov_open (gi_ptr->filename, 0);
195 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
201 /* Merge data from file. */
202 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
204 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
210 length = gcov_read_unsigned ();
211 if (length != GCOV_VERSION)
213 gcov_version_mismatch (gi_ptr, length);
217 /* Merge execution counts for each function. */
218 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions;
220 fi_ptr = (const struct gcov_fn_info *)
221 ((const char *) fi_ptr + fi_stride))
223 tag = gcov_read_unsigned ();
224 length = gcov_read_unsigned ();
227 if (tag != GCOV_TAG_FUNCTION
228 || length != GCOV_TAG_FUNCTION_LENGTH
229 || gcov_read_unsigned () != fi_ptr->ident
230 || gcov_read_unsigned () != fi_ptr->checksum)
233 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
235 f_ix + 1 ? "function" : "summaries");
239 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
240 if ((1 << t_ix) & gi_ptr->ctr_mask)
242 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
243 gcov_merge_fn merge = gi_ptr->counts[c_ix].merge;
245 tag = gcov_read_unsigned ();
246 length = gcov_read_unsigned ();
247 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
248 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
250 (*merge) (values[c_ix], n_counts);
251 values[c_ix] += n_counts;
254 if ((error = gcov_is_error ()))
258 /* Check program & object summary */
261 gcov_position_t base = gcov_position ();
264 tag = gcov_read_unsigned ();
267 length = gcov_read_unsigned ();
268 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
269 if (length != GCOV_TAG_SUMMARY_LENGTH
270 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
272 gcov_read_summary (is_program ? &program : &object);
273 if ((error = gcov_is_error ()))
275 if (is_program && program.checksum == gcov_crc32)
284 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
285 : "profiling:%s:Error merging\n", gi_ptr->filename);
292 memset (&object, 0, sizeof (object));
294 memset (&program, 0, sizeof (program));
296 /* Merge the summaries. */
298 for (t_ix = c_ix = 0,
299 cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
300 cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
302 t_ix != GCOV_COUNTERS_SUMMABLE;
303 t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
305 if ((1 << t_ix) & gi_ptr->ctr_mask)
308 cs_obj->num = cs_tobj->num;
309 else if (cs_obj->num != cs_tobj->num)
311 cs_obj->sum_all += cs_tobj->sum_all;
312 if (cs_obj->run_max < cs_tobj->run_max)
313 cs_obj->run_max = cs_tobj->run_max;
314 cs_obj->sum_max += cs_tobj->run_max;
317 cs_prg->num = cs_tprg->num;
318 else if (cs_prg->num != cs_tprg->num)
320 cs_prg->sum_all += cs_tprg->sum_all;
321 if (cs_prg->run_max < cs_tprg->run_max)
322 cs_prg->run_max = cs_tprg->run_max;
323 cs_prg->sum_max += cs_tprg->run_max;
325 values[c_ix] = gi_ptr->counts[c_ix].values;
328 else if (cs_obj->num || cs_prg->num)
331 if (!cs_all->runs && cs_prg->runs)
332 memcpy (cs_all, cs_prg, sizeof (*cs_all));
333 else if (!all.checksum
334 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
335 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
337 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
338 gi_ptr->filename, GCOV_LOCKED
339 ? "" : " or concurrent update without locking support");
344 program.checksum = gcov_crc32;
346 /* Write out the data. */
347 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
349 /* Write execution counts for each function. */
350 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
351 fi_ptr = (const struct gcov_fn_info *)
352 ((const char *) fi_ptr + fi_stride))
354 /* Announce function. */
355 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
356 gcov_write_unsigned (fi_ptr->ident);
357 gcov_write_unsigned (fi_ptr->checksum);
359 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
360 if ((1 << t_ix) & gi_ptr->ctr_mask)
362 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
365 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
366 GCOV_TAG_COUNTER_LENGTH (n_counts));
367 c_ptr = values[c_ix];
369 gcov_write_counter (*c_ptr++);
370 values[c_ix] = c_ptr;
375 /* Object file summary. */
376 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
378 /* Generate whole program statistics. */
379 gcov_seek (summary_pos);
380 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
381 if ((error = gcov_close ()))
382 fprintf (stderr, error < 0 ?
383 "profiling:%s:Overflow writing\n" :
384 "profiling:%s:Error writing\n",
389 /* Add a new object file onto the bb chain. Invoked automatically
390 when running an object file's global ctors. */
393 __gcov_init (struct gcov_info *info)
397 if (info->version != GCOV_VERSION)
398 gcov_version_mismatch (info, info->version);
401 const char *ptr = info->filename;
402 gcov_unsigned_t crc32 = gcov_crc32;
407 gcov_unsigned_t value = *ptr << 24;
409 for (ix = 8; ix--; value <<= 1)
411 gcov_unsigned_t feedback;
413 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
425 info->next = gcov_list;
431 /* Called before fork or exec - write out profile information gathered so
432 far and reset it to zero. This avoids duplication or loss of the
433 profile information gathered so far. */
438 const struct gcov_info *gi_ptr;
441 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
444 const struct gcov_ctr_info *ci_ptr;
446 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
447 if ((1 << t_ix) & gi_ptr->ctr_mask)
449 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
457 #ifdef L_gcov_merge_add
458 /* The profile merging function that just adds the counters. It is given
459 an array COUNTERS of N_COUNTERS old counters and it reads the same number
460 of counters from the gcov file. */
462 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
464 for (; n_counters; counters++, n_counters--)
465 *counters += gcov_read_counter ();
467 #endif /* L_gcov_merge_add */
469 #endif /* inhibit_libc */