OSDN Git Service

ed2d3d7d1d744391db9d8bb21876137f06995e63
[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 unsigned gcov_crc32;
83
84 static void
85 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
86 {
87   unsigned 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; t_ix++, cs_ptr++)
127         if ((1 << t_ix) & gi_ptr->ctr_mask)
128           {
129             const gcov_type *c_ptr;
130             unsigned 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 write the data  */
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;
156       int merging;
157       unsigned tag, length;
158       unsigned long summary_pos = ~0UL;
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; t_ix++, cs_ptr++)
165         if ((1 << t_ix) & gi_ptr->ctr_mask)
166           {
167             const gcov_type *c_ptr;
168             unsigned 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 (!gcov_is_eof ())
260             {
261               unsigned long base = gcov_position ();
262               int is_program;
263               
264               tag = gcov_read_unsigned ();
265               length = gcov_read_unsigned ();
266               is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
267               if (length != GCOV_TAG_SUMMARY_LENGTH
268                   || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
269                 goto read_mismatch;
270               gcov_read_summary (is_program ? &program : &object);
271               if ((error = gcov_is_error ()))
272                 {
273                 read_error:;
274                   fprintf (stderr, error < 0 ?
275                            "profiling:%s:Overflow merging\n" :
276                            "profiling:%s:Error merging\n", gi_ptr->filename);
277                   goto read_fatal;
278                 }
279               
280               if (!is_program || program.checksum != gcov_crc32)
281                 continue;
282               summary_pos = base;
283               break;
284             }
285           gcov_rewrite ();
286         }
287       else
288         memset (&object, 0, sizeof (object));
289       if (!(summary_pos + 1))
290         memset (&program, 0, sizeof (program));
291
292       /* Merge the summaries.  */
293       f_ix = ~0u;
294       for (t_ix = c_ix = 0,
295              cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
296              cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
297              cs_all = all.ctrs;
298            t_ix != GCOV_COUNTERS;
299            t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
300         {
301           if ((1 << t_ix) & gi_ptr->ctr_mask)
302             {
303               if (!cs_obj->runs++)
304                 cs_obj->num = cs_tobj->num;
305               else if (cs_obj->num != cs_tobj->num)
306                 goto read_mismatch;
307               cs_obj->sum_all += cs_tobj->sum_all;
308               if (cs_obj->run_max < cs_tobj->run_max)
309                 cs_obj->run_max = cs_tobj->run_max;
310               cs_obj->sum_max += cs_tobj->run_max;
311               
312               if (!cs_prg->runs++)
313                 cs_prg->num = cs_tprg->num;
314               else if (cs_prg->num != cs_tprg->num)
315                 goto read_mismatch;
316               cs_prg->sum_all += cs_tprg->sum_all;
317               if (cs_prg->run_max < cs_tprg->run_max)
318                 cs_prg->run_max = cs_tprg->run_max;
319               cs_prg->sum_max += cs_tprg->run_max;
320               
321               values[c_ix] = gi_ptr->counts[c_ix].values;
322               c_ix++;
323             }
324           else if (cs_obj->num || cs_prg->num)
325             goto read_mismatch;
326           
327           if (!cs_all->runs && cs_prg->runs)
328             memcpy (cs_all, cs_prg, sizeof (*cs_all));
329           else if (!all.checksum
330                    && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
331                    && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
332             {
333               fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
334                        gi_ptr->filename, GCOV_LOCKED
335                        ? "" : " or concurrent update without locking support");
336               all.checksum = ~0u;
337             }
338         }
339       
340       program.checksum = gcov_crc32;
341       
342       /* Write out the data.  */
343       gcov_write_unsigned (GCOV_DATA_MAGIC);
344       gcov_write_unsigned (GCOV_VERSION);
345       
346       /* Write execution counts for each function.  */
347       for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
348            fi_ptr = (const struct gcov_fn_info *)
349              ((const char *) fi_ptr + fi_stride))
350         {
351           /* Announce function.  */
352           gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
353           gcov_write_unsigned (fi_ptr->ident);
354           gcov_write_unsigned (fi_ptr->checksum);
355
356           for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
357             if ((1 << t_ix) & gi_ptr->ctr_mask)
358               {
359                 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
360                 gcov_type *c_ptr;
361                     
362                 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
363                                        GCOV_TAG_COUNTER_LENGTH (n_counts));
364                 c_ptr = values[c_ix];
365                 while (n_counts--)
366                   gcov_write_counter (*c_ptr++);
367                 values[c_ix] = c_ptr;
368                 c_ix++;
369               }
370         }
371
372       /* Object file summary.  */
373       gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
374
375       /* Generate whole program statistics.  */
376       gcov_seek (summary_pos);
377       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
378       if ((error = gcov_close ()))
379           fprintf (stderr, error  < 0 ?
380                    "profiling:%s:Overflow writing\n" :
381                    "profiling:%s:Error writing\n",
382                    gi_ptr->filename);
383     }
384 }
385
386 /* Add a new object file onto the bb chain.  Invoked automatically
387    when running an object file's global ctors.  */
388
389 void
390 __gcov_init (struct gcov_info *info)
391 {
392   if (!info->version)
393     return;
394   if (info->version != GCOV_VERSION)
395     gcov_version_mismatch (info, info->version);
396   else
397     {
398       const char *ptr = info->filename;
399       unsigned crc32 = gcov_crc32;
400   
401       do
402         {
403           unsigned ix;
404           unsigned value = *ptr << 24;
405
406           for (ix = 8; ix--; value <<= 1)
407             {
408               unsigned feedback;
409
410               feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
411               crc32 <<= 1;
412               crc32 ^= feedback;
413             }
414         }
415       while (*ptr++);
416       
417       gcov_crc32 = crc32;
418       
419       if (!gcov_list)
420         atexit (gcov_exit);
421       
422       info->next = gcov_list;
423       gcov_list = info;
424     }
425   info->version = 0;
426 }
427
428 /* Called before fork or exec - write out profile information gathered so
429    far and reset it to zero.  This avoids duplication or loss of the
430    profile information gathered so far.  */
431
432 void
433 __gcov_flush (void)
434 {
435   const struct gcov_info *gi_ptr;
436
437   gcov_exit ();
438   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
439     {
440       unsigned t_ix;
441       const struct gcov_ctr_info *ci_ptr;
442       
443       for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
444         if ((1 << t_ix) & gi_ptr->ctr_mask)
445           {
446             memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
447             ci_ptr++;
448           }
449     }
450 }
451
452 #endif /* L_gcov */
453
454 #ifdef L_gcov_merge_add
455 /* The profile merging function that just adds the counters.  It is given
456    an array COUNTERS of N_COUNTERS old counters and it reads the same number
457    of counters from the gcov file.  */
458 void
459 __gcov_merge_add (counters, n_counters)
460      gcov_type *counters;
461      unsigned n_counters;
462 {
463   for (; n_counters; counters++, n_counters--)
464     *counters += gcov_read_counter ();
465 }
466 #endif /* L_gcov_merge_add */
467
468 #endif /* inhibit_libc */