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