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 /* 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
38 #include "coretypes.h"
41 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
46 #if defined (TARGET_HAS_F_SETLKW)
51 /* Chain of per-object gcov structures. */
52 static struct gcov_info
*gcov_list
;
54 /* A program checksum allows us to distinguish program data for an
55 object file included in multiple programs. */
56 static unsigned gcov_crc32
;
59 gcov_version_mismatch (struct gcov_info
*ptr
, unsigned version
)
61 unsigned expected
= GCOV_VERSION
;
65 for (ix
= 4; ix
--; expected
>>= 8, version
>>= 8)
72 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
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. */
86 struct gcov_info
*ptr
;
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;
94 #if defined (TARGET_HAS_F_SETLKW)
97 s_flock
.l_type
= F_WRLCK
;
98 s_flock
.l_whence
= SEEK_SET
;
100 s_flock
.l_len
= 0; /* Until EOF. */
101 s_flock
.l_pid
= getpid ();
104 memset (&program
, 0, sizeof (program
));
105 program
.checksum
= gcov_crc32
;
107 for (ptr
= gcov_list
; ptr
; ptr
= ptr
->next
)
110 struct gcov_summary object
;
111 struct gcov_summary local_prg
;
114 const struct function_info
*fn_info
;
115 gcov_type
**counters
;
116 gcov_type
*count_ptr
;
117 gcov_type object_max_one
= 0;
119 unsigned tag
, length
, flength
, checksum
;
120 unsigned arc_data_index
, f_sect_index
, sect_index
;
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
;
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
;
136 if (arc_data_index
== ptr
->n_counter_sections
)
138 /* For now; later we may want to just measure other profiles,
139 but now I am lazy to check for all consequences. */
142 for (ix
= ptr
->counter_sections
[arc_data_index
].n_counters
,
143 count_ptr
= ptr
->counter_sections
[arc_data_index
].counters
; ix
--;)
145 gcov_type count
= *count_ptr
++;
147 if (count
> object_max_one
)
148 object_max_one
= count
;
150 if (object_max_one
> program_max_one
)
151 program_max_one
= object_max_one
;
153 memset (&local_prg
, 0, sizeof (local_prg
));
154 memset (&object
, 0, sizeof (object
));
156 /* Open for modification */
157 if ((da_file
= fopen (ptr
->filename
, "r+b")))
159 else if ((da_file
= fopen (ptr
->filename
, "w+b")))
163 fprintf (stderr
, "profiling:%s:Cannot open\n", ptr
->filename
);
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
)
178 /* Merge data from file. */
180 if (gcov_read_unsigned (da_file
, &tag
) || tag
!= GCOV_DATA_MAGIC
)
182 fprintf (stderr
, "profiling:%s:Not a gcov data file\n",
189 if (gcov_read_unsigned (da_file
, &length
) || length
!= GCOV_VERSION
)
191 gcov_version_mismatch (ptr
, length
);
195 /* Merge execution counts for each function. */
196 for (ix
= ptr
->n_functions
, fn_info
= ptr
->functions
;
199 if (gcov_read_unsigned (da_file
, &tag
)
200 || gcov_read_unsigned (da_file
, &length
))
203 fprintf (stderr
, "profiling:%s:Error merging\n",
209 if (tag
!= GCOV_TAG_FUNCTION
)
212 fprintf (stderr
, "profiling:%s:Merge mismatch at %s\n",
213 ptr
->filename
, fn_info
->name
);
217 if (gcov_read_unsigned (da_file
, &flength
)
218 || gcov_skip_string (da_file
, flength
)
219 || gcov_read_unsigned (da_file
, &checksum
))
221 if (flength
!= strlen (fn_info
->name
)
222 || checksum
!= fn_info
->checksum
)
226 for (f_sect_index
= 0;
227 f_sect_index
< fn_info
->n_counter_sections
;
230 if (gcov_read_unsigned (da_file
, &tag
)
231 || gcov_read_unsigned (da_file
, &length
))
234 sect_index
< ptr
->n_counter_sections
;
236 if (ptr
->counter_sections
[sect_index
].tag
== tag
)
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
)
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
))
248 *counters
[sect_index
] += count
;
252 /* Check object summary */
253 if (gcov_read_unsigned (da_file
, &tag
)
254 || gcov_read_unsigned (da_file
, &length
))
256 if (tag
!= GCOV_TAG_OBJECT_SUMMARY
)
258 if (gcov_read_summary (da_file
, &object
))
261 /* Check program summary */
264 long base
= ftell (da_file
);
266 if (gcov_read_unsigned (da_file
, &tag
)
267 || gcov_read_unsigned (da_file
, &length
))
273 if (tag
!= GCOV_TAG_PROGRAM_SUMMARY
274 && tag
!= GCOV_TAG_PLACEHOLDER_SUMMARY
275 && tag
!= GCOV_TAG_INCORRECT_SUMMARY
)
277 if (gcov_read_summary (da_file
, &local_prg
))
279 if (local_prg
.checksum
!= program
.checksum
)
281 if (tag
== GCOV_TAG_PLACEHOLDER_SUMMARY
)
284 "profiling:%s:Concurrent race detected\n",
289 if (tag
!= GCOV_TAG_PROGRAM_SUMMARY
)
293 && memcmp (&program
, &local_prg
, sizeof (program
)))
295 fprintf (stderr
, "profiling:%s:Invocation mismatch\n",
300 memcpy (&program
, &local_prg
, sizeof (program
));
304 fseek (da_file
, 0, SEEK_SET
);
308 object
.arcs
= ptr
->counter_sections
[arc_data_index
].n_counters
;
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
;
314 /* Write out the data. */
316 gcov_write_unsigned (da_file
, GCOV_DATA_MAGIC
)
318 || gcov_write_unsigned (da_file
, GCOV_VERSION
))
322 fprintf (stderr
, "profiling:%s:Error writing\n", ptr
->filename
);
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
++)
332 /* Announce function. */
333 if (gcov_write_unsigned (da_file
, GCOV_TAG_FUNCTION
)
334 || !(base
= gcov_reserve_length (da_file
))
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
))
344 for (f_sect_index
= 0;
345 f_sect_index
< fn_info
->n_counter_sections
;
348 tag
= fn_info
->counter_sections
[f_sect_index
].tag
;
350 sect_index
< ptr
->n_counter_sections
;
352 if (ptr
->counter_sections
[sect_index
].tag
== tag
)
354 if (sect_index
== ptr
->n_counter_sections
)
357 if (gcov_write_unsigned (da_file
, tag
)
358 || !(base
= gcov_reserve_length (da_file
)))
361 for (jx
= fn_info
->counter_sections
[f_sect_index
].n_counters
; jx
--;)
363 gcov_type count
= *counters
[sect_index
]++;
365 if (tag
== GCOV_TAG_ARC_COUNTS
)
367 object
.arc_sum
+= count
;
368 if (object
.arc_max_sum
< count
)
369 object
.arc_max_sum
= count
;
371 if (gcov_write_counter (da_file
, count
))
372 goto write_error
; /* RIP Edsger Dijkstra */
374 if (gcov_write_length (da_file
, base
))
379 /* Object file summary. */
380 if (gcov_write_summary (da_file
, GCOV_TAG_OBJECT_SUMMARY
, &object
))
385 if (fseek (da_file
, 0, SEEK_END
))
387 ptr
->wkspc
= ftell (da_file
);
388 if (gcov_write_summary (da_file
, GCOV_TAG_PLACEHOLDER_SUMMARY
,
394 /* Zap trailing program summary */
395 if (fseek (da_file
, ptr
->wkspc
, SEEK_SET
))
399 if (gcov_write_unsigned (da_file
,
400 local_prg
.runs
? GCOV_TAG_PLACEHOLDER_SUMMARY
401 : GCOV_TAG_INCORRECT_SUMMARY
))
404 if (fflush (da_file
))
407 if (fclose (da_file
))
409 fprintf (stderr
, "profiling:%s:Error closing\n", ptr
->filename
);
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
;
422 /* Generate whole program statistics. */
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
;
432 /* Upate whole program statistics. */
433 for (ptr
= gcov_list
; ptr
; ptr
= ptr
->next
)
434 if (ptr
->filename
&& ptr
->wkspc
)
438 da_file
= fopen (ptr
->filename
, "r+b");
441 fprintf (stderr
, "profiling:%s:Cannot open\n", ptr
->filename
);
445 #if defined (TARGET_HAS_F_SETLKW)
446 while (fcntl (fileno (da_file
), F_SETLKW
, &s_flock
)
450 if (fseek (da_file
, ptr
->wkspc
, SEEK_SET
)
451 || gcov_write_summary (da_file
, GCOV_TAG_PROGRAM_SUMMARY
, &program
)
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
);
459 /* Add a new object file onto the bb chain. Invoked automatically
460 when running an object file's global ctors. */
463 __gcov_init (struct gcov_info
*info
)
467 if (info
->version
!= GCOV_VERSION
)
468 gcov_version_mismatch (info
, info
->version
);
471 const char *ptr
= info
->filename
;
472 unsigned crc32
= gcov_crc32
;
477 unsigned value
= *ptr
<< 24;
479 for (ix
= 8; ix
--; value
<<= 1)
483 feedback
= (value
^ crc32
) & 0x80000000 ? 0x04c11db7 : 0;
495 info
->next
= gcov_list
;
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. */
508 struct gcov_info
*ptr
;
511 for (ptr
= gcov_list
; ptr
; ptr
= ptr
->next
)
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;