OSDN Git Service

* toplev.c (rest_of_compilation): Avoid cfg_cleanup calls when not
[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 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
42 #include <stdio.h>
43
44 #include "gcov-io.h"
45 #include <string.h>
46 #if defined (TARGET_HAS_F_SETLKW)
47 #include <fcntl.h>
48 #include <errno.h>
49 #endif
50
51 /* Chain of per-object gcov structures.  */
52 static struct gcov_info *gcov_list;
53
54 /* A program checksum allows us to distinguish program data for an
55    object file included in multiple programs.  */
56 static unsigned gcov_crc32;
57
58 static void
59 gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
60 {
61   unsigned expected = GCOV_VERSION;
62   unsigned ix;
63   char e[4], v[4];
64
65   for (ix = 4; ix--; expected >>= 8, version >>= 8)
66     {
67       e[ix] = expected;
68       v[ix] = version;
69     }
70   
71   fprintf (stderr,
72            "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
73            ptr->filename, e, v);
74 }
75
76 /* Dump the coverage counts. We merge with existing counts when
77    possible, to avoid growing the .da files ad infinitum. We use this
78    program's checksum to make sure we only accumulate whole program
79    statistics to the correct summary. An object file might be embedded
80    in two separate programs, and we must keep the two program
81    summaries separate.  */
82
83 static void
84 gcov_exit (void)
85 {
86   struct gcov_info *ptr;
87   unsigned ix, jx;
88   struct gcov_summary program;
89   gcov_type program_max_one = 0;
90   gcov_type program_max_sum = 0;
91   gcov_type program_sum = 0;
92   unsigned program_arcs = 0;
93   
94 #if defined (TARGET_HAS_F_SETLKW)
95   struct flock s_flock;
96
97   s_flock.l_type = F_WRLCK;
98   s_flock.l_whence = SEEK_SET;
99   s_flock.l_start = 0;
100   s_flock.l_len = 0; /* Until EOF.  */
101   s_flock.l_pid = getpid ();
102 #endif
103
104   memset (&program, 0, sizeof (program));
105   program.checksum = gcov_crc32;
106   
107   for (ptr = gcov_list; ptr; ptr = ptr->next)
108     {
109       FILE *da_file;
110       struct gcov_summary object;
111       struct gcov_summary local_prg;
112       int merging = 0;
113       long base;
114       const struct function_info *fn_info;
115       gcov_type **counters;
116       gcov_type *count_ptr;
117       gcov_type object_max_one = 0;
118       gcov_type count;
119       unsigned tag, length, flength, checksum;
120       unsigned arc_data_index, f_sect_index, sect_index;
121
122       ptr->wkspc = 0;
123       if (!ptr->filename)
124         continue;
125
126       counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
127       for (ix = 0; ix < ptr->n_counter_sections; ix++)
128         counters[ix] = ptr->counter_sections[ix].counters;
129
130       for (arc_data_index = 0;
131            arc_data_index < ptr->n_counter_sections
132            && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
133            arc_data_index++)
134         continue;
135
136       if (arc_data_index == ptr->n_counter_sections)
137         {
138           /* For now; later we may want to just measure other profiles,
139              but now I am lazy to check for all consequences.  */
140           abort ();
141         }
142       for (ix = ptr->counter_sections[arc_data_index].n_counters,
143            count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
144         {
145           gcov_type count = *count_ptr++;
146
147           if (count > object_max_one)
148             object_max_one = count;
149         }
150       if (object_max_one > program_max_one)
151         program_max_one = object_max_one;
152       
153       memset (&local_prg, 0, sizeof (local_prg));
154       memset (&object, 0, sizeof (object));
155       
156       /* Open for modification */
157       if ((da_file = fopen (ptr->filename, "r+b")))
158         merging = 1;
159       else if ((da_file = fopen (ptr->filename, "w+b")))
160         ;
161       else
162         {
163           fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
164           ptr->filename = 0;
165           continue;
166         }
167
168 #if defined (TARGET_HAS_F_SETLKW)
169       /* After a fork, another process might try to read and/or write
170          the same file simultaneously.  So if we can, lock the file to
171          avoid race conditions.  */
172       while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
173              && errno == EINTR)
174         continue;
175 #endif
176       if (merging)
177         {
178           /* Merge data from file.  */
179               
180           if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
181             {
182               fprintf (stderr, "profiling:%s:Not a gcov data file\n",
183                        ptr->filename);
184             read_fatal:;
185               fclose (da_file);
186               ptr->filename = 0;
187               continue;
188             }
189           if (gcov_read_unsigned (da_file, &length) || length != GCOV_VERSION)
190             {
191               gcov_version_mismatch (ptr, length);
192               goto read_fatal;
193             }
194           
195           /* Merge execution counts for each function.  */
196           for (ix = ptr->n_functions, fn_info = ptr->functions;
197                ix--; fn_info++)
198             {
199               if (gcov_read_unsigned (da_file, &tag)
200                   || gcov_read_unsigned (da_file, &length))
201                 {
202                 read_error:;
203                   fprintf (stderr, "profiling:%s:Error merging\n",
204                            ptr->filename);
205                   goto read_fatal;
206                 }
207
208               /* Check function */
209               if (tag != GCOV_TAG_FUNCTION)
210                 {
211                 read_mismatch:;
212                   fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
213                            ptr->filename, fn_info->name);
214                   goto read_fatal;
215                 }
216
217               if (gcov_read_unsigned (da_file, &flength)
218                   || gcov_skip_string (da_file, flength)
219                   || gcov_read_unsigned (da_file, &checksum))
220                 goto read_error;
221               if (flength != strlen (fn_info->name)
222                   || checksum != fn_info->checksum)
223                 goto read_mismatch;
224
225               /* Counters.  */
226               for (f_sect_index = 0;
227                    f_sect_index < fn_info->n_counter_sections;
228                    f_sect_index++)
229                 {
230                   if (gcov_read_unsigned (da_file, &tag)
231                       || gcov_read_unsigned (da_file, &length))
232                     goto read_error;
233                   for (sect_index = 0;
234                        sect_index < ptr->n_counter_sections;
235                        sect_index++)
236                     if (ptr->counter_sections[sect_index].tag == tag)
237                       break;
238                   if (fn_info->counter_sections[f_sect_index].tag != tag
239                       || sect_index == ptr->n_counter_sections
240                       || length / 8 != fn_info->counter_sections[f_sect_index].n_counters)
241                     goto read_mismatch;
242                   
243                   for (jx = fn_info->counter_sections[f_sect_index].n_counters;
244                        jx--; counters[sect_index]++)
245                     if (gcov_read_counter (da_file, &count))
246                       goto read_error;
247                     else
248                       *counters[sect_index] += count;
249                 }
250             }
251
252           /* Check object summary */
253           if (gcov_read_unsigned (da_file, &tag)
254               || gcov_read_unsigned (da_file, &length))
255             goto read_error;
256           if (tag != GCOV_TAG_OBJECT_SUMMARY)
257             goto read_mismatch;
258           if (gcov_read_summary (da_file, &object))
259             goto read_error;
260
261           /* Check program summary */
262           while (1)
263             {
264               long base = ftell (da_file);
265               
266               if (gcov_read_unsigned (da_file, &tag)
267                   || gcov_read_unsigned (da_file, &length))
268                 {
269                   if (feof (da_file))
270                     break;
271                   goto read_error;
272                 }
273               if (tag != GCOV_TAG_PROGRAM_SUMMARY
274                   && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
275                   && tag != GCOV_TAG_INCORRECT_SUMMARY)
276                 goto read_mismatch;
277               if (gcov_read_summary (da_file, &local_prg))
278                 goto read_error;
279               if (local_prg.checksum != program.checksum)
280                 continue;
281               if (tag == GCOV_TAG_PLACEHOLDER_SUMMARY)
282                 {
283                   fprintf (stderr,
284                            "profiling:%s:Concurrent race detected\n",
285                            ptr->filename);
286                   goto read_fatal;
287                 }
288               merging = -1;
289               if (tag != GCOV_TAG_PROGRAM_SUMMARY)
290                 break;
291               
292               if (program.runs
293                   && memcmp (&program, &local_prg, sizeof (program)))
294                 {
295                   fprintf (stderr, "profiling:%s:Invocation mismatch\n",
296                            ptr->filename);
297                   local_prg.runs = 0;
298                 }
299               else
300                 memcpy (&program, &local_prg, sizeof (program));
301               ptr->wkspc = base;
302               break;
303             }
304           fseek (da_file, 0, SEEK_SET);
305         }
306
307       object.runs++;
308       object.arcs = ptr->counter_sections[arc_data_index].n_counters;
309       object.arc_sum = 0;
310       if (object.arc_max_one < object_max_one)
311         object.arc_max_one = object_max_one;
312       object.arc_sum_max += object_max_one;
313       
314       /* Write out the data.  */
315       if (/* magic */
316           gcov_write_unsigned (da_file, GCOV_DATA_MAGIC)
317           /* version number */
318           || gcov_write_unsigned (da_file, GCOV_VERSION))
319         {
320         write_error:;
321           fclose (da_file);
322           fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
323           ptr->filename = 0;
324           continue;
325         }
326       
327       /* Write execution counts for each function.  */
328       for (ix = 0; ix < ptr->n_counter_sections; ix++)
329         counters[ix] = ptr->counter_sections[ix].counters;
330       for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
331         {
332           /* Announce function.  */
333           if (gcov_write_unsigned (da_file, GCOV_TAG_FUNCTION)
334               || !(base = gcov_reserve_length (da_file))
335               /* function name */
336               || gcov_write_string (da_file, fn_info->name,
337                                     strlen (fn_info->name))
338               /* function checksum */
339               || gcov_write_unsigned (da_file, fn_info->checksum)
340               || gcov_write_length (da_file, base))
341             goto write_error;
342
343           /* counters.  */
344           for (f_sect_index = 0;
345                f_sect_index < fn_info->n_counter_sections;
346                f_sect_index++)
347             {
348               tag = fn_info->counter_sections[f_sect_index].tag;
349               for (sect_index = 0;
350                    sect_index < ptr->n_counter_sections;
351                    sect_index++)
352                 if (ptr->counter_sections[sect_index].tag == tag)
353                   break;
354               if (sect_index == ptr->n_counter_sections)
355                 abort ();
356
357               if (gcov_write_unsigned (da_file, tag)
358                   || !(base = gcov_reserve_length (da_file)))
359                 goto write_error;
360           
361               for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
362                 {
363                   gcov_type count = *counters[sect_index]++;
364               
365                   if (tag == GCOV_TAG_ARC_COUNTS)
366                     {
367                       object.arc_sum += count;
368                       if (object.arc_max_sum < count)
369                         object.arc_max_sum = count;
370                     }
371                   if (gcov_write_counter (da_file, count))
372                     goto write_error; /* RIP Edsger Dijkstra */
373                 }
374               if (gcov_write_length (da_file, base))
375                 goto write_error;
376             }
377         }
378
379       /* Object file summary.  */
380       if (gcov_write_summary (da_file, GCOV_TAG_OBJECT_SUMMARY, &object))
381         goto write_error;
382
383       if (merging >= 0)
384         {
385           if (fseek (da_file, 0, SEEK_END))
386             goto write_error;
387           ptr->wkspc = ftell (da_file);
388           if (gcov_write_summary (da_file, GCOV_TAG_PLACEHOLDER_SUMMARY,
389                                   &program))
390             goto write_error;
391         }
392       else if (ptr->wkspc)
393         {
394           /* Zap trailing program summary */
395           if (fseek (da_file, ptr->wkspc, SEEK_SET))
396             goto write_error;
397           if (!local_prg.runs)
398             ptr->wkspc = 0;
399           if (gcov_write_unsigned (da_file,
400                              local_prg.runs ? GCOV_TAG_PLACEHOLDER_SUMMARY
401                              : GCOV_TAG_INCORRECT_SUMMARY))
402             goto write_error;
403         }
404       if (fflush (da_file))
405         goto write_error;
406
407       if (fclose (da_file))
408         {
409           fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
410           ptr->filename = 0;
411         }
412       else
413         {
414           program_arcs += ptr->counter_sections[arc_data_index].n_counters;
415           program_sum += object.arc_sum;
416           if (program_max_sum < object.arc_max_sum)
417             program_max_sum = object.arc_max_sum;
418         }
419       free(counters);
420     }
421
422   /* Generate whole program statistics.  */
423   program.runs++;
424   program.arcs = program_arcs;
425   program.arc_sum = program_sum;
426   if (program.arc_max_one < program_max_one)
427     program.arc_max_one = program_max_one;
428   if (program.arc_max_sum < program_max_sum)
429     program.arc_max_sum = program_max_sum;
430   program.arc_sum_max += program_max_one;
431   
432   /* Upate whole program statistics.  */
433   for (ptr = gcov_list; ptr; ptr = ptr->next)
434     if (ptr->filename && ptr->wkspc)
435       {
436         FILE *da_file;
437         
438         da_file = fopen (ptr->filename, "r+b");
439         if (!da_file)
440           {
441             fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
442             continue;
443           }
444         
445 #if defined (TARGET_HAS_F_SETLKW)
446         while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
447                && errno == EINTR)
448           continue;
449 #endif
450         if (fseek (da_file, ptr->wkspc, SEEK_SET)
451             || gcov_write_summary (da_file, GCOV_TAG_PROGRAM_SUMMARY, &program)
452             || fflush (da_file))
453           fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
454         if (fclose (da_file))
455           fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
456       }
457 }
458
459 /* Add a new object file onto the bb chain.  Invoked automatically
460    when running an object file's global ctors.  */
461
462 void
463 __gcov_init (struct gcov_info *info)
464 {
465   if (!info->version)
466     return;
467   if (info->version != GCOV_VERSION)
468     gcov_version_mismatch (info, info->version);
469   else
470     {
471       const char *ptr = info->filename;
472       unsigned crc32 = gcov_crc32;
473   
474       do
475         {
476           unsigned ix;
477           unsigned value = *ptr << 24;
478
479           for (ix = 8; ix--; value <<= 1)
480             {
481               unsigned feedback;
482
483               feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
484               crc32 <<= 1;
485               crc32 ^= feedback;
486             }
487         }
488       while (*ptr++);
489       
490       gcov_crc32 = crc32;
491       
492       if (!gcov_list)
493         atexit (gcov_exit);
494       
495       info->next = gcov_list;
496       gcov_list = info;
497     }
498   info->version = 0;
499 }
500
501 /* Called before fork or exec - write out profile information gathered so
502    far and reset it to zero.  This avoids duplication or loss of the
503    profile information gathered so far.  */
504
505 void
506 __gcov_flush (void)
507 {
508   struct gcov_info *ptr;
509
510   gcov_exit ();
511   for (ptr = gcov_list; ptr; ptr = ptr->next)
512     {
513       unsigned i, j;
514       
515       for (j = 0; j < ptr->n_counter_sections; j++)
516         for (i = ptr->counter_sections[j].n_counters; i--;)
517           ptr->counter_sections[j].counters[i] = 0;
518     }
519 }