#include "config.h"
#include "system.h"
#include "intl.h"
#include "version.h"
#undef abort
#include <getopt.h>
typedef HOST_WIDEST_INT gcov_type;
#include "gcov-io.h"
#define STRING_SIZE 200
struct sourcefile
{
char *name;
int maxlineno;
struct sourcefile *next;
};
struct sourcefile *sources;
struct adj_list {
int source;
int target;
gcov_type arc_count;
unsigned int count_valid : 1;
unsigned int on_tree : 1;
unsigned int fake : 1;
unsigned int fall_through : 1;
#if 0
rtx branch_insn;
#endif
struct adj_list *pred_next;
struct adj_list *succ_next;
};
struct bb_info {
struct adj_list *succ;
struct adj_list *pred;
gcov_type succ_count;
gcov_type pred_count;
gcov_type exec_count;
unsigned int count_valid : 1;
unsigned int on_tree : 1;
#if 0
rtx first_insn;
#endif
};
struct arcdata
{
gcov_type hits;
gcov_type total;
int call_insn;
struct arcdata *next;
};
struct bb_info_list {
struct bb_info *bb_graph;
int num_blocks;
struct bb_info_list *next;
};
static struct bb_info_list *bb_graph_list = 0;
static char *bbg_file_name;
static FILE *bbg_file;
static char *da_file_name;
static FILE *da_file;
static char *bb_file_name;
static FILE *bb_file;
static char *bb_data;
static long bb_data_size;
static char *gcov_file_name;
static FILE *gcov_file;
static char *input_file_name = 0;
static int output_branch_probs = 0;
static int output_gcov_file = 1;
static int output_long_names = 0;
static int output_function_summary = 0;
static char *object_directory = 0;
static int output_branch_counts = 0;
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 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 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));
extern int main PARAMS ((int, char **));
int
main (argc, argv)
int argc;
char **argv;
{
gcc_init_libintl ();
process_args (argc, argv);
open_files ();
read_files ();
scan_for_source_files ();
output_data ();
return 0;
}
static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
static void
fnotice VPARAMS ((FILE *file, const char *msgid, ...))
{
VA_OPEN (ap, msgid);
VA_FIXEDARG (ap, FILE *, file);
VA_FIXEDARG (ap, const char *, msgid);
vfprintf (file, _(msgid), ap);
VA_CLOSE (ap);
}
extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
void
fancy_abort ()
{
fnotice (stderr, "Internal gcov abort.\n");
exit (FATAL_EXIT_CODE);
}
static void
print_usage (error_p)
int error_p;
{
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, "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");
fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
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");
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",
GCCBUGURL);
exit (status);
}
static void
print_version ()
{
fnotice (stdout, "gcov (GCC) %s\n", version_string);
fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
fnotice (stdout,
"This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
exit (SUCCESS_EXIT_CODE);
}
static const struct option options[] =
{
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "branch-probabilities", no_argument, NULL, 'b' },
{ "branch-counts", no_argument, NULL, 'c' },
{ "no-output", no_argument, NULL, 'n' },
{ "long-file-names", no_argument, NULL, 'l' },
{ "function-summaries", no_argument, NULL, 'f' },
{ "object-directory", required_argument, NULL, 'o' }
};
static void
process_args (argc, argv)
int argc;
char **argv;
{
int opt;
while ((opt = getopt_long (argc, argv, "hvbclnfo:", options, NULL)) != -1)
{
switch (opt)
{
case 'h':
print_usage (false);
case 'v':
print_version ();
case 'b':
output_branch_probs = 1;
break;
case 'c':
output_branch_counts = 1;
break;
case 'n':
output_gcov_file = 0;
break;
case 'l':
output_long_names = 1;
break;
case 'f':
output_function_summary = 1;
break;
case 'o':
object_directory = optarg;
break;
default:
print_usage (true);
}
}
if (optind != argc - 1)
print_usage (true);
input_file_name = argv[optind];
}
static void
open_files ()
{
int count, objdir_count;
char *cptr;
count = strlen (input_file_name);
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);
if (object_directory)
{
strcpy (da_file_name, object_directory);
strcpy (bb_file_name, object_directory);
strcpy (bbg_file_name, object_directory);
if (object_directory[objdir_count - 1] != '/')
{
strcat (da_file_name, "/");
strcat (bb_file_name, "/");
strcat (bbg_file_name, "/");
}
cptr = strrchr (input_file_name, '/');
if (cptr)
{
strcat (da_file_name, cptr + 1);
strcat (bb_file_name, cptr + 1);
strcat (bbg_file_name, cptr + 1);
}
else
{
strcat (da_file_name, input_file_name);
strcat (bb_file_name, input_file_name);
strcat (bbg_file_name, input_file_name);
}
}
else
{
strcpy (da_file_name, input_file_name);
strcpy (bb_file_name, input_file_name);
strcpy (bbg_file_name, input_file_name);
}
cptr = strrchr (bb_file_name, '.');
if (cptr)
strcpy (cptr, ".bb");
else
strcat (bb_file_name, ".bb");
cptr = strrchr (da_file_name, '.');
if (cptr)
strcpy (cptr, ".da");
else
strcat (da_file_name, ".da");
cptr = strrchr (bbg_file_name, '.');
if (cptr)
strcpy (cptr, ".bbg");
else
strcat (bbg_file_name, ".bbg");
bb_file = fopen (bb_file_name, "rb");
if (bb_file == NULL)
{
fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
exit (FATAL_EXIT_CODE);
}
da_file = fopen (da_file_name, "rb");
if (da_file == NULL)
{
fnotice (stderr, "Could not open data file %s.\n", da_file_name);
fnotice (stderr, "Assuming that all execution counts are zero.\n");
}
bbg_file = fopen (bbg_file_name, "rb");
if (bbg_file == NULL)
{
fnotice (stderr, "Could not open program flow graph file %s.\n",
bbg_file_name);
exit (FATAL_EXIT_CODE);
}
ungetc (getc (bbg_file), bbg_file);
if (feof (bbg_file))
{
fnotice (stderr, "No executable code associated with file %s.\n",
input_file_name);
exit (FATAL_EXIT_CODE);
}
}
static void
init_arc (arcptr, source, target, bb_graph)
struct adj_list *arcptr;
int source, target;
struct bb_info *bb_graph;
{
arcptr->target = target;
arcptr->source = source;
arcptr->arc_count = 0;
arcptr->count_valid = 0;
arcptr->on_tree = 0;
arcptr->fake = 0;
arcptr->fall_through = 0;
arcptr->succ_next = bb_graph[source].succ;
bb_graph[source].succ = arcptr;
bb_graph[source].succ_count++;
arcptr->pred_next = bb_graph[target].pred;
bb_graph[target].pred = arcptr;
bb_graph[target].pred_count++;
}
static struct adj_list *
reverse_arcs (arcptr)
struct adj_list *arcptr;
{
struct adj_list *prev = 0;
struct adj_list *next;
for ( ; arcptr; arcptr = next)
{
next = arcptr->succ_next;
arcptr->succ_next = prev;
prev = arcptr;
}
return prev;
}
static void
create_program_flow_graph (bptr)
struct bb_info_list *bptr;
{
long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
int i;
struct adj_list *arcptr;
struct bb_info *bb_graph;
__read_long (&num_blocks, bbg_file, 4);
bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
bptr->bb_graph = bb_graph;
bptr->num_blocks = num_blocks;
__read_long (&number_arcs, bbg_file, 4);
for (i = 0; i < num_blocks; i++)
{
int j;
__read_long (&num_arcs_per_block, bbg_file, 4);
for (j = 0; j < num_arcs_per_block; j++)
{
if (number_arcs-- < 0)
abort ();
src = i;
__read_long (&dest, bbg_file, 4);
arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
init_arc (arcptr, src, dest, bb_graph);
__read_long (&flag_bits, bbg_file, 4);
arcptr->on_tree = flag_bits & 0x1;
arcptr->fake = !! (flag_bits & 0x2);
arcptr->fall_through = !! (flag_bits & 0x4);
}
}
if (number_arcs)
abort ();
__read_long (&src, bbg_file, 4);
if (src != -1)
abort ();
for (i = 0; i < num_blocks; i++)
if (bb_graph[i].succ)
bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
for (i = 0; i < num_blocks; i++)
for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
if (! arcptr->on_tree)
{
gcov_type tmp_count = 0;
if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
abort ();
arcptr->arc_count = tmp_count;
arcptr->count_valid = 1;
bb_graph[i].succ_count--;
bb_graph[arcptr->target].pred_count--;
}
}
static void
solve_program_flow_graph (bptr)
struct bb_info_list *bptr;
{
int passes, changes;
gcov_type total;
int i;
struct adj_list *arcptr;
struct bb_info *bb_graph;
int num_blocks;
num_blocks = bptr->num_blocks;
bb_graph = bptr->bb_graph;
changes = 1;
passes = 0;
while (changes)
{
passes++;
changes = 0;
for (i = num_blocks - 1; i >= 0; i--)
{
if (! bb_graph[i].count_valid)
{
if (bb_graph[i].succ_count == 0)
{
total = 0;
for (arcptr = bb_graph[i].succ; arcptr;
arcptr = arcptr->succ_next)
total += arcptr->arc_count;
bb_graph[i].exec_count = total;
bb_graph[i].count_valid = 1;
changes = 1;
}
else if (bb_graph[i].pred_count == 0)
{
total = 0;
for (arcptr = bb_graph[i].pred; arcptr;
arcptr = arcptr->pred_next)
total += arcptr->arc_count;
bb_graph[i].exec_count = total;
bb_graph[i].count_valid = 1;
changes = 1;
}
}
if (bb_graph[i].count_valid)
{
if (bb_graph[i].succ_count == 1)
{
total = 0;
for (arcptr = bb_graph[i].succ; arcptr;
arcptr = arcptr->succ_next)
total += arcptr->arc_count;
total = bb_graph[i].exec_count - total;
for (arcptr = bb_graph[i].succ; arcptr;
arcptr = arcptr->succ_next)
if (! arcptr->count_valid)
break;
if (! arcptr)
abort ();
arcptr->count_valid = 1;
arcptr->arc_count = total;
bb_graph[i].succ_count--;
bb_graph[arcptr->target].pred_count--;
changes = 1;
}
if (bb_graph[i].pred_count == 1)
{
total = 0;
for (arcptr = bb_graph[i].pred; arcptr;
arcptr = arcptr->pred_next)
total += arcptr->arc_count;
total = bb_graph[i].exec_count - total;
for (arcptr = bb_graph[i].pred; arcptr;
arcptr = arcptr->pred_next)
if (! arcptr->count_valid)
break;
if (! arcptr)
abort ();
arcptr->count_valid = 1;
arcptr->arc_count = total;
bb_graph[i].pred_count--;
bb_graph[arcptr->source].succ_count--;
changes = 1;
}
}
}
}
for (i = 0; i < num_blocks; i++)
if (bb_graph[i].succ_count || bb_graph[i].pred_count)
abort ();
}
static void
read_files ()
{
struct stat buf;
struct bb_info_list *list_end = 0;
struct bb_info_list *b_ptr;
long total;
if (da_file && __read_long (&total, da_file, 8))
abort ();
while (! feof (bbg_file))
{
b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
b_ptr->next = 0;
if (list_end)
list_end->next = b_ptr;
else
bb_graph_list = b_ptr;
list_end = b_ptr;
create_program_flow_graph (b_ptr);
ungetc (getc (bbg_file), bbg_file);
}
if (da_file)
{
if (feof (da_file))
fnotice (stderr, ".da file contents exhausted too early\n");
if (__read_long (&total, da_file, 8) == 0)
fnotice (stderr, ".da file contents not exhausted\n");
}
for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
solve_program_flow_graph (b_ptr);
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);
fclose (bb_file);
if (da_file)
fclose (da_file);
fclose (bbg_file);
}
static void
scan_for_source_files ()
{
struct sourcefile *s_ptr = NULL;
char *ptr;
long count;
long line_num;
ptr = bb_data;
sources = 0;
for (count = 0; count < bb_data_size; count++)
{
__fetch_long (&line_num, ptr, 4);
ptr += 4;
if (line_num == -1)
{
s_ptr = sources;
while (s_ptr && strcmp (s_ptr->name, ptr))
s_ptr = s_ptr->next;
if (s_ptr == 0)
{
s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
s_ptr->name = xstrdup (ptr);
s_ptr->maxlineno = 0;
s_ptr->next = sources;
sources = s_ptr;
}
{
long delim;
do {
count++;
__fetch_long (&delim, ptr, 4);
ptr += 4;
} while (delim != line_num);
}
}
else if (line_num == -2)
{
long delim;
do {
count++;
__fetch_long (&delim, ptr, 4);
ptr += 4;
} while (delim != line_num);
}
else if (line_num > 0)
{
if (s_ptr->maxlineno <= line_num)
s_ptr->maxlineno = line_num + 1;
}
else if (line_num < 0)
{
abort ();
}
}
}
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;
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;
{
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)
{
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->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++;
}
}
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;
}
}
}
static void
function_summary ()
{
if (function_source_lines)
fnotice (stdout, "%6.2f%% of %d source lines executed in function %s\n",
(((double) function_source_lines_executed / function_source_lines)
* 100), function_source_lines, function_name);
else
fnotice (stdout, "No executable source lines in function %s\n",
function_name);
if (output_branch_probs)
{
if (function_branches)
{
fnotice (stdout, "%6.2f%% of %d branches executed in function %s\n",
(((double) function_branches_executed / function_branches)
* 100), function_branches, function_name);
fnotice (stdout,
"%6.2f%% of %d branches taken at least once in function %s\n",
(((double) function_branches_taken / function_branches)
* 100), function_branches, function_name);
}
else
fnotice (stdout, "No branches in function %s\n", function_name);
if (function_calls)
fnotice (stdout, "%6.2f%% of %d calls executed in function %s\n",
(((double) function_calls_executed / function_calls)
* 100), function_calls, function_name);
else
fnotice (stdout, "No calls in function %s\n", function_name);
}
}
static void
output_data ()
{
int this_file;
gcov_type *line_counts;
char *line_exists;
struct arcdata **branch_probs = NULL;
struct sourcefile *s_ptr;
char *source_file_name;
FILE *source_file;
struct bb_info_list *current_graph;
long count;
char *cptr;
long block_num;
long line_num;
long last_line_num = 0;
int i;
struct arcdata *a_ptr;
char string[STRING_SIZE];
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;
for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
{
if (! IS_ABSOLUTE_PATHNAME (s_ptr->name)
&& object_directory != 0
&& *object_directory != '\0')
{
int objdir_count = strlen (object_directory);
source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2);
strcpy (source_file_name, object_directory);
if (object_directory[objdir_count - 1] != '/')
source_file_name[objdir_count++] = '/';
strcpy (source_file_name + objdir_count, s_ptr->name);
}
else
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);
block_num = 0;
this_file = 0;
current_graph = 0;
{
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)
{
if (strcmp (s_ptr->name, ptr))
this_file = 0;
else
this_file = 1;
do {
count++;
__fetch_long (&delim, ptr, 4);
ptr += 4;
} while (delim != line_num);
}
else if (line_num == -2)
{
if (! current_graph)
current_graph = bb_graph_list;
else
{
if (block_num == current_graph->num_blocks - 1)
;
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;
}
function_name = ptr;
do {
count++;
__fetch_long (&delim, ptr, 4);
ptr += 4;
} while (delim != line_num);
}
else if (line_num == 0)
{
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++;
}
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 ();
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++)
{
if (line_exists[count])
{
total_source_lines++;
if (line_counts[count])
total_source_lines_executed++;
}
if (output_branch_probs)
{
for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
{
if (a_ptr->call_insn)
{
total_calls++;
if (a_ptr->total != 0)
total_calls_executed++;
}
else
{
total_branches++;
if (a_ptr->total != 0)
total_branches_executed++;
if (a_ptr->hits > 0)
total_branches_taken++;
}
}
}
}
if (total_source_lines)
fnotice (stdout,
"%6.2f%% of %d source lines executed in file %s\n",
(((double) total_source_lines_executed / total_source_lines)
* 100), total_source_lines, source_file_name);
else
fnotice (stdout, "No executable source lines in file %s\n",
source_file_name);
if (output_branch_probs)
{
if (total_branches)
{
fnotice (stdout, "%6.2f%% of %d branches executed in file %s\n",
(((double) total_branches_executed / total_branches)
* 100), total_branches, source_file_name);
fnotice (stdout,
"%6.2f%% of %d branches taken at least once in file %s\n",
(((double) total_branches_taken / total_branches)
* 100), total_branches, source_file_name);
}
else
fnotice (stdout, "No branches in file %s\n", source_file_name);
if (total_calls)
fnotice (stdout, "%6.2f%% of %d calls executed in file %s\n",
(((double) total_calls_executed / total_calls)
* 100), total_calls, source_file_name);
else
fnotice (stdout, "No calls in file %s\n", source_file_name);
}
if (output_gcov_file)
{
source_file = fopen (source_file_name, "r");
if (source_file == NULL)
{
fnotice (stderr, "Could not open source file %s.\n",
source_file_name);
free (line_counts);
free (line_exists);
continue;
}
count = strlen (source_file_name);
cptr = strrchr (s_ptr->name, '/');
if (cptr)
cptr = cptr + 1;
else
cptr = s_ptr->name;
if (output_long_names && strcmp (cptr, input_file_name))
{
gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
cptr = strrchr (input_file_name, '/');
if (cptr)
strcpy (gcov_file_name, cptr + 1);
else
strcpy (gcov_file_name, input_file_name);
strcat (gcov_file_name, ".");
cptr = strrchr (source_file_name, '/');
if (cptr)
strcat (gcov_file_name, cptr + 1);
else
strcat (gcov_file_name, source_file_name);
}
else
{
gcov_file_name = xmalloc (count + 6);
cptr = strrchr (source_file_name, '/');
if (cptr)
strcpy (gcov_file_name, cptr + 1);
else
strcpy (gcov_file_name, source_file_name);
}
strcat (gcov_file_name, ".gcov");
gcov_file = fopen (gcov_file_name, "w");
if (gcov_file == NULL)
{
fnotice (stderr, "Could not open output file %s.\n",
gcov_file_name);
fclose (source_file);
free (line_counts);
free (line_exists);
continue;
}
fnotice (stdout, "Creating %s.\n", gcov_file_name);
for (count = 1; count < s_ptr->maxlineno; count++)
{
char *retval;
int len;
retval = fgets (string, STRING_SIZE, source_file);
if (line_exists[count])
{
if (line_counts[count])
{
char c[20];
sprintf (c, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)line_counts[count]);
fprintf (gcov_file, "%12s %s", c,
string);
}
else
fprintf (gcov_file, " ###### %s", string);
}
else
fprintf (gcov_file, "\t\t%s", string);
len = strlen (string);
while ((len == 0 || string[strlen (string) - 1] != '\n')
&& retval != NULL)
{
retval = fgets (string, STRING_SIZE, source_file);
fputs (string, gcov_file);
}
if (output_branch_probs)
{
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 %d never executed\n", i);
else
{
if (output_branch_counts)
{
char c[20];
sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
a_ptr->total - a_ptr->hits);
fnotice (gcov_file,
"call %d returns = %s\n", i, c);
}
else
{
char c[20];
sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
100 - ((a_ptr->hits * 100)
+ (a_ptr->total >> 1))
/ a_ptr->total);
fnotice (gcov_file,
"call %d returns = %s%%\n", i, c);
}
}
}
else
{
if (a_ptr->total == 0)
fnotice (gcov_file, "branch %d never executed\n",
i);
else
{
if (output_branch_counts)
{
char c[20];
sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
a_ptr->hits);
fnotice (gcov_file,
"branch %d taken = %s\n", i, c);
}
else
{
char c[20];
sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
((a_ptr->hits * 100)
+ (a_ptr->total >> 1))
/ a_ptr->total);
fnotice (gcov_file,
"branch %d taken = %s%%\n", i, c);
}
}
}
}
}
if (retval == NULL)
{
fnotice (stderr,
"Unexpected EOF while reading source file %s.\n",
source_file_name);
break;
}
}
{
char *retval = fgets (string, STRING_SIZE, source_file);
while (retval != NULL)
{
int len;
fprintf (gcov_file, "\t\t%s", string);
len = strlen (string);
while ((len == 0 || string[strlen (string) - 1] != '\n')
&& retval != NULL)
{
retval = fgets (string, STRING_SIZE, source_file);
fputs (string, gcov_file);
}
retval = fgets (string, STRING_SIZE, source_file);
}
}
fclose (source_file);
fclose (gcov_file);
}
free (line_counts);
free (line_exists);
}
}