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
42 die (const char *message)
44 fprintf (stderr, "%s", message);
48 /* This bizarro function is from gcov-io.h in gcc source tree */
50 fetch_long (long *dest,
57 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
58 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
62 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
64 if ((source[bytes - 1] & 128) && (value > 0))
72 fetch_long64 (dbus_int64_t *dest,
76 dbus_int64_t value = 0;
79 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
80 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
84 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
86 if ((source[bytes - 1] & 128) && (value > 0))
93 #define BB_FILENAME (-1)
94 #define BB_FUNCTION (-2)
95 #define BB_ENDOFLIST 0
98 string_get_int (const DBusString *str,
104 if ((_dbus_string_get_length (str) - start) < 4)
107 p = _dbus_string_get_const_data (str);
111 fetch_long (val, p, 4);
117 string_get_int64 (const DBusString *str,
123 if ((_dbus_string_get_length (str) - start) < 8)
126 p = _dbus_string_get_const_data (str);
130 fetch_long64 (val, p, 8);
136 string_get_string (const DBusString *str,
146 while (string_get_int (str, i, &n))
153 _dbus_string_append_byte (val, n & 0xff);
154 _dbus_string_append_byte (val, (n >> 8) & 0xff);
155 _dbus_string_append_byte (val, (n >> 16) & 0xff);
156 _dbus_string_append_byte (val, (n >> 24) & 0xff);
165 dump_bb_file (const DBusString *contents)
173 while (string_get_int (contents, i, &val))
183 if (!_dbus_string_init (&f))
186 if (string_get_string (contents, i,
190 printf ("File %s\n", _dbus_string_get_const_data (&f));
192 _dbus_string_free (&f);
198 if (!_dbus_string_init (&f))
201 if (string_get_string (contents, i,
205 printf ("Function %s\n", _dbus_string_get_const_data (&f));
207 _dbus_string_free (&f);
213 printf ("End of block\n");
216 printf ("Line %ld\n", val);
221 printf ("%d functions in file\n", n_functions);
224 #define FLAG_ON_TREE 0x1
225 #define FLAG_FAKE 0x2
226 #define FLAG_FALL_THROUGH 0x4
229 dump_bbg_file (const DBusString *contents)
243 while (string_get_int (contents, i, &val))
245 long n_blocks_in_func;
249 n_blocks_in_func = val;
253 if (!string_get_int (contents, i, &n_arcs_in_func))
258 printf ("Function has %ld blocks and %ld arcs\n",
259 n_blocks_in_func, n_arcs_in_func);
262 n_blocks += n_blocks_in_func;
263 n_arcs += n_arcs_in_func;
266 while (j < n_blocks_in_func)
268 long n_arcs_in_block;
271 if (!string_get_int (contents, i, &n_arcs_in_block))
276 printf (" Block has %ld arcs\n", n_arcs_in_block);
279 while (k < n_arcs_in_block)
281 long destination_block;
284 if (!string_get_int (contents, i, &destination_block))
289 if (!string_get_int (contents, i, &flags))
294 printf (" Arc has destination block %ld flags 0x%lx\n",
295 destination_block, flags);
297 if ((flags & FLAG_ON_TREE) == 0)
298 n_arcs_off_tree += 1;
303 if (k < n_arcs_in_block)
309 if (j < n_blocks_in_func)
312 if (!string_get_int (contents, i, &val))
318 die ("-1 separator not found\n");
321 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
322 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
325 /* The da file contains first a count of arcs in the file,
326 * then a count of executions for all "off tree" arcs
330 dump_da_file (const DBusString *contents)
338 if (!string_get_int64 (contents, i, &val))
343 printf ("%ld arcs in file\n", (long) val);
344 claimed_n_arcs = val;
347 while (string_get_int64 (contents, i, &val))
351 printf ("%ld executions of arc %d\n",
357 if (n_arcs != claimed_n_arcs)
359 printf ("File claimed to have %d arcs but only had %d\n",
360 claimed_n_arcs, n_arcs);
364 typedef struct Arc Arc;
365 typedef struct Block Block;
366 typedef struct Function Function;
367 typedef struct File File;
368 typedef struct Line Line;
374 dbus_int64_t arc_count;
375 unsigned int count_valid : 1;
376 unsigned int on_tree : 1;
377 unsigned int fake : 1;
378 unsigned int fall_through : 1;
387 dbus_int64_t succ_count;
388 dbus_int64_t pred_count;
389 dbus_int64_t exec_count;
391 unsigned int count_valid : 1;
392 unsigned int on_tree : 1;
393 unsigned int inside_dbus_build_tests : 1;
401 /* number of blocks in DBUS_BUILD_TESTS */
403 int n_test_blocks_executed;
404 /* number of blocks outside DBUS_BUILD_TESTS */
405 int n_nontest_blocks;
406 int n_nontest_blocks_executed;
407 /* Summary result flags */
408 unsigned int unused : 1;
409 unsigned int inside_dbus_build_tests : 1;
410 unsigned int partial : 1; /* only some of the blocks were executed */
418 unsigned int inside_dbus_build_tests : 1;
419 unsigned int partial : 1; /* only some of the blocks were executed */
431 function_add_arc (Function *function,
438 arc = dbus_new0 (Arc, 1);
442 arc->target = target;
443 arc->source = source;
445 arc->succ_next = function->block_graph[source].succ;
446 function->block_graph[source].succ = arc;
447 function->block_graph[source].succ_count += 1;
449 arc->pred_next = function->block_graph[target].pred;
450 function->block_graph[target].pred = arc;
451 function->block_graph[target].pred_count += 1;
453 if ((flags & FLAG_ON_TREE) != 0)
456 if ((flags & FLAG_FAKE) != 0)
459 if ((flags & FLAG_FALL_THROUGH) != 0)
460 arc->fall_through = TRUE;
465 reverse_arcs (Arc *arc)
467 struct Arc *prev = 0;
470 for ( ; arc; arc = next)
472 next = arc->succ_next;
473 arc->succ_next = prev;
481 function_reverse_succ_arcs (Function *func)
483 /* Must reverse the order of all succ arcs, to ensure that they match
484 * the order of the data in the .da file.
488 for (i = 0; i < func->n_blocks; i++)
489 if (func->block_graph[i].succ)
490 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
494 get_functions_from_bbg (const DBusString *contents,
495 DBusList **functions)
505 printf ("Loading arcs and blocks from .bbg file\n");
513 while (string_get_int (contents, i, &val))
516 long n_blocks_in_func;
520 n_blocks_in_func = val;
524 if (!string_get_int (contents, i, &n_arcs_in_func))
530 n_blocks += n_blocks_in_func;
531 n_arcs += n_arcs_in_func;
533 func = dbus_new0 (Function, 1);
537 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
538 func->n_blocks = n_blocks_in_func;
541 while (j < n_blocks_in_func)
543 long n_arcs_in_block;
546 if (!string_get_int (contents, i, &n_arcs_in_block))
552 while (k < n_arcs_in_block)
554 long destination_block;
557 if (!string_get_int (contents, i, &destination_block))
562 if (!string_get_int (contents, i, &flags))
567 if ((flags & FLAG_ON_TREE) == 0)
568 n_arcs_off_tree += 1;
570 function_add_arc (func, j, destination_block,
576 if (k < n_arcs_in_block)
582 if (j < n_blocks_in_func)
585 function_reverse_succ_arcs (func);
587 if (!_dbus_list_append (functions, func))
590 if (!string_get_int (contents, i, &val))
596 die ("-1 separator not found\n");
600 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
601 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
604 _dbus_assert (n_functions == _dbus_list_get_length (functions));
608 add_counts_from_da (const DBusString *contents,
609 DBusList **functions)
616 Function *current_func;
621 printf ("Loading execution count for each arc from .da file\n");
625 if (!string_get_int64 (contents, i, &val))
630 claimed_n_arcs = val;
632 link = _dbus_list_get_first_link (functions);
636 current_func = link->data;
638 current_arc = current_func->block_graph[current_block].succ;
641 while (string_get_int64 (contents, i, &val))
645 while (current_arc == NULL ||
646 current_arc->on_tree)
648 if (current_arc == NULL)
652 if (current_block == current_func->n_blocks)
654 link = _dbus_list_get_next_link (functions, link);
657 fprintf (stderr, "Ran out of functions loading .da file\n");
660 current_func = link->data;
664 current_arc = current_func->block_graph[current_block].succ;
668 current_arc = current_arc->succ_next;
672 _dbus_assert (current_arc != NULL);
673 _dbus_assert (!current_arc->on_tree);
675 current_arc->arc_count = val;
676 current_arc->count_valid = TRUE;
677 current_func->block_graph[current_block].succ_count -= 1;
678 current_func->block_graph[current_arc->target].pred_count -= 1;
682 current_arc = current_arc->succ_next;
687 if (n_arcs != claimed_n_arcs)
689 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
690 claimed_n_arcs, n_arcs);
695 printf ("%d arcs in file\n", n_arcs);
700 function_solve_graph (Function *func)
710 printf ("Solving function graph\n");
713 n_blocks = func->n_blocks;
714 block_graph = func->block_graph;
716 /* For every block in the file,
717 - if every exit/entrance arc has a known count, then set the block count
718 - if the block count is known, and every exit/entrance arc but one has
719 a known execution count, then set the count of the remaining arc
721 As arc counts are set, decrement the succ/pred count, but don't delete
722 the arc, that way we can easily tell when all arcs are known, or only
723 one arc is unknown. */
725 /* The order that the basic blocks are iterated through is important.
726 Since the code that finds spanning trees starts with block 0, low numbered
727 arcs are put on the spanning tree in preference to high numbered arcs.
728 Hence, most instrumented arcs are at the end. Graph solving works much
729 faster if we propagate numbers from the end to the start.
731 This takes an average of slightly more than 3 passes. */
740 for (i = n_blocks - 1; i >= 0; i--)
742 if (! block_graph[i].count_valid)
744 if (block_graph[i].succ_count == 0)
747 for (arc = block_graph[i].succ; arc;
748 arc = arc->succ_next)
749 total += arc->arc_count;
750 block_graph[i].exec_count = total;
751 block_graph[i].count_valid = 1;
754 else if (block_graph[i].pred_count == 0)
757 for (arc = block_graph[i].pred; arc;
758 arc = arc->pred_next)
759 total += arc->arc_count;
760 block_graph[i].exec_count = total;
761 block_graph[i].count_valid = 1;
765 if (block_graph[i].count_valid)
767 if (block_graph[i].succ_count == 1)
770 /* One of the counts will be invalid, but it is zero,
771 so adding it in also doesn't hurt. */
772 for (arc = block_graph[i].succ; arc;
773 arc = arc->succ_next)
774 total += arc->arc_count;
775 /* Calculate count for remaining arc by conservation. */
776 total = block_graph[i].exec_count - total;
777 /* Search for the invalid arc, and set its count. */
778 for (arc = block_graph[i].succ; arc;
779 arc = arc->succ_next)
780 if (! arc->count_valid)
783 die ("arc == NULL\n");
784 arc->count_valid = 1;
785 arc->arc_count = total;
786 block_graph[i].succ_count -= 1;
788 block_graph[arc->target].pred_count -= 1;
791 if (block_graph[i].pred_count == 1)
794 /* One of the counts will be invalid, but it is zero,
795 so adding it in also doesn't hurt. */
796 for (arc = block_graph[i].pred; arc;
797 arc = arc->pred_next)
798 total += arc->arc_count;
799 /* Calculate count for remaining arc by conservation. */
800 total = block_graph[i].exec_count - total;
801 /* Search for the invalid arc, and set its count. */
802 for (arc = block_graph[i].pred; arc;
803 arc = arc->pred_next)
804 if (! arc->count_valid)
807 die ("arc == NULL\n");
808 arc->count_valid = 1;
809 arc->arc_count = total;
810 block_graph[i].pred_count -= 1;
812 block_graph[arc->source].succ_count -= 1;
819 /* If the graph has been correctly solved, every block will have a
820 * succ and pred count of zero.
822 for (i = 0; i < n_blocks; i++)
824 if (block_graph[i].succ_count || block_graph[i].pred_count)
826 fprintf (stderr, "Block graph solved incorrectly\n");
827 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
828 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
835 solve_graphs (DBusList **functions)
839 link = _dbus_list_get_first_link (functions);
842 Function *func = link->data;
844 function_solve_graph (func);
846 link = _dbus_list_get_next_link (functions, link);
851 load_functions_for_c_file (const DBusString *filename,
852 DBusList **functions)
854 DBusString bbg_filename;
855 DBusString da_filename;
859 dbus_error_init (&error);
861 if (!_dbus_string_init (&bbg_filename) ||
862 !_dbus_string_init (&da_filename) ||
863 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
864 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
865 !_dbus_string_init (&contents))
868 _dbus_string_shorten (&bbg_filename, 2);
869 _dbus_string_shorten (&da_filename, 2);
871 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
872 !_dbus_string_append (&da_filename, ".da"))
875 if (!_dbus_file_get_contents (&contents, &bbg_filename,
878 fprintf (stderr, "Could not open file: %s\n",
883 get_functions_from_bbg (&contents, functions);
885 _dbus_string_set_length (&contents, 0);
887 if (!_dbus_file_get_contents (&contents, &da_filename,
890 fprintf (stderr, "Could not open file: %s\n",
895 add_counts_from_da (&contents, functions);
897 solve_graphs (functions);
899 _dbus_string_free (&contents);
900 _dbus_string_free (&da_filename);
901 _dbus_string_free (&bbg_filename);
905 get_lines_from_bb_file (const DBusString *contents,
911 dbus_bool_t in_our_file;
917 printf ("Getting line numbers for blocks from .bb file\n");
920 /* There's this "filename" field in the .bb file which
921 * mysteriously comes *after* the first function in the
922 * file in the .bb file; and every .bb file seems to
923 * have only one filename. I don't understand
924 * what's going on here, so just set in_our_file = TRUE
925 * at the start categorically.
931 link = _dbus_list_get_first_link (&fl->functions);
934 while (string_get_int (contents, i, &val))
944 if (!_dbus_string_init (&f))
947 if (string_get_string (contents, i,
951 /* fl->name is a full path and the filename in .bb is
956 _dbus_string_init_const (&tmp_str, fl->name);
958 if (_dbus_string_ends_with_c_str (&tmp_str,
959 _dbus_string_get_const_data (&f)))
966 "File %s in .bb, looking for %s, in_our_file = %d\n",
967 _dbus_string_get_const_data (&f),
972 _dbus_string_free (&f);
978 if (!_dbus_string_init (&f))
981 if (string_get_string (contents, i,
986 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
995 fprintf (stderr, "No function object for function %s\n",
996 _dbus_string_get_const_data (&f));
1001 link = _dbus_list_get_next_link (&fl->functions, link);
1003 if (func->name == NULL)
1005 if (!_dbus_string_copy_data (&f, &func->name))
1006 die ("no memory\n");
1010 die ("got two names for function?\n");
1015 _dbus_string_free (&f);
1025 fprintf (stderr, "Line %ld\n", val);
1028 if (val >= fl->n_lines)
1030 fprintf (stderr, "Line %ld but file only has %d lines\n",
1033 else if (func != NULL)
1035 val -= 1; /* To convert the 1-based line number to 0-based */
1036 _dbus_assert (val >= 0);
1038 if (block < func->n_blocks)
1040 if (!_dbus_list_append (&func->block_graph[block].lines,
1042 die ("no memory\n");
1045 if (!_dbus_list_append (&fl->lines[val].blocks,
1046 &func->block_graph[block]))
1047 die ("no memory\n");
1051 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1052 block, func->n_blocks);
1057 fprintf (stderr, "Line %ld given outside of any function\n",
1066 printf ("%d functions in file\n", n_functions);
1072 load_block_line_associations (const DBusString *filename,
1075 DBusString bb_filename;
1076 DBusString contents;
1079 dbus_error_init (&error);
1081 if (!_dbus_string_init (&bb_filename) ||
1082 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1083 !_dbus_string_init (&contents))
1084 die ("no memory\n");
1086 _dbus_string_shorten (&bb_filename, 2);
1088 if (!_dbus_string_append (&bb_filename, ".bb"))
1089 die ("no memory\n");
1091 if (!_dbus_file_get_contents (&contents, &bb_filename,
1094 fprintf (stderr, "Could not open file: %s\n",
1099 get_lines_from_bb_file (&contents, f);
1101 _dbus_string_free (&contents);
1102 _dbus_string_free (&bb_filename);
1106 count_lines_in_string (const DBusString *str)
1112 const char *last_line_end;
1115 printf ("Counting lines in source file\n");
1120 p = _dbus_string_get_const_data (str);
1121 end = p + _dbus_string_get_length (str);
1125 /* too lazy to handle \r\n as one linebreak */
1126 if (*p == '\n' || *p == '\r')
1129 last_line_end = p + 1;
1136 if (last_line_end != p)
1143 fill_line_content (const DBusString *str,
1150 const char *last_line_end;
1153 printf ("Saving contents of each line in source file\n");
1158 p = _dbus_string_get_const_data (str);
1159 end = p + _dbus_string_get_length (str);
1163 if (*p == '\n' || *p == '\r')
1165 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1166 if (lines[n_lines].text == NULL)
1167 die ("no memory\n");
1169 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1170 lines[n_lines].number = n_lines + 1;
1174 last_line_end = p + 1;
1181 if (p != last_line_end)
1183 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1189 mark_inside_dbus_build_tests (File *f)
1197 while (i < f->n_lines)
1199 Line *l = &f->lines[i];
1200 dbus_bool_t is_verbose;
1202 is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
1204 if (inside_depth == 0)
1208 a = strstr (l->text, "#if");
1209 b = strstr (l->text, "DBUS_BUILD_TESTS");
1210 if (a && b && (a < b))
1215 if (strstr (l->text, "#if") != NULL)
1217 else if (strstr (l->text, "#endif") != NULL)
1221 if (inside_depth > 0 || is_verbose)
1223 /* Mark the line and its blocks */
1226 l->inside_dbus_build_tests = TRUE;
1228 blink = _dbus_list_get_first_link (&l->blocks);
1229 while (blink != NULL)
1231 Block *b = blink->data;
1233 b->inside_dbus_build_tests = TRUE;
1235 blink = _dbus_list_get_next_link (&l->blocks, blink);
1242 /* Now mark functions where for all blocks that are associated
1243 * with a source line, the block is inside_dbus_build_tests.
1245 link = _dbus_list_get_first_link (&f->functions);
1246 while (link != NULL)
1248 Function *func = link->data;
1250 /* The issue is that some blocks aren't associated with a source line.
1251 * Assume they are inside/outside tests according to the source
1252 * line of the preceding block. For the first block, make it
1253 * match the first following block with a line associated.
1255 if (func->block_graph[0].lines == NULL)
1257 /* find first following line */
1259 while (i < func->n_blocks)
1261 if (func->block_graph[i].lines != NULL)
1263 func->block_graph[0].inside_dbus_build_tests =
1264 func->block_graph[i].inside_dbus_build_tests;
1272 /* Now mark all blocks but the first */
1274 while (i < func->n_blocks)
1276 if (func->block_graph[i].lines == NULL)
1278 func->block_graph[i].inside_dbus_build_tests =
1279 func->block_graph[i-1].inside_dbus_build_tests;
1286 while (i < func->n_blocks)
1288 /* Break as soon as any block is not a test block */
1289 if (func->block_graph[i].lines != NULL &&
1290 !func->block_graph[i].inside_dbus_build_tests)
1296 if (i == func->n_blocks)
1297 func->inside_dbus_build_tests = TRUE;
1299 link = _dbus_list_get_next_link (&f->functions, link);
1304 mark_coverage (File *f)
1310 while (i < f->n_lines)
1312 Line *l = &f->lines[i];
1315 int n_blocks_executed;
1318 n_blocks_executed = 0;
1319 blink = _dbus_list_get_first_link (&l->blocks);
1320 while (blink != NULL)
1322 Block *b = blink->data;
1324 if (b->exec_count > 0)
1325 n_blocks_executed += 1;
1329 blink = _dbus_list_get_next_link (&l->blocks, blink);
1332 if (n_blocks_executed > 0 &&
1333 n_blocks_executed < n_blocks)
1339 link = _dbus_list_get_first_link (&f->functions);
1340 while (link != NULL)
1342 Function *func = link->data;
1345 int n_test_blocks_executed;
1346 int n_nontest_blocks;
1347 int n_nontest_blocks_executed;
1350 n_test_blocks_executed = 0;
1351 n_nontest_blocks = 0;
1352 n_nontest_blocks_executed = 0;
1355 while (i < func->n_blocks)
1357 if (!func->block_graph[i].inside_dbus_build_tests)
1359 n_nontest_blocks += 1;
1361 if (func->block_graph[i].exec_count > 0)
1362 n_nontest_blocks_executed += 1;
1368 if (func->block_graph[i].exec_count > 0)
1369 n_test_blocks_executed += 1;
1375 if (n_nontest_blocks_executed > 0 &&
1376 n_nontest_blocks_executed < n_nontest_blocks)
1377 func->partial = TRUE;
1379 if (n_nontest_blocks_executed == 0 &&
1380 n_nontest_blocks > 0)
1381 func->unused = TRUE;
1383 func->n_test_blocks = n_test_blocks;
1384 func->n_test_blocks_executed = n_test_blocks_executed;
1385 func->n_nontest_blocks = n_nontest_blocks;
1386 func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1388 link = _dbus_list_get_next_link (&f->functions, link);
1393 load_c_file (const DBusString *filename)
1395 DBusString contents;
1399 f = dbus_new0 (File, 1);
1401 die ("no memory\n");
1403 if (!_dbus_string_copy_data (filename, &f->name))
1404 die ("no memory\n");
1406 if (!_dbus_string_init (&contents))
1407 die ("no memory\n");
1409 dbus_error_init (&error);
1411 if (!_dbus_file_get_contents (&contents, filename,
1414 fprintf (stderr, "Could not open file: %s\n",
1416 dbus_error_free (&error);
1420 load_functions_for_c_file (filename, &f->functions);
1422 f->n_lines = count_lines_in_string (&contents);
1423 f->lines = dbus_new0 (Line, f->n_lines);
1424 if (f->lines == NULL)
1425 die ("no memory\n");
1427 fill_line_content (&contents, f->lines);
1429 _dbus_string_free (&contents);
1431 load_block_line_associations (filename, f);
1433 mark_inside_dbus_build_tests (f);
1439 typedef struct Stats Stats;
1444 int n_blocks_executed;
1445 int n_blocks_inside_dbus_build_tests;
1447 int n_lines; /* lines that have blocks on them */
1448 int n_lines_executed;
1449 int n_lines_partial;
1450 int n_lines_inside_dbus_build_tests;
1453 int n_functions_executed;
1454 int n_functions_partial;
1455 int n_functions_inside_dbus_build_tests;
1459 line_was_executed (Line *l)
1463 link = _dbus_list_get_first_link (&l->blocks);
1464 while (link != NULL)
1466 Block *b = link->data;
1468 if (b->exec_count > 0)
1471 link = _dbus_list_get_next_link (&l->blocks, link);
1479 line_exec_count (Line *l)
1485 link = _dbus_list_get_first_link (&l->blocks);
1486 while (link != NULL)
1488 Block *b = link->data;
1490 total += b->exec_count;
1492 link = _dbus_list_get_next_link (&l->blocks, link);
1499 merge_stats_for_file (Stats *stats,
1505 for (i = 0; i < f->n_lines; ++i)
1507 Line *l = &f->lines[i];
1509 if (l->inside_dbus_build_tests)
1511 stats->n_lines_inside_dbus_build_tests += 1;
1515 if (line_was_executed (l))
1516 stats->n_lines_executed += 1;
1518 if (l->blocks != NULL)
1519 stats->n_lines += 1;
1522 stats->n_lines_partial += 1;
1525 link = _dbus_list_get_first_link (&f->functions);
1526 while (link != NULL)
1528 Function *func = link->data;
1530 if (func->inside_dbus_build_tests)
1531 stats->n_functions_inside_dbus_build_tests += 1;
1534 stats->n_functions += 1;
1537 stats->n_functions_executed += 1;
1540 stats->n_functions_partial += 1;
1543 stats->n_blocks_inside_dbus_build_tests +=
1544 func->n_test_blocks;
1546 stats->n_blocks_executed +=
1547 func->n_nontest_blocks_executed;
1550 func->n_nontest_blocks;
1552 link = _dbus_list_get_next_link (&f->functions, link);
1556 /* The output of this matches gcov exactly ("diff" shows no difference) */
1558 print_annotated_source_gcov_format (File *f)
1563 while (i < f->n_lines)
1565 Line *l = &f->lines[i];
1567 if (l->blocks != NULL)
1571 exec_count = line_exec_count (l);
1574 printf ("%12d %s\n",
1575 exec_count, l->text);
1577 printf (" ###### %s\n", l->text);
1581 printf ("\t\t%s\n", l->text);
1589 print_annotated_source (File *f)
1594 while (i < f->n_lines)
1596 Line *l = &f->lines[i];
1598 if (l->inside_dbus_build_tests)
1603 if (l->blocks != NULL)
1607 exec_count = line_exec_count (l);
1610 printf ("%12d %s\n",
1611 exec_count, l->text);
1613 printf (" ###### %s\n", l->text);
1617 printf ("\t\t%s\n", l->text);
1625 print_block_superdetails (File *f)
1630 link = _dbus_list_get_first_link (&f->functions);
1631 while (link != NULL)
1633 Function *func = link->data;
1635 printf ("=== %s():\n", func->name);
1638 while (i < func->n_blocks)
1640 Block *b = &func->block_graph[i];
1643 printf (" %5d executed %d times%s\n", i,
1644 (int) b->exec_count,
1645 b->inside_dbus_build_tests ?
1646 " [inside DBUS_BUILD_TESTS]" : "");
1648 l = _dbus_list_get_first_link (&b->lines);
1651 Line *line = l->data;
1653 printf ("4%d\t%s\n", line->number, line->text);
1655 l = _dbus_list_get_next_link (&b->lines, l);
1661 link = _dbus_list_get_next_link (&f->functions, link);
1666 print_one_file (const DBusString *filename)
1668 if (_dbus_string_ends_with_c_str (filename, ".bb"))
1670 DBusString contents;
1673 if (!_dbus_string_init (&contents))
1674 die ("no memory\n");
1676 dbus_error_init (&error);
1678 if (!_dbus_file_get_contents (&contents, filename,
1681 fprintf (stderr, "Could not open file: %s\n",
1683 dbus_error_free (&error);
1687 dump_bb_file (&contents);
1689 _dbus_string_free (&contents);
1691 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
1693 DBusString contents;
1696 if (!_dbus_string_init (&contents))
1697 die ("no memory\n");
1699 dbus_error_init (&error);
1701 if (!_dbus_file_get_contents (&contents, filename,
1704 fprintf (stderr, "Could not open file: %s\n",
1706 dbus_error_free (&error);
1710 dump_bbg_file (&contents);
1712 _dbus_string_free (&contents);
1714 else if (_dbus_string_ends_with_c_str (filename, ".da"))
1716 DBusString contents;
1719 if (!_dbus_string_init (&contents))
1720 die ("no memory\n");
1722 dbus_error_init (&error);
1724 if (!_dbus_file_get_contents (&contents, filename,
1727 fprintf (stderr, "Could not open file: %s\n",
1729 dbus_error_free (&error);
1733 dump_da_file (&contents);
1735 _dbus_string_free (&contents);
1737 else if (_dbus_string_ends_with_c_str (filename, ".c"))
1741 f = load_c_file (filename);
1743 print_annotated_source (f);
1747 fprintf (stderr, "Unknown file type %s\n",
1748 _dbus_string_get_const_data (filename));
1754 print_untested_functions (File *f)
1760 link = _dbus_list_get_first_link (&f->functions);
1761 while (link != NULL)
1763 Function *func = link->data;
1766 !func->inside_dbus_build_tests)
1769 link = _dbus_list_get_next_link (&f->functions, link);
1775 printf ("Untested functions in %s\n", f->name);
1776 printf ("=======\n");
1778 link = _dbus_list_get_first_link (&f->functions);
1779 while (link != NULL)
1781 Function *func = link->data;
1784 !func->inside_dbus_build_tests)
1785 printf (" %s\n", func->name);
1787 link = _dbus_list_get_next_link (&f->functions, link);
1794 print_poorly_tested_functions (File *f,
1800 #define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
1802 #define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
1804 #define POORLY_TESTED(function) (!(function)->unused && \
1805 (function)->n_nontest_blocks > 0 && \
1806 TEST_FRACTION (function) < AVERAGE_COVERAGE)
1809 link = _dbus_list_get_first_link (&f->functions);
1810 while (link != NULL)
1812 Function *func = link->data;
1814 if (POORLY_TESTED (func))
1817 link = _dbus_list_get_next_link (&f->functions, link);
1823 printf ("Below average functions in %s\n", f->name);
1824 printf ("=======\n");
1826 link = _dbus_list_get_first_link (&f->functions);
1827 while (link != NULL)
1829 Function *func = link->data;
1831 if (POORLY_TESTED (func))
1832 printf (" %s (%d%%)\n", func->name,
1833 (int) (TEST_FRACTION (func) * 100));
1835 link = _dbus_list_get_next_link (&f->functions, link);
1842 func_cmp (const void *a,
1845 Function *af = *(Function**) a;
1846 Function *bf = *(Function**) b;
1847 int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
1848 int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
1850 /* Sort by number of untested blocks */
1851 return b_untested - a_untested;
1855 print_n_untested_blocks_by_function (File *f,
1864 link = _dbus_list_get_first_link (&f->functions);
1865 while (link != NULL)
1867 Function *func = link->data;
1869 if (func->n_nontest_blocks_executed <
1870 func->n_nontest_blocks)
1873 link = _dbus_list_get_next_link (&f->functions, link);
1879 /* make an array so we can use qsort */
1881 funcs = dbus_new (Function*, n_found);
1886 link = _dbus_list_get_first_link (&f->functions);
1887 while (link != NULL)
1889 Function *func = link->data;
1891 if (func->n_nontest_blocks_executed <
1892 func->n_nontest_blocks)
1898 link = _dbus_list_get_next_link (&f->functions, link);
1901 _dbus_assert (i == n_found);
1903 qsort (funcs, n_found, sizeof (Function*),
1906 printf ("Incomplete functions in %s\n", f->name);
1907 printf ("=======\n");
1912 Function *func = funcs[i];
1914 printf (" %s (%d/%d untested blocks)\n",
1916 func->n_nontest_blocks - func->n_nontest_blocks_executed,
1917 func->n_nontest_blocks);
1928 print_stats (Stats *stats,
1929 const char *of_what)
1933 printf ("Summary (%s)\n", of_what);
1934 printf ("=======\n");
1935 printf (" %g%% blocks executed (%d of %d)\n",
1936 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
1937 stats->n_blocks_executed,
1940 printf (" (ignored %d blocks of test-only/debug-only code)\n",
1941 stats->n_blocks_inside_dbus_build_tests);
1943 printf (" %g%% functions executed (%d of %d)\n",
1944 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
1945 stats->n_functions_executed,
1946 stats->n_functions);
1948 completely = stats->n_functions_executed - stats->n_functions_partial;
1949 printf (" %g%% functions completely executed (%d of %d)\n",
1950 (completely / (double) stats->n_functions) * 100.0,
1952 stats->n_functions);
1954 printf (" (ignored %d functions of test-only/debug-only code)\n",
1955 stats->n_functions_inside_dbus_build_tests);
1957 printf (" %g%% lines executed (%d of %d)\n",
1958 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
1959 stats->n_lines_executed,
1962 completely = stats->n_lines_executed - stats->n_lines_partial;
1963 printf (" %g%% lines completely executed (%d of %d)\n",
1964 (completely / (double) stats->n_lines) * 100.0,
1968 printf (" (ignored %d lines of test-only/debug-only code)\n",
1969 stats->n_lines_inside_dbus_build_tests);
1983 main (int argc, char **argv)
1985 DBusString filename;
1991 fprintf (stderr, "Must specify files on command line\n");
1998 if (strcmp (argv[i], "--report") == 0)
2003 else if (strcmp (argv[i], "--blocks") == 0)
2008 else if (strcmp (argv[i], "--gcov") == 0)
2017 fprintf (stderr, "Must specify files on command line\n");
2021 if (m == MODE_PRINT)
2025 _dbus_string_init_const (&filename, argv[i]);
2027 print_one_file (&filename);
2032 else if (m == MODE_BLOCKS || m == MODE_GCOV)
2038 _dbus_string_init_const (&filename, argv[i]);
2040 f = load_c_file (&filename);
2042 if (m == MODE_BLOCKS)
2043 print_block_superdetails (f);
2044 else if (m == MODE_GCOV)
2045 print_annotated_source_gcov_format (f);
2050 else if (m == MODE_REPORT)
2052 Stats stats = { 0, };
2055 DBusHashTable *stats_by_dir;
2061 _dbus_string_init_const (&filename, argv[i]);
2063 if (_dbus_string_ends_with_c_str (&filename, ".c"))
2067 f = load_c_file (&filename);
2069 if (!_dbus_list_append (&files, f))
2070 die ("no memory\n");
2074 fprintf (stderr, "Unknown file type %s\n",
2075 _dbus_string_get_const_data (&filename));
2082 link = _dbus_list_get_first_link (&files);
2083 while (link != NULL)
2085 File *f = link->data;
2087 merge_stats_for_file (&stats, f);
2089 link = _dbus_list_get_next_link (&files, link);
2092 print_stats (&stats, "all files");
2094 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
2095 dbus_free, dbus_free);
2097 link = _dbus_list_get_first_link (&files);
2098 while (link != NULL)
2100 File *f = link->data;
2105 _dbus_string_init_const (&filename, f->name);
2107 if (!_dbus_string_init (&dirname))
2108 die ("no memory\n");
2110 if (!_dbus_string_get_dirname (&filename, &dirname) ||
2111 !_dbus_string_copy_data (&dirname, &dirname_c))
2112 die ("no memory\n");
2114 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
2117 if (dir_stats == NULL)
2119 dir_stats = dbus_new0 (Stats, 1);
2120 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
2122 die ("no memory\n");
2125 dbus_free (dirname_c);
2127 merge_stats_for_file (dir_stats, f);
2129 link = _dbus_list_get_next_link (&files, link);
2132 _dbus_hash_iter_init (stats_by_dir, &iter);
2133 while (_dbus_hash_iter_next (&iter))
2135 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
2136 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
2138 print_stats (dir_stats, dirname);
2141 _dbus_hash_table_unref (stats_by_dir);
2143 link = _dbus_list_get_first_link (&files);
2144 while (link != NULL)
2146 File *f = link->data;
2148 print_untested_functions (f);
2150 link = _dbus_list_get_next_link (&files, link);
2153 link = _dbus_list_get_first_link (&files);
2154 while (link != NULL)
2156 File *f = link->data;
2158 print_poorly_tested_functions (f, &stats);
2160 link = _dbus_list_get_next_link (&files, link);
2163 link = _dbus_list_get_first_link (&files);
2164 while (link != NULL)
2166 File *f = link->data;
2168 print_n_untested_blocks_by_function (f, &stats);
2170 link = _dbus_list_get_next_link (&files, link);