Commit 8b219a76 by Nathan Sidwell Committed by Nathan Sidwell

gcov.c: Tidy.

	* gcov.c: Tidy.
	(struct line_info, struct coverage): New structures.
	(gcov_file_name, gcov_file): Remove globals.
	(output_data): Take source file parameter. Fix memory leak. Break
	up into ...
	(init_line_info, output_line_info, make_gcov_file_name,
	accumulate_branch_counts): ... here.
	(calculate_branch_probs, function_summary): Adjust.
	(main): Adjust.
	(function_*): Remove global variables.

From-SVN: r56080
parent 317e98c0
2002-08-06 Nathan Sidwell <nathan@codesourcery.com>
* gcov.c: Tidy.
(struct line_info, struct coverage): New structures.
(gcov_file_name, gcov_file): Remove globals.
(output_data): Take source file parameter. Fix memory leak. Break
up into ...
(init_line_info, output_line_info, make_gcov_file_name,
accumulate_branch_counts): ... here.
(calculate_branch_probs, function_summary): Adjust.
(main): Adjust.
(function_*): Remove global variables.
2002-08-06 Neil Booth <neil@daikokuya.co.uk>
* dwarf2out.c: Remove unused macros.
......
......@@ -103,7 +103,8 @@ struct sourcefile *sources;
/* One of these is dynamically created whenever we identify an arc in the
function. */
struct adj_list {
struct adj_list
{
int source;
int target;
gcov_type arc_count;
......@@ -122,7 +123,8 @@ struct adj_list {
/* Count the number of basic blocks, and create an array of these structures,
one for each bb in the function. */
struct bb_info {
struct bb_info
{
struct adj_list *succ;
struct adj_list *pred;
gcov_type succ_count;
......@@ -149,13 +151,37 @@ struct arcdata
/* Used to save the list of bb_graphs, one per function. */
struct bb_info_list {
struct bb_info_list
{
/* Indexed by block number, holds the basic block graph for one function. */
struct bb_info *bb_graph;
int num_blocks;
struct bb_info_list *next;
};
/* Used to hold information about each line. */
struct line_info
{
gcov_type count; /* execution count */
struct arcdata *branches; /* list of branch probabilities for line. */
unsigned exists : 1; /* has code associated with it. */
};
struct coverage
{
int lines;
int lines_executed;
int branches;
int branches_executed;
int branches_taken;
int calls;
int calls_executed;
char *name;
};
/* Holds a list of function basic block graphs. */
static struct bb_info_list *bb_graph_list = 0;
......@@ -187,11 +213,6 @@ static char *bb_data;
static long bb_data_size;
/* 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. */
static char *input_file_name = 0;
......@@ -235,7 +256,7 @@ static void process_args PARAMS ((int, char **));
static void open_files PARAMS ((void));
static void read_files PARAMS ((void));
static void scan_for_source_files PARAMS ((void));
static void output_data PARAMS ((void));
static void output_data PARAMS ((struct sourcefile *));
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 *));
......@@ -243,10 +264,19 @@ static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
static gcov_type *read_profile PARAMS ((char *, long, int));
static void create_program_flow_graph PARAMS ((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));
static void function_summary PARAMS ((void));
static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT, int));
static void accumulate_branch_counts PARAMS ((struct coverage *,
struct arcdata *));
static void calculate_branch_probs PARAMS ((struct bb_info *,
struct line_info *,
struct coverage *));
static void function_summary PARAMS ((struct coverage *, const char *));
static void init_line_info PARAMS ((struct line_info *,
struct coverage *, long));
static void output_line_info PARAMS ((FILE *, const struct line_info *,
const struct coverage *, long));
static char *make_gcov_file_name PARAMS ((char *));
static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
int));
extern int main PARAMS ((int, char **));
......@@ -255,6 +285,8 @@ main (argc, argv)
int argc;
char **argv;
{
struct sourcefile *s_ptr;
gcc_init_libintl ();
process_args (argc, argv);
......@@ -265,7 +297,8 @@ main (argc, argv)
scan_for_source_files ();
output_data ();
for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
output_data (s_ptr);
return 0;
}
......@@ -530,7 +563,6 @@ init_arc (arcptr, source, target, bb_graph)
bb_graph[target].pred_count++;
}
/* Reverse the arcs on an arc list. */
static struct adj_list *
......@@ -1037,77 +1069,61 @@ scan_for_source_files ()
}
}
/* For calculating coverage at the function level. */
static int function_source_lines;
static int function_source_lines_executed;
static int function_branches;
static int function_branches_executed;
static int function_branches_taken;
static int function_calls;
static int function_calls_executed;
static char *function_name;
/* Increment totals in FUNCTION according to arc A_PTR. */
static void
accumulate_branch_counts (function, a_ptr)
struct coverage *function;
struct arcdata *a_ptr;
{
if (a_ptr->call_insn)
{
function->calls++;
if (a_ptr->total)
function->calls_executed++;
}
else
{
function->branches++;
if (a_ptr->total)
function->branches_executed++;
if (a_ptr->hits)
function->branches_taken++;
}
}
/* Calculate the branch taken probabilities for all arcs branches at the
end of this block. */
static void
calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
struct bb_info_list *current_graph;
int block_num;
struct arcdata **branch_probs;
int last_line_num;
calculate_branch_probs (block_ptr, line_info, function)
struct bb_info *block_ptr;
struct line_info *line_info;
struct coverage *function;
{
gcov_type total;
struct adj_list *arcptr;
struct arcdata *end_ptr, *a_ptr;
total = current_graph->bb_graph[block_num].exec_count;
for (arcptr = current_graph->bb_graph[block_num].succ; arcptr;
arcptr = arcptr->succ_next)
total = block_ptr->exec_count;
for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
{
struct arcdata *a_ptr;
/* Ignore fall through arcs as they aren't really branches. */
if (arcptr->fall_through)
continue;
a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
a_ptr->total = total;
if (total == 0)
a_ptr->hits = 0;
else
a_ptr->hits = arcptr->arc_count;
a_ptr->hits = total ? arcptr->arc_count : 0;
a_ptr->call_insn = arcptr->fake;
if (output_function_summary)
{
if (a_ptr->call_insn)
{
function_calls++;
if (a_ptr->total != 0)
function_calls_executed++;
}
else
{
function_branches++;
if (a_ptr->total != 0)
function_branches_executed++;
if (a_ptr->hits > 0)
function_branches_taken++;
}
}
/* Append the new branch to the end of the list. */
a_ptr->next = 0;
if (! branch_probs[last_line_num])
branch_probs[last_line_num] = a_ptr;
else
{
end_ptr = branch_probs[last_line_num];
while (end_ptr->next != 0)
end_ptr = end_ptr->next;
end_ptr->next = a_ptr;
}
if (function)
accumulate_branch_counts (function, a_ptr);
/* Prepend the new branch to the list. */
a_ptr->next = line_info->branches;
line_info->branches = a_ptr;
}
}
......@@ -1162,502 +1178,457 @@ format_hwint (top, bottom, dp)
/* Output summary info for a function. */
static void
function_summary ()
function_summary (function, title)
struct coverage *function;
const char *title;
{
if (function_source_lines)
fnotice (stdout, "%s of %d source lines executed in function %s\n",
format_hwint (function_source_lines_executed,
function_source_lines, 2),
function_source_lines, function_name);
if (function->lines)
fnotice (stdout, "%s of %d lines executed in %s %s\n",
format_hwint (function->lines_executed,
function->lines, 2),
function->lines, title, function->name);
else
fnotice (stdout, "No executable source lines in function %s\n",
function_name);
fnotice (stdout, "No executable lines in %s %s\n",
title, function->name);
if (output_branch_probs)
{
if (function_branches)
if (function->branches)
{
fnotice (stdout, "%s of %d branches executed in function %s\n",
format_hwint (function_branches_executed,
function_branches, 2),
function_branches, function_name);
fnotice (stdout, "%s of %d branches executed in %s %s\n",
format_hwint (function->branches_executed,
function->branches, 2),
function->branches, title, function->name);
fnotice (stdout,
"%s of %d branches taken at least once in function %s\n",
format_hwint (function_branches_taken,
function_branches, 2),
function_branches, function_name);
"%s of %d branches taken at least once in %s %s\n",
format_hwint (function->branches_taken,
function->branches, 2),
function->branches, title, function->name);
}
else
fnotice (stdout, "No branches in function %s\n", function_name);
if (function_calls)
fnotice (stdout, "%s of %d calls executed in function %s\n",
format_hwint (function_calls_executed,
function_calls, 2),
function_calls, function_name);
fnotice (stdout, "No branches in %s %s\n", title, function->name);
if (function->calls)
fnotice (stdout, "%s of %d calls executed in %s %s\n",
format_hwint (function->calls_executed,
function->calls, 2),
function->calls, title, function->name);
else
fnotice (stdout, "No calls in function %s\n", function_name);
fnotice (stdout, "No calls in %s %s\n", title, function->name);
}
}
/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
affect name generation. With preserve_paths we create a filename
from all path components of the source file, replacing '/' with
'#', without it we simply take the basename component. With
long_output_names we prepend the processed name of the input file
to each output name (except when the current source file is the
input file, so you don't get a double concatenation). The two
components are separated by '##'. Also '.' filename components are
removed and '..' components are renamed to '^'. */
static char *
make_gcov_file_name (src_name)
char *src_name;
{
char *cptr;
char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
name[0] = 0;
if (output_long_names && strcmp (src_name, input_file_name))
{
/* Generate the input filename part. */
cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
cptr = cptr ? cptr + 1 : input_file_name;
strcat (name, cptr);
strcat (name, "##");
}
/* Generate the source filename part. */
cptr = preserve_paths ? NULL : strrchr (src_name, '/');
cptr = cptr ? cptr + 1 : src_name;
strcat (name, cptr);
if (preserve_paths)
{
/* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
char *prev;
for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
{
unsigned shift = 0;
if (prev + 1 == cptr && prev[0] == '.')
{
/* Remove '.' */
shift = 2;
}
else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
{
/* Convert '..' */
shift = 1;
prev[1] = '^';
}
else
*cptr++ = '#';
if (shift)
{
cptr = prev;
do
prev[0] = prev[shift];
while (*prev++);
}
}
}
/* Don't strip off the ending for compatibility with tcov, since
this results in confusion if there is more than one file with the
same basename, e.g. tmp.c and tmp.h. */
strcat (name, ".gcov");
return name;
}
/* Calculate line execution counts, and output the data to a .tcov file. */
/* Scan through the bb_data, and when the file name matches the
source file name, then for each following line number, increment
the line number execution count indicated by the execution count of
the appropriate basic block. */
static void
output_data ()
init_line_info (line_info, total, maxlineno)
struct line_info *line_info;
struct coverage *total;
long maxlineno;
{
/* When scanning data, this is true only if the data applies to the
current source file. */
int this_file;
/* An array indexed by line number which indicates how many times that line
was executed. */
gcov_type *line_counts;
/* An array indexed by line number which indicates whether the line was
present in the bb file (i.e. whether it had code associate with it).
Lines never executed are those which both exist, and have zero execution
counts. */
char *line_exists;
/* An array indexed by line number, which contains a list of branch
probabilities, one for each branch on that line. */
struct arcdata **branch_probs = NULL;
struct sourcefile *s_ptr;
char *source_file_name;
FILE *source_file;
struct bb_info_list *current_graph;
long block_num = 0; /* current block number */
struct bb_info *block_ptr = NULL; /* current block ptr */
struct coverage function;
struct coverage *func_ptr = NULL;
struct bb_info_list *current_graph = NULL; /* Graph for current function. */
int is_this_file = 0; /* We're scanning a block from the desired file. */
char *ptr = bb_data;
long count;
char *cptr;
long block_num;
long line_num;
long last_line_num = 0;
int i;
struct arcdata *a_ptr;
/* Buffer used for reading in lines from the source file. */
char string[STRING_SIZE];
/* For calculating coverage at the file level. */
int total_source_lines;
int total_source_lines_executed;
int total_branches;
int total_branches_executed;
int total_branches_taken;
int total_calls;
int total_calls_executed;
/* Now, for each source file, allocate an array big enough to hold a count
for each line. Scan through the bb_data, and when the file name matches
the current file name, then for each following line number, increment
the line number execution count indicated by the execution count of
the appropriate basic block. */
for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
struct line_info *line_ptr; /* line info ptr. */
memset (&function, 0, sizeof (function));
if (output_function_summary)
func_ptr = &function;
for (count = 0; count < bb_data_size; count++)
{
source_file_name = s_ptr->name;
line_counts = (gcov_type *) xcalloc (sizeof (gcov_type), s_ptr->maxlineno);
line_exists = xcalloc (1, s_ptr->maxlineno);
if (output_branch_probs)
branch_probs = (struct arcdata **)
xcalloc (sizeof (struct arcdata *), s_ptr->maxlineno);
/* There will be a zero at the beginning of the bb info, before the
first list of line numbers, so must initialize block_num to 0. */
block_num = 0;
this_file = 0;
current_graph = 0;
{
/* Pointer into the bb_data, incremented while scanning the data. */
char *ptr = bb_data;
for (count = 0; count < bb_data_size; count++)
{
long delim;
__fetch_long (&line_num, ptr, 4);
ptr += 4;
if (line_num == -1)
{
/* Marks the beginning of a file name. Check to see whether
this is the filename we are currently collecting data for. */
if (strcmp (s_ptr->name, ptr))
this_file = 0;
else
this_file = 1;
/* Scan past the file name. */
do {
count++;
__fetch_long (&delim, ptr, 4);
ptr += 4;
} while (delim != line_num);
}
else if (line_num == -2)
{
/* Marks the start of a new function. Advance to the next
program flow graph. */
if (! current_graph)
current_graph = bb_graph_list;
else
{
if (block_num == current_graph->num_blocks - 1)
/* Last block falls through to exit. */
;
else if (block_num == current_graph->num_blocks - 2)
{
if (output_branch_probs && this_file)
calculate_branch_probs (current_graph, block_num,
branch_probs, last_line_num);
}
else
{
fnotice (stderr,
"didn't use all bb entries of graph, function %s\n",
function_name);
fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
block_num, current_graph->num_blocks);
}
current_graph = current_graph->next;
block_num = 0;
if (output_function_summary && this_file)
function_summary ();
}
if (output_function_summary)
{
function_source_lines = 0;
function_source_lines_executed = 0;
function_branches = 0;
function_branches_executed = 0;
function_branches_taken = 0;
function_calls = 0;
function_calls_executed = 0;
}
/* Save the function name for later use. */
function_name = ptr;
/* Scan past the file name. */
do {
count++;
__fetch_long (&delim, ptr, 4);
ptr += 4;
} while (delim != line_num);
}
else if (line_num == 0)
{
/* Marks the end of a block. */
if (block_num >= current_graph->num_blocks)
{
fnotice (stderr, "ERROR: too many basic blocks in .bb file %s\n",
function_name);
abort ();
}
if (output_branch_probs && this_file)
calculate_branch_probs (current_graph, block_num,
branch_probs, last_line_num);
block_num++;
}
else if (this_file)
{
if (output_function_summary)
{
if (line_exists[line_num] == 0)
function_source_lines++;
if (line_counts[line_num] == 0
&& current_graph->bb_graph[block_num].exec_count != 0)
function_source_lines_executed++;
}
/* Accumulate execution data for this line number. */
line_counts[line_num]
+= current_graph->bb_graph[block_num].exec_count;
line_exists[line_num] = 1;
last_line_num = line_num;
}
}
}
if (output_function_summary && this_file)
function_summary ();
/* Calculate summary test coverage statistics. */
total_source_lines = 0;
total_source_lines_executed = 0;
total_branches = 0;
total_branches_executed = 0;
total_branches_taken = 0;
total_calls = 0;
total_calls_executed = 0;
for (count = 1; count < s_ptr->maxlineno; count++)
__fetch_long (&line_num, ptr, 4);
ptr += 4;
if (line_num < 0)
{
if (line_exists[count])
long delim;
if (line_num == -1)
{
total_source_lines++;
if (line_counts[count])
total_source_lines_executed++;
/* Marks the beginning of a file name. Check to see
whether this is the filename we are currently
collecting data for. */
is_this_file = !strcmp (total->name, ptr);
}
if (output_branch_probs)
else if (line_num == -2)
{
for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
/* Marks the start of a new function. Advance to the
next program flow graph. */
if (!current_graph)
current_graph = bb_graph_list;
else
{
if (a_ptr->call_insn)
if (block_num == current_graph->num_blocks - 1)
/* Last block falls through to exit. */
;
else if (block_num == current_graph->num_blocks - 2)
{
total_calls++;
if (a_ptr->total != 0)
total_calls_executed++;
if (output_branch_probs && is_this_file)
calculate_branch_probs (block_ptr, line_ptr, func_ptr);
}
else
{
total_branches++;
if (a_ptr->total != 0)
total_branches_executed++;
if (a_ptr->hits > 0)
total_branches_taken++;
fnotice (stderr,
"didn't use all bb entries of graph, function %s\n",
function.name);
fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
block_num, current_graph->num_blocks);
}
if (func_ptr && is_this_file)
function_summary (func_ptr, "function");
current_graph = current_graph->next;
}
block_num = 0;
block_ptr = current_graph->bb_graph;
memset (&function, 0, sizeof (function));
function.name = ptr;
}
else
{
fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
abort ();
}
}
if (total_source_lines)
fnotice (stdout,
"%s of %d source lines executed in file %s\n",
format_hwint (total_source_lines_executed,
total_source_lines, 2),
total_source_lines, source_file_name);
else
fnotice (stdout, "No executable source lines in file %s\n",
source_file_name);
if (output_branch_probs)
/* Scan past the string. */
for (delim = 0; delim != line_num; count++)
{
__fetch_long (&delim, ptr, 4);
ptr += 4;
}
}
else if (!line_num)
{
if (total_branches)
/* Marks the end of a block. */
if (block_num >= current_graph->num_blocks)
{
fnotice (stdout, "%s of %d branches executed in file %s\n",
format_hwint (total_branches_executed,
total_branches, 2),
total_branches, source_file_name);
fnotice (stdout,
"%s of %d branches taken at least once in file %s\n",
format_hwint (total_branches_taken,
total_branches, 2),
total_branches, source_file_name);
fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
function.name);
abort ();
}
else
fnotice (stdout, "No branches in file %s\n", source_file_name);
if (total_calls)
fnotice (stdout, "%s of %d calls executed in file %s\n",
format_hwint (total_calls_executed, total_calls, 2),
total_calls, source_file_name);
else
fnotice (stdout, "No calls in file %s\n", source_file_name);
if (output_branch_probs && is_this_file)
calculate_branch_probs (block_ptr, line_ptr, func_ptr);
block_num++;
block_ptr++;
}
if (output_gcov_file)
else if (is_this_file)
{
/* Now the statistics are ready. Read in the source file one line
at a time, and output that line to the gcov file preceded by
its execution count if non zero. */
char const *retval;
/* Generate an output file name. LONG_OUTPUT_NAMES and
PRESERVE_PATHS affect name generation. With
preserve_paths we create a filename from all path
components of the source file, replacing '/' with '#',
without it we simply take the basename component. With
long_output_names we prepend the processed name of the
input file to each output name (except when the current
source file is the input file, so you don't get a double
concatenation). The two components are separated by
'##'. Also '.' filename components are removed and '..'
components are renamed to '^'. */
gcov_file_name = xmalloc (strlen (source_file_name)
+ strlen (input_file_name) + 10);
gcov_file_name[0] = 0;
if (output_long_names && strcmp (source_file_name, input_file_name))
if (line_num >= maxlineno)
{
/* Generate the input filename part. */
cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
cptr = cptr ? cptr + 1 : input_file_name;
strcat (gcov_file_name, cptr);
strcat (gcov_file_name, "##");
fnotice (stderr, "ERROR: out of range line number in function %s\n",
function.name);
abort ();
}
/* Generate the source filename part. */
cptr = preserve_paths ? NULL : strrchr (source_file_name, '/');
cptr = cptr ? cptr + 1 : source_file_name;
strcat (gcov_file_name, cptr);
if (preserve_paths)
line_ptr = &line_info[line_num];
if (func_ptr)
{
/* Convert '/' to '#', remove '/./', convert '/../' to
'/^/' */
char *prev;
for (cptr = gcov_file_name;
(cptr = strchr ((prev = cptr), '/'));)
{
unsigned shift = 0;
if (prev + 1 == cptr && prev[0] == '.')
{
/* Remove '.' */
shift = 2;
}
else if (prev + 2 == cptr
&& prev[0] == '.' && prev[1] == '.')
{
/* Convert '..' */
shift = 1;
prev[1] = '^';
}
else
*cptr++ = '#';
if (shift)
{
cptr = prev;
do
prev[0] = prev[shift];
while (*prev++);
}
}
if (!line_ptr->exists)
func_ptr->lines++;
if (!line_ptr->count && block_ptr->exec_count)
func_ptr->lines_executed++;
}
/* Don't strip off the ending for compatibility with tcov, since
this results in confusion if there is more than one file with
the same basename, e.g. tmp.c and tmp.h. */
strcat (gcov_file_name, ".gcov");
/* Accumulate execution data for this line number. */
line_ptr->count += block_ptr->exec_count;
line_ptr->exists = 1;
}
}
if (func_ptr && is_this_file)
function_summary (func_ptr, "function");
/* Calculate summary test coverage statistics. */
for (line_num = 1, line_ptr = &line_info[line_num];
line_num < maxlineno; line_num++, line_ptr++)
{
struct arcdata *a_ptr, *prev, *next;
if (line_ptr->exists)
{
total->lines++;
if (line_ptr->count)
total->lines_executed++;
}
gcov_file = fopen (gcov_file_name, "w");
/* Total and reverse the branch information. */
for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
{
next = a_ptr->next;
a_ptr->next = prev;
prev = a_ptr;
if (gcov_file == NULL)
{
fnotice (stderr, "Could not open output file %s.\n",
gcov_file_name);
free (line_counts);
free (line_exists);
continue;
}
accumulate_branch_counts (total, a_ptr);
}
line_ptr->branches = prev;
}
}
fnotice (stdout, "Creating %s.\n", gcov_file_name);
/* Read in the source file one line at a time, and output that line to
the gcov file preceded by its execution count and other
information. */
fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, source_file_name);
fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
source_file = fopen (source_file_name, "r");
if (source_file == NULL)
fnotice (stderr, "Could not open source file %s.\n",
source_file_name);
else
{
struct stat status;
static void
output_line_info (gcov_file, line_info, total, maxlineno)
FILE *gcov_file;
const struct line_info *line_info;
const struct coverage *total;
long maxlineno;
{
FILE *source_file;
long line_num; /* current line number */
const struct line_info *line_ptr; /* current line info ptr. */
char string[STRING_SIZE]; /* line buffer. */
char const *retval = ""; /* status of source file reading. */
if (!fstat (fileno (source_file), &status)
&& status.st_mtime > bb_file_time)
fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
source_file = fopen (total->name, "r");
if (!source_file)
{
fnotice (stderr, "Could not open source file %s.\n", total->name);
retval = NULL;
}
else
{
struct stat status;
if (!fstat (fileno (source_file), &status)
&& status.st_mtime > bb_file_time)
{
fnotice (stderr, "Warning: source file %s is newer than %s\n",
total->name, bb_file_name);
fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
"-", 0);
}
}
for (line_num = 1, line_ptr = &line_info[line_num];
line_num < maxlineno; line_num++, line_ptr++)
{
/* For lines which don't exist in the .bb file, print '-' before
the source line. For lines which exist but were never
executed, print '#####' before the source line. Otherwise,
print the execution count before the source line. There are
16 spaces of indentation added before the source line so that
tabs won't be messed up. */
fprintf (gcov_file, "%9s:%5ld:",
!line_ptr->exists ? "-"
: !line_ptr->count ? "#####"
: format_hwint (line_ptr->count, 0, -1), line_num);
if (retval)
{
/* Copy source line. */
do
{
retval = fgets (string, STRING_SIZE, source_file);
if (!retval)
{
fnotice (stderr, "Warning: source file %s is newer than %s\n",
source_file_name, bb_file_name);
fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n", "-", 0);
fnotice (stderr,
"Unexpected EOF while reading source file %s.\n",
total->name);
break;
}
fputs (retval, gcov_file);
}
while (!retval[0] || retval[strlen (retval) - 1] != '\n');
}
if (!retval)
fputs ("??\n", gcov_file);
if (output_branch_probs)
{
int i;
struct arcdata *a_ptr;
for (retval = source_file ? "" : NULL, count = 1;
count < s_ptr->maxlineno; count++)
for (i = 0, a_ptr = line_ptr->branches; a_ptr;
a_ptr = a_ptr->next, i++)
{
/* For lines which don't exist in the .bb file, print
'-' before the source line. For lines which exist
but were never executed, print '#####' before the source
line. Otherwise, print the execution count before
the source line. */
/* There are 16 spaces of indentation added before the source
line so that tabs won't be messed up. */
fprintf (gcov_file, "%9s:%5ld:",
!line_exists[count] ? "-"
: !line_counts[count] ? "#####"
: format_hwint (line_counts[count], 0, -1), count);
if (retval)
if (a_ptr->call_insn)
{
do
{
retval = fgets (string, STRING_SIZE, source_file);
if (!retval)
{
fnotice (stderr,
"Unexpected EOF while reading source file %s.\n",
source_file_name);
break;
}
fputs (retval, gcov_file);
}
while (!retval[0] || retval[strlen (retval) - 1] != '\n');
if (a_ptr->total == 0)
fnotice (gcov_file, "call %2d never executed\n", i);
else
fnotice
(gcov_file, "call %2d returns %s\n", i,
format_hwint (a_ptr->total - a_ptr->hits,
a_ptr->total,
-output_branch_counts));
}
if (!retval)
fputs ("??\n", gcov_file);
if (output_branch_probs)
else
{
for (i = 0, a_ptr = branch_probs[count]; a_ptr;
a_ptr = a_ptr->next, i++)
{
if (a_ptr->call_insn)
{
if (a_ptr->total == 0)
fnotice (gcov_file, "call %2d never executed\n", i);
else
fnotice
(gcov_file, "call %2d returns %s\n", i,
format_hwint (a_ptr->total - a_ptr->hits,
a_ptr->total,
-output_branch_counts));
}
else
{
if (a_ptr->total == 0)
fnotice (gcov_file, "branch %2d never executed\n",
i);
else
fnotice
(gcov_file, "branch %2d taken %s\n", i,
format_hwint (a_ptr->hits, a_ptr->total,
-output_branch_counts));
}
}
}
if (a_ptr->total == 0)
fnotice (gcov_file, "branch %2d never executed\n", i);
else
fnotice
(gcov_file, "branch %2d taken %s\n", i,
format_hwint (a_ptr->hits, a_ptr->total,
-output_branch_counts));
}
}
/* Handle all remaining source lines. There may be lines
after the last line of code. */
if (retval)
}
}
/* Handle all remaining source lines. There may be lines after the
last line of code. */
if (retval)
{
for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
{
fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
while (!retval[0] || retval[strlen (retval) - 1] != '\n')
{
for (; (retval = fgets (string, STRING_SIZE, source_file));
count++)
{
fprintf (gcov_file, "%9s:%5ld:%s", "-", count, retval);
while (!retval[0] || retval[strlen (retval) - 1] != '\n')
{
retval = fgets (string, STRING_SIZE, source_file);
if (!retval)
break;
fputs (retval, gcov_file);
}
}
retval = fgets (string, STRING_SIZE, source_file);
if (!retval)
break;
fputs (retval, gcov_file);
}
}
}
if (source_file)
fclose (source_file);
}
/* Calculate line execution counts, and output a .gcov file for source
file S_PTR. Allocate an array big enough to hold a count for each
line. Scan through the bb_data, and when the file name matches the
current file name, then for each following line number, increment
the line number execution count indicated by the execution count of
the appropriate basic block. */
static void
output_data (s_ptr)
struct sourcefile *s_ptr;
{
struct line_info *line_info /* line info data */
= (struct line_info *) xcalloc (s_ptr->maxlineno,
sizeof (struct line_info));
long line_num;
struct coverage total;
memset (&total, 0, sizeof (total));
total.name = s_ptr->name;
init_line_info (line_info, &total, s_ptr->maxlineno);
function_summary (&total, "file");
if (source_file)
fclose (source_file);
if (output_gcov_file)
{
/* Now the statistics are ready. Read in the source file one
line at a time, and output that line to the gcov file
preceded by its execution information. */
char *gcov_file_name = make_gcov_file_name (total.name);
FILE *gcov_file = fopen (gcov_file_name, "w");
if (gcov_file)
{
fnotice (stdout, "Creating %s.\n", gcov_file_name);
output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
if (ferror (gcov_file))
fnotice (stderr, "Error writing output file %s.\n",
gcov_file_name);
fclose (gcov_file);
}
else
fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
free (gcov_file_name);
}
/* Free data. */
for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
{
struct arcdata *branch, *next;
free (line_counts);
free (line_exists);
for (branch = line_info[line_num].branches; branch; branch = next)
{
next = branch->next;
free (branch);
}
}
free (line_info);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment