1 | /* Implementation of file prefix remapping support (-f*-prefix-map options). |
2 | Copyright (C) 2017-2024 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 | bool canonicalize; |
34 | struct file_prefix_map *next; |
35 | }; |
36 | |
37 | /* Record a file prefix mapping in the specified map. ARG is the argument to |
38 | -f*-prefix-map and must be of the form OLD=NEW. OPT is the option name |
39 | for diagnostics. */ |
40 | static void |
41 | add_prefix_map (file_prefix_map *&maps, const char *arg, const char *opt) |
42 | { |
43 | file_prefix_map *map; |
44 | const char *p; |
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 (s: arg, c: '='); |
49 | if (!p) |
50 | { |
51 | error ("invalid argument %qs to %qs" , arg, opt); |
52 | return; |
53 | } |
54 | map = XNEW (file_prefix_map); |
55 | map->canonicalize = flag_canon_prefix_map; |
56 | map->old_prefix = xstrndup (arg, p - arg); |
57 | map->old_len = p - arg; |
58 | if (map->canonicalize) |
59 | { |
60 | char *realname = lrealpath (map->old_prefix); |
61 | free (ptr: const_cast <char *> (map->old_prefix)); |
62 | map->old_prefix = realname; |
63 | map->old_len = strlen (s: realname); |
64 | } |
65 | p++; |
66 | map->new_prefix = xstrdup (p); |
67 | map->new_len = strlen (s: p); |
68 | map->next = maps; |
69 | maps = map; |
70 | } |
71 | |
72 | /* Perform user-specified mapping of filename prefixes. Return the |
73 | GC-allocated new name corresponding to FILENAME or FILENAME if no |
74 | remapping was performed. */ |
75 | |
76 | static const char * |
77 | remap_filename (file_prefix_map *maps, const char *filename) |
78 | { |
79 | file_prefix_map *map; |
80 | char *s; |
81 | const char *name; |
82 | const char *realname = NULL; |
83 | size_t name_len; |
84 | |
85 | if (!filename) |
86 | return filename; |
87 | |
88 | for (map = maps; map; map = map->next) |
89 | if (map->canonicalize) |
90 | { |
91 | if (realname == NULL) |
92 | { |
93 | if (lbasename (filename) == filename) |
94 | realname = filename; |
95 | else |
96 | realname = lrealpath (filename); |
97 | } |
98 | if (filename_ncmp (s1: realname, s2: map->old_prefix, n: map->old_len) == 0) |
99 | break; |
100 | } |
101 | else if (filename_ncmp (s1: filename, s2: map->old_prefix, n: map->old_len) == 0) |
102 | break; |
103 | if (!map) |
104 | { |
105 | if (realname != filename) |
106 | free (ptr: const_cast <char *> (realname)); |
107 | return filename; |
108 | } |
109 | if (map->canonicalize) |
110 | name = realname + map->old_len; |
111 | else |
112 | name = filename + map->old_len; |
113 | name_len = strlen (s: name) + 1; |
114 | |
115 | s = (char *) ggc_alloc_atomic (s: name_len + map->new_len); |
116 | memcpy (dest: s, src: map->new_prefix, n: map->new_len); |
117 | memcpy (dest: s + map->new_len, src: name, n: name_len); |
118 | if (realname != filename) |
119 | free (ptr: const_cast <char *> (realname)); |
120 | return s; |
121 | } |
122 | |
123 | /* NOTE: if adding another -f*-prefix-map option then don't forget to |
124 | ignore it in DW_AT_producer (gen_command_line_string in opts.cc). */ |
125 | |
126 | /* Linked lists of file_prefix_map structures. */ |
127 | static file_prefix_map *macro_prefix_maps; /* -fmacro-prefix-map */ |
128 | static file_prefix_map *debug_prefix_maps; /* -fdebug-prefix-map */ |
129 | static file_prefix_map *profile_prefix_maps; /* -fprofile-prefix-map */ |
130 | |
131 | /* Record a file prefix mapping for -fmacro-prefix-map. */ |
132 | void |
133 | add_macro_prefix_map (const char *arg) |
134 | { |
135 | add_prefix_map (maps&: macro_prefix_maps, arg, opt: "-fmacro-prefix-map" ); |
136 | } |
137 | |
138 | /* Record a file prefix mapping for -fdebug-prefix-map. */ |
139 | void |
140 | add_debug_prefix_map (const char *arg) |
141 | { |
142 | add_prefix_map (maps&: debug_prefix_maps, arg, opt: "-fdebug-prefix-map" ); |
143 | } |
144 | |
145 | /* Record a file prefix mapping for all -f*-prefix-map. */ |
146 | void |
147 | add_file_prefix_map (const char *arg) |
148 | { |
149 | add_prefix_map (maps&: macro_prefix_maps, arg, opt: "-ffile-prefix-map" ); |
150 | add_prefix_map (maps&: debug_prefix_maps, arg, opt: "-ffile-prefix-map" ); |
151 | add_prefix_map (maps&: profile_prefix_maps, arg, opt: "-ffile-prefix-map" ); |
152 | } |
153 | |
154 | /* Record a file prefix mapping for -fprofile-prefix-map. */ |
155 | void |
156 | add_profile_prefix_map (const char *arg) |
157 | { |
158 | add_prefix_map (maps&: profile_prefix_maps, arg, opt: "-fprofile-prefix-map" ); |
159 | } |
160 | |
161 | /* Remap using -fmacro-prefix-map. Return the GC-allocated new name |
162 | corresponding to FILENAME or FILENAME if no remapping was performed. */ |
163 | const char * |
164 | remap_macro_filename (const char *filename) |
165 | { |
166 | return remap_filename (maps: macro_prefix_maps, filename); |
167 | } |
168 | |
169 | /* Remap using -fdebug-prefix-map. Return the GC-allocated new name |
170 | corresponding to FILENAME or FILENAME if no remapping was performed. */ |
171 | const char * |
172 | remap_debug_filename (const char *filename) |
173 | { |
174 | return remap_filename (maps: debug_prefix_maps, filename); |
175 | } |
176 | |
177 | /* Remap using -fprofile-prefix-map. Return the GC-allocated new name |
178 | corresponding to FILENAME or FILENAME if no remapping was performed. */ |
179 | const char * |
180 | remap_profile_filename (const char *filename) |
181 | { |
182 | return remap_filename (maps: profile_prefix_maps, filename); |
183 | } |
184 | |