OSDN Git Service

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