您的位置:首页 > 其它

Studying note of GCC-3.4.6 source (31)

2010-04-20 09:35 309 查看
4.1.3.1.1.1. Validate PCH File
If PCH file is found, it needs ensure this file is valid.

1257 static bool
1258 validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname) in cppfiles.c
1259 {
1260 const char *saved_path = file->path;
1261 bool valid = false;
1262
1263 file->path = pchname;
1264 if (open_file (file))
1265 {
1266 valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd);
1267
1268 if (!valid)
1269 {
1270 close (file->fd);
1271 file->fd = -1;
1272 }
1273
1274 if (CPP_OPTION (pfile, print_include_names))
1275 {
1276 unsigned int i;
1277 for (i = 1; i < pfile->line_maps.depth; i++)
1278 putc ('.', stderr);
1279 fprintf (stderr, "%c %s/n",
1280 valid ? '!' : 'x', pchname);
1281 }
1282 }
1283
1284 file->path = saved_path;
1285 return valid;
1286 }

The format of pre-compiled header is not unified yet, it is possible GCC will adopt other format in future, thus cpp_reader provides the hook cb to bind up operating functions for the specified pre-compiled header format. For C++/C, init_c_lex does the binding. The definition of the hook cb is as below, only the last 2 fields are used for pre-compiled header, and other fields also provide flexibility for the corresponding operation.

379 struct cpp_callbacks in cpplib.h
380 {
381 /* Called when a new line of preprocessed output is started. */
382 void (*line_change) (cpp_reader *, const cpp_token *, int);
383
384 /* Called when switching to/from a new file.
385 The line_map is for the new file. It is NULL if there is no new file.
386 (In C this happens when done with <built-in>+<command line> and also
387 when done with a main file.) This can be used for resource cleanup. */
388 void (*file_change) (cpp_reader *, const struct line_map *);
389
390 void (*dir_change) (cpp_reader *, const char *);
391 void (*include) (cpp_reader *, unsigned int, const unsigned char *,
392 const char *, int);
393 void (*define) (cpp_reader *, unsigned int, cpp_hashnode *);
394 void (*undef) (cpp_reader *, unsigned int, cpp_hashnode *);
395 void (*ident) (cpp_reader *, unsigned int, const cpp_string *);
396 void (*def_pragma) (cpp_reader *, unsigned int);
397 int (*valid_pch) (cpp_reader *, const char *, int);
398 void (*read_pch) (cpp_reader *, const char *, int, const char *);
399 };

Now valid_pch is c_common_valid_pch for C/C++. For PCH file, the very begnning of the file conatins 8 bytes of identification followed by a struct c_pch_validity defined as below.

53 struct c_pch_validity in c-pch.c
54 {
55 unsigned char host_machine_length;
56 unsigned char target_machine_length;
57 unsigned char version_length;
58 unsigned char debug_info_type;
59 unsigned int flags_info;
60 void (*pch_init) (void);
61 size_t target_data_length;
62 };

In c_common_valid_pch, it is easy to find that a common PCH file will contain following content at beginning:



Figure 9 Layout of PCH file

Field debug_info_type indicates the type of debug information generated, and field flags_info is set if switch -funit-at-a-time is in used when generating the PCH file.

219 int
220 c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) in c-pch.c
221 {
222 int sizeread;
223 int result;
224 char ident[IDENT_LENGTH];
225 char short_strings[256 * 3];
226 int strings_length;
227 const char *pch_ident;
228 struct c_pch_validity v;
229 unsigned int current_flags_info = 0;
230
231 if (flag_unit_at_a_time)
232 current_flags_info |= FLAG_UNIT_AT_A_TIME_SET;
233
234 /* Perform a quick test of whether this is a valid
235 precompiled header for the current language
236 and with the current flag settings. */
237
238 sizeread = read (fd, ident, IDENT_LENGTH);
239 if (sizeread == -1)
240 fatal_error ("can't read %s: %m", name);
241 else if (sizeread != IDENT_LENGTH)
242 return 2;
243
244 pch_ident = get_ident();
245 if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0)
246 {
247 if (cpp_get_options (pfile)->warn_invalid_pch)
248 {
249 if (memcmp (ident, pch_ident, 5) == 0)
250 /* It's a PCH, for the right language, but has the wrong version.
251 */
252 cpp_error (pfile, CPP_DL_WARNING,
253 "%s: not compatible with this GCC version", name);
254 else if (memcmp (ident, pch_ident, 4) == 0)
255 /* It's a PCH for the wrong language. */
256 cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name,
257 lang_hooks.name);
258 else
259 /* Not any kind of PCH. */
260 cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name);
261 }
262 return 2;
263 }
264
265 /* At this point, we know it's a PCH file, so it ought to be long enough
266 that we can read a c_pch_validity structure. */
267 if (read (fd, &v, sizeof (v)) != sizeof (v))
268 fatal_error ("can't read %s: %m", name);
269
270 strings_length = (v.host_machine_length + v.target_machine_length
271 + v.version_length);
272 if (read (fd, short_strings, strings_length) != strings_length)
273 fatal_error ("can't read %s: %m", name);
274 if (v.host_machine_length != strlen (host_machine)
275 || memcmp (host_machine, short_strings, strlen (host_machine)) != 0)
276 {
277 if (cpp_get_options (pfile)->warn_invalid_pch)
278 cpp_error (pfile, CPP_DL_WARNING,
279 "%s: created on host `%.*s', but used on host `%s'", name,
280 v.host_machine_length, short_strings, host_machine);
281 return 2;
282 }
283 if (v.target_machine_length != strlen (target_machine)
284 || memcmp (target_machine, short_strings + v.host_machine_length,
285 strlen (target_machine)) != 0)
286 {
287 if (cpp_get_options (pfile)->warn_invalid_pch)
288 cpp_error (pfile, CPP_DL_WARNING,
289 "%s: created for target `%.*s', but used for target `%s'",
290 name, v.target_machine_length,
291 short_strings + v.host_machine_length, target_machine);
292 return 2;
293 }
294 if (v.version_length != strlen (version_string)
295 || memcmp (version_string,
296 (short_strings + v.host_machine_length
297 + v.target_machine_length),
298 v.version_length) != 0)
299 {
300 if (cpp_get_options (pfile)->warn_invalid_pch)
301 cpp_error (pfile, CPP_DL_WARNING,
302 "%s: created by version `%.*s', but this is version `%s'",
303 name, v.version_length,
304 (short_strings + v.host_machine_length
305 + v.target_machine_length),
306 version_string);
307 return 2;
308 }
309 if (v.flags_info != current_flags_info)
310 {
311 if (cpp_get_options (pfile)->warn_invalid_pch)
312 cpp_error (pfile, CPP_DL_WARNING,
313 "%s: created using different flags",
314 name);
315 return 2;
316 }
317
318 /* The allowable debug info combinations are that either the PCH file
319 was built with the same as is being used now, or the PCH file was
320 built for some kind of debug info but now none is in use. */
321 if (v.debug_info_type != write_symbols
322 && write_symbols != NO_DEBUG)
323 {
324 if (cpp_get_options (pfile)->warn_invalid_pch)
325 cpp_error (pfile, CPP_DL_WARNING,
326 "%s: created with -g%s, but used with -g%s", name,
327 debug_type_names[v.debug_info_type],
328 debug_type_names[write_symbols]);
329 return 2;
330 }
331
332 /* If the text segment was not loaded at the same address as it was
333 when the PCH file was created, function pointers loaded from the
334 PCH will not be valid. We could in theory remap all the function
335 pointers, but no support for that exists at present. */
336 if (v.pch_init != &pch_init)
337 {
338 if (cpp_get_options (pfile)->warn_invalid_pch)
339 cpp_error (pfile, CPP_DL_WARNING,
340 "%s: had text segment at different address", name);
341 return 2;
342 }
343
344 /* Check the target-specific validity data. */
345 {
346 void *this_file_data = xmalloc (v.target_data_length);
347 const char *msg;
348
349 if ((size_t) read (fd, this_file_data, v.target_data_length)
350 != v.target_data_length)
351 fatal_error ("can't read %s: %m", name);
352 msg = targetm.pch_valid_p (this_file_data, v.target_data_length);
353 free (this_file_data);
354 if (msg != NULL)
355 {
356 if (cpp_get_options (pfile)->warn_invalid_pch)
357 cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg);
358 return 2;
359 }
360 }
361
362 /* Check the preprocessor macros are the same as when the PCH was
363 generated. */
364
365 result = cpp_valid_state (pfile, name, fd);
366 if (result == -1)
367 return 2;
368 else
369 return result == 0;
370 }

If fields before target_data are valid, the immediate validation of this data is done target depenedent. However, for most targets GCC currently support, the default mehod is enough.

4112 const char *
4113 default_pch_valid_p (const void *data_p, size_t len) in toplev.c
4114 {
4115 const char *data = (const char *)data_p;
4116 const char *flag_that_differs = NULL;
4117 size_t i;
4118
4119 /* -fpic and -fpie also usually make a PCH invalid. */
4120 if (data[0] != flag_pic)
4121 return _("created and used with different settings of -fpic");
4122 if (data[1] != flag_pie)
4123 return _("created and used with different settings of -fpie");
4124 data += 2;
4125
4126 /* Check target_flags. */
4127 if (memcmp (data, &target_flags, sizeof (target_flags)) != 0)
4128 {
4129 for (i = 0; i < ARRAY_SIZE (target_switches); i++)
4130 {
4131 int bits;
4132 int tf;
4133
4134 memcpy (&tf, data, sizeof (target_flags));
4135
4136 bits = target_switches[i].value;
4137 if (bits < 0)
4138 bits = -bits;
4139 if ((target_flags & bits) != (tf & bits))
4140 {
4141 flag_that_differs = target_switches[i].name;
4142 goto make_message;
4143 }
4144 }
4145 abort ();
4146 }
4147 data += sizeof (target_flags);
4148 len -= sizeof (target_flags);
4149
4150 /* Check string options. */
4151 #ifdef TARGET_OPTIONS
4152 for (i = 0; i < ARRAY_SIZE (target_options); i++)
4153 {
4154 const char *str = *target_options[i].variable;
4155 size_t l;
4156 if (! str)
4157 str = "";
4158 l = strlen (str) + 1;
4159 if (len < l || memcmp (data, str, l) != 0)
4160 {
4161 flag_that_differs = target_options[i].prefix;
4162 goto make_message;
4163 }
4164 data += l;
4165 len -= l;
4166 }
4167 #endif
4168
4169 return NULL;
4170
4171 make_message:
4172 {
4173 char *r;
4174 asprintf (&r, _("created and used with differing settings of `-m%s'"),
4175 flag_that_differs);
4176 if (r == NULL)
4177 return _("out of memory");
4178 return r;
4179 }
4180 }

In the function, can see that target_data contains following information. For the setting and meaning of target_flags and target_options refers to Initializing options related to target. Being validate PCH file, its target_data must exactly matches corresponding data current in used. Notice that in target_options part in the data, all target options must appear, and for those not used only “/0” will be present.



Figure 10 Layout of target data of PCH file
If the PCH file is validate, it is what we want, so we can return at line 326 in find_file_in_dir, othewise just try to open the normal file.

_cpp_find_file (continue)

418 if (entry)
419 {
420 /* Cache for START_DIR too, sharing the _cpp_file structure. */
421 free ((char *) file->name);
422 free (file);
423 file = entry->u.file;
424 }
425 else
426 {
427 /* This is a new file; put it in the list. */
428 file->next_file = pfile->all_files;
429 pfile->all_files = file;
430 }
431
432 /* Store this new result in the hash table. */
433 entry = new_file_hash_entry (pfile);
434 entry->next = *hash_slot;
435 entry->start_dir = start_dir;
436 entry->u.file = file;
437 *hash_slot = entry;
438
439 return file;
440 }

If entry at line 418 is not NULL, it means find out the expected file, but not within start_dir. To prevent later lookup in the directory for the same file from duplicate hard search, it is preferred to create a new entry to bind start_dir with the file.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: