From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dedi548.your-server.de (dedi548.your-server.de [85.10.215.148]) by sourceware.org (Postfix) with ESMTPS id A618139A5423 for ; Fri, 23 Jul 2021 09:39:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A618139A5423 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embedded-brains.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embedded-brains.de Received: from sslproxy02.your-server.de ([78.47.166.47]) by dedi548.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1m6reG-00068x-AF; Fri, 23 Jul 2021 11:39:16 +0200 Received: from [82.100.198.138] (helo=mail.embedded-brains.de) by sslproxy02.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1m6reG-0003i7-6k; Fri, 23 Jul 2021 11:39:16 +0200 Received: from localhost (localhost.localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id D60682A1610; Fri, 23 Jul 2021 11:39:15 +0200 (CEST) Received: from mail.embedded-brains.de ([127.0.0.1]) by localhost (zimbra.eb.localhost [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id 2Ku7D4z_NlfI; Fri, 23 Jul 2021 11:39:14 +0200 (CEST) Received: from localhost (localhost.localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id 9B39A2A165B; Fri, 23 Jul 2021 11:39:14 +0200 (CEST) X-Virus-Scanned: amavisd-new at zimbra.eb.localhost Received: from mail.embedded-brains.de ([127.0.0.1]) by localhost (zimbra.eb.localhost [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id AsV-_hZjtpwC; Fri, 23 Jul 2021 11:39:14 +0200 (CEST) Received: from zimbra.eb.localhost (unknown [192.168.96.242]) by mail.embedded-brains.de (Postfix) with ESMTPSA id 72B392A1610; Fri, 23 Jul 2021 11:39:14 +0200 (CEST) From: Sebastian Huber To: gcc-patches@gcc.gnu.org Subject: [PATCH v3] gcov: Add __gcov_info_to_gdca() Date: Fri, 23 Jul 2021 11:39:11 +0200 Message-Id: <20210723093911.81759-1-sebastian.huber@embedded-brains.de> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Sender: smtp-embedded@poldinet.de X-Virus-Scanned: Clear (ClamAV 0.103.2/26241/Fri Jul 23 10:20:30 2021) X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Jul 2021 09:39:20 -0000 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 com= pile it): #include #include #include 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 =3D d; for (unsigned i =3D 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, 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 defi= ne intptr_t somehow. The patch removes one use of memset() which makes the 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 ): New. (#include ): 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 usi= ng a constructor/destructor. The section name is @var{name} if it is specifi= ed, 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 registra= tion -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 resourc= es -which do not support constructors and destructors. The linker could col= lect -the input sections in a continuous memory block and define start and end -symbols. The runtime support could dump the profiling information regis= tered -in this linker set during program termination to a serial line for examp= le. A -GNU linker script example which defines a linker output section follows: +profile information generated by @option{-fprofile-arcs} is placed in th= e +specified section for each translation unit. This option disables the p= rofile +information registration through a constructor and it disables the profi= le +information processing through a destructor. This option is not intende= d 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: =20 @smallexample .gcov_info : @@ -14819,6 +14819,64 @@ GNU linker script example which defines a linker= output section follows: @} @end smallexample =20 +The program could dump the profiling information registered in this link= er set +for example like this: + +@smallexample +#include +#include +#include + +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 =3D d; + + for (unsigned i =3D 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 =3D __gcov_info_start; + const struct gcov_info **end =3D __gcov_info_end; + + /* Obfuscate variable to prevent compiler optimizations. */ + __asm__ ("" : "+r" (end)); + + while (info !=3D end) + @{ + void *arg =3D 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=3D@var{path} @opindex fprofile-note =20 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 =20 #if !IN_GCOV -/* Write unsigned VALUE to coverage file. */ +/* Write DATA of LENGTH characters to coverage file. */ =20 GCOV_LINKAGE void -gcov_write_unsigned (gcov_unsigned_t value) +gcov_write (const void *data, unsigned length) { - gcov_unsigned_t r =3D fwrite (&value, sizeof (value), 1, gcov_var.file= ); + gcov_unsigned_t r =3D fwrite (data, length, 1, gcov_var.file); if (r !=3D 1) gcov_var.error =3D 1; } =20 -/* Write counter VALUE to coverage file. Sets error flag - appropriately. */ +/* Write unsigned VALUE to coverage file. */ =20 -#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 =3D fwrite (&value, sizeof (value), 1, gcov_var.file= ); + if (r !=3D 1) + gcov_var.error =3D 1; } -#endif /* IN_LIBGCOV */ =20 #if !IN_LIBGCOV /* Write STRING to coverage file. Sets error flag on file @@ -347,22 +342,13 @@ gcov_write_length (gcov_position_t position) =20 #else /* IN_LIBGCOV */ =20 -/* 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. */ =20 GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summ= ary) { - 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); =20 #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 =20 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 =3D=3D &counter); + assert (__builtin_strstr (f, "gcov-info-to-gcda.c") =3D=3D 0); +} + +static void +dump (const void *d, unsigned n, void *arg) +{ + unsigned *m =3D (unsigned *)arg; + assert (arg =3D=3D &counter); + + if (*m =3D=3D 0) + { + const unsigned *u =3D d; + assert (*u =3D=3D 0x67636461); + } + + *m +=3D n; +} + +static void * +allocate (unsigned length, void *arg) +{ + assert (arg =3D=3D &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 =3D _gcov_dump _gcov_fork \ _gcov_execl _gcov_execlp \ _gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset \ _gcov_lock_unlock -LIBGCOV_DRIVER =3D _gcov +LIBGCOV_DRIVER =3D _gcov _gcov_info_to_gcda =20 libgcov-merge-objects =3D $(patsubst %,%$(objext),$(LIBGCOV_MERGE)) libgcov-profiler-objects =3D $(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 =20 +struct gcov_info; + /* Set all counters to zero. */ =20 extern void __gcov_reset (void); @@ -33,4 +35,21 @@ extern void __gcov_reset (void); =20 extern void __gcov_dump (void); =20 +/* Convert the gcov information referenced by INFO to a gcda data stream= . + The FILENAME_FN callback is called exactly once with the filename ass= ociated + with the gcov information. The filename may be NULL. Afterwards, th= e + DUMP_FN callback is subsequently called with chunks (the begin and le= ngth of + the chunk are passed as the first two callback parameters) of the gcd= a data + stream. The ALLOCATE_FN callback shall allocate memory with a size i= n + characters specified by the first callback parameter. The ARG parame= ter 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 respectivel= y. If not, see #include "libgcov.h" #include "gcov-io.h" =20 +#include + +/* 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 =3D 0; i < ci_ptr->num; i++) + if (ci_ptr->values[i] !=3D 0) + return 0; + + return 1; +} + #if defined(inhibit_libc) /* If libc and its header files are not available, provide dummy functio= ns. */ =20 @@ -35,8 +49,6 @@ void __gcov_init (struct gcov_info *p __attribute__ ((u= nused))) {} =20 #else /* inhibit_libc */ =20 -#include - #if GCOV_LOCKED #include #include @@ -51,8 +63,17 @@ void __gcov_init (struct gcov_info *p __attribute__ ((= unused))) {} #include #endif =20 -#ifdef L_gcov +#endif /* inhibit_libc */ + +#if defined(L_gcov) && !defined(inhibit_libc) +#define NEED_L_GCOV +#endif =20 +#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 *, ...); =20 @@ -343,6 +364,51 @@ read_error: return -1; } =20 +/* 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 memo= ry. */ + +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)) =20 /* 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 =3D n_counts / GCOV_TOPN_MEM_COUNTERS; gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS =3D=3D 0); @@ -365,46 +434,49 @@ write_topn_counters (const struct gcov_ctr_info *ci= _ptr, if (list_sizes =3D=3D NULL || counters > list_size_length) { list_size_length =3D MAX (LIST_SIZE_MIN_LENGTH, 2 * counters); -#if HAVE_SYS_MMAN_H +#if !defined(inhibit_libc) && HAVE_SYS_MMAN_H list_sizes =3D (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned)); #endif =20 /* Malloc fallback. */ if (list_sizes =3D=3D NULL) - list_sizes =3D (unsigned *)xmalloc (list_size_length * sizeof (unsigned= )); + list_sizes =3D + (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned), + arg); } =20 - memset (list_sizes, 0, counters * sizeof (unsigned)); unsigned pair_total =3D 0; =20 for (unsigned i =3D 0; i < counters; i++) { gcov_type start =3D ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]= ; + unsigned sizes =3D 0; + for (struct gcov_kvp *node =3D (struct gcov_kvp *)(intptr_t)start; node !=3D NULL; node =3D node->next) - { - ++pair_total; - ++list_sizes[i]; - } + ++sizes; + + pair_total +=3D sizes; + list_sizes[i] =3D sizes; } =20 unsigned disk_size =3D GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_t= otal; - 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); =20 for (unsigned i =3D 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 =3D ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]= ; =20 unsigned j =3D 0; for (struct gcov_kvp *node =3D (struct gcov_kvp *)(intptr_t)start; j < list_sizes[i]; node =3D 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, =20 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; =20 - 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); =20 +#ifdef NEED_L_GCOV /* Generate whole program statistics. */ gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p); +#else + (void)prg_p; +#endif =20 /* Write execution counts for each function. */ for (f_ix =3D 0; f_ix !=3D gi_ptr->n_functions; f_ix++) { +#ifdef NEED_L_GCOV unsigned buffered =3D 0; +#endif const struct gcov_fn_info *gfi_ptr; const struct gcov_ctr_info *ci_ptr; gcov_unsigned_t length; unsigned t_ix; =20 +#ifdef NEED_L_GCOV if (fn_buffer && fn_buffer->fn_ix =3D=3D f_ix) { /* Buffered data from another program. */ @@ -442,6 +525,7 @@ write_one_data (const struct gcov_info *gi_ptr, length =3D GCOV_TAG_FUNCTION_LENGTH; } else +#endif { gfi_ptr =3D gi_ptr->functions[f_ix]; if (gfi_ptr && gfi_ptr->key =3D=3D gi_ptr) @@ -450,13 +534,14 @@ write_one_data (const struct gcov_info *gi_ptr, length =3D 0; } =20 - 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; =20 - 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); =20 ci_ptr =3D gfi_ptr->ctrs; for (t_ix =3D 0; t_ix < GCOV_COUNTERS; t_ix++) @@ -469,39 +554,43 @@ write_one_data (const struct gcov_info *gi_ptr, n_counts =3D ci_ptr->num; =20 if (t_ix =3D=3D GCOV_COUNTER_V_TOPN || t_ix =3D=3D GCOV_COUNTER_V_IND= IR) - write_topn_counters (ci_ptr, t_ix, n_counts); + write_topn_counters (ci_ptr, + t_ix, + n_counts, + dump_fn, + allocate_fn, + arg); else { - /* Do not stream when all counters are zero. */ - int all_zeros =3D 1; - for (unsigned i =3D 0; i < n_counts; i++) - if (ci_ptr->values[i] !=3D 0) - { - all_zeros =3D 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); 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 =3D 0; i < n_counts; i++) - gcov_write_counter (ci_ptr->values[i]); + dump_counter (ci_ptr->values[i], dump_fn, arg); } } =20 ci_ptr++; } +#ifdef NEED_L_GCOV if (buffered) fn_buffer =3D free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); +#endif } =20 - gcov_write_unsigned (0); + dump_unsigned (0, dump_fn, arg); } +#endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */ =20 +#ifdef NEED_L_GCOV /* Dump the coverage counts for one gcov_info object. We merge with exis= ting 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 =3D gi_ptr->summary; #endif =20 - write_one_data (gi_ptr, &summary); + write_one_data (gi_ptr, + &summary, + gcov_dump_handler, + gcov_allocate_handler, + NULL); /* fall through */ =20 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 []) =20 /* 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; --=20 2.26.2