aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGrigory Zagorodnev <grigory.zagorodnev@intel.com>2005-05-10 16:10:54 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2005-05-10 16:10:54 +0000
commit992f396fcb3903a363a1ac3c885c492d3e789b63 (patch)
tree88434cdc971ae92b6f0f0bfa67f792324670c31b /gcc
parent0f95e9143a13dfd136675c080fba4038e4b5721c (diff)
downloadgcc-992f396fcb3903a363a1ac3c885c492d3e789b63.zip
gcc-992f396fcb3903a363a1ac3c885c492d3e789b63.tar.gz
gcc-992f396fcb3903a363a1ac3c885c492d3e789b63.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/doc/gcov.texi40
-rw-r--r--gcc/doc/invoke.texi1
-rw-r--r--gcc/libgcov.c135
-rw-r--r--gcc/tsystem.h3
5 files changed, 181 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e54a84d..5152682 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+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
diff --git a/gcc/doc/gcov.texi b/gcc/doc/gcov.texi
index bfe4a3d..d932ab9 100644
--- a/gcc/doc/gcov.texi
+++ b/gcc/doc/gcov.texi
@@ -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.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7c2c49e..d95b354 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index 8061383..8b478a7 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -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;
diff --git a/gcc/tsystem.h b/gcc/tsystem.h
index 1ed0cde..bc8384e 100644
--- a/gcc/tsystem.h
+++ b/gcc/tsystem.h
@@ -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 */