1/* Routines required for instrumenting a program. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1989-2015 Free Software Foundation, Inc. 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 26/* A utility function for outputing errors. */ 27 28static int __attribute__((format(printf, 1, 2))) 29gcov_error (const char *fmt, ...) 30{ 31 int ret; 32 va_list argp; 33 va_start (argp, fmt); 34 ret = vfprintf (stderr, fmt, argp); 35 va_end (argp); 36 return ret; 37} 38 39/* Make sure path component of the given FILENAME exists, create 40 missing directories. FILENAME must be writable. 41 Returns zero on success, or -1 if an error occurred. */ 42 43static int 44create_file_directory (char *filename) 45{ 46#if !defined(TARGET_POSIX_IO) && !defined(_WIN32) 47 (void) filename; 48 return -1; 49#else 50 char *s; 51 52 s = filename; 53 54 if (HAS_DRIVE_SPEC(s)) 55 s += 2; 56 if (IS_DIR_SEPARATOR(*s)) 57 ++s; 58 for (; *s != '\0'; s++) 59 if (IS_DIR_SEPARATOR(*s)) 60 { 61 char sep = *s; 62 *s = '\0'; 63 64 /* Try to make directory if it doesn't already exist. */ 65 if (access (filename, F_OK) == -1 66#ifdef TARGET_POSIX_IO 67 && mkdir (filename, 0755) == -1 68#else 69#ifdef mkdir 70#undef mkdir 71#endif 72 && mkdir (filename) == -1 73#endif 74 /* The directory might have been made by another process. */ 75 && errno != EEXIST) 76 { 77 gcov_error ("profiling:%s:Cannot create directory\n", filename); 78 *s = sep; 79 return -1; 80 }; 81 82 *s = sep; 83 }; 84 return 0; 85#endif 86} 87 88static void 89allocate_filename_struct (struct gcov_filename *gf) 90{ 91 const char *gcov_prefix; 92 size_t prefix_length; 93 int strip = 0; 94 95 { 96 /* Check if the level of dirs to strip off specified. */ 97 char *tmp = getenv("GCOV_PREFIX_STRIP"); 98 if (tmp) 99 { 100 strip = atoi (tmp); 101 /* Do not consider negative values. */ 102 if (strip < 0) 103 strip = 0; 104 } 105 } 106 gf->strip = strip; 107 108 /* Get file name relocation prefix. Non-absolute values are ignored. */ 109 gcov_prefix = getenv("GCOV_PREFIX"); 110 prefix_length = gcov_prefix ? strlen (gcov_prefix) : 0; 111 112 /* Remove an unnecessary trailing '/' */ 113 if (prefix_length && IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])) 114 prefix_length--; 115 116 /* If no prefix was specified and a prefix stip, then we assume 117 relative. */ 118 if (!prefix_length && gf->strip) 119 { 120 gcov_prefix = "."; 121 prefix_length = 1; 122 } 123 gf->prefix = prefix_length; 124 125 /* Allocate and initialize the filename scratch space. */ 126 gf->filename = (char *) xmalloc (gf->max_length + prefix_length + 2); 127 if (prefix_length) 128 memcpy (gf->filename, gcov_prefix, prefix_length); 129} 130 131/* Open a gcda file specified by GI_FILENAME. 132 Return -1 on error. Return 0 on success. */ 133 134static int 135gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, 136 struct gcov_filename *gf) 137{ 138 const char *fname = gi_ptr->filename; 139 char *dst = gf->filename + gf->prefix; 140 141 fname = gi_ptr->filename; 142 143 /* Build relocated filename, stripping off leading 144 directories from the initial filename if requested. */ 145 if (gf->strip > 0) 146 { 147 const char *probe = fname; 148 int level; 149 150 /* Remove a leading separator, without counting it. */ 151 if (IS_DIR_SEPARATOR (*probe)) 152 probe++; 153 154 /* Skip selected directory levels. If we fall off the end, we 155 keep the final part. */ 156 for (level = gf->strip; *probe && level; probe++) 157 if (IS_DIR_SEPARATOR (*probe)) 158 { 159 fname = probe; 160 level--; 161 } 162 } 163 164 /* Update complete filename with stripped original. */ 165 if (gf->prefix) 166 { 167 /* Avoid to add multiple drive letters into combined path. */ 168 if (HAS_DRIVE_SPEC(fname)) 169 fname += 2; 170 171 if (!IS_DIR_SEPARATOR (*fname)) 172 *dst++ = '/'; 173 } 174 strcpy (dst, fname); 175 176 if (!gcov_open (gf->filename)) 177 { 178 /* Open failed likely due to missed directory. 179 Create directory and retry to open file. */ 180 if (create_file_directory (gf->filename)) 181 { 182 fprintf (stderr, "profiling:%s:Skip\n", gf->filename); 183 return -1; 184 } 185 if (!gcov_open (gf->filename)) 186 { 187 fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename); 188 return -1; 189 } 190 } 191 192 return 0; 193} 194