libgcov-driver.c revision 1.1.1.8 1 1.1 mrg /* Routines required for instrumenting a program. */
2 1.1 mrg /* Compile this one with gcc. */
3 1.1.1.8 mrg /* Copyright (C) 1989-2019 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 mrg #if defined(inhibit_libc)
30 1.1 mrg /* If libc and its header files are not available, provide dummy functions. */
31 1.1 mrg
32 1.1 mrg #if defined(L_gcov)
33 1.1 mrg void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
34 1.1 mrg #endif
35 1.1 mrg
36 1.1 mrg #else /* inhibit_libc */
37 1.1 mrg
38 1.1 mrg #include <string.h>
39 1.1 mrg #if GCOV_LOCKED
40 1.1 mrg #include <fcntl.h>
41 1.1 mrg #include <errno.h>
42 1.1 mrg #include <sys/stat.h>
43 1.1 mrg #endif
44 1.1 mrg
45 1.1 mrg #ifdef L_gcov
46 1.1 mrg
47 1.1.1.4 mrg /* A utility function for outputting errors. */
48 1.1 mrg static int gcov_error (const char *, ...);
49 1.1 mrg
50 1.1.1.4 mrg #if !IN_GCOV_TOOL
51 1.1.1.4 mrg static void gcov_error_exit (void);
52 1.1.1.4 mrg #endif
53 1.1.1.4 mrg
54 1.1 mrg #include "gcov-io.c"
55 1.1 mrg
56 1.1.1.8 mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
57 1.1.1.8 mrg
58 1.1 mrg struct gcov_fn_buffer
59 1.1 mrg {
60 1.1 mrg struct gcov_fn_buffer *next;
61 1.1 mrg unsigned fn_ix;
62 1.1 mrg struct gcov_fn_info info;
63 1.1 mrg /* note gcov_fn_info ends in a trailing array. */
64 1.1 mrg };
65 1.1 mrg
66 1.1 mrg struct gcov_summary_buffer
67 1.1 mrg {
68 1.1 mrg struct gcov_summary_buffer *next;
69 1.1 mrg struct gcov_summary summary;
70 1.1 mrg };
71 1.1 mrg
72 1.1 mrg /* A struct that bundles all the related information about the
73 1.1 mrg gcda filename. */
74 1.1 mrg
75 1.1 mrg struct gcov_filename
76 1.1 mrg {
77 1.1 mrg char *filename; /* filename buffer */
78 1.1 mrg int strip; /* leading chars to strip from filename */
79 1.1.1.8 mrg char *prefix; /* prefix string */
80 1.1 mrg };
81 1.1 mrg
82 1.1 mrg static struct gcov_fn_buffer *
83 1.1 mrg free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
84 1.1 mrg unsigned limit)
85 1.1 mrg {
86 1.1 mrg struct gcov_fn_buffer *next;
87 1.1 mrg unsigned ix, n_ctr = 0;
88 1.1 mrg
89 1.1 mrg if (!buffer)
90 1.1 mrg return 0;
91 1.1 mrg next = buffer->next;
92 1.1 mrg
93 1.1 mrg for (ix = 0; ix != limit; ix++)
94 1.1 mrg if (gi_ptr->merge[ix])
95 1.1 mrg free (buffer->info.ctrs[n_ctr++].values);
96 1.1 mrg free (buffer);
97 1.1 mrg return next;
98 1.1 mrg }
99 1.1 mrg
100 1.1 mrg static struct gcov_fn_buffer **
101 1.1 mrg buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
102 1.1 mrg struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
103 1.1 mrg {
104 1.1 mrg unsigned n_ctrs = 0, ix = 0;
105 1.1 mrg struct gcov_fn_buffer *fn_buffer;
106 1.1 mrg unsigned len;
107 1.1 mrg
108 1.1 mrg for (ix = GCOV_COUNTERS; ix--;)
109 1.1 mrg if (gi_ptr->merge[ix])
110 1.1 mrg n_ctrs++;
111 1.1 mrg
112 1.1 mrg len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
113 1.1 mrg fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
114 1.1 mrg
115 1.1 mrg if (!fn_buffer)
116 1.1 mrg goto fail;
117 1.1 mrg
118 1.1 mrg fn_buffer->next = 0;
119 1.1 mrg fn_buffer->fn_ix = fn_ix;
120 1.1 mrg fn_buffer->info.ident = gcov_read_unsigned ();
121 1.1 mrg fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
122 1.1 mrg fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
123 1.1 mrg
124 1.1 mrg for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
125 1.1 mrg {
126 1.1 mrg gcov_unsigned_t length;
127 1.1 mrg gcov_type *values;
128 1.1 mrg
129 1.1 mrg if (!gi_ptr->merge[ix])
130 1.1 mrg continue;
131 1.1 mrg
132 1.1 mrg if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
133 1.1 mrg {
134 1.1 mrg len = 0;
135 1.1 mrg goto fail;
136 1.1 mrg }
137 1.1 mrg
138 1.1 mrg length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
139 1.1 mrg len = length * sizeof (gcov_type);
140 1.1 mrg values = (gcov_type *) xmalloc (len);
141 1.1 mrg if (!values)
142 1.1 mrg goto fail;
143 1.1 mrg
144 1.1 mrg fn_buffer->info.ctrs[n_ctrs].num = length;
145 1.1 mrg fn_buffer->info.ctrs[n_ctrs].values = values;
146 1.1 mrg
147 1.1 mrg while (length--)
148 1.1 mrg *values++ = gcov_read_counter ();
149 1.1 mrg n_ctrs++;
150 1.1 mrg }
151 1.1 mrg
152 1.1 mrg *end_ptr = fn_buffer;
153 1.1 mrg return &fn_buffer->next;
154 1.1 mrg
155 1.1 mrg fail:
156 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
157 1.1 mrg len ? "cannot allocate" : "counter mismatch", len ? len : ix);
158 1.1 mrg
159 1.1 mrg return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
160 1.1 mrg }
161 1.1 mrg
162 1.1.1.8 mrg /* Convert VERSION into a string description and return the it.
163 1.1.1.8 mrg BUFFER is used for storage of the string. The code should be
164 1.1.1.8 mrg aligned wit gcov-iov.c. */
165 1.1.1.8 mrg
166 1.1.1.8 mrg static char *
167 1.1.1.8 mrg gcov_version_string (char *buffer, char version[4])
168 1.1.1.8 mrg {
169 1.1.1.8 mrg if (version[0] < 'A' || version[0] > 'Z'
170 1.1.1.8 mrg || version[1] < '0' || version[1] > '9'
171 1.1.1.8 mrg || version[2] < '0' || version[2] > '9')
172 1.1.1.8 mrg sprintf (buffer, "(unknown)");
173 1.1.1.8 mrg else
174 1.1 mrg {
175 1.1.1.8 mrg unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
176 1.1.1.8 mrg unsigned minor = version[2] - '0';
177 1.1.1.8 mrg sprintf (buffer, "%u.%u (%s)", major, minor,
178 1.1.1.8 mrg version[3] == '*' ? "release" : "experimental");
179 1.1 mrg }
180 1.1.1.8 mrg return buffer;
181 1.1 mrg }
182 1.1 mrg
183 1.1 mrg /* Check if VERSION of the info block PTR matches libgcov one.
184 1.1 mrg Return 1 on success, or zero in case of versions mismatch.
185 1.1 mrg If FILENAME is not NULL, its value used for reporting purposes
186 1.1 mrg instead of value from the info block. */
187 1.1 mrg
188 1.1 mrg static int
189 1.1 mrg gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
190 1.1 mrg const char *filename)
191 1.1 mrg {
192 1.1 mrg if (version != GCOV_VERSION)
193 1.1 mrg {
194 1.1 mrg char v[4], e[4];
195 1.1.1.8 mrg char version_string[128], expected_string[128];
196 1.1 mrg
197 1.1 mrg GCOV_UNSIGNED2STRING (v, version);
198 1.1 mrg GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
199 1.1 mrg
200 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
201 1.1.1.8 mrg "got %s (%.4s)\n",
202 1.1.1.8 mrg filename? filename : ptr->filename,
203 1.1.1.8 mrg gcov_version_string (expected_string, e), e,
204 1.1.1.8 mrg gcov_version_string (version_string, v), v);
205 1.1 mrg return 0;
206 1.1 mrg }
207 1.1 mrg return 1;
208 1.1 mrg }
209 1.1 mrg
210 1.1 mrg /* buffer for the fn_data from another program. */
211 1.1 mrg static struct gcov_fn_buffer *fn_buffer;
212 1.1 mrg
213 1.1 mrg /* Including system dependent components. */
214 1.1 mrg #include "libgcov-driver-system.c"
215 1.1 mrg
216 1.1 mrg /* This function merges counters in GI_PTR to an existing gcda file.
217 1.1 mrg Return 0 on success.
218 1.1 mrg Return -1 on error. In this case, caller will goto read_fatal. */
219 1.1 mrg
220 1.1 mrg static int
221 1.1 mrg merge_one_data (const char *filename,
222 1.1 mrg struct gcov_info *gi_ptr,
223 1.1.1.8 mrg struct gcov_summary *summary)
224 1.1 mrg {
225 1.1 mrg gcov_unsigned_t tag, length;
226 1.1 mrg unsigned t_ix;
227 1.1.1.8 mrg int f_ix = -1;
228 1.1 mrg int error = 0;
229 1.1 mrg struct gcov_fn_buffer **fn_tail = &fn_buffer;
230 1.1 mrg
231 1.1 mrg length = gcov_read_unsigned ();
232 1.1 mrg if (!gcov_version (gi_ptr, length, filename))
233 1.1 mrg return -1;
234 1.1 mrg
235 1.1 mrg length = gcov_read_unsigned ();
236 1.1 mrg if (length != gi_ptr->stamp)
237 1.1 mrg {
238 1.1.1.8 mrg /* Read from a different compilation. Overwrite the file. */
239 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
240 1.1.1.8 mrg "with a different timestamp\n", filename);
241 1.1.1.8 mrg return 0;
242 1.1 mrg }
243 1.1 mrg
244 1.1.1.8 mrg tag = gcov_read_unsigned ();
245 1.1.1.8 mrg if (tag != GCOV_TAG_OBJECT_SUMMARY)
246 1.1.1.8 mrg goto read_mismatch;
247 1.1.1.8 mrg length = gcov_read_unsigned ();
248 1.1.1.8 mrg gcc_assert (length > 0);
249 1.1.1.8 mrg gcov_read_summary (summary);
250 1.1.1.8 mrg
251 1.1.1.8 mrg tag = gcov_read_unsigned ();
252 1.1 mrg /* Merge execution counts for each function. */
253 1.1 mrg for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
254 1.1 mrg f_ix++, tag = gcov_read_unsigned ())
255 1.1 mrg {
256 1.1 mrg const struct gcov_ctr_info *ci_ptr;
257 1.1 mrg const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
258 1.1 mrg
259 1.1 mrg if (tag != GCOV_TAG_FUNCTION)
260 1.1 mrg goto read_mismatch;
261 1.1 mrg
262 1.1 mrg length = gcov_read_unsigned ();
263 1.1 mrg if (!length)
264 1.1 mrg /* This function did not appear in the other program.
265 1.1 mrg We have nothing to merge. */
266 1.1 mrg continue;
267 1.1 mrg
268 1.1 mrg if (length != GCOV_TAG_FUNCTION_LENGTH)
269 1.1 mrg goto read_mismatch;
270 1.1 mrg
271 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gi_ptr)
272 1.1 mrg {
273 1.1 mrg /* This function appears in the other program. We
274 1.1 mrg need to buffer the information in order to write
275 1.1 mrg it back out -- we'll be inserting data before
276 1.1 mrg this point, so cannot simply keep the data in the
277 1.1 mrg file. */
278 1.1 mrg fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
279 1.1 mrg if (!fn_tail)
280 1.1 mrg goto read_mismatch;
281 1.1 mrg continue;
282 1.1 mrg }
283 1.1 mrg
284 1.1 mrg length = gcov_read_unsigned ();
285 1.1 mrg if (length != gfi_ptr->ident)
286 1.1 mrg goto read_mismatch;
287 1.1 mrg
288 1.1 mrg length = gcov_read_unsigned ();
289 1.1 mrg if (length != gfi_ptr->lineno_checksum)
290 1.1 mrg goto read_mismatch;
291 1.1 mrg
292 1.1 mrg length = gcov_read_unsigned ();
293 1.1 mrg if (length != gfi_ptr->cfg_checksum)
294 1.1 mrg goto read_mismatch;
295 1.1 mrg
296 1.1 mrg ci_ptr = gfi_ptr->ctrs;
297 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
298 1.1 mrg {
299 1.1 mrg gcov_merge_fn merge = gi_ptr->merge[t_ix];
300 1.1 mrg
301 1.1 mrg if (!merge)
302 1.1 mrg continue;
303 1.1 mrg
304 1.1 mrg tag = gcov_read_unsigned ();
305 1.1 mrg length = gcov_read_unsigned ();
306 1.1 mrg if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
307 1.1 mrg || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
308 1.1 mrg goto read_mismatch;
309 1.1 mrg (*merge) (ci_ptr->values, ci_ptr->num);
310 1.1 mrg ci_ptr++;
311 1.1 mrg }
312 1.1 mrg if ((error = gcov_is_error ()))
313 1.1 mrg goto read_error;
314 1.1 mrg }
315 1.1 mrg
316 1.1 mrg if (tag)
317 1.1 mrg {
318 1.1 mrg read_mismatch:;
319 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
320 1.1 mrg filename, f_ix >= 0 ? "function" : "summary",
321 1.1 mrg f_ix < 0 ? -1 - f_ix : f_ix);
322 1.1 mrg return -1;
323 1.1 mrg }
324 1.1 mrg return 0;
325 1.1 mrg
326 1.1 mrg read_error:
327 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
328 1.1 mrg error < 0 ? "Overflow": "Error");
329 1.1 mrg return -1;
330 1.1 mrg }
331 1.1 mrg
332 1.1 mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
333 1.1 mrg the case of appending to an existing file, SUMMARY_POS will be non-zero.
334 1.1 mrg We will write the file starting from SUMMAY_POS. */
335 1.1 mrg
336 1.1 mrg static void
337 1.1 mrg write_one_data (const struct gcov_info *gi_ptr,
338 1.1.1.8 mrg const struct gcov_summary *prg_p)
339 1.1 mrg {
340 1.1 mrg unsigned f_ix;
341 1.1 mrg
342 1.1.1.8 mrg gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
343 1.1.1.8 mrg gcov_write_unsigned (gi_ptr->stamp);
344 1.1 mrg
345 1.1 mrg /* Generate whole program statistics. */
346 1.1.1.8 mrg gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
347 1.1 mrg
348 1.1 mrg /* Write execution counts for each function. */
349 1.1 mrg for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
350 1.1 mrg {
351 1.1 mrg unsigned buffered = 0;
352 1.1 mrg const struct gcov_fn_info *gfi_ptr;
353 1.1 mrg const struct gcov_ctr_info *ci_ptr;
354 1.1 mrg gcov_unsigned_t length;
355 1.1 mrg unsigned t_ix;
356 1.1 mrg
357 1.1 mrg if (fn_buffer && fn_buffer->fn_ix == f_ix)
358 1.1 mrg {
359 1.1 mrg /* Buffered data from another program. */
360 1.1 mrg buffered = 1;
361 1.1 mrg gfi_ptr = &fn_buffer->info;
362 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH;
363 1.1 mrg }
364 1.1 mrg else
365 1.1 mrg {
366 1.1 mrg gfi_ptr = gi_ptr->functions[f_ix];
367 1.1 mrg if (gfi_ptr && gfi_ptr->key == gi_ptr)
368 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH;
369 1.1 mrg else
370 1.1 mrg length = 0;
371 1.1 mrg }
372 1.1 mrg
373 1.1 mrg gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
374 1.1 mrg if (!length)
375 1.1 mrg continue;
376 1.1 mrg
377 1.1 mrg gcov_write_unsigned (gfi_ptr->ident);
378 1.1 mrg gcov_write_unsigned (gfi_ptr->lineno_checksum);
379 1.1 mrg gcov_write_unsigned (gfi_ptr->cfg_checksum);
380 1.1 mrg
381 1.1 mrg ci_ptr = gfi_ptr->ctrs;
382 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
383 1.1 mrg {
384 1.1 mrg gcov_unsigned_t n_counts;
385 1.1 mrg gcov_type *c_ptr;
386 1.1 mrg
387 1.1 mrg if (!gi_ptr->merge[t_ix])
388 1.1 mrg continue;
389 1.1 mrg
390 1.1 mrg n_counts = ci_ptr->num;
391 1.1 mrg gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
392 1.1 mrg GCOV_TAG_COUNTER_LENGTH (n_counts));
393 1.1 mrg c_ptr = ci_ptr->values;
394 1.1 mrg while (n_counts--)
395 1.1 mrg gcov_write_counter (*c_ptr++);
396 1.1 mrg ci_ptr++;
397 1.1 mrg }
398 1.1 mrg if (buffered)
399 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
400 1.1 mrg }
401 1.1 mrg
402 1.1 mrg gcov_write_unsigned (0);
403 1.1 mrg }
404 1.1 mrg
405 1.1.1.8 mrg /* Helper function for merging summary. */
406 1.1 mrg
407 1.1.1.8 mrg static void
408 1.1.1.8 mrg merge_summary (int run_counted, struct gcov_summary *summary,
409 1.1.1.8 mrg gcov_type run_max)
410 1.1 mrg {
411 1.1.1.8 mrg if (!run_counted)
412 1.1 mrg {
413 1.1.1.8 mrg summary->runs++;
414 1.1.1.8 mrg summary->sum_max += run_max;
415 1.1 mrg }
416 1.1 mrg }
417 1.1 mrg
418 1.1 mrg /* Sort N entries in VALUE_ARRAY in descending order.
419 1.1 mrg Each entry in VALUE_ARRAY has two values. The sorting
420 1.1 mrg is based on the second value. */
421 1.1 mrg
422 1.1 mrg GCOV_LINKAGE void
423 1.1 mrg gcov_sort_n_vals (gcov_type *value_array, int n)
424 1.1 mrg {
425 1.1 mrg int j, k;
426 1.1 mrg
427 1.1 mrg for (j = 2; j < n; j += 2)
428 1.1 mrg {
429 1.1 mrg gcov_type cur_ent[2];
430 1.1 mrg
431 1.1 mrg cur_ent[0] = value_array[j];
432 1.1 mrg cur_ent[1] = value_array[j + 1];
433 1.1 mrg k = j - 2;
434 1.1 mrg while (k >= 0 && value_array[k + 1] < cur_ent[1])
435 1.1 mrg {
436 1.1 mrg value_array[k + 2] = value_array[k];
437 1.1 mrg value_array[k + 3] = value_array[k+1];
438 1.1 mrg k -= 2;
439 1.1 mrg }
440 1.1 mrg value_array[k + 2] = cur_ent[0];
441 1.1 mrg value_array[k + 3] = cur_ent[1];
442 1.1 mrg }
443 1.1 mrg }
444 1.1 mrg
445 1.1 mrg /* Sort the profile counters for all indirect call sites. Counters
446 1.1 mrg for each call site are allocated in array COUNTERS. */
447 1.1 mrg
448 1.1 mrg static void
449 1.1 mrg gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
450 1.1 mrg {
451 1.1 mrg int i;
452 1.1 mrg gcov_type *values;
453 1.1 mrg int n = counters->num;
454 1.1 mrg
455 1.1 mrg gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
456 1.1 mrg values = counters->values;
457 1.1 mrg
458 1.1 mrg for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
459 1.1 mrg {
460 1.1 mrg gcov_type *value_array = &values[i + 1];
461 1.1 mrg gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
462 1.1 mrg }
463 1.1 mrg }
464 1.1 mrg
465 1.1 mrg /* Sort topn indirect_call profile counters in GI_PTR. */
466 1.1 mrg
467 1.1 mrg static void
468 1.1 mrg gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
469 1.1 mrg {
470 1.1 mrg unsigned int i;
471 1.1 mrg int f_ix;
472 1.1 mrg const struct gcov_fn_info *gfi_ptr;
473 1.1 mrg const struct gcov_ctr_info *ci_ptr;
474 1.1 mrg
475 1.1 mrg if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV])
476 1.1 mrg return;
477 1.1 mrg
478 1.1 mrg for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
479 1.1 mrg {
480 1.1 mrg gfi_ptr = gi_ptr->functions[f_ix];
481 1.1 mrg ci_ptr = gfi_ptr->ctrs;
482 1.1 mrg for (i = 0; i < GCOV_COUNTERS; i++)
483 1.1 mrg {
484 1.1 mrg if (!gi_ptr->merge[i])
485 1.1 mrg continue;
486 1.1 mrg if (i == GCOV_COUNTER_ICALL_TOPNV)
487 1.1 mrg {
488 1.1 mrg gcov_sort_icall_topn_counter (ci_ptr);
489 1.1 mrg break;
490 1.1 mrg }
491 1.1 mrg ci_ptr++;
492 1.1 mrg }
493 1.1 mrg }
494 1.1 mrg }
495 1.1 mrg
496 1.1 mrg /* Dump the coverage counts for one gcov_info object. We merge with existing
497 1.1 mrg counts when possible, to avoid growing the .da files ad infinitum. We use
498 1.1 mrg this program's checksum to make sure we only accumulate whole program
499 1.1 mrg statistics to the correct summary. An object file might be embedded
500 1.1 mrg in two separate programs, and we must keep the two program
501 1.1 mrg summaries separate. */
502 1.1 mrg
503 1.1 mrg static void
504 1.1 mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
505 1.1.1.8 mrg unsigned run_counted, gcov_type run_max)
506 1.1 mrg {
507 1.1.1.8 mrg struct gcov_summary summary = {};
508 1.1 mrg int error;
509 1.1 mrg gcov_unsigned_t tag;
510 1.1 mrg
511 1.1 mrg fn_buffer = 0;
512 1.1 mrg
513 1.1 mrg gcov_sort_topn_counter_arrays (gi_ptr);
514 1.1 mrg
515 1.1 mrg error = gcov_exit_open_gcda_file (gi_ptr, gf);
516 1.1 mrg if (error == -1)
517 1.1 mrg return;
518 1.1 mrg
519 1.1 mrg tag = gcov_read_unsigned ();
520 1.1 mrg if (tag)
521 1.1 mrg {
522 1.1 mrg /* Merge data from file. */
523 1.1 mrg if (tag != GCOV_DATA_MAGIC)
524 1.1 mrg {
525 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
526 1.1.1.8 mrg gf->filename);
527 1.1 mrg goto read_fatal;
528 1.1 mrg }
529 1.1.1.8 mrg error = merge_one_data (gf->filename, gi_ptr, &summary);
530 1.1 mrg if (error == -1)
531 1.1 mrg goto read_fatal;
532 1.1 mrg }
533 1.1 mrg
534 1.1 mrg gcov_rewrite ();
535 1.1 mrg
536 1.1.1.8 mrg merge_summary (run_counted, &summary, run_max);
537 1.1 mrg
538 1.1.1.8 mrg write_one_data (gi_ptr, &summary);
539 1.1 mrg /* fall through */
540 1.1 mrg
541 1.1 mrg read_fatal:;
542 1.1 mrg while (fn_buffer)
543 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
544 1.1 mrg
545 1.1 mrg if ((error = gcov_close ()))
546 1.1 mrg gcov_error (error < 0 ?
547 1.1.1.8 mrg GCOV_PROF_PREFIX "Overflow writing\n" :
548 1.1.1.8 mrg GCOV_PROF_PREFIX "Error writing\n",
549 1.1 mrg gf->filename);
550 1.1 mrg }
551 1.1 mrg
552 1.1 mrg
553 1.1 mrg /* Dump all the coverage counts for the program. It first computes program
554 1.1 mrg summary and then traverses gcov_list list and dumps the gcov_info
555 1.1 mrg objects one by one. */
556 1.1 mrg
557 1.1 mrg #if !IN_GCOV_TOOL
558 1.1 mrg static
559 1.1 mrg #endif
560 1.1 mrg void
561 1.1 mrg gcov_do_dump (struct gcov_info *list, int run_counted)
562 1.1 mrg {
563 1.1 mrg struct gcov_info *gi_ptr;
564 1.1 mrg struct gcov_filename gf;
565 1.1 mrg
566 1.1.1.8 mrg /* Compute run_max of this program run. */
567 1.1.1.8 mrg gcov_type run_max = 0;
568 1.1.1.8 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
569 1.1.1.8 mrg for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
570 1.1.1.8 mrg {
571 1.1.1.8 mrg const struct gcov_ctr_info *cinfo
572 1.1.1.8 mrg = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
573 1.1.1.8 mrg
574 1.1.1.8 mrg for (unsigned i = 0; i < cinfo->num; i++)
575 1.1.1.8 mrg if (run_max < cinfo->values[i])
576 1.1.1.8 mrg run_max = cinfo->values[i];
577 1.1.1.8 mrg }
578 1.1 mrg
579 1.1 mrg allocate_filename_struct (&gf);
580 1.1 mrg
581 1.1 mrg /* Now merge each file. */
582 1.1 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
583 1.1.1.8 mrg {
584 1.1.1.8 mrg dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
585 1.1.1.8 mrg free (gf.filename);
586 1.1.1.8 mrg }
587 1.1 mrg
588 1.1.1.8 mrg free (gf.prefix);
589 1.1 mrg }
590 1.1 mrg
591 1.1.1.2 mrg #if IN_GCOV_TOOL
592 1.1.1.2 mrg const char *
593 1.1.1.2 mrg __attribute__ ((unused))
594 1.1.1.2 mrg gcov_get_filename (struct gcov_info *list)
595 1.1.1.2 mrg {
596 1.1.1.2 mrg return list->filename;
597 1.1.1.2 mrg }
598 1.1.1.2 mrg #endif
599 1.1.1.2 mrg
600 1.1 mrg #if !IN_GCOV_TOOL
601 1.1 mrg void
602 1.1 mrg __gcov_dump_one (struct gcov_root *root)
603 1.1 mrg {
604 1.1 mrg if (root->dumped)
605 1.1 mrg return;
606 1.1 mrg
607 1.1 mrg gcov_do_dump (root->list, root->run_counted);
608 1.1 mrg
609 1.1 mrg root->dumped = 1;
610 1.1 mrg root->run_counted = 1;
611 1.1 mrg }
612 1.1 mrg
613 1.1 mrg /* Per-dynamic-object gcov state. */
614 1.1 mrg struct gcov_root __gcov_root;
615 1.1 mrg
616 1.1 mrg /* Exactly one of these will be live in the process image. */
617 1.1 mrg struct gcov_master __gcov_master =
618 1.1 mrg {GCOV_VERSION, 0};
619 1.1 mrg
620 1.1.1.4 mrg void
621 1.1.1.4 mrg __gcov_exit (void)
622 1.1 mrg {
623 1.1 mrg __gcov_dump_one (&__gcov_root);
624 1.1 mrg if (__gcov_root.next)
625 1.1 mrg __gcov_root.next->prev = __gcov_root.prev;
626 1.1 mrg if (__gcov_root.prev)
627 1.1 mrg __gcov_root.prev->next = __gcov_root.next;
628 1.1 mrg else
629 1.1 mrg __gcov_master.root = __gcov_root.next;
630 1.1.1.4 mrg
631 1.1.1.4 mrg gcov_error_exit ();
632 1.1 mrg }
633 1.1 mrg
634 1.1 mrg /* Add a new object file onto the bb chain. Invoked automatically
635 1.1 mrg when running an object file's global ctors. */
636 1.1 mrg
637 1.1 mrg void
638 1.1 mrg __gcov_init (struct gcov_info *info)
639 1.1 mrg {
640 1.1 mrg if (!info->version || !info->n_functions)
641 1.1 mrg return;
642 1.1 mrg if (gcov_version (info, info->version, 0))
643 1.1 mrg {
644 1.1 mrg if (!__gcov_root.list)
645 1.1 mrg {
646 1.1 mrg /* Add to master list and at exit function. */
647 1.1 mrg if (gcov_version (NULL, __gcov_master.version, "<master>"))
648 1.1 mrg {
649 1.1 mrg __gcov_root.next = __gcov_master.root;
650 1.1 mrg if (__gcov_master.root)
651 1.1 mrg __gcov_master.root->prev = &__gcov_root;
652 1.1 mrg __gcov_master.root = &__gcov_root;
653 1.1 mrg }
654 1.1 mrg }
655 1.1 mrg
656 1.1 mrg info->next = __gcov_root.list;
657 1.1 mrg __gcov_root.list = info;
658 1.1 mrg }
659 1.1 mrg }
660 1.1 mrg #endif /* !IN_GCOV_TOOL */
661 1.1 mrg #endif /* L_gcov */
662 1.1 mrg #endif /* inhibit_libc */
663