OSDN Git Service

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