Multiple input-file patch for gcov 3.2.3
Ed Swierk
eswierk@cs.stanford.edu
Wed Aug 20 00:24:00 GMT 2003
Attached is a patch for gcov (the version included with gcc 3.2.3) that
allows it to process more than one input file at a time. A comment in
gcov.c explains the issue:
/* ??? Does not correctly handle the case where two .bb files refer to the
same included source file. For example, if one has a short file containing
only inline functions, which is then included in two other files, then
there will be two .bb files which refer to the include file, but there
is no way to get the total execution counts for the included file, can
only get execution counts for one or the other of the including files.
*/
Processing all the .bb files in one swoop allows gcov to get total
execution counts for the included file.
This patch is particularly useful for C++ code that makes heavy use of
functions defined in include files.
Unfortunately the patched gcov does not coalesce function summaries (-f)
or branch counts (-c); for a function included in multiple object files,
gcov still prints separate information. Fixing this issue would require
more extensive changes to gcov.
--Ed
--
Ed Swierk
eswierk@cs.stanford.edu
-------------- next part --------------
--- gcc/gcov.c.jj 2002-01-05 14:11:20.000000000 -0800
+++ gcc/gcov.c 2003-06-11 19:03:07.000000000 -0700
@@ -156,41 +156,44 @@
struct bb_info_list *next;
};
-/* Holds a list of function basic block graphs. */
+/* Holds a list of function basic block graphs for all object files, concatenated. */
static struct bb_info_list *bb_graph_list = 0;
+static struct bb_info_list *bb_graph_list_end = 0;
/* Name and file pointer of the input file for the basic block graph. */
-static char *bbg_file_name;
-static FILE *bbg_file;
+static char **bbg_file_names;
+static FILE **bbg_files;
/* Name and file pointer of the input file for the arc count data. */
-static char *da_file_name;
-static FILE *da_file;
+static char **da_file_names;
+static FILE **da_files;
/* Name and file pointer of the input file for the basic block line counts. */
-static char *bb_file_name;
-static FILE *bb_file;
+static char **bb_file_names;
+static FILE **bb_files;
-/* Holds the entire contents of the bb_file read into memory. */
+/* Holds the entire contents of the bb_files read into memory and concatenated. */
-static char *bb_data;
+static char *bb_data = 0;
/* Size of bb_data array in longs. */
-static long bb_data_size;
+static long bb_data_size = 0;
/* Name and file pointer of the output file. */
static char *gcov_file_name;
static FILE *gcov_file;
-/* Name of the file mentioned on the command line. */
+/* Name of the object files mentioned on the command line. */
-static char *input_file_name = 0;
+static char **input_file_names;
+
+static int num_input_files;
/* Output branch probabilities if true. */
@@ -224,15 +227,15 @@
/* Forward declarations. */
static void process_args PARAMS ((int, char **));
-static void open_files PARAMS ((void));
-static void read_files PARAMS ((void));
+static void open_files PARAMS ((int));
+static void read_files PARAMS ((int));
static void scan_for_source_files PARAMS ((void));
static void output_data PARAMS ((void));
static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
-static void create_program_flow_graph PARAMS ((struct bb_info_list *));
+static void create_program_flow_graph PARAMS ((int, struct bb_info_list *));
static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
struct arcdata **, int));
@@ -245,13 +248,17 @@
int argc;
char **argv;
{
+ int input_file_index;
+
gcc_init_libintl ();
process_args (argc, argv);
- open_files ();
-
- read_files ();
+ for (input_file_index = 0; input_file_index < num_input_files; input_file_index++)
+ {
+ open_files (input_file_index);
+ read_files (input_file_index);
+ }
scan_for_source_files ();
@@ -292,7 +299,7 @@
{
FILE *file = error_p ? stderr : stdout;
int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
- fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
+ fnotice (file, "Usage: gcov [OPTION]... SOURCEFILES\n\n");
fnotice (file, "Print code coverage information.\n\n");
fnotice (file, " -h, --help Print this help, then exit\n");
fnotice (file, " -v, --version Print version number, then exit\n");
@@ -301,7 +308,7 @@
rather than percentages\n");
fnotice (file, " -n, --no-output Do not create an output file\n");
fnotice (file, " -l, --long-file-names Use long output file names for included\n\
- source files\n");
+ source files (only w/1 source file)\n");
fnotice (file, " -f, --function-summaries Output summaries for each function\n");
fnotice (file, " -o, --object-directory OBJDIR Search for object files in OBJDIR\n");
fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
@@ -377,117 +384,127 @@
}
}
- if (optind != argc - 1)
+ if (optind > argc - 1)
print_usage (true);
- input_file_name = argv[optind];
+ input_file_names = &argv[optind];
+ num_input_files = argc - optind;
+ printf("reading %d input files\n", num_input_files);
+
+ bbg_file_names = (char **) xcalloc (num_input_files, sizeof(char *));
+ bbg_files = (FILE **) xcalloc (num_input_files, sizeof(FILE *));
+ da_file_names = (char **) xcalloc (num_input_files, sizeof(char *));
+ da_files = (FILE **) xcalloc (num_input_files, sizeof(FILE *));
+ bb_file_names = (char **) xcalloc (num_input_files, sizeof(char *));
+ bb_files = (FILE **) xcalloc (num_input_files, sizeof(FILE *));
}
-/* Find and open the .bb, .da, and .bbg files. */
+/* Find and open the .bb, .da, and .bbg files for input file i. */
static void
-open_files ()
+open_files (input_file_index)
+ int input_file_index;
{
int count, objdir_count;
char *cptr;
/* Determine the names of the .bb, .bbg, and .da files. Strip off the
extension, if any, and append the new extensions. */
- count = strlen (input_file_name);
+ count = strlen (input_file_names[input_file_index]);
if (object_directory)
objdir_count = strlen (object_directory);
else
objdir_count = 0;
- da_file_name = xmalloc (count + objdir_count + 4);
- bb_file_name = xmalloc (count + objdir_count + 4);
- bbg_file_name = xmalloc (count + objdir_count + 5);
+ da_file_names[input_file_index] = xmalloc (count + objdir_count + 4);
+ bb_file_names[input_file_index] = xmalloc (count + objdir_count + 4);
+ bbg_file_names[input_file_index] = xmalloc (count + objdir_count + 5);
if (object_directory)
{
- strcpy (da_file_name, object_directory);
- strcpy (bb_file_name, object_directory);
- strcpy (bbg_file_name, object_directory);
+ strcpy (da_file_names[input_file_index], object_directory);
+ strcpy (bb_file_names[input_file_index], object_directory);
+ strcpy (bbg_file_names[input_file_index], object_directory);
if (object_directory[objdir_count - 1] != '/')
{
- strcat (da_file_name, "/");
- strcat (bb_file_name, "/");
- strcat (bbg_file_name, "/");
+ strcat (da_file_names[input_file_index], "/");
+ strcat (bb_file_names[input_file_index], "/");
+ strcat (bbg_file_names[input_file_index], "/");
}
- cptr = strrchr (input_file_name, '/');
+ cptr = strrchr (input_file_names[input_file_index], '/');
if (cptr)
{
- strcat (da_file_name, cptr + 1);
- strcat (bb_file_name, cptr + 1);
- strcat (bbg_file_name, cptr + 1);
+ strcat (da_file_names[input_file_index], cptr + 1);
+ strcat (bb_file_names[input_file_index], cptr + 1);
+ strcat (bbg_file_names[input_file_index], cptr + 1);
}
else
{
- strcat (da_file_name, input_file_name);
- strcat (bb_file_name, input_file_name);
- strcat (bbg_file_name, input_file_name);
+ strcat (da_file_names[input_file_index], input_file_names[input_file_index]);
+ strcat (bb_file_names[input_file_index], input_file_names[input_file_index]);
+ strcat (bbg_file_names[input_file_index], input_file_names[input_file_index]);
}
}
else
{
- strcpy (da_file_name, input_file_name);
- strcpy (bb_file_name, input_file_name);
- strcpy (bbg_file_name, input_file_name);
+ strcpy (da_file_names[input_file_index], input_file_names[input_file_index]);
+ strcpy (bb_file_names[input_file_index], input_file_names[input_file_index]);
+ strcpy (bbg_file_names[input_file_index], input_file_names[input_file_index]);
}
- cptr = strrchr (bb_file_name, '.');
+ cptr = strrchr (bb_file_names[input_file_index], '.');
if (cptr)
strcpy (cptr, ".bb");
else
- strcat (bb_file_name, ".bb");
+ strcat (bb_file_names[input_file_index], ".bb");
- cptr = strrchr (da_file_name, '.');
+ cptr = strrchr (da_file_names[input_file_index], '.');
if (cptr)
strcpy (cptr, ".da");
else
- strcat (da_file_name, ".da");
+ strcat (da_file_names[input_file_index], ".da");
- cptr = strrchr (bbg_file_name, '.');
+ cptr = strrchr (bbg_file_names[input_file_index], '.');
if (cptr)
strcpy (cptr, ".bbg");
else
- strcat (bbg_file_name, ".bbg");
+ strcat (bbg_file_names[input_file_index], ".bbg");
- bb_file = fopen (bb_file_name, "rb");
- if (bb_file == NULL)
+ bb_files[input_file_index] = fopen (bb_file_names[input_file_index], "rb");
+ if (bb_files[input_file_index] == NULL)
{
- fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
+ fnotice (stderr, "Could not open basic block file %s.\n", bb_file_names[input_file_index]);
exit (FATAL_EXIT_CODE);
}
/* If none of the functions in the file were executed, then there won't
be a .da file. Just assume that all counts are zero in this case. */
- da_file = fopen (da_file_name, "rb");
- if (da_file == NULL)
+ da_files[input_file_index] = fopen (da_file_names[input_file_index], "rb");
+ if (da_files[input_file_index] == NULL)
{
- fnotice (stderr, "Could not open data file %s.\n", da_file_name);
+ fnotice (stderr, "Could not open data file %s.\n", da_file_names[input_file_index]);
fnotice (stderr, "Assuming that all execution counts are zero.\n");
}
- bbg_file = fopen (bbg_file_name, "rb");
- if (bbg_file == NULL)
+ bbg_files[input_file_index] = fopen (bbg_file_names[input_file_index], "rb");
+ if (bbg_files[input_file_index] == NULL)
{
fnotice (stderr, "Could not open program flow graph file %s.\n",
- bbg_file_name);
+ bbg_file_names[input_file_index]);
exit (FATAL_EXIT_CODE);
}
/* Check for empty .bbg file. This indicates that there is no executable
code in this source file. */
/* Set the EOF condition if at the end of file. */
- ungetc (getc (bbg_file), bbg_file);
- if (feof (bbg_file))
+ ungetc (getc (bbg_files[input_file_index]), bbg_files[input_file_index]);
+ if (feof (bbg_files[input_file_index]))
{
fnotice (stderr, "No executable code associated with file %s.\n",
- input_file_name);
+ input_file_names[input_file_index]);
exit (FATAL_EXIT_CODE);
}
}
@@ -540,10 +557,11 @@
/* Construct the program flow graph from the .bbg file, and read in the data
- in the .da file. */
+ in the .da file for the specified object file. */
static void
-create_program_flow_graph (bptr)
+create_program_flow_graph (input_file_index, bptr)
+ int input_file_index;
struct bb_info_list *bptr;
{
long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
@@ -552,7 +570,7 @@
struct bb_info *bb_graph;
/* Read the number of blocks. */
- __read_long (&num_blocks, bbg_file, 4);
+ __read_long (&num_blocks, bbg_files[input_file_index], 4);
/* Create an array of size bb number of bb_info structs. */
bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
@@ -561,24 +579,24 @@
bptr->num_blocks = num_blocks;
/* Read and create each arc from the .bbg file. */
- __read_long (&number_arcs, bbg_file, 4);
+ __read_long (&number_arcs, bbg_files[input_file_index], 4);
for (i = 0; i < num_blocks; i++)
{
int j;
- __read_long (&num_arcs_per_block, bbg_file, 4);
+ __read_long (&num_arcs_per_block, bbg_files[input_file_index], 4);
for (j = 0; j < num_arcs_per_block; j++)
{
if (number_arcs-- < 0)
abort ();
src = i;
- __read_long (&dest, bbg_file, 4);
+ __read_long (&dest, bbg_files[input_file_index], 4);
arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
init_arc (arcptr, src, dest, bb_graph);
- __read_long (&flag_bits, bbg_file, 4);
+ __read_long (&flag_bits, bbg_files[input_file_index], 4);
arcptr->on_tree = flag_bits & 0x1;
arcptr->fake = !! (flag_bits & 0x2);
arcptr->fall_through = !! (flag_bits & 0x4);
@@ -590,7 +608,7 @@
/* Read and ignore the -1 separating the arc list from the arc list of the
next function. */
- __read_long (&src, bbg_file, 4);
+ __read_long (&src, bbg_files[input_file_index], 4);
if (src != -1)
abort ();
@@ -614,7 +632,7 @@
if (! arcptr->on_tree)
{
gcov_type tmp_count = 0;
- if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
+ if (da_files[input_file_index] && __read_gcov_type (&tmp_count, da_files[input_file_index], 8))
abort ();
arcptr->arc_count = tmp_count;
@@ -750,45 +768,45 @@
static void
-read_files ()
+read_files (input_file_index)
+ int input_file_index;
{
struct stat buf;
- struct bb_info_list *list_end = 0;
struct bb_info_list *b_ptr;
long total;
/* Read and ignore the first word of the .da file, which is the count of
how many numbers follow. */
- if (da_file && __read_long (&total, da_file, 8))
+ if (da_files[input_file_index] && __read_long (&total, da_files[input_file_index], 8))
abort ();
- while (! feof (bbg_file))
+ while (! feof (bbg_files[input_file_index]))
{
b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
b_ptr->next = 0;
- if (list_end)
- list_end->next = b_ptr;
+ if (bb_graph_list_end)
+ bb_graph_list_end->next = b_ptr;
else
bb_graph_list = b_ptr;
- list_end = b_ptr;
+ bb_graph_list_end = b_ptr;
/* Read in the data in the .bbg file and reconstruct the program flow
graph for one function. */
- create_program_flow_graph (b_ptr);
+ create_program_flow_graph (input_file_index, b_ptr);
/* Set the EOF condition if at the end of file. */
- ungetc (getc (bbg_file), bbg_file);
+ ungetc (getc (bbg_files[input_file_index]), bbg_files[input_file_index]);
}
/* Check to make sure the .da file data is valid. */
- if (da_file)
+ if (da_files[input_file_index])
{
- if (feof (da_file))
+ if (feof (da_files[input_file_index]))
fnotice (stderr, ".da file contents exhausted too early\n");
/* Should be at end of file now. */
- if (__read_long (&total, da_file, 8) == 0)
+ if (__read_long (&total, da_files[input_file_index], 8) == 0)
fnotice (stderr, ".da file contents not exhausted\n");
}
@@ -800,16 +818,17 @@
/* Read in all of the data from the .bb file. This info will be accessed
sequentially twice. */
- stat (bb_file_name, &buf);
- bb_data_size = buf.st_size / 4;
-
- bb_data = (char *) xmalloc ((unsigned) buf.st_size);
- fread (bb_data, sizeof (char), buf.st_size, bb_file);
+ stat (bb_file_names[input_file_index], &buf);
- fclose (bb_file);
- if (da_file)
- fclose (da_file);
- fclose (bbg_file);
+ bb_data = (char *) xrealloc ((void *) bb_data,
+ bb_data_size * 4 + (unsigned) buf.st_size);
+ fread (bb_data + bb_data_size * 4, sizeof (char), buf.st_size, bb_files[input_file_index]);
+ bb_data_size += buf.st_size / 4;
+
+ fclose (bb_files[input_file_index]);
+ if (da_files[input_file_index])
+ fclose (da_files[input_file_index]);
+ fclose (bbg_files[input_file_index]);
}
@@ -1291,15 +1310,15 @@
cptr = cptr + 1;
else
cptr = s_ptr->name;
- if (output_long_names && strcmp (cptr, input_file_name))
+ if (output_long_names && num_input_files == 1 && strcmp (cptr, input_file_names[0]))
{
- gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
+ gcov_file_name = xmalloc (count + 7 + strlen (input_file_names[0]));
- cptr = strrchr (input_file_name, '/');
+ cptr = strrchr (input_file_names[0], '/');
if (cptr)
strcpy (gcov_file_name, cptr + 1);
else
- strcpy (gcov_file_name, input_file_name);
+ strcpy (gcov_file_name, input_file_names[0]);
strcat (gcov_file_name, ".");
More information about the Gcc
mailing list