mirror of git://gcc.gnu.org/git/gcc.git
gcov.c (struct name_map): New.
* gcov.c (struct name_map): New. (names, n_names, a_names): New global vars. (print_usage): Adjust usage. (generate_results): Canonicalize main file name. (release_structures): Adjust. (name_search, name_sort): New callbacks. (find_source): Look for and create a canonical name. (canonicalize_name): New. (make_gcov_file_name): Reimplement and fix mangling. (mangle_name): New. * doc/gcov.texi: Update documentation about path preservation. testsuite/ * gcc.misc-tests/gcov-15.c: New. From-SVN: r181309
This commit is contained in:
parent
926706f828
commit
eeabee0aac
|
|
@ -1,3 +1,17 @@
|
||||||
|
2011-11-12 Nathan Sidwell <nathan@acm.org>
|
||||||
|
|
||||||
|
* gcov.c (struct name_map): New.
|
||||||
|
(names, n_names, a_names): New global vars.
|
||||||
|
(print_usage): Adjust usage.
|
||||||
|
(generate_results): Canonicalize main file name.
|
||||||
|
(release_structures): Adjust.
|
||||||
|
(name_search, name_sort): New callbacks.
|
||||||
|
(find_source): Look for and create a canonical name.
|
||||||
|
(canonicalize_name): New.
|
||||||
|
(make_gcov_file_name): Reimplement and fix mangling.
|
||||||
|
(mangle_name): New.
|
||||||
|
* doc/gcov.texi: Update documentation about path preservation.
|
||||||
|
|
||||||
2011-11-11 David S. Miller <davem@davemloft.net>
|
2011-11-11 David S. Miller <davem@davemloft.net>
|
||||||
|
|
||||||
* config/sparc/linux.h (ASM_GENERATE_INTERNAL_LABEL): Delete.
|
* config/sparc/linux.h (ASM_GENERATE_INTERNAL_LABEL): Delete.
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ compatible with any other profiling or test coverage mechanism.
|
||||||
@section Invoking @command{gcov}
|
@section Invoking @command{gcov}
|
||||||
|
|
||||||
@smallexample
|
@smallexample
|
||||||
gcov @r{[}@var{options}@r{]} @var{sourcefiles}
|
gcov @r{[}@var{options}@r{]} @var{files}
|
||||||
@end smallexample
|
@end smallexample
|
||||||
|
|
||||||
@command{gcov} accepts the following options:
|
@command{gcov} accepts the following options:
|
||||||
|
|
@ -176,11 +176,12 @@ Do not create the @command{gcov} output file.
|
||||||
@itemx --long-file-names
|
@itemx --long-file-names
|
||||||
Create long file names for included source files. For example, if the
|
Create long file names for included source files. For example, if the
|
||||||
header file @file{x.h} contains code, and was included in the file
|
header file @file{x.h} contains code, and was included in the file
|
||||||
@file{a.c}, then running @command{gcov} on the file @file{a.c} will produce
|
@file{a.c}, then running @command{gcov} on the file @file{a.c} will
|
||||||
an output file called @file{a.c##x.h.gcov} instead of @file{x.h.gcov}.
|
produce an output file called @file{a.c##x.h.gcov} instead of
|
||||||
This can be useful if @file{x.h} is included in multiple source
|
@file{x.h.gcov}. This can be useful if @file{x.h} is included in
|
||||||
files. If you use the @samp{-p} option, both the including and
|
multiple source files and you want to see the individual
|
||||||
included file names will be complete path names.
|
contributions. If you use the @samp{-p} option, both the including
|
||||||
|
and included file names will be complete path names.
|
||||||
|
|
||||||
@item -p
|
@item -p
|
||||||
@itemx --preserve-paths
|
@itemx --preserve-paths
|
||||||
|
|
@ -188,9 +189,9 @@ Preserve complete path information in the names of generated
|
||||||
@file{.gcov} files. Without this option, just the filename component is
|
@file{.gcov} files. Without this option, just the filename component is
|
||||||
used. With this option, all directories are used, with @samp{/} characters
|
used. With this option, all directories are used, with @samp{/} characters
|
||||||
translated to @samp{#} characters, @file{.} directory components
|
translated to @samp{#} characters, @file{.} directory components
|
||||||
removed and @file{..}
|
removed and unremoveable @file{..}
|
||||||
components renamed to @samp{^}. This is useful if sourcefiles are in several
|
components renamed to @samp{^}. This is useful if sourcefiles are in several
|
||||||
different directories. It also affects the @samp{-l} option.
|
different directories.
|
||||||
|
|
||||||
@item -f
|
@item -f
|
||||||
@itemx --function-summaries
|
@itemx --function-summaries
|
||||||
|
|
@ -203,9 +204,8 @@ Specify either the directory containing the gcov data files, or the
|
||||||
object path name. The @file{.gcno}, and
|
object path name. The @file{.gcno}, and
|
||||||
@file{.gcda} data files are searched for using this option. If a directory
|
@file{.gcda} data files are searched for using this option. If a directory
|
||||||
is specified, the data files are in that directory and named after the
|
is specified, the data files are in that directory and named after the
|
||||||
source file name, without its extension. If a file is specified here,
|
input file name, without its extension. If a file is specified here,
|
||||||
the data files are named after that file, without its extension. If this
|
the data files are named after that file, without its extension.
|
||||||
option is not supplied, it defaults to the current directory.
|
|
||||||
|
|
||||||
@item -u
|
@item -u
|
||||||
@itemx --unconditional-branches
|
@itemx --unconditional-branches
|
||||||
|
|
@ -223,12 +223,17 @@ when you invoked the compiler. Otherwise it will not be able to locate
|
||||||
the source files. @command{gcov} produces files called
|
the source files. @command{gcov} produces files called
|
||||||
@file{@var{mangledname}.gcov} in the current directory. These contain
|
@file{@var{mangledname}.gcov} in the current directory. These contain
|
||||||
the coverage information of the source file they correspond to.
|
the coverage information of the source file they correspond to.
|
||||||
One @file{.gcov} file is produced for each source file containing code,
|
One @file{.gcov} file is produced for each source (or header) file
|
||||||
|
containing code,
|
||||||
which was compiled to produce the data files. The @var{mangledname} part
|
which was compiled to produce the data files. The @var{mangledname} part
|
||||||
of the output file name is usually simply the source file name, but can
|
of the output file name is usually simply the source file name, but can
|
||||||
be something more complicated if the @samp{-l} or @samp{-p} options are
|
be something more complicated if the @samp{-l} or @samp{-p} options are
|
||||||
given. Refer to those options for details.
|
given. Refer to those options for details.
|
||||||
|
|
||||||
|
If you invoke @command{gcov} with multiple input files, the
|
||||||
|
contributions from each input file are summed. Typically you would
|
||||||
|
invoke it with the same list of files as the final link of your executable.
|
||||||
|
|
||||||
The @file{.gcov} files contain the @samp{:} separated fields along with
|
The @file{.gcov} files contain the @samp{:} separated fields along with
|
||||||
program source code. The format is
|
program source code. The format is
|
||||||
|
|
||||||
|
|
|
||||||
361
gcc/gcov.c
361
gcc/gcov.c
|
|
@ -231,7 +231,7 @@ typedef struct line_info
|
||||||
|
|
||||||
typedef struct source_info
|
typedef struct source_info
|
||||||
{
|
{
|
||||||
/* Name of source file. */
|
/* Canonical name of source file. */
|
||||||
char *name;
|
char *name;
|
||||||
time_t file_time;
|
time_t file_time;
|
||||||
|
|
||||||
|
|
@ -246,6 +246,12 @@ typedef struct source_info
|
||||||
function_t *functions;
|
function_t *functions;
|
||||||
} source_t;
|
} source_t;
|
||||||
|
|
||||||
|
typedef struct name_map
|
||||||
|
{
|
||||||
|
char *name; /* Source file name */
|
||||||
|
unsigned src; /* Source file */
|
||||||
|
} name_map_t;
|
||||||
|
|
||||||
/* Holds a list of function basic block graphs. */
|
/* Holds a list of function basic block graphs. */
|
||||||
|
|
||||||
static function_t *functions;
|
static function_t *functions;
|
||||||
|
|
@ -255,6 +261,10 @@ static source_t *sources; /* Array of source files */
|
||||||
static unsigned n_sources; /* Number of sources */
|
static unsigned n_sources; /* Number of sources */
|
||||||
static unsigned a_sources; /* Allocated sources */
|
static unsigned a_sources; /* Allocated sources */
|
||||||
|
|
||||||
|
static name_map_t *names; /* Mapping of file names to sources */
|
||||||
|
static unsigned n_names; /* Number of names */
|
||||||
|
static unsigned a_names; /* Allocated names */
|
||||||
|
|
||||||
/* This holds data summary information. */
|
/* This holds data summary information. */
|
||||||
|
|
||||||
static unsigned object_runs;
|
static unsigned object_runs;
|
||||||
|
|
@ -341,6 +351,9 @@ static void print_version (void) ATTRIBUTE_NORETURN;
|
||||||
static void process_file (const char *);
|
static void process_file (const char *);
|
||||||
static void generate_results (const char *);
|
static void generate_results (const char *);
|
||||||
static void create_file_names (const char *);
|
static void create_file_names (const char *);
|
||||||
|
static int name_search (const void *, const void *);
|
||||||
|
static int name_sort (const void *, const void *);
|
||||||
|
static char *canonicalize_name (const char *);
|
||||||
static unsigned find_source (const char *);
|
static unsigned find_source (const char *);
|
||||||
static function_t *read_graph_file (void);
|
static function_t *read_graph_file (void);
|
||||||
static int read_count_file (function_t *);
|
static int read_count_file (function_t *);
|
||||||
|
|
@ -353,6 +366,7 @@ static void accumulate_line_counts (source_t *);
|
||||||
static int output_branch_count (FILE *, int, const arc_t *);
|
static int output_branch_count (FILE *, int, const arc_t *);
|
||||||
static void output_lines (FILE *, const source_t *);
|
static void output_lines (FILE *, const source_t *);
|
||||||
static char *make_gcov_file_name (const char *, const char *);
|
static char *make_gcov_file_name (const char *, const char *);
|
||||||
|
static char *mangle_name (const char *, char *);
|
||||||
static void release_structures (void);
|
static void release_structures (void);
|
||||||
static void release_function (function_t *);
|
static void release_function (function_t *);
|
||||||
extern int main (int, char **);
|
extern int main (int, char **);
|
||||||
|
|
@ -414,7 +428,7 @@ print_usage (int error_p)
|
||||||
FILE *file = error_p ? stderr : stdout;
|
FILE *file = error_p ? stderr : stdout;
|
||||||
int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
|
int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
|
||||||
|
|
||||||
fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE...\n\n");
|
fnotice (file, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
|
||||||
fnotice (file, "Print code coverage information.\n\n");
|
fnotice (file, "Print code coverage information.\n\n");
|
||||||
fnotice (file, " -h, --help Print this help, then exit\n");
|
fnotice (file, " -h, --help Print this help, then exit\n");
|
||||||
fnotice (file, " -v, --version Print version number, then exit\n");
|
fnotice (file, " -v, --version Print version number, then exit\n");
|
||||||
|
|
@ -524,7 +538,7 @@ process_args (int argc, char **argv)
|
||||||
return optind;
|
return optind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process a single source file. */
|
/* Process a single input file. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_file (const char *file_name)
|
process_file (const char *file_name)
|
||||||
|
|
@ -622,6 +636,16 @@ generate_results (const char *file_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file_name)
|
||||||
|
{
|
||||||
|
name_map_t *name_map = (name_map_t *)bsearch
|
||||||
|
(file_name, names, n_names, sizeof (*names), name_search);
|
||||||
|
if (name_map)
|
||||||
|
file_name = sources[name_map->src].name;
|
||||||
|
else
|
||||||
|
file_name = canonicalize_name (file_name);
|
||||||
|
}
|
||||||
|
|
||||||
for (ix = n_sources, src = sources; ix--; src++)
|
for (ix = n_sources, src = sources; ix--; src++)
|
||||||
{
|
{
|
||||||
accumulate_line_counts (src);
|
accumulate_line_counts (src);
|
||||||
|
|
@ -681,10 +705,12 @@ release_structures (void)
|
||||||
function_t *fn;
|
function_t *fn;
|
||||||
|
|
||||||
for (ix = n_sources; ix--;)
|
for (ix = n_sources; ix--;)
|
||||||
{
|
free (sources[ix].lines);
|
||||||
free (sources[ix].name);
|
free (sources);
|
||||||
free (sources[ix].lines);
|
|
||||||
}
|
for (ix = n_names; ix--;)
|
||||||
|
free (names[ix].name);
|
||||||
|
free (names);
|
||||||
|
|
||||||
while ((fn = functions))
|
while ((fn = functions))
|
||||||
{
|
{
|
||||||
|
|
@ -761,28 +787,75 @@ create_file_names (const char *file_name)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A is a string and B is a pointer to name_map_t. Compare for file
|
||||||
|
name orderability. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
name_search (const void *a_, const void *b_)
|
||||||
|
{
|
||||||
|
const char *a = (const char *)a_;
|
||||||
|
const name_map_t *b = (const name_map_t *)b_;
|
||||||
|
|
||||||
|
#if HAVE_DOS_BASED_FILE_SYSTEM
|
||||||
|
return strcasecmp (a, b->name);
|
||||||
|
#else
|
||||||
|
return strcmp (a, b->name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A and B are a pointer to name_map_t. Compare for file name
|
||||||
|
orderability. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
name_sort (const void *a_, const void *b_)
|
||||||
|
{
|
||||||
|
const name_map_t *a = (const name_map_t *)a_;
|
||||||
|
return name_search (a->name, b_);
|
||||||
|
}
|
||||||
|
|
||||||
/* Find or create a source file structure for FILE_NAME. Copies
|
/* Find or create a source file structure for FILE_NAME. Copies
|
||||||
FILE_NAME on creation */
|
FILE_NAME on creation */
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
find_source (const char *file_name)
|
find_source (const char *file_name)
|
||||||
{
|
{
|
||||||
unsigned ix;
|
name_map_t *name_map;
|
||||||
source_t *src = 0;
|
char *canon;
|
||||||
|
unsigned idx;
|
||||||
struct stat status;
|
struct stat status;
|
||||||
|
|
||||||
if (!file_name)
|
if (!file_name)
|
||||||
file_name = "<unknown>";
|
file_name = "<unknown>";
|
||||||
|
name_map = (name_map_t *)bsearch
|
||||||
for (ix = n_sources; ix--;)
|
(file_name, names, n_names, sizeof (*names), name_search);
|
||||||
if (!filename_cmp (file_name, sources[ix].name))
|
if (name_map)
|
||||||
{
|
|
||||||
src = &sources[ix];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!src)
|
|
||||||
{
|
{
|
||||||
|
idx = name_map->src;
|
||||||
|
goto check_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_names + 2 > a_names)
|
||||||
|
{
|
||||||
|
/* Extend the name map array -- we'll be inserting one or two
|
||||||
|
entries. */
|
||||||
|
if (!a_names)
|
||||||
|
a_names = 10;
|
||||||
|
a_names *= 2;
|
||||||
|
name_map = XNEWVEC (name_map_t, a_names);
|
||||||
|
memcpy (name_map, names, n_names * sizeof (*names));
|
||||||
|
free (names);
|
||||||
|
names = name_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found, try the canonical name. */
|
||||||
|
canon = canonicalize_name (file_name);
|
||||||
|
name_map = (name_map_t *)bsearch
|
||||||
|
(canon, names, n_names, sizeof (*names), name_search);
|
||||||
|
if (!name_map)
|
||||||
|
{
|
||||||
|
/* Not found with canonical name, create a new source. */
|
||||||
|
source_t *src;
|
||||||
|
|
||||||
if (n_sources == a_sources)
|
if (n_sources == a_sources)
|
||||||
{
|
{
|
||||||
if (!a_sources)
|
if (!a_sources)
|
||||||
|
|
@ -793,31 +866,51 @@ find_source (const char *file_name)
|
||||||
free (sources);
|
free (sources);
|
||||||
sources = src;
|
sources = src;
|
||||||
}
|
}
|
||||||
ix = n_sources;
|
|
||||||
src = &sources[ix];
|
idx = n_sources;
|
||||||
src->name = xstrdup (file_name);
|
|
||||||
|
name_map = &names[n_names++];
|
||||||
|
name_map->name = canon;
|
||||||
|
name_map->src = idx;
|
||||||
|
|
||||||
|
src = &sources[n_sources++];
|
||||||
|
memset (src, 0, sizeof (*src));
|
||||||
|
src->name = canon;
|
||||||
src->coverage.name = src->name;
|
src->coverage.name = src->name;
|
||||||
n_sources++;
|
if (!stat (src->name, &status))
|
||||||
if (!stat (file_name, &status))
|
|
||||||
src->file_time = status.st_mtime;
|
src->file_time = status.st_mtime;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
idx = name_map->src;
|
||||||
|
|
||||||
if (src->file_time > bbg_file_time)
|
if (name_search (file_name, name_map))
|
||||||
|
{
|
||||||
|
/* Append the non-canonical name. */
|
||||||
|
name_map = &names[n_names++];
|
||||||
|
name_map->name = xstrdup (file_name);
|
||||||
|
name_map->src = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resort the name map. */
|
||||||
|
qsort (names, n_names, sizeof (*names), name_sort);
|
||||||
|
|
||||||
|
check_date:
|
||||||
|
if (sources[idx].file_time > bbg_file_time)
|
||||||
{
|
{
|
||||||
static int info_emitted;
|
static int info_emitted;
|
||||||
|
|
||||||
fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
|
fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
|
||||||
src->name, bbg_file_name);
|
file_name, bbg_file_name);
|
||||||
if (!info_emitted)
|
if (!info_emitted)
|
||||||
{
|
{
|
||||||
fnotice (stderr,
|
fnotice (stderr,
|
||||||
"(the message is only displayed one per source file)\n");
|
"(the message is only displayed one per source file)\n");
|
||||||
info_emitted = 1;
|
info_emitted = 1;
|
||||||
}
|
}
|
||||||
src->file_time = 0;
|
sources[idx].file_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ix;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the graph file. Return list of functions read -- in reverse order. */
|
/* Read the graph file. Return list of functions read -- in reverse order. */
|
||||||
|
|
@ -1510,97 +1603,169 @@ function_summary (const coverage_t *coverage, const char *title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
|
/* Canonicalize the filename NAME by canonicalizing directory
|
||||||
affect name generation. With preserve_paths we create a filename
|
separators, eliding . components and resolving .. components
|
||||||
from all path components of the source file, replacing '/' with
|
appropriately. Always returns a unique string. */
|
||||||
'#', without it we simply take the basename component. With
|
|
||||||
|
static char *
|
||||||
|
canonicalize_name (const char *name)
|
||||||
|
{
|
||||||
|
/* The canonical name cannot be longer than the incoming name. */
|
||||||
|
char *result = XNEWVEC (char, strlen (name) + 1);
|
||||||
|
const char *base = name, *probe;
|
||||||
|
char *ptr = result;
|
||||||
|
char *dd_base;
|
||||||
|
int slash = 0;
|
||||||
|
|
||||||
|
#if HAVE_DOS_BASED_FILE_SYSTEM
|
||||||
|
if (base[0] && base[1] == ':')
|
||||||
|
{
|
||||||
|
result[0] = base[0];
|
||||||
|
result[1] = ':';
|
||||||
|
base += 2;
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (dd_base = ptr; *base; base = probe)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (probe = base; *probe; probe++)
|
||||||
|
if (IS_DIR_SEPARATOR (*probe))
|
||||||
|
break;
|
||||||
|
|
||||||
|
len = probe - base;
|
||||||
|
if (len == 1 && base[0] == '.')
|
||||||
|
/* Elide a '.' directory */
|
||||||
|
;
|
||||||
|
else if (len == 2 && base[0] == '.' && base[1] == '.')
|
||||||
|
{
|
||||||
|
/* '..', we can only elide it and the previous directory, if
|
||||||
|
we're not a symlink. */
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
*ptr = 0;
|
||||||
|
if (dd_base == ptr || stat (result, &buf) || S_ISLNK (buf.st_mode))
|
||||||
|
{
|
||||||
|
/* Cannot elide, or unreadable or a symlink. */
|
||||||
|
dd_base = ptr + 2 + slash;
|
||||||
|
goto regular;
|
||||||
|
}
|
||||||
|
while (ptr != dd_base && *ptr != '/')
|
||||||
|
ptr--;
|
||||||
|
slash = ptr != result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regular:
|
||||||
|
/* Regular pathname component. */
|
||||||
|
if (slash)
|
||||||
|
*ptr++ = '/';
|
||||||
|
memcpy (ptr, base, len);
|
||||||
|
ptr += len;
|
||||||
|
slash = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; IS_DIR_SEPARATOR (*probe); probe++)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate an output file name. INPUT_NAME is the canonicalized main
|
||||||
|
input file and SRC_NAME is the canonicalized file name.
|
||||||
|
LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
|
||||||
long_output_names we prepend the processed name of the input file
|
long_output_names we prepend the processed name of the input file
|
||||||
to each output name (except when the current source file is the
|
to each output name (except when the current source file is the
|
||||||
input file, so you don't get a double concatenation). The two
|
input file, so you don't get a double concatenation). The two
|
||||||
components are separated by '##'. Also '.' filename components are
|
components are separated by '##'. With preserve_paths we create a
|
||||||
removed and '..' components are renamed to '^'. */
|
filename from all path components of the source file, replacing '/'
|
||||||
|
with '#', and .. with '^', without it we simply take the basename
|
||||||
|
component. (Remember, the canonicalized name will already have
|
||||||
|
elided '.' components and converted \\ separators.) */
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
make_gcov_file_name (const char *input_name, const char *src_name)
|
make_gcov_file_name (const char *input_name, const char *src_name)
|
||||||
{
|
{
|
||||||
const char *cptr;
|
char *ptr;
|
||||||
char *name;
|
char *result;
|
||||||
|
|
||||||
if (flag_long_names && input_name && strcmp (src_name, input_name))
|
if (flag_long_names && input_name && strcmp (src_name, input_name))
|
||||||
{
|
{
|
||||||
name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
|
|
||||||
name[0] = 0;
|
|
||||||
/* Generate the input filename part. */
|
/* Generate the input filename part. */
|
||||||
cptr = flag_preserve_paths ? NULL : lbasename (input_name);
|
result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
|
||||||
strcat (name, cptr ? cptr : input_name);
|
|
||||||
strcat (name, "##");
|
ptr = result;
|
||||||
|
ptr = mangle_name (input_name, ptr);
|
||||||
|
ptr[0] = ptr[1] = '#';
|
||||||
|
ptr += 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
name = XNEWVEC (char, strlen (src_name) + 10);
|
result = XNEWVEC (char, strlen (src_name) + 10);
|
||||||
name[0] = 0;
|
ptr = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptr = mangle_name (src_name, ptr);
|
||||||
|
strcpy (ptr, ".gcov");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mangle_name (char const *base, char *ptr)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
/* Generate the source filename part. */
|
/* Generate the source filename part. */
|
||||||
|
if (!flag_preserve_paths)
|
||||||
cptr = flag_preserve_paths ? NULL : lbasename (src_name);
|
|
||||||
strcat (name, cptr ? cptr : src_name);
|
|
||||||
|
|
||||||
if (flag_preserve_paths)
|
|
||||||
{
|
{
|
||||||
/* Convert '/' and '\' to '#', remove '/./', convert '/../' to '#^#',
|
base = lbasename (base);
|
||||||
convert ':' to '~' on DOS based file system. */
|
len = strlen (base);
|
||||||
char *pnew = name, *pold = name;
|
memcpy (ptr, base, len);
|
||||||
|
ptr += len;
|
||||||
/* First check for leading drive separator. */
|
|
||||||
|
|
||||||
while (*pold != '\0')
|
|
||||||
{
|
|
||||||
#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
|
|
||||||
if (*pold == ':')
|
|
||||||
{
|
|
||||||
*pnew++ = '~';
|
|
||||||
pold++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if ((*pold == '/'
|
|
||||||
&& (strstr (pold, "/./") == pold
|
|
||||||
|| strstr (pold, "/.\\") == pold))
|
|
||||||
|| (*pold == '\\'
|
|
||||||
&& (strstr (pold, "\\.\\") == pold
|
|
||||||
|| strstr (pold, "\\./") == pold)))
|
|
||||||
pold += 3;
|
|
||||||
else if (*pold == '/'
|
|
||||||
&& (strstr (pold, "/../") == pold
|
|
||||||
|| strstr (pold, "/..\\") == pold))
|
|
||||||
{
|
|
||||||
strcpy (pnew, "#^#");
|
|
||||||
pnew += 3;
|
|
||||||
pold += 4;
|
|
||||||
}
|
|
||||||
else if (*pold == '\\'
|
|
||||||
&& (strstr (pold, "\\..\\") == pold
|
|
||||||
|| strstr (pold, "\\../") == pold))
|
|
||||||
{
|
|
||||||
strcpy (pnew, "#^#");
|
|
||||||
pnew += 3;
|
|
||||||
pold += 4;
|
|
||||||
}
|
|
||||||
else if (*pold == '/' || *pold == '\\')
|
|
||||||
{
|
|
||||||
*pnew++ = '#';
|
|
||||||
pold++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*pnew++ = *pold++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pnew = '\0';
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Convert '/' to '#', convert '..' to '^',
|
||||||
|
convert ':' to '~' on DOS based file system. */
|
||||||
|
const char *probe;
|
||||||
|
|
||||||
strcat (name, ".gcov");
|
#if HAVE_DOS_BASED_FILE_SYSTEM
|
||||||
return name;
|
if (base[0] && base[1] == ':')
|
||||||
|
{
|
||||||
|
ptr[0] = base[0];
|
||||||
|
ptr[1] = '~';
|
||||||
|
ptr += 2;
|
||||||
|
base += 2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (; *base; base = probe)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (probe = base; *probe; probe++)
|
||||||
|
if (*probe == '/')
|
||||||
|
break;
|
||||||
|
len = probe - base;
|
||||||
|
if (len == 2 && base[0] == '.' && base[1] == '.')
|
||||||
|
*ptr++ = '^';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (ptr, base, len);
|
||||||
|
ptr += len;
|
||||||
|
}
|
||||||
|
if (*probe)
|
||||||
|
{
|
||||||
|
*ptr++ = '#';
|
||||||
|
probe++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan through the bb_data for each line in the block, increment
|
/* Scan through the bb_data for each line in the block, increment
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
2011-11-12 Nathan Sidwell <nathan@acm.org>
|
||||||
|
|
||||||
|
* gcc.misc-tests/gcov-15.c: New.
|
||||||
|
|
||||||
2011-11-11 Jakub Jelinek <jakub@redhat.com>
|
2011-11-11 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR tree-optimization/51058
|
PR tree-optimization/51058
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* Test gcov multiple paths to file. */
|
||||||
|
|
||||||
|
/* { dg-options "-fprofile-arcs -ftest-coverage" } */
|
||||||
|
/* { dg-do run { target native } } */
|
||||||
|
|
||||||
|
#if !RECURSIVE
|
||||||
|
#define RECURSIVE 1
|
||||||
|
#include "./gcov-15.c"
|
||||||
|
#undef RECURSIVE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void __attribute__ ((noinline)) Recursive (void);
|
||||||
|
|
||||||
|
|
||||||
|
#if RECURSIVE
|
||||||
|
static void __attribute__ ((noinline))
|
||||||
|
Recursive ()
|
||||||
|
{
|
||||||
|
return; /* count(1) */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
Recursive (); /* count(1) */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* { dg-final { run-gcov { -a gcov-15.c } } } */
|
||||||
Loading…
Reference in New Issue