/* Gcov.c: prepend line execution counts and branch probabilities to a
source file.
- Copyright (C) 1990, 91, 92, 93, 94, 96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
Contributed by James E. Wilson of Cygnus Support.
Mangled by Bob Manson of Cygnus Support.
You should have received a copy of the GNU General Public License
along with Gcov; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* ??? The code in final.c that produces the struct bb assumes that there is
no padding between the fields. This is not necessary true. The current
#include "config.h"
#include "system.h"
-#include <sys/stat.h>
-#include "gansidecl.h"
+#include "intl.h"
+#undef abort
#include "gcov-io.h"
struct arcdata
{
- int prob;
+ int hits;
+ int total;
int call_insn;
struct arcdata *next;
};
static char *object_directory = 0;
+/* Output the number of times a branch was taken as opposed to the percentage
+ of times it was taken. Turned on by the -c option */
+
+static int output_branch_counts = 0;
+
/* Forward declarations. */
-static void process_args PROTO ((int, char **));
-static void open_files PROTO ((void));
-static void read_files PROTO ((void));
-static void scan_for_source_files PROTO ((void));
-static void output_data PROTO ((void));
-static void print_usage PROTO ((void));
-char * xmalloc ();
+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 ((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;
{
+/* LC_CTYPE determines the character set used by the terminal so it has be set
+ to output messages correctly. */
+
+#ifdef HAVE_LC_MESSAGES
+ setlocale (LC_CTYPE, "");
+ setlocale (LC_MESSAGES, "");
+#else
+ setlocale (LC_ALL, "");
+#endif
+
+ (void) bindtextdomain (PACKAGE, localedir);
+ (void) textdomain (PACKAGE);
+
process_args (argc, argv);
open_files ();
return 0;
}
-char *
-xmalloc (size)
- unsigned size;
+static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
+static void
+fnotice VPARAMS ((FILE *file, const char *msgid, ...))
{
- register char *value = (char *) malloc (size);
- if (value == 0)
- {
- fprintf (stderr, "error: virtual memory exhausted");
- exit (FATAL_EXIT_CODE);
- }
- return value;
+#ifndef ANSI_PROTOTYPES
+ FILE *file;
+ const char *msgid;
+#endif
+ va_list ap;
+
+ VA_START (ap, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ file = va_arg (ap, FILE *);
+ msgid = va_arg (ap, const char *);
+#endif
+
+ vfprintf (file, _(msgid), ap);
+ va_end (ap);
}
/* More 'friendly' abort that prints the line and file.
config.h can #define abort fancy_abort if you like that sort of thing. */
+extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
void
fancy_abort ()
{
- fprintf (stderr, "Internal gcc abort.\n");
+ fnotice (stderr, "Internal gcov abort.\n");
exit (FATAL_EXIT_CODE);
}
\f
static void
print_usage ()
{
- fprintf (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
+ fnotice (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
exit (FATAL_EXIT_CODE);
}
{
if (argv[i][1] == 'b')
output_branch_probs = 1;
+ else if (argv[i][1] == 'c')
+ output_branch_counts = 1;
else if (argv[i][1] == 'v')
fputs (gcov_version_string, stderr);
else if (argv[i][1] == 'n')
strcat (bbg_file_name, "/");
}
- cptr = rindex (input_file_name, '/');
+ cptr = strrchr (input_file_name, '/');
if (cptr)
{
strcat (da_file_name, cptr + 1);
strcpy (bbg_file_name, input_file_name);
}
- cptr = rindex (bb_file_name, '.');
+ cptr = strrchr (bb_file_name, '.');
if (cptr)
strcpy (cptr, ".bb");
else
strcat (bb_file_name, ".bb");
- cptr = rindex (da_file_name, '.');
+ cptr = strrchr (da_file_name, '.');
if (cptr)
strcpy (cptr, ".da");
else
strcat (da_file_name, ".da");
- cptr = rindex (bbg_file_name, '.');
+ cptr = strrchr (bbg_file_name, '.');
if (cptr)
strcpy (cptr, ".bbg");
else
strcat (bbg_file_name, ".bbg");
- bb_file = fopen (bb_file_name, "r");
+ bb_file = fopen (bb_file_name, "rb");
if (bb_file == NULL)
{
- fprintf (stderr, "Could not open basic block file %s.\n", bb_file_name);
+ fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
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, "r");
+ da_file = fopen (da_file_name, "rb");
if (da_file == NULL)
{
- fprintf (stderr, "Could not open data file %s.\n", da_file_name);
- fprintf (stderr, "Assuming that all execution counts are zero.\n");
+ 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, "r");
+ bbg_file = fopen (bbg_file_name, "rb");
if (bbg_file == NULL)
{
- fprintf (stderr, "Could not open program flow graph file %s.\n",
+ 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))
{
- fprintf (stderr, "No executable code associated with file %s.\n",
+ fnotice (stderr, "No executable code associated with file %s.\n",
input_file_name);
exit (FATAL_EXIT_CODE);
}
/* Read the number of blocks. */
__read_long (&num_blocks, bbg_file, 4);
- /* Create an array of size bb number of bb_info structs. Bzero it. */
- bb_graph = (struct bb_info *) xmalloc (num_blocks
- * sizeof (struct bb_info));
- bzero ((char *) bb_graph, sizeof (struct bb_info) * num_blocks);
+ /* Create an array of size bb number of bb_info structs. */
+ bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
bptr->bb_graph = bb_graph;
bptr->num_blocks = num_blocks;
for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
if (! arcptr->on_tree)
{
- long tmp_count = 0;;
+ long tmp_count = 0;
if (da_file && __read_long (&tmp_count, da_file, 8))
abort();
if (da_file)
{
if (feof (da_file))
- fprintf (stderr, ".da file contents exhausted too early\n");
+ fnotice (stderr, ".da file contents exhausted too early\n");
/* Should be at end of file now. */
if (__read_long (&total, da_file, 8) == 0)
- fprintf (stderr, ".da file contents not exhausted\n");
+ fnotice (stderr, ".da file contents not exhausted\n");
}
/* Calculate all of the basic block execution counts and branch
/* No sourcefile structure for this file name exists, create
a new one, and append it to the front of the sources list. */
s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
- s_ptr->name = xmalloc (strlen ((char *) ptr) + 1);
- strcpy (s_ptr->name, (char *) ptr);
+ s_ptr->name = xstrdup (ptr);
s_ptr->maxlineno = 0;
s_ptr->next = sources;
sources = s_ptr;
continue;
a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
+ a_ptr->total = total;
if (total == 0)
- a_ptr->prob = -1;
+ a_ptr->hits = 0;
else
- a_ptr->prob = ((arcptr->arc_count * 100) + (total >> 1)) / total;
+ 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->prob != -1)
+ if (a_ptr->total != 0)
function_calls_executed++;
}
else
{
function_branches++;
- if (a_ptr->prob != -1)
+ if (a_ptr->total != 0)
function_branches_executed++;
- if (a_ptr->prob > 0)
+ if (a_ptr->hits > 0)
function_branches_taken++;
}
}
function_summary ()
{
if (function_source_lines)
- fprintf (stdout, "%6.2f%% of %d source lines executed in function %s\n",
+ 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
- fprintf (stdout, "No executable source lines in function %s\n",
+ fnotice (stdout, "No executable source lines in function %s\n",
function_name);
if (output_branch_probs)
{
if (function_branches)
{
- fprintf (stdout, "%6.2f%% of %d branches executed in function %s\n",
+ fnotice (stdout, "%6.2f%% of %d branches executed in function %s\n",
(((double) function_branches_executed / function_branches)
* 100), function_branches, function_name);
- fprintf (stdout,
+ 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
- fprintf (stdout, "No branches in function %s\n", function_name);
+ fnotice (stdout, "No branches in function %s\n", function_name);
if (function_calls)
- fprintf (stdout, "%6.2f%% of %d calls executed in function %s\n",
+ fnotice (stdout, "%6.2f%% of %d calls executed in function %s\n",
(((double) function_calls_executed / function_calls)
* 100), function_calls, function_name);
else
- fprintf (stdout, "No calls in function %s\n", function_name);
+ fnotice (stdout, "No calls in function %s\n", function_name);
}
}
{
/* If this is a relative file name, and an object directory has been
specified, then make it relative to the object directory name. */
- if (*s_ptr->name != '/' && object_directory != 0
+ if (! (*s_ptr->name == '/' || *s_ptr->name == DIR_SEPARATOR
+ /* Check for disk name on MS-DOS-based systems. */
+ || (DIR_SEPARATOR == '\\'
+ && s_ptr->name[1] == ':'
+ && (s_ptr->name[2] == DIR_SEPARATOR
+ || s_ptr->name[2] == '/')))
+ && object_directory != 0
&& *object_directory != '\0')
{
int objdir_count = strlen (object_directory);
else
source_file_name = s_ptr->name;
- line_counts = (long *) xmalloc (sizeof (long) * s_ptr->maxlineno);
- bzero ((char *) line_counts, sizeof (long) * s_ptr->maxlineno);
- line_exists = xmalloc (s_ptr->maxlineno);
- bzero (line_exists, s_ptr->maxlineno);
+ line_counts = (long *) xcalloc (sizeof (long), s_ptr->maxlineno);
+ line_exists = xcalloc (1, s_ptr->maxlineno);
if (output_branch_probs)
- {
- branch_probs = (struct arcdata **) xmalloc (sizeof (struct arcdata **)
- * s_ptr->maxlineno);
- bzero ((char *) branch_probs,
- sizeof (struct arcdata **) * s_ptr->maxlineno);
- }
+ 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. */
}
else
{
- fprintf (stderr,
+ fnotice (stderr,
"didn't use all bb entries of graph, function %s\n",
function_name);
- fprintf (stderr, "block_num = %ld, num_blocks = %d\n",
+ fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
block_num, current_graph->num_blocks);
}
if (block_num >= current_graph->num_blocks)
{
- fprintf (stderr, "ERROR: too many basic blocks in .bb file %s\n",
+ fnotice (stderr, "ERROR: too many basic blocks in .bb file %s\n",
function_name);
abort ();
}
if (a_ptr->call_insn)
{
total_calls++;
- if (a_ptr->prob != -1)
+ if (a_ptr->total != 0)
total_calls_executed++;
}
else
{
total_branches++;
- if (a_ptr->prob != -1)
+ if (a_ptr->total != 0)
total_branches_executed++;
- if (a_ptr->prob > 0)
+ if (a_ptr->hits > 0)
total_branches_taken++;
}
}
}
if (total_source_lines)
- fprintf (stdout,
+ 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
- fprintf (stdout, "No executable source lines in file %s\n",
+ fnotice (stdout, "No executable source lines in file %s\n",
source_file_name);
if (output_branch_probs)
{
if (total_branches)
{
- fprintf (stdout, "%6.2f%% of %d branches executed in file %s\n",
+ fnotice (stdout, "%6.2f%% of %d branches executed in file %s\n",
(((double) total_branches_executed / total_branches)
* 100), total_branches, source_file_name);
- fprintf (stdout,
+ 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
- fprintf (stdout, "No branches in file %s\n", source_file_name);
+ fnotice (stdout, "No branches in file %s\n", source_file_name);
if (total_calls)
- fprintf (stdout, "%6.2f%% of %d calls executed in file %s\n",
+ 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
- fprintf (stdout, "No calls in file %s\n", source_file_name);
+ 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)
{
- fprintf (stderr, "Could not open source file %s.\n",
+ fnotice (stderr, "Could not open source file %s.\n",
source_file_name);
free (line_counts);
free (line_exists);
}
count = strlen (source_file_name);
- cptr = rindex (s_ptr->name, '/');
+ cptr = strrchr (s_ptr->name, '/');
if (cptr)
cptr = cptr + 1;
else
{
gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
- cptr = rindex (input_file_name, '/');
+ cptr = strrchr (input_file_name, '/');
if (cptr)
strcpy (gcov_file_name, cptr + 1);
else
strcat (gcov_file_name, ".");
- cptr = rindex (source_file_name, '/');
+ cptr = strrchr (source_file_name, '/');
if (cptr)
strcat (gcov_file_name, cptr + 1);
else
else
{
gcov_file_name = xmalloc (count + 6);
- cptr = rindex (source_file_name, '/');
+ cptr = strrchr (source_file_name, '/');
if (cptr)
strcpy (gcov_file_name, cptr + 1);
else
if (gcov_file == NULL)
{
- fprintf (stderr, "Could not open output file %s.\n",
+ fnotice (stderr, "Could not open output file %s.\n",
gcov_file_name);
fclose (source_file);
free (line_counts);
continue;
}
- fprintf (stdout, "Creating %s.\n", gcov_file_name);
+ fnotice (stdout, "Creating %s.\n", gcov_file_name);
for (count = 1; count < s_ptr->maxlineno; count++)
{
{
if (a_ptr->call_insn)
{
- if (a_ptr->prob == -1)
- fprintf (gcov_file, "call %d never executed\n", i);
- else
- fprintf (gcov_file,
- "call %d returns = %d%%\n",
- i, 100 - a_ptr->prob);
+ if (a_ptr->total == 0)
+ fnotice (gcov_file, "call %d never executed\n", i);
+ else
+ {
+ if (output_branch_counts)
+ fnotice (gcov_file,
+ "call %d returns = %d\n",
+ i, a_ptr->total - a_ptr->hits);
+ else
+ fnotice (gcov_file,
+ "call %d returns = %d%%\n",
+ i, 100 - ((a_ptr->hits * 100) +
+ (a_ptr->total >> 1))/a_ptr->total);
+ }
}
else
{
- if (a_ptr->prob == -1)
- fprintf (gcov_file, "branch %d never executed\n",
+ if (a_ptr->total == 0)
+ fnotice (gcov_file, "branch %d never executed\n",
i);
else
- fprintf (gcov_file, "branch %d taken = %d%%\n", i,
- a_ptr->prob);
+ {
+ if (output_branch_counts)
+ fnotice (gcov_file,
+ "branch %d taken = %d\n",
+ i, a_ptr->hits);
+ else
+ fnotice (gcov_file,
+ "branch %d taken = %d%%\n", i,
+ ((a_ptr->hits * 100) +
+ (a_ptr->total >> 1))/
+ a_ptr->total);
+
+ }
}
- }
- }
+ }
+ }
/* Gracefully handle errors while reading the source file. */
if (retval == NULL)
{
- fprintf (stderr,
+ fnotice (stderr,
"Unexpected EOF while reading source file %s.\n",
source_file_name);
break;