OSDN Git Service

PR c++/10784
[pf3gnuchains/gcc-fork.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 #ifdef L_gcov_merge_single
67 void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
68                           unsigned n_counters __attribute__ ((unused))) {}
69 #endif
70
71 #ifdef L_gcov_merge_delta
72 void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
73                          unsigned n_counters __attribute__ ((unused))) {}
74 #endif
75
76 #else
77
78 #include <string.h>
79 #if GCOV_LOCKED
80 #include <fcntl.h>
81 #include <errno.h>
82 #endif
83
84 #ifdef L_gcov
85 #include "gcov-io.c"
86
87 /* Chain of per-object gcov structures.  */
88 static struct gcov_info *gcov_list;
89
90 /* A program checksum allows us to distinguish program data for an
91    object file included in multiple programs.  */
92 static gcov_unsigned_t gcov_crc32;
93
94 static void
95 gcov_version_mismatch (struct gcov_info *ptr, gcov_unsigned_t version)
96 {
97   gcov_unsigned_t expected = GCOV_VERSION;
98   unsigned ix;
99   char e[4], v[4];
100
101   for (ix = 4; ix--; expected >>= 8, version >>= 8)
102     {
103       e[ix] = expected;
104       v[ix] = version;
105     }
106   
107   fprintf (stderr,
108            "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
109            ptr->filename, e, v);
110 }
111
112 /* Dump the coverage counts. We merge with existing counts when
113    possible, to avoid growing the .da files ad infinitum. We use this
114    program's checksum to make sure we only accumulate whole program
115    statistics to the correct summary. An object file might be embedded
116    in two separate programs, and we must keep the two program
117    summaries separate.  */
118
119 static void
120 gcov_exit (void)
121 {
122   struct gcov_info *gi_ptr;
123   struct gcov_summary this_program;
124   struct gcov_summary all;
125
126   memset (&all, 0, sizeof (all));
127   /* Find the totals for this execution.  */
128   memset (&this_program, 0, sizeof (this_program));
129   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
130     {
131       const struct gcov_ctr_info *ci_ptr;
132       struct gcov_ctr_summary *cs_ptr;
133       unsigned t_ix;
134       
135       for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
136            t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++)
137         if ((1 << t_ix) & gi_ptr->ctr_mask)
138           {
139             const gcov_type *c_ptr;
140             gcov_unsigned_t c_num;
141
142             cs_ptr->num += ci_ptr->num;
143             for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
144               {
145                 cs_ptr->sum_all += *c_ptr;
146                 if (cs_ptr->run_max < *c_ptr)
147                   cs_ptr->run_max = *c_ptr;
148               }
149             ci_ptr++;
150           }
151     }
152
153   /* Now merge each file  */
154   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
155     {
156       struct gcov_summary this_object;
157       struct gcov_summary object, program;
158       gcov_type *values[GCOV_COUNTERS];
159       const struct gcov_fn_info *fi_ptr;
160       unsigned fi_stride;
161       unsigned c_ix, t_ix, f_ix;
162       const struct gcov_ctr_info *ci_ptr;
163       struct gcov_ctr_summary *cs_ptr;
164       struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
165       int error = 0;
166       int merging;
167       gcov_unsigned_t tag, length;
168       gcov_position_t summary_pos = 0;
169
170       /* Totals for this object file.  */
171       memset (&this_object, 0, sizeof (this_object));
172       for (t_ix = c_ix = 0,
173              ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
174            t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++)
175         if ((1 << t_ix) & gi_ptr->ctr_mask)
176           {
177             const gcov_type *c_ptr;
178             gcov_unsigned_t c_num;
179
180             cs_ptr->num += ci_ptr->num;
181             values[c_ix] = ci_ptr->values;
182             for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
183               {
184                 cs_ptr->sum_all += *c_ptr;
185                 if (cs_ptr->run_max < *c_ptr)
186                   cs_ptr->run_max = *c_ptr;
187               }
188             c_ix++;
189             ci_ptr++;
190           }
191
192       /* Calculate the function_info stride. This depends on the
193          number of counter types being measured.  */
194       fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
195       if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
196         {
197           fi_stride += __alignof__ (struct gcov_fn_info) - 1;
198           fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
199         }
200       
201       /* Open for modification, if possible */
202       merging = gcov_open (gi_ptr->filename, 0);
203       if (!merging)
204         {
205           fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
206           continue;
207         }
208       
209       if (merging > 0)
210         {
211           /* Merge data from file.  */
212           if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
213             {
214               fprintf (stderr, "profiling:%s:Not a gcov data file\n",
215                        gi_ptr->filename);
216             read_fatal:;
217               gcov_close ();
218               continue;
219             }
220           length = gcov_read_unsigned ();
221           if (length != GCOV_VERSION)
222             {
223               gcov_version_mismatch (gi_ptr, length);
224               goto read_fatal;
225             }
226           
227           /* Merge execution counts for each function.  */
228           for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions;
229                f_ix--;
230                fi_ptr = (const struct gcov_fn_info *)
231                  ((const char *) fi_ptr + fi_stride))
232             {
233               tag = gcov_read_unsigned ();
234               length = gcov_read_unsigned ();
235
236               /* Check function */
237               if (tag != GCOV_TAG_FUNCTION
238                   || length != GCOV_TAG_FUNCTION_LENGTH
239                   || gcov_read_unsigned () != fi_ptr->ident
240                   || gcov_read_unsigned () != fi_ptr->checksum)
241                 {
242                 read_mismatch:;
243                   fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
244                            gi_ptr->filename,
245                            f_ix + 1 ? "function" : "summaries");
246                   goto read_fatal;
247                 }
248
249               for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
250                 if ((1 << t_ix) & gi_ptr->ctr_mask)
251                   {
252                     unsigned n_counts = fi_ptr->n_ctrs[c_ix];
253                     gcov_merge_fn merge = gi_ptr->counts[c_ix].merge;
254                     
255                     tag = gcov_read_unsigned ();
256                     length = gcov_read_unsigned ();
257                     if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
258                         || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
259                       goto read_mismatch;
260                     (*merge) (values[c_ix], n_counts);
261                     values[c_ix] += n_counts;
262                     c_ix++;
263                 }
264               if ((error = gcov_is_error ()))
265                 goto read_error;
266             }
267
268           /* Check program & object summary */
269           while (1)
270             {
271               gcov_position_t base = gcov_position ();
272               int is_program;
273               
274               tag = gcov_read_unsigned ();
275               if (!tag)
276                 break;
277               length = gcov_read_unsigned ();
278               is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
279               if (length != GCOV_TAG_SUMMARY_LENGTH
280                   || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
281                 goto read_mismatch;
282               gcov_read_summary (is_program ? &program : &object);
283               if ((error = gcov_is_error ()))
284                 goto read_error;
285               if (is_program && program.checksum == gcov_crc32)
286                 {
287                   summary_pos = base;
288                   goto rewrite;
289                 }
290             }
291           if (!gcov_is_eof ())
292             {
293             read_error:;
294               fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
295                        : "profiling:%s:Error merging\n", gi_ptr->filename);
296               goto read_fatal;
297             }
298         rewrite:;
299           gcov_rewrite ();
300         }
301       else
302         memset (&object, 0, sizeof (object));
303       if (!summary_pos)
304         memset (&program, 0, sizeof (program));
305
306       /* Merge the summaries.  */
307       f_ix = ~0u;
308       for (t_ix = c_ix = 0,
309              cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
310              cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
311              cs_all = all.ctrs;
312            t_ix != GCOV_COUNTERS_SUMMABLE;
313            t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
314         {
315           if ((1 << t_ix) & gi_ptr->ctr_mask)
316             {
317               if (!cs_obj->runs++)
318                 cs_obj->num = cs_tobj->num;
319               else if (cs_obj->num != cs_tobj->num)
320                 goto read_mismatch;
321               cs_obj->sum_all += cs_tobj->sum_all;
322               if (cs_obj->run_max < cs_tobj->run_max)
323                 cs_obj->run_max = cs_tobj->run_max;
324               cs_obj->sum_max += cs_tobj->run_max;
325               
326               if (!cs_prg->runs++)
327                 cs_prg->num = cs_tprg->num;
328               else if (cs_prg->num != cs_tprg->num)
329                 goto read_mismatch;
330               cs_prg->sum_all += cs_tprg->sum_all;
331               if (cs_prg->run_max < cs_tprg->run_max)
332                 cs_prg->run_max = cs_tprg->run_max;
333               cs_prg->sum_max += cs_tprg->run_max;
334               
335               values[c_ix] = gi_ptr->counts[c_ix].values;
336               c_ix++;
337             }
338           else if (cs_obj->num || cs_prg->num)
339             goto read_mismatch;
340           
341           if (!cs_all->runs && cs_prg->runs)
342             memcpy (cs_all, cs_prg, sizeof (*cs_all));
343           else if (!all.checksum
344                    && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
345                    && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
346             {
347               fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
348                        gi_ptr->filename, GCOV_LOCKED
349                        ? "" : " or concurrent update without locking support");
350               all.checksum = ~0u;
351             }
352         }
353       
354       program.checksum = gcov_crc32;
355       
356       /* Write out the data.  */
357       gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
358       
359       /* Write execution counts for each function.  */
360       for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
361            fi_ptr = (const struct gcov_fn_info *)
362              ((const char *) fi_ptr + fi_stride))
363         {
364           /* Announce function.  */
365           gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
366           gcov_write_unsigned (fi_ptr->ident);
367           gcov_write_unsigned (fi_ptr->checksum);
368
369           for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
370             if ((1 << t_ix) & gi_ptr->ctr_mask)
371               {
372                 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
373                 gcov_type *c_ptr;
374                     
375                 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
376                                        GCOV_TAG_COUNTER_LENGTH (n_counts));
377                 c_ptr = values[c_ix];
378                 while (n_counts--)
379                   gcov_write_counter (*c_ptr++);
380                 values[c_ix] = c_ptr;
381                 c_ix++;
382               }
383         }
384
385       /* Object file summary.  */
386       gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
387
388       /* Generate whole program statistics.  */
389       gcov_seek (summary_pos);
390       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
391       if ((error = gcov_close ()))
392           fprintf (stderr, error  < 0 ?
393                    "profiling:%s:Overflow writing\n" :
394                    "profiling:%s:Error writing\n",
395                    gi_ptr->filename);
396     }
397 }
398
399 /* Add a new object file onto the bb chain.  Invoked automatically
400    when running an object file's global ctors.  */
401
402 void
403 __gcov_init (struct gcov_info *info)
404 {
405   if (!info->version)
406     return;
407   if (info->version != GCOV_VERSION)
408     gcov_version_mismatch (info, info->version);
409   else
410     {
411       const char *ptr = info->filename;
412       gcov_unsigned_t crc32 = gcov_crc32;
413   
414       do
415         {
416           unsigned ix;
417           gcov_unsigned_t value = *ptr << 24;
418
419           for (ix = 8; ix--; value <<= 1)
420             {
421               gcov_unsigned_t feedback;
422
423               feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
424               crc32 <<= 1;
425               crc32 ^= feedback;
426             }
427         }
428       while (*ptr++);
429       
430       gcov_crc32 = crc32;
431       
432       if (!gcov_list)
433         atexit (gcov_exit);
434       
435       info->next = gcov_list;
436       gcov_list = info;
437     }
438   info->version = 0;
439 }
440
441 /* Called before fork or exec - write out profile information gathered so
442    far and reset it to zero.  This avoids duplication or loss of the
443    profile information gathered so far.  */
444
445 void
446 __gcov_flush (void)
447 {
448   const struct gcov_info *gi_ptr;
449
450   gcov_exit ();
451   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
452     {
453       unsigned t_ix;
454       const struct gcov_ctr_info *ci_ptr;
455       
456       for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
457         if ((1 << t_ix) & gi_ptr->ctr_mask)
458           {
459             memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
460             ci_ptr++;
461           }
462     }
463 }
464
465 #endif /* L_gcov */
466
467 #ifdef L_gcov_merge_add
468 /* The profile merging function that just adds the counters.  It is given
469    an array COUNTERS of N_COUNTERS old counters and it reads the same number
470    of counters from the gcov file.  */
471 void
472 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
473 {
474   for (; n_counters; counters++, n_counters--)
475     *counters += gcov_read_counter ();
476 }
477 #endif /* L_gcov_merge_add */
478
479 #ifdef L_gcov_merge_single
480 /* The profile merging function for choosing the most common value.  It is given
481    an array COUNTERS of N_COUNTERS old counters and it reads the same number
482    of counters from the gcov file.  The counters are split into 3-tuples
483    where the members of the tuple have meanings:
484    -- the stored candidate on the most common value of the measured entity
485    -- counter
486    -- total number of evaluations of the value  */
487 void
488 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
489 {
490   unsigned i, n_measures;
491   gcov_type value, counter, all;
492
493   if (n_counters % 3)
494     abort ();
495
496   n_measures = n_counters / 3;
497   for (i = 0; i < n_measures; i++, counters += 3)
498     {
499       value = gcov_read_counter ();
500       counter = gcov_read_counter ();
501       all = gcov_read_counter ();
502
503       if (counters[0] == value)
504         counters[1] += counter;
505       else if (counter > counters[1])
506         {
507           counters[0] = value;
508           counters[1] = counter - counters[1];
509         }
510       else
511         counters[1] -= counter;
512       counters[2] += all;
513     }
514 }
515 #endif /* L_gcov_merge_single */
516
517 #ifdef L_gcov_merge_delta
518 /* The profile merging function for choosing the most common difference between
519    two consecutive evaluations of the value.  It is given an array COUNTERS of
520    N_COUNTERS old counters and it reads the same number of counters from the
521    gcov file.  The counters are split into 4-tuples where the members of the
522    tuple have meanings:
523    -- the last value of the measured entity
524    -- the stored candidate on the most common difference
525    -- counter
526    -- total number of evaluations of the value  */
527 void
528 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
529 {
530   unsigned i, n_measures;
531   gcov_type last, value, counter, all;
532
533   if (n_counters % 4)
534     abort ();
535
536   n_measures = n_counters / 4;
537   for (i = 0; i < n_measures; i++, counters += 4)
538     {
539       last = gcov_read_counter ();
540       value = gcov_read_counter ();
541       counter = gcov_read_counter ();
542       all = gcov_read_counter ();
543
544       if (counters[1] == value)
545         counters[2] += counter;
546       else if (counter > counters[2])
547         {
548           counters[1] = value;
549           counters[2] = counter - counters[2];
550         }
551       else
552         counters[2] -= counter;
553       counters[3] += all;
554     }
555 }
556 #endif /* L_gcov_merge_delta */
557
558 #endif /* inhibit_libc */