OSDN Git Service

* Makefile.in (LIBGCC_DEPS): Add gcov headers.
[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 #if defined(inhibit_libc)
33 /* If libc and its header files are not available, provide dummy functions.  */
34
35 void __gcov_init (void *p);
36 void __gcov_flush (void);
37
38 void __gcov_init (void *p) { }
39 void __gcov_flush (void) { }
40
41 #else
42
43 /* It is incorrect to include config.h here, because this file is being
44    compiled for the target, and hence definitions concerning only the host
45    do not apply.  */
46
47 #include "tconfig.h"
48 #include "tsystem.h"
49 #include "coretypes.h"
50 #include "tm.h"
51
52 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
53 #include <stdio.h>
54
55 #include <string.h>
56 #if defined (TARGET_HAS_F_SETLKW)
57 #include <fcntl.h>
58 #include <errno.h>
59 #endif
60 #define IN_LIBGCOV 1
61 #include "gcov-io.h"
62 #include "gcov-io.c"
63
64 /* Chain of per-object gcov structures.  */
65 static struct gcov_info *gcov_list;
66
67 /* A program checksum allows us to distinguish program data for an
68    object file included in multiple programs.  */
69 static unsigned gcov_crc32;
70
71 static void
72 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
73 {
74   unsigned expected = GCOV_VERSION;
75   unsigned ix;
76   char e[4], v[4];
77
78   for (ix = 4; ix--; expected >>= 8, version >>= 8)
79     {
80       e[ix] = expected;
81       v[ix] = version;
82     }
83   
84   fprintf (stderr,
85            "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
86            ptr->filename, e, v);
87 }
88
89 /* Dump the coverage counts. We merge with existing counts when
90    possible, to avoid growing the .da files ad infinitum. We use this
91    program's checksum to make sure we only accumulate whole program
92    statistics to the correct summary. An object file might be embedded
93    in two separate programs, and we must keep the two program
94    summaries separate.  */
95
96 static void
97 gcov_exit (void)
98 {
99   struct gcov_info *gi_ptr;
100   struct gcov_summary this_program;
101   struct gcov_summary all;
102
103   memset (&all, 0, sizeof (all));
104   /* Find the totals for this execution.  */
105   memset (&this_program, 0, sizeof (this_program));
106   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
107     {
108       const struct gcov_ctr_info *ci_ptr;
109       struct gcov_ctr_summary *cs_ptr;
110       unsigned t_ix;
111       
112       for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
113            t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
114         if ((1 << t_ix) & gi_ptr->ctr_mask)
115           {
116             const gcov_type *c_ptr;
117             unsigned c_num;
118
119             cs_ptr->num += ci_ptr->num;
120             for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
121               {
122                 cs_ptr->sum_all += *c_ptr;
123                 if (cs_ptr->run_max < *c_ptr)
124                   cs_ptr->run_max = *c_ptr;
125               }
126             ci_ptr++;
127           }
128     }
129
130   /* Now write the data  */
131   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
132     {
133       struct gcov_summary this_object;
134       struct gcov_summary object, program;
135       gcov_type *values[GCOV_COUNTERS];
136       const struct gcov_fn_info *fi_ptr;
137       unsigned fi_stride;
138       unsigned c_ix, t_ix, f_ix;
139       const struct gcov_ctr_info *ci_ptr;
140       struct gcov_ctr_summary *cs_ptr;
141       struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
142       int error;
143       int merging;
144       unsigned long base;
145       unsigned tag, length;
146       unsigned long summary_pos = 0;
147
148       /* Totals for this object file.  */
149       memset (&this_object, 0, sizeof (this_object));
150       for (t_ix = c_ix = 0,
151              ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
152            t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
153         if ((1 << t_ix) & gi_ptr->ctr_mask)
154           {
155             const gcov_type *c_ptr;
156             unsigned c_num;
157
158             cs_ptr->num += ci_ptr->num;
159             values[c_ix] = ci_ptr->values;
160             for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
161               {
162                 cs_ptr->sum_all += *c_ptr;
163                 if (cs_ptr->run_max < *c_ptr)
164                   cs_ptr->run_max = *c_ptr;
165               }
166             c_ix++;
167             ci_ptr++;
168           }
169
170       /* Calculate the function_info stride. This depends on the
171          number of counter types being measured.  */
172       fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
173       if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
174         {
175           fi_stride += __alignof__ (struct gcov_fn_info) - 1;
176           fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
177         }
178       
179       /* Open for modification, if possible */
180       merging = gcov_open (gi_ptr->filename, 0);
181       if (!merging)
182         {
183           fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
184           continue;
185         }
186       
187       if (merging > 0)
188         {
189           /* Merge data from file.  */
190           if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
191             {
192               fprintf (stderr, "profiling:%s:Not a gcov data file\n",
193                        gi_ptr->filename);
194             read_fatal:;
195               gcov_close ();
196               continue;
197             }
198           length = gcov_read_unsigned ();
199           if (length != GCOV_VERSION)
200             {
201               gcov_version_mismatch (gi_ptr, length);
202               goto read_fatal;
203             }
204           
205           /* Merge execution counts for each function.  */
206           for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
207                fi_ptr = (const struct gcov_fn_info *)
208                  ((const char *) fi_ptr + fi_stride))
209             {
210               tag = gcov_read_unsigned ();
211               length = gcov_read_unsigned ();
212
213               /* Check function */
214               if (tag != GCOV_TAG_FUNCTION)
215                 {
216                 read_mismatch:;
217                   fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
218                            gi_ptr->filename,
219                            fi_ptr ? fi_ptr->name : "summaries");
220                   goto read_fatal;
221                 }
222
223               if (strcmp (gcov_read_string (), fi_ptr->name)
224                   || gcov_read_unsigned () != fi_ptr->checksum)
225                 goto read_mismatch;
226
227               for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
228                 if ((1 << t_ix) & gi_ptr->ctr_mask)
229                   {
230                     unsigned n_counts;
231                     gcov_type *c_ptr;
232                     
233                     tag = gcov_read_unsigned ();
234                     length = gcov_read_unsigned ();
235
236                     if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
237                         || fi_ptr->n_ctrs[c_ix] * 8 != length)
238                       goto read_mismatch;
239                     c_ptr = values[c_ix];
240                     for (n_counts = fi_ptr->n_ctrs[c_ix];
241                          n_counts--; c_ptr++)
242                       *c_ptr += gcov_read_counter ();
243                     values[c_ix] = c_ptr;
244                     c_ix++;
245                 }
246               if ((error = gcov_is_error ()))
247                 goto read_error;
248             }
249
250           /* Check object summary */
251           if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
252             goto read_mismatch;
253           gcov_read_unsigned ();
254           gcov_read_summary (&object);
255
256           /* Check program summary */
257           while (!gcov_is_eof ())
258             {
259               base = gcov_position ();
260               tag = gcov_read_unsigned ();
261               gcov_read_unsigned ();
262               if (tag != GCOV_TAG_PROGRAM_SUMMARY)
263                 goto read_mismatch;
264               gcov_read_summary (&program);
265               if ((error = gcov_is_error ()))
266                 {
267                 read_error:;
268                   fprintf (stderr, error < 0 ?
269                            "profiling:%s:Overflow merging\n" :
270                            "profiling:%s:Error merging\n",
271                            gi_ptr->filename);
272                   goto read_fatal;
273                 }
274               
275               if (program.checksum != gcov_crc32)
276                 continue;
277               summary_pos = base;
278               break;
279             }
280           gcov_seek (0, 0);
281         }
282       else
283         memset (&object, 0, sizeof (object));
284       if (!summary_pos)
285         memset (&program, 0, sizeof (program));
286
287       fi_ptr = 0;
288       
289       /* Merge the summaries.  */
290       for (t_ix = c_ix = 0,
291              cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
292              cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
293              cs_all = all.ctrs;
294            t_ix != GCOV_COUNTERS;
295            t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
296         {
297           if ((1 << t_ix) & gi_ptr->ctr_mask)
298             {
299               if (!cs_obj->runs++)
300                 cs_obj->num = cs_tobj->num;
301               else if (cs_obj->num != cs_tobj->num)
302                 goto read_mismatch;
303               cs_obj->sum_all += cs_tobj->sum_all;
304               if (cs_obj->run_max < cs_tobj->run_max)
305                 cs_obj->run_max = cs_tobj->run_max;
306               cs_obj->sum_max += cs_tobj->run_max;
307               
308               if (!cs_prg->runs++)
309                 cs_prg->num = cs_tprg->num;
310               else if (cs_prg->num != cs_tprg->num)
311                 goto read_mismatch;
312               cs_prg->sum_all += cs_tprg->sum_all;
313               if (cs_prg->run_max < cs_tprg->run_max)
314                 cs_prg->run_max = cs_tprg->run_max;
315               cs_prg->sum_max += cs_tprg->run_max;
316               
317               values[c_ix] = gi_ptr->counts[c_ix].values;
318               c_ix++;
319             }
320           else if (cs_obj->num || cs_prg->num)
321             goto read_mismatch;
322           
323           if (!cs_all->runs && cs_prg->runs)
324             memcpy (cs_all, cs_prg, sizeof (*cs_all));
325           else if (!all.checksum
326                    && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
327                    && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
328             {
329               fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
330                        gi_ptr->filename, GCOV_LOCKED
331                        ? "" : " or concurrent update without locking support");
332               all.checksum = ~0u;
333             }
334         }
335       
336       program.checksum = gcov_crc32;
337       
338       /* Write out the data.  */
339       gcov_write_unsigned (GCOV_DATA_MAGIC);
340       gcov_write_unsigned (GCOV_VERSION);
341       
342       /* Write execution counts for each function.  */
343       for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
344            fi_ptr = (const struct gcov_fn_info *)
345              ((const char *) fi_ptr + fi_stride))
346         {
347           /* Announce function.  */
348           base = gcov_write_tag (GCOV_TAG_FUNCTION);
349           gcov_write_string (fi_ptr->name);
350           gcov_write_unsigned (fi_ptr->checksum);
351           gcov_write_length (base);
352
353           for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
354             if ((1 << t_ix) & gi_ptr->ctr_mask)
355               {
356                 unsigned n_counts;
357                 gcov_type *c_ptr;
358                     
359                 base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
360                 c_ptr = values[c_ix];
361                 for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
362                   gcov_write_counter (*c_ptr);
363                 values[c_ix] = c_ptr;
364                 gcov_write_length (base);
365                 c_ix++;
366               }
367         }
368
369       /* Object file summary.  */
370       gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
371
372       /* Generate whole program statistics.  */
373       if (summary_pos)
374         gcov_seek (summary_pos, 0);
375       else
376         gcov_seek_end ();
377       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
378       if ((error = gcov_close ()))
379         {
380           fprintf (stderr, error  < 0 ?
381                    "profiling:%s:Overflow writing\n" :
382                    "profiling:%s:Error writing\n",
383                    gi_ptr->filename);
384           gi_ptr->filename = 0;
385         }
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       unsigned crc32 = gcov_crc32;
403   
404       do
405         {
406           unsigned ix;
407           unsigned value = *ptr << 24;
408
409           for (ix = 8; ix--; value <<= 1)
410             {
411               unsigned 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 /* inhibit_libc */