Commit 992f396f by Grigory Zagorodnev Committed by Nathan Sidwell

libgcov.c (create_file_directory): New function.

	* libgcov.c (create_file_directory): New function. Create
	directory for the given file name.
	(gcov_max_filename): New static var. Keeps size of the longest
	file name.
	(gcov_exit): Always try to create directory for output
	file. Relocate each filename basing on environment vars.
	(__gcov_init): Remember the longest file name.
	* tsystem.h: include filenames.h to get IS_DIR_SEPARATOR
	* doc/gcov.texi (Cross-profiling): New node documenting
	cross-profiling management.
	* doc/invoke.texi (-fprofile-arcs): Add xref to cross-profiling.

From-SVN: r99523
parent 0f95e914
2005-05-11 Grigory Zagorodnev <grigory.zagorodnev@intel.com>
H.J. Lu <hongjiu.lu@intel.com
* libgcov.c (create_file_directory): New function. Create
directory for the given file name.
(gcov_max_filename): New static var. Keeps size of the longest
file name.
(gcov_exit): Always try to create directory for output
file. Relocate each filename basing on environment vars.
(__gcov_init): Remember the longest file name.
* tsystem.h: include filenames.h to get IS_DIR_SEPARATOR
* doc/gcov.texi (Cross-profiling): New node documenting
cross-profiling management.
* doc/invoke.texi (-fprofile-arcs): Add xref to cross-profiling.
2005-05-10 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.c (mem_min_alignment): Do not rely
......
......@@ -42,6 +42,7 @@ test code coverage in your programs.
* Invoking Gcov:: How to use gcov.
* Gcov and Optimization:: Using gcov with GCC optimization.
* Gcov Data Files:: The files used by gcov.
* Cross-profiling:: Data file relocation.
@end menu
@node Gcov Intro
......@@ -531,3 +532,42 @@ information.
The full details of the file format is specified in @file{gcov-io.h},
and functions provided in that header file should be used to access the
coverage files.
@node Cross-profiling
@section Data file relocation to support cross-profiling
Running the program will cause profile output to be generated. For each
source file compiled with @option{-fprofile-arcs}, an accompanying @file{.gcda}
file will be placed in the object file directory. That implicitly requires
running the program on the same system as it was built or having the same
absolute directory structure on the target system. The program will try
to create the needed directory structure, if it is not already present.
To support cross-profiling, a program compiled with @option{-fprofile-arcs}
can relocate the data files based on two environment variables:
@itemize @bullet
@item
GCOV_PREFIX contains the prefix to add to the absolute paths
in the object file. Prefix must be absolute as well, otherwise its
value is ignored. The default is no prefix.
@item
GCOV_PREFIX_STRIP indicates the how many initial directory names to strip off
the hardwired absolute paths. Default value is 0.
@emph{Note:} GCOV_PREFIX_STRIP has no effect if GCOV_PREFIX is undefined, empty
or non-absolute.
@end itemize
For example, if the object file @file{/user/build/foo.o} was built with
@option{-fprofile-arcs}, the final executable will try to create the data file
@file{/user/build/foo.gcda} when running on the target system. This will
fail if the corresponding directory does not exist and it is unable to create
it. This can be overcome by, for example, setting the environment as
@samp{GCOV_PREFIX=/target/run} and @samp{GCOV_PREFIX_STRIP=1}. Such a
setting will name the data file @file{/target/run/build/foo.gcda}.
You must move the data files to the expected directory tree in order to
use them for profile directed optimizations (@option{--use-profile}), or to
use the the @command{gcov} tool.
......@@ -3427,6 +3427,7 @@ explicitly specified and it is not the final executable, otherwise it is
the basename of the source file. In both cases any suffix is removed
(e.g.@: @file{foo.gcda} for input file @file{dir/foo.c}, or
@file{dir/foo.gcda} for output file specified as @option{-o dir/foo.o}).
@xref{Cross-profiling}.
@cindex @command{gcov}
@item --coverage
......
......@@ -88,8 +88,49 @@ static struct gcov_info *gcov_list;
object file included in multiple programs. */
static gcov_unsigned_t gcov_crc32;
/* Size of the longest file name. */
static size_t gcov_max_filename = 0;
/* Make sure path compenent of the given FILENAME exists, create
missing directories. FILENAME must be writable.
Returns zero on success, or -1 if an error occurred. */
static int
create_file_directory (char *filename)
{
char *s;
for (s = filename + 1; *s != '\0'; s++)
if (IS_DIR_SEPARATOR(*s))
{
char sep = *s;
*s = '\0';
/* Try to make directory if it doesn't already exist. */
if (access (filename, F_OK) == -1
&& mkdir (filename, 0755) == -1
/* The directory might have been made by another process. */
&& errno != EEXIST)
{
fprintf (stderr, "profiling:%s:Cannot create directory\n",
filename);
*s = sep;
return -1;
};
*s = sep;
};
return 0;
}
/* Check if VERSION of the info block PTR matches libgcov one.
Return 1 on success, or zero in case of versions mismatch.
If FILENAME is not NULL, its value used for reporting purposes
instead of value from the info block. */
static int
gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
const char *filename)
{
if (version != GCOV_VERSION)
{
......@@ -100,7 +141,7 @@ gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
fprintf (stderr,
"profiling:%s:Version mismatch - expected %.4s got %.4s\n",
ptr->filename, e, v);
filename? filename : ptr->filename, e, v);
return 0;
}
return 1;
......@@ -123,6 +164,10 @@ gcov_exit (void)
const struct gcov_ctr_info *ci_ptr;
unsigned t_ix;
gcov_unsigned_t c_num;
const char *gcov_prefix;
int gcov_prefix_strip = 0;
size_t prefix_length;
char *gi_filename, *gi_filename_up;
memset (&all, 0, sizeof (all));
/* Find the totals for this execution. */
......@@ -147,6 +192,33 @@ gcov_exit (void)
}
}
/* Get file name relocation prefix. Non-absolute values are ignored. */
gcov_prefix = getenv("GCOV_PREFIX");
if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
{
/* Check if the level of dirs to strip off specified. */
char *tmp = getenv("GCOV_PREFIX_STRIP");
if (tmp)
{
gcov_prefix_strip = atoi (tmp);
/* Do not consider negative values. */
if (gcov_prefix_strip < 0)
gcov_prefix_strip = 0;
}
prefix_length = strlen(gcov_prefix);
/* Remove an unneccesary trailing '/' */
if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
prefix_length--;
}
/* Allocate and initialize the filename scratch space. */
gi_filename = alloca (prefix_length + gcov_max_filename + 1);
if (prefix_length)
memcpy (gi_filename, gcov_prefix, prefix_length);
gi_filename_up = gi_filename + prefix_length;
/* Now merge each file. */
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
......@@ -165,6 +237,28 @@ gcov_exit (void)
memset (&this_object, 0, sizeof (this_object));
memset (&object, 0, sizeof (object));
/* Build relocated filename, stripping off leading
directories from the initial filename if requested. */
if (gcov_prefix_strip > 0)
{
int level = 0;
const char *fname = gi_ptr->filename;
const char *s;
/* Skip selected directory levels. */
for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
if (IS_DIR_SEPARATOR(*s))
{
fname = s;
level++;
};
/* Update complete filename with stripped original. */
strcpy (gi_filename_up, fname);
}
else
strcpy (gi_filename_up, gi_ptr->filename);
/* Totals for this object file. */
ci_ptr = gi_ptr->counts;
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
......@@ -201,10 +295,20 @@ gcov_exit (void)
fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
}
if (!gcov_open (gi_ptr->filename))
if (!gcov_open (gi_filename))
{
fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
continue;
/* Open failed likely due to missed directory.
Create directory and retry to open file. */
if (create_file_directory (gi_filename))
{
fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
continue;
}
if (!gcov_open (gi_filename))
{
fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
continue;
}
}
tag = gcov_read_unsigned ();
......@@ -214,11 +318,11 @@ gcov_exit (void)
if (tag != GCOV_DATA_MAGIC)
{
fprintf (stderr, "profiling:%s:Not a gcov data file\n",
gi_ptr->filename);
gi_filename);
goto read_fatal;
}
length = gcov_read_unsigned ();
if (!gcov_version (gi_ptr, length))
if (!gcov_version (gi_ptr, length, gi_filename))
goto read_fatal;
length = gcov_read_unsigned ();
......@@ -242,7 +346,7 @@ gcov_exit (void)
{
read_mismatch:;
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
gi_ptr->filename,
gi_filename,
f_ix + 1 ? "function" : "summaries");
goto read_fatal;
}
......@@ -301,7 +405,7 @@ gcov_exit (void)
read_error:;
fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
: "profiling:%s:Error merging\n", gi_ptr->filename);
: "profiling:%s:Error merging\n", gi_filename);
read_fatal:;
gcov_close ();
......@@ -352,7 +456,7 @@ gcov_exit (void)
&& memcmp (cs_all, cs_prg, sizeof (*cs_all)))
{
fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
gi_ptr->filename, GCOV_LOCKED
gi_filename, GCOV_LOCKED
? "" : " or concurrent update without locking support");
all.checksum = ~0u;
}
......@@ -417,7 +521,7 @@ gcov_exit (void)
fprintf (stderr, error < 0 ?
"profiling:%s:Overflow writing\n" :
"profiling:%s:Error writing\n",
gi_ptr->filename);
gi_filename);
}
}
......@@ -429,11 +533,16 @@ __gcov_init (struct gcov_info *info)
{
if (!info->version)
return;
if (gcov_version (info, info->version))
if (gcov_version (info, info->version, 0))
{
const char *ptr = info->filename;
gcov_unsigned_t crc32 = gcov_crc32;
size_t filename_length = strlen(info->filename);
/* Refresh the longest file name information */
if (filename_length > gcov_max_filename)
gcov_max_filename = filename_length;
do
{
unsigned ix;
......
......@@ -131,4 +131,7 @@ extern int errno;
unreachable default case of a switch. Do not use gcc_assert(0). */
#define gcc_unreachable() (abort ())
/* Filename handling macros. */
#include "filenames.h"
#endif /* ! GCC_TSYSTEM_H */
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