This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[4.1 patch] relocate profile data file


On Wed, May 04, 2005 at 04:41:59PM -0400, Andrew Pinski wrote:
> > 
> > This is a multi-part message in MIME format.
> > --------------050500090302080900090107
> > Content-Type: text/plain; charset=KOI8-R; format=flowed
> > Content-Transfer-Encoding: 7bit
> > 
> > Hi,
> > 
> > Attached is the libgconv patch that allows .gcda files relocation when 
> > running instrumented executable on system other than executable been 
> > built on (cross-profiling). This is the solution of problem discussed a 
> > while ago http://gcc.gnu.org/ml/gcc/2005-04/msg01290.html.
> > 
> > In particular the patch allows to:
> > 1\ automatically create directory structure if does not exist
> > 2\ relocate filename basing on value of two optional environment variables:
> > 	GCOV_PREFIX contains the prefix to add to the absolute paths
> > 	in the object file.
> > 	GCOV_PREFIX_STRIP indicates the how many initial directory names
> > 	to strip off the hardwired absolute paths. Default is 0.
> > 
> > Tested on x86_64-redhat-linux. Is it Ok for 3.4 branch?
> 
> No. This first should go on the mainline.  Please write a patch for
> the mainline.  Really since this is not a regression and an enhancement,
> it __should not__ go on the release branches at all.
> 
> 

This is for gcc 4.1.


H.J.
--
2005-05-04  Grigory Zagorodnev  <grigory.zagorodnev@intel.com>
	    H.J. Lu  <hongjiu.lu@intel.com>

	* gcov-io.c (gcov_open): When in libgcov library
	use given data file relocation prefix to build file name.
	* gcov-io.h (gcov_open): Updated proto to accept
	data file relocation prefix.
	* libgcov.c (create_file_directory): New function.
	(gcov_prefix): New static variable to hold data file
	relocation prefix.
	(gcov_version): Use relocation prefix.
	(gcov_exit): Always try to create directory for output
	file. Relocate filename at each use.
	(__gcov_init): Initialize directory relocation prefix
	if required. Strip off leading directories from
	the initial filename.
	* tsystem.h: include filenames.h
	(DIR_SEPARATOR): Macro copied from system.h.
	(DIR_SEPARATOR_2): Likewise.
	* doc/gcov.texi (Cross-profiling): New node documenting
	cross-profiling management.
	* doc/invoke.texi (-fprofile-arcs): xref to cross-profiling.

--- gcc/doc/gcov.texi.prefex	2005-03-28 11:56:34.000000000 -0800
+++ gcc/doc/gcov.texi	2005-05-04 14:56:17.000000000 -0700
@@ -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 files relocation.
 @end menu
 
 @node Gcov Intro
@@ -531,3 +532,36 @@ 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 files 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 at the same system as it was build or having same 
+absolute directory structure on the target system (program will try 
+to create needed directory structure).
+
+To support cross-profiling, program compiled with @option{-fprofile-arcs}
+performs data file relocation basing on two environment variables:
+
+@itemize @bullet
+@item
+GCOV_PREFIX contains the prefix to add to the absolute paths 
+in the object file.
+
+@item
+GCOV_PREFIX_STRIP indicates the how many initial directory names to strip off 
+the hardwired absolute paths. Default value is 0.
+@end itemize
+
+For example, if object file @file{/user/build/foo.o} was build with 
+@option{-fprofile-arcs}, the final executable will try to create data file 
+@file{/user/build/foo.gcda} when running at the target system and will 
+fail if corresponding directory does not exists and is not allowed to create. 
+
+In this case, manipulating environment variables you can relocate data file 
+to the suitable local directory. For our example, setting @samp{GCOV_PREFIX=/target/run} 
+and @samp{GCOV_PREFIX_STRIP=1} values will force use of @file{/target/run/build/foo.gcda} 
+file name.
--- gcc/doc/invoke.texi.prefex	2005-05-04 11:21:00.000000000 -0700
+++ gcc/doc/invoke.texi	2005-05-04 14:56:17.000000000 -0700
@@ -3420,6 +3420,7 @@ explicitly specified and it is not the f
 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
--- gcc/gcov-io.c.prefex	2005-04-28 16:11:30.000000000 -0700
+++ gcc/gcov-io.c	2005-05-04 14:56:17.000000000 -0700
@@ -55,13 +55,14 @@ static inline gcov_unsigned_t from_file 
 
 GCOV_LINKAGE int
 #if IN_LIBGCOV
-gcov_open (const char *name)
+gcov_open (const char *prefix, const char *name)
 #else
 gcov_open (const char *name, int mode)
 #endif
 {
 #if IN_LIBGCOV
   const int mode = 0;
+  char *tmp;
 #endif
 #if GCOV_LOCKED
   struct flock s_flock;
@@ -82,6 +83,14 @@ gcov_open (const char *name, int mode)
 #if !IN_LIBGCOV
   gcov_var.endian = 0;
 #endif
+
+#if IN_LIBGCOV
+  /* Build complete filename with prefix */
+  tmp = alloca( strlen(prefix) + strlen(name) + 1);
+  *tmp = '\0';
+  name = strcat( strcat(tmp, prefix), name);
+#endif
+
 #if GCOV_LOCKED
   if (mode > 0)
     fd = open (name, O_RDWR);
--- gcc/gcov-io.h.prefex	2005-05-02 17:43:08.000000000 -0700
+++ gcc/gcov-io.h	2005-05-04 14:56:17.000000000 -0700
@@ -515,7 +515,7 @@ GCOV_LINKAGE struct gcov_var
    functions for writing.  Your file may become corrupted if you break
    these invariants.  */
 #if IN_LIBGCOV
-GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE int gcov_open (const char */*prefix*/, const char */*name*/) ATTRIBUTE_HIDDEN;
 #else
 GCOV_LINKAGE int gcov_open (const char */*name*/, int /*direction*/);
 GCOV_LINKAGE int gcov_magic (gcov_unsigned_t, gcov_unsigned_t);
--- gcc/libgcov.c.prefex	2005-04-28 16:11:30.000000000 -0700
+++ gcc/libgcov.c	2005-05-04 15:04:47.000000000 -0700
@@ -92,6 +92,70 @@ static struct gcov_info *gcov_list;
    object file included in multiple programs.  */
 static gcov_unsigned_t gcov_crc32;
 
+/* Directory prefix to relocate coverage data file names */
+static char *gcov_prefix = 0;
+
+/* Level of dirs to strip off the initial filename to relocate */
+static int gcov_prefix_strip = 0;
+
+static int
+create_file_directory (const char *prefix, const char *filename)
+{
+  char *dname;
+  char sep, *r, *s;
+  size_t plen, flen;
+  
+  /* Detect directory separator */
+  s = strrchr (prefix, DIR_SEPARATOR);
+#ifdef DIR_SEPARATOR_2
+  if (! s)
+    s = strrchr (prefix, DIR_SEPARATOR_2);
+#endif
+  if (s)
+    sep = *s;
+  else
+    sep = DIR_SEPARATOR;
+
+  /* join prefix and filename, split path */
+  plen  = strlen(prefix);
+  flen  = strlen(filename);
+  r     = alloca(plen + flen + 1);
+  strncpy(r, prefix, plen);
+  strncpy(r + plen, filename, flen);
+  r[plen + flen] = '\0';
+  s = strrchr(r, sep);
+  if (s)
+    *(s + 1) = '\0';
+
+  if (access (r, F_OK) == 0)
+    return 0;
+
+  /* Skip consecutive separators.  */
+  for (dname = r; *dname && *dname == sep; ++dname);
+  while (1)
+    {
+      char *s = strchr (dname, sep);
+      if (s == 0)
+        break;
+      *s = '\0';
+      /* Try to make directory if it doesn't already exist.  */
+      if (access (r, F_OK) == -1
+          && mkdir (r, 0755) == -1
+          /* The directory might have been made by another process.  */
+	  && errno != EEXIST)
+	{
+          *s = sep;
+          fprintf (stderr, "profiling:%s:Cannot create directory\n", r);
+	  return -1;
+	};
+      *s = sep;
+      /* Skip consecutive separators.  */
+      for (dname = s + 1; *dname && *dname == sep; ++dname)
+        ;
+    }
+  return 0;
+}
+
 static int
 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
 {
@@ -103,8 +167,8 @@ gcov_version (struct gcov_info *ptr, gco
       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
       
       fprintf (stderr,
-	       "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
-	       ptr->filename, e, v);
+	       "profiling:%s%s:Version mismatch - expected %.4s got %.4s\n",
+	       gcov_prefix, ptr->filename, e, v);
       return 0;
     }
   return 1;
@@ -205,9 +269,16 @@ gcov_exit (void)
 	  fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
 	}
       
-      if (!gcov_open (gi_ptr->filename))
+      if (create_file_directory (gcov_prefix, gi_ptr->filename))
+	{
+	  fprintf (stderr, "profiling:%s%s:Skip\n", gcov_prefix,
+		   gi_ptr->filename);
+	  continue;
+	}
+      else if (!gcov_open (gcov_prefix, gi_ptr->filename))
 	{
-	  fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
+	  fprintf (stderr, "profiling:%s%s:Cannot open\n", gcov_prefix,
+		   gi_ptr->filename);
 	  continue;
 	}
 
@@ -217,8 +288,8 @@ gcov_exit (void)
 	  /* Merge data from file.  */
 	  if (tag != GCOV_DATA_MAGIC)
 	    {
-	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
-		       gi_ptr->filename);
+	      fprintf (stderr, "profiling:%s%s:Not a gcov data file\n",
+		       gcov_prefix, gi_ptr->filename);
 	      goto read_fatal;
 	    }
 	  length = gcov_read_unsigned ();
@@ -245,8 +316,8 @@ gcov_exit (void)
 		  || gcov_read_unsigned () != fi_ptr->checksum)
 		{
 		read_mismatch:;
-		  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
-			   gi_ptr->filename,
+		  fprintf (stderr, "profiling:%s%s:Merge mismatch for %s\n",
+			   gcov_prefix, gi_ptr->filename,
 			   f_ix + 1 ? "function" : "summaries");
 		  goto read_fatal;
 		}
@@ -305,7 +376,8 @@ gcov_exit (void)
       
     read_error:;
       fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
-	       : "profiling:%s:Error merging\n", gi_ptr->filename);
+	       : "profiling:%s%s:Error merging\n", gcov_prefix,
+	       gi_ptr->filename);
 	      
     read_fatal:;
       gcov_close ();
@@ -355,8 +427,8 @@ gcov_exit (void)
 		   && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
 		   && 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
+	      fprintf (stderr, "profiling:%s%s:Invocation mismatch - some data files may have been removed%s",
+		       gcov_prefix, gi_ptr->filename, GCOV_LOCKED
 		       ? "" : " or concurrent update without locking support");
 	      all.checksum = ~0u;
 	    }
@@ -419,9 +491,9 @@ gcov_exit (void)
 	gcov_write_unsigned (0);
       if ((error = gcov_close ()))
 	  fprintf (stderr, error  < 0 ?
-		   "profiling:%s:Overflow writing\n" :
-		   "profiling:%s:Error writing\n",
-		   gi_ptr->filename);
+		   "profiling:%s%s:Overflow writing\n" :
+		   "profiling:%s%s:Error writing\n",
+		   gcov_prefix, gi_ptr->filename);
     }
 }
 
@@ -431,11 +503,69 @@ gcov_exit (void)
 void
 __gcov_init (struct gcov_info *info)
 {
+  /* Save initial filename pointer to calculate CRC. */
+  const char *ptr = info->filename;
+  
   if (!info->version)
     return;
+
+  /* Initialize directory prefix if requred */
+  if (gcov_prefix == 0)
+    {
+      if ((gcov_prefix = getenv("GCOV_PREFIX")))
+        {
+          char *tmp;
+	
+          /* Normalize prefix: take off trailing separator. */
+	  tmp = gcov_prefix + strlen(gcov_prefix) - 1;
+          if (IS_DIR_SEPARATOR(*tmp))
+            *tmp = '\0';
+
+          /* Check if the level of dirs to strip off specified */
+          if ((tmp = getenv("GCOV_PREFIX_STRIP")))
+            {
+	      gcov_prefix_strip = atoi (tmp);
+	      /* Do not consider negative values. */
+	      if (gcov_prefix_strip < 0)
+	        gcov_prefix_strip = 0;
+	    };
+        }
+      else 
+          gcov_prefix = (char *) "";
+    };
+    
+  /* Strip off leading directories from the initial filename */
+  if (gcov_prefix_strip > 0)
+    {
+      char sep, *s;
+      int level;
+      const char *fname = info->filename;
+      
+      /* Detect directory separator */
+      s = strrchr (fname, DIR_SEPARATOR);
+#ifdef DIR_SEPARATOR_2
+      if (! s)
+        s = strrchr (fname, DIR_SEPARATOR_2);
+#endif
+      if (s)
+        sep = *s;
+      else
+        sep = DIR_SEPARATOR;
+
+      /* Skip selected directory levels */
+      for ( level = gcov_prefix_strip; level > 0; level--)
+        if ((s = strchr(fname + 1, sep)))
+	  fname = s;
+	else
+	  break;
+	  
+      /* From this point info block refers stripped file name and 
+         further operations must add prefix to get complete name.*/
+      info->filename = fname;
+    };
+
   if (gcov_version (info, info->version))
     {
-      const char *ptr = info->filename;
       gcov_unsigned_t crc32 = gcov_crc32;
   
       do
--- gcc/tsystem.h.prefex	2005-03-29 16:06:26.000000000 -0800
+++ gcc/tsystem.h	2005-05-04 14:56:17.000000000 -0700
@@ -131,4 +131,15 @@ 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"
+
+/* These should be phased out in favor of IS_DIR_SEPARATOR, where possible.  */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# ifdef HAVE_DOS_BASED_FILE_SYSTEM
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+#endif
+
 #endif /* ! GCC_TSYSTEM_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]