]> gcc.gnu.org Git - gcc.git/blame - gcc/libgcov.c
re PR other/10658 (Change copyright year.)
[gcc.git] / gcc / libgcov.c
CommitLineData
23af32e6
NS
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.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13In addition to the permissions in the GNU General Public License, the
14Free Software Foundation gives you unlimited permission to link the
15compiled version of this file into combinations with other programs,
16and to distribute those combinations without any restriction coming
17from the use of this file. (The General Public License restrictions
18do apply in other respects; for example, they cover modification of
19the file, and distribution when not linked into a combine
20executable.)
21
22GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23WARRANTY; without even the implied warranty of MERCHANTABILITY or
24FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received a copy of the GNU General Public License
28along with GCC; see the file COPYING. If not, write to the Free
29Software Foundation, 59 Temple Place - Suite 330, Boston, MA
3002111-1307, USA. */
31
01e60c33
JJ
32#if defined(inhibit_libc)
33/* If libc and its header files are not available, provide dummy functions. */
34
09780dfb 35#ifdef L_gcov
01e60c33
JJ
36void __gcov_init (void *p);
37void __gcov_flush (void);
38
39void __gcov_init (void *p) { }
40void __gcov_flush (void) { }
09780dfb
ZD
41#endif
42
43#ifdef L_gcov_merge_add
1e77e673 44void __gcov_merge_add (void *, unsigned);
09780dfb 45
1e77e673 46void __gcov_merge_add (void *counters, unsigned n_counters) { }
09780dfb 47#endif
01e60c33
JJ
48
49#else
50
23af32e6
NS
51/* It is incorrect to include config.h here, because this file is being
52 compiled for the target, and hence definitions concerning only the host
53 do not apply. */
54
55#include "tconfig.h"
56#include "tsystem.h"
57#include "coretypes.h"
58#include "tm.h"
59
60#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
61#include <stdio.h>
62
23af32e6
NS
63#include <string.h>
64#if defined (TARGET_HAS_F_SETLKW)
65#include <fcntl.h>
66#include <errno.h>
67#endif
546d2adb 68#define IN_LIBGCOV 1
ec4a0419 69#include "gcov-io.h"
09780dfb
ZD
70
71#ifdef L_gcov
ca29da43 72#include "gcov-io.c"
23af32e6
NS
73
74/* Chain of per-object gcov structures. */
75static struct gcov_info *gcov_list;
76
77/* A program checksum allows us to distinguish program data for an
78 object file included in multiple programs. */
79static unsigned gcov_crc32;
80
81static void
82gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
83{
84 unsigned expected = GCOV_VERSION;
85 unsigned ix;
86 char e[4], v[4];
87
88 for (ix = 4; ix--; expected >>= 8, version >>= 8)
89 {
90 e[ix] = expected;
91 v[ix] = version;
92 }
93
94 fprintf (stderr,
95 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
96 ptr->filename, e, v);
97}
98
99/* Dump the coverage counts. We merge with existing counts when
100 possible, to avoid growing the .da files ad infinitum. We use this
101 program's checksum to make sure we only accumulate whole program
102 statistics to the correct summary. An object file might be embedded
103 in two separate programs, and we must keep the two program
104 summaries separate. */
105
106static void
107gcov_exit (void)
108{
cdb23767
NS
109 struct gcov_info *gi_ptr;
110 struct gcov_summary this_program;
111 struct gcov_summary all;
112
113 memset (&all, 0, sizeof (all));
114 /* Find the totals for this execution. */
115 memset (&this_program, 0, sizeof (this_program));
116 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
d101590b 117 {
cdb23767
NS
118 const struct gcov_ctr_info *ci_ptr;
119 struct gcov_ctr_summary *cs_ptr;
120 unsigned t_ix;
121
122 for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
123 t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
124 if ((1 << t_ix) & gi_ptr->ctr_mask)
125 {
126 const gcov_type *c_ptr;
127 unsigned c_num;
128
129 cs_ptr->num += ci_ptr->num;
130 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
131 {
132 cs_ptr->sum_all += *c_ptr;
133 if (cs_ptr->run_max < *c_ptr)
134 cs_ptr->run_max = *c_ptr;
135 }
136 ci_ptr++;
137 }
d101590b 138 }
cdb23767
NS
139
140 /* Now write the data */
141 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
23af32e6 142 {
cdb23767
NS
143 struct gcov_summary this_object;
144 struct gcov_summary object, program;
145 gcov_type *values[GCOV_COUNTERS];
146 const struct gcov_fn_info *fi_ptr;
147 unsigned fi_stride;
148 unsigned c_ix, t_ix, f_ix;
149 const struct gcov_ctr_info *ci_ptr;
150 struct gcov_ctr_summary *cs_ptr;
151 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
94de45d9 152 int error;
546d2adb 153 int merging;
94de45d9 154 unsigned long base;
94de45d9 155 unsigned tag, length;
cdb23767
NS
156 unsigned long summary_pos = 0;
157
158 /* Totals for this object file. */
159 memset (&this_object, 0, sizeof (this_object));
160 for (t_ix = c_ix = 0,
161 ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
162 t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
163 if ((1 << t_ix) & gi_ptr->ctr_mask)
164 {
165 const gcov_type *c_ptr;
166 unsigned c_num;
167
168 cs_ptr->num += ci_ptr->num;
169 values[c_ix] = ci_ptr->values;
170 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
171 {
172 cs_ptr->sum_all += *c_ptr;
173 if (cs_ptr->run_max < *c_ptr)
174 cs_ptr->run_max = *c_ptr;
175 }
176 c_ix++;
177 ci_ptr++;
178 }
179
180 /* Calculate the function_info stride. This depends on the
181 number of counter types being measured. */
182 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
183 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
cb9e4555 184 {
cdb23767
NS
185 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
186 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
cb9e4555 187 }
546d2adb 188
cdb23767
NS
189 /* Open for modification, if possible */
190 merging = gcov_open (gi_ptr->filename, 0);
546d2adb 191 if (!merging)
23af32e6 192 {
cdb23767 193 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
23af32e6
NS
194 continue;
195 }
546d2adb
NS
196
197 if (merging > 0)
23af32e6
NS
198 {
199 /* Merge data from file. */
94de45d9 200 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
23af32e6
NS
201 {
202 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
cdb23767 203 gi_ptr->filename);
23af32e6 204 read_fatal:;
546d2adb 205 gcov_close ();
23af32e6
NS
206 continue;
207 }
94de45d9
NS
208 length = gcov_read_unsigned ();
209 if (length != GCOV_VERSION)
23af32e6 210 {
cdb23767 211 gcov_version_mismatch (gi_ptr, length);
23af32e6
NS
212 goto read_fatal;
213 }
214
215 /* Merge execution counts for each function. */
796621e8
NS
216 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions;
217 f_ix--;
cdb23767
NS
218 fi_ptr = (const struct gcov_fn_info *)
219 ((const char *) fi_ptr + fi_stride))
23af32e6 220 {
94de45d9
NS
221 tag = gcov_read_unsigned ();
222 length = gcov_read_unsigned ();
23af32e6
NS
223
224 /* Check function */
796621e8
NS
225 if (tag != GCOV_TAG_FUNCTION
226 || gcov_read_unsigned () != fi_ptr->ident
227 || gcov_read_unsigned () != fi_ptr->checksum)
23af32e6
NS
228 {
229 read_mismatch:;
cdb23767
NS
230 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
231 gi_ptr->filename,
796621e8 232 f_ix + 1 ? "function" : "summaries");
23af32e6
NS
233 goto read_fatal;
234 }
cb9e4555 235
cdb23767
NS
236 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
237 if ((1 << t_ix) & gi_ptr->ctr_mask)
238 {
239 unsigned n_counts;
09780dfb 240 gcov_merge_fn merge;
cdb23767
NS
241
242 tag = gcov_read_unsigned ();
243 length = gcov_read_unsigned ();
244
245 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
246 || fi_ptr->n_ctrs[c_ix] * 8 != length)
247 goto read_mismatch;
09780dfb
ZD
248 n_counts = fi_ptr->n_ctrs[c_ix];
249 merge = gi_ptr->counts[c_ix].merge;
250 (*merge) (values[c_ix], n_counts);
251 values[c_ix] += n_counts;
cdb23767 252 c_ix++;
cb9e4555 253 }
94de45d9
NS
254 if ((error = gcov_is_error ()))
255 goto read_error;
23af32e6
NS
256 }
257
258 /* Check object summary */
94de45d9 259 if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
23af32e6 260 goto read_mismatch;
94de45d9
NS
261 gcov_read_unsigned ();
262 gcov_read_summary (&object);
23af32e6
NS
263
264 /* Check program summary */
94de45d9 265 while (!gcov_is_eof ())
23af32e6 266 {
cdb23767 267 base = gcov_position ();
94de45d9
NS
268 tag = gcov_read_unsigned ();
269 gcov_read_unsigned ();
d101590b 270 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
23af32e6 271 goto read_mismatch;
cdb23767 272 gcov_read_summary (&program);
94de45d9
NS
273 if ((error = gcov_is_error ()))
274 {
275 read_error:;
276 fprintf (stderr, error < 0 ?
277 "profiling:%s:Overflow merging\n" :
278 "profiling:%s:Error merging\n",
cdb23767 279 gi_ptr->filename);
94de45d9
NS
280 goto read_fatal;
281 }
282
cdb23767
NS
283 if (program.checksum != gcov_crc32)
284 continue;
d101590b 285 summary_pos = base;
23af32e6
NS
286 break;
287 }
94de45d9 288 gcov_seek (0, 0);
23af32e6 289 }
cdb23767
NS
290 else
291 memset (&object, 0, sizeof (object));
292 if (!summary_pos)
293 memset (&program, 0, sizeof (program));
23af32e6 294
cdb23767 295 /* Merge the summaries. */
796621e8 296 f_ix = ~0u;
cdb23767
NS
297 for (t_ix = c_ix = 0,
298 cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
299 cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
300 cs_all = all.ctrs;
301 t_ix != GCOV_COUNTERS;
302 t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
303 {
304 if ((1 << t_ix) & gi_ptr->ctr_mask)
305 {
306 if (!cs_obj->runs++)
307 cs_obj->num = cs_tobj->num;
308 else if (cs_obj->num != cs_tobj->num)
309 goto read_mismatch;
310 cs_obj->sum_all += cs_tobj->sum_all;
311 if (cs_obj->run_max < cs_tobj->run_max)
312 cs_obj->run_max = cs_tobj->run_max;
313 cs_obj->sum_max += cs_tobj->run_max;
314
315 if (!cs_prg->runs++)
316 cs_prg->num = cs_tprg->num;
317 else if (cs_prg->num != cs_tprg->num)
318 goto read_mismatch;
319 cs_prg->sum_all += cs_tprg->sum_all;
320 if (cs_prg->run_max < cs_tprg->run_max)
321 cs_prg->run_max = cs_tprg->run_max;
322 cs_prg->sum_max += cs_tprg->run_max;
323
324 values[c_ix] = gi_ptr->counts[c_ix].values;
325 c_ix++;
326 }
327 else if (cs_obj->num || cs_prg->num)
328 goto read_mismatch;
329
330 if (!cs_all->runs && cs_prg->runs)
331 memcpy (cs_all, cs_prg, sizeof (*cs_all));
332 else if (!all.checksum
333 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
334 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
335 {
336 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
337 gi_ptr->filename, GCOV_LOCKED
338 ? "" : " or concurrent update without locking support");
339 all.checksum = ~0u;
340 }
341 }
342
343 program.checksum = gcov_crc32;
23af32e6
NS
344
345 /* Write out the data. */
94de45d9
NS
346 gcov_write_unsigned (GCOV_DATA_MAGIC);
347 gcov_write_unsigned (GCOV_VERSION);
23af32e6
NS
348
349 /* Write execution counts for each function. */
cdb23767
NS
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))
23af32e6
NS
353 {
354 /* Announce function. */
94de45d9 355 base = gcov_write_tag (GCOV_TAG_FUNCTION);
796621e8 356 gcov_write_unsigned (fi_ptr->ident);
cdb23767 357 gcov_write_unsigned (fi_ptr->checksum);
94de45d9 358 gcov_write_length (base);
cb9e4555 359
cdb23767
NS
360 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
361 if ((1 << t_ix) & gi_ptr->ctr_mask)
362 {
363 unsigned n_counts;
364 gcov_type *c_ptr;
365
366 base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
367 c_ptr = values[c_ix];
368 for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
369 gcov_write_counter (*c_ptr);
370 values[c_ix] = c_ptr;
371 gcov_write_length (base);
372 c_ix++;
373 }
23af32e6
NS
374 }
375
376 /* Object file summary. */
94de45d9 377 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
23af32e6 378
d101590b 379 /* Generate whole program statistics. */
cdb23767
NS
380 if (summary_pos)
381 gcov_seek (summary_pos, 0);
382 else
383 gcov_seek_end ();
384 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
385 if ((error = gcov_close ()))
23af32e6 386 {
cdb23767
NS
387 fprintf (stderr, error < 0 ?
388 "profiling:%s:Overflow writing\n" :
389 "profiling:%s:Error writing\n",
390 gi_ptr->filename);
391 gi_ptr->filename = 0;
23af32e6 392 }
23af32e6 393 }
23af32e6
NS
394}
395
396/* Add a new object file onto the bb chain. Invoked automatically
397 when running an object file's global ctors. */
398
399void
400__gcov_init (struct gcov_info *info)
401{
402 if (!info->version)
403 return;
404 if (info->version != GCOV_VERSION)
405 gcov_version_mismatch (info, info->version);
406 else
407 {
408 const char *ptr = info->filename;
409 unsigned crc32 = gcov_crc32;
410
411 do
412 {
413 unsigned ix;
414 unsigned value = *ptr << 24;
415
416 for (ix = 8; ix--; value <<= 1)
417 {
418 unsigned feedback;
419
420 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
421 crc32 <<= 1;
422 crc32 ^= feedback;
423 }
424 }
425 while (*ptr++);
426
427 gcov_crc32 = crc32;
428
429 if (!gcov_list)
430 atexit (gcov_exit);
431
432 info->next = gcov_list;
433 gcov_list = info;
434 }
435 info->version = 0;
436}
437
438/* Called before fork or exec - write out profile information gathered so
439 far and reset it to zero. This avoids duplication or loss of the
440 profile information gathered so far. */
441
442void
443__gcov_flush (void)
444{
cdb23767 445 const struct gcov_info *gi_ptr;
23af32e6
NS
446
447 gcov_exit ();
cdb23767 448 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
23af32e6 449 {
cdb23767
NS
450 unsigned t_ix;
451 const struct gcov_ctr_info *ci_ptr;
23af32e6 452
cdb23767
NS
453 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
454 if ((1 << t_ix) & gi_ptr->ctr_mask)
455 {
456 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
457 ci_ptr++;
458 }
23af32e6
NS
459 }
460}
01e60c33 461
09780dfb
ZD
462#endif /* L_gcov */
463
464#ifdef L_gcov_merge_add
465/* The profile merging function that just adds the counters. It is given
466 an array COUNTERS of N_COUNTERS old counters and it reads the same number
467 of counters from the gcov file. */
468void
469__gcov_merge_add (counters, n_counters)
470 gcov_type *counters;
471 unsigned n_counters;
472{
473 for (; n_counters; counters++, n_counters--)
474 *counters += gcov_read_counter ();
475}
476#endif /* L_gcov_merge_add */
477
01e60c33 478#endif /* inhibit_libc */
This page took 0.249855 seconds and 5 git commands to generate.