aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/doc/invoke.texi80
-rw-r--r--gcc/gcov-io.c36
-rw-r--r--gcc/gcov-io.h1
-rw-r--r--gcc/testsuite/gcc.dg/gcov-info-to-gcda.c60
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;
+}