diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-11-14 13:51:09 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-08-06 07:28:26 +0200 |
commit | 9124bbe1857f0d3a3015d6461d5f8d04f07cab85 (patch) | |
tree | 7da449bf5bade4e861d82257bf12350cfa7a9dba /gcc | |
parent | a3d3e8c362c2d850543eb2e2631128e1efc368f0 (diff) | |
download | gcc-9124bbe1857f0d3a3015d6461d5f8d04f07cab85.zip gcc-9124bbe1857f0d3a3015d6461d5f8d04f07cab85.tar.gz gcc-9124bbe1857f0d3a3015d6461d5f8d04f07cab85.tar.bz2 |
gcov: Add __gcov_info_to_gdca()
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 -lgcov test.c" to compile
it):
#include <gcov.h>
#include <stdio.h>
#include <stdlib.h>
extern const struct gcov_info *my_info;
static void
filename (const char *f, void *arg)
{
printf("filename: %s\n", f);
}
static void
dump (const void *d, unsigned n, void *arg)
{
const unsigned char *c = d;
for (unsigned i = 0; i < n; ++i)
printf ("%02x", c[i]);
}
static void *
allocate (unsigned length, void *arg)
{
return malloc (length);
}
int main()
{
__asm__ volatile (".set my_info, .LPBX2");
__gcov_info_to_gcda (my_info, filename, dump, allocate, NULL);
return 0;
}
With this patch, <stdint.h> is included in libgcov-driver.c even if
inhibit_libc is defined. This header file should be also available for
freestanding environments. If this is not the case, then we have to define
intptr_t somehow.
The patch removes one use of memset() which makes the <string.h> include
superfluous.
gcc/
* gcov-io.h (gcov_write): Declare.
* gcov-io.c (gcov_write): New.
(gcov_write_counter): Remove.
(gcov_write_tag_length): Likewise.
(gcov_write_summary): Replace gcov_write_tag_length() with calls to
gcov_write_unsigned().
* doc/invoke.texi (fprofile-info-section): Mention
__gcov_info_to_gdca().
gcc/testsuite/
* gcc.dg/gcov-info-to-gcda.c: New test.
libgcc/
* Makefile.in (LIBGCOV_DRIVER): Add _gcov_info_to_gcda.
* gcov.h (gcov_info): Declare.
(__gcov_info_to_gdca): Likewise.
* libgcov.h (gcov_write_counter): Remove.
(gcov_write_tag_length): Likewise.
* libgcov-driver.c (#include <stdint.h>): New.
(#include <string.h>): Remove.
(NEED_L_GCOV): Conditionally define.
(NEED_L_GCOV_INFO_TO_GCDA): Likewise.
(are_all_counters_zero): New.
(gcov_dump_handler): Likewise.
(gcov_allocate_handler): Likewise.
(dump_unsigned): Likewise.
(dump_counter): Likewise.
(write_topn_counters): Add dump_fn, allocate_fn, and arg parameters.
Use dump_unsigned() and dump_counter().
(write_one_data): Add dump_fn, allocate_fn, and arg parameters. Use
dump_unsigned(), dump_counter(), and are_all_counters_zero().
(__gcov_info_to_gcda): New.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/doc/invoke.texi | 80 | ||||
-rw-r--r-- | gcc/gcov-io.c | 36 | ||||
-rw-r--r-- | gcc/gcov-io.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/gcov-info-to-gcda.c | 60 |
4 files changed, 141 insertions, 36 deletions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4efc8b7..a64cec5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -14801,17 +14801,17 @@ To optimize the program based on the collected profile information, use Register the profile information in the specified section instead of using a constructor/destructor. The section name is @var{name} if it is specified, otherwise the section name defaults to @code{.gcov_info}. A pointer to the -profile information generated by @option{-fprofile-arcs} or -@option{-ftest-coverage} is placed in the specified section for each -translation unit. This option disables the profile information registration -through a constructor and it disables the profile information processing -through a destructor. This option is not intended to be used in hosted -environments such as GNU/Linux. It targets systems with limited resources -which do not support constructors and destructors. The linker could collect -the input sections in a continuous memory block and define start and end -symbols. The runtime support could dump the profiling information registered -in this linker set during program termination to a serial line for example. A -GNU linker script example which defines a linker output section follows: +profile information generated by @option{-fprofile-arcs} is placed in the +specified section for each translation unit. This option disables the profile +information registration through a constructor and it disables the profile +information processing through a destructor. This option is not intended to be +used in hosted environments such as GNU/Linux. It targets free-standing +environments (for example embedded systems) with limited resources which do not +support constructors/destructors or the C library file I/O. + +The linker could collect the input sections in a continuous memory block and +define start and end symbols. A GNU linker script example which defines a +linker output section follows: @smallexample .gcov_info : @@ -14822,6 +14822,64 @@ GNU linker script example which defines a linker output section follows: @} @end smallexample +The program could dump the profiling information registered in this linker set +for example like this: + +@smallexample +#include <gcov.h> +#include <stdio.h> +#include <stdlib.h> + +extern const struct gcov_info *__gcov_info_start[]; +extern const struct gcov_info *__gcov_info_end[]; + +static void +filename (const char *f, void *arg) +@{ + puts (f); +@} + +static void +dump (const void *d, unsigned n, void *arg) +@{ + const unsigned char *c = d; + + for (unsigned i = 0; i < n; ++i) + printf ("%02x", c[i]); +@} + +static void * +allocate (unsigned length, void *arg) +@{ + return malloc (length); +@} + +static void +dump_gcov_info (void) +@{ + const struct gcov_info **info = __gcov_info_start; + const struct gcov_info **end = __gcov_info_end; + + /* Obfuscate variable to prevent compiler optimizations. */ + __asm__ ("" : "+r" (info)); + + while (info != end) + @{ + void *arg = NULL; + __gcov_info_to_gcda (*info, filename, dump, allocate, arg); + putchar ('\n'); + ++info; + @} +@} + +int +main() +@{ + dump_gcov_info(); + return 0; +@} +@end smallexample + @item -fprofile-note=@var{path} @opindex fprofile-note diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c index 7819593..d3e56af 100644 --- a/gcc/gcov-io.c +++ b/gcc/gcov-io.c @@ -229,30 +229,25 @@ gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected) #endif #if !IN_GCOV -/* Write unsigned VALUE to coverage file. */ +/* Write DATA of LENGTH characters to coverage file. */ GCOV_LINKAGE void -gcov_write_unsigned (gcov_unsigned_t value) +gcov_write (const void *data, unsigned length) { - gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file); + gcov_unsigned_t r = fwrite (data, length, 1, gcov_var.file); if (r != 1) gcov_var.error = 1; } -/* Write counter VALUE to coverage file. Sets error flag - appropriately. */ +/* Write unsigned VALUE to coverage file. */ -#if IN_LIBGCOV GCOV_LINKAGE void -gcov_write_counter (gcov_type value) +gcov_write_unsigned (gcov_unsigned_t value) { - gcov_write_unsigned ((gcov_unsigned_t) value); - if (sizeof (value) > sizeof (gcov_unsigned_t)) - gcov_write_unsigned ((gcov_unsigned_t) (value >> 32)); - else - gcov_write_unsigned (0); + gcov_unsigned_t r = fwrite (&value, sizeof (value), 1, gcov_var.file); + if (r != 1) + gcov_var.error = 1; } -#endif /* IN_LIBGCOV */ #if !IN_LIBGCOV /* Write STRING to coverage file. Sets error flag on file @@ -349,22 +344,13 @@ gcov_write_length (gcov_position_t position) #else /* IN_LIBGCOV */ -/* Write a tag TAG and length LENGTH. */ - -GCOV_LINKAGE void -gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) -{ - gcov_write_unsigned (tag); - gcov_write_unsigned (length); -} - -/* Write a summary structure to the gcov file. Return nonzero on - overflow. */ +/* Write a summary structure to the gcov file. */ GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) { - gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH); + gcov_write_unsigned (tag); + gcov_write_unsigned (GCOV_TAG_SUMMARY_LENGTH); gcov_write_unsigned (summary->runs); gcov_write_unsigned (summary->sum_max); } diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index 538bee8..99e1964 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -367,6 +367,7 @@ char *mangle_path (char const *base); #if !IN_GCOV /* Available outside gcov */ +GCOV_LINKAGE void gcov_write (const void *, unsigned) ATTRIBUTE_HIDDEN; GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN; #endif diff --git a/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c b/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c new file mode 100644 index 0000000..a42a768 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gcov-info-to-gcda.c @@ -0,0 +1,60 @@ +/* { dg-do run } */ +/* { dg-skip-if "profile-info-section" { powerpc-ibm-aix* } } */ +/* { dg-options "-fprofile-arcs -fprofile-info-section" } */ + +#define assert(expr) \ + ((expr) \ + ? (void)0 \ + : (__builtin_printf ("%s:%i: Assertion `%s' failed.\n", \ + __FILE__, __LINE__, #expr), \ + __builtin_abort ())) + +struct gcov_info; + +extern void +__gcov_info_to_gcda (const struct gcov_info *__info, + void (*__filename_fn) (const char *, void *), + void (*__dump_fn) (const void *, unsigned, void *), + void *(*__allocate_fn) (unsigned, void *), + void *__arg); + +extern const struct gcov_info *my_info; + +static unsigned counter; + +static void +filename (const char *f, void *arg) +{ + assert (arg == &counter); + assert (__builtin_strstr (f, "gcov-info-to-gcda.c") == 0); +} + +static void +dump (const void *d, unsigned n, void *arg) +{ + unsigned *m = (unsigned *)arg; + assert (arg == &counter); + + if (*m == 0) + { + const unsigned *u = d; + assert (*u == 0x67636461); + } + + *m += n; +} + +static void * +allocate (unsigned length, void *arg) +{ + assert (arg == &counter); + return __builtin_malloc (length); +} + +int main() +{ + __asm__ volatile (".set my_info, .LPBX2"); + __gcov_info_to_gcda (my_info, filename, dump, allocate, &counter); + assert (counter > 4); + return 0; +} |