libgcov-driver.c revision 1.1.1.11 1 1.1 mrg /* Routines required for instrumenting a program. */
2 1.1 mrg /* Compile this one with gcc. */
3 1.1.1.11 mrg /* Copyright (C) 1989-2024 Free Software Foundation, Inc.
4 1.1 mrg
5 1.1 mrg This file is part of GCC.
6 1.1 mrg
7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under
8 1.1 mrg the terms of the GNU General Public License as published by the Free
9 1.1 mrg Software Foundation; either version 3, or (at your option) any later
10 1.1 mrg version.
11 1.1 mrg
12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 1.1 mrg for more details.
16 1.1 mrg
17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
18 1.1 mrg permissions described in the GCC Runtime Library Exception, version
19 1.1 mrg 3.1, as published by the Free Software Foundation.
20 1.1 mrg
21 1.1 mrg You should have received a copy of the GNU General Public License and
22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1 mrg <http://www.gnu.org/licenses/>. */
25 1.1 mrg
26 1.1 mrg #include "libgcov.h"
27 1.1.1.8 mrg #include "gcov-io.h"
28 1.1 mrg
29 1.1.1.10 mrg /* Return 1, if all counter values are zero, otherwise 0. */
30 1.1.1.10 mrg
31 1.1.1.10 mrg static inline int
32 1.1.1.10 mrg are_all_counters_zero (const struct gcov_ctr_info *ci_ptr)
33 1.1.1.10 mrg {
34 1.1.1.10 mrg for (unsigned i = 0; i < ci_ptr->num; i++)
35 1.1.1.10 mrg if (ci_ptr->values[i] != 0)
36 1.1.1.10 mrg return 0;
37 1.1.1.10 mrg
38 1.1.1.10 mrg return 1;
39 1.1.1.10 mrg }
40 1.1.1.10 mrg
41 1.1 mrg #if defined(inhibit_libc)
42 1.1 mrg /* If libc and its header files are not available, provide dummy functions. */
43 1.1 mrg
44 1.1 mrg #if defined(L_gcov)
45 1.1 mrg void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
46 1.1 mrg #endif
47 1.1 mrg
48 1.1 mrg #else /* inhibit_libc */
49 1.1 mrg
50 1.1 mrg #if GCOV_LOCKED
51 1.1 mrg #include <fcntl.h>
52 1.1 mrg #include <errno.h>
53 1.1 mrg #include <sys/stat.h>
54 1.1.1.10 mrg #elif GCOV_LOCKED_WITH_LOCKING
55 1.1.1.10 mrg #include <fcntl.h>
56 1.1.1.10 mrg #include <sys/locking.h>
57 1.1.1.10 mrg #include <sys/stat.h>
58 1.1.1.10 mrg #endif
59 1.1.1.10 mrg
60 1.1.1.10 mrg #if HAVE_SYS_MMAN_H
61 1.1.1.10 mrg #include <sys/mman.h>
62 1.1.1.10 mrg #endif
63 1.1.1.10 mrg
64 1.1.1.10 mrg #endif /* inhibit_libc */
65 1.1.1.10 mrg
66 1.1.1.10 mrg #if defined(L_gcov) && !defined(inhibit_libc)
67 1.1.1.10 mrg #define NEED_L_GCOV
68 1.1 mrg #endif
69 1.1 mrg
70 1.1.1.10 mrg #if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL
71 1.1.1.10 mrg #define NEED_L_GCOV_INFO_TO_GCDA
72 1.1.1.10 mrg #endif
73 1.1 mrg
74 1.1.1.10 mrg #ifdef NEED_L_GCOV
75 1.1.1.4 mrg /* A utility function for outputting errors. */
76 1.1 mrg static int gcov_error (const char *, ...);
77 1.1 mrg
78 1.1.1.4 mrg #if !IN_GCOV_TOOL
79 1.1.1.4 mrg static void gcov_error_exit (void);
80 1.1.1.4 mrg #endif
81 1.1.1.4 mrg
82 1.1.1.10 mrg #include "gcov-io.cc"
83 1.1 mrg
84 1.1.1.8 mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
85 1.1.1.8 mrg
86 1.1 mrg struct gcov_fn_buffer
87 1.1 mrg {
88 1.1 mrg struct gcov_fn_buffer *next;
89 1.1 mrg unsigned fn_ix;
90 1.1 mrg struct gcov_fn_info info;
91 1.1 mrg /* note gcov_fn_info ends in a trailing array. */
92 1.1 mrg };
93 1.1 mrg
94 1.1 mrg struct gcov_summary_buffer
95 1.1 mrg {
96 1.1 mrg struct gcov_summary_buffer *next;
97 1.1 mrg struct gcov_summary summary;
98 1.1 mrg };
99 1.1 mrg
100 1.1 mrg /* A struct that bundles all the related information about the
101 1.1 mrg gcda filename. */
102 1.1 mrg
103 1.1 mrg struct gcov_filename
104 1.1 mrg {
105 1.1 mrg char *filename; /* filename buffer */
106 1.1 mrg int strip; /* leading chars to strip from filename */
107 1.1.1.8 mrg char *prefix; /* prefix string */
108 1.1 mrg };
109 1.1 mrg
110 1.1 mrg static struct gcov_fn_buffer *
111 1.1 mrg free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
112 1.1 mrg unsigned limit)
113 1.1 mrg {
114 1.1 mrg struct gcov_fn_buffer *next;
115 1.1 mrg unsigned ix, n_ctr = 0;
116 1.1 mrg
117 1.1 mrg if (!buffer)
118 1.1 mrg return 0;
119 1.1 mrg next = buffer->next;
120 1.1 mrg
121 1.1 mrg for (ix = 0; ix != limit; ix++)
122 1.1 mrg if (gi_ptr->merge[ix])
123 1.1 mrg free (buffer->info.ctrs[n_ctr++].values);
124 1.1 mrg free (buffer);
125 1.1 mrg return next;
126 1.1 mrg }
127 1.1 mrg
128 1.1 mrg static struct gcov_fn_buffer **
129 1.1 mrg buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
130 1.1 mrg struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
131 1.1 mrg {
132 1.1 mrg unsigned n_ctrs = 0, ix = 0;
133 1.1 mrg struct gcov_fn_buffer *fn_buffer;
134 1.1 mrg unsigned len;
135 1.1 mrg
136 1.1 mrg for (ix = GCOV_COUNTERS; ix--;)
137 1.1 mrg if (gi_ptr->merge[ix])
138 1.1 mrg n_ctrs++;
139 1.1 mrg
140 1.1 mrg len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
141 1.1 mrg fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
142 1.1 mrg
143 1.1 mrg if (!fn_buffer)
144 1.1 mrg goto fail;
145 1.1 mrg
146 1.1 mrg fn_buffer->next = 0;
147 1.1 mrg fn_buffer->fn_ix = fn_ix;
148 1.1 mrg fn_buffer->info.ident = gcov_read_unsigned ();
149 1.1 mrg fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
150 1.1 mrg fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
151 1.1 mrg
152 1.1 mrg for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
153 1.1 mrg {
154 1.1 mrg gcov_unsigned_t length;
155 1.1 mrg gcov_type *values;
156 1.1 mrg
157 1.1 mrg if (!gi_ptr->merge[ix])
158 1.1 mrg continue;
159 1.1 mrg
160 1.1 mrg if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
161 1.1 mrg {
162 1.1 mrg len = 0;
163 1.1 mrg goto fail;
164 1.1 mrg }
165 1.1 mrg
166 1.1 mrg length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
167 1.1 mrg len = length * sizeof (gcov_type);
168 1.1 mrg values = (gcov_type *) xmalloc (len);
169 1.1 mrg if (!values)
170 1.1 mrg goto fail;
171 1.1 mrg
172 1.1 mrg fn_buffer->info.ctrs[n_ctrs].num = length;
173 1.1 mrg fn_buffer->info.ctrs[n_ctrs].values = values;
174 1.1 mrg
175 1.1 mrg while (length--)
176 1.1 mrg *values++ = gcov_read_counter ();
177 1.1 mrg n_ctrs++;
178 1.1 mrg }
179 1.1 mrg
180 1.1 mrg *end_ptr = fn_buffer;
181 1.1 mrg return &fn_buffer->next;
182 1.1 mrg
183 1.1 mrg fail:
184 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
185 1.1 mrg len ? "cannot allocate" : "counter mismatch", len ? len : ix);
186 1.1 mrg
187 1.1 mrg return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
188 1.1 mrg }
189 1.1 mrg
190 1.1.1.8 mrg /* Convert VERSION into a string description and return the it.
191 1.1.1.8 mrg BUFFER is used for storage of the string. The code should be
192 1.1.1.8 mrg aligned wit gcov-iov.c. */
193 1.1.1.8 mrg
194 1.1.1.8 mrg static char *
195 1.1.1.8 mrg gcov_version_string (char *buffer, char version[4])
196 1.1.1.8 mrg {
197 1.1.1.8 mrg if (version[0] < 'A' || version[0] > 'Z'
198 1.1.1.8 mrg || version[1] < '0' || version[1] > '9'
199 1.1.1.8 mrg || version[2] < '0' || version[2] > '9')
200 1.1.1.8 mrg sprintf (buffer, "(unknown)");
201 1.1.1.8 mrg else
202 1.1 mrg {
203 1.1.1.8 mrg unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
204 1.1.1.8 mrg unsigned minor = version[2] - '0';
205 1.1.1.8 mrg sprintf (buffer, "%u.%u (%s)", major, minor,
206 1.1.1.8 mrg version[3] == '*' ? "release" : "experimental");
207 1.1 mrg }
208 1.1.1.8 mrg return buffer;
209 1.1 mrg }
210 1.1 mrg
211 1.1 mrg /* Check if VERSION of the info block PTR matches libgcov one.
212 1.1 mrg Return 1 on success, or zero in case of versions mismatch.
213 1.1 mrg If FILENAME is not NULL, its value used for reporting purposes
214 1.1 mrg instead of value from the info block. */
215 1.1 mrg
216 1.1 mrg static int
217 1.1 mrg gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
218 1.1 mrg const char *filename)
219 1.1 mrg {
220 1.1 mrg if (version != GCOV_VERSION)
221 1.1 mrg {
222 1.1 mrg char v[4], e[4];
223 1.1.1.10 mrg char ver_string[128], expected_string[128];
224 1.1 mrg
225 1.1 mrg GCOV_UNSIGNED2STRING (v, version);
226 1.1 mrg GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
227 1.1 mrg
228 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
229 1.1.1.8 mrg "got %s (%.4s)\n",
230 1.1.1.8 mrg filename? filename : ptr->filename,
231 1.1.1.8 mrg gcov_version_string (expected_string, e), e,
232 1.1.1.10 mrg gcov_version_string (ver_string, v), v);
233 1.1 mrg return 0;
234 1.1 mrg }
235 1.1 mrg return 1;
236 1.1 mrg }
237 1.1 mrg
238 1.1 mrg /* buffer for the fn_data from another program. */
239 1.1 mrg static struct gcov_fn_buffer *fn_buffer;
240 1.1 mrg
241 1.1 mrg /* Including system dependent components. */
242 1.1 mrg #include "libgcov-driver-system.c"
243 1.1 mrg
244 1.1 mrg /* This function merges counters in GI_PTR to an existing gcda file.
245 1.1 mrg Return 0 on success.
246 1.1 mrg Return -1 on error. In this case, caller will goto read_fatal. */
247 1.1 mrg
248 1.1 mrg static int
249 1.1 mrg merge_one_data (const char *filename,
250 1.1 mrg struct gcov_info *gi_ptr,
251 1.1.1.8 mrg struct gcov_summary *summary)
252 1.1 mrg {
253 1.1 mrg gcov_unsigned_t tag, length;
254 1.1 mrg unsigned t_ix;
255 1.1.1.8 mrg int f_ix = -1;
256 1.1 mrg int error = 0;
257 1.1 mrg struct gcov_fn_buffer **fn_tail = &fn_buffer;
258 1.1 mrg
259 1.1 mrg length = gcov_read_unsigned ();
260 1.1 mrg if (!gcov_version (gi_ptr, length, filename))
261 1.1 mrg return -1;
262 1.1 mrg
263 1.1.1.10 mrg /* Skip timestamp. */
264 1.1.1.10 mrg gcov_read_unsigned ();
265 1.1.1.10 mrg
266 1.1 mrg length = gcov_read_unsigned ();
267 1.1.1.10 mrg if (length != gi_ptr->checksum)
268 1.1 mrg {
269 1.1.1.8 mrg /* Read from a different compilation. Overwrite the file. */
270 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
271 1.1.1.10 mrg "with a different checksum\n", filename);
272 1.1.1.8 mrg return 0;
273 1.1 mrg }
274 1.1 mrg
275 1.1.1.8 mrg tag = gcov_read_unsigned ();
276 1.1.1.8 mrg if (tag != GCOV_TAG_OBJECT_SUMMARY)
277 1.1.1.8 mrg goto read_mismatch;
278 1.1.1.8 mrg length = gcov_read_unsigned ();
279 1.1.1.8 mrg gcc_assert (length > 0);
280 1.1.1.8 mrg gcov_read_summary (summary);
281 1.1.1.8 mrg
282 1.1.1.8 mrg tag = gcov_read_unsigned ();
283 1.1 mrg /* Merge execution counts for each function. */
284 1.1 mrg for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
285 1.1 mrg f_ix++, tag = gcov_read_unsigned ())
286 1.1 mrg {
287 1.1 mrg const struct gcov_ctr_info *ci_ptr;
288 1.1 mrg const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
289 1.1 mrg
290 1.1 mrg if (tag != GCOV_TAG_FUNCTION)
291 1.1 mrg goto read_mismatch;
292 1.1 mrg
293 1.1 mrg length = gcov_read_unsigned ();
294 1.1 mrg if (!length)
295 1.1 mrg /* This function did not appear in the other program.
296 1.1 mrg We have nothing to merge. */
297 1.1 mrg continue;
298 1.1 mrg
299 1.1 mrg if (length != GCOV_TAG_FUNCTION_LENGTH)
300 1.1 mrg goto read_mismatch;
301 1.1 mrg
302 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gi_ptr)
303 1.1 mrg {
304 1.1 mrg /* This function appears in the other program. We
305 1.1 mrg need to buffer the information in order to write
306 1.1 mrg it back out -- we'll be inserting data before
307 1.1 mrg this point, so cannot simply keep the data in the
308 1.1 mrg file. */
309 1.1 mrg fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
310 1.1 mrg if (!fn_tail)
311 1.1 mrg goto read_mismatch;
312 1.1 mrg continue;
313 1.1 mrg }
314 1.1 mrg
315 1.1 mrg length = gcov_read_unsigned ();
316 1.1 mrg if (length != gfi_ptr->ident)
317 1.1 mrg goto read_mismatch;
318 1.1 mrg
319 1.1 mrg length = gcov_read_unsigned ();
320 1.1 mrg if (length != gfi_ptr->lineno_checksum)
321 1.1 mrg goto read_mismatch;
322 1.1 mrg
323 1.1 mrg length = gcov_read_unsigned ();
324 1.1 mrg if (length != gfi_ptr->cfg_checksum)
325 1.1 mrg goto read_mismatch;
326 1.1 mrg
327 1.1 mrg ci_ptr = gfi_ptr->ctrs;
328 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
329 1.1 mrg {
330 1.1 mrg gcov_merge_fn merge = gi_ptr->merge[t_ix];
331 1.1 mrg
332 1.1 mrg if (!merge)
333 1.1 mrg continue;
334 1.1 mrg
335 1.1.1.10 mrg tag = gcov_read_unsigned ();
336 1.1.1.10 mrg int read_length = (int)gcov_read_unsigned ();
337 1.1.1.10 mrg length = abs (read_length);
338 1.1.1.10 mrg if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
339 1.1.1.10 mrg || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num)
340 1.1.1.10 mrg && t_ix != GCOV_COUNTER_V_TOPN
341 1.1.1.10 mrg && t_ix != GCOV_COUNTER_V_INDIR))
342 1.1.1.10 mrg goto read_mismatch;
343 1.1.1.10 mrg /* Merging with all zero counters does not make sense. */
344 1.1.1.10 mrg if (read_length > 0)
345 1.1.1.10 mrg (*merge) (ci_ptr->values, ci_ptr->num);
346 1.1.1.10 mrg ci_ptr++;
347 1.1.1.10 mrg }
348 1.1 mrg if ((error = gcov_is_error ()))
349 1.1.1.10 mrg goto read_error;
350 1.1 mrg }
351 1.1 mrg
352 1.1 mrg if (tag)
353 1.1 mrg {
354 1.1 mrg read_mismatch:;
355 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
356 1.1 mrg filename, f_ix >= 0 ? "function" : "summary",
357 1.1 mrg f_ix < 0 ? -1 - f_ix : f_ix);
358 1.1 mrg return -1;
359 1.1 mrg }
360 1.1 mrg return 0;
361 1.1 mrg
362 1.1 mrg read_error:
363 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
364 1.1 mrg error < 0 ? "Overflow": "Error");
365 1.1 mrg return -1;
366 1.1 mrg }
367 1.1 mrg
368 1.1.1.10 mrg /* Write the DATA of LENGTH characters to the gcov file. */
369 1.1.1.10 mrg
370 1.1.1.10 mrg static void
371 1.1.1.10 mrg gcov_dump_handler (const void *data,
372 1.1.1.10 mrg unsigned length,
373 1.1.1.10 mrg void *arg ATTRIBUTE_UNUSED)
374 1.1.1.10 mrg {
375 1.1.1.10 mrg gcov_write (data, length);
376 1.1.1.10 mrg }
377 1.1.1.10 mrg
378 1.1.1.10 mrg /* Allocate SIZE characters and return the address of the allocated memory. */
379 1.1.1.10 mrg
380 1.1.1.10 mrg static void *
381 1.1.1.10 mrg gcov_allocate_handler (unsigned size, void *arg ATTRIBUTE_UNUSED)
382 1.1.1.10 mrg {
383 1.1.1.10 mrg return xmalloc (size);
384 1.1.1.10 mrg }
385 1.1.1.10 mrg #endif /* NEED_L_GCOV */
386 1.1.1.10 mrg
387 1.1.1.10 mrg #if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
388 1.1.1.10 mrg /* Dump the WORD using the DUMP handler called with ARG. */
389 1.1.1.10 mrg
390 1.1.1.10 mrg static inline void
391 1.1.1.10 mrg dump_unsigned (gcov_unsigned_t word,
392 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
393 1.1.1.10 mrg void *arg)
394 1.1.1.10 mrg {
395 1.1.1.10 mrg (*dump_fn) (&word, sizeof (word), arg);
396 1.1.1.10 mrg }
397 1.1.1.10 mrg
398 1.1.1.10 mrg /* Dump the COUNTER using the DUMP handler called with ARG. */
399 1.1.1.10 mrg
400 1.1.1.10 mrg static inline void
401 1.1.1.10 mrg dump_counter (gcov_type counter,
402 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
403 1.1.1.10 mrg void *arg)
404 1.1.1.10 mrg {
405 1.1.1.10 mrg dump_unsigned ((gcov_unsigned_t)counter, dump_fn, arg);
406 1.1.1.10 mrg
407 1.1.1.10 mrg if (sizeof (counter) > sizeof (gcov_unsigned_t))
408 1.1.1.10 mrg dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg);
409 1.1.1.10 mrg else
410 1.1.1.10 mrg dump_unsigned (0, dump_fn, arg);
411 1.1.1.10 mrg }
412 1.1.1.10 mrg
413 1.1.1.11 mrg /* Dump the STRING using the DUMP handler called with ARG. */
414 1.1.1.11 mrg
415 1.1.1.11 mrg static inline void
416 1.1.1.11 mrg ATTRIBUTE_UNUSED
417 1.1.1.11 mrg dump_string (const char *string,
418 1.1.1.11 mrg void (*dump_fn) (const void *, unsigned, void *),
419 1.1.1.11 mrg void *arg)
420 1.1.1.11 mrg {
421 1.1.1.11 mrg unsigned length = 0;
422 1.1.1.11 mrg
423 1.1.1.11 mrg if (string)
424 1.1.1.11 mrg length = strlen (string) + 1;
425 1.1.1.11 mrg
426 1.1.1.11 mrg dump_unsigned (length, dump_fn, arg);
427 1.1.1.11 mrg if (string)
428 1.1.1.11 mrg (*dump_fn) (string, length, arg);
429 1.1.1.11 mrg }
430 1.1.1.11 mrg
431 1.1.1.10 mrg #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
432 1.1.1.10 mrg
433 1.1.1.10 mrg /* Store all TOP N counters where each has a dynamic length. */
434 1.1.1.10 mrg
435 1.1.1.10 mrg static void
436 1.1.1.10 mrg write_topn_counters (const struct gcov_ctr_info *ci_ptr,
437 1.1.1.10 mrg unsigned t_ix,
438 1.1.1.10 mrg gcov_unsigned_t n_counts,
439 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
440 1.1.1.10 mrg void *(*allocate_fn)(unsigned, void *),
441 1.1.1.10 mrg void *arg)
442 1.1.1.10 mrg {
443 1.1.1.10 mrg unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
444 1.1.1.10 mrg gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
445 1.1.1.10 mrg
446 1.1.1.10 mrg /* It can happen in a multi-threaded environment that number of counters is
447 1.1.1.10 mrg different from the size of the corresponding linked lists. */
448 1.1.1.10 mrg #define LIST_SIZE_MIN_LENGTH 4 * 1024
449 1.1.1.10 mrg
450 1.1.1.10 mrg static unsigned *list_sizes = NULL;
451 1.1.1.10 mrg static unsigned list_size_length = 0;
452 1.1.1.10 mrg
453 1.1.1.10 mrg if (list_sizes == NULL || counters > list_size_length)
454 1.1.1.10 mrg {
455 1.1.1.10 mrg list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
456 1.1.1.10 mrg #if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
457 1.1.1.10 mrg list_sizes
458 1.1.1.10 mrg = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
459 1.1.1.10 mrg #endif
460 1.1.1.10 mrg
461 1.1.1.10 mrg /* Malloc fallback. */
462 1.1.1.10 mrg if (list_sizes == NULL)
463 1.1.1.10 mrg list_sizes =
464 1.1.1.10 mrg (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned),
465 1.1.1.10 mrg arg);
466 1.1.1.10 mrg }
467 1.1.1.10 mrg
468 1.1.1.10 mrg unsigned pair_total = 0;
469 1.1.1.10 mrg
470 1.1.1.10 mrg for (unsigned i = 0; i < counters; i++)
471 1.1.1.10 mrg {
472 1.1.1.10 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
473 1.1.1.10 mrg unsigned sizes = 0;
474 1.1.1.10 mrg
475 1.1.1.10 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start;
476 1.1.1.10 mrg node != NULL; node = node->next)
477 1.1.1.10 mrg ++sizes;
478 1.1.1.10 mrg
479 1.1.1.10 mrg pair_total += sizes;
480 1.1.1.10 mrg list_sizes[i] = sizes;
481 1.1.1.10 mrg }
482 1.1.1.10 mrg
483 1.1.1.10 mrg unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
484 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg),
485 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump_fn, arg);
486 1.1.1.10 mrg
487 1.1.1.10 mrg for (unsigned i = 0; i < counters; i++)
488 1.1.1.10 mrg {
489 1.1.1.10 mrg dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump_fn, arg);
490 1.1.1.10 mrg dump_counter (list_sizes[i], dump_fn, arg);
491 1.1.1.10 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
492 1.1.1.10 mrg
493 1.1.1.10 mrg unsigned j = 0;
494 1.1.1.10 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start;
495 1.1.1.10 mrg j < list_sizes[i]; node = node->next, j++)
496 1.1.1.10 mrg {
497 1.1.1.10 mrg dump_counter (node->value, dump_fn, arg);
498 1.1.1.10 mrg dump_counter (node->count, dump_fn, arg);
499 1.1.1.10 mrg }
500 1.1.1.10 mrg }
501 1.1.1.10 mrg }
502 1.1.1.10 mrg
503 1.1 mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
504 1.1 mrg the case of appending to an existing file, SUMMARY_POS will be non-zero.
505 1.1 mrg We will write the file starting from SUMMAY_POS. */
506 1.1 mrg
507 1.1 mrg static void
508 1.1 mrg write_one_data (const struct gcov_info *gi_ptr,
509 1.1.1.10 mrg const struct gcov_summary *prg_p ATTRIBUTE_UNUSED,
510 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
511 1.1.1.10 mrg void *(*allocate_fn) (unsigned, void *),
512 1.1.1.10 mrg void *arg)
513 1.1 mrg {
514 1.1 mrg unsigned f_ix;
515 1.1 mrg
516 1.1.1.10 mrg dump_unsigned (GCOV_DATA_MAGIC, dump_fn, arg);
517 1.1.1.10 mrg dump_unsigned (GCOV_VERSION, dump_fn, arg);
518 1.1.1.10 mrg dump_unsigned (gi_ptr->stamp, dump_fn, arg);
519 1.1.1.10 mrg dump_unsigned (gi_ptr->checksum, dump_fn, arg);
520 1.1 mrg
521 1.1.1.10 mrg #ifdef NEED_L_GCOV
522 1.1 mrg /* Generate whole program statistics. */
523 1.1.1.11 mrg gcov_write_object_summary (prg_p);
524 1.1.1.10 mrg #endif
525 1.1 mrg
526 1.1 mrg /* Write execution counts for each function. */
527 1.1 mrg for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
528 1.1 mrg {
529 1.1.1.10 mrg #ifdef NEED_L_GCOV
530 1.1 mrg unsigned buffered = 0;
531 1.1.1.10 mrg #endif
532 1.1 mrg const struct gcov_fn_info *gfi_ptr;
533 1.1 mrg const struct gcov_ctr_info *ci_ptr;
534 1.1 mrg gcov_unsigned_t length;
535 1.1 mrg unsigned t_ix;
536 1.1 mrg
537 1.1.1.10 mrg #ifdef NEED_L_GCOV
538 1.1 mrg if (fn_buffer && fn_buffer->fn_ix == f_ix)
539 1.1 mrg {
540 1.1 mrg /* Buffered data from another program. */
541 1.1 mrg buffered = 1;
542 1.1 mrg gfi_ptr = &fn_buffer->info;
543 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH;
544 1.1 mrg }
545 1.1 mrg else
546 1.1.1.10 mrg #endif
547 1.1 mrg {
548 1.1 mrg gfi_ptr = gi_ptr->functions[f_ix];
549 1.1 mrg if (gfi_ptr && gfi_ptr->key == gi_ptr)
550 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH;
551 1.1 mrg else
552 1.1 mrg length = 0;
553 1.1 mrg }
554 1.1 mrg
555 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FUNCTION, dump_fn, arg);
556 1.1.1.10 mrg dump_unsigned (length, dump_fn, arg);
557 1.1 mrg if (!length)
558 1.1 mrg continue;
559 1.1 mrg
560 1.1.1.10 mrg dump_unsigned (gfi_ptr->ident, dump_fn, arg);
561 1.1.1.10 mrg dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg);
562 1.1.1.10 mrg dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg);
563 1.1 mrg
564 1.1 mrg ci_ptr = gfi_ptr->ctrs;
565 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
566 1.1 mrg {
567 1.1.1.10 mrg gcov_position_t n_counts;
568 1.1 mrg
569 1.1.1.10 mrg if (!gi_ptr->merge[t_ix])
570 1.1.1.10 mrg continue;
571 1.1 mrg
572 1.1.1.10 mrg n_counts = ci_ptr->num;
573 1.1.1.10 mrg
574 1.1.1.10 mrg if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
575 1.1.1.10 mrg write_topn_counters (ci_ptr, t_ix, n_counts, dump_fn, allocate_fn,
576 1.1.1.10 mrg arg);
577 1.1.1.10 mrg else
578 1.1.1.10 mrg {
579 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg);
580 1.1.1.10 mrg if (are_all_counters_zero (ci_ptr))
581 1.1.1.10 mrg /* Do not stream when all counters are zero. */
582 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts),
583 1.1.1.10 mrg dump_fn, arg);
584 1.1.1.10 mrg else
585 1.1.1.10 mrg {
586 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts),
587 1.1.1.10 mrg dump_fn, arg);
588 1.1.1.10 mrg for (unsigned i = 0; i < n_counts; i++)
589 1.1.1.10 mrg dump_counter (ci_ptr->values[i], dump_fn, arg);
590 1.1.1.10 mrg }
591 1.1.1.10 mrg }
592 1.1.1.10 mrg
593 1.1.1.10 mrg ci_ptr++;
594 1.1.1.10 mrg }
595 1.1.1.10 mrg #ifdef NEED_L_GCOV
596 1.1 mrg if (buffered)
597 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
598 1.1.1.10 mrg #endif
599 1.1 mrg }
600 1.1 mrg
601 1.1.1.10 mrg dump_unsigned (0, dump_fn, arg);
602 1.1 mrg }
603 1.1.1.10 mrg #endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
604 1.1 mrg
605 1.1.1.10 mrg #ifdef NEED_L_GCOV
606 1.1 mrg /* Dump the coverage counts for one gcov_info object. We merge with existing
607 1.1 mrg counts when possible, to avoid growing the .da files ad infinitum. We use
608 1.1 mrg this program's checksum to make sure we only accumulate whole program
609 1.1 mrg statistics to the correct summary. An object file might be embedded
610 1.1 mrg in two separate programs, and we must keep the two program
611 1.1 mrg summaries separate. */
612 1.1 mrg
613 1.1 mrg static void
614 1.1 mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
615 1.1.1.10 mrg unsigned run_counted ATTRIBUTE_UNUSED,
616 1.1.1.11 mrg gcov_type run_max ATTRIBUTE_UNUSED, int mode)
617 1.1 mrg {
618 1.1.1.8 mrg struct gcov_summary summary = {};
619 1.1 mrg int error;
620 1.1 mrg gcov_unsigned_t tag;
621 1.1 mrg fn_buffer = 0;
622 1.1 mrg
623 1.1.1.11 mrg error = gcov_exit_open_gcda_file (gi_ptr, gf, mode);
624 1.1 mrg if (error == -1)
625 1.1 mrg return;
626 1.1 mrg
627 1.1 mrg tag = gcov_read_unsigned ();
628 1.1 mrg if (tag)
629 1.1 mrg {
630 1.1 mrg /* Merge data from file. */
631 1.1 mrg if (tag != GCOV_DATA_MAGIC)
632 1.1 mrg {
633 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
634 1.1.1.8 mrg gf->filename);
635 1.1 mrg goto read_fatal;
636 1.1 mrg }
637 1.1.1.8 mrg error = merge_one_data (gf->filename, gi_ptr, &summary);
638 1.1 mrg if (error == -1)
639 1.1 mrg goto read_fatal;
640 1.1 mrg }
641 1.1 mrg
642 1.1 mrg gcov_rewrite ();
643 1.1 mrg
644 1.1.1.10 mrg #if !IN_GCOV_TOOL
645 1.1.1.10 mrg if (!run_counted)
646 1.1.1.10 mrg {
647 1.1.1.10 mrg summary.runs++;
648 1.1.1.10 mrg summary.sum_max += run_max;
649 1.1.1.10 mrg }
650 1.1.1.10 mrg #else
651 1.1.1.10 mrg summary = gi_ptr->summary;
652 1.1.1.10 mrg #endif
653 1.1 mrg
654 1.1.1.10 mrg write_one_data (gi_ptr, &summary, gcov_dump_handler, gcov_allocate_handler,
655 1.1.1.10 mrg NULL);
656 1.1 mrg /* fall through */
657 1.1 mrg
658 1.1 mrg read_fatal:;
659 1.1 mrg while (fn_buffer)
660 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
661 1.1 mrg
662 1.1 mrg if ((error = gcov_close ()))
663 1.1.1.10 mrg gcov_error ((error < 0 ? GCOV_PROF_PREFIX "Overflow writing\n"
664 1.1.1.10 mrg : GCOV_PROF_PREFIX "Error writing\n"), gf->filename);
665 1.1 mrg }
666 1.1 mrg
667 1.1 mrg
668 1.1 mrg /* Dump all the coverage counts for the program. It first computes program
669 1.1 mrg summary and then traverses gcov_list list and dumps the gcov_info
670 1.1.1.11 mrg objects one by one. Use MODE to open files. */
671 1.1 mrg
672 1.1 mrg #if !IN_GCOV_TOOL
673 1.1 mrg static
674 1.1 mrg #endif
675 1.1 mrg void
676 1.1.1.11 mrg gcov_do_dump (struct gcov_info *list, int run_counted, int mode)
677 1.1 mrg {
678 1.1 mrg struct gcov_info *gi_ptr;
679 1.1 mrg struct gcov_filename gf;
680 1.1 mrg
681 1.1.1.8 mrg /* Compute run_max of this program run. */
682 1.1.1.8 mrg gcov_type run_max = 0;
683 1.1.1.8 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
684 1.1.1.8 mrg for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
685 1.1.1.8 mrg {
686 1.1.1.8 mrg const struct gcov_ctr_info *cinfo
687 1.1.1.8 mrg = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
688 1.1.1.8 mrg
689 1.1.1.8 mrg for (unsigned i = 0; i < cinfo->num; i++)
690 1.1.1.8 mrg if (run_max < cinfo->values[i])
691 1.1.1.8 mrg run_max = cinfo->values[i];
692 1.1.1.8 mrg }
693 1.1 mrg
694 1.1 mrg allocate_filename_struct (&gf);
695 1.1 mrg
696 1.1 mrg /* Now merge each file. */
697 1.1 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
698 1.1.1.8 mrg {
699 1.1.1.11 mrg dump_one_gcov (gi_ptr, &gf, run_counted, run_max, mode);
700 1.1.1.8 mrg free (gf.filename);
701 1.1.1.8 mrg }
702 1.1 mrg
703 1.1.1.8 mrg free (gf.prefix);
704 1.1 mrg }
705 1.1 mrg
706 1.1.1.2 mrg #if IN_GCOV_TOOL
707 1.1.1.2 mrg const char *
708 1.1.1.2 mrg __attribute__ ((unused))
709 1.1.1.2 mrg gcov_get_filename (struct gcov_info *list)
710 1.1.1.2 mrg {
711 1.1.1.2 mrg return list->filename;
712 1.1.1.2 mrg }
713 1.1.1.2 mrg #endif
714 1.1.1.2 mrg
715 1.1 mrg #if !IN_GCOV_TOOL
716 1.1 mrg void
717 1.1 mrg __gcov_dump_one (struct gcov_root *root)
718 1.1 mrg {
719 1.1 mrg if (root->dumped)
720 1.1 mrg return;
721 1.1 mrg
722 1.1.1.11 mrg gcov_do_dump (root->list, root->run_counted, 0);
723 1.1 mrg
724 1.1 mrg root->dumped = 1;
725 1.1 mrg root->run_counted = 1;
726 1.1 mrg }
727 1.1 mrg
728 1.1 mrg /* Per-dynamic-object gcov state. */
729 1.1 mrg struct gcov_root __gcov_root;
730 1.1 mrg
731 1.1 mrg /* Exactly one of these will be live in the process image. */
732 1.1 mrg struct gcov_master __gcov_master =
733 1.1 mrg {GCOV_VERSION, 0};
734 1.1 mrg
735 1.1.1.10 mrg /* Dynamic pool for gcov_kvp structures. */
736 1.1.1.10 mrg struct gcov_kvp *__gcov_kvp_dynamic_pool;
737 1.1.1.10 mrg
738 1.1.1.10 mrg /* Index into __gcov_kvp_dynamic_pool array. */
739 1.1.1.10 mrg unsigned __gcov_kvp_dynamic_pool_index;
740 1.1.1.10 mrg
741 1.1.1.10 mrg /* Size of _gcov_kvp_dynamic_pool array. */
742 1.1.1.10 mrg unsigned __gcov_kvp_dynamic_pool_size;
743 1.1.1.10 mrg
744 1.1.1.4 mrg void
745 1.1.1.4 mrg __gcov_exit (void)
746 1.1 mrg {
747 1.1 mrg __gcov_dump_one (&__gcov_root);
748 1.1 mrg if (__gcov_root.next)
749 1.1 mrg __gcov_root.next->prev = __gcov_root.prev;
750 1.1 mrg if (__gcov_root.prev)
751 1.1 mrg __gcov_root.prev->next = __gcov_root.next;
752 1.1 mrg else
753 1.1 mrg __gcov_master.root = __gcov_root.next;
754 1.1.1.4 mrg
755 1.1.1.4 mrg gcov_error_exit ();
756 1.1 mrg }
757 1.1 mrg
758 1.1 mrg /* Add a new object file onto the bb chain. Invoked automatically
759 1.1 mrg when running an object file's global ctors. */
760 1.1 mrg
761 1.1 mrg void
762 1.1 mrg __gcov_init (struct gcov_info *info)
763 1.1 mrg {
764 1.1 mrg if (!info->version || !info->n_functions)
765 1.1 mrg return;
766 1.1 mrg if (gcov_version (info, info->version, 0))
767 1.1 mrg {
768 1.1 mrg if (!__gcov_root.list)
769 1.1 mrg {
770 1.1 mrg /* Add to master list and at exit function. */
771 1.1 mrg if (gcov_version (NULL, __gcov_master.version, "<master>"))
772 1.1 mrg {
773 1.1 mrg __gcov_root.next = __gcov_master.root;
774 1.1 mrg if (__gcov_master.root)
775 1.1 mrg __gcov_master.root->prev = &__gcov_root;
776 1.1 mrg __gcov_master.root = &__gcov_root;
777 1.1 mrg }
778 1.1 mrg }
779 1.1 mrg
780 1.1 mrg info->next = __gcov_root.list;
781 1.1 mrg __gcov_root.list = info;
782 1.1 mrg }
783 1.1 mrg }
784 1.1 mrg #endif /* !IN_GCOV_TOOL */
785 1.1.1.10 mrg #endif /* NEED_L_GCOV */
786 1.1.1.10 mrg
787 1.1.1.10 mrg #ifdef NEED_L_GCOV_INFO_TO_GCDA
788 1.1.1.10 mrg /* Convert the gcov info to a gcda data stream. It is intended for
789 1.1.1.11 mrg freestanding environments which do not support the C library file I/O. */
790 1.1.1.10 mrg
791 1.1.1.10 mrg void
792 1.1.1.10 mrg __gcov_info_to_gcda (const struct gcov_info *gi_ptr,
793 1.1.1.10 mrg void (*filename_fn) (const char *, void *),
794 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
795 1.1.1.10 mrg void *(*allocate_fn) (unsigned, void *),
796 1.1.1.10 mrg void *arg)
797 1.1.1.10 mrg {
798 1.1.1.10 mrg (*filename_fn) (gi_ptr->filename, arg);
799 1.1.1.10 mrg write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg);
800 1.1.1.10 mrg }
801 1.1.1.11 mrg
802 1.1.1.11 mrg /* Convert the filename to a gcfn data stream. It is intended for
803 1.1.1.11 mrg freestanding environments which do not support the C library file I/O. */
804 1.1.1.11 mrg
805 1.1.1.11 mrg void
806 1.1.1.11 mrg __gcov_filename_to_gcfn (const char *filename,
807 1.1.1.11 mrg void (*dump_fn) (const void *, unsigned, void *),
808 1.1.1.11 mrg void *arg)
809 1.1.1.11 mrg {
810 1.1.1.11 mrg dump_unsigned (GCOV_FILENAME_MAGIC, dump_fn, arg);
811 1.1.1.11 mrg dump_unsigned (GCOV_VERSION, dump_fn, arg);
812 1.1.1.11 mrg dump_string (filename, dump_fn, arg);
813 1.1.1.11 mrg }
814 1.1.1.10 mrg #endif /* NEED_L_GCOV_INFO_TO_GCDA */
815