OSDN Git Service

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