gcc/
* 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/gcov-tool.cc | 76 ++++++++++++++++++++++++++++++++++++++++
libgcc/libgcov-util.c | 80 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 156 insertions(+)
diff --git a/gcc/gcov-tool.cc b/gcc/gcov-tool.cc
index d712715cf7e..d8572b184e9 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] [stream-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 622d5a9dc71..0fe60528b48 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -735,6 +735,86 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct
gcov_info *src_profile
return tgt_profile;
}
+ 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;
+}
+
+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;
+}
+
+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 = consume_stream (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. */