gcov-io.h (GCOV_LOCKED): New #define.
[gcc.git] / gcc / libgcov.c
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
6 This file is part of GCC.
7
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.
12
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.)
21
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.
26
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. */
31
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. */
35
36 #include "tconfig.h"
37 #include "tsystem.h"
38 #include "coretypes.h"
39 #include "tm.h"
40
41 #if defined(inhibit_libc)
42 #define IN_LIBGCOV (-1)
43 #else
44 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
45 #include <stdio.h>
46 #define IN_LIBGCOV 1
47 #if defined(L_gcov)
48 #define GCOV_LINKAGE /* nothing */
49 #endif
50 #endif
51 #include "gcov-io.h"
52
53 #if defined(inhibit_libc)
54 /* If libc and its header files are not available, provide dummy functions. */
55
56 #ifdef L_gcov
57 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
58 void __gcov_flush (void) {}
59 #endif
60
61 #ifdef L_gcov_merge_add
62 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
63 unsigned n_counters __attribute__ ((unused))) {}
64 #endif
65
66 #else
67
68 #include <string.h>
69 #if GCOV_LOCKED
70 #include <fcntl.h>
71 #include <errno.h>
72 #endif
73
74 #ifdef L_gcov
75 #include "gcov-io.c"
76
77 /* Chain of per-object gcov structures. */
78 static struct gcov_info *gcov_list;
79
80 /* A program checksum allows us to distinguish program data for an
81 object file included in multiple programs. */
82 static unsigned gcov_crc32;
83
84 static void
85 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
86 {
87 unsigned expected = GCOV_VERSION;
88 unsigned ix;
89 char e[4], v[4];
90
91 for (ix = 4; ix--; expected >>= 8, version >>= 8)
92 {
93 e[ix] = expected;
94 v[ix] = version;
95 }
96
97 fprintf (stderr,
98 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
99 ptr->filename, e, v);
100 }
101
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. */
108
109 static void
110 gcov_exit (void)
111 {
112 struct gcov_info *gi_ptr;
113 struct gcov_summary this_program;
114 struct gcov_summary all;
115
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)
120 {
121 const struct gcov_ctr_info *ci_ptr;
122 struct gcov_ctr_summary *cs_ptr;
123 unsigned t_ix;
124
125 for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
126 t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
127 if ((1 << t_ix) & gi_ptr->ctr_mask)
128 {
129 const gcov_type *c_ptr;
130 unsigned c_num;
131
132 cs_ptr->num += ci_ptr->num;
133 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
134 {
135 cs_ptr->sum_all += *c_ptr;
136 if (cs_ptr->run_max < *c_ptr)
137 cs_ptr->run_max = *c_ptr;
138 }
139 ci_ptr++;
140 }
141 }
142
143 /* Now write the data */
144 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
145 {
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;
150 unsigned fi_stride;
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;
155 int error;
156 int merging;
157 unsigned tag, length;
158 unsigned long summary_pos = ~0UL;
159
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; t_ix++, cs_ptr++)
165 if ((1 << t_ix) & gi_ptr->ctr_mask)
166 {
167 const gcov_type *c_ptr;
168 unsigned c_num;
169
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++)
173 {
174 cs_ptr->sum_all += *c_ptr;
175 if (cs_ptr->run_max < *c_ptr)
176 cs_ptr->run_max = *c_ptr;
177 }
178 c_ix++;
179 ci_ptr++;
180 }
181
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))
186 {
187 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
188 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
189 }
190
191 /* Open for modification, if possible */
192 merging = gcov_open (gi_ptr->filename, 0);
193 if (!merging)
194 {
195 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
196 continue;
197 }
198
199 if (merging > 0)
200 {
201 /* Merge data from file. */
202 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
203 {
204 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
205 gi_ptr->filename);
206 read_fatal:;
207 gcov_close ();
208 continue;
209 }
210 length = gcov_read_unsigned ();
211 if (length != GCOV_VERSION)
212 {
213 gcov_version_mismatch (gi_ptr, length);
214 goto read_fatal;
215 }
216
217 /* Merge execution counts for each function. */
218 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions;
219 f_ix--;
220 fi_ptr = (const struct gcov_fn_info *)
221 ((const char *) fi_ptr + fi_stride))
222 {
223 tag = gcov_read_unsigned ();
224 length = gcov_read_unsigned ();
225
226 /* Check function */
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)
231 {
232 read_mismatch:;
233 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
234 gi_ptr->filename,
235 f_ix + 1 ? "function" : "summaries");
236 goto read_fatal;
237 }
238
239 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
240 if ((1 << t_ix) & gi_ptr->ctr_mask)
241 {
242 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
243 gcov_merge_fn merge = gi_ptr->counts[c_ix].merge;
244
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))
249 goto read_mismatch;
250 (*merge) (values[c_ix], n_counts);
251 values[c_ix] += n_counts;
252 c_ix++;
253 }
254 if ((error = gcov_is_error ()))
255 goto read_error;
256 }
257
258 /* Check program & object summary */
259 while (!gcov_is_eof ())
260 {
261 unsigned long base = gcov_position ();
262 int is_program;
263
264 tag = gcov_read_unsigned ();
265 length = gcov_read_unsigned ();
266 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
267 if (length != GCOV_TAG_SUMMARY_LENGTH
268 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
269 goto read_mismatch;
270 gcov_read_summary (is_program ? &program : &object);
271 if ((error = gcov_is_error ()))
272 {
273 read_error:;
274 fprintf (stderr, error < 0 ?
275 "profiling:%s:Overflow merging\n" :
276 "profiling:%s:Error merging\n", gi_ptr->filename);
277 goto read_fatal;
278 }
279
280 if (!is_program || program.checksum != gcov_crc32)
281 continue;
282 summary_pos = base;
283 break;
284 }
285 gcov_rewrite ();
286 }
287 else
288 memset (&object, 0, sizeof (object));
289 if (!(summary_pos + 1))
290 memset (&program, 0, sizeof (program));
291
292 /* Merge the summaries. */
293 f_ix = ~0u;
294 for (t_ix = c_ix = 0,
295 cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
296 cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
297 cs_all = all.ctrs;
298 t_ix != GCOV_COUNTERS;
299 t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
300 {
301 if ((1 << t_ix) & gi_ptr->ctr_mask)
302 {
303 if (!cs_obj->runs++)
304 cs_obj->num = cs_tobj->num;
305 else if (cs_obj->num != cs_tobj->num)
306 goto read_mismatch;
307 cs_obj->sum_all += cs_tobj->sum_all;
308 if (cs_obj->run_max < cs_tobj->run_max)
309 cs_obj->run_max = cs_tobj->run_max;
310 cs_obj->sum_max += cs_tobj->run_max;
311
312 if (!cs_prg->runs++)
313 cs_prg->num = cs_tprg->num;
314 else if (cs_prg->num != cs_tprg->num)
315 goto read_mismatch;
316 cs_prg->sum_all += cs_tprg->sum_all;
317 if (cs_prg->run_max < cs_tprg->run_max)
318 cs_prg->run_max = cs_tprg->run_max;
319 cs_prg->sum_max += cs_tprg->run_max;
320
321 values[c_ix] = gi_ptr->counts[c_ix].values;
322 c_ix++;
323 }
324 else if (cs_obj->num || cs_prg->num)
325 goto read_mismatch;
326
327 if (!cs_all->runs && cs_prg->runs)
328 memcpy (cs_all, cs_prg, sizeof (*cs_all));
329 else if (!all.checksum
330 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
331 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
332 {
333 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
334 gi_ptr->filename, GCOV_LOCKED
335 ? "" : " or concurrent update without locking support");
336 all.checksum = ~0u;
337 }
338 }
339
340 program.checksum = gcov_crc32;
341
342 /* Write out the data. */
343 gcov_write_unsigned (GCOV_DATA_MAGIC);
344 gcov_write_unsigned (GCOV_VERSION);
345
346 /* Write execution counts for each function. */
347 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
348 fi_ptr = (const struct gcov_fn_info *)
349 ((const char *) fi_ptr + fi_stride))
350 {
351 /* Announce function. */
352 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
353 gcov_write_unsigned (fi_ptr->ident);
354 gcov_write_unsigned (fi_ptr->checksum);
355
356 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
357 if ((1 << t_ix) & gi_ptr->ctr_mask)
358 {
359 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
360 gcov_type *c_ptr;
361
362 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
363 GCOV_TAG_COUNTER_LENGTH (n_counts));
364 c_ptr = values[c_ix];
365 while (n_counts--)
366 gcov_write_counter (*c_ptr++);
367 values[c_ix] = c_ptr;
368 c_ix++;
369 }
370 }
371
372 /* Object file summary. */
373 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
374
375 /* Generate whole program statistics. */
376 gcov_seek (summary_pos);
377 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
378 if ((error = gcov_close ()))
379 fprintf (stderr, error < 0 ?
380 "profiling:%s:Overflow writing\n" :
381 "profiling:%s:Error writing\n",
382 gi_ptr->filename);
383 }
384 }
385
386 /* Add a new object file onto the bb chain. Invoked automatically
387 when running an object file's global ctors. */
388
389 void
390 __gcov_init (struct gcov_info *info)
391 {
392 if (!info->version)
393 return;
394 if (info->version != GCOV_VERSION)
395 gcov_version_mismatch (info, info->version);
396 else
397 {
398 const char *ptr = info->filename;
399 unsigned crc32 = gcov_crc32;
400
401 do
402 {
403 unsigned ix;
404 unsigned value = *ptr << 24;
405
406 for (ix = 8; ix--; value <<= 1)
407 {
408 unsigned feedback;
409
410 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
411 crc32 <<= 1;
412 crc32 ^= feedback;
413 }
414 }
415 while (*ptr++);
416
417 gcov_crc32 = crc32;
418
419 if (!gcov_list)
420 atexit (gcov_exit);
421
422 info->next = gcov_list;
423 gcov_list = info;
424 }
425 info->version = 0;
426 }
427
428 /* Called before fork or exec - write out profile information gathered so
429 far and reset it to zero. This avoids duplication or loss of the
430 profile information gathered so far. */
431
432 void
433 __gcov_flush (void)
434 {
435 const struct gcov_info *gi_ptr;
436
437 gcov_exit ();
438 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
439 {
440 unsigned t_ix;
441 const struct gcov_ctr_info *ci_ptr;
442
443 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
444 if ((1 << t_ix) & gi_ptr->ctr_mask)
445 {
446 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
447 ci_ptr++;
448 }
449 }
450 }
451
452 #endif /* L_gcov */
453
454 #ifdef L_gcov_merge_add
455 /* The profile merging function that just adds the counters. It is given
456 an array COUNTERS of N_COUNTERS old counters and it reads the same number
457 of counters from the gcov file. */
458 void
459 __gcov_merge_add (counters, n_counters)
460 gcov_type *counters;
461 unsigned n_counters;
462 {
463 for (; n_counters; counters++, n_counters--)
464 *counters += gcov_read_counter ();
465 }
466 #endif /* L_gcov_merge_add */
467
468 #endif /* inhibit_libc */