public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gcov v2 00/14] Add merge-stream subcommand to gcov-tool
@ 2022-04-25  7:09 Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 01/14] gcov-tool: Allow merging of empty profile lists Sebastian Huber
                   ` (14 more replies)
  0 siblings, 15 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

This patch set is for GCC 13.

The aim is to better support gcov in free-standing environments. For example,
you can run a test executable which dumps all gcov info objects in a serial
data stream using __gcov_info_to_gcda() and the new __gcov_filename_to_gcfn().
It could be encoded as base64. It could be also compressed. On the host you
unpack the encoded data stream and feed it into gcov-tool using the new
"merge-stream" subcommand:

gcov-tool --help
Usage: gcov-tool [OPTION]... SUB_COMMAND [OPTION]...

Offline tool to handle gcda counts

  -h, --help                            Print this help, then exit
  -v, --version                         Print version number, then exit
  merge-stream [options] [stream-file]  Merge coverage stream file (or stdin)
                                        and coverage file contents
    -v, --verbose                       Verbose mode
    -w, --weight <w1,w2>                Set weights (float point values)

Example:

base64 -d log.txt | gcov-tool merge-stream

The patch set does not change the format of .gcda files.

TODO:

* Tests for gcov-tool

v2:

* Address review comments from v1

* Simple test for __gcov_filename_to_gcfn()

* Use xstrerror()

* Add documentation

Sebastian Huber (14):
  gcov-tool: Allow merging of empty profile lists
  gcov: Add mode to all gcov_open()
  gcov: Add open mode parameter to gcov_do_dump()
  gcov: Make gcov_seek() static
  gcov: Add __gcov_filename_to_gcfn()
  gcov-tool: Support file input from stdin
  gcov: Use xstrdup()
  gcov: Move prepend to list to read_gcda_file()
  gcov: Move gcov_open() to caller of read_gcda_file()
  gcov: Fix integer types in ftw_read_file()
  gcov: Record EOF error during read
  gcov-tool: Add merge-stream subcommand
  gcov: Use xstrerror()
  gcov: Add section for freestanding environments

 gcc/doc/gcov-tool.texi                   |  36 +++
 gcc/doc/gcov.texi                        | 375 +++++++++++++++++++++++
 gcc/doc/invoke.texi                      |  31 +-
 gcc/gcov-io.cc                           |  79 +++--
 gcc/gcov-io.h                            |  35 ++-
 gcc/gcov-tool.cc                         | 107 +++++--
 gcc/testsuite/gcc.dg/gcov-info-to-gcda.c |  36 ++-
 libgcc/gcov.h                            |  17 +-
 libgcc/libgcov-driver-system.c           |   7 +-
 libgcc/libgcov-driver.c                  |  44 ++-
 libgcc/libgcov-util.c                    | 150 +++++++--
 libgcc/libgcov.h                         |   3 -
 12 files changed, 803 insertions(+), 117 deletions(-)

-- 
2.34.1


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

* [gcov v2 01/14] gcov-tool: Allow merging of empty profile lists
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 02/14] gcov: Add mode to all gcov_open() Sebastian Huber
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

The gcov_profile_merge() already had code to deal with profile information
which had no counterpart to merge with.  For profile information from files
with no associated counterpart, the profile information is simply used as is
with the weighting transformation applied.  Make sure that gcov_profile_merge()
works with an empty target profile list.  Return the merged profile list.

gcc/
	* gcov-tool.cc (gcov_profile_merge): Adjust return type.
	(profile_merge): Allow merging of directories which contain no profile
	files.

libgcc/
	* libgcov-util.c (gcov_profile_merge): Return the list of merged
	profiles.  Accept empty target and source profile lists.
---
 gcc/gcov-tool.cc      | 27 ++++++++++-----------------
 libgcc/libgcov-util.c | 19 +++++++++++--------
 2 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/gcc/gcov-tool.cc b/gcc/gcov-tool.cc
index f4e42ae763c..2e4083a664d 100644
--- a/gcc/gcov-tool.cc
+++ b/gcc/gcov-tool.cc
@@ -40,7 +40,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #endif
 #include <getopt.h>
 
-extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
+extern struct gcov_info *gcov_profile_merge (struct gcov_info*,
+					     struct gcov_info*, int, int);
 extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
@@ -141,26 +142,18 @@ profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2)
 {
   struct gcov_info *d1_profile;
   struct gcov_info *d2_profile;
-  int ret;
+  struct gcov_info *merged_profile;
 
   d1_profile = gcov_read_profile_dir (d1, 0);
-  if (!d1_profile)
-    return 1;
-
-  if (d2)
-    {
-      d2_profile = gcov_read_profile_dir (d2, 0);
-      if (!d2_profile)
-        return 1;
+  d2_profile = gcov_read_profile_dir (d2, 0);
 
-      /* The actual merge: we overwrite to d1_profile.  */
-      ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
+  /* The actual merge: we overwrite to d1_profile.  */
+  merged_profile = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
 
-      if (ret)
-        return ret;
-    }
-
-  gcov_output_files (out, d1_profile);
+  if (merged_profile)
+    gcov_output_files (out, merged_profile);
+  else if (verbose)
+    fnotice (stdout, "no profile files were merged\n");
 
   return 0;
 }
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index ba7fb924b53..100f1b19f1a 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -674,16 +674,16 @@ find_match_gcov_info (struct gcov_info **array, int size,
 }
 
 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
-   Return 0 on success: without mismatch.
-   Reutrn 1 on error.  */
+   Return the list of merged gcov_info objects.  Return NULL if the list is
+   empty.  */
 
-int
+struct gcov_info *
 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
                     int w1, int w2)
 {
   struct gcov_info *gi_ptr;
   struct gcov_info **tgt_infos;
-  struct gcov_info *tgt_tail;
+  struct gcov_info **tgt_tail;
   struct gcov_info **in_src_not_tgt;
   unsigned tgt_cnt = 0, src_cnt = 0;
   unsigned unmatch_info_cnt = 0;
@@ -703,7 +703,10 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
   for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
     tgt_infos[i] = gi_ptr;
 
-  tgt_tail = tgt_infos[tgt_cnt - 1];
+  if (tgt_cnt)
+     tgt_tail = &tgt_infos[tgt_cnt - 1]->next;
+  else
+     tgt_tail = &tgt_profile;
 
   /* First pass on tgt_profile, we multiply w1 to all counters.  */
   if (w1 > 1)
@@ -732,14 +735,14 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
       gi_ptr = in_src_not_tgt[i];
       gcov_merge (gi_ptr, gi_ptr, w2 - 1);
       gi_ptr->next = NULL;
-      tgt_tail->next = gi_ptr;
-      tgt_tail = gi_ptr;
+      *tgt_tail = gi_ptr;
+      tgt_tail = &gi_ptr->next;
     }
 
   free (in_src_not_tgt);
   free (tgt_infos);
 
-  return 0;
+  return tgt_profile;
 }
 
 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
-- 
2.34.1


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

* [gcov v2 02/14] gcov: Add mode to all gcov_open()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 01/14] gcov-tool: Allow merging of empty profile lists Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 03/14] gcov: Add open mode parameter to gcov_do_dump() Sebastian Huber
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

gcc/

	* gcov-io.cc (gcov_open): Always use the mode parameter.
	* gcov-io.h (gcov_open): Declare it unconditionally.

libgcc/

	* libgcov-driver-system.c (gcov_exit_open_gcda_file): Open file for
	reading and writing.
	* libgcov-util.c (read_gcda_file): Open file for reading.
	* libgcov.h (gcov_open): Delete declaration.
---
 gcc/gcov-io.cc                 | 7 -------
 gcc/gcov-io.h                  | 5 +----
 libgcc/libgcov-driver-system.c | 4 ++--
 libgcc/libgcov-util.c          | 2 +-
 libgcc/libgcov.h               | 1 -
 5 files changed, 4 insertions(+), 15 deletions(-)

diff --git a/gcc/gcov-io.cc b/gcc/gcov-io.cc
index 72c40f8eaa0..017a6e32a5d 100644
--- a/gcc/gcov-io.cc
+++ b/gcc/gcov-io.cc
@@ -89,15 +89,8 @@ from_file (gcov_unsigned_t value)
    Return zero on failure, non-zero on success.  */
 
 GCOV_LINKAGE int
-#if IN_LIBGCOV
-gcov_open (const char *name)
-#else
 gcov_open (const char *name, int mode)
-#endif
 {
-#if IN_LIBGCOV
-  int mode = 0;
-#endif
 #if GCOV_LOCKED
   struct flock s_flock;
   int fd;
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 99ce7dbccc8..afe74b002f1 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -347,15 +347,12 @@ struct gcov_summary
    functions for writing.  Your file may become corrupted if you break
    these invariants.  */
 
-#if !IN_LIBGCOV
-GCOV_LINKAGE int gcov_open (const char */*name*/, int /*direction*/);
-#endif
-
 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
 GCOV_LINKAGE int gcov_magic (gcov_unsigned_t, gcov_unsigned_t);
 #endif
 
 /* Available everywhere.  */
+GCOV_LINKAGE int gcov_open (const char *, int) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN;
diff --git a/libgcc/libgcov-driver-system.c b/libgcc/libgcov-driver-system.c
index eef6e3cbda1..9abb2fe7f74 100644
--- a/libgcc/libgcov-driver-system.c
+++ b/libgcc/libgcov-driver-system.c
@@ -309,7 +309,7 @@ gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
 
   gf->filename = replace_filename_variables (gf->filename);
 
-  if (!gcov_open (gf->filename))
+  if (!gcov_open (gf->filename, 0))
     {
       /* Open failed likely due to missed directory.
          Create directory and retry to open file. */
@@ -318,7 +318,7 @@ gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
           fprintf (stderr, "profiling:%s:Skip\n", gf->filename);
           return -1;
         }
-      if (!gcov_open (gf->filename))
+      if (!gcov_open (gf->filename, 0))
         {
           fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename);
           return -1;
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index 100f1b19f1a..db157220c9d 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -268,7 +268,7 @@ read_gcda_file (const char *filename)
     k_ctrs_mask[i] = 0;
   k_ctrs_types = 0;
 
-  if (!gcov_open (filename))
+  if (!gcov_open (filename, 1))
     {
       fnotice (stderr, "%s:cannot open\n", filename);
       return NULL;
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index 40e845ce3ea..f190547e819 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -343,7 +343,6 @@ extern int __gcov_execve (const char *, char  *const [], char *const [])
   ATTRIBUTE_HIDDEN;
 
 /* Functions that only available in libgcov.  */
-GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
                                       const struct gcov_summary *)
     ATTRIBUTE_HIDDEN;
-- 
2.34.1


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

* [gcov v2 03/14] gcov: Add open mode parameter to gcov_do_dump()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 01/14] gcov-tool: Allow merging of empty profile lists Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 02/14] gcov: Add mode to all gcov_open() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 04/14] gcov: Make gcov_seek() static Sebastian Huber
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

gcc/

	* gcov-tool.cc (gcov_do_dump): Add mode parameter.
	(gcov_output_files): Open files for reading and writing.

libgcc/

	* libgcov-driver-system.c (gcov_exit_open_gcda_file): Add mode
	parameter.  Pass mode to gcov_open() calls.
	* libgcov-driver.c (dump_one_gcov):  Add mode parameter.  Pass mode to
	gcov_exit_open_gcda_file() call.
	(gcov_do_dump): Add mode parameter.  Pass mode to dump_one_gcov()
	calls.
	(__gcov_dump_one):  Open file for reading and writing.
---
 gcc/gcov-tool.cc               |  4 ++--
 libgcc/libgcov-driver-system.c |  7 ++++---
 libgcc/libgcov-driver.c        | 12 ++++++------
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/gcc/gcov-tool.cc b/gcc/gcov-tool.cc
index 2e4083a664d..d712715cf7e 100644
--- a/gcc/gcov-tool.cc
+++ b/gcc/gcov-tool.cc
@@ -46,7 +46,7 @@ extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
 extern struct gcov_info* gcov_read_profile_dir (const char*, int);
-extern void gcov_do_dump (struct gcov_info *, int);
+extern void gcov_do_dump (struct gcov_info *, int, int);
 extern const char *gcov_get_filename (struct gcov_info *list);
 extern void gcov_set_verbose (void);
 
@@ -124,7 +124,7 @@ gcov_output_files (const char *out, struct gcov_info *profile)
     fatal_error (input_location, "output file %s already exists in folder %s",
 		 filename, out);
 
-  gcov_do_dump (profile, 0);
+  gcov_do_dump (profile, 0, 0);
 
   ret = chdir (pwd);
   if (ret)
diff --git a/libgcc/libgcov-driver-system.c b/libgcc/libgcov-driver-system.c
index 9abb2fe7f74..ac405c38e3a 100644
--- a/libgcc/libgcov-driver-system.c
+++ b/libgcc/libgcov-driver-system.c
@@ -261,7 +261,8 @@ allocate_filename_struct (struct gcov_filename *gf)
 
 static int
 gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
-			  struct gcov_filename *gf)
+			  struct gcov_filename *gf,
+			  int mode)
 {
   int append_slash = 0;
   const char *fname = gi_ptr->filename;
@@ -309,7 +310,7 @@ gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
 
   gf->filename = replace_filename_variables (gf->filename);
 
-  if (!gcov_open (gf->filename, 0))
+  if (!gcov_open (gf->filename, mode))
     {
       /* Open failed likely due to missed directory.
          Create directory and retry to open file. */
@@ -318,7 +319,7 @@ gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
           fprintf (stderr, "profiling:%s:Skip\n", gf->filename);
           return -1;
         }
-      if (!gcov_open (gf->filename, 0))
+      if (!gcov_open (gf->filename, mode))
         {
           fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename);
           return -1;
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 7e52c5676e5..10831e84b61 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -595,14 +595,14 @@ write_one_data (const struct gcov_info *gi_ptr,
 static void
 dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
 	       unsigned run_counted ATTRIBUTE_UNUSED,
-	       gcov_type run_max ATTRIBUTE_UNUSED)
+	       gcov_type run_max ATTRIBUTE_UNUSED, int mode)
 {
   struct gcov_summary summary = {};
   int error;
   gcov_unsigned_t tag;
   fn_buffer = 0;
 
-  error = gcov_exit_open_gcda_file (gi_ptr, gf);
+  error = gcov_exit_open_gcda_file (gi_ptr, gf, mode);
   if (error == -1)
     return;
 
@@ -649,13 +649,13 @@ read_fatal:;
 
 /* Dump all the coverage counts for the program. It first computes program
    summary and then traverses gcov_list list and dumps the gcov_info
-   objects one by one.  */
+   objects one by one.  Use MODE to open files.  */
 
 #if !IN_GCOV_TOOL
 static
 #endif
 void
-gcov_do_dump (struct gcov_info *list, int run_counted)
+gcov_do_dump (struct gcov_info *list, int run_counted, int mode)
 {
   struct gcov_info *gi_ptr;
   struct gcov_filename gf;
@@ -678,7 +678,7 @@ gcov_do_dump (struct gcov_info *list, int run_counted)
   /* Now merge each file.  */
   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
     {
-      dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
+      dump_one_gcov (gi_ptr, &gf, run_counted, run_max, mode);
       free (gf.filename);
     }
 
@@ -701,7 +701,7 @@ __gcov_dump_one (struct gcov_root *root)
   if (root->dumped)
     return;
 
-  gcov_do_dump (root->list, root->run_counted);
+  gcov_do_dump (root->list, root->run_counted, 0);
   
   root->dumped = 1;
   root->run_counted = 1;
-- 
2.34.1


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

* [gcov v2 04/14] gcov: Make gcov_seek() static
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (2 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 03/14] gcov: Add open mode parameter to gcov_do_dump() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 05/14] gcov: Add __gcov_filename_to_gcfn() Sebastian Huber
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

This function is only used by gcov_write_length() in the gcov-io.cc file.

gcc/

	* gcov-io.cc (gcov_seek): Make it static.
	* gcov-io.h (struct gcov_summary): Do not mention gcov_seek().

libgcc/

	* libgcov.h (gcov_seek): Remove define and declaration.
---
 gcc/gcov-io.cc   | 4 +---
 gcc/gcov-io.h    | 6 +++---
 libgcc/libgcov.h | 2 --
 3 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/gcc/gcov-io.cc b/gcc/gcov-io.cc
index 017a6e32a5d..fee3130f94a 100644
--- a/gcc/gcov-io.cc
+++ b/gcc/gcov-io.cc
@@ -294,17 +294,15 @@ gcov_write_filename (const char *filename)
 
   gcov_write_string (filename);
 }
-#endif
 
 /* Move to a given position in a gcov file.  */
 
-GCOV_LINKAGE void
+static void
 gcov_seek (gcov_position_t base)
 {
   fseek (gcov_var.file, base, SEEK_SET);
 }
 
-#if !IN_LIBGCOV
 /* Write a tag TAG and reserve space for the record length. Return a
    value to be used for gcov_write_length.  */
 
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index afe74b002f1..204ae0ccf7f 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -340,9 +340,9 @@ struct gcov_summary
 /* Functions for reading and writing gcov files. In libgcov you can
    open the file for reading then writing. Elsewhere you can open the
    file either for reading or for writing. When reading a file you may
-   use the gcov_read_* functions, gcov_sync, gcov_position, &
-   gcov_error. When writing a file you may use the gcov_write
-   functions, gcov_seek & gcov_error. When a file is to be rewritten
+   use the gcov_read_* functions, gcov_sync, gcov_position, and
+   gcov_error. When writing a file you may use the gcov_write*
+   functions and gcov_error. When a file is to be rewritten
    you use the functions for reading, then gcov_rewrite then the
    functions for writing.  Your file may become corrupted if you break
    these invariants.  */
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index f190547e819..487bd1464cd 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -115,7 +115,6 @@ typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
 #define gcov_open __gcov_open
 #define gcov_close __gcov_close
 #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
@@ -346,7 +345,6 @@ extern int __gcov_execve (const char *, char  *const [], char *const [])
 GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
                                       const struct gcov_summary *)
     ATTRIBUTE_HIDDEN;
-GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_rewrite (void) ATTRIBUTE_HIDDEN;
 
 /* "Counts" stored in gcda files can be a real counter value, or
-- 
2.34.1


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

* [gcov v2 05/14] gcov: Add __gcov_filename_to_gcfn()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (3 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 04/14] gcov: Make gcov_seek() static Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 06/14] gcov-tool: Support file input from stdin Sebastian Huber
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

gcc/

	* doc/invoke.texi (fprofile-info-section): Mention
	__gcov_filename_to_gcfn().  Use "freestanding" to match with C11
	standard language.  Fix minor example code issues.
	* gcov-io.h (GCOV_FILENAME_MAGIC): Define and document.

gcc/testsuite/

	* gcc.dg/gcov-info-to-gcda.c: Test __gcov_filename_to_gcfn().

libgcc/

	* gcov.h (__gcov_info_to_gcda): Mention __gcov_filename_to_gcfn().
	(__gcov_filename_to_gcfn): Declare and document.
	* libgcov-driver.c (dump_string): New.
	(__gcov_filename_to_gcfn): Likewise.
	(__gcov_info_to_gcda): Adjust comment to match C11 standard language.
---
 gcc/doc/invoke.texi                      | 26 ++++++++---------
 gcc/gcov-io.h                            | 24 ++++++++++------
 gcc/testsuite/gcc.dg/gcov-info-to-gcda.c | 36 +++++++++++++++++++-----
 libgcc/gcov.h                            | 17 ++++++++++-
 libgcc/libgcov-driver.c                  | 32 ++++++++++++++++++++-
 5 files changed, 105 insertions(+), 30 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 07b440190c3..af5495e75c6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -15462,7 +15462,7 @@ 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
+used in hosted environments such as GNU/Linux.  It targets freestanding
 environments (for example embedded systems) with limited resources which do not
 support constructors/destructors or the C library file I/O.
 
@@ -15487,14 +15487,8 @@ for example like this:
 #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);
-@}
+extern const struct gcov_info *const __gcov_info_start[];
+extern const struct gcov_info *const __gcov_info_end[];
 
 static void
 dump (const void *d, unsigned n, void *arg)
@@ -15505,6 +15499,12 @@ dump (const void *d, unsigned n, void *arg)
     printf ("%02x", c[i]);
 @}
 
+static void
+filename (const char *f, void *arg)
+@{
+  __gcov_filename_to_gcfn (f, dump, arg );
+@}
+
 static void *
 allocate (unsigned length, void *arg)
 @{
@@ -15514,8 +15514,8 @@ allocate (unsigned length, void *arg)
 static void
 dump_gcov_info (void)
 @{
-  const struct gcov_info **info = __gcov_info_start;
-  const struct gcov_info **end = __gcov_info_end;
+  const struct gcov_info *const *info = __gcov_info_start;
+  const struct gcov_info *const *end = __gcov_info_end;
 
   /* Obfuscate variable to prevent compiler optimizations.  */
   __asm__ ("" : "+r" (info));
@@ -15530,9 +15530,9 @@ dump_gcov_info (void)
 @}
 
 int
-main()
+main (void)
 @{
-  dump_gcov_info();
+  dump_gcov_info ();
   return 0;
 @}
 @end smallexample
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 204ae0ccf7f..30947634d73 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -60,14 +60,21 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
    	file : int32:magic int32:version int32:stamp record*
 
-   The magic ident is different for the notes and the data files.  The
-   magic ident is used to determine the endianness of the file, when
-   reading.  The version is the same for both files and is derived
-   from gcc's version number. The stamp value is used to synchronize
-   note and data files and to synchronize merging within a data
-   file. It need not be an absolute time stamp, merely a ticker that
-   increments fast enough and cycles slow enough to distinguish
-   different compile/run/compile cycles.
+   A filename header may be used to provide a filename for the data in
+   a stream of data to support gcov in freestanding environments.  This
+   header is used by the merge-stream subcommand of the gcov-tool.  The
+   format of the filename header is
+
+	filename-header : int32:magic int32:version string
+
+   The magic ident is different for the notes and the data files as
+   well as the filename header.  The magic ident is used to determine
+   the endianness of the file, when reading.  The version is the same
+   for both files and is derived from gcc's version number. The stamp
+   value is used to synchronize note and data files and to synchronize
+   merging within a data file. It need not be an absolute time stamp,
+   merely a ticker that increments fast enough and cycles slow enough
+   to distinguish different compile/run/compile cycles.
 
    Although the ident and version are formally 32 bit numbers, they
    are derived from 4 character ASCII strings.  The version number
@@ -228,6 +235,7 @@ typedef uint64_t gcov_type_unsigned;
 /* File magic. Must not be palindromes.  */
 #define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461) /* "gcda" */
 #define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f) /* "gcno" */
+#define GCOV_FILENAME_MAGIC ((gcov_unsigned_t)0x6763666e) /* "gcfn" */
 
 #include "version.h"
 
diff --git a/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c b/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c
index 4583360feef..ca9b3e831fe 100644
--- a/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c
+++ b/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c
@@ -17,16 +17,20 @@ __gcov_info_to_gcda (const struct gcov_info *__info,
 		     void *(*__allocate_fn) (unsigned, void *),
 		     void *__arg);
 
+extern void
+__gcov_filename_to_gcfn (const char *__filename,
+			 void (*__dump_fn) (const void *, 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 unsigned counter_after_filename;
+
+static int check_zero;
+
+static int check_after_filename;
 
 static void
 dump (const void *d, unsigned n, void *arg)
@@ -35,14 +39,30 @@ dump (const void *d, unsigned n, void *arg)
   assert (arg == &counter);
 
   if (*m == 0)
+  {
+    const unsigned *u = d;
+    assert (*u == 0x6763666e);
+    check_zero = 1;
+  }
+  else if (*m == counter_after_filename)
   {
     const unsigned *u = d;
     assert (*u == 0x67636461);
+    check_after_filename = 1;
   }
 
   *m += n;
 }
 
+static void
+filename (const char *f, void *arg)
+{
+  assert (arg == &counter);
+  assert (__builtin_strstr (f, "gcov-info-to-gcda.c") == 0);
+  __gcov_filename_to_gcfn (f, dump, arg);
+  counter_after_filename = counter;
+}
+
 static void *
 allocate (unsigned length, void *arg)
 {
@@ -54,6 +74,8 @@ int main()
 {
   __asm__ volatile (".set my_info, .LPBX2");
   __gcov_info_to_gcda (my_info, filename, dump, allocate, &counter);
-  assert (counter > 4);
+  assert (counter > 8);
+  assert (check_zero);
+  assert (check_after_filename);
   return 0;
 }
diff --git a/libgcc/gcov.h b/libgcc/gcov.h
index cea93023920..cdd4206f625 100644
--- a/libgcc/gcov.h
+++ b/libgcc/gcov.h
@@ -43,7 +43,8 @@ extern void __gcov_dump (void);
    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.  */
+   functions.  It is recommended to use the __gcov_filename_to_gcfn()
+   in the filename callback function.  */
 
 extern void
 __gcov_info_to_gcda (const struct gcov_info *__info,
@@ -52,4 +53,18 @@ __gcov_info_to_gcda (const struct gcov_info *__info,
 		     void *(*__allocate_fn) (unsigned, void *),
 		     void *__arg);
 
+/* Convert the FILENAME to a gcfn data stream.  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 gcfn data stream.
+   The ARG parameter is a user-provided argument passed as the last
+   argument to the DUMP_FN callback function.  This function is intended
+   to be used by the filename callback of __gcov_info_to_gcda().  The gcfn
+   data stream is used by the merge-stream subcommand of the gcov-tool to
+   get the filename associated with a gcda data stream.  */
+
+extern void
+__gcov_filename_to_gcfn (const char *__filename,
+			 void (*__dump_fn) (const void *, unsigned, void *),
+			 void *__arg);
+
 #endif /* GCC_GCOV_H */
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 10831e84b61..d4517d269eb 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -410,6 +410,23 @@ dump_counter (gcov_type counter,
     dump_unsigned (0, dump_fn, arg);
 }
 
+/* Dump the STRING using the DUMP handler called with ARG.  */
+
+static inline void
+dump_string (const char *string,
+	     void (*dump_fn) (const void *, unsigned, void *),
+	     void *arg)
+{
+  unsigned length = 0;
+
+  if (string)
+    length = strlen (string) + 1;
+
+  dump_unsigned (length, dump_fn, arg);
+  if (string)
+    (*dump_fn) (string, length, arg);
+}
+
 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
 
 /* Store all TOP N counters where each has a dynamic length.  */
@@ -768,7 +785,7 @@ __gcov_init (struct gcov_info *info)
 
 #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.  */
+   freestanding environments which do not support the C library file I/O.  */
 
 void
 __gcov_info_to_gcda (const struct gcov_info *gi_ptr,
@@ -780,4 +797,17 @@ __gcov_info_to_gcda (const struct gcov_info *gi_ptr,
   (*filename_fn) (gi_ptr->filename, arg);
   write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg);
 }
+
+/* Convert the filename to a gcfn data stream.  It is intended for
+   freestanding environments which do not support the C library file I/O.  */
+
+void
+__gcov_filename_to_gcfn (const char *filename,
+			 void (*dump_fn) (const void *, unsigned, void *),
+			 void *arg)
+{
+  dump_unsigned (GCOV_FILENAME_MAGIC, dump_fn, arg);
+  dump_unsigned (GCOV_VERSION, dump_fn, arg);
+  dump_string (filename, dump_fn, arg);
+}
 #endif /* NEED_L_GCOV_INFO_TO_GCDA */
-- 
2.34.1


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

* [gcov v2 06/14] gcov-tool: Support file input from stdin
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (4 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 05/14] gcov: Add __gcov_filename_to_gcfn() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 07/14] gcov: Use xstrdup() Sebastian Huber
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

gcc/

	* gcov-io.cc (GCOV_MODE_STDIN): Define.
	(gcov_position): For gcov-tool, return calculated position if file is
	stdin.
	(gcov_open):  For gcov-tool, use stdin if filename is NULL.
	(gcov_close): For gcov-tool, do not close stdin.
	(gcov_read_bytes): For gcov-tool, update position if file is stdin.
	(gcov_sync): For gcov-tool, discard input if file is stdin.
---
 gcc/gcov-io.cc | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/gcc/gcov-io.cc b/gcc/gcov-io.cc
index fee3130f94a..7e1fb10b612 100644
--- a/gcc/gcov-io.cc
+++ b/gcc/gcov-io.cc
@@ -35,8 +35,13 @@ struct gcov_var
   int error;			/* < 0 overflow, > 0 disk error.  */
   int mode;			/* < 0 writing, > 0 reading.  */
   int endian;			/* Swap endianness.  */
+#ifdef IN_GCOV_TOOL
+  gcov_position_t pos;		/* File position for stdin support.  */
+#endif
 } gcov_var;
 
+#define GCOV_MODE_STDIN 2
+
 /* Save the current position in the gcov file.  */
 /* We need to expose this function when compiling for gcov-tool.  */
 #ifndef IN_GCOV_TOOL
@@ -45,6 +50,10 @@ static inline
 gcov_position_t
 gcov_position (void)
 {
+#ifdef IN_GCOV_TOOL
+  if (gcov_var.mode == GCOV_MODE_STDIN)
+    return gcov_var.pos;
+#endif
   return ftell (gcov_var.file);
 }
 
@@ -108,6 +117,16 @@ gcov_open (const char *name, int mode)
 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
   gcov_var.endian = 0;
 #endif
+#ifdef IN_GCOV_TOOL
+  gcov_var.pos = 0;
+  if (!name)
+    {
+      gcov_nonruntime_assert (gcov_var.mode > 0);
+      gcov_var.file = stdin;
+      gcov_var.mode = GCOV_MODE_STDIN;
+      return 1;
+    }
+#endif
 #if GCOV_LOCKED
   if (mode > 0)
     {
@@ -190,6 +209,11 @@ gcov_open (const char *name, int mode)
 GCOV_LINKAGE int
 gcov_close (void)
 {
+#ifdef IN_GCOV_TOOL
+  if (gcov_var.file == stdin)
+    gcov_var.file = 0;
+  else
+#endif
   if (gcov_var.file)
     {
       if (fclose (gcov_var.file))
@@ -363,6 +387,9 @@ gcov_read_bytes (void *buffer, unsigned count)
   if (read != 1)
     return NULL;
 
+#ifdef IN_GCOV_TOOL
+  gcov_var.pos += count;
+#endif
   return buffer;
 }
 
@@ -499,6 +526,17 @@ gcov_sync (gcov_position_t base, gcov_unsigned_t length)
 {
   gcov_nonruntime_assert (gcov_var.mode > 0);
   base += length;
+#ifdef IN_GCOV_TOOL
+  if (gcov_var.mode == GCOV_MODE_STDIN)
+    {
+      while (gcov_var.pos < base)
+	{
+	  ++gcov_var.pos;
+	  (void)fgetc (gcov_var.file);
+	}
+      return;
+    }
+#endif
   fseek (gcov_var.file, base, SEEK_SET);
 }
 #endif
-- 
2.34.1


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

* [gcov v2 07/14] gcov: Use xstrdup()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (5 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 06/14] gcov-tool: Support file input from stdin Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 08/14] gcov: Move prepend to list to read_gcda_file() Sebastian Huber
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

Move duplication of filename to caller and use xstrdup() instead of custom
code.  This helps to reuse read_gcda_file() for other purposes.

libgcc/

	* libgcov-util.c (read_gcda_file): Do not duplicate filename.
	(ftw_read_file): Duplicate filename for read_gcda_file().
---
 libgcc/libgcov-util.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index db157220c9d..ae5712c0138 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -296,16 +296,11 @@ read_gcda_file (const char *filename)
              sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
 
   obj_info->version = version;
+  obj_info->filename = filename;
   obstack_init (&fn_info);
   num_fn_info = 0;
   curr_fn_info = 0;
-  {
-    size_t len = strlen (filename) + 1;
-    char *str_dup = (char*) xmalloc (len);
 
-    memcpy (str_dup, filename, len);
-    obj_info->filename = str_dup;
-  }
 
   /* Read stamp.  */
   obj_info->stamp = gcov_read_unsigned ();
@@ -415,7 +410,7 @@ ftw_read_file (const char *filename,
   if (verbose)
     fnotice (stderr, "reading file: %s\n", filename);
 
-  obj_info = read_gcda_file (filename);
+  obj_info = read_gcda_file (xstrdup (filename));
   if (!obj_info)
     return 0;
 
-- 
2.34.1


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

* [gcov v2 08/14] gcov: Move prepend to list to read_gcda_file()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (6 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 07/14] gcov: Use xstrdup() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 09/14] gcov: Move gcov_open() to caller of read_gcda_file() Sebastian Huber
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

This helps to reuse read_gcda_file().

libgcc/

	* libgcov-util.c (read_gcda_file): Prepend new info object to global
	list.
	(ftw_read_file): Remove list append here.
---
 libgcc/libgcov-util.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index ae5712c0138..906ea645547 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -301,6 +301,9 @@ read_gcda_file (const char *filename)
   num_fn_info = 0;
   curr_fn_info = 0;
 
+  /* Prepend to global gcov info list.  */
+  obj_info->next = gcov_info_head;
+  gcov_info_head = obj_info;
 
   /* Read stamp.  */
   obj_info->stamp = gcov_read_unsigned ();
@@ -392,7 +395,6 @@ ftw_read_file (const char *filename,
 {
   int filename_len;
   int suffix_len;
-  struct gcov_info *obj_info;
 
   /* Only read regular files.  */
   if (type != FTW_F)
@@ -410,12 +412,7 @@ ftw_read_file (const char *filename,
   if (verbose)
     fnotice (stderr, "reading file: %s\n", filename);
 
-  obj_info = read_gcda_file (xstrdup (filename));
-  if (!obj_info)
-    return 0;
-
-  obj_info->next = gcov_info_head;
-  gcov_info_head = obj_info;
+  (void)read_gcda_file (xstrdup (filename));
 
   return 0;
 }
-- 
2.34.1


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

* [gcov v2 09/14] gcov: Move gcov_open() to caller of read_gcda_file()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (7 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 08/14] gcov: Move prepend to list to read_gcda_file() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 10/14] gcov: Fix integer types in ftw_read_file() Sebastian Huber
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

This allows to reuse read_gcda_file() to read multiple objects from a single
file.

libgcc/

	* libgcov-util.c (read_gcda_file): Do not open file.
	(ftw_read_file): Open file here.
---
 libgcc/libgcov-util.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index 906ea645547..6093a74531d 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -268,17 +268,10 @@ read_gcda_file (const char *filename)
     k_ctrs_mask[i] = 0;
   k_ctrs_types = 0;
 
-  if (!gcov_open (filename, 1))
-    {
-      fnotice (stderr, "%s:cannot open\n", filename);
-      return NULL;
-    }
-
   /* Read magic.  */
   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
     {
       fnotice (stderr, "%s:not a gcov data file\n", filename);
-      gcov_close ();
       return NULL;
     }
 
@@ -287,7 +280,6 @@ read_gcda_file (const char *filename)
   if (version != GCOV_VERSION)
     {
       fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
-      gcov_close ();
       return NULL;
     }
 
@@ -379,7 +371,6 @@ read_gcda_file (const char *filename)
     }
 
   read_gcda_finalize (obj_info);
-  gcov_close ();
 
   return obj_info;
 }
@@ -412,7 +403,14 @@ ftw_read_file (const char *filename,
   if (verbose)
     fnotice (stderr, "reading file: %s\n", filename);
 
+  if (!gcov_open (filename, 1))
+    {
+      fnotice (stderr, "%s:cannot open\n", filename);
+      return 0;
+    }
+
   (void)read_gcda_file (xstrdup (filename));
+  gcov_close ();
 
   return 0;
 }
-- 
2.34.1


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

* [gcov v2 10/14] gcov: Fix integer types in ftw_read_file()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (8 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 09/14] gcov: Move gcov_open() to caller of read_gcda_file() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 11/14] gcov: Record EOF error during read Sebastian Huber
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

libgcc/

	* libgcov-util.c (ftw_read_file): Use size_t for strlen() variables.
---
 libgcc/libgcov-util.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index 6093a74531d..bf96f508db0 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -384,8 +384,8 @@ ftw_read_file (const char *filename,
                const struct stat *status ATTRIBUTE_UNUSED,
                int type)
 {
-  int filename_len;
-  int suffix_len;
+  size_t filename_len;
+  size_t suffix_len;
 
   /* Only read regular files.  */
   if (type != FTW_F)
-- 
2.34.1


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

* [gcov v2 11/14] gcov: Record EOF error during read
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (9 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 10/14] gcov: Fix integer types in ftw_read_file() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-05-02  6:32   ` Martin Liška
  2022-04-25  7:09 ` [gcov v2 12/14] gcov-tool: Add merge-stream subcommand Sebastian Huber
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

Use an enum for file error codes.

gcc/

	* gcov-io.cc (gcov_file_error): New enum.
	(gcov_var): Use gcov_file_error enum for the error member.
	(gcov_open): Use GCOV_FILE_NO_ERROR.
	(gcov_close): Use GCOV_FILE_WRITE_ERROR.
	(gcov_write): Likewise.
	(gcov_write_unsigned): Likewise.
	(gcov_write_string): Likewise.
	(gcov_read_bytes): Set error code if EOF is reached.
	(gcov_read_counter): Use GCOV_FILE_COUNTER_OVERFLOW.
---
 gcc/gcov-io.cc | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/gcc/gcov-io.cc b/gcc/gcov-io.cc
index 7e1fb10b612..fdf745e6ce1 100644
--- a/gcc/gcov-io.cc
+++ b/gcc/gcov-io.cc
@@ -29,10 +29,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 static gcov_unsigned_t *gcov_read_words (void *buffer, unsigned);
 
+/* Indicates the last gcov file access error or that no error occurred
+   so far.  */
+enum gcov_file_error
+{
+  GCOV_FILE_COUNTER_OVERFLOW = -1,
+  GCOV_FILE_NO_ERROR = 0,
+  GCOV_FILE_WRITE_ERROR = 1,
+  GCOV_FILE_EOF = 2
+};
+
 struct gcov_var
 {
   FILE *file;
-  int error;			/* < 0 overflow, > 0 disk error.  */
+  enum gcov_file_error error;
   int mode;			/* < 0 writing, > 0 reading.  */
   int endian;			/* Swap endianness.  */
 #ifdef IN_GCOV_TOOL
@@ -113,7 +123,7 @@ gcov_open (const char *name, int mode)
 #endif
 
   gcov_nonruntime_assert (!gcov_var.file);
-  gcov_var.error = 0;
+  gcov_var.error = GCOV_FILE_NO_ERROR;
 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL)
   gcov_var.endian = 0;
 #endif
@@ -217,7 +227,7 @@ gcov_close (void)
   if (gcov_var.file)
     {
       if (fclose (gcov_var.file))
-	gcov_var.error = 1;
+	gcov_var.error = GCOV_FILE_WRITE_ERROR;
 
       gcov_var.file = 0;
     }
@@ -253,7 +263,7 @@ 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;
+    gcov_var.error = GCOV_FILE_WRITE_ERROR;
 }
 
 /* Write unsigned VALUE to coverage file.  */
@@ -263,7 +273,7 @@ gcov_write_unsigned (gcov_unsigned_t value)
 {
   gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file);
   if (r != 1)
-    gcov_var.error = 1;
+    gcov_var.error = GCOV_FILE_WRITE_ERROR;
 }
 
 #if !IN_LIBGCOV
@@ -283,7 +293,7 @@ gcov_write_string (const char *string)
     {
       gcov_unsigned_t r = fwrite (string, length, 1, gcov_var.file);
       if (r != 1)
-	gcov_var.error = 1;
+	gcov_var.error = GCOV_FILE_WRITE_ERROR;
     }
 }
 #endif
@@ -385,7 +395,11 @@ gcov_read_bytes (void *buffer, unsigned count)
 
   unsigned read = fread (buffer, count, 1, gcov_var.file);
   if (read != 1)
-    return NULL;
+    {
+      if (feof (gcov_var.file))
+	gcov_var.error = GCOV_FILE_EOF;
+      return NULL;
+    }
 
 #ifdef IN_GCOV_TOOL
   gcov_var.pos += count;
@@ -434,7 +448,7 @@ gcov_read_counter (void)
   if (sizeof (value) > sizeof (gcov_unsigned_t))
     value |= ((gcov_type) from_file (buffer[1])) << 32;
   else if (buffer[1])
-    gcov_var.error = -1;
+    gcov_var.error = GCOV_FILE_COUNTER_OVERFLOW;
 
   return value;
 }
-- 
2.34.1


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

* [gcov v2 12/14] gcov-tool: Add merge-stream subcommand
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (10 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 11/14] gcov: Record EOF error during read Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 13/14] gcov: Use xstrerror() Sebastian Huber
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

gcc/

	* doc/gcov-tool.texi: Document merge-stream subcommand.
	* doc/invoke.texi (fprofile-info-section): Mention merge-stream
	subcommand of gcov-tool.
	* gcov-tool.cc (gcov_profile_merge_stream): Declare.
	(print_merge_stream_usage_message): New.
	(merge_stream_usage): Likewise.
	(do_merge_stream): Likewise.
	(print_usage): Call print_merge_stream_usage_message().
	(main): Call do_merge_stream() to execute merge-stream subcommand.

libgcc/

	* libgcov-util.c (consume_stream): New.
	(get_target_profiles_for_merge): Likewise.
	(gcov_profile_merge_stream): Likewise.
---
 gcc/doc/gcov-tool.texi | 36 ++++++++++++++++
 gcc/doc/invoke.texi    |  5 +++
 gcc/gcov-tool.cc       | 76 +++++++++++++++++++++++++++++++++
 libgcc/libgcov-util.c  | 95 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 212 insertions(+)

diff --git a/gcc/doc/gcov-tool.texi b/gcc/doc/gcov-tool.texi
index d79dbc94a8c..77150836acc 100644
--- a/gcc/doc/gcov-tool.texi
+++ b/gcc/doc/gcov-tool.texi
@@ -52,6 +52,10 @@ Current gcov-tool supports the following functionalities:
 @item
 merge two sets of profiles with weights.
 
+@item
+read a stream of profiles with associated filenames and merge it with a set of
+profiles with weights.
+
 @item
 read one set of profile and rewrite profile contents. One can scale or
 normalize the count values.
@@ -64,6 +68,12 @@ Collect the profiles for different set of inputs, and use this tool to merge
 them. One can specify the weight to factor in the relative importance of
 each input.
 
+@item
+Collect profiles from target systems without a filesystem (freestanding
+environments).  Merge the collected profiles with associated profiles
+present on the host system.  One can specify the weight to factor in the
+relative importance of each input.
+
 @item
 Rewrite the profile after removing a subset of the gcda files, while maintaining
 the consistency of the summary and the histogram.
@@ -117,6 +127,10 @@ gcov-tool merge [merge-options] @var{directory1} @var{directory2}
      [@option{-v}|@option{--verbose}]
      [@option{-w}|@option{--weight} @var{w1,w2}]
 
+gcov-tool merge-stream [merge-stream-options] [@var{file}]
+     [@option{-v}|@option{--verbose}]
+     [@option{-w}|@option{--weight} @var{w1,w2}]
+
 gcov-tool rewrite [rewrite-options] @var{directory}
      [@option{-n}|@option{--normalize} @var{long_long_value}]
      [@option{-o}|@option{--output} @var{directory}]
@@ -169,6 +183,28 @@ Set the merge weights of the @var{directory1} and @var{directory2},
 respectively. The default weights are 1 for both.
 @end table
 
+@item merge-stream
+Collect profiles with associated filenames from a @emph{gcfn} and @emph{gcda}
+data stream.  Read the stream from the file specified by @var{file} or from
+@file{stdin}.  Merge the profiles with associated profiles in the host
+filesystem.  Apply the optional weights while merging profiles.
+
+For the generation of a @emph{gcfn} and @emph{gcda} data stream on the target
+system, please have a look at the @code{__gcov_filename_to_gcfn()} and
+@code{__gcov_info_to_gcda()} functions declared in @code{#include <gcov.h>}.
+@table @gcctabopt
+
+@item -v
+@itemx --verbose
+Set the verbose mode.
+
+@item -w @var{w1},@var{w2}
+@itemx --weight @var{w1},@var{w2}
+Set the merge weights of the profiles from the @emph{gcfn} and @emph{gcda} data
+stream and the associated profiles in the host filesystem, respectively.  The
+default weights are 1 for both.
+@end table
+
 @item rewrite
 Read the specified profile directory and rewrite to a new directory.
 @table @gcctabopt
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index af5495e75c6..cef0fa9f084 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -15537,6 +15537,11 @@ main (void)
 @}
 @end smallexample
 
+The @command{merge-stream} subcommand of @command{gcov-tool} may be used to
+deserialize the data stream generated by the @code{__gcov_filename_to_gcfn} and
+@code{__gcov_info_to_gcda} functions and merge the profile information into
+@file{.gcda} files on the host filesystem.
+
 @item -fprofile-note=@var{path}
 @opindex fprofile-note
 
diff --git a/gcc/gcov-tool.cc b/gcc/gcov-tool.cc
index d712715cf7e..ceb250143c8 100644
--- a/gcc/gcov-tool.cc
+++ b/gcc/gcov-tool.cc
@@ -42,6 +42,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 extern struct gcov_info *gcov_profile_merge (struct gcov_info*,
 					     struct gcov_info*, int, int);
+extern struct gcov_info *gcov_profile_merge_stream (const char *, int, int);
 extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
@@ -229,6 +230,78 @@ do_merge (int argc, char **argv)
   return profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
 }
 
+/* Usage message for profile merge-stream.  */
+
+static void
+print_merge_stream_usage_message (int error_p)
+{
+  FILE *file = error_p ? stderr : stdout;
+
+  fnotice (file, "  merge-stream [options] [<file>]       Merge coverage stream file (or stdin)\n"
+		 "                                        and coverage file contents\n");
+  fnotice (file, "    -v, --verbose                       Verbose mode\n");
+  fnotice (file, "    -w, --weight <w1,w2>                Set weights (float point values)\n");
+}
+
+static const struct option merge_stream_options[] =
+{
+  { "verbose",                no_argument,       NULL, 'v' },
+  { "weight",                 required_argument, NULL, 'w' },
+  { 0, 0, 0, 0 }
+};
+
+/* Print merge-stream usage and exit.  */
+
+static void ATTRIBUTE_NORETURN
+merge_stream_usage (void)
+{
+  fnotice (stderr, "Merge-stream subcomand usage:");
+  print_merge_stream_usage_message (true);
+  exit (FATAL_EXIT_CODE);
+}
+
+/* Driver for profile merge-stream sub-command.  */
+
+static int
+do_merge_stream (int argc, char **argv)
+{
+  int opt;
+  int w1 = 1, w2 = 1;
+  struct gcov_info *merged_profile;
+
+  optind = 0;
+  while ((opt = getopt_long (argc, argv, "vw:",
+			     merge_stream_options, NULL)) != -1)
+    {
+      switch (opt)
+	{
+	case 'v':
+	  verbose = true;
+	  gcov_set_verbose ();
+	  break;
+	case 'w':
+	  sscanf (optarg, "%d,%d", &w1, &w2);
+	  if (w1 < 0 || w2 < 0)
+	    fatal_error (input_location, "weights need to be non-negative");
+	  break;
+	default:
+	  merge_stream_usage ();
+	}
+    }
+
+  if (argc - optind > 1)
+    merge_stream_usage ();
+
+  merged_profile = gcov_profile_merge_stream (argv[optind], w1, w2);
+
+  if (merged_profile)
+    gcov_do_dump (merged_profile, 0, -1);
+  else if (verbose)
+    fnotice (stdout, "no profile files were merged\n");
+
+  return 0;
+}
+
 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
    counter value to N_VAL and scale others counters proportionally.
    Otherwise, multiply the all counters by SCALE.  */
@@ -505,6 +578,7 @@ print_usage (int error_p)
   fnotice (file, "  -h, --help                            Print this help, then exit\n");
   fnotice (file, "  -v, --version                         Print version number, then exit\n");
   print_merge_usage_message (error_p);
+  print_merge_stream_usage_message (error_p);
   print_rewrite_usage_message (error_p);
   print_overlap_usage_message (error_p);
   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
@@ -594,6 +668,8 @@ main (int argc, char **argv)
 
   if (!strcmp (sub_command, "merge"))
     return do_merge (argc - optind, argv + optind);
+  else if (!strcmp (sub_command, "merge-stream"))
+    return do_merge_stream (argc - optind, argv + optind);
   else if (!strcmp (sub_command, "rewrite"))
     return do_rewrite (argc - optind, argv + optind);
   else if (!strcmp (sub_command, "overlap"))
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index bf96f508db0..250dddd8e21 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -735,6 +735,101 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
   return tgt_profile;
 }
 
+/* Deserialize gcov_info objects and associated filenames from the file
+   specified by FILENAME to create a profile list.  When FILENAME is NULL, read
+   from stdin.  Return the profile list.  */
+
+struct gcov_info *
+deserialize_profiles (const char *filename)
+{
+  read_profile_dir_init ();
+
+  while (true)
+    {
+      unsigned version;
+      const char *filename_of_info;
+      struct gcov_info *obj_info;
+
+      if (!gcov_magic (gcov_read_unsigned (), GCOV_FILENAME_MAGIC))
+	{
+	  if (gcov_is_error () != 2)
+	    fnotice (stderr, "%s:not a gcfn stream\n", filename);
+	  break;
+	}
+
+      version = gcov_read_unsigned ();
+      if (version != GCOV_VERSION)
+	{
+	  fnotice (stderr, "%s:incorrect gcov version %d vs %d \n",
+		   filename, version, GCOV_VERSION);
+	  break;
+	}
+
+      filename_of_info = gcov_read_string ();
+      if (!filename_of_info)
+	{
+	  fnotice (stderr, "%s:no filename in gcfn stream\n",
+		   filename);
+	  break;
+	}
+
+      obj_info = read_gcda_file (filename);
+      if (!obj_info)
+	break;
+
+      obj_info->filename = filename_of_info;
+    }
+
+  return gcov_info_head;
+}
+
+/* For each profile of the list specified by SRC_PROFILE, read the GCDA file of
+   the profile.  If a GCDA file exists, add the profile to a list.  Return the
+   profile list.  */
+
+struct gcov_info *
+get_target_profiles_for_merge (struct gcov_info *src_profile)
+{
+  struct gcov_info *gi_ptr;
+
+  read_profile_dir_init ();
+
+  for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
+    if (gcov_open (gi_ptr->filename, 1))
+      {
+	(void)read_gcda_file (gi_ptr->filename);
+	gcov_close ();
+      }
+
+  return gcov_info_head;
+}
+
+/* Deserialize gcov_info objects and associated filenames from the file
+   specified by FILENAME to create a source profile list.  When FILENAME is
+   NULL, read from stdin.  Use the filenames of the source profile list to get
+   a target profile list.  Merge the source profile list into the target
+   profile list using weights W1 and W2.  Return the list of merged gcov_info
+   objects.  Return NULL if the list is empty.  */
+
+struct gcov_info *
+gcov_profile_merge_stream (const char *filename, int w1, int w2)
+{
+  struct gcov_info *tgt_profile;
+  struct gcov_info *src_profile;
+
+  if (!gcov_open (filename, 1))
+    {
+      fnotice (stderr, "%s:cannot open\n", filename);
+      return NULL;
+    }
+
+  src_profile = deserialize_profiles (filename ? filename : "<stdin>");
+  gcov_close ();
+  tgt_profile = get_target_profiles_for_merge (src_profile);
+
+  return gcov_profile_merge (tgt_profile, src_profile, w1, w2);
+}
+
 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
 
 /* Performing FN upon arc counters.  */
-- 
2.34.1


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

* [gcov v2 13/14] gcov: Use xstrerror()
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (11 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 12/14] gcov-tool: Add merge-stream subcommand Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-25  7:09 ` [gcov v2 14/14] gcov: Add section for freestanding environments Sebastian Huber
  2022-04-26 13:54 ` [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Martin Liška
  14 siblings, 0 replies; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

libgcc/

	* libgcov-util.c (ftw_read_file): Improve notice using xstrerror().
	(gcov_profile_merge_stream): Likewise.
---
 libgcc/libgcov-util.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index 250dddd8e21..ba4670b3c0d 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -405,7 +405,7 @@ ftw_read_file (const char *filename,
 
   if (!gcov_open (filename, 1))
     {
-      fnotice (stderr, "%s:cannot open\n", filename);
+      fnotice (stderr, "%s:cannot open:%s\n", filename, xstrerror (errno));
       return 0;
     }
 
@@ -819,7 +819,7 @@ gcov_profile_merge_stream (const char *filename, int w1, int w2)
 
   if (!gcov_open (filename, 1))
     {
-      fnotice (stderr, "%s:cannot open\n", filename);
+      fnotice (stderr, "%s:cannot open:%s\n", filename, xstrerror (errno));
       return NULL;
     }
 
-- 
2.34.1


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

* [gcov v2 14/14] gcov: Add section for freestanding environments
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (12 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 13/14] gcov: Use xstrerror() Sebastian Huber
@ 2022-04-25  7:09 ` Sebastian Huber
  2022-04-26 13:53   ` Martin Liška
  2022-04-26 13:54 ` [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Martin Liška
  14 siblings, 1 reply; 20+ messages in thread
From: Sebastian Huber @ 2022-04-25  7:09 UTC (permalink / raw)
  To: gcc-patches

gcc/

	* doc/gcov.texi (Profiling and Test Coverage in Freestanding
	Environments): New section.
---
 gcc/doc/gcov.texi | 375 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 375 insertions(+)

diff --git a/gcc/doc/gcov.texi b/gcc/doc/gcov.texi
index fc39da0f02d..751a11314f3 100644
--- a/gcc/doc/gcov.texi
+++ b/gcc/doc/gcov.texi
@@ -41,6 +41,8 @@ test code coverage in your programs.
 * Gcov and Optimization::       Using gcov with GCC optimization.
 * Gcov Data Files::             The files used by gcov.
 * Cross-profiling::             Data file relocation.
+* Freestanding Environments::   How to use profiling and test
+                                coverage in freestanding environments.
 @end menu
 
 @node Gcov Intro
@@ -971,3 +973,376 @@ setting will name the data file @file{/target/run/build/foo.gcda}.
 You must move the data files to the expected directory tree in order to
 use them for profile directed optimizations (@option{-fprofile-use}), or to
 use the @command{gcov} tool.
+
+@node Freestanding Environments
+@section Profiling and Test Coverage in Freestanding Environments
+
+In case your application runs in a hosted environment such as GNU/Linux, then
+this section is likely not relevant to you.  This section is intended for
+application developers targeting freestanding environments (for example
+embedded systems) with limited resources.  In particular, systems or test cases
+which do not support constructors/destructors or the C library file I/O.  In
+this section, the @dfn{target system} runs your application instrumented for
+profiling or test coverage.  You develop and analyze your application on the
+@dfn{host system}.  We give now an overview how profiling and test coverage can
+be obtained in this scenario followed by a tutorial which can be exercised on
+the host system.  Finally, some system initialization caveats are listed.
+
+@subsection Overview
+
+For an application instrumented for profiling or test coverage, the compiler
+generates some global data structures which are updated by instrumentation code
+while the application runs.  These data structures are called the @dfn{gcov
+information}.  Normally, when the application exits, the gcov information is
+stored to @file{.gcda} files.  There is one file per translation unit
+instrumented for profiling or test coverage.  The function
+@code{__gcov_exit()}, which stores the gcov information to a file, is called by
+a global destructor function for each translation unit instrumented for
+profiling or test coverage.  It runs at process exit.  In a global constructor
+function, the @code{__gcov_init()} function is called to register the gcov
+information of a translation unit in a global list.  In some situations, this
+procedure does not work.  Firstly, if you want to profile the global
+constructor or exit processing of an operating system, the compiler generated
+functions may conflict with the test objectives.  Secondly, you may want to
+test early parts of the system initialization or abnormal program behaviour
+which do not allow a global constructor or exit processing.  Thirdly, you need
+a filesystem to store the files.
+
+The @option{-fprofile-info-section} GCC option enables you to use profiling and
+test coverage in freestanding environments.  This option disables the use of
+global constructors and destructors for the gcov information.  Instead, a
+pointer to the gcov information is stored in a special linker input section for
+each translation unit which is compiled with this option.  By default, the
+section name is @code{.gcov_info}.  The gcov information is statically
+initialized.  The pointers to the gcov information from all translation units
+of an executable can be collected by the linker in a continuous memory block.
+For the GNU linker, the below linker script output section definition can be
+used to achieve this:
+
+@smallexample
+  .gcov_info      :
+  @{
+    PROVIDE (__gcov_info_start = .);
+    KEEP (*(.gcov_info))
+    PROVIDE (__gcov_info_end = .);
+  @}
+@end smallexample
+
+The linker will provide two global symbols, @code{__gcov_info_start} and
+@code{__gcov_info_end}, which define the start and end of the array of pointers
+to gcov information blocks, respectively.  The @code{KEEP ()} directive is
+required to prevent a garbage collection of the pointers.  They are not
+directly referenced by anything in the executable.  The section may be placed
+in a read-only memory area.
+
+In order to transfer the profiling and test coverage data from the target to
+the host system, the application has to provide a function to produce a
+reliable in order byte stream from the target to the host.  The byte stream may
+be compressed and encoded using error detection and correction codes to meet
+application-specific requirements.  The GCC provided @file{libgcov} target
+library provides two functions, @code{__gcov_info_to_gcda()} and
+@code{__gcov_filename_to_gcfn()}, to generate a byte stream from a gcov
+information bock.  The functions are declared in @code{#include <gcov.h>}.  The
+byte stream can be deserialized by the @command{merge-stream} subcommand of the
+@command{gcov-tool} to create or update @file{.gcda} files in the host
+filesystem for the instrumented application. 
+
+@subsection Tutorial
+
+This tutorial should be exercised on the host system.  We will build a program
+instrumented for test coverage.  The program runs an application and dumps the
+gcov information to @file{stderr} encoded as a printable character stream.  The
+application simply decodes such character streams from @file{stdin} and writes
+the decoded character stream to @file{stdout} (warning: this is binary data).
+The decoded character stream is consumed by the @command{merge-stream}
+subcommand of the @command{gcov-tool} to create or update the @file{.gcda}
+files.
+
+To get started, create an empty directory.  Change into the new directory.
+Create a header file @file{app.h} with the following content:
+
+@smallexample
+static const unsigned char a = 'a';
+
+static inline unsigned char *
+encode (unsigned char c, unsigned char buf[2])
+@{
+  buf[0] = c % 16 + a;
+  buf[1] = (c / 16) % 16 + a;
+  return buf;
+@}
+
+extern void application (void);
+@end smallexample
+
+Create a source file @file{app.c} with the following content:
+
+@smallexample
+#include "app.h"
+
+#include <stdio.h>
+
+/* The application reads a character stream encoded by encode() from stdin,
+   decodes it, and writes the decoded characters to stdout.  Characters other
+   than the 16 characters 'a' to 'p' are ignored.  */
+
+static int can_decode (unsigned char c)
+@{
+  return (unsigned char)(c - a) < 16;
+@}
+
+void
+application (void)
+@{
+  int first = 1;
+  int i;
+  unsigned char c;
+
+  while ((i = fgetc (stdin)) != EOF)
+    @{
+      unsigned char x = (unsigned char)i;
+
+      if (can_decode (x))
+        @{
+          if (first)
+            c = x - a;
+          else
+            fputc (c + 16 * (x - a), stdout);
+          first = !first;
+        @}
+      else
+        first = 1;
+    @}
+@}
+@end smallexample
+
+Create a source file @file{main.c} with the following content:
+
+@smallexample
+#include "app.h"
+
+#include <gcov.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* The start and end symbols are provided by the linker script.  We use the
+   array notation to avoid issues with a potential small-data area.  */
+
+extern const struct gcov_info *const __gcov_info_start[];
+extern const struct gcov_info *const __gcov_info_end[];
+
+/* This function shall produce a reliable in order byte stream to transfer the
+   gcov information from the target to the host system.  */
+
+static void
+dump (const void *d, unsigned n, void *arg)
+@{
+  (void)arg;
+  const unsigned char *c = d;
+  unsigned char buf[2];
+
+  for (unsigned i = 0; i < n; ++i)
+    fwrite (encode (c[i], buf), sizeof (buf), 1, stderr);
+@}
+
+/* The filename is serialized to a gcfn data stream by the
+   __gcov_filename_to_gcfn() function.  The gcfn data is used by the
+   "merge-stream" subcommand of the "gcov-tool" to figure out the filename
+   associated with the gcov information. */
+
+static void
+filename (const char *f, void *arg)
+@{
+  __gcov_filename_to_gcfn (f, dump, arg);
+@}
+
+/* The __gcov_info_to_gcda() function may have to allocate memory under
+   certain conditions.  Simply try it out if it is needed for your application
+   or not.  */
+
+static void *
+allocate (unsigned length, void *arg)
+@{
+  (void)arg;
+  return malloc (length);
+@}
+
+/* Dump the gcov information of all translation units.  */
+
+static void
+dump_gcov_info (void)
+@{
+  const struct gcov_info *const *info = __gcov_info_start;
+  const struct gcov_info *const *end = __gcov_info_end;
+
+  /* Obfuscate variable to prevent compiler optimizations.  */
+  __asm__ ("" : "+r" (info));
+
+  while (info != end)
+  @{
+    void *arg = NULL;
+    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
+    fputc ('\n', stderr);
+    ++info;
+  @}
+@}
+
+/* The main() function just runs the application and then dumps the gcov
+   information to stderr.  */
+
+int
+main (void)
+@{
+  application ();
+  dump_gcov_info ();
+  return 0;
+@}
+@end smallexample
+
+If we compile @file{app.c} with test coverage and no extra profiling options,
+then a global constructor (@code{_sub_I_00100_0} here, it may have a different
+name in your environment) and destructor (@code{_sub_D_00100_1}) is used to
+dump the gcov information.  We also see undefined references to
+@code{__gcov_init} and @code{__gcov_exit}:
+
+@smallexample
+$ gcc -ftest-coverage -fprofile-arcs -c app.c
+$ nm app.o
+0000000000000000 r a
+0000000000000030 T application
+0000000000000000 t can_decode
+                 U fgetc
+                 U fputc
+0000000000000000 b __gcov0.application
+0000000000000038 b __gcov0.can_decode
+0000000000000000 d __gcov_.application
+00000000000000c0 d __gcov_.can_decode
+                 U __gcov_exit
+                 U __gcov_init
+                 U __gcov_merge_add
+                 U stdin
+                 U stdout
+0000000000000161 t _sub_D_00100_1
+0000000000000151 t _sub_I_00100_0
+@end smallexample
+
+Compile @file{app.c} and @file{main.c} with test coverage and
+@option{-fprofile-info-section}.  Now, a read-only pointer size object is
+present in the @code{.gcov_info} section and there are no undefined references
+to @code{__gcov_init} and @code{__gcov_exit}:
+
+@smallexample
+$ gcc -ftest-coverage -fprofile-arcs -fprofile-info-section -c main.c
+$ gcc -ftest-coverage -fprofile-arcs -fprofile-info-section -c app.c
+$ objdump -h app.o 
+
+app.o:     file format elf64-x86-64
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+  0 .text         00000151  0000000000000000  0000000000000000  00000040  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+  1 .data         00000100  0000000000000000  0000000000000000  000001a0  2**5
+                  CONTENTS, ALLOC, LOAD, RELOC, DATA
+  2 .bss          00000040  0000000000000000  0000000000000000  000002a0  2**5
+                  ALLOC
+  3 .rodata       0000003c  0000000000000000  0000000000000000  000002a0  2**3
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+  4 .gcov_info    00000008  0000000000000000  0000000000000000  000002e0  2**3
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+  5 .comment      0000004e  0000000000000000  0000000000000000  000002e8  2**0
+                  CONTENTS, READONLY
+  6 .note.GNU-stack 00000000  0000000000000000  0000000000000000  00000336  2**0
+                  CONTENTS, READONLY
+  7 .eh_frame     00000058  0000000000000000  0000000000000000  00000338  2**3
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+@end smallexample
+
+We have to customize the program link process so that all the @code{.gcov_info}
+linker input sections are placed in a continuous memory block with a begin and
+end symbol.  Firstly, get the default linker script using the following
+commands (we assume a GNU linker):
+
+@smallexample
+$ ld --verbose | sed '1,/^===/d' | sed '/^===/d' > linkcmds
+@end smallexample
+
+Secondly, open the file @file{linkcmds} with a text editor and place the linker
+output section definition from the overview after the @code{.rodata} section
+definition.  Link the program executable using the customized linker script:
+
+@smallexample
+$ gcc main.o app.o -T linkcmds -lgcov -Wl,-Map,app.map
+@end smallexample
+
+In the linker map file @file{app.map}, we see that the linker placed the
+read-only pointer size objects of our objects files @file{main.o} and
+@file{app.o} into a continuous memory block and provided the symbols
+@code{__gcov_info_start} and @code{__gcov_info_end}:
+
+@smallexample
+$ grep -C 1 "\.gcov_info" app.map
+
+.gcov_info      0x0000000000403ac0       0x10
+                0x0000000000403ac0                PROVIDE (__gcov_info_start = .)
+ *(.gcov_info)
+ .gcov_info     0x0000000000403ac0        0x8 main.o
+ .gcov_info     0x0000000000403ac8        0x8 app.o
+                0x0000000000403ad0                PROVIDE (__gcov_info_end = .)
+@end smallexample
+
+Make sure no @file{.gcda} files are present.  Run the program with nothing to
+decode and dump @file{stderr} to the file @file{gcda-0.txt} (first run).  Run
+the program to decode @file{gcda-0.txt} and send it to the @command{gcov-tool}
+using the @command{merge-stream} subcommand to create the @file{.gcda} files
+(second run).  Run @command{gcov} to produce a report for @file{app.c}.  We see
+that the first run with nothing to decode resulted in a partially covered
+application:
+
+@smallexample
+$ rm -f app.gcda main.gcda
+$ echo "" | ./a.out 2>gcda-0.txt
+$ ./a.out <gcda-0.txt 2>gcda-1.txt | gcov-tool merge-stream
+$ gcov -bc app.c
+File 'app.c'
+Lines executed:69.23% of 13
+Branches executed:66.67% of 6
+Taken at least once:50.00% of 6
+Calls executed:66.67% of 3
+Creating 'app.c.gcov'
+
+Lines executed:69.23% of 13
+@end smallexample
+
+Run the program to decode @file{gcda-1.txt} and send it to the
+@command{gcov-tool} using the @command{merge-stream} subcommand to update the
+@file{.gcda} files.  Run @command{gcov} to produce a report for @file{app.c}.
+Since the second run decoded the gcov information of the first run, we have now
+a fully covered application:
+
+@smallexample
+$ ./a.out <gcda-1.txt 2>gcda-2.txt | gcov-tool merge-stream
+$ gcov -bc app.c
+File 'app.c'
+Lines executed:100.00% of 13
+Branches executed:100.00% of 6
+Taken at least once:100.00% of 6
+Calls executed:100.00% of 3
+Creating 'app.c.gcov'
+
+Lines executed:100.00% of 13
+@end smallexample
+
+@subsection System Initialization Caveats
+
+The gcov information of a translation unit consists of several global data
+structures.  For example, the instrumented code may update program flow graph
+edge counters in a zero-initialized data structure.  It is safe to run
+instrumented code before the zero-initialized data is cleared to zero.  The
+coverage information obtained before the zero-initialized data is cleared to
+zero is unusable.  Dumping the gcov information using
+@code{__gcov_info_to_gcda()} before the zero-initialized data is cleared to
+zero or the initialized data is loaded, is undefined behaviour.  Clearing the
+zero-initialized data to zero through a function instrumented for profiling or
+test coverage is undefined behaviour, since it may produce inconsistent program
+flow graph edge counters for example.
-- 
2.34.1


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

* Re: [gcov v2 14/14] gcov: Add section for freestanding environments
  2022-04-25  7:09 ` [gcov v2 14/14] gcov: Add section for freestanding environments Sebastian Huber
@ 2022-04-26 13:53   ` Martin Liška
  2022-04-26 17:49     ` Sebastian Huber
  0 siblings, 1 reply; 20+ messages in thread
From: Martin Liška @ 2022-04-26 13:53 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

Hi.

This if fine, except 2 places where you have trailing whitespace
at the end of a line.

Martin

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

* Re: [gcov v2 00/14] Add merge-stream subcommand to gcov-tool
  2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
                   ` (13 preceding siblings ...)
  2022-04-25  7:09 ` [gcov v2 14/14] gcov: Add section for freestanding environments Sebastian Huber
@ 2022-04-26 13:54 ` Martin Liška
  14 siblings, 0 replies; 20+ messages in thread
From: Martin Liška @ 2022-04-26 13:54 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 4/25/22 09:09, Sebastian Huber wrote:
> This patch set is for GCC 13.
> 
> The aim is to better support gcov in free-standing environments. For example,
> you can run a test executable which dumps all gcov info objects in a serial
> data stream using __gcov_info_to_gcda() and the new __gcov_filename_to_gcfn().
> It could be encoded as base64. It could be also compressed. On the host you
> unpack the encoded data stream and feed it into gcov-tool using the new
> "merge-stream" subcommand:
> 
> gcov-tool --help
> Usage: gcov-tool [OPTION]... SUB_COMMAND [OPTION]...
> 
> Offline tool to handle gcda counts
> 
>   -h, --help                            Print this help, then exit
>   -v, --version                         Print version number, then exit
>   merge-stream [options] [stream-file]  Merge coverage stream file (or stdin)
>                                         and coverage file contents
>     -v, --verbose                       Verbose mode
>     -w, --weight <w1,w2>                Set weights (float point values)
> 
> Example:
> 
> base64 -d log.txt | gcov-tool merge-stream
> 
> The patch set does not change the format of .gcda files.
> 
> TODO:
> 
> * Tests for gcov-tool
> 
> v2:
> 
> * Address review comments from v1
> 
> * Simple test for __gcov_filename_to_gcfn()
> 
> * Use xstrerror()
> 
> * Add documentation

Hi.

Thank you for it. Please install the patch set once Stage 1 opens.

Cheers,
Martin

> 
> Sebastian Huber (14):
>   gcov-tool: Allow merging of empty profile lists
>   gcov: Add mode to all gcov_open()
>   gcov: Add open mode parameter to gcov_do_dump()
>   gcov: Make gcov_seek() static
>   gcov: Add __gcov_filename_to_gcfn()
>   gcov-tool: Support file input from stdin
>   gcov: Use xstrdup()
>   gcov: Move prepend to list to read_gcda_file()
>   gcov: Move gcov_open() to caller of read_gcda_file()
>   gcov: Fix integer types in ftw_read_file()
>   gcov: Record EOF error during read
>   gcov-tool: Add merge-stream subcommand
>   gcov: Use xstrerror()
>   gcov: Add section for freestanding environments
> 
>  gcc/doc/gcov-tool.texi                   |  36 +++
>  gcc/doc/gcov.texi                        | 375 +++++++++++++++++++++++
>  gcc/doc/invoke.texi                      |  31 +-
>  gcc/gcov-io.cc                           |  79 +++--
>  gcc/gcov-io.h                            |  35 ++-
>  gcc/gcov-tool.cc                         | 107 +++++--
>  gcc/testsuite/gcc.dg/gcov-info-to-gcda.c |  36 ++-
>  libgcc/gcov.h                            |  17 +-
>  libgcc/libgcov-driver-system.c           |   7 +-
>  libgcc/libgcov-driver.c                  |  44 ++-
>  libgcc/libgcov-util.c                    | 150 +++++++--
>  libgcc/libgcov.h                         |   3 -
>  12 files changed, 803 insertions(+), 117 deletions(-)
> 


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

* Re: [gcov v2 14/14] gcov: Add section for freestanding environments
  2022-04-26 13:53   ` Martin Liška
@ 2022-04-26 17:49     ` Sebastian Huber
  2022-04-27  8:16       ` Martin Liška
  0 siblings, 1 reply; 20+ messages in thread
From: Sebastian Huber @ 2022-04-26 17:49 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

On 26.04.22 15:53, Martin Liška wrote:
> This if fine, except 2 places where you have trailing whitespace
> at the end of a line.

Thanks for the review.

Should I use "-ftest-coverage -fprofile-arcs" or "--coverage" in the 
tutorial?

-- 
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] 20+ messages in thread

* Re: [gcov v2 14/14] gcov: Add section for freestanding environments
  2022-04-26 17:49     ` Sebastian Huber
@ 2022-04-27  8:16       ` Martin Liška
  0 siblings, 0 replies; 20+ messages in thread
From: Martin Liška @ 2022-04-27  8:16 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

On 4/26/22 19:49, Sebastian Huber wrote:
> Should I use "-ftest-coverage -fprofile-arcs" or "--coverage" in the tutorial?

The later one, please.

Cheers,
Martin

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

* Re: [gcov v2 11/14] gcov: Record EOF error during read
  2022-04-25  7:09 ` [gcov v2 11/14] gcov: Record EOF error during read Sebastian Huber
@ 2022-05-02  6:32   ` Martin Liška
  0 siblings, 0 replies; 20+ messages in thread
From: Martin Liška @ 2022-05-02  6:32 UTC (permalink / raw)
  To: Sebastian Huber, gcc-patches

> @@ -385,7 +395,11 @@ gcov_read_bytes (void *buffer, unsigned count)
>  
>    unsigned read = fread (buffer, count, 1, gcov_var.file);
>    if (read != 1)
> -    return NULL;
> +    {
> +      if (feof (gcov_var.file))
> +	gcov_var.error = GCOV_FILE_EOF;
> +      return NULL;
> +    }

Hello.

This hunk is causing troubles when we instrument a binary and it's the first
time we dump to it.

See:

gcc --coverage main.c && ./a.out
libgcov profiling error:/home/marxin/Programming/testcases/a-main.gcda:Error writing

Can you please fix it?
Thanks,
Martin

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

end of thread, other threads:[~2022-05-02  6:32 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-25  7:09 [gcov v2 00/14] Add merge-stream subcommand to gcov-tool Sebastian Huber
2022-04-25  7:09 ` [gcov v2 01/14] gcov-tool: Allow merging of empty profile lists Sebastian Huber
2022-04-25  7:09 ` [gcov v2 02/14] gcov: Add mode to all gcov_open() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 03/14] gcov: Add open mode parameter to gcov_do_dump() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 04/14] gcov: Make gcov_seek() static Sebastian Huber
2022-04-25  7:09 ` [gcov v2 05/14] gcov: Add __gcov_filename_to_gcfn() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 06/14] gcov-tool: Support file input from stdin Sebastian Huber
2022-04-25  7:09 ` [gcov v2 07/14] gcov: Use xstrdup() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 08/14] gcov: Move prepend to list to read_gcda_file() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 09/14] gcov: Move gcov_open() to caller of read_gcda_file() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 10/14] gcov: Fix integer types in ftw_read_file() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 11/14] gcov: Record EOF error during read Sebastian Huber
2022-05-02  6:32   ` Martin Liška
2022-04-25  7:09 ` [gcov v2 12/14] gcov-tool: Add merge-stream subcommand Sebastian Huber
2022-04-25  7:09 ` [gcov v2 13/14] gcov: Use xstrerror() Sebastian Huber
2022-04-25  7:09 ` [gcov v2 14/14] gcov: Add section for freestanding environments Sebastian Huber
2022-04-26 13:53   ` Martin Liška
2022-04-26 17:49     ` Sebastian Huber
2022-04-27  8:16       ` Martin Liška
2022-04-26 13:54 ` [gcov v2 00/14] Add merge-stream subcommand to gcov-tool 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).