Update contrib.
2 /* -*- mode: C; c-file-style: "gnu" -*- */
3 /* decode-gcov.c gcov decoder program
5 * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
6 * Copyright (C) 2003 Red Hat Inc.
8 * Partially derived from gcov,
9 * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
10 * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12 * This file is NOT licensed under the Academic Free License
13 * as it is largely derived from gcov.c and gcov-io.h in the
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #define DBUS_COMPILATION /* cheat */
34 #include <dbus/dbus-list.h>
35 #include <dbus/dbus-string.h>
36 #include <dbus/dbus-sysdeps.h>
37 #include <dbus/dbus-hash.h>
39 #include "dbus-list.h"
40 #include "dbus-string.h"
41 #include "dbus-sysdeps.h"
42 #include "dbus-hash.h"
46 #undef DBUS_COMPILATION
52 #define DBUS_HAVE_INT64 1
55 #ifndef DBUS_HAVE_INT64
56 #error "gcov support can't be built without 64-bit integer support"
60 die (const char *message)
62 fprintf (stderr, "%s", message);
66 /* This bizarro function is from gcov-io.h in gcc source tree */
68 fetch_long (long *dest,
75 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
76 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
80 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
82 if ((source[bytes - 1] & 128) && (value > 0))
90 fetch_long64 (dbus_int64_t *dest,
94 dbus_int64_t value = 0;
97 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
98 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
102 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
104 if ((source[bytes - 1] & 128) && (value > 0))
111 #define BB_FILENAME (-1)
112 #define BB_FUNCTION (-2)
113 #define BB_ENDOFLIST 0
116 string_get_int (const DBusString *str,
122 if ((_dbus_string_get_length (str) - start) < 4)
125 p = _dbus_string_get_const_data (str);
129 fetch_long (val, p, 4);
135 string_get_int64 (const DBusString *str,
141 if ((_dbus_string_get_length (str) - start) < 8)
144 p = _dbus_string_get_const_data (str);
148 fetch_long64 (val, p, 8);
154 string_get_string (const DBusString *str,
164 while (string_get_int (str, i, &n))
176 _dbus_string_append_byte (val, b);
180 _dbus_string_append_byte (val, b);
181 b = (n >> 16) & 0xff;
184 _dbus_string_append_byte (val, b);
185 b = (n >> 24) & 0xff;
187 _dbus_string_append_byte (val, b);
198 #ifdef DBUS_HAVE_GCC33_GCOV
199 /* In gcc33 .bbg files, there's a function name of the form:
200 * -1, length, name (padded to 4), -1, checksum
203 string_get_function (const DBusString *str,
205 DBusString *funcname,
215 if (!string_get_int (str, i, &val))
216 die ("no room for -1 before function name\n");
221 die ("value before function name is not -1\n");
223 if (!string_get_int (str, i, &val))
224 die ("no length found for function name\n");
229 if (end > _dbus_string_get_length (str))
230 die ("Function name length points past end of file\n");
232 if (!_dbus_string_append (funcname,
233 _dbus_string_get_const_data (str) + i))
236 /* skip alignment padding the length doesn't include the nul so add 1
238 i = _DBUS_ALIGN_VALUE (end + 1, 4);
240 if (!string_get_int (str, i, &val) ||
242 die ("-1 at end of function name not found\n");
246 if (!string_get_int (str, i, &val))
247 die ("no checksum found at end of function name\n");
257 #endif /* DBUS_HAVE_GCC33_GCOV */
260 dump_bb_file (const DBusString *contents)
268 while (string_get_int (contents, i, &val))
278 if (!_dbus_string_init (&f))
281 if (string_get_string (contents, i,
285 printf ("File %s\n", _dbus_string_get_const_data (&f));
287 _dbus_string_free (&f);
293 if (!_dbus_string_init (&f))
296 if (string_get_string (contents, i,
300 printf ("Function %s\n", _dbus_string_get_const_data (&f));
302 _dbus_string_free (&f);
308 printf ("End of block\n");
311 printf ("Line %ld\n", val);
316 printf ("%d functions in file\n", n_functions);
319 #define FLAG_ON_TREE 0x1
320 #define FLAG_FAKE 0x2
321 #define FLAG_FALL_THROUGH 0x4
324 dump_bbg_file (const DBusString *contents)
338 while (i < _dbus_string_get_length (contents))
340 long n_blocks_in_func;
344 #ifdef DBUS_HAVE_GCC33_GCOV
345 /* In gcc33 .bbg files, there's a function name of the form:
346 * -1, length, name (padded to 4), -1, checksum
347 * after that header on each function description, it's
348 * the same as in gcc32
355 if (!_dbus_string_init (&funcname))
358 if (!string_get_function (contents, i,
359 &funcname, &checksum, &i))
360 die ("could not read function name\n");
362 printf ("Function name is \"%s\" checksum %d\n",
363 _dbus_string_get_const_data (&funcname),
366 _dbus_string_free (&funcname);
368 #endif /* DBUS_HAVE_GCC33_GCOV */
370 if (!string_get_int (contents, i, &val))
371 die ("no count of blocks in func found\n");
375 n_blocks_in_func = val;
377 if (!string_get_int (contents, i, &n_arcs_in_func))
382 printf ("Function has %ld blocks and %ld arcs\n",
383 n_blocks_in_func, n_arcs_in_func);
386 n_blocks += n_blocks_in_func;
387 n_arcs += n_arcs_in_func;
390 while (j < n_blocks_in_func)
392 long n_arcs_in_block;
395 if (!string_get_int (contents, i, &n_arcs_in_block))
400 printf (" Block has %ld arcs\n", n_arcs_in_block);
403 while (k < n_arcs_in_block)
405 long destination_block;
408 if (!string_get_int (contents, i, &destination_block))
413 if (!string_get_int (contents, i, &flags))
418 printf (" Arc has destination block %ld flags 0x%lx\n",
419 destination_block, flags);
421 if ((flags & FLAG_ON_TREE) == 0)
422 n_arcs_off_tree += 1;
427 if (k < n_arcs_in_block)
433 if (j < n_blocks_in_func)
436 if (!string_get_int (contents, i, &val))
442 die ("-1 separator not found\n");
445 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
446 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
449 #ifndef DBUS_HAVE_GCC33_GCOV
452 * The da file contains first a count of arcs in the file,
453 * then a count of executions for all "off tree" arcs
457 dump_da_file (const DBusString *contents)
465 if (!string_get_int64 (contents, i, &val))
470 printf ("%ld arcs in file\n", (long) val);
471 claimed_n_arcs = val;
474 while (string_get_int64 (contents, i, &val))
478 printf ("%ld executions of arc %d\n",
484 if (n_arcs != claimed_n_arcs)
486 printf ("File claimed to have %d arcs but only had %d\n",
487 claimed_n_arcs, n_arcs);
491 #else /* DBUS_HAVE_GCC33_GCOV */
494 * The da file is more complex than 3.2.
496 * We have a magic value of "-123" only it isn't really
497 * -123, it's -123 as encoded by the crackass gcov-io.h
498 * routines. Anyway, 4 bytes.
502 * - 4 byte count of how many functions in the following list
503 * - 4 byte length of random extra data
504 * - the random extra data, just skip it, info pages have some
505 * details on what might be in there or see __bb_exit_func in gcc
506 * - then for each function (number of functions given above):
507 * . -1, length, funcname, alignment padding, -1
509 * . 4 byte number of arcs in function
510 * . 8 bytes each, a count of execution for each arc
512 * Now, the whole thing *starting with the magic* can repeat.
513 * This is caused by multiple runs of the profiled app appending
517 dump_da_file (const DBusString *contents)
529 while (i < _dbus_string_get_length (contents))
531 int claimed_n_functions;
535 printf (".da file section %d\n", n_sections);
537 if (!string_get_int (contents, i, &val))
538 die ("no magic found in .da file\n");
543 die ("wrong file magic in .da file\n");
545 if (!string_get_int (contents, i, &val))
546 die ("no function count in .da file\n");
548 claimed_n_functions = val;
550 printf ("%d functions expected in section %d of .da file\n",
551 claimed_n_functions, n_sections);
553 if (!string_get_int (contents, i, &val))
554 die ("no extra data length in .da file\n");
562 while (n_functions < claimed_n_functions)
569 if (!_dbus_string_init (&funcname))
572 if (!string_get_function (contents, i,
573 &funcname, &checksum, &i))
574 die ("could not read function name\n");
576 if (!string_get_int (contents, i, &val))
577 die ("no arc count for function\n");
580 claimed_n_arcs = val;
582 printf (" %d arcs in function %d %s checksum %d\n",
583 claimed_n_arcs, n_functions,
584 _dbus_string_get_const_data (&funcname),
588 while (n_arcs < claimed_n_arcs)
590 if (!string_get_int64 (contents, i, &v64))
591 die ("did not get execution count for arc\n");
595 printf (" %ld executions of arc %d (total arcs %d)\n",
596 (long) v64, n_arcs, total_arcs + n_arcs);
601 _dbus_string_free (&funcname);
603 total_arcs += n_arcs;
607 printf ("total of %d functions and %d arcs in section %d\n",
608 n_functions, total_arcs, n_sections);
610 total_functions += n_functions;
614 printf ("%d total function sections in %d total .da file sections\n",
615 total_functions, n_sections);
618 #endif /* DBUS_HAVE_GCC33_GCOV */
620 typedef struct Arc Arc;
621 typedef struct Block Block;
622 typedef struct Function Function;
623 typedef struct File File;
624 typedef struct Line Line;
630 dbus_int64_t arc_count;
631 unsigned int count_valid : 1;
632 unsigned int on_tree : 1;
633 unsigned int fake : 1;
634 unsigned int fall_through : 1;
643 dbus_int64_t succ_count;
644 dbus_int64_t pred_count;
645 dbus_int64_t exec_count;
647 unsigned int count_valid : 1;
648 unsigned int on_tree : 1;
649 unsigned int inside_dbus_build_tests : 1;
658 /* number of blocks in DBUS_BUILD_TESTS */
660 int n_test_blocks_executed;
661 /* number of blocks outside DBUS_BUILD_TESTS */
662 int n_nontest_blocks;
663 int n_nontest_blocks_executed;
664 /* Summary result flags */
665 unsigned int unused : 1;
666 unsigned int inside_dbus_build_tests : 1;
667 unsigned int partial : 1; /* only some of the blocks were executed */
675 unsigned int inside_dbus_build_tests : 1;
676 unsigned int partial : 1; /* only some of the blocks were executed */
688 function_add_arc (Function *function,
695 arc = dbus_new0 (Arc, 1);
699 arc->target = target;
700 arc->source = source;
702 arc->succ_next = function->block_graph[source].succ;
703 function->block_graph[source].succ = arc;
704 function->block_graph[source].succ_count += 1;
706 arc->pred_next = function->block_graph[target].pred;
707 function->block_graph[target].pred = arc;
708 function->block_graph[target].pred_count += 1;
710 if ((flags & FLAG_ON_TREE) != 0)
713 if ((flags & FLAG_FAKE) != 0)
716 if ((flags & FLAG_FALL_THROUGH) != 0)
717 arc->fall_through = TRUE;
722 reverse_arcs (Arc *arc)
724 struct Arc *prev = 0;
727 for ( ; arc; arc = next)
729 next = arc->succ_next;
730 arc->succ_next = prev;
738 function_reverse_succ_arcs (Function *func)
740 /* Must reverse the order of all succ arcs, to ensure that they match
741 * the order of the data in the .da file.
745 for (i = 0; i < func->n_blocks; i++)
746 if (func->block_graph[i].succ)
747 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
751 get_functions_from_bbg (const DBusString *contents,
752 DBusList **functions)
762 printf ("Loading arcs and blocks from .bbg file\n");
770 while (i < _dbus_string_get_length (contents))
773 long n_blocks_in_func;
777 #ifdef DBUS_HAVE_GCC33_GCOV
781 /* In gcc33 .bbg files, there's a function name of the form:
782 * -1, length, name (padded to 4), -1, checksum
783 * after that header on each function description, it's
784 * the same as in gcc32
786 if (!_dbus_string_init (&funcname))
789 if (!string_get_function (contents, i,
790 &funcname, &checksum, &i))
791 die ("could not read function name\n");
792 #endif /* DBUS_HAVE_GCC33_GCOV */
794 if (!string_get_int (contents, i, &val))
797 n_blocks_in_func = val;
801 if (!string_get_int (contents, i, &n_arcs_in_func))
807 n_blocks += n_blocks_in_func;
808 n_arcs += n_arcs_in_func;
810 func = dbus_new0 (Function, 1);
814 #ifdef DBUS_HAVE_GCC33_GCOV
815 func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
816 func->checksum = checksum;
817 _dbus_string_free (&funcname);
820 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
821 func->n_blocks = n_blocks_in_func;
824 while (j < n_blocks_in_func)
826 long n_arcs_in_block;
829 if (!string_get_int (contents, i, &n_arcs_in_block))
835 while (k < n_arcs_in_block)
837 long destination_block;
840 if (!string_get_int (contents, i, &destination_block))
845 if (!string_get_int (contents, i, &flags))
850 if ((flags & FLAG_ON_TREE) == 0)
851 n_arcs_off_tree += 1;
853 function_add_arc (func, j, destination_block,
859 if (k < n_arcs_in_block)
865 if (j < n_blocks_in_func)
868 function_reverse_succ_arcs (func);
870 if (!_dbus_list_append (functions, func))
873 if (!string_get_int (contents, i, &val))
879 die ("-1 separator not found in .bbg file\n");
883 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
884 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
887 _dbus_assert (n_functions == _dbus_list_get_length (functions));
890 #ifdef DBUS_HAVE_GCC33_GCOV
892 add_counts_from_da (const DBusString *contents,
893 DBusList **functions)
900 Function *current_func;
907 while (i < _dbus_string_get_length (contents))
909 int claimed_n_functions;
912 if (!string_get_int (contents, i, &val))
913 die ("no magic found in .da file\n");
918 die ("wrong file magic in .da file\n");
920 if (!string_get_int (contents, i, &val))
921 die ("no function count in .da file\n");
923 claimed_n_functions = val;
925 if (!string_get_int (contents, i, &val))
926 die ("no extra data length in .da file\n");
932 link = _dbus_list_get_first_link (functions);
934 goto no_more_functions;
937 while (n_functions < claimed_n_functions && link != NULL)
944 current_func = link->data;
946 current_arc = current_func->block_graph[current_block].succ;
948 if (!_dbus_string_init (&funcname))
951 if (!string_get_function (contents, i,
952 &funcname, &checksum, &i))
953 die ("could not read function name\n");
955 if (!_dbus_string_equal_c_str (&funcname, current_func->name))
957 fprintf (stderr, "Expecting .da info for %s but got %s\n",
959 _dbus_string_get_const_data (&funcname));
963 if (checksum != current_func->checksum)
964 die (".da file checksum doesn't match checksum from .bbg file\n");
966 if (!string_get_int (contents, i, &val))
967 die ("no arc count for function\n");
970 claimed_n_arcs = val;
972 /* For each arc in the profile, find the corresponding
973 * arc in the function and increment its count
976 while (n_arcs < claimed_n_arcs)
978 if (!string_get_int64 (contents, i, &v64))
979 die ("did not get execution count for arc\n");
983 /* Find the next arc in the function that isn't on tree */
984 while (current_arc == NULL ||
985 current_arc->on_tree)
987 if (current_arc == NULL)
991 if (current_block >= current_func->n_blocks)
992 die ("too many blocks in function\n");
994 current_arc = current_func->block_graph[current_block].succ;
998 current_arc = current_arc->succ_next;
1002 _dbus_assert (current_arc != NULL);
1003 _dbus_assert (!current_arc->on_tree);
1005 current_arc->arc_count = v64;
1006 current_arc->count_valid = TRUE;
1007 current_func->block_graph[current_block].succ_count -= 1;
1008 current_func->block_graph[current_arc->target].pred_count -= 1;
1012 current_arc = current_arc->succ_next;
1015 _dbus_string_free (&funcname);
1017 link = _dbus_list_get_next_link (functions, link);
1020 if (link == NULL && n_functions < claimed_n_functions)
1022 fprintf (stderr, "Ran out of functions loading .da file\n");
1023 goto no_more_functions;
1032 #else /* DBUS_HAVE_GCC33_GCOV */
1034 add_counts_from_da (const DBusString *contents,
1035 DBusList **functions)
1042 Function *current_func;
1047 printf ("Loading execution count for each arc from .da file\n");
1051 if (!string_get_int64 (contents, i, &val))
1056 claimed_n_arcs = val;
1058 link = _dbus_list_get_first_link (functions);
1062 current_func = link->data;
1064 current_arc = current_func->block_graph[current_block].succ;
1067 while (string_get_int64 (contents, i, &val))
1071 while (current_arc == NULL ||
1072 current_arc->on_tree)
1074 if (current_arc == NULL)
1078 if (current_block == current_func->n_blocks)
1080 link = _dbus_list_get_next_link (functions, link);
1083 fprintf (stderr, "Ran out of functions loading .da file\n");
1086 current_func = link->data;
1090 current_arc = current_func->block_graph[current_block].succ;
1094 current_arc = current_arc->succ_next;
1098 _dbus_assert (current_arc != NULL);
1099 _dbus_assert (!current_arc->on_tree);
1101 current_arc->arc_count = val;
1102 current_arc->count_valid = TRUE;
1103 current_func->block_graph[current_block].succ_count -= 1;
1104 current_func->block_graph[current_arc->target].pred_count -= 1;
1108 current_arc = current_arc->succ_next;
1113 if (n_arcs != claimed_n_arcs)
1115 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
1116 claimed_n_arcs, n_arcs);
1121 printf ("%d arcs in file\n", n_arcs);
1127 function_solve_graph (Function *func)
1129 int passes, changes;
1137 printf ("Solving function graph\n");
1140 n_blocks = func->n_blocks;
1141 block_graph = func->block_graph;
1143 /* For every block in the file,
1144 - if every exit/entrance arc has a known count, then set the block count
1145 - if the block count is known, and every exit/entrance arc but one has
1146 a known execution count, then set the count of the remaining arc
1148 As arc counts are set, decrement the succ/pred count, but don't delete
1149 the arc, that way we can easily tell when all arcs are known, or only
1150 one arc is unknown. */
1152 /* The order that the basic blocks are iterated through is important.
1153 Since the code that finds spanning trees starts with block 0, low numbered
1154 arcs are put on the spanning tree in preference to high numbered arcs.
1155 Hence, most instrumented arcs are at the end. Graph solving works much
1156 faster if we propagate numbers from the end to the start.
1158 This takes an average of slightly more than 3 passes. */
1167 for (i = n_blocks - 1; i >= 0; i--)
1169 if (! block_graph[i].count_valid)
1171 if (block_graph[i].succ_count == 0)
1174 for (arc = block_graph[i].succ; arc;
1175 arc = arc->succ_next)
1176 total += arc->arc_count;
1177 block_graph[i].exec_count = total;
1178 block_graph[i].count_valid = 1;
1181 else if (block_graph[i].pred_count == 0)
1184 for (arc = block_graph[i].pred; arc;
1185 arc = arc->pred_next)
1186 total += arc->arc_count;
1187 block_graph[i].exec_count = total;
1188 block_graph[i].count_valid = 1;
1192 if (block_graph[i].count_valid)
1194 if (block_graph[i].succ_count == 1)
1197 /* One of the counts will be invalid, but it is zero,
1198 so adding it in also doesn't hurt. */
1199 for (arc = block_graph[i].succ; arc;
1200 arc = arc->succ_next)
1201 total += arc->arc_count;
1202 /* Calculate count for remaining arc by conservation. */
1203 total = block_graph[i].exec_count - total;
1204 /* Search for the invalid arc, and set its count. */
1205 for (arc = block_graph[i].succ; arc;
1206 arc = arc->succ_next)
1207 if (! arc->count_valid)
1210 die ("arc == NULL\n");
1211 arc->count_valid = 1;
1212 arc->arc_count = total;
1213 block_graph[i].succ_count -= 1;
1215 block_graph[arc->target].pred_count -= 1;
1218 if (block_graph[i].pred_count == 1)
1221 /* One of the counts will be invalid, but it is zero,
1222 so adding it in also doesn't hurt. */
1223 for (arc = block_graph[i].pred; arc;
1224 arc = arc->pred_next)
1225 total += arc->arc_count;
1226 /* Calculate count for remaining arc by conservation. */
1227 total = block_graph[i].exec_count - total;
1228 /* Search for the invalid arc, and set its count. */
1229 for (arc = block_graph[i].pred; arc;
1230 arc = arc->pred_next)
1231 if (! arc->count_valid)
1234 die ("arc == NULL\n");
1235 arc->count_valid = 1;
1236 arc->arc_count = total;
1237 block_graph[i].pred_count -= 1;
1239 block_graph[arc->source].succ_count -= 1;
1246 /* If the graph has been correctly solved, every block will have a
1247 * succ and pred count of zero.
1250 dbus_bool_t header = FALSE;
1251 for (i = 0; i < n_blocks; i++)
1253 if (block_graph[i].succ_count || block_graph[i].pred_count)
1257 fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
1259 fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
1262 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
1263 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
1270 solve_graphs (DBusList **functions)
1274 link = _dbus_list_get_first_link (functions);
1275 while (link != NULL)
1277 Function *func = link->data;
1279 function_solve_graph (func);
1281 link = _dbus_list_get_next_link (functions, link);
1286 load_functions_for_c_file (const DBusString *filename,
1287 DBusList **functions)
1289 DBusString bbg_filename;
1290 DBusString da_filename;
1291 DBusString gcno_filename;
1292 DBusString gcda_filename;
1293 DBusString contents;
1297 /* With latest gcc it's .gcno instead of .bbg and
1298 * gcda instead of .da
1301 dbus_error_init (&error);
1303 if (!_dbus_string_init (&bbg_filename) ||
1304 !_dbus_string_init (&da_filename) ||
1305 !_dbus_string_init (&gcno_filename) ||
1306 !_dbus_string_init (&gcda_filename) ||
1307 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
1308 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
1309 !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
1310 !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
1311 !_dbus_string_init (&contents))
1312 die ("no memory\n");
1314 _dbus_string_shorten (&bbg_filename, 2);
1315 _dbus_string_shorten (&da_filename, 2);
1317 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
1318 !_dbus_string_append (&da_filename, ".da") ||
1319 !_dbus_string_append (&bbg_filename, ".gcno") ||
1320 !_dbus_string_append (&bbg_filename, ".gcda"))
1321 die ("no memory\n");
1323 if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
1324 name = &gcno_filename;
1326 name = &bbg_filename;
1328 if (!_dbus_file_get_contents (&contents, name,
1331 fprintf (stderr, "Could not open file: %s\n",
1336 get_functions_from_bbg (&contents, functions);
1338 _dbus_string_set_length (&contents, 0);
1340 if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
1341 name = &gcda_filename;
1343 name = &da_filename;
1345 if (!_dbus_file_get_contents (&contents, name,
1348 /* Try .libs/file.da */
1351 if (_dbus_string_find_byte_backward (name,
1352 _dbus_string_get_length (name),
1357 _dbus_string_init_const (&libs, "/.libs");
1359 if (!_dbus_string_copy (&libs, 0, name, slash))
1362 dbus_error_free (&error);
1363 if (!_dbus_file_get_contents (&contents, name,
1366 fprintf (stderr, "Could not open file: %s\n",
1373 fprintf (stderr, "Could not open file: %s\n",
1379 add_counts_from_da (&contents, functions);
1381 solve_graphs (functions);
1383 _dbus_string_free (&contents);
1384 _dbus_string_free (&da_filename);
1385 _dbus_string_free (&bbg_filename);
1389 get_lines_from_bb_file (const DBusString *contents,
1395 dbus_bool_t in_our_file;
1401 printf ("Getting line numbers for blocks from .bb file\n");
1404 /* There's this "filename" field in the .bb file which
1405 * mysteriously comes *after* the first function in the
1406 * file in the .bb file; and every .bb file seems to
1407 * have only one filename. I don't understand
1408 * what's going on here, so just set in_our_file = TRUE
1409 * at the start categorically.
1415 link = _dbus_list_get_first_link (&fl->functions);
1418 while (string_get_int (contents, i, &val))
1428 if (!_dbus_string_init (&f))
1429 die ("no memory\n");
1431 if (string_get_string (contents, i,
1435 /* fl->name is a full path and the filename in .bb is
1440 _dbus_string_init_const (&tmp_str, fl->name);
1442 if (_dbus_string_ends_with_c_str (&tmp_str,
1443 _dbus_string_get_const_data (&f)))
1446 in_our_file = FALSE;
1450 "File %s in .bb, looking for %s, in_our_file = %d\n",
1451 _dbus_string_get_const_data (&f),
1456 _dbus_string_free (&f);
1462 if (!_dbus_string_init (&f))
1463 die ("no memory\n");
1465 if (string_get_string (contents, i,
1470 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
1479 fprintf (stderr, "No function object for function %s\n",
1480 _dbus_string_get_const_data (&f));
1485 link = _dbus_list_get_next_link (&fl->functions, link);
1487 if (func->name == NULL)
1489 if (!_dbus_string_copy_data (&f, &func->name))
1490 die ("no memory\n");
1494 if (!_dbus_string_equal_c_str (&f, func->name))
1496 fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
1497 func->name, strlen (func->name),
1498 _dbus_string_get_const_data (&f),
1499 _dbus_string_get_length (&f));
1506 _dbus_string_free (&f);
1516 fprintf (stderr, "Line %ld\n", val);
1519 if (val >= fl->n_lines)
1521 fprintf (stderr, "Line %ld but file only has %d lines\n",
1524 else if (func != NULL)
1526 val -= 1; /* To convert the 1-based line number to 0-based */
1527 _dbus_assert (val >= 0);
1529 if (block < func->n_blocks)
1531 if (!_dbus_list_append (&func->block_graph[block].lines,
1533 die ("no memory\n");
1536 if (!_dbus_list_append (&fl->lines[val].blocks,
1537 &func->block_graph[block]))
1538 die ("no memory\n");
1542 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1543 block, func->n_blocks);
1548 fprintf (stderr, "Line %ld given outside of any function\n",
1557 printf ("%d functions in file\n", n_functions);
1563 load_block_line_associations (const DBusString *filename,
1566 DBusString bb_filename;
1567 DBusString contents;
1570 dbus_error_init (&error);
1572 if (!_dbus_string_init (&bb_filename) ||
1573 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1574 !_dbus_string_init (&contents))
1575 die ("no memory\n");
1577 _dbus_string_shorten (&bb_filename, 2);
1579 if (!_dbus_string_append (&bb_filename, ".bb"))
1580 die ("no memory\n");
1582 if (!_dbus_file_get_contents (&contents, &bb_filename,
1585 fprintf (stderr, "Could not open file: %s\n",
1590 get_lines_from_bb_file (&contents, f);
1592 _dbus_string_free (&contents);
1593 _dbus_string_free (&bb_filename);
1597 count_lines_in_string (const DBusString *str)
1603 const char *last_line_end;
1606 printf ("Counting lines in source file\n");
1611 p = _dbus_string_get_const_data (str);
1612 end = p + _dbus_string_get_length (str);
1616 /* too lazy to handle \r\n as one linebreak */
1617 if (*p == '\n' || *p == '\r')
1620 last_line_end = p + 1;
1627 if (last_line_end != p)
1634 fill_line_content (const DBusString *str,
1641 const char *last_line_end;
1644 printf ("Saving contents of each line in source file\n");
1649 p = _dbus_string_get_const_data (str);
1650 end = p + _dbus_string_get_length (str);
1654 if (*p == '\n' || *p == '\r')
1656 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1657 if (lines[n_lines].text == NULL)
1658 die ("no memory\n");
1660 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1661 lines[n_lines].number = n_lines + 1;
1665 last_line_end = p + 1;
1672 if (p != last_line_end)
1674 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1680 mark_inside_dbus_build_tests (File *f)
1688 while (i < f->n_lines)
1690 Line *l = &f->lines[i];
1691 dbus_bool_t is_verbose;
1693 is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
1695 if (inside_depth == 0)
1699 a = strstr (l->text, "#if");
1700 b = strstr (l->text, "DBUS_BUILD_TESTS");
1701 if (a && b && (a < b))
1706 if (strstr (l->text, "#if") != NULL)
1708 else if (strstr (l->text, "#endif") != NULL)
1712 if (inside_depth > 0 || is_verbose)
1714 /* Mark the line and its blocks */
1717 l->inside_dbus_build_tests = TRUE;
1719 blink = _dbus_list_get_first_link (&l->blocks);
1720 while (blink != NULL)
1722 Block *b = blink->data;
1724 b->inside_dbus_build_tests = TRUE;
1726 blink = _dbus_list_get_next_link (&l->blocks, blink);
1733 /* Now mark functions where for all blocks that are associated
1734 * with a source line, the block is inside_dbus_build_tests.
1736 link = _dbus_list_get_first_link (&f->functions);
1737 while (link != NULL)
1739 Function *func = link->data;
1741 /* The issue is that some blocks aren't associated with a source line.
1742 * Assume they are inside/outside tests according to the source
1743 * line of the preceding block. For the first block, make it
1744 * match the first following block with a line associated.
1746 if (func->block_graph[0].lines == NULL)
1748 /* find first following line */
1750 while (i < func->n_blocks)
1752 if (func->block_graph[i].lines != NULL)
1754 func->block_graph[0].inside_dbus_build_tests =
1755 func->block_graph[i].inside_dbus_build_tests;
1763 /* Now mark all blocks but the first */
1765 while (i < func->n_blocks)
1767 if (func->block_graph[i].lines == NULL)
1769 func->block_graph[i].inside_dbus_build_tests =
1770 func->block_graph[i-1].inside_dbus_build_tests;
1777 while (i < func->n_blocks)
1779 /* Break as soon as any block is not a test block */
1780 if (func->block_graph[i].lines != NULL &&
1781 !func->block_graph[i].inside_dbus_build_tests)
1787 if (i == func->n_blocks)
1788 func->inside_dbus_build_tests = TRUE;
1790 link = _dbus_list_get_next_link (&f->functions, link);
1795 mark_coverage (File *f)
1801 while (i < f->n_lines)
1803 Line *l = &f->lines[i];
1806 int n_blocks_executed;
1809 n_blocks_executed = 0;
1810 blink = _dbus_list_get_first_link (&l->blocks);
1811 while (blink != NULL)
1813 Block *b = blink->data;
1815 if (b->exec_count > 0)
1816 n_blocks_executed += 1;
1820 blink = _dbus_list_get_next_link (&l->blocks, blink);
1823 if (n_blocks_executed > 0 &&
1824 n_blocks_executed < n_blocks)
1830 link = _dbus_list_get_first_link (&f->functions);
1831 while (link != NULL)
1833 Function *func = link->data;
1836 int n_test_blocks_executed;
1837 int n_nontest_blocks;
1838 int n_nontest_blocks_executed;
1841 n_test_blocks_executed = 0;
1842 n_nontest_blocks = 0;
1843 n_nontest_blocks_executed = 0;
1846 while (i < func->n_blocks)
1848 if (!func->block_graph[i].inside_dbus_build_tests)
1850 n_nontest_blocks += 1;
1852 if (func->block_graph[i].exec_count > 0)
1853 n_nontest_blocks_executed += 1;
1859 if (func->block_graph[i].exec_count > 0)
1860 n_test_blocks_executed += 1;
1866 if (n_nontest_blocks_executed > 0 &&
1867 n_nontest_blocks_executed < n_nontest_blocks)
1868 func->partial = TRUE;
1870 if (n_nontest_blocks_executed == 0 &&
1871 n_nontest_blocks > 0)
1872 func->unused = TRUE;
1874 func->n_test_blocks = n_test_blocks;
1875 func->n_test_blocks_executed = n_test_blocks_executed;
1876 func->n_nontest_blocks = n_nontest_blocks;
1877 func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1879 link = _dbus_list_get_next_link (&f->functions, link);
1884 load_c_file (const DBusString *filename)
1886 DBusString contents;
1890 f = dbus_new0 (File, 1);
1892 die ("no memory\n");
1894 if (!_dbus_string_copy_data (filename, &f->name))
1895 die ("no memory\n");
1897 if (!_dbus_string_init (&contents))
1898 die ("no memory\n");
1900 dbus_error_init (&error);
1902 if (!_dbus_file_get_contents (&contents, filename,
1905 fprintf (stderr, "Could not open file: %s\n",
1907 dbus_error_free (&error);
1911 load_functions_for_c_file (filename, &f->functions);
1913 f->n_lines = count_lines_in_string (&contents);
1914 f->lines = dbus_new0 (Line, f->n_lines);
1915 if (f->lines == NULL)
1916 die ("no memory\n");
1918 fill_line_content (&contents, f->lines);
1920 _dbus_string_free (&contents);
1922 load_block_line_associations (filename, f);
1924 mark_inside_dbus_build_tests (f);
1930 typedef struct Stats Stats;
1935 int n_blocks_executed;
1936 int n_blocks_inside_dbus_build_tests;
1938 int n_lines; /* lines that have blocks on them */
1939 int n_lines_executed;
1940 int n_lines_partial;
1941 int n_lines_inside_dbus_build_tests;
1944 int n_functions_executed;
1945 int n_functions_partial;
1946 int n_functions_inside_dbus_build_tests;
1950 line_was_executed (Line *l)
1954 link = _dbus_list_get_first_link (&l->blocks);
1955 while (link != NULL)
1957 Block *b = link->data;
1959 if (b->exec_count > 0)
1962 link = _dbus_list_get_next_link (&l->blocks, link);
1970 line_exec_count (Line *l)
1976 link = _dbus_list_get_first_link (&l->blocks);
1977 while (link != NULL)
1979 Block *b = link->data;
1981 total += b->exec_count;
1983 link = _dbus_list_get_next_link (&l->blocks, link);
1990 merge_stats_for_file (Stats *stats,
1996 for (i = 0; i < f->n_lines; ++i)
1998 Line *l = &f->lines[i];
2000 if (l->inside_dbus_build_tests)
2002 stats->n_lines_inside_dbus_build_tests += 1;
2006 if (line_was_executed (l))
2007 stats->n_lines_executed += 1;
2009 if (l->blocks != NULL)
2010 stats->n_lines += 1;
2013 stats->n_lines_partial += 1;
2016 link = _dbus_list_get_first_link (&f->functions);
2017 while (link != NULL)
2019 Function *func = link->data;
2021 if (func->inside_dbus_build_tests)
2022 stats->n_functions_inside_dbus_build_tests += 1;
2025 stats->n_functions += 1;
2028 stats->n_functions_executed += 1;
2031 stats->n_functions_partial += 1;
2034 stats->n_blocks_inside_dbus_build_tests +=
2035 func->n_test_blocks;
2037 stats->n_blocks_executed +=
2038 func->n_nontest_blocks_executed;
2041 func->n_nontest_blocks;
2043 link = _dbus_list_get_next_link (&f->functions, link);
2047 /* The output of this matches gcov exactly ("diff" shows no difference) */
2049 print_annotated_source_gcov_format (File *f)
2054 while (i < f->n_lines)
2056 Line *l = &f->lines[i];
2058 if (l->blocks != NULL)
2062 exec_count = line_exec_count (l);
2065 printf ("%12d %s\n",
2066 exec_count, l->text);
2068 printf (" ###### %s\n", l->text);
2072 printf ("\t\t%s\n", l->text);
2080 print_annotated_source (File *f)
2085 while (i < f->n_lines)
2087 Line *l = &f->lines[i];
2089 if (l->inside_dbus_build_tests)
2094 if (l->blocks != NULL)
2098 exec_count = line_exec_count (l);
2101 printf ("%12d %s\n",
2102 exec_count, l->text);
2104 printf (" ###### %s\n", l->text);
2108 printf ("\t\t%s\n", l->text);
2116 print_block_superdetails (File *f)
2121 link = _dbus_list_get_first_link (&f->functions);
2122 while (link != NULL)
2124 Function *func = link->data;
2126 printf ("=== %s():\n", func->name);
2129 while (i < func->n_blocks)
2131 Block *b = &func->block_graph[i];
2134 printf (" %5d executed %d times%s\n", i,
2135 (int) b->exec_count,
2136 b->inside_dbus_build_tests ?
2137 " [inside DBUS_BUILD_TESTS]" : "");
2139 l = _dbus_list_get_first_link (&b->lines);
2142 Line *line = l->data;
2144 printf ("4%d\t%s\n", line->number, line->text);
2146 l = _dbus_list_get_next_link (&b->lines, l);
2152 link = _dbus_list_get_next_link (&f->functions, link);
2157 print_one_file (const DBusString *filename)
2159 if (_dbus_string_ends_with_c_str (filename, ".bb"))
2161 DBusString contents;
2164 if (!_dbus_string_init (&contents))
2165 die ("no memory\n");
2167 dbus_error_init (&error);
2169 if (!_dbus_file_get_contents (&contents, filename,
2172 fprintf (stderr, "Could not open file: %s\n",
2174 dbus_error_free (&error);
2178 dump_bb_file (&contents);
2180 _dbus_string_free (&contents);
2182 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
2184 DBusString contents;
2187 if (!_dbus_string_init (&contents))
2188 die ("no memory\n");
2190 dbus_error_init (&error);
2192 if (!_dbus_file_get_contents (&contents, filename,
2195 fprintf (stderr, "Could not open file: %s\n",
2197 dbus_error_free (&error);
2201 dump_bbg_file (&contents);
2203 _dbus_string_free (&contents);
2205 else if (_dbus_string_ends_with_c_str (filename, ".da"))
2207 DBusString contents;
2210 if (!_dbus_string_init (&contents))
2211 die ("no memory\n");
2213 dbus_error_init (&error);
2215 if (!_dbus_file_get_contents (&contents, filename,
2218 fprintf (stderr, "Could not open file: %s\n",
2220 dbus_error_free (&error);
2224 dump_da_file (&contents);
2226 _dbus_string_free (&contents);
2228 else if (_dbus_string_ends_with_c_str (filename, ".c"))
2232 f = load_c_file (filename);
2234 print_annotated_source (f);
2238 fprintf (stderr, "Unknown file type %s\n",
2239 _dbus_string_get_const_data (filename));
2245 print_untested_functions (File *f)
2251 link = _dbus_list_get_first_link (&f->functions);
2252 while (link != NULL)
2254 Function *func = link->data;
2257 !func->inside_dbus_build_tests)
2260 link = _dbus_list_get_next_link (&f->functions, link);
2266 printf ("Untested functions in %s\n", f->name);
2267 printf ("=======\n");
2269 link = _dbus_list_get_first_link (&f->functions);
2270 while (link != NULL)
2272 Function *func = link->data;
2275 !func->inside_dbus_build_tests)
2276 printf (" %s\n", func->name);
2278 link = _dbus_list_get_next_link (&f->functions, link);
2285 print_poorly_tested_functions (File *f,
2291 #define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
2293 #define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
2295 #define POORLY_TESTED(function) (!(function)->unused && \
2296 (function)->n_nontest_blocks > 0 && \
2297 TEST_FRACTION (function) < AVERAGE_COVERAGE)
2300 link = _dbus_list_get_first_link (&f->functions);
2301 while (link != NULL)
2303 Function *func = link->data;
2305 if (POORLY_TESTED (func))
2308 link = _dbus_list_get_next_link (&f->functions, link);
2314 printf ("Below average functions in %s\n", f->name);
2315 printf ("=======\n");
2317 link = _dbus_list_get_first_link (&f->functions);
2318 while (link != NULL)
2320 Function *func = link->data;
2322 if (POORLY_TESTED (func))
2323 printf (" %s (%d%%)\n", func->name,
2324 (int) (TEST_FRACTION (func) * 100));
2326 link = _dbus_list_get_next_link (&f->functions, link);
2333 func_cmp (const void *a,
2336 Function *af = *(Function**) a;
2337 Function *bf = *(Function**) b;
2338 int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
2339 int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
2341 /* Sort by number of untested blocks */
2342 return b_untested - a_untested;
2346 print_n_untested_blocks_by_function (File *f,
2355 link = _dbus_list_get_first_link (&f->functions);
2356 while (link != NULL)
2358 Function *func = link->data;
2360 if (func->n_nontest_blocks_executed <
2361 func->n_nontest_blocks)
2364 link = _dbus_list_get_next_link (&f->functions, link);
2370 /* make an array so we can use qsort */
2372 funcs = dbus_new (Function*, n_found);
2377 link = _dbus_list_get_first_link (&f->functions);
2378 while (link != NULL)
2380 Function *func = link->data;
2382 if (func->n_nontest_blocks_executed <
2383 func->n_nontest_blocks)
2389 link = _dbus_list_get_next_link (&f->functions, link);
2392 _dbus_assert (i == n_found);
2394 qsort (funcs, n_found, sizeof (Function*),
2397 printf ("Incomplete functions in %s\n", f->name);
2398 printf ("=======\n");
2403 Function *func = funcs[i];
2405 printf (" %s (%d/%d untested blocks)\n",
2407 func->n_nontest_blocks - func->n_nontest_blocks_executed,
2408 func->n_nontest_blocks);
2419 print_stats (Stats *stats,
2420 const char *of_what)
2424 printf ("Summary (%s)\n", of_what);
2425 printf ("=======\n");
2426 printf (" %g%% blocks executed (%d of %d)\n",
2427 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
2428 stats->n_blocks_executed,
2431 printf (" (ignored %d blocks of test-only/debug-only code)\n",
2432 stats->n_blocks_inside_dbus_build_tests);
2434 printf (" %g%% functions executed (%d of %d)\n",
2435 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
2436 stats->n_functions_executed,
2437 stats->n_functions);
2439 completely = stats->n_functions_executed - stats->n_functions_partial;
2440 printf (" %g%% functions completely executed (%d of %d)\n",
2441 (completely / (double) stats->n_functions) * 100.0,
2443 stats->n_functions);
2445 printf (" (ignored %d functions of test-only/debug-only code)\n",
2446 stats->n_functions_inside_dbus_build_tests);
2448 printf (" %g%% lines executed (%d of %d)\n",
2449 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
2450 stats->n_lines_executed,
2453 completely = stats->n_lines_executed - stats->n_lines_partial;
2454 printf (" %g%% lines completely executed (%d of %d)\n",
2455 (completely / (double) stats->n_lines) * 100.0,
2459 printf (" (ignored %d lines of test-only/debug-only code)\n",
2460 stats->n_lines_inside_dbus_build_tests);
2474 main (int argc, char **argv)
2476 DBusString filename;
2482 fprintf (stderr, "Must specify files on command line\n");
2489 if (strcmp (argv[i], "--report") == 0)
2494 else if (strcmp (argv[i], "--blocks") == 0)
2499 else if (strcmp (argv[i], "--gcov") == 0)
2508 fprintf (stderr, "Must specify files on command line\n");
2512 if (m == MODE_PRINT)
2516 _dbus_string_init_const (&filename, argv[i]);
2518 print_one_file (&filename);
2523 else if (m == MODE_BLOCKS || m == MODE_GCOV)
2529 _dbus_string_init_const (&filename, argv[i]);
2531 f = load_c_file (&filename);
2533 if (m == MODE_BLOCKS)
2534 print_block_superdetails (f);
2535 else if (m == MODE_GCOV)
2536 print_annotated_source_gcov_format (f);
2541 else if (m == MODE_REPORT)
2543 Stats stats = { 0, };
2546 DBusHashTable *stats_by_dir;
2552 _dbus_string_init_const (&filename, argv[i]);
2554 if (_dbus_string_ends_with_c_str (&filename, ".c"))
2558 f = load_c_file (&filename);
2560 if (!_dbus_list_append (&files, f))
2561 die ("no memory\n");
2565 fprintf (stderr, "Unknown file type %s\n",
2566 _dbus_string_get_const_data (&filename));
2573 link = _dbus_list_get_first_link (&files);
2574 while (link != NULL)
2576 File *f = link->data;
2578 merge_stats_for_file (&stats, f);
2580 link = _dbus_list_get_next_link (&files, link);
2583 print_stats (&stats, "all files");
2585 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
2586 dbus_free, dbus_free);
2588 link = _dbus_list_get_first_link (&files);
2589 while (link != NULL)
2591 File *f = link->data;
2596 _dbus_string_init_const (&filename, f->name);
2598 if (!_dbus_string_init (&dirname))
2599 die ("no memory\n");
2601 if (!_dbus_string_get_dirname (&filename, &dirname) ||
2602 !_dbus_string_copy_data (&dirname, &dirname_c))
2603 die ("no memory\n");
2605 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
2608 if (dir_stats == NULL)
2610 dir_stats = dbus_new0 (Stats, 1);
2611 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
2613 die ("no memory\n");
2616 dbus_free (dirname_c);
2618 merge_stats_for_file (dir_stats, f);
2620 link = _dbus_list_get_next_link (&files, link);
2623 _dbus_hash_iter_init (stats_by_dir, &iter);
2624 while (_dbus_hash_iter_next (&iter))
2626 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
2627 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
2629 print_stats (dir_stats, dirname);
2632 _dbus_hash_table_unref (stats_by_dir);
2634 link = _dbus_list_get_first_link (&files);
2635 while (link != NULL)
2637 File *f = link->data;
2639 print_untested_functions (f);
2641 link = _dbus_list_get_next_link (&files, link);
2644 link = _dbus_list_get_first_link (&files);
2645 while (link != NULL)
2647 File *f = link->data;
2649 print_poorly_tested_functions (f, &stats);
2651 link = _dbus_list_get_next_link (&files, link);
2654 link = _dbus_list_get_first_link (&files);
2655 while (link != NULL)
2657 File *f = link->data;
2659 print_n_untested_blocks_by_function (f, &stats);
2661 link = _dbus_list_get_next_link (&files, link);