libgcov-driver.c revision 1.1.1.10 1 1.1 mrg /* Routines required for instrumenting a program. */
2 1.1 mrg /* Compile this one with gcc. */
3 1.1.1.10 mrg /* Copyright (C) 1989-2022 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.10 mrg #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
414 1.1.1.10 mrg
415 1.1.1.10 mrg /* Store all TOP N counters where each has a dynamic length. */
416 1.1.1.10 mrg
417 1.1.1.10 mrg static void
418 1.1.1.10 mrg write_topn_counters (const struct gcov_ctr_info *ci_ptr,
419 1.1.1.10 mrg unsigned t_ix,
420 1.1.1.10 mrg gcov_unsigned_t n_counts,
421 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
422 1.1.1.10 mrg void *(*allocate_fn)(unsigned, void *),
423 1.1.1.10 mrg void *arg)
424 1.1.1.10 mrg {
425 1.1.1.10 mrg unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
426 1.1.1.10 mrg gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
427 1.1.1.10 mrg
428 1.1.1.10 mrg /* It can happen in a multi-threaded environment that number of counters is
429 1.1.1.10 mrg different from the size of the corresponding linked lists. */
430 1.1.1.10 mrg #define LIST_SIZE_MIN_LENGTH 4 * 1024
431 1.1.1.10 mrg
432 1.1.1.10 mrg static unsigned *list_sizes = NULL;
433 1.1.1.10 mrg static unsigned list_size_length = 0;
434 1.1.1.10 mrg
435 1.1.1.10 mrg if (list_sizes == NULL || counters > list_size_length)
436 1.1.1.10 mrg {
437 1.1.1.10 mrg list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
438 1.1.1.10 mrg #if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
439 1.1.1.10 mrg list_sizes
440 1.1.1.10 mrg = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
441 1.1.1.10 mrg #endif
442 1.1.1.10 mrg
443 1.1.1.10 mrg /* Malloc fallback. */
444 1.1.1.10 mrg if (list_sizes == NULL)
445 1.1.1.10 mrg list_sizes =
446 1.1.1.10 mrg (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned),
447 1.1.1.10 mrg arg);
448 1.1.1.10 mrg }
449 1.1.1.10 mrg
450 1.1.1.10 mrg unsigned pair_total = 0;
451 1.1.1.10 mrg
452 1.1.1.10 mrg for (unsigned i = 0; i < counters; i++)
453 1.1.1.10 mrg {
454 1.1.1.10 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
455 1.1.1.10 mrg unsigned sizes = 0;
456 1.1.1.10 mrg
457 1.1.1.10 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start;
458 1.1.1.10 mrg node != NULL; node = node->next)
459 1.1.1.10 mrg ++sizes;
460 1.1.1.10 mrg
461 1.1.1.10 mrg pair_total += sizes;
462 1.1.1.10 mrg list_sizes[i] = sizes;
463 1.1.1.10 mrg }
464 1.1.1.10 mrg
465 1.1.1.10 mrg unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
466 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg),
467 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump_fn, arg);
468 1.1.1.10 mrg
469 1.1.1.10 mrg for (unsigned i = 0; i < counters; i++)
470 1.1.1.10 mrg {
471 1.1.1.10 mrg dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump_fn, arg);
472 1.1.1.10 mrg dump_counter (list_sizes[i], dump_fn, arg);
473 1.1.1.10 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
474 1.1.1.10 mrg
475 1.1.1.10 mrg unsigned j = 0;
476 1.1.1.10 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start;
477 1.1.1.10 mrg j < list_sizes[i]; node = node->next, j++)
478 1.1.1.10 mrg {
479 1.1.1.10 mrg dump_counter (node->value, dump_fn, arg);
480 1.1.1.10 mrg dump_counter (node->count, dump_fn, arg);
481 1.1.1.10 mrg }
482 1.1.1.10 mrg }
483 1.1.1.10 mrg }
484 1.1.1.10 mrg
485 1.1 mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
486 1.1 mrg the case of appending to an existing file, SUMMARY_POS will be non-zero.
487 1.1 mrg We will write the file starting from SUMMAY_POS. */
488 1.1 mrg
489 1.1 mrg static void
490 1.1 mrg write_one_data (const struct gcov_info *gi_ptr,
491 1.1.1.10 mrg const struct gcov_summary *prg_p ATTRIBUTE_UNUSED,
492 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
493 1.1.1.10 mrg void *(*allocate_fn) (unsigned, void *),
494 1.1.1.10 mrg void *arg)
495 1.1 mrg {
496 1.1 mrg unsigned f_ix;
497 1.1 mrg
498 1.1.1.10 mrg dump_unsigned (GCOV_DATA_MAGIC, dump_fn, arg);
499 1.1.1.10 mrg dump_unsigned (GCOV_VERSION, dump_fn, arg);
500 1.1.1.10 mrg dump_unsigned (gi_ptr->stamp, dump_fn, arg);
501 1.1.1.10 mrg dump_unsigned (gi_ptr->checksum, dump_fn, arg);
502 1.1 mrg
503 1.1.1.10 mrg #ifdef NEED_L_GCOV
504 1.1 mrg /* Generate whole program statistics. */
505 1.1.1.8 mrg gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
506 1.1.1.10 mrg #endif
507 1.1 mrg
508 1.1 mrg /* Write execution counts for each function. */
509 1.1 mrg for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
510 1.1 mrg {
511 1.1.1.10 mrg #ifdef NEED_L_GCOV
512 1.1 mrg unsigned buffered = 0;
513 1.1.1.10 mrg #endif
514 1.1 mrg const struct gcov_fn_info *gfi_ptr;
515 1.1 mrg const struct gcov_ctr_info *ci_ptr;
516 1.1 mrg gcov_unsigned_t length;
517 1.1 mrg unsigned t_ix;
518 1.1 mrg
519 1.1.1.10 mrg #ifdef NEED_L_GCOV
520 1.1 mrg if (fn_buffer && fn_buffer->fn_ix == f_ix)
521 1.1 mrg {
522 1.1 mrg /* Buffered data from another program. */
523 1.1 mrg buffered = 1;
524 1.1 mrg gfi_ptr = &fn_buffer->info;
525 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH;
526 1.1 mrg }
527 1.1 mrg else
528 1.1.1.10 mrg #endif
529 1.1 mrg {
530 1.1 mrg gfi_ptr = gi_ptr->functions[f_ix];
531 1.1 mrg if (gfi_ptr && gfi_ptr->key == gi_ptr)
532 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH;
533 1.1 mrg else
534 1.1 mrg length = 0;
535 1.1 mrg }
536 1.1 mrg
537 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FUNCTION, dump_fn, arg);
538 1.1.1.10 mrg dump_unsigned (length, dump_fn, arg);
539 1.1 mrg if (!length)
540 1.1 mrg continue;
541 1.1 mrg
542 1.1.1.10 mrg dump_unsigned (gfi_ptr->ident, dump_fn, arg);
543 1.1.1.10 mrg dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg);
544 1.1.1.10 mrg dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg);
545 1.1 mrg
546 1.1 mrg ci_ptr = gfi_ptr->ctrs;
547 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
548 1.1 mrg {
549 1.1.1.10 mrg gcov_position_t n_counts;
550 1.1 mrg
551 1.1.1.10 mrg if (!gi_ptr->merge[t_ix])
552 1.1.1.10 mrg continue;
553 1.1 mrg
554 1.1.1.10 mrg n_counts = ci_ptr->num;
555 1.1.1.10 mrg
556 1.1.1.10 mrg if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
557 1.1.1.10 mrg write_topn_counters (ci_ptr, t_ix, n_counts, dump_fn, allocate_fn,
558 1.1.1.10 mrg arg);
559 1.1.1.10 mrg else
560 1.1.1.10 mrg {
561 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg);
562 1.1.1.10 mrg if (are_all_counters_zero (ci_ptr))
563 1.1.1.10 mrg /* Do not stream when all counters are zero. */
564 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts),
565 1.1.1.10 mrg dump_fn, arg);
566 1.1.1.10 mrg else
567 1.1.1.10 mrg {
568 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts),
569 1.1.1.10 mrg dump_fn, arg);
570 1.1.1.10 mrg for (unsigned i = 0; i < n_counts; i++)
571 1.1.1.10 mrg dump_counter (ci_ptr->values[i], dump_fn, arg);
572 1.1.1.10 mrg }
573 1.1.1.10 mrg }
574 1.1.1.10 mrg
575 1.1.1.10 mrg ci_ptr++;
576 1.1.1.10 mrg }
577 1.1.1.10 mrg #ifdef NEED_L_GCOV
578 1.1 mrg if (buffered)
579 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
580 1.1.1.10 mrg #endif
581 1.1 mrg }
582 1.1 mrg
583 1.1.1.10 mrg dump_unsigned (0, dump_fn, arg);
584 1.1 mrg }
585 1.1.1.10 mrg #endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
586 1.1 mrg
587 1.1.1.10 mrg #ifdef NEED_L_GCOV
588 1.1 mrg /* Dump the coverage counts for one gcov_info object. We merge with existing
589 1.1 mrg counts when possible, to avoid growing the .da files ad infinitum. We use
590 1.1 mrg this program's checksum to make sure we only accumulate whole program
591 1.1 mrg statistics to the correct summary. An object file might be embedded
592 1.1 mrg in two separate programs, and we must keep the two program
593 1.1 mrg summaries separate. */
594 1.1 mrg
595 1.1 mrg static void
596 1.1 mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
597 1.1.1.10 mrg unsigned run_counted ATTRIBUTE_UNUSED,
598 1.1.1.10 mrg gcov_type run_max ATTRIBUTE_UNUSED)
599 1.1 mrg {
600 1.1.1.8 mrg struct gcov_summary summary = {};
601 1.1 mrg int error;
602 1.1 mrg gcov_unsigned_t tag;
603 1.1 mrg fn_buffer = 0;
604 1.1 mrg
605 1.1 mrg error = gcov_exit_open_gcda_file (gi_ptr, gf);
606 1.1 mrg if (error == -1)
607 1.1 mrg return;
608 1.1 mrg
609 1.1 mrg tag = gcov_read_unsigned ();
610 1.1 mrg if (tag)
611 1.1 mrg {
612 1.1 mrg /* Merge data from file. */
613 1.1 mrg if (tag != GCOV_DATA_MAGIC)
614 1.1 mrg {
615 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
616 1.1.1.8 mrg gf->filename);
617 1.1 mrg goto read_fatal;
618 1.1 mrg }
619 1.1.1.8 mrg error = merge_one_data (gf->filename, gi_ptr, &summary);
620 1.1 mrg if (error == -1)
621 1.1 mrg goto read_fatal;
622 1.1 mrg }
623 1.1 mrg
624 1.1 mrg gcov_rewrite ();
625 1.1 mrg
626 1.1.1.10 mrg #if !IN_GCOV_TOOL
627 1.1.1.10 mrg if (!run_counted)
628 1.1.1.10 mrg {
629 1.1.1.10 mrg summary.runs++;
630 1.1.1.10 mrg summary.sum_max += run_max;
631 1.1.1.10 mrg }
632 1.1.1.10 mrg #else
633 1.1.1.10 mrg summary = gi_ptr->summary;
634 1.1.1.10 mrg #endif
635 1.1 mrg
636 1.1.1.10 mrg write_one_data (gi_ptr, &summary, gcov_dump_handler, gcov_allocate_handler,
637 1.1.1.10 mrg NULL);
638 1.1 mrg /* fall through */
639 1.1 mrg
640 1.1 mrg read_fatal:;
641 1.1 mrg while (fn_buffer)
642 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
643 1.1 mrg
644 1.1 mrg if ((error = gcov_close ()))
645 1.1.1.10 mrg gcov_error ((error < 0 ? GCOV_PROF_PREFIX "Overflow writing\n"
646 1.1.1.10 mrg : GCOV_PROF_PREFIX "Error writing\n"), gf->filename);
647 1.1 mrg }
648 1.1 mrg
649 1.1 mrg
650 1.1 mrg /* Dump all the coverage counts for the program. It first computes program
651 1.1 mrg summary and then traverses gcov_list list and dumps the gcov_info
652 1.1 mrg objects one by one. */
653 1.1 mrg
654 1.1 mrg #if !IN_GCOV_TOOL
655 1.1 mrg static
656 1.1 mrg #endif
657 1.1 mrg void
658 1.1 mrg gcov_do_dump (struct gcov_info *list, int run_counted)
659 1.1 mrg {
660 1.1 mrg struct gcov_info *gi_ptr;
661 1.1 mrg struct gcov_filename gf;
662 1.1 mrg
663 1.1.1.8 mrg /* Compute run_max of this program run. */
664 1.1.1.8 mrg gcov_type run_max = 0;
665 1.1.1.8 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
666 1.1.1.8 mrg for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
667 1.1.1.8 mrg {
668 1.1.1.8 mrg const struct gcov_ctr_info *cinfo
669 1.1.1.8 mrg = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
670 1.1.1.8 mrg
671 1.1.1.8 mrg for (unsigned i = 0; i < cinfo->num; i++)
672 1.1.1.8 mrg if (run_max < cinfo->values[i])
673 1.1.1.8 mrg run_max = cinfo->values[i];
674 1.1.1.8 mrg }
675 1.1 mrg
676 1.1 mrg allocate_filename_struct (&gf);
677 1.1 mrg
678 1.1 mrg /* Now merge each file. */
679 1.1 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
680 1.1.1.8 mrg {
681 1.1.1.8 mrg dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
682 1.1.1.8 mrg free (gf.filename);
683 1.1.1.8 mrg }
684 1.1 mrg
685 1.1.1.8 mrg free (gf.prefix);
686 1.1 mrg }
687 1.1 mrg
688 1.1.1.2 mrg #if IN_GCOV_TOOL
689 1.1.1.2 mrg const char *
690 1.1.1.2 mrg __attribute__ ((unused))
691 1.1.1.2 mrg gcov_get_filename (struct gcov_info *list)
692 1.1.1.2 mrg {
693 1.1.1.2 mrg return list->filename;
694 1.1.1.2 mrg }
695 1.1.1.2 mrg #endif
696 1.1.1.2 mrg
697 1.1 mrg #if !IN_GCOV_TOOL
698 1.1 mrg void
699 1.1 mrg __gcov_dump_one (struct gcov_root *root)
700 1.1 mrg {
701 1.1 mrg if (root->dumped)
702 1.1 mrg return;
703 1.1 mrg
704 1.1 mrg gcov_do_dump (root->list, root->run_counted);
705 1.1 mrg
706 1.1 mrg root->dumped = 1;
707 1.1 mrg root->run_counted = 1;
708 1.1 mrg }
709 1.1 mrg
710 1.1 mrg /* Per-dynamic-object gcov state. */
711 1.1 mrg struct gcov_root __gcov_root;
712 1.1 mrg
713 1.1 mrg /* Exactly one of these will be live in the process image. */
714 1.1 mrg struct gcov_master __gcov_master =
715 1.1 mrg {GCOV_VERSION, 0};
716 1.1 mrg
717 1.1.1.10 mrg /* Dynamic pool for gcov_kvp structures. */
718 1.1.1.10 mrg struct gcov_kvp *__gcov_kvp_dynamic_pool;
719 1.1.1.10 mrg
720 1.1.1.10 mrg /* Index into __gcov_kvp_dynamic_pool array. */
721 1.1.1.10 mrg unsigned __gcov_kvp_dynamic_pool_index;
722 1.1.1.10 mrg
723 1.1.1.10 mrg /* Size of _gcov_kvp_dynamic_pool array. */
724 1.1.1.10 mrg unsigned __gcov_kvp_dynamic_pool_size;
725 1.1.1.10 mrg
726 1.1.1.4 mrg void
727 1.1.1.4 mrg __gcov_exit (void)
728 1.1 mrg {
729 1.1 mrg __gcov_dump_one (&__gcov_root);
730 1.1 mrg if (__gcov_root.next)
731 1.1 mrg __gcov_root.next->prev = __gcov_root.prev;
732 1.1 mrg if (__gcov_root.prev)
733 1.1 mrg __gcov_root.prev->next = __gcov_root.next;
734 1.1 mrg else
735 1.1 mrg __gcov_master.root = __gcov_root.next;
736 1.1.1.4 mrg
737 1.1.1.4 mrg gcov_error_exit ();
738 1.1 mrg }
739 1.1 mrg
740 1.1 mrg /* Add a new object file onto the bb chain. Invoked automatically
741 1.1 mrg when running an object file's global ctors. */
742 1.1 mrg
743 1.1 mrg void
744 1.1 mrg __gcov_init (struct gcov_info *info)
745 1.1 mrg {
746 1.1 mrg if (!info->version || !info->n_functions)
747 1.1 mrg return;
748 1.1 mrg if (gcov_version (info, info->version, 0))
749 1.1 mrg {
750 1.1 mrg if (!__gcov_root.list)
751 1.1 mrg {
752 1.1 mrg /* Add to master list and at exit function. */
753 1.1 mrg if (gcov_version (NULL, __gcov_master.version, "<master>"))
754 1.1 mrg {
755 1.1 mrg __gcov_root.next = __gcov_master.root;
756 1.1 mrg if (__gcov_master.root)
757 1.1 mrg __gcov_master.root->prev = &__gcov_root;
758 1.1 mrg __gcov_master.root = &__gcov_root;
759 1.1 mrg }
760 1.1 mrg }
761 1.1 mrg
762 1.1 mrg info->next = __gcov_root.list;
763 1.1 mrg __gcov_root.list = info;
764 1.1 mrg }
765 1.1 mrg }
766 1.1 mrg #endif /* !IN_GCOV_TOOL */
767 1.1.1.10 mrg #endif /* NEED_L_GCOV */
768 1.1.1.10 mrg
769 1.1.1.10 mrg #ifdef NEED_L_GCOV_INFO_TO_GCDA
770 1.1.1.10 mrg /* Convert the gcov info to a gcda data stream. It is intended for
771 1.1.1.10 mrg free-standing environments which do not support the C library file I/O. */
772 1.1.1.10 mrg
773 1.1.1.10 mrg void
774 1.1.1.10 mrg __gcov_info_to_gcda (const struct gcov_info *gi_ptr,
775 1.1.1.10 mrg void (*filename_fn) (const char *, void *),
776 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *),
777 1.1.1.10 mrg void *(*allocate_fn) (unsigned, void *),
778 1.1.1.10 mrg void *arg)
779 1.1.1.10 mrg {
780 1.1.1.10 mrg (*filename_fn) (gi_ptr->filename, arg);
781 1.1.1.10 mrg write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg);
782 1.1.1.10 mrg }
783 1.1.1.10 mrg #endif /* NEED_L_GCOV_INFO_TO_GCDA */
784