1 /* Implementation of file prefix remapping support (-f*-prefix-map options). 2 Copyright (C) 2017 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; 44 45 /* Note: looking for the last '='. The thinking is we can control the paths 46 inside our projects but not where the users build them. */ 47 p = strrchr (arg, '='); 48 if (!p) 49 { 50 error ("invalid argument %qs to %qs", arg, opt); 51 return; 52 } 53 map = XNEW (file_prefix_map); 54 map->old_prefix = xstrndup (arg, p - arg); 55 map->old_len = p - arg; 56 p++; 57 map->new_prefix = xstrdup (p); 58 map->new_len = strlen (p); 59 map->next = maps; 60 maps = map; 61 } 62 63 /* Perform user-specified mapping of filename prefixes. Return the 64 GC-allocated new name corresponding to FILENAME or FILENAME if no 65 remapping was performed. */ 66 67 static const char * 68 remap_filename (file_prefix_map *maps, const char *filename) 69 { 70 file_prefix_map *map; 71 char *s; 72 const char *name; 73 size_t name_len; 74 75 for (map = maps; map; map = map->next) 76 if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0) 77 break; 78 if (!map) 79 return filename; 80 name = filename + map->old_len; 81 name_len = strlen (name) + 1; 82 83 s = (char *) ggc_alloc_atomic (name_len + map->new_len); 84 memcpy (s, map->new_prefix, map->new_len); 85 memcpy (s + map->new_len, name, name_len); 86 return s; 87 } 88 89 /* NOTE: if adding another -f*-prefix-map option then don't forget to 90 ignore it in DW_AT_producer (dwarf2out.c). */ 91 92 /* Linked lists of file_prefix_map structures. */ 93 static file_prefix_map *macro_prefix_maps; /* -fmacro-prefix-map */ 94 static file_prefix_map *debug_prefix_maps; /* -fdebug-prefix-map */ 95 96 /* Record a file prefix mapping for -fmacro-prefix-map. */ 97 void 98 add_macro_prefix_map (const char *arg) 99 { 100 add_prefix_map (macro_prefix_maps, arg, "-fmacro-prefix-map"); 101 } 102 103 /* Record a file prefix mapping for -fdebug-prefix-map. */ 104 void 105 add_debug_prefix_map (const char *arg) 106 { 107 add_prefix_map (debug_prefix_maps, arg, "-fdebug-prefix-map"); 108 } 109 110 /* Record a file prefix mapping for all -f*-prefix-map. */ 111 void 112 add_file_prefix_map (const char *arg) 113 { 114 add_prefix_map (macro_prefix_maps, arg, "-ffile-prefix-map"); 115 add_prefix_map (debug_prefix_maps, arg, "-ffile-prefix-map"); 116 } 117 118 /* Remap using -fmacro-prefix-map. Return the GC-allocated new name 119 corresponding to FILENAME or FILENAME if no remapping was performed. */ 120 const char * 121 remap_macro_filename (const char *filename) 122 { 123 return remap_filename (macro_prefix_maps, filename); 124 } 125 126 /* Original GCC version disabled. The NetBSD version handles regex */ 127 #if 0 128 /* Remap using -fdebug-prefix-map. Return the GC-allocated new name 129 corresponding to FILENAME or FILENAME if no remapping was performed. */ 130 const char * 131 remap_debug_filename (const char *filename) 132 { 133 return remap_filename (debug_prefix_maps, filename); 134 } 135 #endif 136 137 /***** 138 ***** The following code is a NetBSD extension that allows regex and 139 ***** \[0-9] substitutition arguments. 140 *****/ 141 142 /* Perform user-specified mapping of debug filename prefixes. Return 143 the new name corresponding to FILENAME. */ 144 145 static const char * 146 remap_debug_prefix_filename (const char *filename) 147 { 148 file_prefix_map *map; 149 char *s; 150 const char *name; 151 size_t name_len; 152 153 for (map = debug_prefix_maps; map; map = map->next) 154 if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0) 155 break; 156 if (!map) 157 return filename; 158 name = filename + map->old_len; 159 name_len = strlen (name) + 1; 160 s = (char *) alloca (name_len + map->new_len); 161 memcpy (s, map->new_prefix, map->new_len); 162 memcpy (s + map->new_len, name, name_len); 163 return ggc_strdup (s); 164 } 165 166 #include <regex.h> 167 168 typedef struct debug_regex_map 169 { 170 regex_t re; 171 const char *sub; 172 struct debug_regex_map *next; 173 } debug_regex_map; 174 175 /* Linked list of such structures. */ 176 debug_regex_map *debug_regex_maps; 177 178 179 /* Record a debug file regex mapping. ARG is the argument to 180 -fdebug-regex-map and must be of the form OLD=NEW. */ 181 182 void 183 add_debug_regex_map (const char *arg) 184 { 185 debug_regex_map *map; 186 const char *p; 187 char *old; 188 char buf[1024]; 189 regex_t re; 190 int e; 191 192 p = strchr (arg, '='); 193 if (!p) 194 { 195 error ("invalid argument %qs to -fdebug-regex-map", arg); 196 return; 197 } 198 199 old = xstrndup (arg, p - arg); 200 if ((e = regcomp(&re, old, REG_EXTENDED)) != 0) 201 { 202 regerror(e, &re, buf, sizeof(buf)); 203 warning (0, "regular expression compilation for %qs in argument to " 204 "-fdebug-regex-map failed: %qs", old, buf); 205 free(old); 206 return; 207 } 208 free(old); 209 210 map = XNEW (debug_regex_map); 211 map->re = re; 212 p++; 213 map->sub = xstrdup (p); 214 map->next = debug_regex_maps; 215 debug_regex_maps = map; 216 } 217 218 extern "C" ssize_t regasub(char **, const char *, 219 const regmatch_t *rm, const char *); 220 221 /* Perform user-specified mapping of debug filename regular expressions. Return 222 the new name corresponding to FILENAME. */ 223 224 static const char * 225 remap_debug_regex_filename (const char *filename) 226 { 227 debug_regex_map *map; 228 char *s; 229 regmatch_t rm[10]; 230 231 for (map = debug_regex_maps; map; map = map->next) 232 if (regexec (&map->re, filename, 10, rm, 0) == 0 233 && regasub (&s, map->sub, rm, filename) >= 0) 234 { 235 const char *name = ggc_strdup(s); 236 free(s); 237 return name; 238 } 239 return filename; 240 } 241 242 const char * 243 remap_debug_filename (const char *filename) 244 { 245 return remap_debug_regex_filename (remap_debug_prefix_filename (filename)); 246 } 247