1 | /* Precompiled header implementation for the C languages. |
2 | Copyright (C) 2000-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 3, or (at your option) |
9 | any later version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #include "config.h" |
21 | #include "system.h" |
22 | #include "coretypes.h" |
23 | #include "target.h" |
24 | #include "c-common.h" |
25 | #include "timevar.h" |
26 | #include "flags.h" |
27 | #include "debug.h" |
28 | #include "c-pragma.h" |
29 | #include "langhooks.h" |
30 | #include "hosthooks.h" |
31 | |
32 | /* This is a list of flag variables that must match exactly, and their |
33 | names for the error message. The possible values for *flag_var must |
34 | fit in a 'signed char'. */ |
35 | |
36 | static const struct c_pch_matching |
37 | { |
38 | int *flag_var; |
39 | const char *flag_name; |
40 | } pch_matching[] = { |
41 | { .flag_var: &flag_exceptions, .flag_name: "-fexceptions" }, |
42 | }; |
43 | |
44 | enum { |
45 | MATCH_SIZE = ARRAY_SIZE (pch_matching) |
46 | }; |
47 | |
48 | /* Information about flags and suchlike that affect PCH validity. |
49 | |
50 | Before this structure is read, both an initial 8-character identification |
51 | string, and a 16-byte checksum, have been read and validated. */ |
52 | |
53 | struct c_pch_validity |
54 | { |
55 | uint32_t pch_write_symbols; |
56 | signed char match[MATCH_SIZE]; |
57 | size_t target_data_length; |
58 | }; |
59 | |
60 | #define IDENT_LENGTH 8 |
61 | |
62 | /* The file we'll be writing the PCH to. */ |
63 | static FILE *pch_outfile; |
64 | |
65 | static const char *get_ident (void); |
66 | |
67 | /* Compute an appropriate 8-byte magic number for the PCH file, so that |
68 | utilities like file(1) can identify it, and so that GCC can quickly |
69 | ignore non-PCH files and PCH files that are of a completely different |
70 | format. */ |
71 | |
72 | static const char * |
73 | get_ident (void) |
74 | { |
75 | static char result[IDENT_LENGTH]; |
76 | static const char templ[] = "gpch.014" ; |
77 | static const char c_language_chars[] = "Co+O" ; |
78 | |
79 | memcpy (dest: result, src: templ, IDENT_LENGTH); |
80 | result[4] = c_language_chars[c_language]; |
81 | |
82 | return result; |
83 | } |
84 | |
85 | /* Whether preprocessor state should be saved by pch_init. */ |
86 | |
87 | static bool pch_ready_to_save_cpp_state = false; |
88 | |
89 | /* Prepare to write a PCH file, if one is being written. This is |
90 | called at the start of compilation. */ |
91 | |
92 | void |
93 | pch_init (void) |
94 | { |
95 | FILE *f; |
96 | struct c_pch_validity v; |
97 | void *target_validity; |
98 | static const char partial_pch[] = "gpcWrite" ; |
99 | |
100 | if (!pch_file) |
101 | return; |
102 | |
103 | f = fopen (filename: pch_file, modes: "w+b" ); |
104 | if (f == NULL) |
105 | fatal_error (input_location, "cannot create precompiled header %s: %m" , |
106 | pch_file); |
107 | pch_outfile = f; |
108 | |
109 | memset (s: &v, c: '\0', n: sizeof (v)); |
110 | v.pch_write_symbols = write_symbols; |
111 | { |
112 | size_t i; |
113 | for (i = 0; i < MATCH_SIZE; i++) |
114 | { |
115 | v.match[i] = *pch_matching[i].flag_var; |
116 | gcc_assert (v.match[i] == *pch_matching[i].flag_var); |
117 | } |
118 | } |
119 | target_validity = targetm.get_pch_validity (&v.target_data_length); |
120 | |
121 | if (fwrite (ptr: partial_pch, IDENT_LENGTH, n: 1, s: f) != 1 |
122 | || fwrite (ptr: executable_checksum, size: 16, n: 1, s: f) != 1 |
123 | || fwrite (ptr: &v, size: sizeof (v), n: 1, s: f) != 1 |
124 | || fwrite (ptr: target_validity, size: v.target_data_length, n: 1, s: f) != 1) |
125 | fatal_error (input_location, "cannot write to %s: %m" , pch_file); |
126 | |
127 | /* Let the debugging format deal with the PCHness. */ |
128 | (*debug_hooks->handle_pch) (0); |
129 | |
130 | if (pch_ready_to_save_cpp_state) |
131 | pch_cpp_save_state (); |
132 | |
133 | XDELETE (target_validity); |
134 | } |
135 | |
136 | /* Whether preprocessor state has been saved in a PCH file. */ |
137 | |
138 | static bool pch_cpp_state_saved = false; |
139 | |
140 | /* Save preprocessor state in a PCH file, after implicitly included |
141 | headers have been read. If the PCH file has not yet been opened, |
142 | record that state should be saved when it is opened. */ |
143 | |
144 | void |
145 | pch_cpp_save_state (void) |
146 | { |
147 | if (!pch_cpp_state_saved) |
148 | { |
149 | if (pch_outfile) |
150 | { |
151 | cpp_save_state (parse_in, pch_outfile); |
152 | pch_cpp_state_saved = true; |
153 | } |
154 | else |
155 | pch_ready_to_save_cpp_state = true; |
156 | } |
157 | } |
158 | |
159 | /* Write the PCH file. This is called at the end of a compilation which |
160 | will produce a PCH file. */ |
161 | |
162 | void |
163 | c_common_write_pch (void) |
164 | { |
165 | timevar_push (tv: TV_PCH_SAVE); |
166 | |
167 | targetm.prepare_pch_save (); |
168 | |
169 | (*debug_hooks->handle_pch) (1); |
170 | |
171 | prepare_target_option_nodes_for_pch (); |
172 | |
173 | cpp_write_pch_deps (parse_in, pch_outfile); |
174 | |
175 | gt_pch_save (f: pch_outfile); |
176 | |
177 | timevar_push (tv: TV_PCH_CPP_SAVE); |
178 | cpp_write_pch_state (parse_in, pch_outfile); |
179 | timevar_pop (tv: TV_PCH_CPP_SAVE); |
180 | |
181 | if (fseek (stream: pch_outfile, off: 0, SEEK_SET) != 0 |
182 | || fwrite (ptr: get_ident (), IDENT_LENGTH, n: 1, s: pch_outfile) != 1) |
183 | fatal_error (input_location, "cannot write %s: %m" , pch_file); |
184 | |
185 | fclose (stream: pch_outfile); |
186 | |
187 | timevar_pop (tv: TV_PCH_SAVE); |
188 | } |
189 | |
190 | /* Check the PCH file called NAME, open on FD, to see if it can be |
191 | used in this compilation. Return 1 if valid, 0 if the file can't |
192 | be used now but might be if it's seen later in the compilation, and |
193 | 2 if this file could never be used in the compilation. */ |
194 | |
195 | int |
196 | c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) |
197 | { |
198 | int sizeread; |
199 | int result; |
200 | char ident[IDENT_LENGTH + 16]; |
201 | const char *pch_ident; |
202 | struct c_pch_validity v; |
203 | |
204 | /* Perform a quick test of whether this is a valid |
205 | precompiled header for the current language. */ |
206 | |
207 | /* C++ modules and PCH don't play together. */ |
208 | if (flag_modules) |
209 | return 2; |
210 | |
211 | sizeread = read (fd: fd, buf: ident, IDENT_LENGTH + 16); |
212 | if (sizeread == -1) |
213 | fatal_error (input_location, "cannot read %s: %m" , name); |
214 | else if (sizeread != IDENT_LENGTH + 16) |
215 | { |
216 | cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: too short to be a PCH file" , |
217 | name); |
218 | return 2; |
219 | } |
220 | |
221 | pch_ident = get_ident(); |
222 | if (memcmp (s1: ident, s2: pch_ident, IDENT_LENGTH) != 0) |
223 | { |
224 | if (memcmp (s1: ident, s2: pch_ident, n: 5) == 0) |
225 | /* It's a PCH, for the right language, but has the wrong version. */ |
226 | cpp_warning (pfile, CPP_W_INVALID_PCH, |
227 | msgid: "%s: not compatible with this GCC version" , name); |
228 | else if (memcmp (s1: ident, s2: pch_ident, n: 4) == 0) |
229 | /* It's a PCH for the wrong language. */ |
230 | cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: not for %s" , name, |
231 | lang_hooks.name); |
232 | else |
233 | /* Not any kind of PCH. */ |
234 | cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: not a PCH file" , name); |
235 | return 2; |
236 | } |
237 | if (memcmp (s1: ident + IDENT_LENGTH, s2: executable_checksum, n: 16) != 0) |
238 | { |
239 | cpp_warning (pfile, CPP_W_INVALID_PCH, |
240 | msgid: "%s: created by a different GCC executable" , name); |
241 | return 2; |
242 | } |
243 | |
244 | /* At this point, we know it's a PCH file created by this |
245 | executable, so it ought to be long enough that we can read a |
246 | c_pch_validity structure. */ |
247 | if (read (fd: fd, buf: &v, nbytes: sizeof (v)) != sizeof (v)) |
248 | fatal_error (input_location, "cannot read %s: %m" , name); |
249 | |
250 | /* The allowable debug info combinations are that either the PCH file |
251 | was built with the same as is being used now, or the PCH file was |
252 | built for some kind of debug info but now none is in use. */ |
253 | if (v.pch_write_symbols != write_symbols |
254 | && write_symbols != NO_DEBUG) |
255 | { |
256 | char *created_str = xstrdup (debug_set_names (w_symbols: v.pch_write_symbols)); |
257 | char *used_str = xstrdup (debug_set_names (write_symbols)); |
258 | cpp_warning (pfile, CPP_W_INVALID_PCH, |
259 | msgid: "%s: created with '%s' debug info, but used with '%s'" , name, |
260 | created_str, used_str); |
261 | free (ptr: created_str); |
262 | free (ptr: used_str); |
263 | return 2; |
264 | } |
265 | |
266 | /* Check flags that must match exactly. */ |
267 | { |
268 | size_t i; |
269 | for (i = 0; i < MATCH_SIZE; i++) |
270 | if (*pch_matching[i].flag_var != v.match[i]) |
271 | { |
272 | cpp_warning (pfile, CPP_W_INVALID_PCH, |
273 | msgid: "%s: settings for %s do not match" , name, |
274 | pch_matching[i].flag_name); |
275 | return 2; |
276 | } |
277 | } |
278 | |
279 | /* Check the target-specific validity data. */ |
280 | { |
281 | void *this_file_data = xmalloc (v.target_data_length); |
282 | const char *msg; |
283 | |
284 | if ((size_t) read (fd: fd, buf: this_file_data, nbytes: v.target_data_length) |
285 | != v.target_data_length) |
286 | fatal_error (input_location, "cannot read %s: %m" , name); |
287 | msg = targetm.pch_valid_p (this_file_data, v.target_data_length); |
288 | free (ptr: this_file_data); |
289 | if (msg != NULL) |
290 | { |
291 | cpp_warning (pfile, CPP_W_INVALID_PCH, msgid: "%s: %s" , name, msg); |
292 | return 2; |
293 | } |
294 | } |
295 | |
296 | /* Check the preprocessor macros are the same as when the PCH was |
297 | generated. */ |
298 | |
299 | result = cpp_valid_state (pfile, name, fd); |
300 | if (result == -1) |
301 | return 2; |
302 | else |
303 | return result == 0; |
304 | } |
305 | |
306 | /* If non-NULL, this function is called after a precompile header file |
307 | is loaded. */ |
308 | void (*lang_post_pch_load) (void); |
309 | |
310 | /* Load in the PCH file NAME, open on FD. It was originally searched for |
311 | by ORIG_NAME. */ |
312 | |
313 | void |
314 | c_common_read_pch (cpp_reader *pfile, const char *name, |
315 | int fd, const char *orig_name ATTRIBUTE_UNUSED) |
316 | { |
317 | FILE *f; |
318 | struct save_macro_data *smd; |
319 | expanded_location saved_loc; |
320 | bool saved_trace_includes; |
321 | |
322 | timevar_push (tv: TV_PCH_RESTORE); |
323 | |
324 | f = fdopen (fd, "rb" ); |
325 | if (f == NULL) |
326 | { |
327 | cpp_errno (pfile, CPP_DL_ERROR, msgid: "calling fdopen" ); |
328 | close (fd: fd); |
329 | goto end; |
330 | } |
331 | |
332 | cpp_get_callbacks (parse_in)->valid_pch = NULL; |
333 | |
334 | /* Save the location and then restore it after reading the PCH. */ |
335 | saved_loc = expand_location (line_table->highest_line); |
336 | saved_trace_includes = line_table->trace_includes; |
337 | |
338 | timevar_push (tv: TV_PCH_CPP_RESTORE); |
339 | cpp_prepare_state (pfile, &smd); |
340 | timevar_pop (tv: TV_PCH_CPP_RESTORE); |
341 | |
342 | gt_pch_restore (f); |
343 | cpp_set_line_map (pfile, line_table); |
344 | rebuild_location_adhoc_htab (line_table); |
345 | |
346 | timevar_push (tv: TV_PCH_CPP_RESTORE); |
347 | if (cpp_read_state (pfile, name, f, smd) != 0) |
348 | { |
349 | fclose (stream: f); |
350 | timevar_pop (tv: TV_PCH_CPP_RESTORE); |
351 | goto end; |
352 | } |
353 | timevar_pop (tv: TV_PCH_CPP_RESTORE); |
354 | |
355 | |
356 | fclose (stream: f); |
357 | |
358 | line_table->trace_includes = saved_trace_includes; |
359 | linemap_add (line_table, LC_ENTER, sysp: 0, to_file: saved_loc.file, to_line: saved_loc.line); |
360 | |
361 | /* Give the front end a chance to take action after a PCH file has |
362 | been loaded. */ |
363 | if (lang_post_pch_load) |
364 | (*lang_post_pch_load) (); |
365 | |
366 | end: |
367 | timevar_pop (tv: TV_PCH_RESTORE); |
368 | } |
369 | |
370 | /* Indicate that no more PCH files should be read. */ |
371 | |
372 | void |
373 | c_common_no_more_pch (void) |
374 | { |
375 | if (cpp_get_callbacks (parse_in)->valid_pch) |
376 | { |
377 | cpp_get_callbacks (parse_in)->valid_pch = NULL; |
378 | void *addr = NULL; |
379 | host_hooks.gt_pch_use_address (addr, 0, -1, 0); |
380 | } |
381 | } |
382 | |
383 | /* Handle #pragma GCC pch_preprocess, to load in the PCH file. */ |
384 | |
385 | void |
386 | c_common_pch_pragma (cpp_reader *pfile, const char *name) |
387 | { |
388 | int fd; |
389 | |
390 | if (!cpp_get_options (pfile)->preprocessed) |
391 | { |
392 | error ("%<pch_preprocess%> pragma should only be used " |
393 | "with %<-fpreprocessed%>" ); |
394 | inform (input_location, "use %<#include%> instead" ); |
395 | return; |
396 | } |
397 | |
398 | fd = open (file: name, O_RDONLY | O_BINARY, 0666); |
399 | if (fd == -1) |
400 | fatal_error (input_location, "%s: couldn%'t open PCH file: %m" , name); |
401 | |
402 | if (c_common_valid_pch (pfile, name, fd) != 1) |
403 | { |
404 | if (!cpp_get_options (pfile)->warn_invalid_pch) |
405 | inform (input_location, "use %<-Winvalid-pch%> for more information" ); |
406 | fatal_error (input_location, "%s: PCH file was invalid" , name); |
407 | } |
408 | |
409 | c_common_read_pch (pfile, name, fd, orig_name: name); |
410 | |
411 | close (fd: fd); |
412 | } |
413 | |
414 | |