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 #undef DBUS_COMPILATION
41 die (const char *message)
43 fprintf (stderr, "%s", message);
47 /* This bizarro function is from gcov-io.h in gcc source tree */
49 fetch_long (long *dest,
56 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
57 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
61 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
63 if ((source[bytes - 1] & 128) && (value > 0))
70 typedef DBUS_INT64_TYPE dbus_int64_t;
73 fetch_long64 (dbus_int64_t *dest,
77 dbus_int64_t value = 0;
80 for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
81 if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
85 value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
87 if ((source[bytes - 1] & 128) && (value > 0))
94 #define BB_FILENAME (-1)
95 #define BB_FUNCTION (-2)
96 #define BB_ENDOFLIST 0
99 string_get_int (const DBusString *str,
105 if ((_dbus_string_get_length (str) - start) < 4)
108 p = _dbus_string_get_const_data (str);
112 fetch_long (val, p, 4);
118 string_get_int64 (const DBusString *str,
124 if ((_dbus_string_get_length (str) - start) < 8)
127 p = _dbus_string_get_const_data (str);
131 fetch_long64 (val, p, 8);
137 string_get_string (const DBusString *str,
147 while (string_get_int (str, i, &n))
154 _dbus_string_append_byte (val, n & 0xff);
155 _dbus_string_append_byte (val, (n >> 8) & 0xff);
156 _dbus_string_append_byte (val, (n >> 16) & 0xff);
157 _dbus_string_append_byte (val, (n >> 24) & 0xff);
166 dump_bb_file (const DBusString *contents)
174 while (string_get_int (contents, i, &val))
184 if (!_dbus_string_init (&f))
187 if (string_get_string (contents, i,
191 printf ("File %s\n", _dbus_string_get_const_data (&f));
193 _dbus_string_free (&f);
199 if (!_dbus_string_init (&f))
202 if (string_get_string (contents, i,
206 printf ("Function %s\n", _dbus_string_get_const_data (&f));
208 _dbus_string_free (&f);
214 printf ("End of block\n");
217 printf ("Line %ld\n", val);
222 printf ("%d functions in file\n", n_functions);
225 #define FLAG_ON_TREE 0x1
226 #define FLAG_FAKE 0x2
227 #define FLAG_FALL_THROUGH 0x4
230 dump_bbg_file (const DBusString *contents)
244 while (string_get_int (contents, i, &val))
246 long n_blocks_in_func;
250 n_blocks_in_func = val;
254 if (!string_get_int (contents, i, &n_arcs_in_func))
259 printf ("Function has %ld blocks and %ld arcs\n",
260 n_blocks_in_func, n_arcs_in_func);
263 n_blocks += n_blocks_in_func;
264 n_arcs += n_arcs_in_func;
267 while (j < n_blocks_in_func)
269 long n_arcs_in_block;
272 if (!string_get_int (contents, i, &n_arcs_in_block))
277 printf (" Block has %ld arcs\n", n_arcs_in_block);
280 while (k < n_arcs_in_block)
282 long destination_block;
285 if (!string_get_int (contents, i, &destination_block))
290 if (!string_get_int (contents, i, &flags))
295 printf (" Arc has destination block %ld flags 0x%lx\n",
296 destination_block, flags);
298 if ((flags & FLAG_ON_TREE) == 0)
299 n_arcs_off_tree += 1;
304 if (k < n_arcs_in_block)
310 if (j < n_blocks_in_func)
313 if (!string_get_int (contents, i, &val))
319 die ("-1 separator not found\n");
322 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
323 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
326 /* The da file contains first a count of arcs in the file,
327 * then a count of executions for all "off tree" arcs
331 dump_da_file (const DBusString *contents)
339 if (!string_get_int64 (contents, i, &val))
344 printf ("%ld arcs in file\n", (long) val);
345 claimed_n_arcs = val;
348 while (string_get_int64 (contents, i, &val))
352 printf ("%ld executions of arc %d\n",
358 if (n_arcs != claimed_n_arcs)
360 printf ("File claimed to have %d arcs but only had %d\n",
361 claimed_n_arcs, n_arcs);
365 typedef struct Arc Arc;
366 typedef struct Block Block;
367 typedef struct Function Function;
368 typedef struct File File;
369 typedef struct Line Line;
375 dbus_int64_t arc_count;
376 unsigned int count_valid : 1;
377 unsigned int on_tree : 1;
378 unsigned int fake : 1;
379 unsigned int fall_through : 1;
388 dbus_int64_t succ_count;
389 dbus_int64_t pred_count;
390 dbus_int64_t exec_count;
392 unsigned int count_valid : 1;
393 unsigned int on_tree : 1;
394 unsigned int inside_dbus_build_tests : 1;
402 unsigned int unused : 1;
403 unsigned int inside_dbus_build_tests : 1;
404 unsigned int partial : 1; /* only some of the blocks were executed */
412 unsigned int inside_dbus_build_tests : 1;
413 unsigned int partial : 1; /* only some of the blocks were executed */
425 function_add_arc (Function *function,
432 arc = dbus_new0 (Arc, 1);
436 arc->target = target;
437 arc->source = source;
439 arc->succ_next = function->block_graph[source].succ;
440 function->block_graph[source].succ = arc;
441 function->block_graph[source].succ_count += 1;
443 arc->pred_next = function->block_graph[target].pred;
444 function->block_graph[target].pred = arc;
445 function->block_graph[target].pred_count += 1;
447 if ((flags & FLAG_ON_TREE) != 0)
450 if ((flags & FLAG_FAKE) != 0)
453 if ((flags & FLAG_FALL_THROUGH) != 0)
454 arc->fall_through = TRUE;
459 reverse_arcs (Arc *arc)
461 struct Arc *prev = 0;
464 for ( ; arc; arc = next)
466 next = arc->succ_next;
467 arc->succ_next = prev;
475 function_reverse_succ_arcs (Function *func)
477 /* Must reverse the order of all succ arcs, to ensure that they match
478 * the order of the data in the .da file.
482 for (i = 0; i < func->n_blocks; i++)
483 if (func->block_graph[i].succ)
484 func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
488 get_functions_from_bbg (const DBusString *contents,
489 DBusList **functions)
499 printf ("Loading arcs and blocks from .bbg file\n");
507 while (string_get_int (contents, i, &val))
510 long n_blocks_in_func;
514 n_blocks_in_func = val;
518 if (!string_get_int (contents, i, &n_arcs_in_func))
524 n_blocks += n_blocks_in_func;
525 n_arcs += n_arcs_in_func;
527 func = dbus_new0 (Function, 1);
531 func->block_graph = dbus_new0 (Block, n_blocks_in_func);
532 func->n_blocks = n_blocks_in_func;
535 while (j < n_blocks_in_func)
537 long n_arcs_in_block;
540 if (!string_get_int (contents, i, &n_arcs_in_block))
546 while (k < n_arcs_in_block)
548 long destination_block;
551 if (!string_get_int (contents, i, &destination_block))
556 if (!string_get_int (contents, i, &flags))
561 if ((flags & FLAG_ON_TREE) == 0)
562 n_arcs_off_tree += 1;
564 function_add_arc (func, j, destination_block,
570 if (k < n_arcs_in_block)
576 if (j < n_blocks_in_func)
579 function_reverse_succ_arcs (func);
581 if (!_dbus_list_append (functions, func))
584 if (!string_get_int (contents, i, &val))
590 die ("-1 separator not found\n");
594 printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
595 n_functions, n_blocks, n_arcs, n_arcs_off_tree);
598 _dbus_assert (n_functions == _dbus_list_get_length (functions));
602 add_counts_from_da (const DBusString *contents,
603 DBusList **functions)
610 Function *current_func;
615 printf ("Loading execution count for each arc from .da file\n");
619 if (!string_get_int64 (contents, i, &val))
624 claimed_n_arcs = val;
626 link = _dbus_list_get_first_link (functions);
630 current_func = link->data;
632 current_arc = current_func->block_graph[current_block].succ;
635 while (string_get_int64 (contents, i, &val))
639 while (current_arc == NULL ||
640 current_arc->on_tree)
642 if (current_arc == NULL)
646 if (current_block == current_func->n_blocks)
648 link = _dbus_list_get_next_link (functions, link);
651 fprintf (stderr, "Ran out of functions loading .da file\n");
654 current_func = link->data;
658 current_arc = current_func->block_graph[current_block].succ;
662 current_arc = current_arc->succ_next;
666 _dbus_assert (current_arc != NULL);
667 _dbus_assert (!current_arc->on_tree);
669 current_arc->arc_count = val;
670 current_arc->count_valid = TRUE;
671 current_func->block_graph[current_block].succ_count -= 1;
672 current_func->block_graph[current_arc->target].pred_count -= 1;
676 current_arc = current_arc->succ_next;
681 if (n_arcs != claimed_n_arcs)
683 fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
684 claimed_n_arcs, n_arcs);
689 printf ("%d arcs in file\n", n_arcs);
694 function_solve_graph (Function *func)
704 printf ("Solving function graph\n");
707 n_blocks = func->n_blocks;
708 block_graph = func->block_graph;
710 /* For every block in the file,
711 - if every exit/entrance arc has a known count, then set the block count
712 - if the block count is known, and every exit/entrance arc but one has
713 a known execution count, then set the count of the remaining arc
715 As arc counts are set, decrement the succ/pred count, but don't delete
716 the arc, that way we can easily tell when all arcs are known, or only
717 one arc is unknown. */
719 /* The order that the basic blocks are iterated through is important.
720 Since the code that finds spanning trees starts with block 0, low numbered
721 arcs are put on the spanning tree in preference to high numbered arcs.
722 Hence, most instrumented arcs are at the end. Graph solving works much
723 faster if we propagate numbers from the end to the start.
725 This takes an average of slightly more than 3 passes. */
734 for (i = n_blocks - 1; i >= 0; i--)
736 if (! block_graph[i].count_valid)
738 if (block_graph[i].succ_count == 0)
741 for (arc = block_graph[i].succ; arc;
742 arc = arc->succ_next)
743 total += arc->arc_count;
744 block_graph[i].exec_count = total;
745 block_graph[i].count_valid = 1;
748 else if (block_graph[i].pred_count == 0)
751 for (arc = block_graph[i].pred; arc;
752 arc = arc->pred_next)
753 total += arc->arc_count;
754 block_graph[i].exec_count = total;
755 block_graph[i].count_valid = 1;
759 if (block_graph[i].count_valid)
761 if (block_graph[i].succ_count == 1)
764 /* One of the counts will be invalid, but it is zero,
765 so adding it in also doesn't hurt. */
766 for (arc = block_graph[i].succ; arc;
767 arc = arc->succ_next)
768 total += arc->arc_count;
769 /* Calculate count for remaining arc by conservation. */
770 total = block_graph[i].exec_count - total;
771 /* Search for the invalid arc, and set its count. */
772 for (arc = block_graph[i].succ; arc;
773 arc = arc->succ_next)
774 if (! arc->count_valid)
777 die ("arc == NULL\n");
778 arc->count_valid = 1;
779 arc->arc_count = total;
780 block_graph[i].succ_count -= 1;
782 block_graph[arc->target].pred_count -= 1;
785 if (block_graph[i].pred_count == 1)
788 /* One of the counts will be invalid, but it is zero,
789 so adding it in also doesn't hurt. */
790 for (arc = block_graph[i].pred; arc;
791 arc = arc->pred_next)
792 total += arc->arc_count;
793 /* Calculate count for remaining arc by conservation. */
794 total = block_graph[i].exec_count - total;
795 /* Search for the invalid arc, and set its count. */
796 for (arc = block_graph[i].pred; arc;
797 arc = arc->pred_next)
798 if (! arc->count_valid)
801 die ("arc == NULL\n");
802 arc->count_valid = 1;
803 arc->arc_count = total;
804 block_graph[i].pred_count -= 1;
806 block_graph[arc->source].succ_count -= 1;
813 /* If the graph has been correctly solved, every block will have a
814 * succ and pred count of zero.
816 for (i = 0; i < n_blocks; i++)
818 if (block_graph[i].succ_count || block_graph[i].pred_count)
820 fprintf (stderr, "Block graph solved incorrectly\n");
821 fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
822 i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
829 solve_graphs (DBusList **functions)
833 link = _dbus_list_get_first_link (functions);
836 Function *func = link->data;
838 function_solve_graph (func);
840 link = _dbus_list_get_next_link (functions, link);
845 load_functions_for_c_file (const DBusString *filename,
846 DBusList **functions)
848 DBusString bbg_filename;
849 DBusString da_filename;
853 dbus_error_init (&error);
855 if (!_dbus_string_init (&bbg_filename) ||
856 !_dbus_string_init (&da_filename) ||
857 !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
858 !_dbus_string_copy (filename, 0, &da_filename, 0) ||
859 !_dbus_string_init (&contents))
862 _dbus_string_shorten (&bbg_filename, 2);
863 _dbus_string_shorten (&da_filename, 2);
865 if (!_dbus_string_append (&bbg_filename, ".bbg") ||
866 !_dbus_string_append (&da_filename, ".da"))
869 if (!_dbus_file_get_contents (&contents, &bbg_filename,
872 fprintf (stderr, "Could not open file: %s\n",
877 get_functions_from_bbg (&contents, functions);
879 _dbus_string_set_length (&contents, 0);
881 if (!_dbus_file_get_contents (&contents, &da_filename,
884 fprintf (stderr, "Could not open file: %s\n",
889 add_counts_from_da (&contents, functions);
891 solve_graphs (functions);
893 _dbus_string_free (&contents);
894 _dbus_string_free (&da_filename);
895 _dbus_string_free (&bbg_filename);
899 get_lines_from_bb_file (const DBusString *contents,
905 dbus_bool_t in_our_file;
911 printf ("Getting line numbers for blocks from .bb file\n");
914 /* There's this "filename" field in the .bb file which
915 * mysteriously comes *after* the first function in the
916 * file in the .bb file; and every .bb file seems to
917 * have only one filename. I don't understand
918 * what's going on here, so just set in_our_file = TRUE
919 * at the start categorically.
925 link = _dbus_list_get_first_link (&fl->functions);
928 while (string_get_int (contents, i, &val))
938 if (!_dbus_string_init (&f))
941 if (string_get_string (contents, i,
945 /* fl->name is a full path and the filename in .bb is
950 _dbus_string_init_const (&tmp_str, fl->name);
952 if (_dbus_string_ends_with_c_str (&tmp_str,
953 _dbus_string_get_const_data (&f)))
960 "File %s in .bb, looking for %s, in_our_file = %d\n",
961 _dbus_string_get_const_data (&f),
966 _dbus_string_free (&f);
972 if (!_dbus_string_init (&f))
975 if (string_get_string (contents, i,
980 fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
989 fprintf (stderr, "No function object for function %s\n",
990 _dbus_string_get_const_data (&f));
995 link = _dbus_list_get_next_link (&fl->functions, link);
997 if (func->name == NULL)
999 if (!_dbus_string_copy_data (&f, &func->name))
1000 die ("no memory\n");
1004 die ("got two names for function?\n");
1009 _dbus_string_free (&f);
1019 fprintf (stderr, "Line %ld\n", val);
1022 if (val >= fl->n_lines)
1024 fprintf (stderr, "Line %ld but file only has %d lines\n",
1027 else if (func != NULL)
1029 val -= 1; /* To convert the 1-based line number to 0-based */
1030 _dbus_assert (val >= 0);
1032 if (block < func->n_blocks)
1034 if (!_dbus_list_append (&func->block_graph[block].lines,
1036 die ("no memory\n");
1039 if (!_dbus_list_append (&fl->lines[val].blocks,
1040 &func->block_graph[block]))
1041 die ("no memory\n");
1045 fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
1046 block, func->n_blocks);
1051 fprintf (stderr, "Line %ld given outside of any function\n",
1060 printf ("%d functions in file\n", n_functions);
1066 load_block_line_associations (const DBusString *filename,
1069 DBusString bb_filename;
1070 DBusString contents;
1073 dbus_error_init (&error);
1075 if (!_dbus_string_init (&bb_filename) ||
1076 !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
1077 !_dbus_string_init (&contents))
1078 die ("no memory\n");
1080 _dbus_string_shorten (&bb_filename, 2);
1082 if (!_dbus_string_append (&bb_filename, ".bb"))
1083 die ("no memory\n");
1085 if (!_dbus_file_get_contents (&contents, &bb_filename,
1088 fprintf (stderr, "Could not open file: %s\n",
1093 get_lines_from_bb_file (&contents, f);
1095 _dbus_string_free (&contents);
1096 _dbus_string_free (&bb_filename);
1100 count_lines_in_string (const DBusString *str)
1106 const char *last_line_end;
1109 printf ("Counting lines in source file\n");
1114 p = _dbus_string_get_const_data (str);
1115 end = p + _dbus_string_get_length (str);
1119 /* too lazy to handle \r\n as one linebreak */
1120 if (*p == '\n' || *p == '\r')
1123 last_line_end = p + 1;
1130 if (last_line_end != p)
1137 fill_line_content (const DBusString *str,
1144 const char *last_line_end;
1147 printf ("Saving contents of each line in source file\n");
1152 p = _dbus_string_get_const_data (str);
1153 end = p + _dbus_string_get_length (str);
1157 if (*p == '\n' || *p == '\r')
1159 lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
1160 if (lines[n_lines].text == NULL)
1161 die ("no memory\n");
1163 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1164 lines[n_lines].number = n_lines + 1;
1168 last_line_end = p + 1;
1175 if (p != last_line_end)
1177 memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
1183 mark_unused_functions (File *f)
1188 link = _dbus_list_get_first_link (&f->functions);
1189 while (link != NULL)
1191 Function *func = link->data;
1196 while (i < func->n_blocks)
1198 if (func->block_graph[i].exec_count > 0)
1205 func->unused = TRUE;
1207 link = _dbus_list_get_next_link (&f->functions, link);
1212 mark_inside_dbus_build_tests (File *f)
1220 while (i < f->n_lines)
1222 Line *l = &f->lines[i];
1224 if (inside_depth == 0)
1228 a = strstr (l->text, "#ifdef");
1229 b = strstr (l->text, "DBUS_BUILD_TESTS");
1235 if (strstr (l->text, "#if") != NULL)
1237 else if (strstr (l->text, "#endif") != NULL)
1241 if (inside_depth > 0)
1243 /* Mark the line and its blocks */
1246 l->inside_dbus_build_tests = TRUE;
1248 blink = _dbus_list_get_first_link (&l->blocks);
1249 while (blink != NULL)
1251 Block *b = blink->data;
1253 b->inside_dbus_build_tests = TRUE;
1255 blink = _dbus_list_get_next_link (&l->blocks, blink);
1262 /* Now mark functions where for all blocks that are associated
1263 * with a source line, the block is inside_dbus_build_tests.
1265 link = _dbus_list_get_first_link (&f->functions);
1266 while (link != NULL)
1268 Function *func = link->data;
1271 while (i < func->n_blocks)
1273 /* Break as soon as any block is not a test block */
1274 if (func->block_graph[i].lines != NULL &&
1275 !func->block_graph[i].inside_dbus_build_tests)
1281 if (i == func->n_blocks)
1282 func->inside_dbus_build_tests = TRUE;
1284 link = _dbus_list_get_next_link (&f->functions, link);
1289 mark_partials (File *f)
1295 while (i < f->n_lines)
1297 Line *l = &f->lines[i];
1300 int n_blocks_executed;
1303 n_blocks_executed = 0;
1304 blink = _dbus_list_get_first_link (&l->blocks);
1305 while (blink != NULL)
1307 Block *b = blink->data;
1309 if (b->exec_count > 0)
1310 n_blocks_executed += 1;
1314 blink = _dbus_list_get_next_link (&l->blocks, blink);
1317 if (n_blocks_executed > 0 &&
1318 n_blocks_executed < n_blocks)
1324 link = _dbus_list_get_first_link (&f->functions);
1325 while (link != NULL)
1327 Function *func = link->data;
1330 int n_blocks_executed;
1333 n_blocks_executed = 0;
1335 while (i < func->n_blocks)
1337 /* Break as soon as any block is not a test block */
1338 if (func->block_graph[i].exec_count > 0)
1339 n_blocks_executed += 1;
1345 if (n_blocks_executed > 0 &&
1346 n_blocks_executed < n_blocks)
1347 func->partial = TRUE;
1349 link = _dbus_list_get_next_link (&f->functions, link);
1354 load_c_file (const DBusString *filename)
1356 DBusString contents;
1360 f = dbus_new0 (File, 1);
1362 die ("no memory\n");
1364 if (!_dbus_string_copy_data (filename, &f->name))
1365 die ("no memory\n");
1367 if (!_dbus_string_init (&contents))
1368 die ("no memory\n");
1370 dbus_error_init (&error);
1372 if (!_dbus_file_get_contents (&contents, filename,
1375 fprintf (stderr, "Could not open file: %s\n",
1377 dbus_error_free (&error);
1381 load_functions_for_c_file (filename, &f->functions);
1383 f->n_lines = count_lines_in_string (&contents);
1384 f->lines = dbus_new0 (Line, f->n_lines);
1385 if (f->lines == NULL)
1386 die ("no memory\n");
1388 fill_line_content (&contents, f->lines);
1390 _dbus_string_free (&contents);
1392 load_block_line_associations (filename, f);
1394 mark_unused_functions (f);
1395 mark_inside_dbus_build_tests (f);
1401 typedef struct Stats Stats;
1406 int n_blocks_executed;
1407 int n_blocks_inside_dbus_build_tests;
1409 int n_lines; /* lines that have blocks on them */
1410 int n_lines_executed;
1411 int n_lines_partial;
1412 int n_lines_inside_dbus_build_tests;
1415 int n_functions_executed;
1416 int n_functions_partial;
1417 int n_functions_inside_dbus_build_tests;
1421 line_was_executed (Line *l)
1425 link = _dbus_list_get_first_link (&l->blocks);
1426 while (link != NULL)
1428 Block *b = link->data;
1430 if (b->exec_count > 0)
1433 link = _dbus_list_get_next_link (&l->blocks, link);
1441 line_exec_count (Line *l)
1447 link = _dbus_list_get_first_link (&l->blocks);
1448 while (link != NULL)
1450 Block *b = link->data;
1452 total += b->exec_count;
1454 link = _dbus_list_get_next_link (&l->blocks, link);
1461 merge_stats_for_file (Stats *stats,
1467 for (i = 0; i < f->n_lines; ++i)
1469 Line *l = &f->lines[i];
1471 if (l->inside_dbus_build_tests)
1473 stats->n_lines_inside_dbus_build_tests += 1;
1477 if (line_was_executed (l))
1478 stats->n_lines_executed += 1;
1480 if (l->blocks != NULL)
1481 stats->n_lines += 1;
1484 stats->n_lines_partial += 1;
1487 link = _dbus_list_get_first_link (&f->functions);
1488 while (link != NULL)
1490 Function *func = link->data;
1492 if (func->inside_dbus_build_tests)
1493 stats->n_functions_inside_dbus_build_tests += 1;
1496 stats->n_functions += 1;
1499 stats->n_functions_executed += 1;
1502 stats->n_functions_partial += 1;
1506 while (i < func->n_blocks)
1508 Block *b = &func->block_graph[i];
1510 if (b->inside_dbus_build_tests)
1511 stats->n_blocks_inside_dbus_build_tests += 1;
1514 if (b->exec_count > 0)
1515 stats->n_blocks_executed += 1;
1517 stats->n_blocks += 1;
1523 link = _dbus_list_get_next_link (&f->functions, link);
1527 /* The output of this matches gcov exactly ("diff" shows no difference) */
1529 print_annotated_source_gcov_format (File *f)
1534 while (i < f->n_lines)
1536 Line *l = &f->lines[i];
1538 if (l->blocks != NULL)
1542 exec_count = line_exec_count (l);
1545 printf ("%12d %s\n",
1546 exec_count, l->text);
1548 printf (" ###### %s\n", l->text);
1552 printf ("\t\t%s\n", l->text);
1560 print_annotated_source (File *f)
1565 while (i < f->n_lines)
1567 Line *l = &f->lines[i];
1569 if (l->inside_dbus_build_tests)
1574 if (l->blocks != NULL)
1578 exec_count = line_exec_count (l);
1581 printf ("%12d %s\n",
1582 exec_count, l->text);
1584 printf (" ###### %s\n", l->text);
1588 printf ("\t\t%s\n", l->text);
1596 print_block_superdetails (File *f)
1601 link = _dbus_list_get_first_link (&f->functions);
1602 while (link != NULL)
1604 Function *func = link->data;
1606 printf ("=== %s():\n", func->name);
1609 while (i < func->n_blocks)
1611 Block *b = &func->block_graph[i];
1614 printf (" %5d executed %d times%s\n", i,
1615 (int) b->exec_count,
1616 b->inside_dbus_build_tests ?
1617 " [inside DBUS_BUILD_TESTS]" : "");
1619 l = _dbus_list_get_first_link (&b->lines);
1622 Line *line = l->data;
1624 printf ("4%d\t%s\n", line->number, line->text);
1626 l = _dbus_list_get_next_link (&b->lines, l);
1632 link = _dbus_list_get_next_link (&f->functions, link);
1637 print_one_file (const DBusString *filename)
1639 if (_dbus_string_ends_with_c_str (filename, ".bb"))
1641 DBusString contents;
1644 if (!_dbus_string_init (&contents))
1645 die ("no memory\n");
1647 dbus_error_init (&error);
1649 if (!_dbus_file_get_contents (&contents, filename,
1652 fprintf (stderr, "Could not open file: %s\n",
1654 dbus_error_free (&error);
1658 dump_bb_file (&contents);
1660 _dbus_string_free (&contents);
1662 else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
1664 DBusString contents;
1667 if (!_dbus_string_init (&contents))
1668 die ("no memory\n");
1670 dbus_error_init (&error);
1672 if (!_dbus_file_get_contents (&contents, filename,
1675 fprintf (stderr, "Could not open file: %s\n",
1677 dbus_error_free (&error);
1681 dump_bbg_file (&contents);
1683 _dbus_string_free (&contents);
1685 else if (_dbus_string_ends_with_c_str (filename, ".da"))
1687 DBusString contents;
1690 if (!_dbus_string_init (&contents))
1691 die ("no memory\n");
1693 dbus_error_init (&error);
1695 if (!_dbus_file_get_contents (&contents, filename,
1698 fprintf (stderr, "Could not open file: %s\n",
1700 dbus_error_free (&error);
1704 dump_da_file (&contents);
1706 _dbus_string_free (&contents);
1708 else if (_dbus_string_ends_with_c_str (filename, ".c"))
1712 f = load_c_file (filename);
1714 print_annotated_source (f);
1718 fprintf (stderr, "Unknown file type %s\n",
1719 _dbus_string_get_const_data (filename));
1725 print_untested_functions (File *f)
1731 link = _dbus_list_get_first_link (&f->functions);
1732 while (link != NULL)
1734 Function *func = link->data;
1737 !func->inside_dbus_build_tests)
1740 link = _dbus_list_get_next_link (&f->functions, link);
1746 printf ("Untested functions in %s\n", f->name);
1747 printf ("=======\n");
1749 link = _dbus_list_get_first_link (&f->functions);
1750 while (link != NULL)
1752 Function *func = link->data;
1755 !func->inside_dbus_build_tests)
1756 printf (" %s\n", func->name);
1758 link = _dbus_list_get_next_link (&f->functions, link);
1773 main (int argc, char **argv)
1775 DBusString filename;
1781 fprintf (stderr, "Must specify files on command line\n");
1788 if (strcmp (argv[i], "--report") == 0)
1793 else if (strcmp (argv[i], "--blocks") == 0)
1798 else if (strcmp (argv[i], "--gcov") == 0)
1807 fprintf (stderr, "Must specify files on command line\n");
1811 if (m == MODE_PRINT)
1815 _dbus_string_init_const (&filename, argv[i]);
1817 print_one_file (&filename);
1822 else if (m == MODE_BLOCKS || m == MODE_GCOV)
1828 _dbus_string_init_const (&filename, argv[i]);
1830 f = load_c_file (&filename);
1832 if (m == MODE_BLOCKS)
1833 print_block_superdetails (f);
1834 else if (m == MODE_GCOV)
1835 print_annotated_source_gcov_format (f);
1840 else if (m == MODE_REPORT)
1842 Stats stats = { 0, };
1850 _dbus_string_init_const (&filename, argv[i]);
1852 if (_dbus_string_ends_with_c_str (&filename, ".c"))
1856 f = load_c_file (&filename);
1858 if (!_dbus_list_append (&files, f))
1859 die ("no memory\n");
1863 fprintf (stderr, "Unknown file type %s\n",
1864 _dbus_string_get_const_data (&filename));
1871 link = _dbus_list_get_first_link (&files);
1872 while (link != NULL)
1874 File *f = link->data;
1876 merge_stats_for_file (&stats, f);
1878 link = _dbus_list_get_next_link (&files, link);
1881 printf ("Summary\n");
1882 printf ("=======\n");
1883 printf (" %g%% blocks executed (%d of %d)\n",
1884 (stats.n_blocks_executed / (double) stats.n_blocks) * 100.0,
1885 stats.n_blocks_executed,
1888 printf (" (ignored %d blocks inside DBUS_BUILD_TESTS)\n",
1889 stats.n_blocks_inside_dbus_build_tests);
1891 printf (" %g%% functions executed (%d of %d)\n",
1892 (stats.n_functions_executed / (double) stats.n_functions) * 100.0,
1893 stats.n_functions_executed,
1896 completely = stats.n_functions_executed - stats.n_functions_partial;
1897 printf (" %g%% functions completely executed (%d of %d)\n",
1898 (completely / (double) stats.n_functions) * 100.0,
1902 printf (" (ignored %d functions inside DBUS_BUILD_TESTS)\n",
1903 stats.n_functions_inside_dbus_build_tests);
1905 printf (" %g%% lines executed (%d of %d)\n",
1906 (stats.n_lines_executed / (double) stats.n_lines) * 100.0,
1907 stats.n_lines_executed,
1910 completely = stats.n_lines_executed - stats.n_lines_partial;
1911 printf (" %g%% lines completely executed (%d of %d)\n",
1912 (completely / (double) stats.n_lines) * 100.0,
1916 printf (" (ignored %d lines inside DBUS_BUILD_TESTS)\n",
1917 stats.n_lines_inside_dbus_build_tests);
1921 link = _dbus_list_get_first_link (&files);
1922 while (link != NULL)
1924 File *f = link->data;
1926 print_untested_functions (f);
1928 link = _dbus_list_get_next_link (&files, link);