Bug Summary

File:build/gcc/../libgcc/libgcov-util.c
Warning:line 706, column 14
Use of zero-allocated memory

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name libgcov-util.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -resource-dir /usr/lib64/clang/13.0.0 -D IN_GCC -D HAVE_CONFIG_H -I . -I . -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/. -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../include -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcpp/include -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcody -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber/bid -I ../libdecnumber -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libbacktrace -I . -I . -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/. -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../include -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcpp/include -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcody -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber/bid -I ../libdecnumber -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libbacktrace -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/11/../../../../include/c++/11 -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/11/../../../../include/c++/11/x86_64-suse-linux -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/11/../../../../include/c++/11/backward -internal-isystem /usr/lib64/clang/13.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/11/../../../../x86_64-suse-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-narrowing -Wwrite-strings -Wno-error=format-diag -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -Wno-error -fdeprecated-macro -fdebug-compilation-dir=/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=plist-html -analyzer-config silence-checkers=core.NullDereference -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/clang-static-analyzer/2021-11-20-133755-20252-1/report-JIfiFq.plist -x c++ /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c
1/* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3/* Copyright (C) 2014-2021 Free Software Foundation, Inc.
4 Contributed by Rong Xu <xur@google.com>.
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 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25<http://www.gnu.org/licenses/>. */
26
27
28#define IN_GCOV_TOOL1 1
29
30#include "libgcov.h"
31#include "intl.h"
32#include "diagnostic.h"
33#include "version.h"
34#include "demangle.h"
35#include "gcov-io.h"
36
37/* Borrowed from basic-block.h. */
38#define RDIV(X,Y)(((X) + (Y) / 2) / (Y)) (((X) + (Y) / 2) / (Y))
39
40extern gcov_position_t gcov_position();
41extern int gcov_is_error();
42
43/* Verbose mode for debug. */
44static int verbose;
45
46/* Set verbose flag. */
47void gcov_set_verbose (void)
48{
49 verbose = 1;
50}
51
52/* The following part is to read Gcda and reconstruct GCOV_INFO. */
53
54#include "obstack.h"
55#include <unistd.h>
56#ifdef HAVE_FTW_H1
57#include <ftw.h>
58#endif
59
60static void tag_function (unsigned, int);
61static void tag_blocks (unsigned, int);
62static void tag_arcs (unsigned, int);
63static void tag_lines (unsigned, int);
64static void tag_counters (unsigned, int);
65static void tag_summary (unsigned, int);
66
67/* The gcov_info for the first module. */
68static struct gcov_info *curr_gcov_info;
69/* The gcov_info being processed. */
70static struct gcov_info *gcov_info_head;
71/* This variable contains all the functions in current module. */
72static struct obstack fn_info;
73/* The function being processed. */
74static struct gcov_fn_info *curr_fn_info;
75/* The number of functions seen so far. */
76static unsigned num_fn_info;
77/* This variable contains all the counters for current module. */
78static int k_ctrs_mask[GCOV_COUNTERS];
79/* The kind of counters that have been seen. */
80static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
81/* Number of kind of counters that have been seen. */
82static int k_ctrs_types;
83
84/* Merge functions for counters. */
85#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
86static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
87#include "gcov-counter.def"
88};
89#undef DEF_GCOV_COUNTER
90
91/* Set the ctrs field in gcov_fn_info object FN_INFO. */
92
93static void
94set_fn_ctrs (struct gcov_fn_info *fn_info)
95{
96 int j = 0, i;
97
98 for (i = 0; i < GCOV_COUNTERS; i++)
99 {
100 if (k_ctrs_mask[i] == 0)
101 continue;
102 fn_info->ctrs[j].num = k_ctrs[i].num;
103 fn_info->ctrs[j].values = k_ctrs[i].values;
104 j++;
105 }
106 if (k_ctrs_types == 0)
107 k_ctrs_types = j;
108 else
109 gcc_assert (j == k_ctrs_types)((void)(!(j == k_ctrs_types) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 109, __FUNCTION__), 0 : 0))
;
110}
111
112/* For each tag in gcda file, we have an entry here.
113 TAG is the tag value; NAME is the tag name; and
114 PROC is the handler function. */
115
116typedef struct tag_format
117{
118 unsigned tag;
119 char const *name;
120 void (*proc) (unsigned, int);
121} tag_format_t;
122
123/* Handler table for various Tags. */
124
125static const tag_format_t tag_table[] =
126{
127 {0, "NOP", NULL__null},
128 {0, "UNKNOWN", NULL__null},
129 {0, "COUNTERS", tag_counters},
130 {GCOV_TAG_FUNCTION((gcov_unsigned_t)0x01000000), "FUNCTION", tag_function},
131 {GCOV_TAG_BLOCKS((gcov_unsigned_t)0x01410000), "BLOCKS", tag_blocks},
132 {GCOV_TAG_ARCS((gcov_unsigned_t)0x01430000), "ARCS", tag_arcs},
133 {GCOV_TAG_LINES((gcov_unsigned_t)0x01450000), "LINES", tag_lines},
134 {GCOV_TAG_OBJECT_SUMMARY((gcov_unsigned_t)0xa1000000), "OBJECT_SUMMARY", tag_summary},
135 {0, NULL__null, NULL__null}
136};
137
138/* Handler for reading function tag. */
139
140static void
141tag_function (unsigned tag ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int length ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
142{
143 int i;
144
145 /* write out previous fn_info. */
146 if (num_fn_info)
147 {
148 set_fn_ctrs (curr_fn_info);
149 obstack_ptr_grow (&fn_info, curr_fn_info)__extension__ ({ struct obstack *__o = (&fn_info); if (__extension__
({ struct obstack const *__o1 = (__o); (size_t) (__o1->chunk_limit
- __o1->next_free); }) < sizeof (void *)) _obstack_newchunk
(__o, sizeof (void *)); __extension__ ({ struct obstack *__o1
= (__o); void *__p1 = __o1->next_free; *(const void **) __p1
= (curr_fn_info); __o1->next_free += sizeof (const void *
); (void) 0; }); })
;
150 }
151
152 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
153 counter types. */
154 curr_fn_info = (struct gcov_fn_info *) xcalloccalloc (sizeof (struct gcov_fn_info)
155 + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
156
157 for (i = 0; i < GCOV_COUNTERS; i++)
158 k_ctrs[i].num = 0;
159 k_ctrs_types = 0;
160
161 curr_fn_info->key = curr_gcov_info;
162 curr_fn_info->ident = gcov_read_unsigned ();
163 curr_fn_info->lineno_checksum = gcov_read_unsigned ();
164 curr_fn_info->cfg_checksum = gcov_read_unsigned ();
165 num_fn_info++;
166
167 if (verbose)
168 fnotice (stdoutstdout, "tag one function id=%d\n", curr_fn_info->ident);
169}
170
171/* Handler for reading block tag. */
172
173static void
174tag_blocks (unsigned tag ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int length ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
175{
176 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
177 gcc_unreachable ()(fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 177, __FUNCTION__))
;
178}
179
180/* Handler for reading flow arc tag. */
181
182static void
183tag_arcs (unsigned tag ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int length ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
184{
185 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
186 gcc_unreachable ()(fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 186, __FUNCTION__))
;
187}
188
189/* Handler for reading line tag. */
190
191static void
192tag_lines (unsigned tag ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int length ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
193{
194 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
195 gcc_unreachable ()(fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 195, __FUNCTION__))
;
196}
197
198/* Handler for reading counters array tag with value as TAG and length of LENGTH. */
199
200static void
201tag_counters (unsigned tag, int length)
202{
203 unsigned n_counts = GCOV_TAG_COUNTER_NUM (abs (length))((abs (length) / 4) / 2);
204 gcov_type *values;
205 unsigned ix;
206 unsigned tag_ix;
207
208 tag_ix = GCOV_COUNTER_FOR_TAG (tag)((unsigned)(((tag) - ((gcov_unsigned_t)0x01a10000)) >> 17
))
;
209 gcc_assert (tag_ix < GCOV_COUNTERS)((void)(!(tag_ix < GCOV_COUNTERS) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 209, __FUNCTION__), 0 : 0))
;
210 k_ctrs_mask [tag_ix] = 1;
211 gcc_assert (k_ctrs[tag_ix].num == 0)((void)(!(k_ctrs[tag_ix].num == 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 211, __FUNCTION__), 0 : 0))
;
212 k_ctrs[tag_ix].num = n_counts;
213
214 k_ctrs[tag_ix].values = values = (gcov_type *) xcalloccalloc (sizeof (gcov_type),
215 n_counts);
216 gcc_assert (values)((void)(!(values) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 216, __FUNCTION__), 0 : 0))
;
217
218 if (length > 0)
219 for (ix = 0; ix != n_counts; ix++)
220 values[ix] = gcov_read_counter ();
221}
222
223/* Handler for reading summary tag. */
224
225static void
226tag_summary (unsigned tag ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
227{
228 gcov_read_summary (&curr_gcov_info->summary);
229}
230
231/* This function is called at the end of reading a gcda file.
232 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
233
234static void
235read_gcda_finalize (struct gcov_info *obj_info)
236{
237 int i;
238
239 set_fn_ctrs (curr_fn_info);
240 obstack_ptr_grow (&fn_info, curr_fn_info)__extension__ ({ struct obstack *__o = (&fn_info); if (__extension__
({ struct obstack const *__o1 = (__o); (size_t) (__o1->chunk_limit
- __o1->next_free); }) < sizeof (void *)) _obstack_newchunk
(__o, sizeof (void *)); __extension__ ({ struct obstack *__o1
= (__o); void *__p1 = __o1->next_free; *(const void **) __p1
= (curr_fn_info); __o1->next_free += sizeof (const void *
); (void) 0; }); })
;
241
242 /* We set the following fields: merge, n_functions, functions
243 and summary. */
244 obj_info->n_functions = num_fn_info;
245 obj_info->functions = (struct gcov_fn_info**) obstack_finish (&fn_info)__extension__ ({ struct obstack *__o1 = (&fn_info); void *
__value = (void *) __o1->object_base; if (__o1->next_free
== __value) __o1->maybe_empty_object = 1; __o1->next_free
= (sizeof (ptrdiff_t) < sizeof (void *) ? ((__o1->object_base
) + (((__o1->next_free) - (__o1->object_base) + (__o1->
alignment_mask)) & ~(__o1->alignment_mask))) : (char *
) (((ptrdiff_t) (__o1->next_free) + (__o1->alignment_mask
)) & ~(__o1->alignment_mask))); if ((size_t) (__o1->
next_free - (char *) __o1->chunk) > (size_t) (__o1->
chunk_limit - (char *) __o1->chunk)) __o1->next_free = __o1
->chunk_limit; __o1->object_base = __o1->next_free; __value
; })
;
246
247 /* wrap all the counter array. */
248 for (i=0; i< GCOV_COUNTERS; i++)
249 {
250 if (k_ctrs_mask[i])
251 obj_info->merge[i] = ctr_merge_functions[i];
252 }
253}
254
255/* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
256 Program level summary CURRENT_SUMMARY will also be updated. */
257
258static struct gcov_info *
259read_gcda_file (const char *filename)
260{
261 unsigned tags[4];
262 unsigned depth = 0;
263 unsigned version;
264 struct gcov_info *obj_info;
265 int i;
266
267 for (i=0; i< GCOV_COUNTERS; i++)
268 k_ctrs_mask[i] = 0;
269 k_ctrs_types = 0;
270
271 if (!gcov_open (filename))
272 {
273 fnotice (stderrstderr, "%s:cannot open\n", filename);
274 return NULL__null;
275 }
276
277 /* Read magic. */
278 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC((gcov_unsigned_t)0x67636461)))
279 {
280 fnotice (stderrstderr, "%s:not a gcov data file\n", filename);
281 gcov_close ();
282 return NULL__null;
283 }
284
285 /* Read version. */
286 version = gcov_read_unsigned ();
287 if (version != GCOV_VERSION((gcov_unsigned_t)0x42323020))
288 {
289 fnotice (stderrstderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION((gcov_unsigned_t)0x42323020));
290 gcov_close ();
291 return NULL__null;
292 }
293
294 /* Instantiate a gcov_info object. */
295 curr_gcov_info = obj_info = (struct gcov_info *) xcalloccalloc (sizeof (struct gcov_info) +
296 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
297
298 obj_info->version = version;
299 obstack_init (&fn_info)_obstack_begin ((&fn_info), 0, 0, (mempool_obstack_chunk_alloc
), (mempool_obstack_chunk_free))
;
300 num_fn_info = 0;
301 curr_fn_info = 0;
302 {
303 size_t len = strlen (filename) + 1;
304 char *str_dup = (char*) xmallocmalloc (len);
305
306 memcpy (str_dup, filename, len);
307 obj_info->filename = str_dup;
308 }
309
310 /* Read stamp. */
311 obj_info->stamp = gcov_read_unsigned ();
312
313 /* Read checksum. */
314 obj_info->checksum = gcov_read_unsigned ();
315
316 while (1)
317 {
318 gcov_position_t base;
319 unsigned tag, length;
320 tag_format_t const *format;
321 unsigned tag_depth;
322 int error;
323 unsigned mask;
324
325 tag = gcov_read_unsigned ();
326 if (!tag)
327 break;
328 int read_length = (int)gcov_read_unsigned ();
329 length = read_length > 0 ? read_length : 0;
330 base = gcov_position ();
331 mask = GCOV_TAG_MASK (tag)(((tag) - 1) ^ (tag)) >> 1;
332 for (tag_depth = 4; mask; mask >>= 8)
333 {
334 if (((mask & 0xff) != 0xff))
335 {
336 warning (0, "%s:tag %qx is invalid", filename, tag);
337 break;
338 }
339 tag_depth--;
340 }
341 for (format = tag_table; format->name; format++)
342 if (format->tag == tag)
343 goto found;
344 format = &tag_table[GCOV_TAG_IS_COUNTER (tag)(!((tag) & 0xFFFF) && ((unsigned)(((tag) - ((gcov_unsigned_t
)0x01a10000)) >> 17)) < GCOV_COUNTERS)
? 2 : 1];
345 found:;
346 if (tag)
347 {
348 if (depth && depth < tag_depth)
349 {
350 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)((((tags[depth - 1]) - 1) ^ (tags[depth - 1])) >> 8 == (
((tag) - 1) ^ (tag)) && !(((tag) ^ (tags[depth - 1]))
& ~(((tags[depth - 1]) - 1) ^ (tags[depth - 1]))))
)
351 warning (0, "%s:tag %qx is incorrectly nested",
352 filename, tag);
353 }
354 depth = tag_depth;
355 tags[depth - 1] = tag;
356 }
357
358 if (format->proc)
359 {
360 unsigned long actual_length;
361
362 (*format->proc) (tag, read_length);
363
364 actual_length = gcov_position () - base;
365 if (actual_length > length)
366 warning (0, "%s:record size mismatch %lu bytes overread",
367 filename, actual_length - length);
368 else if (length > actual_length)
369 warning (0, "%s:record size mismatch %lu bytes unread",
370 filename, length - actual_length);
371 }
372
373 gcov_sync (base, length);
374 if ((error = gcov_is_error ()))
375 {
376 warning (0, error < 0 ? "%s:counter overflow at %lu" :
377 "%s:read error at %lu", filename,
378 (long unsigned) gcov_position ());
379 break;
380 }
381 }
382
383 read_gcda_finalize (obj_info);
384 gcov_close ();
385
386 return obj_info;
387}
388
389#ifdef HAVE_FTW_H1
390/* This will be called by ftw(). It opens and read a gcda file FILENAME.
391 Return a non-zero value to stop the tree walk. */
392
393static int
394ftw_read_file (const char *filename,
395 const struct stat *status ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
396 int type)
397{
398 int filename_len;
399 int suffix_len;
400 struct gcov_info *obj_info;
401
402 /* Only read regular files. */
403 if (type != FTW_FFTW_F)
404 return 0;
405
406 filename_len = strlen (filename);
407 suffix_len = strlen (GCOV_DATA_SUFFIX".gcda");
408
409 if (filename_len <= suffix_len)
410 return 0;
411
412 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX".gcda"))
413 return 0;
414
415 if (verbose)
416 fnotice (stderrstderr, "reading file: %s\n", filename);
417
418 obj_info = read_gcda_file (filename);
419 if (!obj_info)
420 return 0;
421
422 obj_info->next = gcov_info_head;
423 gcov_info_head = obj_info;
424
425 return 0;
426}
427#endif
428
429/* Initializer for reading a profile dir. */
430
431static inline void
432read_profile_dir_init (void)
433{
434 gcov_info_head = 0;
435}
436
437/* Driver for read a profile directory and convert into gcov_info list in memory.
438 Return NULL on error,
439 Return the head of gcov_info list on success. */
440
441struct gcov_info *
442gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
443{
444 char *pwd;
445 int ret;
446
447 read_profile_dir_init ();
448
449 if (access (dir_name, R_OK4) != 0)
450 {
451 fnotice (stderrstderr, "cannot access directory %s\n", dir_name);
452 return NULL__null;
453 }
454 pwd = getcwd (NULL__null, 0);
455 gcc_assert (pwd)((void)(!(pwd) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 455, __FUNCTION__), 0 : 0))
;
456 ret = chdir (dir_name);
457 if (ret !=0)
458 {
459 fnotice (stderrstderr, "%s is not a directory\n", dir_name);
460 return NULL__null;
461 }
462#ifdef HAVE_FTW_H1
463 ftw (".", ftw_read_file, 50);
464#endif
465 chdir (pwd);
466 free (pwd);
467
468 return gcov_info_head;;
469}
470
471/* This part of the code is to merge profile counters. These
472 variables are set in merge_wrapper and to be used by
473 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
474
475/* We save the counter value address to this variable. */
476static gcov_type *gcov_value_buf;
477
478/* The number of counter values to be read by current merging. */
479static gcov_unsigned_t gcov_value_buf_size;
480
481/* The index of counter values being read. */
482static gcov_unsigned_t gcov_value_buf_pos;
483
484/* The weight of current merging. */
485static unsigned gcov_merge_weight;
486
487/* Read a counter value from gcov_value_buf array. */
488
489gcov_type
490gcov_read_counter_mem (void)
491{
492 gcov_type ret;
493 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size)((void)(!(gcov_value_buf_pos < gcov_value_buf_size) ? fancy_abort
("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 493, __FUNCTION__), 0 : 0))
;
494 ret = *(gcov_value_buf + gcov_value_buf_pos);
495 ++gcov_value_buf_pos;
496 return ret;
497}
498
499/* Return the recorded merge weight. */
500
501unsigned
502gcov_get_merge_weight (void)
503{
504 return gcov_merge_weight;
505}
506
507/* A wrapper function for merge functions. It sets up the
508 value buffer and weights and then calls the merge function. */
509
510static void
511merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n1,
512 gcov_type *v2, gcov_unsigned_t n2, unsigned w)
513{
514 gcov_value_buf = v2;
515 gcov_value_buf_pos = 0;
516 gcov_value_buf_size = n2;
517 gcov_merge_weight = w;
518 (*f) (v1, n1);
519}
520
521/* Convert on disk representation of a TOPN counter to in memory representation
522 that is expected from __gcov_merge_topn function. */
523
524static void
525topn_to_memory_representation (struct gcov_ctr_info *info)
526{
527 auto_vec<gcov_type> output;
528 gcov_type *values = info->values;
529 int count = info->num;
530
531 while (count > 0)
532 {
533 output.safe_push (values[0]);
534 gcov_type n = values[1];
535 output.safe_push (n);
536 if (n > 0)
537 {
538 struct gcov_kvp *tuples
539 = (struct gcov_kvp *)xcalloccalloc (sizeof (struct gcov_kvp), n);
540 for (unsigned i = 0; i < n - 1; i++)
541 tuples[i].next = &tuples[i + 1];
542 for (unsigned i = 0; i < n; i++)
543 {
544 tuples[i].value = values[2 + 2 * i];
545 tuples[i].count = values[2 + 2 * i + 1];
546 }
547 output.safe_push ((intptr_t)&tuples[0]);
548 }
549 else
550 output.safe_push (0);
551
552 unsigned len = 2 * n + 2;
553 values += len;
554 count -= len;
555 }
556 gcc_assert (count == 0)((void)(!(count == 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 556, __FUNCTION__), 0 : 0))
;
557
558 /* Allocate new buffer and copy it there. */
559 info->num = output.length ();
560 info->values = (gcov_type *)xmallocmalloc (sizeof (gcov_type) * info->num);
561 for (unsigned i = 0; i < info->num; i++)
562 info->values[i] = output[i];
563}
564
565/* Offline tool to manipulate profile data.
566 This tool targets on matched profiles. But it has some tolerance on
567 unmatched profiles.
568 When merging p1 to p2 (p2 is the dst),
569 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
570 emit warning
571 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
572 specified weight; emit warning.
573 * m.gcda in both p1 and p2:
574 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
575 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
576 p2->m.gcda->f and
577 drop p1->m.gcda->f. A warning is emitted. */
578
579/* Add INFO2's counter to INFO1, multiplying by weight W. */
580
581static int
582gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
583{
584 unsigned f_ix;
585 unsigned n_functions = info1->n_functions;
586 int has_mismatch = 0;
587
588 gcc_assert (info2->n_functions == n_functions)((void)(!(info2->n_functions == n_functions) ? fancy_abort
("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 588, __FUNCTION__), 0 : 0))
;
589
590 /* Merge summary. */
591 info1->summary.runs += info2->summary.runs;
592 info1->summary.sum_max += info2->summary.sum_max;
593
594 for (f_ix = 0; f_ix < n_functions; f_ix++)
595 {
596 unsigned t_ix;
597 struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
598 struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
599 struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
600
601 if (!gfi_ptr1 || gfi_ptr1->key != info1)
602 continue;
603 if (!gfi_ptr2 || gfi_ptr2->key != info2)
604 continue;
605
606 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
607 {
608 fnotice (stderrstderr, "in %s, cfg_checksum mismatch, skipping\n",
609 info1->filename);
610 has_mismatch = 1;
611 continue;
612 }
613 ci_ptr1 = gfi_ptr1->ctrs;
614 ci_ptr2 = gfi_ptr2->ctrs;
615 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
616 {
617 gcov_merge_fn merge1 = info1->merge[t_ix];
618 gcov_merge_fn merge2 = info2->merge[t_ix];
619
620 gcc_assert (merge1 == merge2)((void)(!(merge1 == merge2) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 620, __FUNCTION__), 0 : 0))
;
621 if (!merge1)
622 continue;
623
624 if (merge1 == __gcov_merge_topn)
625 topn_to_memory_representation (ci_ptr1);
626 else
627 gcc_assert (ci_ptr1->num == ci_ptr2->num)((void)(!(ci_ptr1->num == ci_ptr2->num) ? fancy_abort (
"/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 627, __FUNCTION__), 0 : 0))
;
628
629 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num,
630 ci_ptr2->values, ci_ptr2->num, w);
631 ci_ptr1++;
632 ci_ptr2++;
633 }
634 }
635
636 return has_mismatch;
637}
638
639/* Find and return the match gcov_info object for INFO from ARRAY.
640 SIZE is the length of ARRAY.
641 Return NULL if there is no match. */
642
643static struct gcov_info *
644find_match_gcov_info (struct gcov_info **array, int size,
645 struct gcov_info *info)
646{
647 struct gcov_info *gi_ptr;
648 struct gcov_info *ret = NULL__null;
649 int i;
650
651 for (i = 0; i < size; i++)
652 {
653 gi_ptr = array[i];
654 if (gi_ptr == 0)
655 continue;
656 if (!strcmp (gi_ptr->filename, info->filename))
657 {
658 ret = gi_ptr;
659 array[i] = 0;
660 break;
661 }
662 }
663
664 if (ret && ret->n_functions != info->n_functions)
665 {
666 fnotice (stderrstderr, "mismatched profiles in %s (%d functions"
667 " vs %d functions)\n",
668 ret->filename,
669 ret->n_functions,
670 info->n_functions);
671 ret = NULL__null;
672 }
673 return ret;
674}
675
676/* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
677 Return 0 on success: without mismatch.
678 Reutrn 1 on error. */
679
680int
681gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
682 int w1, int w2)
683{
684 struct gcov_info *gi_ptr;
685 struct gcov_info **tgt_infos;
686 struct gcov_info *tgt_tail;
687 struct gcov_info **in_src_not_tgt;
688 unsigned tgt_cnt = 0, src_cnt = 0;
689 unsigned unmatch_info_cnt = 0;
690 unsigned int i;
691
692 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
1
Loop condition is false. Execution continues on line 694
693 tgt_cnt++;
694 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
2
Loop condition is false. Execution continues on line 696
695 src_cnt++;
696 tgt_infos = (struct gcov_info **) xmallocmalloc (sizeof (struct gcov_info *)
3
Memory is allocated
697 * tgt_cnt);
698 gcc_assert (tgt_infos)((void)(!(tgt_infos) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 698, __FUNCTION__), 0 : 0))
;
4
Assuming 'tgt_infos' is non-null
5
'?' condition is false
699 in_src_not_tgt = (struct gcov_info **) xmallocmalloc (sizeof (struct gcov_info *)
700 * src_cnt);
701 gcc_assert (in_src_not_tgt)((void)(!(in_src_not_tgt) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 701, __FUNCTION__), 0 : 0))
;
6
Assuming 'in_src_not_tgt' is non-null
7
'?' condition is false
702
703 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
8
Loop condition is false. Execution continues on line 706
704 tgt_infos[i] = gi_ptr;
705
706 tgt_tail = tgt_infos[tgt_cnt - 1];
9
Use of zero-allocated memory
707
708 /* First pass on tgt_profile, we multiply w1 to all counters. */
709 if (w1 > 1)
710 {
711 for (i = 0; i < tgt_cnt; i++)
712 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
713 }
714
715 /* Second pass, add src_profile to the tgt_profile. */
716 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
717 {
718 struct gcov_info *gi_ptr1;
719
720 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
721 if (gi_ptr1 == NULL__null)
722 {
723 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
724 continue;
725 }
726 gcov_merge (gi_ptr1, gi_ptr, w2);
727 }
728
729 /* For modules in src but not in tgt. We adjust the counter and append. */
730 for (i = 0; i < unmatch_info_cnt; i++)
731 {
732 gi_ptr = in_src_not_tgt[i];
733 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
734 gi_ptr->next = NULL__null;
735 tgt_tail->next = gi_ptr;
736 tgt_tail = gi_ptr;
737 }
738
739 free (in_src_not_tgt);
740 free (tgt_infos);
741
742 return 0;
743}
744
745typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
746
747/* Performing FN upon arc counters. */
748
749static void
750__gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
751 counter_op_fn fn, void *data1, void *data2)
752{
753 for (; n_counters; counters++, n_counters--)
754 {
755 gcov_type val = *counters;
756 *counters = fn(val, data1, data2);
757 }
758}
759
760/* Performing FN upon ior counters. */
761
762static void
763__gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
764 unsigned n_counters ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
765 counter_op_fn fn ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
766 void *data1 ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
767 void *data2 ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
768{
769 /* Do nothing. */
770}
771
772/* Performing FN upon time-profile counters. */
773
774static void
775__gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
776 unsigned n_counters ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
777 counter_op_fn fn ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
778 void *data1 ATTRIBUTE_UNUSED__attribute__ ((__unused__)),
779 void *data2 ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
780{
781 /* Do nothing. */
782}
783
784/* Performing FN upon TOP N counters. */
785
786static void
787__gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
788 counter_op_fn fn, void *data1, void *data2)
789{
790 unsigned i, n_measures;
791
792 gcc_assert (!(n_counters % 3))((void)(!(!(n_counters % 3)) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 792, __FUNCTION__), 0 : 0))
;
793 n_measures = n_counters / 3;
794 for (i = 0; i < n_measures; i++, counters += 3)
795 {
796 counters[1] = fn (counters[1], data1, data2);
797 counters[2] = fn (counters[2], data1, data2);
798 }
799}
800
801/* Scaling the counter value V by multiplying *(float*) DATA1. */
802
803static gcov_type
804fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED__attribute__ ((__unused__)))
805{
806 float f = *(float *) data1;
807 return (gcov_type) (v * f);
808}
809
810/* Scaling the counter value V by multiplying DATA2/DATA1. */
811
812static gcov_type
813int_scale (gcov_type v, void *data1, void *data2)
814{
815 int n = *(int *) data1;
816 int d = *(int *) data2;
817 return (gcov_type) ( RDIV (v,d)(((v) + (d) / 2) / (d)) * n);
818}
819
820/* Type of function used to process counters. */
821typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
822 counter_op_fn, void *, void *);
823
824/* Function array to process profile counters. */
825#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
826 __gcov ## FN_TYPE ## _counter_op,
827static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
828#include "gcov-counter.def"
829};
830#undef DEF_GCOV_COUNTER
831
832/* Driver for scaling profile counters. */
833
834int
835gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
836{
837 struct gcov_info *gi_ptr;
838 unsigned f_ix;
839
840 if (verbose)
841 fnotice (stdoutstdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
842
843 /* Scaling the counters. */
844 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
845 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
846 {
847 unsigned t_ix;
848 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
849 const struct gcov_ctr_info *ci_ptr;
850
851 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
852 continue;
853
854 ci_ptr = gfi_ptr->ctrs;
855 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
856 {
857 gcov_merge_fn merge = gi_ptr->merge[t_ix];
858
859 if (!merge)
860 continue;
861 if (d == 0)
862 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
863 fp_scale, &scale_factor, NULL__null);
864 else
865 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
866 int_scale, &n, &d);
867 ci_ptr++;
868 }
869 }
870
871 return 0;
872}
873
874/* Driver to normalize profile counters. */
875
876int
877gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
878{
879 struct gcov_info *gi_ptr;
880 gcov_type curr_max_val = 0;
881 unsigned f_ix;
882 unsigned int i;
883 float scale_factor;
884
885 /* Find the largest count value. */
886 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
887 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
888 {
889 unsigned t_ix;
890 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
891 const struct gcov_ctr_info *ci_ptr;
892
893 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
894 continue;
895
896 ci_ptr = gfi_ptr->ctrs;
897 for (t_ix = 0; t_ix < 1; t_ix++)
898 {
899 for (i = 0; i < ci_ptr->num; i++)
900 if (ci_ptr->values[i] > curr_max_val)
901 curr_max_val = ci_ptr->values[i];
902 ci_ptr++;
903 }
904 }
905
906 scale_factor = (float)max_val / curr_max_val;
907 if (verbose)
908 fnotice (stdoutstdout, "max_val is %" PRId64"l" "d" "\n", curr_max_val);
909
910 return gcov_profile_scale (profile, scale_factor, 0, 0);
911}
912
913/* The following variables are defined in gcc/gcov-tool.c. */
914extern int overlap_func_level;
915extern int overlap_obj_level;
916extern int overlap_hot_only;
917extern int overlap_use_fullname;
918extern double overlap_hot_threshold;
919
920/* Compute the overlap score of two values. The score is defined as:
921 min (V1/SUM_1, V2/SUM_2) */
922
923static double
924calculate_2_entries (const unsigned long v1, const unsigned long v2,
925 const double sum_1, const double sum_2)
926{
927 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
928 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
929
930 if (val2 < val1)
931 val1 = val2;
932
933 return val1;
934}
935
936/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
937 This function also updates cumulative score CUM_1_RESULT and
938 CUM_2_RESULT. */
939
940static double
941compute_one_gcov (const struct gcov_info *gcov_info1,
942 const struct gcov_info *gcov_info2,
943 const double sum_1, const double sum_2,
944 double *cum_1_result, double *cum_2_result)
945{
946 unsigned f_ix;
947 double ret = 0;
948 double cum_1 = 0, cum_2 = 0;
949 const struct gcov_info *gcov_info = 0;
950 double *cum_p;
951 double sum;
952
953 gcc_assert (gcov_info1 || gcov_info2)((void)(!(gcov_info1 || gcov_info2) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 953, __FUNCTION__), 0 : 0))
;
954 if (!gcov_info1)
955 {
956 gcov_info = gcov_info2;
957 cum_p = cum_2_result;
958 sum = sum_2;
959 *cum_1_result = 0;
960 } else
961 if (!gcov_info2)
962 {
963 gcov_info = gcov_info1;
964 cum_p = cum_1_result;
965 sum = sum_1;
966 *cum_2_result = 0;
967 }
968
969 if (gcov_info)
970 {
971 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
972 {
973 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
974 if (!gfi_ptr || gfi_ptr->key != gcov_info)
975 continue;
976 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
977 unsigned c_num;
978 for (c_num = 0; c_num < ci_ptr->num; c_num++)
979 cum_1 += ci_ptr->values[c_num] / sum;
980 }
981 *cum_p = cum_1;
982 return 0.0;
983 }
984
985 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
986 {
987 double func_cum_1 = 0.0;
988 double func_cum_2 = 0.0;
989 double func_val = 0.0;
990 int nonzero = 0;
991 int hot = 0;
992 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
993 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
994
995 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
996 continue;
997 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
998 continue;
999
1000 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
1001 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
1002 unsigned c_num;
1003 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
1004 {
1005 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1006 {
1007 func_val += calculate_2_entries (ci_ptr1->values[c_num],
1008 ci_ptr2->values[c_num],
1009 sum_1, sum_2);
1010
1011 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1012 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1013 nonzero = 1;
1014 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
1015 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1016 hot = 1;
1017 }
1018 }
1019
1020 ret += func_val;
1021 cum_1 += func_cum_1;
1022 cum_2 += func_cum_2;
1023 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1024 {
1025 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1026 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1027 }
1028 }
1029 *cum_1_result = cum_1;
1030 *cum_2_result = cum_2;
1031 return ret;
1032}
1033
1034/* Test if all counter values in this GCOV_INFO are cold.
1035 "Cold" is defined as the counter value being less than
1036 or equal to THRESHOLD. */
1037
1038static bool
1039gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1040 gcov_type threshold)
1041{
1042 unsigned f_ix;
1043
1044 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1045 {
1046 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1047
1048 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1049 continue;
1050 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1051 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
1052 if (ci_ptr->values[c_num] > threshold)
1053 return false;
1054 }
1055
1056 return true;
1057}
1058
1059/* Test if all counter values in this GCOV_INFO are 0. */
1060
1061static bool
1062gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1063{
1064 return gcov_info_count_all_cold (gcov_info, 0);
1065}
1066
1067/* A pair of matched GCOV_INFO.
1068 The flag is a bitvector:
1069 b0: obj1's all counts are 0;
1070 b1: obj1's all counts are cold (but no 0);
1071 b2: obj1 is hot;
1072 b3: no obj1 to match obj2;
1073 b4: obj2's all counts are 0;
1074 b5: obj2's all counts are cold (but no 0);
1075 b6: obj2 is hot;
1076 b7: no obj2 to match obj1;
1077 */
1078struct overlap_t {
1079 const struct gcov_info *obj1;
1080 const struct gcov_info *obj2;
1081 char flag;
1082};
1083
1084#define FLAG_BOTH_ZERO(flag)((flag & 0x1) && (flag & 0x10)) ((flag & 0x1) && (flag & 0x10))
1085#define FLAG_BOTH_COLD(flag)((flag & 0x2) && (flag & 0x20)) ((flag & 0x2) && (flag & 0x20))
1086#define FLAG_ONE_HOT(flag)((flag & 0x4) || (flag & 0x40)) ((flag & 0x4) || (flag & 0x40))
1087
1088/* Cumlative overlap dscore for profile1 and profile2. */
1089static double overlap_sum_1, overlap_sum_2;
1090
1091/* The number of gcda files in the profiles. */
1092static unsigned gcda_files[2];
1093
1094/* The number of unique gcda files in the profiles
1095 (not existing in the other profile). */
1096static unsigned unique_gcda_files[2];
1097
1098/* The number of gcda files that all counter values are 0. */
1099static unsigned zero_gcda_files[2];
1100
1101/* The number of gcda files that all counter values are cold (but not 0). */
1102static unsigned cold_gcda_files[2];
1103
1104/* The number of gcda files that includes hot counter values. */
1105static unsigned hot_gcda_files[2];
1106
1107/* The number of gcda files with hot count value in either profiles. */
1108static unsigned both_hot_cnt;
1109
1110/* The number of gcda files with all counts cold (but not 0) in
1111 both profiles. */
1112static unsigned both_cold_cnt;
1113
1114/* The number of gcda files with all counts 0 in both profiles. */
1115static unsigned both_zero_cnt;
1116
1117/* Extract the basename of the filename NAME. */
1118
1119static char *
1120extract_file_basename (const char *name)
1121{
1122 char *str;
1123 int len = 0;
1124 char *path = xstrdup (name);
1125 char sep_str[2];
1126
1127 sep_str[0] = DIR_SEPARATOR'/';
1128 sep_str[1] = 0;
1129 str = strstr(path, sep_str);
1130 do{
1131 len = strlen(str) + 1;
1132 path = &path[strlen(path) - len + 2];
1133 str = strstr(path, sep_str);
1134 } while(str);
1135
1136 return path;
1137}
1138
1139/* Utility function to get the filename. */
1140
1141static const char *
1142get_file_basename (const char *name)
1143{
1144 if (overlap_use_fullname)
1145 return name;
1146 return extract_file_basename (name);
1147}
1148
1149/* A utility function to set the flag for the gcda files. */
1150
1151static void
1152set_flag (struct overlap_t *e)
1153{
1154 char flag = 0;
1155
1156 if (!e->obj1)
1157 {
1158 unique_gcda_files[1]++;
1159 flag = 0x8;
1160 }
1161 else
1162 {
1163 gcda_files[0]++;
1164 if (gcov_info_count_all_zero (e->obj1))
1165 {
1166 zero_gcda_files[0]++;
1167 flag = 0x1;
1168 }
1169 else
1170 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1171 * overlap_hot_threshold))
1172 {
1173 cold_gcda_files[0]++;
1174 flag = 0x2;
1175 }
1176 else
1177 {
1178 hot_gcda_files[0]++;
1179 flag = 0x4;
1180 }
1181 }
1182
1183 if (!e->obj2)
1184 {
1185 unique_gcda_files[0]++;
1186 flag |= (0x8 << 4);
1187 }
1188 else
1189 {
1190 gcda_files[1]++;
1191 if (gcov_info_count_all_zero (e->obj2))
1192 {
1193 zero_gcda_files[1]++;
1194 flag |= (0x1 << 4);
1195 }
1196 else
1197 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1198 * overlap_hot_threshold))
1199 {
1200 cold_gcda_files[1]++;
1201 flag |= (0x2 << 4);
1202 }
1203 else
1204 {
1205 hot_gcda_files[1]++;
1206 flag |= (0x4 << 4);
1207 }
1208 }
1209
1210 gcc_assert (flag)((void)(!(flag) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 1210, __FUNCTION__), 0 : 0))
;
1211 e->flag = flag;
1212}
1213
1214/* Test if INFO1 and INFO2 are from the matched source file.
1215 Return 1 if they match; return 0 otherwise. */
1216
1217static int
1218matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1219{
1220 /* For FDO, we have to match the name. This can be expensive.
1221 Maybe we should use hash here. */
1222 if (strcmp (info1->filename, info2->filename))
1223 return 0;
1224
1225 if (info1->n_functions != info2->n_functions)
1226 {
1227 fnotice (stderrstderr, "mismatched profiles in %s (%d functions"
1228 " vs %d functions)\n",
1229 info1->filename,
1230 info1->n_functions,
1231 info2->n_functions);
1232 return 0;
1233 }
1234 return 1;
1235}
1236
1237/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1238 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1239 match and 1.0 meaning a perfect match. */
1240
1241static double
1242calculate_overlap (struct gcov_info *gcov_list1,
1243 struct gcov_info *gcov_list2)
1244{
1245 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1246 unsigned int i, j;
1247 const struct gcov_info *gi_ptr;
1248 struct overlap_t *all_infos;
1249
1250 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1251 list1_cnt++;
1252 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1253 list2_cnt++;
1254 all_cnt = list1_cnt + list2_cnt;
1255 all_infos = (struct overlap_t *) xmallocmalloc (sizeof (struct overlap_t)
1256 * all_cnt * 2);
1257 gcc_assert (all_infos)((void)(!(all_infos) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libgcc/libgcov-util.c"
, 1257, __FUNCTION__), 0 : 0))
;
1258
1259 i = 0;
1260 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1261 {
1262 all_infos[i].obj1 = gi_ptr;
1263 all_infos[i].obj2 = 0;
1264 }
1265
1266 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1267 {
1268 all_infos[i].obj1 = 0;
1269 all_infos[i].obj2 = gi_ptr;
1270 }
1271
1272 for (i = list1_cnt; i < all_cnt; i++)
1273 {
1274 if (all_infos[i].obj2 == 0)
1275 continue;
1276 for (j = 0; j < list1_cnt; j++)
1277 {
1278 if (all_infos[j].obj2 != 0)
1279 continue;
1280 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1281 {
1282 all_infos[j].obj2 = all_infos[i].obj2;
1283 all_infos[i].obj2 = 0;
1284 break;
1285 }
1286 }
1287 }
1288
1289 for (i = 0; i < all_cnt; i++)
1290 if (all_infos[i].obj1 || all_infos[i].obj2)
1291 {
1292 set_flag (all_infos + i);
1293 if (FLAG_ONE_HOT (all_infos[i].flag)((all_infos[i].flag & 0x4) || (all_infos[i].flag & 0x40
))
)
1294 both_hot_cnt++;
1295 if (FLAG_BOTH_COLD(all_infos[i].flag)((all_infos[i].flag & 0x2) && (all_infos[i].flag &
0x20))
)
1296 both_cold_cnt++;
1297 if (FLAG_BOTH_ZERO(all_infos[i].flag)((all_infos[i].flag & 0x1) && (all_infos[i].flag &
0x10))
)
1298 both_zero_cnt++;
1299 }
1300
1301 double prg_val = 0;
1302 double sum_val = 0;
1303 double sum_cum_1 = 0;
1304 double sum_cum_2 = 0;
1305
1306 for (i = 0; i < all_cnt; i++)
1307 {
1308 double val;
1309 double cum_1, cum_2;
1310 const char *filename;
1311
1312 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1313 continue;
1314 if (FLAG_BOTH_ZERO (all_infos[i].flag)((all_infos[i].flag & 0x1) && (all_infos[i].flag &
0x10))
)
1315 continue;
1316
1317 if (all_infos[i].obj1)
1318 filename = get_file_basename (all_infos[i].obj1->filename);
1319 else
1320 filename = get_file_basename (all_infos[i].obj2->filename);
1321
1322 if (overlap_func_level)
1323 printf("\n processing %36s:\n", filename);
1324
1325 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1326 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1327
1328 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)((all_infos[i].flag & 0x4) || (all_infos[i].flag & 0x40
))
))
1329 {
1330 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1331 filename, val*100, cum_1*100, cum_2*100);
1332 sum_val += val;
1333 sum_cum_1 += cum_1;
1334 sum_cum_2 += cum_2;
1335 }
1336
1337 prg_val += val;
1338
1339 }
1340
1341 free (all_infos);
1342
1343 if (overlap_obj_level)
1344 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1345 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1346
1347 printf (" Statistics:\n"
1348 " profile1_# profile2_# overlap_#\n");
1349 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1350 gcda_files[0]-unique_gcda_files[0]);
1351 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1352 unique_gcda_files[1]);
1353 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1354 hot_gcda_files[1], both_hot_cnt);
1355 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1356 cold_gcda_files[1], both_cold_cnt);
1357 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1358 zero_gcda_files[1], both_zero_cnt);
1359
1360 return prg_val;
1361}
1362
1363/* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1364 PROFILE2.
1365 Return 0 on success: without mismatch. Reutrn 1 on error. */
1366
1367int
1368gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1369{
1370 double result;
1371
1372 result = calculate_overlap (profile1, profile2);
1373
1374 if (result > 0)
1375 {
1376 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1377 return 0;
1378 }
1379 return 1;
1380}