re PR c++/79652 (ICE on invalid c++ code in warn_extern_redeclared_static in cp/decl...
[official-gcc.git] / libgcc / libgcov-driver-system.c
blob5cfc950ab0592b20f10dffe979824641cd16be69
1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2017 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #if !IN_GCOV_TOOL
27 /* Configured via the GCOV_ERROR_FILE environment variable;
28 it will either be stderr, or a file of the user's choosing.
29 Non-static to prevent multiple gcov-aware shared objects from
30 instantiating their own copies. */
31 FILE *__gcov_error_file = NULL;
32 #endif
34 /* A utility function to populate the __gcov_error_file pointer.
35 This should NOT be called outside of the gcov system driver code. */
37 static FILE *
38 get_gcov_error_file (void)
40 #if IN_GCOV_TOOL
41 return stderr;
42 #else
43 if (!__gcov_error_file)
45 const char *gcov_error_filename = getenv ("GCOV_ERROR_FILE");
47 if (gcov_error_filename)
48 __gcov_error_file = fopen (gcov_error_filename, "a");
49 if (!__gcov_error_file)
50 __gcov_error_file = stderr;
52 return __gcov_error_file;
53 #endif
56 /* A utility function for outputting errors. */
58 static int __attribute__((format(printf, 1, 2)))
59 gcov_error (const char *fmt, ...)
61 int ret;
62 va_list argp;
64 va_start (argp, fmt);
65 ret = vfprintf (get_gcov_error_file (), fmt, argp);
66 va_end (argp);
67 return ret;
70 #if !IN_GCOV_TOOL
71 static void
72 gcov_error_exit (void)
74 if (__gcov_error_file && __gcov_error_file != stderr)
76 fclose (__gcov_error_file);
77 __gcov_error_file = NULL;
80 #endif
82 /* Make sure path component of the given FILENAME exists, create
83 missing directories. FILENAME must be writable.
84 Returns zero on success, or -1 if an error occurred. */
86 static int
87 create_file_directory (char *filename)
89 #if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
90 (void) filename;
91 return -1;
92 #else
93 char *s;
95 s = filename;
97 if (HAS_DRIVE_SPEC(s))
98 s += 2;
99 if (IS_DIR_SEPARATOR(*s))
100 ++s;
101 for (; *s != '\0'; s++)
102 if (IS_DIR_SEPARATOR(*s))
104 char sep = *s;
105 *s = '\0';
107 /* Try to make directory if it doesn't already exist. */
108 if (access (filename, F_OK) == -1
109 #ifdef TARGET_POSIX_IO
110 && mkdir (filename, 0755) == -1
111 #else
112 #ifdef mkdir
113 #undef mkdir
114 #endif
115 && mkdir (filename) == -1
116 #endif
117 /* The directory might have been made by another process. */
118 && errno != EEXIST)
120 gcov_error ("profiling:%s:Cannot create directory\n", filename);
121 *s = sep;
122 return -1;
125 *s = sep;
127 return 0;
128 #endif
131 static void
132 allocate_filename_struct (struct gcov_filename *gf)
134 const char *gcov_prefix;
135 size_t prefix_length;
136 int strip = 0;
139 /* Check if the level of dirs to strip off specified. */
140 char *tmp = getenv("GCOV_PREFIX_STRIP");
141 if (tmp)
143 strip = atoi (tmp);
144 /* Do not consider negative values. */
145 if (strip < 0)
146 strip = 0;
149 gf->strip = strip;
151 /* Get file name relocation prefix. Non-absolute values are ignored. */
152 gcov_prefix = getenv("GCOV_PREFIX");
153 prefix_length = gcov_prefix ? strlen (gcov_prefix) : 0;
155 /* Remove an unnecessary trailing '/' */
156 if (prefix_length && IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
157 prefix_length--;
159 /* If no prefix was specified and a prefix stip, then we assume
160 relative. */
161 if (!prefix_length && gf->strip)
163 gcov_prefix = ".";
164 prefix_length = 1;
166 gf->prefix = prefix_length;
168 /* Allocate and initialize the filename scratch space. */
169 gf->filename = (char *) xmalloc (gf->max_length + prefix_length + 2);
170 if (prefix_length)
171 memcpy (gf->filename, gcov_prefix, prefix_length);
174 /* Open a gcda file specified by GI_FILENAME.
175 Return -1 on error. Return 0 on success. */
177 static int
178 gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
179 struct gcov_filename *gf)
181 const char *fname = gi_ptr->filename;
182 char *dst = gf->filename + gf->prefix;
184 fname = gi_ptr->filename;
186 /* Build relocated filename, stripping off leading
187 directories from the initial filename if requested. */
188 if (gf->strip > 0)
190 const char *probe = fname;
191 int level;
193 /* Remove a leading separator, without counting it. */
194 if (IS_DIR_SEPARATOR (*probe))
195 probe++;
197 /* Skip selected directory levels. If we fall off the end, we
198 keep the final part. */
199 for (level = gf->strip; *probe && level; probe++)
200 if (IS_DIR_SEPARATOR (*probe))
202 fname = probe;
203 level--;
207 /* Update complete filename with stripped original. */
208 if (gf->prefix)
210 /* Avoid to add multiple drive letters into combined path. */
211 if (HAS_DRIVE_SPEC(fname))
212 fname += 2;
214 if (!IS_DIR_SEPARATOR (*fname))
215 *dst++ = '/';
217 strcpy (dst, fname);
219 if (!gcov_open (gf->filename))
221 /* Open failed likely due to missed directory.
222 Create directory and retry to open file. */
223 if (create_file_directory (gf->filename))
225 fprintf (stderr, "profiling:%s:Skip\n", gf->filename);
226 return -1;
228 if (!gcov_open (gf->filename))
230 fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename);
231 return -1;
235 return 0;