Hello David,
I also would like to use GCC to get code coverage on an embedded system.
My approach would be to place the gcov information in a dedicated linker
set:
https://gcc.gnu.org/pipermail/gcc-patches/2020-November/559004.html
Please have a look at the attached patches for a proposal to get the
data from the target.
--
embedded brains GmbH
Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.hu...@embedded-brains.de
Phone: +49-89-18 94 741 - 16
Fax: +49-89-18 94 741 - 08
PGP: Public key available on request.
embedded brains GmbH
Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/
>From ace43807e322dbdb075e507d9a84e676d4c34c64 Mon Sep 17 00:00:00 2001
From: Sebastian Huber <sebastian.hu...@embedded-brains.de>
Date: Sat, 14 Nov 2020 13:51:09 +0100
Subject: [PATCH 1/2] gcov: Add and use gcov_are_all_counters_zero()
libgcc/
libgcov.h (gcov_are_all_counters_zero): New.
libgcov-driver.c (write_one_data): Use gcov_are_all_counters_zero().
---
libgcc/libgcov-driver.c | 12 ++----------
libgcc/libgcov.h | 12 ++++++++++++
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index e53e4dc392a..ba308438474 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -428,16 +428,8 @@ write_one_data (const struct gcov_info *gi_ptr,
write_top_counters (ci_ptr, t_ix, n_counts);
else
{
- /* Do not stream when all counters are zero. */
- int all_zeros = 1;
- for (unsigned i = 0; i < n_counts; i++)
- if (ci_ptr->values[i] != 0)
- {
- all_zeros = 0;
- break;
- }
-
- if (all_zeros)
+ if (gcov_are_all_counters_zero (ci_ptr))
+ /* Do not stream when all counters are zero. */
gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
GCOV_TAG_COUNTER_LENGTH (-n_counts));
else
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index e70cf63b414..915a1b1530d 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -304,6 +304,18 @@ extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type);
extern void __gcov_ior_profiler (gcov_type *, gcov_type);
extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type);
+/* Return 1, if all counter values are zero, otherwise 0. */
+
+static inline int
+gcov_are_all_counters_zero (const struct gcov_ctr_info *ci_ptr)
+{
+ for (unsigned i = 0; i < ci_ptr->num; i++)
+ if (ci_ptr->values[i] != 0)
+ return 0;
+
+ return 1;
+}
+
#ifndef inhibit_libc
/* The wrappers around some library functions.. */
extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN;
--
2.26.2
>From 9235be68b52ee7b321d985fe2d82a38d685ffb4f Mon Sep 17 00:00:00 2001
From: Sebastian Huber <sebastian.hu...@embedded-brains.de>
Date: Fri, 13 Nov 2020 22:01:14 +0100
Subject: [PATCH 2/2] gcov: Add __gcov_info_to_gdca()
libgcc/
Makefile.in: Add libgcov-info-to-gcda.c to libgcov.a.
gcov.h (gcov_info): Declare.
(__gcov_info_to_gdca): Likewise.
libgcov-info-to-gcda.c: New.
---
libgcc/Makefile.in | 7 ++-
libgcc/gcov.h | 9 +++
libgcc/libgcov-info-to-gcda.c | 106 ++++++++++++++++++++++++++++++++++
3 files changed, 121 insertions(+), 1 deletion(-)
create mode 100644 libgcc/libgcov-info-to-gcda.c
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index d6075d32bd4..ae8ddc23955 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -909,13 +909,16 @@ LIBGCOV_INTERFACE = _gcov_dump _gcov_fork \
_gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset \
_gcov_lock_unlock
LIBGCOV_DRIVER = _gcov
+LIBGCOV_INFO_TO_GCDA = _gcov_info_to_gcda
libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE))
libgcov-profiler-objects = $(patsubst %,%$(objext),$(LIBGCOV_PROFILER))
libgcov-interface-objects = $(patsubst %,%$(objext),$(LIBGCOV_INTERFACE))
libgcov-driver-objects = $(patsubst %,%$(objext),$(LIBGCOV_DRIVER))
+libgcov-info-to-gcda-objects = $(patsubst %,%$(objext),$(LIBGCOV_INFO_TO_GCDA))
libgcov-objects = $(libgcov-merge-objects) $(libgcov-profiler-objects) \
- $(libgcov-interface-objects) $(libgcov-driver-objects)
+ $(libgcov-interface-objects) $(libgcov-driver-objects) \
+ $(libgcov-info-to-gcda-objects)
$(libgcov-merge-objects): %$(objext): $(srcdir)/libgcov-merge.c $(srcdir)/gcov.h $(srcdir)/libgcov.h
$(gcc_compile) -DL$* -c $(srcdir)/libgcov-merge.c
@@ -926,6 +929,8 @@ $(libgcov-interface-objects): %$(objext): $(srcdir)/libgcov-interface.c $(srcdir
$(libgcov-driver-objects): %$(objext): $(srcdir)/libgcov-driver.c \
$(srcdir)/libgcov-driver-system.c $(srcdir)/gcov.h $(srcdir)/libgcov.h
$(gcc_compile) -DL$* -c $(srcdir)/libgcov-driver.c
+$(libgcov-info-to-gcda-objects): %$(objext): $(srcdir)/libgcov-info-to-gcda.c $(srcdir)/gcov.h $(srcdir)/libgcov.h
+ $(gcc_compile) -DL$* -c $(srcdir)/libgcov-info-to-gcda.c
# Static libraries.
diff --git a/libgcc/gcov.h b/libgcc/gcov.h
index 0e3eed31032..f5ee7d49052 100644
--- a/libgcc/gcov.h
+++ b/libgcc/gcov.h
@@ -25,6 +25,8 @@
#ifndef GCC_GCOV_H
#define GCC_GCOV_H
+struct gcov_info;
+
/* Set all counters to zero. */
extern void __gcov_reset (void);
@@ -33,4 +35,11 @@ extern void __gcov_reset (void);
extern void __gcov_dump (void);
+/* Output gcov information as gcda data stream. */
+
+extern void __gcov_info_to_gcda (const struct gcov_info *,
+ void (*) (const char *, void *),
+ void (*) (const void *, unsigned, void *),
+ void *);
+
#endif /* GCC_GCOV_H */
diff --git a/libgcc/libgcov-info-to-gcda.c b/libgcc/libgcov-info-to-gcda.c
new file mode 100644
index 00000000000..d40d279b372
--- /dev/null
+++ b/libgcc/libgcov-info-to-gcda.c
@@ -0,0 +1,106 @@
+/* Routines required for instrumenting a program. */
+/* Compile this one with gcc. */
+/* Copyright (C) 2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "libgcov.h"
+
+static void
+gcov_fn_info_to_gcda (const struct gcov_info *gi_ptr,
+ const struct gcov_fn_info *gfi_ptr,
+ void (*dump) (const void *, unsigned, void *),
+ void *arg)
+{
+ const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+
+ for (unsigned t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+ {
+ if (!gi_ptr->merge[t_ix])
+ continue;
+
+ if (t_ix != GCOV_COUNTER_V_TOPN && t_ix != GCOV_COUNTER_V_INDIR)
+ {
+ gcov_unsigned_t word = GCOV_TAG_FOR_COUNTER (t_ix);
+ (*dump) (&word, sizeof (word), arg);
+ gcov_position_t n_counts = ci_ptr->num;
+
+ if (gcov_are_all_counters_zero (ci_ptr))
+ {
+ /* Do not stream when all counters are zero. */
+ word = GCOV_TAG_COUNTER_LENGTH (-n_counts);
+ (*dump) (&word, sizeof (word), arg);
+ }
+ else
+ {
+ word = GCOV_TAG_COUNTER_LENGTH (n_counts);
+ (*dump) (&word, sizeof (word), arg);
+
+ for (unsigned i = 0; i < n_counts; i++)
+ {
+ gcov_type value = ci_ptr->values[i];
+ word = (gcov_unsigned_t) value;
+ (*dump) (&word, sizeof (word), arg);
+
+ if (sizeof (value) > sizeof (word))
+ word = (gcov_unsigned_t) (value >> 32);
+ else
+ word = 0;
+
+ (*dump) (&word, sizeof (word), arg);
+ }
+ }
+ }
+
+ ci_ptr++;
+ }
+}
+
+void
+__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
+ void (*filename) (const char *, void *),
+ void (*dump) (const void *, unsigned, void *),
+ void *arg)
+{
+ (*filename) (gi_ptr->filename, arg);
+ gcov_unsigned_t word = GCOV_DATA_MAGIC;
+ (*dump) (&word, sizeof (word), arg);
+ (*dump) (&gi_ptr->version, sizeof (gi_ptr->version), arg);
+ (*dump) (&gi_ptr->stamp, sizeof (gi_ptr->stamp), arg);
+
+ for (unsigned f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
+ {
+ const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+ word = GCOV_TAG_FUNCTION;
+ (*dump) (&word, sizeof (word), arg);
+ word = GCOV_TAG_FUNCTION_LENGTH;
+ (*dump) (&word, sizeof (word), arg);
+ (*dump) (&gfi_ptr->ident, sizeof (gfi_ptr->ident), arg);
+ (*dump) (&gfi_ptr->lineno_checksum,
+ sizeof (gfi_ptr->lineno_checksum), arg);
+ (*dump) (&gfi_ptr->cfg_checksum, sizeof (gfi_ptr->cfg_checksum), arg);
+ gcov_fn_info_to_gcda (gi_ptr, gfi_ptr, dump, arg);
+ }
+
+ word = 0;
+ (*dump) (&word, sizeof (word), arg);
+}
--
2.26.2