1 /* -*- mode: C; c-file-style: "gnu" -*- */
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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))
157 _dbus_string_append_byte (val, n & 0xff);
158 _dbus_string_append_byte (val, (n >> 8) & 0xff);
159 _dbus_string_append_byte (val, (n >> 16) & 0xff);
160 _dbus_string_append_byte (val, (n >> 24) & 0xff);
169 dump_bb_file (const DBusString *contents)
177 while (string_get_int (contents, i, &val))
187 if (!_dbus_string_init (&f))
190 if (string_get_string (contents, i,
194 printf ("File %s\n", _dbus_string_get_const_data (&f));
196 _dbus_string_free (&f);
202 if (!_dbus_string_init (&f))
205 if (string_get_string (contents, i,
209 printf ("Function %s\n", _dbus_string_get_const_data (&f));
211 _dbus_string_free (&f);
217 printf ("End of block\n");
220 printf ("Line %ld\n", val);
225 printf ("%d functions in file\n", n_functions);
228 #define FLAG_ON_TREE 0x1
229 #define FLAG_FAKE 0x2
230 #define FLAG_FALL_THROUGH 0x4
233 dump_bbg_file (const DBusString *contents)
247 while (string_get_int (contents, i, &val))
249 long n_blocks_in_func;
253 n_blocks_in_func = val;
257 if (!string_get_int (contents, i, &n_arcs_in_func))
262 printf ("Function has %ld blocks and %ld arcs\n",
263 n_blocks_in_func, n_arcs_in_func);
266 n_blocks += n_blocks_in_func;
267 n_arcs += n_arcs_in_func;
270 while (j < n_blocks_in_func)
272 long n_arcs_in_block;
275 if (!string_get_int (contents, i, &n_arcs_in_block))
280 printf (" Block has %ld arcs\n", n_arcs_in_block);
283 while (k < n_arcs_in_block)
285 long destination_block;
288 if (!string_get_int (contents, i, &destination_block))
293 if (!string_get_int (contents, i, &flags))
298 printf (" Arc has destination block %ld flags 0x%lx\n",
299 destination_block, flags);
301 if ((flags & FLAG_ON_TREE) == 0)
302 n_arcs_off_tree += 1;
307 if (k < n_arcs_in_block)
313 if (j < n_blocks_in_func)
316 if (!string_get_int (contents, i, &val))
322 die ("-1 separator not found\n");
325 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
326 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
329 /* The da file contains first a count of arcs in the file,
330 * then a count of executions for all "off tree" arcs
334 dump_da_file (const DBusString *contents)
342 if (!string_get_int64 (contents, i, &val))
347 printf ("%ld arcs in file\n", (long) val);
348 claimed_n_arcs = val;
351 while (string_get_int64 (contents, i, &val))
355 printf ("%ld executions of arc %d\n",
361 if (n_arcs != claimed_n_arcs)
363 printf ("File claimed to have %d arcs but only had %d\n",
364 claimed_n_arcs, n_arcs);
368 typedef struct Arc Arc;
369 typedef struct Block Block;
370 typedef struct Function Function;
371 typedef struct File File;
372 typedef struct Line Line;
378 dbus_int64_t arc_count;
379 unsigned int count_valid : 1;
380 unsigned int on_tree : 1;
381 unsigned int fake : 1;
382 unsigned int fall_through : 1;
391 dbus_int64_t succ_count;
392 dbus_int64_t pred_count;
393 dbus_int64_t exec_count;
395 unsigned int count_valid : 1;
396 unsigned int on_tree : 1;
397 unsigned int inside_dbus_build_tests : 1;
405 /* number of blocks in DBUS_BUILD_TESTS */
407 int n_test_blocks_executed;
408 /* number of blocks outside DBUS_BUILD_TESTS */
409 int n_nontest_blocks;
410 int n_nontest_blocks_executed;
411 /* Summary result flags */
412 unsigned int unused : 1;
413 unsigned int inside_dbus_build_tests : 1;
414 unsigned int partial : 1; /* only some of the blocks were executed */
422 unsigned int inside_dbus_build_tests : 1;
423 unsigned int partial : 1; /* only some of the blocks were executed */
435 function_add_arc (Function *function,
442 arc = dbus_new0 (Arc, 1);
446 arc->target = target;
447 arc->source = source;
449 arc->succ_next = function->block_graph[source].succ;
450 function->block_graph[source].succ = arc;
451 function->block_graph[source].succ_count += 1;
453 arc->pred_next = function->block_graph[target].pred;
454 function->block_graph[target].pred = arc;
455 function->block_graph[target].pred_count += 1;
457 if ((flags & FLAG_ON_TREE) != 0)
460 if ((flags & FLAG_FAKE) != 0)
463 if ((flags & FLAG_FALL_THROUGH) != 0)
464 arc->fall_through = TRUE;
469 reverse_arcs (Arc *arc)
471 struct Arc *prev = 0;
474 for ( ; arc; arc = next)
476 next = arc->succ_next;
477 arc->succ_next = prev;
485 function_reverse_succ_arcs (Function *func)
487 /* Must reverse the order of all succ arcs, to ensure that they match
488 * the order of the data in the .da file.
492 for (i = 0; i < func->n_blocks; i++)
493 if (func->block_graph[i].succ)
494 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
498 get_functions_from_bbg (const DBusString *contents,
499 DBusList **functions)
509 printf ("Loading arcs and blocks from .bbg file\n");
517 while (string_get_int (contents, i, &val))
520 long n_blocks_in_func;
524 n_blocks_in_func = val;
528 if (!string_get_int (contents, i, &n_arcs_in_func))
534 n_blocks += n_blocks_in_func;
535 n_arcs += n_arcs_in_func;
537 func = dbus_new0 (Function, 1);
541 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
542 func->n_blocks = n_blocks_in_func;
545 while (j < n_blocks_in_func)
547 long n_arcs_in_block;
550 if (!string_get_int (contents, i, &n_arcs_in_block))
556 while (k < n_arcs_in_block)
558 long destination_block;
561 if (!string_get_int (contents, i, &destination_block))
566 if (!string_get_int (contents, i, &flags))
571 if ((flags & FLAG_ON_TREE) == 0)
572 n_arcs_off_tree += 1;
574 function_add_arc (func, j, destination_block,
580 if (k < n_arcs_in_block)
586 if (j < n_blocks_in_func)
589 function_reverse_succ_arcs (func);
591 if (!_dbus_list_append (functions, func))
594 if (!string_get_int (contents, i, &val))
600 die ("-1 separator not found\n");
604 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
605 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
608 _dbus_assert (n_functions == _dbus_list_get_length (functions));
612 add_counts_from_da (const DBusString *contents,
613 DBusList **functions)
620 Function *current_func;
625 printf ("Loading execution count for each arc from .da file\n");
629 if (!string_get_int64 (contents, i, &val))
634 claimed_n_arcs = val;
636 link = _dbus_list_get_first_link (functions);
640 current_func = link->data;
642 current_arc = current_func->block_graph[current_block].succ;
645 while (string_get_int64 (contents, i, &val))
649 while (current_arc == NULL ||
650 current_arc->on_tree)
652 if (current_arc == NULL)
656 if (current_block == current_func->n_blocks)
658 link = _dbus_list_get_next_link (functions, link);
661 fprintf (stderr, "Ran out of functions loading .da file\n");
664 current_func = link->data;
668 current_arc = current_func->block_graph[current_block].succ;
672 current_arc = current_arc->succ_next;
676 _dbus_assert (current_arc != NULL);
677 _dbus_assert (!current_arc->on_tree);
679 current_arc->arc_count = val;
680 current_arc->count_valid = TRUE;
681 current_func->block_graph[current_block].succ_count -= 1;
682 current_func->block_graph[current_arc->target].pred_count -= 1;
686 current_arc = current_arc->succ_next;
691 if (n_arcs != claimed_n_arcs)
693 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
694 claimed_n_arcs, n_arcs);
699 printf ("%d arcs in file\n", n_arcs);
704 function_solve_graph (Function *func)
714 printf ("Solving function graph\n");
717 n_blocks = func->n_blocks;
718 block_graph = func->block_graph;
720 /* For every block in the file,
721 - if every exit/entrance arc has a known count, then set the block count
722 - if the block count is known, and every exit/entrance arc but one has
723 a known execution count, then set the count of the remaining arc
725 As arc counts are set, decrement the succ/pred count, but don't delete
726 the arc, that way we can easily tell when all arcs are known, or only
727 one arc is unknown. */
729 /* The order that the basic blocks are iterated through is important.
730 Since the code that finds spanning trees starts with block 0, low numbered
731 arcs are put on the spanning tree in preference to high numbered arcs.
732 Hence, most instrumented arcs are at the end. Graph solving works much
733 faster if we propagate numbers from the end to the start.
735 This takes an average of slightly more than 3 passes. */
744 for (i = n_blocks - 1; i >= 0; i--)
746 if (! block_graph[i].count_valid)
748 if (block_graph[i].succ_count == 0)
751 for (arc = block_graph[i].succ; arc;
752 arc = arc->succ_next)
753 total += arc->arc_count;
754 block_graph[i].exec_count = total;
755 block_graph[i].count_valid = 1;
758 else if (block_graph[i].pred_count == 0)
761 for (arc = block_graph[i].pred; arc;
762 arc = arc->pred_next)
763 total += arc->arc_count;
764 block_graph[i].exec_count = total;
765 block_graph[i].count_valid = 1;
769 if (block_graph[i].count_valid)
771 if (block_graph[i].succ_count == 1)
774 /* One of the counts will be invalid, but it is zero,
775 so adding it in also doesn't hurt. */
776 for (arc = block_graph[i].succ; arc;
777 arc = arc->succ_next)
778 total += arc->arc_count;
779 /* Calculate count for remaining arc by conservation. */
780 total = block_graph[i].exec_count - total;
781 /* Search for the invalid arc, and set its count. */
782 for (arc = block_graph[i].succ; arc;
783 arc = arc->succ_next)
784 if (! arc->count_valid)
787 die ("arc == NULL\n");
788 arc->count_valid = 1;
789 arc->arc_count = total;
790 block_graph[i].succ_count -= 1;
792 block_graph[arc->target].pred_count -= 1;
795 if (block_graph[i].pred_count == 1)
798 /* One of the counts will be invalid, but it is zero,
799 so adding it in also doesn't hurt. */
800 for (arc = block_graph[i].pred; arc;
801 arc = arc->pred_next)
802 total += arc->arc_count;
803 /* Calculate count for remaining arc by conservation. */
804 total = block_graph[i].exec_count - total;
805 /* Search for the invalid arc, and set its count. */
806 for (arc = block_graph[i].pred; arc;
807 arc = arc->pred_next)
808 if (! arc->count_valid)
811 die ("arc == NULL\n");
812 arc->count_valid = 1;
813 arc->arc_count = total;
814 block_graph[i].pred_count -= 1;
816 block_graph[arc->source].succ_count -= 1;
823 /* If the graph has been correctly solved, every block will have a
824 * succ and pred count of zero.
826 for (i = 0; i < n_blocks; i++)
828 if (block_graph[i].succ_count || block_graph[i].pred_count)
830 fprintf (stderr, "Block graph solved incorrectly\n");
831 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
832 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
839 solve_graphs (DBusList **functions)
843 link = _dbus_list_get_first_link (functions);
846 Function *func = link->data;
848 function_solve_graph (func);
850 link = _dbus_list_get_next_link (functions, link);
855 load_functions_for_c_file (const DBusString *filename,
856 DBusList **functions)
858 DBusString bbg_filename;
859 DBusString da_filename;
863 dbus_error_init (&error);
865 if (!_dbus_string_init (&bbg_filename) ||
866 !_dbus_string_init (&da_filename) ||
867 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
868 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
869 !_dbus_string_init (&contents))
872 _dbus_string_shorten (&bbg_filename, 2);
873 _dbus_string_shorten (&da_filename, 2);
875 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
876 !_dbus_string_append (&da_filename, ".da"))
879 if (!_dbus_file_get_contents (&contents, &bbg_filename,
882 fprintf (stderr, "Could not open file: %s\n",
887 get_functions_from_bbg (&contents, functions);
889 _dbus_string_set_length (&contents, 0);
891 if (!_dbus_file_get_contents (&contents, &da_filename,
894 fprintf (stderr, "Could not open file: %s\n",
899 add_counts_from_da (&contents, functions);
901 solve_graphs (functions);
903 _dbus_string_free (&contents);
904 _dbus_string_free (&da_filename);
905 _dbus_string_free (&bbg_filename);
909 get_lines_from_bb_file (const DBusString *contents,
915 dbus_bool_t in_our_file;
921 printf ("Getting line numbers for blocks from .bb file\n");
924 /* There's this "filename" field in the .bb file which
925 * mysteriously comes *after* the first function in the
926 * file in the .bb file; and every .bb file seems to
927 * have only one filename. I don't understand
928 * what's going on here, so just set in_our_file = TRUE
929 * at the start categorically.
935 link = _dbus_list_get_first_link (&fl->functions);
938 while (string_get_int (contents, i, &val))
948 if (!_dbus_string_init (&f))
951 if (string_get_string (contents, i,
955 /* fl->name is a full path and the filename in .bb is
960 _dbus_string_init_const (&tmp_str, fl->name);
962 if (_dbus_string_ends_with_c_str (&tmp_str,
963 _dbus_string_get_const_data (&f)))
970 "File %s in .bb, looking for %s, in_our_file = %d\n",
971 _dbus_string_get_const_data (&f),
976 _dbus_string_free (&f);
982 if (!_dbus_string_init (&f))
985 if (string_get_string (contents, i,
990 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
999 fprintf (stderr, "No function object for function %s\n",
1000 _dbus_string_get_const_data (&f));
1005 link = _dbus_list_get_next_link (&fl->functions, link);
1007 if (func->name == NULL)
1009 if (!_dbus_string_copy_data (&f, &func->name))
1010 die ("no memory\n");
1014 die ("got two names for function?\n");
1019 _dbus_string_free (&f);
1029 fprintf (stderr, "Line %ld\n", val);
1032 if (val >= fl->n_lines)
1034 fprintf (stderr, "Line %ld but file only has %d lines\n",
1037 else if (func != NULL)
1039 val -= 1; /* To convert the 1-based line number to 0-based */
1040 _dbus_assert (val >= 0);
1042 if (block < func->n_blocks)
1044 if (!_dbus_list_append (&func->block_graph[block].lines,
1046 die ("no memory\n");
1049 if (!_dbus_list_append (&fl->lines[val].blocks,
1050 &func->block_graph[block]))
1051 die ("no memory\n");
1055 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1056 block, func->n_blocks);
1061 fprintf (stderr, "Line %ld given outside of any function\n",
1070 printf ("%d functions in file\n", n_functions);
1076 load_block_line_associations (const DBusString *filename,
1079 DBusString bb_filename;
1080 DBusString contents;
1083 dbus_error_init (&error);
1085 if (!_dbus_string_init (&bb_filename) ||
1086 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1087 !_dbus_string_init (&contents))
1088 die ("no memory\n");
1090 _dbus_string_shorten (&bb_filename, 2);
1092 if (!_dbus_string_append (&bb_filename, ".bb"))
1093 die ("no memory\n");
1095 if (!_dbus_file_get_contents (&contents, &bb_filename,
1098 fprintf (stderr, "Could not open file: %s\n",
1103 get_lines_from_bb_file (&contents, f);
1105 _dbus_string_free (&contents);
1106 _dbus_string_free (&bb_filename);
1110 count_lines_in_string (const DBusString *str)
1116 const char *last_line_end;
1119 printf ("Counting lines in source file\n");
1124 p = _dbus_string_get_const_data (str);
1125 end = p + _dbus_string_get_length (str);
1129 /* too lazy to handle \r\n as one linebreak */
1130 if (*p == '\n' || *p == '\r')
1133 last_line_end = p + 1;
1140 if (last_line_end != p)
1147 fill_line_content (const DBusString *str,
1154 const char *last_line_end;
1157 printf ("Saving contents of each line in source file\n");
1162 p = _dbus_string_get_const_data (str);
1163 end = p + _dbus_string_get_length (str);
1167 if (*p == '\n' || *p == '\r')
1169 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1170 if (lines[n_lines].text == NULL)
1171 die ("no memory\n");
1173 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1174 lines[n_lines].number = n_lines + 1;
1178 last_line_end = p + 1;
1185 if (p != last_line_end)
1187 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1193 mark_inside_dbus_build_tests (File *f)
1201 while (i < f->n_lines)
1203 Line *l = &f->lines[i];
1204 dbus_bool_t is_verbose;
1206 is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
1208 if (inside_depth == 0)
1212 a = strstr (l->text, "#if");
1213 b = strstr (l->text, "DBUS_BUILD_TESTS");
1214 if (a && b && (a < b))
1219 if (strstr (l->text, "#if") != NULL)
1221 else if (strstr (l->text, "#endif") != NULL)
1225 if (inside_depth > 0 || is_verbose)
1227 /* Mark the line and its blocks */
1230 l->inside_dbus_build_tests = TRUE;
1232 blink = _dbus_list_get_first_link (&l->blocks);
1233 while (blink != NULL)
1235 Block *b = blink->data;
1237 b->inside_dbus_build_tests = TRUE;
1239 blink = _dbus_list_get_next_link (&l->blocks, blink);
1246 /* Now mark functions where for all blocks that are associated
1247 * with a source line, the block is inside_dbus_build_tests.
1249 link = _dbus_list_get_first_link (&f->functions);
1250 while (link != NULL)
1252 Function *func = link->data;
1254 /* The issue is that some blocks aren't associated with a source line.
1255 * Assume they are inside/outside tests according to the source
1256 * line of the preceding block. For the first block, make it
1257 * match the first following block with a line associated.
1259 if (func->block_graph[0].lines == NULL)
1261 /* find first following line */
1263 while (i < func->n_blocks)
1265 if (func->block_graph[i].lines != NULL)
1267 func->block_graph[0].inside_dbus_build_tests =
1268 func->block_graph[i].inside_dbus_build_tests;
1276 /* Now mark all blocks but the first */
1278 while (i < func->n_blocks)
1280 if (func->block_graph[i].lines == NULL)
1282 func->block_graph[i].inside_dbus_build_tests =
1283 func->block_graph[i-1].inside_dbus_build_tests;
1290 while (i < func->n_blocks)
1292 /* Break as soon as any block is not a test block */
1293 if (func->block_graph[i].lines != NULL &&
1294 !func->block_graph[i].inside_dbus_build_tests)
1300 if (i == func->n_blocks)
1301 func->inside_dbus_build_tests = TRUE;
1303 link = _dbus_list_get_next_link (&f->functions, link);
1308 mark_coverage (File *f)
1314 while (i < f->n_lines)
1316 Line *l = &f->lines[i];
1319 int n_blocks_executed;
1322 n_blocks_executed = 0;
1323 blink = _dbus_list_get_first_link (&l->blocks);
1324 while (blink != NULL)
1326 Block *b = blink->data;
1328 if (b->exec_count > 0)
1329 n_blocks_executed += 1;
1333 blink = _dbus_list_get_next_link (&l->blocks, blink);
1336 if (n_blocks_executed > 0 &&
1337 n_blocks_executed < n_blocks)
1343 link = _dbus_list_get_first_link (&f->functions);
1344 while (link != NULL)
1346 Function *func = link->data;
1349 int n_test_blocks_executed;
1350 int n_nontest_blocks;
1351 int n_nontest_blocks_executed;
1354 n_test_blocks_executed = 0;
1355 n_nontest_blocks = 0;
1356 n_nontest_blocks_executed = 0;
1359 while (i < func->n_blocks)
1361 if (!func->block_graph[i].inside_dbus_build_tests)
1363 n_nontest_blocks += 1;
1365 if (func->block_graph[i].exec_count > 0)
1366 n_nontest_blocks_executed += 1;
1372 if (func->block_graph[i].exec_count > 0)
1373 n_test_blocks_executed += 1;
1379 if (n_nontest_blocks_executed > 0 &&
1380 n_nontest_blocks_executed < n_nontest_blocks)
1381 func->partial = TRUE;
1383 if (n_nontest_blocks_executed == 0 &&
1384 n_nontest_blocks > 0)
1385 func->unused = TRUE;
1387 func->n_test_blocks = n_test_blocks;
1388 func->n_test_blocks_executed = n_test_blocks_executed;
1389 func->n_nontest_blocks = n_nontest_blocks;
1390 func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1392 link = _dbus_list_get_next_link (&f->functions, link);
1397 load_c_file (const DBusString *filename)
1399 DBusString contents;
1403 f = dbus_new0 (File, 1);
1405 die ("no memory\n");
1407 if (!_dbus_string_copy_data (filename, &f->name))
1408 die ("no memory\n");
1410 if (!_dbus_string_init (&contents))
1411 die ("no memory\n");
1413 dbus_error_init (&error);
1415 if (!_dbus_file_get_contents (&contents, filename,
1418 fprintf (stderr, "Could not open file: %s\n",
1420 dbus_error_free (&error);
1424 load_functions_for_c_file (filename, &f->functions);
1426 f->n_lines = count_lines_in_string (&contents);
1427 f->lines = dbus_new0 (Line, f->n_lines);
1428 if (f->lines == NULL)
1429 die ("no memory\n");
1431 fill_line_content (&contents, f->lines);
1433 _dbus_string_free (&contents);
1435 load_block_line_associations (filename, f);
1437 mark_inside_dbus_build_tests (f);
1443 typedef struct Stats Stats;
1448 int n_blocks_executed;
1449 int n_blocks_inside_dbus_build_tests;
1451 int n_lines; /* lines that have blocks on them */
1452 int n_lines_executed;
1453 int n_lines_partial;
1454 int n_lines_inside_dbus_build_tests;
1457 int n_functions_executed;
1458 int n_functions_partial;
1459 int n_functions_inside_dbus_build_tests;
1463 line_was_executed (Line *l)
1467 link = _dbus_list_get_first_link (&l->blocks);
1468 while (link != NULL)
1470 Block *b = link->data;
1472 if (b->exec_count > 0)
1475 link = _dbus_list_get_next_link (&l->blocks, link);
1483 line_exec_count (Line *l)
1489 link = _dbus_list_get_first_link (&l->blocks);
1490 while (link != NULL)
1492 Block *b = link->data;
1494 total += b->exec_count;
1496 link = _dbus_list_get_next_link (&l->blocks, link);
1503 merge_stats_for_file (Stats *stats,
1509 for (i = 0; i < f->n_lines; ++i)
1511 Line *l = &f->lines[i];
1513 if (l->inside_dbus_build_tests)
1515 stats->n_lines_inside_dbus_build_tests += 1;
1519 if (line_was_executed (l))
1520 stats->n_lines_executed += 1;
1522 if (l->blocks != NULL)
1523 stats->n_lines += 1;
1526 stats->n_lines_partial += 1;
1529 link = _dbus_list_get_first_link (&f->functions);
1530 while (link != NULL)
1532 Function *func = link->data;
1534 if (func->inside_dbus_build_tests)
1535 stats->n_functions_inside_dbus_build_tests += 1;
1538 stats->n_functions += 1;
1541 stats->n_functions_executed += 1;
1544 stats->n_functions_partial += 1;
1547 stats->n_blocks_inside_dbus_build_tests +=
1548 func->n_test_blocks;
1550 stats->n_blocks_executed +=
1551 func->n_nontest_blocks_executed;
1554 func->n_nontest_blocks;
1556 link = _dbus_list_get_next_link (&f->functions, link);
1560 /* The output of this matches gcov exactly ("diff" shows no difference) */
1562 print_annotated_source_gcov_format (File *f)
1567 while (i < f->n_lines)
1569 Line *l = &f->lines[i];
1571 if (l->blocks != NULL)
1575 exec_count = line_exec_count (l);
1578 printf ("%12d %s\n",
1579 exec_count, l->text);
1581 printf (" ###### %s\n", l->text);
1585 printf ("\t\t%s\n", l->text);
1593 print_annotated_source (File *f)
1598 while (i < f->n_lines)
1600 Line *l = &f->lines[i];
1602 if (l->inside_dbus_build_tests)
1607 if (l->blocks != NULL)
1611 exec_count = line_exec_count (l);
1614 printf ("%12d %s\n",
1615 exec_count, l->text);
1617 printf (" ###### %s\n", l->text);
1621 printf ("\t\t%s\n", l->text);
1629 print_block_superdetails (File *f)
1634 link = _dbus_list_get_first_link (&f->functions);
1635 while (link != NULL)
1637 Function *func = link->data;
1639 printf ("=== %s():\n", func->name);
1642 while (i < func->n_blocks)
1644 Block *b = &func->block_graph[i];
1647 printf (" %5d executed %d times%s\n", i,
1648 (int) b->exec_count,
1649 b->inside_dbus_build_tests ?
1650 " [inside DBUS_BUILD_TESTS]" : "");
1652 l = _dbus_list_get_first_link (&b->lines);
1655 Line *line = l->data;
1657 printf ("4%d\t%s\n", line->number, line->text);
1659 l = _dbus_list_get_next_link (&b->lines, l);
1665 link = _dbus_list_get_next_link (&f->functions, link);
1670 print_one_file (const DBusString *filename)
1672 if (_dbus_string_ends_with_c_str (filename, ".bb"))
1674 DBusString contents;
1677 if (!_dbus_string_init (&contents))
1678 die ("no memory\n");
1680 dbus_error_init (&error);
1682 if (!_dbus_file_get_contents (&contents, filename,
1685 fprintf (stderr, "Could not open file: %s\n",
1687 dbus_error_free (&error);
1691 dump_bb_file (&contents);
1693 _dbus_string_free (&contents);
1695 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
1697 DBusString contents;
1700 if (!_dbus_string_init (&contents))
1701 die ("no memory\n");
1703 dbus_error_init (&error);
1705 if (!_dbus_file_get_contents (&contents, filename,
1708 fprintf (stderr, "Could not open file: %s\n",
1710 dbus_error_free (&error);
1714 dump_bbg_file (&contents);
1716 _dbus_string_free (&contents);
1718 else if (_dbus_string_ends_with_c_str (filename, ".da"))
1720 DBusString contents;
1723 if (!_dbus_string_init (&contents))
1724 die ("no memory\n");
1726 dbus_error_init (&error);
1728 if (!_dbus_file_get_contents (&contents, filename,
1731 fprintf (stderr, "Could not open file: %s\n",
1733 dbus_error_free (&error);
1737 dump_da_file (&contents);
1739 _dbus_string_free (&contents);
1741 else if (_dbus_string_ends_with_c_str (filename, ".c"))
1745 f = load_c_file (filename);
1747 print_annotated_source (f);
1751 fprintf (stderr, "Unknown file type %s\n",
1752 _dbus_string_get_const_data (filename));
1758 print_untested_functions (File *f)
1764 link = _dbus_list_get_first_link (&f->functions);
1765 while (link != NULL)
1767 Function *func = link->data;
1770 !func->inside_dbus_build_tests)
1773 link = _dbus_list_get_next_link (&f->functions, link);
1779 printf ("Untested functions in %s\n", f->name);
1780 printf ("=======\n");
1782 link = _dbus_list_get_first_link (&f->functions);
1783 while (link != NULL)
1785 Function *func = link->data;
1788 !func->inside_dbus_build_tests)
1789 printf (" %s\n", func->name);
1791 link = _dbus_list_get_next_link (&f->functions, link);
1798 print_poorly_tested_functions (File *f,
1804 #define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
1806 #define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
1808 #define POORLY_TESTED(function) (!(function)->unused && \
1809 (function)->n_nontest_blocks > 0 && \
1810 TEST_FRACTION (function) < AVERAGE_COVERAGE)
1813 link = _dbus_list_get_first_link (&f->functions);
1814 while (link != NULL)
1816 Function *func = link->data;
1818 if (POORLY_TESTED (func))
1821 link = _dbus_list_get_next_link (&f->functions, link);
1827 printf ("Below average functions in %s\n", f->name);
1828 printf ("=======\n");
1830 link = _dbus_list_get_first_link (&f->functions);
1831 while (link != NULL)
1833 Function *func = link->data;
1835 if (POORLY_TESTED (func))
1836 printf (" %s (%d%%)\n", func->name,
1837 (int) (TEST_FRACTION (func) * 100));
1839 link = _dbus_list_get_next_link (&f->functions, link);
1846 func_cmp (const void *a,
1849 Function *af = *(Function**) a;
1850 Function *bf = *(Function**) b;
1851 int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
1852 int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
1854 /* Sort by number of untested blocks */
1855 return b_untested - a_untested;
1859 print_n_untested_blocks_by_function (File *f,
1868 link = _dbus_list_get_first_link (&f->functions);
1869 while (link != NULL)
1871 Function *func = link->data;
1873 if (func->n_nontest_blocks_executed <
1874 func->n_nontest_blocks)
1877 link = _dbus_list_get_next_link (&f->functions, link);
1883 /* make an array so we can use qsort */
1885 funcs = dbus_new (Function*, n_found);
1890 link = _dbus_list_get_first_link (&f->functions);
1891 while (link != NULL)
1893 Function *func = link->data;
1895 if (func->n_nontest_blocks_executed <
1896 func->n_nontest_blocks)
1902 link = _dbus_list_get_next_link (&f->functions, link);
1905 _dbus_assert (i == n_found);
1907 qsort (funcs, n_found, sizeof (Function*),
1910 printf ("Incomplete functions in %s\n", f->name);
1911 printf ("=======\n");
1916 Function *func = funcs[i];
1918 printf (" %s (%d/%d untested blocks)\n",
1920 func->n_nontest_blocks - func->n_nontest_blocks_executed,
1921 func->n_nontest_blocks);
1932 print_stats (Stats *stats,
1933 const char *of_what)
1937 printf ("Summary (%s)\n", of_what);
1938 printf ("=======\n");
1939 printf (" %g%% blocks executed (%d of %d)\n",
1940 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
1941 stats->n_blocks_executed,
1944 printf (" (ignored %d blocks of test-only/debug-only code)\n",
1945 stats->n_blocks_inside_dbus_build_tests);
1947 printf (" %g%% functions executed (%d of %d)\n",
1948 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
1949 stats->n_functions_executed,
1950 stats->n_functions);
1952 completely = stats->n_functions_executed - stats->n_functions_partial;
1953 printf (" %g%% functions completely executed (%d of %d)\n",
1954 (completely / (double) stats->n_functions) * 100.0,
1956 stats->n_functions);
1958 printf (" (ignored %d functions of test-only/debug-only code)\n",
1959 stats->n_functions_inside_dbus_build_tests);
1961 printf (" %g%% lines executed (%d of %d)\n",
1962 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
1963 stats->n_lines_executed,
1966 completely = stats->n_lines_executed - stats->n_lines_partial;
1967 printf (" %g%% lines completely executed (%d of %d)\n",
1968 (completely / (double) stats->n_lines) * 100.0,
1972 printf (" (ignored %d lines of test-only/debug-only code)\n",
1973 stats->n_lines_inside_dbus_build_tests);
1987 main (int argc, char **argv)
1989 DBusString filename;
1995 fprintf (stderr, "Must specify files on command line\n");
2002 if (strcmp (argv[i], "--report") == 0)
2007 else if (strcmp (argv[i], "--blocks") == 0)
2012 else if (strcmp (argv[i], "--gcov") == 0)
2021 fprintf (stderr, "Must specify files on command line\n");
2025 if (m == MODE_PRINT)
2029 _dbus_string_init_const (&filename, argv[i]);
2031 print_one_file (&filename);
2036 else if (m == MODE_BLOCKS || m == MODE_GCOV)
2042 _dbus_string_init_const (&filename, argv[i]);
2044 f = load_c_file (&filename);
2046 if (m == MODE_BLOCKS)
2047 print_block_superdetails (f);
2048 else if (m == MODE_GCOV)
2049 print_annotated_source_gcov_format (f);
2054 else if (m == MODE_REPORT)
2056 Stats stats = { 0, };
2059 DBusHashTable *stats_by_dir;
2065 _dbus_string_init_const (&filename, argv[i]);
2067 if (_dbus_string_ends_with_c_str (&filename, ".c"))
2071 f = load_c_file (&filename);
2073 if (!_dbus_list_append (&files, f))
2074 die ("no memory\n");
2078 fprintf (stderr, "Unknown file type %s\n",
2079 _dbus_string_get_const_data (&filename));
2086 link = _dbus_list_get_first_link (&files);
2087 while (link != NULL)
2089 File *f = link->data;
2091 merge_stats_for_file (&stats, f);
2093 link = _dbus_list_get_next_link (&files, link);
2096 print_stats (&stats, "all files");
2098 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
2099 dbus_free, dbus_free);
2101 link = _dbus_list_get_first_link (&files);
2102 while (link != NULL)
2104 File *f = link->data;
2109 _dbus_string_init_const (&filename, f->name);
2111 if (!_dbus_string_init (&dirname))
2112 die ("no memory\n");
2114 if (!_dbus_string_get_dirname (&filename, &dirname) ||
2115 !_dbus_string_copy_data (&dirname, &dirname_c))
2116 die ("no memory\n");
2118 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
2121 if (dir_stats == NULL)
2123 dir_stats = dbus_new0 (Stats, 1);
2124 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
2126 die ("no memory\n");
2129 dbus_free (dirname_c);
2131 merge_stats_for_file (dir_stats, f);
2133 link = _dbus_list_get_next_link (&files, link);
2136 _dbus_hash_iter_init (stats_by_dir, &iter);
2137 while (_dbus_hash_iter_next (&iter))
2139 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
2140 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
2142 print_stats (dir_stats, dirname);
2145 _dbus_hash_table_unref (stats_by_dir);
2147 link = _dbus_list_get_first_link (&files);
2148 while (link != NULL)
2150 File *f = link->data;
2152 print_untested_functions (f);
2154 link = _dbus_list_get_next_link (&files, link);
2157 link = _dbus_list_get_first_link (&files);
2158 while (link != NULL)
2160 File *f = link->data;
2162 print_poorly_tested_functions (f, &stats);
2164 link = _dbus_list_get_next_link (&files, link);
2167 link = _dbus_list_get_first_link (&files);
2168 while (link != NULL)
2170 File *f = link->data;
2172 print_n_untested_blocks_by_function (f, &stats);
2174 link = _dbus_list_get_next_link (&files, link);