00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023 #include "coretypes.h"
00024 #include "version.h"
00025 #include "cpplib.h"
00026 #include "tree.h"
00027 #include "flags.h"
00028 #include "c-common.h"
00029 #include "output.h"
00030 #include "toplev.h"
00031 #include "debug.h"
00032 #include "c-pragma.h"
00033 #include "ggc.h"
00034 #include "langhooks.h"
00035 #include "hosthooks.h"
00036 #include "target.h"
00037
00038
00039
00040
00041
00042 static const struct c_pch_matching
00043 {
00044 int *flag_var;
00045 const char *flag_name;
00046 } pch_matching[] = {
00047 { &flag_exceptions, "-fexceptions" },
00048 { &flag_unit_at_a_time, "-funit-at-a-time" }
00049 };
00050
00051 enum {
00052 MATCH_SIZE = ARRAY_SIZE (pch_matching)
00053 };
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 struct c_pch_validity
00067 {
00068 unsigned char host_machine_length;
00069 unsigned char target_machine_length;
00070 unsigned char version_length;
00071 unsigned char debug_info_type;
00072 signed char match[MATCH_SIZE];
00073 void (*pch_init) (void);
00074 size_t target_data_length;
00075 };
00076
00077 struct c_pch_header
00078 {
00079 unsigned long asm_size;
00080 };
00081
00082 #define IDENT_LENGTH 8
00083
00084
00085 static FILE *pch_outfile;
00086
00087
00088 static long asm_file_startpos;
00089
00090
00091 static const char host_machine[] = HOST_MACHINE;
00092 static const char target_machine[] = TARGET_MACHINE;
00093
00094 static const char *get_ident (void);
00095
00096
00097
00098
00099
00100
00101 static const char *
00102 get_ident (void)
00103 {
00104 static char result[IDENT_LENGTH];
00105 static const char template[IDENT_LENGTH] = "gpch.012";
00106 static const char c_language_chars[] = "Co+O";
00107
00108 memcpy (result, template, IDENT_LENGTH);
00109 result[4] = c_language_chars[c_language];
00110
00111 return result;
00112 }
00113
00114
00115
00116
00117 void
00118 pch_init (void)
00119 {
00120 FILE *f;
00121 struct c_pch_validity v;
00122 void *target_validity;
00123 static const char partial_pch[IDENT_LENGTH] = "gpcWrite";
00124
00125 if (!pch_file)
00126 return;
00127
00128 f = fopen (pch_file, "w+b");
00129 if (f == NULL)
00130 fatal_error ("can%'t create precompiled header %s: %m", pch_file);
00131 pch_outfile = f;
00132
00133 gcc_assert (strlen (host_machine) < 256
00134 && strlen (target_machine) < 256
00135 && strlen (version_string) < 256);
00136
00137 v.host_machine_length = strlen (host_machine);
00138 v.target_machine_length = strlen (target_machine);
00139 v.version_length = strlen (version_string);
00140 v.debug_info_type = write_symbols;
00141 {
00142 size_t i;
00143 for (i = 0; i < MATCH_SIZE; i++)
00144 {
00145 v.match[i] = *pch_matching[i].flag_var;
00146 gcc_assert (v.match[i] == *pch_matching[i].flag_var);
00147 }
00148 }
00149 v.pch_init = &pch_init;
00150 target_validity = targetm.get_pch_validity (&v.target_data_length);
00151
00152 if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
00153 || fwrite (&v, sizeof (v), 1, f) != 1
00154 || fwrite (host_machine, v.host_machine_length, 1, f) != 1
00155 || fwrite (target_machine, v.target_machine_length, 1, f) != 1
00156 || fwrite (version_string, v.version_length, 1, f) != 1
00157 || fwrite (target_validity, v.target_data_length, 1, f) != 1)
00158 fatal_error ("can%'t write to %s: %m", pch_file);
00159
00160
00161
00162 if (asm_file_name == NULL
00163 || strcmp (asm_file_name, "-") == 0)
00164 fatal_error ("%qs is not a valid output file", asm_file_name);
00165
00166 asm_file_startpos = ftell (asm_out_file);
00167
00168
00169 (*debug_hooks->handle_pch) (0);
00170
00171 cpp_save_state (parse_in, f);
00172 }
00173
00174
00175
00176
00177 void
00178 c_common_write_pch (void)
00179 {
00180 char *buf;
00181 long asm_file_end;
00182 long written;
00183 struct c_pch_header h;
00184
00185 (*debug_hooks->handle_pch) (1);
00186
00187 cpp_write_pch_deps (parse_in, pch_outfile);
00188
00189 asm_file_end = ftell (asm_out_file);
00190 h.asm_size = asm_file_end - asm_file_startpos;
00191
00192 if (fwrite (&h, sizeof (h), 1, pch_outfile) != 1)
00193 fatal_error ("can%'t write %s: %m", pch_file);
00194
00195 buf = xmalloc (16384);
00196
00197 if (fseek (asm_out_file, asm_file_startpos, SEEK_SET) != 0)
00198 fatal_error ("can%'t seek in %s: %m", asm_file_name);
00199
00200 for (written = asm_file_startpos; written < asm_file_end; )
00201 {
00202 long size = asm_file_end - written;
00203 if (size > 16384)
00204 size = 16384;
00205 if (fread (buf, size, 1, asm_out_file) != 1)
00206 fatal_error ("can%'t read %s: %m", asm_file_name);
00207 if (fwrite (buf, size, 1, pch_outfile) != 1)
00208 fatal_error ("can%'t write %s: %m", pch_file);
00209 written += size;
00210 }
00211 free (buf);
00212
00213
00214 if (fseek (asm_out_file, 0, SEEK_END) != 0)
00215 fatal_error ("can%'t seek in %s: %m", asm_file_name);
00216
00217 gt_pch_save (pch_outfile);
00218 cpp_write_pch_state (parse_in, pch_outfile);
00219
00220 if (fseek (pch_outfile, 0, SEEK_SET) != 0
00221 || fwrite (get_ident (), IDENT_LENGTH, 1, pch_outfile) != 1)
00222 fatal_error ("can%'t write %s: %m", pch_file);
00223
00224 fclose (pch_outfile);
00225 }
00226
00227
00228
00229
00230
00231
00232 int
00233 c_common_valid_pch (cpp_reader *pfile, const char *name, int fd)
00234 {
00235 int sizeread;
00236 int result;
00237 char ident[IDENT_LENGTH];
00238 char short_strings[256 * 3];
00239 int strings_length;
00240 const char *pch_ident;
00241 struct c_pch_validity v;
00242
00243
00244
00245
00246 sizeread = read (fd, ident, IDENT_LENGTH);
00247 if (sizeread == -1)
00248 fatal_error ("can%'t read %s: %m", name);
00249 else if (sizeread != IDENT_LENGTH)
00250 return 2;
00251
00252 pch_ident = get_ident();
00253 if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0)
00254 {
00255 if (cpp_get_options (pfile)->warn_invalid_pch)
00256 {
00257 if (memcmp (ident, pch_ident, 5) == 0)
00258
00259
00260 cpp_error (pfile, CPP_DL_WARNING,
00261 "%s: not compatible with this GCC version", name);
00262 else if (memcmp (ident, pch_ident, 4) == 0)
00263
00264 cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name,
00265 lang_hooks.name);
00266 else
00267
00268 cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name);
00269 }
00270 return 2;
00271 }
00272
00273
00274
00275 if (read (fd, &v, sizeof (v)) != sizeof (v))
00276 fatal_error ("can%'t read %s: %m", name);
00277
00278 strings_length = (v.host_machine_length + v.target_machine_length
00279 + v.version_length);
00280 if (read (fd, short_strings, strings_length) != strings_length)
00281 fatal_error ("can%'t read %s: %m", name);
00282 if (v.host_machine_length != strlen (host_machine)
00283 || memcmp (host_machine, short_strings, strlen (host_machine)) != 0)
00284 {
00285 if (cpp_get_options (pfile)->warn_invalid_pch)
00286 cpp_error (pfile, CPP_DL_WARNING,
00287 "%s: created on host '%.*s', but used on host '%s'", name,
00288 v.host_machine_length, short_strings, host_machine);
00289 return 2;
00290 }
00291 if (v.target_machine_length != strlen (target_machine)
00292 || memcmp (target_machine, short_strings + v.host_machine_length,
00293 strlen (target_machine)) != 0)
00294 {
00295 if (cpp_get_options (pfile)->warn_invalid_pch)
00296 cpp_error (pfile, CPP_DL_WARNING,
00297 "%s: created for target '%.*s', but used for target '%s'",
00298 name, v.target_machine_length,
00299 short_strings + v.host_machine_length, target_machine);
00300 return 2;
00301 }
00302 if (v.version_length != strlen (version_string)
00303 || memcmp (version_string,
00304 (short_strings + v.host_machine_length
00305 + v.target_machine_length),
00306 v.version_length) != 0)
00307 {
00308 if (cpp_get_options (pfile)->warn_invalid_pch)
00309 cpp_error (pfile, CPP_DL_WARNING,
00310 "%s: created by version '%.*s', but this is version '%s'",
00311 name, v.version_length,
00312 (short_strings + v.host_machine_length
00313 + v.target_machine_length),
00314 version_string);
00315 return 2;
00316 }
00317
00318
00319
00320
00321 if (v.debug_info_type != write_symbols
00322 && write_symbols != NO_DEBUG)
00323 {
00324 if (cpp_get_options (pfile)->warn_invalid_pch)
00325 cpp_error (pfile, CPP_DL_WARNING,
00326 "%s: created with -g%s, but used with -g%s", name,
00327 debug_type_names[v.debug_info_type],
00328 debug_type_names[write_symbols]);
00329 return 2;
00330 }
00331
00332
00333 {
00334 size_t i;
00335 for (i = 0; i < MATCH_SIZE; i++)
00336 if (*pch_matching[i].flag_var != v.match[i])
00337 {
00338 if (cpp_get_options (pfile)->warn_invalid_pch)
00339 cpp_error (pfile, CPP_DL_WARNING,
00340 "%s: settings for %s do not match", name,
00341 pch_matching[i].flag_name);
00342 return 2;
00343 }
00344 }
00345
00346
00347
00348
00349
00350 if (v.pch_init != &pch_init)
00351 {
00352 if (cpp_get_options (pfile)->warn_invalid_pch)
00353 cpp_error (pfile, CPP_DL_WARNING,
00354 "%s: had text segment at different address", name);
00355 return 2;
00356 }
00357
00358
00359 {
00360 void *this_file_data = xmalloc (v.target_data_length);
00361 const char *msg;
00362
00363 if ((size_t) read (fd, this_file_data, v.target_data_length)
00364 != v.target_data_length)
00365 fatal_error ("can%'t read %s: %m", name);
00366 msg = targetm.pch_valid_p (this_file_data, v.target_data_length);
00367 free (this_file_data);
00368 if (msg != NULL)
00369 {
00370 if (cpp_get_options (pfile)->warn_invalid_pch)
00371 cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg);
00372 return 2;
00373 }
00374 }
00375
00376
00377
00378
00379 result = cpp_valid_state (pfile, name, fd);
00380 if (result == -1)
00381 return 2;
00382 else
00383 return result == 0;
00384 }
00385
00386
00387
00388 void (*lang_post_pch_load) (void);
00389
00390
00391
00392
00393 void
00394 c_common_read_pch (cpp_reader *pfile, const char *name,
00395 int fd, const char *orig_name ATTRIBUTE_UNUSED)
00396 {
00397 FILE *f;
00398 struct c_pch_header h;
00399 struct save_macro_data *smd;
00400
00401 f = fdopen (fd, "rb");
00402 if (f == NULL)
00403 {
00404 cpp_errno (pfile, CPP_DL_ERROR, "calling fdopen");
00405 return;
00406 }
00407
00408 cpp_get_callbacks (parse_in)->valid_pch = NULL;
00409
00410 if (fread (&h, sizeof (h), 1, f) != 1)
00411 {
00412 cpp_errno (pfile, CPP_DL_ERROR, "reading");
00413 return;
00414 }
00415
00416 if (!flag_preprocess_only)
00417 {
00418 unsigned long written;
00419 char * buf = xmalloc (16384);
00420
00421 for (written = 0; written < h.asm_size; )
00422 {
00423 long size = h.asm_size - written;
00424 if (size > 16384)
00425 size = 16384;
00426 if (fread (buf, size, 1, f) != 1
00427 || fwrite (buf, size, 1, asm_out_file) != 1)
00428 cpp_errno (pfile, CPP_DL_ERROR, "reading");
00429 written += size;
00430 }
00431 free (buf);
00432 }
00433 else
00434 {
00435
00436
00437 if (fseek (f, h.asm_size, SEEK_CUR) != 0)
00438 cpp_errno (pfile, CPP_DL_ERROR, "seeking");
00439 }
00440
00441 cpp_prepare_state (pfile, &smd);
00442
00443 gt_pch_restore (f);
00444
00445 if (cpp_read_state (pfile, name, f, smd) != 0)
00446 return;
00447
00448 fclose (f);
00449
00450
00451
00452 if (lang_post_pch_load)
00453 (*lang_post_pch_load) ();
00454 }
00455
00456
00457
00458 void
00459 c_common_no_more_pch (void)
00460 {
00461 if (cpp_get_callbacks (parse_in)->valid_pch)
00462 {
00463 cpp_get_callbacks (parse_in)->valid_pch = NULL;
00464 host_hooks.gt_pch_use_address (NULL, 0, -1, 0);
00465 }
00466 }
00467
00468
00469
00470 #ifndef O_BINARY
00471 # define O_BINARY 0
00472 #endif
00473
00474 void
00475 c_common_pch_pragma (cpp_reader *pfile)
00476 {
00477 tree name_t;
00478 const char *name;
00479 int fd;
00480
00481 if (c_lex (&name_t) != CPP_STRING)
00482 {
00483 error ("malformed #pragma GCC pch_preprocess, ignored");
00484 return;
00485 }
00486
00487 if (!cpp_get_options (pfile)->preprocessed)
00488 {
00489 error ("pch_preprocess pragma should only be used with -fpreprocessed");
00490 inform ("use #include instead");
00491 return;
00492 }
00493
00494 name = TREE_STRING_POINTER (name_t);
00495
00496 fd = open (name, O_RDONLY | O_BINARY, 0666);
00497 if (fd == -1)
00498 fatal_error ("%s: couldn%'t open PCH file: %m\n", name);
00499
00500 if (c_common_valid_pch (pfile, name, fd) != 1)
00501 {
00502 if (!cpp_get_options (pfile)->warn_invalid_pch)
00503 inform ("use -Winvalid-pch for more information");
00504 fatal_error ("%s: PCH file was invalid", name);
00505 }
00506
00507 c_common_read_pch (pfile, name, fd, name);
00508
00509 close (fd);
00510 }