public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v2] gcov: Add __gcov_info_to_gdca()
@ 2021-07-13 20:15 Sebastian Huber
  2021-07-23  5:31 ` Martin Liška
  0 siblings, 1 reply; 13+ messages in thread
From: Sebastian Huber @ 2021-07-13 20:15 UTC (permalink / raw)
  To: gcc-patches

Add __gcov_info_to_gcda() to libgcov to get the gcda data for a gcda info in a
freestanding environment.  It is intended to be used with the
-fprofile-info-section option.  A crude test program which doesn't use a linker
script is (use "gcc -coverage -fprofile-info-section -lgcc test.c" to compile
it):

  #include <gcov.h>
  #include <stdio.h>
  #include <stdlib.h>

  extern const struct gcov_info *my_info;

  static void
  filename (const char *f, void *arg)
  {
    printf("filename: %s\n", f);
  }

  static void
  dump (const void *d, unsigned n, void *arg)
  {
    const unsigned char *c = d;

    for (unsigned i = 0; i < n; ++i)
      printf ("%02x", c[i]);
  }

  static void *
  allocate (unsigned length, void *arg)
  {
    return malloc (length);
  }

  int main()
  {
    __asm__ volatile (".set my_info, .LPBX2");
    __gcov_info_to_gcda (my_info, filename, dump, allocate, NULL);
    return 0;
  }

With this patch, <stdint.h> is included in libgcov-driver.c even if
inhibit_libc is defined.  This header file should be also available for
freestanding environments.  If this is not the case, then we have to define
intptr_t somehow.

The patch removes one use of memset() which makes the <string.h> include
superfluous.

gcc/

	* gcc/gcov-io.h (gcov_write): Declare.
	* gcc/gcov-io.c (gcov_write): New.
	* doc/invoke.texi (fprofile-info-section): Mention
	__gcov_info_to_gdca().

libgcc/

	Makefile.in (LIBGCOV_DRIVER): Add _gcov_info_to_gcda.
	gcov.h (gcov_info): Declare.
	(__gcov_info_to_gdca): Likewise.
	libgcov-driver.c (#include <stdint.h>): New.
	(#include <string.h>): Remove.
	(NEED_L_GCOV): Conditionally define.
	(NEED_L_GCOV_INFO_TO_GCDA): Likewise.
	(are_all_counters_zero): New.
	(dump_handler): Likewise.
	(allocate_handler): Likewise.
	(dump_unsigned): Likewise.
	(dump_counter): Likewise.
	(write_topn_counters): Add dump, allocate, and arg parameters.  Use
	dump_unsigned() and dump_counter().
	(write_one_data): Add dump, allocate, and arg parameters.  Use
	dump_unsigned(), dump_counter(), and are_all_counters_zero().
	(__gcov_info_to_gcda): New.
---
 gcc/doc/invoke.texi     |  80 +++++++++++++++---
 gcc/gcov-io.c           |  10 +++
 gcc/gcov-io.h           |   1 +
 libgcc/Makefile.in      |   2 +-
 libgcc/gcov.h           |  17 ++++
 libgcc/libgcov-driver.c | 176 ++++++++++++++++++++++++++++++----------
 6 files changed, 230 insertions(+), 56 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e67d47af676d..2c514acf2003 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -14782,17 +14782,17 @@ To optimize the program based on the collected profile information, use
 Register the profile information in the specified section instead of using a
 constructor/destructor.  The section name is @var{name} if it is specified,
 otherwise the section name defaults to @code{.gcov_info}.  A pointer to the
-profile information generated by @option{-fprofile-arcs} or
-@option{-ftest-coverage} is placed in the specified section for each
-translation unit.  This option disables the profile information registration
-through a constructor and it disables the profile information processing
-through a destructor.  This option is not intended to be used in hosted
-environments such as GNU/Linux.  It targets systems with limited resources
-which do not support constructors and destructors.  The linker could collect
-the input sections in a continuous memory block and define start and end
-symbols.  The runtime support could dump the profiling information registered
-in this linker set during program termination to a serial line for example.  A
-GNU linker script example which defines a linker output section follows:
+profile information generated by @option{-fprofile-arcs} is placed in the
+specified section for each translation unit.  This option disables the profile
+information registration through a constructor and it disables the profile
+information processing through a destructor.  This option is not intended to be
+used in hosted environments such as GNU/Linux.  It targets free-standing
+environments (for example embedded systems) with limited resources which do not
+support constructors/destructors or the C library file I/O.
+
+The linker could collect the input sections in a continuous memory block and
+define start and end symbols.  A GNU linker script example which defines a
+linker output section follows:
 
 @smallexample
   .gcov_info      :
@@ -14803,6 +14803,64 @@ GNU linker script example which defines a linker output section follows:
   @}
 @end smallexample
 
+The program could dump the profiling information registered in this linker set
+for example like this:
+
+@smallexample
+#include <gcov.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern const struct gcov_info *__gcov_info_start[];
+extern const struct gcov_info *__gcov_info_end[];
+
+static void
+filename (const char *f, void *arg)
+@{
+  puts (f);
+@}
+
+static void
+dump (const void *d, unsigned n, void *arg)
+@{
+  const unsigned char *c = d;
+
+  for (unsigned i = 0; i < n; ++i)
+    printf ("%02x", c[i]);
+@}
+
+static void *
+allocate (unsigned length, void *arg)
+@{
+  return malloc (length);
+@}
+
+static void
+dump_gcov_info (void)
+@{
+  const struct gcov_info **info = __gcov_info_start;
+  const struct gcov_info **end = __gcov_info_end;
+
+  /* Obfuscate variable to prevent compiler optimizations.  */
+  __asm__ ("" : "+r" (end));
+
+  while (info != end)
+  @{
+    void *arg = NULL;
+    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
+    putchar ('\n');
+    ++info;
+  @}
+@}
+
+int
+main()
+@{
+  dump_gcov_info();
+  return 0;
+@}
+@end smallexample
+
 @item -fprofile-note=@var{path}
 @opindex fprofile-note
 
diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c
index 4b1e11d45305..8155cd129f6e 100644
--- a/gcc/gcov-io.c
+++ b/gcc/gcov-io.c
@@ -227,6 +227,16 @@ gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
 #endif
 
 #if !IN_GCOV
+/* Write DATA of LENGTH characters to coverage file.  */
+
+GCOV_LINKAGE void
+gcov_write (const void *data, unsigned length)
+{
+  gcov_unsigned_t r = fwrite (data, length, 1, gcov_var.file);
+  if (r != 1)
+    gcov_var.error = 1;
+}
+
 /* Write unsigned VALUE to coverage file.  */
 
 GCOV_LINKAGE void
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 538bee81263a..99e1964c1094 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -367,6 +367,7 @@ char *mangle_path (char const *base);
 
 #if !IN_GCOV
 /* Available outside gcov */
+GCOV_LINKAGE void gcov_write (const void *, unsigned) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN;
 #endif
 
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 2c8be561eb53..7ec975845544 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -908,7 +908,7 @@ LIBGCOV_INTERFACE = _gcov_dump _gcov_fork				\
 	_gcov_execl _gcov_execlp					\
 	_gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset  \
 	_gcov_lock_unlock
-LIBGCOV_DRIVER = _gcov
+LIBGCOV_DRIVER = _gcov _gcov_info_to_gcda
 
 libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE))
 libgcov-profiler-objects = $(patsubst %,%$(objext),$(LIBGCOV_PROFILER))
diff --git a/libgcc/gcov.h b/libgcc/gcov.h
index e6492cdd31ea..eea97fb8e9c9 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,19 @@ extern void __gcov_reset (void);
 
 extern void __gcov_dump (void);
 
+/* Convert the gcov information to a gcda data stream.  The first callback is
+   called exactly once with the filename associated with the gcov information.
+   The filename may be NULL.  Afterwards, the second callback is subsequently
+   called with chunks (the begin and length of the chunk are passed as the
+   first two callback parameters) of the gcda data stream.  The third callback
+   shall allocate memory with a size in characters specified by the first
+   callback parameter.  The fifth parameter is a user-provided argument passed
+   as the last argument to the callback functions.  */
+
+extern void __gcov_info_to_gcda (const struct gcov_info *,
+				 void (*) (const char *, void *),
+				 void (*) (const void *, unsigned, void *),
+				 void *(*) (unsigned, void *),
+				 void *);
+
 #endif /* GCC_GCOV_H */
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index df7ccb235677..c10f0c2c0a23 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -26,6 +26,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "libgcov.h"
 #include "gcov-io.h"
 
+#include <stdint.h>
+
+/* Return 1, if all counter values are zero, otherwise 0. */
+
+static inline int
+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;
+}
+
 #if defined(inhibit_libc)
 /* If libc and its header files are not available, provide dummy functions.  */
 
@@ -35,8 +49,6 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
 
 #else /* inhibit_libc */
 
-#include <string.h>
-
 #if GCOV_LOCKED
 #include <fcntl.h>
 #include <errno.h>
@@ -51,8 +63,17 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
 #include <sys/mman.h>
 #endif
 
-#ifdef L_gcov
+#endif /* inhibit_libc */
+
+#if defined(L_gcov) && !defined(inhibit_libc)
+#define NEED_L_GCOV
+#endif
+
+#if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL
+#define NEED_L_GCOV_INFO_TO_GCDA
+#endif
 
+#ifdef NEED_L_GCOV
 /* A utility function for outputting errors.  */
 static int gcov_error (const char *, ...);
 
@@ -343,6 +364,43 @@ read_error:
   return -1;
 }
 
+static void
+dump_handler (const void *data, unsigned length, void *unused)
+{
+  (void)unused;
+  gcov_write (data, length);
+}
+
+static void *
+allocate_handler (unsigned size, void *unused)
+{
+  (void)unused;
+  return xmalloc (size);
+}
+#endif /* NEED_L_GCOV */
+
+#if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
+static inline void
+dump_unsigned (gcov_unsigned_t word,
+	       void (*dump) (const void *, unsigned, void *),
+	       void *arg)
+{
+  (*dump) (&word, sizeof (word), arg);
+}
+
+static inline void
+dump_counter (gcov_type counter,
+	      void (*dump) (const void *, unsigned, void *),
+	      void *arg)
+{
+  dump_unsigned ((gcov_unsigned_t)counter, dump, arg);
+
+  if (sizeof (counter) > sizeof (gcov_unsigned_t))
+    dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump, arg);
+  else
+    dump_unsigned (0, dump, arg);
+}
+
 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
 
 /* Store all TOP N counters where each has a dynamic length.  */
@@ -350,7 +408,10 @@ read_error:
 static void
 write_topn_counters (const struct gcov_ctr_info *ci_ptr,
 		     unsigned t_ix,
-		     gcov_unsigned_t n_counts)
+		     gcov_unsigned_t n_counts,
+		     void (*dump) (const void *, unsigned, void *),
+		     void *(*allocate)(unsigned, void *),
+		     void *arg)
 {
   unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
   gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
@@ -365,46 +426,48 @@ write_topn_counters (const struct gcov_ctr_info *ci_ptr,
   if (list_sizes == NULL || counters > list_size_length)
     {
       list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
-#if HAVE_SYS_MMAN_H
+#if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
       list_sizes
 	= (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
 #endif
 
       /* Malloc fallback.  */
       if (list_sizes == NULL)
-	list_sizes = (unsigned *)xmalloc (list_size_length * sizeof (unsigned));
+	list_sizes =
+	  (unsigned *)(*allocate) (list_size_length * sizeof (unsigned), arg);
     }
 
-  memset (list_sizes, 0, counters * sizeof (unsigned));
   unsigned pair_total = 0;
 
   for (unsigned i = 0; i < counters; i++)
     {
       gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
+      unsigned sizes = 0;
+
       for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
 	   node != NULL; node = node->next)
-	{
-	  ++pair_total;
-	  ++list_sizes[i];
-	}
+	++sizes;
+
+      pair_total += sizes;
+      list_sizes[i] = sizes;
     }
 
   unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
-  gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
-			 GCOV_TAG_COUNTER_LENGTH (disk_size));
+  dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump, arg),
+  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump, arg);
 
   for (unsigned i = 0; i < counters; i++)
     {
-      gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]);
-      gcov_write_counter (list_sizes[i]);
+      dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump, arg);
+      dump_counter (list_sizes[i], dump, arg);
       gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
 
       unsigned j = 0;
       for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
 	   j < list_sizes[i]; node = node->next, j++)
 	{
-	  gcov_write_counter (node->value);
-	  gcov_write_counter (node->count);
+	  dump_counter (node->value, dump, arg);
+	  dump_counter (node->count, dump, arg);
 	}
     }
 }
@@ -415,25 +478,36 @@ write_topn_counters (const struct gcov_ctr_info *ci_ptr,
 
 static void
 write_one_data (const struct gcov_info *gi_ptr,
-		const struct gcov_summary *prg_p)
+		const struct gcov_summary *prg_p,
+		void (*dump) (const void *, unsigned, void *),
+		void *(*allocate) (unsigned, void *),
+		void *arg)
 {
   unsigned f_ix;
 
-  gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
-  gcov_write_unsigned (gi_ptr->stamp);
+  dump_unsigned (GCOV_DATA_MAGIC, dump, arg);
+  dump_unsigned (GCOV_VERSION, dump, arg);
+  dump_unsigned (gi_ptr->stamp, dump, arg);
 
+#ifdef NEED_L_GCOV
   /* Generate whole program statistics.  */
   gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
+#else
+  (void)prg_p;
+#endif
 
   /* Write execution counts for each function.  */
   for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
     {
+#ifdef NEED_L_GCOV
       unsigned buffered = 0;
+#endif
       const struct gcov_fn_info *gfi_ptr;
       const struct gcov_ctr_info *ci_ptr;
       gcov_unsigned_t length;
       unsigned t_ix;
 
+#ifdef NEED_L_GCOV
       if (fn_buffer && fn_buffer->fn_ix == f_ix)
         {
           /* Buffered data from another program.  */
@@ -442,6 +516,7 @@ write_one_data (const struct gcov_info *gi_ptr,
           length = GCOV_TAG_FUNCTION_LENGTH;
         }
       else
+#endif
         {
           gfi_ptr = gi_ptr->functions[f_ix];
           if (gfi_ptr && gfi_ptr->key == gi_ptr)
@@ -450,13 +525,14 @@ write_one_data (const struct gcov_info *gi_ptr,
                 length = 0;
         }
 
-      gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
+      dump_unsigned (GCOV_TAG_FUNCTION, dump, arg);
+      dump_unsigned (length, dump, arg);
       if (!length)
         continue;
 
-      gcov_write_unsigned (gfi_ptr->ident);
-      gcov_write_unsigned (gfi_ptr->lineno_checksum);
-      gcov_write_unsigned (gfi_ptr->cfg_checksum);
+      dump_unsigned (gfi_ptr->ident, dump, arg);
+      dump_unsigned (gfi_ptr->lineno_checksum, dump, arg);
+      dump_unsigned (gfi_ptr->cfg_checksum, dump, arg);
 
       ci_ptr = gfi_ptr->ctrs;
       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
@@ -469,39 +545,36 @@ write_one_data (const struct gcov_info *gi_ptr,
 	  n_counts = ci_ptr->num;
 
 	  if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
-	    write_topn_counters (ci_ptr, t_ix, n_counts);
+	    write_topn_counters (ci_ptr, t_ix, n_counts, dump, allocate, arg);
 	  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)
-		gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
-				       GCOV_TAG_COUNTER_LENGTH (-n_counts));
+	      dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump, arg);
+	      if (are_all_counters_zero (ci_ptr))
+		/* Do not stream when all counters are zero.  */
+		dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts), dump, arg);
 	      else
 		{
-		  gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
-					 GCOV_TAG_COUNTER_LENGTH (n_counts));
+		  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts),
+				 dump,
+				 arg);
 		  for (unsigned i = 0; i < n_counts; i++)
-		    gcov_write_counter (ci_ptr->values[i]);
+		    dump_counter (ci_ptr->values[i], dump, arg);
 		}
 	    }
 
 	  ci_ptr++;
 	}
+#ifdef NEED_L_GCOV
       if (buffered)
         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
+#endif
     }
 
-  gcov_write_unsigned (0);
+  dump_unsigned (0, dump, arg);
 }
+#endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
 
+#ifdef NEED_L_GCOV
 /* Dump the coverage counts for one gcov_info object. We merge with existing
    counts when possible, to avoid growing the .da files ad infinitum. We use
    this program's checksum to make sure we only accumulate whole program
@@ -550,7 +623,7 @@ dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
   summary = gi_ptr->summary;
 #endif
 
-  write_one_data (gi_ptr, &summary);
+  write_one_data (gi_ptr, &summary, dump_handler, allocate_handler, NULL);
   /* fall through */
 
 read_fatal:;
@@ -680,5 +753,20 @@ __gcov_init (struct gcov_info *info)
     }
 }
 #endif /* !IN_GCOV_TOOL */
-#endif /* L_gcov */
-#endif /* inhibit_libc */
+#endif /* NEED_L_GCOV */
+
+#ifdef NEED_L_GCOV_INFO_TO_GCDA
+/* Convert the gcov info to a gcda data stream.  It is intended for
+   free-standing environments which do not support the C library file I/O.  */
+
+void
+__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
+		     void (*filename) (const char *, void *),
+		     void (*dump) (const void *, unsigned, void *),
+		     void *(*allocate) (unsigned, void *),
+		     void *arg)
+{
+  (*filename) (gi_ptr->filename, arg);
+  write_one_data (gi_ptr, NULL, dump, allocate, arg);
+}
+#endif /* NEED_L_GCOV_INFO_TO_GCDA */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-13 20:15 [PATCH v2] gcov: Add __gcov_info_to_gdca() Sebastian Huber
@ 2021-07-23  5:31 ` Martin Liška
  2021-07-23  6:10   ` Sebastian Huber
                     ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Martin Liška @ 2021-07-23  5:31 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 7/13/21 10:15 PM, Sebastian Huber wrote:

Hello.

Thanks for working on that, there's my review:

> Add __gcov_info_to_gcda() to libgcov to get the gcda data for a gcda info in a
> freestanding environment.  It is intended to be used with the
> -fprofile-info-section option.  A crude test program which doesn't use a linker
> script is (use "gcc -coverage -fprofile-info-section -lgcc test.c" to compile
> it):
> 
>    #include <gcov.h>
>    #include <stdio.h>
>    #include <stdlib.h>
> 
>    extern const struct gcov_info *my_info;
> 
>    static void
>    filename (const char *f, void *arg)
>    {
>      printf("filename: %s\n", f);
>    }
> 
>    static void
>    dump (const void *d, unsigned n, void *arg)
>    {
>      const unsigned char *c = d;
> 
>      for (unsigned i = 0; i < n; ++i)
>        printf ("%02x", c[i]);
>    }
> 
>    static void *
>    allocate (unsigned length, void *arg)
>    {
>      return malloc (length);
>    }
> 
>    int main()
>    {
>      __asm__ volatile (".set my_info, .LPBX2");
>      __gcov_info_to_gcda (my_info, filename, dump, allocate, NULL);
>      return 0;
>    }
> 
> With this patch, <stdint.h> is included in libgcov-driver.c even if
> inhibit_libc is defined.  This header file should be also available for
> freestanding environments.  If this is not the case, then we have to define
> intptr_t somehow.
> 
> The patch removes one use of memset() which makes the <string.h> include
> superfluous.
> 
> gcc/
> 
> 	* gcc/gcov-io.h (gcov_write): Declare.
> 	* gcc/gcov-io.c (gcov_write): New.
> 	* doc/invoke.texi (fprofile-info-section): Mention
> 	__gcov_info_to_gdca().
> 
> libgcc/
> 
> 	Makefile.in (LIBGCOV_DRIVER): Add _gcov_info_to_gcda.
> 	gcov.h (gcov_info): Declare.
> 	(__gcov_info_to_gdca): Likewise.
> 	libgcov-driver.c (#include <stdint.h>): New.
> 	(#include <string.h>): Remove.
> 	(NEED_L_GCOV): Conditionally define.
> 	(NEED_L_GCOV_INFO_TO_GCDA): Likewise.
> 	(are_all_counters_zero): New.
> 	(dump_handler): Likewise.
> 	(allocate_handler): Likewise.
> 	(dump_unsigned): Likewise.
> 	(dump_counter): Likewise.
> 	(write_topn_counters): Add dump, allocate, and arg parameters.  Use
> 	dump_unsigned() and dump_counter().
> 	(write_one_data): Add dump, allocate, and arg parameters.  Use
> 	dump_unsigned(), dump_counter(), and are_all_counters_zero().
> 	(__gcov_info_to_gcda): New.
> ---
>   gcc/doc/invoke.texi     |  80 +++++++++++++++---
>   gcc/gcov-io.c           |  10 +++
>   gcc/gcov-io.h           |   1 +
>   libgcc/Makefile.in      |   2 +-
>   libgcc/gcov.h           |  17 ++++
>   libgcc/libgcov-driver.c | 176 ++++++++++++++++++++++++++++++----------
>   6 files changed, 230 insertions(+), 56 deletions(-)
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index e67d47af676d..2c514acf2003 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -14782,17 +14782,17 @@ To optimize the program based on the collected profile information, use
>   Register the profile information in the specified section instead of using a
>   constructor/destructor.  The section name is @var{name} if it is specified,
>   otherwise the section name defaults to @code{.gcov_info}.  A pointer to the
> -profile information generated by @option{-fprofile-arcs} or
> -@option{-ftest-coverage} is placed in the specified section for each
> -translation unit.  This option disables the profile information registration
> -through a constructor and it disables the profile information processing
> -through a destructor.  This option is not intended to be used in hosted
> -environments such as GNU/Linux.  It targets systems with limited resources
> -which do not support constructors and destructors.  The linker could collect
> -the input sections in a continuous memory block and define start and end
> -symbols.  The runtime support could dump the profiling information registered
> -in this linker set during program termination to a serial line for example.  A
> -GNU linker script example which defines a linker output section follows:
> +profile information generated by @option{-fprofile-arcs} is placed in the
> +specified section for each translation unit.  This option disables the profile
> +information registration through a constructor and it disables the profile
> +information processing through a destructor.  This option is not intended to be
> +used in hosted environments such as GNU/Linux.  It targets free-standing
> +environments (for example embedded systems) with limited resources which do not
> +support constructors/destructors or the C library file I/O.
> +
> +The linker could collect the input sections in a continuous memory block and
> +define start and end symbols.  A GNU linker script example which defines a
> +linker output section follows:
>   
>   @smallexample
>     .gcov_info      :
> @@ -14803,6 +14803,64 @@ GNU linker script example which defines a linker output section follows:
>     @}
>   @end smallexample
>   
> +The program could dump the profiling information registered in this linker set
> +for example like this:
> +
> +@smallexample
> +#include <gcov.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +extern const struct gcov_info *__gcov_info_start[];
> +extern const struct gcov_info *__gcov_info_end[];
> +
> +static void
> +filename (const char *f, void *arg)
> +@{
> +  puts (f);
> +@}
> +
> +static void
> +dump (const void *d, unsigned n, void *arg)
> +@{
> +  const unsigned char *c = d;
> +
> +  for (unsigned i = 0; i < n; ++i)
> +    printf ("%02x", c[i]);
> +@}
> +
> +static void *
> +allocate (unsigned length, void *arg)
> +@{
> +  return malloc (length);
> +@}
> +
> +static void
> +dump_gcov_info (void)
> +@{
> +  const struct gcov_info **info = __gcov_info_start;
> +  const struct gcov_info **end = __gcov_info_end;
> +
> +  /* Obfuscate variable to prevent compiler optimizations.  */
> +  __asm__ ("" : "+r" (end));
> +
> +  while (info != end)
> +  @{
> +    void *arg = NULL;
> +    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
> +    putchar ('\n');
> +    ++info;
> +  @}
> +@}
> +
> +int
> +main()
> +@{
> +  dump_gcov_info();
> +  return 0;
> +@}
> +@end smallexample
> +
>   @item -fprofile-note=@var{path}
>   @opindex fprofile-note
>   
> diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c
> index 4b1e11d45305..8155cd129f6e 100644
> --- a/gcc/gcov-io.c
> +++ b/gcc/gcov-io.c
> @@ -227,6 +227,16 @@ gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
>   #endif
>   
>   #if !IN_GCOV
> +/* Write DATA of LENGTH characters to coverage file.  */
> +
> +GCOV_LINKAGE void
> +gcov_write (const void *data, unsigned length)
> +{
> +  gcov_unsigned_t r = fwrite (data, length, 1, gcov_var.file);
> +  if (r != 1)
> +    gcov_var.error = 1;
> +}
> +
>   /* Write unsigned VALUE to coverage file.  */
>   
>   GCOV_LINKAGE void
> diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
> index 538bee81263a..99e1964c1094 100644
> --- a/gcc/gcov-io.h
> +++ b/gcc/gcov-io.h
> @@ -367,6 +367,7 @@ char *mangle_path (char const *base);
>   
>   #if !IN_GCOV
>   /* Available outside gcov */
> +GCOV_LINKAGE void gcov_write (const void *, unsigned) ATTRIBUTE_HIDDEN;
>   GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN;
>   #endif
>   
> diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
> index 2c8be561eb53..7ec975845544 100644
> --- a/libgcc/Makefile.in
> +++ b/libgcc/Makefile.in
> @@ -908,7 +908,7 @@ LIBGCOV_INTERFACE = _gcov_dump _gcov_fork				\
>   	_gcov_execl _gcov_execlp					\
>   	_gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset  \
>   	_gcov_lock_unlock
> -LIBGCOV_DRIVER = _gcov
> +LIBGCOV_DRIVER = _gcov _gcov_info_to_gcda
>   
>   libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE))
>   libgcov-profiler-objects = $(patsubst %,%$(objext),$(LIBGCOV_PROFILER))
> diff --git a/libgcc/gcov.h b/libgcc/gcov.h
> index e6492cdd31ea..eea97fb8e9c9 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,19 @@ extern void __gcov_reset (void);
>   
>   extern void __gcov_dump (void);
>   
> +/* Convert the gcov information to a gcda data stream.  The first callback is
> +   called exactly once with the filename associated with the gcov information.
> +   The filename may be NULL.  Afterwards, the second callback is subsequently
> +   called with chunks (the begin and length of the chunk are passed as the
> +   first two callback parameters) of the gcda data stream.  The third callback
> +   shall allocate memory with a size in characters specified by the first
> +   callback parameter.  The fifth parameter is a user-provided argument passed
> +   as the last argument to the callback functions.  */
> +
> +extern void __gcov_info_to_gcda (const struct gcov_info *,
> +				 void (*) (const char *, void *),
> +				 void (*) (const void *, unsigned, void *),
> +				 void *(*) (unsigned, void *),
> +				 void *);

I would prefer having argument names in the function declaration, it would be more readable.

> +
>   #endif /* GCC_GCOV_H */
> diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
> index df7ccb235677..c10f0c2c0a23 100644
> --- a/libgcc/libgcov-driver.c
> +++ b/libgcc/libgcov-driver.c
> @@ -26,6 +26,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>   #include "libgcov.h"
>   #include "gcov-io.h"
>   
> +#include <stdint.h>
> +
> +/* Return 1, if all counter values are zero, otherwise 0. */
> +
> +static inline int
> +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;

There's one more level of the indentation if I'm correct.

> +
> +  return 1;
> +}
> +
>   #if defined(inhibit_libc)
>   /* If libc and its header files are not available, provide dummy functions.  */
>   
> @@ -35,8 +49,6 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
>   
>   #else /* inhibit_libc */
>   
> -#include <string.h>
> -
>   #if GCOV_LOCKED
>   #include <fcntl.h>
>   #include <errno.h>
> @@ -51,8 +63,17 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
>   #include <sys/mman.h>
>   #endif
>   
> -#ifdef L_gcov
> +#endif /* inhibit_libc */
> +
> +#if defined(L_gcov) && !defined(inhibit_libc)
> +#define NEED_L_GCOV
> +#endif
> +
> +#if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL
> +#define NEED_L_GCOV_INFO_TO_GCDA
> +#endif
>   
> +#ifdef NEED_L_GCOV
>   /* A utility function for outputting errors.  */
>   static int gcov_error (const char *, ...);
>   
> @@ -343,6 +364,43 @@ read_error:
>     return -1;
>   }

A comment is missing. I would rather name it gcov_dump_handler.

>   
> +static void
> +dump_handler (const void *data, unsigned length, void *unused)
> +{
> +  (void)unused;
> +  gcov_write (data, length);
> +}
> +

Simiarly here, gcov_ prefix would be preferred.

> +static void *
> +allocate_handler (unsigned size, void *unused)
> +{
> +  (void)unused;
> +  return xmalloc (size);
> +}
> +#endif /* NEED_L_GCOV */
> +
> +#if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
> +static inline void

Likewise here.

> +dump_unsigned (gcov_unsigned_t word,
> +	       void (*dump) (const void *, unsigned, void *),
> +	       void *arg)
> +{
> +  (*dump) (&word, sizeof (word), arg);
> +}

Likewise here.

> +
> +static inline void
> +dump_counter (gcov_type counter,
> +	      void (*dump) (const void *, unsigned, void *),
> +	      void *arg)
> +{
> +  dump_unsigned ((gcov_unsigned_t)counter, dump, arg);
> +
> +  if (sizeof (counter) > sizeof (gcov_unsigned_t))
> +    dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump, arg);
> +  else
> +    dump_unsigned (0, dump, arg);
> +}
> +
>   #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
>   
>   /* Store all TOP N counters where each has a dynamic length.  */
> @@ -350,7 +408,10 @@ read_error:
>   static void
>   write_topn_counters (const struct gcov_ctr_info *ci_ptr,
>   		     unsigned t_ix,
> -		     gcov_unsigned_t n_counts)
> +		     gcov_unsigned_t n_counts,
> +		     void (*dump) (const void *, unsigned, void *),
> +		     void *(*allocate)(unsigned, void *),
> +		     void *arg)

I would likely prefer dump_fn and allocate_fn argumen t names.

>   {
>     unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
>     gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
> @@ -365,46 +426,48 @@ write_topn_counters (const struct gcov_ctr_info *ci_ptr,
>     if (list_sizes == NULL || counters > list_size_length)
>       {
>         list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
> -#if HAVE_SYS_MMAN_H
> +#if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
>         list_sizes
>   	= (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
>   #endif
>   
>         /* Malloc fallback.  */
>         if (list_sizes == NULL)
> -	list_sizes = (unsigned *)xmalloc (list_size_length * sizeof (unsigned));
> +	list_sizes =
> +	  (unsigned *)(*allocate) (list_size_length * sizeof (unsigned), arg);
>       }
>   
> -  memset (list_sizes, 0, counters * sizeof (unsigned));

Are you sure we don't need this zeroing?

>     unsigned pair_total = 0;
>   
>     for (unsigned i = 0; i < counters; i++)
>       {
>         gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
> +      unsigned sizes = 0;
> +
>         for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
>   	   node != NULL; node = node->next)
> -	{
> -	  ++pair_total;
> -	  ++list_sizes[i];
> -	}
> +	++sizes;
> +
> +      pair_total += sizes;
> +      list_sizes[i] = sizes;
>       }
>   
>     unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
> -  gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
> -			 GCOV_TAG_COUNTER_LENGTH (disk_size));
> +  dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump, arg),
> +  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump, arg);
>   
>     for (unsigned i = 0; i < counters; i++)
>       {
> -      gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]);
> -      gcov_write_counter (list_sizes[i]);
> +      dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump, arg);
> +      dump_counter (list_sizes[i], dump, arg);
>         gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
>   
>         unsigned j = 0;
>         for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
>   	   j < list_sizes[i]; node = node->next, j++)
>   	{
> -	  gcov_write_counter (node->value);
> -	  gcov_write_counter (node->count);
> +	  dump_counter (node->value, dump, arg);
> +	  dump_counter (node->count, dump, arg);
>   	}
>       }
>   }
> @@ -415,25 +478,36 @@ write_topn_counters (const struct gcov_ctr_info *ci_ptr,
>   
>   static void
>   write_one_data (const struct gcov_info *gi_ptr,
> -		const struct gcov_summary *prg_p)
> +		const struct gcov_summary *prg_p,
> +		void (*dump) (const void *, unsigned, void *),
> +		void *(*allocate) (unsigned, void *),
> +		void *arg)
>   {
>     unsigned f_ix;
>   
> -  gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
> -  gcov_write_unsigned (gi_ptr->stamp);
> +  dump_unsigned (GCOV_DATA_MAGIC, dump, arg);
> +  dump_unsigned (GCOV_VERSION, dump, arg);
> +  dump_unsigned (gi_ptr->stamp, dump, arg);
>   
> +#ifdef NEED_L_GCOV
>     /* Generate whole program statistics.  */
>     gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
> +#else
> +  (void)prg_p;
> +#endif

Please use rather ATTRIBUTE_UNUSED.
>   
>     /* Write execution counts for each function.  */
>     for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
>       {
> +#ifdef NEED_L_GCOV
>         unsigned buffered = 0;
> +#endif
>         const struct gcov_fn_info *gfi_ptr;
>         const struct gcov_ctr_info *ci_ptr;
>         gcov_unsigned_t length;
>         unsigned t_ix;
>   
> +#ifdef NEED_L_GCOV
>         if (fn_buffer && fn_buffer->fn_ix == f_ix)
>           {
>             /* Buffered data from another program.  */
> @@ -442,6 +516,7 @@ write_one_data (const struct gcov_info *gi_ptr,
>             length = GCOV_TAG_FUNCTION_LENGTH;
>           }
>         else
> +#endif
>           {
>             gfi_ptr = gi_ptr->functions[f_ix];
>             if (gfi_ptr && gfi_ptr->key == gi_ptr)
> @@ -450,13 +525,14 @@ write_one_data (const struct gcov_info *gi_ptr,
>                   length = 0;
>           }
>   
> -      gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
> +      dump_unsigned (GCOV_TAG_FUNCTION, dump, arg);
> +      dump_unsigned (length, dump, arg);
>         if (!length)
>           continue;
>   
> -      gcov_write_unsigned (gfi_ptr->ident);
> -      gcov_write_unsigned (gfi_ptr->lineno_checksum);
> -      gcov_write_unsigned (gfi_ptr->cfg_checksum);
> +      dump_unsigned (gfi_ptr->ident, dump, arg);
> +      dump_unsigned (gfi_ptr->lineno_checksum, dump, arg);
> +      dump_unsigned (gfi_ptr->cfg_checksum, dump, arg);
>   
>         ci_ptr = gfi_ptr->ctrs;
>         for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
> @@ -469,39 +545,36 @@ write_one_data (const struct gcov_info *gi_ptr,
>   	  n_counts = ci_ptr->num;
>   
>   	  if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
> -	    write_topn_counters (ci_ptr, t_ix, n_counts);
> +	    write_topn_counters (ci_ptr, t_ix, n_counts, dump, allocate, arg);
>   	  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)
> -		gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
> -				       GCOV_TAG_COUNTER_LENGTH (-n_counts));
> +	      dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump, arg);
> +	      if (are_all_counters_zero (ci_ptr))
> +		/* Do not stream when all counters are zero.  */
> +		dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts), dump, arg);
>   	      else
>   		{
> -		  gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
> -					 GCOV_TAG_COUNTER_LENGTH (n_counts));
> +		  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts),
> +				 dump,
> +				 arg);
>   		  for (unsigned i = 0; i < n_counts; i++)
> -		    gcov_write_counter (ci_ptr->values[i]);
> +		    dump_counter (ci_ptr->values[i], dump, arg);
>   		}
>   	    }
>   
>   	  ci_ptr++;
>   	}
> +#ifdef NEED_L_GCOV
>         if (buffered)
>           fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
> +#endif
>       }
>   
> -  gcov_write_unsigned (0);
> +  dump_unsigned (0, dump, arg);
>   }
> +#endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
>   
> +#ifdef NEED_L_GCOV
>   /* Dump the coverage counts for one gcov_info object. We merge with existing
>      counts when possible, to avoid growing the .da files ad infinitum. We use
>      this program's checksum to make sure we only accumulate whole program
> @@ -550,7 +623,7 @@ dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
>     summary = gi_ptr->summary;
>   #endif
>   
> -  write_one_data (gi_ptr, &summary);
> +  write_one_data (gi_ptr, &summary, dump_handler, allocate_handler, NULL);
>     /* fall through */
>   
>   read_fatal:;
> @@ -680,5 +753,20 @@ __gcov_init (struct gcov_info *info)
>       }
>   }
>   #endif /* !IN_GCOV_TOOL */
> -#endif /* L_gcov */
> -#endif /* inhibit_libc */
> +#endif /* NEED_L_GCOV */
> +
> +#ifdef NEED_L_GCOV_INFO_TO_GCDA
> +/* Convert the gcov info to a gcda data stream.  It is intended for
> +   free-standing environments which do not support the C library file I/O.  */
> +
> +void
> +__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
> +		     void (*filename) (const char *, void *),

What about begin_finaname_fn?

> +		     void (*dump) (const void *, unsigned, void *),
> +		     void *(*allocate) (unsigned, void *),
> +		     void *arg)
> +{
> +  (*filename) (gi_ptr->filename, arg);
> +  write_one_data (gi_ptr, NULL, dump, allocate, arg);
> +}
> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
> 

About gcov_write_summary: it should be also dumped in order to have a complete .gcda file, right?
Can we remove gcov_write_counter function?
I think it can be handy having a script that creates a .gcda file from your reference dump output,
what do you think?
It would be nice having a test-case that can test your approach.

Thanks,
Martin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  5:31 ` Martin Liška
@ 2021-07-23  6:10   ` Sebastian Huber
  2021-07-23  6:52     ` Martin Liška
  2021-07-23  6:14   ` Sebastian Huber
  2021-07-23  6:21   ` Sebastian Huber
  2 siblings, 1 reply; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23  6:10 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

Hallo Martin,

thanks for your review.

On 23/07/2021 07:31, Martin Liška wrote:
> On 7/13/21 10:15 PM, Sebastian Huber wrote:
> 
> Hello.
> 
> Thanks for working on that, there's my review:
> 
>> Add __gcov_info_to_gcda() to libgcov to get the gcda data for a gcda 
>> info in a
>> freestanding environment.  It is intended to be used with the
>> -fprofile-info-section option.  A crude test program which doesn't use 
>> a linker
>> script is (use "gcc -coverage -fprofile-info-section -lgcc test.c" to 
>> compile
>> it):
[...]>> @@ -365,46 +426,48 @@ write_topn_counters (const struct 
gcov_ctr_info
>> *ci_ptr,
>>     if (list_sizes == NULL || counters > list_size_length)
>>       {
>>         list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
>> -#if HAVE_SYS_MMAN_H
>> +#if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
>>         list_sizes
>>       = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
>>   #endif
>>         /* Malloc fallback.  */
>>         if (list_sizes == NULL)
>> -    list_sizes = (unsigned *)xmalloc (list_size_length * sizeof 
>> (unsigned));
>> +    list_sizes =
>> +      (unsigned *)(*allocate) (list_size_length * sizeof (unsigned), 
>> arg);
>>       }
>> -  memset (list_sizes, 0, counters * sizeof (unsigned));
> 
> Are you sure we don't need this zeroing?

The list_sizes array is iterated two times using the same "counters" 
limit. In the first iteration ...

> 
>>     unsigned pair_total = 0;
>>     for (unsigned i = 0; i < counters; i++)
>>       {
>>         gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
>> +      unsigned sizes = 0;
>> +

... the sizes is initialized to zero here and ...

>>         for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
>>          node != NULL; node = node->next)
>> -    {
>> -      ++pair_total;
>> -      ++list_sizes[i];
>> -    }
>> +    ++sizes;
>> +
>> +      pair_total += sizes;
>> +      list_sizes[i] = sizes;

... written to the array here.

>>       }
>>     unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * 
>> pair_total;
>> -  gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
>> -             GCOV_TAG_COUNTER_LENGTH (disk_size));
>> +  dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump, arg),
>> +  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump, arg);
>>     for (unsigned i = 0; i < counters; i++)
>>       {
>> -      gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]);
>> -      gcov_write_counter (list_sizes[i]);
>> +      dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump, 
>> arg);
>> +      dump_counter (list_sizes[i], dump, arg);
>>         gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
>>         unsigned j = 0;
>>         for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
>>          j < list_sizes[i]; node = node->next, j++)
>>       {
>> -      gcov_write_counter (node->value);
>> -      gcov_write_counter (node->count);
>> +      dump_counter (node->value, dump, arg);
>> +      dump_counter (node->count, dump, arg);
>>       }
>>       }
>>   }
[...]
>> +#ifdef NEED_L_GCOV_INFO_TO_GCDA
>> +/* Convert the gcov info to a gcda data stream.  It is intended for
>> +   free-standing environments which do not support the C library file 
>> I/O.  */
>> +
>> +void
>> +__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
>> +             void (*filename) (const char *, void *),
> 
> What about begin_finaname_fn?
> 
>> +             void (*dump) (const void *, unsigned, void *),
>> +             void *(*allocate) (unsigned, void *),
>> +             void *arg)
>> +{
>> +  (*filename) (gi_ptr->filename, arg);
>> +  write_one_data (gi_ptr, NULL, dump, allocate, arg);
>> +}
>> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
>>
> 
> About gcov_write_summary: it should be also dumped in order to have a 
> complete .gcda file, right?

How can I get access to the summary information? Here it is not available:

/* Information about a single object file.  */
struct gcov_info
{
[...]
#ifndef IN_GCOV_TOOL
   const struct gcov_fn_info *const *functions; /* pointer to pointers
                                                   to function 
information  */
#else
   struct gcov_fn_info **functions;
   struct gcov_summary summary;
#endif /* !IN_GCOV_TOOL */
};

Should we dump a memset(&summary, 0, summary) summary?

> Can we remove gcov_write_counter function?

It is no longer used. What is the policy to remove functions?

> I think it can be handy having a script that creates a .gcda file from 
> your reference dump output,
> what do you think?

I think the dump output from the example is not useful for real 
applications. In an embedded system you would probably dump the 
information via a serial interface. The dump could be compressed and 
base64 encoded with some sort of EDAC.

> It would be nice having a test-case that can test your approach.

The problem is that you need the linker set to get access to the gcov 
information. The test program of the commit message works on my Linux 
machine. I am not sure if it is generic enough for the test suite. 
Instead of printing the information we could compare it against an 
expected output so that we have a self-contained test program.

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  5:31 ` Martin Liška
  2021-07-23  6:10   ` Sebastian Huber
@ 2021-07-23  6:14   ` Sebastian Huber
  2021-07-23  6:53     ` Martin Liška
  2021-07-23  6:21   ` Sebastian Huber
  2 siblings, 1 reply; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23  6:14 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

On 23/07/2021 07:31, Martin Liška wrote:
>>   write_topn_counters (const struct gcov_ctr_info *ci_ptr,
>>                unsigned t_ix,
>> -             gcov_unsigned_t n_counts)
>> +             gcov_unsigned_t n_counts,
>> +             void (*dump) (const void *, unsigned, void *),
>> +             void *(*allocate)(unsigned, void *),
>> +             void *arg)
> 
> I would likely prefer dump_fn and allocate_fn argumen t names.

If I use dump_fn and allocate_fn throughout the code, then several lines 
would exceed 79 characters.  This needs more vertical space. Should I 
still add the _fn postfix?

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  5:31 ` Martin Liška
  2021-07-23  6:10   ` Sebastian Huber
  2021-07-23  6:14   ` Sebastian Huber
@ 2021-07-23  6:21   ` Sebastian Huber
  2021-07-23  6:53     ` Martin Liška
  2 siblings, 1 reply; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23  6:21 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

On 23/07/2021 07:31, Martin Liška wrote:
>> +static void *
>> +allocate_handler (unsigned size, void *unused)
>> +{
>> +  (void)unused;
>> +  return xmalloc (size);
>> +}
>> +#endif /* NEED_L_GCOV */
>> +
>> +#if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
>> +static inline void
> 
> Likewise here.
> 
>> +dump_unsigned (gcov_unsigned_t word,
>> +           void (*dump) (const void *, unsigned, void *),
>> +           void *arg)
>> +{
>> +  (*dump) (&word, sizeof (word), arg);
>> +}
> 
> Likewise here.

Adding the gcov_ prefix would make some lines longer than 79 characters. 
We already have several functions in this file without a gocv_ prefix, 
for example write_one_data(), write_topn_counters().

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  6:10   ` Sebastian Huber
@ 2021-07-23  6:52     ` Martin Liška
  2021-07-23  7:06       ` Sebastian Huber
  2021-07-23  9:17       ` Sebastian Huber
  0 siblings, 2 replies; 13+ messages in thread
From: Martin Liška @ 2021-07-23  6:52 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 7/23/21 8:10 AM, Sebastian Huber wrote:
> Hallo Martin,

Hello.

> 
> thanks for your review.
> 
> On 23/07/2021 07:31, Martin Liška wrote:
>> On 7/13/21 10:15 PM, Sebastian Huber wrote:
>>
>> Hello.
>>
>> Thanks for working on that, there's my review:
>>
>>> Add __gcov_info_to_gcda() to libgcov to get the gcda data for a gcda info in a
>>> freestanding environment.  It is intended to be used with the
>>> -fprofile-info-section option.  A crude test program which doesn't use a linker
>>> script is (use "gcc -coverage -fprofile-info-section -lgcc test.c" to compile
>>> it):
> [...]>> @@ -365,46 +426,48 @@ write_topn_counters (const struct gcov_ctr_info
>>> *ci_ptr,
>>>     if (list_sizes == NULL || counters > list_size_length)
>>>       {
>>>         list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
>>> -#if HAVE_SYS_MMAN_H
>>> +#if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
>>>         list_sizes
>>>       = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
>>>   #endif
>>>         /* Malloc fallback.  */
>>>         if (list_sizes == NULL)
>>> -    list_sizes = (unsigned *)xmalloc (list_size_length * sizeof (unsigned));
>>> +    list_sizes =
>>> +      (unsigned *)(*allocate) (list_size_length * sizeof (unsigned), arg);
>>>       }
>>> -  memset (list_sizes, 0, counters * sizeof (unsigned));
>>
>> Are you sure we don't need this zeroing?
> 
> The list_sizes array is iterated two times using the same "counters" limit. In the first iteration ...
> 
>>
>>>     unsigned pair_total = 0;
>>>     for (unsigned i = 0; i < counters; i++)
>>>       {
>>>         gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
>>> +      unsigned sizes = 0;
>>> +
> 
> ... the sizes is initialized to zero here and ...
> 
>>>         for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
>>>          node != NULL; node = node->next)
>>> -    {
>>> -      ++pair_total;
>>> -      ++list_sizes[i];
>>> -    }
>>> +    ++sizes;
>>> +
>>> +      pair_total += sizes;
>>> +      list_sizes[i] = sizes;
> 
> ... written to the array here.

Oh, good then!

> 
>>>       }
>>>     unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
>>> -  gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
>>> -             GCOV_TAG_COUNTER_LENGTH (disk_size));
>>> +  dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump, arg),
>>> +  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump, arg);
>>>     for (unsigned i = 0; i < counters; i++)
>>>       {
>>> -      gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]);
>>> -      gcov_write_counter (list_sizes[i]);
>>> +      dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump, arg);
>>> +      dump_counter (list_sizes[i], dump, arg);
>>>         gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
>>>         unsigned j = 0;
>>>         for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
>>>          j < list_sizes[i]; node = node->next, j++)
>>>       {
>>> -      gcov_write_counter (node->value);
>>> -      gcov_write_counter (node->count);
>>> +      dump_counter (node->value, dump, arg);
>>> +      dump_counter (node->count, dump, arg);
>>>       }
>>>       }
>>>   }
> [...]
>>> +#ifdef NEED_L_GCOV_INFO_TO_GCDA
>>> +/* Convert the gcov info to a gcda data stream.  It is intended for
>>> +   free-standing environments which do not support the C library file I/O.  */
>>> +
>>> +void
>>> +__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
>>> +             void (*filename) (const char *, void *),
>>
>> What about begin_finaname_fn?
>>
>>> +             void (*dump) (const void *, unsigned, void *),
>>> +             void *(*allocate) (unsigned, void *),
>>> +             void *arg)
>>> +{
>>> +  (*filename) (gi_ptr->filename, arg);
>>> +  write_one_data (gi_ptr, NULL, dump, allocate, arg);
>>> +}
>>> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
>>>
>>
>> About gcov_write_summary: it should be also dumped in order to have a complete .gcda file, right?
> 
> How can I get access to the summary information? Here it is not available:

You only need to change gcov_write_summary in gcov-io.c.

> 
> /* Information about a single object file.  */
> struct gcov_info
> {
> [...]
> #ifndef IN_GCOV_TOOL
>    const struct gcov_fn_info *const *functions; /* pointer to pointers
>                                                    to function information  */
> #else
>    struct gcov_fn_info **functions;
>    struct gcov_summary summary;
> #endif /* !IN_GCOV_TOOL */
> };
> 
> Should we dump a memset(&summary, 0, summary) summary?
> 
>> Can we remove gcov_write_counter function?
> 
> It is no longer used. What is the policy to remove functions?

We can remove it if it's unused :)

> 
>> I think it can be handy having a script that creates a .gcda file from your reference dump output,
>> what do you think?
> 
> I think the dump output from the example is not useful for real applications. In an embedded system you would probably dump the information via a serial interface. The dump could be compressed and base64 encoded with some sort of EDAC.

Sure, but a host system needs to take such a stream and reconstruct .gcda files. That's what I mean. Btw. do you use the created .gcda files only for gcov (coverage reports), or
do you use it for -fprofile-use (PGO/FDO)? Btw. the generated .gcda files should also survive gcov-dump command.

> 
>> It would be nice having a test-case that can test your approach.
> 
> The problem is that you need the linker set to get access to the gcov information. The test program of the commit message works on my Linux machine. I am not sure if it is generic enough for the test suite. Instead of printing the information we could compare it against an expected output so that we have a self-contained test program.

Yep, that would be nice.

Martin

> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  6:14   ` Sebastian Huber
@ 2021-07-23  6:53     ` Martin Liška
  0 siblings, 0 replies; 13+ messages in thread
From: Martin Liška @ 2021-07-23  6:53 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 7/23/21 8:14 AM, Sebastian Huber wrote:
> On 23/07/2021 07:31, Martin Liška wrote:
>>>   write_topn_counters (const struct gcov_ctr_info *ci_ptr,
>>>                unsigned t_ix,
>>> -             gcov_unsigned_t n_counts)
>>> +             gcov_unsigned_t n_counts,
>>> +             void (*dump) (const void *, unsigned, void *),
>>> +             void *(*allocate)(unsigned, void *),
>>> +             void *arg)
>>
>> I would likely prefer dump_fn and allocate_fn argumen t names.
> 
> If I use dump_fn and allocate_fn throughout the code, then several lines would exceed 79 characters.  This needs more vertical space. Should I still add the _fn postfix?
> 

Yes, please do so.

Martin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  6:21   ` Sebastian Huber
@ 2021-07-23  6:53     ` Martin Liška
  0 siblings, 0 replies; 13+ messages in thread
From: Martin Liška @ 2021-07-23  6:53 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 7/23/21 8:21 AM, Sebastian Huber wrote:
> On 23/07/2021 07:31, Martin Liška wrote:
>>> +static void *
>>> +allocate_handler (unsigned size, void *unused)
>>> +{
>>> +  (void)unused;
>>> +  return xmalloc (size);
>>> +}
>>> +#endif /* NEED_L_GCOV */
>>> +
>>> +#if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
>>> +static inline void
>>
>> Likewise here.
>>
>>> +dump_unsigned (gcov_unsigned_t word,
>>> +           void (*dump) (const void *, unsigned, void *),
>>> +           void *arg)
>>> +{
>>> +  (*dump) (&word, sizeof (word), arg);
>>> +}
>>
>> Likewise here.
> 
> Adding the gcov_ prefix would make some lines longer than 79 characters. We already have several functions in this file without a gocv_ prefix, for example write_one_data(), write_topn_counters().
> 

All right, I don't insist on that.

Cheers,
Martin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  6:52     ` Martin Liška
@ 2021-07-23  7:06       ` Sebastian Huber
  2021-07-23  7:16         ` Martin Liška
  2021-07-23  9:17       ` Sebastian Huber
  1 sibling, 1 reply; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23  7:06 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

On 23/07/2021 08:52, Martin Liška wrote:
>>>> +#ifdef NEED_L_GCOV_INFO_TO_GCDA
>>>> +/* Convert the gcov info to a gcda data stream.  It is intended for
>>>> +   free-standing environments which do not support the C library 
>>>> file I/O.  */
>>>> +
>>>> +void
>>>> +__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
>>>> +             void (*filename) (const char *, void *),
>>>
>>> What about begin_finaname_fn?
>>>
>>>> +             void (*dump) (const void *, unsigned, void *),
>>>> +             void *(*allocate) (unsigned, void *),
>>>> +             void *arg)
>>>> +{
>>>> +  (*filename) (gi_ptr->filename, arg);
>>>> +  write_one_data (gi_ptr, NULL, dump, allocate, arg);
>>>> +}
>>>> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
>>>>
>>>
>>> About gcov_write_summary: it should be also dumped in order to have a 
>>> complete .gcda file, right?
>>
>> How can I get access to the summary information? Here it is not 
>> available:
> 
> You only need to change gcov_write_summary in gcov-io.c.

Sorry, I still don't know how I can get the summary information if I 
only have a pointer to the gcov_info structure which does not contain a 
summary member.

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  7:06       ` Sebastian Huber
@ 2021-07-23  7:16         ` Martin Liška
  2021-07-23 12:01           ` Sebastian Huber
  0 siblings, 1 reply; 13+ messages in thread
From: Martin Liška @ 2021-07-23  7:16 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 7/23/21 9:06 AM, Sebastian Huber wrote:
> On 23/07/2021 08:52, Martin Liška wrote:
>>>>> +#ifdef NEED_L_GCOV_INFO_TO_GCDA
>>>>> +/* Convert the gcov info to a gcda data stream.  It is intended for
>>>>> +   free-standing environments which do not support the C library file I/O.  */
>>>>> +
>>>>> +void
>>>>> +__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
>>>>> +             void (*filename) (const char *, void *),
>>>>
>>>> What about begin_finaname_fn?
>>>>
>>>>> +             void (*dump) (const void *, unsigned, void *),
>>>>> +             void *(*allocate) (unsigned, void *),
>>>>> +             void *arg)
>>>>> +{
>>>>> +  (*filename) (gi_ptr->filename, arg);
>>>>> +  write_one_data (gi_ptr, NULL, dump, allocate, arg);
>>>>> +}
>>>>> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
>>>>>
>>>>
>>>> About gcov_write_summary: it should be also dumped in order to have a complete .gcda file, right?
>>>
>>> How can I get access to the summary information? Here it is not available:
>>
>> You only need to change gcov_write_summary in gcov-io.c.
> 
> Sorry, I still don't know how I can get the summary information if I only have a pointer to the gcov_info structure which does not contain a summary member.

You're right, sorry! But in your case, it will be simple to re-created it by the script at a host system.


gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
{
   gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
   gcov_write_unsigned (summary->runs);
   gcov_write_unsigned (summary->sum_max);
}

Where summary->runs will be 1 and sum_max is maximum counter during the run.

Cheers,
Martin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  6:52     ` Martin Liška
  2021-07-23  7:06       ` Sebastian Huber
@ 2021-07-23  9:17       ` Sebastian Huber
  2021-07-23  9:31         ` Sebastian Huber
  1 sibling, 1 reply; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23  9:17 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2158 bytes --]

On 23/07/2021 08:52, Martin Liška wrote:
>>
>>> It would be nice having a test-case that can test your approach.
>>
>> The problem is that you need the linker set to get access to the gcov 
>> information. The test program of the commit message works on my Linux 
>> machine. I am not sure if it is generic enough for the test suite. 
>> Instead of printing the information we could compare it against an 
>> expected output so that we have a self-contained test program.
> 
> Yep, that would be nice.

I tried to run the attached test case as 
"gcc/testsuite/gcc.dg/gcov-info-to-gcda.c". However, I get this error:

Invoking the compiler as /tmp/sh/b-gcc-git-linux/gcc/xgcc 
-B/tmp/sh/b-gcc-git-linux/gcc/ 
/home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c 
  -fdiagnostics-plain-output   -fprofile-arcs -fprofile-info-section 
-lm  -o ./gcov-info-to-gcda.exe
Setting timeout to 300
Executing on host: /tmp/sh/b-gcc-git-linux/gcc/xgcc 
-B/tmp/sh/b-gcc-git-linux/gcc/ 
/home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c 
  -fdiagnostics-plain-output   -fprofile-arcs -fprofile-info-section 
-lm  -o ./gcov-info-to-gcda.exe    (timeout = 300)
spawn -ignore SIGHUP /tmp/sh/b-gcc-git-linux/gcc/xgcc 
-B/tmp/sh/b-gcc-git-linux/gcc/ 
/home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c 
-fdiagnostics-plain-output -fprofile-arcs -fprofile-info-section -lm -o 
./gcov-info-to-gcda.exe

pid is 79704 -79704
/home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c:5:10: 
fatal error: gcov.h: No such file or directory

compilation terminated.


Is it possible to do such kind of tests? I also have to link to -lgcov?

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

[-- Attachment #2: gcov-info-to-gcda.c --]
[-- Type: text/x-csrc, Size: 937 bytes --]

/* { dg-do run } */
/* { dg-skip-if "profile-info-section" { powerpc-ibm-aix* } } */
/* { dg-options "-fprofile-arcs -fprofile-info-section" } */

#include <gcov.h>

extern const struct gcov_info *my_info;

static unsigned counter;

static void
filename (const char *f, void *arg)
{
  if (arg != &counter)
    __builtin_abort ();

  if (__builtin_strcmp (f, __FILE__) != 0)
    __builtin_abort ();
}

static void
dump (const void *d, unsigned n, void *arg)
{
  unsigned *m = (unsigned *)arg;
  if (m != &counter)
    __builtin_abort ();

  if (*m == 0)
  {
    const unsigned *u = d;
    if (*u != 0x67636461)
      __builtin_abort ();
  }

  *m += n;
}

static void *
allocate (unsigned length, void *arg)
{
  if (arg != &counter)
    __builtin_abort ();

  return __builtin_malloc (length);
}

int main()
{
  __asm__ volatile (".set my_info, .LPBX2");
  __gcov_info_to_gcda (my_info, filename, dump, allocate, &counter);
  return 0;
}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  9:17       ` Sebastian Huber
@ 2021-07-23  9:31         ` Sebastian Huber
  0 siblings, 0 replies; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23  9:31 UTC (permalink / raw)
  To: Martin Liška, gcc-patches



On 23/07/2021 11:17, Sebastian Huber wrote:
> On 23/07/2021 08:52, Martin Liška wrote:
>>>
>>>> It would be nice having a test-case that can test your approach.
>>>
>>> The problem is that you need the linker set to get access to the gcov 
>>> information. The test program of the commit message works on my Linux 
>>> machine. I am not sure if it is generic enough for the test suite. 
>>> Instead of printing the information we could compare it against an 
>>> expected output so that we have a self-contained test program.
>>
>> Yep, that would be nice.
> 
> I tried to run the attached test case as 
> "gcc/testsuite/gcc.dg/gcov-info-to-gcda.c". However, I get this error:
> 
> Invoking the compiler as /tmp/sh/b-gcc-git-linux/gcc/xgcc 
> -B/tmp/sh/b-gcc-git-linux/gcc/ 
> /home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c 
>   -fdiagnostics-plain-output   -fprofile-arcs -fprofile-info-section 
> -lm  -o ./gcov-info-to-gcda.exe
> Setting timeout to 300
> Executing on host: /tmp/sh/b-gcc-git-linux/gcc/xgcc 
> -B/tmp/sh/b-gcc-git-linux/gcc/ 
> /home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c 
>   -fdiagnostics-plain-output   -fprofile-arcs -fprofile-info-section 
> -lm  -o ./gcov-info-to-gcda.exe    (timeout = 300)
> spawn -ignore SIGHUP /tmp/sh/b-gcc-git-linux/gcc/xgcc 
> -B/tmp/sh/b-gcc-git-linux/gcc/ 
> /home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c 
> -fdiagnostics-plain-output -fprofile-arcs -fprofile-info-section -lm -o 
> ./gcov-info-to-gcda.exe
> 
> pid is 79704 -79704
> /home/EB/sebastian_h/src/gcc/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c:5:10: 
> fatal error: gcov.h: No such file or directory
> 
> compilation terminated.
> 
> 
> Is it possible to do such kind of tests? I also have to link to -lgcov?

Ok, the linking is not the problem. If I declare __gcov_info_to_gcda() 
locally, the test runs.

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] gcov: Add __gcov_info_to_gdca()
  2021-07-23  7:16         ` Martin Liška
@ 2021-07-23 12:01           ` Sebastian Huber
  0 siblings, 0 replies; 13+ messages in thread
From: Sebastian Huber @ 2021-07-23 12:01 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

On 23/07/2021 09:16, Martin Liška wrote:
> On 7/23/21 9:06 AM, Sebastian Huber wrote:
>> On 23/07/2021 08:52, Martin Liška wrote:
>>>>>> +#ifdef NEED_L_GCOV_INFO_TO_GCDA
>>>>>> +/* Convert the gcov info to a gcda data stream.  It is intended for
>>>>>> +   free-standing environments which do not support the C library 
>>>>>> file I/O.  */
>>>>>> +
>>>>>> +void
>>>>>> +__gcov_info_to_gcda (const struct gcov_info *gi_ptr,
>>>>>> +             void (*filename) (const char *, void *),
>>>>>
>>>>> What about begin_finaname_fn?
>>>>>
>>>>>> +             void (*dump) (const void *, unsigned, void *),
>>>>>> +             void *(*allocate) (unsigned, void *),
>>>>>> +             void *arg)
>>>>>> +{
>>>>>> +  (*filename) (gi_ptr->filename, arg);
>>>>>> +  write_one_data (gi_ptr, NULL, dump, allocate, arg);
>>>>>> +}
>>>>>> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
>>>>>>
>>>>>
>>>>> About gcov_write_summary: it should be also dumped in order to have 
>>>>> a complete .gcda file, right?
>>>>
>>>> How can I get access to the summary information? Here it is not 
>>>> available:
>>>
>>> You only need to change gcov_write_summary in gcov-io.c.
>>
>> Sorry, I still don't know how I can get the summary information if I 
>> only have a pointer to the gcov_info structure which does not contain 
>> a summary member.
> 
> You're right, sorry! But in your case, it will be simple to re-created 
> it by the script at a host system.
> 
> 
> gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary 
> *summary)
> {
>    gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
>    gcov_write_unsigned (summary->runs);
>    gcov_write_unsigned (summary->sum_max);
> }
> 
> Where summary->runs will be 1 and sum_max is maximum counter during the 
> run.

This __gcov_info_to_gcda() is just a low-level piece which is necessary 
to get the gcda stream from an embedded system to a host without having 
to know the details of gcov. In follow up patches we could think about a 
standard format to serialize the gcda stream.  For this format we could 
add support to the host gcov tools. One of the tools could read this 
stream and output proper *.gcda files.

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-07-23 12:01 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-13 20:15 [PATCH v2] gcov: Add __gcov_info_to_gdca() Sebastian Huber
2021-07-23  5:31 ` Martin Liška
2021-07-23  6:10   ` Sebastian Huber
2021-07-23  6:52     ` Martin Liška
2021-07-23  7:06       ` Sebastian Huber
2021-07-23  7:16         ` Martin Liška
2021-07-23 12:01           ` Sebastian Huber
2021-07-23  9:17       ` Sebastian Huber
2021-07-23  9:31         ` Sebastian Huber
2021-07-23  6:14   ` Sebastian Huber
2021-07-23  6:53     ` Martin Liška
2021-07-23  6:21   ` Sebastian Huber
2021-07-23  6:53     ` Martin Liška

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).