diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5896688..3b312d3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5879,10 +5879,9 @@ cp_rest_of_decl_compilation (tree decl, int top_level, int at_end)
 {
   rest_of_decl_compilation (decl, top_level, at_end);
 
-  /* If we are generating a PPH image, add DECL to the list of
-     declarations that need to be registered when this image is read.  */
+  /* If we are generating a PPH image, add DECL to its symbol table.  */
   if (pph_out_file)
-    pph_add_decl_to_register (decl);
+    pph_add_decl_to_symtab (decl);
 }
 
 
@@ -12815,10 +12814,9 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
 
   store_parm_decls (current_function_parms);
 
-  /* If we are generating a PPH image, add DECL1 to the list of
-     declarations that need to be registered when restoring the image.  */
+  /* If we are generating a PPH image, add DECL1 to its symbol table.  */
   if (pph_out_file)
-    pph_add_decl_to_register (decl1);
+    pph_add_decl_to_symtab (decl1);
 }
 
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c48807d..e069441 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -604,20 +604,19 @@ cp_lexer_new_main (void)
   cp_lexer *lexer;
   cp_token token;
 
-  if (pph_out_file != NULL || query_have_pph_map ())
+  if (pph_enabled_p ())
     {
       /* FIXME pph.  PPH is incompatible with PCH, so do not read ahead to
 	 the first token looking for a PCH pragma.  This convoluted
 	 initialization could be simplified if PCH was implemented in
-	 terms of the incremental compiler.  */
+	 terms of PPH.  */
       lexer = cp_lexer_alloc ();
-      pph_init ();
       cp_lexer_get_tokens (lexer);
     }
   else
     {
       /* FIXME pph.  Get rid of this duplicate and call cp_lexer_get_tokens
-	 all the time.  This is needed only because for PCH support we
+	 all the time.  This is needed only because, for PCH support, we
 	 are forced to read one token in advance before starting the
 	 main lexer loop.  */
 
@@ -25662,12 +25661,17 @@ c_parse_file (void)
     }
   already_called = true;
 
+  if (pph_enabled_p ())
+    pph_init ();
+
   the_parser = cp_parser_new ();
   push_deferring_access_checks (flag_access_control
 				? dk_no_deferred : dk_no_check);
   cp_parser_translation_unit (the_parser);
   the_parser = NULL;
-  pph_finish ();
+
+  if (pph_enabled_p ())
+    pph_finish ();
 }
 
 #include "gt-cp-parser.h"
diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c
index da006a1..eda93b8 100644
--- a/gcc/cp/pph-streamer-in.c
+++ b/gcc/cp/pph-streamer-in.c
@@ -1412,6 +1412,25 @@ pph_in_symtab (pph_stream *stream)
 }
 
 
+/* Read all the images included by STREAM.  */
+
+static void
+pph_in_includes (pph_stream *stream)
+{
+  unsigned i, num;
+
+  num = pph_in_uint (stream);
+  for (i = 0; i < num; i++)
+    {
+      const char *include_name = pph_in_string (stream);
+      /* FIXME pph.  Disabled for now.  Need to re-work caching so
+	 external symbol references are properly saved and restored.  */
+      if (0)
+	pph_read_file (include_name);
+    }
+}
+
+
 /* Read contents of PPH file in STREAM.  */
 
 static void
@@ -1425,6 +1444,11 @@ pph_read_file_contents (pph_stream *stream)
   unsigned i;
   VEC(tree,gc) *file_unemitted_tinfo_decls;
 
+  /* Read all the images included by STREAM.  */
+  pph_in_includes (stream);
+
+  /* Read all the identifiers and pre-processor symbols in the global
+     namespace.  */
   pph_in_identifiers (stream, &idents_used);
 
   /* FIXME pph: This validation is weak.  */
@@ -1459,6 +1483,12 @@ pph_read_file_contents (pph_stream *stream)
 
   /* Read and process the symbol table.  */
   pph_in_symtab (stream);
+
+  /* If we are generating an image, the PPH contents we just read from
+     STREAM will need to be read again the next time we want to read
+     the image we are now generating.  */
+  if (pph_out_file)
+    pph_add_include (stream);
 }
 
 
@@ -1477,9 +1507,6 @@ pph_read_file (const char *filename)
     {
       pph_read_file_contents (stream);
       pph_stream_close (stream);
-
-      if (flag_pph_debug >= 1)
-        fprintf (pph_logfile, "PPH: Closing %s\n", filename);
     }
   else
     error ("Cannot open PPH file for reading: %s: %m", filename);
diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c
index 0e42131..cbd2446 100644
--- a/gcc/cp/pph-streamer-out.c
+++ b/gcc/cp/pph-streamer-out.c
@@ -33,26 +33,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "cppbuiltin.h"
 #include "cgraph.h"
 
-/* FIXME pph.  This holds the FILE handle for the current PPH file
-   that we are writing.  It is necessary because the LTO callbacks do
-   not allow passing a FILE handle to them.  */
-static FILE *current_pph_file = NULL;
-
-/* List of declarations to register with the middle end.  This is
-   collected as the compiler instantiates symbols and functions.  Once
-   we finish parsing the header file, this array is written out to the
-   PPH image.  This way, the reader will be able to instantiate these
-   symbols in the same order that they were instantiated originally.  */
-typedef struct decls_to_register_t {
-  /* Table of all the declarations to register in declaration order.  */
-  VEC(tree,heap) *v;
-
-  /* Set of declarations to register used to avoid adding duplicate
-     entries to the table.  */
-  struct pointer_set_t *m;
-} decls_to_register_t;
-
-static decls_to_register_t decls_to_register = { NULL, NULL };
+/* PPH stream that we are currently generating.  FIXME pph, this
+   global is needed because we call back from various parts of the
+   compiler that do not know about PPH (e.g., some LTO callbacks,
+   cp_rest_of_decl_compilation).  */
+static pph_stream *pph_out_stream = NULL;
 
 /* Callback for packing value fields in ASTs.  BP is the bitpack 
    we are packing into.  EXPR is the tree to pack.  */
@@ -119,13 +104,13 @@ pph_begin_section (const char *name ATTRIBUTE_UNUSED)
 
 
 /* Callback for lang_hooks.lto.append_data.  Write LEN bytes from DATA
-   into current_pph_file.  BLOCK is currently unused.  */
+   into pph_out_stream.  BLOCK is currently unused.  */
 
 static void
 pph_out (const void *data, size_t len, void *block ATTRIBUTE_UNUSED)
 {
   if (data)
-    fwrite (data, len, 1, current_pph_file);
+    fwrite (data, len, 1, pph_out_stream->file);
 }
 
 
@@ -194,9 +179,6 @@ pph_out_body (pph_stream *stream)
 void
 pph_flush_buffers (pph_stream *stream)
 {
-  gcc_assert (current_pph_file == NULL);
-  current_pph_file = stream->file;
-
   /* Redirect the LTO basic I/O langhooks.  */
   lang_hooks.lto.begin_section = pph_begin_section;
   lang_hooks.lto.append_data = pph_out;
@@ -207,7 +189,6 @@ pph_flush_buffers (pph_stream *stream)
   pph_out_header (stream);
   pph_out_body (stream);
   lto_end_section ();
-  current_pph_file = NULL;
 }
 
 
@@ -1186,7 +1167,7 @@ pph_out_identifiers (pph_stream *stream, cpp_idents_used *identifiers)
 static inline void
 pph_out_symtab_marker (pph_stream *stream, enum pph_symtab_marker marker)
 {
-  pph_out_uchar (stream, marker);
+  pph_out_uchar (stream, (unsigned char) marker);
 }
 
 
@@ -1204,8 +1185,8 @@ pph_out_symtab (pph_stream *stream)
   tree decl;
   unsigned i;
 
-  pph_out_uint (stream, VEC_length (tree, decls_to_register.v));
-  FOR_EACH_VEC_ELT (tree, decls_to_register.v, i, decl)
+  pph_out_uint (stream, VEC_length (tree, stream->symtab.v));
+  FOR_EACH_VEC_ELT (tree, stream->symtab.v, i, decl)
     if (TREE_CODE (decl) == FUNCTION_DECL && DECL_STRUCT_FUNCTION (decl))
       {
 	if (DECL_SAVED_TREE (decl))
@@ -1219,13 +1200,20 @@ pph_out_symtab (pph_stream *stream)
 	pph_out_symtab_marker (stream, PPH_SYMTAB_DECL);
 	pph_out_tree (stream, decl);
       }
+}
 
-  if (decls_to_register.m)
-    {
-      VEC_free (tree, heap, decls_to_register.v);
-      pointer_set_destroy (decls_to_register.m);
-      decls_to_register.m = NULL;
-    }
+
+/* Emit the list of all the PPH files included by STREAM.  */
+
+static void
+pph_out_includes (pph_stream *stream)
+{
+  unsigned i;
+  pph_stream *include;
+
+  pph_out_uint (stream, VEC_length (pph_stream_ptr, stream->includes));
+  FOR_EACH_VEC_ELT (pph_stream_ptr, stream->includes, i, include)
+    pph_out_string (stream, include->name);
 }
 
 
@@ -1234,7 +1222,12 @@ pph_out_symtab (pph_stream *stream)
 static void
 pph_write_file_contents (pph_stream *stream, cpp_idents_used *idents_used)
 { 
-  /* Emit all the identifiers and symbols in the global namespace.  */
+  /* Emit the list of PPH files included by STREAM.  These files will
+     be read and instantiated before any of the content in STREAM.  */
+  pph_out_includes (stream);
+
+  /* Emit all the identifiers and pre-processor symbols in the global
+     namespace.  */
   pph_out_identifiers (stream, idents_used);
 
   /* Emit the bindings for the global namespace.  */
@@ -1257,25 +1250,18 @@ pph_write_file_contents (pph_stream *stream, cpp_idents_used *idents_used)
 }
 
 
-/* Write PPH output file.  */
+/* Write all the collected parse trees to STREAM.  */
 
-void
-pph_write_file (void)
+static void
+pph_write_file (pph_stream *stream)
 {
-  pph_stream *stream;
   cpp_idents_used idents_used;
 
   if (flag_pph_debug >= 1)
     fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file);
 
-  stream = pph_stream_open (pph_out_file, "wb");
-  if (!stream)
-    fatal_error ("Cannot open PPH file for writing: %s: %m", pph_out_file);
-
   idents_used = cpp_lt_capture (parse_in);
   pph_write_file_contents (stream, &idents_used);
-
-  pph_stream_close (stream);
 }
 
 
@@ -1634,18 +1620,58 @@ pph_write_tree (struct output_block *ob, tree expr,
 }
 
 
-/* Add DECL to the list of symbols that need to be registered with the
-   middle end when reading current_pph_stream.  */
+/* Add DECL to the symbol table for pph_out_stream.  */
 
 void
-pph_add_decl_to_register (tree decl)
+pph_add_decl_to_symtab (tree decl)
 {
-  if (decl)
-    {
-      if (decls_to_register.m == NULL)
-	decls_to_register.m = pointer_set_create ();
+  pph_stream *stream = pph_out_stream;
 
-      if (!pointer_set_insert (decls_to_register.m, decl))
-	VEC_safe_push (tree, heap, decls_to_register.v, decl);
-    }
+  if (decl == NULL || stream == NULL)
+    return;
+
+  if (!pointer_set_insert (stream->symtab.m, decl))
+    VEC_safe_push (tree, heap, stream->symtab.v, decl);
+}
+
+
+/* Add STREAM to the list of files included by pph_out_stream.  */
+
+void
+pph_add_include (pph_stream *stream)
+{
+  pph_stream *out_stream = pph_out_stream;
+  VEC_safe_push (pph_stream_ptr, heap, out_stream->includes, stream);
+  stream->nested_p = true;
+}
+
+
+/* Initialize the PPH writer.  */
+
+void
+pph_writer_init (void)
+{
+  gcc_assert (pph_out_stream == NULL);
+
+  pph_out_stream = pph_stream_open (pph_out_file, "wb");
+  if (pph_out_stream == NULL)
+    fatal_error ("Cannot open PPH file for writing: %s: %m", pph_out_file);
+}
+
+
+/* Finalize the PPH writer.  */
+
+void
+pph_writer_finish (void)
+{
+  pph_stream *out_stream = pph_out_stream;
+  const char *offending_file = cpp_main_missing_guard (parse_in);
+
+  if (offending_file == NULL)
+    pph_write_file (out_stream);
+  else
+    error ("header lacks guard for PPH: %s", offending_file);
+
+  pph_stream_close (out_stream);
+  pph_out_stream = NULL;
 }
diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index 08b8a46..a7a59a9 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -127,37 +127,56 @@ pph_stream_open (const char *name, const char *mode)
 
   stream = NULL;
   f = fopen (name, mode);
-  if (f)
-    {
-      pph_hooks_init ();
-      stream = XCNEW (pph_stream);
-      stream->file = f;
-      stream->name = xstrdup (name);
-      stream->write_p = (strchr (mode, 'w') != NULL);
-      if (stream->write_p)
-	pph_init_write (stream);
-      else
-	pph_init_read (stream);
-      stream->cache.v = NULL;
-      stream->cache.m = pointer_map_create ();
-    }
+  if (!f)
+    return NULL;
+
+  pph_hooks_init ();
+  stream = XCNEW (pph_stream);
+  stream->file = f;
+  stream->name = xstrdup (name);
+  stream->write_p = (strchr (mode, 'w') != NULL);
+  stream->cache.m = pointer_map_create ();
+  stream->open_p = true;
+  stream->symtab.m = pointer_set_create ();
+  if (stream->write_p)
+    pph_init_write (stream);
+  else
+    pph_init_read (stream);
 
   return stream;
 }
 
 
-/* Close PPH stream STREAM.  Write all the ASTs to disk and deallocate
-   all memory used by it.  */
 
-void
-pph_stream_close (pph_stream *stream)
+/* Helper for pph_stream_close.  Do not check whether STREAM is a
+   nested header.  */
+
+static void
+pph_stream_close_1 (pph_stream *stream)
 {
+  unsigned i;
+  pph_stream *include;
+
+  if (flag_pph_debug >= 1)
+    fprintf (pph_logfile, "PPH: Closing %s\n", stream->name);
+
+  /* If we were writing to STREAM, flush all the memory buffers.  This
+     does the actual writing of all the pickled data structures.  */
   if (stream->write_p)
     pph_flush_buffers (stream);
+
   fclose (stream->file);
+
+  /* Close all the streams we opened for included PPH images.  */
+  FOR_EACH_VEC_ELT (pph_stream_ptr, stream->includes, i, include)
+    pph_stream_close_1 (include);
+
+  /* Deallocate all memory used.  */
   stream->file = NULL;
   VEC_free (void_p, heap, stream->cache.v);
   pointer_map_destroy (stream->cache.m);
+  VEC_free (tree, heap, stream->symtab.v);
+  pointer_set_destroy (stream->symtab.m);
 
   if (stream->write_p)
     {
@@ -181,6 +200,26 @@ pph_stream_close (pph_stream *stream)
 }
 
 
+/* Close PPH stream STREAM.  */
+
+void
+pph_stream_close (pph_stream *stream)
+{
+  /* If STREAM is nested into another PPH file, then we cannot
+     close it just yet.  The parent PPH file will need to access
+     STREAM's symbol table (to avoid writing the same symbol
+     more than once).  In this case, STREAM will be closed by the
+     parent file.  */
+  if (stream->nested_p)
+    {
+      gcc_assert (!stream->write_p);
+      return;
+    }
+
+  pph_stream_close_1 (stream);
+}
+
+
 /* Data types supported by the PPH tracer.  */
 enum pph_trace_type
 {
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index d0c7f85..0f29c31 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -92,6 +92,22 @@ typedef struct pph_pickle_cache {
   struct pointer_map_t *m;
 } pph_pickle_cache;
 
+/* Symbol table for a PPH stream.  */
+typedef struct pph_symtab
+{
+  /* Table of all the declarations to register in declaration order.  */
+  VEC(tree,heap) *v;
+
+  /* Set of declarations to register used to avoid adding duplicate
+     entries to the table.  */
+  struct pointer_set_t *m;
+} pph_symtab;
+
+/* Vector of pph_stream pointers.  */
+struct pph_stream;
+typedef struct pph_stream *pph_stream_ptr;
+DEF_VEC_P(pph_stream_ptr);
+DEF_VEC_ALLOC_P(pph_stream_ptr,heap);
 
 /* Data structures used to encode and decode trees.  */
 
@@ -128,6 +144,27 @@ typedef struct pph_stream {
 
   /* Nonzero if the stream was opened for writing.  */
   unsigned int write_p : 1;
+
+  /* Nonzero if the file associated with this stream is open.
+     After we read a PPH image, we deallocate all the memory used
+     during streaming, but we keep the stream around to access its
+     symbol table.  */
+  unsigned int open_p : 1;
+
+  /* Nonzero if this PPH file is included from another PPH file.  */
+  unsigned int nested_p : 1;
+
+  /* Symbol table.  This is collected as the compiler instantiates
+    symbols and functions.  Once we finish parsing the header file,
+    this array is written out to the PPH image.  This way, the reader
+    will be able to instantiate these symbols in the same order that
+    they were instantiated originally.  */
+  pph_symtab symtab;
+
+  /* List of PPH files included by the PPH file that we are currently
+     generating.  Note that this list only contains PPH files, not
+     regular text headers.  Those are embedded in this stream.  */
+  VEC(pph_stream_ptr,heap) *includes;
 } pph_stream;
 
 /* Filter values for pph_out_chain_filtered.  */
@@ -154,8 +191,10 @@ void pph_init_write (pph_stream *);
 void pph_write_tree (struct output_block *, tree, bool);
 void pph_pack_value_fields (struct bitpack_d *, tree);
 void pph_out_tree_header (struct output_block *, tree);
-void pph_write_file (void);
-void pph_add_decl_to_register (tree);
+void pph_add_decl_to_symtab (tree);
+void pph_add_include (pph_stream *);
+void pph_writer_init (void);
+void pph_writer_finish (void);
 
 /* In name-lookup.c.  */
 struct binding_table_s;
@@ -348,7 +387,7 @@ pph_in_bytes (pph_stream *stream, void *p, size_t n)
     pph_trace_bytes (stream, p, n);
 }
 
-/* Read and return a string of up to MAX characters from STREAM.  */
+/* Read and return a string from STREAM.  */
 
 static inline const char *
 pph_in_string (pph_stream *stream)
diff --git a/gcc/cp/pph.c b/gcc/cp/pph.c
index 4e1a593..4bb3842 100644
--- a/gcc/cp/pph.c
+++ b/gcc/cp/pph.c
@@ -152,16 +152,17 @@ pph_init (void)
   if (flag_pph_debug >= 1)
     fprintf (pph_logfile, "PPH: Initializing.\n");
 
+  /* Set up the libcpp handler for #include.  */
   cb = cpp_get_callbacks (parse_in);
   cb->include = pph_include_handler;
-  /* FIXME pph: Use file change instead.
-  state->file_change_prev = cb->file_change;
-  cb->file_change = pph_file_change;
-  */
 
   table = cpp_lt_exchange (parse_in,
                            cpp_lt_create (cpp_lt_order, flag_pph_debug));
   gcc_assert (table == NULL);
+
+  /* If we are generating a PPH file, initialize the writer.  */
+  if (pph_out_file != NULL)
+    pph_writer_init ();
 }
 
 
@@ -171,13 +172,7 @@ void
 pph_finish (void)
 {
   if (pph_out_file != NULL)
-    {
-      const char *offending_file = cpp_main_missing_guard (parse_in);
-      if (offending_file == NULL)
-        pph_write_file ();
-      else
-        error ("header lacks guard for PPH: %s", offending_file);
-    }
+    pph_writer_finish ();
 
   if (flag_pph_debug >= 1)
     fprintf (pph_logfile, "PPH: Finishing.\n");
diff --git a/gcc/cp/pph.h b/gcc/cp/pph.h
index dc41ff6..b312685 100644
--- a/gcc/cp/pph.h
+++ b/gcc/cp/pph.h
@@ -43,10 +43,17 @@ typedef struct cp_token_hunk *cp_token_hunk_ptr;
 DEF_VEC_P (cp_token_hunk_ptr);
 DEF_VEC_ALLOC_P (cp_token_hunk_ptr,gc);
 
+/* Return true if PPH has been enabled.  */
+static inline bool
+pph_enabled_p (void)
+{
+  return pph_out_file != NULL || query_have_pph_map ();
+}
+
 /* Global state.  FIXME pph, get rid of these.  */
 
 /* Log file where PPH analysis is written to.  Controlled by
-   -fpph_logfile.  If this flag is not given, stdout is used.  */
+   -fpph-logfile.  If this flag is not given, stdout is used.  */
 extern FILE *pph_logfile;
 
 /* In pph.c  */
diff --git a/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc b/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc
index c13ee87..d64c9ae 100644
--- a/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc
+++ b/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc
@@ -1,3 +1,2 @@
-// { dg-xfail-if "INFINITE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: in lto_streamer_cache_get, at lto-streamer.c" "" { xfail *-*-* } 0 }
+/* { dg-options "-O -Wno-psabi -mtune=generic" } */
 #include "c0pr44948-1a.h"
