[Darwin] Revert one hunk from r273016 (TLC for older Darwin versions).
[gcc.git] / libgcc / libgcov-driver-system.c
index ff8a521690b150e1177c9e647bd615d4ccd715e4..7d48a1f87d887a068dc90ef29027586998ce71ea 100644 (file)
@@ -1,6 +1,6 @@
 /* Routines required for instrumenting a program.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -23,31 +23,32 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#if !IN_GCOV_TOOL
 /* Configured via the GCOV_ERROR_FILE environment variable;
    it will either be stderr, or a file of the user's choosing.
    Non-static to prevent multiple gcov-aware shared objects from
    instantiating their own copies. */
 FILE *__gcov_error_file = NULL;
+#endif
 
 /* A utility function to populate the __gcov_error_file pointer.
    This should NOT be called outside of the gcov system driver code. */
 
 static FILE *
-get_gcov_error_file(void)
+get_gcov_error_file (void)
 {
-#if !IN_GCOV_TOOL
+#if IN_GCOV_TOOL
   return stderr;
 #else
-  char *gcov_error_filename = getenv ("GCOV_ERROR_FILE");
-
-  if (gcov_error_filename)
+  if (!__gcov_error_file)
     {
-      FILE *openfile = fopen (gcov_error_filename, "a");
-      if (openfile)
-        __gcov_error_file = openfile;
+      const char *gcov_error_filename = getenv ("GCOV_ERROR_FILE");
+
+      if (gcov_error_filename)
+       __gcov_error_file = fopen (gcov_error_filename, "a");
+      if (!__gcov_error_file)
+       __gcov_error_file = stderr;
     }
-  if (!__gcov_error_file)
-    __gcov_error_file = stderr;
   return __gcov_error_file;
 #endif
 }
@@ -60,12 +61,17 @@ gcov_error (const char *fmt, ...)
   int ret;
   va_list argp;
 
-  if (!__gcov_error_file)
-    __gcov_error_file = get_gcov_error_file ();
-
   va_start (argp, fmt);
-  ret = vfprintf (__gcov_error_file, fmt, argp);
+  FILE *f = get_gcov_error_file ();
+  ret = vfprintf (f, fmt, argp);
   va_end (argp);
+
+  if (getenv ("GCOV_EXIT_AT_ERROR"))
+    {
+      fprintf (f, "profiling:exiting after an error\n");
+      exit (1);
+    }
+
   return ret;
 }
 
@@ -130,12 +136,85 @@ create_file_directory (char *filename)
 #endif
 }
 
+/* Replace filename variables in FILENAME.  We currently support expansion:
+
+   %p - process ID
+   %q{ENV} - value of environment variable ENV
+   */
+
+static char *
+replace_filename_variables (char *filename)
+{
+  char buffer[16];
+  char empty[] = "";
+  for (char *p = filename; *p != '\0'; p++)
+    {
+      unsigned length = strlen (filename);
+      if (*p == '%' && *(p + 1) != '\0')
+       {
+         unsigned start = p - filename;
+         p++;
+         char *replacement = NULL;
+         switch (*p)
+           {
+           case 'p':
+             sprintf (buffer, "%d", getpid ());
+             replacement = buffer;
+             p++;
+             break;
+           case 'q':
+             if (*(p + 1) == '{')
+               {
+                 p += 2;
+                 char *e = strchr (p, '}');
+                 if (e)
+                   {
+                     *e = '\0';
+                     replacement = getenv (p);
+                     if (replacement == NULL)
+                       replacement = empty;
+                     p = e + 1;
+                   }
+                 else
+                   return filename;
+               }
+             break;
+           default:
+             return filename;
+           }
+
+         /* Concat beginning of the path, replacement and
+            ending of the path.  */
+         unsigned end = length - (p - filename);
+         unsigned repl_length = replacement != NULL ? strlen (replacement) : 0;
+
+         char *buffer = (char *)xmalloc (start + end + repl_length + 1);
+         char *buffer_ptr = buffer;
+         buffer_ptr = (char *)memcpy (buffer_ptr, filename, start);
+         buffer_ptr += start;
+         if (replacement != NULL)
+           buffer_ptr = (char *)memcpy (buffer_ptr, replacement, repl_length);
+         buffer_ptr += repl_length;
+         buffer_ptr = (char *)memcpy (buffer_ptr, p, end);
+         buffer_ptr += end;
+         *buffer_ptr = '\0';
+
+         free (filename);
+         filename = buffer;
+         p = buffer + start + repl_length;
+       }
+    }
+
+  return filename;
+}
+
 static void
 allocate_filename_struct (struct gcov_filename *gf)
 {
   const char *gcov_prefix;
   size_t prefix_length;
   int strip = 0;
+  gf->filename = NULL;
 
   {
     /* Check if the level of dirs to strip off specified. */
@@ -165,12 +244,16 @@ allocate_filename_struct (struct gcov_filename *gf)
       gcov_prefix = ".";
       prefix_length = 1;
     }
-  gf->prefix = prefix_length;
 
   /* Allocate and initialize the filename scratch space.  */
-  gf->filename = (char *) xmalloc (gf->max_length + prefix_length + 2);
   if (prefix_length)
-    memcpy (gf->filename, gcov_prefix, prefix_length);
+    {
+      gf->prefix = (char *) xmalloc (prefix_length + 1);
+      char *p = (char *) memcpy (gf->prefix, gcov_prefix, prefix_length);
+      *(p + prefix_length) = '\0';
+    }
+  else
+    gf->prefix = NULL;
 }
 
 /* Open a gcda file specified by GI_FILENAME.
@@ -180,10 +263,8 @@ static int
 gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
                          struct gcov_filename *gf)
 {
+  int append_slash = 0;
   const char *fname = gi_ptr->filename;
-  char *dst = gf->filename + gf->prefix;
-
-  fname = gi_ptr->filename;
 
   /* Build relocated filename, stripping off leading
      directories from the initial filename if requested. */
@@ -214,9 +295,19 @@ gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
        fname += 2;
 
       if (!IS_DIR_SEPARATOR (*fname))
-       *dst++ = '/';
+       append_slash = 1;
     }
-  strcpy (dst, fname);
+
+  size_t prefix_length = gf->prefix ? strlen (gf->prefix) : 0;
+  gf->filename = (char *) xmalloc (prefix_length + strlen (fname) + 2);
+  *gf->filename = '\0';
+  if (prefix_length)
+    strcat (gf->filename, gf->prefix);
+  if (append_slash)
+    *gf->filename++ = '/';
+  strcat (gf->filename, fname);
+
+  gf->filename = replace_filename_variables (gf->filename);
 
   if (!gcov_open (gf->filename))
     {