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 unsigned int unused : 1;
404 unsigned int inside_dbus_build_tests : 1;
405 unsigned int partial : 1; /* only some of the blocks were executed */
413 unsigned int inside_dbus_build_tests : 1;
414 unsigned int partial : 1; /* only some of the blocks were executed */
426 function_add_arc (Function *function,
433 arc = dbus_new0 (Arc, 1);
437 arc->target = target;
438 arc->source = source;
440 arc->succ_next = function->block_graph[source].succ;
441 function->block_graph[source].succ = arc;
442 function->block_graph[source].succ_count += 1;
444 arc->pred_next = function->block_graph[target].pred;
445 function->block_graph[target].pred = arc;
446 function->block_graph[target].pred_count += 1;
448 if ((flags & FLAG_ON_TREE) != 0)
451 if ((flags & FLAG_FAKE) != 0)
454 if ((flags & FLAG_FALL_THROUGH) != 0)
455 arc->fall_through = TRUE;
460 reverse_arcs (Arc *arc)
462 struct Arc *prev = 0;
465 for ( ; arc; arc = next)
467 next = arc->succ_next;
468 arc->succ_next = prev;
476 function_reverse_succ_arcs (Function *func)
478 /* Must reverse the order of all succ arcs, to ensure that they match
479 * the order of the data in the .da file.
483 for (i = 0; i < func->n_blocks; i++)
484 if (func->block_graph[i].succ)
485 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
489 get_functions_from_bbg (const DBusString *contents,
490 DBusList **functions)
500 printf ("Loading arcs and blocks from .bbg file\n");
508 while (string_get_int (contents, i, &val))
511 long n_blocks_in_func;
515 n_blocks_in_func = val;
519 if (!string_get_int (contents, i, &n_arcs_in_func))
525 n_blocks += n_blocks_in_func;
526 n_arcs += n_arcs_in_func;
528 func = dbus_new0 (Function, 1);
532 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
533 func->n_blocks = n_blocks_in_func;
536 while (j < n_blocks_in_func)
538 long n_arcs_in_block;
541 if (!string_get_int (contents, i, &n_arcs_in_block))
547 while (k < n_arcs_in_block)
549 long destination_block;
552 if (!string_get_int (contents, i, &destination_block))
557 if (!string_get_int (contents, i, &flags))
562 if ((flags & FLAG_ON_TREE) == 0)
563 n_arcs_off_tree += 1;
565 function_add_arc (func, j, destination_block,
571 if (k < n_arcs_in_block)
577 if (j < n_blocks_in_func)
580 function_reverse_succ_arcs (func);
582 if (!_dbus_list_append (functions, func))
585 if (!string_get_int (contents, i, &val))
591 die ("-1 separator not found\n");
595 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
596 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
599 _dbus_assert (n_functions == _dbus_list_get_length (functions));
603 add_counts_from_da (const DBusString *contents,
604 DBusList **functions)
611 Function *current_func;
616 printf ("Loading execution count for each arc from .da file\n");
620 if (!string_get_int64 (contents, i, &val))
625 claimed_n_arcs = val;
627 link = _dbus_list_get_first_link (functions);
631 current_func = link->data;
633 current_arc = current_func->block_graph[current_block].succ;
636 while (string_get_int64 (contents, i, &val))
640 while (current_arc == NULL ||
641 current_arc->on_tree)
643 if (current_arc == NULL)
647 if (current_block == current_func->n_blocks)
649 link = _dbus_list_get_next_link (functions, link);
652 fprintf (stderr, "Ran out of functions loading .da file\n");
655 current_func = link->data;
659 current_arc = current_func->block_graph[current_block].succ;
663 current_arc = current_arc->succ_next;
667 _dbus_assert (current_arc != NULL);
668 _dbus_assert (!current_arc->on_tree);
670 current_arc->arc_count = val;
671 current_arc->count_valid = TRUE;
672 current_func->block_graph[current_block].succ_count -= 1;
673 current_func->block_graph[current_arc->target].pred_count -= 1;
677 current_arc = current_arc->succ_next;
682 if (n_arcs != claimed_n_arcs)
684 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
685 claimed_n_arcs, n_arcs);
690 printf ("%d arcs in file\n", n_arcs);
695 function_solve_graph (Function *func)
705 printf ("Solving function graph\n");
708 n_blocks = func->n_blocks;
709 block_graph = func->block_graph;
711 /* For every block in the file,
712 - if every exit/entrance arc has a known count, then set the block count
713 - if the block count is known, and every exit/entrance arc but one has
714 a known execution count, then set the count of the remaining arc
716 As arc counts are set, decrement the succ/pred count, but don't delete
717 the arc, that way we can easily tell when all arcs are known, or only
718 one arc is unknown. */
720 /* The order that the basic blocks are iterated through is important.
721 Since the code that finds spanning trees starts with block 0, low numbered
722 arcs are put on the spanning tree in preference to high numbered arcs.
723 Hence, most instrumented arcs are at the end. Graph solving works much
724 faster if we propagate numbers from the end to the start.
726 This takes an average of slightly more than 3 passes. */
735 for (i = n_blocks - 1; i >= 0; i--)
737 if (! block_graph[i].count_valid)
739 if (block_graph[i].succ_count == 0)
742 for (arc = block_graph[i].succ; arc;
743 arc = arc->succ_next)
744 total += arc->arc_count;
745 block_graph[i].exec_count = total;
746 block_graph[i].count_valid = 1;
749 else if (block_graph[i].pred_count == 0)
752 for (arc = block_graph[i].pred; arc;
753 arc = arc->pred_next)
754 total += arc->arc_count;
755 block_graph[i].exec_count = total;
756 block_graph[i].count_valid = 1;
760 if (block_graph[i].count_valid)
762 if (block_graph[i].succ_count == 1)
765 /* One of the counts will be invalid, but it is zero,
766 so adding it in also doesn't hurt. */
767 for (arc = block_graph[i].succ; arc;
768 arc = arc->succ_next)
769 total += arc->arc_count;
770 /* Calculate count for remaining arc by conservation. */
771 total = block_graph[i].exec_count - total;
772 /* Search for the invalid arc, and set its count. */
773 for (arc = block_graph[i].succ; arc;
774 arc = arc->succ_next)
775 if (! arc->count_valid)
778 die ("arc == NULL\n");
779 arc->count_valid = 1;
780 arc->arc_count = total;
781 block_graph[i].succ_count -= 1;
783 block_graph[arc->target].pred_count -= 1;
786 if (block_graph[i].pred_count == 1)
789 /* One of the counts will be invalid, but it is zero,
790 so adding it in also doesn't hurt. */
791 for (arc = block_graph[i].pred; arc;
792 arc = arc->pred_next)
793 total += arc->arc_count;
794 /* Calculate count for remaining arc by conservation. */
795 total = block_graph[i].exec_count - total;
796 /* Search for the invalid arc, and set its count. */
797 for (arc = block_graph[i].pred; arc;
798 arc = arc->pred_next)
799 if (! arc->count_valid)
802 die ("arc == NULL\n");
803 arc->count_valid = 1;
804 arc->arc_count = total;
805 block_graph[i].pred_count -= 1;
807 block_graph[arc->source].succ_count -= 1;
814 /* If the graph has been correctly solved, every block will have a
815 * succ and pred count of zero.
817 for (i = 0; i < n_blocks; i++)
819 if (block_graph[i].succ_count || block_graph[i].pred_count)
821 fprintf (stderr, "Block graph solved incorrectly\n");
822 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
823 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
830 solve_graphs (DBusList **functions)
834 link = _dbus_list_get_first_link (functions);
837 Function *func = link->data;
839 function_solve_graph (func);
841 link = _dbus_list_get_next_link (functions, link);
846 load_functions_for_c_file (const DBusString *filename,
847 DBusList **functions)
849 DBusString bbg_filename;
850 DBusString da_filename;
854 dbus_error_init (&error);
856 if (!_dbus_string_init (&bbg_filename) ||
857 !_dbus_string_init (&da_filename) ||
858 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
859 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
860 !_dbus_string_init (&contents))
863 _dbus_string_shorten (&bbg_filename, 2);
864 _dbus_string_shorten (&da_filename, 2);
866 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
867 !_dbus_string_append (&da_filename, ".da"))
870 if (!_dbus_file_get_contents (&contents, &bbg_filename,
873 fprintf (stderr, "Could not open file: %s\n",
878 get_functions_from_bbg (&contents, functions);
880 _dbus_string_set_length (&contents, 0);
882 if (!_dbus_file_get_contents (&contents, &da_filename,
885 fprintf (stderr, "Could not open file: %s\n",
890 add_counts_from_da (&contents, functions);
892 solve_graphs (functions);
894 _dbus_string_free (&contents);
895 _dbus_string_free (&da_filename);
896 _dbus_string_free (&bbg_filename);
900 get_lines_from_bb_file (const DBusString *contents,
906 dbus_bool_t in_our_file;
912 printf ("Getting line numbers for blocks from .bb file\n");
915 /* There's this "filename" field in the .bb file which
916 * mysteriously comes *after* the first function in the
917 * file in the .bb file; and every .bb file seems to
918 * have only one filename. I don't understand
919 * what's going on here, so just set in_our_file = TRUE
920 * at the start categorically.
926 link = _dbus_list_get_first_link (&fl->functions);
929 while (string_get_int (contents, i, &val))
939 if (!_dbus_string_init (&f))
942 if (string_get_string (contents, i,
946 /* fl->name is a full path and the filename in .bb is
951 _dbus_string_init_const (&tmp_str, fl->name);
953 if (_dbus_string_ends_with_c_str (&tmp_str,
954 _dbus_string_get_const_data (&f)))
961 "File %s in .bb, looking for %s, in_our_file = %d\n",
962 _dbus_string_get_const_data (&f),
967 _dbus_string_free (&f);
973 if (!_dbus_string_init (&f))
976 if (string_get_string (contents, i,
981 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
990 fprintf (stderr, "No function object for function %s\n",
991 _dbus_string_get_const_data (&f));
996 link = _dbus_list_get_next_link (&fl->functions, link);
998 if (func->name == NULL)
1000 if (!_dbus_string_copy_data (&f, &func->name))
1001 die ("no memory\n");
1005 die ("got two names for function?\n");
1010 _dbus_string_free (&f);
1020 fprintf (stderr, "Line %ld\n", val);
1023 if (val >= fl->n_lines)
1025 fprintf (stderr, "Line %ld but file only has %d lines\n",
1028 else if (func != NULL)
1030 val -= 1; /* To convert the 1-based line number to 0-based */
1031 _dbus_assert (val >= 0);
1033 if (block < func->n_blocks)
1035 if (!_dbus_list_append (&func->block_graph[block].lines,
1037 die ("no memory\n");
1040 if (!_dbus_list_append (&fl->lines[val].blocks,
1041 &func->block_graph[block]))
1042 die ("no memory\n");
1046 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1047 block, func->n_blocks);
1052 fprintf (stderr, "Line %ld given outside of any function\n",
1061 printf ("%d functions in file\n", n_functions);
1067 load_block_line_associations (const DBusString *filename,
1070 DBusString bb_filename;
1071 DBusString contents;
1074 dbus_error_init (&error);
1076 if (!_dbus_string_init (&bb_filename) ||
1077 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1078 !_dbus_string_init (&contents))
1079 die ("no memory\n");
1081 _dbus_string_shorten (&bb_filename, 2);
1083 if (!_dbus_string_append (&bb_filename, ".bb"))
1084 die ("no memory\n");
1086 if (!_dbus_file_get_contents (&contents, &bb_filename,
1089 fprintf (stderr, "Could not open file: %s\n",
1094 get_lines_from_bb_file (&contents, f);
1096 _dbus_string_free (&contents);
1097 _dbus_string_free (&bb_filename);
1101 count_lines_in_string (const DBusString *str)
1107 const char *last_line_end;
1110 printf ("Counting lines in source file\n");
1115 p = _dbus_string_get_const_data (str);
1116 end = p + _dbus_string_get_length (str);
1120 /* too lazy to handle \r\n as one linebreak */
1121 if (*p == '\n' || *p == '\r')
1124 last_line_end = p + 1;
1131 if (last_line_end != p)
1138 fill_line_content (const DBusString *str,
1145 const char *last_line_end;
1148 printf ("Saving contents of each line in source file\n");
1153 p = _dbus_string_get_const_data (str);
1154 end = p + _dbus_string_get_length (str);
1158 if (*p == '\n' || *p == '\r')
1160 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1161 if (lines[n_lines].text == NULL)
1162 die ("no memory\n");
1164 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1165 lines[n_lines].number = n_lines + 1;
1169 last_line_end = p + 1;
1176 if (p != last_line_end)
1178 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1184 mark_unused_functions (File *f)
1189 link = _dbus_list_get_first_link (&f->functions);
1190 while (link != NULL)
1192 Function *func = link->data;
1197 while (i < func->n_blocks)
1199 if (func->block_graph[i].exec_count > 0)
1206 func->unused = TRUE;
1208 link = _dbus_list_get_next_link (&f->functions, link);
1213 mark_inside_dbus_build_tests (File *f)
1221 while (i < f->n_lines)
1223 Line *l = &f->lines[i];
1225 if (inside_depth == 0)
1229 a = strstr (l->text, "#ifdef");
1230 b = strstr (l->text, "DBUS_BUILD_TESTS");
1236 if (strstr (l->text, "#if") != NULL)
1238 else if (strstr (l->text, "#endif") != NULL)
1242 if (inside_depth > 0)
1244 /* Mark the line and its blocks */
1247 l->inside_dbus_build_tests = TRUE;
1249 blink = _dbus_list_get_first_link (&l->blocks);
1250 while (blink != NULL)
1252 Block *b = blink->data;
1254 b->inside_dbus_build_tests = TRUE;
1256 blink = _dbus_list_get_next_link (&l->blocks, blink);
1263 /* Now mark functions where for all blocks that are associated
1264 * with a source line, the block is inside_dbus_build_tests.
1266 link = _dbus_list_get_first_link (&f->functions);
1267 while (link != NULL)
1269 Function *func = link->data;
1272 while (i < func->n_blocks)
1274 /* Break as soon as any block is not a test block */
1275 if (func->block_graph[i].lines != NULL &&
1276 !func->block_graph[i].inside_dbus_build_tests)
1282 if (i == func->n_blocks)
1283 func->inside_dbus_build_tests = TRUE;
1285 link = _dbus_list_get_next_link (&f->functions, link);
1290 mark_partials (File *f)
1296 while (i < f->n_lines)
1298 Line *l = &f->lines[i];
1301 int n_blocks_executed;
1304 n_blocks_executed = 0;
1305 blink = _dbus_list_get_first_link (&l->blocks);
1306 while (blink != NULL)
1308 Block *b = blink->data;
1310 if (b->exec_count > 0)
1311 n_blocks_executed += 1;
1315 blink = _dbus_list_get_next_link (&l->blocks, blink);
1318 if (n_blocks_executed > 0 &&
1319 n_blocks_executed < n_blocks)
1325 link = _dbus_list_get_first_link (&f->functions);
1326 while (link != NULL)
1328 Function *func = link->data;
1331 int n_blocks_executed;
1334 n_blocks_executed = 0;
1336 while (i < func->n_blocks)
1338 /* Break as soon as any block is not a test block */
1339 if (func->block_graph[i].exec_count > 0)
1340 n_blocks_executed += 1;
1346 if (n_blocks_executed > 0 &&
1347 n_blocks_executed < n_blocks)
1348 func->partial = TRUE;
1350 link = _dbus_list_get_next_link (&f->functions, link);
1355 load_c_file (const DBusString *filename)
1357 DBusString contents;
1361 f = dbus_new0 (File, 1);
1363 die ("no memory\n");
1365 if (!_dbus_string_copy_data (filename, &f->name))
1366 die ("no memory\n");
1368 if (!_dbus_string_init (&contents))
1369 die ("no memory\n");
1371 dbus_error_init (&error);
1373 if (!_dbus_file_get_contents (&contents, filename,
1376 fprintf (stderr, "Could not open file: %s\n",
1378 dbus_error_free (&error);
1382 load_functions_for_c_file (filename, &f->functions);
1384 f->n_lines = count_lines_in_string (&contents);
1385 f->lines = dbus_new0 (Line, f->n_lines);
1386 if (f->lines == NULL)
1387 die ("no memory\n");
1389 fill_line_content (&contents, f->lines);
1391 _dbus_string_free (&contents);
1393 load_block_line_associations (filename, f);
1395 mark_unused_functions (f);
1396 mark_inside_dbus_build_tests (f);
1402 typedef struct Stats Stats;
1407 int n_blocks_executed;
1408 int n_blocks_inside_dbus_build_tests;
1410 int n_lines; /* lines that have blocks on them */
1411 int n_lines_executed;
1412 int n_lines_partial;
1413 int n_lines_inside_dbus_build_tests;
1416 int n_functions_executed;
1417 int n_functions_partial;
1418 int n_functions_inside_dbus_build_tests;
1422 line_was_executed (Line *l)
1426 link = _dbus_list_get_first_link (&l->blocks);
1427 while (link != NULL)
1429 Block *b = link->data;
1431 if (b->exec_count > 0)
1434 link = _dbus_list_get_next_link (&l->blocks, link);
1442 line_exec_count (Line *l)
1448 link = _dbus_list_get_first_link (&l->blocks);
1449 while (link != NULL)
1451 Block *b = link->data;
1453 total += b->exec_count;
1455 link = _dbus_list_get_next_link (&l->blocks, link);
1462 merge_stats_for_file (Stats *stats,
1468 for (i = 0; i < f->n_lines; ++i)
1470 Line *l = &f->lines[i];
1472 if (l->inside_dbus_build_tests)
1474 stats->n_lines_inside_dbus_build_tests += 1;
1478 if (line_was_executed (l))
1479 stats->n_lines_executed += 1;
1481 if (l->blocks != NULL)
1482 stats->n_lines += 1;
1485 stats->n_lines_partial += 1;
1488 link = _dbus_list_get_first_link (&f->functions);
1489 while (link != NULL)
1491 Function *func = link->data;
1493 if (func->inside_dbus_build_tests)
1494 stats->n_functions_inside_dbus_build_tests += 1;
1497 stats->n_functions += 1;
1500 stats->n_functions_executed += 1;
1503 stats->n_functions_partial += 1;
1507 while (i < func->n_blocks)
1509 Block *b = &func->block_graph[i];
1511 if (b->inside_dbus_build_tests)
1512 stats->n_blocks_inside_dbus_build_tests += 1;
1515 if (b->exec_count > 0)
1516 stats->n_blocks_executed += 1;
1518 stats->n_blocks += 1;
1524 link = _dbus_list_get_next_link (&f->functions, link);
1528 /* The output of this matches gcov exactly ("diff" shows no difference) */
1530 print_annotated_source_gcov_format (File *f)
1535 while (i < f->n_lines)
1537 Line *l = &f->lines[i];
1539 if (l->blocks != NULL)
1543 exec_count = line_exec_count (l);
1546 printf ("%12d %s\n",
1547 exec_count, l->text);
1549 printf (" ###### %s\n", l->text);
1553 printf ("\t\t%s\n", l->text);
1561 print_annotated_source (File *f)
1566 while (i < f->n_lines)
1568 Line *l = &f->lines[i];
1570 if (l->inside_dbus_build_tests)
1575 if (l->blocks != NULL)
1579 exec_count = line_exec_count (l);
1582 printf ("%12d %s\n",
1583 exec_count, l->text);
1585 printf (" ###### %s\n", l->text);
1589 printf ("\t\t%s\n", l->text);
1597 print_block_superdetails (File *f)
1602 link = _dbus_list_get_first_link (&f->functions);
1603 while (link != NULL)
1605 Function *func = link->data;
1607 printf ("=== %s():\n", func->name);
1610 while (i < func->n_blocks)
1612 Block *b = &func->block_graph[i];
1615 printf (" %5d executed %d times%s\n", i,
1616 (int) b->exec_count,
1617 b->inside_dbus_build_tests ?
1618 " [inside DBUS_BUILD_TESTS]" : "");
1620 l = _dbus_list_get_first_link (&b->lines);
1623 Line *line = l->data;
1625 printf ("4%d\t%s\n", line->number, line->text);
1627 l = _dbus_list_get_next_link (&b->lines, l);
1633 link = _dbus_list_get_next_link (&f->functions, link);
1638 print_one_file (const DBusString *filename)
1640 if (_dbus_string_ends_with_c_str (filename, ".bb"))
1642 DBusString contents;
1645 if (!_dbus_string_init (&contents))
1646 die ("no memory\n");
1648 dbus_error_init (&error);
1650 if (!_dbus_file_get_contents (&contents, filename,
1653 fprintf (stderr, "Could not open file: %s\n",
1655 dbus_error_free (&error);
1659 dump_bb_file (&contents);
1661 _dbus_string_free (&contents);
1663 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
1665 DBusString contents;
1668 if (!_dbus_string_init (&contents))
1669 die ("no memory\n");
1671 dbus_error_init (&error);
1673 if (!_dbus_file_get_contents (&contents, filename,
1676 fprintf (stderr, "Could not open file: %s\n",
1678 dbus_error_free (&error);
1682 dump_bbg_file (&contents);
1684 _dbus_string_free (&contents);
1686 else if (_dbus_string_ends_with_c_str (filename, ".da"))
1688 DBusString contents;
1691 if (!_dbus_string_init (&contents))
1692 die ("no memory\n");
1694 dbus_error_init (&error);
1696 if (!_dbus_file_get_contents (&contents, filename,
1699 fprintf (stderr, "Could not open file: %s\n",
1701 dbus_error_free (&error);
1705 dump_da_file (&contents);
1707 _dbus_string_free (&contents);
1709 else if (_dbus_string_ends_with_c_str (filename, ".c"))
1713 f = load_c_file (filename);
1715 print_annotated_source (f);
1719 fprintf (stderr, "Unknown file type %s\n",
1720 _dbus_string_get_const_data (filename));
1726 print_untested_functions (File *f)
1732 link = _dbus_list_get_first_link (&f->functions);
1733 while (link != NULL)
1735 Function *func = link->data;
1738 !func->inside_dbus_build_tests)
1741 link = _dbus_list_get_next_link (&f->functions, link);
1747 printf ("Untested functions in %s\n", f->name);
1748 printf ("=======\n");
1750 link = _dbus_list_get_first_link (&f->functions);
1751 while (link != NULL)
1753 Function *func = link->data;
1756 !func->inside_dbus_build_tests)
1757 printf (" %s\n", func->name);
1759 link = _dbus_list_get_next_link (&f->functions, link);
1766 print_stats (Stats *stats,
1767 const char *of_what)
1771 printf ("Summary (%s)\n", of_what);
1772 printf ("=======\n");
1773 printf (" %g%% blocks executed (%d of %d)\n",
1774 (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
1775 stats->n_blocks_executed,
1778 printf (" (ignored %d blocks inside DBUS_BUILD_TESTS)\n",
1779 stats->n_blocks_inside_dbus_build_tests);
1781 printf (" %g%% functions executed (%d of %d)\n",
1782 (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
1783 stats->n_functions_executed,
1784 stats->n_functions);
1786 completely = stats->n_functions_executed - stats->n_functions_partial;
1787 printf (" %g%% functions completely executed (%d of %d)\n",
1788 (completely / (double) stats->n_functions) * 100.0,
1790 stats->n_functions);
1792 printf (" (ignored %d functions inside DBUS_BUILD_TESTS)\n",
1793 stats->n_functions_inside_dbus_build_tests);
1795 printf (" %g%% lines executed (%d of %d)\n",
1796 (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
1797 stats->n_lines_executed,
1800 completely = stats->n_lines_executed - stats->n_lines_partial;
1801 printf (" %g%% lines completely executed (%d of %d)\n",
1802 (completely / (double) stats->n_lines) * 100.0,
1806 printf (" (ignored %d lines inside DBUS_BUILD_TESTS)\n",
1807 stats->n_lines_inside_dbus_build_tests);
1821 main (int argc, char **argv)
1823 DBusString filename;
1829 fprintf (stderr, "Must specify files on command line\n");
1836 if (strcmp (argv[i], "--report") == 0)
1841 else if (strcmp (argv[i], "--blocks") == 0)
1846 else if (strcmp (argv[i], "--gcov") == 0)
1855 fprintf (stderr, "Must specify files on command line\n");
1859 if (m == MODE_PRINT)
1863 _dbus_string_init_const (&filename, argv[i]);
1865 print_one_file (&filename);
1870 else if (m == MODE_BLOCKS || m == MODE_GCOV)
1876 _dbus_string_init_const (&filename, argv[i]);
1878 f = load_c_file (&filename);
1880 if (m == MODE_BLOCKS)
1881 print_block_superdetails (f);
1882 else if (m == MODE_GCOV)
1883 print_annotated_source_gcov_format (f);
1888 else if (m == MODE_REPORT)
1890 Stats stats = { 0, };
1893 DBusHashTable *stats_by_dir;
1899 _dbus_string_init_const (&filename, argv[i]);
1901 if (_dbus_string_ends_with_c_str (&filename, ".c"))
1905 f = load_c_file (&filename);
1907 if (!_dbus_list_append (&files, f))
1908 die ("no memory\n");
1912 fprintf (stderr, "Unknown file type %s\n",
1913 _dbus_string_get_const_data (&filename));
1920 link = _dbus_list_get_first_link (&files);
1921 while (link != NULL)
1923 File *f = link->data;
1925 merge_stats_for_file (&stats, f);
1927 link = _dbus_list_get_next_link (&files, link);
1930 print_stats (&stats, "all files");
1932 stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
1933 dbus_free, dbus_free);
1935 link = _dbus_list_get_first_link (&files);
1936 while (link != NULL)
1938 File *f = link->data;
1943 _dbus_string_init_const (&filename, f->name);
1945 if (!_dbus_string_init (&dirname))
1946 die ("no memory\n");
1948 if (!_dbus_string_get_dirname (&filename, &dirname) ||
1949 !_dbus_string_copy_data (&dirname, &dirname_c))
1950 die ("no memory\n");
1952 dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
1955 if (dir_stats == NULL)
1957 dir_stats = dbus_new0 (Stats, 1);
1958 if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
1960 die ("no memory\n");
1963 dbus_free (dirname_c);
1965 merge_stats_for_file (dir_stats, f);
1967 link = _dbus_list_get_next_link (&files, link);
1970 _dbus_hash_iter_init (stats_by_dir, &iter);
1971 while (_dbus_hash_iter_next (&iter))
1973 const char *dirname = _dbus_hash_iter_get_string_key (&iter);
1974 Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
1976 print_stats (dir_stats, dirname);
1979 _dbus_hash_table_unref (stats_by_dir);
1981 link = _dbus_list_get_first_link (&files);
1982 while (link != NULL)
1984 File *f = link->data;
1986 print_untested_functions (f);
1988 link = _dbus_list_get_next_link (&files, link);