/* 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.
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
}
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;
}
#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. */
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.
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. */
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))
{