Makefile.in (LIBGCC_DEPS): Add gcov headers.
[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 #if defined(inhibit_libc)
33 /* If libc and its header files are not available, provide dummy functions. */
34
35 void __gcov_init (void *p);
36 void __gcov_flush (void);
37
38 void __gcov_init (void *p) { }
39 void __gcov_flush (void) { }
40
41 #else
42
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
45 do not apply. */
46
47 #include "tconfig.h"
48 #include "tsystem.h"
49 #include "coretypes.h"
50 #include "tm.h"
51
52 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
53 #include <stdio.h>
54
55 #include <string.h>
56 #if defined (TARGET_HAS_F_SETLKW)
57 #include <fcntl.h>
58 #include <errno.h>
59 #endif
60 #define IN_LIBGCOV 1
61 #include "gcov-io.h"
62 #include "gcov-io.c"
63
64 /* Chain of per-object gcov structures. */
65 static struct gcov_info *gcov_list;
66
67 /* A program checksum allows us to distinguish program data for an
68 object file included in multiple programs. */
69 static unsigned gcov_crc32;
70
71 static void
72 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
73 {
74 unsigned expected = GCOV_VERSION;
75 unsigned ix;
76 char e[4], v[4];
77
78 for (ix = 4; ix--; expected >>= 8, version >>= 8)
79 {
80 e[ix] = expected;
81 v[ix] = version;
82 }
83
84 fprintf (stderr,
85 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
86 ptr->filename, e, v);
87 }
88
89 /* Dump the coverage counts. We merge with existing counts when
90 possible, to avoid growing the .da files ad infinitum. We use this
91 program's checksum to make sure we only accumulate whole program
92 statistics to the correct summary. An object file might be embedded
93 in two separate programs, and we must keep the two program
94 summaries separate. */
95
96 static void
97 gcov_exit (void)
98 {
99 struct gcov_info *gi_ptr;
100 struct gcov_summary this_program;
101 struct gcov_summary all;
102
103 memset (&all, 0, sizeof (all));
104 /* Find the totals for this execution. */
105 memset (&this_program, 0, sizeof (this_program));
106 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
107 {
108 const struct gcov_ctr_info *ci_ptr;
109 struct gcov_ctr_summary *cs_ptr;
110 unsigned t_ix;
111
112 for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
113 t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
114 if ((1 << t_ix) & gi_ptr->ctr_mask)
115 {
116 const gcov_type *c_ptr;
117 unsigned c_num;
118
119 cs_ptr->num += ci_ptr->num;
120 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
121 {
122 cs_ptr->sum_all += *c_ptr;
123 if (cs_ptr->run_max < *c_ptr)
124 cs_ptr->run_max = *c_ptr;
125 }
126 ci_ptr++;
127 }
128 }
129
130 /* Now write the data */
131 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
132 {
133 struct gcov_summary this_object;
134 struct gcov_summary object, program;
135 gcov_type *values[GCOV_COUNTERS];
136 const struct gcov_fn_info *fi_ptr;
137 unsigned fi_stride;
138 unsigned c_ix, t_ix, f_ix;
139 const struct gcov_ctr_info *ci_ptr;
140 struct gcov_ctr_summary *cs_ptr;
141 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
142 int error;
143 int merging;
144 unsigned long base;
145 unsigned tag, length;
146 unsigned long summary_pos = 0;
147
148 /* Totals for this object file. */
149 memset (&this_object, 0, sizeof (this_object));
150 for (t_ix = c_ix = 0,
151 ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
152 t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
153 if ((1 << t_ix) & gi_ptr->ctr_mask)
154 {
155 const gcov_type *c_ptr;
156 unsigned c_num;
157
158 cs_ptr->num += ci_ptr->num;
159 values[c_ix] = ci_ptr->values;
160 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
161 {
162 cs_ptr->sum_all += *c_ptr;
163 if (cs_ptr->run_max < *c_ptr)
164 cs_ptr->run_max = *c_ptr;
165 }
166 c_ix++;
167 ci_ptr++;
168 }
169
170 /* Calculate the function_info stride. This depends on the
171 number of counter types being measured. */
172 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
173 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
174 {
175 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
176 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
177 }
178
179 /* Open for modification, if possible */
180 merging = gcov_open (gi_ptr->filename, 0);
181 if (!merging)
182 {
183 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
184 continue;
185 }
186
187 if (merging > 0)
188 {
189 /* Merge data from file. */
190 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
191 {
192 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
193 gi_ptr->filename);
194 read_fatal:;
195 gcov_close ();
196 continue;
197 }
198 length = gcov_read_unsigned ();
199 if (length != GCOV_VERSION)
200 {
201 gcov_version_mismatch (gi_ptr, length);
202 goto read_fatal;
203 }
204
205 /* Merge execution counts for each function. */
206 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
207 fi_ptr = (const struct gcov_fn_info *)
208 ((const char *) fi_ptr + fi_stride))
209 {
210 tag = gcov_read_unsigned ();
211 length = gcov_read_unsigned ();
212
213 /* Check function */
214 if (tag != GCOV_TAG_FUNCTION)
215 {
216 read_mismatch:;
217 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
218 gi_ptr->filename,
219 fi_ptr ? fi_ptr->name : "summaries");
220 goto read_fatal;
221 }
222
223 if (strcmp (gcov_read_string (), fi_ptr->name)
224 || gcov_read_unsigned () != fi_ptr->checksum)
225 goto read_mismatch;
226
227 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
228 if ((1 << t_ix) & gi_ptr->ctr_mask)
229 {
230 unsigned n_counts;
231 gcov_type *c_ptr;
232
233 tag = gcov_read_unsigned ();
234 length = gcov_read_unsigned ();
235
236 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
237 || fi_ptr->n_ctrs[c_ix] * 8 != length)
238 goto read_mismatch;
239 c_ptr = values[c_ix];
240 for (n_counts = fi_ptr->n_ctrs[c_ix];
241 n_counts--; c_ptr++)
242 *c_ptr += gcov_read_counter ();
243 values[c_ix] = c_ptr;
244 c_ix++;
245 }
246 if ((error = gcov_is_error ()))
247 goto read_error;
248 }
249
250 /* Check object summary */
251 if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
252 goto read_mismatch;
253 gcov_read_unsigned ();
254 gcov_read_summary (&object);
255
256 /* Check program summary */
257 while (!gcov_is_eof ())
258 {
259 base = gcov_position ();
260 tag = gcov_read_unsigned ();
261 gcov_read_unsigned ();
262 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
263 goto read_mismatch;
264 gcov_read_summary (&program);
265 if ((error = gcov_is_error ()))
266 {
267 read_error:;
268 fprintf (stderr, error < 0 ?
269 "profiling:%s:Overflow merging\n" :
270 "profiling:%s:Error merging\n",
271 gi_ptr->filename);
272 goto read_fatal;
273 }
274
275 if (program.checksum != gcov_crc32)
276 continue;
277 summary_pos = base;
278 break;
279 }
280 gcov_seek (0, 0);
281 }
282 else
283 memset (&object, 0, sizeof (object));
284 if (!summary_pos)
285 memset (&program, 0, sizeof (program));
286
287 fi_ptr = 0;
288
289 /* Merge the summaries. */
290 for (t_ix = c_ix = 0,
291 cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
292 cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
293 cs_all = all.ctrs;
294 t_ix != GCOV_COUNTERS;
295 t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
296 {
297 if ((1 << t_ix) & gi_ptr->ctr_mask)
298 {
299 if (!cs_obj->runs++)
300 cs_obj->num = cs_tobj->num;
301 else if (cs_obj->num != cs_tobj->num)
302 goto read_mismatch;
303 cs_obj->sum_all += cs_tobj->sum_all;
304 if (cs_obj->run_max < cs_tobj->run_max)
305 cs_obj->run_max = cs_tobj->run_max;
306 cs_obj->sum_max += cs_tobj->run_max;
307
308 if (!cs_prg->runs++)
309 cs_prg->num = cs_tprg->num;
310 else if (cs_prg->num != cs_tprg->num)
311 goto read_mismatch;
312 cs_prg->sum_all += cs_tprg->sum_all;
313 if (cs_prg->run_max < cs_tprg->run_max)
314 cs_prg->run_max = cs_tprg->run_max;
315 cs_prg->sum_max += cs_tprg->run_max;
316
317 values[c_ix] = gi_ptr->counts[c_ix].values;
318 c_ix++;
319 }
320 else if (cs_obj->num || cs_prg->num)
321 goto read_mismatch;
322
323 if (!cs_all->runs && cs_prg->runs)
324 memcpy (cs_all, cs_prg, sizeof (*cs_all));
325 else if (!all.checksum
326 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
327 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
328 {
329 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
330 gi_ptr->filename, GCOV_LOCKED
331 ? "" : " or concurrent update without locking support");
332 all.checksum = ~0u;
333 }
334 }
335
336 program.checksum = gcov_crc32;
337
338 /* Write out the data. */
339 gcov_write_unsigned (GCOV_DATA_MAGIC);
340 gcov_write_unsigned (GCOV_VERSION);
341
342 /* Write execution counts for each function. */
343 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
344 fi_ptr = (const struct gcov_fn_info *)
345 ((const char *) fi_ptr + fi_stride))
346 {
347 /* Announce function. */
348 base = gcov_write_tag (GCOV_TAG_FUNCTION);
349 gcov_write_string (fi_ptr->name);
350 gcov_write_unsigned (fi_ptr->checksum);
351 gcov_write_length (base);
352
353 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
354 if ((1 << t_ix) & gi_ptr->ctr_mask)
355 {
356 unsigned n_counts;
357 gcov_type *c_ptr;
358
359 base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
360 c_ptr = values[c_ix];
361 for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
362 gcov_write_counter (*c_ptr);
363 values[c_ix] = c_ptr;
364 gcov_write_length (base);
365 c_ix++;
366 }
367 }
368
369 /* Object file summary. */
370 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
371
372 /* Generate whole program statistics. */
373 if (summary_pos)
374 gcov_seek (summary_pos, 0);
375 else
376 gcov_seek_end ();
377 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
378 if ((error = gcov_close ()))
379 {
380 fprintf (stderr, error < 0 ?
381 "profiling:%s:Overflow writing\n" :
382 "profiling:%s:Error writing\n",
383 gi_ptr->filename);
384 gi_ptr->filename = 0;
385 }
386 }
387 }
388
389 /* Add a new object file onto the bb chain. Invoked automatically
390 when running an object file's global ctors. */
391
392 void
393 __gcov_init (struct gcov_info *info)
394 {
395 if (!info->version)
396 return;
397 if (info->version != GCOV_VERSION)
398 gcov_version_mismatch (info, info->version);
399 else
400 {
401 const char *ptr = info->filename;
402 unsigned crc32 = gcov_crc32;
403
404 do
405 {
406 unsigned ix;
407 unsigned value = *ptr << 24;
408
409 for (ix = 8; ix--; value <<= 1)
410 {
411 unsigned feedback;
412
413 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
414 crc32 <<= 1;
415 crc32 ^= feedback;
416 }
417 }
418 while (*ptr++);
419
420 gcov_crc32 = crc32;
421
422 if (!gcov_list)
423 atexit (gcov_exit);
424
425 info->next = gcov_list;
426 gcov_list = info;
427 }
428 info->version = 0;
429 }
430
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. */
434
435 void
436 __gcov_flush (void)
437 {
438 const struct gcov_info *gi_ptr;
439
440 gcov_exit ();
441 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
442 {
443 unsigned t_ix;
444 const struct gcov_ctr_info *ci_ptr;
445
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)
448 {
449 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
450 ci_ptr++;
451 }
452 }
453 }
454
455 #endif /* inhibit_libc */