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.
6 This file is part of GCC.
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
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
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
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
32 #if defined(inhibit_libc)
33 /* If libc and its header files are not available, provide dummy functions. */
35 void __gcov_init (void *p
);
36 void __gcov_flush (void);
38 void __gcov_init (void *p
) { }
39 void __gcov_flush (void) { }
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
49 #include "coretypes.h"
52 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
56 #if defined (TARGET_HAS_F_SETLKW)
62 /* Chain of per-object gcov structures. */
63 static struct gcov_info
*gcov_list
;
65 /* A program checksum allows us to distinguish program data for an
66 object file included in multiple programs. */
67 static unsigned gcov_crc32
;
70 gcov_version_mismatch (struct gcov_info
*ptr
, unsigned version
)
72 unsigned expected
= GCOV_VERSION
;
76 for (ix
= 4; ix
--; expected
>>= 8, version
>>= 8)
83 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
87 /* Dump the coverage counts. We merge with existing counts when
88 possible, to avoid growing the .da files ad infinitum. We use this
89 program's checksum to make sure we only accumulate whole program
90 statistics to the correct summary. An object file might be embedded
91 in two separate programs, and we must keep the two program
92 summaries separate. */
97 struct gcov_info
*ptr
;
99 struct gcov_summary program
;
100 gcov_type program_max_one
= 0;
101 gcov_type program_max_sum
= 0;
102 gcov_type program_sum
= 0;
103 unsigned program_arcs
= 0;
105 #if defined (TARGET_HAS_F_SETLKW)
106 struct flock s_flock
;
108 s_flock
.l_type
= F_WRLCK
;
109 s_flock
.l_whence
= SEEK_SET
;
111 s_flock
.l_len
= 0; /* Until EOF. */
112 s_flock
.l_pid
= getpid ();
115 memset (&program
, 0, sizeof (program
));
116 program
.checksum
= gcov_crc32
;
118 for (ptr
= gcov_list
; ptr
; ptr
= ptr
->next
)
120 struct gcov_summary object
;
121 struct gcov_summary local_prg
;
124 const struct function_info
*fn_info
;
125 gcov_type
**counters
;
126 gcov_type
*count_ptr
;
127 gcov_type object_max_one
= 0;
129 unsigned tag
, length
, flength
, checksum
;
130 unsigned arc_data_index
, f_sect_index
, sect_index
;
136 counters
= malloc (sizeof (gcov_type
*) * ptr
->n_counter_sections
);
137 for (ix
= 0; ix
< ptr
->n_counter_sections
; ix
++)
138 counters
[ix
] = ptr
->counter_sections
[ix
].counters
;
140 for (arc_data_index
= 0;
141 arc_data_index
< ptr
->n_counter_sections
142 && ptr
->counter_sections
[arc_data_index
].tag
!= GCOV_TAG_ARC_COUNTS
;
146 if (arc_data_index
== ptr
->n_counter_sections
)
148 /* For now; later we may want to just measure other profiles,
149 but now I am lazy to check for all consequences. */
152 for (ix
= ptr
->counter_sections
[arc_data_index
].n_counters
,
153 count_ptr
= ptr
->counter_sections
[arc_data_index
].counters
; ix
--;)
155 gcov_type count
= *count_ptr
++;
157 if (count
> object_max_one
)
158 object_max_one
= count
;
160 if (object_max_one
> program_max_one
)
161 program_max_one
= object_max_one
;
163 memset (&local_prg
, 0, sizeof (local_prg
));
164 memset (&object
, 0, sizeof (object
));
166 /* Open for modification */
167 if (!da_file_open (ptr
->filename
, &merging
))
169 fprintf (stderr
, "profiling:%s:Cannot open\n", ptr
->filename
);
176 /* Merge data from file. */
178 if (gcov_read_unsigned (0, &tag
) || tag
!= GCOV_DATA_MAGIC
)
180 fprintf (stderr
, "profiling:%s:Not a gcov data file\n",
187 if (gcov_read_unsigned (0, &length
) || length
!= GCOV_VERSION
)
189 gcov_version_mismatch (ptr
, length
);
193 /* Merge execution counts for each function. */
194 for (ix
= ptr
->n_functions
, fn_info
= ptr
->functions
;
197 if (gcov_read_unsigned (0, &tag
)
198 || gcov_read_unsigned (0, &length
))
201 fprintf (stderr
, "profiling:%s:Error merging\n",
207 if (tag
!= GCOV_TAG_FUNCTION
)
210 fprintf (stderr
, "profiling:%s:Merge mismatch at %s\n",
211 ptr
->filename
, fn_info
->name
);
215 if (gcov_read_unsigned (0, &flength
)
216 || gcov_skip_string (0, flength
)
217 || gcov_read_unsigned (0, &checksum
))
219 if (flength
!= strlen (fn_info
->name
)
220 || checksum
!= fn_info
->checksum
)
224 for (f_sect_index
= 0;
225 f_sect_index
< fn_info
->n_counter_sections
;
230 if (gcov_read_unsigned (0, &tag
)
231 || gcov_read_unsigned (0, &length
))
234 sect_index
< ptr
->n_counter_sections
;
236 if (ptr
->counter_sections
[sect_index
].tag
== tag
)
238 if (sect_index
== ptr
->n_counter_sections
239 || fn_info
->counter_sections
[f_sect_index
].tag
!= tag
)
242 n_counters
= fn_info
->counter_sections
[f_sect_index
].n_counters
;
243 if (n_counters
!= length
/ 8)
246 for (jx
= 0; jx
< n_counters
; jx
++)
247 if (gcov_read_counter (0, &count
))
250 counters
[sect_index
][jx
] += count
;
251 counters
[sect_index
] += n_counters
;
255 /* Check object summary */
256 if (gcov_read_unsigned (0, &tag
)
257 || gcov_read_unsigned (0, &length
))
259 if (tag
!= GCOV_TAG_OBJECT_SUMMARY
)
261 if (gcov_read_summary (0, &object
))
264 /* Check program summary */
267 long base
= da_file_position (0);
269 if (gcov_read_unsigned (0, &tag
)
270 || gcov_read_unsigned (0, &length
))
276 if (tag
!= GCOV_TAG_PROGRAM_SUMMARY
277 && tag
!= GCOV_TAG_PLACEHOLDER_SUMMARY
278 && tag
!= GCOV_TAG_INCORRECT_SUMMARY
)
280 if (gcov_read_summary (0, &local_prg
))
282 if (local_prg
.checksum
!= program
.checksum
)
284 if (tag
== GCOV_TAG_PLACEHOLDER_SUMMARY
)
287 "profiling:%s:Concurrent race detected\n",
292 if (tag
!= GCOV_TAG_PROGRAM_SUMMARY
)
296 && memcmp (&program
, &local_prg
, sizeof (program
)))
298 fprintf (stderr
, "profiling:%s:Invocation mismatch\n",
303 memcpy (&program
, &local_prg
, sizeof (program
));
307 da_file_seek (0, 0, SEEK_SET
);
311 object
.arcs
= ptr
->counter_sections
[arc_data_index
].n_counters
;
313 if (object
.arc_max_one
< object_max_one
)
314 object
.arc_max_one
= object_max_one
;
315 object
.arc_sum_max
+= object_max_one
;
317 /* Write out the data. */
319 gcov_write_unsigned (0, GCOV_DATA_MAGIC
)
321 || gcov_write_unsigned (0, GCOV_VERSION
))
325 fprintf (stderr
, "profiling:%s:Error writing\n", ptr
->filename
);
330 /* Write execution counts for each function. */
331 for (ix
= 0; ix
< ptr
->n_counter_sections
; ix
++)
332 counters
[ix
] = ptr
->counter_sections
[ix
].counters
;
333 for (ix
= ptr
->n_functions
, fn_info
= ptr
->functions
; ix
--; fn_info
++)
335 /* Announce function. */
336 if (gcov_write_unsigned (0, GCOV_TAG_FUNCTION
)
337 || !(base
= gcov_reserve_length (0))
339 || gcov_write_string (0, fn_info
->name
,
340 strlen (fn_info
->name
))
341 /* function checksum */
342 || gcov_write_unsigned (0, fn_info
->checksum
)
343 || gcov_write_length (0, base
))
347 for (f_sect_index
= 0;
348 f_sect_index
< fn_info
->n_counter_sections
;
351 tag
= fn_info
->counter_sections
[f_sect_index
].tag
;
353 sect_index
< ptr
->n_counter_sections
;
355 if (ptr
->counter_sections
[sect_index
].tag
== tag
)
357 if (sect_index
== ptr
->n_counter_sections
)
360 if (gcov_write_unsigned (0, tag
)
361 || !(base
= gcov_reserve_length (0)))
364 for (jx
= fn_info
->counter_sections
[f_sect_index
].n_counters
; jx
--;)
366 gcov_type count
= *counters
[sect_index
]++;
368 if (tag
== GCOV_TAG_ARC_COUNTS
)
370 object
.arc_sum
+= count
;
371 if (object
.arc_max_sum
< count
)
372 object
.arc_max_sum
= count
;
374 if (gcov_write_counter (0, count
))
375 goto write_error
; /* RIP Edsger Dijkstra */
377 if (gcov_write_length (0, base
))
382 /* Object file summary. */
383 if (gcov_write_summary (0, GCOV_TAG_OBJECT_SUMMARY
, &object
))
388 if (da_file_seek (0, 0, SEEK_END
))
390 ptr
->wkspc
= da_file_position (0);
391 if (gcov_write_summary (0, GCOV_TAG_PLACEHOLDER_SUMMARY
,
397 /* Zap trailing program summary */
398 if (da_file_seek (0, ptr
->wkspc
, SEEK_SET
))
402 if (gcov_write_unsigned (0, local_prg
.runs
403 ? GCOV_TAG_PLACEHOLDER_SUMMARY
404 : GCOV_TAG_INCORRECT_SUMMARY
))
408 if (da_file_close ())
410 fprintf (stderr
, "profiling:%s:Error closing\n", ptr
->filename
);
415 program_arcs
+= ptr
->counter_sections
[arc_data_index
].n_counters
;
416 program_sum
+= object
.arc_sum
;
417 if (program_max_sum
< object
.arc_max_sum
)
418 program_max_sum
= object
.arc_max_sum
;
423 /* Generate whole program statistics. */
425 program
.arcs
= program_arcs
;
426 program
.arc_sum
= program_sum
;
427 if (program
.arc_max_one
< program_max_one
)
428 program
.arc_max_one
= program_max_one
;
429 if (program
.arc_max_sum
< program_max_sum
)
430 program
.arc_max_sum
= program_max_sum
;
431 program
.arc_sum_max
+= program_max_one
;
433 /* Upate whole program statistics. */
434 for (ptr
= gcov_list
; ptr
; ptr
= ptr
->next
)
435 if (ptr
->filename
&& ptr
->wkspc
)
439 da_file
= fopen (ptr
->filename
, "r+b");
442 fprintf (stderr
, "profiling:%s:Cannot open\n", ptr
->filename
);
446 #if defined (TARGET_HAS_F_SETLKW)
447 while (fcntl (fileno (da_file
), F_SETLKW
, &s_flock
)
451 if (fseek (da_file
, ptr
->wkspc
, SEEK_SET
)
452 || gcov_write_summary (da_file
, GCOV_TAG_PROGRAM_SUMMARY
, &program
)
454 fprintf (stderr
, "profiling:%s:Error writing\n", ptr
->filename
);
455 if (fclose (da_file
))
456 fprintf (stderr
, "profiling:%s:Error closing\n", ptr
->filename
);
460 /* Add a new object file onto the bb chain. Invoked automatically
461 when running an object file's global ctors. */
464 __gcov_init (struct gcov_info
*info
)
468 if (info
->version
!= GCOV_VERSION
)
469 gcov_version_mismatch (info
, info
->version
);
472 const char *ptr
= info
->filename
;
473 unsigned crc32
= gcov_crc32
;
478 unsigned value
= *ptr
<< 24;
480 for (ix
= 8; ix
--; value
<<= 1)
484 feedback
= (value
^ crc32
) & 0x80000000 ? 0x04c11db7 : 0;
496 info
->next
= gcov_list
;
502 /* Called before fork or exec - write out profile information gathered so
503 far and reset it to zero. This avoids duplication or loss of the
504 profile information gathered so far. */
509 struct gcov_info
*ptr
;
512 for (ptr
= gcov_list
; ptr
; ptr
= ptr
->next
)
516 for (j
= 0; j
< ptr
->n_counter_sections
; j
++)
517 for (i
= ptr
->counter_sections
[j
].n_counters
; i
--;)
518 ptr
->counter_sections
[j
].counters
[i
] = 0;
522 #endif /* inhibit_libc */