1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2018 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
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
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/>. */
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
;
34 /* A utility function to populate the __gcov_error_file pointer.
35 This should NOT be called outside of the gcov system driver code. */
38 get_gcov_error_file (void)
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
;
56 /* A utility function for outputting errors. */
58 static int __attribute__((format(printf
, 1, 2)))
59 gcov_error (const char *fmt
, ...)
65 FILE *f
= get_gcov_error_file ();
66 ret
= vfprintf (f
, fmt
, argp
);
69 if (getenv ("GCOV_EXIT_AT_ERROR"))
71 fprintf (f
, "profiling:exiting after an error\n");
80 gcov_error_exit (void)
82 if (__gcov_error_file
&& __gcov_error_file
!= stderr
)
84 fclose (__gcov_error_file
);
85 __gcov_error_file
= NULL
;
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. */
95 create_file_directory (char *filename
)
97 #if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
105 if (HAS_DRIVE_SPEC(s
))
107 if (IS_DIR_SEPARATOR(*s
))
109 for (; *s
!= '\0'; s
++)
110 if (IS_DIR_SEPARATOR(*s
))
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
123 && mkdir (filename
) == -1
125 /* The directory might have been made by another process. */
128 gcov_error ("profiling:%s:Cannot create directory\n", filename
);
140 allocate_filename_struct (struct gcov_filename
*gf
)
142 const char *gcov_prefix
;
143 size_t prefix_length
;
147 /* Check if the level of dirs to strip off specified. */
148 char *tmp
= getenv("GCOV_PREFIX_STRIP");
152 /* Do not consider negative values. */
159 /* Get file name relocation prefix. Non-absolute values are ignored. */
160 gcov_prefix
= getenv("GCOV_PREFIX");
161 prefix_length
= gcov_prefix
? strlen (gcov_prefix
) : 0;
163 /* Remove an unnecessary trailing '/' */
164 if (prefix_length
&& IS_DIR_SEPARATOR (gcov_prefix
[prefix_length
- 1]))
167 /* If no prefix was specified and a prefix stip, then we assume
169 if (!prefix_length
&& gf
->strip
)
174 gf
->prefix
= prefix_length
;
176 /* Allocate and initialize the filename scratch space. */
177 gf
->filename
= (char *) xmalloc (gf
->max_length
+ prefix_length
+ 2);
179 memcpy (gf
->filename
, gcov_prefix
, prefix_length
);
182 /* Open a gcda file specified by GI_FILENAME.
183 Return -1 on error. Return 0 on success. */
186 gcov_exit_open_gcda_file (struct gcov_info
*gi_ptr
,
187 struct gcov_filename
*gf
)
189 const char *fname
= gi_ptr
->filename
;
190 char *dst
= gf
->filename
+ gf
->prefix
;
192 fname
= gi_ptr
->filename
;
194 /* Build relocated filename, stripping off leading
195 directories from the initial filename if requested. */
198 const char *probe
= fname
;
201 /* Remove a leading separator, without counting it. */
202 if (IS_DIR_SEPARATOR (*probe
))
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
))
215 /* Update complete filename with stripped original. */
218 /* Avoid to add multiple drive letters into combined path. */
219 if (HAS_DRIVE_SPEC(fname
))
222 if (!IS_DIR_SEPARATOR (*fname
))
227 if (!gcov_open (gf
->filename
))
229 /* Open failed likely due to missed directory.
230 Create directory and retry to open file. */
231 if (create_file_directory (gf
->filename
))
233 fprintf (stderr
, "profiling:%s:Skip\n", gf
->filename
);
236 if (!gcov_open (gf
->filename
))
238 fprintf (stderr
, "profiling:%s:Cannot open\n", gf
->filename
);