OSDN Git Service

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