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