diff --git a/.gitignore b/.gitignore
index bb3817ba57d9980397c21bf2e3eca3fd1dc7bcd5..201d04da66c25dd78b2aa59f6f9f3ca773f231c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -152,6 +152,8 @@
 /src/or/or_sha1.i
 /src/or/tor
 /src/or/tor.exe
+/src/or/tor-cov
+/src/or/tor-cov.exe
 /src/or/libtor.a
 /src/or/libtor-testing.a
 /src/or/libtor.lib
diff --git a/Makefile.am b/Makefile.am
index a736638e4b2165d344845f88801801b81a4a0beb..1bc1077ebb84e5609a66b1e91cf6fad55b275c81 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,12 @@ EXTRA_DIST+= \
 	README						\
 	ReleaseNotes
 
+if COVERAGE_ENABLED
+TEST_CFLAGS=-fno-inline -fprofile-arcs -ftest-coverage
+else
+TEST_CFLAGS=
+endif
+
 #install-data-local:
 #	$(INSTALL) -m 755 -d $(LOCALSTATEDIR)/lib/tor
 
@@ -89,3 +95,5 @@ version:
 	   (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \
 	fi
 
+mostlyclean-local:
+	rm -f src/*/*.gc{da,no}
diff --git a/changes/fancy_testing b/changes/fancy_testing
index 3e8ccbca483be291e515c1602772503fe80c2c9b..ad197c6f584314a35ffa2d75c020e8913594c41f 100644
--- a/changes/fancy_testing
+++ b/changes/fancy_testing
@@ -10,3 +10,7 @@
       in the unit tests; all functions exposed from a module for
       unit-testing only are now static in production builds.
 
+    - Add an --enable-coverage configuration option to make the unit
+      tests (and a new src/or/tor-cov target) to build with gcov test
+      coverage support.
+
diff --git a/configure.ac b/configure.ac
index 34ed524dd85533ee2b608403d82507b17a7f3557..22aac31bf2c7ba16942b0dd12830b13096104656 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,8 +41,13 @@ AC_ARG_ENABLE(curve25519,
    AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support))
 AC_ARG_ENABLE(unittests,
    AS_HELP_STRING(--disable-unittests, [Don't build unit tests for Tor. Risky!]))
+AC_ARG_ENABLE(coverage,
+   AS_HELP_STRING(--enable-coverage, [Enable coverage support in the unit-test build]))
 
-AM_CONDITIONAL(UNITTESTS_ENABLED, test x$unittests != xno)
+AM_CONDITIONAL(UNITTESTS_ENABLED, test x$enable_unittests != xno)
+AM_CONDITIONAL(COVERAGE_ENABLED, test x$enable_coverage = xyes)
+
+echo "COVERAGE: $enable_coverage"
 
 if test "$enable_static_tor" = "yes"; then
   enable_static_libevent="yes";
@@ -1457,7 +1462,12 @@ if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xy
 # CFLAGS="$CFLAGS -Winline"
 fi
 
-
+if test "$enable_coverage" = yes && test "$have_clang" = "no"; then
+   case "$host_os" in
+    darwin*)
+      AC_MSG_WARN([Tried to enable coverage on OSX without using the clang compiler. This might not work! If coverage fails, use CC=clang when configuring with --enable-profiling.])
+   esac
+fi
 
 CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib"
 
diff --git a/contrib/coverage b/contrib/coverage
new file mode 100755
index 0000000000000000000000000000000000000000..52fe96d75611b86af063cb085578c6f67567492c
--- /dev/null
+++ b/contrib/coverage
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright 2013  The Tor Project, Inc.
+# See LICENSE for licensing information.
+
+# coverage -- run gcov on the appropriate set of object files to extract
+# coverage information.
+
+for fn in src/{or,common}/*.c; do
+    BN=`basename $fn`
+    DN=`dirname $fn`
+    F=`echo $BN | sed -e 's/\.c$//;'`
+    gcov -o $DN/src_*$F.o $fn
+done
diff --git a/src/common/include.am b/src/common/include.am
index 3d8cc8e9ebdd2c8b6b2bbd81c37b79c2f3363116..3f5a0e0d0ee9b000fc791b6a0bf261a3190d7cb6 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -82,6 +82,10 @@ src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SOURCES)
 src_common_libor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
 src_common_libor_crypto_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
 src_common_libor_event_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
 
 COMMONHEADERS = \
   src/common/address.h				\
diff --git a/src/or/include.am b/src/or/include.am
index 91b9bfce728e2e9b161f9ceaabbb181dba814699..f5002e6986deba567b8f19e24156e1bfd5c551cf 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -5,6 +5,9 @@ if UNITTESTS_ENABLED
 noinst_LIBRARIES += \
 	src/or/libtor-testing.a
 endif
+if COVERAGE_ENABLED
+noinst_PROGRAMS+= src/or/tor-cov
+endif
 
 if BUILD_NT_SERVICES
 tor_platform_source=src/or/ntmain.c
@@ -99,6 +102,7 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
         -DBINDIR="\"$(bindir)\""
 
 src_or_libtor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 # -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
 # This seems to matter nowhere but on windows, but I assure you that it
@@ -112,6 +116,18 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
 	@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
 
+if COVERAGE_ENABLED
+src_or_tor_cov_SOURCES = src/or/tor_main.c
+src_or_tor_cov_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
+	src/common/libor-crypto-testing.a $(LIBDONNA) \
+	src/common/libor-event-testing.a \
+	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+	@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+endif
+
 ORHEADERS = \
 	src/or/addressmap.h				\
 	src/or/buffers.h				\
diff --git a/src/test/include.am b/src/test/include.am
index 08eb7fba6715fcc1da69e06e4db76d94c99569fb..989cf4ebfcb3c3bbc115cdc8bd386e1e457ba2b1 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -31,6 +31,8 @@ src_test_test_SOURCES = \
 	src/test/test_config.c \
 	src/ext/tinytest.c
 
+src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
 src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
 
 src_test_bench_SOURCES = \