summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2011-02-02 16:51:30 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2011-02-17 17:07:12 +0000
commit9a97f820793a4400d7d2dbb71838f5be06e427c6 (patch)
tree429d1b36c781fd87d2dc8dedb05a02394268f657
parentf6e2c958a0345a57c6b9b7f27acf5aee2ff1877b (diff)
Import compiler.m4 and lcov.am from telepathy-glib, and use them to replace gcov
Reviewed-by: Colin Walters <walters@verbum.org> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=10887
-rw-r--r--.gitignore5
-rw-r--r--HACKING6
-rw-r--r--Makefile.am42
-rw-r--r--README2
-rw-r--r--cmake/test/CMakeLists.txt7
-rw-r--r--configure.in36
-rw-r--r--m4/compiler.m467
-rw-r--r--test/Makefile.am13
-rw-r--r--test/decode-gcov.c2653
-rw-r--r--tools/lcov.am46
10 files changed, 129 insertions, 2748 deletions
diff --git a/.gitignore b/.gitignore
index d5e84b7f..db3db97f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,11 @@ config.h.in
*.bbg
*.da
*.gcov
+*.gcda
+*.gcno
tags
/dbus-1.*/
/dbus-1.*.tar.*
+/lcov.html/
+/lcov.info
+/lcov.info.tmp
diff --git a/HACKING b/HACKING
index 442508a0..2e417153 100644
--- a/HACKING
+++ b/HACKING
@@ -289,10 +289,8 @@ is to add a test in here.
"make check" runs all the deterministic test programs (i.e. not break-loader).
-"make check-coverage" is available if you configure with --enable-gcov and
-gives a complete report on test suite coverage. You can also run
-"test/decode-gcov foo.c" on any source file to get annotated source,
-after running make check with a gcov-enabled tree.
+"make lcov-check" is available if you configure with --enable-compiler-coverage
+and gives a complete report on test suite coverage.
Patches
===
diff --git a/Makefile.am b/Makefile.am
index 2ce25d5c..ac7dcb15 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,46 +23,6 @@ EXTRA_DIST = \
all-local: Doxyfile
-if DBUS_GCOV_ENABLED
-clean-gcov:
- find -name "*.da" -o -name "*.gcov" | xargs rm || true
-
-clean-bbg:
- find -name "*.bbg" -o -name "*.bb" | xargs rm || true
-
-GCOV_DIRS=dbus bus
-
-## .PHONY so it always rebuilds it
-.PHONY: coverage-report.txt
-coverage-report.txt:
- BBG_FILES=`find $(GCOV_DIRS) -name "*.bbg" -o -name "*.gcno"` ; \
- C_FILES= ; \
- for F in $$BBG_FILES ; do \
- F_nolibs=`echo $$F | sed -e 's/.libs\///g'` ; \
- C=`echo $$F_nolibs | sed -e 's/.bbg/.c/g' | sed -e 's/.gcno/.c/g'` ; \
- B=`basename $$F .bbg` ; \
- D=`dirname $$F` ; \
- DA=`echo $$F | sed -e 's/.bbg/.da/g'` ; \
- DA_libs=`echo $$D/.libs/$$B/.da` ; \
- if test -e $$DA || test -e $$DA_libs; then \
- C_FILES="$$C_FILES $$C" ; \
- fi ; \
- done ; \
- echo $$C_FILES ; \
- $(top_builddir)/test/decode-gcov --report $$C_FILES > coverage-report.txt
-
-check-coverage: clean-gcov all check coverage-report.txt
- cat coverage-report.txt
-
-else
-coverage-report.txt:
- echo "Need to reconfigure with --enable-gcov"
-
-check-coverage:
- echo "Need to reconfigure with --enable-gcov"
-
-endif
-
update-authors:
git shortlog -s -e | cut -c 8- | sort > AUTHORS
@@ -70,3 +30,5 @@ DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
ACLOCAL_AMFLAGS = -I m4
+
+include tools/lcov.am
diff --git a/README b/README
index 89bfaf70..be4aede2 100644
--- a/README
+++ b/README
@@ -83,7 +83,7 @@ the ./configure program are these
--enable-checks include sanity checks on public API
--enable-xml-docs build XML documentation (requires xmlto)
--enable-doxygen-docs build DOXYGEN documentation (requires Doxygen)
- --enable-gcov compile with coverage profiling instrumentation (gcc only)
+ --enable-compiler-coverage compile with coverage profiling instrumentation (gcc only)
--enable-abstract-sockets use abstract socket namespace (linux only)
--enable-selinux build with SELinux support
--enable-dnotify build with dnotify support (linux only)
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 7bb80aba..9a259d22 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -52,10 +52,6 @@ set (test-sleep-forever_SOURCES
${CMAKE_SOURCE_DIR}/../test/test-sleep-forever.c
)
-set (decode_gcov_SOURCES
- ${CMAKE_SOURCE_DIR}/../test/decode-gcov.c
-)
-
add_executable(test-service ${test-service_SOURCES})
target_link_libraries(test-service ${DBUS_INTERNAL_LIBRARIES})
@@ -81,9 +77,6 @@ target_link_libraries(test-segfault ${DBUS_INTERNAL_LIBRARIES})
add_executable(test-sleep-forever ${test-sleep-forever_SOURCES})
target_link_libraries(test-sleep-forever ${DBUS_INTERNAL_LIBRARIES})
-#add_executable(decode-gcov ${decode_gcov_SOURCES})
-#target_link_libraries(decode-gcov ${DBUS_INTERNAL_LIBRARIES})
-
### keep these in creation order, i.e. uppermost dirs first
set (TESTDIRS
test/data
diff --git a/configure.in b/configure.in
index 2b1929ed..9485ebb4 100644
--- a/configure.in
+++ b/configure.in
@@ -71,6 +71,8 @@ AC_HEADER_STDC
AC_C_INLINE
AM_PROG_LIBTOOL
AC_PROG_MKDIR_P
+COMPILER_COVERAGE
+COMPILER_OPTIMISATIONS
# Set some internal variables depending on the platform for later use.
dbus_win=no
@@ -128,7 +130,6 @@ AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion chec
AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes)
AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto)]),enable_xml_docs=$enableval,enable_xml_docs=auto)
AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto)
-AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no)
AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)
AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto)
AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto)
@@ -202,20 +203,10 @@ if test x$enable_userdb_cache = xyes; then
AC_DEFINE(DBUS_ENABLE_USERDB_CACHE,1,[Build with caching of user data])
fi
-if test x$enable_gcov = xyes; then
+if test x$enable_compiler_coverage = xyes; then
## so that config.h changes when you toggle gcov support
AC_DEFINE_UNQUOTED(DBUS_GCOV_ENABLED, 1, [Defined if gcov is enabled to force a rebuild due to config.h changing])
-
- AC_MSG_CHECKING([for gcc 3.3 version of gcov file format])
- have_gcc33_gcov=no
- AC_RUN_IFELSE( [AC_LANG_PROGRAM( , [[ if (__GNUC__ >=3 && __GNUC_MINOR__ >= 3) exit (0); else exit (1); ]])],
- have_gcc33_gcov=yes)
- if test x$have_gcc33_gcov = xyes ; then
- AC_DEFINE_UNQUOTED(DBUS_HAVE_GCC33_GCOV, 1, [Defined if we have gcc 3.3 and thus the new gcov format])
- fi
- AC_MSG_RESULT($have_gcc33_gcov)
fi
-AM_CONDITIONAL(DBUS_GCOV_ENABLED, test x$enable_gcov = xyes)
# glibc21.m4 serial 3
dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc.
@@ -1295,24 +1286,7 @@ if test "x$GCC" = "xyes"; then
*) CFLAGS="$CFLAGS -pedantic" ;;
esac
fi
- if test x$enable_gcov = xyes; then
- case " $CFLAGS " in
- *[\ \ ]-fprofile-arcs[\ \ ]*) ;;
- *) CFLAGS="$CFLAGS -fprofile-arcs" ;;
- esac
- case " $CFLAGS " in
- *[\ \ ]-ftest-coverage[\ \ ]*) ;;
- *) CFLAGS="$CFLAGS -ftest-coverage" ;;
- esac
-
- ## remove optimization
- CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9]*//g'`
- fi
changequote([,])dnl
-else
- if test x$enable_gcov = xyes; then
- AC_MSG_ERROR([--enable-gcov can only be used with gcc])
- fi
fi
AC_SUBST(PIC_CFLAGS)
@@ -1704,7 +1678,7 @@ echo "
echo "
Maintainer mode: ${USE_MAINTAINER_MODE}
- gcc coverage profiling: ${enable_gcov}
+ gcc coverage profiling: ${enable_compiler_coverage}
Building unit tests: ${enable_tests}
Building verbose mode: ${enable_verbose_mode}
Building assertions: ${enable_asserts}
@@ -1743,7 +1717,7 @@ fi
if test x$enable_tests = xyes -a x$enable_asserts = xno; then
echo "NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)"
fi
-if test x$enable_gcov = xyes; then
+if test x$enable_compiler_coverage = xyes; then
echo "NOTE: building with coverage profiling is definitely for developers only."
fi
if test x$enable_verbose_mode = xyes; then
diff --git a/m4/compiler.m4 b/m4/compiler.m4
new file mode 100644
index 00000000..5aff5d81
--- /dev/null
+++ b/m4/compiler.m4
@@ -0,0 +1,67 @@
+# compiler.m4 - autoconf macros for compiler settings
+#
+# Copyright © 2005 Scott James Remnant <scott@netsplit.com>.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# COMPILER_WARNINGS
+# ----------------------
+# Add configure option to enable additional compiler warnings and treat
+# them as errors.
+AC_DEFUN([COMPILER_WARNINGS],
+[AC_ARG_ENABLE(compiler-warnings,
+ AS_HELP_STRING([--enable-compiler-warnings],
+ [Enable additional compiler warnings]),
+[if test "x$enable_compiler_warnings" = "xyes"; then
+ if test "x$GCC" = "xyes"; then
+ CFLAGS="-Wall -Werror $CFLAGS"
+ fi
+ if test "x$GXX" = "xyes"; then
+ CXXFLAGS="-Wall -Werror $CXXFLAGS"
+ fi
+fi])dnl
+])# COMPILER_WARNINGS
+
+# COMPILER_OPTIMISATIONS
+# ---------------------------
+# Add configure option to disable optimisations.
+AC_DEFUN([COMPILER_OPTIMISATIONS],
+[AC_ARG_ENABLE(compiler-optimisations,
+ AS_HELP_STRING([--disable-compiler-optimisations],
+ [Disable compiler optimisations]),
+[if test "x$enable_compiler_optimisations" = "xno"; then
+ [CFLAGS=`echo "$CFLAGS" | sed -e "s/ -O[1-9]*\b/ -O0/g"`]
+fi])dnl
+])# COMPILER_OPTIMISATIONS
+
+# COMPILER_COVERAGE
+# ----------------------
+# Add configure option to enable coverage data.
+AC_DEFUN([COMPILER_COVERAGE],
+[AC_ARG_ENABLE(compiler-coverage,
+ AS_HELP_STRING([--enable-compiler-coverage],
+ [Enable generation of coverage data]),
+[if test "x$enable_compiler_coverage" = "xyes"; then
+ if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage"
+ fi
+fi])dnl
+])# COMPILER_COVERAGE
diff --git a/test/Makefile.am b/test/Makefile.am
index 110e5dc3..9d0681b7 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -23,13 +23,7 @@ TEST_BINARIES=
TESTS=
endif
-if DBUS_GCOV_ENABLED
-GCOV_BINARIES=decode-gcov
-else
-GCOV_BINARIES=
-endif
-
-noinst_PROGRAMS= $(TEST_BINARIES) $(GCOV_BINARIES)
+noinst_PROGRAMS= $(TEST_BINARIES)
test_service_SOURCES= \
test-service.c
@@ -58,9 +52,6 @@ test_segfault_SOURCES = \
test_sleep_forever_SOURCES = \
test-sleep-forever.c
-decode_gcov_SOURCES= \
- decode-gcov.c
-
# When any programs are not linked to libdbus-internal, fix this.
AM_CPPFLAGS=-DDBUS_STATIC_BUILD
TEST_LIBS=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
@@ -77,8 +68,6 @@ shell_test_LDADD=libdbus-testutils.la $(TEST_LIBS)
shell_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
spawn_test_LDADD=$(TEST_LIBS)
spawn_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
-decode_gcov_LDADD=$(TEST_LIBS)
-decode_gcov_LDFLAGS=@R_DYNAMIC_LDFLAG@
EXTRA_DIST=
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;
-}
diff --git a/tools/lcov.am b/tools/lcov.am
new file mode 100644
index 00000000..3178ba9f
--- /dev/null
+++ b/tools/lcov.am
@@ -0,0 +1,46 @@
+# Copyright © 2008-2011 Collabora Ltd.
+# Copyright © 2008-2011 Nokia Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+lcov-reset:
+ lcov --directory @abs_top_srcdir@ --zerocounters
+
+# gcov takes ~forever to process config-parser.c for some reason?
+lcov-report:
+ true > bus/bus_test-config-parser.gcno
+ true > bus/dbus_daemon-config-parser.gcno
+ lcov --directory @abs_top_srcdir@ --capture \
+ --output-file @abs_top_builddir@/lcov.info
+ $(mkdir_p) @abs_top_builddir@/lcov.html
+ git_commit=`GIT_DIR=@abs_top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\
+ genhtml --title "@PACKAGE_STRING@ $$git_commit" \
+ --output-directory @abs_top_builddir@/lcov.html lcov.info
+ @echo
+ @echo 'lcov report can be found in:'
+ @echo 'file://@abs_top_builddir@/lcov.html/index.html'
+ @echo
+
+lcov-check:
+ $(MAKE) lcov-reset
+ $(MAKE) check $(LCOV_CHECK_ARGS)
+ $(MAKE) lcov-report
+
+## vim:set ft=automake: