diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h
index 1433ffdf7e30e0d777147b14d2a90d8ed800f3d8..ffc5982bc034cf2243e52e341ef0364922cc0bba 100644
--- a/include/grpc/byte_buffer.h
+++ b/include/grpc/byte_buffer.h
@@ -106,6 +106,9 @@ void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
 int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
                                  gpr_slice *slice);
 
+/** Merge all data from \a reader into single slice */
+gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader);
+
 /** Returns a RAW byte buffer instance from the output of \a reader. */
 grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
     grpc_byte_buffer_reader *reader);
diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c
index 283db83833d75aa7d383cc7c917d375d2a0dd2da..9f830df68ce70dd57ad3b41c4ba30dc1f4ac956a 100644
--- a/src/core/surface/byte_buffer_reader.c
+++ b/src/core/surface/byte_buffer_reader.c
@@ -31,6 +31,7 @@
  *
  */
 
+#include <string.h>
 #include <grpc/byte_buffer_reader.h>
 
 #include <grpc/compression.h>
@@ -103,3 +104,21 @@ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
   }
   return 0;
 }
+
+gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
+  gpr_slice in_slice;
+  size_t bytes_read = 0;
+  const size_t input_size = grpc_byte_buffer_length(reader->buffer_out);
+  gpr_slice out_slice = gpr_slice_malloc(input_size);
+  gpr_uint8 *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */
+
+  while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) {
+    const size_t slice_length = GPR_SLICE_LENGTH(in_slice);
+    memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length);
+    bytes_read += slice_length;
+    gpr_slice_unref(in_slice);
+    GPR_ASSERT(bytes_read <= input_size);
+  }
+  return out_slice;
+}
+
diff --git a/test/core/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c
index 560e0ac7b23a476da832d5915a2fc5ec61ddd204..c654f80f71ce0adf386baba1f3400a7c9989fa72 100644
--- a/test/core/surface/byte_buffer_reader_test.c
+++ b/test/core/surface/byte_buffer_reader_test.c
@@ -184,6 +184,39 @@ static void test_byte_buffer_from_reader(void) {
   grpc_byte_buffer_destroy(buffer_from_reader);
 }
 
+static void test_readall(void) {
+  const char* lotsa_as[512];
+  const char* lotsa_bs[1024];
+  gpr_slice slices[2];
+  grpc_byte_buffer *buffer;
+  grpc_byte_buffer_reader reader;
+  gpr_slice slice_out;
+
+  LOG_TEST("test_readall");
+
+  memset(lotsa_as, 'a', 512);
+  memset(lotsa_bs, 'b', 1024);
+  /* use slices large enough to overflow inlining */
+  slices[0] = gpr_slice_malloc(512);
+  memcpy(GPR_SLICE_START_PTR(slices[0]), lotsa_as, 512);
+  slices[1] = gpr_slice_malloc(1024);
+  memcpy(GPR_SLICE_START_PTR(slices[1]), lotsa_bs, 1024);
+
+  buffer = grpc_raw_byte_buffer_create(slices, 2);
+  gpr_slice_unref(slices[0]);
+  gpr_slice_unref(slices[1]);
+
+  grpc_byte_buffer_reader_init(&reader, buffer);
+  slice_out = grpc_byte_buffer_reader_readall(&reader);
+
+  GPR_ASSERT(GPR_SLICE_LENGTH(slice_out) == 512 + 1024);
+  GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(slice_out), lotsa_as, 512) == 0);
+  GPR_ASSERT(memcmp(&(GPR_SLICE_START_PTR(slice_out)[512]), lotsa_bs, 1024) ==
+             0);
+  gpr_slice_unref(slice_out);
+  grpc_byte_buffer_destroy(buffer);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_read_one_slice();
@@ -192,6 +225,6 @@ int main(int argc, char **argv) {
   test_read_gzip_compressed_slice();
   test_read_deflate_compressed_slice();
   test_byte_buffer_from_reader();
-
+  test_readall();
   return 0;
 }
diff --git a/tools/run_tests/post_tests_c.sh b/tools/run_tests/post_tests_c.sh
index f2f3ce9432df6493e1a94dce45331615de4ea618..4409526dab256ef620af474e842d007077dad979 100755
--- a/tools/run_tests/post_tests_c.sh
+++ b/tools/run_tests/post_tests_c.sh
@@ -34,8 +34,12 @@ if [ "$CONFIG" != "gcov" ] ; then exit ; fi
 
 root=$(readlink -f $(dirname $0)/../..)
 out=$root/reports/c_cxx_coverage
-tmp=$(mktemp)
+tmp1=$(mktemp)
+tmp2=$(mktemp)
 cd $root
-lcov --capture --directory . --output-file $tmp
-genhtml $tmp --output-directory $out
-rm $tmp
+lcov --capture --directory . --output-file $tmp1
+lcov --extract $tmp1 "$root/src/*" "$root/include/*" --output-file $tmp2
+genhtml $tmp2 --output-directory $out
+rm $tmp2
+rm $tmp1
+
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index a91c3f62d04c7c7736dfcde9fd284d0bf39b8fc6..85c73d6fbd20eb9dca23061d3227e8d2c3c5523c 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -849,6 +849,7 @@ def _build_and_run(
                  for _ in range(0, args.antagonists)]
   port_server_port = 32767
   _start_port_server(port_server_port)
+  resultset = None
   try:
     infinite_runs = runs_per_test == 0
     one_run = set(
@@ -894,7 +895,7 @@ def _build_and_run(
   finally:
     for antagonist in antagonists:
       antagonist.kill()
-    if xml_report:
+    if xml_report and resultset:
       report_utils.render_xml_report(resultset, xml_report)
 
   number_failures, _ = jobset.run(