diff --git a/externals/lcov/CONTRIBUTING b/externals/lcov/CONTRIBUTING
index 6890789bd140c4443e89b6d3412a362860ebffda..e8152d847ec21b51d1493f8345a69662d5aea3db 100644
--- a/externals/lcov/CONTRIBUTING
+++ b/externals/lcov/CONTRIBUTING
@@ -16,8 +16,8 @@ inclusion:
  2. The contribution must follow a particular format.
  3. The contribution must be signed.
 
-Once you have made sure that your contribution follows these rules, send it via
-e-mail to the LTP coverage mailing list [1].
+Once you have made sure that your contribution follows these rules, open a
+pull request for the LCOV code repository [1].
 
 
 Signing your work
@@ -31,7 +31,7 @@ end of the explanation of a patch:
 By signing a patch, you certify the following:
 
   By making a contribution to the LTP GCOV extension (LCOV) on
-  http://ltp.sourceforge.net, I certify that:
+  https://github.com/linux-test-project/lcov, I certify that:
 
   a) The contribution was created by me and I have the right to submit it
      under the terms and conditions of the open source license
@@ -56,8 +56,8 @@ collect, process and visualize code coverage data as produced by the gcov tool
 that is part of the GNU Compiler Collection (GCC) [2].
 
 If you have an idea for a contribution but are unsure if it aligns with the
-project goals, feel free to discuss the idea on the LTP coverage mailing
-list [1].
+project goals, feel free to discuss the idea using the issue tracker on the
+LCOV code repository site [1].
 
 
 Contribution format
@@ -89,5 +89,5 @@ With your Signed-off-by, you certify the rules stated in section
 
 -- 
 
-[1] ltp-coverage@lists.sourceforge.net
-[2] http://gcc.gnu.org
+[1] https://github.com/linux-test-project/lcov
+[2] https://gcc.gnu.org
diff --git a/externals/lcov/Makefile b/externals/lcov/Makefile
index 1207cb19add633f0b5f99f2e7c0c4ce1b95bed95..62bf293bc211513b7694a5d12d66ddaea2feef41 100644
--- a/externals/lcov/Makefile
+++ b/externals/lcov/Makefile
@@ -9,6 +9,7 @@
 #                and RELEASE variables below - both version and date strings
 #                will be updated in all necessary files.
 #   - clean:     remove all generated files
+#   - release:   finalize release and create git tag for specified VERSION
 #
 
 VERSION := $(shell bin/get_version.sh --version)
@@ -37,13 +38,14 @@ info:
 	@echo "  install   : install binaries and man pages in DESTDIR (default /)"
 	@echo "  uninstall : delete binaries and man pages from DESTDIR (default /)"
 	@echo "  dist      : create packages (RPM, tarball) ready for distribution"
-	@echo "  test      : perform self-tests"
+	@echo "  check     : perform self-tests"
+	@echo "  release   : finalize release and create git tag for specified VERSION"
 
 clean:
 	rm -f lcov-*.tar.gz
 	rm -f lcov-*.rpm
 	make -C example clean
-	make -C test -s clean
+	make -C tests -s clean
 
 install:
 	bin/install.sh bin/lcov $(DESTDIR)$(BIN_DIR)/lcov -m 755
@@ -95,7 +97,8 @@ lcov-$(VERSION).tar.gz: $(FILES)
 	bin/updateversion.pl $(TMP_DIR)/lcov-$(VERSION) $(VERSION) $(RELEASE) $(FULL)
 	bin/get_changes.sh > $(TMP_DIR)/lcov-$(VERSION)/CHANGES
 	cd $(TMP_DIR) ; \
-	tar cfz $(TMP_DIR)/lcov-$(VERSION).tar.gz lcov-$(VERSION)
+	tar cfz $(TMP_DIR)/lcov-$(VERSION).tar.gz lcov-$(VERSION) \
+	    --owner root --group root
 	mv $(TMP_DIR)/lcov-$(VERSION).tar.gz .
 	rm -rf $(TMP_DIR)
 
@@ -112,11 +115,33 @@ rpms: lcov-$(VERSION).tar.gz
 	cd $(TMP_DIR)/BUILD ; \
 	tar xfz $(TMP_DIR)/SOURCES/lcov-$(VERSION).tar.gz \
 		lcov-$(VERSION)/rpm/lcov.spec
-	rpmbuild --define '_topdir $(TMP_DIR)' \
+	rpmbuild --define '_topdir $(TMP_DIR)' --define '_buildhost localhost' \
+		 --undefine vendor --undefine packager \
 		 -ba $(TMP_DIR)/BUILD/lcov-$(VERSION)/rpm/lcov.spec
 	mv $(TMP_DIR)/RPMS/noarch/lcov-$(VERSION)-$(RELEASE).noarch.rpm .
 	mv $(TMP_DIR)/SRPMS/lcov-$(VERSION)-$(RELEASE).src.rpm .
 	rm -rf $(TMP_DIR)
 
-test:
-	@make -C test -s all
+test: check
+
+check:
+	@make -s -C tests check
+
+release:
+	@if [ "$(origin VERSION)" != "command line" ] ; then echo "Please specify new version number, e.g. VERSION=1.16" >&2 ; exit 1 ; fi
+	@if [ -n "$$(git status --porcelain 2>&1)" ] ; then echo "The repository contains uncommited changes" >&2 ; exit 1 ; fi
+	@if [ -n "$$(git tag -l v$(VERSION))" ] ; then echo "A tag for the specified version already exists (v$(VERSION))" >&2 ; exit 1 ; fi
+	@echo "Preparing release tag for version $(VERSION)"
+	git checkout master
+	bin/copy_dates.sh . .
+	for FILE in README man/* rpm/* ; do \
+		bin/updateversion.pl "$$FILE" $(VERSION) 1 $(VERSION) ; \
+	done
+	git commit -a -s -m "lcov: Finalize release $(VERSION)"
+	git tag v$(VERSION) -m "LCOV version $(VERSION)"
+	@echo "**********************************************"
+	@echo "Release tag v$(VERSION) successfully created"
+	@echo "Next steps:"
+	@echo " - Review resulting commit and tag"
+	@echo " - Publish with: git push origin master v$(VERSION)"
+	@echo "**********************************************"
diff --git a/externals/lcov/README b/externals/lcov/README
index ad53c3cbcbf06c6cd326b2bac49cd973ebf6bb8b..e2e416c6882c3143b982e8209b129f4ce57dbd75 100644
--- a/externals/lcov/README
+++ b/externals/lcov/README
@@ -1,6 +1,6 @@
 -------------------------------------------------
 - README file for the LTP GCOV extension (LCOV) -
-- Last changes: 2019-02-28                      -
+- Last changes: 2022-06-03                      -
 -------------------------------------------------
 
 Description
@@ -53,7 +53,7 @@ Further README contents
 ------------------
 The LCOV package is available as either RPM or tarball from:
      
-  http://ltp.sourceforge.net/coverage/lcov.php
+  https://github.com/linux-test-project/lcov/releases
 
 To install the tarball, unpack it to a directory and run:
 
@@ -68,14 +68,13 @@ Change to the resulting lcov directory and type:
   make install
 
 
-3. An example of how to access kernel coverage data
----------------------------------------------------
-Requirements: get and install the gcov-kernel package from
+3. An example of how to access Linux kernel coverage data
+---------------------------------------------------------
+Requirements: Follow the Linux kernel coverage setup instructions at:
 
-  http://sourceforge.net/projects/ltp
+  https://docs.kernel.org/dev-tools/gcov.html
 
-Copy the resulting gcov kernel module file to either the system wide modules
-directory or the same directory as the Perl scripts. As root, do the following:
+As root, do the following:
 
   a) Resetting counters
 
@@ -130,6 +129,7 @@ consult the gcov man page.
 -------------------------
 See the included man pages for more information on how to use the LCOV tools.
 
-Please email further questions or comments regarding this tool to the
-LTP Mailing list at ltp-coverage@lists.sourceforge.net  
+In case of further questions, feel free to open a new issue using the issue
+tracker on the LCOV code repository site at:
 
+  https://github.com/linux-test-project/lcov
diff --git a/externals/lcov/bin/gendesc b/externals/lcov/bin/gendesc
index 334ee7892372935d48dc349ce2fb3cc373af3080..9a4251b65ec1d43955788dd0f173a4fb995cb832 100755
--- a/externals/lcov/bin/gendesc
+++ b/externals/lcov/bin/gendesc
@@ -13,8 +13,8 @@
 #   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # gendesc
@@ -44,8 +44,8 @@ use Cwd qw/abs_path/;
 
 # Constants
 our $tool_dir		= abs_path(dirname($0));
-our $lcov_version	= "LCOV version 1.14";
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $lcov_version	= 'LCOV version '.`"$tool_dir"/get_version.sh --full`;
+our $lcov_url		= "https://github.com/linux-test-project/lcov";
 our $tool_name		= basename($0);
 
 
diff --git a/externals/lcov/bin/genhtml b/externals/lcov/bin/genhtml
index 2352300c11403acdc39f4b27582d68f6387ac685..d02c92c82228ccef9137bca73147e1e678eb5698 100755
--- a/externals/lcov/bin/genhtml
+++ b/externals/lcov/bin/genhtml
@@ -13,8 +13,8 @@
 #   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # genhtml
@@ -76,8 +76,8 @@ use Cwd qw/abs_path cwd/;
 # Global constants
 our $title		= "LCOV - code coverage report";
 our $tool_dir		= abs_path(dirname($0));
-our $lcov_version	= "LCOV version 1.14";
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $lcov_version	= 'LCOV version '.`"$tool_dir"/get_version.sh --full`;
+our $lcov_url		= "https://github.com/linux-test-project/lcov";
 our $tool_name		= basename($0);
 
 # Specify coverage rate default precision
@@ -155,6 +155,9 @@ our $BR_CLOSE	= 5;
 our $BR_SUB = 0;
 our $BR_ADD = 1;
 
+# Block value used for unnamed blocks
+our $UNNAMED_BLOCK = vec(pack('b*', 1 x 32), 0, 32);
+
 # Error classes which users may specify to ignore during processing
 our $ERROR_SOURCE	= 0;
 our %ERROR_ID = (
@@ -243,7 +246,7 @@ sub write_overview_line(*$$$);
 sub write_overview(*$$$$);
 
 # External prototype (defined in genpng)
-sub gen_png($$$@);
+sub gen_png($$$$@);
 
 
 # Global variables & initialization
@@ -254,7 +257,9 @@ our %test_description;	# Hash containing test descriptions if available
 our $date = get_date_string();
 
 our @info_filenames;	# List of .info files to use as data source
-our $test_title;	# Title for output as written to each page header
+our $header_title;	# Title at top of HTML report page (above table)
+our $footer;		# String at bottom of HTML report page
+our $test_title;	# Title shown in header table of each page
 our $output_directory;	# Name of directory in which to store output
 our $base_filename;	# Optional name of file containing baseline data
 our $desc_filename;	# Name of file containing test descriptions
@@ -284,11 +289,14 @@ our $html_epilog;	# Actual HTML epilog
 our $html_ext = "html";	# Extension for generated HTML files
 our $html_gzip = 0;	# Compress with gzip
 our $demangle_cpp = 0;	# Demangle C++ function names
+our $demangle_cpp_tool = "c++filt"; # Default demangler for C++ function names
+our $demangle_cpp_params = ""; # Extra parameters for demangling
 our @opt_ignore_errors;	# Ignore certain error classes during processing
 our @ignore;
 our $opt_config_file;	# User-specified configuration file location
 our %opt_rc;
 our $opt_missed;	# List/sort lines by missed counts
+our $dark_mode;         # Use dark mode palette or normal
 our $charset = "UTF-8";	# Default charset for HTML pages
 our @fileview_sortlist;
 our @fileview_sortname = ("", "-sort-l", "-sort-f", "-sort-b");
@@ -348,6 +356,8 @@ if ($config || %opt_rc)
 	# Copy configuration file and --rc values to variables
 	apply_config({
 		"genhtml_css_file"		=> \$css_filename,
+		"genhtml_header"		=> \$header_title,
+		"genhtml_footer"		=> \$footer,
 		"genhtml_hi_limit"		=> \$hi_limit,
 		"genhtml_med_limit"		=> \$med_limit,
 		"genhtml_line_field_width"	=> \$line_field_width,
@@ -376,6 +386,9 @@ if ($config || %opt_rc)
 		"genhtml_charset"		=> \$charset,
 		"genhtml_desc_html"		=> \$rc_desc_html,
 		"genhtml_demangle_cpp"		=> \$demangle_cpp,
+		"genhtml_demangle_cpp_tool"	=> \$demangle_cpp_tool,
+		"genhtml_demangle_cpp_params"	=> \$demangle_cpp_params,
+		"genhtml_dark_mode"             => \$dark_mode,
 		"genhtml_missed"		=> \$opt_missed,
 		"lcov_function_coverage"	=> \$lcov_func_coverage,
 		"lcov_branch_coverage"		=> \$lcov_branch_coverage,
@@ -392,6 +405,8 @@ $br_coverage	= $lcov_branch_coverage if (!defined($br_coverage));
 
 # Parse command line options
 if (!GetOptions("output-directory|o=s"	=> \$output_directory,
+		"header-title=s"        => \$header_title,
+		"footer=s"		=> \$footer,
 		"title|t=s"		=> \$test_title,
 		"description-file|d=s"	=> \$desc_filename,
 		"keep-descriptions|k"	=> \$keep_descriptions,
@@ -424,6 +439,7 @@ if (!GetOptions("output-directory|o=s"	=> \$output_directory,
 		"rc=s%"			=> \%opt_rc,
 		"precision=i"		=> \$default_precision,
 		"missed"		=> \$opt_missed,
+		"dark-mode"		=> \$dark_mode,
 		))
 {
 	print(STDERR "Use $tool_name --help to get usage information\n");
@@ -441,6 +457,10 @@ if (!GetOptions("output-directory|o=s"	=> \$output_directory,
 	if ($no_sort) {
 		$sort = 0;
 	}
+
+	if (defined($header_title)) {
+		$title = $header_title;
+	}
 }
 
 @info_filenames = @ARGV;
@@ -544,8 +564,8 @@ if ($frames)
 # Ensure that the c++filt tool is available when using --demangle-cpp
 if ($demangle_cpp)
 {
-	if (system_no_output(3, "c++filt", "--version")) {
-		die("ERROR: could not find c++filt tool needed for ".
+	if (system_no_output(3, $demangle_cpp_tool, "--version")) {
+		die("ERROR: could not find $demangle_cpp_tool tool needed for ".
 		    "--demangle-cpp\n");
 	}
 }
@@ -612,8 +632,10 @@ Operation:
 
 HTML output:
   -f, --frames                      Use HTML frames for source code view
-  -t, --title TITLE                 Display TITLE in header of all pages
+  -t, --title TITLE                 Show TITLE in header table of each page
   -c, --css-file CSSFILE            Use external style sheet file CSSFILE
+      --header-title BANNER         Banner text at top of each HTML page
+      --footer FOOTER               Footer text at bottom of each HTML page
       --no-source                   Do not create source code view
       --num-spaces NUM              Replace tabs with NUM spaces in source view
       --highlight                   Highlight lines with converted-only data
@@ -626,6 +648,7 @@ HTML output:
       --demangle-cpp                Demangle C++ function names
       --precision NUM               Set precision of coverage rate
       --missed                      Show miss counts as negative numbers
+      --dark-mode                   Use the dark-mode CSS
 
 For more information see: $lcov_url
 END_OF_USAGE
@@ -1346,7 +1369,7 @@ sub process_file($$$)
 	}
 
 	# Create overview png file
-	gen_png("$rel_dir/$base_name.gcov.png", $overview_width, $tab_size,
+	gen_png("$rel_dir/$base_name.gcov.png", $dark_mode, $overview_width, $tab_size,
 		@source);
 
 	# Create frameset page
@@ -1625,6 +1648,7 @@ sub read_info_file($)
 				   ($1, $2, $3, $4);
 
 				last if (!$br_coverage);
+				$block = -1 if ($block == $UNNAMED_BLOCK);
 				$sumbrcount->{$line} .=
 					"$block,$branch,$taken:";
 
@@ -2725,70 +2749,131 @@ sub write_png_files()
 	my %data;
 	local *PNG_HANDLE;
 
-	$data{"ruby.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x18, 0x10, 0x5d, 0x57, 
-		 0x34, 0x6e, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x35, 0x2f, 
-		 0x00, 0x00, 0x00, 0xd0, 0x33, 0x9a, 0x9d, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"amber.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x28, 0x04, 0x98, 0xcb, 
-		 0xd6, 0xe0, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xe0, 0x50, 
-		 0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-	  	 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"emerald.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x22, 0x2b, 0xc9, 0xf5, 
-		 0x03, 0x33, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0xea, 0x59, 
-		 0x0a, 0x0a, 0x0a, 0x0f, 0xba, 0x50, 0x83, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"snow.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x1e, 0x1d, 0x75, 0xbc, 
-		 0xef, 0x55, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 
-		 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
+	if ($dark_mode) {
+		$data{"ruby.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x06, 0x50, 0x4c, 0x54, 0x45, 0x80, 0x1b, 0x18, 0x00,
+			 0x00, 0x00, 0x39, 0x4a, 0x74, 0xf4, 0x00, 0x00, 0x00,
+			 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60,
+			 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe2, 0x21, 0xbc,
+			 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+			 0xae, 0x42, 0x60, 0x82];
+	} else {
+		$data{"ruby.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11,
+			 0x0f, 0x18, 0x10, 0x5d, 0x57, 0x34, 0x6e, 0x00, 0x00,
+			 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
+			 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e,
+			 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41,
+			 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00,
+			 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x35,
+			 0x2f, 0x00, 0x00, 0x00, 0xd0, 0x33, 0x9a, 0x9d, 0x00,
+			 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda,
+			 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5,
+			 0x27, 0xde, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+			 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
+	}
+	if ($dark_mode) {
+		$data{"amber.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x06, 0x50, 0x4c, 0x54, 0x45, 0x99, 0x86, 0x30, 0x00,
+			 0x00, 0x00, 0x51, 0x83, 0x43, 0xd7, 0x00, 0x00, 0x00,
+			 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60,
+			 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe2, 0x21, 0xbc,
+			 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+			 0xae, 0x42, 0x60, 0x82];
+	} else {
+		$data{"amber.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11,
+			 0x0f, 0x28, 0x04, 0x98, 0xcb, 0xd6, 0xe0, 0x00, 0x00,
+			 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
+			 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e,
+			 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41,
+			 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00,
+			 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xe0,
+			 0x50, 0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00,
+			 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda,
+			 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5,
+			 0x27, 0xde, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+			 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
+	}
+	if ($dark_mode) {
+		$data{"emerald.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x06, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x66, 0x00, 0x0a,
+			 0x0a, 0x0a, 0xa4, 0xb8, 0xbf, 0x60, 0x00, 0x00, 0x00,
+			 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60,
+			 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe2, 0x21, 0xbc,
+			 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+			 0xae, 0x42, 0x60, 0x82];
+	} else {
+		$data{"emerald.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11,
+			 0x0f, 0x22, 0x2b, 0xc9, 0xf5, 0x03, 0x33, 0x00, 0x00,
+			 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
+			 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e,
+			 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41,
+			 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00,
+			 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0xea,
+			 0x59, 0x0a, 0x0a, 0x0a, 0x0f, 0xba, 0x50, 0x83, 0x00,
+			 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda,
+			 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5,
+			 0x27, 0xde, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+			 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
+	}
+	if ($dark_mode) {
+		$data{"snow.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x06, 0x50, 0x4c, 0x54, 0x45, 0xdd, 0xdd, 0xdd, 0x00,
+			 0x00, 0x00, 0xae, 0x9c, 0x6c, 0x92, 0x00, 0x00, 0x00,
+			 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60,
+			 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe2, 0x21, 0xbc,
+			 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+			 0xae, 0x42, 0x60, 0x82];
+	} else {
+		$data{"snow.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00,
+			 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00,
+			 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11,
+			 0x0f, 0x1e, 0x1d, 0x75, 0xbc, 0xef, 0x55, 0x00, 0x00,
+			 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
+			 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e,
+			 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41,
+			 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00,
+			 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff,
+			 0xff, 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00,
+			 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda,
+			 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5,
+			 0x27, 0xde, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+			 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
+	}
+
 	$data{"glass.png"} =
 		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
 		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
@@ -2807,19 +2892,40 @@ sub write_png_files()
 		 0x54, 0x78, 0x9c, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 
 		 0x01, 0x48, 0xaf, 0xa4, 0x71, 0x00, 0x00, 0x00, 0x00, 0x49, 
 		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
-	$data{"updown.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a, 
-		 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x16, 
-		 0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00, 0x3c, 0x49, 0x44, 0x41, 
-		 0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x03, 0xff, 0xa1, 0x00, 
-		 0x5d, 0x9c, 0x11, 0x5d, 0x11, 0x8a, 0x24, 0x23, 0x23, 0x23, 
-		 0x86, 0x42, 0x6c, 0xa6, 0x20, 0x2b, 0x66, 0xc4, 0xa7, 0x08, 
-		 0x59, 0x31, 0x23, 0x21, 0x45, 0x30, 0xc0, 0xc4, 0x30, 0x60, 
-		 0x80, 0xfa, 0x6e, 0x24, 0x3e, 0x78, 0x48, 0x0a, 0x70, 0x62, 
-		 0xa2, 0x90, 0x81, 0xd8, 0x44, 0x01, 0x00, 0xe9, 0x5c, 0x2f, 
-		 0xf5, 0xe2, 0x9d, 0x0f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x49, 
-		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort);
+
+	if ($dark_mode) {
+		$data{"updown.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00,
+			 0x00, 0x00, 0x16, 0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00,
+			 0x43, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60,
+			 0x40, 0x03, 0x77, 0xef, 0xde, 0xfd, 0x7f, 0xf7, 0xee,
+			 0xdd, 0xff, 0xe8, 0xe2, 0x8c, 0xe8, 0x8a, 0x90, 0xf9,
+			 0xca, 0xca, 0xca, 0x8c, 0x18, 0x0a, 0xb1, 0x99, 0x82,
+			 0xac, 0x98, 0x11, 0x9f, 0x22, 0x64, 0xc5, 0x8c, 0x84,
+			 0x14, 0xc1, 0x00, 0x13, 0xc3, 0x80, 0x01, 0xea, 0xbb,
+			 0x91, 0xf8, 0xe0, 0x21, 0x29, 0xc0, 0x89, 0x89, 0x42,
+			 0x06, 0x62, 0x13, 0x05, 0x00, 0xe1, 0xd3, 0x2d, 0x91,
+			 0x93, 0x15, 0xa4, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x49,
+			 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort);
+	} else {
+		$data{"updown.png"} =
+			[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
+			 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
+			 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00,
+			 0x00, 0x00, 0x16, 0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00,
+			 0x3c, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60,
+			 0x40, 0x03, 0xff, 0xa1, 0x00, 0x5d, 0x9c, 0x11, 0x5d,
+			 0x11, 0x8a, 0x24, 0x23, 0x23, 0x23, 0x86, 0x42, 0x6c,
+			 0xa6, 0x20, 0x2b, 0x66, 0xc4, 0xa7, 0x08, 0x59, 0x31,
+			 0x23, 0x21, 0x45, 0x30, 0xc0, 0xc4, 0x30, 0x60, 0x80,
+			 0xfa, 0x6e, 0x24, 0x3e, 0x78, 0x48, 0x0a, 0x70, 0x62,
+			 0xa2, 0x90, 0x81, 0xd8, 0x44, 0x01, 0x00, 0xe9, 0x5c,
+			 0x2f, 0xf5, 0xe2, 0x9d, 0x0f, 0xf9, 0x00, 0x00, 0x00,
+			 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82]
+			 if ($sort);
+	}
 	foreach (keys(%data))
 	{
 		open(PNG_HANDLE, ">", $_)
@@ -2883,28 +2989,28 @@ sub write_css_file()
 	/* All views: initial background and text color */
 	body
 	{
-	  color: #000000;
-	  background-color: #FFFFFF;
+	  color: #COLOR_00;
+	  background-color: #COLOR_14;
 	}
 	
 	/* All views: standard link format*/
 	a:link
 	{
-	  color: #284FA8;
+	  color: #COLOR_15;
 	  text-decoration: underline;
 	}
 	
 	/* All views: standard link - visited format */
 	a:visited
 	{
-	  color: #00CB40;
+	  color: #COLOR_01;
 	  text-decoration: underline;
 	}
 	
 	/* All views: standard link - activated format */
 	a:active
 	{
-	  color: #FF0040;
+	  color: #COLOR_11;
 	  text-decoration: underline;
 	}
 	
@@ -2934,7 +3040,7 @@ sub write_css_file()
 	td.headerValue
 	{
 	  text-align: left;
-	  color: #284FA8;
+	  color: #COLOR_02;
 	  font-family: sans-serif;
 	  font-weight: bold;
 	  white-space: nowrap;
@@ -2956,59 +3062,59 @@ sub write_css_file()
 	td.headerCovTableEntry
 	{
 	  text-align: right;
-	  color: #284FA8;
+	  color: #COLOR_02;
 	  font-family: sans-serif;
 	  font-weight: bold;
 	  white-space: nowrap;
 	  padding-left: 12px;
 	  padding-right: 4px;
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	}
 	
 	/* All views: header item coverage table entry for high coverage rate */
 	td.headerCovTableEntryHi
 	{
 	  text-align: right;
-	  color: #000000;
+	  color: #COLOR_00;
 	  font-family: sans-serif;
 	  font-weight: bold;
 	  white-space: nowrap;
 	  padding-left: 12px;
 	  padding-right: 4px;
-	  background-color: #A7FC9D;
+	  background-color: #COLOR_04;
 	}
 	
 	/* All views: header item coverage table entry for medium coverage rate */
 	td.headerCovTableEntryMed
 	{
 	  text-align: right;
-	  color: #000000;
+	  color: #COLOR_00;
 	  font-family: sans-serif;
 	  font-weight: bold;
 	  white-space: nowrap;
 	  padding-left: 12px;
 	  padding-right: 4px;
-	  background-color: #FFEA20;
+	  background-color: #COLOR_13;
 	}
 	
 	/* All views: header item coverage table entry for ow coverage rate */
 	td.headerCovTableEntryLo
 	{
 	  text-align: right;
-	  color: #000000;
+	  color: #COLOR_00;
 	  font-family: sans-serif;
 	  font-weight: bold;
 	  white-space: nowrap;
 	  padding-left: 12px;
 	  padding-right: 4px;
-	  background-color: #FF0000;
+	  background-color: #COLOR_10;
 	}
 	
 	/* All views: header legend value for legend entry */
 	td.headerValueLeg
 	{
 	  text-align: left;
-	  color: #000000;
+	  color: #COLOR_00;
 	  font-family: sans-serif;
 	  font-size: 80%;
 	  white-space: nowrap;
@@ -3018,7 +3124,7 @@ sub write_css_file()
 	/* All views: color of horizontal ruler */
 	td.ruler
 	{
-	  background-color: #6688D4;
+	  background-color: #COLOR_03;
 	}
 	
 	/* All views: version string format */
@@ -3035,8 +3141,8 @@ sub write_css_file()
 	td.tableHead
 	{
 	  text-align: center;
-	  color: #FFFFFF;
-	  background-color: #6688D4;
+	  color: #COLOR_16;
+	  background-color: #COLOR_03;
 	  font-family: sans-serif;
 	  font-size: 120%;
 	  font-weight: bold;
@@ -3056,8 +3162,8 @@ sub write_css_file()
 	  text-align: left;
 	  padding-left: 10px;
 	  padding-right: 20px; 
-	  color: #284FA8;
-	  background-color: #DAE7FE;
+	  color: #COLOR_02;
+	  background-color: #COLOR_08;
 	  font-family: monospace;
 	}
 	
@@ -3066,13 +3172,13 @@ sub write_css_file()
 	{
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	}
 	
 	/* Directory view/File view (all): bar-graph outline color */
 	td.coverBarOutline
 	{
-	  background-color: #000000;
+	  background-color: #COLOR_00;
 	}
 	
 	/* Directory view/File view (all): percentage entry for files with
@@ -3082,7 +3188,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #A7FC9D;
+	  background-color: #COLOR_04;
 	  font-weight: bold;
 	  font-family: sans-serif;
 	}
@@ -3094,7 +3200,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #A7FC9D;
+	  background-color: #COLOR_04;
 	  white-space: nowrap;
 	  font-family: sans-serif;
 	}
@@ -3106,7 +3212,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #FFEA20;
+	  background-color: #COLOR_13;
 	  font-weight: bold;
 	  font-family: sans-serif;
 	}
@@ -3118,7 +3224,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #FFEA20;
+	  background-color: #COLOR_13;
 	  white-space: nowrap;
 	  font-family: sans-serif;
 	}
@@ -3130,7 +3236,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #FF0000;
+	  background-color: #COLOR_10;
 	  font-weight: bold;
 	  font-family: sans-serif;
 	}
@@ -3142,7 +3248,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #FF0000;
+	  background-color: #COLOR_10;
 	  white-space: nowrap;
 	  font-family: sans-serif;
 	}
@@ -3164,7 +3270,7 @@ sub write_css_file()
 	/* File view (all): "show/hide details" link - activated format */
 	a.detail:active
 	{
-	  color: #FFFFFF;
+	  color: #COLOR_14;
 	  font-size:80%;
 	}
 	
@@ -3173,7 +3279,7 @@ sub write_css_file()
 	{
 	  text-align: right;
 	  padding-right: 10px;
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	  font-family: sans-serif;
 	}
 	
@@ -3183,7 +3289,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px; 
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	  font-family: sans-serif;
 	}
 	
@@ -3193,7 +3299,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px; 
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	  font-family: sans-serif;
 	}
 	
@@ -3211,7 +3317,7 @@ sub write_css_file()
 	  padding-left: 30px;
 	  padding-bottom: 10px;
 	  padding-right: 30px;
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	}
 	
 	/* Source code view: function entry */
@@ -3220,8 +3326,8 @@ sub write_css_file()
 	  text-align: left;
 	  padding-left: 10px;
 	  padding-right: 20px; 
-	  color: #284FA8;
-	  background-color: #DAE7FE;
+	  color: #COLOR_02;
+	  background-color: #COLOR_08;
 	  font-family: monospace;
 	}
 
@@ -3231,7 +3337,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #FF0000;
+	  background-color: #COLOR_10;
 	  font-weight: bold;
 	  font-family: sans-serif;
 	}
@@ -3242,7 +3348,7 @@ sub write_css_file()
 	  text-align: right;
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #DAE7FE;
+	  background-color: #COLOR_08;
 	  font-weight: bold;
 	  font-family: sans-serif;
 	}
@@ -3258,14 +3364,14 @@ sub write_css_file()
 	/* Source code view: line number format */
 	span.lineNum
 	{
-	  background-color: #EFE383;
+	  background-color: #COLOR_09;
 	}
 	
 	/* Source code view: format for lines which were executed */
 	td.lineCov,
 	span.lineCov
 	{
-	  background-color: #CAD7FE;
+	  background-color: #COLOR_07;
 	}
 	
 	/* Source code view: format for Cov legend */
@@ -3274,14 +3380,14 @@ sub write_css_file()
 	  padding-left: 10px;
 	  padding-right: 10px;
 	  padding-bottom: 2px;
-	  background-color: #CAD7FE;
+	  background-color: #COLOR_07;
 	}
 	
 	/* Source code view: format for lines which were not executed */
 	td.lineNoCov,
 	span.lineNoCov
 	{
-	  background-color: #FF6230;
+	  background-color: #COLOR_12;
 	}
 	
 	/* Source code view: format for NoCov legend */
@@ -3290,14 +3396,14 @@ sub write_css_file()
 	  padding-left: 10px;
 	  padding-right: 10px;
 	  padding-bottom: 2px;
-	  background-color: #FF6230;
+	  background-color: #COLOR_12;
 	}
 	
 	/* Source code view (function table): standard link - visited format */
 	td.lineNoCov > a:visited,
 	td.lineCov > a:visited
 	{  
-	  color: black;
+	  color: #COLOR_00;
 	  text-decoration: underline;
 	}  
 	
@@ -3305,27 +3411,27 @@ sub write_css_file()
 	   previous version */
 	span.lineDiffCov
 	{
-	  background-color: #B5F7AF;
+	  background-color: #COLOR_05;
 	}
 	
 	/* Source code view: format for branches which were executed
 	 * and taken */
 	span.branchCov
 	{
-	  background-color: #CAD7FE;
+	  background-color: #COLOR_07;
 	}
 
 	/* Source code view: format for branches which were executed
 	 * but not taken */
 	span.branchNoCov
 	{
-	  background-color: #FF6230;
+	  background-color: #COLOR_12;
 	}
 
 	/* Source code view: format for branches which were not executed */
 	span.branchNoExec
 	{
-	  background-color: #FF6230;
+	  background-color: #COLOR_12;
 	}
 
 	/* Source code view: format for the source code heading line */
@@ -3345,7 +3451,7 @@ sub write_css_file()
 	  white-space: nowrap;
 	  padding-left: 4px;
 	  padding-right: 2px;
-	  background-color: #FF0000;
+	  background-color: #COLOR_10;
 	  font-size: 80%;
 	}
 
@@ -3357,7 +3463,7 @@ sub write_css_file()
 	  white-space: nowrap;
 	  padding-left: 2px;
 	  padding-right: 2px;
-	  background-color: #FFEA20;
+	  background-color: #COLOR_13;
 	  font-size: 80%;
 	}
 
@@ -3369,7 +3475,7 @@ sub write_css_file()
 	  white-space: nowrap;
 	  padding-left: 2px;
 	  padding-right: 4px;
-	  background-color: #A7FC9D;
+	  background-color: #COLOR_04;
 	  font-size: 80%;
 	}
 
@@ -3379,7 +3485,7 @@ sub write_css_file()
 	  padding-left: 10px;
 	  padding-right: 10px;
 	  padding-top: 2px;
-	  background-color: #FF0000;
+	  background-color: #COLOR_10;
 	}
 
 	/* All views except source code view: legend format for med coverage */
@@ -3388,7 +3494,7 @@ sub write_css_file()
 	  padding-left: 10px;
 	  padding-right: 10px;
 	  padding-top: 2px;
-	  background-color: #FFEA20;
+	  background-color: #COLOR_13;
 	}
 
 	/* All views except source code view: legend format for hi coverage */
@@ -3397,7 +3503,7 @@ sub write_css_file()
 	  padding-left: 10px;
 	  padding-right: 10px;
 	  padding-top: 2px;
-	  background-color: #A7FC9D;
+	  background-color: #COLOR_04;
 	}
 END_OF_CSS
 	;
@@ -3407,6 +3513,48 @@ END_OF_CSS
 
 	# Remove leading tab from all lines
 	$css_data =~ s/^\t//gm;
+	my %palette = ( 'COLOR_00' => "000000",
+			'COLOR_01' => "00cb40",
+			'COLOR_02' => "284fa8",
+			'COLOR_03' => "6688d4",
+			'COLOR_04' => "a7fc9d",
+			'COLOR_05' => "b5f7af",
+			'COLOR_06' => "b8d0ff",
+			'COLOR_07' => "cad7fe",
+			'COLOR_08' => "dae7fe",
+			'COLOR_09' => "efe383",
+			'COLOR_10' => "ff0000",
+			'COLOR_11' => "ff0040",
+			'COLOR_12' => "ff6230",
+			'COLOR_13' => "ffea20",
+			'COLOR_14' => "ffffff",
+			'COLOR_15' => "284fa8",
+			'COLOR_16' => "ffffff");
+
+	if ($dark_mode) {
+		%palette =  (   'COLOR_00' => "e4e4e4",
+				'COLOR_01' => "58a6ff",
+				'COLOR_02' => "8b949e",
+				'COLOR_03' => "3b4c71",
+				'COLOR_04' => "006600",
+				'COLOR_05' => "4b6648",
+				'COLOR_06' => "495366",
+				'COLOR_07' => "143e4f",
+				'COLOR_08' => "1c1e23",
+				'COLOR_09' => "202020",
+				'COLOR_10' => "801b18",
+				'COLOR_11' => "66001a",
+				'COLOR_12' => "772d16",
+				'COLOR_13' => "796a25",
+				'COLOR_14' => "000000",
+				'COLOR_15' => "58a6ff",
+				'COLOR_16' => "eeeeee");
+	}
+
+	# Apply palette
+	for (keys %palette) {
+            $css_data =~ s/$_/$palette{$_}/gm;
+	}
 
 	print(CSS_HANDLE $css_data);
 
@@ -4271,13 +4419,14 @@ sub write_html_epilog(*$;$)
 	{
 		$break_code = " target=\"_parent\"";
 	}
+	my $f = defined($main::footer) ? $footer : "Generated by: <a href=\"$lcov_url\"$break_code>$lcov_version</a>";
 
 	# *************************************************************
 
 	write_html($_[0], <<END_OF_HTML)
 	  <table width="100%" border=0 cellspacing=0 cellpadding=0>
 	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
-	    <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
+	    <tr><td class="versionInfo">$f</td></tr>
 	  </table>
 	  <br>
 END_OF_HTML
@@ -5242,7 +5391,7 @@ sub demangle_list($)
 	my $tmpfile;
 	my $handle;
 	my %demangle;
-	my $demangle_arg = "";
+	my $demangle_arg = $demangle_cpp_params;
 	my %versions;
 
 	# Write function names to file
@@ -5253,12 +5402,12 @@ sub demangle_list($)
 
 	# Extra flag necessary on OS X so that symbols listed by gcov get demangled
 	# properly.
-	if ($^O eq "darwin") {
-		$demangle_arg = "--no-strip-underscores";
+	if ($demangle_arg eq "" && $^O eq "darwin") {
+		$demangle_arg = "--no-strip-underscore";
 	}
 
 	# Build translation hash from c++filt output
-	open($handle, "-|", "c++filt $demangle_arg < $tmpfile") or
+	open($handle, "-|", "$demangle_cpp_tool $demangle_arg < $tmpfile") or
 		die("ERROR: could not run c++filt: $!\n");
 	foreach my $func (@$list) {
 		my $translated = <$handle>;
@@ -5656,6 +5805,10 @@ sub apply_prefix($@)
 	{
 		foreach my $prefix (@dir_prefix)
 		{
+			if ($prefix eq $filename)
+			{
+				return "root";
+			}
 			if ($prefix ne "" && $filename =~ /^\Q$prefix\E\/(.*)$/)
 			{
 				return substr($filename, length($prefix) + 1);
diff --git a/externals/lcov/bin/geninfo b/externals/lcov/bin/geninfo
index f41eaec1cdfaadddecec3184eaeb4f7ff93c9890..31c0b574e7e0f961537c2c3df8d844526fc859f3 100755
--- a/externals/lcov/bin/geninfo
+++ b/externals/lcov/bin/geninfo
@@ -13,8 +13,8 @@
 #   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # geninfo
@@ -54,9 +54,15 @@ use warnings;
 use File::Basename; 
 use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir
 			      splitpath catpath/;
+use File::Temp qw(tempfile tempdir);
+use File::Copy qw(copy);
 use Getopt::Long;
 use Digest::MD5 qw(md5_base64);
 use Cwd qw/abs_path/;
+use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
+use Module::Load;
+use Module::Load::Conditional qw(check_install);
+
 if( $^O eq "msys" )
 {
 	require File::Spec::Win32;
@@ -64,8 +70,8 @@ if( $^O eq "msys" )
 
 # Constants
 our $tool_dir		= abs_path(dirname($0));
-our $lcov_version	= "LCOV version 1.14";
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $lcov_version	= 'LCOV version '.`"$tool_dir"/get_version.sh --full`;
+our $lcov_url		= "https://github.com/linux-test-project/lcov";
 our $gcov_tool		= "gcov";
 our $tool_name		= basename($0);
 
@@ -91,10 +97,14 @@ our %ERROR_ID = (
 our $EXCL_START = "LCOV_EXCL_START";
 our $EXCL_STOP = "LCOV_EXCL_STOP";
 
-# Marker to exclude branch coverage but keep function and line coveage
+# Marker to exclude branch coverage but keep function and line coverage
 our $EXCL_BR_START = "LCOV_EXCL_BR_START";
 our $EXCL_BR_STOP = "LCOV_EXCL_BR_STOP";
 
+# Marker to exclude exception branch coverage but keep function, line coverage and non-exception branch coverage
+our $EXCL_EXCEPTION_BR_START = "LCOV_EXCL_EXCEPTION_BR_START";
+our $EXCL_EXCEPTION_BR_STOP = "LCOV_EXCL_EXCEPTION_BR_STOP";
+
 # Compatibility mode values
 our $COMPAT_VALUE_OFF	= 0;
 our $COMPAT_VALUE_ON	= 1;
@@ -163,13 +173,13 @@ sub solve_relative_path($$);
 sub read_gcov_header($);
 sub read_gcov_file($);
 sub info(@);
+sub process_intermediate($$$);
 sub map_llvm_version($);
 sub version_to_str($);
 sub get_gcov_version();
 sub system_no_output($@);
 sub read_config($);
 sub apply_config($);
-sub get_exclusion_data($);
 sub apply_exclusion_data($$);
 sub process_graphfile($$);
 sub filter_fn_name($);
@@ -215,6 +225,7 @@ sub compat_name($);
 sub parse_compat_modes($);
 sub is_compat($);
 sub is_compat_auto($);
+sub load_json_module($);
 
 
 # Global variables
@@ -263,9 +274,14 @@ our %compat_value;
 our $gcno_split_crc;
 our $func_coverage = 1;
 our $br_coverage = 0;
+our $no_exception_br = 0;
 our $rc_auto_base = 1;
+our $rc_intermediate = "auto";
+our $rc_json_module = "auto";
+our $intermediate;
 our $excl_line = "LCOV_EXCL_LINE";
 our $excl_br_line = "LCOV_EXCL_BR_LINE";
+our $excl_exception_br_line = "LCOV_EXCL_EXCEPTION_BR_LINE";
 
 our $cwd = `pwd`;
 chomp($cwd);
@@ -331,10 +347,14 @@ if ($config || %opt_rc)
 		"geninfo_compat"		=> \$opt_compat,
 		"geninfo_adjust_src_path"	=> \$rc_adjust_src_path,
 		"geninfo_auto_base"		=> \$rc_auto_base,
+		"geninfo_intermediate"		=> \$rc_intermediate,
+		"lcov_json_module"		=> \$rc_json_module,
+		"geninfo_no_exception_branch"	=> \$no_exception_br,
 		"lcov_function_coverage"	=> \$func_coverage,
 		"lcov_branch_coverage"		=> \$br_coverage,
 		"lcov_excl_line"		=> \$excl_line,
 		"lcov_excl_br_line"		=> \$excl_br_line,
+		"lcov_excl_exception_br_line"		=> \$excl_exception_br_line,
 	});
 
 	# Merge options
@@ -364,7 +384,7 @@ if ($config || %opt_rc)
 			$adjust_src_replace = $replace;
 		}
 	}
-	for my $regexp (($excl_line, $excl_br_line)) {
+	for my $regexp (($excl_line, $excl_br_line, $excl_exception_br_line)) {
 		eval 'qr/'.$regexp.'/';
 		my $error = $@;
 		chomp($error);
@@ -460,15 +480,52 @@ if (system_no_output(3, $gcov_tool, "--help") == -1)
 }
 
 ($gcov_version, $gcov_version_string) = get_gcov_version();
+$gcov_caps = get_gcov_capabilities();
+
+# Determine intermediate mode
+if ($rc_intermediate eq "0") {
+	$intermediate = 0;
+} elsif ($rc_intermediate eq "1") {
+	$intermediate = 1;
+} elsif (lc($rc_intermediate) eq "auto") {
+	# Use intermediate format if supported by gcov and not conflicting with
+	# exception branch exclusion
+	$intermediate = (($gcov_caps->{'intermediate-format'} && !$no_exception_br) ||
+			 $gcov_caps->{'json-format'}) ? 1 : 0;
+} else {
+	die("ERROR: invalid value for geninfo_intermediate: ".
+	    "'$rc_intermediate'\n");
+}
+
+if ($intermediate) {
+	info("Using intermediate gcov format\n");
+	if ($opt_derive_func_data) {
+		warn("WARNING: --derive-func-data is not compatible with ".
+		     "intermediate format - ignoring\n");
+		$opt_derive_func_data = 0;
+	}
+	if ($no_exception_br && !$gcov_caps->{'json-format'}) {
+		die("ERROR: excluding exception branches is not compatible with ".
+		    "text intermediate format\n");
+	}
+	if ($gcov_caps->{'json-format'}) {
+		load_json_module($rc_json_module);
+	}
+}
+
+if ($no_exception_br && ($gcov_version < $GCOV_VERSION_3_3_0)) {
+	die("ERROR: excluding exception branches is not compatible with ".
+	    "gcov versions older than 3.3\n");
+}
 
 # Determine gcov options
-$gcov_caps = get_gcov_capabilities();
 push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'} &&
 			      ($br_coverage || $func_coverage));
 push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'} &&
 			      $br_coverage);
 push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'} &&
-			      $opt_gcov_all_blocks && $br_coverage);
+			      $opt_gcov_all_blocks && $br_coverage &&
+			      !$intermediate);
 if ($gcov_caps->{'hash-filenames'})
 {
 	push(@gcov_options, "-x");
@@ -599,7 +656,7 @@ foreach my $entry (@data_directory) {
 	gen_info($entry);
 }
 
-if ($initial && $br_coverage) {
+if ($initial && $br_coverage && !$intermediate) {
 	warn("Note: --initial does not generate branch coverage ".
 	     "data\n");
 }
@@ -768,6 +825,7 @@ sub gen_info($)
 	my $prefix;
 	my $type;
 	my $ext;
+	my $tempdir;
 
 	if ($initial) {
 		$type = "graph";
@@ -798,16 +856,22 @@ sub gen_info($)
 		$prefix = "";
 	}
 
+	$tempdir = tempdir(CLEANUP => 1);
+
 	# Process all files in list
 	foreach $file (@file_list) {
 		# Process file
-		if ($initial) {
+		if ($intermediate) {
+			process_intermediate($file, $prefix, $tempdir);
+		} elsif ($initial) {
 			process_graphfile($file, $prefix);
 		} else {
 			process_dafile($file, $prefix);
 		}
 	}
 
+	unlink($tempdir);
+
 	# Report whether files were excluded.
 	if (%excluded_files) {
 		info("Excluded data for %d files due to include/exclude options\n",
@@ -1058,10 +1122,12 @@ sub process_dafile($$)
 
 	# Try to find base directory automatically if requested by user
 	if ($rc_auto_base) {
-		$base_dir = find_base_from_graph($base_dir, $instr, $graph);
+		$base_dir = find_base_from_source($base_dir,
+			[ keys(%{$instr}), keys(%{$graph}) ]);
 	}
 
-	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+	adjust_source_filenames($instr, $base_dir);
+	adjust_source_filenames($graph, $base_dir);
 
 	# Set $object_dir to real location of object files. This may differ
 	# from $da_dir if the graph file is just a link to the "real" object
@@ -1802,7 +1868,9 @@ sub read_gcov_file($)
 	my $exclude_flag = 0;
 	my $exclude_line = 0;
 	my $exclude_br_flag = 0;
+	my $exclude_exception_br_flag = 0;
 	my $exclude_branch = 0;
+	my $exclude_exception_branch = 0;
 	my $last_block = $UNNAMED_BLOCK;
 	my $last_line = 0;
 	local *INPUT;
@@ -1872,6 +1940,13 @@ sub read_gcov_file($)
 						$exclude_branch = 0;
 					}
 				}
+				# Check for exclusion markers (exception branch exclude)
+				if (!$no_markers && 
+					/($EXCL_EXCEPTION_BR_STOP|$EXCL_EXCEPTION_BR_START|$excl_exception_br_line)/) {
+					warn("WARNING: $1 found at $filename:$last_line but ".
+					"branch exceptions exclusion is not supported with ".
+					"gcov versions older than 3.3\n");
+				}
 				# Source code execution data
 				if (/^\t\t(.*)$/)
 				{
@@ -1914,10 +1989,12 @@ sub read_gcov_file($)
 				# branches
 				$last_line = $2;
 				$last_block = $3;
-			} elsif (/^branch\s+(\d+)\s+taken\s+(\d+)/) {
+			} elsif (/^branch\s+(\d+)\s+taken\s+(\d+)(?:\s+\(([^)]*)\))?/) {
 				next if (!$br_coverage);
 				next if ($exclude_line);
 				next if ($exclude_branch);
+				next if (($exclude_exception_branch || $no_exception_br) && 
+						 defined($3) && ($3 eq "throw"));
 				$branches = br_gvec_push($branches, $last_line,
 						$last_block, $1, $2);
 			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
@@ -1974,6 +2051,19 @@ sub read_gcov_file($)
 						$exclude_branch = 0;
 					}
 				}
+				# Check for exclusion markers (exception branch exclude)
+				if (!$no_markers) {
+					if (/$EXCL_EXCEPTION_BR_STOP/) {
+						$exclude_exception_br_flag = 0;
+					} elsif (/$EXCL_EXCEPTION_BR_START/) {
+						$exclude_exception_br_flag = 1;
+					}
+					if (/$excl_exception_br_line/ || $exclude_exception_br_flag) {
+						$exclude_exception_branch = 1;
+					} else {
+						$exclude_exception_branch = 0;
+					}
+				}
 
 				# Strip unexecuted basic block marker
 				$count =~ s/\*$//;
@@ -2010,13 +2100,529 @@ sub read_gcov_file($)
 	}
 
 	close(INPUT);
-	if ($exclude_flag || $exclude_br_flag) {
+	if ($exclude_flag || $exclude_br_flag || $exclude_exception_br_flag) {
 		warn("WARNING: unterminated exclusion section in $filename\n");
 	}
 	return(\@result, $branches, \@functions);
 }
 
 
+#
+# read_intermediate_text(gcov_filename, data)
+#
+# Read gcov intermediate text format in GCOV_FILENAME and add the resulting
+# data to DATA in the following format:
+#
+# data:      source_filename -> file_data
+# file_data: concatenated lines of intermediate text data
+#
+
+sub read_intermediate_text($$)
+{
+	my ($gcov_filename, $data) = @_;
+	my $fd;
+	my $filename;
+
+	open($fd, "<", $gcov_filename) or
+		die("ERROR: Could not read $gcov_filename: $!\n");
+	while (my $line = <$fd>) {
+		if ($line =~ /^file:(.*)$/) {
+			$filename = $1;
+			$filename =~ s/[\r\n]$//g;
+		} elsif (defined($filename)) {
+			$data->{$filename} .= $line;
+		}
+	}
+	close($fd);
+}
+
+
+#
+# read_intermediate_json(gcov_filename, data, basedir_ref)
+#
+# Read gcov intermediate JSON format in GCOV_FILENAME and add the resulting
+# data to DATA in the following format:
+#
+# data:      source_filename -> file_data
+# file_data: GCOV JSON data for file
+#
+# Also store the value for current_working_directory to BASEDIR_REF.
+#
+
+sub read_intermediate_json($$$)
+{
+	my ($gcov_filename, $data, $basedir_ref) = @_;
+	my $text;
+	my $json;
+
+	gunzip($gcov_filename, \$text) or
+		die("ERROR: Could not read $gcov_filename: $GunzipError\n");
+
+	$json = decode_json($text);
+	if (!defined($json) || !exists($json->{"files"}) ||
+	    ref($json->{"files"} ne "ARRAY")) {
+		die("ERROR: Unrecognized JSON output format in ".
+		    "$gcov_filename\n");
+	}
+
+	$$basedir_ref = $json->{"current_working_directory"};
+
+	# Workaround for bug in MSYS GCC 9.x that encodes \ as \n in gcov JSON
+	# output
+	if ($^O eq "msys" && $$basedir_ref =~ /\n/) {
+		$$basedir_ref =~ s#\n#/#g;
+	}
+
+	for my $file (@{$json->{"files"}}) {
+		# decode_json() is decoding UTF-8 strings from the JSON file into
+		# Perl's internal encoding, but filenames on the filesystem are
+		# usually UTF-8 encoded, so the filename strings need to be
+		# converted back to UTF-8 so that they actually match the name
+		# on the filesystem.
+		utf8::encode($file->{"file"});
+
+		my $filename = $file->{"file"};
+
+		$data->{$filename} = $file;
+	}
+}
+
+
+#
+# intermediate_text_to_info(fd, data, srcdata)
+#
+# Write DATA in info format to file descriptor FD.
+#
+# data:      filename -> file_data:
+# file_data: concatenated lines of intermediate text data
+#
+# srcdata:   filename -> [ excl, brexcl, checksums ]
+# excl:      lineno -> 1 for all lines for which to exclude all data
+# brexcl:    lineno -> 1 for all lines for which to exclude branch data
+#                      2 for all lines for which to exclude exception branch data
+# checksums: lineno -> source code checksum
+#
+# Note: To simplify processing, gcov data is not combined here, that is counts
+#       that appear multiple times for the same lines/branches are not added.
+#       This is done by lcov/genhtml when reading the data files.
+#
+
+sub intermediate_text_to_info($$$)
+{
+	my ($fd, $data, $srcdata) = @_;
+	my $branch_num = 0;
+	my $c;
+
+	return if (!%{$data});
+
+	print($fd "TN:$test_name\n");
+	for my $filename (keys(%{$data})) {
+		my ($excl, $brexcl, $checksums);
+		my $lines_found = 0;
+		my $lines_hit = 0;
+		my $functions_found = 0;
+		my $functions_hit = 0;
+		my $branches_found = 0;
+		my $branches_hit = 0;
+
+		if (defined($srcdata->{$filename})) {
+			($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};
+		}
+
+		print($fd "SF:$filename\n");
+		for my $line (split(/\n/, $data->{$filename})) {
+			if ($line =~ /^lcount:(\d+),(\d+),?/) {
+				# lcount:<line>,<count>
+				# lcount:<line>,<count>,<has_unexecuted_blocks>
+				if ($checksum && exists($checksums->{$1})) {
+					$c = ",".$checksums->{$1};
+				} else {
+					$c = "";
+				}
+				print($fd "DA:$1,$2$c\n") if (!$excl->{$1});
+
+				# Intermediate text format does not provide
+				# branch numbers, and the same branch may appear
+				# multiple times on the same line (e.g. in
+				# template instances). Synthesize a branch
+				# number based on the assumptions:
+				# a) the order of branches is fixed across
+				#    instances
+				# b) an instance starts with an lcount line
+				$branch_num = 0;
+
+				$lines_found++;
+				$lines_hit++ if ($2 > 0);
+			} elsif ($line =~ /^function:(\d+),(\d+),([^,]+)$/) {
+				next if (!$func_coverage || $excl->{$1});
+
+				# function:<line>,<count>,<name>
+				print($fd "FN:$1,$3\n");
+				print($fd "FNDA:$2,$3\n");
+
+				$functions_found++;
+				$functions_hit++ if ($2 > 0);
+			} elsif ($line =~ /^function:(\d+),\d+,(\d+),([^,]+)$/) {
+				next if (!$func_coverage || $excl->{$1});
+
+				# function:<start_line>,<end_line>,<count>,
+				#          <name>
+				print($fd "FN:$1,$3\n");
+				print($fd "FNDA:$2,$3\n");
+
+				$functions_found++;
+				$functions_hit++ if ($2 > 0);
+			} elsif ($line =~ /^branch:(\d+),(taken|nottaken|notexec)/) {
+				next if (!$br_coverage || $excl->{$1} ||
+					 (defined($brexcl->{$1}) && ($brexcl->{$1} == 1)));
+
+				# branch:<line>,taken|nottaken|notexec
+				if ($2 eq "taken") {
+					$c = 1;
+				} elsif ($2 eq "nottaken") {
+					$c = 0;
+				} else {
+					$c = "-";
+				}
+				print($fd "BRDA:$1,0,$branch_num,$c\n");
+				$branch_num++;
+
+				$branches_found++;
+				$branches_hit++ if ($2 eq "taken");
+			}
+		}
+		
+		if ($functions_found > 0) {
+			printf($fd "FNF:%s\n", $functions_found);
+			printf($fd "FNH:%s\n", $functions_hit);
+		}
+		if ($branches_found > 0) {
+			printf($fd "BRF:%s\n", $branches_found);
+			printf($fd "BRH:%s\n", $branches_hit);
+		}
+		printf($fd "LF:%s\n", $lines_found);
+		printf($fd "LH:%s\n", $lines_hit);
+		print($fd "end_of_record\n");
+	}
+}
+
+
+#
+# intermediate_json_to_info(fd, data, srcdata)
+#
+# Write DATA in info format to file descriptor FD.
+#
+# data:      filename -> file_data:
+# file_data: GCOV JSON data for file
+#
+# srcdata:   filename -> [ excl, brexcl, checksums ]
+# excl:      lineno -> 1 for all lines for which to exclude all data
+# brexcl:    lineno -> 1 for all lines for which to exclude branch data
+#                      2 for all lines for which to exclude exception branch data
+# checksums: lineno -> source code checksum
+#
+# Note: To simplify processing, gcov data is not combined here, that is counts
+#       that appear multiple times for the same lines/branches are not added.
+#       This is done by lcov/genhtml when reading the data files.
+#
+
+sub intermediate_json_to_info($$$)
+{
+	my ($fd, $data, $srcdata) = @_;
+	my $branch_num = 0;
+
+	return if (!%{$data});
+
+	print($fd "TN:$test_name\n");
+	for my $filename (keys(%{$data})) {
+		my ($excl, $brexcl, $checksums);
+		my $file_data = $data->{$filename};
+		my $lines_found = 0;
+		my $lines_hit = 0;
+		my $functions_found = 0;
+		my $functions_hit = 0;
+		my $branches_found = 0;
+		my $branches_hit = 0;
+
+		if (defined($srcdata->{$filename})) {
+			($excl, $brexcl, $checksums) = @{$srcdata->{$filename}};
+		}
+
+		print($fd "SF:$filename\n");
+
+		# Function data
+		if ($func_coverage) {
+			for my $d (@{$file_data->{"functions"}}) {
+				my $line = $d->{"start_line"};
+				my $count = $d->{"execution_count"};
+				my $name = $d->{"name"};
+
+				next if (!defined($line) || !defined($count) ||
+					 !defined($name) || $excl->{$line});
+
+				print($fd "FN:$line,$name\n");
+				print($fd "FNDA:$count,$name\n");
+
+				$functions_found++;
+				$functions_hit++ if ($count > 0);
+			}
+		}
+
+		if ($functions_found > 0) {
+			printf($fd "FNF:%s\n", $functions_found);
+			printf($fd "FNH:%s\n", $functions_hit);
+		}
+
+		# Line data
+		for my $d (@{$file_data->{"lines"}}) {
+			my $line = $d->{"line_number"};
+			my $count = $d->{"count"};
+			my $c;
+			my $branches = $d->{"branches"};
+			my $unexec = $d->{"unexecuted_block"};
+
+			next if (!defined($line) || !defined($count) ||
+				 $excl->{$line});
+
+			if (defined($unexec) && $unexec && $count == 0) {
+				$unexec = 1;
+			} else {
+				$unexec = 0;
+			}
+
+			if ($checksum && exists($checksums->{$line})) {
+				$c = ",".$checksums->{$line};
+			} else {
+				$c = "";
+			}
+			print($fd "DA:$line,$count$c\n");
+
+			$lines_found++;
+			$lines_hit++ if ($count > 0);
+
+			$branch_num = 0;
+			# Branch data
+			if ($br_coverage && (!defined($brexcl->{$line}) || 
+					($brexcl->{$line} != 1))) {
+				for my $b (@$branches) {
+					my $brcount = $b->{"count"};
+					my $is_exception = $b->{"throw"};
+
+					if (!$is_exception || ((!defined($brexcl->{$line}) || 
+							($brexcl->{$line} != 2)) && !$no_exception_br)) {
+						if (!defined($brcount) || $unexec) {
+							$brcount = "-";
+						}
+						print($fd "BRDA:$line,0,$branch_num,".
+						      "$brcount\n");
+					}
+
+					$branches_found++;
+					$branches_hit++ if ($brcount ne "-" && $brcount > 0);
+					$branch_num++;
+				}
+			}
+		}
+
+		if ($branches_found > 0) {
+			printf($fd "BRF:%s\n", $branches_found);
+			printf($fd "BRH:%s\n", $branches_hit);
+		}
+		printf($fd "LF:%s\n", $lines_found);
+		printf($fd "LH:%s\n", $lines_hit);
+		print($fd "end_of_record\n");
+	}
+}
+
+
+sub get_output_fd($$)
+{
+	my ($outfile, $file) = @_;
+	my $fd;
+
+	if (!defined($outfile)) {
+		open($fd, ">", "$file.info") or
+			die("ERROR: Cannot create file $file.info: $!\n");
+	} elsif ($outfile eq "-") {
+		open($fd, ">&STDOUT") or
+			die("ERROR: Cannot duplicate stdout: $!\n");
+	} else {
+		open($fd, ">>", $outfile) or
+			die("ERROR: Cannot write to file $outfile: $!\n");
+	}
+
+	return $fd;
+}
+
+
+#
+# print_gcov_warnings(stderr_file, is_graph, map)
+#
+# Print GCOV warnings in file STDERR_FILE to STDERR. If IS_GRAPH is non-zero,
+# suppress warnings about missing as these are expected. Replace keys found
+# in MAP with their values.
+#
+
+sub print_gcov_warnings($$$)
+{
+	my ($stderr_file, $is_graph, $map) = @_;
+	my $fd;
+
+	if (!open($fd, "<", $stderr_file)) {
+		warn("WARNING: Could not open GCOV stderr file ".
+		     "$stderr_file: $!\n");
+		return;
+	}
+	while (my $line = <$fd>) {
+		next if ($is_graph && $line =~ /cannot open data file/);
+
+		for my $key (keys(%{$map})) {
+			$line =~ s/\Q$key\E/$map->{$key}/g;
+		}
+
+		print(STDERR $line);
+	}
+	close($fd);
+}
+
+
+#
+# process_intermediate(file, dir, tempdir)
+#
+# Create output for a single file (either a data file or a graph file) using
+# gcov's intermediate option.
+#
+
+sub process_intermediate($$$)
+{
+	my ($file, $dir, $tempdir) = @_;
+	my ($fdir, $fbase, $fext);
+	my $data_file;
+	my $errmsg;
+	my %data;
+	my $fd;
+	my $base;
+	my $srcdata;
+	my $is_graph = 0;
+	my ($out, $err, $rc);
+	my $json_basedir;
+	my $json_format;
+
+	info("Processing %s\n", abs2rel($file, $dir));
+
+	$file = solve_relative_path($cwd, $file);
+	($fdir, $fbase, $fext) = split_filename($file);
+
+	$is_graph = 1 if (".$fext" eq $graph_file_extension);
+
+	if ($is_graph) {
+		# Process graph file - copy to temp directory to prevent
+		# accidental processing of associated data file
+		$data_file = "$tempdir/$fbase$graph_file_extension";
+		if (!copy($file, $data_file)) {
+			$errmsg = "ERROR: Could not copy file $file";
+			goto err;
+		}
+	} else {
+		# Process data file in place
+		$data_file = $file;
+	}
+
+	# Change directory
+	if (!chdir($tempdir)) {
+		$errmsg = "Could not change to directory $tempdir: $!";
+		goto err;
+	}
+
+	# Run gcov on data file
+	($out, $err, $rc) = system_no_output(1 + 2 + 4, $gcov_tool,
+					     $data_file, @gcov_options, "-i");
+	defined($out) && unlink($out);
+	if (defined($err)) {
+		print_gcov_warnings($err, $is_graph, {
+			$data_file => $file,
+		});
+		unlink($err);
+	}
+	if ($rc) {
+		$errmsg = "GCOV failed for $file";
+		goto err;
+	}
+
+	if ($is_graph) {
+		# Remove graph file copy
+		unlink($data_file);
+	}
+
+	# Parse resulting file(s)
+	for my $gcov_filename (glob("*.gcov")) {
+		read_intermediate_text($gcov_filename, \%data);
+		unlink($gcov_filename);
+	}
+
+	for my $gcov_filename (glob("*.gcov.json.gz")) {
+		read_intermediate_json($gcov_filename, \%data, \$json_basedir);
+		unlink($gcov_filename);
+		$json_format = 1;
+	}
+
+	if (!%data) {
+		warn("WARNING: GCOV did not produce any data for $file\n");
+		return;
+	}
+
+	# Determine base directory
+	if (defined($base_directory)) {
+		$base = $base_directory;
+	} elsif (defined($json_basedir)) {
+		$base = $json_basedir;
+	} else {
+		$base = $fdir;
+
+		if (is_compat($COMPAT_MODE_LIBTOOL)) {
+			# Avoid files from .libs dirs
+			$base =~ s/\.libs$//;
+		}
+
+		# Try to find base directory automatically if requested by user
+		if ($rc_auto_base) {
+			$base = find_base_from_source($base, [ keys(%data) ]);
+		}
+	}
+
+	# Apply base file name to relative source files
+	adjust_source_filenames(\%data, $base);
+
+	# Remove excluded source files
+	filter_source_files(\%data);
+
+	# Get data on exclusion markers and checksums if requested
+	if (!$no_markers || $checksum) {
+		$srcdata = get_all_source_data(keys(%data));
+	}
+
+	# Generate output
+	$fd = get_output_fd($output_filename, $file);
+	if ($json_format) {
+		intermediate_json_to_info($fd, \%data, $srcdata);
+	} else {
+		intermediate_text_to_info($fd, \%data, $srcdata);
+	}
+	close($fd);
+
+	chdir($cwd);
+
+	return;
+
+err:
+	if ($ignore[$ERROR_GCOV]) {
+		warn("WARNING: $errmsg!\n");
+	} else {
+		die("ERROR: $errmsg!\n")
+	}
+}
+
+
 # Map LLVM versions to the version of GCC gcov which they emulate.
 
 sub map_llvm_version($)
@@ -2074,7 +2680,7 @@ sub get_gcov_version()
 	#       Default target: x86_64-apple-darwin16.0.0
 	#       Host CPU: haswell
 
-	open(GCOV_PIPE, "-|", "$gcov_tool --version")
+	open(GCOV_PIPE, "-|", "\"$gcov_tool\" --version")
 		or die("ERROR: cannot retrieve gcov version!\n");
 	local $/;
 	$version_string = <GCOV_PIPE>;
@@ -2151,8 +2757,12 @@ sub int_handler()
 #
 #   MODE & 1: suppress STDOUT
 #   MODE & 2: suppress STDERR
+#   MODE & 4: redirect to temporary files instead of suppressing
 #
-# Return 0 on success, non-zero otherwise.
+# Return (stdout, stderr, rc):
+#    stdout: path to tempfile containing stdout or undef
+#    stderr: path to tempfile containing stderr or undef
+#    0 on success, non-zero otherwise
 #
 
 sub system_no_output($@)
@@ -2161,14 +2771,31 @@ sub system_no_output($@)
 	my $result;
 	local *OLD_STDERR;
 	local *OLD_STDOUT;
+	my $stdout_file;
+	my $stderr_file;
+	my $fd;
 
 	# Save old stdout and stderr handles
 	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
 	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
 
-	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">", "/dev/null");
-	($mode & 2) && open(STDERR, ">", "/dev/null");
+	if ($mode & 4) {
+		# Redirect to temporary files
+		if ($mode & 1) {
+			($fd, $stdout_file) = tempfile(UNLINK => 1);
+			open(STDOUT, ">", $stdout_file) || warn("$!\n");
+			close($fd);
+		}
+		if ($mode & 2) {
+			($fd, $stderr_file) = tempfile(UNLINK => 1);
+			open(STDERR, ">", $stderr_file) || warn("$!\n");
+			close($fd);
+		}
+	} else {
+		# Redirect to /dev/null
+		($mode & 1) && open(STDOUT, ">", "/dev/null");
+		($mode & 2) && open(STDERR, ">", "/dev/null");
+	}
  
 	debug("system(".join(' ', @_).")\n");
 	system(@_);
@@ -2181,8 +2808,18 @@ sub system_no_output($@)
 	# Restore old handles
 	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
 	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
+
+	# Remove empty output files
+	if (defined($stdout_file) && -z $stdout_file) {
+		unlink($stdout_file);
+		$stdout_file = undef;
+	}
+	if (defined($stderr_file) && -z $stderr_file) {
+		unlink($stderr_file);
+		$stderr_file = undef;
+	}
  
-	return $result;
+	return ($stdout_file, $stderr_file, $result);
 }
 
 
@@ -2260,23 +2897,29 @@ sub apply_config($)
 
 
 #
-# get_exclusion_data(filename)
+# get_source_data(filename)
 #
-# Scan specified source code file for exclusion markers and return
-#   linenumber -> 1
-# for all lines which should be excluded.
+# Scan specified source code file for exclusion markers and checksums. Return
+#   ( excl, brexcl, checksums ) where
+#   excl:      lineno -> 1 for all lines for which to exclude all data
+#   brexcl:    lineno -> 1 for all lines for which to exclude branch data
+#   checksums: lineno -> source code checksum
 #
 
-sub get_exclusion_data($)
+sub get_source_data($)
 {
 	my ($filename) = @_;
 	my %list;
 	my $flag = 0;
+	my %brdata;
+	my $brflag = 0;
+	my $exceptionbrflag = 0;
+	my %checksums;
 	local *HANDLE;
 
 	if (!open(HANDLE, "<", $filename)) {
 		warn("WARNING: could not open $filename\n");
-		return undef;
+		return;
 	}
 	while (<HANDLE>) {
 		if (/$EXCL_STOP/) {
@@ -2287,14 +2930,75 @@ sub get_exclusion_data($)
 		if (/$excl_line/ || $flag) {
 			$list{$.} = 1;
 		}
+		if (/$EXCL_BR_STOP/) {
+			$brflag = 0;
+		} elsif (/$EXCL_BR_START/) {
+			$brflag = 1;
+		}
+		if (/$EXCL_EXCEPTION_BR_STOP/) {
+			$exceptionbrflag = 0;
+		} elsif (/$EXCL_EXCEPTION_BR_START/) {
+			$exceptionbrflag = 1;
+		}
+		if (/$excl_br_line/ || $brflag) {
+			$brdata{$.} = 1;
+		} elsif (/$excl_exception_br_line/ || $exceptionbrflag) {
+			$brdata{$.} = 2;
+		}
+		if ($checksum) {
+			chomp();
+			$checksums{$.} = md5_base64($_);
+		}
+		if ($intermediate && !$gcov_caps->{'json-format'} &&
+				/($EXCL_EXCEPTION_BR_STOP|$EXCL_EXCEPTION_BR_START|$excl_exception_br_line)/) {
+			warn("WARNING: $1 found at $filename:$. but branch exceptions ".
+				"exclusion is not supported when using text intermediate ".
+				"format\n");
+		}
 	}
 	close(HANDLE);
 
-	if ($flag) {
+	if ($flag || $brflag || $exceptionbrflag) {
 		warn("WARNING: unterminated exclusion section in $filename\n");
 	}
 
-	return \%list;
+	return (\%list, \%brdata, \%checksums);
+}
+
+
+#
+# get_all_source_data(filenames)
+#
+# Scan specified source code files for exclusion markers and return
+#   filename -> [ excl, brexcl, checksums ]
+#   excl:      lineno -> 1 for all lines for which to exclude all data
+#   brexcl:    lineno -> 1 for all lines for which to exclude branch data
+#   checksums: lineno -> source code checksum
+#
+
+sub get_all_source_data(@)
+{
+	my @filenames = @_;
+	my %data;
+	my $failed = 0;
+
+	for my $filename (@filenames) {
+		my @d;
+		next if (exists($data{$filename}));
+
+		@d = get_source_data($filename);
+		if (@d) {
+			$data{$filename} = [ @d ];
+		} else {
+			$failed = 1;
+		}
+	}
+
+	if ($failed) {
+		warn("WARNING: some exclusion markers may be ignored\n");
+	}
+
+	return \%data;
 }
 
 
@@ -2318,35 +3022,17 @@ sub apply_exclusion_data($$)
 {
 	my ($instr, $graph) = @_;
 	my $filename;
-	my %excl_data;
-	my $excl_read_failed = 0;
-
-	# Collect exclusion marker data
-	foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {
-		my $excl = get_exclusion_data($filename);
-
-		# Skip and note if file could not be read
-		if (!defined($excl)) {
-			$excl_read_failed = 1;
-			next;
-		}
-
-		# Add to collection if there are markers
-		$excl_data{$filename} = $excl if (keys(%{$excl}) > 0);
-	}
+	my $excl_data;
 
-	# Warn if not all source files could be read
-	if ($excl_read_failed) {
-		warn("WARNING: some exclusion markers may be ignored\n");
-	}
+	($excl_data) = get_all_source_data(keys(%{$graph}), keys(%{$instr}));
 
 	# Skip if no markers were found
-	return ($instr, $graph) if (keys(%excl_data) == 0);
+	return ($instr, $graph) if (!%$excl_data);
 
 	# Apply exclusion marker data to graph
-	foreach $filename (keys(%excl_data)) {
+	foreach $filename (keys(%$excl_data)) {
 		my $function_data = $graph->{$filename};
-		my $excl = $excl_data{$filename};
+		my $excl = $excl_data->{$filename}->[0];
 		my $function;
 
 		next if (!defined($function_data));
@@ -2384,9 +3070,9 @@ sub apply_exclusion_data($$)
 	}
 
 	# Apply exclusion marker data to instr
-	foreach $filename (keys(%excl_data)) {
+	foreach $filename (keys(%$excl_data)) {
 		my $line_data = $instr->{$filename};
-		my $excl = $excl_data{$filename};
+		my $excl = $excl_data->{$filename}->[0];
 		my $line;
 		my @new_data;
 
@@ -2468,10 +3154,12 @@ sub process_graphfile($$)
 
 	# Try to find base directory automatically if requested by user
 	if ($rc_auto_base) {
-		$base_dir = find_base_from_graph($base_dir, $instr, $graph);
+		$base_dir = find_base_from_source($base_dir,
+			[ keys(%{$instr}), keys(%{$graph}) ]);
 	}
 
-	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+	adjust_source_filenames($instr, $base_dir);
+	adjust_source_filenames($graph, $base_dir);
 
 	if (!$no_markers) {
 		# Apply exclusion marker data to graph file data
@@ -2767,11 +3455,11 @@ sub parent_dir($)
 }
 
 #
-# find_base_from_graph(base_dir, instr, graph)
+# find_base_from_source(base_dir, source_files)
 #
-# Try to determine the base directory of the graph file specified by INSTR
-# and GRAPH. The base directory is the base for all relative filenames in
-# the graph file. It is defined by the current working directory at time
+# Try to determine the base directory of the object file built from
+# SOURCE_FILES. The base directory is the base for all relative filenames in
+# the gcov data. It is defined by the current working directory at time
 # of compiling the source file.
 #
 # This function implements a heuristic which relies on the following
@@ -2781,16 +3469,16 @@ sub parent_dir($)
 # - files by the same name are not present in multiple parent directories
 #
 
-sub find_base_from_graph($$$)
+sub find_base_from_source($$)
 {
-	my ($base_dir, $instr, $graph) = @_;
+	my ($base_dir, $source_files) = @_;
 	my $old_base;
 	my $best_miss;
 	my $best_base;
 	my %rel_files;
 
 	# Determine list of relative paths
-	foreach my $filename (keys(%{$instr}), keys(%{$graph})) {
+	foreach my $filename (@$source_files) {
 		next if (file_name_is_absolute($filename));
 
 		$rel_files{$filename} = 1;
@@ -2829,17 +3517,17 @@ sub find_base_from_graph($$$)
 }
 
 #
-# adjust_graph_filenames(base_dir, instr, graph)
+# adjust_source_filenames(hash, base_dir)
 #
-# Make relative paths in INSTR and GRAPH absolute and apply
-# geninfo_adjust_src_path setting to graph file data.
+# Transform all keys of HASH to absolute form and apply requested
+# transformations.
 #
 
-sub adjust_graph_filenames($$$)
+sub adjust_source_filenames($$$)
 {
-	my ($base_dir, $instr, $graph) = @_;
+	my ($hash, $base_dir) = @_;
 
-	foreach my $filename (keys(%{$instr})) {
+	foreach my $filename (keys(%{$hash})) {
 		my $old_filename = $filename;
 
 		# Convert to absolute canonical form
@@ -2851,28 +3539,50 @@ sub adjust_graph_filenames($$$)
 		}
 
 		if ($filename ne $old_filename) {
-			$instr->{$filename} = delete($instr->{$old_filename});
+			$hash->{$filename} = delete($hash->{$old_filename});
 		}
 	}
+}
 
-	foreach my $filename (keys(%{$graph})) {
-		my $old_filename = $filename;
 
-		# Make absolute
-		# Convert to absolute canonical form
-		$filename = solve_relative_path($base_dir, $filename);
+#
+# filter_source_files(hash)
+#
+# Remove unwanted source file data from HASH.
+#
 
-		# Apply adjustment
-		if (defined($adjust_src_pattern)) {
-			$filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+sub filter_source_files($)
+{
+	my ($hash) = @_;
+
+	foreach my $filename (keys(%{$hash})) {
+		# Skip external files if requested
+		goto del if (!$opt_external && is_external($filename));
+
+		# Apply include patterns
+		if (@include_patterns) {
+			my $keep;
+
+			foreach my $pattern (@include_patterns) {
+				if ($filename =~ (/^$pattern$/)) {
+					$keep = 1;
+					last;
+				}
+			}
+			goto del if (!$keep);
 		}
 
-		if ($filename ne $old_filename) {
-			$graph->{$filename} = delete($graph->{$old_filename});
+		# Apply exclude patterns
+		foreach my $pattern (@exclude_patterns) {
+			goto del if ($filename =~ (/^$pattern$/));
 		}
-	}
+		next;
 
-	return ($instr, $graph);
+del:
+		# Remove file data
+		delete($hash->{$filename});
+		$excluded_files{$filename} = 1;
+	}
 }
 
 #
@@ -3776,7 +4486,7 @@ sub debug($)
 
 sub get_gcov_capabilities()
 {
-	my $help = `$gcov_tool --help`;
+	my $help = `"$gcov_tool" --help`;
 	my %capabilities;
 	my %short_option_translations = (
 		'a' => 'all-blocks',
@@ -3784,6 +4494,7 @@ sub get_gcov_capabilities()
 		'c' => 'branch-counts',
 		'f' => 'function-summaries',
 		'h' => 'help',
+		'i' => 'intermediate-format',
 		'l' => 'long-file-names',
 		'n' => 'no-output',
 		'o' => 'object-directory',
@@ -4012,3 +4723,45 @@ sub is_compat_auto($)
 	return 1 if ($compat_value{$mode} == $COMPAT_VALUE_AUTO);
 	return 0;
 }
+
+#
+# load_json_module(rc)
+#
+# If RC is "auto", load best available JSON module from a list of alternatives,
+# otherwise load the module specified by RC.
+#
+sub load_json_module($)
+{
+	my ($rc) = @_;
+	# List of alternative JSON modules to try
+	my @alternatives = (
+	        "JSON::XS",             # Fast, but not always installed
+	        "Cpanel::JSON::XS",     # Fast, a more recent fork
+	        "JSON::PP",             # Slow, part of core-modules
+	        "JSON",                 # Not available in all distributions
+	);
+	my $mod;
+
+	# Determine JSON module
+	if (lc($rc) eq "auto") {
+		for my $m (@alternatives) {
+			if (check_install(module => $m)) {
+				$mod = $m;
+				last;
+			}
+		}
+
+		if (!defined($mod)) {
+			die("No JSON module found (tried ".
+			     join(" ", @alternatives).")\n");
+		}
+	} else {
+		$mod = $rc;
+	}
+
+	eval "load '$mod', 'decode_json'";
+	if ($@) {
+		die("Module is not installed: ". "'$mod'\n");
+	}
+	info("Using JSON module $mod\n");
+}
diff --git a/externals/lcov/bin/genpng b/externals/lcov/bin/genpng
index 943a49d5f0454e01aa12430fbc97a44805ac404e..5049f1f571d7634d9ef61c91a033ea5d5c0fcec2 100755
--- a/externals/lcov/bin/genpng
+++ b/externals/lcov/bin/genpng
@@ -13,8 +13,8 @@
 #   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # genpng
@@ -38,16 +38,16 @@ use Cwd qw/abs_path/;
 
 # Constants
 our $tool_dir		= abs_path(dirname($0));
-our $lcov_version	= "LCOV version 1.14";
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $lcov_version	= 'LCOV version '.`"$tool_dir"/get_version.sh --full`;
+our $lcov_url		= "https://github.com/linux-test-project/lcov";
 our $tool_name		= basename($0);
 
 
 # Prototypes
-sub gen_png($$$@);
+sub gen_png($$$$@);
 sub check_and_load_module($);
 sub genpng_print_usage(*);
-sub genpng_process_file($$$$);
+sub genpng_process_file($$$$$);
 sub genpng_warn_handler($);
 sub genpng_die_handler($);
 
@@ -74,6 +74,7 @@ if (!caller)
 	my $filename;
 	my $tab_size = 4;
 	my $width = 80;
+	my $dark = 0;
 	my $out_filename;
 	my $help;
 	my $version;
@@ -85,6 +86,7 @@ if (!caller)
 	if (!GetOptions("tab-size=i" => \$tab_size,
 			"width=i" => \$width,
 			"output-filename=s" => \$out_filename,
+			"dark-mode" => \$dark,
 			"help" => \$help,
 			"version" => \$version))
 	{
@@ -121,7 +123,7 @@ if (!caller)
 		$out_filename = "$filename.png";
 	}
 
-	genpng_process_file($filename, $out_filename, $width, $tab_size);
+	genpng_process_file($filename, $out_filename, $width, $tab_size, $dark);
 	exit(0);
 }
 
@@ -146,6 +148,7 @@ or .gcov file format.
   -v, --version                     Print version number, then exit
   -t, --tab-size TABSIZE            Use TABSIZE spaces in place of tab
   -w, --width WIDTH                 Set width of output image to WIDTH pixel
+  -d, --dark-mode                   Use a light-on-dark color scheme
   -o, --output-filename FILENAME    Write image to FILENAME
 
 For more information see: $lcov_url
@@ -170,15 +173,16 @@ sub check_and_load_module($)
 
 
 #
-# genpng_process_file(filename, out_filename, width, tab_size)
+# genpng_process_file(filename, out_filename, width, tab_size, dark)
 #
 
-sub genpng_process_file($$$$)
+sub genpng_process_file($$$$$)
 {
 	my $filename		= $_[0];
 	my $out_filename	= $_[1];
 	my $width		= $_[2];
 	my $tab_size		= $_[3];
+	my $dark		= $_[4];
 	local *HANDLE;
 	my @source;
 
@@ -215,12 +219,12 @@ sub genpng_process_file($$$$)
 	}
 	close(HANDLE);
 
-	gen_png($out_filename, $width, $tab_size, @source);
+	gen_png($out_filename, $dark, $width, $tab_size, @source);
 }
 
 
 #
-# gen_png(filename, width, tab_size, source)
+# gen_png(filename, dark, width, tab_size, source)
 #
 # Write an overview PNG file to FILENAME. Source code is defined by SOURCE
 # which is a list of lines <count>:<source code> per source code line.
@@ -232,9 +236,10 @@ sub genpng_process_file($$$$)
 # Die on error.
 #
 
-sub gen_png($$$@)
+sub gen_png($$$$@)
 {
 	my $filename = shift(@_);	# Filename for PNG file
+	my $dark_mode = shift(@_);      # dark-on-light, if set
 	my $overview_width = shift(@_);	# Imagewidth for image
 	my $tab_size = shift(@_);	# Replacement string for tab signs
 	my @source = @_;	# Source code as passed via argument 2
@@ -271,14 +276,28 @@ sub gen_png($$$@)
 		or die("ERROR: cannot allocate overview image!\n");
 
 	# Define colors
-	$col_plain_back	= $overview->colorAllocate(0xff, 0xff, 0xff);
-	$col_plain_text	= $overview->colorAllocate(0xaa, 0xaa, 0xaa);
-	$col_cov_back	= $overview->colorAllocate(0xaa, 0xa7, 0xef);
-	$col_cov_text	= $overview->colorAllocate(0x5d, 0x5d, 0xea);
-	$col_nocov_back = $overview->colorAllocate(0xff, 0x00, 0x00);
-	$col_nocov_text = $overview->colorAllocate(0xaa, 0x00, 0x00);
-	$col_hi_back = $overview->colorAllocate(0x00, 0xff, 0x00);
-	$col_hi_text = $overview->colorAllocate(0x00, 0xaa, 0x00);
+	# overview->colorAllocate(red, green, blue)
+	if ($dark_mode) {
+	  # just reverse foregrond and background
+	  #  there is probably a better color scheme than this.
+	  $col_plain_text = $overview->colorAllocate(0xaa, 0xaa, 0xaa); # light grey
+	  $col_plain_back = $overview->colorAllocate(0x00, 0x00, 0x00);
+	  $col_cov_text	  = $overview->colorAllocate(0xaa, 0xa7, 0xef);
+	  $col_cov_back	  = $overview->colorAllocate(0x5d, 0x5d, 0xea);
+	  $col_nocov_text = $overview->colorAllocate(0xff, 0x00, 0x00);
+	  $col_nocov_back = $overview->colorAllocate(0xaa, 0x00, 0x00);
+	  $col_hi_text    = $overview->colorAllocate(0x00, 0xff, 0x00);
+	  $col_hi_back    = $overview->colorAllocate(0x00, 0xaa, 0x00);
+	} else {
+	  $col_plain_back = $overview->colorAllocate(0xff, 0xff, 0xff);
+	  $col_plain_text = $overview->colorAllocate(0xaa, 0xaa, 0xaa);
+	  $col_cov_back	  = $overview->colorAllocate(0xaa, 0xa7, 0xef);
+	  $col_cov_text	  = $overview->colorAllocate(0x5d, 0x5d, 0xea);
+	  $col_nocov_back = $overview->colorAllocate(0xff, 0x00, 0x00);
+	  $col_nocov_text = $overview->colorAllocate(0xaa, 0x00, 0x00);
+	  $col_hi_back    = $overview->colorAllocate(0x00, 0xff, 0x00);
+	  $col_hi_text    = $overview->colorAllocate(0x00, 0xaa, 0x00);
+	}
 
 	# Visualize each line
 	foreach $line (@source)
diff --git a/externals/lcov/bin/get_version.sh b/externals/lcov/bin/get_version.sh
index ac5a36314699c7ccfa374d14a1c6e5ab68a62270..62b493314194d6a5efd9a559649d9ea79f6104b7 100755
--- a/externals/lcov/bin/get_version.sh
+++ b/externals/lcov/bin/get_version.sh
@@ -4,9 +4,9 @@
 #
 # Print lcov version or release information as provided by Git, .version
 # or a fallback.
-
-TOOLDIR=$(cd $(dirname $0) >/dev/null ; pwd)
-GITVER=$(cd $TOOLDIR ; git describe --tags 2>/dev/null)
+DIRPATH=$(dirname "$0")
+TOOLDIR=$(cd "$DIRPATH" >/dev/null ; pwd)
+GITVER=$(cd "$TOOLDIR" ; git describe --tags 2>/dev/null)
 
 if [ -z "$GITVER" ] ; then
 	# Get version information from file
diff --git a/externals/lcov/bin/lcov b/externals/lcov/bin/lcov
index 33c9f4d16e718f2f76e83d090b2ed2beeec4435f..7c73ab3d23397f76aaaa40a6d2832bcae279fbf8 100755
--- a/externals/lcov/bin/lcov
+++ b/externals/lcov/bin/lcov
@@ -13,8 +13,8 @@
 #   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#   along with this program;  if not, see
+#   <http://www.gnu.org/licenses/>.
 #
 #
 # lcov
@@ -73,8 +73,8 @@ use Cwd qw /abs_path getcwd/;
 
 # Global constants
 our $tool_dir		= abs_path(dirname($0));
-our $lcov_version	= "LCOV version 1.14";
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
+our $lcov_version	= 'LCOV version '.`"$tool_dir"/get_version.sh --full`;
+our $lcov_url		= "https://github.com/linux-test-project/lcov";
 our $tool_name		= basename($0);
 
 # Directory containing gcov kernel files
@@ -131,6 +131,7 @@ sub temp_cleanup();
 sub setup_gkv();
 sub get_overall_line($$$$);
 sub print_overall_rate($$$$$$$$$);
+sub check_rates($$);
 sub lcov_geninfo(@);
 sub create_package($$$;$);
 sub get_func_found_and_hit($);
@@ -159,6 +160,7 @@ our $cwd = `pwd`;	# Current working directory
 our $data_stdout;	# If set, indicates that data is written to stdout
 our $follow;		# If set, indicates that find shall follow links
 our $diff_path = "";	# Path removed from tracefile when applying diff
+our $opt_fail_under_lines = 0;
 our $base_directory;	# Base directory (cwd of gcc during compilation)
 our $checksum;		# If set, calculate a checksum for each line
 our $no_checksum;	# If set, don't calculate a checksum for each line
@@ -254,6 +256,7 @@ if ($config || %opt_rc)
 		"lcov_list_truncate_max"=> \$opt_list_truncate_max,
 		"lcov_branch_coverage"	=> \$br_coverage,
 		"lcov_function_coverage"=> \$func_coverage,
+		"lcov_fail_under_lines" => \$opt_fail_under_lines,
 	});
 }
 
@@ -300,6 +303,7 @@ if (!GetOptions("directory|d|di=s" => \@directory,
 		"compat=s" => \$opt_compat,
 		"config-file=s" => \$opt_config_file,
 		"rc=s%" => \%opt_rc,
+		"fail-under-lines=s" => \$opt_fail_under_lines,
 		))
 {
 	print(STDERR "Use $tool_name --help to get usage information\n");
@@ -400,6 +404,7 @@ if (!$from_package && !@directory && ($capture || $reset)) {
 	($gcov_gkv, $gcov_dir) = setup_gkv();
 }
 
+our $exit_code = 0;
 # Check for requested functionality
 if ($reset)
 {
@@ -473,6 +478,7 @@ elsif (@opt_summary)
 	($ln_overall_found, $ln_overall_hit,
 	 $fn_overall_found, $fn_overall_hit,
 	 $br_overall_found, $br_overall_hit) = summary();
+	$exit_code = check_rates($ln_overall_found, $ln_overall_hit);
 }
 
 temp_cleanup();
@@ -484,7 +490,7 @@ if (defined($ln_overall_found)) {
 } else {
 	info("Done.\n") if (!$list && !$capture);
 }
-exit(0);
+exit($exit_code);
 
 #
 # print_usage(handle)
@@ -545,6 +551,8 @@ Options:
       --compat MODE=on|off|auto   Set compat MODE (libtool, hammer, split_crc)
       --include PATTERN           Include files matching PATTERN
       --exclude PATTERN           Exclude files matching PATTERN
+      --fail-under-lines MIN      Exit with a status of 1 if the total line
+                                  coverage is less than MIN (summary option).
 
 For more information see: $lcov_url
 END_OF_USAGE
@@ -4293,6 +4301,33 @@ sub print_overall_rate($$$$$$$$$)
 		if ($br_do);
 }
 
+#
+# check_rates(ln_found, ln_hit)
+#
+# Check line coverage if it meets a specified threshold.
+#
+
+sub check_rates($$)
+{
+	my ($ln_found, $ln_hit) = @_;
+
+	if ($opt_fail_under_lines <= 0) {
+		return 0;
+	}
+
+	if ($ln_found == 0) {
+		return 1;
+	}
+
+	my $actual_rate = ($ln_hit / $ln_found);
+	my $expected_rate = $opt_fail_under_lines / 100;
+	if ($actual_rate >= $expected_rate) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
 
 #
 # rate(hit, found[, suffix, precision, width])
diff --git a/externals/lcov/bin/updateversion.pl b/externals/lcov/bin/updateversion.pl
index 19db81ecd3e3228e0f5115dada99755eae2f611d..d39918a6c9ce29abbdbb428d5fe647f867322a08 100755
--- a/externals/lcov/bin/updateversion.pl
+++ b/externals/lcov/bin/updateversion.pl
@@ -84,7 +84,9 @@ sub get_file_info($)
 
 	return (0, 0, 0) if (!-e $filename);
 	@stat = stat($filename);
-	($sec, $min, $hour, $day, $month, $year) = gmtime($stat[9]);
+	my $epoch = int($ENV{SOURCE_DATE_EPOCH} || $stat[9]);
+	$epoch = $stat[9] if $stat[9] < $epoch;
+	($sec, $min, $hour, $day, $month, $year) = gmtime($epoch);
 	$year += 1900;
 	$month += 1;
 
diff --git a/externals/lcov/example/methods/iterate.c b/externals/lcov/example/methods/iterate.c
index 023d1801c9364f71c994e8c0dbe04b93f3992f34..3dac70d7cf63ec19b689d986300394d2e80abfec 100644
--- a/externals/lcov/example/methods/iterate.c
+++ b/externals/lcov/example/methods/iterate.c
@@ -13,6 +13,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 #include "iterate.h"
 
 
@@ -28,9 +29,9 @@ int iterate_get_sum (int min, int max)
 	for (i = min; i <= max; i++)
 	{
 		/* We can detect an overflow by checking whether the new
-		   sum would become negative. */
+		   sum would exceed the maximum integer value. */
 
-		if (total + i < total)
+		if (total > INT_MAX - i)
 		{
 			printf ("Error: sum too large!\n");
 			exit (1);
diff --git a/externals/lcov/lcovrc b/externals/lcov/lcovrc
index 40f364f17aa6497f4ccd8af98145367f4b8341ae..4112b8f70f56d1c818522aa2548e50dcbdeda492 100644
--- a/externals/lcov/lcovrc
+++ b/externals/lcov/lcovrc
@@ -8,6 +8,18 @@
 # Specify an external style sheet file (same as --css-file option of genhtml)
 #genhtml_css_file = gcov.css
 
+# use 'dark' mode display (light foreground, dark background) instead of default
+# same as 'genhtml --dark-mode ....'
+#genhtml_dark_mode = 1
+
+# Header text to use at top of each page
+# Default is "LCOV - coverage report"
+#genhtml_header = Coverage report for my project
+
+# Footer text to use at the bottom of each page
+# Default is LCOV tool version
+#genhtml_footer = My footer text
+
 # Specify coverage rate limits (in %) for classifying file entries
 # HI:   hi_limit <= rate <= 100         graph color: green
 # MED: med_limit <= rate <  hi_limit    graph color: orange
@@ -102,6 +114,12 @@ genhtml_desc_html=0
 # Demangle C++ symbols
 #genhtml_demangle_cpp=1
 
+# Name of the tool used for demangling C++ function names
+#genhtml_demangle_cpp_tool = c++filt
+
+# Specify extra parameters to be passed to the demangling tool
+#genhtml_demangle_cpp_params = ""
+
 # Location of the gcov tool (same as --gcov-info option of geninfo)
 #geninfo_gcov_tool = gcov
 
@@ -134,6 +152,12 @@ genhtml_desc_html=0
 # when collecting coverage data.
 geninfo_auto_base = 1
 
+# Use gcov intermediate format? Valid values are 0, 1, auto
+geninfo_intermediate = auto
+
+# Specify if exception branches should be excluded from branch coverage.
+geninfo_no_exception_branch = 0
+
 # Directory containing gcov kernel files
 # lcov_gcov_dir = /proc/gcov
 
@@ -167,3 +191,10 @@ lcov_function_coverage = 1
 
 # Specify if branch coverage data should be collected and processed.
 lcov_branch_coverage = 0
+
+# Ask LCOV to return non-zero exit code if line coverage is below threshold
+# Default is 0.0 - i.e., do not check threshold.
+#lcov_fail_under_lines = 97.5
+
+# Specify JSON module to use, or choose best available if set to auto
+lcov_json_module = auto
diff --git a/externals/lcov/man/gendesc.1 b/externals/lcov/man/gendesc.1
index 9c9a7084db2f39c8245a19c2a08db3e610acf5b8..3d965ad4c5733eb7aedf5688ada6b76a6f957c4a 100644
--- a/externals/lcov/man/gendesc.1
+++ b/externals/lcov/man/gendesc.1
@@ -1,4 +1,4 @@
-.TH gendesc 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.TH gendesc 1 "LCOV 1.16" 2020\-08\-12 "User Manuals"
 .SH NAME
 gendesc \- Generate a test case description file
 .SH SYNOPSIS
diff --git a/externals/lcov/man/genhtml.1 b/externals/lcov/man/genhtml.1
index 949bd4c574b977f1824150751763e2c81a45bb95..e03f06bc17bbd5805a75a946205d234f1c751f76 100644
--- a/externals/lcov/man/genhtml.1
+++ b/externals/lcov/man/genhtml.1
@@ -1,4 +1,4 @@
-.TH genhtml 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.TH genhtml 1 "LCOV 1.16" 2022\-06\-02 "User Manuals"
 .SH NAME
 genhtml \- Generate HTML view from LCOV coverage data files
 .SH SYNOPSIS
@@ -17,6 +17,12 @@ genhtml \- Generate HTML view from LCOV coverage data files
 .RB [ \-o | \-\-output\-directory
 .IR output\-directory ]
 .br
+.RB [ \-\-header-title
+.IR banner ]
+.br
+.RB [ \-\-footer
+.IR string ]
+.br
 .RB [ \-t | \-\-title
 .IR title ]
 .br
@@ -65,8 +71,11 @@ genhtml \- Generate HTML view from LCOV coverage data files
 .IR keyword = value ]
 .br
 .RB [ \-\-precision
+.IR num ]
 .RB [ \-\-missed ]
 .br
+.RB [ \-\-dark\-mode ]
+.br
 .IR tracefile(s)
 .RE
 .SH DESCRIPTION
@@ -201,13 +210,41 @@ project size, a lot of files and subdirectories may be created.
 .RS
 Display 
 .I title
-in header of all pages.
+in header table of all pages.
 
 .I title
-is written to the header portion of each generated HTML page to
-identify the context in which a particular output
+is written to the "Test:"-field in the header table at the top of each
+generated HTML page to identify the context in which a particular output
 was created. By default this is the name of the tracefile.
 
+A potential use is to specify a test run name, or a version control system
+identifier that indicates the code level that was tested.
+
+.RE
+.BI "\-\-header\-title " BANNER
+.RS
+Display
+.I BANNER
+in header of all pages.
+
+.I BANNER
+is written to the header portion of each generated HTML page. By default this
+simply identifies this as an LCOV coverage report.
+
+A potential use is to specify the name of the project or project branch and
+build ID.
+
+.RE
+.BI "\-\-footer " FOOTER
+.RS
+Display
+.I FOOTER
+in footer of all pages.
+
+.I FOOTER
+is written to the footer portion of each generated HTML page.
+The default simply identifies the LCOV tool version used to generate the report.
+
 .RE
 .BI "\-d " description\-file
 .br
@@ -576,6 +613,13 @@ option
 .IR genhtml_missed .
 .RE
 
+.B \-\-dark\-mode
+.RS
+Use a light-display-on-dark-background color scheme rather than the default dark-display-on-light-background.
+
+The idea is to reduce eye strain due to viewing dark text on a bright screen - particularly at night.
+
+
 .SH FILES
 
 .I /etc/lcovrc
diff --git a/externals/lcov/man/geninfo.1 b/externals/lcov/man/geninfo.1
index 2ce917126c413c54919907147202b18141062b2f..b805591db6e47cff071af0496920ba3844cdc892 100644
--- a/externals/lcov/man/geninfo.1
+++ b/externals/lcov/man/geninfo.1
@@ -1,4 +1,4 @@
-.TH geninfo 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.TH geninfo 1 "LCOV 1.16" 2020\-08\-12 "User Manuals"
 .SH NAME
 geninfo \- Generate tracefiles from .da files
 .SH SYNOPSIS
@@ -123,6 +123,25 @@ Marks the end of a section which is excluded from branch coverage. The current
 line not part of this section.
 .RE
 .br
+LCOV_EXCL_EXCEPTION_BR_LINE
+.RS
+Lines containing this marker will be excluded from exception branch coverage:
+Exception branches will be ignored, but non-exception branches will not be
+affected.
+.br
+.RE
+LCOV_EXCL_EXCEPTION_BR_START
+.RS
+Marks the beginning of a section which is excluded from exception branch 
+coverage. The current line is part of this section.
+.br
+.RE
+LCOV_EXCL_EXCEPTION_BR_STOP
+.RS
+Marks the end of a section which is excluded from exception branch coverage. 
+The current line not part of this section.
+.RE
+.br
 
 .SH OPTIONS
 
@@ -307,6 +326,10 @@ command line switches. The
 will be interpreted as shell wildcard patterns (note that they may need to be
 escaped accordingly to prevent the shell from expanding them first).
 
+Note: The pattern must be specified to match the
+.B absolute
+path of each source file.
+
 Can be combined with the
 .B --include
 command line switch. If a given file matches both the include pattern and the
@@ -366,6 +389,10 @@ command line switches. The
 .I patterns
 will be interpreted as shell wildcard patterns (note that they may need to be
 escaped accordingly to prevent the shell from expanding them first).
+
+Note: The pattern must be specified to match the
+.B absolute
+path of each source file.
 .RE
 
 .B \-\-ignore\-errors
diff --git a/externals/lcov/man/genpng.1 b/externals/lcov/man/genpng.1
index f6a49b8a5d48af9f9b0c10b151592fd703ca01d4..2d1d8206ac0d442660187a9e33f6eefcf6697079 100644
--- a/externals/lcov/man/genpng.1
+++ b/externals/lcov/man/genpng.1
@@ -1,4 +1,4 @@
-.TH genpng 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.TH genpng 1 "LCOV 1.16" 2022\-06\-01 "User Manuals"
 .SH NAME
 genpng \- Generate an overview image from a source file
 .SH SYNOPSIS
@@ -11,6 +11,7 @@ genpng \- Generate an overview image from a source file
 .IR tabsize ]
 .RB [ \-w | \-\-width
 .IR width ]
+.RB [ \-d | \-\-dark\-mode ]
 .br
 .RB [ \-o | \-\-output\-filename
 .IR output\-filename ]
@@ -79,6 +80,12 @@ Note that source code lines which are longer than
 will be truncated.
 .RE
 
+.B \-d
+.br
+.B \-\-dark\-mode
+.RS
+Use a light-display-on-dark-background color scheme rather than the default dark-display-on-light-background.
+.RE
 
 .BI "\-o " filename
 .br
diff --git a/externals/lcov/man/lcov.1 b/externals/lcov/man/lcov.1
index e86eb3aa7624a76d122d791eaca2666dd41362de..22e4639520ddd7968426d7df7adb7b21d2e512f3 100644
--- a/externals/lcov/man/lcov.1
+++ b/externals/lcov/man/lcov.1
@@ -1,4 +1,4 @@
-.TH lcov 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.TH lcov 1 "LCOV 1.16" 2022\-06\-03 "User Manuals"
 .SH NAME
 lcov \- a graphical GCOV front\-end
 .SH SYNOPSIS
@@ -170,6 +170,8 @@ lcov \- a graphical GCOV front\-end
 .RS 5
 .br
 .RB [ \-q | \-\-quiet ]
+.RB [ \-\-fail-under-lines
+.IR percentage ]
 .br
 .RE
 
@@ -198,7 +200,7 @@ you have to complete the following preparation steps:
 For Linux kernel coverage:
 .RS
 Follow the setup instructions for the gcov\-kernel infrastructure:
-.I http://ltp.sourceforge.net/coverage/gcov.php
+.I https://docs.kernel.org/dev-tools/gcov.html
 .br
 
 
@@ -497,6 +499,10 @@ command line switches. The
 will be interpreted as shell wildcard patterns (note that they may need to be
 escaped accordingly to prevent the shell from expanding them first).
 
+Note: The pattern must be specified to match the
+.B absolute
+path of each source file.
+
 Can be combined with the
 .B --include
 command line switch. If a given file matches both the include pattern and the
@@ -540,6 +546,10 @@ Every file entry in
 .I tracefile
 which matches at least one of those patterns will be extracted.
 
+Note: The pattern must be specified to match the
+.B absolute
+path of each source file.
+
 The result of the extract operation will be written to stdout or the tracefile
 specified with \-o.
 
@@ -598,6 +608,10 @@ command line switches. The
 .I patterns
 will be interpreted as shell wildcard patterns (note that they may need to be
 escaped accordingly to prevent the shell from expanding them first).
+
+Note: The pattern must be specified to match the
+.B absolute
+path of each source file.
 .RE
 
 .B \-\-ignore\-errors
@@ -799,6 +813,10 @@ Every file entry in
 .I tracefile
 which matches at least one of those patterns will be removed.
 
+Note: The pattern must be specified to match the
+.B absolute
+path of each source file.
+
 The result of the remove operation will be written to stdout or the tracefile
 specified with \-o.
 
@@ -828,6 +846,14 @@ Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
 specified at a time.
 .RE
 
+.B \-\-fail-under-lines
+.I percentage
+.br
+.RS
+Use this option together with \-\-summary to tell lcov to exit with a status of 1 if the total
+line coverage is less than percentage.
+.RE
+
 .B \-t
 .I testname
 .br
diff --git a/externals/lcov/man/lcovrc.5 b/externals/lcov/man/lcovrc.5
index f20d273a92c8ebd48ac8a9f68498024124ef0a8f..61a5a3ce9d2614e88eb414ed054d22ba99093957 100644
--- a/externals/lcov/man/lcovrc.5
+++ b/externals/lcov/man/lcovrc.5
@@ -1,4 +1,4 @@
-.TH lcovrc 5 "LCOV 1.14" 2019\-02\-28 "User Manuals"
+.TH lcovrc 5 "LCOV 1.16" 2022\-06\-02 "User Manuals"
 
 .SH NAME
 lcovrc \- lcov configuration file
@@ -47,6 +47,23 @@ section 'OPTIONS' below.
 #genhtml_css_file = gcov.css
 .br
 
+# Use 'dark' mode display (light foreground/dark background)
+.br
+# rather than default
+.br
+#genhtml_dark_mode = 1
+.br
+
+# Alternate header text to use at top of each page
+.br
+#genhtml_header = Coverage report for my project
+.br
+
+# Alternate footer text to use at the bottom of each page
+.br
+#genhtml_footer = My footer text
+.br
+
 # Coverage rate limits
 .br
 genhtml_hi_limit = 90
@@ -169,6 +186,16 @@ genhtml_desc_html=0
 #genhtml_demangle_cpp=1
 .br
 
+# Name of the tool used for demangling C++ function names
+.br
+#genhtml_demangle_cpp_tool = c++filt
+.br
+
+# Specify extra parameters to be passed to the demangling tool
+.br
+#genhtml_demangle_cpp_params = ""
+.br
+
 # Location of the gcov tool
 .br
 #geninfo_gcov_tool = gcov
@@ -223,6 +250,11 @@ geninfo_compat_libtool = 0
 geninfo_auto_base = 1
 .br
 
+# Use gcov intermediate format? Valid values are 0, 1, auto
+.br
+geninfo_intermediate = auto
+.br
+
 # Directory containing gcov kernel files
 .br
 lcov_gcov_dir = /proc/gcov
@@ -266,6 +298,21 @@ lcov_function_coverage = 1
 .br
 lcov_branch_coverage = 0
 .br
+
+# Ask LCOV to return non-zero exit code if line coverage is
+.br
+# below specified threshold percentage.
+.br
+lcov_fail_under_lines = 97.5
+.br
+
+# Specify JSON module to use, or choose best available if
+.br
+# set to auto
+.br
+lcov_json_module = auto
+.br
+
 .PP
 
 .SH OPTIONS
@@ -286,6 +333,45 @@ This option corresponds to the \-\-css\-file command line option of
 By default, a standard CSS file is generated.
 .PP
 
+.BR genhtml_header " ="
+.I string
+.IP
+Specify header text to use at top of each HTML page.
+.br
+
+This option corresponds to the \-\-header\-title command line option of
+.BR genhtml .
+.br
+
+Default is "LCOV - coverage report".
+.PP
+
+.BR genhtml_footer " ="
+.I string
+.IP
+Specify footer text to use at bottom of each HTML page.
+.br
+
+This option corresponds to the \-\-footer command line option of
+.BR genhtml .
+.br
+
+Default is LCOV tool version string.
+.PP
+
+.BR genhtml_dark_mode " ="
+.IR  0 | 1
+.IP
+If non-zero, display using light text on dark background rather than dark text on light background.
+.br
+
+This option corresponds to the \-\-dark\-mode command line option of
+.BR genhtml .
+.br
+
+By default, a 'light' palette is used.
+.PP
+
 .BR genhtml_hi_limit "  ="
 .I hi_limit
 .br
@@ -586,6 +672,32 @@ This option corresponds to the \-\-demangle\-cpp command line option of
 Default is 0.
 .PP
 
+.BR genhtml_demangle_cpp_tool " ="
+.I path_to_c++filt
+.IP
+Specify the location of the demangle tool (see
+.BR c++filt (1))
+used to convert C++ internal function names to human readable format
+for display on the HTML function overview page.
+.br
+
+Default is 'c++filt'.
+.PP
+
+.BR genhtml_demangle_cpp_params " ="
+.I parameters
+.IP
+Specify extra parameters to be passed to the demangling tool
+
+Use this option if your environment requires additional parameters such
+as --no-strip-underscore for correctly demangling C++ internal function
+names. See also
+.BR c++filt (1)).
+.br
+
+Default is "".
+.PP
+
 .BR genhtml_desc_html " ="
 .IR 0 | 1
 .IP
@@ -789,6 +901,34 @@ located, and in addition, is different between files of the same project.
 Default is 1.
 .PP
 
+.BR geninfo_intermediate " ="
+.IR 0 | 1 | auto
+.IP
+Specify whether to use gcov intermediate format
+.br
+
+Use this option to control whether geninfo should use the gcov intermediate
+format while collecting coverage data. The use of the gcov intermediate format
+should increase processing speed. It also provides branch coverage data when
+using the \-\-initial command line option.
+.br
+
+Valid values are 0 for off, 1 for on, and "auto" to let geninfo automatically
+use immediate format when supported by gcov.
+.br
+
+Default is "auto".
+.PP
+
+.BR geninfo_no_exception_branch " ="
+.IR 0 | 1
+.IP
+Specify whether to exclude exception branches from branch coverage.
+.br
+
+Default is 0.
+.PP
+
 .BR lcov_gcov_dir " ="
 .I path_to_kernel_coverage_data
 .IP
@@ -893,6 +1033,39 @@ Specify the regular expression of lines to exclude from branch coverage.
 Default is 'LCOV_EXCL_BR_LINE'.
 .PP
 
+.BR lcov_excl_exception_br_line " ="
+.I expression
+.IP
+Specify the regular expression of lines to exclude from exception branch coverage.
+.br
+
+Default is 'LCOV_EXCL_EXCEPTION_BR_LINE'.
+.PP
+
+.BR lcov_fail_under_lines " ="
+.I percentage
+.IP
+Specify line coverage threshold to lcov.  If the line coverage is below this threshold, lcov will generate all the normal result files and messages, but will return a non-zero exit code.
+.br
+
+This option is equivalent to the \-\-fail\-under\-lines lcov command line option.
+
+.br
+The default is 0 (no threshold).
+.PP
+
+.BR lcov_json_module " ="
+.IR module | auto
+.IP
+Specify the JSON module to use, or choose best available from a set of
+alternatives if set to 'auto'. Note that some JSON modules are slower than
+others (notably JSON::PP can be very slow compared to JSON::XS).
+.br
+
+Default is 'auto'.
+.PP
+
+
 .SH FILES
 
 .TP
diff --git a/externals/lcov/rpm/lcov.spec b/externals/lcov/rpm/lcov.spec
index e96c8d47bd08ce9c2c185c0ac417f88b1e25e77f..06e62d8c41602a87e95fe555eff5cb31805aa675 100644
--- a/externals/lcov/rpm/lcov.spec
+++ b/externals/lcov/rpm/lcov.spec
@@ -1,11 +1,11 @@
 Summary: A graphical GCOV front-end
 Name: lcov
-Version: 1.14
+Version: 1.16
 Release: 1
 License: GPLv2+
 Group: Development/Tools
-URL: http://ltp.sourceforge.net/coverage/lcov.php
-Source0: http://downloads.sourceforge.net/ltp/%{name}-%{version}.tar.gz
+URL: https://github.com/linux-test-project/lcov
+Source0: https://github.com/linux-test-project/%{name}/releases/download/v%{version}/%{name}-%{version}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-root
 BuildArch: noarch
 Requires: perl >= 5.8.8