1 /* Implementation of file prefix remapping support (-f*-prefix-map options). 2 Copyright (C) 2017-2020 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify it 5 under the terms of the GNU General Public License as published by the 6 Free Software Foundation; either version 3, or (at your option) any 7 later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; see the file COPYING3. If not see 16 <http://www.gnu.org/licenses/>. */ 17 18 #include "config.h" 19 #include "system.h" 20 #include "coretypes.h" 21 #include "diagnostic.h" 22 #include "file-prefix-map.h" 23 24 /* Structure recording the mapping from source file and directory names at 25 compile time to those to be embedded in the compilation result (debug 26 information, the __FILE__ macro expansion, etc). */ 27 struct file_prefix_map 28 { 29 const char *old_prefix; 30 const char *new_prefix; 31 size_t old_len; 32 size_t new_len; 33 struct file_prefix_map *next; 34 }; 35 36 /* Record a file prefix mapping in the specified map. ARG is the argument to 37 -f*-prefix-map and must be of the form OLD=NEW. OPT is the option name 38 for diagnostics. */ 39 static void 40 add_prefix_map (file_prefix_map *&maps, const char *arg, const char *opt) 41 { 42 file_prefix_map *map; 43 const char *p, *old; 44 size_t oldlen; 45 46 /* Note: looking for the last '='. The thinking is we can control the paths 47 inside our projects but not where the users build them. */ 48 p = strrchr (arg, '='); 49 if (!p) 50 { 51 error ("invalid argument %qs to %qs", arg, opt); 52 return; 53 } 54 if (*arg == '$') 55 { 56 char *env = xstrndup (arg + 1, p - (arg + 1)); 57 old = getenv(env); 58 if (!old) 59 { 60 warning (0, "environment variable %qs not set in argument to " 61 "%s", env, opt); 62 free(env); 63 return; 64 } 65 oldlen = strlen(old); 66 free(env); 67 } 68 else 69 { 70 old = xstrndup (arg, p - arg); 71 oldlen = p - arg; 72 } 73 map = XNEW (file_prefix_map); 74 map->old_prefix = old; 75 map->old_len = oldlen; 76 p++; 77 map->new_prefix = xstrdup (p); 78 map->new_len = strlen (p); 79 map->next = maps; 80 maps = map; 81 } 82 83 /* Perform user-specified mapping of filename prefixes. Return the 84 GC-allocated new name corresponding to FILENAME or FILENAME if no 85 remapping was performed. */ 86 87 static const char * 88 remap_filename (file_prefix_map *maps, const char *filename) 89 { 90 file_prefix_map *map; 91 char *s; 92 const char *name; 93 size_t name_len; 94 95 for (map = maps; map; map = map->next) 96 if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0) 97 break; 98 if (!map) 99 return filename; 100 name = filename + map->old_len; 101 name_len = strlen (name) + 1; 102 103 s = (char *) ggc_alloc_atomic (name_len + map->new_len); 104 memcpy (s, map->new_prefix, map->new_len); 105 memcpy (s + map->new_len, name, name_len); 106 return s; 107 } 108 109 /* NOTE: if adding another -f*-prefix-map option then don't forget to 110 ignore it in DW_AT_producer (dwarf2out.c). */ 111 112 /* Linked lists of file_prefix_map structures. */ 113 static file_prefix_map *macro_prefix_maps; /* -fmacro-prefix-map */ 114 static file_prefix_map *debug_prefix_maps; /* -fdebug-prefix-map */ 115 116 /* Record a file prefix mapping for -fmacro-prefix-map. */ 117 void 118 add_macro_prefix_map (const char *arg) 119 { 120 add_prefix_map (macro_prefix_maps, arg, "-fmacro-prefix-map"); 121 } 122 123 /* Record a file prefix mapping for -fdebug-prefix-map. */ 124 void 125 add_debug_prefix_map (const char *arg) 126 { 127 add_prefix_map (debug_prefix_maps, arg, "-fdebug-prefix-map"); 128 } 129 130 /* Record a file prefix mapping for all -f*-prefix-map. */ 131 void 132 add_file_prefix_map (const char *arg) 133 { 134 add_prefix_map (macro_prefix_maps, arg, "-ffile-prefix-map"); 135 add_prefix_map (debug_prefix_maps, arg, "-ffile-prefix-map"); 136 } 137 138 /* Remap using -fmacro-prefix-map. Return the GC-allocated new name 139 corresponding to FILENAME or FILENAME if no remapping was performed. */ 140 const char * 141 remap_macro_filename (const char *filename) 142 { 143 return remap_filename (macro_prefix_maps, filename); 144 } 145 146 /* Original GCC version disabled. The NetBSD version handles regex */ 147 #if 0 148 /* Remap using -fdebug-prefix-map. Return the GC-allocated new name 149 corresponding to FILENAME or FILENAME if no remapping was performed. */ 150 const char * 151 remap_debug_filename (const char *filename) 152 { 153 return remap_filename (debug_prefix_maps, filename); 154 } 155 #endif 156 157 /***** 158 ***** The following code is a NetBSD extension that allows regex and 159 ***** \[0-9] substitutition arguments. 160 *****/ 161 162 /* Perform user-specified mapping of debug filename prefixes. Return 163 the new name corresponding to FILENAME. */ 164 165 static const char * 166 remap_debug_prefix_filename (const char *filename) 167 { 168 file_prefix_map *map; 169 char *s; 170 const char *name; 171 size_t name_len; 172 173 for (map = debug_prefix_maps; map; map = map->next) 174 if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0) 175 break; 176 if (!map) 177 return filename; 178 name = filename + map->old_len; 179 name_len = strlen (name) + 1; 180 s = (char *) alloca (name_len + map->new_len); 181 memcpy (s, map->new_prefix, map->new_len); 182 memcpy (s + map->new_len, name, name_len); 183 return ggc_strdup (s); 184 } 185 186 #include <regex.h> 187 188 typedef struct debug_regex_map 189 { 190 regex_t re; 191 const char *sub; 192 struct debug_regex_map *next; 193 } debug_regex_map; 194 195 /* Linked list of such structures. */ 196 debug_regex_map *debug_regex_maps; 197 198 199 /* Record a debug file regex mapping. ARG is the argument to 200 -fdebug-regex-map and must be of the form OLD=NEW. */ 201 202 void 203 add_debug_regex_map (const char *arg) 204 { 205 debug_regex_map *map; 206 const char *p; 207 char *old; 208 char buf[1024]; 209 regex_t re; 210 int e; 211 212 p = strchr (arg, '='); 213 if (!p) 214 { 215 error ("invalid argument %qs to -fdebug-regex-map", arg); 216 return; 217 } 218 219 old = xstrndup (arg, p - arg); 220 if ((e = regcomp(&re, old, REG_EXTENDED)) != 0) 221 { 222 regerror(e, &re, buf, sizeof(buf)); 223 warning (0, "regular expression compilation for %qs in argument to " 224 "-fdebug-regex-map failed: %qs", old, buf); 225 free(old); 226 return; 227 } 228 free(old); 229 230 map = XNEW (debug_regex_map); 231 map->re = re; 232 p++; 233 map->sub = xstrdup (p); 234 map->next = debug_regex_maps; 235 debug_regex_maps = map; 236 } 237 238 extern "C" ssize_t regasub(char **, const char *, 239 const regmatch_t *rm, const char *); 240 241 /* Perform user-specified mapping of debug filename regular expressions. Return 242 the new name corresponding to FILENAME. */ 243 244 static const char * 245 remap_debug_regex_filename (const char *filename) 246 { 247 debug_regex_map *map; 248 char *s; 249 regmatch_t rm[10]; 250 251 for (map = debug_regex_maps; map; map = map->next) 252 if (regexec (&map->re, filename, 10, rm, 0) == 0 253 && regasub (&s, map->sub, rm, filename) >= 0) 254 { 255 const char *name = ggc_strdup(s); 256 free(s); 257 return name; 258 } 259 return filename; 260 } 261 262 const char * 263 remap_debug_filename (const char *filename) 264 { 265 return remap_debug_regex_filename (remap_debug_prefix_filename (filename)); 266 } 267