1 /* Routines required for instrumenting a program. */ 2 /* Compile this one with gcc. */ 3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc. 4 5 This file is part of GCC. 6 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. 11 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. 16 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. 20 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/>. */ 25 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 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 37 static FILE * 38 get_gcov_error_file (void) 39 { 40 #if IN_GCOV_TOOL 41 return stderr; 42 #else 43 if (!__gcov_error_file) 44 { 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; 51 } 52 return __gcov_error_file; 53 #endif 54 } 55 56 /* A utility function for outputting errors. */ 57 58 static int __attribute__((format(printf, 1, 2))) 59 gcov_error (const char *fmt, ...) 60 { 61 int ret; 62 va_list argp; 63 64 va_start (argp, fmt); 65 ret = vfprintf (get_gcov_error_file (), fmt, argp); 66 va_end (argp); 67 return ret; 68 } 69 70 #if !IN_GCOV_TOOL 71 static void 72 gcov_error_exit (void) 73 { 74 if (__gcov_error_file && __gcov_error_file != stderr) 75 { 76 fclose (__gcov_error_file); 77 __gcov_error_file = NULL; 78 } 79 } 80 #endif 81 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. */ 85 86 static int 87 create_file_directory (char *filename) 88 { 89 #if !defined(TARGET_POSIX_IO) && !defined(_WIN32) 90 (void) filename; 91 return -1; 92 #else 93 char *s; 94 95 s = filename; 96 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)) 103 { 104 char sep = *s; 105 *s = '\0'; 106 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) 119 { 120 gcov_error ("profiling:%s:Cannot create directory\n", filename); 121 *s = sep; 122 return -1; 123 }; 124 125 *s = sep; 126 }; 127 return 0; 128 #endif 129 } 130 131 static void 132 allocate_filename_struct (struct gcov_filename *gf) 133 { 134 const char *gcov_prefix; 135 size_t prefix_length; 136 int strip = 0; 137 138 { 139 /* Check if the level of dirs to strip off specified. */ 140 char *tmp = getenv("GCOV_PREFIX_STRIP"); 141 if (tmp) 142 { 143 strip = atoi (tmp); 144 /* Do not consider negative values. */ 145 if (strip < 0) 146 strip = 0; 147 } 148 } 149 gf->strip = strip; 150 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; 154 155 /* Remove an unnecessary trailing '/' */ 156 if (prefix_length && IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])) 157 prefix_length--; 158 159 /* If no prefix was specified and a prefix stip, then we assume 160 relative. */ 161 if (!prefix_length && gf->strip) 162 { 163 gcov_prefix = "."; 164 prefix_length = 1; 165 } 166 gf->prefix = prefix_length; 167 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); 172 } 173 174 /* Open a gcda file specified by GI_FILENAME. 175 Return -1 on error. Return 0 on success. */ 176 177 static int 178 gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, 179 struct gcov_filename *gf) 180 { 181 const char *fname = gi_ptr->filename; 182 char *dst = gf->filename + gf->prefix; 183 184 fname = gi_ptr->filename; 185 186 /* Build relocated filename, stripping off leading 187 directories from the initial filename if requested. */ 188 if (gf->strip > 0) 189 { 190 const char *probe = fname; 191 int level; 192 193 /* Remove a leading separator, without counting it. */ 194 if (IS_DIR_SEPARATOR (*probe)) 195 probe++; 196 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)) 201 { 202 fname = probe; 203 level--; 204 } 205 } 206 207 /* Update complete filename with stripped original. */ 208 if (gf->prefix) 209 { 210 /* Avoid to add multiple drive letters into combined path. */ 211 if (HAS_DRIVE_SPEC(fname)) 212 fname += 2; 213 214 if (!IS_DIR_SEPARATOR (*fname)) 215 *dst++ = '/'; 216 } 217 strcpy (dst, fname); 218 219 if (!gcov_open (gf->filename)) 220 { 221 /* Open failed likely due to missed directory. 222 Create directory and retry to open file. */ 223 if (create_file_directory (gf->filename)) 224 { 225 fprintf (stderr, "profiling:%s:Skip\n", gf->filename); 226 return -1; 227 } 228 if (!gcov_open (gf->filename)) 229 { 230 fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename); 231 return -1; 232 } 233 } 234 235 return 0; 236 } 237