New GCOV_TAG_FUNCTION layout
[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;
207 f_ix--;
208 fi_ptr = (const struct gcov_fn_info *)
209 ((const char *) fi_ptr + fi_stride))
210 {
211 tag = gcov_read_unsigned ();
212 length = gcov_read_unsigned ();
213
214 /* Check function */
215 if (tag != GCOV_TAG_FUNCTION
216 || gcov_read_unsigned () != fi_ptr->ident
217 || gcov_read_unsigned () != fi_ptr->checksum)
218 {
219 read_mismatch:;
220 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
221 gi_ptr->filename,
222 f_ix + 1 ? "function" : "summaries");
223 goto read_fatal;
224 }
225
226 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
227 if ((1 << t_ix) & gi_ptr->ctr_mask)
228 {
229 unsigned n_counts;
230 gcov_type *c_ptr;
231
232 tag = gcov_read_unsigned ();
233 length = gcov_read_unsigned ();
234
235 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
236 || fi_ptr->n_ctrs[c_ix] * 8 != length)
237 goto read_mismatch;
238 c_ptr = values[c_ix];
239 for (n_counts = fi_ptr->n_ctrs[c_ix];
240 n_counts--; c_ptr++)
241 *c_ptr += gcov_read_counter ();
242 values[c_ix] = c_ptr;
243 c_ix++;
244 }
245 if ((error = gcov_is_error ()))
246 goto read_error;
247 }
248
249 /* Check object summary */
250 if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
251 goto read_mismatch;
252 gcov_read_unsigned ();
253 gcov_read_summary (&object);
254
255 /* Check program summary */
256 while (!gcov_is_eof ())
257 {
258 base = gcov_position ();
259 tag = gcov_read_unsigned ();
260 gcov_read_unsigned ();
261 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
262 goto read_mismatch;
263 gcov_read_summary (&program);
264 if ((error = gcov_is_error ()))
265 {
266 read_error:;
267 fprintf (stderr, error < 0 ?
268 "profiling:%s:Overflow merging\n" :
269 "profiling:%s:Error merging\n",
270 gi_ptr->filename);
271 goto read_fatal;
272 }
273
274 if (program.checksum != gcov_crc32)
275 continue;
276 summary_pos = base;
277 break;
278 }
279 gcov_seek (0, 0);
280 }
281 else
282 memset (&object, 0, sizeof (object));
283 if (!summary_pos)
284 memset (&program, 0, sizeof (program));
285
286 /* Merge the summaries. */
287 f_ix = ~0u;
288 for (t_ix = c_ix = 0,
289 cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
290 cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
291 cs_all = all.ctrs;
292 t_ix != GCOV_COUNTERS;
293 t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
294 {
295 if ((1 << t_ix) & gi_ptr->ctr_mask)
296 {
297 if (!cs_obj->runs++)
298 cs_obj->num = cs_tobj->num;
299 else if (cs_obj->num != cs_tobj->num)
300 goto read_mismatch;
301 cs_obj->sum_all += cs_tobj->sum_all;
302 if (cs_obj->run_max < cs_tobj->run_max)
303 cs_obj->run_max = cs_tobj->run_max;
304 cs_obj->sum_max += cs_tobj->run_max;
305
306 if (!cs_prg->runs++)
307 cs_prg->num = cs_tprg->num;
308 else if (cs_prg->num != cs_tprg->num)
309 goto read_mismatch;
310 cs_prg->sum_all += cs_tprg->sum_all;
311 if (cs_prg->run_max < cs_tprg->run_max)
312 cs_prg->run_max = cs_tprg->run_max;
313 cs_prg->sum_max += cs_tprg->run_max;
314
315 values[c_ix] = gi_ptr->counts[c_ix].values;
316 c_ix++;
317 }
318 else if (cs_obj->num || cs_prg->num)
319 goto read_mismatch;
320
321 if (!cs_all->runs && cs_prg->runs)
322 memcpy (cs_all, cs_prg, sizeof (*cs_all));
323 else if (!all.checksum
324 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
325 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
326 {
327 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
328 gi_ptr->filename, GCOV_LOCKED
329 ? "" : " or concurrent update without locking support");
330 all.checksum = ~0u;
331 }
332 }
333
334 program.checksum = gcov_crc32;
335
336 /* Write out the data. */
337 gcov_write_unsigned (GCOV_DATA_MAGIC);
338 gcov_write_unsigned (GCOV_VERSION);
339
340 /* Write execution counts for each function. */
341 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
342 fi_ptr = (const struct gcov_fn_info *)
343 ((const char *) fi_ptr + fi_stride))
344 {
345 /* Announce function. */
346 base = gcov_write_tag (GCOV_TAG_FUNCTION);
347 gcov_write_unsigned (fi_ptr->ident);
348 gcov_write_unsigned (fi_ptr->checksum);
349 gcov_write_length (base);
350
351 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
352 if ((1 << t_ix) & gi_ptr->ctr_mask)
353 {
354 unsigned n_counts;
355 gcov_type *c_ptr;
356
357 base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
358 c_ptr = values[c_ix];
359 for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
360 gcov_write_counter (*c_ptr);
361 values[c_ix] = c_ptr;
362 gcov_write_length (base);
363 c_ix++;
364 }
365 }
366
367 /* Object file summary. */
368 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
369
370 /* Generate whole program statistics. */
371 if (summary_pos)
372 gcov_seek (summary_pos, 0);
373 else
374 gcov_seek_end ();
375 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
376 if ((error = gcov_close ()))
377 {
378 fprintf (stderr, error < 0 ?
379 "profiling:%s:Overflow writing\n" :
380 "profiling:%s:Error writing\n",
381 gi_ptr->filename);
382 gi_ptr->filename = 0;
383 }
384 }
385 }
386
387 /* Add a new object file onto the bb chain. Invoked automatically
388 when running an object file's global ctors. */
389
390 void
391 __gcov_init (struct gcov_info *info)
392 {
393 if (!info->version)
394 return;
395 if (info->version != GCOV_VERSION)
396 gcov_version_mismatch (info, info->version);
397 else
398 {
399 const char *ptr = info->filename;
400 unsigned crc32 = gcov_crc32;
401
402 do
403 {
404 unsigned ix;
405 unsigned value = *ptr << 24;
406
407 for (ix = 8; ix--; value <<= 1)
408 {
409 unsigned feedback;
410
411 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
412 crc32 <<= 1;
413 crc32 ^= feedback;
414 }
415 }
416 while (*ptr++);
417
418 gcov_crc32 = crc32;
419
420 if (!gcov_list)
421 atexit (gcov_exit);
422
423 info->next = gcov_list;
424 gcov_list = info;
425 }
426 info->version = 0;
427 }
428
429 /* Called before fork or exec - write out profile information gathered so
430 far and reset it to zero. This avoids duplication or loss of the
431 profile information gathered so far. */
432
433 void
434 __gcov_flush (void)
435 {
436 const struct gcov_info *gi_ptr;
437
438 gcov_exit ();
439 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
440 {
441 unsigned t_ix;
442 const struct gcov_ctr_info *ci_ptr;
443
444 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
445 if ((1 << t_ix) & gi_ptr->ctr_mask)
446 {
447 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
448 ci_ptr++;
449 }
450 }
451 }
452
453 #endif /* inhibit_libc */