mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			905 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			905 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Part of CPP library.  (Precompiled header reading/writing.)
 | |
|    Copyright (C) 2000-2017 Free Software Foundation, Inc.
 | |
| 
 | |
| This program is free software; you can redistribute it and/or modify it
 | |
| under the terms of the GNU General Public License as published by the
 | |
| Free Software Foundation; either version 3, or (at your option) any
 | |
| later version.
 | |
| 
 | |
| This program is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with this program; see the file COPYING3.  If not see
 | |
| <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include "config.h"
 | |
| #include "system.h"
 | |
| #include "cpplib.h"
 | |
| #include "internal.h"
 | |
| #include "hashtab.h"
 | |
| #include "mkdeps.h"
 | |
| 
 | |
| static int write_macdef (cpp_reader *, cpp_hashnode *, void *);
 | |
| static int save_idents (cpp_reader *, cpp_hashnode *, void *);
 | |
| static hashval_t hashmem (const void *, size_t);
 | |
| static hashval_t cpp_string_hash (const void *);
 | |
| static int cpp_string_eq (const void *, const void *);
 | |
| static int count_defs (cpp_reader *, cpp_hashnode *, void *);
 | |
| static int comp_hashnodes (const void *, const void *);
 | |
| static int collect_ht_nodes (cpp_reader *, cpp_hashnode *, void *);
 | |
| static int write_defs (cpp_reader *, cpp_hashnode *, void *);
 | |
| static int save_macros (cpp_reader *, cpp_hashnode *, void *);
 | |
| static int _cpp_save_pushed_macros (cpp_reader *, FILE *);
 | |
| static int _cpp_restore_pushed_macros (cpp_reader *, FILE *);
 | |
| 
 | |
| /* This structure represents a macro definition on disk.  */
 | |
| struct macrodef_struct
 | |
| {
 | |
|   unsigned int definition_length;
 | |
|   unsigned short name_length;
 | |
|   unsigned short flags;
 | |
| };
 | |
| 
 | |
| /* This is how we write out a macro definition.
 | |
|    Suitable for being called by cpp_forall_identifiers.  */
 | |
| 
 | |
| static int
 | |
| write_macdef (cpp_reader *pfile, cpp_hashnode *hn, void *file_p)
 | |
| {
 | |
|   FILE *f = (FILE *) file_p;
 | |
|   switch (hn->type)
 | |
|     {
 | |
|     case NT_VOID:
 | |
|       if (! (hn->flags & NODE_POISONED))
 | |
| 	return 1;
 | |
|       /* XXX Really fallthru?  */
 | |
|       /* FALLTHRU */
 | |
| 
 | |
|     case NT_MACRO:
 | |
|       if ((hn->flags & NODE_BUILTIN)
 | |
| 	  && (!pfile->cb.user_builtin_macro
 | |
| 	      || !pfile->cb.user_builtin_macro (pfile, hn)))
 | |
| 	return 1;
 | |
| 
 | |
|       {
 | |
| 	struct macrodef_struct s;
 | |
| 	const unsigned char *defn;
 | |
| 
 | |
| 	s.name_length = NODE_LEN (hn);
 | |
| 	s.flags = hn->flags & NODE_POISONED;
 | |
| 
 | |
| 	if (hn->type == NT_MACRO)
 | |
| 	  {
 | |
| 	    defn = cpp_macro_definition (pfile, hn);
 | |
| 	    s.definition_length = ustrlen (defn);
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    defn = NODE_NAME (hn);
 | |
| 	    s.definition_length = s.name_length;
 | |
| 	  }
 | |
| 
 | |
| 	if (fwrite (&s, sizeof (s), 1, f) != 1
 | |
| 	    || fwrite (defn, 1, s.definition_length, f) != s.definition_length)
 | |
| 	  {
 | |
| 	    cpp_errno (pfile, CPP_DL_ERROR,
 | |
| 		       "while writing precompiled header");
 | |
| 	    return 0;
 | |
| 	  }
 | |
|       }
 | |
|       return 1;
 | |
| 
 | |
|     case NT_ASSERTION:
 | |
|       /* Not currently implemented.  */
 | |
|       return 1;
 | |
| 
 | |
|     default:
 | |
|       abort ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* This structure records the names of the defined macros.
 | |
|    It's also used as a callback structure for size_initial_idents
 | |
|    and save_idents.  */
 | |
| 
 | |
| struct cpp_savedstate
 | |
| {
 | |
|   /* A hash table of the defined identifiers.  */
 | |
|   htab_t definedhash;
 | |
|   /* The size of the definitions of those identifiers (the size of
 | |
|      'definedstrs').  */
 | |
|   size_t hashsize;
 | |
|   /* Number of definitions */
 | |
|   size_t n_defs;
 | |
|   /* Array of definitions.  In cpp_write_pch_deps it is used for sorting.  */
 | |
|   cpp_hashnode **defs;
 | |
|   /* Space for the next definition.  Definitions are null-terminated
 | |
|      strings.  */
 | |
|   unsigned char *definedstrs;
 | |
| };
 | |
| 
 | |
| /* Save this identifier into the state: put it in the hash table,
 | |
|    put the definition in 'definedstrs'.  */
 | |
| 
 | |
| static int
 | |
| save_idents (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
 | |
| {
 | |
|   struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
 | |
| 
 | |
|   if (hn->type != NT_VOID)
 | |
|     {
 | |
|       struct cpp_string news;
 | |
|       void **slot;
 | |
| 
 | |
|       news.len = NODE_LEN (hn);
 | |
|       news.text= NODE_NAME (hn);
 | |
|       slot = htab_find_slot (ss->definedhash, &news, INSERT);
 | |
|       if (*slot == NULL)
 | |
| 	{
 | |
| 	  struct cpp_string *sp;
 | |
| 	  unsigned char *text;
 | |
| 
 | |
| 	  sp = XNEW (struct cpp_string);
 | |
| 	  *slot = sp;
 | |
| 
 | |
| 	  sp->len = NODE_LEN (hn);
 | |
| 	  sp->text = text = XNEWVEC (unsigned char, NODE_LEN (hn));
 | |
| 	  memcpy (text, NODE_NAME (hn), NODE_LEN (hn));
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Hash some memory in a generic way.  */
 | |
| 
 | |
| static hashval_t
 | |
| hashmem (const void *p_p, size_t sz)
 | |
| {
 | |
|   const unsigned char *p = (const unsigned char *)p_p;
 | |
|   size_t i;
 | |
|   hashval_t h;
 | |
| 
 | |
|   h = 0;
 | |
|   for (i = 0; i < sz; i++)
 | |
|     h = h * 67 - (*p++ - 113);
 | |
|   return h;
 | |
| }
 | |
| 
 | |
| /* Hash a cpp string for the hashtable machinery.  */
 | |
| 
 | |
| static hashval_t
 | |
| cpp_string_hash (const void *a_p)
 | |
| {
 | |
|   const struct cpp_string *a = (const struct cpp_string *) a_p;
 | |
|   return hashmem (a->text, a->len);
 | |
| }
 | |
| 
 | |
| /* Compare two cpp strings for the hashtable machinery.  */
 | |
| 
 | |
| static int
 | |
| cpp_string_eq (const void *a_p, const void *b_p)
 | |
| {
 | |
|   const struct cpp_string *a = (const struct cpp_string *) a_p;
 | |
|   const struct cpp_string *b = (const struct cpp_string *) b_p;
 | |
|   return (a->len == b->len
 | |
| 	  && memcmp (a->text, b->text, a->len) == 0);
 | |
| }
 | |
| 
 | |
| /* Free memory associated with cpp_string.  */
 | |
| 
 | |
| static void
 | |
| cpp_string_free (void *a_p)
 | |
| {
 | |
|   struct cpp_string *a = (struct cpp_string *) a_p;
 | |
|   free ((void *) a->text);
 | |
|   free (a);
 | |
| }
 | |
| 
 | |
| /* Save the current definitions of the cpp_reader for dependency
 | |
|    checking purposes.  When writing a precompiled header, this should
 | |
|    be called at the same point in the compilation as cpp_valid_state
 | |
|    would be called when reading the precompiled header back in.  */
 | |
| 
 | |
| int
 | |
| cpp_save_state (cpp_reader *r, FILE *f)
 | |
| {
 | |
|   /* Save the list of non-void identifiers for the dependency checking.  */
 | |
|   r->savedstate = XNEW (struct cpp_savedstate);
 | |
|   r->savedstate->definedhash = htab_create (100, cpp_string_hash,
 | |
| 					    cpp_string_eq, cpp_string_free);
 | |
|   cpp_forall_identifiers (r, save_idents, r->savedstate);
 | |
| 
 | |
|   /* Write out the list of defined identifiers.  */
 | |
|   cpp_forall_identifiers (r, write_macdef, f);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Calculate the 'hashsize' field of the saved state.  */
 | |
| 
 | |
| static int
 | |
| count_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
 | |
| {
 | |
|   struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
 | |
| 
 | |
|   switch (hn->type)
 | |
|     {
 | |
|     case NT_MACRO:
 | |
|       if (hn->flags & NODE_BUILTIN)
 | |
| 	return 1;
 | |
| 
 | |
|       /* fall through.  */
 | |
| 
 | |
|     case NT_VOID:
 | |
|       {
 | |
| 	struct cpp_string news;
 | |
| 	void **slot;
 | |
| 
 | |
| 	news.len = NODE_LEN (hn);
 | |
| 	news.text = NODE_NAME (hn);
 | |
| 	slot = (void **) htab_find (ss->definedhash, &news);
 | |
| 	if (slot == NULL)
 | |
| 	  {
 | |
| 	    ss->hashsize += NODE_LEN (hn) + 1;
 | |
| 	    ss->n_defs += 1;
 | |
| 	  }
 | |
|       }
 | |
|       return 1;
 | |
| 
 | |
|     case NT_ASSERTION:
 | |
|       /* Not currently implemented.  */
 | |
|       return 1;
 | |
| 
 | |
|     default:
 | |
|       abort ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Collect the identifiers into the state's string table.  */
 | |
| static int
 | |
| write_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)
 | |
| {
 | |
|   struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
 | |
| 
 | |
|   switch (hn->type)
 | |
|     {
 | |
|     case NT_MACRO:
 | |
|       if (hn->flags & NODE_BUILTIN)
 | |
| 	return 1;
 | |
| 
 | |
|       /* fall through.  */
 | |
| 
 | |
|     case NT_VOID:
 | |
|       {
 | |
| 	struct cpp_string news;
 | |
| 	void **slot;
 | |
| 
 | |
| 	news.len = NODE_LEN (hn);
 | |
| 	news.text = NODE_NAME (hn);
 | |
| 	slot = (void **) htab_find (ss->definedhash, &news);
 | |
| 	if (slot == NULL)
 | |
| 	  {
 | |
| 	    ss->defs[ss->n_defs] = hn;
 | |
| 	    ss->n_defs += 1;
 | |
| 	  }
 | |
|       }
 | |
|       return 1;
 | |
| 
 | |
|     case NT_ASSERTION:
 | |
|       /* Not currently implemented.  */
 | |
|       return 1;
 | |
| 
 | |
|     default:
 | |
|       abort ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Comparison function for qsort.  The arguments point to pointers of
 | |
|    type ht_hashnode *.  */
 | |
| static int
 | |
| comp_hashnodes (const void *px, const void *py)
 | |
| {
 | |
|   cpp_hashnode *x = *(cpp_hashnode **) px;
 | |
|   cpp_hashnode *y = *(cpp_hashnode **) py;
 | |
|   return ustrcmp (NODE_NAME (x), NODE_NAME (y));
 | |
| }
 | |
| 
 | |
| /* Write out the remainder of the dependency information.  This should be
 | |
|    called after the PCH is ready to be saved.  */
 | |
| 
 | |
| int
 | |
| cpp_write_pch_deps (cpp_reader *r, FILE *f)
 | |
| {
 | |
|   struct macrodef_struct z;
 | |
|   struct cpp_savedstate *const ss = r->savedstate;
 | |
|   unsigned char *definedstrs;
 | |
|   size_t i;
 | |
| 
 | |
|   /* Collect the list of identifiers which have been seen and
 | |
|      weren't defined to anything previously.  */
 | |
|   ss->hashsize = 0;
 | |
|   ss->n_defs = 0;
 | |
|   cpp_forall_identifiers (r, count_defs, ss);
 | |
| 
 | |
|   ss->defs = XNEWVEC (cpp_hashnode *, ss->n_defs);
 | |
|   ss->n_defs = 0;
 | |
|   cpp_forall_identifiers (r, write_defs, ss);
 | |
| 
 | |
|   /* Sort the list, copy it into a buffer, and write it out.  */
 | |
|   qsort (ss->defs, ss->n_defs, sizeof (cpp_hashnode *), &comp_hashnodes);
 | |
|   definedstrs = ss->definedstrs = XNEWVEC (unsigned char, ss->hashsize);
 | |
|   for (i = 0; i < ss->n_defs; ++i)
 | |
|     {
 | |
|       size_t len = NODE_LEN (ss->defs[i]);
 | |
|       memcpy (definedstrs, NODE_NAME (ss->defs[i]), len + 1);
 | |
|       definedstrs += len + 1;
 | |
|     }
 | |
| 
 | |
|   memset (&z, 0, sizeof (z));
 | |
|   z.definition_length = ss->hashsize;
 | |
|   if (fwrite (&z, sizeof (z), 1, f) != 1
 | |
|       || fwrite (ss->definedstrs, ss->hashsize, 1, f) != 1)
 | |
|     {
 | |
|       cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
 | |
|       return -1;
 | |
|     }
 | |
|   free (ss->definedstrs);
 | |
|   free (ss->defs);
 | |
|   htab_delete (ss->definedhash);
 | |
| 
 | |
|   /* Free the saved state.  */
 | |
|   free (ss);
 | |
|   r->savedstate = NULL;
 | |
| 
 | |
|   /* Save the next value of __COUNTER__. */
 | |
|   if (fwrite (&r->counter, sizeof (r->counter), 1, f) != 1)
 | |
|     {
 | |
|       cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Write out the definitions of the preprocessor, in a form suitable for
 | |
|    cpp_read_state.  */
 | |
| 
 | |
| int
 | |
| cpp_write_pch_state (cpp_reader *r, FILE *f)
 | |
| {
 | |
|   if (!r->deps)
 | |
|     r->deps = deps_init ();
 | |
| 
 | |
|   if (deps_save (r->deps, f) != 0)
 | |
|     {
 | |
|       cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   if (! _cpp_save_file_entries (r, f))
 | |
|     {
 | |
|       cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   /* Save the next __COUNTER__ value.  When we include a precompiled header,
 | |
|      we need to start at the offset we would have if the header had been
 | |
|      included normally. */
 | |
|   if (fwrite (&r->counter, sizeof (r->counter), 1, f) != 1)
 | |
|     {
 | |
|       cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   /* Write saved macros.  */
 | |
|   if (! _cpp_save_pushed_macros (r, f))
 | |
|     {
 | |
|       cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| _cpp_restore_pushed_macros (cpp_reader *r, FILE *f)
 | |
| {
 | |
|   size_t count_saved = 0;
 | |
|   size_t i;
 | |
|   struct def_pragma_macro *p;
 | |
|   size_t nlen;
 | |
|   uchar *defn;
 | |
|   size_t defnlen;
 | |
| 
 | |
|   if (fread (&count_saved, sizeof (count_saved), 1, f) != 1)
 | |
|     return 0;
 | |
|   if (! count_saved)
 | |
|     return 1;
 | |
|   for (i = 0; i < count_saved; i++)
 | |
|     {
 | |
|       if (fread (&nlen, sizeof (nlen), 1, f) != 1)
 | |
| 	return 0;
 | |
|       p = XNEW (struct def_pragma_macro);
 | |
|       memset (p, 0, sizeof (struct def_pragma_macro));
 | |
|       p->name = XNEWVAR (char, nlen + 1);
 | |
|       p->name[nlen] = 0;
 | |
|       if (fread (p->name, nlen, 1, f) != 1)
 | |
| 	return 0;
 | |
|       if (fread (&defnlen, sizeof (defnlen), 1, f) != 1)
 | |
| 	return 0;
 | |
|       if (defnlen == 0)
 | |
|         p->is_undef = 1;
 | |
|       else
 | |
|         {
 | |
| 	  defn = XNEWVEC (uchar, defnlen + 1);
 | |
| 	  defn[defnlen] = 0;
 | |
| 
 | |
| 	  if (fread (defn, defnlen, 1, f) != 1)
 | |
| 	    return 0;
 | |
| 
 | |
| 	  p->definition = defn;
 | |
| 	  if (fread (&(p->line), sizeof (source_location), 1, f) != 1)
 | |
| 	    return 0;
 | |
| 	  defnlen = 0;
 | |
| 	  if (fread (&defnlen, sizeof (defnlen), 1, f) != 1)
 | |
| 	    return 0;
 | |
| 	  p->syshdr = ((defnlen & 1) != 0 ? 1 : 0);
 | |
| 	  p->used =  ((defnlen & 2) != 0 ? 1 : 0);
 | |
| 	}
 | |
| 
 | |
|       p->next = r->pushed_macros;
 | |
|       r->pushed_macros = p;
 | |
|     }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| _cpp_save_pushed_macros (cpp_reader *r, FILE *f)
 | |
| {
 | |
|   size_t count_saved = 0;
 | |
|   size_t i;
 | |
|   struct def_pragma_macro *p,**pp;
 | |
|   size_t defnlen;
 | |
| 
 | |
|   /* Get count. */
 | |
|   p = r->pushed_macros;
 | |
|   while (p != NULL)
 | |
|     {
 | |
|       count_saved++;
 | |
|       p = p->next;
 | |
|     }
 | |
|   if (fwrite (&count_saved, sizeof (count_saved), 1, f) != 1)
 | |
|     return 0;
 | |
|   if (!count_saved)
 | |
|     return 1;
 | |
| 
 | |
|   pp = (struct def_pragma_macro **) alloca (sizeof (struct def_pragma_macro *)
 | |
| 					    * count_saved);
 | |
|   /* Store them in reverse order.  */
 | |
|   p = r->pushed_macros;
 | |
|   i = count_saved;
 | |
|   while (p != NULL)
 | |
|     {
 | |
|       --i;
 | |
|       pp[i] = p;
 | |
|       p = p->next;
 | |
|     }
 | |
|   for (i = 0; i < count_saved; i++)
 | |
|     {
 | |
|       defnlen = strlen (pp[i]->name);
 | |
|       if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
 | |
| 	  || fwrite (pp[i]->name, defnlen, 1, f) != 1)
 | |
| 	return 0;
 | |
|       if (pp[i]->is_undef)
 | |
| 	{
 | |
| 	  defnlen = 0;
 | |
| 	  if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1)
 | |
| 	    return 0;
 | |
| 	}
 | |
|       else
 | |
|         {
 | |
| 	  defnlen = ustrlen (pp[i]->definition);
 | |
| 	  if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
 | |
| 	      || fwrite (pp[i]->definition, defnlen, 1, f) != 1)
 | |
| 	    return 0;
 | |
| 	  if (fwrite (&(pp[i]->line), sizeof (source_location), 1, f) != 1)
 | |
| 	    return 0;
 | |
| 	  defnlen = 0;
 | |
| 	  defnlen |= (pp[i]->syshdr != 0 ? 1 : 0);
 | |
| 	  defnlen |= (pp[i]->used != 0 ? 2 : 0);
 | |
| 	  if (fwrite (&defnlen, sizeof (defnlen), 1, f) != 1)
 | |
| 	    return 0;
 | |
| 	}
 | |
|     }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Data structure to transform hash table nodes into a sorted list */
 | |
| 
 | |
| struct ht_node_list
 | |
| {
 | |
|   /* Array of nodes */
 | |
|   cpp_hashnode **defs;
 | |
|   /* Number of nodes in the array */
 | |
|   size_t n_defs;
 | |
|   /* Size of the allocated array */
 | |
|   size_t asize;
 | |
| };
 | |
| 
 | |
| /* Callback for collecting identifiers from hash table */
 | |
| 
 | |
| static int
 | |
| collect_ht_nodes (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn,
 | |
| 		  void *nl_p)
 | |
| {
 | |
|   struct ht_node_list *const nl = (struct ht_node_list *)nl_p;
 | |
| 
 | |
|   if (hn->type != NT_VOID || hn->flags & NODE_POISONED)
 | |
|     {
 | |
|       if (nl->n_defs == nl->asize)
 | |
|         {
 | |
|           nl->asize *= 2;
 | |
|           nl->defs = XRESIZEVEC (cpp_hashnode *, nl->defs, nl->asize);
 | |
|         }
 | |
| 
 | |
|       nl->defs[nl->n_defs] = hn;
 | |
|       ++nl->n_defs;
 | |
|     }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Return nonzero if FD is a precompiled header which is consistent
 | |
|    with the preprocessor's current definitions.  It will be consistent
 | |
|    when:
 | |
| 
 | |
|    - anything that was defined just before the PCH was generated
 | |
|      is defined the same way now; and
 | |
|    - anything that was not defined then, but is defined now, was not
 | |
|      used by the PCH.
 | |
| 
 | |
|    NAME is used to print warnings if `warn_invalid_pch' is set in the
 | |
|    reader's flags.
 | |
| */
 | |
| 
 | |
| int
 | |
| cpp_valid_state (cpp_reader *r, const char *name, int fd)
 | |
| {
 | |
|   struct macrodef_struct m;
 | |
|   size_t namebufsz = 256;
 | |
|   unsigned char *namebuf = XNEWVEC (unsigned char, namebufsz);
 | |
|   unsigned char *undeftab = NULL;
 | |
|   struct ht_node_list nl = { 0, 0, 0 };
 | |
|   unsigned char *first, *last;
 | |
|   unsigned int i;
 | |
|   unsigned int counter;
 | |
| 
 | |
|   /* Read in the list of identifiers that must be defined
 | |
|      Check that they are defined in the same way.  */
 | |
|   for (;;)
 | |
|     {
 | |
|       cpp_hashnode *h;
 | |
|       const unsigned char *newdefn;
 | |
| 
 | |
|       if (read (fd, &m, sizeof (m)) != sizeof (m))
 | |
| 	goto error;
 | |
| 
 | |
|       if (m.name_length == 0)
 | |
| 	break;
 | |
| 
 | |
|       /* If this file is already preprocessed, there won't be any
 | |
| 	 macros defined, and that's OK.  */
 | |
|       if (CPP_OPTION (r, preprocessed))
 | |
| 	{
 | |
| 	  if (lseek (fd, m.definition_length, SEEK_CUR) == -1)
 | |
| 	    goto error;
 | |
| 	  continue;
 | |
| 	}
 | |
| 
 | |
|       if (m.definition_length > namebufsz)
 | |
| 	{
 | |
| 	  free (namebuf);
 | |
| 	  namebufsz = m.definition_length + 256;
 | |
| 	  namebuf = XNEWVEC (unsigned char, namebufsz);
 | |
| 	}
 | |
| 
 | |
|       if ((size_t)read (fd, namebuf, m.definition_length)
 | |
| 	  != m.definition_length)
 | |
| 	goto error;
 | |
| 
 | |
|       h = cpp_lookup (r, namebuf, m.name_length);
 | |
|       if (m.flags & NODE_POISONED
 | |
| 	  || h->flags & NODE_POISONED)
 | |
| 	{
 | |
| 	  if (CPP_OPTION (r, warn_invalid_pch))
 | |
| 	    cpp_warning_syshdr (r, CPP_W_INVALID_PCH,
 | |
| 		                "%s: not used because `%.*s' is poisoned",
 | |
| 		                name, m.name_length, namebuf);
 | |
| 	  goto fail;
 | |
| 	}
 | |
| 
 | |
|       if (h->type != NT_MACRO)
 | |
| 	{
 | |
| 	  /* It's ok if __GCC_HAVE_DWARF2_CFI_ASM becomes undefined,
 | |
| 	     as in, when the PCH file is created with -g and we're
 | |
| 	     attempting to use it without -g.  Restoring the PCH file
 | |
| 	     is supposed to bring in this definition *and* enable the
 | |
| 	     generation of call frame information, so that precompiled
 | |
| 	     definitions that take this macro into account, to decide
 | |
| 	     what asm to emit, won't issue .cfi directives when the
 | |
| 	     compiler doesn't.  */
 | |
| 	  if (!(h->flags & NODE_USED)
 | |
| 	      && m.name_length == sizeof ("__GCC_HAVE_DWARF2_CFI_ASM") - 1
 | |
| 	      && !memcmp (namebuf, "__GCC_HAVE_DWARF2_CFI_ASM", m.name_length))
 | |
| 	    continue;
 | |
| 
 | |
| 	  if (CPP_OPTION (r, warn_invalid_pch))
 | |
| 	    cpp_warning_syshdr (r, CPP_W_INVALID_PCH,
 | |
| 		                "%s: not used because `%.*s' not defined",
 | |
| 		                name, m.name_length, namebuf);
 | |
| 	  goto fail;
 | |
| 	}
 | |
| 
 | |
|       newdefn = cpp_macro_definition (r, h);
 | |
| 
 | |
|       if (m.definition_length != ustrlen (newdefn)
 | |
| 	  || memcmp (namebuf, newdefn, m.definition_length) != 0)
 | |
| 	{
 | |
| 	  if (CPP_OPTION (r, warn_invalid_pch))
 | |
| 	    cpp_warning_syshdr (r, CPP_W_INVALID_PCH,
 | |
| 	       "%s: not used because `%.*s' defined as `%s' not `%.*s'",
 | |
| 		       name, m.name_length, namebuf, newdefn + m.name_length,
 | |
| 		       m.definition_length - m.name_length,
 | |
| 		       namebuf +  m.name_length);
 | |
| 	  goto fail;
 | |
| 	}
 | |
|     }
 | |
|   free (namebuf);
 | |
|   namebuf = NULL;
 | |
| 
 | |
|   /* Read in the list of identifiers that must not be defined.
 | |
|      Check that they really aren't.  */
 | |
|   undeftab = XNEWVEC (unsigned char, m.definition_length);
 | |
|   if ((size_t) read (fd, undeftab, m.definition_length) != m.definition_length)
 | |
|     goto error;
 | |
| 
 | |
|   /* Collect identifiers from the current hash table.  */
 | |
|   nl.n_defs = 0;
 | |
|   nl.asize = 10;
 | |
|   nl.defs = XNEWVEC (cpp_hashnode *, nl.asize);
 | |
|   cpp_forall_identifiers (r, &collect_ht_nodes, &nl);
 | |
|   qsort (nl.defs, nl.n_defs, sizeof (cpp_hashnode *), &comp_hashnodes);
 | |
| 
 | |
|   /* Loop through nl.defs and undeftab, both of which are sorted lists.
 | |
|      There should be no matches.  */
 | |
|   first = undeftab;
 | |
|   last = undeftab + m.definition_length;
 | |
|   i = 0;
 | |
| 
 | |
|   while (first < last && i < nl.n_defs)
 | |
|     {
 | |
|       int cmp = ustrcmp (first, NODE_NAME (nl.defs[i]));
 | |
| 
 | |
|       if (cmp < 0)
 | |
|  	first += ustrlen (first) + 1;
 | |
|       else if (cmp > 0)
 | |
|  	++i;
 | |
|       else
 | |
| 	{
 | |
| 	  if (CPP_OPTION (r, warn_invalid_pch))
 | |
| 	    cpp_warning_syshdr (r, CPP_W_INVALID_PCH,
 | |
| 		                "%s: not used because `%s' is defined",
 | |
| 		                name, first);
 | |
| 	  goto fail;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   free(nl.defs);
 | |
|   nl.defs = NULL;
 | |
|   free (undeftab);
 | |
|   undeftab = NULL;
 | |
| 
 | |
|   /* Read in the next value of __COUNTER__.
 | |
|      Check that (a) __COUNTER__ was not used in the pch or (b) __COUNTER__
 | |
|      has not been used in this translation unit. */
 | |
|   if (read (fd, &counter, sizeof (counter)) != sizeof (counter))
 | |
|     goto error;
 | |
|   if (counter && r->counter)
 | |
|     {
 | |
|       if (CPP_OPTION (r, warn_invalid_pch))
 | |
| 	cpp_warning_syshdr (r, CPP_W_INVALID_PCH,
 | |
| 		            "%s: not used because `__COUNTER__' is invalid",
 | |
| 		            name);
 | |
|       goto fail;
 | |
|     }
 | |
| 
 | |
|   /* We win!  */
 | |
|   return 0;
 | |
| 
 | |
|  error:
 | |
|   cpp_errno (r, CPP_DL_ERROR, "while reading precompiled header");
 | |
| 
 | |
|  fail:
 | |
|   free (namebuf);
 | |
|   free (undeftab);
 | |
|   free (nl.defs);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Save all the existing macros.  */
 | |
| 
 | |
| struct save_macro_data
 | |
| {
 | |
|   uchar **defns;
 | |
|   size_t count;
 | |
|   size_t array_size;
 | |
|   char **saved_pragmas;
 | |
| };
 | |
| 
 | |
| /* Save the definition of a single macro, so that it will persist
 | |
|    across a PCH restore.  Because macro data is in GCed memory, which
 | |
|    will be blown away by PCH, it must be temporarily copied to
 | |
|    malloced memory.  (The macros will refer to identifier nodes which
 | |
|    are also GCed and so on, so the copying is done by turning them
 | |
|    into self-contained strings.)  The assumption is that most macro
 | |
|    definitions will come from the PCH file, not from the compilation
 | |
|    before the PCH file is loaded, so it doesn't matter that this is
 | |
|    a little expensive.
 | |
| 
 | |
|    It would reduce the cost even further if macros defined in the PCH
 | |
|    file were not saved in this way, but this is not done (yet), except
 | |
|    for builtins, and for #assert by default.  */
 | |
| 
 | |
| static int
 | |
| save_macros (cpp_reader *r, cpp_hashnode *h, void *data_p)
 | |
| {
 | |
|   struct save_macro_data *data = (struct save_macro_data *)data_p;
 | |
| 
 | |
|   if ((h->flags & NODE_BUILTIN)
 | |
|       && h->type == NT_MACRO
 | |
|       && r->cb.user_builtin_macro)
 | |
|     r->cb.user_builtin_macro (r, h);
 | |
| 
 | |
|   if (h->type != NT_VOID
 | |
|       && (h->flags & NODE_BUILTIN) == 0)
 | |
|     {
 | |
|       if (data->count == data->array_size)
 | |
| 	{
 | |
| 	  data->array_size *= 2;
 | |
| 	  data->defns = XRESIZEVEC (uchar *, data->defns, (data->array_size));
 | |
| 	}
 | |
| 
 | |
|       switch (h->type)
 | |
| 	{
 | |
| 	case NT_ASSERTION:
 | |
| 	  /* Not currently implemented.  */
 | |
| 	  return 1;
 | |
| 
 | |
| 	case NT_MACRO:
 | |
| 	  {
 | |
| 	    const uchar * defn = cpp_macro_definition (r, h);
 | |
| 	    size_t defnlen = ustrlen (defn);
 | |
| 
 | |
| 	    data->defns[data->count] = (uchar *) xmemdup (defn, defnlen,
 | |
|                                                           defnlen + 2);
 | |
| 	    data->defns[data->count][defnlen] = '\n';
 | |
| 	  }
 | |
| 	  break;
 | |
| 
 | |
| 	default:
 | |
| 	  abort ();
 | |
| 	}
 | |
|       data->count++;
 | |
|     }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* Prepare to restore the state, by saving the currently-defined
 | |
|    macros in 'data'.  */
 | |
| 
 | |
| void
 | |
| cpp_prepare_state (cpp_reader *r, struct save_macro_data **data)
 | |
| {
 | |
|   struct save_macro_data *d = XNEW (struct save_macro_data);
 | |
| 
 | |
|   d->array_size = 512;
 | |
|   d->defns = XNEWVEC (uchar *, d->array_size);
 | |
|   d->count = 0;
 | |
|   cpp_forall_identifiers (r, save_macros, d);
 | |
|   d->saved_pragmas = _cpp_save_pragma_names (r);
 | |
|   *data = d;
 | |
| }
 | |
| 
 | |
| /* Given a precompiled header that was previously determined to be valid,
 | |
|    apply all its definitions (and undefinitions) to the current state.
 | |
|    DEPNAME is passed to deps_restore.  */
 | |
| 
 | |
| int
 | |
| cpp_read_state (cpp_reader *r, const char *name, FILE *f,
 | |
| 		struct save_macro_data *data)
 | |
| {
 | |
|   size_t i;
 | |
|   struct lexer_state old_state;
 | |
|   unsigned int counter;
 | |
| 
 | |
|   /* Restore spec_nodes, which will be full of references to the old
 | |
|      hashtable entries and so will now be invalid.  */
 | |
|   {
 | |
|     struct spec_nodes *s = &r->spec_nodes;
 | |
|     s->n_defined	= cpp_lookup (r, DSC("defined"));
 | |
|     s->n_true		= cpp_lookup (r, DSC("true"));
 | |
|     s->n_false		= cpp_lookup (r, DSC("false"));
 | |
|     s->n__VA_ARGS__     = cpp_lookup (r, DSC("__VA_ARGS__"));
 | |
|     s->n__has_include__ = cpp_lookup (r, DSC("__has_include__"));
 | |
|     s->n__has_include_next__ = cpp_lookup (r, DSC("__has_include_next__"));
 | |
|   }
 | |
| 
 | |
|   old_state = r->state;
 | |
|   r->state.in_directive = 1;
 | |
|   r->state.prevent_expansion = 1;
 | |
|   r->state.angled_headers = 0;
 | |
| 
 | |
|   /* Run through the carefully-saved macros, insert them.  */
 | |
|   for (i = 0; i < data->count; i++)
 | |
|     {
 | |
|       cpp_hashnode *h;
 | |
|       size_t namelen;
 | |
|       uchar *defn;
 | |
| 
 | |
|       namelen = ustrcspn (data->defns[i], "( \n");
 | |
|       h = cpp_lookup (r, data->defns[i], namelen);
 | |
|       defn = data->defns[i] + namelen;
 | |
| 
 | |
|       /* The PCH file is valid, so we know that if there is a definition
 | |
| 	 from the PCH file it must be the same as the one we had
 | |
| 	 originally, and so do not need to restore it.  */
 | |
|       if (h->type == NT_VOID)
 | |
| 	{
 | |
| 	  if (cpp_push_buffer (r, defn, ustrchr (defn, '\n') - defn, true)
 | |
| 	      != NULL)
 | |
| 	    {
 | |
| 	      _cpp_clean_line (r);
 | |
| 	      if (!_cpp_create_definition (r, h))
 | |
| 		abort ();
 | |
| 	      _cpp_pop_buffer (r);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    abort ();
 | |
| 	}
 | |
| 
 | |
|       free (data->defns[i]);
 | |
|     }
 | |
|   r->state = old_state;
 | |
| 
 | |
|   _cpp_restore_pragma_names (r, data->saved_pragmas);
 | |
| 
 | |
|   free (data);
 | |
| 
 | |
|   if (deps_restore (r->deps, f, CPP_OPTION (r, restore_pch_deps) ? name : NULL)
 | |
|       != 0)
 | |
|     goto error;
 | |
| 
 | |
|   if (! _cpp_read_file_entries (r, f))
 | |
|     goto error;
 | |
| 
 | |
|   if (fread (&counter, sizeof (counter), 1, f) != 1)
 | |
|     goto error;
 | |
| 
 | |
|   if (!r->counter)
 | |
|     r->counter = counter;
 | |
| 
 | |
|   /* Read pushed macros. */
 | |
|   if (! _cpp_restore_pushed_macros (r, f))
 | |
|     goto error;
 | |
|   return 0;
 | |
| 
 | |
|  error:
 | |
|   cpp_errno (r, CPP_DL_ERROR, "while reading precompiled header");
 | |
|   return -1;
 | |
| }
 |