OSDN Git Service

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