Studying note of GCC-3.4.6 source (31)

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.

你可能感兴趣的:(Studying note of GCC-3.4.6 source (31))