OSDN Git Service

New GCOV_TAG_FUNCTION layout
[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;
207                f_ix--;
208                fi_ptr = (const struct gcov_fn_info *)
209                  ((const char *) fi_ptr + fi_stride))
210             {
211               tag = gcov_read_unsigned ();
212               length = gcov_read_unsigned ();
213
214               /* Check function */
215               if (tag != GCOV_TAG_FUNCTION
216                   || gcov_read_unsigned () != fi_ptr->ident
217                   || gcov_read_unsigned () != fi_ptr->checksum)
218                 {
219                 read_mismatch:;
220                   fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
221                            gi_ptr->filename,
222                            f_ix + 1 ? "function" : "summaries");
223                   goto read_fatal;
224                 }
225
226               for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
227                 if ((1 << t_ix) & gi_ptr->ctr_mask)
228                   {
229                     unsigned n_counts;
230                     gcov_type *c_ptr;
231                     
232                     tag = gcov_read_unsigned ();
233                     length = gcov_read_unsigned ();
234
235                     if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
236                         || fi_ptr->n_ctrs[c_ix] * 8 != length)
237                       goto read_mismatch;
238                     c_ptr = values[c_ix];
239                     for (n_counts = fi_ptr->n_ctrs[c_ix];
240                          n_counts--; c_ptr++)
241                       *c_ptr += gcov_read_counter ();
242                     values[c_ix] = c_ptr;
243                     c_ix++;
244                 }
245               if ((error = gcov_is_error ()))
246                 goto read_error;
247             }
248
249           /* Check object summary */
250           if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
251             goto read_mismatch;
252           gcov_read_unsigned ();
253           gcov_read_summary (&object);
254
255           /* Check program summary */
256           while (!gcov_is_eof ())
257             {
258               base = gcov_position ();
259               tag = gcov_read_unsigned ();
260               gcov_read_unsigned ();
261               if (tag != GCOV_TAG_PROGRAM_SUMMARY)
262                 goto read_mismatch;
263               gcov_read_summary (&program);
264               if ((error = gcov_is_error ()))
265                 {
266                 read_error:;
267                   fprintf (stderr, error < 0 ?
268                            "profiling:%s:Overflow merging\n" :
269                            "profiling:%s:Error merging\n",
270                            gi_ptr->filename);
271                   goto read_fatal;
272                 }
273               
274               if (program.checksum != gcov_crc32)
275                 continue;
276               summary_pos = base;
277               break;
278             }
279           gcov_seek (0, 0);
280         }
281       else
282         memset (&object, 0, sizeof (object));
283       if (!summary_pos)
284         memset (&program, 0, sizeof (program));
285
286       /* Merge the summaries.  */
287       f_ix = ~0u;
288       for (t_ix = c_ix = 0,
289              cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
290              cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
291              cs_all = all.ctrs;
292            t_ix != GCOV_COUNTERS;
293            t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
294         {
295           if ((1 << t_ix) & gi_ptr->ctr_mask)
296             {
297               if (!cs_obj->runs++)
298                 cs_obj->num = cs_tobj->num;
299               else if (cs_obj->num != cs_tobj->num)
300                 goto read_mismatch;
301               cs_obj->sum_all += cs_tobj->sum_all;
302               if (cs_obj->run_max < cs_tobj->run_max)
303                 cs_obj->run_max = cs_tobj->run_max;
304               cs_obj->sum_max += cs_tobj->run_max;
305               
306               if (!cs_prg->runs++)
307                 cs_prg->num = cs_tprg->num;
308               else if (cs_prg->num != cs_tprg->num)
309                 goto read_mismatch;
310               cs_prg->sum_all += cs_tprg->sum_all;
311               if (cs_prg->run_max < cs_tprg->run_max)
312                 cs_prg->run_max = cs_tprg->run_max;
313               cs_prg->sum_max += cs_tprg->run_max;
314               
315               values[c_ix] = gi_ptr->counts[c_ix].values;
316               c_ix++;
317             }
318           else if (cs_obj->num || cs_prg->num)
319             goto read_mismatch;
320           
321           if (!cs_all->runs && cs_prg->runs)
322             memcpy (cs_all, cs_prg, sizeof (*cs_all));
323           else if (!all.checksum
324                    && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
325                    && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
326             {
327               fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
328                        gi_ptr->filename, GCOV_LOCKED
329                        ? "" : " or concurrent update without locking support");
330               all.checksum = ~0u;
331             }
332         }
333       
334       program.checksum = gcov_crc32;
335       
336       /* Write out the data.  */
337       gcov_write_unsigned (GCOV_DATA_MAGIC);
338       gcov_write_unsigned (GCOV_VERSION);
339       
340       /* Write execution counts for each function.  */
341       for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
342            fi_ptr = (const struct gcov_fn_info *)
343              ((const char *) fi_ptr + fi_stride))
344         {
345           /* Announce function.  */
346           base = gcov_write_tag (GCOV_TAG_FUNCTION);
347           gcov_write_unsigned (fi_ptr->ident);
348           gcov_write_unsigned (fi_ptr->checksum);
349           gcov_write_length (base);
350
351           for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
352             if ((1 << t_ix) & gi_ptr->ctr_mask)
353               {
354                 unsigned n_counts;
355                 gcov_type *c_ptr;
356                     
357                 base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
358                 c_ptr = values[c_ix];
359                 for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
360                   gcov_write_counter (*c_ptr);
361                 values[c_ix] = c_ptr;
362                 gcov_write_length (base);
363                 c_ix++;
364               }
365         }
366
367       /* Object file summary.  */
368       gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
369
370       /* Generate whole program statistics.  */
371       if (summary_pos)
372         gcov_seek (summary_pos, 0);
373       else
374         gcov_seek_end ();
375       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
376       if ((error = gcov_close ()))
377         {
378           fprintf (stderr, error  < 0 ?
379                    "profiling:%s:Overflow writing\n" :
380                    "profiling:%s:Error writing\n",
381                    gi_ptr->filename);
382           gi_ptr->filename = 0;
383         }
384     }
385 }
386
387 /* Add a new object file onto the bb chain.  Invoked automatically
388    when running an object file's global ctors.  */
389
390 void
391 __gcov_init (struct gcov_info *info)
392 {
393   if (!info->version)
394     return;
395   if (info->version != GCOV_VERSION)
396     gcov_version_mismatch (info, info->version);
397   else
398     {
399       const char *ptr = info->filename;
400       unsigned crc32 = gcov_crc32;
401   
402       do
403         {
404           unsigned ix;
405           unsigned value = *ptr << 24;
406
407           for (ix = 8; ix--; value <<= 1)
408             {
409               unsigned feedback;
410
411               feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
412               crc32 <<= 1;
413               crc32 ^= feedback;
414             }
415         }
416       while (*ptr++);
417       
418       gcov_crc32 = crc32;
419       
420       if (!gcov_list)
421         atexit (gcov_exit);
422       
423       info->next = gcov_list;
424       gcov_list = info;
425     }
426   info->version = 0;
427 }
428
429 /* Called before fork or exec - write out profile information gathered so
430    far and reset it to zero.  This avoids duplication or loss of the
431    profile information gathered so far.  */
432
433 void
434 __gcov_flush (void)
435 {
436   const struct gcov_info *gi_ptr;
437
438   gcov_exit ();
439   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
440     {
441       unsigned t_ix;
442       const struct gcov_ctr_info *ci_ptr;
443       
444       for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
445         if ((1 << t_ix) & gi_ptr->ctr_mask)
446           {
447             memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
448             ci_ptr++;
449           }
450     }
451 }
452
453 #endif /* inhibit_libc */