diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 8922a3b3fa1e1174b386ed3f027bba6f9e67c9d0..6c6e386b96eab473650fc035c8cc31049b6591e6 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,21 @@ +2014-09-17 Nathan sidwell <nathan@acm.org> + + * Makefile.in (LIBGCOV_INTERFACE): Add _gcov_dump from ... + (LIBGCOV_DRIVER): ... here. + * libgcov-driver.c (gcov_master): New. + (gcov_exit): Remove from master chain. + (__gcov_init): Add to master chain if version compatible. Don't + clear the version. + * libgcov_interface (__gcov_flust): Call gcov_dump_int. + (gcov_reset_int): Clear master chain, if compatible. + (gcov_dump_int): New internal interface. Dump master chain, if + compatible. + (gcov_dump): Alias for gcov_dump_int. + * libgcov.h (struct gcov_root): Add next and prev fields. + (struct gcov_master): New struct. + (__gcov_master): New. + (gcov_dump_int): Declare. + 2014-09-17 Olivier Hainque <hainque@adacore.com> * config.host (x86_64-*-mingw*): Add i386/t-cygming to tmake_file diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index 6a6cf66d6989f73daf2bf7c64b6859e1e75fc551..de03c47b6d14febcfd2a370e3d2dcc7b1be66e6d 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -858,9 +858,10 @@ LIBGCOV_PROFILER = _gcov_interval_profiler _gcov_pow2_profiler \ _gcov_one_value_profiler _gcov_indirect_call_profiler \ _gcov_average_profiler _gcov_ior_profiler \ _gcov_indirect_call_profiler_v2 _gcov_time_profiler -LIBGCOV_INTERFACE = _gcov_flush _gcov_fork _gcov_execl _gcov_execlp \ +LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork \ + _gcov_execl _gcov_execlp \ _gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset -LIBGCOV_DRIVER = _gcov _gcov_dump +LIBGCOV_DRIVER = _gcov libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE)) libgcov-profiler-objects = $(patsubst %,%$(objext),$(LIBGCOV_PROFILER)) diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c index 34c58cd5feca5c6db06c14c8f8c691f9d780bca2..7bde5261878a2ccab36e8fb3c65dc9879b4364eb 100644 --- a/libgcc/libgcov-driver.c +++ b/libgcc/libgcov-driver.c @@ -777,13 +777,23 @@ __gcov_dump_one (struct gcov_root *root) root->run_counted = 1; } -/* Per-program/shared-object gcov state. */ +/* Per-dynamic-object gcov state. */ struct gcov_root __gcov_root; +/* Exactly one of these will be live in the process image. */ +struct gcov_master __gcov_master = + {GCOV_VERSION, 0}; + static void gcov_exit (void) { __gcov_dump_one (&__gcov_root); + if (__gcov_root.next) + __gcov_root.next->prev = __gcov_root.prev; + if (__gcov_root.prev) + __gcov_root.prev->next = __gcov_root.next; + else + __gcov_master.root = __gcov_root.next; } /* Add a new object file onto the bb chain. Invoked automatically @@ -797,12 +807,21 @@ __gcov_init (struct gcov_info *info) if (gcov_version (info, info->version, 0)) { if (!__gcov_root.list) - atexit (gcov_exit); + { + /* Add to master list and at exit function. */ + if (gcov_version (NULL, __gcov_master.version, "<master>")) + { + __gcov_root.next = __gcov_master.root; + if (__gcov_master.root) + __gcov_master.root->prev = &__gcov_root; + __gcov_master.root = &__gcov_root; + } + atexit (gcov_exit); + } info->next = __gcov_root.list; __gcov_root.list = info; } - info->version = 0; } #endif /* !IN_GCOV_TOOL */ #endif /* L_gcov */ diff --git a/libgcc/libgcov-interface.c b/libgcc/libgcov-interface.c index e40268991af57de16e1539fcd99f4e936d05ae24..3e6ec20b99950731cedd4cfd42f15b953d69984d 100644 --- a/libgcc/libgcov-interface.c +++ b/libgcc/libgcov-interface.c @@ -85,7 +85,7 @@ __gcov_flush (void) init_mx_once (); __gthread_mutex_lock (&__gcov_flush_mx); - __gcov_dump_one (&__gcov_root); + __gcov_dump_int (); __gcov_reset_int (); __gthread_mutex_unlock (&__gcov_flush_mx); @@ -132,8 +132,16 @@ gcov_clear (const struct gcov_info *list) void __gcov_reset_int (void) { - gcov_clear (__gcov_root.list); - __gcov_root.dumped = 0; + struct gcov_root *root; + + /* If we're compatible with the master, iterate over everything, + otherise just do us. */ + for (root = __gcov_master.version == GCOV_VERSION + ? __gcov_master.root : &__gcov_root; root; root = root->next) + { + gcov_clear (root->list); + root->dumped = 0; + } } ALIAS_void_fn (__gcov_reset_int, __gcov_reset); @@ -145,11 +153,19 @@ ALIAS_void_fn (__gcov_reset_int, __gcov_reset); so far, in order to collect profile in region of interest. */ void -__gcov_dump (void) +__gcov_dump_int (void) { - __gcov_dump_one (&__gcov_root); + struct gcov_root *root; + + /* If we're compatible with the master, iterate over everything, + otherise just do us. */ + for (root = __gcov_master.version == GCOV_VERSION + ? __gcov_master.root : &__gcov_root; root; root = root->next) + __gcov_dump_one (root); } +ALIAS_void_fn (__gcov_dump_int, __gcov_dump); + #endif /* L_gcov_dump */ #ifdef L_gcov_fork @@ -169,8 +185,8 @@ __gcov_fork (void) #endif #ifdef L_gcov_execl -/* A wrapper for the execl function. Flushes the accumulated profiling data, so - that they are not lost. */ +/* A wrapper for the execl function. Flushes the accumulated + profiling data, so that they are not lost. */ int __gcov_execl (const char *path, char *arg, ...) diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h index 98a15d134a7adcaa2c0da09e7c4dd4ba474fd9b5..3816b6a7090ec62c430812619f1e994cb009910d 100644 --- a/libgcc/libgcov.h +++ b/libgcc/libgcov.h @@ -212,10 +212,21 @@ struct gcov_root struct gcov_info *list; unsigned dumped : 1; /* counts have been dumped. */ unsigned run_counted : 1; /* run has been accounted for. */ + struct gcov_root *next; + struct gcov_root *prev; }; extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN; +struct gcov_master +{ + gcov_unsigned_t version; + struct gcov_root *root; +}; + +/* Exactly one of these will be active in the process. */ +extern struct gcov_master __gcov_master; + /* Dump a set of gcov objects. */ extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN; @@ -230,8 +241,9 @@ extern void __gcov_flush (void) ATTRIBUTE_HIDDEN; extern void __gcov_reset (void); extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN; -/* Function to enable early write of profile information so far. */ +/* User function to enable early write of profile information so far. */ extern void __gcov_dump (void); +extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN; /* The merge function that just sums the counters. */ extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;