public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Martin Liška" <mliska@suse.cz>
To: Sebastian Huber <sebastian.huber@embedded-brains.de>,
	gcc-patches@gcc.gnu.org
Subject: Re: [PATCH v3] gcov: Add __gcov_info_to_gdca()
Date: Thu, 5 Aug 2021 14:53:59 +0200	[thread overview]
Message-ID: <ae2c2f6a-c82f-54f2-4f8c-870f926870d2@suse.cz> (raw)
In-Reply-To: <20210723093911.81759-1-sebastian.huber@embedded-brains.de>

On 7/23/21 11:39 AM, Sebastian Huber wrote:
> 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):

The patch can be installed once the following nits are fixed:

> 
>    #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/
> 
> 	* gcov-io.h (gcov_write): Declare.
> 	* gcov-io.c (gcov_write): New.
> 	(gcov_write_counter): Remove.
> 	(gcov_write_tag_length): Likewise.
> 	(gcov_write_summary): Replace gcov_write_tag_length() with calls to
> 	gcov_write_unsigned().
> 	* doc/invoke.texi (fprofile-info-section): Mention
> 	__gcov_info_to_gdca().
> 
> gcc/testsuite/
> 
> 	* gcc.dg/gcov-info-to-gcda.c: New test.
> 
> libgcc/
> 
> 	* Makefile.in (LIBGCOV_DRIVER): Add _gcov_info_to_gcda.
> 	* gcov.h (gcov_info): Declare.
> 	(__gcov_info_to_gdca): Likewise.
> 	* libgcov.h (gcov_write_counter): Remove.
> 	(gcov_write_tag_length): 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.
> 	(gcov_dump_handler): Likewise.
> 	(gcov_allocate_handler): Likewise.
> 	(dump_unsigned): Likewise.
> 	(dump_counter): Likewise.
> 	(write_topn_counters): Add dump_fn, allocate_fn, and arg parameters.
> 	Use dump_unsigned() and dump_counter().
> 	(write_one_data): Add dump_fn, allocate_fn, 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                            |  36 ++---
>   gcc/gcov-io.h                            |   1 +
>   gcc/testsuite/gcc.dg/gcov-info-to-gcda.c |  60 +++++++
>   libgcc/Makefile.in                       |   2 +-
>   libgcc/gcov.h                            |  19 +++
>   libgcc/libgcov-driver.c                  | 196 ++++++++++++++++++-----
>   libgcc/libgcov.h                         |   5 -
>   8 files changed, 313 insertions(+), 86 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.dg/gcov-info-to-gcda.c
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 32697e6117c0..5f31312b9485 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -14798,17 +14798,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      :
> @@ -14819,6 +14819,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..864c01f04a97 100644
> --- a/gcc/gcov-io.c
> +++ b/gcc/gcov-io.c
> @@ -227,30 +227,25 @@ gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
>   #endif
>   
>   #if !IN_GCOV
> -/* Write unsigned VALUE to coverage file.  */
> +/* Write DATA of LENGTH characters to coverage file.  */
>   
>   GCOV_LINKAGE void
> -gcov_write_unsigned (gcov_unsigned_t value)
> +gcov_write (const void *data, unsigned length)
>   {
> -  gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file);
> +  gcov_unsigned_t r = fwrite (data, length, 1, gcov_var.file);
>     if (r != 1)
>       gcov_var.error = 1;
>   }
>   
> -/* Write counter VALUE to coverage file.  Sets error flag
> -   appropriately.  */
> +/* Write unsigned VALUE to coverage file.  */
>   
> -#if IN_LIBGCOV
>   GCOV_LINKAGE void
> -gcov_write_counter (gcov_type value)
> +gcov_write_unsigned (gcov_unsigned_t value)
>   {
> -  gcov_write_unsigned ((gcov_unsigned_t) value);
> -  if (sizeof (value) > sizeof (gcov_unsigned_t))
> -    gcov_write_unsigned ((gcov_unsigned_t) (value >> 32));
> -  else
> -    gcov_write_unsigned (0);
> +  gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file);
> +  if (r != 1)
> +    gcov_var.error = 1;
>   }
> -#endif /* IN_LIBGCOV */
>   
>   #if !IN_LIBGCOV
>   /* Write STRING to coverage file.  Sets error flag on file
> @@ -347,22 +342,13 @@ gcov_write_length (gcov_position_t position)
>   
>   #else /* IN_LIBGCOV */
>   
> -/* Write a tag TAG and length LENGTH.  */
> -
> -GCOV_LINKAGE void
> -gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
> -{
> -  gcov_write_unsigned (tag);
> -  gcov_write_unsigned (length);
> -}
> -
> -/* Write a summary structure to the gcov file.  Return nonzero on
> -   overflow.  */
> +/* Write a summary structure to the gcov file.  */
>   
>   GCOV_LINKAGE void
>   gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
>   {
> -  gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
> +  gcov_write_unsigned (tag);
> +  gcov_write_unsigned (GCOV_TAG_SUMMARY_LENGTH);
>     gcov_write_unsigned (summary->runs);
>     gcov_write_unsigned (summary->sum_max);
>   }
> 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/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c b/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c
> new file mode 100644
> index 000000000000..390f377de4fe
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c
> @@ -0,0 +1,60 @@
> +/* { dg-do run } */
> +/* { dg-skip-if "profile-info-section" { powerpc-ibm-aix* } } */
> +/* { dg-options "-fprofile-arcs -fprofile-info-section" } */
> +
> +#define assert(expr)						\
> +  ((expr)                                                       \
> +   ? (void)0                                                    \
> +   : (__builtin_printf ("%s:%i: Assertion `%s' failed.\n",	\
> +                        __FILE__, __LINE__, #expr),		\
> +      __builtin_abort ()))
> +
> +struct gcov_info;
> +
> +extern void
> +__gcov_info_to_gcda (const struct gcov_info *__info,
> +		     void (*__filename_fn) (const char *, void *),
> +		     void (*__dump_fn) (const void *, unsigned, void *),
> +		     void *(*__allocate_fn) (unsigned, void *),
> +		     void *__arg);
> +
> +extern const struct gcov_info *my_info;
> +
> +static unsigned counter;
> +
> +static void
> +filename (const char *f, void *arg)
> +{
> +  assert (arg == &counter);
> +  assert (__builtin_strstr (f, "gcov-info-to-gcda.c") == 0);
> +}
> +
> +static void
> +dump (const void *d, unsigned n, void *arg)
> +{
> +  unsigned *m = (unsigned *)arg;
> +  assert (arg == &counter);
> +
> +  if (*m == 0)
> +  {
> +    const unsigned *u = d;
> +    assert (*u == 0x67636461);
> +  }
> +
> +  *m += n;
> +}
> +
> +static void *
> +allocate (unsigned length, void *arg)
> +{
> +  assert (arg == &counter);
> +  return __builtin_malloc (length);
> +}
> +
> +int main()
> +{
> +  __asm__ volatile (".set my_info, .LPBX2");
> +  __gcov_info_to_gcda (my_info, filename, dump, allocate, &counter);
> +  assert (counter > 4);
> +  return 0;
> +}
> 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..66d03bf4e5d4 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,21 @@ extern void __gcov_reset (void);
>   
>   extern void __gcov_dump (void);
>   
> +/* Convert the gcov information referenced by INFO to a gcda data stream.
> +   The FILENAME_FN callback is called exactly once with the filename associated
> +   with the gcov information.  The filename may be NULL.  Afterwards, the
> +   DUMP_FN 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 ALLOCATE_FN callback shall allocate memory with a size in
> +   characters specified by the first callback parameter.  The ARG 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 *__info,
> +		     void (*__filename_fn) (const char *, void *),
> +		     void (*__dump_fn) (const void *, unsigned, void *),
> +		     void *(*__allocate_fn) (unsigned, void *),
> +		     void *__arg);
> +
>   #endif /* GCC_GCOV_H */
> diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
> index df7ccb235677..32e312ec3cfa 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,51 @@ read_error:
>     return -1;
>   }
>   
> +/* Write the DATA of LENGTH characters to the gcov file.  */
> +
> +static void
> +gcov_dump_handler (const void *data,
> +		   unsigned length,
> +		   void *arg ATTRIBUTE_UNUSED)
> +{
> +  gcov_write (data, length);
> +}
> +
> +/* Allocate SIZE characters and return the address of the allocated memory.  */
> +
> +static void *
> +gcov_allocate_handler (unsigned size, void *arg ATTRIBUTE_UNUSED)
> +{
> +  return xmalloc (size);
> +}
> +#endif /* NEED_L_GCOV */
> +
> +#if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
> +/* Dump the WORD using the DUMP handler called with ARG.  */
> +
> +static inline void
> +dump_unsigned (gcov_unsigned_t word,
> +	       void (*dump_fn) (const void *, unsigned, void *),
> +	       void *arg)
> +{
> +  (*dump_fn) (&word, sizeof (word), arg);
> +}
> +
> +/* Dump the COUNTER using the DUMP handler called with ARG.  */
> +
> +static inline void
> +dump_counter (gcov_type counter,
> +	      void (*dump_fn) (const void *, unsigned, void *),
> +	      void *arg)
> +{
> +  dump_unsigned ((gcov_unsigned_t)counter, dump_fn, arg);
> +
> +  if (sizeof (counter) > sizeof (gcov_unsigned_t))
> +    dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg);
> +  else
> +    dump_unsigned (0, dump_fn, arg);
> +}
> +
>   #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
>   
>   /* Store all TOP N counters where each has a dynamic length.  */
> @@ -350,7 +416,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_fn) (const void *, unsigned, void *),
> +		     void *(*allocate_fn)(unsigned, void *),
> +		     void *arg)
>   {
>     unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
>     gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
> @@ -365,46 +434,49 @@ 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_fn) (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_fn, arg),
> +  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump_fn, 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_fn, arg);
> +      dump_counter (list_sizes[i], dump_fn, 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_fn, arg);
> +	  dump_counter (node->count, dump_fn, arg);
>   	}
>       }
>   }
> @@ -415,25 +487,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_fn) (const void *, unsigned, void *),
> +		void *(*allocate_fn) (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_fn, arg);
> +  dump_unsigned (GCOV_VERSION, dump_fn, arg);
> +  dump_unsigned (gi_ptr->stamp, dump_fn, arg);
>   
> +#ifdef NEED_L_GCOV
>     /* Generate whole program statistics.  */
>     gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
> +#else
> +  (void)prg_p;

Can you please use rather ATTRIBUTE_UNUSED for the argument?

> +#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 +525,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 +534,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_fn, arg);
> +      dump_unsigned (length, dump_fn, 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_fn, arg);
> +      dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg);
> +      dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg);
>   
>         ci_ptr = gfi_ptr->ctrs;
>         for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
> @@ -469,39 +554,43 @@ 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_fn,
> +				 allocate_fn,
> +				 arg);

Please reduce the number of newlines.

>   	  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_fn, 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_fn,
> +			       arg);

Likewise here.

>   	      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_fn,
> +				 arg);
>   		  for (unsigned i = 0; i < n_counts; i++)
> -		    gcov_write_counter (ci_ptr->values[i]);
> +		    dump_counter (ci_ptr->values[i], dump_fn, 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_fn, 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 +639,11 @@ 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,
> +		  gcov_dump_handler,
> +		  gcov_allocate_handler,
> +		  NULL);

Same here.

Martin

>     /* fall through */
>   
>   read_fatal:;
> @@ -680,5 +773,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_fn) (const char *, void *),
> +		     void (*dump_fn) (const void *, unsigned, void *),
> +		     void *(*allocate_fn) (unsigned, void *),
> +		     void *arg)
> +{
> +  (*filename_fn) (gi_ptr->filename, arg);
> +  write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg);
> +}
> +#endif /* NEED_L_GCOV_INFO_TO_GCDA */
> diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
> index 8d323db05386..9c537253293f 100644
> --- a/libgcc/libgcov.h
> +++ b/libgcc/libgcov.h
> @@ -114,13 +114,11 @@ typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
>   #define gcov_var __gcov_var
>   #define gcov_open __gcov_open
>   #define gcov_close __gcov_close
> -#define gcov_write_tag_length __gcov_write_tag_length
>   #define gcov_position __gcov_position
>   #define gcov_seek __gcov_seek
>   #define gcov_rewrite __gcov_rewrite
>   #define gcov_is_error __gcov_is_error
>   #define gcov_write_unsigned __gcov_write_unsigned
> -#define gcov_write_counter __gcov_write_counter
>   #define gcov_write_summary __gcov_write_summary
>   #define gcov_read_unsigned __gcov_read_unsigned
>   #define gcov_read_counter __gcov_read_counter
> @@ -345,9 +343,6 @@ extern int __gcov_execve (const char *, char  *const [], char *const [])
>   
>   /* Functions that only available in libgcov.  */
>   GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
> -GCOV_LINKAGE void gcov_write_counter (gcov_type) ATTRIBUTE_HIDDEN;
> -GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, gcov_unsigned_t)
> -    ATTRIBUTE_HIDDEN;
>   GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
>                                         const struct gcov_summary *)
>       ATTRIBUTE_HIDDEN;
> 


  reply	other threads:[~2021-08-05 12:54 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-23  9:39 Sebastian Huber
2021-08-05 12:53 ` Martin Liška [this message]
2021-08-06  5:31   ` Sebastian Huber
2021-08-06  7:50     ` Christophe Lyon
2021-08-06  8:05       ` Sebastian Huber
2021-08-06  9:15         ` Christophe Lyon
2021-08-06 10:26         ` Martin Liška
2021-08-06 10:29           ` Sebastian Huber

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ae2c2f6a-c82f-54f2-4f8c-870f926870d2@suse.cz \
    --to=mliska@suse.cz \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=sebastian.huber@embedded-brains.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).