]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-driver-system.c
libgcov: report about a different timestamp (PR gcov-profile/85759).
[thirdparty/gcc.git] / libgcc / libgcov-driver-system.c
CommitLineData
d6d3f033
RX
1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
85ec4feb 3/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
d6d3f033
RX
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
0a0ec53d 26#if !IN_GCOV_TOOL
8aa5bdd6
AC
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. */
31FILE *__gcov_error_file = NULL;
0a0ec53d 32#endif
8aa5bdd6
AC
33
34/* A utility function to populate the __gcov_error_file pointer.
35 This should NOT be called outside of the gcov system driver code. */
36
37static FILE *
0a0ec53d 38get_gcov_error_file (void)
8aa5bdd6 39{
0a0ec53d 40#if IN_GCOV_TOOL
8aa5bdd6
AC
41 return stderr;
42#else
0a0ec53d 43 if (!__gcov_error_file)
8aa5bdd6 44 {
0a0ec53d
AC
45 const char *gcov_error_filename = getenv ("GCOV_ERROR_FILE");
46
47 if (gcov_error_filename)
48 __gcov_error_file = fopen (gcov_error_filename, "a");
49 if (!__gcov_error_file)
50 __gcov_error_file = stderr;
8aa5bdd6 51 }
8aa5bdd6
AC
52 return __gcov_error_file;
53#endif
54}
55
56/* A utility function for outputting errors. */
d6d3f033
RX
57
58static int __attribute__((format(printf, 1, 2)))
59gcov_error (const char *fmt, ...)
60{
61 int ret;
62 va_list argp;
8aa5bdd6 63
d6d3f033 64 va_start (argp, fmt);
0e8f29da
ML
65 FILE *f = get_gcov_error_file ();
66 ret = vfprintf (f, fmt, argp);
d6d3f033 67 va_end (argp);
0e8f29da
ML
68
69 if (getenv ("GCOV_EXIT_AT_ERROR"))
70 {
71 fprintf (f, "profiling:exiting after an error\n");
72 exit (1);
73 }
74
d6d3f033
RX
75 return ret;
76}
77
8aa5bdd6
AC
78#if !IN_GCOV_TOOL
79static void
80gcov_error_exit (void)
81{
82 if (__gcov_error_file && __gcov_error_file != stderr)
83 {
84 fclose (__gcov_error_file);
85 __gcov_error_file = NULL;
86 }
87}
88#endif
89
d6d3f033
RX
90/* Make sure path component of the given FILENAME exists, create
91 missing directories. FILENAME must be writable.
92 Returns zero on success, or -1 if an error occurred. */
93
94static int
95create_file_directory (char *filename)
96{
97#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
98 (void) filename;
99 return -1;
100#else
101 char *s;
102
103 s = filename;
104
105 if (HAS_DRIVE_SPEC(s))
106 s += 2;
107 if (IS_DIR_SEPARATOR(*s))
108 ++s;
109 for (; *s != '\0'; s++)
110 if (IS_DIR_SEPARATOR(*s))
111 {
112 char sep = *s;
113 *s = '\0';
114
115 /* Try to make directory if it doesn't already exist. */
116 if (access (filename, F_OK) == -1
117#ifdef TARGET_POSIX_IO
118 && mkdir (filename, 0755) == -1
119#else
98174188
RE
120#ifdef mkdir
121#undef mkdir
122#endif
d6d3f033
RX
123 && mkdir (filename) == -1
124#endif
125 /* The directory might have been made by another process. */
126 && errno != EEXIST)
127 {
128 gcov_error ("profiling:%s:Cannot create directory\n", filename);
129 *s = sep;
130 return -1;
131 };
132
133 *s = sep;
134 };
135 return 0;
136#endif
137}
138
139static void
6dc33097 140allocate_filename_struct (struct gcov_filename *gf)
d6d3f033
RX
141{
142 const char *gcov_prefix;
d6d3f033 143 size_t prefix_length;
6dc33097 144 int strip = 0;
d6d3f033 145
d6d3f033
RX
146 {
147 /* Check if the level of dirs to strip off specified. */
148 char *tmp = getenv("GCOV_PREFIX_STRIP");
149 if (tmp)
150 {
6dc33097 151 strip = atoi (tmp);
d6d3f033 152 /* Do not consider negative values. */
6dc33097
NS
153 if (strip < 0)
154 strip = 0;
d6d3f033
RX
155 }
156 }
6dc33097 157 gf->strip = strip;
d6d3f033
RX
158
159 /* Get file name relocation prefix. Non-absolute values are ignored. */
160 gcov_prefix = getenv("GCOV_PREFIX");
6dc33097
NS
161 prefix_length = gcov_prefix ? strlen (gcov_prefix) : 0;
162
163 /* Remove an unnecessary trailing '/' */
164 if (prefix_length && IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
165 prefix_length--;
d6d3f033
RX
166
167 /* If no prefix was specified and a prefix stip, then we assume
168 relative. */
6dc33097 169 if (!prefix_length && gf->strip)
d6d3f033
RX
170 {
171 gcov_prefix = ".";
172 prefix_length = 1;
173 }
6dc33097 174 gf->prefix = prefix_length;
d6d3f033 175
6dc33097
NS
176 /* Allocate and initialize the filename scratch space. */
177 gf->filename = (char *) xmalloc (gf->max_length + prefix_length + 2);
178 if (prefix_length)
179 memcpy (gf->filename, gcov_prefix, prefix_length);
d6d3f033
RX
180}
181
182/* Open a gcda file specified by GI_FILENAME.
183 Return -1 on error. Return 0 on success. */
184
185static int
6dc33097
NS
186gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
187 struct gcov_filename *gf)
d6d3f033 188{
6dc33097
NS
189 const char *fname = gi_ptr->filename;
190 char *dst = gf->filename + gf->prefix;
d6d3f033 191
d6d3f033
RX
192 fname = gi_ptr->filename;
193
d6d3f033
RX
194 /* Build relocated filename, stripping off leading
195 directories from the initial filename if requested. */
6dc33097 196 if (gf->strip > 0)
d6d3f033 197 {
6dc33097
NS
198 const char *probe = fname;
199 int level;
d6d3f033 200
6dc33097
NS
201 /* Remove a leading separator, without counting it. */
202 if (IS_DIR_SEPARATOR (*probe))
203 probe++;
d6d3f033 204
6dc33097
NS
205 /* Skip selected directory levels. If we fall off the end, we
206 keep the final part. */
207 for (level = gf->strip; *probe && level; probe++)
208 if (IS_DIR_SEPARATOR (*probe))
d6d3f033 209 {
6dc33097
NS
210 fname = probe;
211 level--;
d6d3f033
RX
212 }
213 }
214
215 /* Update complete filename with stripped original. */
6dc33097 216 if (gf->prefix)
d6d3f033 217 {
6dc33097
NS
218 /* Avoid to add multiple drive letters into combined path. */
219 if (HAS_DRIVE_SPEC(fname))
220 fname += 2;
221
222 if (!IS_DIR_SEPARATOR (*fname))
223 *dst++ = '/';
d6d3f033 224 }
6dc33097 225 strcpy (dst, fname);
d6d3f033 226
6dc33097 227 if (!gcov_open (gf->filename))
d6d3f033
RX
228 {
229 /* Open failed likely due to missed directory.
230 Create directory and retry to open file. */
6dc33097 231 if (create_file_directory (gf->filename))
d6d3f033 232 {
6dc33097 233 fprintf (stderr, "profiling:%s:Skip\n", gf->filename);
d6d3f033
RX
234 return -1;
235 }
6dc33097 236 if (!gcov_open (gf->filename))
d6d3f033 237 {
6dc33097 238 fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename);
d6d3f033
RX
239 return -1;
240 }
241 }
242
243 return 0;
244}