]> gcc.gnu.org Git - gcc.git/blame - gcc/libgcov.c
re PR rtl-optimization/10339 ([sparc,ppc,ppc64] Invalid optimization: replacing strnc...
[gcc.git] / gcc / libgcov.c
CommitLineData
23af32e6
NS
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
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13In addition to the permissions in the GNU General Public License, the
14Free Software Foundation gives you unlimited permission to link the
15compiled version of this file into combinations with other programs,
16and to distribute those combinations without any restriction coming
17from the use of this file. (The General Public License restrictions
18do apply in other respects; for example, they cover modification of
19the file, and distribution when not linked into a combine
20executable.)
21
22GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23WARRANTY; without even the implied warranty of MERCHANTABILITY or
24FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received a copy of the GNU General Public License
28along with GCC; see the file COPYING. If not, write to the Free
29Software Foundation, 59 Temple Place - Suite 330, Boston, MA
3002111-1307, USA. */
31
01e60c33
JJ
32#if defined(inhibit_libc)
33/* If libc and its header files are not available, provide dummy functions. */
34
35void __gcov_init (void *p);
36void __gcov_flush (void);
37
38void __gcov_init (void *p) { }
39void __gcov_flush (void) { }
40
41#else
42
23af32e6
NS
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
23af32e6
NS
55#include <string.h>
56#if defined (TARGET_HAS_F_SETLKW)
57#include <fcntl.h>
58#include <errno.h>
59#endif
546d2adb 60#define IN_LIBGCOV 1
ec4a0419 61#include "gcov-io.h"
ca29da43 62#include "gcov-io.c"
23af32e6
NS
63
64/* Chain of per-object gcov structures. */
65static 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. */
69static unsigned gcov_crc32;
70
71static void
72gcov_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
96static void
97gcov_exit (void)
98{
99 struct gcov_info *ptr;
100 unsigned ix, jx;
23af32e6 101 gcov_type program_max_one = 0;
23af32e6
NS
102 gcov_type program_sum = 0;
103 unsigned program_arcs = 0;
d101590b 104 struct gcov_summary last_prg;
23af32e6 105
d101590b
JH
106 last_prg.runs = 0;
107
108 for (ptr = gcov_list; ptr; ptr = ptr->next)
109 {
110 unsigned arc_data_index;
111 gcov_type *count_ptr;
112
113 if (!ptr->filename)
114 continue;
115
116 for (arc_data_index = 0;
117 arc_data_index < ptr->n_counter_sections
118 && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
119 arc_data_index++)
120 continue;
121
122 for (ix = ptr->counter_sections[arc_data_index].n_counters,
123 count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
124 {
125 gcov_type count = *count_ptr++;
126
127 if (count > program_max_one)
128 program_max_one = count;
129 program_sum += count;
130 }
131 program_arcs += ptr->counter_sections[arc_data_index].n_counters;
132 }
23af32e6
NS
133 for (ptr = gcov_list; ptr; ptr = ptr->next)
134 {
23af32e6
NS
135 struct gcov_summary object;
136 struct gcov_summary local_prg;
94de45d9 137 int error;
546d2adb 138 int merging;
94de45d9 139 unsigned long base;
ca29da43 140 const struct gcov_function_info *fn_info;
cb9e4555 141 gcov_type **counters;
23af32e6
NS
142 gcov_type *count_ptr;
143 gcov_type object_max_one = 0;
94de45d9 144 unsigned tag, length;
cb9e4555 145 unsigned arc_data_index, f_sect_index, sect_index;
d101590b 146 long summary_pos = 0;
23af32e6 147
23af32e6
NS
148 if (!ptr->filename)
149 continue;
150
cb9e4555
ZD
151 counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
152 for (ix = 0; ix < ptr->n_counter_sections; ix++)
153 counters[ix] = ptr->counter_sections[ix].counters;
154
155 for (arc_data_index = 0;
156 arc_data_index < ptr->n_counter_sections
157 && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
158 arc_data_index++)
159 continue;
160
161 if (arc_data_index == ptr->n_counter_sections)
162 {
163 /* For now; later we may want to just measure other profiles,
164 but now I am lazy to check for all consequences. */
165 abort ();
166 }
167 for (ix = ptr->counter_sections[arc_data_index].n_counters,
168 count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
23af32e6
NS
169 {
170 gcov_type count = *count_ptr++;
171
172 if (count > object_max_one)
173 object_max_one = count;
174 }
23af32e6
NS
175
176 memset (&local_prg, 0, sizeof (local_prg));
177 memset (&object, 0, sizeof (object));
178
179 /* Open for modification */
546d2adb
NS
180 merging = gcov_open (ptr->filename, 0);
181
182 if (!merging)
23af32e6
NS
183 {
184 fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
185 ptr->filename = 0;
186 continue;
187 }
546d2adb
NS
188
189 if (merging > 0)
23af32e6
NS
190 {
191 /* Merge data from file. */
94de45d9 192 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
23af32e6
NS
193 {
194 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
195 ptr->filename);
196 read_fatal:;
546d2adb 197 gcov_close ();
23af32e6
NS
198 ptr->filename = 0;
199 continue;
200 }
94de45d9
NS
201 length = gcov_read_unsigned ();
202 if (length != GCOV_VERSION)
23af32e6
NS
203 {
204 gcov_version_mismatch (ptr, length);
205 goto read_fatal;
206 }
207
208 /* Merge execution counts for each function. */
23af32e6
NS
209 for (ix = ptr->n_functions, fn_info = ptr->functions;
210 ix--; fn_info++)
211 {
94de45d9
NS
212 tag = gcov_read_unsigned ();
213 length = gcov_read_unsigned ();
23af32e6
NS
214
215 /* Check function */
216 if (tag != GCOV_TAG_FUNCTION)
217 {
218 read_mismatch:;
219 fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
220 ptr->filename, fn_info->name);
221 goto read_fatal;
222 }
cb9e4555 223
94de45d9
NS
224 if (strcmp (gcov_read_string (), fn_info->name)
225 || gcov_read_unsigned () != fn_info->checksum)
23af32e6 226 goto read_mismatch;
cb9e4555
ZD
227
228 /* Counters. */
229 for (f_sect_index = 0;
230 f_sect_index < fn_info->n_counter_sections;
231 f_sect_index++)
232 {
ec4a0419
ZD
233 unsigned n_counters;
234
94de45d9
NS
235 tag = gcov_read_unsigned ();
236 length = gcov_read_unsigned ();
237
cb9e4555
ZD
238 for (sect_index = 0;
239 sect_index < ptr->n_counter_sections;
240 sect_index++)
241 if (ptr->counter_sections[sect_index].tag == tag)
242 break;
ec4a0419
ZD
243 if (sect_index == ptr->n_counter_sections
244 || fn_info->counter_sections[f_sect_index].tag != tag)
cb9e4555 245 goto read_mismatch;
ec4a0419
ZD
246
247 n_counters = fn_info->counter_sections[f_sect_index].n_counters;
248 if (n_counters != length / 8)
249 goto read_mismatch;
250
251 for (jx = 0; jx < n_counters; jx++)
94de45d9
NS
252 counters[sect_index][jx] += gcov_read_counter ();
253
ec4a0419 254 counters[sect_index] += n_counters;
cb9e4555 255 }
94de45d9
NS
256 if ((error = gcov_is_error ()))
257 goto read_error;
23af32e6
NS
258 }
259
260 /* Check object summary */
94de45d9 261 if (gcov_read_unsigned () != GCOV_TAG_OBJECT_SUMMARY)
23af32e6 262 goto read_mismatch;
94de45d9
NS
263 gcov_read_unsigned ();
264 gcov_read_summary (&object);
23af32e6
NS
265
266 /* Check program summary */
94de45d9 267 while (!gcov_is_eof ())
23af32e6 268 {
94de45d9 269 unsigned long base = gcov_position ();
23af32e6 270
94de45d9
NS
271 tag = gcov_read_unsigned ();
272 gcov_read_unsigned ();
d101590b 273 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
23af32e6 274 goto read_mismatch;
94de45d9
NS
275 gcov_read_summary (&local_prg);
276 if ((error = gcov_is_error ()))
277 {
278 read_error:;
279 fprintf (stderr, error < 0 ?
280 "profiling:%s:Overflow merging\n" :
281 "profiling:%s:Error merging\n",
282 ptr->filename);
283 goto read_fatal;
284 }
285
d101590b 286 if (local_prg.checksum != gcov_crc32)
23af32e6 287 {
d101590b
JH
288 memset (&local_prg, 0, sizeof (local_prg));
289 continue;
23af32e6 290 }
546d2adb 291 merging = 0;
23af32e6
NS
292 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
293 break;
294
d101590b
JH
295 /* If everything done correctly, the summaries should be
296 computed equal for each module. */
297 if (last_prg.runs
298#ifdef TARGET_HAS_F_SETLKW
299 && last_prg.runs == local_prg.runs
300#endif
301 && memcmp (&last_prg, &local_prg, sizeof (last_prg)))
23af32e6 302 {
d101590b
JH
303#ifdef TARGET_HAS_F_SETLKW
304 fprintf (stderr, "profiling:%s:Invocation mismatch\n\
305Probably some files were removed\n",
306 ptr->filename);
307#else
308 fprintf (stderr, "profiling:%s:Invocation mismatch\n\
309Probably some files were removed or parallel race happent because libgcc\n\
310is compiled without file locking support.\n",
23af32e6 311 ptr->filename);
d101590b 312#endif
23af32e6
NS
313 local_prg.runs = 0;
314 }
315 else
d101590b
JH
316 memcpy (&last_prg, &local_prg, sizeof (last_prg));
317 summary_pos = base;
23af32e6
NS
318 break;
319 }
94de45d9 320 gcov_seek (0, 0);
23af32e6
NS
321 }
322
323 object.runs++;
cb9e4555 324 object.arcs = ptr->counter_sections[arc_data_index].n_counters;
23af32e6
NS
325 object.arc_sum = 0;
326 if (object.arc_max_one < object_max_one)
327 object.arc_max_one = object_max_one;
328 object.arc_sum_max += object_max_one;
329
330 /* Write out the data. */
94de45d9
NS
331 gcov_write_unsigned (GCOV_DATA_MAGIC);
332 gcov_write_unsigned (GCOV_VERSION);
23af32e6
NS
333
334 /* Write execution counts for each function. */
cb9e4555
ZD
335 for (ix = 0; ix < ptr->n_counter_sections; ix++)
336 counters[ix] = ptr->counter_sections[ix].counters;
23af32e6
NS
337 for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
338 {
339 /* Announce function. */
94de45d9
NS
340 base = gcov_write_tag (GCOV_TAG_FUNCTION);
341 gcov_write_string (fn_info->name);
342 gcov_write_unsigned (fn_info->checksum);
343 gcov_write_length (base);
cb9e4555
ZD
344
345 /* counters. */
346 for (f_sect_index = 0;
347 f_sect_index < fn_info->n_counter_sections;
348 f_sect_index++)
23af32e6 349 {
cb9e4555
ZD
350 tag = fn_info->counter_sections[f_sect_index].tag;
351 for (sect_index = 0;
352 sect_index < ptr->n_counter_sections;
353 sect_index++)
354 if (ptr->counter_sections[sect_index].tag == tag)
355 break;
356 if (sect_index == ptr->n_counter_sections)
357 abort ();
358
94de45d9 359 base = gcov_write_tag (tag);
cb9e4555
ZD
360 for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
361 {
362 gcov_type count = *counters[sect_index]++;
23af32e6 363
cb9e4555
ZD
364 if (tag == GCOV_TAG_ARC_COUNTS)
365 {
366 object.arc_sum += count;
cb9e4555 367 }
94de45d9 368 gcov_write_counter (count);
cb9e4555 369 }
94de45d9 370 gcov_write_length (base);
23af32e6 371 }
23af32e6
NS
372 }
373
374 /* Object file summary. */
94de45d9 375 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
23af32e6 376
d101590b
JH
377 /* Generate whole program statistics. */
378 local_prg.runs++;
379 local_prg.checksum = gcov_crc32;
380 local_prg.arcs = program_arcs;
381 local_prg.arc_sum += program_sum;
382 if (local_prg.arc_max_one < program_max_one)
383 local_prg.arc_max_one = program_max_one;
384 local_prg.arc_sum_max += program_max_one;
385
546d2adb 386 if (merging)
23af32e6 387 {
d101590b
JH
388 gcov_seek_end ();
389 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg);
23af32e6 390 }
d101590b 391 else if (summary_pos)
23af32e6
NS
392 {
393 /* Zap trailing program summary */
d101590b 394 gcov_seek (summary_pos, 0);
23af32e6
NS
395 if (!local_prg.runs)
396 ptr->wkspc = 0;
d101590b 397 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg);
23af32e6 398 }
546d2adb 399 if (gcov_close ())
23af32e6 400 {
94de45d9 401 fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
23af32e6
NS
402 ptr->filename = 0;
403 }
23af32e6 404 }
d101590b
JH
405 /* All statistic we gather can be done in one pass trought the file.
406 Originally we did two - one for counts and other for the statistics. This
407 brings problem with the file locking interface, but it is possible to
408 implement so if need appears in the future - first pass updates local
409 statistics and number of runs. Second pass then overwrite global
410 statistics only when number of runs match. */
23af32e6
NS
411}
412
413/* Add a new object file onto the bb chain. Invoked automatically
414 when running an object file's global ctors. */
415
416void
417__gcov_init (struct gcov_info *info)
418{
419 if (!info->version)
420 return;
421 if (info->version != GCOV_VERSION)
422 gcov_version_mismatch (info, info->version);
423 else
424 {
425 const char *ptr = info->filename;
426 unsigned crc32 = gcov_crc32;
427
428 do
429 {
430 unsigned ix;
431 unsigned value = *ptr << 24;
432
433 for (ix = 8; ix--; value <<= 1)
434 {
435 unsigned feedback;
436
437 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
438 crc32 <<= 1;
439 crc32 ^= feedback;
440 }
441 }
442 while (*ptr++);
443
444 gcov_crc32 = crc32;
445
446 if (!gcov_list)
447 atexit (gcov_exit);
448
449 info->next = gcov_list;
450 gcov_list = info;
451 }
452 info->version = 0;
453}
454
455/* Called before fork or exec - write out profile information gathered so
456 far and reset it to zero. This avoids duplication or loss of the
457 profile information gathered so far. */
458
459void
460__gcov_flush (void)
461{
462 struct gcov_info *ptr;
463
464 gcov_exit ();
465 for (ptr = gcov_list; ptr; ptr = ptr->next)
466 {
cb9e4555 467 unsigned i, j;
23af32e6 468
cb9e4555
ZD
469 for (j = 0; j < ptr->n_counter_sections; j++)
470 for (i = ptr->counter_sections[j].n_counters; i--;)
471 ptr->counter_sections[j].counters[i] = 0;
23af32e6
NS
472 }
473}
01e60c33
JJ
474
475#endif /* inhibit_libc */
This page took 0.182785 seconds and 5 git commands to generate.