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
31 #define DBUS_COMPILATION /* cheat */
32 #include <dbus/dbus-list.h>
33 #include <dbus/dbus-string.h>
34 #include <dbus/dbus-sysdeps.h>
35 #include <dbus/dbus-marshal.h>
36 #include <dbus/dbus-hash.h>
37 #undef DBUS_COMPILATION
42 #ifndef DBUS_HAVE_INT64
43 #error "gcov support can't be built without 64-bit integer support"
47 die (const char *message)
49 fprintf (stderr, "%s", message);
53 /* This bizarro function is from gcov-io.h in gcc source tree */
55 fetch_long (long *dest,
62 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
63 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
67 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
69 if ((source[bytes - 1] & 128) && (value > 0))
77 fetch_long64 (dbus_int64_t *dest,
81 dbus_int64_t value = 0;
84 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
85 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
89 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
91 if ((source[bytes - 1] & 128) && (value > 0))
98 #define BB_FILENAME (-1)
99 #define BB_FUNCTION (-2)
100 #define BB_ENDOFLIST 0
103 string_get_int (const DBusString *str,
109 if ((_dbus_string_get_length (str) - start) < 4)
112 p = _dbus_string_get_const_data (str);
116 fetch_long (val, p, 4);
122 string_get_int64 (const DBusString *str,
128 if ((_dbus_string_get_length (str) - start) < 8)
131 p = _dbus_string_get_const_data (str);
135 fetch_long64 (val, p, 8);
141 string_get_string (const DBusString *str,
151 while (string_get_int (str, i, &n))
163 _dbus_string_append_byte (val, b);
167 _dbus_string_append_byte (val, b);
168 b = (n >> 16) & 0xff;
171 _dbus_string_append_byte (val, b);
172 b = (n >> 24) & 0xff;
174 _dbus_string_append_byte (val, b);
185 #ifdef DBUS_HAVE_GCC33_GCOV
186 /* In gcc33 .bbg files, there's a function name of the form:
187 * -1, length, name (padded to 4), -1, checksum
190 string_get_function (const DBusString *str,
192 DBusString *funcname,
202 if (!string_get_int (str, i, &val))
203 die ("no room for -1 before function name\n");
208 die ("value before function name is not -1\n");
210 if (!string_get_int (str, i, &val))
211 die ("no length found for function name\n");
216 if (end > _dbus_string_get_length (str))
217 die ("Function name length points past end of file\n");
219 if (!_dbus_string_append (funcname,
220 _dbus_string_get_const_data (str) + i))
223 /* skip alignment padding the length doesn't include the nul so add 1
225 i = _DBUS_ALIGN_VALUE (end + 1, 4);
227 if (!string_get_int (str, i, &val) ||
229 die ("-1 at end of function name not found\n");
233 if (!string_get_int (str, i, &val))
234 die ("no checksum found at end of function name\n");
244 #endif /* DBUS_HAVE_GCC33_GCOV */
247 dump_bb_file (const DBusString *contents)
255 while (string_get_int (contents, i, &val))
265 if (!_dbus_string_init (&f))
268 if (string_get_string (contents, i,
272 printf ("File %s\n", _dbus_string_get_const_data (&f));
274 _dbus_string_free (&f);
280 if (!_dbus_string_init (&f))
283 if (string_get_string (contents, i,
287 printf ("Function %s\n", _dbus_string_get_const_data (&f));
289 _dbus_string_free (&f);
295 printf ("End of block\n");
298 printf ("Line %ld\n", val);
303 printf ("%d functions in file\n", n_functions);
306 #define FLAG_ON_TREE 0x1
307 #define FLAG_FAKE 0x2
308 #define FLAG_FALL_THROUGH 0x4
311 dump_bbg_file (const DBusString *contents)
325 while (i < _dbus_string_get_length (contents))
327 long n_blocks_in_func;
331 #ifdef DBUS_HAVE_GCC33_GCOV
332 /* In gcc33 .bbg files, there's a function name of the form:
333 * -1, length, name (padded to 4), -1, checksum
334 * after that header on each function description, it's
335 * the same as in gcc32
342 if (!_dbus_string_init (&funcname))
345 if (!string_get_function (contents, i,
346 &funcname, &checksum, &i))
347 die ("could not read function name\n");
349 printf ("Function name is \"%s\" checksum %d\n",
350 _dbus_string_get_const_data (&funcname),
353 _dbus_string_free (&funcname);
355 #endif /* DBUS_HAVE_GCC33_GCOV */
357 if (!string_get_int (contents, i, &val))
358 die ("no count of blocks in func found\n");
362 n_blocks_in_func = val;
364 if (!string_get_int (contents, i, &n_arcs_in_func))
369 printf ("Function has %ld blocks and %ld arcs\n",
370 n_blocks_in_func, n_arcs_in_func);
373 n_blocks += n_blocks_in_func;
374 n_arcs += n_arcs_in_func;
377 while (j < n_blocks_in_func)
379 long n_arcs_in_block;
382 if (!string_get_int (contents, i, &n_arcs_in_block))
387 printf (" Block has %ld arcs\n", n_arcs_in_block);
390 while (k < n_arcs_in_block)
392 long destination_block;
395 if (!string_get_int (contents, i, &destination_block))
400 if (!string_get_int (contents, i, &flags))
405 printf (" Arc has destination block %ld flags 0x%lx\n",
406 destination_block, flags);
408 if ((flags & FLAG_ON_TREE) == 0)
409 n_arcs_off_tree += 1;
414 if (k < n_arcs_in_block)
420 if (j < n_blocks_in_func)
423 if (!string_get_int (contents, i, &val))
429 die ("-1 separator not found\n");
432 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
433 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
436 #ifndef DBUS_HAVE_GCC33_GCOV
439 * The da file contains first a count of arcs in the file,
440 * then a count of executions for all "off tree" arcs
444 dump_da_file (const DBusString *contents)
452 if (!string_get_int64 (contents, i, &val))
457 printf ("%ld arcs in file\n", (long) val);
458 claimed_n_arcs = val;
461 while (string_get_int64 (contents, i, &val))
465 printf ("%ld executions of arc %d\n",
471 if (n_arcs != claimed_n_arcs)
473 printf ("File claimed to have %d arcs but only had %d\n",
474 claimed_n_arcs, n_arcs);
478 #else /* DBUS_HAVE_GCC33_GCOV */
481 * The da file is more complex than 3.2.
483 * We have a magic value of "-123" only it isn't really
484 * -123, it's -123 as encoded by the crackass gcov-io.h
485 * routines. Anyway, 4 bytes.
489 * - 4 byte count of how many functions in the following list
490 * - 4 byte length of random extra data
491 * - the random extra data, just skip it, info pages have some
492 * details on what might be in there or see __bb_exit_func in gcc
493 * - then for each function (number of functions given above):
494 * . -1, length, funcname, alignment padding, -1
496 * . 4 byte number of arcs in function
497 * . 8 bytes each, a count of execution for each arc
499 * Now, the whole thing *starting with the magic* can repeat.
500 * This is caused by multiple runs of the profiled app appending
504 dump_da_file (const DBusString *contents)
516 while (i < _dbus_string_get_length (contents))
518 int claimed_n_functions;
522 printf (".da file section %d\n", n_sections);
524 if (!string_get_int (contents, i, &val))
525 die ("no magic found in .da file\n");
530 die ("wrong file magic in .da file\n");
532 if (!string_get_int (contents, i, &val))
533 die ("no function count in .da file\n");
535 claimed_n_functions = val;
537 printf ("%d functions expected in section %d of .da file\n",
538 claimed_n_functions, n_sections);
540 if (!string_get_int (contents, i, &val))
541 die ("no extra data length in .da file\n");
549 while (n_functions < claimed_n_functions)
556 if (!_dbus_string_init (&funcname))
559 if (!string_get_function (contents, i,
560 &funcname, &checksum, &i))
561 die ("could not read function name\n");
563 if (!string_get_int (contents, i, &val))
564 die ("no arc count for function\n");
567 claimed_n_arcs = val;
569 printf (" %d arcs in function %d %s checksum %d\n",
570 claimed_n_arcs, n_functions,
571 _dbus_string_get_const_data (&funcname),
575 while (n_arcs < claimed_n_arcs)
577 if (!string_get_int64 (contents, i, &v64))
578 die ("did not get execution count for arc\n");
582 printf (" %ld executions of arc %d (total arcs %d)\n",
583 (long) v64, n_arcs, total_arcs + n_arcs);
588 _dbus_string_free (&funcname);
590 total_arcs += n_arcs;
594 printf ("total of %d functions and %d arcs in section %d\n",
595 n_functions, total_arcs, n_sections);
597 total_functions += n_functions;
601 printf ("%d total function sections in %d total .da file sections\n",
602 total_functions, n_sections);
605 #endif /* DBUS_HAVE_GCC33_GCOV */
607 typedef struct Arc Arc;
608 typedef struct Block Block;
609 typedef struct Function Function;
610 typedef struct File File;
611 typedef struct Line Line;
617 dbus_int64_t arc_count;
618 unsigned int count_valid : 1;
619 unsigned int on_tree : 1;
620 unsigned int fake : 1;
621 unsigned int fall_through : 1;
630 dbus_int64_t succ_count;
631 dbus_int64_t pred_count;
632 dbus_int64_t exec_count;
634 unsigned int count_valid : 1;
635 unsigned int on_tree : 1;
636 unsigned int inside_dbus_build_tests : 1;
645 /* number of blocks in DBUS_BUILD_TESTS */
647 int n_test_blocks_executed;
648 /* number of blocks outside DBUS_BUILD_TESTS */
649 int n_nontest_blocks;
650 int n_nontest_blocks_executed;
651 /* Summary result flags */
652 unsigned int unused : 1;
653 unsigned int inside_dbus_build_tests : 1;
654 unsigned int partial : 1; /* only some of the blocks were executed */
662 unsigned int inside_dbus_build_tests : 1;
663 unsigned int partial : 1; /* only some of the blocks were executed */
675 function_add_arc (Function *function,
682 arc = dbus_new0 (Arc, 1);
686 arc->target = target;
687 arc->source = source;
689 arc->succ_next = function->block_graph[source].succ;
690 function->block_graph[source].succ = arc;
691 function->block_graph[source].succ_count += 1;
693 arc->pred_next = function->block_graph[target].pred;
694 function->block_graph[target].pred = arc;
695 function->block_graph[target].pred_count += 1;
697 if ((flags & FLAG_ON_TREE) != 0)
700 if ((flags & FLAG_FAKE) != 0)
703 if ((flags & FLAG_FALL_THROUGH) != 0)
704 arc->fall_through = TRUE;
709 reverse_arcs (Arc *arc)
711 struct Arc *prev = 0;
714 for ( ; arc; arc = next)
716 next = arc->succ_next;
717 arc->succ_next = prev;
725 function_reverse_succ_arcs (Function *func)
727 /* Must reverse the order of all succ arcs, to ensure that they match
728 * the order of the data in the .da file.
732 for (i = 0; i < func->n_blocks; i++)
733 if (func->block_graph[i].succ)
734 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
738 get_functions_from_bbg (const DBusString *contents,
739 DBusList **functions)
749 printf ("Loading arcs and blocks from .bbg file\n");
757 while (i < _dbus_string_get_length (contents))
760 long n_blocks_in_func;
764 #ifdef DBUS_HAVE_GCC33_GCOV
768 /* In gcc33 .bbg files, there's a function name of the form:
769 * -1, length, name (padded to 4), -1, checksum
770 * after that header on each function description, it's
771 * the same as in gcc32
773 if (!_dbus_string_init (&funcname))
776 if (!string_get_function (contents, i,
777 &funcname, &checksum, &i))
778 die ("could not read function name\n");
779 #endif /* DBUS_HAVE_GCC33_GCOV */
781 if (!string_get_int (contents, i, &val))
784 n_blocks_in_func = val;
788 if (!string_get_int (contents, i, &n_arcs_in_func))
794 n_blocks += n_blocks_in_func;
795 n_arcs += n_arcs_in_func;
797 func = dbus_new0 (Function, 1);
801 #ifdef DBUS_HAVE_GCC33_GCOV
802 func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
803 func->checksum = checksum;
804 _dbus_string_free (&funcname);
807 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
808 func->n_blocks = n_blocks_in_func;
811 while (j < n_blocks_in_func)
813 long n_arcs_in_block;
816 if (!string_get_int (contents, i, &n_arcs_in_block))
822 while (k < n_arcs_in_block)
824 long destination_block;
827 if (!string_get_int (contents, i, &destination_block))
832 if (!string_get_int (contents, i, &flags))
837 if ((flags & FLAG_ON_TREE) == 0)
838 n_arcs_off_tree += 1;
840 function_add_arc (func, j, destination_block,
846 if (k < n_arcs_in_block)
852 if (j < n_blocks_in_func)
855 function_reverse_succ_arcs (func);
857 if (!_dbus_list_append (functions, func))
860 if (!string_get_int (contents, i, &val))
866 die ("-1 separator not found in .bbg file\n");
870 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
871 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
874 _dbus_assert (n_functions == _dbus_list_get_length (functions));
877 #ifdef DBUS_HAVE_GCC33_GCOV
879 add_counts_from_da (const DBusString *contents,
880 DBusList **functions)
887 Function *current_func;
894 while (i < _dbus_string_get_length (contents))
896 int claimed_n_functions;
899 if (!string_get_int (contents, i, &val))
900 die ("no magic found in .da file\n");
905 die ("wrong file magic in .da file\n");
907 if (!string_get_int (contents, i, &val))
908 die ("no function count in .da file\n");
910 claimed_n_functions = val;
912 if (!string_get_int (contents, i, &val))
913 die ("no extra data length in .da file\n");
919 link = _dbus_list_get_first_link (functions);
921 goto no_more_functions;
924 while (n_functions < claimed_n_functions && link != NULL)
931 current_func = link->data;
933 current_arc = current_func->block_graph[current_block].succ;
935 if (!_dbus_string_init (&funcname))
938 if (!string_get_function (contents, i,
939 &funcname, &checksum, &i))
940 die ("could not read function name\n");
942 if (!_dbus_string_equal_c_str (&funcname, current_func->name))
944 fprintf (stderr, "Expecting .da info for %s but got %s\n",
946 _dbus_string_get_const_data (&funcname));
950 if (checksum != current_func->checksum)
951 die (".da file checksum doesn't match checksum from .bbg file\n");
953 if (!string_get_int (contents, i, &val))
954 die ("no arc count for function\n");
957 claimed_n_arcs = val;
959 /* For each arc in the profile, find the corresponding
960 * arc in the function and increment its count
963 while (n_arcs < claimed_n_arcs)
965 if (!string_get_int64 (contents, i, &v64))
966 die ("did not get execution count for arc\n");
970 /* Find the next arc in the function that isn't on tree */
971 while (current_arc == NULL ||
972 current_arc->on_tree)
974 if (current_arc == NULL)
978 if (current_block >= current_func->n_blocks)
979 die ("too many blocks in function\n");
981 current_arc = current_func->block_graph[current_block].succ;
985 current_arc = current_arc->succ_next;
989 _dbus_assert (current_arc != NULL);
990 _dbus_assert (!current_arc->on_tree);
992 current_arc->arc_count = v64;
993 current_arc->count_valid = TRUE;
994 current_func->block_graph[current_block].succ_count -= 1;
995 current_func->block_graph[current_arc->target].pred_count -= 1;
999 current_arc = current_arc->succ_next;
1002 _dbus_string_free (&funcname);
1004 link = _dbus_list_get_next_link (functions, link);
1007 if (link == NULL && n_functions < claimed_n_functions)
1009 fprintf (stderr, "Ran out of functions loading .da file\n");
1010 goto no_more_functions;
1019 #else /* DBUS_HAVE_GCC33_GCOV */
1021 add_counts_from_da (const DBusString *contents,
1022 DBusList **functions)
1029 Function *current_func;
1034 printf ("Loading execution count for each arc from .da file\n");
1038 if (!string_get_int64 (contents, i, &val))
1043 claimed_n_arcs = val;
1045 link = _dbus_list_get_first_link (functions);
1049 current_func = link->data;
1051 current_arc = current_func->block_graph[current_block].succ;
1054 while (string_get_int64 (contents, i, &val))
1058 while (current_arc == NULL ||
1059 current_arc->on_tree)
1061 if (current_arc == NULL)
1065 if (current_block == current_func->n_blocks)
1067 link = _dbus_list_get_next_link (functions, link);
1070 fprintf (stderr, "Ran out of functions loading .da file\n");
1073 current_func = link->data;
1077 current_arc = current_func->block_graph[current_block].succ;
1081 current_arc = current_arc->succ_next;
1085 _dbus_assert (current_arc != NULL);
1086 _dbus_assert (!current_arc->on_tree);
1088 current_arc->arc_count = val;
1089 current_arc->count_valid = TRUE;
1090 current_func->block_graph[current_block].succ_count -= 1;
1091 current_func->block_graph[current_arc->target].pred_count -= 1;
1095 current_arc = current_arc->succ_next;
1100 if (n_arcs != claimed_n_arcs)
1102 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
1103 claimed_n_arcs, n_arcs);
1108 printf ("%d arcs in file\n", n_arcs);
1114 function_solve_graph (Function *func)
1116 int passes, changes;
1124 printf ("Solving function graph\n");
1127 n_blocks = func->n_blocks;
1128 block_graph = func->block_graph;
1130 /* For every block in the file,
1131 - if every exit/entrance arc has a known count, then set the block count
1132 - if the block count is known, and every exit/entrance arc but one has
1133 a known execution count, then set the count of the remaining arc
1135 As arc counts are set, decrement the succ/pred count, but don't delete
1136 the arc, that way we can easily tell when all arcs are known, or only
1137 one arc is unknown. */
1139 /* The order that the basic blocks are iterated through is important.
1140 Since the code that finds spanning trees starts with block 0, low numbered
1141 arcs are put on the spanning tree in preference to high numbered arcs.
1142 Hence, most instrumented arcs are at the end. Graph solving works much
1143 faster if we propagate numbers from the end to the start.
1145 This takes an average of slightly more than 3 passes. */
1154 for (i = n_blocks - 1; i >= 0; i--)
1156 if (! block_graph[i].count_valid)
1158 if (block_graph[i].succ_count == 0)
1161 for (arc = block_graph[i].succ; arc;
1162 arc = arc->succ_next)
1163 total += arc->arc_count;
1164 block_graph[i].exec_count = total;
1165 block_graph[i].count_valid = 1;
1168 else if (block_graph[i].pred_count == 0)
1171 for (arc = block_graph[i].pred; arc;
1172 arc = arc->pred_next)
1173 total += arc->arc_count;
1174 block_graph[i].exec_count = total;
1175 block_graph[i].count_valid = 1;
1179 if (block_graph[i].count_valid)
1181 if (block_graph[i].succ_count == 1)
1184 /* One of the counts will be invalid, but it is zero,
1185 so adding it in also doesn't hurt. */
1186 for (arc = block_graph[i].succ; arc;
1187 arc = arc->succ_next)
1188 total += arc->arc_count;
1189 /* Calculate count for remaining arc by conservation. */
1190 total = block_graph[i].exec_count - total;
1191 /* Search for the invalid arc, and set its count. */
1192 for (arc = block_graph[i].succ; arc;
1193 arc = arc->succ_next)
1194 if (! arc->count_valid)
1197 die ("arc == NULL\n");
1198 arc->count_valid = 1;
1199 arc->arc_count = total;
1200 block_graph[i].succ_count -= 1;
1202 block_graph[arc->target].pred_count -= 1;
1205 if (block_graph[i].pred_count == 1)
1208 /* One of the counts will be invalid, but it is zero,
1209 so adding it in also doesn't hurt. */
1210 for (arc = block_graph[i].pred; arc;
1211 arc = arc->pred_next)
1212 total += arc->arc_count;
1213 /* Calculate count for remaining arc by conservation. */
1214 total = block_graph[i].exec_count - total;
1215 /* Search for the invalid arc, and set its count. */
1216 for (arc = block_graph[i].pred; arc;
1217 arc = arc->pred_next)
1218 if (! arc->count_valid)
1221 die ("arc == NULL\n");
1222 arc->count_valid = 1;
1223 arc->arc_count = total;
1224 block_graph[i].pred_count -= 1;
1226 block_graph[arc->source].succ_count -= 1;
1233 /* If the graph has been correctly solved, every block will have a
1234 * succ and pred count of zero.
1237 dbus_bool_t header = FALSE;
1238 for (i = 0; i < n_blocks; i++)
1240 if (block_graph[i].succ_count || block_graph[i].pred_count)
1244 fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
1246 fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
1249 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
1250 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
1257 solve_graphs (DBusList **functions)
1261 link = _dbus_list_get_first_link (functions);
1262 while (link != NULL)
1264 Function *func = link->data;
1266 function_solve_graph (func);
1268 link = _dbus_list_get_next_link (functions, link);
1273 load_functions_for_c_file (const DBusString *filename,
1274 DBusList **functions)
1276 DBusString bbg_filename;
1277 DBusString da_filename;
1278 DBusString gcno_filename;
1279 DBusString gcda_filename;
1280 DBusString contents;
1284 /* With latest gcc it's .gcno instead of .bbg and
1285 * gcda instead of .da
1288 dbus_error_init (&error);
1290 if (!_dbus_string_init (&bbg_filename) ||
1291 !_dbus_string_init (&da_filename) ||
1292 !_dbus_string_init (&gcno_filename) ||
1293 !_dbus_string_init (&gcda_filename) ||
1294 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
1295 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
1296 !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
1297 !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
1298 !_dbus_string_init (&contents))
1299 die ("no memory\n");
1301 _dbus_string_shorten (&bbg_filename, 2);
1302 _dbus_string_shorten (&da_filename, 2);
1304 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
1305 !_dbus_string_append (&da_filename, ".da") ||
1306 !_dbus_string_append (&bbg_filename, ".gcno") ||
1307 !_dbus_string_append (&bbg_filename, ".gcda"))
1308 die ("no memory\n");
1310 if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
1311 name = &gcno_filename;
1313 name = &bbg_filename;
1315 if (!_dbus_file_get_contents (&contents, name,
1318 fprintf (stderr, "Could not open file: %s\n",
1323 get_functions_from_bbg (&contents, functions);
1325 _dbus_string_set_length (&contents, 0);
1327 if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
1328 name = &gcda_filename;
1330 name = &da_filename;
1332 if (!_dbus_file_get_contents (&contents, name,
1335 /* Try .libs/file.da */
1338 if (_dbus_string_find_byte_backward (name,
1339 _dbus_string_get_length (name),
1344 _dbus_string_init_const (&libs, "/.libs");
1346 if (!_dbus_string_copy (&libs, 0, name, slash))
1349 dbus_error_free (&error);
1350 if (!_dbus_file_get_contents (&contents, name,
1353 fprintf (stderr, "Could not open file: %s\n",
1360 fprintf (stderr, "Could not open file: %s\n",
1366 add_counts_from_da (&contents, functions);
1368 solve_graphs (functions);
1370 _dbus_string_free (&contents);
1371 _dbus_string_free (&da_filename);
1372 _dbus_string_free (&bbg_filename);
1376 get_lines_from_bb_file (const DBusString *contents,
1382 dbus_bool_t in_our_file;
1388 printf ("Getting line numbers for blocks from .bb file\n");
1391 /* There's this "filename" field in the .bb file which
1392 * mysteriously comes *after* the first function in the
1393 * file in the .bb file; and every .bb file seems to
1394 * have only one filename. I don't understand
1395 * what's going on here, so just set in_our_file = TRUE
1396 * at the start categorically.
1402 link = _dbus_list_get_first_link (&fl->functions);
1405 while (string_get_int (contents, i, &val))
1415 if (!_dbus_string_init (&f))
1416 die ("no memory\n");
1418 if (string_get_string (contents, i,
1422 /* fl->name is a full path and the filename in .bb is
1427 _dbus_string_init_const (&tmp_str, fl->name);
1429 if (_dbus_string_ends_with_c_str (&tmp_str,
1430 _dbus_string_get_const_data (&f)))
1433 in_our_file = FALSE;
1437 "File %s in .bb, looking for %s, in_our_file = %d\n",
1438 _dbus_string_get_const_data (&f),
1443 _dbus_string_free (&f);
1449 if (!_dbus_string_init (&f))
1450 die ("no memory\n");
1452 if (string_get_string (contents, i,
1457 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
1466 fprintf (stderr, "No function object for function %s\n",
1467 _dbus_string_get_const_data (&f));
1472 link = _dbus_list_get_next_link (&fl->functions, link);
1474 if (func->name == NULL)
1476 if (!_dbus_string_copy_data (&f, &func->name))
1477 die ("no memory\n");
1481 if (!_dbus_string_equal_c_str (&f, func->name))
1483 fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
1484 func->name, strlen (func->name),
1485 _dbus_string_get_const_data (&f),
1486 _dbus_string_get_length (&f));
1493 _dbus_string_free (&f);
1503 fprintf (stderr, "Line %ld\n", val);
1506 if (val >= fl->n_lines)
1508 fprintf (stderr, "Line %ld but file only has %d lines\n",
1511 else if (func != NULL)
1513 val -= 1; /* To convert the 1-based line number to 0-based */
1514 _dbus_assert (val >= 0);
1516 if (block < func->n_blocks)
1518 if (!_dbus_list_append (&func->block_graph[block].lines,
1520 die ("no memory\n");
1523 if (!_dbus_list_append (&fl->lines[val].blocks,
1524 &func->block_graph[block]))
1525 die ("no memory\n");
1529 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1530 block, func->n_blocks);
1535 fprintf (stderr, "Line %ld given outside of any function\n",
1544 printf ("%d functions in file\n", n_functions);
1550 load_block_line_associations (const DBusString *filename,
1553 DBusString bb_filename;
1554 DBusString contents;
1557 dbus_error_init (&error);
1559 if (!_dbus_string_init (&bb_filename) ||
1560 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1561 !_dbus_string_init (&contents))
1562 die ("no memory\n");
1564 _dbus_string_shorten (&bb_filename, 2);
1566 if (!_dbus_string_append (&bb_filename, ".bb"))
1567 die ("no memory\n");
1569 if (!_dbus_file_get_contents (&contents, &bb_filename,
1572 fprintf (stderr, "Could not open file: %s\n",
1577 get_lines_from_bb_file (&contents, f);
1579 _dbus_string_free (&contents);
1580 _dbus_string_free (&bb_filename);
1584 count_lines_in_string (const DBusString *str)
1590 const char *last_line_end;
1593 printf ("Counting lines in source file\n");
1598 p = _dbus_string_get_const_data (str);
1599 end = p + _dbus_string_get_length (str);
1603 /* too lazy to handle \r\n as one linebreak */
1604 if (*p == '\n' || *p == '\r')
1607 last_line_end = p + 1;
1614 if (last_line_end != p)
1621 fill_line_content (const DBusString *str,
1628 const char *last_line_end;
1631 printf ("Saving contents of each line in source file\n");
1636 p = _dbus_string_get_const_data (str);
1637 end = p + _dbus_string_get_length (str);
1641 if (*p == '\n' || *p == '\r')
1643 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1644 if (lines[n_lines].text == NULL)
1645 die ("no memory\n");
1647 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1648 lines[n_lines].number = n_lines + 1;
1652 last_line_end = p + 1;
1659 if (p != last_line_end)
1661 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1667 mark_inside_dbus_build_tests (File *f)
1675 while (i < f->n_lines)
1677 Line *l = &f->lines[i];
1678 dbus_bool_t is_verbose;
1680 is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
1682 if (inside_depth == 0)
1686 a = strstr (l->text, "#if");
1687 b = strstr (l->text, "DBUS_BUILD_TESTS");
1688 if (a && b && (a < b))
1693 if (strstr (l->text, "#if") != NULL)
1695 else if (strstr (l->text, "#endif") != NULL)
1699 if (inside_depth > 0 || is_verbose)
1701 /* Mark the line and its blocks */
1704 l->inside_dbus_build_tests = TRUE;
1706 blink = _dbus_list_get_first_link (&l->blocks);
1707 while (blink != NULL)
1709 Block *b = blink->data;
1711 b->inside_dbus_build_tests = TRUE;
1713 blink = _dbus_list_get_next_link (&l->blocks, blink);
1720 /* Now mark functions where for all blocks that are associated
1721 * with a source line, the block is inside_dbus_build_tests.
1723 link = _dbus_list_get_first_link (&f->functions);
1724 while (link != NULL)
1726 Function *func = link->data;
1728 /* The issue is that some blocks aren't associated with a source line.
1729 * Assume they are inside/outside tests according to the source
1730 * line of the preceding block. For the first block, make it
1731 * match the first following block with a line associated.
1733 if (func->block_graph[0].lines == NULL)
1735 /* find first following line */
1737 while (i < func->n_blocks)
1739 if (func->block_graph[i].lines != NULL)
1741 func->block_graph[0].inside_dbus_build_tests =
1742 func->block_graph[i].inside_dbus_build_tests;
1750 /* Now mark all blocks but the first */
1752 while (i < func->n_blocks)
1754 if (func->block_graph[i].lines == NULL)
1756 func->block_graph[i].inside_dbus_build_tests =
1757 func->block_graph[i-1].inside_dbus_build_tests;
1764 while (i < func->n_blocks)
1766 /* Break as soon as any block is not a test block */
1767 if (func->block_graph[i].lines != NULL &&
1768 !func->block_graph[i].inside_dbus_build_tests)
1774 if (i == func->n_blocks)
1775 func->inside_dbus_build_tests = TRUE;
1777 link = _dbus_list_get_next_link (&f->functions, link);
1782 mark_coverage (File *f)
1788 while (i < f->n_lines)
1790 Line *l = &f->lines[i];
1793 int n_blocks_executed;
1796 n_blocks_executed = 0;
1797 blink = _dbus_list_get_first_link (&l->blocks);
1798 while (blink != NULL)
1800 Block *b = blink->data;
1802 if (b->exec_count > 0)
1803 n_blocks_executed += 1;
1807 blink = _dbus_list_get_next_link (&l->blocks, blink);
1810 if (n_blocks_executed > 0 &&
1811 n_blocks_executed < n_blocks)
1817 link = _dbus_list_get_first_link (&f->functions);
1818 while (link != NULL)
1820 Function *func = link->data;
1823 int n_test_blocks_executed;
1824 int n_nontest_blocks;
1825 int n_nontest_blocks_executed;
1828 n_test_blocks_executed = 0;
1829 n_nontest_blocks = 0;
1830 n_nontest_blocks_executed = 0;
1833 while (i < func->n_blocks)
1835 if (!func->block_graph[i].inside_dbus_build_tests)
1837 n_nontest_blocks += 1;
1839 if (func->block_graph[i].exec_count > 0)
1840 n_nontest_blocks_executed += 1;
1846 if (func->block_graph[i].exec_count > 0)
1847 n_test_blocks_executed += 1;
1853 if (n_nontest_blocks_executed > 0 &&
1854 n_nontest_blocks_executed < n_nontest_blocks)
1855 func->partial = TRUE;
1857 if (n_nontest_blocks_executed == 0 &&
1858 n_nontest_blocks > 0)
1859 func->unused = TRUE;
1861 func->n_test_blocks = n_test_blocks;
1862 func->n_test_blocks_executed = n_test_blocks_executed;
1863 func->n_nontest_blocks = n_nontest_blocks;
1864 func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1866 link = _dbus_list_get_next_link (&f->functions, link);
1871 load_c_file (const DBusString *filename)
1873 DBusString contents;
1877 f = dbus_new0 (File, 1);
1879 die ("no memory\n");
1881 if (!_dbus_string_copy_data (filename, &f->name))
1882 die ("no memory\n");
1884 if (!_dbus_string_init (&contents))
1885 die ("no memory\n");
1887 dbus_error_init (&error);
1889 if (!_dbus_file_get_contents (&contents, filename,
1892 fprintf (stderr, "Could not open file: %s\n",
1894 dbus_error_free (&error);
1898 load_functions_for_c_file (filename, &f->functions);
1900 f->n_lines = count_lines_in_string (&contents);
1901 f->lines = dbus_new0 (Line, f->n_lines);
1902 if (f->lines == NULL)
1903 die ("no memory\n");
1905 fill_line_content (&contents, f->lines);
1907 _dbus_string_free (&contents);
1909 load_block_line_associations (filename, f);
1911 mark_inside_dbus_build_tests (f);
1917 typedef struct Stats Stats;
1922 int n_blocks_executed;
1923 int n_blocks_inside_dbus_build_tests;
1925 int n_lines; /* lines that have blocks on them */
1926 int n_lines_executed;
1927 int n_lines_partial;
1928 int n_lines_inside_dbus_build_tests;
1931 int n_functions_executed;
1932 int n_functions_partial;
1933 int n_functions_inside_dbus_build_tests;
1937 line_was_executed (Line *l)
1941 link = _dbus_list_get_first_link (&l->blocks);
1942 while (link != NULL)
1944 Block *b = link->data;
1946 if (b->exec_count > 0)
1949 link = _dbus_list_get_next_link (&l->blocks, link);
1957 line_exec_count (Line *l)
1963 link = _dbus_list_get_first_link (&l->blocks);
1964 while (link != NULL)
1966 Block *b = link->data;
1968 total += b->exec_count;
1970 link = _dbus_list_get_next_link (&l->blocks, link);
1977 merge_stats_for_file (Stats *stats,
1983 for (i = 0; i < f->n_lines; ++i)
1985 Line *l = &f->lines[i];
1987 if (l->inside_dbus_build_tests)
1989 stats->n_lines_inside_dbus_build_tests += 1;
1993 if (line_was_executed (l))
1994 stats->n_lines_executed += 1;
1996 if (l->blocks != NULL)
1997 stats->n_lines += 1;
2000 stats->n_lines_partial += 1;
2003 link = _dbus_list_get_first_link (&f->functions);
2004 while (link != NULL)
2006 Function *func = link->data;
2008 if (func->inside_dbus_build_tests)
2009 stats->n_functions_inside_dbus_build_tests += 1;
2012 stats->n_functions += 1;
2015 stats->n_functions_executed += 1;
2018 stats->n_functions_partial += 1;
2021 stats->n_blocks_inside_dbus_build_tests +=
2022 func->n_test_blocks;
2024 stats->n_blocks_executed +=
2025 func->n_nontest_blocks_executed;
2028 func->n_nontest_blocks;
2030 link = _dbus_list_get_next_link (&f->functions, link);
2034 /* The output of this matches gcov exactly ("diff" shows no difference) */
2036 print_annotated_source_gcov_format (File *f)
2041 while (i < f->n_lines)
2043 Line *l = &f->lines[i];
2045 if (l->blocks != NULL)
2049 exec_count = line_exec_count (l);
2052 printf ("%12d %s\n",
2053 exec_count, l->text);
2055 printf (" ###### %s\n", l->text);
2059 printf ("\t\t%s\n", l->text);
2067 print_annotated_source (File *f)
2072 while (i < f->n_lines)
2074 Line *l = &f->lines[i];
2076 if (l->inside_dbus_build_tests)
2081 if (l->blocks != NULL)
2085 exec_count = line_exec_count (l);
2088 printf ("%12d %s\n",
2089 exec_count, l->text);
2091 printf (" ###### %s\n", l->text);
2095 printf ("\t\t%s\n", l->text);
2103 print_block_superdetails (File *f)
2108 link = _dbus_list_get_first_link (&f->functions);
2109 while (link != NULL)
2111 Function *func = link->data;
2113 printf ("=== %s():\n", func->name);
2116 while (i < func->n_blocks)
2118 Block *b = &func->block_graph[i];
2121 printf (" %5d executed %d times%s\n", i,
2122 (int) b->exec_count,
2123 b->inside_dbus_build_tests ?
2124 " [inside DBUS_BUILD_TESTS]" : "");
2126 l = _dbus_list_get_first_link (&b->lines);
2129 Line *line = l->data;
2131 printf ("4%d\t%s\n", line->number, line->text);
2133 l = _dbus_list_get_next_link (&b->lines, l);
2139 link = _dbus_list_get_next_link (&f->functions, link);
2144 print_one_file (const DBusString *filename)
2146 if (_dbus_string_ends_with_c_str (filename, ".bb"))
2148 DBusString contents;
2151 if (!_dbus_string_init (&contents))
2152 die ("no memory\n");
2154 dbus_error_init (&error);
2156 if (!_dbus_file_get_contents (&contents, filename,
2159 fprintf (stderr, "Could not open file: %s\n",
2161 dbus_error_free (&error);
2165 dump_bb_file (&contents);
2167 _dbus_string_free (&contents);
2169 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
2171 DBusString contents;
2174 if (!_dbus_string_init (&contents))
2175 die ("no memory\n");
2177 dbus_error_init (&error);
2179 if (!_dbus_file_get_contents (&contents, filename,
2182 fprintf (stderr, "Could not open file: %s\n",
2184 dbus_error_free (&error);
2188 dump_bbg_file (&contents);
2190 _dbus_string_free (&contents);
2192 else if (_dbus_string_ends_with_c_str (filename, ".da"))
2194 DBusString contents;
2197 if (!_dbus_string_init (&contents))
2198 die ("no memory\n");
2200 dbus_error_init (&error);
2202 if (!_dbus_file_get_contents (&contents, filename,
2205 fprintf (stderr, "Could not open file: %s\n",
2207 dbus_error_free (&error);
2211 dump_da_file (&contents);
2213 _dbus_string_free (&contents);
2215 else if (_dbus_string_ends_with_c_str (filename, ".c"))
2219 f = load_c_file (filename);
2221 print_annotated_source (f);
2225 fprintf (stderr, "Unknown file type %s\n",
2226 _dbus_string_get_const_data (filename));
2232 print_untested_functions (File *f)
2238 link = _dbus_list_get_first_link (&f->functions);
2239 while (link != NULL)
2241 Function *func = link->data;
2244 !func->inside_dbus_build_tests)
2247 link = _dbus_list_get_next_link (&f->functions, link);
2253 printf ("Untested functions in %s\n", f->name);
2254 printf ("=======\n");
2256 link = _dbus_list_get_first_link (&f->functions);
2257 while (link != NULL)
2259 Function *func = link->data;
2262 !func->inside_dbus_build_tests)
2263 printf (" %s\n", func->name);
2265 link = _dbus_list_get_next_link (&f->functions, link);
2272 print_poorly_tested_functions (File *f,
2278 #define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
2280 #define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
2282 #define POORLY_TESTED(function) (!(function)->unused && \
2283 (function)->n_nontest_blocks > 0 && \
2284 TEST_FRACTION (function) < AVERAGE_COVERAGE)
2287 link = _dbus_list_get_first_link (&f->functions);
2288 while (link != NULL)
2290 Function *func = link->data;
2292 if (POORLY_TESTED (func))
2295 link = _dbus_list_get_next_link (&f->functions, link);
2301 printf ("Below average functions in %s\n", f->name);
2302 printf ("=======\n");
2304 link = _dbus_list_get_first_link (&f->functions);
2305 while (link != NULL)
2307 Function *func = link->data;
2309 if (POORLY_TESTED (func))
2310 printf (" %s (%d%%)\n", func->name,
2311 (int) (TEST_FRACTION (func) * 100));
2313 link = _dbus_list_get_next_link (&f->functions, link);
2320 func_cmp (const void *a,
2323 Function *af = *(Function**) a;
2324 Function *bf = *(Function**) b;
2325 int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
2326 int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
2328 /* Sort by number of untested blocks */
2329 return b_untested - a_untested;
2333 print_n_untested_blocks_by_function (File *f,
2342 link = _dbus_list_get_first_link (&f->functions);
2343 while (link != NULL)
2345 Function *func = link->data;
2347 if (func->n_nontest_blocks_executed <
2348 func->n_nontest_blocks)
2351 link = _dbus_list_get_next_link (&f->functions, link);
2357 /* make an array so we can use qsort */
2359 funcs = dbus_new (Function*, n_found);
2364 link = _dbus_list_get_first_link (&f->functions);
2365 while (link != NULL)
2367 Function *func = link->data;
2369 if (func->n_nontest_blocks_executed <
2370 func->n_nontest_blocks)
2376 link = _dbus_list_get_next_link (&f->functions, link);
2379 _dbus_assert (i == n_found);
2381 qsort (funcs, n_found, sizeof (Function*),
2384 printf ("Incomplete functions in %s\n", f->name);
2385 printf ("=======\n");
2390 Function *func = funcs[i];
2392 printf (" %s (%d/%d untested blocks)\n",
2394 func->n_nontest_blocks - func->n_nontest_blocks_executed,
2395 func->n_nontest_blocks);
2406 print_stats (Stats *stats,
2407 const char *of_what)
2411 printf ("Summary (%s)\n", of_what);
2412 printf ("=======\n");
2413 printf (" %g%% blocks executed (%d of %d)\n",
2414 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
2415 stats->n_blocks_executed,
2418 printf (" (ignored %d blocks of test-only/debug-only code)\n",
2419 stats->n_blocks_inside_dbus_build_tests);
2421 printf (" %g%% functions executed (%d of %d)\n",
2422 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
2423 stats->n_functions_executed,
2424 stats->n_functions);
2426 completely = stats->n_functions_executed - stats->n_functions_partial;
2427 printf (" %g%% functions completely executed (%d of %d)\n",
2428 (completely / (double) stats->n_functions) * 100.0,
2430 stats->n_functions);
2432 printf (" (ignored %d functions of test-only/debug-only code)\n",
2433 stats->n_functions_inside_dbus_build_tests);
2435 printf (" %g%% lines executed (%d of %d)\n",
2436 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
2437 stats->n_lines_executed,
2440 completely = stats->n_lines_executed - stats->n_lines_partial;
2441 printf (" %g%% lines completely executed (%d of %d)\n",
2442 (completely / (double) stats->n_lines) * 100.0,
2446 printf (" (ignored %d lines of test-only/debug-only code)\n",
2447 stats->n_lines_inside_dbus_build_tests);
2461 main (int argc, char **argv)
2463 DBusString filename;
2469 fprintf (stderr, "Must specify files on command line\n");
2476 if (strcmp (argv[i], "--report") == 0)
2481 else if (strcmp (argv[i], "--blocks") == 0)
2486 else if (strcmp (argv[i], "--gcov") == 0)
2495 fprintf (stderr, "Must specify files on command line\n");
2499 if (m == MODE_PRINT)
2503 _dbus_string_init_const (&filename, argv[i]);
2505 print_one_file (&filename);
2510 else if (m == MODE_BLOCKS || m == MODE_GCOV)
2516 _dbus_string_init_const (&filename, argv[i]);
2518 f = load_c_file (&filename);
2520 if (m == MODE_BLOCKS)
2521 print_block_superdetails (f);
2522 else if (m == MODE_GCOV)
2523 print_annotated_source_gcov_format (f);
2528 else if (m == MODE_REPORT)
2530 Stats stats = { 0, };
2533 DBusHashTable *stats_by_dir;
2539 _dbus_string_init_const (&filename, argv[i]);
2541 if (_dbus_string_ends_with_c_str (&filename, ".c"))
2545 f = load_c_file (&filename);
2547 if (!_dbus_list_append (&files, f))
2548 die ("no memory\n");
2552 fprintf (stderr, "Unknown file type %s\n",
2553 _dbus_string_get_const_data (&filename));
2560 link = _dbus_list_get_first_link (&files);
2561 while (link != NULL)
2563 File *f = link->data;
2565 merge_stats_for_file (&stats, f);
2567 link = _dbus_list_get_next_link (&files, link);
2570 print_stats (&stats, "all files");
2572 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
2573 dbus_free, dbus_free);
2575 link = _dbus_list_get_first_link (&files);
2576 while (link != NULL)
2578 File *f = link->data;
2583 _dbus_string_init_const (&filename, f->name);
2585 if (!_dbus_string_init (&dirname))
2586 die ("no memory\n");
2588 if (!_dbus_string_get_dirname (&filename, &dirname) ||
2589 !_dbus_string_copy_data (&dirname, &dirname_c))
2590 die ("no memory\n");
2592 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
2595 if (dir_stats == NULL)
2597 dir_stats = dbus_new0 (Stats, 1);
2598 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
2600 die ("no memory\n");
2603 dbus_free (dirname_c);
2605 merge_stats_for_file (dir_stats, f);
2607 link = _dbus_list_get_next_link (&files, link);
2610 _dbus_hash_iter_init (stats_by_dir, &iter);
2611 while (_dbus_hash_iter_next (&iter))
2613 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
2614 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
2616 print_stats (dir_stats, dirname);
2619 _dbus_hash_table_unref (stats_by_dir);
2621 link = _dbus_list_get_first_link (&files);
2622 while (link != NULL)
2624 File *f = link->data;
2626 print_untested_functions (f);
2628 link = _dbus_list_get_next_link (&files, link);
2631 link = _dbus_list_get_first_link (&files);
2632 while (link != NULL)
2634 File *f = link->data;
2636 print_poorly_tested_functions (f, &stats);
2638 link = _dbus_list_get_next_link (&files, link);
2641 link = _dbus_list_get_first_link (&files);
2642 while (link != NULL)
2644 File *f = link->data;
2646 print_n_untested_blocks_by_function (f, &stats);
2648 link = _dbus_list_get_next_link (&files, link);