diff --git a/.gitignore b/.gitignore
index dfde6313c202bef74d078fce87990a3ed75f6703..3cae07ed12fb99adfecd0f135675fab3cf473803 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
 bins
+coverage
 deps
+*.gcno
 gens
 libs
 objs
diff --git a/Makefile b/Makefile
index 9c696369617ebc29fffba5495aaab00875284d3c..76e6407b880f1af536a799e383898b0d493d5c6f 100644
--- a/Makefile
+++ b/Makefile
@@ -49,6 +49,15 @@ CPPFLAGS_msan = -O1 -fsanitize=memory -fno-omit-frame-pointer
 LDFLAGS_msan = -fsanitize=memory
 DEFINES_msan = NDEBUG
 
+VALID_CONFIG_gcov = 1
+CC_gcov = gcc
+CXX_gcov = g++
+LD_gcov = gcc
+LDXX_gcov = g++
+CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage
+LDFLAGS_gcov = -fprofile-arcs -ftest-coverage
+DEFINES_gcov = NDEBUG
+
 # General settings.
 # You may want to change these depending on your system.
 
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 798e7e3377546f32dc8a7ce33b9af1b97c001c8d..256380c2ddc1d51a1a1d501fb0364297d0171c0e 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -66,6 +66,15 @@ CPPFLAGS_msan = -O1 -fsanitize=memory -fno-omit-frame-pointer
 LDFLAGS_msan = -fsanitize=memory
 DEFINES_msan = NDEBUG
 
+VALID_CONFIG_gcov = 1
+CC_gcov = gcc
+CXX_gcov = g++
+LD_gcov = gcc
+LDXX_gcov = g++
+CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage
+LDFLAGS_gcov = -fprofile-arcs -ftest-coverage
+DEFINES_gcov = NDEBUG
+
 # General settings.
 # You may want to change these depending on your system.
 
diff --git a/tools/run_tests/run_lcov.sh b/tools/run_tests/run_lcov.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6f22b0e8a4110389edecf92801448a80c1281a03
--- /dev/null
+++ b/tools/run_tests/run_lcov.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -ex
+
+out=`realpath ${1:-coverage}`
+
+root=`realpath $(dirname $0)/../..`
+tmp=`mktemp`
+cd $root
+tools/run_tests/run_tests.py -c gcov
+lcov --capture --directory . --output-file $tmp
+genhtml $tmp --output-directory $out
+rm $tmp
+if which xdg-open > /dev/null
+then
+  xdg-open file://$out/index.html
+fi
+
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 6ab80d90453e5893bacadbf21a6944faecee0f16..bb25b38e57052e10eeda76b196500ae41499c293 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -36,6 +36,7 @@ _CONFIGS = {
   'tsan': SimpleConfig('tsan'),
   'msan': SimpleConfig('msan'),
   'asan': SimpleConfig('asan'),
+  'gcov': SimpleConfig('gcov'),
   'valgrind': ValgrindConfig('dbg'),
   }