1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* decode-gcov.c gcov decoder program
4 * Copyright (C) 2003 Red Hat Inc.
6 * Partially derived from gcov,
7 * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
8 * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
10 * This file is NOT licensed under the Academic Free License
11 * as it is largely derived from gcov.c and gcov-io.h in the
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 #define DBUS_COMPILATION /* cheat */
31 #include <dbus/dbus-list.h>
32 #include <dbus/dbus-string.h>
33 #include <dbus/dbus-sysdeps.h>
34 #include <dbus/dbus-marshal.h>
35 #include <dbus/dbus-hash.h>
36 #undef DBUS_COMPILATION
41 #ifndef DBUS_HAVE_INT64
42 #error "gcov support can't be built without 64-bit integer support"
46 die (const char *message)
48 fprintf (stderr, "%s", message);
52 /* This bizarro function is from gcov-io.h in gcc source tree */
54 fetch_long (long *dest,
61 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
62 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
66 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
68 if ((source[bytes - 1] & 128) && (value > 0))
76 fetch_long64 (dbus_int64_t *dest,
80 dbus_int64_t value = 0;
83 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
84 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
88 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
90 if ((source[bytes - 1] & 128) && (value > 0))
97 #define BB_FILENAME (-1)
98 #define BB_FUNCTION (-2)
99 #define BB_ENDOFLIST 0
102 string_get_int (const DBusString *str,
108 if ((_dbus_string_get_length (str) - start) < 4)
111 p = _dbus_string_get_const_data (str);
115 fetch_long (val, p, 4);
121 string_get_int64 (const DBusString *str,
127 if ((_dbus_string_get_length (str) - start) < 8)
130 p = _dbus_string_get_const_data (str);
134 fetch_long64 (val, p, 8);
140 string_get_string (const DBusString *str,
150 while (string_get_int (str, i, &n))
162 _dbus_string_append_byte (val, b);
166 _dbus_string_append_byte (val, b);
167 b = (n >> 16) & 0xff;
170 _dbus_string_append_byte (val, b);
171 b = (n >> 24) & 0xff;
173 _dbus_string_append_byte (val, b);
184 #ifdef DBUS_HAVE_GCC33_GCOV
185 /* In gcc33 .bbg files, there's a function name of the form:
186 * -1, length, name (padded to 4), -1, checksum
189 string_get_function (const DBusString *str,
191 DBusString *funcname,
201 if (!string_get_int (str, i, &val))
202 die ("no room for -1 before function name\n");
207 die ("value before function name is not -1\n");
209 if (!string_get_int (str, i, &val))
210 die ("no length found for function name\n");
215 if (end > _dbus_string_get_length (str))
216 die ("Function name length points past end of file\n");
218 if (!_dbus_string_append (funcname,
219 _dbus_string_get_const_data (str) + i))
222 /* skip alignment padding the length doesn't include the nul so add 1
224 i = _DBUS_ALIGN_VALUE (end + 1, 4);
226 if (!string_get_int (str, i, &val) ||
228 die ("-1 at end of function name not found\n");
232 if (!string_get_int (str, i, &val))
233 die ("no checksum found at end of function name\n");
243 #endif /* DBUS_HAVE_GCC33_GCOV */
246 dump_bb_file (const DBusString *contents)
254 while (string_get_int (contents, i, &val))
264 if (!_dbus_string_init (&f))
267 if (string_get_string (contents, i,
271 printf ("File %s\n", _dbus_string_get_const_data (&f));
273 _dbus_string_free (&f);
279 if (!_dbus_string_init (&f))
282 if (string_get_string (contents, i,
286 printf ("Function %s\n", _dbus_string_get_const_data (&f));
288 _dbus_string_free (&f);
294 printf ("End of block\n");
297 printf ("Line %ld\n", val);
302 printf ("%d functions in file\n", n_functions);
305 #define FLAG_ON_TREE 0x1
306 #define FLAG_FAKE 0x2
307 #define FLAG_FALL_THROUGH 0x4
310 dump_bbg_file (const DBusString *contents)
324 while (i < _dbus_string_get_length (contents))
326 long n_blocks_in_func;
330 #ifdef DBUS_HAVE_GCC33_GCOV
331 /* In gcc33 .bbg files, there's a function name of the form:
332 * -1, length, name (padded to 4), -1, checksum
333 * after that header on each function description, it's
334 * the same as in gcc32
341 if (!_dbus_string_init (&funcname))
344 if (!string_get_function (contents, i,
345 &funcname, &checksum, &i))
346 die ("could not read function name\n");
348 printf ("Function name is \"%s\" checksum %d\n",
349 _dbus_string_get_const_data (&funcname),
352 _dbus_string_free (&funcname);
354 #endif /* DBUS_HAVE_GCC33_GCOV */
356 if (!string_get_int (contents, i, &val))
357 die ("no count of blocks in func found\n");
361 n_blocks_in_func = val;
363 if (!string_get_int (contents, i, &n_arcs_in_func))
368 printf ("Function has %ld blocks and %ld arcs\n",
369 n_blocks_in_func, n_arcs_in_func);
372 n_blocks += n_blocks_in_func;
373 n_arcs += n_arcs_in_func;
376 while (j < n_blocks_in_func)
378 long n_arcs_in_block;
381 if (!string_get_int (contents, i, &n_arcs_in_block))
386 printf (" Block has %ld arcs\n", n_arcs_in_block);
389 while (k < n_arcs_in_block)
391 long destination_block;
394 if (!string_get_int (contents, i, &destination_block))
399 if (!string_get_int (contents, i, &flags))
404 printf (" Arc has destination block %ld flags 0x%lx\n",
405 destination_block, flags);
407 if ((flags & FLAG_ON_TREE) == 0)
408 n_arcs_off_tree += 1;
413 if (k < n_arcs_in_block)
419 if (j < n_blocks_in_func)
422 if (!string_get_int (contents, i, &val))
428 die ("-1 separator not found\n");
431 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
432 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
435 #ifndef DBUS_HAVE_GCC33_GCOV
438 * The da file contains first a count of arcs in the file,
439 * then a count of executions for all "off tree" arcs
443 dump_da_file (const DBusString *contents)
451 if (!string_get_int64 (contents, i, &val))
456 printf ("%ld arcs in file\n", (long) val);
457 claimed_n_arcs = val;
460 while (string_get_int64 (contents, i, &val))
464 printf ("%ld executions of arc %d\n",
470 if (n_arcs != claimed_n_arcs)
472 printf ("File claimed to have %d arcs but only had %d\n",
473 claimed_n_arcs, n_arcs);
477 #else /* DBUS_HAVE_GCC33_GCOV */
480 * The da file is more complex than 3.2.
482 * We have a magic value of "-123" only it isn't really
483 * -123, it's -123 as encoded by the crackass gcov-io.h
484 * routines. Anyway, 4 bytes.
488 * - 4 byte count of how many functions in the following list
489 * - 4 byte length of random extra data
490 * - the random extra data, just skip it, info pages have some
491 * details on what might be in there or see __bb_exit_func in gcc
492 * - then for each function (number of functions given above):
493 * . -1, length, funcname, alignment padding, -1
495 * . 4 byte number of arcs in function
496 * . 8 bytes each, a count of execution for each arc
498 * Now, the whole thing *starting with the magic* can repeat.
499 * This is caused by multiple runs of the profiled app appending
503 dump_da_file (const DBusString *contents)
515 while (i < _dbus_string_get_length (contents))
517 int claimed_n_functions;
521 printf (".da file section %d\n", n_sections);
523 if (!string_get_int (contents, i, &val))
524 die ("no magic found in .da file\n");
529 die ("wrong file magic in .da file\n");
531 if (!string_get_int (contents, i, &val))
532 die ("no function count in .da file\n");
534 claimed_n_functions = val;
536 printf ("%d functions expected in section %d of .da file\n",
537 claimed_n_functions, n_sections);
539 if (!string_get_int (contents, i, &val))
540 die ("no extra data length in .da file\n");
548 while (n_functions < claimed_n_functions)
555 if (!_dbus_string_init (&funcname))
558 if (!string_get_function (contents, i,
559 &funcname, &checksum, &i))
560 die ("could not read function name\n");
562 if (!string_get_int (contents, i, &val))
563 die ("no arc count for function\n");
566 claimed_n_arcs = val;
568 printf (" %d arcs in function %d %s checksum %d\n",
569 claimed_n_arcs, n_functions,
570 _dbus_string_get_const_data (&funcname),
574 while (n_arcs < claimed_n_arcs)
576 if (!string_get_int64 (contents, i, &v64))
577 die ("did not get execution count for arc\n");
581 printf (" %ld executions of arc %d (total arcs %d)\n",
582 (long) v64, n_arcs, total_arcs + n_arcs);
587 _dbus_string_free (&funcname);
589 total_arcs += n_arcs;
593 printf ("total of %d functions and %d arcs in section %d\n",
594 n_functions, total_arcs, n_sections);
596 total_functions += n_functions;
600 printf ("%d total function sections in %d total .da file sections\n",
601 total_functions, n_sections);
604 #endif /* DBUS_HAVE_GCC33_GCOV */
606 typedef struct Arc Arc;
607 typedef struct Block Block;
608 typedef struct Function Function;
609 typedef struct File File;
610 typedef struct Line Line;
616 dbus_int64_t arc_count;
617 unsigned int count_valid : 1;
618 unsigned int on_tree : 1;
619 unsigned int fake : 1;
620 unsigned int fall_through : 1;
629 dbus_int64_t succ_count;
630 dbus_int64_t pred_count;
631 dbus_int64_t exec_count;
633 unsigned int count_valid : 1;
634 unsigned int on_tree : 1;
635 unsigned int inside_dbus_build_tests : 1;
644 /* number of blocks in DBUS_BUILD_TESTS */
646 int n_test_blocks_executed;
647 /* number of blocks outside DBUS_BUILD_TESTS */
648 int n_nontest_blocks;
649 int n_nontest_blocks_executed;
650 /* Summary result flags */
651 unsigned int unused : 1;
652 unsigned int inside_dbus_build_tests : 1;
653 unsigned int partial : 1; /* only some of the blocks were executed */
661 unsigned int inside_dbus_build_tests : 1;
662 unsigned int partial : 1; /* only some of the blocks were executed */
674 function_add_arc (Function *function,
681 arc = dbus_new0 (Arc, 1);
685 arc->target = target;
686 arc->source = source;
688 arc->succ_next = function->block_graph[source].succ;
689 function->block_graph[source].succ = arc;
690 function->block_graph[source].succ_count += 1;
692 arc->pred_next = function->block_graph[target].pred;
693 function->block_graph[target].pred = arc;
694 function->block_graph[target].pred_count += 1;
696 if ((flags & FLAG_ON_TREE) != 0)
699 if ((flags & FLAG_FAKE) != 0)
702 if ((flags & FLAG_FALL_THROUGH) != 0)
703 arc->fall_through = TRUE;
708 reverse_arcs (Arc *arc)
710 struct Arc *prev = 0;
713 for ( ; arc; arc = next)
715 next = arc->succ_next;
716 arc->succ_next = prev;
724 function_reverse_succ_arcs (Function *func)
726 /* Must reverse the order of all succ arcs, to ensure that they match
727 * the order of the data in the .da file.
731 for (i = 0; i < func->n_blocks; i++)
732 if (func->block_graph[i].succ)
733 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
737 get_functions_from_bbg (const DBusString *contents,
738 DBusList **functions)
748 printf ("Loading arcs and blocks from .bbg file\n");
756 while (i < _dbus_string_get_length (contents))
759 long n_blocks_in_func;
763 #ifdef DBUS_HAVE_GCC33_GCOV
767 /* In gcc33 .bbg files, there's a function name of the form:
768 * -1, length, name (padded to 4), -1, checksum
769 * after that header on each function description, it's
770 * the same as in gcc32
772 if (!_dbus_string_init (&funcname))
775 if (!string_get_function (contents, i,
776 &funcname, &checksum, &i))
777 die ("could not read function name\n");
778 #endif /* DBUS_HAVE_GCC33_GCOV */
780 if (!string_get_int (contents, i, &val))
783 n_blocks_in_func = val;
787 if (!string_get_int (contents, i, &n_arcs_in_func))
793 n_blocks += n_blocks_in_func;
794 n_arcs += n_arcs_in_func;
796 func = dbus_new0 (Function, 1);
800 #ifdef DBUS_HAVE_GCC33_GCOV
801 func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
802 func->checksum = checksum;
803 _dbus_string_free (&funcname);
806 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
807 func->n_blocks = n_blocks_in_func;
810 while (j < n_blocks_in_func)
812 long n_arcs_in_block;
815 if (!string_get_int (contents, i, &n_arcs_in_block))
821 while (k < n_arcs_in_block)
823 long destination_block;
826 if (!string_get_int (contents, i, &destination_block))
831 if (!string_get_int (contents, i, &flags))
836 if ((flags & FLAG_ON_TREE) == 0)
837 n_arcs_off_tree += 1;
839 function_add_arc (func, j, destination_block,
845 if (k < n_arcs_in_block)
851 if (j < n_blocks_in_func)
854 function_reverse_succ_arcs (func);
856 if (!_dbus_list_append (functions, func))
859 if (!string_get_int (contents, i, &val))
865 die ("-1 separator not found in .bbg file\n");
869 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
870 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
873 _dbus_assert (n_functions == _dbus_list_get_length (functions));
876 #ifdef DBUS_HAVE_GCC33_GCOV
878 add_counts_from_da (const DBusString *contents,
879 DBusList **functions)
886 Function *current_func;
893 while (i < _dbus_string_get_length (contents))
895 int claimed_n_functions;
898 if (!string_get_int (contents, i, &val))
899 die ("no magic found in .da file\n");
904 die ("wrong file magic in .da file\n");
906 if (!string_get_int (contents, i, &val))
907 die ("no function count in .da file\n");
909 claimed_n_functions = val;
911 if (!string_get_int (contents, i, &val))
912 die ("no extra data length in .da file\n");
918 link = _dbus_list_get_first_link (functions);
920 goto no_more_functions;
923 while (n_functions < claimed_n_functions && link != NULL)
930 current_func = link->data;
932 current_arc = current_func->block_graph[current_block].succ;
934 if (!_dbus_string_init (&funcname))
937 if (!string_get_function (contents, i,
938 &funcname, &checksum, &i))
939 die ("could not read function name\n");
941 if (!_dbus_string_equal_c_str (&funcname, current_func->name))
943 fprintf (stderr, "Expecting .da info for %s but got %s\n",
945 _dbus_string_get_const_data (&funcname));
949 if (checksum != current_func->checksum)
950 die (".da file checksum doesn't match checksum from .bbg file\n");
952 if (!string_get_int (contents, i, &val))
953 die ("no arc count for function\n");
956 claimed_n_arcs = val;
958 /* For each arc in the profile, find the corresponding
959 * arc in the function and increment its count
962 while (n_arcs < claimed_n_arcs)
964 if (!string_get_int64 (contents, i, &v64))
965 die ("did not get execution count for arc\n");
969 /* Find the next arc in the function that isn't on tree */
970 while (current_arc == NULL ||
971 current_arc->on_tree)
973 if (current_arc == NULL)
977 if (current_block >= current_func->n_blocks)
978 die ("too many blocks in function\n");
980 current_arc = current_func->block_graph[current_block].succ;
984 current_arc = current_arc->succ_next;
988 _dbus_assert (current_arc != NULL);
989 _dbus_assert (!current_arc->on_tree);
991 current_arc->arc_count = v64;
992 current_arc->count_valid = TRUE;
993 current_func->block_graph[current_block].succ_count -= 1;
994 current_func->block_graph[current_arc->target].pred_count -= 1;
998 current_arc = current_arc->succ_next;
1001 _dbus_string_free (&funcname);
1003 link = _dbus_list_get_next_link (functions, link);
1006 if (link == NULL && n_functions < claimed_n_functions)
1008 fprintf (stderr, "Ran out of functions loading .da file\n");
1009 goto no_more_functions;
1018 #else /* DBUS_HAVE_GCC33_GCOV */
1020 add_counts_from_da (const DBusString *contents,
1021 DBusList **functions)
1028 Function *current_func;
1033 printf ("Loading execution count for each arc from .da file\n");
1037 if (!string_get_int64 (contents, i, &val))
1042 claimed_n_arcs = val;
1044 link = _dbus_list_get_first_link (functions);
1048 current_func = link->data;
1050 current_arc = current_func->block_graph[current_block].succ;
1053 while (string_get_int64 (contents, i, &val))
1057 while (current_arc == NULL ||
1058 current_arc->on_tree)
1060 if (current_arc == NULL)
1064 if (current_block == current_func->n_blocks)
1066 link = _dbus_list_get_next_link (functions, link);
1069 fprintf (stderr, "Ran out of functions loading .da file\n");
1072 current_func = link->data;
1076 current_arc = current_func->block_graph[current_block].succ;
1080 current_arc = current_arc->succ_next;
1084 _dbus_assert (current_arc != NULL);
1085 _dbus_assert (!current_arc->on_tree);
1087 current_arc->arc_count = val;
1088 current_arc->count_valid = TRUE;
1089 current_func->block_graph[current_block].succ_count -= 1;
1090 current_func->block_graph[current_arc->target].pred_count -= 1;
1094 current_arc = current_arc->succ_next;
1099 if (n_arcs != claimed_n_arcs)
1101 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
1102 claimed_n_arcs, n_arcs);
1107 printf ("%d arcs in file\n", n_arcs);
1113 function_solve_graph (Function *func)
1115 int passes, changes;
1123 printf ("Solving function graph\n");
1126 n_blocks = func->n_blocks;
1127 block_graph = func->block_graph;
1129 /* For every block in the file,
1130 - if every exit/entrance arc has a known count, then set the block count
1131 - if the block count is known, and every exit/entrance arc but one has
1132 a known execution count, then set the count of the remaining arc
1134 As arc counts are set, decrement the succ/pred count, but don't delete
1135 the arc, that way we can easily tell when all arcs are known, or only
1136 one arc is unknown. */
1138 /* The order that the basic blocks are iterated through is important.
1139 Since the code that finds spanning trees starts with block 0, low numbered
1140 arcs are put on the spanning tree in preference to high numbered arcs.
1141 Hence, most instrumented arcs are at the end. Graph solving works much
1142 faster if we propagate numbers from the end to the start.
1144 This takes an average of slightly more than 3 passes. */
1153 for (i = n_blocks - 1; i >= 0; i--)
1155 if (! block_graph[i].count_valid)
1157 if (block_graph[i].succ_count == 0)
1160 for (arc = block_graph[i].succ; arc;
1161 arc = arc->succ_next)
1162 total += arc->arc_count;
1163 block_graph[i].exec_count = total;
1164 block_graph[i].count_valid = 1;
1167 else if (block_graph[i].pred_count == 0)
1170 for (arc = block_graph[i].pred; arc;
1171 arc = arc->pred_next)
1172 total += arc->arc_count;
1173 block_graph[i].exec_count = total;
1174 block_graph[i].count_valid = 1;
1178 if (block_graph[i].count_valid)
1180 if (block_graph[i].succ_count == 1)
1183 /* One of the counts will be invalid, but it is zero,
1184 so adding it in also doesn't hurt. */
1185 for (arc = block_graph[i].succ; arc;
1186 arc = arc->succ_next)
1187 total += arc->arc_count;
1188 /* Calculate count for remaining arc by conservation. */
1189 total = block_graph[i].exec_count - total;
1190 /* Search for the invalid arc, and set its count. */
1191 for (arc = block_graph[i].succ; arc;
1192 arc = arc->succ_next)
1193 if (! arc->count_valid)
1196 die ("arc == NULL\n");
1197 arc->count_valid = 1;
1198 arc->arc_count = total;
1199 block_graph[i].succ_count -= 1;
1201 block_graph[arc->target].pred_count -= 1;
1204 if (block_graph[i].pred_count == 1)
1207 /* One of the counts will be invalid, but it is zero,
1208 so adding it in also doesn't hurt. */
1209 for (arc = block_graph[i].pred; arc;
1210 arc = arc->pred_next)
1211 total += arc->arc_count;
1212 /* Calculate count for remaining arc by conservation. */
1213 total = block_graph[i].exec_count - total;
1214 /* Search for the invalid arc, and set its count. */
1215 for (arc = block_graph[i].pred; arc;
1216 arc = arc->pred_next)
1217 if (! arc->count_valid)
1220 die ("arc == NULL\n");
1221 arc->count_valid = 1;
1222 arc->arc_count = total;
1223 block_graph[i].pred_count -= 1;
1225 block_graph[arc->source].succ_count -= 1;
1232 /* If the graph has been correctly solved, every block will have a
1233 * succ and pred count of zero.
1236 dbus_bool_t header = FALSE;
1237 for (i = 0; i < n_blocks; i++)
1239 if (block_graph[i].succ_count || block_graph[i].pred_count)
1243 fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
1245 fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
1248 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
1249 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
1256 solve_graphs (DBusList **functions)
1260 link = _dbus_list_get_first_link (functions);
1261 while (link != NULL)
1263 Function *func = link->data;
1265 function_solve_graph (func);
1267 link = _dbus_list_get_next_link (functions, link);
1272 load_functions_for_c_file (const DBusString *filename,
1273 DBusList **functions)
1275 DBusString bbg_filename;
1276 DBusString da_filename;
1277 DBusString gcno_filename;
1278 DBusString gcda_filename;
1279 DBusString contents;
1283 /* With latest gcc it's .gcno instead of .bbg and
1284 * gcda instead of .da
1287 dbus_error_init (&error);
1289 if (!_dbus_string_init (&bbg_filename) ||
1290 !_dbus_string_init (&da_filename) ||
1291 !_dbus_string_init (&gcno_filename) ||
1292 !_dbus_string_init (&gcda_filename) ||
1293 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
1294 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
1295 !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
1296 !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
1297 !_dbus_string_init (&contents))
1298 die ("no memory\n");
1300 _dbus_string_shorten (&bbg_filename, 2);
1301 _dbus_string_shorten (&da_filename, 2);
1303 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
1304 !_dbus_string_append (&da_filename, ".da") ||
1305 !_dbus_string_append (&bbg_filename, ".gcno") ||
1306 !_dbus_string_append (&bbg_filename, ".gcda"))
1307 die ("no memory\n");
1309 if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
1310 name = &gcno_filename;
1312 name = &bbg_filename;
1314 if (!_dbus_file_get_contents (&contents, name,
1317 fprintf (stderr, "Could not open file: %s\n",
1322 get_functions_from_bbg (&contents, functions);
1324 _dbus_string_set_length (&contents, 0);
1326 if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
1327 name = &gcda_filename;
1329 name = &da_filename;
1331 if (!_dbus_file_get_contents (&contents, name,
1334 /* Try .libs/file.da */
1337 if (_dbus_string_find_byte_backward (name,
1338 _dbus_string_get_length (name),
1343 _dbus_string_init_const (&libs, "/.libs");
1345 if (!_dbus_string_copy (&libs, 0, name, slash))
1348 dbus_error_free (&error);
1349 if (!_dbus_file_get_contents (&contents, name,
1352 fprintf (stderr, "Could not open file: %s\n",
1359 fprintf (stderr, "Could not open file: %s\n",
1365 add_counts_from_da (&contents, functions);
1367 solve_graphs (functions);
1369 _dbus_string_free (&contents);
1370 _dbus_string_free (&da_filename);
1371 _dbus_string_free (&bbg_filename);
1375 get_lines_from_bb_file (const DBusString *contents,
1381 dbus_bool_t in_our_file;
1387 printf ("Getting line numbers for blocks from .bb file\n");
1390 /* There's this "filename" field in the .bb file which
1391 * mysteriously comes *after* the first function in the
1392 * file in the .bb file; and every .bb file seems to
1393 * have only one filename. I don't understand
1394 * what's going on here, so just set in_our_file = TRUE
1395 * at the start categorically.
1401 link = _dbus_list_get_first_link (&fl->functions);
1404 while (string_get_int (contents, i, &val))
1414 if (!_dbus_string_init (&f))
1415 die ("no memory\n");
1417 if (string_get_string (contents, i,
1421 /* fl->name is a full path and the filename in .bb is
1426 _dbus_string_init_const (&tmp_str, fl->name);
1428 if (_dbus_string_ends_with_c_str (&tmp_str,
1429 _dbus_string_get_const_data (&f)))
1432 in_our_file = FALSE;
1436 "File %s in .bb, looking for %s, in_our_file = %d\n",
1437 _dbus_string_get_const_data (&f),
1442 _dbus_string_free (&f);
1448 if (!_dbus_string_init (&f))
1449 die ("no memory\n");
1451 if (string_get_string (contents, i,
1456 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
1465 fprintf (stderr, "No function object for function %s\n",
1466 _dbus_string_get_const_data (&f));
1471 link = _dbus_list_get_next_link (&fl->functions, link);
1473 if (func->name == NULL)
1475 if (!_dbus_string_copy_data (&f, &func->name))
1476 die ("no memory\n");
1480 if (!_dbus_string_equal_c_str (&f, func->name))
1482 fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
1483 func->name, strlen (func->name),
1484 _dbus_string_get_const_data (&f),
1485 _dbus_string_get_length (&f));
1492 _dbus_string_free (&f);
1502 fprintf (stderr, "Line %ld\n", val);
1505 if (val >= fl->n_lines)
1507 fprintf (stderr, "Line %ld but file only has %d lines\n",
1510 else if (func != NULL)
1512 val -= 1; /* To convert the 1-based line number to 0-based */
1513 _dbus_assert (val >= 0);
1515 if (block < func->n_blocks)
1517 if (!_dbus_list_append (&func->block_graph[block].lines,
1519 die ("no memory\n");
1522 if (!_dbus_list_append (&fl->lines[val].blocks,
1523 &func->block_graph[block]))
1524 die ("no memory\n");
1528 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1529 block, func->n_blocks);
1534 fprintf (stderr, "Line %ld given outside of any function\n",
1543 printf ("%d functions in file\n", n_functions);
1549 load_block_line_associations (const DBusString *filename,
1552 DBusString bb_filename;
1553 DBusString contents;
1556 dbus_error_init (&error);
1558 if (!_dbus_string_init (&bb_filename) ||
1559 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1560 !_dbus_string_init (&contents))
1561 die ("no memory\n");
1563 _dbus_string_shorten (&bb_filename, 2);
1565 if (!_dbus_string_append (&bb_filename, ".bb"))
1566 die ("no memory\n");
1568 if (!_dbus_file_get_contents (&contents, &bb_filename,
1571 fprintf (stderr, "Could not open file: %s\n",
1576 get_lines_from_bb_file (&contents, f);
1578 _dbus_string_free (&contents);
1579 _dbus_string_free (&bb_filename);
1583 count_lines_in_string (const DBusString *str)
1589 const char *last_line_end;
1592 printf ("Counting lines in source file\n");
1597 p = _dbus_string_get_const_data (str);
1598 end = p + _dbus_string_get_length (str);
1602 /* too lazy to handle \r\n as one linebreak */
1603 if (*p == '\n' || *p == '\r')
1606 last_line_end = p + 1;
1613 if (last_line_end != p)
1620 fill_line_content (const DBusString *str,
1627 const char *last_line_end;
1630 printf ("Saving contents of each line in source file\n");
1635 p = _dbus_string_get_const_data (str);
1636 end = p + _dbus_string_get_length (str);
1640 if (*p == '\n' || *p == '\r')
1642 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1643 if (lines[n_lines].text == NULL)
1644 die ("no memory\n");
1646 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1647 lines[n_lines].number = n_lines + 1;
1651 last_line_end = p + 1;
1658 if (p != last_line_end)
1660 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1666 mark_inside_dbus_build_tests (File *f)
1674 while (i < f->n_lines)
1676 Line *l = &f->lines[i];
1677 dbus_bool_t is_verbose;
1679 is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
1681 if (inside_depth == 0)
1685 a = strstr (l->text, "#if");
1686 b = strstr (l->text, "DBUS_BUILD_TESTS");
1687 if (a && b && (a < b))
1692 if (strstr (l->text, "#if") != NULL)
1694 else if (strstr (l->text, "#endif") != NULL)
1698 if (inside_depth > 0 || is_verbose)
1700 /* Mark the line and its blocks */
1703 l->inside_dbus_build_tests = TRUE;
1705 blink = _dbus_list_get_first_link (&l->blocks);
1706 while (blink != NULL)
1708 Block *b = blink->data;
1710 b->inside_dbus_build_tests = TRUE;
1712 blink = _dbus_list_get_next_link (&l->blocks, blink);
1719 /* Now mark functions where for all blocks that are associated
1720 * with a source line, the block is inside_dbus_build_tests.
1722 link = _dbus_list_get_first_link (&f->functions);
1723 while (link != NULL)
1725 Function *func = link->data;
1727 /* The issue is that some blocks aren't associated with a source line.
1728 * Assume they are inside/outside tests according to the source
1729 * line of the preceding block. For the first block, make it
1730 * match the first following block with a line associated.
1732 if (func->block_graph[0].lines == NULL)
1734 /* find first following line */
1736 while (i < func->n_blocks)
1738 if (func->block_graph[i].lines != NULL)
1740 func->block_graph[0].inside_dbus_build_tests =
1741 func->block_graph[i].inside_dbus_build_tests;
1749 /* Now mark all blocks but the first */
1751 while (i < func->n_blocks)
1753 if (func->block_graph[i].lines == NULL)
1755 func->block_graph[i].inside_dbus_build_tests =
1756 func->block_graph[i-1].inside_dbus_build_tests;
1763 while (i < func->n_blocks)
1765 /* Break as soon as any block is not a test block */
1766 if (func->block_graph[i].lines != NULL &&
1767 !func->block_graph[i].inside_dbus_build_tests)
1773 if (i == func->n_blocks)
1774 func->inside_dbus_build_tests = TRUE;
1776 link = _dbus_list_get_next_link (&f->functions, link);
1781 mark_coverage (File *f)
1787 while (i < f->n_lines)
1789 Line *l = &f->lines[i];
1792 int n_blocks_executed;
1795 n_blocks_executed = 0;
1796 blink = _dbus_list_get_first_link (&l->blocks);
1797 while (blink != NULL)
1799 Block *b = blink->data;
1801 if (b->exec_count > 0)
1802 n_blocks_executed += 1;
1806 blink = _dbus_list_get_next_link (&l->blocks, blink);
1809 if (n_blocks_executed > 0 &&
1810 n_blocks_executed < n_blocks)
1816 link = _dbus_list_get_first_link (&f->functions);
1817 while (link != NULL)
1819 Function *func = link->data;
1822 int n_test_blocks_executed;
1823 int n_nontest_blocks;
1824 int n_nontest_blocks_executed;
1827 n_test_blocks_executed = 0;
1828 n_nontest_blocks = 0;
1829 n_nontest_blocks_executed = 0;
1832 while (i < func->n_blocks)
1834 if (!func->block_graph[i].inside_dbus_build_tests)
1836 n_nontest_blocks += 1;
1838 if (func->block_graph[i].exec_count > 0)
1839 n_nontest_blocks_executed += 1;
1845 if (func->block_graph[i].exec_count > 0)
1846 n_test_blocks_executed += 1;
1852 if (n_nontest_blocks_executed > 0 &&
1853 n_nontest_blocks_executed < n_nontest_blocks)
1854 func->partial = TRUE;
1856 if (n_nontest_blocks_executed == 0 &&
1857 n_nontest_blocks > 0)
1858 func->unused = TRUE;
1860 func->n_test_blocks = n_test_blocks;
1861 func->n_test_blocks_executed = n_test_blocks_executed;
1862 func->n_nontest_blocks = n_nontest_blocks;
1863 func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1865 link = _dbus_list_get_next_link (&f->functions, link);
1870 load_c_file (const DBusString *filename)
1872 DBusString contents;
1876 f = dbus_new0 (File, 1);
1878 die ("no memory\n");
1880 if (!_dbus_string_copy_data (filename, &f->name))
1881 die ("no memory\n");
1883 if (!_dbus_string_init (&contents))
1884 die ("no memory\n");
1886 dbus_error_init (&error);
1888 if (!_dbus_file_get_contents (&contents, filename,
1891 fprintf (stderr, "Could not open file: %s\n",
1893 dbus_error_free (&error);
1897 load_functions_for_c_file (filename, &f->functions);
1899 f->n_lines = count_lines_in_string (&contents);
1900 f->lines = dbus_new0 (Line, f->n_lines);
1901 if (f->lines == NULL)
1902 die ("no memory\n");
1904 fill_line_content (&contents, f->lines);
1906 _dbus_string_free (&contents);
1908 load_block_line_associations (filename, f);
1910 mark_inside_dbus_build_tests (f);
1916 typedef struct Stats Stats;
1921 int n_blocks_executed;
1922 int n_blocks_inside_dbus_build_tests;
1924 int n_lines; /* lines that have blocks on them */
1925 int n_lines_executed;
1926 int n_lines_partial;
1927 int n_lines_inside_dbus_build_tests;
1930 int n_functions_executed;
1931 int n_functions_partial;
1932 int n_functions_inside_dbus_build_tests;
1936 line_was_executed (Line *l)
1940 link = _dbus_list_get_first_link (&l->blocks);
1941 while (link != NULL)
1943 Block *b = link->data;
1945 if (b->exec_count > 0)
1948 link = _dbus_list_get_next_link (&l->blocks, link);
1956 line_exec_count (Line *l)
1962 link = _dbus_list_get_first_link (&l->blocks);
1963 while (link != NULL)
1965 Block *b = link->data;
1967 total += b->exec_count;
1969 link = _dbus_list_get_next_link (&l->blocks, link);
1976 merge_stats_for_file (Stats *stats,
1982 for (i = 0; i < f->n_lines; ++i)
1984 Line *l = &f->lines[i];
1986 if (l->inside_dbus_build_tests)
1988 stats->n_lines_inside_dbus_build_tests += 1;
1992 if (line_was_executed (l))
1993 stats->n_lines_executed += 1;
1995 if (l->blocks != NULL)
1996 stats->n_lines += 1;
1999 stats->n_lines_partial += 1;
2002 link = _dbus_list_get_first_link (&f->functions);
2003 while (link != NULL)
2005 Function *func = link->data;
2007 if (func->inside_dbus_build_tests)
2008 stats->n_functions_inside_dbus_build_tests += 1;
2011 stats->n_functions += 1;
2014 stats->n_functions_executed += 1;
2017 stats->n_functions_partial += 1;
2020 stats->n_blocks_inside_dbus_build_tests +=
2021 func->n_test_blocks;
2023 stats->n_blocks_executed +=
2024 func->n_nontest_blocks_executed;
2027 func->n_nontest_blocks;
2029 link = _dbus_list_get_next_link (&f->functions, link);
2033 /* The output of this matches gcov exactly ("diff" shows no difference) */
2035 print_annotated_source_gcov_format (File *f)
2040 while (i < f->n_lines)
2042 Line *l = &f->lines[i];
2044 if (l->blocks != NULL)
2048 exec_count = line_exec_count (l);
2051 printf ("%12d %s\n",
2052 exec_count, l->text);
2054 printf (" ###### %s\n", l->text);
2058 printf ("\t\t%s\n", l->text);
2066 print_annotated_source (File *f)
2071 while (i < f->n_lines)
2073 Line *l = &f->lines[i];
2075 if (l->inside_dbus_build_tests)
2080 if (l->blocks != NULL)
2084 exec_count = line_exec_count (l);
2087 printf ("%12d %s\n",
2088 exec_count, l->text);
2090 printf (" ###### %s\n", l->text);
2094 printf ("\t\t%s\n", l->text);
2102 print_block_superdetails (File *f)
2107 link = _dbus_list_get_first_link (&f->functions);
2108 while (link != NULL)
2110 Function *func = link->data;
2112 printf ("=== %s():\n", func->name);
2115 while (i < func->n_blocks)
2117 Block *b = &func->block_graph[i];
2120 printf (" %5d executed %d times%s\n", i,
2121 (int) b->exec_count,
2122 b->inside_dbus_build_tests ?
2123 " [inside DBUS_BUILD_TESTS]" : "");
2125 l = _dbus_list_get_first_link (&b->lines);
2128 Line *line = l->data;
2130 printf ("4%d\t%s\n", line->number, line->text);
2132 l = _dbus_list_get_next_link (&b->lines, l);
2138 link = _dbus_list_get_next_link (&f->functions, link);
2143 print_one_file (const DBusString *filename)
2145 if (_dbus_string_ends_with_c_str (filename, ".bb"))
2147 DBusString contents;
2150 if (!_dbus_string_init (&contents))
2151 die ("no memory\n");
2153 dbus_error_init (&error);
2155 if (!_dbus_file_get_contents (&contents, filename,
2158 fprintf (stderr, "Could not open file: %s\n",
2160 dbus_error_free (&error);
2164 dump_bb_file (&contents);
2166 _dbus_string_free (&contents);
2168 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
2170 DBusString contents;
2173 if (!_dbus_string_init (&contents))
2174 die ("no memory\n");
2176 dbus_error_init (&error);
2178 if (!_dbus_file_get_contents (&contents, filename,
2181 fprintf (stderr, "Could not open file: %s\n",
2183 dbus_error_free (&error);
2187 dump_bbg_file (&contents);
2189 _dbus_string_free (&contents);
2191 else if (_dbus_string_ends_with_c_str (filename, ".da"))
2193 DBusString contents;
2196 if (!_dbus_string_init (&contents))
2197 die ("no memory\n");
2199 dbus_error_init (&error);
2201 if (!_dbus_file_get_contents (&contents, filename,
2204 fprintf (stderr, "Could not open file: %s\n",
2206 dbus_error_free (&error);
2210 dump_da_file (&contents);
2212 _dbus_string_free (&contents);
2214 else if (_dbus_string_ends_with_c_str (filename, ".c"))
2218 f = load_c_file (filename);
2220 print_annotated_source (f);
2224 fprintf (stderr, "Unknown file type %s\n",
2225 _dbus_string_get_const_data (filename));
2231 print_untested_functions (File *f)
2237 link = _dbus_list_get_first_link (&f->functions);
2238 while (link != NULL)
2240 Function *func = link->data;
2243 !func->inside_dbus_build_tests)
2246 link = _dbus_list_get_next_link (&f->functions, link);
2252 printf ("Untested functions in %s\n", f->name);
2253 printf ("=======\n");
2255 link = _dbus_list_get_first_link (&f->functions);
2256 while (link != NULL)
2258 Function *func = link->data;
2261 !func->inside_dbus_build_tests)
2262 printf (" %s\n", func->name);
2264 link = _dbus_list_get_next_link (&f->functions, link);
2271 print_poorly_tested_functions (File *f,
2277 #define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
2279 #define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
2281 #define POORLY_TESTED(function) (!(function)->unused && \
2282 (function)->n_nontest_blocks > 0 && \
2283 TEST_FRACTION (function) < AVERAGE_COVERAGE)
2286 link = _dbus_list_get_first_link (&f->functions);
2287 while (link != NULL)
2289 Function *func = link->data;
2291 if (POORLY_TESTED (func))
2294 link = _dbus_list_get_next_link (&f->functions, link);
2300 printf ("Below average functions in %s\n", f->name);
2301 printf ("=======\n");
2303 link = _dbus_list_get_first_link (&f->functions);
2304 while (link != NULL)
2306 Function *func = link->data;
2308 if (POORLY_TESTED (func))
2309 printf (" %s (%d%%)\n", func->name,
2310 (int) (TEST_FRACTION (func) * 100));
2312 link = _dbus_list_get_next_link (&f->functions, link);
2319 func_cmp (const void *a,
2322 Function *af = *(Function**) a;
2323 Function *bf = *(Function**) b;
2324 int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
2325 int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
2327 /* Sort by number of untested blocks */
2328 return b_untested - a_untested;
2332 print_n_untested_blocks_by_function (File *f,
2341 link = _dbus_list_get_first_link (&f->functions);
2342 while (link != NULL)
2344 Function *func = link->data;
2346 if (func->n_nontest_blocks_executed <
2347 func->n_nontest_blocks)
2350 link = _dbus_list_get_next_link (&f->functions, link);
2356 /* make an array so we can use qsort */
2358 funcs = dbus_new (Function*, n_found);
2363 link = _dbus_list_get_first_link (&f->functions);
2364 while (link != NULL)
2366 Function *func = link->data;
2368 if (func->n_nontest_blocks_executed <
2369 func->n_nontest_blocks)
2375 link = _dbus_list_get_next_link (&f->functions, link);
2378 _dbus_assert (i == n_found);
2380 qsort (funcs, n_found, sizeof (Function*),
2383 printf ("Incomplete functions in %s\n", f->name);
2384 printf ("=======\n");
2389 Function *func = funcs[i];
2391 printf (" %s (%d/%d untested blocks)\n",
2393 func->n_nontest_blocks - func->n_nontest_blocks_executed,
2394 func->n_nontest_blocks);
2405 print_stats (Stats *stats,
2406 const char *of_what)
2410 printf ("Summary (%s)\n", of_what);
2411 printf ("=======\n");
2412 printf (" %g%% blocks executed (%d of %d)\n",
2413 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
2414 stats->n_blocks_executed,
2417 printf (" (ignored %d blocks of test-only/debug-only code)\n",
2418 stats->n_blocks_inside_dbus_build_tests);
2420 printf (" %g%% functions executed (%d of %d)\n",
2421 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
2422 stats->n_functions_executed,
2423 stats->n_functions);
2425 completely = stats->n_functions_executed - stats->n_functions_partial;
2426 printf (" %g%% functions completely executed (%d of %d)\n",
2427 (completely / (double) stats->n_functions) * 100.0,
2429 stats->n_functions);
2431 printf (" (ignored %d functions of test-only/debug-only code)\n",
2432 stats->n_functions_inside_dbus_build_tests);
2434 printf (" %g%% lines executed (%d of %d)\n",
2435 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
2436 stats->n_lines_executed,
2439 completely = stats->n_lines_executed - stats->n_lines_partial;
2440 printf (" %g%% lines completely executed (%d of %d)\n",
2441 (completely / (double) stats->n_lines) * 100.0,
2445 printf (" (ignored %d lines of test-only/debug-only code)\n",
2446 stats->n_lines_inside_dbus_build_tests);
2460 main (int argc, char **argv)
2462 DBusString filename;
2468 fprintf (stderr, "Must specify files on command line\n");
2475 if (strcmp (argv[i], "--report") == 0)
2480 else if (strcmp (argv[i], "--blocks") == 0)
2485 else if (strcmp (argv[i], "--gcov") == 0)
2494 fprintf (stderr, "Must specify files on command line\n");
2498 if (m == MODE_PRINT)
2502 _dbus_string_init_const (&filename, argv[i]);
2504 print_one_file (&filename);
2509 else if (m == MODE_BLOCKS || m == MODE_GCOV)
2515 _dbus_string_init_const (&filename, argv[i]);
2517 f = load_c_file (&filename);
2519 if (m == MODE_BLOCKS)
2520 print_block_superdetails (f);
2521 else if (m == MODE_GCOV)
2522 print_annotated_source_gcov_format (f);
2527 else if (m == MODE_REPORT)
2529 Stats stats = { 0, };
2532 DBusHashTable *stats_by_dir;
2538 _dbus_string_init_const (&filename, argv[i]);
2540 if (_dbus_string_ends_with_c_str (&filename, ".c"))
2544 f = load_c_file (&filename);
2546 if (!_dbus_list_append (&files, f))
2547 die ("no memory\n");
2551 fprintf (stderr, "Unknown file type %s\n",
2552 _dbus_string_get_const_data (&filename));
2559 link = _dbus_list_get_first_link (&files);
2560 while (link != NULL)
2562 File *f = link->data;
2564 merge_stats_for_file (&stats, f);
2566 link = _dbus_list_get_next_link (&files, link);
2569 print_stats (&stats, "all files");
2571 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
2572 dbus_free, dbus_free);
2574 link = _dbus_list_get_first_link (&files);
2575 while (link != NULL)
2577 File *f = link->data;
2582 _dbus_string_init_const (&filename, f->name);
2584 if (!_dbus_string_init (&dirname))
2585 die ("no memory\n");
2587 if (!_dbus_string_get_dirname (&filename, &dirname) ||
2588 !_dbus_string_copy_data (&dirname, &dirname_c))
2589 die ("no memory\n");
2591 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
2594 if (dir_stats == NULL)
2596 dir_stats = dbus_new0 (Stats, 1);
2597 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
2599 die ("no memory\n");
2602 dbus_free (dirname_c);
2604 merge_stats_for_file (dir_stats, f);
2606 link = _dbus_list_get_next_link (&files, link);
2609 _dbus_hash_iter_init (stats_by_dir, &iter);
2610 while (_dbus_hash_iter_next (&iter))
2612 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
2613 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
2615 print_stats (dir_stats, dirname);
2618 _dbus_hash_table_unref (stats_by_dir);
2620 link = _dbus_list_get_first_link (&files);
2621 while (link != NULL)
2623 File *f = link->data;
2625 print_untested_functions (f);
2627 link = _dbus_list_get_next_link (&files, link);
2630 link = _dbus_list_get_first_link (&files);
2631 while (link != NULL)
2633 File *f = link->data;
2635 print_poorly_tested_functions (f, &stats);
2637 link = _dbus_list_get_next_link (&files, link);
2640 link = _dbus_list_get_first_link (&files);
2641 while (link != NULL)
2643 File *f = link->data;
2645 print_n_untested_blocks_by_function (f, &stats);
2647 link = _dbus_list_get_next_link (&files, link);