summaryrefslogtreecommitdiff
path: root/test/decode-gcov.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/decode-gcov.c')
-rw-r--r--test/decode-gcov.c2653
1 files changed, 0 insertions, 2653 deletions
diff --git a/test/decode-gcov.c b/test/decode-gcov.c
deleted file mode 100644
index 3b2a1522..00000000
--- a/test/decode-gcov.c
+++ /dev/null
@@ -1,2653 +0,0 @@
- /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/* decode-gcov.c gcov decoder program
- *
- * Copyright (C) 2003 Red Hat Inc.
- *
- * Partially derived from gcov,
- * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
- * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
- *
- * This file is NOT licensed under the Academic Free License
- * as it is largely derived from gcov.c and gcov-io.h in the
- * gcc source code.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <config.h>
-#define DBUS_COMPILATION /* cheat */
-#include <dbus/dbus-list.h>
-#include <dbus/dbus-string.h>
-#include <dbus/dbus-sysdeps.h>
-#include <dbus/dbus-marshal.h>
-#include <dbus/dbus-hash.h>
-#undef DBUS_COMPILATION
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef DBUS_HAVE_INT64
-#error "gcov support can't be built without 64-bit integer support"
-#endif
-
-static void
-die (const char *message)
-{
- fprintf (stderr, "%s", message);
- exit (1);
-}
-
-/* This bizarro function is from gcov-io.h in gcc source tree */
-static int
-fetch_long (long *dest,
- const char *source,
- size_t bytes)
-{
- long value = 0;
- int i;
-
- for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
- if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
- return 1;
-
- for (; i >= 0; i--)
- value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
-
- if ((source[bytes - 1] & 128) && (value > 0))
- value = - value;
-
- *dest = value;
- return 0;
-}
-
-static int
-fetch_long64 (dbus_int64_t *dest,
- const char *source,
- size_t bytes)
-{
- dbus_int64_t value = 0;
- int i;
-
- for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
- if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
- return 1;
-
- for (; i >= 0; i--)
- value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
-
- if ((source[bytes - 1] & 128) && (value > 0))
- value = - value;
-
- *dest = value;
- return 0;
-}
-
-#define BB_FILENAME (-1)
-#define BB_FUNCTION (-2)
-#define BB_ENDOFLIST 0
-
-static dbus_bool_t
-string_get_int (const DBusString *str,
- int start,
- long *val)
-{
- const char *p;
-
- if ((_dbus_string_get_length (str) - start) < 4)
- return FALSE;
-
- p = _dbus_string_get_const_data (str);
-
- p += start;
-
- fetch_long (val, p, 4);
-
- return TRUE;
-}
-
-static dbus_bool_t
-string_get_int64 (const DBusString *str,
- int start,
- dbus_int64_t *val)
-{
- const char *p;
-
- if ((_dbus_string_get_length (str) - start) < 8)
- return FALSE;
-
- p = _dbus_string_get_const_data (str);
-
- p += start;
-
- fetch_long64 (val, p, 8);
-
- return TRUE;
-}
-
-static dbus_bool_t
-string_get_string (const DBusString *str,
- int start,
- long terminator,
- DBusString *val,
- int *end)
-{
- int i;
- long n;
-
- i = start;
- while (string_get_int (str, i, &n))
- {
- unsigned char b;
-
- i += 4;
-
- if (n == terminator)
- break;
-
- b = n & 0xff;
- if (b)
- {
- _dbus_string_append_byte (val, b);
- b = (n >> 8) & 0xff;
- if (b)
- {
- _dbus_string_append_byte (val, b);
- b = (n >> 16) & 0xff;
- if (b)
- {
- _dbus_string_append_byte (val, b);
- b = (n >> 24) & 0xff;
- if (b)
- _dbus_string_append_byte (val, b);
- }
- }
- }
- }
-
- *end = i;
-
- return TRUE;
-}
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-/* In gcc33 .bbg files, there's a function name of the form:
- * -1, length, name (padded to 4), -1, checksum
- */
-static dbus_bool_t
-string_get_function (const DBusString *str,
- int start,
- DBusString *funcname,
- int *checksum,
- int *next)
-{
- int end;
- long val;
- int i;
-
- i = start;
-
- if (!string_get_int (str, i, &val))
- die ("no room for -1 before function name\n");
-
- i += 4;
-
- if (val != -1)
- die ("value before function name is not -1\n");
-
- if (!string_get_int (str, i, &val))
- die ("no length found for function name\n");
-
- i += 4;
-
- end = i + val;
- if (end > _dbus_string_get_length (str))
- die ("Function name length points past end of file\n");
-
- if (!_dbus_string_append (funcname,
- _dbus_string_get_const_data (str) + i))
- die ("no memory\n");
-
- /* skip alignment padding the length doesn't include the nul so add 1
- */
- i = _DBUS_ALIGN_VALUE (end + 1, 4);
-
- if (!string_get_int (str, i, &val) ||
- val != -1)
- die ("-1 at end of function name not found\n");
-
- i += 4;
-
- if (!string_get_int (str, i, &val))
- die ("no checksum found at end of function name\n");
-
- i += 4;
-
- *checksum = val;
-
- *next = i;
-
- return TRUE;
-}
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
-static void
-dump_bb_file (const DBusString *contents)
-{
- int i;
- long val;
- int n_functions;
-
- n_functions = 0;
- i = 0;
- while (string_get_int (contents, i, &val))
- {
- i += 4;
-
- switch (val)
- {
- case BB_FILENAME:
- {
- DBusString f;
-
- if (!_dbus_string_init (&f))
- die ("no memory\n");
-
- if (string_get_string (contents, i,
- BB_FILENAME,
- &f, &i))
- {
- printf ("File %s\n", _dbus_string_get_const_data (&f));
- }
- _dbus_string_free (&f);
- }
- break;
- case BB_FUNCTION:
- {
- DBusString f;
- if (!_dbus_string_init (&f))
- die ("no memory\n");
-
- if (string_get_string (contents, i,
- BB_FUNCTION,
- &f, &i))
- {
- printf ("Function %s\n", _dbus_string_get_const_data (&f));
- }
- _dbus_string_free (&f);
-
- n_functions += 1;
- }
- break;
- case BB_ENDOFLIST:
- printf ("End of block\n");
- break;
- default:
- printf ("Line %ld\n", val);
- break;
- }
- }
-
- printf ("%d functions in file\n", n_functions);
-}
-
-#define FLAG_ON_TREE 0x1
-#define FLAG_FAKE 0x2
-#define FLAG_FALL_THROUGH 0x4
-
-static void
-dump_bbg_file (const DBusString *contents)
-{
- int i;
- long val;
- int n_functions;
- int n_arcs;
- int n_blocks;
- int n_arcs_off_tree;
-
- n_arcs_off_tree = 0;
- n_blocks = 0;
- n_arcs = 0;
- n_functions = 0;
- i = 0;
- while (i < _dbus_string_get_length (contents))
- {
- long n_blocks_in_func;
- long n_arcs_in_func;
- int j;
-
-#ifdef DBUS_HAVE_GCC33_GCOV
- /* In gcc33 .bbg files, there's a function name of the form:
- * -1, length, name (padded to 4), -1, checksum
- * after that header on each function description, it's
- * the same as in gcc32
- */
-
- {
- DBusString funcname;
- int checksum;
-
- if (!_dbus_string_init (&funcname))
- die ("no memory\n");
-
- if (!string_get_function (contents, i,
- &funcname, &checksum, &i))
- die ("could not read function name\n");
-
- printf ("Function name is \"%s\" checksum %d\n",
- _dbus_string_get_const_data (&funcname),
- checksum);
-
- _dbus_string_free (&funcname);
- }
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
- if (!string_get_int (contents, i, &val))
- die ("no count of blocks in func found\n");
-
- i += 4;
-
- n_blocks_in_func = val;
-
- if (!string_get_int (contents, i, &n_arcs_in_func))
- break;
-
- i += 4;
-
- printf ("Function has %ld blocks and %ld arcs\n",
- n_blocks_in_func, n_arcs_in_func);
-
- n_functions += 1;
- n_blocks += n_blocks_in_func;
- n_arcs += n_arcs_in_func;
-
- j = 0;
- while (j < n_blocks_in_func)
- {
- long n_arcs_in_block;
- int k;
-
- if (!string_get_int (contents, i, &n_arcs_in_block))
- break;
-
- i += 4;
-
- printf (" Block has %ld arcs\n", n_arcs_in_block);
-
- k = 0;
- while (k < n_arcs_in_block)
- {
- long destination_block;
- long flags;
-
- if (!string_get_int (contents, i, &destination_block))
- break;
-
- i += 4;
-
- if (!string_get_int (contents, i, &flags))
- break;
-
- i += 4;
-
- printf (" Arc has destination block %ld flags 0x%lx\n",
- destination_block, flags);
-
- if ((flags & FLAG_ON_TREE) == 0)
- n_arcs_off_tree += 1;
-
- ++k;
- }
-
- if (k < n_arcs_in_block)
- break;
-
- ++j;
- }
-
- if (j < n_blocks_in_func)
- break;
-
- if (!string_get_int (contents, i, &val))
- break;
-
- i += 4;
-
- if (val != -1)
- die ("-1 separator not found\n");
- }
-
- printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
- n_functions, n_blocks, n_arcs, n_arcs_off_tree);
-}
-
-#ifndef DBUS_HAVE_GCC33_GCOV
-
-/* gcc 3.2 version:
- * The da file contains first a count of arcs in the file,
- * then a count of executions for all "off tree" arcs
- * in the file.
- */
-static void
-dump_da_file (const DBusString *contents)
-{
- int i;
- dbus_int64_t val;
- int n_arcs;
- int claimed_n_arcs;
-
- i = 0;
- if (!string_get_int64 (contents, i, &val))
- return;
-
- i += 8;
-
- printf ("%ld arcs in file\n", (long) val);
- claimed_n_arcs = val;
-
- n_arcs = 0;
- while (string_get_int64 (contents, i, &val))
- {
- i += 8;
-
- printf ("%ld executions of arc %d\n",
- (long) val, n_arcs);
-
- ++n_arcs;
- }
-
- if (n_arcs != claimed_n_arcs)
- {
- printf ("File claimed to have %d arcs but only had %d\n",
- claimed_n_arcs, n_arcs);
- }
-}
-
-#else /* DBUS_HAVE_GCC33_GCOV */
-
-/* gcc 3.3 version:
- * The da file is more complex than 3.2.
- *
- * We have a magic value of "-123" only it isn't really
- * -123, it's -123 as encoded by the crackass gcov-io.h
- * routines. Anyway, 4 bytes.
- *
- * We then have:
- *
- * - 4 byte count of how many functions in the following list
- * - 4 byte length of random extra data
- * - the random extra data, just skip it, info pages have some
- * details on what might be in there or see __bb_exit_func in gcc
- * - then for each function (number of functions given above):
- * . -1, length, funcname, alignment padding, -1
- * . checksum
- * . 4 byte number of arcs in function
- * . 8 bytes each, a count of execution for each arc
- *
- * Now, the whole thing *starting with the magic* can repeat.
- * This is caused by multiple runs of the profiled app appending
- * to the file.
- */
-static void
-dump_da_file (const DBusString *contents)
-{
- int i;
- dbus_int64_t v64;
- long val;
- int n_sections;
- int total_functions;
-
- total_functions = 0;
- n_sections = 0;
-
- i = 0;
- while (i < _dbus_string_get_length (contents))
- {
- int claimed_n_functions;
- int n_functions;
- int total_arcs;
-
- printf (".da file section %d\n", n_sections);
-
- if (!string_get_int (contents, i, &val))
- die ("no magic found in .da file\n");
-
- i += 4;
-
- if (val != -123)
- die ("wrong file magic in .da file\n");
-
- if (!string_get_int (contents, i, &val))
- die ("no function count in .da file\n");
- i += 4;
- claimed_n_functions = val;
-
- printf ("%d functions expected in section %d of .da file\n",
- claimed_n_functions, n_sections);
-
- if (!string_get_int (contents, i, &val))
- die ("no extra data length in .da file\n");
-
- i += 4;
-
- i += val;
-
- total_arcs = 0;
- n_functions = 0;
- while (n_functions < claimed_n_functions)
- {
- DBusString funcname;
- int checksum;
- int claimed_n_arcs;
- int n_arcs;
-
- if (!_dbus_string_init (&funcname))
- die ("no memory\n");
-
- if (!string_get_function (contents, i,
- &funcname, &checksum, &i))
- die ("could not read function name\n");
-
- if (!string_get_int (contents, i, &val))
- die ("no arc count for function\n");
-
- i += 4;
- claimed_n_arcs = val;
-
- printf (" %d arcs in function %d %s checksum %d\n",
- claimed_n_arcs, n_functions,
- _dbus_string_get_const_data (&funcname),
- checksum);
-
- n_arcs = 0;
- while (n_arcs < claimed_n_arcs)
- {
- if (!string_get_int64 (contents, i, &v64))
- die ("did not get execution count for arc\n");
-
- i += 8;
-
- printf (" %ld executions of arc %d (total arcs %d)\n",
- (long) v64, n_arcs, total_arcs + n_arcs);
-
- ++n_arcs;
- }
-
- _dbus_string_free (&funcname);
-
- total_arcs += n_arcs;
- ++n_functions;
- }
-
- printf ("total of %d functions and %d arcs in section %d\n",
- n_functions, total_arcs, n_sections);
-
- total_functions += n_functions;
- ++n_sections;
- }
-
- printf ("%d total function sections in %d total .da file sections\n",
- total_functions, n_sections);
-}
-
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
-typedef struct Arc Arc;
-typedef struct Block Block;
-typedef struct Function Function;
-typedef struct File File;
-typedef struct Line Line;
-
-struct Arc
-{
- int source;
- int target;
- dbus_int64_t arc_count;
- unsigned int count_valid : 1;
- unsigned int on_tree : 1;
- unsigned int fake : 1;
- unsigned int fall_through : 1;
- Arc *pred_next;
- Arc *succ_next;
-};
-
-struct Block
-{
- Arc *succ;
- Arc *pred;
- dbus_int64_t succ_count;
- dbus_int64_t pred_count;
- dbus_int64_t exec_count;
- DBusList *lines;
- unsigned int count_valid : 1;
- unsigned int on_tree : 1;
- unsigned int inside_dbus_build_tests : 1;
-};
-
-struct Function
-{
- char *name;
- int checksum;
- Block *block_graph;
- int n_blocks;
- /* number of blocks in DBUS_BUILD_TESTS */
- int n_test_blocks;
- int n_test_blocks_executed;
- /* number of blocks outside DBUS_BUILD_TESTS */
- int n_nontest_blocks;
- int n_nontest_blocks_executed;
- /* Summary result flags */
- unsigned int unused : 1;
- unsigned int inside_dbus_build_tests : 1;
- unsigned int partial : 1; /* only some of the blocks were executed */
-};
-
-struct Line
-{
- int number;
- char *text;
- DBusList *blocks;
- unsigned int inside_dbus_build_tests : 1;
- unsigned int partial : 1; /* only some of the blocks were executed */
-};
-
-struct File
-{
- char *name;
- Line *lines;
- int n_lines;
- DBusList *functions;
-};
-
-static void
-function_add_arc (Function *function,
- long source,
- long target,
- long flags)
-{
- Arc *arc;
-
- arc = dbus_new0 (Arc, 1);
- if (arc == NULL)
- die ("no memory\n");
-
- arc->target = target;
- arc->source = source;
-
- arc->succ_next = function->block_graph[source].succ;
- function->block_graph[source].succ = arc;
- function->block_graph[source].succ_count += 1;
-
- arc->pred_next = function->block_graph[target].pred;
- function->block_graph[target].pred = arc;
- function->block_graph[target].pred_count += 1;
-
- if ((flags & FLAG_ON_TREE) != 0)
- arc->on_tree = TRUE;
-
- if ((flags & FLAG_FAKE) != 0)
- arc->fake = TRUE;
-
- if ((flags & FLAG_FALL_THROUGH) != 0)
- arc->fall_through = TRUE;
-}
-
-
-static Arc*
-reverse_arcs (Arc *arc)
-{
- struct Arc *prev = 0;
- struct Arc *next;
-
- for ( ; arc; arc = next)
- {
- next = arc->succ_next;
- arc->succ_next = prev;
- prev = arc;
- }
-
- return prev;
-}
-
-static void
-function_reverse_succ_arcs (Function *func)
-{
- /* Must reverse the order of all succ arcs, to ensure that they match
- * the order of the data in the .da file.
- */
- int i;
-
- for (i = 0; i < func->n_blocks; i++)
- if (func->block_graph[i].succ)
- func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
-}
-
-static void
-get_functions_from_bbg (const DBusString *contents,
- DBusList **functions)
-{
- int i;
- long val;
- int n_functions;
- int n_arcs;
- int n_blocks;
- int n_arcs_off_tree;
-
-#if 0
- printf ("Loading arcs and blocks from .bbg file\n");
-#endif
-
- n_arcs_off_tree = 0;
- n_blocks = 0;
- n_arcs = 0;
- n_functions = 0;
- i = 0;
- while (i < _dbus_string_get_length (contents))
- {
- Function *func;
- long n_blocks_in_func;
- long n_arcs_in_func;
- int j;
-
-#ifdef DBUS_HAVE_GCC33_GCOV
- DBusString funcname;
- int checksum;
-
- /* In gcc33 .bbg files, there's a function name of the form:
- * -1, length, name (padded to 4), -1, checksum
- * after that header on each function description, it's
- * the same as in gcc32
- */
- if (!_dbus_string_init (&funcname))
- die ("no memory\n");
-
- if (!string_get_function (contents, i,
- &funcname, &checksum, &i))
- die ("could not read function name\n");
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
- if (!string_get_int (contents, i, &val))
- break;
-
- n_blocks_in_func = val;
-
- i += 4;
-
- if (!string_get_int (contents, i, &n_arcs_in_func))
- break;
-
- i += 4;
-
- n_functions += 1;
- n_blocks += n_blocks_in_func;
- n_arcs += n_arcs_in_func;
-
- func = dbus_new0 (Function, 1);
- if (func == NULL)
- die ("no memory\n");
-
-#ifdef DBUS_HAVE_GCC33_GCOV
- func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
- func->checksum = checksum;
- _dbus_string_free (&funcname);
-#endif
-
- func->block_graph = dbus_new0 (Block, n_blocks_in_func);
- func->n_blocks = n_blocks_in_func;
-
- j = 0;
- while (j < n_blocks_in_func)
- {
- long n_arcs_in_block;
- int k;
-
- if (!string_get_int (contents, i, &n_arcs_in_block))
- break;
-
- i += 4;
-
- k = 0;
- while (k < n_arcs_in_block)
- {
- long destination_block;
- long flags;
-
- if (!string_get_int (contents, i, &destination_block))
- break;
-
- i += 4;
-
- if (!string_get_int (contents, i, &flags))
- break;
-
- i += 4;
-
- if ((flags & FLAG_ON_TREE) == 0)
- n_arcs_off_tree += 1;
-
- function_add_arc (func, j, destination_block,
- flags);
-
- ++k;
- }
-
- if (k < n_arcs_in_block)
- break;
-
- ++j;
- }
-
- if (j < n_blocks_in_func)
- break;
-
- function_reverse_succ_arcs (func);
-
- if (!_dbus_list_append (functions, func))
- die ("no memory\n");
-
- if (!string_get_int (contents, i, &val))
- break;
-
- i += 4;
-
- if (val != -1)
- die ("-1 separator not found in .bbg file\n");
- }
-
-#if 0
- printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
- n_functions, n_blocks, n_arcs, n_arcs_off_tree);
-#endif
-
- _dbus_assert (n_functions == _dbus_list_get_length (functions));
-}
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-static void
-add_counts_from_da (const DBusString *contents,
- DBusList **functions)
-{
- int i;
- dbus_int64_t v64;
- long val;
- int n_sections;
- DBusList *link;
- Function *current_func;
- int current_block;
- Arc *current_arc;
-
- n_sections = 0;
-
- i = 0;
- while (i < _dbus_string_get_length (contents))
- {
- int claimed_n_functions;
- int n_functions;
-
- if (!string_get_int (contents, i, &val))
- die ("no magic found in .da file\n");
-
- i += 4;
-
- if (val != -123)
- die ("wrong file magic in .da file\n");
-
- if (!string_get_int (contents, i, &val))
- die ("no function count in .da file\n");
- i += 4;
- claimed_n_functions = val;
-
- if (!string_get_int (contents, i, &val))
- die ("no extra data length in .da file\n");
-
- i += 4;
-
- i += val;
-
- link = _dbus_list_get_first_link (functions);
- if (link == NULL)
- goto no_more_functions;
-
- n_functions = 0;
- while (n_functions < claimed_n_functions && link != NULL)
- {
- DBusString funcname;
- int checksum;
- int claimed_n_arcs;
- int n_arcs;
-
- current_func = link->data;
- current_block = 0;
- current_arc = current_func->block_graph[current_block].succ;
-
- if (!_dbus_string_init (&funcname))
- die ("no memory\n");
-
- if (!string_get_function (contents, i,
- &funcname, &checksum, &i))
- die ("could not read function name\n");
-
- if (!_dbus_string_equal_c_str (&funcname, current_func->name))
- {
- fprintf (stderr, "Expecting .da info for %s but got %s\n",
- current_func->name,
- _dbus_string_get_const_data (&funcname));
- exit (1);
- }
-
- if (checksum != current_func->checksum)
- die (".da file checksum doesn't match checksum from .bbg file\n");
-
- if (!string_get_int (contents, i, &val))
- die ("no arc count for function\n");
-
- i += 4;
- claimed_n_arcs = val;
-
- /* For each arc in the profile, find the corresponding
- * arc in the function and increment its count
- */
- n_arcs = 0;
- while (n_arcs < claimed_n_arcs)
- {
- if (!string_get_int64 (contents, i, &v64))
- die ("did not get execution count for arc\n");
-
- i += 8;
-
- /* Find the next arc in the function that isn't on tree */
- while (current_arc == NULL ||
- current_arc->on_tree)
- {
- if (current_arc == NULL)
- {
- ++current_block;
-
- if (current_block >= current_func->n_blocks)
- die ("too many blocks in function\n");
-
- current_arc = current_func->block_graph[current_block].succ;
- }
- else
- {
- current_arc = current_arc->succ_next;
- }
- }
-
- _dbus_assert (current_arc != NULL);
- _dbus_assert (!current_arc->on_tree);
-
- current_arc->arc_count = v64;
- current_arc->count_valid = TRUE;
- current_func->block_graph[current_block].succ_count -= 1;
- current_func->block_graph[current_arc->target].pred_count -= 1;
-
- ++n_arcs;
-
- current_arc = current_arc->succ_next;
- }
-
- _dbus_string_free (&funcname);
-
- link = _dbus_list_get_next_link (functions, link);
- ++n_functions;
-
- if (link == NULL && n_functions < claimed_n_functions)
- {
- fprintf (stderr, "Ran out of functions loading .da file\n");
- goto no_more_functions;
- }
- }
-
- no_more_functions:
-
- ++n_sections;
- }
-}
-#else /* DBUS_HAVE_GCC33_GCOV */
-static void
-add_counts_from_da (const DBusString *contents,
- DBusList **functions)
-{
- int i;
- dbus_int64_t val;
- int n_arcs;
- int claimed_n_arcs;
- DBusList *link;
- Function *current_func;
- int current_block;
- Arc *current_arc;
-
-#if 0
- printf ("Loading execution count for each arc from .da file\n");
-#endif
-
- i = 0;
- if (!string_get_int64 (contents, i, &val))
- return;
-
- i += 8;
-
- claimed_n_arcs = val;
-
- link = _dbus_list_get_first_link (functions);
- if (link == NULL)
- goto done;
-
- current_func = link->data;
- current_block = 0;
- current_arc = current_func->block_graph[current_block].succ;
-
- n_arcs = 0;
- while (string_get_int64 (contents, i, &val))
- {
- i += 8;
-
- while (current_arc == NULL ||
- current_arc->on_tree)
- {
- if (current_arc == NULL)
- {
- ++current_block;
-
- if (current_block == current_func->n_blocks)
- {
- link = _dbus_list_get_next_link (functions, link);
- if (link == NULL)
- {
- fprintf (stderr, "Ran out of functions loading .da file\n");
- goto done;
- }
- current_func = link->data;
- current_block = 0;
- }
-
- current_arc = current_func->block_graph[current_block].succ;
- }
- else
- {
- current_arc = current_arc->succ_next;
- }
- }
-
- _dbus_assert (current_arc != NULL);
- _dbus_assert (!current_arc->on_tree);
-
- current_arc->arc_count = val;
- current_arc->count_valid = TRUE;
- current_func->block_graph[current_block].succ_count -= 1;
- current_func->block_graph[current_arc->target].pred_count -= 1;
-
- ++n_arcs;
-
- current_arc = current_arc->succ_next;
- }
-
- done:
-
- if (n_arcs != claimed_n_arcs)
- {
- fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
- claimed_n_arcs, n_arcs);
- exit (1);
- }
-
-#if 0
- printf ("%d arcs in file\n", n_arcs);
-#endif
-}
-#endif
-
-static void
-function_solve_graph (Function *func)
-{
- int passes, changes;
- dbus_int64_t total;
- int i;
- Arc *arc;
- Block *block_graph;
- int n_blocks;
-
-#if 0
- printf ("Solving function graph\n");
-#endif
-
- n_blocks = func->n_blocks;
- block_graph = func->block_graph;
-
- /* For every block in the file,
- - if every exit/entrance arc has a known count, then set the block count
- - if the block count is known, and every exit/entrance arc but one has
- a known execution count, then set the count of the remaining arc
-
- As arc counts are set, decrement the succ/pred count, but don't delete
- the arc, that way we can easily tell when all arcs are known, or only
- one arc is unknown. */
-
- /* The order that the basic blocks are iterated through is important.
- Since the code that finds spanning trees starts with block 0, low numbered
- arcs are put on the spanning tree in preference to high numbered arcs.
- Hence, most instrumented arcs are at the end. Graph solving works much
- faster if we propagate numbers from the end to the start.
-
- This takes an average of slightly more than 3 passes. */
-
- changes = 1;
- passes = 0;
- while (changes)
- {
- passes++;
- changes = 0;
-
- for (i = n_blocks - 1; i >= 0; i--)
- {
- if (! block_graph[i].count_valid)
- {
- if (block_graph[i].succ_count == 0)
- {
- total = 0;
- for (arc = block_graph[i].succ; arc;
- arc = arc->succ_next)
- total += arc->arc_count;
- block_graph[i].exec_count = total;
- block_graph[i].count_valid = 1;
- changes = 1;
- }
- else if (block_graph[i].pred_count == 0)
- {
- total = 0;
- for (arc = block_graph[i].pred; arc;
- arc = arc->pred_next)
- total += arc->arc_count;
- block_graph[i].exec_count = total;
- block_graph[i].count_valid = 1;
- changes = 1;
- }
- }
- if (block_graph[i].count_valid)
- {
- if (block_graph[i].succ_count == 1)
- {
- total = 0;
- /* One of the counts will be invalid, but it is zero,
- so adding it in also doesn't hurt. */
- for (arc = block_graph[i].succ; arc;
- arc = arc->succ_next)
- total += arc->arc_count;
- /* Calculate count for remaining arc by conservation. */
- total = block_graph[i].exec_count - total;
- /* Search for the invalid arc, and set its count. */
- for (arc = block_graph[i].succ; arc;
- arc = arc->succ_next)
- if (! arc->count_valid)
- break;
- if (! arc)
- die ("arc == NULL\n");
- arc->count_valid = 1;
- arc->arc_count = total;
- block_graph[i].succ_count -= 1;
-
- block_graph[arc->target].pred_count -= 1;
- changes = 1;
- }
- if (block_graph[i].pred_count == 1)
- {
- total = 0;
- /* One of the counts will be invalid, but it is zero,
- so adding it in also doesn't hurt. */
- for (arc = block_graph[i].pred; arc;
- arc = arc->pred_next)
- total += arc->arc_count;
- /* Calculate count for remaining arc by conservation. */
- total = block_graph[i].exec_count - total;
- /* Search for the invalid arc, and set its count. */
- for (arc = block_graph[i].pred; arc;
- arc = arc->pred_next)
- if (! arc->count_valid)
- break;
- if (! arc)
- die ("arc == NULL\n");
- arc->count_valid = 1;
- arc->arc_count = total;
- block_graph[i].pred_count -= 1;
-
- block_graph[arc->source].succ_count -= 1;
- changes = 1;
- }
- }
- }
- }
-
- /* If the graph has been correctly solved, every block will have a
- * succ and pred count of zero.
- */
- {
- dbus_bool_t header = FALSE;
- for (i = 0; i < n_blocks; i++)
- {
- if (block_graph[i].succ_count || block_graph[i].pred_count)
- {
- if (!header)
- {
- fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
- func->name);
- fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
- header = TRUE;
- }
- fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
- i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
- }
- }
- }
-}
-
-static void
-solve_graphs (DBusList **functions)
-{
- DBusList *link;
-
- link = _dbus_list_get_first_link (functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- function_solve_graph (func);
-
- link = _dbus_list_get_next_link (functions, link);
- }
-}
-
-static void
-load_functions_for_c_file (const DBusString *filename,
- DBusList **functions)
-{
- DBusString bbg_filename;
- DBusString da_filename;
- DBusString gcno_filename;
- DBusString gcda_filename;
- DBusString contents;
- DBusString *name;
- DBusError error;
-
- /* With latest gcc it's .gcno instead of .bbg and
- * gcda instead of .da
- */
-
- dbus_error_init (&error);
-
- if (!_dbus_string_init (&bbg_filename) ||
- !_dbus_string_init (&da_filename) ||
- !_dbus_string_init (&gcno_filename) ||
- !_dbus_string_init (&gcda_filename) ||
- !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
- !_dbus_string_copy (filename, 0, &da_filename, 0) ||
- !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
- !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
- !_dbus_string_init (&contents))
- die ("no memory\n");
-
- _dbus_string_shorten (&bbg_filename, 2);
- _dbus_string_shorten (&da_filename, 2);
-
- if (!_dbus_string_append (&bbg_filename, ".bbg") ||
- !_dbus_string_append (&da_filename, ".da") ||
- !_dbus_string_append (&bbg_filename, ".gcno") ||
- !_dbus_string_append (&bbg_filename, ".gcda"))
- die ("no memory\n");
-
- if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
- name = &gcno_filename;
- else
- name = &bbg_filename;
-
- if (!_dbus_file_get_contents (&contents, name,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- exit (1);
- }
-
- get_functions_from_bbg (&contents, functions);
-
- _dbus_string_set_length (&contents, 0);
-
- if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
- name = &gcda_filename;
- else
- name = &da_filename;
-
- if (!_dbus_file_get_contents (&contents, name,
- &error))
- {
- /* Try .libs/file.da */
- int slash;
-
- if (_dbus_string_find_byte_backward (name,
- _dbus_string_get_length (name),
- '/',
- &slash))
- {
- DBusString libs;
- _dbus_string_init_const (&libs, "/.libs");
-
- if (!_dbus_string_copy (&libs, 0, name, slash))
- die ("no memory");
-
- dbus_error_free (&error);
- if (!_dbus_file_get_contents (&contents, name,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- exit (1);
- }
- }
- else
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- exit (1);
- }
- }
-
- add_counts_from_da (&contents, functions);
-
- solve_graphs (functions);
-
- _dbus_string_free (&contents);
- _dbus_string_free (&da_filename);
- _dbus_string_free (&bbg_filename);
-}
-
-static void
-get_lines_from_bb_file (const DBusString *contents,
- File *fl)
-{
- int i;
- long val;
- int n_functions;
- dbus_bool_t in_our_file;
- DBusList *link;
- Function *func;
- int block;
-
-#if 0
- printf ("Getting line numbers for blocks from .bb file\n");
-#endif
-
- /* There's this "filename" field in the .bb file which
- * mysteriously comes *after* the first function in the
- * file in the .bb file; and every .bb file seems to
- * have only one filename. I don't understand
- * what's going on here, so just set in_our_file = TRUE
- * at the start categorically.
- */
-
- block = 0;
- func = NULL;
- in_our_file = TRUE;
- link = _dbus_list_get_first_link (&fl->functions);
- n_functions = 0;
- i = 0;
- while (string_get_int (contents, i, &val))
- {
- i += 4;
-
- switch (val)
- {
- case BB_FILENAME:
- {
- DBusString f;
-
- if (!_dbus_string_init (&f))
- die ("no memory\n");
-
- if (string_get_string (contents, i,
- BB_FILENAME,
- &f, &i))
- {
- /* fl->name is a full path and the filename in .bb is
- * not.
- */
- DBusString tmp_str;
-
- _dbus_string_init_const (&tmp_str, fl->name);
-
- if (_dbus_string_ends_with_c_str (&tmp_str,
- _dbus_string_get_const_data (&f)))
- in_our_file = TRUE;
- else
- in_our_file = FALSE;
-
-#if 0
- fprintf (stderr,
- "File %s in .bb, looking for %s, in_our_file = %d\n",
- _dbus_string_get_const_data (&f),
- fl->name,
- in_our_file);
-#endif
- }
- _dbus_string_free (&f);
- }
- break;
- case BB_FUNCTION:
- {
- DBusString f;
- if (!_dbus_string_init (&f))
- die ("no memory\n");
-
- if (string_get_string (contents, i,
- BB_FUNCTION,
- &f, &i))
- {
-#if 0
- fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
-#endif
-
- block = 0;
-
- if (in_our_file)
- {
- if (link == NULL)
- {
- fprintf (stderr, "No function object for function %s\n",
- _dbus_string_get_const_data (&f));
- }
- else
- {
- func = link->data;
- link = _dbus_list_get_next_link (&fl->functions, link);
-
- if (func->name == NULL)
- {
- if (!_dbus_string_copy_data (&f, &func->name))
- die ("no memory\n");
- }
- else
- {
- if (!_dbus_string_equal_c_str (&f, func->name))
- {
- fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
- func->name, strlen (func->name),
- _dbus_string_get_const_data (&f),
- _dbus_string_get_length (&f));
-
- }
- }
- }
- }
- }
- _dbus_string_free (&f);
-
- n_functions += 1;
- }
- break;
- case BB_ENDOFLIST:
- block += 1;
- break;
- default:
-#if 0
- fprintf (stderr, "Line %ld\n", val);
-#endif
-
- if (val >= fl->n_lines)
- {
- fprintf (stderr, "Line %ld but file only has %d lines\n",
- val, fl->n_lines);
- }
- else if (func != NULL)
- {
- val -= 1; /* To convert the 1-based line number to 0-based */
- _dbus_assert (val >= 0);
-
- if (block < func->n_blocks)
- {
- if (!_dbus_list_append (&func->block_graph[block].lines,
- &fl->lines[val]))
- die ("no memory\n");
-
-
- if (!_dbus_list_append (&fl->lines[val].blocks,
- &func->block_graph[block]))
- die ("no memory\n");
- }
- else
- {
- fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
- block, func->n_blocks);
- }
- }
- else
- {
- fprintf (stderr, "Line %ld given outside of any function\n",
- val);
- }
-
- break;
- }
- }
-
-#if 0
- printf ("%d functions in file\n", n_functions);
-#endif
-}
-
-
-static void
-load_block_line_associations (const DBusString *filename,
- File *f)
-{
- DBusString bb_filename;
- DBusString contents;
- DBusError error;
-
- dbus_error_init (&error);
-
- if (!_dbus_string_init (&bb_filename) ||
- !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
- !_dbus_string_init (&contents))
- die ("no memory\n");
-
- _dbus_string_shorten (&bb_filename, 2);
-
- if (!_dbus_string_append (&bb_filename, ".bb"))
- die ("no memory\n");
-
- if (!_dbus_file_get_contents (&contents, &bb_filename,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- exit (1);
- }
-
- get_lines_from_bb_file (&contents, f);
-
- _dbus_string_free (&contents);
- _dbus_string_free (&bb_filename);
-}
-
-static int
-count_lines_in_string (const DBusString *str)
-{
- int n_lines;
- const char *p;
- const char *prev;
- const char *end;
- const char *last_line_end;
-
-#if 0
- printf ("Counting lines in source file\n");
-#endif
-
- n_lines = 0;
- prev = NULL;
- p = _dbus_string_get_const_data (str);
- end = p + _dbus_string_get_length (str);
- last_line_end = p;
- while (p != end)
- {
- /* too lazy to handle \r\n as one linebreak */
- if (*p == '\n' || *p == '\r')
- {
- ++n_lines;
- last_line_end = p + 1;
- }
-
- prev = p;
- ++p;
- }
-
- if (last_line_end != p)
- ++n_lines;
-
- return n_lines;
-}
-
-static void
-fill_line_content (const DBusString *str,
- Line *lines)
-{
- int n_lines;
- const char *p;
- const char *prev;
- const char *end;
- const char *last_line_end;
-
-#if 0
- printf ("Saving contents of each line in source file\n");
-#endif
-
- n_lines = 0;
- prev = NULL;
- p = _dbus_string_get_const_data (str);
- end = p + _dbus_string_get_length (str);
- last_line_end = p;
- while (p != end)
- {
- if (*p == '\n' || *p == '\r')
- {
- lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
- if (lines[n_lines].text == NULL)
- die ("no memory\n");
-
- memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
- lines[n_lines].number = n_lines + 1;
-
- ++n_lines;
-
- last_line_end = p + 1;
- }
-
- prev = p;
- ++p;
- }
-
- if (p != last_line_end)
- {
- memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
- ++n_lines;
- }
-}
-
-static void
-mark_inside_dbus_build_tests (File *f)
-{
- int i;
- DBusList *link;
- int inside_depth;
-
- inside_depth = 0;
- i = 0;
- while (i < f->n_lines)
- {
- Line *l = &f->lines[i];
- dbus_bool_t is_verbose;
-
- is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
-
- if (inside_depth == 0)
- {
- const char *a, *b;
-
- a = strstr (l->text, "#if");
- b = strstr (l->text, "DBUS_BUILD_TESTS");
- if (a && b && (a < b))
- inside_depth += 1;
- }
- else
- {
- if (strstr (l->text, "#if") != NULL)
- inside_depth += 1;
- else if (strstr (l->text, "#endif") != NULL)
- inside_depth -= 1;
- }
-
- if (inside_depth > 0 || is_verbose)
- {
- /* Mark the line and its blocks */
- DBusList *blink;
-
- l->inside_dbus_build_tests = TRUE;
-
- blink = _dbus_list_get_first_link (&l->blocks);
- while (blink != NULL)
- {
- Block *b = blink->data;
-
- b->inside_dbus_build_tests = TRUE;
-
- blink = _dbus_list_get_next_link (&l->blocks, blink);
- }
- }
-
- ++i;
- }
-
- /* Now mark functions where for all blocks that are associated
- * with a source line, the block is inside_dbus_build_tests.
- */
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- /* The issue is that some blocks aren't associated with a source line.
- * Assume they are inside/outside tests according to the source
- * line of the preceding block. For the first block, make it
- * match the first following block with a line associated.
- */
- if (func->block_graph[0].lines == NULL)
- {
- /* find first following line */
- i = 1;
- while (i < func->n_blocks)
- {
- if (func->block_graph[i].lines != NULL)
- {
- func->block_graph[0].inside_dbus_build_tests =
- func->block_graph[i].inside_dbus_build_tests;
- break;
- }
-
- ++i;
- }
- }
-
- /* Now mark all blocks but the first */
- i = 1;
- while (i < func->n_blocks)
- {
- if (func->block_graph[i].lines == NULL)
- {
- func->block_graph[i].inside_dbus_build_tests =
- func->block_graph[i-1].inside_dbus_build_tests;
- }
-
- ++i;
- }
-
- i = 0;
- while (i < func->n_blocks)
- {
- /* Break as soon as any block is not a test block */
- if (func->block_graph[i].lines != NULL &&
- !func->block_graph[i].inside_dbus_build_tests)
- break;
-
- ++i;
- }
-
- if (i == func->n_blocks)
- func->inside_dbus_build_tests = TRUE;
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-}
-
-static void
-mark_coverage (File *f)
-{
- int i;
- DBusList *link;
-
- i = 0;
- while (i < f->n_lines)
- {
- Line *l = &f->lines[i];
- DBusList *blink;
- int n_blocks;
- int n_blocks_executed;
-
- n_blocks = 0;
- n_blocks_executed = 0;
- blink = _dbus_list_get_first_link (&l->blocks);
- while (blink != NULL)
- {
- Block *b = blink->data;
-
- if (b->exec_count > 0)
- n_blocks_executed += 1;
-
- n_blocks += 1;
-
- blink = _dbus_list_get_next_link (&l->blocks, blink);
- }
-
- if (n_blocks_executed > 0 &&
- n_blocks_executed < n_blocks)
- l->partial = TRUE;
-
- ++i;
- }
-
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
- int i;
- int n_test_blocks;
- int n_test_blocks_executed;
- int n_nontest_blocks;
- int n_nontest_blocks_executed;
-
- n_test_blocks = 0;
- n_test_blocks_executed = 0;
- n_nontest_blocks = 0;
- n_nontest_blocks_executed = 0;
-
- i = 0;
- while (i < func->n_blocks)
- {
- if (!func->block_graph[i].inside_dbus_build_tests)
- {
- n_nontest_blocks += 1;
-
- if (func->block_graph[i].exec_count > 0)
- n_nontest_blocks_executed += 1;
- }
- else
- {
- n_test_blocks += 1;
-
- if (func->block_graph[i].exec_count > 0)
- n_test_blocks_executed += 1;
- }
-
- ++i;
- }
-
- if (n_nontest_blocks_executed > 0 &&
- n_nontest_blocks_executed < n_nontest_blocks)
- func->partial = TRUE;
-
- if (n_nontest_blocks_executed == 0 &&
- n_nontest_blocks > 0)
- func->unused = TRUE;
-
- func->n_test_blocks = n_test_blocks;
- func->n_test_blocks_executed = n_test_blocks_executed;
- func->n_nontest_blocks = n_nontest_blocks;
- func->n_nontest_blocks_executed = n_nontest_blocks_executed;
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-}
-
-static File*
-load_c_file (const DBusString *filename)
-{
- DBusString contents;
- DBusError error;
- File *f;
-
- f = dbus_new0 (File, 1);
- if (f == NULL)
- die ("no memory\n");
-
- if (!_dbus_string_copy_data (filename, &f->name))
- die ("no memory\n");
-
- if (!_dbus_string_init (&contents))
- die ("no memory\n");
-
- dbus_error_init (&error);
-
- if (!_dbus_file_get_contents (&contents, filename,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- dbus_error_free (&error);
- exit (1);
- }
-
- load_functions_for_c_file (filename, &f->functions);
-
- f->n_lines = count_lines_in_string (&contents);
- f->lines = dbus_new0 (Line, f->n_lines);
- if (f->lines == NULL)
- die ("no memory\n");
-
- fill_line_content (&contents, f->lines);
-
- _dbus_string_free (&contents);
-
- load_block_line_associations (filename, f);
-
- mark_inside_dbus_build_tests (f);
- mark_coverage (f);
-
- return f;
-}
-
-typedef struct Stats Stats;
-
-struct Stats
-{
- int n_blocks;
- int n_blocks_executed;
- int n_blocks_inside_dbus_build_tests;
-
- int n_lines; /* lines that have blocks on them */
- int n_lines_executed;
- int n_lines_partial;
- int n_lines_inside_dbus_build_tests;
-
- int n_functions;
- int n_functions_executed;
- int n_functions_partial;
- int n_functions_inside_dbus_build_tests;
-};
-
-static dbus_bool_t
-line_was_executed (Line *l)
-{
- DBusList *link;
-
- link = _dbus_list_get_first_link (&l->blocks);
- while (link != NULL)
- {
- Block *b = link->data;
-
- if (b->exec_count > 0)
- return TRUE;
-
- link = _dbus_list_get_next_link (&l->blocks, link);
- }
-
- return FALSE;
-}
-
-
-static int
-line_exec_count (Line *l)
-{
- DBusList *link;
- dbus_int64_t total;
-
- total = 0;
- link = _dbus_list_get_first_link (&l->blocks);
- while (link != NULL)
- {
- Block *b = link->data;
-
- total += b->exec_count;
-
- link = _dbus_list_get_next_link (&l->blocks, link);
- }
-
- return total;
-}
-
-static void
-merge_stats_for_file (Stats *stats,
- File *f)
-{
- int i;
- DBusList *link;
-
- for (i = 0; i < f->n_lines; ++i)
- {
- Line *l = &f->lines[i];
-
- if (l->inside_dbus_build_tests)
- {
- stats->n_lines_inside_dbus_build_tests += 1;
- continue;
- }
-
- if (line_was_executed (l))
- stats->n_lines_executed += 1;
-
- if (l->blocks != NULL)
- stats->n_lines += 1;
-
- if (l->partial)
- stats->n_lines_partial += 1;
- }
-
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (func->inside_dbus_build_tests)
- stats->n_functions_inside_dbus_build_tests += 1;
- else
- {
- stats->n_functions += 1;
-
- if (!func->unused)
- stats->n_functions_executed += 1;
-
- if (func->partial)
- stats->n_functions_partial += 1;
- }
-
- stats->n_blocks_inside_dbus_build_tests +=
- func->n_test_blocks;
-
- stats->n_blocks_executed +=
- func->n_nontest_blocks_executed;
-
- stats->n_blocks +=
- func->n_nontest_blocks;
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-}
-
-/* The output of this matches gcov exactly ("diff" shows no difference) */
-static void
-print_annotated_source_gcov_format (File *f)
-{
- int i;
-
- i = 0;
- while (i < f->n_lines)
- {
- Line *l = &f->lines[i];
-
- if (l->blocks != NULL)
- {
- int exec_count;
-
- exec_count = line_exec_count (l);
-
- if (exec_count > 0)
- printf ("%12d %s\n",
- exec_count, l->text);
- else
- printf (" ###### %s\n", l->text);
- }
- else
- {
- printf ("\t\t%s\n", l->text);
- }
-
- ++i;
- }
-}
-
-static void
-print_annotated_source (File *f)
-{
- int i;
-
- i = 0;
- while (i < f->n_lines)
- {
- Line *l = &f->lines[i];
-
- if (l->inside_dbus_build_tests)
- printf ("*");
- else
- printf (" ");
-
- if (l->blocks != NULL)
- {
- int exec_count;
-
- exec_count = line_exec_count (l);
-
- if (exec_count > 0)
- printf ("%12d %s\n",
- exec_count, l->text);
- else
- printf (" ###### %s\n", l->text);
- }
- else
- {
- printf ("\t\t%s\n", l->text);
- }
-
- ++i;
- }
-}
-
-static void
-print_block_superdetails (File *f)
-{
- DBusList *link;
- int i;
-
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- printf ("=== %s():\n", func->name);
-
- i = 0;
- while (i < func->n_blocks)
- {
- Block *b = &func->block_graph[i];
- DBusList *l;
-
- printf (" %5d executed %d times%s\n", i,
- (int) b->exec_count,
- b->inside_dbus_build_tests ?
- " [inside DBUS_BUILD_TESTS]" : "");
-
- l = _dbus_list_get_first_link (&b->lines);
- while (l != NULL)
- {
- Line *line = l->data;
-
- printf ("4%d\t%s\n", line->number, line->text);
-
- l = _dbus_list_get_next_link (&b->lines, l);
- }
-
- ++i;
- }
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-}
-
-static void
-print_one_file (const DBusString *filename)
-{
- if (_dbus_string_ends_with_c_str (filename, ".bb"))
- {
- DBusString contents;
- DBusError error;
-
- if (!_dbus_string_init (&contents))
- die ("no memory\n");
-
- dbus_error_init (&error);
-
- if (!_dbus_file_get_contents (&contents, filename,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- dbus_error_free (&error);
- exit (1);
- }
-
- dump_bb_file (&contents);
-
- _dbus_string_free (&contents);
- }
- else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
- {
- DBusString contents;
- DBusError error;
-
- if (!_dbus_string_init (&contents))
- die ("no memory\n");
-
- dbus_error_init (&error);
-
- if (!_dbus_file_get_contents (&contents, filename,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- dbus_error_free (&error);
- exit (1);
- }
-
- dump_bbg_file (&contents);
-
- _dbus_string_free (&contents);
- }
- else if (_dbus_string_ends_with_c_str (filename, ".da"))
- {
- DBusString contents;
- DBusError error;
-
- if (!_dbus_string_init (&contents))
- die ("no memory\n");
-
- dbus_error_init (&error);
-
- if (!_dbus_file_get_contents (&contents, filename,
- &error))
- {
- fprintf (stderr, "Could not open file: %s\n",
- error.message);
- dbus_error_free (&error);
- exit (1);
- }
-
- dump_da_file (&contents);
-
- _dbus_string_free (&contents);
- }
- else if (_dbus_string_ends_with_c_str (filename, ".c"))
- {
- File *f;
-
- f = load_c_file (filename);
-
- print_annotated_source (f);
- }
- else
- {
- fprintf (stderr, "Unknown file type %s\n",
- _dbus_string_get_const_data (filename));
- exit (1);
- }
-}
-
-static void
-print_untested_functions (File *f)
-{
- DBusList *link;
- dbus_bool_t found;
-
- found = FALSE;
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (func->unused &&
- !func->inside_dbus_build_tests)
- found = TRUE;
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-
- if (!found)
- return;
-
- printf ("Untested functions in %s\n", f->name);
- printf ("=======\n");
-
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (func->unused &&
- !func->inside_dbus_build_tests)
- printf (" %s\n", func->name);
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-
- printf ("\n");
-}
-
-static void
-print_poorly_tested_functions (File *f,
- Stats *stats)
-{
- DBusList *link;
- dbus_bool_t found;
-
-#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
-
-#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
-
-#define POORLY_TESTED(function) (!(function)->unused && \
- (function)->n_nontest_blocks > 0 && \
- TEST_FRACTION (function) < AVERAGE_COVERAGE)
-
- found = FALSE;
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (POORLY_TESTED (func))
- found = TRUE;
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-
- if (!found)
- return;
-
- printf ("Below average functions in %s\n", f->name);
- printf ("=======\n");
-
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (POORLY_TESTED (func))
- printf (" %s (%d%%)\n", func->name,
- (int) (TEST_FRACTION (func) * 100));
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-
- printf ("\n");
-}
-
-static int
-func_cmp (const void *a,
- const void *b)
-{
- Function *af = *(Function**) a;
- Function *bf = *(Function**) b;
- int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
- int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
-
- /* Sort by number of untested blocks */
- return b_untested - a_untested;
-}
-
-static void
-print_n_untested_blocks_by_function (File *f,
- Stats *stats)
-{
- DBusList *link;
- Function **funcs;
- int n_found;
- int i;
-
- n_found = 0;
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (func->n_nontest_blocks_executed <
- func->n_nontest_blocks)
- n_found += 1;
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-
- if (n_found == 0)
- return;
-
- /* make an array so we can use qsort */
-
- funcs = dbus_new (Function*, n_found);
- if (funcs == NULL)
- return;
-
- i = 0;
- link = _dbus_list_get_first_link (&f->functions);
- while (link != NULL)
- {
- Function *func = link->data;
-
- if (func->n_nontest_blocks_executed <
- func->n_nontest_blocks)
- {
- funcs[i] = func;
- ++i;
- }
-
- link = _dbus_list_get_next_link (&f->functions, link);
- }
-
- _dbus_assert (i == n_found);
-
- qsort (funcs, n_found, sizeof (Function*),
- func_cmp);
-
- printf ("Incomplete functions in %s\n", f->name);
- printf ("=======\n");
-
- i = 0;
- while (i < n_found)
- {
- Function *func = funcs[i];
-
- printf (" %s (%d/%d untested blocks)\n",
- func->name,
- func->n_nontest_blocks - func->n_nontest_blocks_executed,
- func->n_nontest_blocks);
-
- ++i;
- }
-
- dbus_free (funcs);
-
- printf ("\n");
-}
-
-static void
-print_stats (Stats *stats,
- const char *of_what)
-{
- int completely;
-
- printf ("Summary (%s)\n", of_what);
- printf ("=======\n");
- printf (" %g%% blocks executed (%d of %d)\n",
- (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
- stats->n_blocks_executed,
- stats->n_blocks);
-
- printf (" (ignored %d blocks of test-only/debug-only code)\n",
- stats->n_blocks_inside_dbus_build_tests);
-
- printf (" %g%% functions executed (%d of %d)\n",
- (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
- stats->n_functions_executed,
- stats->n_functions);
-
- completely = stats->n_functions_executed - stats->n_functions_partial;
- printf (" %g%% functions completely executed (%d of %d)\n",
- (completely / (double) stats->n_functions) * 100.0,
- completely,
- stats->n_functions);
-
- printf (" (ignored %d functions of test-only/debug-only code)\n",
- stats->n_functions_inside_dbus_build_tests);
-
- printf (" %g%% lines executed (%d of %d)\n",
- (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
- stats->n_lines_executed,
- stats->n_lines);
-
- completely = stats->n_lines_executed - stats->n_lines_partial;
- printf (" %g%% lines completely executed (%d of %d)\n",
- (completely / (double) stats->n_lines) * 100.0,
- completely,
- stats->n_lines);
-
- printf (" (ignored %d lines of test-only/debug-only code)\n",
- stats->n_lines_inside_dbus_build_tests);
-
- printf ("\n");
-}
-
-typedef enum
-{
- MODE_PRINT,
- MODE_REPORT,
- MODE_BLOCKS,
- MODE_GCOV
-} Mode;
-
-int
-main (int argc, char **argv)
-{
- DBusString filename;
- int i;
- Mode m;
-
- if (argc < 2)
- {
- fprintf (stderr, "Must specify files on command line\n");
- return 1;
- }
-
- m = MODE_PRINT;
- i = 1;
-
- if (strcmp (argv[i], "--report") == 0)
- {
- m = MODE_REPORT;
- ++i;
- }
- else if (strcmp (argv[i], "--blocks") == 0)
- {
- m = MODE_BLOCKS;
- ++i;
- }
- else if (strcmp (argv[i], "--gcov") == 0)
- {
- m = MODE_GCOV;
- ++i;
- }
-
-
- if (i == argc)
- {
- fprintf (stderr, "Must specify files on command line\n");
- return 1;
- }
-
- if (m == MODE_PRINT)
- {
- while (i < argc)
- {
- _dbus_string_init_const (&filename, argv[i]);
-
- print_one_file (&filename);
-
- ++i;
- }
- }
- else if (m == MODE_BLOCKS || m == MODE_GCOV)
- {
- while (i < argc)
- {
- File *f;
-
- _dbus_string_init_const (&filename, argv[i]);
-
- f = load_c_file (&filename);
-
- if (m == MODE_BLOCKS)
- print_block_superdetails (f);
- else if (m == MODE_GCOV)
- print_annotated_source_gcov_format (f);
-
- ++i;
- }
- }
- else if (m == MODE_REPORT)
- {
- Stats stats = { 0, };
- DBusList *files;
- DBusList *link;
- DBusHashTable *stats_by_dir;
- DBusHashIter iter;
-
- files = NULL;
- while (i < argc)
- {
- _dbus_string_init_const (&filename, argv[i]);
-
- if (_dbus_string_ends_with_c_str (&filename, ".c"))
- {
- File *f;
-
- f = load_c_file (&filename);
-
- if (!_dbus_list_append (&files, f))
- die ("no memory\n");
- }
- else
- {
- fprintf (stderr, "Unknown file type %s\n",
- _dbus_string_get_const_data (&filename));
- exit (1);
- }
-
- ++i;
- }
-
- link = _dbus_list_get_first_link (&files);
- while (link != NULL)
- {
- File *f = link->data;
-
- merge_stats_for_file (&stats, f);
-
- link = _dbus_list_get_next_link (&files, link);
- }
-
- print_stats (&stats, "all files");
-
- stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
- dbus_free, dbus_free);
-
- link = _dbus_list_get_first_link (&files);
- while (link != NULL)
- {
- File *f = link->data;
- DBusString dirname;
- char *dirname_c;
- Stats *dir_stats;
-
- _dbus_string_init_const (&filename, f->name);
-
- if (!_dbus_string_init (&dirname))
- die ("no memory\n");
-
- if (!_dbus_string_get_dirname (&filename, &dirname) ||
- !_dbus_string_copy_data (&dirname, &dirname_c))
- die ("no memory\n");
-
- dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
- dirname_c);
-
- if (dir_stats == NULL)
- {
- dir_stats = dbus_new0 (Stats, 1);
- if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
- dir_stats))
- die ("no memory\n");
- }
- else
- dbus_free (dirname_c);
-
- merge_stats_for_file (dir_stats, f);
-
- link = _dbus_list_get_next_link (&files, link);
- }
-
- _dbus_hash_iter_init (stats_by_dir, &iter);
- while (_dbus_hash_iter_next (&iter))
- {
- const char *dirname = _dbus_hash_iter_get_string_key (&iter);
- Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
-
- print_stats (dir_stats, dirname);
- }
-
- _dbus_hash_table_unref (stats_by_dir);
-
- link = _dbus_list_get_first_link (&files);
- while (link != NULL)
- {
- File *f = link->data;
-
- print_untested_functions (f);
-
- link = _dbus_list_get_next_link (&files, link);
- }
-
- link = _dbus_list_get_first_link (&files);
- while (link != NULL)
- {
- File *f = link->data;
-
- print_poorly_tested_functions (f, &stats);
-
- link = _dbus_list_get_next_link (&files, link);
- }
-
- link = _dbus_list_get_first_link (&files);
- while (link != NULL)
- {
- File *f = link->data;
-
- print_n_untested_blocks_by_function (f, &stats);
-
- link = _dbus_list_get_next_link (&files, link);
- }
- }
-
- return 0;
-}