From d4a64e3f38a9ad7a27554547c2720f17ed3580a3 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Thu, 10 Oct 2024 20:35:19 +0200 Subject: [PATCH] autoconf: Add support for code coverage Add support for code coverage collection. This helps developers to check if their test scenarios really exercised all the OpenOCD functionality that they intended to test. - Option --enable-gcov has been added to configure.ac which enables the coverage collection using Gcov. (Disabled by default.) - The steps to collect and inspect the coverage have been described in HACKING file. Change-Id: I259e401937a255e7ad7f155359a0b7787e4d0752 Signed-off-by: Jan Matyas Reviewed-on: https://review.openocd.org/c/openocd/+/8521 Tested-by: jenkins Reviewed-by: Evgeniy Naydanov Reviewed-by: Antonio Borneo --- .gitignore | 4 ++++ HACKING | 16 ++++++++++++++++ Makefile.am | 7 +++++++ configure.ac | 21 ++++++++++++++++++++- src/openocd.c | 7 +++++++ 5 files changed, 54 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5de33077e..1b4e08ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,10 @@ src/jtag/minidriver_imp.h src/jtag/jtag_minidriver.h +# coverage files (gcov) +*.gcda +*.gcno + # OpenULINK driver files generated by SDCC src/jtag/drivers/OpenULINK/*.rel src/jtag/drivers/OpenULINK/*.asm diff --git a/HACKING b/HACKING index 9e8cd357f..8988b1617 100644 --- a/HACKING +++ b/HACKING @@ -92,6 +92,22 @@ patch: make @endcode +- Code coverage analysis + + By inspecting the code coverage, you can identify potential gaps in your testing + and use that information to improve your test scenarios. + + Example usage: + @code + mkdir build-gcov; cd build-gcov + ../configure --enable-gcov [...] + make + # ... Now execute your test scenarios to collect OpenOCD code coverage ... + lcov --capture --directory ./src --output-file openocd-coverage.info + genhtml openocd-coverage.info --output-directory coverage_report + # ... Open coverage_report/index.html in a web browser ... + @endcode + Please consider performing these additional checks where appropriate (especially Clang Static Analyzer for big portions of new code) and mention the results (e.g. "Valgrind-clean, no new Clang analyzer diff --git a/Makefile.am b/Makefile.am index 2230e628f..ab0a2373d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,7 @@ endif # common flags used in openocd build AM_CFLAGS = $(GCC_WARNINGS) +AM_LDFLAGS = AM_CPPFLAGS = $(HOST_CPPFLAGS)\ -I$(top_srcdir)/src \ @@ -51,6 +52,12 @@ AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \ else AM_CPPFLAGS += $(JIMTCL_CFLAGS) endif + +if USE_GCOV +AM_CFLAGS += --coverage +AM_LDFLAGS += --coverage +endif + EXTRA_DIST += \ BUGS \ HACKING \ diff --git a/configure.ac b/configure.ac index 9355ffb93..291e854a4 100644 --- a/configure.ac +++ b/configure.ac @@ -171,6 +171,9 @@ m4_define([DUMMY_ADAPTER], m4_define([OPTIONAL_LIBRARIES], [[[capstone], [Use Capstone disassembly framework], []]]) +m4_define([COVERAGE], + [[[gcov], [Collect coverage using gcov], []]]) + AC_ARG_ENABLE([doxygen-html], AS_HELP_STRING([--disable-doxygen-html], [Disable building Doxygen manual as HTML.]), @@ -199,6 +202,19 @@ AC_ARG_ENABLE([werror], AS_HELP_STRING([--disable-werror], [Do not treat warnings as errors]), [gcc_werror=$enableval], [gcc_werror=$gcc_warnings]) +AC_ARG_ENABLE([gcov], + AS_HELP_STRING([--enable-gcov], [Enable runtime coverage collection via gcov]), + [enable_gcov=$enableval], [enable_gcov=no]) + +AS_IF([test "x$enable_gcov" = "xyes"], [ + AC_DEFINE([USE_GCOV], [1], [1 to enable coverage collection using gcov.]) + dnl When collecting coverage, disable optimizations. + dnl This overrides the "-O2" that autoconf uses by default: + CFLAGS+=" -O0" +], [ + AC_DEFINE([USE_GCOV], [0], [0 to leave coverage collection disabled.]) +]) + # set default verbose options, overridden by following options debug_usb_io=no debug_usb_comms=no @@ -787,6 +803,8 @@ AM_CONDITIONAL([INTERNAL_JIMTCL], [test "x$use_internal_jimtcl" = "xyes"]) AM_CONDITIONAL([HAVE_JIMTCL_PKG_CONFIG], [test "x$have_jimtcl_pkg_config" = "xyes"]) AM_CONDITIONAL([INTERNAL_LIBJAYLINK], [test "x$use_internal_libjaylink" = "xyes"]) +AM_CONDITIONAL([USE_GCOV], [test "x$enable_gcov" = "xyes"]) + # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? AC_MSG_CHECKING([for environ in unistd.h and stdlib.h]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -862,7 +880,8 @@ m4_foreach([adapter], [USB1_ADAPTERS, LIBGPIOD_ADAPTERS, LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, DUMMY_ADAPTER, - OPTIONAL_LIBRARIES], + OPTIONAL_LIBRARIES, + COVERAGE], [s=m4_format(["%-40s"], ADAPTER_DESC([adapter])) AS_CASE([$ADAPTER_VAR([adapter])], [auto], [ diff --git a/src/openocd.c b/src/openocd.c index 7a5147050..9fd709e32 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -375,6 +375,13 @@ int openocd_main(int argc, char *argv[]) log_exit(); +#if USE_GCOV + /* Always explicitly dump coverage data before terminating. + * Otherwise coverage would not be dumped when exit_on_signal occurs. */ + void __gcov_dump(void); + __gcov_dump(); +#endif + if (ret == ERROR_FAIL) return EXIT_FAILURE; else if (ret != ERROR_OK)