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))
71 typedef DBUS_INT64_TYPE dbus_int64_t;
74 fetch_long64 (dbus_int64_t *dest,
78 dbus_int64_t value = 0;
81 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
82 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
86 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
88 if ((source[bytes - 1] & 128) && (value > 0))
95 #define BB_FILENAME (-1)
96 #define BB_FUNCTION (-2)
97 #define BB_ENDOFLIST 0
100 string_get_int (const DBusString *str,
106 if ((_dbus_string_get_length (str) - start) < 4)
109 p = _dbus_string_get_const_data (str);
113 fetch_long (val, p, 4);
119 string_get_int64 (const DBusString *str,
125 if ((_dbus_string_get_length (str) - start) < 8)
128 p = _dbus_string_get_const_data (str);
132 fetch_long64 (val, p, 8);
138 string_get_string (const DBusString *str,
148 while (string_get_int (str, i, &n))
155 _dbus_string_append_byte (val, n & 0xff);
156 _dbus_string_append_byte (val, (n >> 8) & 0xff);
157 _dbus_string_append_byte (val, (n >> 16) & 0xff);
158 _dbus_string_append_byte (val, (n >> 24) & 0xff);
167 dump_bb_file (const DBusString *contents)
175 while (string_get_int (contents, i, &val))
185 if (!_dbus_string_init (&f))
188 if (string_get_string (contents, i,
192 printf ("File %s\n", _dbus_string_get_const_data (&f));
194 _dbus_string_free (&f);
200 if (!_dbus_string_init (&f))
203 if (string_get_string (contents, i,
207 printf ("Function %s\n", _dbus_string_get_const_data (&f));
209 _dbus_string_free (&f);
215 printf ("End of block\n");
218 printf ("Line %ld\n", val);
223 printf ("%d functions in file\n", n_functions);
226 #define FLAG_ON_TREE 0x1
227 #define FLAG_FAKE 0x2
228 #define FLAG_FALL_THROUGH 0x4
231 dump_bbg_file (const DBusString *contents)
245 while (string_get_int (contents, i, &val))
247 long n_blocks_in_func;
251 n_blocks_in_func = val;
255 if (!string_get_int (contents, i, &n_arcs_in_func))
260 printf ("Function has %ld blocks and %ld arcs\n",
261 n_blocks_in_func, n_arcs_in_func);
264 n_blocks += n_blocks_in_func;
265 n_arcs += n_arcs_in_func;
268 while (j < n_blocks_in_func)
270 long n_arcs_in_block;
273 if (!string_get_int (contents, i, &n_arcs_in_block))
278 printf (" Block has %ld arcs\n", n_arcs_in_block);
281 while (k < n_arcs_in_block)
283 long destination_block;
286 if (!string_get_int (contents, i, &destination_block))
291 if (!string_get_int (contents, i, &flags))
296 printf (" Arc has destination block %ld flags 0x%lx\n",
297 destination_block, flags);
299 if ((flags & FLAG_ON_TREE) == 0)
300 n_arcs_off_tree += 1;
305 if (k < n_arcs_in_block)
311 if (j < n_blocks_in_func)
314 if (!string_get_int (contents, i, &val))
320 die ("-1 separator not found\n");
323 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
324 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
327 /* The da file contains first a count of arcs in the file,
328 * then a count of executions for all "off tree" arcs
332 dump_da_file (const DBusString *contents)
340 if (!string_get_int64 (contents, i, &val))
345 printf ("%ld arcs in file\n", (long) val);
346 claimed_n_arcs = val;
349 while (string_get_int64 (contents, i, &val))
353 printf ("%ld executions of arc %d\n",
359 if (n_arcs != claimed_n_arcs)
361 printf ("File claimed to have %d arcs but only had %d\n",
362 claimed_n_arcs, n_arcs);
366 typedef struct Arc Arc;
367 typedef struct Block Block;
368 typedef struct Function Function;
369 typedef struct File File;
370 typedef struct Line Line;
376 dbus_int64_t arc_count;
377 unsigned int count_valid : 1;
378 unsigned int on_tree : 1;
379 unsigned int fake : 1;
380 unsigned int fall_through : 1;
389 dbus_int64_t succ_count;
390 dbus_int64_t pred_count;
391 dbus_int64_t exec_count;
393 unsigned int count_valid : 1;
394 unsigned int on_tree : 1;
395 unsigned int inside_dbus_build_tests : 1;
403 /* number of blocks in DBUS_BUILD_TESTS */
405 int n_test_blocks_executed;
406 /* number of blocks outside DBUS_BUILD_TESTS */
407 int n_nontest_blocks;
408 int n_nontest_blocks_executed;
409 /* Summary result flags */
410 unsigned int unused : 1;
411 unsigned int inside_dbus_build_tests : 1;
412 unsigned int partial : 1; /* only some of the blocks were executed */
420 unsigned int inside_dbus_build_tests : 1;
421 unsigned int partial : 1; /* only some of the blocks were executed */
433 function_add_arc (Function *function,
440 arc = dbus_new0 (Arc, 1);
444 arc->target = target;
445 arc->source = source;
447 arc->succ_next = function->block_graph[source].succ;
448 function->block_graph[source].succ = arc;
449 function->block_graph[source].succ_count += 1;
451 arc->pred_next = function->block_graph[target].pred;
452 function->block_graph[target].pred = arc;
453 function->block_graph[target].pred_count += 1;
455 if ((flags & FLAG_ON_TREE) != 0)
458 if ((flags & FLAG_FAKE) != 0)
461 if ((flags & FLAG_FALL_THROUGH) != 0)
462 arc->fall_through = TRUE;
467 reverse_arcs (Arc *arc)
469 struct Arc *prev = 0;
472 for ( ; arc; arc = next)
474 next = arc->succ_next;
475 arc->succ_next = prev;
483 function_reverse_succ_arcs (Function *func)
485 /* Must reverse the order of all succ arcs, to ensure that they match
486 * the order of the data in the .da file.
490 for (i = 0; i < func->n_blocks; i++)
491 if (func->block_graph[i].succ)
492 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
496 get_functions_from_bbg (const DBusString *contents,
497 DBusList **functions)
507 printf ("Loading arcs and blocks from .bbg file\n");
515 while (string_get_int (contents, i, &val))
518 long n_blocks_in_func;
522 n_blocks_in_func = val;
526 if (!string_get_int (contents, i, &n_arcs_in_func))
532 n_blocks += n_blocks_in_func;
533 n_arcs += n_arcs_in_func;
535 func = dbus_new0 (Function, 1);
539 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
540 func->n_blocks = n_blocks_in_func;
543 while (j < n_blocks_in_func)
545 long n_arcs_in_block;
548 if (!string_get_int (contents, i, &n_arcs_in_block))
554 while (k < n_arcs_in_block)
556 long destination_block;
559 if (!string_get_int (contents, i, &destination_block))
564 if (!string_get_int (contents, i, &flags))
569 if ((flags & FLAG_ON_TREE) == 0)
570 n_arcs_off_tree += 1;
572 function_add_arc (func, j, destination_block,
578 if (k < n_arcs_in_block)
584 if (j < n_blocks_in_func)
587 function_reverse_succ_arcs (func);
589 if (!_dbus_list_append (functions, func))
592 if (!string_get_int (contents, i, &val))
598 die ("-1 separator not found\n");
602 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
603 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
606 _dbus_assert (n_functions == _dbus_list_get_length (functions));
610 add_counts_from_da (const DBusString *contents,
611 DBusList **functions)
618 Function *current_func;
623 printf ("Loading execution count for each arc from .da file\n");
627 if (!string_get_int64 (contents, i, &val))
632 claimed_n_arcs = val;
634 link = _dbus_list_get_first_link (functions);
638 current_func = link->data;
640 current_arc = current_func->block_graph[current_block].succ;
643 while (string_get_int64 (contents, i, &val))
647 while (current_arc == NULL ||
648 current_arc->on_tree)
650 if (current_arc == NULL)
654 if (current_block == current_func->n_blocks)
656 link = _dbus_list_get_next_link (functions, link);
659 fprintf (stderr, "Ran out of functions loading .da file\n");
662 current_func = link->data;
666 current_arc = current_func->block_graph[current_block].succ;
670 current_arc = current_arc->succ_next;
674 _dbus_assert (current_arc != NULL);
675 _dbus_assert (!current_arc->on_tree);
677 current_arc->arc_count = val;
678 current_arc->count_valid = TRUE;
679 current_func->block_graph[current_block].succ_count -= 1;
680 current_func->block_graph[current_arc->target].pred_count -= 1;
684 current_arc = current_arc->succ_next;
689 if (n_arcs != claimed_n_arcs)
691 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
692 claimed_n_arcs, n_arcs);
697 printf ("%d arcs in file\n", n_arcs);
702 function_solve_graph (Function *func)
712 printf ("Solving function graph\n");
715 n_blocks = func->n_blocks;
716 block_graph = func->block_graph;
718 /* For every block in the file,
719 - if every exit/entrance arc has a known count, then set the block count
720 - if the block count is known, and every exit/entrance arc but one has
721 a known execution count, then set the count of the remaining arc
723 As arc counts are set, decrement the succ/pred count, but don't delete
724 the arc, that way we can easily tell when all arcs are known, or only
725 one arc is unknown. */
727 /* The order that the basic blocks are iterated through is important.
728 Since the code that finds spanning trees starts with block 0, low numbered
729 arcs are put on the spanning tree in preference to high numbered arcs.
730 Hence, most instrumented arcs are at the end. Graph solving works much
731 faster if we propagate numbers from the end to the start.
733 This takes an average of slightly more than 3 passes. */
742 for (i = n_blocks - 1; i >= 0; i--)
744 if (! block_graph[i].count_valid)
746 if (block_graph[i].succ_count == 0)
749 for (arc = block_graph[i].succ; arc;
750 arc = arc->succ_next)
751 total += arc->arc_count;
752 block_graph[i].exec_count = total;
753 block_graph[i].count_valid = 1;
756 else if (block_graph[i].pred_count == 0)
759 for (arc = block_graph[i].pred; arc;
760 arc = arc->pred_next)
761 total += arc->arc_count;
762 block_graph[i].exec_count = total;
763 block_graph[i].count_valid = 1;
767 if (block_graph[i].count_valid)
769 if (block_graph[i].succ_count == 1)
772 /* One of the counts will be invalid, but it is zero,
773 so adding it in also doesn't hurt. */
774 for (arc = block_graph[i].succ; arc;
775 arc = arc->succ_next)
776 total += arc->arc_count;
777 /* Calculate count for remaining arc by conservation. */
778 total = block_graph[i].exec_count - total;
779 /* Search for the invalid arc, and set its count. */
780 for (arc = block_graph[i].succ; arc;
781 arc = arc->succ_next)
782 if (! arc->count_valid)
785 die ("arc == NULL\n");
786 arc->count_valid = 1;
787 arc->arc_count = total;
788 block_graph[i].succ_count -= 1;
790 block_graph[arc->target].pred_count -= 1;
793 if (block_graph[i].pred_count == 1)
796 /* One of the counts will be invalid, but it is zero,
797 so adding it in also doesn't hurt. */
798 for (arc = block_graph[i].pred; arc;
799 arc = arc->pred_next)
800 total += arc->arc_count;
801 /* Calculate count for remaining arc by conservation. */
802 total = block_graph[i].exec_count - total;
803 /* Search for the invalid arc, and set its count. */
804 for (arc = block_graph[i].pred; arc;
805 arc = arc->pred_next)
806 if (! arc->count_valid)
809 die ("arc == NULL\n");
810 arc->count_valid = 1;
811 arc->arc_count = total;
812 block_graph[i].pred_count -= 1;
814 block_graph[arc->source].succ_count -= 1;
821 /* If the graph has been correctly solved, every block will have a
822 * succ and pred count of zero.
824 for (i = 0; i < n_blocks; i++)
826 if (block_graph[i].succ_count || block_graph[i].pred_count)
828 fprintf (stderr, "Block graph solved incorrectly\n");
829 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
830 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
837 solve_graphs (DBusList **functions)
841 link = _dbus_list_get_first_link (functions);
844 Function *func = link->data;
846 function_solve_graph (func);
848 link = _dbus_list_get_next_link (functions, link);
853 load_functions_for_c_file (const DBusString *filename,
854 DBusList **functions)
856 DBusString bbg_filename;
857 DBusString da_filename;
861 dbus_error_init (&error);
863 if (!_dbus_string_init (&bbg_filename) ||
864 !_dbus_string_init (&da_filename) ||
865 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
866 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
867 !_dbus_string_init (&contents))
870 _dbus_string_shorten (&bbg_filename, 2);
871 _dbus_string_shorten (&da_filename, 2);
873 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
874 !_dbus_string_append (&da_filename, ".da"))
877 if (!_dbus_file_get_contents (&contents, &bbg_filename,
880 fprintf (stderr, "Could not open file: %s\n",
885 get_functions_from_bbg (&contents, functions);
887 _dbus_string_set_length (&contents, 0);
889 if (!_dbus_file_get_contents (&contents, &da_filename,
892 fprintf (stderr, "Could not open file: %s\n",
897 add_counts_from_da (&contents, functions);
899 solve_graphs (functions);
901 _dbus_string_free (&contents);
902 _dbus_string_free (&da_filename);
903 _dbus_string_free (&bbg_filename);
907 get_lines_from_bb_file (const DBusString *contents,
913 dbus_bool_t in_our_file;
919 printf ("Getting line numbers for blocks from .bb file\n");
922 /* There's this "filename" field in the .bb file which
923 * mysteriously comes *after* the first function in the
924 * file in the .bb file; and every .bb file seems to
925 * have only one filename. I don't understand
926 * what's going on here, so just set in_our_file = TRUE
927 * at the start categorically.
933 link = _dbus_list_get_first_link (&fl->functions);
936 while (string_get_int (contents, i, &val))
946 if (!_dbus_string_init (&f))
949 if (string_get_string (contents, i,
953 /* fl->name is a full path and the filename in .bb is
958 _dbus_string_init_const (&tmp_str, fl->name);
960 if (_dbus_string_ends_with_c_str (&tmp_str,
961 _dbus_string_get_const_data (&f)))
968 "File %s in .bb, looking for %s, in_our_file = %d\n",
969 _dbus_string_get_const_data (&f),
974 _dbus_string_free (&f);
980 if (!_dbus_string_init (&f))
983 if (string_get_string (contents, i,
988 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
997 fprintf (stderr, "No function object for function %s\n",
998 _dbus_string_get_const_data (&f));
1003 link = _dbus_list_get_next_link (&fl->functions, link);
1005 if (func->name == NULL)
1007 if (!_dbus_string_copy_data (&f, &func->name))
1008 die ("no memory\n");
1012 die ("got two names for function?\n");
1017 _dbus_string_free (&f);
1027 fprintf (stderr, "Line %ld\n", val);
1030 if (val >= fl->n_lines)
1032 fprintf (stderr, "Line %ld but file only has %d lines\n",
1035 else if (func != NULL)
1037 val -= 1; /* To convert the 1-based line number to 0-based */
1038 _dbus_assert (val >= 0);
1040 if (block < func->n_blocks)
1042 if (!_dbus_list_append (&func->block_graph[block].lines,
1044 die ("no memory\n");
1047 if (!_dbus_list_append (&fl->lines[val].blocks,
1048 &func->block_graph[block]))
1049 die ("no memory\n");
1053 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1054 block, func->n_blocks);
1059 fprintf (stderr, "Line %ld given outside of any function\n",
1068 printf ("%d functions in file\n", n_functions);
1074 load_block_line_associations (const DBusString *filename,
1077 DBusString bb_filename;
1078 DBusString contents;
1081 dbus_error_init (&error);
1083 if (!_dbus_string_init (&bb_filename) ||
1084 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1085 !_dbus_string_init (&contents))
1086 die ("no memory\n");
1088 _dbus_string_shorten (&bb_filename, 2);
1090 if (!_dbus_string_append (&bb_filename, ".bb"))
1091 die ("no memory\n");
1093 if (!_dbus_file_get_contents (&contents, &bb_filename,
1096 fprintf (stderr, "Could not open file: %s\n",
1101 get_lines_from_bb_file (&contents, f);
1103 _dbus_string_free (&contents);
1104 _dbus_string_free (&bb_filename);
1108 count_lines_in_string (const DBusString *str)
1114 const char *last_line_end;
1117 printf ("Counting lines in source file\n");
1122 p = _dbus_string_get_const_data (str);
1123 end = p + _dbus_string_get_length (str);
1127 /* too lazy to handle \r\n as one linebreak */
1128 if (*p == '\n' || *p == '\r')
1131 last_line_end = p + 1;
1138 if (last_line_end != p)
1145 fill_line_content (const DBusString *str,
1152 const char *last_line_end;
1155 printf ("Saving contents of each line in source file\n");
1160 p = _dbus_string_get_const_data (str);
1161 end = p + _dbus_string_get_length (str);
1165 if (*p == '\n' || *p == '\r')
1167 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1168 if (lines[n_lines].text == NULL)
1169 die ("no memory\n");
1171 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1172 lines[n_lines].number = n_lines + 1;
1176 last_line_end = p + 1;
1183 if (p != last_line_end)
1185 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1191 mark_inside_dbus_build_tests (File *f)
1199 while (i < f->n_lines)
1201 Line *l = &f->lines[i];
1203 if (inside_depth == 0)
1207 a = strstr (l->text, "#ifdef");
1208 b = strstr (l->text, "DBUS_BUILD_TESTS");
1214 if (strstr (l->text, "#if") != NULL)
1216 else if (strstr (l->text, "#endif") != NULL)
1220 if (inside_depth > 0)
1222 /* Mark the line and its blocks */
1225 l->inside_dbus_build_tests = TRUE;
1227 blink = _dbus_list_get_first_link (&l->blocks);
1228 while (blink != NULL)
1230 Block *b = blink->data;
1232 b->inside_dbus_build_tests = TRUE;
1234 blink = _dbus_list_get_next_link (&l->blocks, blink);
1241 /* Now mark functions where for all blocks that are associated
1242 * with a source line, the block is inside_dbus_build_tests.
1244 link = _dbus_list_get_first_link (&f->functions);
1245 while (link != NULL)
1247 Function *func = link->data;
1250 while (i < func->n_blocks)
1252 /* Break as soon as any block is not a test block */
1253 if (func->block_graph[i].lines != NULL &&
1254 !func->block_graph[i].inside_dbus_build_tests)
1260 if (i == func->n_blocks)
1261 func->inside_dbus_build_tests = TRUE;
1263 link = _dbus_list_get_next_link (&f->functions, link);
1268 mark_coverage (File *f)
1274 while (i < f->n_lines)
1276 Line *l = &f->lines[i];
1279 int n_blocks_executed;
1282 n_blocks_executed = 0;
1283 blink = _dbus_list_get_first_link (&l->blocks);
1284 while (blink != NULL)
1286 Block *b = blink->data;
1288 if (b->exec_count > 0)
1289 n_blocks_executed += 1;
1293 blink = _dbus_list_get_next_link (&l->blocks, blink);
1296 if (n_blocks_executed > 0 &&
1297 n_blocks_executed < n_blocks)
1303 link = _dbus_list_get_first_link (&f->functions);
1304 while (link != NULL)
1306 Function *func = link->data;
1309 int n_test_blocks_executed;
1310 int n_nontest_blocks;
1311 int n_nontest_blocks_executed;
1314 n_test_blocks_executed = 0;
1315 n_nontest_blocks = 0;
1316 n_nontest_blocks_executed = 0;
1319 while (i < func->n_blocks)
1321 if (!func->block_graph[i].inside_dbus_build_tests)
1323 n_nontest_blocks += 1;
1325 if (func->block_graph[i].exec_count > 0)
1326 n_nontest_blocks_executed += 1;
1332 if (func->block_graph[i].exec_count > 0)
1333 n_test_blocks_executed += 1;
1339 if (n_nontest_blocks_executed > 0 &&
1340 n_nontest_blocks_executed < n_nontest_blocks)
1341 func->partial = TRUE;
1343 if (n_nontest_blocks_executed == 0 &&
1344 n_nontest_blocks > 0)
1345 func->unused = TRUE;
1347 func->n_test_blocks = n_test_blocks;
1348 func->n_test_blocks_executed = n_test_blocks_executed;
1349 func->n_nontest_blocks = n_nontest_blocks;
1350 func->n_nontest_blocks_executed = n_nontest_blocks_executed;
1352 link = _dbus_list_get_next_link (&f->functions, link);
1357 load_c_file (const DBusString *filename)
1359 DBusString contents;
1363 f = dbus_new0 (File, 1);
1365 die ("no memory\n");
1367 if (!_dbus_string_copy_data (filename, &f->name))
1368 die ("no memory\n");
1370 if (!_dbus_string_init (&contents))
1371 die ("no memory\n");
1373 dbus_error_init (&error);
1375 if (!_dbus_file_get_contents (&contents, filename,
1378 fprintf (stderr, "Could not open file: %s\n",
1380 dbus_error_free (&error);
1384 load_functions_for_c_file (filename, &f->functions);
1386 f->n_lines = count_lines_in_string (&contents);
1387 f->lines = dbus_new0 (Line, f->n_lines);
1388 if (f->lines == NULL)
1389 die ("no memory\n");
1391 fill_line_content (&contents, f->lines);
1393 _dbus_string_free (&contents);
1395 load_block_line_associations (filename, f);
1397 mark_inside_dbus_build_tests (f);
1403 typedef struct Stats Stats;
1408 int n_blocks_executed;
1409 int n_blocks_inside_dbus_build_tests;
1411 int n_lines; /* lines that have blocks on them */
1412 int n_lines_executed;
1413 int n_lines_partial;
1414 int n_lines_inside_dbus_build_tests;
1417 int n_functions_executed;
1418 int n_functions_partial;
1419 int n_functions_inside_dbus_build_tests;
1423 line_was_executed (Line *l)
1427 link = _dbus_list_get_first_link (&l->blocks);
1428 while (link != NULL)
1430 Block *b = link->data;
1432 if (b->exec_count > 0)
1435 link = _dbus_list_get_next_link (&l->blocks, link);
1443 line_exec_count (Line *l)
1449 link = _dbus_list_get_first_link (&l->blocks);
1450 while (link != NULL)
1452 Block *b = link->data;
1454 total += b->exec_count;
1456 link = _dbus_list_get_next_link (&l->blocks, link);
1463 merge_stats_for_file (Stats *stats,
1469 for (i = 0; i < f->n_lines; ++i)
1471 Line *l = &f->lines[i];
1473 if (l->inside_dbus_build_tests)
1475 stats->n_lines_inside_dbus_build_tests += 1;
1479 if (line_was_executed (l))
1480 stats->n_lines_executed += 1;
1482 if (l->blocks != NULL)
1483 stats->n_lines += 1;
1486 stats->n_lines_partial += 1;
1489 link = _dbus_list_get_first_link (&f->functions);
1490 while (link != NULL)
1492 Function *func = link->data;
1494 if (func->inside_dbus_build_tests)
1495 stats->n_functions_inside_dbus_build_tests += 1;
1498 stats->n_functions += 1;
1501 stats->n_functions_executed += 1;
1504 stats->n_functions_partial += 1;
1507 stats->n_blocks_inside_dbus_build_tests +=
1508 func->n_test_blocks;
1510 stats->n_blocks_executed +=
1511 func->n_nontest_blocks_executed;
1514 func->n_nontest_blocks;
1516 link = _dbus_list_get_next_link (&f->functions, link);
1520 /* The output of this matches gcov exactly ("diff" shows no difference) */
1522 print_annotated_source_gcov_format (File *f)
1527 while (i < f->n_lines)
1529 Line *l = &f->lines[i];
1531 if (l->blocks != NULL)
1535 exec_count = line_exec_count (l);
1538 printf ("%12d %s\n",
1539 exec_count, l->text);
1541 printf (" ###### %s\n", l->text);
1545 printf ("\t\t%s\n", l->text);
1553 print_annotated_source (File *f)
1558 while (i < f->n_lines)
1560 Line *l = &f->lines[i];
1562 if (l->inside_dbus_build_tests)
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_block_superdetails (File *f)
1594 link = _dbus_list_get_first_link (&f->functions);
1595 while (link != NULL)
1597 Function *func = link->data;
1599 printf ("=== %s():\n", func->name);
1602 while (i < func->n_blocks)
1604 Block *b = &func->block_graph[i];
1607 printf (" %5d executed %d times%s\n", i,
1608 (int) b->exec_count,
1609 b->inside_dbus_build_tests ?
1610 " [inside DBUS_BUILD_TESTS]" : "");
1612 l = _dbus_list_get_first_link (&b->lines);
1615 Line *line = l->data;
1617 printf ("4%d\t%s\n", line->number, line->text);
1619 l = _dbus_list_get_next_link (&b->lines, l);
1625 link = _dbus_list_get_next_link (&f->functions, link);
1630 print_one_file (const DBusString *filename)
1632 if (_dbus_string_ends_with_c_str (filename, ".bb"))
1634 DBusString contents;
1637 if (!_dbus_string_init (&contents))
1638 die ("no memory\n");
1640 dbus_error_init (&error);
1642 if (!_dbus_file_get_contents (&contents, filename,
1645 fprintf (stderr, "Could not open file: %s\n",
1647 dbus_error_free (&error);
1651 dump_bb_file (&contents);
1653 _dbus_string_free (&contents);
1655 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
1657 DBusString contents;
1660 if (!_dbus_string_init (&contents))
1661 die ("no memory\n");
1663 dbus_error_init (&error);
1665 if (!_dbus_file_get_contents (&contents, filename,
1668 fprintf (stderr, "Could not open file: %s\n",
1670 dbus_error_free (&error);
1674 dump_bbg_file (&contents);
1676 _dbus_string_free (&contents);
1678 else if (_dbus_string_ends_with_c_str (filename, ".da"))
1680 DBusString contents;
1683 if (!_dbus_string_init (&contents))
1684 die ("no memory\n");
1686 dbus_error_init (&error);
1688 if (!_dbus_file_get_contents (&contents, filename,
1691 fprintf (stderr, "Could not open file: %s\n",
1693 dbus_error_free (&error);
1697 dump_da_file (&contents);
1699 _dbus_string_free (&contents);
1701 else if (_dbus_string_ends_with_c_str (filename, ".c"))
1705 f = load_c_file (filename);
1707 print_annotated_source (f);
1711 fprintf (stderr, "Unknown file type %s\n",
1712 _dbus_string_get_const_data (filename));
1718 print_untested_functions (File *f)
1724 link = _dbus_list_get_first_link (&f->functions);
1725 while (link != NULL)
1727 Function *func = link->data;
1730 !func->inside_dbus_build_tests)
1733 link = _dbus_list_get_next_link (&f->functions, link);
1739 printf ("Untested functions in %s\n", f->name);
1740 printf ("=======\n");
1742 link = _dbus_list_get_first_link (&f->functions);
1743 while (link != NULL)
1745 Function *func = link->data;
1748 !func->inside_dbus_build_tests)
1749 printf (" %s\n", func->name);
1751 link = _dbus_list_get_next_link (&f->functions, link);
1758 print_poorly_tested_functions (File *f,
1764 #define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
1766 #define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
1768 #define POORLY_TESTED(function) (!(function)->unused && \
1769 (function)->n_nontest_blocks > 0 && \
1770 TEST_FRACTION (function) < AVERAGE_COVERAGE)
1773 link = _dbus_list_get_first_link (&f->functions);
1774 while (link != NULL)
1776 Function *func = link->data;
1778 if (POORLY_TESTED (func))
1781 link = _dbus_list_get_next_link (&f->functions, link);
1787 printf ("Below average functions in %s\n", f->name);
1788 printf ("=======\n");
1790 link = _dbus_list_get_first_link (&f->functions);
1791 while (link != NULL)
1793 Function *func = link->data;
1795 if (POORLY_TESTED (func))
1796 printf (" %s (%d%%)\n", func->name,
1797 (int) (TEST_FRACTION (func) * 100));
1799 link = _dbus_list_get_next_link (&f->functions, link);
1806 print_stats (Stats *stats,
1807 const char *of_what)
1811 printf ("Summary (%s)\n", of_what);
1812 printf ("=======\n");
1813 printf (" %g%% blocks executed (%d of %d)\n",
1814 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
1815 stats->n_blocks_executed,
1818 printf (" (ignored %d blocks inside DBUS_BUILD_TESTS)\n",
1819 stats->n_blocks_inside_dbus_build_tests);
1821 printf (" %g%% functions executed (%d of %d)\n",
1822 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
1823 stats->n_functions_executed,
1824 stats->n_functions);
1826 completely = stats->n_functions_executed - stats->n_functions_partial;
1827 printf (" %g%% functions completely executed (%d of %d)\n",
1828 (completely / (double) stats->n_functions) * 100.0,
1830 stats->n_functions);
1832 printf (" (ignored %d functions inside DBUS_BUILD_TESTS)\n",
1833 stats->n_functions_inside_dbus_build_tests);
1835 printf (" %g%% lines executed (%d of %d)\n",
1836 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
1837 stats->n_lines_executed,
1840 completely = stats->n_lines_executed - stats->n_lines_partial;
1841 printf (" %g%% lines completely executed (%d of %d)\n",
1842 (completely / (double) stats->n_lines) * 100.0,
1846 printf (" (ignored %d lines inside DBUS_BUILD_TESTS)\n",
1847 stats->n_lines_inside_dbus_build_tests);
1861 main (int argc, char **argv)
1863 DBusString filename;
1869 fprintf (stderr, "Must specify files on command line\n");
1876 if (strcmp (argv[i], "--report") == 0)
1881 else if (strcmp (argv[i], "--blocks") == 0)
1886 else if (strcmp (argv[i], "--gcov") == 0)
1895 fprintf (stderr, "Must specify files on command line\n");
1899 if (m == MODE_PRINT)
1903 _dbus_string_init_const (&filename, argv[i]);
1905 print_one_file (&filename);
1910 else if (m == MODE_BLOCKS || m == MODE_GCOV)
1916 _dbus_string_init_const (&filename, argv[i]);
1918 f = load_c_file (&filename);
1920 if (m == MODE_BLOCKS)
1921 print_block_superdetails (f);
1922 else if (m == MODE_GCOV)
1923 print_annotated_source_gcov_format (f);
1928 else if (m == MODE_REPORT)
1930 Stats stats = { 0, };
1933 DBusHashTable *stats_by_dir;
1939 _dbus_string_init_const (&filename, argv[i]);
1941 if (_dbus_string_ends_with_c_str (&filename, ".c"))
1945 f = load_c_file (&filename);
1947 if (!_dbus_list_append (&files, f))
1948 die ("no memory\n");
1952 fprintf (stderr, "Unknown file type %s\n",
1953 _dbus_string_get_const_data (&filename));
1960 link = _dbus_list_get_first_link (&files);
1961 while (link != NULL)
1963 File *f = link->data;
1965 merge_stats_for_file (&stats, f);
1967 link = _dbus_list_get_next_link (&files, link);
1970 print_stats (&stats, "all files");
1972 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
1973 dbus_free, dbus_free);
1975 link = _dbus_list_get_first_link (&files);
1976 while (link != NULL)
1978 File *f = link->data;
1983 _dbus_string_init_const (&filename, f->name);
1985 if (!_dbus_string_init (&dirname))
1986 die ("no memory\n");
1988 if (!_dbus_string_get_dirname (&filename, &dirname) ||
1989 !_dbus_string_copy_data (&dirname, &dirname_c))
1990 die ("no memory\n");
1992 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
1995 if (dir_stats == NULL)
1997 dir_stats = dbus_new0 (Stats, 1);
1998 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
2000 die ("no memory\n");
2003 dbus_free (dirname_c);
2005 merge_stats_for_file (dir_stats, f);
2007 link = _dbus_list_get_next_link (&files, link);
2010 _dbus_hash_iter_init (stats_by_dir, &iter);
2011 while (_dbus_hash_iter_next (&iter))
2013 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
2014 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
2016 print_stats (dir_stats, dirname);
2019 _dbus_hash_table_unref (stats_by_dir);
2021 link = _dbus_list_get_first_link (&files);
2022 while (link != NULL)
2024 File *f = link->data;
2026 print_untested_functions (f);
2028 link = _dbus_list_get_next_link (&files, link);
2031 link = _dbus_list_get_first_link (&files);
2032 while (link != NULL)
2034 File *f = link->data;
2036 print_poorly_tested_functions (f, &stats);
2038 link = _dbus_list_get_next_link (&files, link);